rr with rust
2022-07-30 ยท 3 min read
github: https://github.com/rr-debugger/rr site: https://rr-project.org/
what #
- rr is a lightweight tool for recording, replaying, and debugging applications.
- rr records deterministic traces of the entire program execution (including all child processes and spawned threads), which can be replayed many times or even run in reverse.
- rr models a single-threaded machine. It creates a deterministic trace by intercepting and recording all Linux syscalls for later replay. rr also controls the thread and process scheduling so we can even determinstically replay concurrent programs.
why #
- you have a flaky concurrency bug that only manifests occasionally. - ==> use rr to record 1000s of execution traces (also try --chaosmode!) until a lucky one finally triggers the bug. Later, replay the failing trace as many times as you please.
 
- ==> use rr to record 1000s of execution traces (also try 
- if you're like me, you're terrible at setting breakpoints. - ==> with rr you can just replay the same exact execution with better breakpoints; no state changing under your feet between runs.
 
- you have a backtrace but the offending code isn't in any of the backtrace frames - ==> just execute the program backwards until you hit the problem.
 
- your fuzzer sometimes finds a bug after 10 hr, but when you run again the bug ain't there - ==> run your fuzzers inside rr. when the fuzzer hits a bug, you can easily replay it.
 
Better yet, use rr as a general purpose gdb enhancement : )
requirements #
- Linux kernel >= 3.11 - Works inside a VM if the VM supports virtualization of hardware perf counters. (incl. VMware and KVM; does not incl. Xen).
 
- One of: - Intel CPU with Nehalem (2010) or later
- Certain AMD Zen or later https://github.com/rr-debugger/rr/wiki/Zen
- Certain AArch64 archs (includes Apple Silicon M-series)
 
setup #
$ sudo apt install rr
You will also need gdb installed, since rr replay is "just" a wrapper around gdb.
$ sudo apt install gdb
When debugging rust code, there are a few extra command flags that rr needs. Tests are also slightly more annoying to debug, since cargo runs your test binary in a sub-process. The cargo rr tool makes the debugging process painless.
$ cargo install cargo-rr
record a trace for deterministic replay #
# Record a test
$ cargo rr test my_failing_test
# Record a binary
$ cargo rr run --bin=foo -- --arg=bar
NOTE: if you get an error message like rr needs /proc/sys/kernel/perf_event_paranoid <= 1, but it is 2. then try:
$ echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid
replay last trace #
$ cargo rr replay
If you prefer a more visual debugging experience and hate the letter l, try the TUI debugger:
(rr) <CTRL-X a>
# if that doesn't work, try
(rr) tui enable
See: gdb ref > TUI keybindings not working
debugging #
Debugging with rr looks the same as debugging with gdb, except you have a few extra commands for executing backwards.
(rr) help reverse-continue
reverse-continue, rc
Continue program being debugged but run it in reverse.
If proceeding from breakpoint, a number N may be used as an argument,
which means to set the ignore count of that breakpoint to N - 1 (so that
the breakpoint won't break until the Nth time it is reached).
(rr) help reverse-step
reverse-step, rs
Step program backward until it reaches the beginning of another source line.
Argument N means do this N times (or till program stops for another reason).
(rr) help reverse-next
reverse-next, rn
Step program backward, proceeding through subroutine calls.
Like the "reverse-step" command as long as subroutine calls do not happen;
when they do, the call is treated as one instruction.
Argument N means do this N times (or till program stops for another reason).
...
(rr) help r<TAB>
rbreak                    return                    rr-history-push
rc                        reverse-continue          rr-hook-run
record                    reverse-finish            rr-set-suppress-run-hook
refresh                   reverse-next              rr-where
remote                    reverse-nexti             rsi
remove-inferiors          reverse-search            run
remove-symbol-file        reverse-step              running
restart                   reverse-stepi             rwatch
restore                   rni