Example 2: Debugging with breakpoints

The program fact.c, which is in the examples directory, prints factorials for the numbers 1 through 10. The printed values, however, are wrong. This example demonstrates how to use breakpoints to debug a program.

You can start this example by compiling the program with the command:

gcc -g -o fact fact.c

In the same directory, run the program:

$ ./fact
fact(1)=8517820
fact(2)=8410550
fact(3)=25231650
fact(4)=100926600
fact(5)=504633000
fact(6)=-1267169296
fact(7)=-280250480
fact(8)=2052963456
fact(9)=1296801920
fact(10)=83117312
$

The results are incorrect. Debug the program by starting gdb with fact as an argument:

$ gdb --quiet fact
(gdb)

You can find and correct the problem by setting a breakpoint to stop its execution. A breakpoint can be either a function name or line number. Because this is a C program, the entry to the main() function is a good place to set the first breakpoint. The basic syntax is the break command, followed by a function name or line number:

(gdb) break main
Breakpoint 1 at 0x402aaf: file fact.c, line 22.

For reference purposes, all breakpoints are assigned a number. In this example, the breakpoint is assigned the number 1. Using the number, you can delete a breakpoint, disable it (render it ineffective), or enable it (render it effective again).

Now you can run the program again. The gdb utility stops the program when it enters the main() function. Your output might differ slightly because of the setup of your computer.

(gdb) run
Starting program: /dev/fs/C/SFU/usr/examples/gdb/fact

Breakpoint 1, main (argc=1, argv=0x205c8) at
fact.c:22
22 for (i=1; i <= 10; i++)

Print the value of the program variable i with the print command:

(gdb) print i
$1 = 4197045

The program is stopped before all of the line is executed. The variable i has not yet been initialized to 1. You can go to the next line of source code using the next command, and then you can print the value of i again:

(gdb) next
23 printf("fact(%d)=%d\n", i, fact(i));
(gdb) print i
$2 = 1

The next command does not descend into subroutines. If you want to observe what is happening in the fact() routine, use the step command:

(gdb) step
fact (n=1) at fact.c:12
12 while (n > 1)
(gdb) print n
$3 = 1
(gdb) step
14 return (result);
(gdb) print result
$4 = 8517812
(gdb)

To determine where the value of result originated, you can check the source with the list command:

(gdb) list
9	 {
10		int result;
11
12		while (n > 1)
13			 result *= n--;
14		return (result);
15}
16
17	int
18	main(int argc, char *argv[])

This reveals the problem. The result variable appears to be uninitialized. You can test this by assigning a value to result. During a debugging session, you assign a value to a variable by using an expression as the argument to the print command. You must also set a breakpoint at the fact() function call.

(gdb) print result=1
$5 = 1
(gdb) break fact
Breakpoint 2 at 0x402a7e: file fact.c, line 12.
(gdb) continue
Continuing.
fact(1)=1

Breakpoint 2, fact (n=2) at fact.c:12
12		while (n > 1)
(gdb)

In this instance, the output fact(1)=1 is correct. You can test this further by setting the value of the result variable again. If necessary, you can do this several times.