rr-debugger

发布时间 2023-08-16 15:40:50作者: sinferwu

 

rr-debugger/rr: Record and Replay Framework (github.com)

 

Debug C and C++ programs with rr | Red Hat Developer

 

rr来debug你的C/C++程序(Linux)_rr gdb_pd很不专业的博客-CSDN博客

CPlusPlusThings/tool/用rr来进行debug.md at master · Light-City/CPlusPlusThings (github.com)

 

rr(debugging) 的配置与基本使用 (smartkeyerror.com)

 

rr: lightweight recording & deterministic debugging (rr-project.org)

 

what rr does

rr aspires to be your primary C/C++ debugging tool for Linux, replacing — well, enhancing — gdb. You record a failure once, then debug the recording, deterministically, as many times as you want. The same execution is replayed every time.

rr also provides efficient reverse execution under gdb. Set breakpoints and data watchpoints and quickly reverse-execute to where they were hit.

rr works on real applications and is used by many developers to fix real bugs. It makes debugging hard bugs much easier, but also speeds up debugging of easy bugs.

rr features:

  • Low overhead compared to other similar tools, especially on mostly-single-threaded workloads
  • Supports recording and replay of all kinds of applications: Firefox, Chrome, QEMU, LibreOffice, Go programs, ...
  • Record, replay and debug multiple-process workloads, including entire containers
  • Works with gdb scripting and IDE integration
  • Durablecompact traces that can be ported between machines
  • Chaos mode to make intermittent bugs more reproducible

the rr debugging experience

 

Start by using rr to record your application:

$ rr record /your/application --args
...
FAIL: oh no!

The entire execution, including the failure, was saved to disk. That recording can now be debugged.

$ rr replay
GNU gdb (GDB) ...
...
0x4cee2050 in _start () from /lib/ld-linux.so.2
(gdb)

Remember, you're debugging the recorded trace deterministically; not a live, nondeterministic execution. The replayed execution's address spaces, register contents, syscall data etc are exactly the same in every run.

Most of the common gdb commands can be used.

(gdb) break mozilla::dom::HTMLMediaElement::HTMLMediaElement
...
(gdb) continue
Continuing.
...
Breakpoint 1, mozilla::dom::HTMLMediaElement::HTMLMediaElement (this=0x61362f70, aNodeInfo=...)
...

If you need to restart the debugging session, for example because you missed breaking on some critical execution point, no problem. Just use gdb's command to restart replay. run

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
...
Breakpoint 1, mozilla::dom::HTMLMediaElement::HTMLMediaElement (this=0x61362f70, aNodeInfo=...)
...
(gdb) 

The command started another replay run of your recording from the beginning. But after the session restarted, the same execution was replayed again. And all your debugging state was preserved across the restart. run

Note that the pointer of the dynamically-allocated object was the same in both replay sessions. Memory allocations are exactly the same in each replay, meaning you can hard-code addresses you want to watch. this

Even more powerful is reverse execution. Suppose we're debugging Firefox layout:

Breakpoint 1, nsCanvasFrame::BuildDisplayList (this=0x2aaadd7dbeb0, aBuilder=0x7fffffffaaa0, aDirtyRect=..., aLists=...)
    at /home/roc/mozilla-inbound/layout/generic/nsCanvasFrame.cpp:460
460   if (GetPrevInFlow()) {
(gdp) p mRect.width
12000

We happen to know that that value is wrong. We want to find out where it was set. rr makes that quick and easy. This combination of hardware data watchpoints with reverse execution is extremely powerful!

(gdb) watch -l mRect.width
(gdb) reverse-cont
Continuing.
Hardware watchpoint 2: -location mRect.width
Old value = 12000
New value = 11220
0x00002aaab100c0fd in nsIFrame::SetRect (this=0x2aaadd7dbeb0, aRect=...)
    at /home/roc/mozilla-inbound/layout/base/../generic/nsIFrame.h:718
718       mRect = aRect;