GNU/Linux >> Tutoriales Linux >  >> Linux

5 consejos para el depurador GNU

El depurador GNU (gdb) es una herramienta invaluable para inspeccionar procesos en ejecución y solucionar problemas mientras desarrolla programas.

Puede establecer puntos de interrupción en ubicaciones específicas (por nombre de función, número de línea, etc.), habilitar y deshabilitar esos puntos de interrupción, mostrar y modificar valores de variables y hacer todas las cosas estándar que esperaría que hiciera cualquier depurador. Pero tiene muchas otras características con las que quizás no haya experimentado. Aquí hay cinco para que pruebes.

Puntos de interrupción condicionales

Establecer un punto de interrupción es una de las primeras cosas que aprenderá a hacer con el depurador GNU. El programa se detiene cuando llega a un punto de interrupción y puede ejecutar comandos gdb para inspeccionarlo o cambiar las variables antes de permitir que el programa continúe.

Por ejemplo, es posible que sepa que una función a la que se llama con frecuencia falla a veces, pero solo cuando obtiene un determinado valor de parámetro. Puede establecer un punto de interrupción al comienzo de esa función y ejecutar el programa. Los parámetros de la función se muestran cada vez que llega al punto de interrupción y, si no se proporciona el valor del parámetro que desencadena el bloqueo, puede continuar hasta que se vuelva a llamar a la función. Cuando el parámetro problemático desencadena un bloqueo, puede revisar el código para ver qué está mal.

