Ejecute una aplicación en GDB hasta que ocurra una excepción

102

Estoy trabajando en una aplicación multiproceso y quiero depurarla usando GDB.

El problema es que uno de mis hilos sigue muriendo con el mensaje:

pure virtual method called
terminate called without an active exception
Abort

Conozco la causa de ese mensaje, pero no tengo idea de en qué parte de mi hilo ocurre. Realmente sería útil un seguimiento.

Cuando ejecuto mi aplicación en GDB, se detiene cada vez que se suspende o reanuda un hilo. Quiero que mi aplicación continúe ejecutándose normalmente hasta que uno de los subprocesos muera con esa excepción, momento en el que todo debería detenerse para poder obtener un seguimiento.

Ankur Sethi
fuente
¿Qué señal emite el BGF cuando se detiene? deberías poder ejecutar un comando comohandle SIGUSR1 pass noprint nostop
Hasturkun

Respuestas:

147

Puede intentar usar un "punto de captura" ( catch throw) para detener el depurador en el punto donde se genera la excepción.

El siguiente extracto del manual de gdb describe la función de punto de captura.


5.1.3 Establecer puntos de captura

Puede usar puntos de captura para hacer que el depurador se detenga para ciertos tipos de eventos de programa, como excepciones de C ++ o la carga de una biblioteca compartida. Utilice el comando catch para establecer un punto de captura.

  • evento de captura

    Deténgase cuando ocurra el evento . El evento puede ser cualquiera de los siguientes:

    • lanzar

      Lanzamiento de una excepción de C ++.

    • captura

      La captura de una excepción de C ++.

    • ejecutivo

      Una llamada al ejecutivo. Actualmente, solo está disponible para HP-UX.

    • tenedor

      Una llamada a la bifurcación. Actualmente, solo está disponible para HP-UX.

    • vfork

      Una llamada a vfork. Actualmente, solo está disponible para HP-UX.

    • cargar o cargar libname

      La carga dinámica de cualquier biblioteca compartida o la carga de la biblioteca libname. Actualmente, solo está disponible para HP-UX.

    • descargar o descargar libname

      La descarga de cualquier biblioteca compartida cargada dinámicamente o la descarga de la biblioteca libname. Actualmente, solo está disponible para HP-UX.

  • evento tcatch

    Establezca un punto de captura que esté habilitado solo para una parada. El punto de captura se elimina automáticamente después de la primera captura del evento.

Utilice el info breakcomando para enumerar los puntos de captura actuales.

Actualmente existen algunas limitaciones para el manejo de excepciones de C ++ (catch throw y catch catch) en GDB:

  • Si llama a una función de forma interactiva, GDB normalmente le devuelve el control cuando la función ha terminado de ejecutarse. Sin embargo, si la llamada genera una excepción, la llamada puede omitir el mecanismo que le devuelve el control y hacer que su programa se anule o simplemente continúe ejecutándose hasta que llegue a un punto de interrupción, capte una señal de que GDB está escuchando o salga. Este es el caso incluso si establece un punto de captura para la excepción; los puntos de captura en las excepciones están deshabilitados dentro de las llamadas interactivas.

  • No puede plantear una excepción de forma interactiva.

  • No puede instalar un controlador de excepciones de forma interactiva.

A veces, catch no es la mejor manera de depurar el manejo de excepciones: si necesita saber exactamente dónde se genera una excepción, es mejor detenerse antes de que se llame al controlador de excepciones, ya que de esa manera puede ver la pila antes de que se realice cualquier desenrollado. Si establece un punto de interrupción en un controlador de excepciones, puede que no sea fácil averiguar dónde se generó la excepción.

Para detenerse justo antes de que se llame a un controlador de excepciones, necesita algunos conocimientos de la implementación. En el caso de GNU C ++, las excepciones se generan al llamar a una función de biblioteca llamada __raise_exception que tiene la siguiente interfaz ANSI C:

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

Para que el depurador detecte todas las excepciones antes de que se produzca el desenrollado de la pila, establezca un punto de interrupción en __raise_exception (consulte la sección Puntos de interrupción, puntos de observación y excepciones).

Con un punto de interrupción condicional (consulte la sección Condiciones de interrupción) que depende del valor de id, puede detener su programa cuando se genera una excepción específica. Puede utilizar varios puntos de interrupción condicionales para detener su programa cuando se genera alguna de las excepciones.

Dan
fuente
También puede especificar el tipo de excepción a capturar, por ejemplo catch throw std::runtime_exception.
Scai
5

Establecer un punto de interrupción en __pure_virtual

Steve Folly
fuente
En la respuesta de @JeffreyHill, ahora se llama __cxa_pure_virtual. No sé cómo comprobarlo yo mismo, por lo que no quiero editar la respuesta. No tengo la intención de votar en contra, pero la respuesta podría ser incorrecta ahora y debería ser editada por alguien que sepa qué es correcto.
Philipp Claßen
5

FWIW, aparentemente, en gcc 4.1, el nombre de función apropiado ha cambiado y uno debe establecer un punto de interrupción en esta función.

__cxa_pure_virtual

Jeffrey Hill
fuente
0

Solo debajo de uno funcionó para mí con gdb 8.3:

break _Unwind_RaiseException

"atrapar tiro" o "romper __cxx_throw" no funcionó para mí.

soumeng78
fuente