From 6f5b0cb0cfac62fc0e1876726d05e1d30587ccf9 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Wed, 1 May 2024 15:27:02 +0200 Subject: debug: move gdb, gdbserver to own group --- src/debug/README.md | 4 + src/debug/gdb.md | 508 +++++++++++++++++++++++++++++++++++++++++++++++++ src/debug/gdbserver.md | 33 ++++ 3 files changed, 545 insertions(+) create mode 100644 src/debug/README.md create mode 100644 src/debug/gdb.md create mode 100644 src/debug/gdbserver.md (limited to 'src/debug') diff --git a/src/debug/README.md b/src/debug/README.md new file mode 100644 index 0000000..9bf1933 --- /dev/null +++ b/src/debug/README.md @@ -0,0 +1,4 @@ +# Debug + +- [gdb](./gdb.md) +- [gdbserver](./gdbserver.md) diff --git a/src/debug/gdb.md b/src/debug/gdb.md new file mode 100644 index 0000000..41d26f7 --- /dev/null +++ b/src/debug/gdb.md @@ -0,0 +1,508 @@ +# gdb(1) + +# CLI + +```markdown + gdb [opts] [prg [-c coredump | -p pid]] + gdb [opts] --args prg + opts: + -p attach to pid + -c use + -x execute script before prompt + -ex execute command before prompt + --tty set I/O tty for debugee + --batch run in batch mode, exit after processing options (eg used + for scripting) + --batch-silent link --batch, but surpress gdb stdout +``` + +# Interactive usage + +## Misc +```markdown + apropos + Search commands matching regex. + + tty + Set as tty for debugee. + Make sure nobody reads from target tty, easiest is to spawn a shell + and run following in target tty: + > while true; do sleep 1024; done + + sharedlibrary [] + Load symbols of shared libs loaded by debugee. Optionally use + to filter libs for symbol loading. + + display [/FMT] + Print every time debugee stops. Eg print next instr, see + examples below. + + undisplay [] + Delete display expressions either all or one referenced by . + + info display + List display expressions. + + info sharedlibrary [] + List shared libraries loaded. Optionally use to filter. +``` + +## Breakpoints +```markdown + break [-qualified] thread + Set a breakpoint only for a specific thread. + -qualified: Treat as fully qualified symbol (quiet handy to set + breakpoints on C symbols in C++ contexts) + + break if + Set conditional breakpoint (see examples below). + + delete [] + Delete breakpoint either all or one referenced by . + + info break + List breakpoints. + + cond + Make existing breakpoint conditional with . + + cond + Remove condition from breakpoint . + + tbreak + Set temporary breakpoint, will be deleted when hit. + Same syntax as `break`. + + rbreak + Set breakpoints matching , where matching internally is done + on: .*.* + + command [] + Define commands to run after breakpoint hit. If is not + specified attach command to last created breakpoint. Command block + terminated with 'end' token. + + : Space separates list, eg 'command 2 5-8' to run command + for breakpoints: 2,5,6,7,8. + + save break + Save breakpoints to . Can be loaded with the `source` command. +``` + +## Watchpoints +```markdown + watch [-location|-l] [thread ] + Create a watchpoint for , will break if is written to. + Watchpoints respect scope of variables, -l can be used to watch the + memory location instead. + + rwatch ... + Sets a read watchpoint, will break if is read from. + + awatch ... + Sets an access watchpoint, will break if is written to or read + from. +``` + +## Catchpoints +```markdown + catch load [] + Stop when shared libraries are loaded, optionally specify a + to stop only on matches. + catch unload [] + Stop when shared libraries are unloaded, optionally specify a + to stop only on matches. + + catch throw + Stop when an exception is thrown. + catch rethrow + Stop when an exception is rethrown. + catch catch + Stop when an exception is caught. + + catch fork + Stop at calls to fork (also stops at clones, as some systems + implement fork via clone). + + catch syscall [ ..] + Stop at syscall. If no argument is given, stop at all syscalls. + Optionally give a list of syscalls to stop at. +``` + +## Inspection +```markdown + info functions [] + List functions matching . List all functions if no + provided. + + info variables [] + List variables matching . List all variables if no + provided. + + info register [ ..] + Dump content of all registers or only the specified ister. +``` + +## Signal handling +```markdown + info handle [] + Print how to handle . If no specified print for all + signals. + + handle + Configure how gdb handles sent to debugee. + : + stop/nostop Catch signal in gdb and break. + print/noprint Print message when gdb catches signal. + pass/nopass Pass signal down to debugee. + + catch signal + Create a catchpoint for . +``` + +## Multi-threading +```markdown +info thread + List all threads. + +thread apply [] + Run command on all threads listed by (space separated list). + When 'all' is specified as the is run on all threads. + +thread name + The for the current thread. +``` + +## Multi-process +```markdown + set follow-fork-mode + Specify which process to follow when debuggee makes a fork(2) + syscall. + + set detach-on-fork + Turn on/off detaching from new child processes (on by default). + Turning this off allows to debug multiple processes (inferiors) with + one gdb session. + + info inferiors + List all processes gdb debugs. + + inferior + Switch to inferior with . +``` + +## Scheduling +```markdown + set schedule-multiple + on: Resume all threads of all processes (inferiors) when continuing + or stepping. + off: (default) Resume only threads of current process (inferior). +``` + +## Shell commands +```markdown + shell + Run the shell_cmd and print the output, can also contain a pipeline. + + pipe | + Evaluate the gdb_cmd and run the shell_cmd which receives the output + of the gdb_cmd via stdin. +``` + +## Source file locations +```markdown + dir + Add to the beginning of the searh path for source files. + + show dir + Show current search path. + + set substitute-path + Add substitution rule checked during source file lookup. + + show substitute-path + Show current substitution rules. +``` + +## Configuration + +```markdown + set disassembly-flavor + Set the disassembly style "flavor". + + set pagination + Turn on/off gdb's pagination. + + set breakpoint pending + on: always set pending breakpoints. + off: error when trying to set pending breakpoints. + auto: interatively query user to set breakpoint. + + set print pretty + Turn on/off pertty printing of structures. + + set style enabled + Turn on/off styling (eg colored output). + + set logging + Enable output logging to file (default gdb.txt). + + set logging file + Change output log file to + + set logging redirect + on: only log to file. + off: log to file and tty. + + set logging overwrite + on: Truncate log file on each run. + off: Append to logfile (default). + + set history filename + Change file where to save and restore command history to and from. + + set history + Enable or disable saving of command history. +``` +> Logging options should be configured before logging is turned on. + +# Text user interface (TUI) +```markdown + C-x a Toggle UI. + C-l Redraw UI (curses UI can be messed up after the debugee prints to + stdout/stderr). + C-x o Change focus. +``` + +# User commands (macros) + +Gdb allows to create & document user commands as follows: +```markdown + define + # cmds + end + + document + # docu + end +``` + +To get all user commands or documentations one can use: +```markdown + help user-defined + help +``` + +# Hooks + +Gdb allows to create two types of command `hooks` +- `hook-` will be run before `` +- `hookpost-` will be run after `` +```markdown + define hook- + # cmds + end + + define hookpost- + # cmds + end +``` + +# Examples + +## Automatically print next instr +When ever the debugee stops automatically print the memory at the current +instruction pointer (`$rip` x86) and format as instruction `/i`. +```markdown + # rip - x86 + display /i $rip + + # step instruction, after the step the next instruction is automatically printed + si +``` + +## Conditional breakpoints +Create conditional breakpoints for a function `void foo(int i)` in the debugee. +```markdown + # Create conditional breakpoint + b foo if i == 42 + + b foo # would create bp 2 + # Make existing breakpoint conditional + cond 2 i == 7 +``` + +## Set breakpoint on all threads except one +Create conditional breakpoint using the `$_thread` [convenience +variable][gdb-convenience-vars]. +```markdown + # Create conditional breakpoint on all threads except thread 12. + b foo if $_thread != 12 +``` + +## Catch SIGSEGV and execute commands +This creates a `catchpoint` for the `SIGSEGV` signal and attached the `command` +to it. +```markdown + catch signal SIGSEGV + command + bt + c + end +``` + +## Run `backtrace` on thread 1 (batch mode) +```markdown + gdb --batch -ex 'thread 1' -ex 'bt' -p +``` + +## Script gdb for automating debugging sessions +To script gdb add commands into a file and pass it to gdb via `-x`. +For example create `run.gdb`: +```markdown + set pagination off + + break mmap + command + info reg rdi rsi rdx + bt + c + end + + #initial drop + c +``` +This script can be used as: +```markdown + gdb --batch -x ./run.gdb -p +``` + +## Hook to automatically save breakpoints on `quit` +```markdown +define break-save + save breakpoint $arg0.gdb.bp +end +define break-load + source $arg0.gdb.bp +end + +define hook-quit + break-save quit +end +``` + +## Watchpoint on struct / class member +A symbolic watchpoint defined on a member variable for debugging is only valid +as long as the expression is in scope. Once out of scope the watchpoint gets +deleted. + +When debugging some memory corruption we want to keep the watchpoint even the +expression goes out of scope to find the location that overrides the variable +and introduces the corruption. + +```markdown +(gdb) l +1 struct S { int v; }; +2 +3 void set(struct S* s, int v) { +4 s->v = v; +5 } +6 +7 int main() { +8 struct S s; +9 set(&s, 1); +10 set(&s, 2); +11 set(&s, 3); +... + +(gdb) s +set (s=0x7fffffffe594, v=1) at test.c:4 +4 s->v = v; + +# Define a new watchpoint on the member of the struct. The expression however +# is only valid in the current functions scope. + +(gdb) watch s->v +Hardware watchpoint 2: s->v + +(gdb) c +Hardware watchpoint 2: s->v +Old value = 0 +New value = 1 +set (s=0x7fffffffe594, v=1) at test.c:5 +5 } + +# The watchpoint gets deleted as soon as we leave the function scope. + +(gdb) c +Watchpoint 2 deleted because the program has left the block in +which its expression is valid. +main () at test.c:10 +10 set(&s, 2); + +# Define the watchpoint on the location of the object to watch. + +(gdb) watch -l s->v + +# This is equivalent to the following. + +(gdb) p &s->v +$1 = (int *) 0x7fffffffe594 + +# Define a watchpoint to the address of the member variable of the s instance. +# This of course only makes sense as long as the s instance is not moved in memory. + +(gdb) watch *0x7fffffffe594 +Hardware watchpoint 3: *0x7fffffffe594 + +(gdb) c +Hardware watchpoint 3: *0x7fffffffe594 +Old value = 1 +New value = 2 +set (s=0x7fffffffe594, v=2) at test.c:5 +5 } + +(gdb) c +Hardware watchpoint 3: *0x7fffffffe594 +Old value = 2 +New value = 3 +set (s=0x7fffffffe594, v=3) at test.c:5 +5 } +``` + +## Shell commands +```markdown +# Run shell commands. + +(gdb) shell zcat /proc/config.gz | grep CONFIG_KVM= +CONFIG_KVM=m + +# Pipe gdb command to shell command. + +(gdb) pipe info proc mapping | grep libc + 0x7ffff7a1a000 0x7ffff7a42000 0x28000 0x0 r--p /usr/lib/libc.so.6 + 0x7ffff7a42000 0x7ffff7b9d000 0x15b000 0x28000 r-xp /usr/lib/libc.so.6 + 0x7ffff7b9d000 0x7ffff7bf2000 0x55000 0x183000 r--p /usr/lib/libc.so.6 + 0x7ffff7bf2000 0x7ffff7bf6000 0x4000 0x1d7000 r--p /usr/lib/libc.so.6 + 0x7ffff7bf6000 0x7ffff7bf8000 0x2000 0x1db000 rw-p /usr/lib/libc.so.6 +``` + +# Know Bugs + +## Workaround `command + finish` bug +When using `finish` inside a `command` block, commands after `finish` are not +executed. To workaround that bug one can create a wrapper function which calls +`finish`. +```markdown + define handler + bt + finish + info reg rax + end + + command + handler + end +``` + +[gdb-convenience-vars]: https://sourceware.org/gdb/onlinedocs/gdb/Convenience-Vars.html#Convenience-Vars diff --git a/src/debug/gdbserver.md b/src/debug/gdbserver.md new file mode 100644 index 0000000..203846d --- /dev/null +++ b/src/debug/gdbserver.md @@ -0,0 +1,33 @@ +# gdbserver(1) + +# CLI + +```markdown + gdbserver [opts] comm prog [args] + opts: + --disable-randomization + --no-disable-randomization + --wrapper W -- + + comm: + host:port + tty +``` + +## Example + +```markdown +# Start gdbserver. +gdbserver localhost:1234 /bin/ls + +# Attach gdb. +gdb -ex 'target remote localhost:1234' +``` + +## Wrapper example: Set environment variables just for the debugee +Set `env` as execution wrapper with some variables. +The wrapper will be executed before the debugee. + +```markdown +gdbserver --wrapper env FOO=123 BAR=321 -- :12345 /bin/ls +``` -- cgit v1.2.3