GDB (GNU’s DeBugger) is an open-source debugger.
Recommendation
Install pwndbg (see pwndbg setup) or gef if you intend to use GDB for CTF challenges. See Pwndbg Features
Multi-line commands
gdb has several multi-line commands. Once you finish inputting a multi-line command, use
end
to issue it. You can also exit out of the multiline input withCtrl-C
.
Vanilla GDB Usage
I compiled a list of commands that I have found useful.
Command-line
$ gdb /path/to/program [ /path/to/coredump ]
$ gdb -p `pidof /path/to/program`
If the program segfaults but doesn’t dump corefile, consider running ulimit -c unlimited
to bypass corefile size limits, or add <your-username> - core unlimited
in /etc/security/limits.conf to persist this setting.
Common Configuration
Place the following in ~/.gdbinit
or /etc/gdb/gdbinit
to persist across debugging sessions.
set disassembly-flavor intel # a must on x86 for my sanity
set pagination off # disable "Type <RET> for more, ..."
Place the following in .gdbearlyinit
set startup-quietly on # hide startup banner; GDB v11+
Disassembly
disass main # prints disassembly of main()
disass /m main # also prints source code if available
disass *0xdeadbeef # disassemble function at 0xdeadbeef
Breakpoints
b <*addr> # create breakpoint at address, supports symbol offset (e.g., break *(main+47))
b <symbol> # create breakpoint at symbol (e.g., break main)
b <*addr|symbol> if <condition> # conditional breakpoint (supports C expressions)
ctx # show current program state; runs on every bp
command hook-stop # MULTILINE: run something every time the program stops (e.g., breakpoint, nexti, stepi, etc)
i b # list breakpoints
en <bp> # enable breakpoint
dis <bp> # disable breakpoint
d <bp> # delete breakpoint
comm[and] <bp> # MULTILINE: enter commands to be run on <bp>
tb <*addr|symbol> # temporary breakpoint
rb <regex> # break at symbols matching regex
save break [file] # save bp's; recover with `source file`
Watchpoint
A watchpoint can be define to monitor the value of an expression (function calls allowed probably) and pause when the value changes.
wa <expr> # add watchpoint to stop if expr change
i b # also lists watchpoints
rw <expr> # read watchpoints: triggers when value of expression is read
rw -l <expr> # evaluates expr as an address and watches the pointed memory
Execution
r # run program
r < file # redirect file to stdin
start # temporarily break at main and run program
ni # next instruction
si # next instruction, but step into function calls
fin # continue until after ret (step out of function)
c # continue (until breakpoint)
n # next source line
s # next source line, but step into function call
until <line-nr> # execute until given source line
<ENTER> # repeat last command (can be used repeatedly)
Reversible Debugging
Reversible debugging is a powerful feature that allows you to run the program backwards, but you must begin recording process state first.
record # enable full reversible debugging for the process
record stop
# see `help record` for partial recording options
rsi [n] # reverse-stepi, optionally n times
rni [n] # reverse-nexti, optionally n times
rc # reverse-continue
# note that breakpoints and watchpoints also work backwards!
Inspect Memory
x/[num][size][fmt] *<addr> # examine `num` of `size` at `addr`
x/10gx $rsp # prints 10 elements on stack, top to bottom
p <value> # evaluate value and print
p *arr[i]@n # print n elements starting from arr[i] (note: for multidimension arrays use arr[i][j][...])
disp <expr> # same as p, but displays value of expr on every breakpoint
For x
:
num
is 1 by defaultsize
could be- b (bytes)
- h (half word / two bytes)
- w (word / four bytes - default)
- g (giant word / eight bytes)
- Notes
- Note that gdb assumes the memory to be integers of the size you requested, so be aware of little endianness!
- GDB’s word size (32-bit) does not match convention for x86 (16-bit).
- Naturally,
size
does not matter whenfmt
is nots
ori
. - The order of
size
andfmt
does not matter, since the sets of letters used are disjoint.
fmt
could be- x (hexadecimal - default)
- i (instruction)
- s (null-terminated string)
- d (signed decimal numbers)
- u (unsigned decimal numbers)
- See full list of format specifiers here
- Note: Often times, gef and pwndbg’s telescope command is helpful equivalent of examining pointer-sized hex values (e.g.,
telescope $rsp 20
is the same asx/20gx $rsp
, but also automatically and recursively dereference valid pointers for you)
Program / Memory Info
# mt / maint / maintenance
mt i sec # show all sections (current binary only)
# i / inf / info
i fi # show sections for all linked object files
i proc map # show all segments
i f # show stack frame
i fu [ filter ] # show functions
i args # list command-line arguments
i reg # show register contents
i var # show all global variables
i locals # show local variables
# gdb disable ASLR when debuggin by default
# you might want to undo this sometimes
set disable-randomization off
# auto-attach to chlid process when forking
set follow-fork-mode child
Backtrace
bt # print bracktrace
up <n> # in a backtrace, move to caller recursively n times
down <n> # in a backtrace, move to callee recursively n times
Find byte sequence in memory
find <start>,<end>,<string> # search literal string in given memory
find <start>,+<offset>,<string> # search from start to start+offset
find /b <start>,<end>,<hexbyte...> # search byte sequence in given memory range
# e.g. find /b 0xb7e97000,0xb7fd5000,0xff,0xe4
# you can also use p/x "string" to convert string to hex
Alternatively, to find offset of a string in a library, e.g., libc, you can use grep -Rabo /bin/sh /lib/libc.so.6
.
Python
# You can interact with gdb via python
# .gdbinit also supports python
python <code> # evaluate python code
python # multi-line supported (use `end` to stop)
python print(gdb.breakpoints()[0].location)
python gdb.Breakpoint("7") # create break on line 7
Source
For debug builds (e.g., gcc -g
):
l # list 10 more source lines
l - # list previous 10 source lines
TUI
- Use
Ctrl-X A
to enter TUI mode. The default view is source code. - Use
Ctrl-L
to rerender the view (e.g., in case some printf statements from the debugged binary mess up the UI). - Use
Ctrl-X 2
to add a second window. - Use the same keybind to switch between views (e.g., registers, source code, etc).
tui reg float
to show floating registersCtrl-<P/N>
to view previous commands (up and down arrows now scroll the source code view)