The GNU Debugger


Command quick reference

  • run [arg1 arg2 …] - execute program with command line arguments
  • list - print source code
  • print [var] - print value of variable
  • break [line number function] - set breakpoint at line number or function
  • info break- list all breakpoints
  • delete [n] - delete breakpoint n
  • continue - resume execution after breakpoint
  • next - execute next line and pause
  • step - descend into function call an pause
  • backtrace - show function call stack

What is gdb?

The GNU Debugger is a program that you can use to examine your code while it is running. It allows you to do things like pause execution of the program, inspect variables, and view the stack. The debugger is extremely useful in tracking down bugs because it provides you with a lot of information about the running state of your program.

Starting gdb

Before we can use gdb, it requires some extra information from the compiler. We’ll use the timeless hello.c program as our example code:

#include <stdio.h>

void hello() {
  char *a = NULL;
  a[1] = "I'm a segfault!";
  printf("Hello world!\n");
}

int main() {
  hello();
  return 0;
}

We must compile our program with the -g flag to include debugging information in the executable:

$ clang -g hello.c # compile hello.c with debugging information

To start the debugger, we simply use the gdb command followed by the name of the executable:

$ gdb a.out # run the debugger on a.out

The gdb prompt is (gdb). We can enter commands after this prompt to control execution of our program. To run the executable in gdb we use the run command followed by any command line arguments the program takes:

(gdb) run arg1 arg2 # run a.out with the arguments "arg1" and "arg2"

Backtrace

We can use the backtrace command at any time to see which functions are on the stack. This is particularly useful after the program has been interrupted (for example by a segmentation fault or a ^C interrupt); we can see exactly where the error occurred:

Program received signal SIGSEGV, Segmentation fault.
0x000000000040053e in hello () at hello.c:5
5               a[1] = "I'm a segfault!";
(gdb) backtrace # print the function stack
#0  0x000000000040053e in hello () at hello.c:5
#1  0x0000000000400574 in main () at hello.c:10
(gdb)

Here we see that the segmentation fault occurred while executing line 5 of hello.c. The backtrace shows us that it occurred in the function hello() which was called by main().

Breakpoints

One of the most useful features of gdb is the ability to stop our code at specific points called breakpoints. Breakpoints are set with the break command. We can break at a line number:

(gdb) break hello.c:4  # program will pause at line 4 of hello.c

or at a function call:

(gdb) break hello.c:hello  # program will pause before executing hello()

We can view the breakpoints that are set using info break:

(gdb) info break # list all breakpoints
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x080483da in hello at hello.c:4
2       breakpoint     keep y   0x080483ee in main at hello.c:9
(gdb)

Breakpoints must be referenced by their number. To delete the break at line 4:

(gdb) delete 1 # delete breakpoint 1

We can resume the program using the continue command:

(gdb) continue # resume execution

Alternatively we can walk through the code using next and step. next will execute the next line of code, stepping over any function calls and then stop:

Breakpoint 1, main () at hello.c:9
9               hello();
(gdb) next # execute line 9 of hello.c and then pause at line 10
Hello world!
10              return 0;
(gdb)

The step command will step into any function calls. We can use it to walk through the function being called:

Breakpoint 1, main () at hello.c:9 9 hello(); (gdb) step # pause at the first line of the function hello() hello () at hello.c:4 4 printf(“Hello world!\n”); (gdb)

Inspecting variables

We can examine the values of variables in our program during executing with the “print” command:

Breakpoint 1, hello () at hello.c:4
4               char *a = NULL;
(gdb) print a # print the current value of a
$1 = 0x0
(gdb)

Here we see that a is NULL (so we get a segmentation fault when we try to dereference it!)

Other useful commands

The “list” command allows you to view the source code of the program executing.

The “help” command gives detailed instructions on how to use different gdb commands.

Almost all of the commands in gdb can be abbreviated. For instance r is equivalent to run, bt is equivalent to backtrace and so on. Use the help command to see acceptable abbreviations.

 

Template design by Andreas Viklund