java 8 i gdb - debugowanie java z gdb

0

Pytanie - da się debugować kod java z poziomu gdb? Mam 2 konsole, w jednej sobie leci program w pętliw, w drugiej gdb. Próbuję wpiąć się do procesu w linuxie takimi komendami

gdb // uruchamia się gdb
!pidof java // szukam pid procesu mojej aplikacji
set non-stop on // zmieniam tryb żeby nie zatrzymywało wszystkich wątków 
attach 82448 // czyli podłączam się pod proces np o pid 82448

jak dam info threads widzę jakieś 15 wątków, w tym kompilatory c1, c2 itp. I zatrzymuje się gdzieś poza wątkiem Main, tylko gdzieś w pthread_join.c:92. Jak dam disassemble to widzę kod tego pthread_join. I wszystkie wątki są zatrzymane mimo że dałem set non-stop on jako root. A jak wpiszę continue & to pokazuje Asynchronous execution not supported on this target.. Idzie jakoś debugować kod java przez gdb podpinając się pod proces ? nawet jak dam samo continue to potem już nie ruszy, zatrzymane jest wszystko i tylko wyjście z gdb wznowi wykonywanie programu dalej.

Niech bedzie że to jest ta aplikacja. Proces java jaki uruchamiam.

public class Main {
    private static volatile int val = 0;
    public static void main(String[] args) throws InterruptedException{
        while(true) {
            System.out.format("%d \n", val);
            setVal();
            Thread.sleep(100);          
        }
    }
    public static void setVal() {
        val++;
    }
}

Linux Ubuntu 14.04LTS, Intel i3 2220, gdb GNU gdb (Ubuntu 7.7.1-0ubuntu514.04.3) 7.7.1, java openjdk version "1.8.0_222" OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-114.04-b10) OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)

1

Tak to debugujesz jvm. Bez sensu. Możesz użyć gdb jeśli uda ci się skompilować do binarki. Gcc ma kompilator Javy, ale nie mam pojęcia na ile można na tym polegać.

2
elwis napisał(a):

Gcc ma kompilator Javy, ale nie mam pojęcia na ile można na tym polegać.

Nie można. Przestał być wspierany. Ale teraz jest GraalVM

3

No można tak robić, ale to totalny hardkor, bo debugujesz JVMa który interpretuje javowy bajtkod. Debugowanie ten sposób aplikacji javowej to dramatyczny pomysł i nawet hello world będzie tu bardzo trudny do ogarnięcia i to już przy założeniu że bajtkod javy masz w małym palcu.

Czemu nie zrobisz tego po ludzku? IntelliJ ma opcje "remote debug", która pokazuje ci jakie parametry dodajesz do tej javowej aplikacji żeby debugger mógł się podłączyć.

0

Nie wiedziałem o Remote Debug. Ale nie mogę tego uruchomić. Próbowałem różne porty ale to nie to jednak. Unable to open debugger port (localhost:8787): java.net.ConnectException "Connection refused (Connection refused)" . Coś trzeba mieć jeszcze odpalone? I potem w gdb będę mógł się połączyć przez (gdb) target remote localost:8787 z tym? jdb jakoś mi póki co nie lezy, nie wiem co tym można debugować i jak. A ogólnie chciałbym zejść trochę głębiej w to co się dzieje w tym kodzie java.

2

@shab Remote debug nie służy do łączenia się przez gdb, tylko przez remote debug w IntelliJ :)

  1. Tworzysz w IntelliJ konfiguracje Remote Debug i dostajesz argumenty które masz dodać przy odpalaniu aplikacji. Zapisujesz też tą konfiguracje
  2. Dodajesz te parametry i uruchamiasz aplikacje
  3. Odpalasz ten remote debug w IntelliJ
  4. Profit!

Unable to open debugger port

Sugeruje że może port juz jest zajęty albo program nie ma uprawnień albo coś podobnego.

1
shab napisał(a):

A ogólnie chciałbym zejść trochę głębiej w to co się dzieje w tym kodzie java.

Czyli np. co konkretnie? Bo może wcale nie debugera szukasz.

1

Ewidentnie @shab pyta nie o to co jest mu potrzebne, ale o to jak naprawić coś co myśli, że jest mu potrzebne.
Klasyczny przypadek problemu XY.
sens użycia gdb widzę wtedy, gdy używasz jni lub jna, czyli mieszasz kod Java z C lub C++ lub innym językiem kompilowanym do kodu maszynowego.
Jeśli to jest ten przypadek to go dokładnie opisz, zwłaszcza to co chcesz zdebugować.

1
shab napisał(a):

Nie wiedziałem o Remote Debug. Ale nie mogę tego uruchomić. Próbowałem różne porty ale to nie to jednak. Unable to open debugger port (localhost:8787): java.net.ConnectException "Connection refused (Connection refused)" . Coś trzeba mieć jeszcze odpalone?

Tak, trzeba mieć odpalonego jara w trybie do debugowania i samemu wystawić port do debugowania są to parametry w rodzaju java -jar -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 your_jar_file.jar. Ogólnie nigdy tego nie robiłem z konsoli, bo łatwiej takie uruchomienie z opcją debuga wyklikać z idea intellij.

