GDB Cheatsheet
Frames and Backtraces
Use this GDB reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Reading a Backtrace
backtrace is bt. Frame 0 is where the program is stopped, and the numbers grow
toward main.
(gdb) bt #0 parse_row (line=0x0, n=3) at parse.c:18 #1 0x000055555555527d in load_file (path=0x7fffffffe2b0 "in.csv") at load.c:44 #2 0x00005555555553c1 in main (argc=2, argv=0x7fffffffe1f8) at prog.c:61
| Command | Short | Shows |
|---|---|---|
backtrace | bt | every frame |
backtrace 5 | bt 5 | the innermost 5 frames |
backtrace -5 | bt -5 | the outermost 5 frames, nearest main |
backtrace full | bt full | every frame plus its local variables |
backtrace -full | — | same, the modern option spelling |
backtrace -frame-arguments all | — | print struct args instead of ... |
backtrace -past-main | — | keep walking below main into libc startup |
backtrace -entry-values both | — | show argument values at entry and now |
bt -hide | — | hide frames that a frame filter marked |
thread apply all bt | — | a backtrace for every thread |
Frame 0 has no address printed because it is exactly where execution stopped. Higher frames show the return address, which is the instruction after the call, so the reported line can look one off in a multi-line call.
Moving Between Frames
Almost every info locals mistake is really "you were in the wrong frame". Select
one and gdb re-points every expression at it.
| Command | Short | Effect |
|---|---|---|
frame 2 | f 2 | select frame 2 and print it |
frame | f | reprint the currently selected frame |
up | — | one frame toward main |
down | do | one frame toward frame 0 |
up 3 | — | three frames out |
frame function parse_row | — | select the innermost frame of that function |
frame address 0x7fff... | — | select by frame address |
info frame | — | the raw frame layout, saved registers, addresses |
info locals | — | locals in the selected frame |
info args | — | arguments in the selected frame |
info locals -t lock_t | — | only locals whose type matches a regex |
list | l | source around the selected frame |
(gdb) f 1 #1 0x000055555555527d in load_file (path=0x7fffffffe2b0 "in.csv") at load.c:44 44 return parse_row(line, n); (gdb) info args path = 0x7fffffffe2b0 "in.csv" (gdb) info locals line = 0x0 n = 3 (gdb) p line $1 = 0x0
info frame is what you fall back to when the backtrace itself looks wrong. It
prints the saved rip, the caller frame address, and which registers were saved
where, which is enough to unwind one level by hand.
Missing and Broken Symbols
A frame with no debug info shows the raw address and the library name. That is not a crash in gdb, it just means that object was stripped.
#0 0x00007ffff7a8f2c1 in ?? () from /lib/x86_64-linux-gnu/libfoo.so.1 #1 0x00007ffff7a91004 in foo_run () from /lib/x86_64-linux-gnu/libfoo.so.1 #2 0x0000555555555199 in main () at prog.c:14
| Symptom | Cause and fix |
|---|---|
?? () in every frame | no symbols at all, install the debuginfo package |
<optimized out> args | built with -O2, rebuild that file with -Og |
| backtrace stops after 1 frame | frame pointer omitted, add -fno-omit-frame-pointer |
Backtrace stopped: previous frame inner to this frame | corrupted stack, likely a buffer overflow into the return address |
Cannot access memory at address 0x0 | the frame chain ran into a null pointer |
| inline functions collapsed | rebuild with -fno-inline, or trust the [inlined] markers |
export DEBUGINFOD_URLS="https://debuginfod.elfutils.org/" gdb ./prog # symbols now fetched on demand
(gdb) info sharedlibrary # which objects have symbols read (gdb) set backtrace past-main on (gdb) set backtrace limit 20 # cap runaway recursion (gdb) set print frame-arguments scalars
A stack that is genuinely corrupted still has usable data. x/40a $sp prints the
raw stack words, and any value that info symbol resolves to a function is
probably a real return address from before the smash.
Backtrace Display Settings
(gdb) set print pretty on # struct args on multiple lines (gdb) set print frame-info short-location (gdb) set filename-display absolute # full paths instead of basenames (gdb) set print address off # drop the 0x... column (gdb) set backtrace past-entry off (gdb) show backtrace limit
| Setting | Default | Effect |
|---|---|---|
set backtrace limit N | unlimited | stop after N frames |
set backtrace past-main | off | keep going below main |
set backtrace past-entry | off | keep going below the ELF entry point |
set filename-display | relative | relative, basename, or absolute |
set print frame-arguments | scalars | all, scalars, none, presence |
set print entry-values | default | show argument values at function entry |
set print frame-arguments all is worth turning on when a backtrace is full of
... where struct arguments should be. It costs nothing except a longer trace, and
struct contents at the call site are often the whole answer.
Saving a Trace
gdb -q -batch -ex "bt full" ./prog core > trace.txt(gdb) set logging file gdb.log (gdb) set logging enabled on (gdb) thread apply all bt full (gdb) set logging enabled off
set logging enabled on replaced the older set logging on in gdb 11, and both
spellings still work in current releases. The output file appends by default, so
set logging overwrite on if you want a fresh file each run.