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
CommandShortShows
backtracebtevery frame
backtrace 5bt 5the innermost 5 frames
backtrace -5bt -5the outermost 5 frames, nearest main
backtrace fullbt fullevery 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.

CommandShortEffect
frame 2f 2select frame 2 and print it
framefreprint the currently selected frame
up—one frame toward main
downdoone 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
listlsource 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
SymptomCause and fix
?? () in every frameno symbols at all, install the debuginfo package
<optimized out> argsbuilt with -O2, rebuild that file with -Og
backtrace stops after 1 frameframe pointer omitted, add -fno-omit-frame-pointer
Backtrace stopped: previous frame inner to this framecorrupted stack, likely a buffer overflow into the return address
Cannot access memory at address 0x0the frame chain ran into a null pointer
inline functions collapsedrebuild 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
SettingDefaultEffect
set backtrace limit Nunlimitedstop after N frames
set backtrace past-mainoffkeep going below main
set backtrace past-entryoffkeep going below the ELF entry point
set filename-displayrelativerelative, basename, or absolute
set print frame-argumentsscalarsall, scalars, none, presence
set print entry-valuesdefaultshow 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.