Konfiguracja "post-mortem debugging"

1

Chciałbym aby w momencie gdy aplikacja zaliczy crash automatycznie uruchomił się debugger gdzie mógłbym obejrzeć co się wydarzyło. Aplikacja skompilowana w msys2+clang16.0.5 (Windows)

Moje eksperymenty:
[1]
QtCreator i opcja Edit > Preferences > Debugger > General > Use Qt Creator for post-mortem debugging.
W momencie wyjatku uruchamia się QtCreator tylko że domyslnie jest CDB a nie GDB wiec symboli gdb nie czyta

[2]
Trochę błądzę ale umiem uruchomić windbg.exe
https://learn.microsoft.com/en-us/windows/win32/debug/configuring-automatic-debugging#configuring-automatic-debugging-for-application-crashes
windbg też nie rozumie symboli gdb ale sukcesem jest że wiem gdzie to jest w rejestrach :D

[3]
Tutaj znalazłem opis jak zarejestrować gdb
https://www.msys2.org/wiki/JIT-Debugging/
ale to też nie działa poprawnie bo zamiast GDB uruchamia się jakieś okno (chyba wiersz poleceń) ktore ma zablokowana kolejkę komunikatów, jak je zamknę to uruchomi sie okno GDB ale nie jest połączone z martwa aplikacją

0

co rozumiesz przez crash ?
Możesz zawsze wyłączyć/obsłużyć sobie segfaulta, bo to tylko sygnał. Nie wiem jak jest na windows, taka wskazówka tylko.

0
ksh napisał(a):

co rozumiesz przez crash ?
Możesz zawsze wyłączyć/obsłużyć sobie segfaulta, bo to tylko sygnał. Nie wiem jak jest na windows, taka wskazówka tylko.

Na mainframach w fortranie, paaaaaanie to było postmortem, niii to co teraz młode robiom
Robiło się dzielenie przez zero (kompilacja debug) i spowiadał się ze zmiennych

Ale już bardziej serio: @Marius.Maximus
Decydując sie na kompilację Debug masz większe szanse, pytanie czy chcesz mieć Debug na produkcji.

0
            auto crash_example = [](){
                char * foo = nullptr;
                *foo = 42;
            } ;

Nie wiem jak pod Windows kompilując kompilatorem clang z msys2 ogarnąć tego typu sytuacje.
Pod Linux mogę to oprogramować reagując na odpowiedni sygnał , działa tez fsanitize
Po Windows nie działa mi fsanitize w polaczeniu z Qt wiec szukam alternatywnej drogi na zbadanie dlaczego aplikacja zakończyła przedwcześnie swój żywot

Ideałem było by podobne rozwiązanie jak w Delphi

  procedure crash_example;
  var
    foo:PChar;
  begin
    foo := nil;
    foo^ := #42;
  end;

W Release wywolanie funkcji crash_example mam to oprogramowane w postaci komunikatu
screenshot-20230616083133.png

czyli wyszedł problem XY ;)

2

A nie możesz w tym rejestrze zamiast windbg.exe" -p %ld -e %ld -g wpisać powershell" -Command "gdb -p %ld" , ewentualnie terminal windows lub cmd i w nim gdb z attachem pod pid.

0

w rejestrze mogę wpisać zamiast windbg dowolną aplikację

np. C:\msys64\clang64\bin\gdb -p %ld

I gdb sie uruchamia

[New Thread 28192.0x6738]
[New Thread 28192.0x28ec]
[New Thread 28192.0x24ac]
[New Thread 28192.0x6064]
[New Thread 28192.0x68cc]
Reading symbols from C:\Users\X\Desktop\gity\bin\app3.exe...
(gdb)

tylko nie mam zielonego pojęcia jak obsługiwać gdb z linii polecen.

1

Chciałbym aby w momencie gdy aplikacja zaliczy crash automatycznie uruchomił się debugger gdzie mógłbym obejrzeć co się wydarzyło.

nie możesz sobie core dump wygenerować, i obejrzeć później?

3

@Marius.Maximus: Pora się nauczyć :P

Ale nie jest jakoś trudno, tryb graficzny włączasz wpisując tui enable
masz poruszanie się za pomocą n,s, ni, si, gdzie masz odpowiednio następna linia kodu, lub następna instrukcja i masz też następna instrukcja, ale jak funkcja to wejdź w nią itp.
Jak użyjesz jednej to potem możesz F7, F8 wciskać.

Jak włączysz TUI to wyświetli ci się kod źródłowy i możesz iterować linia po linii.
Jak breakpoint chcesz ustawić to break *address lub break main.c:35 co powinno ustawić na 35 lini breakpoint w main.c pliku.

display/10i $rip będzie ci co każdy krok w gdb wyświetlać 10 instrukcji assemblera
dissassembly-flavor intel zmieni assembly na intela

help to masz pomoc
info reg
info line *0xaddress

