What it is
GDB is the GNU Debugger, a powerful command-line tool for inspecting and controlling the execution of programs to find and fix bugs. You reach for GDB when you need to step through code, examine variables, set breakpoints, and understand program flow at runtime.
Installation
Linux
sudo apt update && sudo apt install gdb
# or
sudo yum install gdb
macOS
GDB is not installed by default on macOS. You can install it using Homebrew:
brew install gdb
Note: On macOS, you’ll need to sign GDB for debugging. After installation, run:
codesign --entitlements /tmp/entitlements.xml -s gdb_codesign_identity /path/to/your/gdb/executable
You’ll first need to create /tmp/entitlements.xml with content like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>
And then create a codesign identity:
sudo security create-generic-password -a $(whoami) -s gdb_codesign_identity -l "gdb-entitlement"
Finally, you’ll need to allow the signed GDB executable to run.
Windows
GDB is typically installed as part of the MinGW-w64 distribution.
Download and install MinGW-w64 from mingw-w64.org. Ensure the gdb package is selected during installation. The executable will be available in the MinGW’s bin directory.
Core Concepts
- Inferior Process: The program you are debugging.
- Breakpoints: Points in your code where you tell GDB to stop execution.
- Stepping: Executing code line by line or function by function.
- Stack Trace: A list of active function calls at a given point in execution, showing the call history.
- Frame: A single function call on the stack, containing local variables and arguments.
- Watchpoints: Breakpoints that trigger when the value of a specific variable or memory location changes.
- Symbols: Information about functions, variables, and types in your program, usually generated by the compiler with debugging flags (e.g.,
-g).
Commands / Usage
Starting GDB
-
Start GDB with a program:
gdb ./my_programStarts GDB and loads
my_programwithout running it yet. -
Start GDB and run with arguments:
gdb ./my_program arg1 arg2Starts GDB, loads
my_program, and prepares to run it witharg1andarg2as command-line arguments. -
Attach to a running process:
gdb -p 12345Attaches GDB to the process with PID
12345. -
Start GDB and load core dump:
gdb ./my_program core.12345Loads the core dump
core.12345from the crashedmy_programfor post-mortem debugging.
Running and Controlling Execution
-
Run the program:
(gdb) runStarts execution of the loaded program. If arguments were specified during
gdbstartup, they are used. -
Run with new arguments:
(gdb) run arg3 arg4Restarts the program with the new command-line arguments
arg3andarg4. -
Continue execution:
(gdb) continueResumes execution until the next breakpoint, signal, or program termination.
-
Continue with a count:
(gdb) continue 5Continues execution, stopping at the 5th breakpoint encountered.
-
Step to the next line:
(gdb) nextExecutes the current line and stops at the next line in the current source file. If the current line is a function call,
nextexecutes the function entirely and stops after it returns. -
Step into a function:
(gdb) stepExecutes the current line. If the current line is a function call,
stepstops at the first line inside that function. -
Step until a specific line:
(gdb) next-line 25Executes lines until line
25in the current file is reached. -
Step until a specific function:
(gdb) step-at my_functionExecutes until the first line of
my_functionis reached. -
Step until return:
(gdb) finishContinues execution until the current function returns, then stops.
-
Continue until a specific line:
(gdb) until 42Continues execution until line
42in the current file is reached. -
Interrupt execution:
(gdb) interruptStops the running program. Equivalent to pressing
Ctrl+Cin the terminal where GDB is running. -
Kill the inferior process:
(gdb) killTerminates the program being debugged.
Breakpoints
-
Set a breakpoint at a line number:
(gdb) break 15Sets a breakpoint at line
15in the current source file. -
Set a breakpoint at a function name:
(gdb) break my_functionSets a breakpoint at the first line of the function
my_function. -
Set a breakpoint at a specific file and line:
(gdb) break main.c:20Sets a breakpoint at line
20inmain.c. -
Set a breakpoint with a condition:
(gdb) break my_function if i == 10Sets a breakpoint at
my_functionthat only stops when the variableiis equal to10. -
Set a breakpoint that runs a command:
(gdb) break my_function commands > silent # Don't print "Breakpoint hit" message > printf "Value of x: %d\n", x > continue > endSets a breakpoint that silently prints the value of
xand then continues execution. -
Set a watchpoint for a variable:
(gdb) watch my_variableStops execution whenever the value of
my_variablechanges. -
Set a watchpoint for an expression:
(gdb) watch *ptrStops execution whenever the memory location pointed to by
ptrchanges. -
Set a hardware watchpoint:
(gdb) awatch my_variableStops when
my_variableis accessed (read or written). -
Set a watchpoint for write access:
(gdb) rwatch my_variableStops when
my_variableis read. -
List all breakpoints:
(gdb) info breakpointsDisplays a numbered list of all breakpoints, watchpoints, and catchpoints.
-
Delete a breakpoint:
(gdb) delete 1Deletes breakpoint number
1. -
Disable a breakpoint:
(gdb) disable 1Temporarily disables breakpoint number
1. -
Enable a breakpoint:
(gdb) enable 1Re-enables a disabled breakpoint number
1. -
Clear breakpoints in a file/function:
(gdb) clear main.c:20Removes breakpoints at line
20inmain.c. -
Clear all breakpoints:
(gdb) clearRemoves all breakpoints.
Inspecting Data
-
Print a variable’s value:
(gdb) print my_variableDisplays the current value of
my_variable. -
Print an expression’s value:
(gdb) print my_variable * 2 + 5Evaluates and prints the result of the expression.
-
Print a pointer’s value (address):
(gdb) print &my_variablePrints the memory address of
my_variable. -
Print the value at a memory address:
(gdb) print *0x7fffffffdc88Prints the value stored at the specified memory address.
-
Print a variable in hexadecimal:
(gdb) print/x my_variablePrints
my_variablein hexadecimal format. -
Print a variable in decimal:
(gdb) print/d my_variablePrints
my_variablein decimal format. -
Print a variable in character format:
(gdb) print/c my_variablePrints
my_variableas a character. -
Print a variable as a string:
(gdb) print/s my_string_pointerPrints the null-terminated string pointed to by
my_string_pointer. -
Display a variable automatically:
(gdb) display my_variablePrints
my_variable’s value every time the program stops. -
Undisplay a variable:
(gdb) undisplay 1Stops automatically displaying the variable associated with display number
1. -
List displayed variables:
(gdb) info displayShows all variables that are set to be displayed automatically.
-
Examine memory:
(gdb) x/10xw 0x7fffffffdc88Examines 10 words (
x) in hexadecimal (x) format starting at memory address0x7fffffffdc88. Format specifiers:x: hexadecimald: decimalu: unsigned decimalo: octalt: binarya: addressi: instructionc: characterf: floats: string Size specifiers:b: byte (8 bits)h: halfword (16 bits)w: word (32 bits)g: giant word (64 bits) Count: number of units to display.
Stack and Frames
-
Backtrace (show call stack):
(gdb) backtracePrints a list of all function calls that led to the current point of execution.
-
Backtrace with frame numbers:
(gdb) btShorthand for
backtrace. -
Backtrace with more output:
(gdb) backtrace fullPrints the call stack and the local variables for each frame.
-
Select a stack frame:
(gdb) frame 2Selects frame number
2from the backtrace. You can then examine variables and source code in that frame’s context. -
Select a frame by function name:
(gdb) frame my_functionSelects the most recent frame associated with
my_function. -
Up one stack frame:
(gdb) upMoves the current frame selection one level up the call stack.
-
Down one stack frame:
(gdb) downMoves the current frame selection one level down the call stack.
-
List local variables in the current frame:
(gdb) info locals -
List function arguments in the current frame:
(gdb) info args -
List all symbols in the current frame:
(gdb) info locals (gdb) info args
Source Code Navigation
-
List source code around the current line:
(gdb) listShows 10 lines of source code centered around the current execution point.
-
List source code around a specific line:
(gdb) list 30Shows 10 lines of source code centered around line
30. -
List source code for a specific function:
(gdb) list my_functionShows the source code for
my_function. -
List source code for a file and line:
(gdb) list main.c:50Shows source code around line
50inmain.c. -
Set the current line:
(gdb) set line-number 25Changes the current line number to
25without executing any code. -
Set the current file:
(gdb) set filename my_other_file.cChanges the current source file.
Program Information
-
Show current file and line number:
(gdb) info line -
Show program status:
(gdb) info program -
Show loaded shared libraries:
(gdb) info sharedlibrary -
Show threads:
(gdb) info threads -
Select a thread:
(gdb) thread 2
Exiting GDB
-
Quit GDB:
(gdb) quitExits the GDB debugger.
-
Quit without saving history:
(gdb) quit -n
Scripting and Configuration
-
Source a GDB script file:
(gdb) source my_script.gdbExecutes commands from
my_script.gdb. -
Set a GDB init file:
gdb -x ~/.gdbinit ./my_programRuns GDB with commands from
~/.gdbinit. -
Set a GDB command:
(gdb) set variable my_var = 10Assigns a value to a variable.
-
Set an environment variable:
(gdb) set env MY_VAR=some_value -
Show environment variables:
(gdb) show env
Assembly Level Debugging
-
Disassemble a function:
(gdb) disassemble my_functionShows the assembly code for
my_function. -
Disassemble current function:
(gdb) disassemble -
Disassemble memory region:
(gdb) disassemble $pc, +50Disassembles 50 bytes starting from the program counter (
$pc). -
Set instruction pointer:
(gdb) set $pc = 0x400500Manually sets the instruction pointer to a specific address.
Other Useful Commands
-
Help:
(gdb) helpShows a list of available help topics.
-
Help on a specific command:
(gdb) help printShows detailed help for the
printcommand. -
Set output radix (number base):
(gdb) set radix 16Sets the default number base for printing to hexadecimal.
-
Show output radix:
(gdb) show radix -
Set disassembly flavor:
(gdb) set disassembly-flavor intelSets the assembly syntax to Intel style (default is AT&T).
-
Set disassembly flavor:
(gdb) set disassembly-flavor attSets the assembly syntax to AT&T style.
Common Patterns
-
Debugging a crash (core dump):
gdb ./your_program core_file (gdb) bt (gdb) frame <frame_number> (gdb) info locals (gdb) print <variable>Analyze the state of the program at the time of the crash.
-
Finding a memory leak (using Valgrind, then GDB): Run your program with Valgrind first to identify potential leaks. Then, use GDB to step through the code paths that Valgrind indicates are problematic.
valgrind --leak-check=full ./your_program gdb ./your_program (gdb) run # ... step through code ... (gdb) break <line_number> (gdb) continue -
Debugging a specific function:
gdb ./your_program (gdb) break my_function (gdb) run # Program stops at the beginning of my_function (gdb) next # Step through lines (gdb) step # Step into functions (gdb) print my_variable -
Watching a variable change:
gdb ./your_program (gdb) watch my_changing_variable (gdb) run # Program stops when my_changing_variable's value changes (gdb) backtrace -
Debugging a race condition (using thread breakpoints):
gdb ./your_program (gdb) break my_thread_function (gdb) set a breakpoint condition for specific threads if needed (gdb) run # ... inspect threads ... (gdb) info threads (gdb) thread <thread_id> (gdb) backtrace -
Conditional breakpoint for debugging a loop:
gdb ./your_program (gdb) break my_loop_function if loop_counter == 1000 (gdb) run # Program stops when loop_counter reaches 1000 -
Debugging with a .gdbinit file for common settings: Create
~/.gdbinitwith content like:set disassembly-flavor intel set print pretty on set print array onThen simply run:
gdb ./your_program
Gotchas
-
No Symbols (
-gflag): If your program was compiled without debugging symbols (e.g., without-g), GDB will have very limited information. You won’t see source code, function names, or variable names, making debugging extremely difficult.# Compile with debugging symbols gcc -g my_program.c -o my_program -
Optimized Code: Compilers often optimize code, which can rearrange instructions, remove variables, or inline functions. This makes debugging harder as the execution flow in GDB might not match the source code line-by-line. Compile with
-O0for less optimization during debugging.gcc -g -O0 my_program.c -o my_program -
Attach Permissions (Linux): On Linux, you often need root privileges or specific
ptrace_scopesettings to attach GDB to a running process.# To allow non-root users to attach to any process (use with caution) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope -
macOS Code Signing: As mentioned in installation, GDB on macOS requires special code signing to attach to processes. Forgetting this step will prevent GDB from working correctly.
-
Watchpoint Limitations: Hardware watchpoints are limited by the number of available hardware watchpoint registers on the CPU. If you set too many, GDB might fall back to software watchpoints, which are much slower.
-
Signal Handling: GDB intercepts signals by default. If you want the program to handle signals itself, you need to tell GDB not to catch them.
(gdb) info signals # Shows which signals GDB is handling (gdb) handle SIGSEGV nostop noprint pass # Tells GDB not to stop for SIGSEGV, not to print a message, and to pass it to the program. -
printvsdisplay:printshows the value once.displayshows the value every time the program stops. Forgetting toundisplaya variable can lead to a lot of output. -
Floating Point Precision: Printing floating-point numbers might show fewer digits than you expect due to default precision settings.
(gdb) set print float-precision 10Sets the precision for printing floating-point numbers.