Ejemplos java y C/linux

Tutoriales

Enlaces

Licencia

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.
Para reconocer la autoría debes poner el enlace https://old.chuidiang.org

Sesión básica con el debugger gdb

Lo bueno de los ordenadores es que hacen lo que les pedimos. Lo malo es que hacen exactamente lo que les pedimos. Muchas veces (todas) hacemos un programa y no funciona como queremos. El error suele ser (siempre) que hay algo mal en nuestro código. Para ver como se ejecuta nuestro programa paso a paso y ver qué está mal,  tenemos un programa que se llama debugger. En linux viene un debuger más o menos estandard que es gdb. Si tienes suerte o te has preocupado de instalarlo, también tendrás otro más bonito que se llama ddd.

gdb es un debugger de linea, es decir, nos saca un "prompt" en el que escribimos comandos (por ejemplo, un comando que indique al programa que empiece a ejecutarse, otro que le dice al programa que ejecute una sola línea, otro que escribe en pantalla el valor de una variable, etc).

ddd es el gdb, pero con una interface gráfica de botoncitos y algunos añadidos. El resultado es que no tenemos que saber el comando, basta con apretar un botón. Por ejemplo, para ver el valor de una variable, basta con seleccionarla con el ratón y pulsar el botón print.

Puesto que el gdb es el estandard, vamos con él.

Un programa con un fallo

Vamos a hacer un programa Largo.c con un fallo.

#include <stdio.h> int main()
{
    int i;
    int *a = NULL;
    for (i=0; i<10; i++)
        printf ("%d, ", i);
    printf ("\n");
    *a = 3;  /* Esto es erróneo. Dará un "Violación de segmento" */
    return 0;
}

El fallo está al intentar meter el 3 en *a. a apunta a NULL, es decir, a una dirección de memoria que no le pertenece al programa. Cuando intentamos meter ahi un 3, el programa se cae dando una "Violación de segmento". Puedes ver un pequeño tutorial de punteros.

Compilamos nuestro programa y lo ejecutamos.

$ gcc Largo.c -o Largo
$ ./Largo
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
Error, violación de segmento y demás.

Efectivamente, nuestro programa falla. Para que nuestro programa se pueda ejecutar en el debugger, debemos compilarlo con la opción -g. Esta opción mete dentro del ejecutable información que el debugger es capaz de leer. Cuando nuestro programa funcione, si queremos que el ejecutable sea algo más pequeño, debemos recompilarlo sin esta opción.

$ gcc -g Largo.c -o Largo

Ya tenemos el ejecutable que se puede depurar. Arrancamos el debugger, pasándo como parámetro en la línea de comandos el nombre del ejecutable.

$ gdb Largo
un pequeño rollo
...
fin del pequeño rollo
(gdb) 

Nos aparece un prompt distinto del $ de la shell. Este prompt (gdb) nos indica que estamos en el debugger y que está esperando una orden nuestra.

Sesión básica con el debugger

El comando list nos permite ver nuestro código fuente. Admite dos parámetros, la línea en la que se empiza a listar y la línea en que queremos que termine el listado, separadas por una coma.

(gdb) list 1,10
1 #include <stdio.h>

3 int main()
4 {
5     int i;
6     int *a = NULL;

8     for (i=0; i<10; i++)
9         printf ("%d, ", i);
10   printf ("\n");
(gdb)

Ejecutamos nuestro programa con el comando run. Nuestro programa se ejecuta y se parará en la línea que ha provocado la violación de segmento.

(gdb) run
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
Error, violación de segmento y demás.
12    *a = 3;  /* Esto es erróneo. Dará un "Violación de segmento" */
(gdb)

Ya sabemos la línea. Podemos ver, por ejemplo, el valor de a (la dirección de memoria a la que apunta), con el comando print

(gdb) print a
a = 0x0

Esto nos permite ver  que a 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. Este error es muy tonto, pero en ocasiones lo normal es pasarse horas con el debugger buscando el fallo.

Podemos ejecutar nuestro programa  paso a paso. Para ello debemos poner una señal de stop en la primera línea de código ejecutable del main. Para poner señales de stop está el comando break con el número de línea en el que queremos el stop. Luego se ejecuta con run. La primera línea de código que hace algo es la 6, en la que se asigna NULL a la variable a

(gdb) break 6
sale un aviso de que se ha puesto el breakpoint en la línea 6
(gdb) run
sale un aviso de que el programa se ha detenido en la linea 6
6    int *a = NULL;
(gdb)

A partir de aqui, para ejecutar paso a paso, ponemos next. Cada vez que pongamos next, se ejecuta una línea.

(gdb) next
8     for (i=0; i<10; i++)
(gdb) next
9        printf ("%d, ", i);
(gdb) print i
i = 0
(gdb)

Cuando nos cansemos de ir paso a paso, y de ver el valor de la variable i, podemos decirle al programa que continue hasta el final con cont (el programa se caerá antes de llegar al final, en la línea 12). Se sale del debugger con quit.

(gdb) cont
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
Error, violación de segmento y demás.
12    *a = 3;  /* Esto es erróneo. Dará un "Violación de segmento" */
(gdb) quit
Se acabó
$

Un último detalle para los curiosos. El comando help del debugger o el man gdb de unix nos cuenta más comandos.

Otra curiosidad más. Supongamos que tenemos el programa acabado y más o menos nos fiamos de que está bien. Es posible que quede todavía algún fallo y un día ese programa haga algo que al sistema linux no le gusta, por ejemplo, acceder a una dirección de memoria no válida. El sistema linux hace que ese programa se detenga inmediatamente, pero para que podamos ver por qué, vuelca toda la memoria del mismo en un fichero de nombre "core". Suele haber algún tipo de aviso de que este fichero se ha creado ("core dumped" o similar). Con el debugger podermos ver ese fichero core de la siguiente manera

$ ./Largo
error con "core dumped"
$ gdb Largo core
...información variada...
12    *a = 3;  /* Esto es erróneo. Dará un "Violación de segmento" */
(gdb)

Poniendo gdb, el nombre del ejecutable (Largo) y el nombre del fichero "core" (core), se abre el debugger mostrando la línea que ha provacado la caida del programa. Podemos además, con el comando print, ver los valores de las variables en el momento de la caida.

Estadísticas y comentarios

Numero de visitas desde el 4 Feb 2007:

Aviso Legal