5. Linux系统 RR(Record and Replay)工具重现Linux系统崩溃的调用栈
在 Linux 开发中,调试复杂程序尤其是多线程程序时,复现 Bug 往往非常困难。RR(Record and Replay)是一款由 Mozilla 开发的 用户态程序记录与回放工具,可以精确记录程序执行轨迹,并在回放时可在 gdb 中进行调试,使调试变得可重复和精确。
一、RR 是什么
RR 是一个 轻量级的用户态动态二进制插桩工具,主要功能:
记录(Record)在程序运行时记录指令执行、系统调用、线程调度顺序等信息。
回放(Replay)可以在任意时间重复回放程序执行,保证线程调度和指令执行一致,使调试非确定性 Bug(如竞态条件)变得可复现。
和GDB 一起使用通过 RR 的回放机制,可在 gdb 中精准调试程序,设置断点、观察变量和调用栈,无需担心线程调度导致的不可复现问题。
RR 的核心特点:
二、RR 安装
RR 在 Linux 上有官方支持(主要是 Ubuntu/Debian),安装方式如下:
sudo apt updatesudo apt install rr -y
git clone https://github.com/mozilla/rr.gitcd rrcmake -G "Unix Makefiles" .makesudo make install
安装完成后可验证:
三、RR 的基本使用
1. 记录程序执行
2. 回放程序
3. 命令行调试
rr replay(gdb) b foo(gdb) c
(gdb) reverse-step(gdb) reverse-next
4. 调试多线程程序
RR 会记录所有线程调度顺序,并在回放时保证一致,因此即使是竞态条件,也可以稳定复现。
四、RR 实战案例
1. 复现多线程竞态 Bug
假设有一个程序 race_test.c:
#include<stdio.h>#include<pthread.h>int counter = 0;void* thread_func(void* arg){ for(int i=0; i<100000; i++) counter++; return NULL;}intmain(){ pthread_t t1, t2; pthread_create(&t1, NULL, thread_func, NULL); pthread_create(&t2, NULL, thread_func, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); printf("Counter = %d\n", counter); return 0;}
这个程序在不同运行中可能输出不同结果(竞态条件)。
使用 RR 记录:
回放调试:
rr replay(gdb) b main(gdb) c
通过反向调试(reverse-step)可以精确定位哪条指令导致 counter 写入冲突,从而定位竞态条件。
2. 调试崩溃
当程序随机崩溃时:
rr record ./crash_programrr replay
五、RR 使用技巧
只记录指定线程或程序
rr record --threads=1 ./program
保存历史记录
与 gdb 高级功能结合
六、RR 局限性
仅支持 x86_64 Linux不支持 Windows 或 macOS
性能开销记录模式会比原程序慢 2~10 倍(取决于程序复杂度)
内核依赖某些系统调用行为在 RR 中有特定限制,需要最新版内核支持
大型程序记录空间消耗大对长时间运行或大程序,记录文件可能很大,需要做好磁盘规划
七、总结
RR 是调试多线程、异步或随机崩溃程序的利器,通过记录与回放机制:
精确复现 Bug
支持反向调试
集成 GDB 调试功能
保证程序执行可重复性
结合 Valgrind、ltrace 等工具,作为资深工程师的你可以实现从内存错误、库函数调用到线程竞态问题的全方位分析。
还有许多使用方式见man手册: