GDB (GNU debugger) can pause the execution of a running program and let you examine/take control of its memory. It's probably one of the most powerful tools that can help you nail down the exact cause of a problem with your program. For most of the time it works like having printf
s in your code but it's much more extensible and efficient. In the examples below, a "$
" prompt means a command is typed to a operating system shell, and a "#
" prompt means a command is typed to the GDB command prompt.
Preparation
Before running gdb
, please be sure that the program is compiled with the -g
compiler flag. This flag tells the compiler to insert "debug symbols" into the executable so that you can refer to the variables by the same names as you declared them in C.
Launch a Program in GDB
To debug a program, we must launch it with GDB.
$ gdb ./program
If the program requires command line arguments, please take a look at the Programs with Command Line Arguments section (on the same page). After GDB successfully loads the program we will be taken to the GDB command prompt. We can interact with GDB through a set of GDB commands. Type a command and press return to execute the command.
Useful GDB Commands
break
: Insert a breakpoint. A breakpoint is a special location in the program, and GDB will pause the execution of the program once this location is reached. A breakpoint is identified by a file name and a line number (like hello_world.c:10
, meaning the 10th line in file hello_world.c
). Example:
break hello_world.c:10
run
: This command tells the GDB to start executing the program from the very beginning. The program will keep executing until it hits a "breakpoint" set with the break
command above.
next
: Only works when the program is "paused" because of a breakpoint. It executes the next statement in the program and pause the program again. This behavior is also known as "step over", which means if the next statement to execute is a function call, it will "step over" the function call and will only pause the program again after the function call returns.
step
: Similar to "next"
, but it works in a "step into" fashion. If the next statement to execute is a function call, step
will pause the program at the first executable statement INSIDE that function.
finish
: This command continues the currently executing function, and pause the program again right after the function returns. It's particularly useful when you inadvertly step
ped into a function that you don't actually care about (like printf
).
continue
: Continue executing a paused program. It works similarly to run
in the sense that the program will only stop once another breakpoint is hit, but it doesn't restart the program.
backtrace
: When a program is paused or encounted an error, this command can be used to inspect the most recent call stack. It will give you information about which code called a certain function - it's particularly useful when you have problems like a segmentation fault.
print
: This is the ultimate command! Pretty much everything else we do in GDB is to set things up so we can use print
to print out a variable value. The print
command accepts variable names (subject to scopes), or even plain memory locations. It can also be used to execute a function and print out the return value. Example:
// int count = 0;
# print count
up/down
: This pair of commands help you navigate between different function frames in the call stack. For example, you want to access a local variable in the caller's frame of the current executing function, which is out-of-scope, you cannot direct access it via print
by referring to it using the variable name. What you can do instead is to go up one level in the call stack using up
and then print the variable. It's often used in conjunction with the backtrace
command so that you know which function you are looking at/going to.
info breakpoints
: This command gives you a list of breakpoints that are currently set in the program. (There are many other useful info
commands; see notes)
disable/enable
: This pair of command is used to manage breakpoints. You can have a lot of breakpoints in a program and that's fine, just disable the ones you don't need, and re-enable them when you need them again! You should refer to breakpoints using the breakpoint number returned by the "info breakpoints"
command mentioned above. Example:
# disable 2
Using the TUI
GDB provides a useful feature called the TUI (terminal user interface) that allows you to see code and/or assembly alongside the debugging console. This prevents you from having to list
frequently to find where you are. To activate the TUI, press either Ctrl + X 2
(control + X, followed by 2) to view both source and assembly, or Ctrl + X 1
to view just source. To switch between views, use Ctrl + X O
.
Programs with Command Line Arguments
There are two ways to launch a program with command line arguments.
1. To use the --args
argument when launching GDB in shell:
$ gdb --args arg1 arg2 ./program
2. To attach arguments to the "run" command in GDB command prompt:
# run arg1 arg2
Notes
- Many of these commands have short-hand representations (in most cases it's just the first letter of the full command, like
b
forbreak
, etc.). - Once you feel comfortable with GDB, it's good to know some more "advanced" commands that may help you debug your code later in this course. Many of those commands operate at a lower level, interacting with machine instructions and plain memory locations. This list contains many such commands.