tutorial onlinegdb online compiler compilador c++ gdb

c++ - onlinegdb - online gdb python



¿Cómo interrumpirse cuando se lanza un tipo de excepción específico en GDB? (7)

De acuerdo con la documentación, puedo interrumpir un tipo de excepción específico utilizando puntos de interrupción condicionales. Sin embargo, la sintaxis de la condición no es muy clara para mí:

condition bnum <expression>

Mirando la sintaxis de la expresión, creo que este es el patrón que necesito:

{type} addr

Sin embargo, no sé qué debo aprobar para el argumento addr . Intenté lo siguiente:

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

Pero no funciona (gdb se rompe en todos los tipos de excepción).

¿Alguien puede ayudar?

Actualizar

También probé la sugerencia de @ Adam, pero da como resultado un mensaje de error:

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

Sin boost:: espacio de nombres:

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

Solución

Romper en el constructor de bad_function_call funciona.

Como otros ya han mencionado, esta funcionalidad no funciona en la práctica. Pero como solución puede poner condiciones en el catch throw . Cuando se lanza la excepción, llegamos a la función __cxa_throw . Tiene varios parámetros que apuntan a la clase de excepción, por lo que podemos establecer la condición en uno de ellos. En la sesión gdb de muestra a continuación, puse condición en el parámetro dest de __cxa_throw . El único problema es que el valor de dest (0x80486ec en este caso) se desconoce de antemano. Se puede conocer, por ejemplo, ejecutando primero gdb sin condiciones en el punto de interrupción.

