UC3M

Grado en Ing. Telemática/Sist. Audiovisuales/Sist. de Comunicaciones

Arquitectura de Sistemas

Septiembre 2017 - Enero 2018

16.4. Ejecución controlada de un programa

Aparte de detener la ejecución de un programa con Crtl-C, lo más útil es detener la ejecución en una línea concreta del código. Para ello es preciso insertar un punto de parada (en inglés breakpoint). Dicho punto es una marca que almacena el depurador, y cada vez que la ejecución del programa pasa por dicho punto, suspende la ejecución y devuelve el control al usuario. Para insertar un punto de parada se utiliza el comando break (abreviado b) seguido de la línea en la que se desea introducir.

(gdb) l 41
36
37      int main(int argc, char **argv) 
38      {
39        unit_ptr buf;
40
41        buf = (unit_ptr)calloc(SIZE, sizeof(struct data_unit));
42        function(buf);
43        if (check(buf)) 
44        {
(gdb) b 41
Breakpoint 1 at 0x8048471: file gdb_use.c, line 41.
(gdb) 

Se pueden introducir tantos puntos de parada como sean necesarios en diferentes lugares del código. El depurador asigna un número entero a cada uno de ellos comenzando por el 1. En la última línea del mensaje anterior se puede ver como al punto introducido en la línea 41 del fichero gdb_use.c se le ha asignado el número 1.

El comando info breakpoints (o su abreviatura info b) muestra por pantalla la lista de puntos de parada que contiene el depurador.

(gdb) l 42
37      int main(int argc, char **argv) 
38      {
39        unit_ptr buf;
40
41        buf = (unit_ptr)calloc(SIZE, sizeof(struct data_unit));
42        function(buf);
43        if (check(buf)) 
44        {
45          printf("Error detectado en tabla\n");
(gdb) b 42
Breakpoint 2 at 0x8048486: file gdb_use.c, line 42.
(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x08048471 in main at gdb_use.c:41
2   breakpoint     keep y   0x08048486 in main at gdb_use.c:42
(gdb) 

Los puntos de parada se pueden introducir en cualquier momento de la ejecución de un proceso. Una vez introducidos, si se comienza la ejecución del programa mediante el comando run (o su abreviatura r), ésta se detiene en cuanto se ejecuta una línea con un punto de parada.

(gdb) r
Starting program: /home/test/gdb_use 

Breakpoint 1, main (argc=1, argv=0xfefff604) at gdb_use.c:41
41        buf = (unit_ptr)calloc(SIZE, sizeof(struct data_unit));
(gdb) 

Los puntos de parada se pueden poner utilizando el nombre de una función. En tal caso la ejecución se detiene justo antes de ejecutar la primera línea de código de dicha función.

(gdb) b check
Breakpoint 3 at 0x80483ce: file gdb_use.c, line 27.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/test/gdb_use 

Breakpoint 1, main (argc=1, argv=0xfefff604) at gdb_use.c:41
41        buf = (unit_ptr)calloc(SIZE, sizeof(struct data_unit));
(gdb) c
Continuing.

Breakpoint 2, main (argc=1, argv=0xfefff604) at gdb_use.c:42
42        function(buf);
(gdb) c
Continuing.

Breakpoint 3, check (table=0x804a008) at gdb_use.c:27
27        for (y = 0; y < SIZE; y++) {
(gdb) 

Tal y como muestra el listado anterior, el depurador primero se ha detenido en el punto de parada 1. Tras introducir el comando continue se ha detenido en el punto de parada 2. Al ejecutar el comando continue de nuevo, la ejecución continua hasta la primera línea de la función check. Además de mostrar la línea de código en la que se ha detenido, también se muestra el valor de los parámetros con los que ha sido invocada la función. A menudo esta información es crucial para identificar la procedencia de un error. El comando where también ofrece esta información, pero para todas las funciones en ejecución en ese instante.

Cada punto de parada puede ser temporalmente desactivado/activado de manera independiente. Los comandos enable y disable seguido de un número de punto de parada activan y desactivan respectivamente dichos puntos.

Para reanudar la ejecución del programa previamente suspendida hay tres comandos posibles. El primero que ya se ha visto es continue (o c). Este comando continua la ejecución del programa y no se detendrá hasta que se encuentre otro punto de parada, se termine la ejecución, o se produzca un error. El segundo comando para continuar la ejecución es next (o su abreviatura n). Este comando ejecuta únicamente la línea de código en el que está detenido el programa y vuelve de nuevo a suspender la ejecución.

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/test/gdb_use 

Breakpoint 1, main (argc=1, argv=0xfefff604) at gdb_use.c:41
41        buf = (unit_ptr)calloc(SIZE, sizeof(struct data_unit));
(gdb) n

Breakpoint 2, main (argc=1, argv=0xfefff604) at gdb_use.c:42
42        function(buf);
(gdb) n
43        if (check(buf)) {
(gdb) 

Nótese que si la línea de código procesada con el comando next es una invocación a una función, el depurador ejecuta la función y se detiene en la línea siguiente. Por tanto, este comando no permite introducirse en una llamada a una función. Para ese cometido existe el comando step (o su abreviatura s). Este comando, cuando se ejecuta sobre una línea de código que contiene una llamada a una función, en lugar de pasar a la siguiente línea, se introduce en la función y suspende de nuevo la ejecución.

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/test/gdb_use 

Breakpoint 1, main (argc=1, argv=0xfefff604) at gdb_use.c:41
41        buf = (unit_ptr)calloc(SIZE, sizeof(struct data_unit));
(gdb) n

Breakpoint 2, main (argc=1, argv=0xfefff604) at gdb_use.c:42
42        function(buf);
(gdb) s
function (table=0x804a008) at gdb_use.c:16
16        for (y = 0; y < SIZE - 1; y++)
(gdb) 

Si el depurador está detenido sobre una línea que no contiene ninguna llamada a una función, el efecto de los comandos next y step es idéntico. Con el comando where se puede comprobar como el programa se ha detenido en la invocación de la función function desde la función main.

(gdb) where
#0  function (table=0x804a008) at gdb_use.c:16
#1  0x08048491 in main (argc=1, argv=0xfefff604) at gdb_use.c:42
(gdb)