UC3M

Telematic/Audiovisual Syst./Communication Syst. Engineering

Systems Architecture

September 2017 - January 2018

16.6.  Conditional Breakpoints

Despite offering the possibility of executing a program step by step and evaluating any expression, when locating "bugs" in a program, sometimes this is not effective enough. Sometimes, a program needs to be stopped on a certain location but on certain condition. For example, let us assume a program that contains a loop with a large number of iterations. The next and step commands allow a step by step execution of each iteration. But if an error appears in the last iteration, a very tedious sequence of these commands is required to reach the point in which the error occurs. In this situation next and step are not so useful.

A first step towards locating the error would be to execute the program with no breakpoints, see where the error is produced (assuming it is a "segmentation fault" type of error) and inspecting the variable values at that point by using the print. By combining this command with the up and down commands, the current values of all active functions can be explored.

In many cases, a variable is detected containing an incorrect value which is causing the anomaly. However, in general, what is required is to know how such variable acquired that value. Therefore, what is really useful is to execute the program and stop the execution in the line of code right before the anomaly occurs.

To illustrate this situation in the example program, first all breakpoints are temporarily disable by using the disable command with no arguments. The info breakpoints command shows the value n in the Enb field for all the breakpoints.

(gdb) disable
(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep n   0x08048471 in main at gdb_use.c:41
        breakpoint already hit 1 time
2   breakpoint     keep n   0x08048486 in main at gdb_use.c:42
        breakpoint already hit 1 time
3   breakpoint     keep n   0x0804843d in check at gdb_use.c:27
(gdb) 

The program is then executed and, as it can be seen, a segmentation fault occurs on line 29, more precisely, within function check.

(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 

Program received signal SIGSEGV, Segmentation fault.
0x08048441 in check (table=0x804a008) at gdb_use.c:29
29          if ((table[y].data + 1) != table[y].next->data)
(gdb) 

The error is included in a loop, and its index is stored in variable y. The iteration in which the error appears can be found by printing the value of this variable

(gdb) p y
$6 = 999
(gdb) 

The error appears in the last iteration of the loop. It is clear that reaching the line producing the error only using next and step is very tedious and inefficient.

For this reason, gdb allows the definition of conditional breakpoints. These points are defined by first creating a regular breakpoint, and then attaching a condition. The execution is suspended if the breakpoint is reached and the condition satisfied. If the condition is not satisfied, the breakpoint has no effect.

In the example, a conditional breakpoint is defined in line 29. Two commands are required:

(gdb) b 29
Breakpoint 4 at 0x804844f: file gdb_use.c, line 29.
(gdb) condition 4 y == 999
(gdb) 

The first command defines a conventional breakpoint on file gdb_use.c, line 29. This line contains the condition inside the loop in function check. The condition command adds to breakpoint number 4 the condition y == 999. It should be noted that the syntax used for the expression is identical to C. The presence of the condition can be seen by using the info breakpoints command.

(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep n   0x080484a1 in main at gdb_use.c:41
2   breakpoint     keep n   0x080484b6 in main at gdb_use.c:42
3   breakpoint     keep n   0x0804843d in check at gdb_use.c:27
4   breakpoint     keep y   0x0804844f in check at gdb_use.c:29
	stop only if y == 999
(gdb) 

Out of all 4 defined breakpoints, the first three are disabled as shown in the fourth field. The last breakpoint is enabled but it is active only if y == 999.

A conditional breakpoint insertion can be done by using one single command by using the breakpoint command followed by the word if followed by a condition. In the previous example, the breakpoint can be inserted with the line b 29 if (y == 999).

If the program is executed again, this time, it stops exactly on iteration 999 right before the line the produces the error.

(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 4, check (table=0x804a008) at gdb_use.c:29
29	    if ((table[y].data + 1) != table[y].next->data)
(gdb) 

Since the error occurs in this line, the next step is to visualize the value of the different elements of the condition by using the print command.

(gdb) p table[y].data + 1
$2 = 1000
(gdb) p table[y].next
$3 = (struct data_unit *) 0x0
(gdb) p table[y].next->data
Cannot access memory at address 0x0
(gdb) 

It can be seen that an indirection is done with the next field of the current table element. The value of this fields is zero, and therefore, it is an incorrect address. At this point, the variable with the incorrect value has been detected. It remains to find out if this is the correct value for this field, and if so, why is it used as a memory address. The code needs to be modified to obtain a correct execution (which is left as an exercise for the reader).

To remove a condition from a breakpoint, an empty condition is added (condition command followed only by the breakpoint id).

(gdb) condition 4
Breakpoint 4 now unconditional.
(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep n   0x080484a1 in main at gdb_use.c:41
2   breakpoint     keep n   0x080484b6 in main at gdb_use.c:42
3   breakpoint     keep n   0x0804843d in check at gdb_use.c:27
4   breakpoint     keep y   0x0804844f in check at gdb_use.c:29
	breakpoint already hit 1 time
(gdb)