[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 <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute 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: <http://www.gnu.org/software/gdb/bugs/>... 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) i b Num Type Disp Enb Address What 1 breakpoint keep y 0x008d9ddb exception throw stop only if dest==0x80486ec breakpoint already hit 1 time (gdb)

Actualizar

También debe cargar la información de depuración para libstdc ++ para que esta solución funcione.


Creo que puedo responder a la parte sobre el establecimiento de descansos condicionales. No responderé a la pregunta sobre las excepciones, ya que __raise_exception parece no existir en g ++ 4.5.2 (?)

Supongamos que tiene el siguiente código (uso void para obtener algo similar a __raise_exception de gdb doc)

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

para romper en foo (2) usas los siguientes comandos

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

Si corres con

(gdb) r

Verás que se detiene en la segunda llamada foo, pero no en la primera.

Creo que lo que querían decir en los documentos es que establece la interrupción en la función __raise_exception (depende de la implementación)

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

y luego configure la ruptura condicional en la identificación como se describió anteriormente (tiene que determinar de alguna manera cuál es la identificación para su tipo de excepción).

Desafortunadamente

(gdb) break __raise_exception

resultados con (g ++ 4.5.2)

Function "__raise_exception" not defined.


Cuando el comando gdb ''catch throw'' falla, intente esta solución:
(probado con Linux g ++ 4.4.5 / gdb 6.6)
1 / Agregue este código en cualquier parte del programa para depurar:

#include <stdexcept> #include <exception> #include <typeinfo> 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 / En gdb entonces podrás filtrar excepciones con:

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

donde N es el número de punto de interrupción, y nombre_excepción es el nombre de excepción para el que deseamos interrumpir.


Otro enfoque es confiar en el argumento tinfo disponible cuando se activa el punto de captura, que es un puntero al objeto devuelto por typeid(type) .

Entonces, si quiero detectar la excepción std::bad_alloc está std::bad_alloc , podría hacer:

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


Por lo que he entendido de la pregunta aquí, desea interrumpirse cuando se lance una aplicación específica boost::bad_function_call en su aplicación.

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

Entonces, cuando el objeto temporal boost::bad_function_call se construye en preparación para el throw ; gdb estallará!

He probado esto y funciona. Si conoce con precisión la forma en que se está construyendo el objeto de excepción, puede establecer un punto de interrupción en el constructor específico; de lo contrario, como se muestra en el siguiente ejemplo, puede omitir la lista de prototipos de argumentos, y gdb establecerá puntos de ruptura en todos los sabores diferentes de constructor.

$ 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 <MULTIPLE> 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 <boost::bad_function_call::bad_function_call()+4> 1.4 y 0x086490ee <boost::bad_function_call::bad_function_call(boost::bad_function_call const&)+6>


Supongamos que tiene el siguiente code.cpp con un subproceso que produce una excepción:

#include <iostream> #include <thread> void thr() { while (true) { new int[1000000000000ul]; } } int main(int argc, char* argv[]) { std::thread t(thr); t.join(); std::cout << "Hello, World!" << std::endl; return 0; }

Compílalo usando el siguiente CMakeLists.txt

cmake_minimum_required(VERSION 3.5) project(tutorial) set(CMAKE_CXX_STANDARD 11) add_executable(test_exceptions main.cpp) target_link_libraries(test stdc++ pthread)

Ahora puedes jugar con, ejecutarlo te dará un aborto debido a bad_alloc. Antes de continuar, es mejor si instala los símbolos de depuración de libstd, sudo apt-get install libstdc++6-5-dbg o la versión que tenga.

Compilación de depuración

Si está compilando en Debug , puede seguir esta respuesta https://.com/a/12434170/5639395 porque los constructores generalmente están definidos.

Compilación de lanzamiento

Si está compilando en DebWithRelInfo es posible que no pueda encontrar un constructor adecuado donde colocar su punto de interrupción debido a la optimización del compilador. En este caso, tienes otras opciones. Continuemos.

Solución de cambio de código fuente

Si puede cambiar el código fuente fácilmente, esto funcionará https://.com/a/9363680/5639395

Gdb captura fácil solución

Si no desea cambiar el código, puede intentar ver si funciona el catch throw bad_alloc o, en general, catch throw exception_name .

Solución de tiro de captura de Gdb

Construiré sobre esta respuesta https://.com/a/6849989/5639395 __cxxabiv1::__cxa_throw un punto de interrupción en gdb en la función __cxxabiv1::__cxa_throw . Esta función toma un parámetro llamado tinfo que tiene la información que necesitamos para verificar condicionalmente la excepción que nos importa.

Queremos algo como el lanzamiento de la captura si la excepción == bad_alloc , entonces, ¿cómo encontrar la comparación adecuada? Resulta que tinfo es un puntero a una estructura que tiene una variable llamada __name dentro. Esta variable tiene una cadena con el nombre mutilado del tipo de excepción.

Así que podemos hacer algo como: atrapar tiros si tinfo -> __ name == mangled_exception_name

¡Estamos casi alli!

Necesitamos una forma de hacer una comparación de cadenas, y resulta que gdb tiene una función integrada $ _streq (str1, str2) que hace exactamente lo que necesitamos. El nombre mutilado de la excepción es un poco más difícil de encontrar, pero puede intentar adivinarlo o consultar el Apéndice de esta respuesta. Supongamos que por ahora es "St9bad_alloc".

La instrucción final es:

catch throw if $_streq(tinfo->__name , "St9bad_alloc")

o equivalente

break __cxxabiv1::__cxa_throw if $_streq(tinfo->__name , "St9bad_alloc")

Cómo encontrar el nombre de su excepción

Tienes dos opciones

Busca el símbolo en la biblioteca.

Suponiendo que instaló los símbolos de depuración libstd, puede encontrar el nombre de la biblioteca así:

apt search libstd | grep dbg | grep installed

El nombre es algo así como libstdc++6-5-dbg

Ahora revisa los archivos instalados:

dpkg -L libstdc++6-5-dbg

Busque algo que tenga una depuración en la ruta y una extensión .so. En mi PC tengo /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 . Finalmente, busque la excepción que desea allí.

nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i bad_alloc

O nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i runtime_error nm /usr/lib/x86_64-linux-gnu/debug/libstdc++.so.6.0.21 | grep -i runtime_error etc.

En mi caso, encontré algo como 00000000003a4b20 V _ZTISt9bad_alloc que me sugirió usar "St9bad_alloc" como nombre.

Tirarlo en gdb e inspeccionar el nombre allí

Esto es fácil, solo inicia gdb, catch throw todo y ejecuta el pequeño ejecutable que escribí antes. Cuando estés dentro de gdb, puedes emitir un p *tinfo y buscar la descripción de __name en gdb.

gdb -ex ''file test_exceptions'' -ex ''catch throw'' -ex ''run''

(gdb) p *tinfo $1 = {_vptr.type_info = 0x406260 <vtable for __cxxabiv1::__si_class_type_info+16>, __name = 0x7ffff7b8ae78 <typeinfo name for std::bad_alloc> "St9bad_alloc"}


EDITAR

La documentación sugiere que el catch throw <exceptname> puede usarse para romper cuando se lanza una excepción de tipo <exceptname> ; Sin embargo, eso no parece funcionar en la práctica.

(gdb) help catch Set catchpoints to catch events. Raised signals may be caught: catch signal - all signals catch signal <signame> - a particular signal Raised exceptions may be caught: catch throw - all exceptions, when thrown catch throw <exceptname> - a particular exception, when thrown catch catch - all exceptions, when caught catch catch <exceptname> - 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 <libname> - loads of a particular library catch unload - unloads of any library catch unload <libname> - 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 <name> - 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.