2011-12-28 26 views
13

Parece que tengo algún tipo de error de subprocesamiento múltiple en mi código que lo hace fallar una vez cada 30 ejecuciones de su suite de pruebas. El conjunto de pruebas no es interactivo. Quiero ejecutar mi suite de pruebas en gdb, y hacer que gdb salga normalmente si el programa sale normalmente, o romper (y mostrar un indicador de depuración) si falla. De esta forma puedo dejar que el banco de pruebas se ejecute repetidamente, tomar una taza de café, volver y recibir un buen aviso de depuración. ¿Cómo puedo hacer esto con gdb?¿Cómo hacer que gdb salga si el programa tiene éxito, se rompe si el programa falla?

Respuesta

18

Esto es un poco hacky, pero se podía hacer:

gdb --eval-command=run --eval-command=quit --args ./a.out 

Si una. termina normalmente, simplemente lo dejará fuera de GDB. Pero si te estrellas, el programa seguirá siendo activa, por lo que el BGF normalmente pedirá si realmente quiere dejar de fumar con un inferior activa:

Program received signal SIGABRT, Aborted. 
0x00007ffff72dad05 in raise (sig=...) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 
64 ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory. 
    in ../nptl/sysdeps/unix/sysv/linux/raise.c 
A debugging session is active. 

    Inferior 1 [process 15126] will be killed. 

Quit anyway? (y or n) 

Como dije, no es bonito, pero funciona, siempre y cuando se no ha desactivado el aviso para salir con un proceso activo. Probablemente también exista una forma de usar el comando quit de gdb: se necesita un argumento numérico que es el código de salida para la sesión de depuración. Entonces tal vez puedas usar --eval-command = "quit stuff", donde cosas son algunas expresiones GDB que reflejan si el inferior se está ejecutando o no.

+0

Estoy en OS X Snow Leopard y gdb aquí no son compatibles con --eval-command, pero elegiré su respuesta de todos modos. – Hongli

+0

intente gdb --command = <(echo run) --command = <(echo quit) – acm

+0

Creo que esto no funcionará si tiene un 'set confirm off' en su archivo' .gdbinit', GDB siempre return ... – Kevin

3

Hacer que se vuelque el núcleo cuando se bloquea. Si está en Linux, lea la página del manual man core y también el ulimit incorporado si está ejecutando bash.

De esta manera cuando se rompe encontrará un buen fichero de núcleo que se puede alimentar a GDB:

$ ulimit -c unlimited 
$ ... run program ..., gopher coffee (or reddit ;) 
$ gdb progname corefile 
0

¿No está obteniendo un archivo central cuando se bloquea? Comience gdb como este 'gdb -c core' y haga un traceback de la pila.

Es muy probable que desee utilizar Valgrind.

6

La forma más sencilla es utilizar el Python API ofrecido por gdb:

def exit_handler(event): 
    gdb.execute("quit") 

gdb.events.exited.connect(exit_handler) 

Incluso puede hacerlo con una sola línea:

(gdb) gdb.events.exited.connect(lambda x : gdb.execute("quit") 

También puede examinar el código de retorno para asegurarse de que es la código "normal" que esperaba con event.exit_code.

Puede usarlo en conjunción con --eval-command o --command como lo menciona @acm para registrar el controlador de eventos desde la línea de comandos, o con un archivo .gdbinit.

3

También puede desencadenar una traza inversa, cuando el programa se bloquea y deja de salida GDB con el código de retorno del proceso hijo:

gdb -return-child-result -ex run -ex "thread apply all bt" -ex "quit" --args myProgram -myProgramArg 
+3

Esto no es la mejor respuesta a esta pregunta en particular, pero me ayudó mucho con mi pregunta! Gracias, no sabía sobre '-return-child-result' –

1

Crear un archivo llamado .gdbinit y que se utilizará cuando se inicie el BGF.

run 
quit 

Ejecutar sin opciones:

gdb --args prog arg1... 

Usted está diciendo GDB para correr y dejar de fumar, pero debe dejar de procesar el archivo si se produce un error.

0

Si pones las siguientes líneas en el archivo de ~/.gdbinit, gdb terminará cuando el programa termina con un código de estado de 0.

python 

def exit_handler (event): 
    if event .exit_code == 0: 
    gdb .execute ("quit") 

gdb .events .exited .connect (exit_handler) 

end 

Lo anterior es un refinamiento de la respuesta de Kevin.

Cuestiones relacionadas