Uruchom aplikację w GDB do wystąpienia wyjątku

102

Pracuję nad aplikacją wielowątkową i chcę ją debugować za pomocą GDB.

Problem w tym, że jeden z moich wątków umiera wraz z komunikatem:

pure virtual method called
terminate called without an active exception
Abort

Znam przyczynę tej wiadomości, ale nie mam pojęcia, gdzie w moim wątku się pojawia. Ślad wsteczny byłby naprawdę pomocny.

Gdy uruchamiam aplikację w GDB, zatrzymuje się ona za każdym razem, gdy wątek jest zawieszany lub wznawiany. Chcę, aby moja aplikacja działała normalnie, dopóki jeden z wątków nie umrze z tym wyjątkiem, w którym to momencie wszystko powinno się zatrzymać, aby można było uzyskać ślad.

Ankur Sethi
źródło
Jaki sygnał zgłasza GDB po wstrzymaniu? powinieneś być w stanie uruchomić polecenie takie jakhandle SIGUSR1 pass noprint nostop
Hasturkun

Odpowiedzi:

148

Możesz spróbować użyć „catchpoint” ( catch throw), aby zatrzymać debugger w punkcie, w którym generowany jest wyjątek.

Poniższy fragment podręcznika gdb opisuje funkcję catchpoint.


5.1.3 Ustawianie catchpointów

Możesz użyć punktów przechwytywania, aby spowodować zatrzymanie debugera dla niektórych rodzajów zdarzeń programu, takich jak wyjątki C ++ lub ładowanie biblioteki współużytkowanej. Użyj polecenia catch, aby ustawić punkt zaczepienia.

  • złapać zdarzenie

    Zatrzymaj się, gdy nastąpi zdarzenie . zdarzenie może być dowolne z następujących:

    • rzucać

      Zgłaszanie wyjątku C ++.

    • łapać

      Przechwytywanie wyjątku C ++.

    • exec

      Wezwanie do exec. Obecnie jest to dostępne tylko dla HP-UX.

    • widelec

      Wezwanie do rozwidlenia. Obecnie jest to dostępne tylko dla HP-UX.

    • vfork

      Wezwanie do vfork. Obecnie jest to dostępne tylko dla HP-UX.

    • load lub load libname

      Dynamiczne ładowanie dowolnej biblioteki współdzielonej lub ładowanie biblioteki nazwa_biblioteki. Obecnie jest to dostępne tylko dla HP-UX.

    • unload lub unload libname

      Wyładowanie dowolnej dynamicznie ładowanej biblioteki współdzielonej lub usunięcie biblioteki nazwa_biblioteki. Obecnie jest to dostępne tylko dla HP-UX.

  • tcatch zdarzenie

    Ustaw punkt zaczepienia, który jest włączony tylko dla jednego przystanku. Punkt przechwytywania jest automatycznie usuwany po pierwszym złapaniu zdarzenia.

Użyj info breakpolecenia, aby wyświetlić bieżące punkty zaczepienia.

Obecnie istnieją pewne ograniczenia dotyczące obsługi wyjątków C ++ (rzut przechwytywania i przechwytywanie) w GDB:

  • Jeśli wywołasz funkcję interaktywnie, GDB zwykle zwraca kontrolę po zakończeniu wykonywania funkcji. Jeśli jednak wywołanie wywoła wyjątek, wywołanie może ominąć mechanizm, który zwraca ci kontrolę i spowodować przerwanie programu lub po prostu kontynuowanie działania, aż osiągnie punkt przerwania, przechwyci sygnał, którego nasłuchuje GDB, lub zakończy działanie. Dzieje się tak nawet wtedy, gdy ustawisz punkt zaczepienia dla wyjątku; punkty przechwytywania wyjątków są wyłączone w wywołaniach interaktywnych.

  • Nie możesz interaktywnie zgłosić wyjątku.

  • Nie można zainstalować interaktywnej obsługi wyjątków.

Czasami catch nie jest najlepszym sposobem debugowania obsługi wyjątków: jeśli chcesz dokładnie wiedzieć, gdzie został zgłoszony wyjątek, lepiej zatrzymać się przed wywołaniem procedury obsługi wyjątków, ponieważ w ten sposób możesz zobaczyć stos przed jakimkolwiek odwinięciem. Jeśli zamiast tego ustawisz punkt przerwania w programie obsługi wyjątków, ustalenie, gdzie został zgłoszony wyjątek, może nie być łatwe.

Aby zatrzymać się tuż przed wywołaniem procedury obsługi wyjątków, potrzebujesz pewnej wiedzy na temat implementacji. W przypadku GNU C ++ wyjątki są zgłaszane przez wywołanie funkcji bibliotecznej o nazwie __raise_exception, która ma następujący interfejs ANSI C:

/* addr is where the exception identifier is stored.
   id is the exception identifier.  */
void __raise_exception (void **addr, void *id);

Aby debuger przechwytywał wszystkie wyjątki, zanim nastąpi rozwijanie stosu, ustaw punkt przerwania na __raise_exception (zobacz sekcję Punkty przerwania; punkty obserwacyjne; i wyjątki).

Za pomocą warunkowego punktu przerwania (zob. Sekcja Warunki przerwania), który zależy od wartości id, możesz zatrzymać program, gdy zostanie zgłoszony określony wyjątek. Możesz użyć wielu warunkowych punktów przerwania, aby zatrzymać program, gdy zostanie zgłoszony dowolny z wielu wyjątków.

Dan
źródło
Możesz również określić typ wyjątku do wyłapania, np catch throw std::runtime_exception.
scai
5

Ustaw punkt przerwania na __pure_virtual

Steve Folly
źródło
W odpowiedzi @JeffreyHill nazywa się teraz __cxa_pure_virtual. Sam nie wiem, jak to sprawdzić, więc nie chcę edytować odpowiedzi. Nie zamierzam głosować przeciw, ale teraz odpowiedź może być błędna i powinna zostać zredagowana przez kogoś, kto wie, co jest poprawne.
Philipp Claßen
5

FWIW najwyraźniej w gcc 4.1 zmieniła się odpowiednia nazwa funkcji i należy ustawić w tej funkcji punkt przerwania.

__cxa_pure_virtual

Jeffrey Hill
źródło
0

Tylko poniżej jeden działał u mnie z gdb 8.3:

break _Unwind_RaiseException

„Złap rzut” lub „przerwa __cxx_throw” nie działały dla mnie.

soumeng78
źródło