Comment casser quand un type d’exception spécifique est lancé dans GDB?

Selon la documentation, je peux rompre avec un type d’exception spécifique en utilisant des points d’arrêt conditionnels. Cependant, la syntaxe de la condition n’est pas très claire pour moi:

condition bnum  

En regardant la syntaxe de l’expression, je pense que c’est le modèle dont j’ai besoin:

{type} addr

Cependant, je ne sais pas ce que je devrais passer pour l’argument addr . J’ai essayé ce qui suit:

 (gdb) catch throw (gdb) condition 1 boost::bad_function_call * 

Mais cela ne fonctionne pas (gdb se casse sur tous les types d’exceptions).

Quelqu’un peut-il aider?


Mettre à jour

J’ai également essayé la suggestion de @Adam, mais cela se traduit par un message d’erreur:

 (gdb) catch throw boost::bad_function_call Junk at end of arguments. 

Sans boost:: namespace:

 (gdb) catch throw bad_function_call Junk at end of arguments. 

solution de contournement

Briser le constructeur de bad_function_call fonctionne.

MODIFIER

La documentation suggère que catch throw peut être utilisé pour rompre chaque fois qu’une exception de type est lancée; Cependant, cela ne semble pas fonctionner dans la pratique.

 (gdb) help catch Set catchpoints to catch events. Raised signals may be caught: catch signal - all signals catch signal  - a particular signal Raised exceptions may be caught: catch throw - all exceptions, when thrown catch throw  - a particular exception, when thrown catch catch - all exceptions, when caught catch catch  - a particular exception, when caught Thread or process events may be caught: catch thread_start - any threads, just after creation catch thread_exit - any threads, just before expiration catch thread_join - any threads, just after joins Process events may be caught: catch start - any processes, just after creation catch exit - any processes, just before expiration catch fork - calls to fork() catch vfork - calls to vfork() catch exec - calls to exec() Dynamically-linked library events may be caught: catch load - loads of any library catch load  - loads of a particular library catch unload - unloads of any library catch unload  - unloads of a particular library The act of your program's execution stopping may also be caught: catch stop C++ exceptions may be caught: catch throw - all exceptions, when thrown catch catch - all exceptions, when caught Ada exceptions may be caught: catch exception - all exceptions, when raised catch exception  - a particular exception, when raised catch exception unhandled - all unhandled exceptions, when raised catch assert - all failed assertions, when raised Do "help set follow-fork-mode" for info on debugging your program after a fork or vfork is caught. Do "help breakpoints" for info on other commands dealing with breakpoints. 

Lorsque la commande gdb ‘catch throw’ échoue, essayez cette solution de contournement:
(testé avec Linux g ++ 4.4.5 / gdb 6.6)
1 / Ajoutez ce code n’importe où dans le programme pour le déboguer:

 #include  #include  #include  struct __cxa_exception { std::type_info *inf; }; struct __cxa_eh_globals { __cxa_exception *exc; }; extern "C" __cxa_eh_globals* __cxa_get_globals(); const char* what_exc() { __cxa_eh_globals* eh = __cxa_get_globals(); if (eh && eh->exc && eh->exc->inf) return eh->exc->inf->name(); return NULL; } 

2 / Dans gdb, vous pourrez alors filtrer les exceptions avec:

 (gdb) break __cxa_begin_catch (gdb) cond N (what_exc()?strstr(what_exc(),"exception_name"):0!=0) 

où N est le numéro du point d’arrêt et nom_exception est le nom de l’exception pour laquelle nous souhaitons rompre.

D’après ce que j’ai compris de la question ici, vous voulez rompre quand une exception spécifique boost::bad_function_call est lancée dans votre application.

 $> gdb /path/to/binary (gdb) break boost::bad_function_call::bad_function_call() (gdb) run --some-cli-options 

Donc, lorsque l’object temporaire boost::bad_function_call est construit en préparation du throw ; gdb va éclater!

