UC3M

Telematic/Audiovisual Syst./Communication Syst. Engineering

Systems Architecture

September 2017 - January 2018

16.4.  Controlled Program Execution

Other than stopping a program execution with Crtl-C, it is more effective to be able to stop in a concrete line of code. In order to achieve this, a breakpoint needs to be inserted in the code. A breakpoint is a mark the debugger keeps in the code. Whenever the execution reaches a breakpoint, it is suspended and control is taken by the debugger command interpreter. The command to insert a breakpoint is break (or abbreviated as b) followed by the code line to be inserted.

(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) 

The user may introduce as many breakpoints as needed in different locations in the code. The debugger assigns an integer to each of them as the breakpoint id starting at 1. In the last line of the previous message it can be seen how the introduced breakpoint on line 41 of file gdb_use.c has been assigned the id 1.

The info breakpoints command (or its abbreviation info b) shows the breakpoint list present in the debugger.

(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) 

Breakpoints can be added at any point in the process execution. Once set, if execution starts with the run (or its abbreviated form r), it stops whenever the first line of code with a breakpoint is reached.

(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) 

Breakpoints can also be inserted using a function name instead of a code line number. In this case, execution is suspended just before the first line of code of such function.

(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) 

As it can be seen in the previous listing, the debugger suspended the execution when breakpoint number 1 has been reached. After typing the continue command, execution has proceeded until breakpoint number 2. The continue command is introduced again and execution proceeds until the first line of function check. The tool shows the line of code about to be executed as well as the parameter values with which the function has been invoked. Very often, this information is crucial to diagnose an execution error. The where command also shows this information but for all functions that are currently executing.

Each breakpoint can be temporarily disabled/enabled independently. Commands enable and disable followed by the breakpoint number achieve these respectively.

There are three possible commands to continue the program execution. The first one, continue (or c) has already been covered. Execution is continued until the next breakpoint is reached, an error occurs or the execution is interrupted. The second command is next (or its abbreviation n). This command executes one single line of code and suspends again the execution.

(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) 

If the line of code executed through the next command contains a function invocation, the debugger suspends the execution after the function has completed. Therefore, this command does not allow to enter in the function and suspend again the execution. The step (or its abbreviation s) command does precisely this. If invoked in a line with a function call, instead of finishing the execution, it enters the function and stops before the first line of code.

(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) 

If the debugger is about to execute a line with no function call, then the effect of the next and step commands is identical. Using the where command it can be checked how the program stopped in the first line of function, itself invoked from 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)