Esegui un'applicazione in GDB finché non si verifica un'eccezione


102

Sto lavorando su un'applicazione multithread e voglio eseguirne il debug utilizzando GDB.

Il problema è che uno dei miei thread continua a morire con il messaggio:

pure virtual method called
terminate called without an active exception
Abort

Conosco la causa di quel messaggio, ma non ho idea di dove si trovi nel mio thread. Un backtrace sarebbe davvero utile.

Quando eseguo la mia app in GDB, si ferma ogni volta che un thread viene sospeso o ripreso. Voglio che la mia app continui a funzionare normalmente fino a quando uno dei thread non muore con quell'eccezione, a quel punto tutto dovrebbe interrompersi in modo da poter ottenere un backtrace.


Quale segnale sta segnalando GDB quando si ferma? dovresti essere in grado di eseguire un comando comehandle SIGUSR1 pass noprint nostop
Hasturkun

Risposte:


147

Puoi provare a utilizzare un "catchpoint" ( catch throw) per arrestare il debugger nel punto in cui viene generata l'eccezione.

Il seguente estratto dal manuale gdb descrive la funzione catchpoint.


5.1.3 Impostazione dei punti di incontro

È possibile utilizzare i punti di incontro per arrestare il debugger per determinati tipi di eventi del programma, come le eccezioni C ++ o il caricamento di una libreria condivisa. Usa il comando catch per impostare un catchpoint.

  • evento di cattura

    Fermati quando si verifica un evento . evento può essere uno dei seguenti:

    • gettare

      La generazione di un'eccezione C ++.

    • catturare

      La cattura di un'eccezione C ++.

    • exec

      Una chiamata a exec. Attualmente è disponibile solo per HP-UX.

    • forchetta

      Una chiamata al fork. Attualmente è disponibile solo per HP-UX.

    • vfork

      Una chiamata a vfork. Attualmente è disponibile solo per HP-UX.

    • carica o carica libname

      Il caricamento dinamico di qualsiasi libreria condivisa o il caricamento della libreria libname. Attualmente è disponibile solo per HP-UX.

    • scaricare o scaricare libname

      Lo scaricamento di qualsiasi libreria condivisa caricata dinamicamente o lo scaricamento della libreria libname. Attualmente è disponibile solo per HP-UX.

  • evento tcatch

    Impostare un punto di incontro abilitato solo per una sosta. Il punto di incontro viene automaticamente eliminato dopo la prima volta che l'evento viene rilevato.

Utilizzare il info breakcomando per elencare i punti di cattura correnti.

Ci sono attualmente alcune limitazioni alla gestione delle eccezioni C ++ (catch throw e catch catch) in GDB:

  • Se chiami una funzione in modo interattivo, GDB normalmente ti restituisce il controllo quando la funzione ha terminato l'esecuzione. Se la chiamata solleva un'eccezione, tuttavia, la chiamata può bypassare il meccanismo che ti restituisce il controllo e causare l'interruzione del programma o semplicemente continuare a funzionare finché non raggiunge un punto di interruzione, cattura un segnale che GDB sta ascoltando o esce. Questo è il caso anche se si imposta un punto di incontro per l'eccezione; i punti di incontro sulle eccezioni sono disabilitati nelle chiamate interattive.

  • Non è possibile sollevare un'eccezione in modo interattivo.

  • Non è possibile installare un gestore di eccezioni in modo interattivo.

A volte catch non è il modo migliore per eseguire il debug della gestione delle eccezioni: se hai bisogno di sapere esattamente dove viene sollevata un'eccezione, è meglio fermarti prima che venga chiamato il gestore delle eccezioni, poiché in questo modo puoi vedere lo stack prima che avvenga qualsiasi svolgimento. Se invece imposti un punto di interruzione in un gestore di eccezioni, potrebbe non essere facile scoprire dove è stata sollevata l'eccezione.

Per interrompere appena prima che venga chiamato un gestore di eccezioni, è necessaria una certa conoscenza dell'implementazione. Nel caso di GNU C ++, le eccezioni vengono sollevate chiamando una funzione di libreria denominata __raise_exception che ha la seguente interfaccia ANSI C:

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

Per fare in modo che il debugger rilevi tutte le eccezioni prima che avvenga qualsiasi svolgimento dello stack, impostare un breakpoint su __raise_exception (vedere la sezione Breakpoints; watchpoints; ed eccezioni).

Con un punto di interruzione condizionale (vedere la sezione Condizioni di interruzione) che dipende dal valore di id, è possibile interrompere il programma quando viene sollevata un'eccezione specifica. È possibile utilizzare più punti di interruzione condizionali per interrompere il programma quando viene sollevata una qualsiasi di una serie di eccezioni.


Puoi anche specificare il tipo di eccezione da catturare, ad es catch throw std::runtime_exception.
scai

5

Imposta un punto di interruzione su __pure_virtual


Nella risposta di @JeffreyHill, ora si chiama __cxa_pure_virtual. Non so come verificarlo da solo, quindi non voglio modificare la risposta. Non intendo votare per difetto, ma la risposta potrebbe essere sbagliata ora e dovrebbe essere modificata da qualcuno che sa cosa è corretto.
Philipp Claßen

5

FWIW, apparentemente, in gcc 4.1, il nome della funzione appropriata è cambiato e si deve impostare un punto di interruzione in questa funzione.

__cxa_pure_virtual


0

Solo sotto uno ha funzionato per me con gdb 8.3:

break _Unwind_RaiseException

"catch throw" o "break __cxx_throw" non ha funzionato per me.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.