Imprimir

Manual de C/C++ en Linux: El debugger GDB

Un debugger es un programa que nos permite ejecutar nuestro programa paso a paso y así localizar los errores. Utilizaremos el debugger de línea de comandos del GNU GDB (GNU Debugger, comando gdb, paquete gdb). Para ello, vamos a incluir un error en hello.c y lo guardaremos como hello_error.c:

#include <stdio.h>
int main() {
    int *a = NULL;
    printf("Hola mundo\n");
    *a = 3;  /* Esto es erroneo. Dara un fallo de "Violacion de segmento" */
    return 0;
}

Lo compilamos:

$ gcc -o hello_error hello_error.c

Lo ejecutamos:

$ ./hello_error
Hola mundo
Violacion de segmento

Efectivamente, nuestro programa falla al intentar meter 3 en *a cuando a apunta a NULL (una dirección de memoria que no pertenece al programa), dando una Violación de segmento.

Para poder depurar nuestro programa en el debugger debemos compilarlo con la opción -g, que indica al compilador que incluya en el ejecutable la información necesaria para poder rastrear los errores usando un debugger (una vez depurado recompilaremos nuestro programa sin esta opción).

$ gcc -g -o hello_error hello_error.c

Ya tenemos el ejecutable preparado para depurarlo. Arrancaremos el debugger pasándole como parámetro el ejecutable. Entraremos en el modo interactivo de GDB y nos mostrará el promt quedando a la espera de un comando:

$ gdb hello_error
(gdb)

El comando run ejecuta el programa. Lo ejecutamos y se parará en la línea que ha provocado el error:

(gdb) run
Starting program: /home/francis/hello_error
Hola mundo
Program received signal SIGSEGV, Segmentation fault.
0x0804837b in main () at hello_error.c:5
5  *a = 3;  /* Esto es erroneo. Dara un fallo de "Violacion de segmento" */

Ya sabemos que el error es en la línea 5. Podemos ver el valor de a, la dirección de memoria a la que apunta, con el comando print:

(gdb) print a
a = (int *) 0x0

Esto nos permite ver que apunta a la dirección 0, que como no es nuestro espacio de memoria, no podemos meter nada en ella. El debugger nos ha ayudado a encontrar el error.

Podemos ejecutar nuestro programa paso a paso. Para ello debemos poner una señal de stop en la primera línea que haga algo (la línea 3, en la que se asigna NULL a la variable a), cosa que haremos con el comando break:

(gdb) break 3
Breakpoint 1 at 0x8048365: file hello_error.c, line 3.

Lo ejecutamos con run (el programa se detendrá antes de ejecutar la línea 3):

(gdb) run
Breakpoint 1
3    int *a = NULL;

A partir de aquí para ejecutar paso a paso usaremos next (cada next ejecuta una línea):

(gdb) next
4     printf("Hola mundo\n");
(gdb) next
Hola mundo
5     *a = 3;  /* Esto es erroneo. Dara un fallo de "Violacion de segmento" */

Para continuar directamente hasta el final usaremos el comando cont (el programa fallará antes de llegar al final, en la línea 5):

(gdb) cont
Error: Violacion de segmento 5
5     *a = 3;  /* Esto es erroneo. Dara un fallo de "Violacion de segmento" */

Como los errores de los programas frecuentemente no se encuentran en el punto donde se produce el fallo sino que el error viene de antes, tenemos un comando que recorre la pila de llamadas inversamente para saber desde qué función se hizo la llamada:

(gdb) backtrace

Obtendremos ayuda con el comando help:

(gdb) help

Se sale del debugger con el comando quit:

(gdb) quit

El proceso de depuración es mucho más sencillo con DDD (Data Display Debugger, comando ddd, paquete ddd), un frontal gráfico para GDB. Una de sus ventajas es la facilidad para mostrar los contenidos de las posiciones de memoria durante la ejecución de los programas.

DDD

1 comentario en “Manual de C/C++ en Linux: El debugger GDB”

  • cjlasluisa dice:

    La verdad es que el aporte es muy bueno, pero quisiera molestarlos con la siguiente pregunta…

    ¿como lo instalo en linux debian?

Deja un comentario