Skip to content

GDB Debugger

The GNU debugger, gdb for short, is a command line tool that allows you to diagnose coding erros. gdb is included in the gcc package. Running your program within gdb you can interactively step line by line to do some detective work about what might be wrong.

Prerequisite

To use gdb the program must compile without errors.

Compile with debugging

We need to compile a program with the compiler debugging flag -g. This instructs the compiler to include the original source code into the executable.

For example, compile as

gcc -g -o [MY_PROGRAM] [MY_SOURCE].c

Run program with gdb

Launch the program through gdb

gdb [PATH_TO_EXECUTABLE]

Example source code to test gdb

ex_debug.c:

#include <stdio.h>

float otherFunction(float a) {
  float b = 3.2*a;
  return b;
}

float someFunction(float a) {
  int b = 2*otherFunction(a);
  return b;
}

int main(int argc, char **argv) {
  float a = 1.2;
  float b = someFunction(a);

  printf("a=%f, b=%f\n", a, b);

  return 0;
}

There is something wrong with this code. It should print out a=1.2, b=7.68.

Commands to control gdb

(gdb) run

Run the entire program

(gdb) run
For the example, the output is
Starting program: [PATH_TO_EXECUTABLE]
a=1.200000, b=7.000000
[Inferior 1 (process 2070606) exited normally]

(gdb) break

Set a breakpoint in a function and then start gdb running the program until the breakpoint.

(gdb) break [FUNCTION_NAME]
(gdb) run
For the example, break at the main function
(gdb) break main
(gdb) run
shows
Breakpoint 1 at 0x5555555551c1: file ex_debug.c, line 14.

The debugger stops execution at the first executable statement in the function where the breakpoint is set. Thus, run only keeps going until the breakpoint:

(gdb) run
Starting program: [PATH_TO_EXECUTABLE]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffe1d8) at ex_debug.c:14
14    float a = 1.2;

(gdb) list

You can see the next few lines of code by typing list.

For the example, the output is

(gdb) list
9     int b = 2*otherFunction(a);
10    return b;
11  }
12
13  int main(int argc, char **argv) {
14    float a = 1.2;
15    float b = someFunction(a);
16
17    printf("a=%f, b=%f\n", a, b);
18

(gdb) step

We can step through line by line as the code is executed using the step command.

In the following example, typing step and pressing Enter makes the debugger either processes the next line of code or step into the function if the statement is a function call (with each time pressing Enter).

For the example, the output is

(gdb) step
15    float b = someFunction(a);
(gdb)
someFunction (a=1.20000005) at ex_debug.c:9
9     int b = 2*otherFunction(a);
(gdb)
otherFunction (a=1.20000005) at ex_debug.c:4
4     float b = 3.2*a;
(gdb)
5     return b;
(gdb)
6   }
Note: Enter was pressed at each line, which says only (gdb). This repeats the last command given to gdb.

(gdb) cont

When stopped at a breakpoint, type cont for the debugger to continue until the next breakpoint.

For the example, continue after breaking at main

(gdb) cont
Continuing.
a=1.200000, b=7.000000
[Inferior 1 (process 2070606) exited normally]

For the example, suppose that something went wrong in the function someFunction. Add another breakpoint at someFunction. When running the program, gdb first stops in main (i.e., the first breakpoint). Type cont and the debugger will continue until the second breakpoint.

(gdb) break otherFunction
Breakpoint 2 at 0x555555555156: file ex_debug.c, line 4.
(gdb) run
Starting program: [PATH_TO_EXECUTABLE]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffe1d8) at ex_debug.c:14
14    float a = 1.2;
(gdb) cont
Continuing.

Breakpoint 2, otherFunction (a=1.20000005) at ex_debug.c:4
4     float b = 3.2*a;

(gdb) print

Print the values of variables. Use as

(gdb) print [VARIABLE_NAME]

Continuing the example,

(gdb) print a
$1 = 1.20000005
(gdb) cont
Continuing.
a=1.200000, b=7.000000
[Inferior 1 (process 2070738) exited normally]

(gdb) next

Similar to step command, but does not go into functions (also know as "step over" command).

Continuing the example, the output is

(gdb) next
5     return b;
(gdb)
6   }
(gdb)
someFunction (a=1.20000005) at ex_debug.c:9
9     int b = 2*otherFunction(a);
(gdb)
10    return b;
(gdb)
11  }
(gdb)
main (argc=1, argv=0x7fffffffe1d8) at ex_debug.c:17
17    printf("a=%f, b=%f\n", a, b);
(gdb)
a=1.200000, b=7.000000
19    return 0;
(gdb)
20  }
(gdb) cont
Continuing.
[Inferior 1 (process 2070748) exited normally]
Note: Enter was pressed at each line, which says only (gdb). This repeats the last command given to gdb.

(gdb) where

See where we are in the call stack, this means see the nested sequence of function calls.

For the example, the output is

(gdb) run
Starting program: /home/jrudi/cmda3634-fa23/L09/debug
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main (argc=1, argv=0x7fffffffe1d8) at ex_debug.c:14
14    float a = 1.2;
(gdb) where
#0  main (argc=1, argv=0x7fffffffe1d8) at ex_debug.c:14
(gdb) cont
Continuing.

Breakpoint 2, otherFunction (a=1.20000005) at ex_debug.c:4
4     float b = 3.2*a;
(gdb) where
#0  otherFunction (a=1.20000005) at ex_debug.c:4
#1  0x0000555555555198 in someFunction (a=1.20000005) at ex_debug.c:9
#2  0x00005555555551da in main (argc=1, argv=0x7fffffffe1d8) at ex_debug.c:15
At the bottom of the terminal listing is a stack trace showing the arguments to each of the functions in the call stack. We see we are two functions down the stack from the main function:
#0  otherFunction (a=1.20000005) at ex_debug.c:4
#1  0x0000555555555198 in someFunction (a=1.20000005) at ex_debug.c:9
#2  0x00005555555551da in main (argc=1, argv=0x7fffffffe1d8) at ex_debug.c:15

Finding the bug

Continuing the example, we advance the program to return from otherFunction.

(gdb) step
5     return b;
(gdb)
6   }
(gdb)
someFunction (a=1.20000005) at ex_debug.c:9
9     int b = 2*otherFunction(a);
(gdb) where
#0  someFunction (a=1.20000005) at ex_debug.c:9
#1  0x00005555555551da in main (argc=1, argv=0x7fffffffe1d8) at ex_debug.c:15
We advance the program and print the return variable from someFunction
(gdb) step
10    return b;
(gdb) print b
$2 = 7
Something weird happened in the program: A floating point number was returned from otherFunction but turned into an integer inside someFunction. Looking at the code for someFunction, we see that the b variable is actually an int. Bug found!

(gdb) quit

Quit the debugger when finished.


Cheat Sheet for GDB

Note: One can just use the first letter of each command instead of the whole command.

run [PATH_TO_EXECUTABLE]  # Start running
break [FUNCTION]          # Add a breakpoint in [FUNCTION]
cont                      # Continue running after breakpoint
print [VARIABLE_NAME]     # Print value of [VARIABLE_NAME]
next                      # Process next statement
step                      # Step into next function or process next step
where                     # Print call stack trace
list                      # List next few lines of code
up                        # Move up the call stack
down                      # Mode down the call stack
quit                      # Quit debugger