wyświetlanie i konwersje masz z C, p (char*)$rax jeśli w rax był wskaźnik na stringa, to rzutujesz go na typ char* pointer i print func.
Jak masz symbole debuggera to bezpośrednio do zmiennych można się odwoływać, a nie poprzez adresy i rejestry.

backtrace lub bt 10 do wyświetlania stack trace.

Można też skryptować w pythonie, ale trochę do poczytania.
https://sourceware.org/gdb/onlinedocs/gdb/Python-API.html#Python-API

2

Sprawdziłem "Use Qt Creator for post-mortem debugging" na projekcie skompilowany w Visual studio , i tutaj wszystko działa idealnie
Wywołanie "crash_example() " powoduje uruchomienie QtCreator i jestem w miejscu wyjątku.
Czyli wszystko działa pięknie w QtCreator jak jest odpowiedni kompilator :D

0

@GodOfCode gdy JIT-Debugging skonfiguruje dla GDB to mogę obejrzeć wszystkie watki ale nie mam informacji w którym wątku był wyjątek,jak obejrzę watki to mogę znaleźć miejsce na podstawie funkcji w okolicy np.:

w #11 jest mój wyjątek
zawsze jest uruchamiane 'KiUserExceptionDispatcheriRtlRaiseException`

(gdb) thread 1
[Switching to thread 1 (Thread 20108.0x69d8)]
#0  0x00007fff6452dc04 in ntdll!ZwWaitForMultipleObjects () from C:\Windows\SYSTEM32\ntdll.dll
(gdb) bt
#0  0x00007fff6452dc04 in ntdll!ZwWaitForMultipleObjects () from C:\Windows\SYSTEM32\ntdll.dll
#1  0x00007fff62021b40 in WaitForMultipleObjectsEx () from C:\Windows\System32\KernelBase.dll
#2  0x00007fff62021a3e in WaitForMultipleObjects () from C:\Windows\System32\KernelBase.dll
#3  0x00007fff63bf0eba in WerpLaunchAeDebug () from C:\Windows\System32\kernel32.dll
#4  0x00007fff63bf08f6 in WerpLaunchAeDebug () from C:\Windows\System32\kernel32.dll
#5  0x00007fff620fdf99 in UnhandledExceptionFilter () from C:\Windows\System32\KernelBase.dll
#6  0x00007fff64535570 in ntdll!memset () from C:\Windows\SYSTEM32\ntdll.dll
#7  0x00007fff6451c8c6 in ntdll!__C_specific_handler () from C:\Windows\SYSTEM32\ntdll.dll
#8  0x00007fff6453247f in ntdll!.chkstk () from C:\Windows\SYSTEM32\ntdll.dll
#9  0x00007fff644e14f4 in ntdll!RtlRaiseException () from C:\Windows\SYSTEM32\ntdll.dll
#10 0x00007fff64530f8e in ntdll!KiUserExceptionDispatcher () from C:\Windows\SYSTEM32\ntdll.dll
#11 0x00007ff72763f3f5 in Menu::Menu(QWidget*)::$_44::operator()() const::{lambda()#1}::operator()() const (this=0xee4b2fb688) at C:/Main.cpp:888
2

Ja bym to zrobił tak:

Można złapać tego throw jeśli to był rzucony z c++, ale widzę że nie ma __cxa_throw, to jest jakiś inny chyba exception.

Tak można złapać go na catch throw i potem zrobić w gdb run.

Nawet jak nie złapiesz to też tam pies, można ustawić breakpoint na KiUserExcepitonDispatcher, ale nawet bez ustawiania breakpointa można sobie poradzić.
Powinien automatycznie się ustawić thread, który został złapany na breakpoint lub tym exceptionie.

Teraz tak jak zrobisz bt to jesteś pod adresem 0x00007fff6452dc04 funkcji na tej ramce stosu.
jak zrobisz up to przejdziesz ramkę do góry, musisz wejść do ramki 0x00007ff72763f3f5 czyli możesz też od razu up 11 gdyż ( #11 0x00007ff72763f3f5 in Menu) powinno wypisać się kod źródłowy main.cpp:888

lub możesz ręcznie wypisać, list *0x00007ff72763f3f5 to powinno wypisać kod źródłowy ewentualnie list main.cpp:888 nie idzie się przesuwać w tym kodzie źródłowym to odpal sobie tui enable teraz strzałkami można sobie zobaczyć jak wygląda.

Jak za pomocą tego up lub down idziesz jedną ramkę do góry i na dół to jak ustawisz odpowiednią ramkę to możesz zmienne w tej ramce wypisywać po nazwie np. p zmienna_int.

Ogólnie tutaj już musisz popatrzeć czemu jakiś warunek został spełniony, że akurat tędy poszło wykonanie programu.

2

Napisz czy poradziłeś sobie jak coś to mogę wbić na remote desktop lub udostępnisz remote debugging i ci pomogę to zdebugować.

0

Wszystko jest banalnie proste jak już wiesz jak to zrobić :)
Jak dodam w clang generowanie CodeView i wygeneruje pdb to wszystko po prostu działa w każdym windowsowym narzędziu

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