A ogólnie chciałbym zejść trochę głębiej w to co się dzieje w tym kodzie java.

A może to czego szukasz to profiler? Można wyciągnąć wiele różnych statystyk jak to które metody wykonują się najczęściej a które najdłużej

0
jarekr000000 napisał(a):

Czyli np. co konkretnie? Bo może wcale nie debugera szukasz.

Możesz mieć rację. Pierwotnie chciałem sprawdzać problemy z moim kodem, np dlaczego wywala mi wyjątki ConcurrentModificationException, co tam się dzieje dokładnie że jest jakaś kolizja. Ten profiler może też być ciekawy, jeśli mierzy czas wykonania, albo ilość wywołań jakiejś funkcji, odwołań do obiektu i robi tego typu statystyki. To jest ciekawe. Na razie dzięki, przejrzę to co podrzuciliście.

2

np dlaczego wywala mi wyjątki ConcurrentModificationException

Dlaczego to raczej oczywiste, bo dokumentacja jasno określa kiedy taki wyjątek jest rzucany. Ale debuger często w tej sytuacji nie pomoże, bo wprowadza synchronizacje i szansa na złapanie wyjątku concurrent jest znikoma.

6

E tam, wcale nie potrzeba wielu wątków:

List<String> list = new ArrayList<>();
list.add("ala");
list.add("ma");
list.add("kota");

for (String s : list) {
  if(s.equals("ala")) {
    list.remove(s);
  }
 }

Wypluwa:

java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
3

Java ma wbudowany debugger, trzeba go tylko włączyć ustawiając odpowiednie opcje w linii poleceń. GDB służy do debugowania aplikacji natywnych, a nie interpretowanych i/ lub JITowanych (jak typowo w przypadku Javy).

Jeśli jesteś hardkorem to możesz debugować za pomocą JDB https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jdb.html ale każde sensowne IDE do Javy posiada graficznego debuggera, którego normalni ludzie używają zamiast tego JDB.

0

Może zapytam trochę inaczej. A co jeśli chciałbym dodać w kodzie java, gdzieś w głębi aplikacji pułapkę dla debugera. W procesorach x86 jest instrukcja int3, przerwanie dla debugera. Jeśli w kodzie zrobi się wstawkę asemblera asm ("int 3");" albo po prostu int 3 używając samego koplilatora asm to program się zatrzyma w gdb na tej instrukcji. Jak zrobić tego typu wstawkę w java, żeby debuger zachował się w ten sposób jak int3 razem z gdb. Najprościej byłoby mieć wstawki asm w java, ale chyba nie ma ;/ A może jakoś inaczej da się do tego podejść ? Bo wewnątrz intelijj można robić breakpointy w swoim programie. Ale jak program nie jest mój, tylko mogę go jedynie uruchomić, a pod nim odpalać jakieś podpgoramy które napiszę w oparciu o jego API, wtedy debugowanie przez intelijj, eclipse raczej nie jest możliwe.

2

Znowu coś kombinujesz.
Można debugować nie swoje programy, biblioteki itd. Nie trzeba mieć źródeł. Można robić braeakpointy w cudzym kodzie.

Czasem - jeśli źródła (bytecode) są skompilowane bez obcji debug i jeszcze obfuscowane jest to trochę bardziej męczące - ale nadal łatwiejsze w użyciu niż gdb :-)

gdm ogólnie javę możesz sobie też debugować tylko nie ma to żadnego sensu - choćby przez jit - ten sam kawałek kodu w javie może być kilkukrotnie skompilowany do innego fragmentu kodu asm - dośc prawdopodobne, że nawet jak ustawisz pułapkę to nic w nią potem nie wpadnie.

2

@shab:
Java nie używa przerwań. Jaki masz problem ze wstawieniem breakpointa? IntelliJ zawiera wbudowany dekompilator. Możesz dzięki niemu podejrzeć klasę, a potem zapinasz pułapkę i gotowe. Ja tak właśnie zrobiłem (dla JARa, którego ściągnąłem ręcznie bez źródeł i wstawiłem do projektu) i działa.

0

Będziem kontynuować ten temat, bo jednak debugowanie javy nie jest to tak oczywiste jak z kodem C albo ASM. A widzę że jest jeszcze javah i to też daje możliwości połączenia C i Java. Pozdrawiam :)

1

Debugowanie Javy jest oczywiste i proste. Wystarczy tylko debugować javę.

1

Jeżeli interesuje Cie debugowanie JVM'a za pomocą GDB to polecam . Generalnie nie wydaje się to przydatna umiejętność (ale na pewno ciekawa, przejście przez build + zapięcie break pointa i wywołanie paru JVMowych funkcji daje trochę dziwnej satysfakcji :D), ale jesteś w stanie ustawić breakpoint (wystarczy że robisz follow stepów z filmu). Jako przykładowy case Volker pokazuje debugowanie problemu javy za pomocą gdb ponieważ nie dało się tego problemu debugować javovym debugerem, ponieważ w momencie kiedy wpinasz sie debugiem (javowym) wyłącza się JIT :) - (za dużo "ponieważ")

1 użytkowników online, w tym zalogowanych: 0, gości: 1