Comment obtenir la valeur et le type de l’exception actuelle en C ++ à l’aide de gdb?

gdb permet d’attraper des exceptions quand elles sont lancées et quand elles sont capturées. Mais parfois, la ligne générée par une exception ne contient aucun symbole, ou un point d’arrêt est déclenché lors de la gestion des exceptions. Comment inspecter la valeur de l’exception actuelle?

Mis à jour


Voici quelques informations du manuel GDB

Il y a 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 rend normalement le contrôle une fois l’exécution de la fonction terminée. Toutefois, si l’appel déclenche une exception, il peut contourner le mécanisme qui vous redonne le contrôle et entraîner soit l’interruption de votre programme, soit simplement sa poursuite, jusqu’à ce qu’il atteigne un point d’arrêt, capte le signal que gdb est à l’écoute ou se ferme. C’est le cas même si vous définissez un sharepoint capture pour l’exception; Les points de capture des 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 levé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 stack avant tout déroulement. Si vous définissez plutôt un point d’arrêt dans un gestionnaire d’exceptions, il peut s’avérer difficile de savoir où l’exception a été déclenchée.

Pour arrêter juste avant l’appel d’un gestionnaire d’exceptions, vous devez avoir quelques connaissances de l’implémentation. Dans le cas de gnu C ++, des exceptions sont déclenchées en appelant une fonction de bibliothèque nommée __raise_exception, dotée de 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); To make the debugger catch all exceptions before any stack unwinding takes place, 

définissez un point d’arrêt sur __raise_exception (voir Points d’arrêt, Points de contrôle et Exceptions).


Cela dit

Cela dépend du code et de l’emplacement de la stack. Si vous avez réellement capté l’exception comme dans:

 try { .... } catch (std::exception &e) { //do stuff } 

Vous pourriez probablement essayer d’imprimer e.what() ou consulter les membres de l’exception. Si vous attrapez juste comme (…) alors je ne suis pas sûr de ce que vous pourriez rassembler.

Une autre chose à faire est d’attraper «jeter» dans gdb et d’attraper aussi bien si vous voulez vraiment suivre l’ensemble du stream.

 gdb> catch catch gdb> catch throw 

De cette façon, vous obtiendrez des points d’arrêt juste avant que des exceptions ne soient lancées et dès qu’elles seront détectées, vous pourrez ensuite parcourir la stack pour obtenir plus d’informations sur ce qui se passait. Même si vous vous trouvez à un autre point d’arrêt, vous devriez pouvoir remonter la stack (en utilisant la flèche vers le haut ou vers le bas) pour obtenir le cadre dans lequel l’exception est visible.

Les réponses précédentes étaient correctes lors de la rédaction (en 2013), mais depuis lors, gdb et libstdc ++ ont changé.

libstdc ++ a maintenant quelques crochets qui permettent à gdb d’interagir plus facilement avec le système des exceptions. En particulier, il existe maintenant suffisamment d’informations exposées pour que gdb fournisse une variable de commodité $_exception à l’utilisateur. Cette variable contient l’exception en cours de projection. Il n’est valable qu’à l’endroit même où l’exception est capturée; auquel vous pouvez vous arrêter en utilisant catch catch .

Voir la page du manuel pour plus de détails.

Réponse courte: vous ne pouvez pas, car la plupart des tâches de traitement des exceptions sont effectuées en dehors de votre programme et sont donc en dehors du domaine d’application de gdb.

Réponse expliquée:

parfois la ligne une exception est levée n’a pas de symboles

Si le binary que vous déboguez n’a pas de symbole de débogage, il est probablement supprimé et vous ne pourrez pas en apprendre plus sur les types / valeurs de quoi que ce soit.

Comment inspecter la valeur de l’exception actuelle?

Je pense que vous supposez ici qu’une exception est une fonctionnalité de langage que gdb peut inspecter; en fait, une exception en C ++ est une combinaison de fonctionnalités de C ++ en tant que langage, de libc ++ et de l’ABI. Et il pourrait même y avoir plus d’une seule exception de courant active.

Comme UpAndAdam le fait remarquer, vous pouvez définir un point d’arrêt dans un bloc catch avec un spécificateur de type, puis inspecter cet élément, mais je suppose que votre problème réside dans les cas où vous trouvez un “catch (…)”. Dans ces cas, vous ne pourrez pas en apprendre beaucoup sur l’exception en cours à moins de creuser dans l’implémentation de la gestion des exceptions.

Avec une description très courte et incomplète, nous pourrions dire que pour lancer une exception:

  1. Votre programme appellera libc ++ pour déclencher une exception
  2. la libc ++ appellera “un déroulement” dans la glibc pour démarrer le déroulement de la stack
  3. undind rappelera une “fonction de personnalité” de libc ++ pour chaque cadre de stack (chaque appel de fonction dans la stack, en gros)
  4. la fonction de personnalité décidera en quelque sorte si le cadre de stack actuel peut ou non gérer cette exception
  5. si l’exception peut être gérée, le bloc catch sera exécuté

Il est difficile maintenant de parler de détails, car la gestion des exceptions dépend de votre chaîne d’outils (compilateur, plate-forme, architecture, libc ++, etc.), mais dans la plupart des cas, un “catch (…)” ne recevra même pas l’exception originale. comme argument. Dans tous les cas, pour répondre à votre question, vous pouvez essayer quelque chose comme ceci dans gcc avec la libc ++ de gnu:

  1. Obtenir une libc ++ avec des symboles de débogage
  2. Définissez un point d’arrêt dans __gxx_personality_v0 (appelé fonction de personnalité). Cette fonction sera appelée pour déterminer si un cadre de stack (un appel de fonction, en principe) dispose d’un bloc catch approprié pour gérer l’exception.
  3. Dans la fonction de personnalité, vous pourrez trouver un pointeur sur _Unwind_Exception, qui encapsule votre véritable exception.
  4. Obtenez les informations de type pour votre exception comme suit: __cxa_exception * exception_header = (__cxa_exception *) (unwind_exception + 1) -1; std :: type_info * thrown_exception_type = exception_header-> exceptionType;
  5. Vous obtiendrez un type d’exception que vous pourrez ensuite rechercher avec le rest du RTTI défini pour votre code.

Dans tous les cas, vous devrez probablement passer un peu de temps à essayer de comprendre comment la gestion des exceptions est implémentée sur votre plate-forme. Si vous voulez en savoir un peu plus sur la gestion des exceptions, j’ai déjà passé un certain temps à écrire sur le sujet @ http://monoinfinito.wordpress.com/series/exception-handling-in-c/ . Ce n’est pas une source officielle, mais elle contient des liens vers les spécifications de chaque partie impliquée dans le traitement d’une exception.