Exécuter une application dans GDB jusqu'à ce qu'une exception se produise

102

Je travaille sur une application multithread et je souhaite la déboguer à l'aide de GDB.

Le problème est que l'un de mes fils continue de mourir avec le message:

pure virtual method called
terminate called without an active exception
Abort

Je connais la cause de ce message, mais je ne sais pas où dans mon fil il se produit. Un retour en arrière serait vraiment utile.

Lorsque j'exécute mon application dans GDB, elle s'interrompt chaque fois qu'un thread est suspendu ou repris. Je veux que mon application continue de fonctionner normalement jusqu'à ce que l'un des threads meure avec cette exception, auquel point tout devrait s'arrêter pour que je puisse obtenir une trace arrière.

Ankur Sethi
la source
Quel signal GDB signale-t-il lorsqu'il s'arrête? vous devriez pouvoir exécuter une commande commehandle SIGUSR1 pass noprint nostop
Hasturkun

Réponses:

147

Vous pouvez essayer d'utiliser un "catchpoint" ( catch throw) pour arrêter le débogueur au point où l'exception est générée.

L' extrait suivant du manuel gdb décrit la fonction de point de capture.


5.1.3 Définition des points de capture

Vous pouvez utiliser des points de capture pour provoquer l'arrêt du débogueur pour certains types d'événements de programme, tels que les exceptions C ++ ou le chargement d'une bibliothèque partagée. Utilisez la commande catch pour définir un point de capture.

  • événement de capture

    Arrêtez-vous lorsque l' événement se produit. l'événement peut être l'un des suivants:

    • jeter

      Le lancement d'une exception C ++.

    • capture

      La capture d'une exception C ++.

    • exec

      Un appel à l'exécutif. Ceci n'est actuellement disponible que pour HP-UX.

    • fourchette

      Un appel à la fourchette. Ceci n'est actuellement disponible que pour HP-UX.

    • vfork

      Un appel à vfork. Ceci n'est actuellement disponible que pour HP-UX.

    • charger ou charger libname

      Le chargement dynamique de n'importe quelle bibliothèque partagée, ou le chargement de la bibliothèque libname. Ceci n'est actuellement disponible que pour HP-UX.

    • décharger ou décharger libname

      Le déchargement de toute bibliothèque partagée chargée dynamiquement ou le déchargement de la bibliothèque libname. Ceci n'est actuellement disponible que pour HP-UX.

  • événement tcatch

    Définissez un point de capture qui n'est activé que pour un arrêt. Le point de capture est automatiquement supprimé après la première capture de l'événement.

Utilisez la info breakcommande pour répertorier les points de capture actuels.

Il existe actuellement quelques limitations à la gestion des exceptions C ++ (catch throw et catch catch) dans GDB:

  • Si vous appelez une fonction de manière interactive, GDB vous renvoie normalement le contrôle lorsque la fonction a fini de s'exécuter. Si l'appel lève une exception, cependant, l'appel peut contourner le mécanisme qui vous renvoie le contrôle et provoquer l'abandon ou la poursuite de l'exécution de votre programme jusqu'à ce qu'il atteigne un point d'arrêt, capte un signal que GDB écoute ou quitte. C'est le cas même si vous définissez un point de capture pour l'exception; les points de capture sur les exceptions sont désactivés dans les appels interactifs.

  • Vous ne pouvez pas déclencher une exception de manière interactive.

  • Vous ne pouvez pas installer un gestionnaire d'exceptions de manière interactive.

Parfois, catch n'est pas le meilleur moyen de déboguer la gestion des exceptions: si vous avez besoin de savoir exactement où une exception est déclenchée, il est préférable de s'arrêter avant que le gestionnaire d'exceptions ne soit appelé, car vous pouvez ainsi voir la pile avant tout déroulement. Si vous définissez un point d'arrêt dans un gestionnaire d'exceptions à la place, il peut ne pas être facile de savoir où l'exception a été déclenchée.

Pour arrêter juste avant l'appel d'un gestionnaire d'exceptions, vous devez connaître l'implémentation. Dans le cas de GNU C ++, les exceptions sont levées en appelant une fonction de bibliothèque nommée __raise_exception qui a l'interface ANSI C suivante:

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

Pour que le débogueur intercepte toutes les exceptions avant tout déroulement de la pile, définissez un point d'arrêt sur __raise_exception (voir la section Points d'arrêt; points de surveillance; et exceptions).

Avec un point d'arrêt conditionnel (voir la section Conditions de rupture) qui dépend de la valeur de id, vous pouvez arrêter votre programme lorsqu'une exception spécifique est déclenchée. Vous pouvez utiliser plusieurs points d'arrêt conditionnels pour arrêter votre programme lorsqu'une des nombreuses exceptions est déclenchée.

Dan
la source
Vous pouvez également spécifier le type d'exception à capturer, par exemple catch throw std::runtime_exception.
scai
5

Définir un point d'arrêt sur __pure_virtual

Steve Folly
la source
Dans la réponse @JeffreyHill, il s'appelle maintenant __cxa_pure_virtual. Je ne sais pas comment le vérifier moi-même, donc je ne veux pas modifier la réponse. Je n'ai pas l'intention de voter contre, mais la réponse pourrait être erronée maintenant et devrait être éditée par quelqu'un qui sait ce qui est correct.
Philipp Claßen
5

FWIW, apparemment, dans gcc 4.1, le nom de la fonction appropriée a changé et il faut définir un point d'arrêt dans cette fonction.

__cxa_pure_virtual

Jeffrey Hill
la source
0

Seulement en dessous d'un a fonctionné pour moi avec gdb 8.3:

break _Unwind_RaiseException

"catch throw" ou "break __cxx_throw" ne fonctionnait pas pour moi.

soumeng78
la source