(gdb) break sometimes_crashes
Breakpoint 1 at 0x40110e: file prog.c, line 5.
(gdb) run
[...]
Breakpoint 1, sometimes_crashes (f=0x7fffffffd1bc) at prog.c:5
5      fprintf(stderr,
(gdb) continue
Breakpoint 1, sometimes_crashes (f=0x7fffffffd1bc) at prog.c:5
5      fprintf(stderr,
(gdb) continue

Para que esto sea más repetible, puede contar cuántas veces se llama a la función antes de la llamada específica que le interesa y establecer un contador en ese punto de interrupción (por ejemplo, "continuar 30" para que ignore las próximas 29 veces que llegue el punto de interrupción).

Pero donde los puntos de interrupción se vuelven realmente poderosos es en su capacidad para evaluar expresiones en tiempo de ejecución, lo que le permite automatizar este tipo de prueba. Introduzca:puntos de interrupción condicionales.

break [LOCATION] if CONDITION

(gdb) break sometimes_crashes if !f
Breakpoint 1 at 0x401132: file prog.c, line 5.
(gdb) run
[...]
Breakpoint 1, sometimes_crashes (f=0x0) at prog.c:5
5      fprintf(stderr,
(gdb)

En lugar de que gdb pregunte qué hacer cada vez que se llama a la función, un punto de interrupción condicional le permite hacer que gdb se detenga en esa ubicación solo cuando una expresión particular se evalúa como verdadera. Si la ejecución alcanza la ubicación del punto de interrupción condicional, pero la expresión se evalúa como falsa, el

Más recursos de Linux

  • Hoja de trucos de los comandos de Linux
  • Hoja de trucos de comandos avanzados de Linux
  • Curso en línea gratuito:Descripción general técnica de RHEL
  • Hoja de trucos de red de Linux
  • Hoja de trucos de SELinux
  • Hoja de trucos de los comandos comunes de Linux
  • ¿Qué son los contenedores de Linux?
  • Nuestros últimos artículos sobre Linux

El depurador permite que el programa continúe automáticamente sin preguntarle al usuario qué hacer.

Comandos de punto de interrupción

Una característica aún más sofisticada de los puntos de interrupción en GNU Debugger es la capacidad de crear un script de respuesta para alcanzar un punto de interrupción. Los comandos de punto de interrupción le permiten escribir una lista de comandos de GNU Debugger para ejecutar cada vez que llegue a un punto de interrupción.

Podemos usar esto para evitar el error que ya conocemos en a veces_fallas función y hacer que regrese de esa función de manera inofensiva cuando proporciona un puntero nulo.

Podemos usar silencio como la primera línea para obtener más control sobre la salida. Sin esto, el marco de la pila se mostrará cada vez que se alcance el punto de interrupción, incluso antes de que se ejecuten nuestros comandos de punto de interrupción.

(gdb) break sometimes_crashes
Breakpoint 1 at 0x401132: file prog.c, line 5.
(gdb) commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent
>if !f
 >frame
 >printf "Skipping call\n"
 >return 0
 >continue
 >end
>printf "Continuing\n"
>continue
>end
(gdb) run
Starting program: /home/twaugh/Documents/GDB/prog
warning: Loadable section ".note.gnu.property" outside of ELF segments
Continuing
Continuing
Continuing
#0  sometimes_crashes (f=0x0) at prog.c:5
5      fprintf(stderr,
Skipping call
[Inferior 1 (process 9373) exited normally]
(gdb)

Volcar memoria binaria

GNU Debugger tiene soporte incorporado para examinar la memoria usando x comando en varios formatos, incluidos octal, hexadecimal, etc. Pero me gusta ver dos formatos uno al lado del otro:bytes hexadecimales a la izquierda y caracteres ASCII representados por esos mismos bytes a la derecha.

Cuando quiero ver el contenido de un archivo byte a byte, a menudo uso hexdump -C (hexdump proviene del paquete util-linux). Aquí está la x de gdb comando que muestra bytes hexadecimales:

(gdb) x/33xb mydata
0x404040 <mydata>:    0x02    0x01    0x00    0x02    0x00    0x00    0x00    0x01
0x404048 <mydata+8>:    0x01    0x47    0x00    0x12    0x61    0x74    0x74    0x72
0x404050 <mydata+16>:    0x69    0x62    0x75    0x74    0x65    0x73    0x2d    0x63
0x404058 <mydata+24>:    0x68    0x61    0x72    0x73    0x65    0x75    0x00    0x05
0x404060 <mydata+32>:    0x00

¿Qué pasaría si pudieras enseñarle a gdb a mostrar la memoria como lo hace hexdump? Puede, y de hecho, puede usar este método para cualquier formato que prefiera.

Combinando el volcado comando para almacenar los bytes en un archivo, el shell comando para ejecutar hexdump en el archivo, y define comando, podemos hacer nuestro propio hexdump nuevo Comando para usar hexdump para mostrar el contenido de la memoria.

(gdb) define hexdump
Type commands for definition of "hexdump".
End with a line saying just "end".
>dump binary memory /tmp/dump.bin $arg0 $arg0+$arg1
>shell hexdump -C /tmp/dump.bin
>end

Esos comandos pueden incluso ir en ~/.gdbinit para definir el comando hexdump de forma permanente. Aquí está en acción:

(gdb) hexdump mydata sizeof(mydata)
00000000  02 01 00 02 00 00 00 01  01 47 00 12 61 74 74 72  |.........G..attr|
00000010  69 62 75 74 65 73 2d 63  68 61 72 73 65 75 00 05  |ibutes-charseu..|
00000020  00                                                |.|
00000021

Desmontaje en línea

A veces, desea comprender más sobre lo que sucedió antes de un bloqueo, y el código fuente no es suficiente. Quiere ver lo que sucede en el nivel de instrucción de la CPU.

El desmontaje El comando le permite ver las instrucciones de la CPU que implementan una función. Pero a veces la salida puede ser difícil de seguir. Por lo general, quiero ver qué instrucciones corresponden a una determinada sección del código fuente en la función. Para lograr esto, use el /s modificador para incluir líneas de código fuente con el desensamblado.

(gdb) disassemble/s main
Dump of assembler code for function main:
prog.c:
11    {
   0x0000000000401158 <+0>:    push   %rbp
   0x0000000000401159 <+1>:    mov      %rsp,%rbp
   0x000000000040115c <+4>:    sub      $0x10,%rsp

12      int n = 0;
   0x0000000000401160 <+8>:    movl   $0x0,-0x4(%rbp)

13      sometimes_crashes(&n);
   0x0000000000401167 <+15>:    lea     -0x4(%rbp),%rax
   0x000000000040116b <+19>:    mov     %rax,%rdi
   0x000000000040116e <+22>:    callq  0x401126 <sometimes_crashes>
[...snipped...]

Esto, junto con registros de información para ver los valores actuales de todos los registros de la CPU y comandos como stepi al paso de una instrucción a la vez, le permite tener una comprensión mucho más detallada del programa.

Depuración inversa

A veces desearías poder retroceder el tiempo. Imagine que ha llegado a un punto de observación en una variable. Un punto de observación es como un punto de interrupción, pero en lugar de establecerse en una ubicación en el programa, se establece en una expresión (usando el reloj dominio). Cada vez que cambia el valor de la expresión, la ejecución se detiene y el depurador toma el control.

Así que imagine que ha llegado a este punto de observación y la memoria utilizada por una variable ha cambiado de valor. Esto puede resultar causado por algo que ocurrió mucho antes; por ejemplo, la memoria se liberó y ahora se está reutilizando. Pero, ¿cuándo y por qué fue liberado?

¡El depurador GNU puede resolver incluso este problema porque puede ejecutar su programa a la inversa!

Logra esto al registrar cuidadosamente el estado del programa en cada paso para que pueda restaurar los estados registrados previamente, dando la ilusión de que el tiempo fluye hacia atrás.

Para habilitar este registro de estado, use el registro de destino completo dominio. Entonces puedes usar comandos que suenan imposibles, como:

  • paso inverso , que retrocede a la línea fuente anterior
  • inverso-siguiente , que retrocede a la línea de origen anterior, retrocediendo sobre las llamadas a funciones
  • acabado inverso , que retrocede hasta el punto en que la función actual estaba a punto de llamarse
  • invertir-continuar , que rebobina al estado anterior en el programa que (ahora) desencadenaría un punto de interrupción (o cualquier otra cosa que haga que se detenga)

Este es un ejemplo de depuración inversa en acción:

(gdb) b main
Breakpoint 1 at 0x401160: file prog.c, line 12.
(gdb) r
Starting program: /home/twaugh/Documents/GDB/prog
[...]

Breakpoint 1, main () at prog.c:12
12      int n = 0;
(gdb) target record-full
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401154 in sometimes_crashes (f=0x0) at prog.c:7
7      return *f;
(gdb) reverse-finish
Run back to call of #0  0x0000000000401154 in sometimes_crashes (f=0x0)
        at prog.c:7
0x0000000000401190 in main () at prog.c:16
16      sometimes_crashes(0);

Estas son solo algunas de las cosas útiles que puede hacer el depurador GNU. Hay muchos más por descubrir. ¿Qué característica oculta, poco conocida o simplemente sorprendente de gdb es tu favorita? Compártelo en los comentarios.


Linux
  1. Consejos de Linux para usar cron para programar tareas

  2. 3 consejos para imprimir con Linux

  3. Sugerencias rápidas para el cliente OpenShift oc

  4. Unix Less Command:10 consejos para una navegación eficaz

  5. Depende.exe para GNU/Linux

Un tutorial práctico para usar GNU Project Debugger

Consejos para usar el comando superior en Linux

Consejos/trucos útiles de Meld para usuarios intermedios

Consejos para usar tmux

Consejos para usar la pantalla

Convertir milisegundos a especificación de tiempo para el puerto GNU