Debug in Linux
Tool list
performance profiling: perf trace, ftrace, strace, lstrace
Two main classes of debugging tool today:
checker (static and dynamic)
did my code do bad thing x, y, z?
Examples: Address Sanitizer, Valgrind, Converity
Debuggers
what exactly did my code do?
Examples: GDG, LLDB, rr, UndoDB, Live Recorder
GDB:
-ggdb3 is better than -g
1 | 编译debug info |
GDB TUI(Test User Interface) top tips
1 | quick shortcut |
1 | gdb program |
using python in gdb
gdb invoke python interpret, but library need be installed in target system. gdb need to find it.
1 | the gdb python module gives most access to gdb |
In-built pretty printers for STL
1 | this relies on Python pretty printers installed on the target system |
.gdbinit
Hint: have a project gdbinit with lots of stuff in it, and source that
1 | set history save on |
gdb is built atop ptrace and signals
when a program being traced receives a signal, it is suspends and the tracer gets notified(via waitpid).
So when the inferior receives a signal, it stop and gdb gets control.
Usually gdb return to the prompt, but what it will do depends on the signal and how it is configured.
Two signals are special:
SIGINT is generated when you hit ^C
SIGTRAP is generated when the inferior hits a breakpoint or is single stepped.
Actually, not so special, - these signals are treated no differently to any others.
1 | set pagination on |
Breakpoints and watchpoints
1 | stop when foo is modified |
thread apply
1 | info threads |
Dynamic Printf
use dprintf
to put printf’s in your code without recompiling, e.g.
1 | dprintf mutex_lock, "m is %p m->magic is %u\n", m, m->magic |
control how the printfs hapen:
1 | set dprintf-style gdb|call|agent |
calling
call
foo() will call foo in your inferior
1 | call strcpy(buffer, "hello, world!\n") |
1 | but beware, `print` may well do too, e.g. |
Catchpoints
Catchpoints are like breakpoints but catch certain events, such as c++ exceptions.
1 | catch catch # to stop when c++ exceptions are caught |
Remote Debugging
1 | Debug over serial/sockets to a remote server |
Multiprocess Debugging
1 | set follow-fork-mode child|parent |
Yet More Python
hook certain kinds of events
1 | def stop_handler(ev): |
[reverse execution](Recording Inferior’s Execution and Replaying It)
1 | > start |
GDB inbuilt reversible debugging: Work well, but is very slow
GDB in-build record btrace
: Uses Intel branch trace.
Not really reversible, no data
Quite slow
rr
: Very good at what it does, though somewhat limited features/platform support
Other cool things…
1 |
|
Valgrind
memcheck is default and the most used/known.
Also there is: cachegrind, callgrind, helgrind, drd, massif, lackey, none
1 | > valgrind ./program |
Sanitizers
AddressSanitizer, MemorySanitizer, ThreadSanitizer, LeakSanitizer
1 | faster and more powerful |
ftrace
“function tracer” - a fast way to trace various kernel functions.
- Lots of pre-defined events(i.e. trace-points)
- Controlled through /sys/kernel/debug/tracing
- Or, use the trace-cmd utility
strace
Trace all the system calls of a process.
1 | strace cmd # Print all system calls issued by cmd |
ltrace
Trace all the dynamic library calls of a process.
1 | ltrace cmd # Print all library calls issued by cmd |
perf trace
Like strace but better(and worse).
1 | perf trace # Trace everything - every syscall by every process |
Better than strace: Much faster; more flexible.
Worse than strace: Needs privileges, doesn’t do as much decoding(e.g. strings look like pointers)
Fortify(加固)
Compile with -D_FORTIFY_SOURCE=1
memcpy, strcpy, et al do bounds checking where they can.
Very low(typically impossible to measure), performance overhead.
nm
1 | You can find out all functions defined (but not necessarily called) in an application with the nm command, e.g. |