¿Cuáles son las mejores formas de automatizar una sesión de depuración de GDB?


¿GDB tiene un mecanismo de scripting integrado, debo codificar un script de espera, o hay una solución aún mejor por ahí?

Enviaré la misma secuencia de comandos cada vez y guardaré la salida de cada comando en un archivo (lo más probable es que use el mecanismo de registro integrado de GDB, a menos que alguien tenga una idea mejor).

3 answers

gdb ejecuta file .gdbinit después de ejecutar. Así que puede agregar sus comandos a este archivo y ver si está bien para usted. Este es un ejemplo de .gdbinit para imprimir trazas traseras para todas las llamadas f():

set pagination off
set logging file gdb.txt
set logging on
file a.out
b f
commands
bt
continue
end
info breakpoints
r
set logging off
quit
 49
Author: Sergei Kurenkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-25 05:13:45

Estaba pasando por algo similar, y se me ocurrió un ejemplo básico - y sabiendo que me olvidaré pronto, pensé que sería mejor publicarlo :) Así que lo publicaré aquí, ya que parece relacionado con la pregunta.

Básicamente, en este ejemplo quería obtener algunos valores de variables en lugares particulares del código; y hacerlos salir hasta que el programa se bloquee. Así que aquí está primero un pequeño programa que está garantizado para bloquearse en unos pocos pasos, test.c:

#include <stdio.h>
#include <stdlib.h>

int icount = 1; // default value

main(int argc, char *argv[])
{
  int i;

  if (argc == 2) {
    icount = atoi(argv[1]);
  }

  i = icount;
  while (i > -1) {
    int b = 5 / i;
    printf(" 5 / %d = %d \n", i, b );
    i = i - 1;
  }

  printf("Finished\n");
  return 0;
}

La única razón por la que el programa acepta argumentos de línea de comandos es para poder elegir el número de pasos antes de bloquearse-y para mostrar que gdb ignora --args en modo batch. Esto compilo con:

gcc -g test.c -o test.exe

Entonces, preparo el siguiente script - el truco principal aquí es asignar un command a cada breakpoint, que eventualmente continue (ver también Automatizar gdb: mostrar traza inversa en cada llamada a la función puts). Este script lo llamo test.gdb:

# http://sourceware.org/gdb/wiki/FAQ: to disable the
# "---Type <return> to continue, or q <return> to quit---"
# in batch mode:
set width 0
set height 0
set verbose off

# at entry point - cmd1
b main
commands 1
  print argc
  continue
end

# printf line - cmd2
b test.c:17
commands 2
  p i
  p b
  continue
end

# int b = line - cmd3
b test.c:16
commands 3
  p i
  p b
  continue
end

# show arguments for program
show args
printf "Note, however: in batch mode, arguments will be ignored!\n"

# note: even if arguments are shown;
# must specify cmdline arg for "run"
# when running in batch mode! (then they are ignored)
# below, we specify command line argument "2":
run 2     # run

#start # alternative to run: runs to main, and stops
#continue

Tenga en cuenta que, si tiene la intención de usarlo en modo por lotes, debe "iniciar" el script al final, con run o start o algo similar.

Con este script en su lugar, puedo llamar a gdb en modo batch - que generará la siguiente salida en el terminal:

$ gdb --batch --command=test.gdb --args ./test.exe 5
Breakpoint 1 at 0x804844d: file test.c, line 10.
Breakpoint 2 at 0x8048485: file test.c, line 17.
Breakpoint 3 at 0x8048473: file test.c, line 16.
Argument list to give program being debugged when it is started is "5".
Note, however: in batch mode, arguments will be ignored!

Breakpoint 1, main (argc=2, argv=0xbffff424) at test.c:10
10    if (argc == 2) {
$1 = 2

Breakpoint 3, main (argc=2, argv=0xbffff424) at test.c:16
16      int b = 5 / i;
$2 = 2
$3 = 134513899

Breakpoint 2, main (argc=2, argv=0xbffff424) at test.c:17
17      printf(" 5 / %d = %d \n", i, b );
$4 = 2
$5 = 2
 5 / 2 = 2 

Breakpoint 3, main (argc=2, argv=0xbffff424) at test.c:16
16      int b = 5 / i;
$6 = 1
$7 = 2

Breakpoint 2, main (argc=2, argv=0xbffff424) at test.c:17
17      printf(" 5 / %d = %d \n", i, b );
$8 = 1
$9 = 5
 5 / 1 = 5 

Breakpoint 3, main (argc=2, argv=0xbffff424) at test.c:16
16      int b = 5 / i;
$10 = 0
$11 = 5

Program received signal SIGFPE, Arithmetic exception.
0x0804847d in main (argc=2, argv=0xbffff424) at test.c:16
16      int b = 5 / i;

Tenga en cuenta que mientras especificamos el argumento 5 de la línea de comandos, el bucle sigue girando solo dos veces (como es la especificación de run en el script gdb); si run no tenía argumentos, gira solo una vez (el valor predeterminado del programa) confirmando que --args ./test.exe 5 es ignorado.

Sin embargo, dado que ahora esto se genera en una sola llamada, y sin ninguna interacción del usuario, la salida de la línea de comandos se puede capturar fácilmente en un archivo de texto utilizando la redirección bash, digamos:

gdb --batch --command=test.gdb --args ./test.exe 5 > out.txt

También hay un ejemplo de uso de python para automatizar gdb en c - GDB auto stepping - impresión automática de líneas, mientras se ejecuta libremente?

Espero que esto ayuda,
¡Salud!

 69
Author: sdaau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:46

Si un-x con un archivo es demasiado para usted, simplemente use múltiples-ex. Este es un ejemplo para rastrear un programa en ejecución que muestra (y guarda) la traza inversa en los bloqueos

sudo gdb -p $(pidof my-app) -batch \
  -ex "set logging on" \
  -ex continue \
  -ex "bt full" \
  -ex quit
 3
Author: Treviño,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-21 20:38:40