GDB Debugging
-
tui enableenables the text-user-interface mode where you can see in with a split-window the current code locationfocus cmdto make arrows keys work normally in tui mode- ctrl+l if tui mode messes up
-
tab autocomplete to find options
-
breakpoints
-
tbreak: temporary break -
rbreak: match regular expression to break point locations and add for all of them -
crtl+x+2: second window; cycle through -
ignore <breakpoint number> <occurunces>to skip over a breakpoint a certain number of times -> very useful if determinsitic program fails after a certain number of times -
Couple this with
ignore <breakpoint number> 99999999and after completion/crash useinfo breakto find number of times breakpoint was hit -
To avoid arbitrary big number add
continuetocommands <breakpoint number> -
cond <breakpoint number> <condition>to make breakpoint conditional -
break foo if bar > 10: create new conditional break point -
break foo thread 3: stop at foo only in thread 3 -
watch foo: stop when foo is modified -
Can be conditions etc. like above
-
watch -levaluates once and then watches the resultant memory location, NOT the reevaluation of the expression -
rwatchis NOT regex watchpoint, but weatch point for reads to things -
awatchis access watchpoint (read or write, but value might not change for example) -
Backtrace (
bt) is useful, but doesn't go back in time -
record -
reverse-stepi -
reverse-continue(e.g. to a watch point) -
N.B hardware watchpoints don't work with stack pointer (
set can-use-hw-watchpionts 0to force software watch point)-
Hardware watch points uses special registers (use too many and you will get an unexplained crash (normally 4))
-
Software watch point evaluates after every step. This incurs a heavy context switching performance penalty
-
Can alleviate this by making sure it is run locally etc. if on a remote machine
whatistells you type information
-
-
Catchpoints also exist!
-
catch catchto stop when C++ exceptions are caught -
catch syscall nanosleepto stop at nanosleep system call -
catch syscall 100to stop at system call number 100 -
You can
callfunctions too e.g.call foo() -
Be aware that this is what happens if you do
print foo()too -
dprintf foo.c:10, "bar is %d\n", barallows you to dynamically add prints without recompiling! At least do this if you have to do printf debugging! -
set dprintf-style gdb|call|agent -
set dprintf-function fprintf -
set dprintf-channel mylog -
skipfunctions/libraries that your don't care about or trust -
e.g.
skip -rfu ^std::.*will skip stepping into all code in the std namespace -
This can get a little unintutive if you use things such as callbacks or step out of a function into skipped code etc.
-
compile code- compile code typed at console and run it -
compile filecompile source code from a file and run it -
compile printuse compiler to evaluate an expression, print result -
All can inject into the program and is very powerful. You can combine this with gdb scripting (
cat <flie.gdb> && cat > gdb ...) -
You can run commands on gdb startup by using a dotfile:
~/.gdbinit -
Compile with
-g 3or later etc. to get better debug info (to stop "value optimised out" etc.)
Docker compatibility
To be able to use gdb in a docker container, you need to run the container with additional arguments.
docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined ...
If you are using docker-compose, this can be specified like so:
security_opt:
- seccomp:unconfined
cap_add:
- SYS_PTRACE