J’ai testé cela et ça marche. Si vous connaissez précisément la manière dont l’object d’exception est construit, vous pouvez définir un point d’arrêt sur le constructeur spécifique. Sinon, comme illustré dans l’exemple ci-dessous, vous pouvez omettre la liste des arguments et gdb définir des points d’arrêt sur constructeur.

 $ gdb /path/to/binary (gdb) break boost::bad_function_call::bad_function_call Breakpoint 1 at 0x850f7bf: boost::bad_function_call::bad_function_call. (4 locations) (gdb) info breakpoints Num Type Disp Enb Address What 1 breakpoint keep y  1.1 y 0x0850f7bf in boost::bad_function_call::bad_function_call() at /usr/include/boost/function/function_base.hpp:742 1.2 y 0x0850fdd5 in boost::bad_function_call::bad_function_call(boost::bad_function_call const&) at /usr/include/boost/function/function_base.hpp:739 1.3 y 0x0863b7d2  1.4 y 0x086490ee  

Une autre approche consiste à s’appuyer sur l’argument tinfo disponible lorsque le point d’ tinfo est déclenché, qui est un pointeur sur l’object renvoyé par typeid(type) .

Donc, si je veux que l’exception std::bad_alloc soit lancée, je pourrais simplement faire:

 > p &typeid(std::bad_alloc) > $1 = (__cxxabiv1::__si_class_type_info *) 0x8c6db60  > catch throw if tinfo == 0x8c6db60 

Comme d’autres l’ont déjà mentionné, cette fonctionnalité ne fonctionne pas en pratique. Mais comme solution de contournement, vous pouvez mettre une condition sur le catch throw . Lorsque l’exception est lancée, nous arrivons à la fonction __cxa_throw . Plusieurs parameters pointent vers la classe des exceptions, nous pouvons donc définir une condition sur l’un d’eux. Dans l’exemple de session gdb ci-dessous, je mets la condition sur le paramètre dest de __cxa_throw . Le seul problème est que la valeur de dest (0x80486ec dans ce cas) est inconnue à l’avance. On peut le savoir, par exemple, en exécutant d’abord gdb sans condition sur le point d’arrêt.

 [root@localhost ~]# [root@localhost ~]# gdb ./a.out GNU gdb (GDB) 7.2 Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later  This is free software: you are free to change and redissortingbute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu". For bug reporting instructions, please see: ... Reading symbols from /root/a.out...done. (gdb) catch throw Catchpoint 1 (throw) (gdb) condition 1 dest==0x80486ec No symbol "dest" in current context. (gdb) r warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context. warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context. warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context. Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x804a080, tinfo=0x8049ca0, dest=0x80486ec <_ZNSt13runtime_errorD1Ev@plt>) at ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc:68 68 ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory. in ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc (gdb) bt #0 __cxxabiv1::__cxa_throw (obj=0x804a080, tinfo=0x8049ca0, dest=0x80486ec <_ZNSt13runtime_errorD1Ev@plt>) at ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc:68 #1 0x08048940 in main () at test.cpp:14 (gdb) ib Num Type Disp Enb Address What 1 breakpoint keep y 0x008d9ddb exception throw stop only if dest==0x80486ec breakpoint already hit 1 time (gdb) 

Mettre à jour

Vous devez également charger les informations de débogage pour libstdc ++ pour que cette solution fonctionne.

Je pense pouvoir répondre à la question de la définition des pauses conditionnelles. Je ne répondrai pas à la question concernant les exceptions car __raise_exception semble ne pas exister dans g ++ 4.5.2 (?)

Supposons que vous ayez le code suivant (j’utilise void pour obtenir quelque chose de similaire à __raise_exception de gdb doc)

 void foo(void* x) { } int main() { foo((void*)1); foo((void*)2); } 

pour casser à foo (2) vous utilisez les commandes suivantes

 (gdb) break foo Breakpoint 1 at 0x804851c: file q.cpp, line 20. (gdb) condition 1 x == 2 

Si vous courez avec

 (gdb) r 

vous verrez qu’il s’arrête sur le deuxième appel foo, mais pas sur le premier

Je pense que ce qu’ils voulaient dire dans docs, c’est que vous définissiez la fonction __raise_exception (très dépendante de la mise en œuvre)

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

puis définissez la rupture conditionnelle sur l’ID comme décrit ci-dessus (vous devez en quelque sorte déterminer ce qu’est l’ID pour votre type d’exception).

Malheureusement

  (gdb) break __raise_exception 

résultats avec (g ++ 4.5.2)

  Function "__raise_exception" not defined.