1 unstable release
0.1.0 | Sep 25, 2024 |
---|
#655 in Development tools
50 downloads per month
22KB
290 lines
Breakpoints when the debugger is attached
Set breakpoints with the breakpoint!()
macro on many target architectures
and popular OSes like FreeBSD, macOS, iOS, Linux distro's, Windows without
using the nightly toolchain. Break into the debugger with an easy
breakpoint_if_debugging()
call, too!
Well, sure, but why?
- It might be more convinient to add the call to
breakpoint_if_debugging
from inside the comfort of your editor than to remember the incantion in the debugger, - Some callsites like lambdas and async routines/coroutines can be tricky to set a breakpoint to in the debugger due to name mangling or because the toolchain doesn't give them a name that is easily-discovered/human-friendly,
- Can add this to your
#[panic_handler]
to break into the debugger on a panic.
This model might be reminiscent of "semihosting" where the execution environment includes a host or a debugger who's services might be requested by the program.
Here is the example of how one can make use of this: runme.rs
.
Do exercise extreme caution when using any of this in the production environment, i.e.
out of the inner development loop. Heisenbugs and crashes might be sighted.
Platform- and target-specific notes follow.
Windows
The library provides breakpoint_if_debugging()
and breakpoint_if_debugging_seh()
The latter might be useful to detect the debugger if it is trying to hide its presence
via some cheap tricks.
Linux, macOS and FreeBSD
The debugger detection logic will detect any tracer like strace
as the debugger, and
if the tracer isn't able to skip over the breakpoint CPU instruction, the program will
crash. That can be fixed by handling SIGTRAP
inside your program.
arm64
brk #imm16
is used for breakpoint on arm64.
Just FYI, the #imm16
value can be inside the Linux kernel 6.1
at the time of writing:
0x004
: for installing kprobes0x005
: for installing uprobes0x006
: for kprobe software single-step0x400
-0x7ff
: kgdb0x100
: for triggering a fault on purpose (reserved)0x400
: for dynamic BRK instruction0x401
: for compile time BRK instruction0x800
: kernel-mode BUG() and WARN() traps0x9xx
: tag-based KASAN trap (allowed values 0x900 - 0x9ff)0x8xxx
: Control-Flow Integrity traps
Here, we're talking the user mode yet the above illustrates the point
that the value supplied after brk
influences what to expect.
For __builtin_trap()
, gcc
produces brk #0x3e8
, clang
generates brk #1
.
This library uses 0xf000
as the debuggers on Windows and macOS skip over the debug
trap automatically in this case by advancing the instruction pointer behind the
curtain.
See also
- C++'s "Debugging Support" paper.
Dependencies
~44KB