Extended GDB Example

This has been a lot of information, so a short example of setting breakpoints that you can follow along with is warranted. Consider the following multi-file C code:

main.c

#include <stdio.h>
void swap(int *a, int *b);

int main(void)
{
   int i = 3;
   int j = 5;

   printf("i: %d, j: %d\n", i, j);
   swap(&i, &j);
   printf("i: %d, j: %d\n", i, j);

   return 0;
}

swapper.c

void swap(int *a, int *b)
{
   int c = *a;
   *a = *b;
   *b = c;
}

Compile this code and run GDB on the executable:

$ gcc -g3 -Wall -Wextra -c main.c swapper.c
$ gcc -o swap main.o swapper.o
$ gdb swap

Note

This is the first time in this book that we've compiled a multi-file C program, so a word is in order. The first line of the compilation process (above) produces two object files containing unresolved object code with debugging information. The second line links the object files into an executable containing all debugging information. There is no need to use GCC's -g switch during the linking process.

Setting a breakpoint at main() is very common when starting a debugging session. This sets a breakpoint on the first line of that function.[5]

(gdb) break main
Breakpoint 1 at 0x80483f6: file main.c, line 6.

The examples below all set a breakpoint at the first line of the function swap(). While they may not look the same, they all do the same thing: break at the top of swap().

(gdb) break swapper.c:1
Breakpoint 2 at 0x8048454: file swapper.c, line 1.
(gdb) break swapper.c:swap
Breakpoint 3 at 0x804845a: file swapper.c, line 3.
(gdb) break swap
Note: breakpoint 3 also set at pc 0x804845a.
Breakpoint 4 at 0x804845a: file swapper.c, line 3.

At any given time, GDB has (for lack of a better word) a focus, which you can think of as being the currently "active" file. This means that unless you qualify your commands, they are performed on the file that has GDB's focus. By default, the file that has GDB's initial focus is the one containing the main() function, but the focus is changed to a different file when any of the following actions occurs:

  • You apply the list command to a different source file.

  • You step into code residing in a different source file.

  • GDB hits a breakpoint while executing code in a different source file.

Let's look at an example. Although breakpoints have been set in swapper.c, we haven't actually listed code from that file. Hence, the focus is still trained on main.c. You can verify this by setting a breakpoint at line 6. When you set this breakpoint without a filename, GDB will set the breakpoint at line 6 of the currently active file:

(gdb) break 6
Breakpoint 5 at 0x8048404: file main.c, line 6.

Sure enough, main.c has the focus: When you start GDB, a breakpoint set only by line number is set within the file containing main(). You can change the focus by listing code from swapper.c:

(gdb) list swap
1   void swap(int *a, int *b)
2   {
3      int c = *a;
4      *a = *b;
5      *b = c;
6   }

Let's verify that swapper.c now has the focus by trying to set a another breakpoint at line 6:

(gdb) break 6
Breakpoint 6 at 0x8048474: file swapper.c, line 6.

Yep, the breakpoint was set at line 6 of swapper.c. Then you'll set a temporary breakpoint at line 4 of swapper.c:

(gdb) tbreak swapper.c:4
Breakpoint 7 at 0x8048462: file swapper.c, line 4.

Lastly, use the info breakpoints command that was introduced in Breakpoint Lists in GDB to marvel at all the breakpoints you've set:

(gdb) info breakpoints
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x080483f6 in main at main.c:6
2   breakpoint     keep y   0x08048454 in swap at swapper.c:1
3   breakpoint     keep y   0x0804845a in swap at swapper.c:3
4   breakpoint     keep y   0x0804845a in swap at swapper.c:3
5   breakpoint     keep y   0x08048404 in main at main.c:9
6   breakpoint     keep y   0x08048474 in swap at swapper.c:6
7   breakpoint     del  y   0x08048462 in swap at swapper.c:4

Much later on, when you are done with your GDB session, use the quit command to leave GDB:

(gdb) quit
$


[5] Recall that the breakpoint may not be at exactly the first line of main(), but it'll be close. Unlike our previous example of this point, though, the line here is executable, since it assigns a value to i.