反向执行时Watchpoint失效的原因及解决方法咨询
GDB反向调试中Watchpoint未触发的问题分析与解决
调试场景
- 创建起始断点A和结束断点B
- 启动
record记录执行过程,继续程序运行 - 程序到达断点B
- 设置watchpoint监视目标内存的写入操作(目标内存地址仅在此阶段可确定)
- 执行
reverse-continue,期望watchpoint触发并停在内存写入的位置
示例代码
// main.c int main(void) { int num; num = 5; return 0; }
调试会话
$ cc main.c $ gdb -q -nx -ex 'set disassembly-flavor intel' ./a.out Reading symbols from ./a.out... (No debugging symbols found in ./a.out) (gdb) b *main + 0 Breakpoint 1 at 0x1129 (gdb) disas main Dump of assembler code for function main: 0x0000000000001129 <+0>: push rbp 0x000000000000112a <+1>: mov rbp,rsp 0x000000000000112d <+4>: mov DWORD PTR [rbp-0x4],0x5 0x0000000000001134 <+11>: mov eax,0x0 0x0000000000001139 <+16>: pop rbp 0x000000000000113a <+17>: ret End of assembler dump. (gdb) b *main + 16 Breakpoint 2 at 0x1139 (gdb) r Starting program: /var/tmp/test/a.out [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Breakpoint 1, 0x0000555555555129 in main () (gdb) record (gdb) c Continuing. Breakpoint 2, 0x0000555555555139 in main () (gdb) p/x $rbp-0x4 $1 = 0x7fffffffe63c (gdb) watch *(int*)0x7fffffffe63c Hardware watchpoint 3: *(int*)0x7fffffffe63c (gdb) reverse-continue Continuing. No more reverse-execution history. 0x0000555555555129 in main () (gdb)
问题现象
反向执行未在预期的*main+4处(即内存写入操作发生的位置)停止,而是直接回到了record记录的起始点,完全忽略了之前发生的内存写入操作。
原因分析
GDB的record功能在记录执行历史时,只会记录指令流和内存状态变化,不会为后续设置的watchpoint回溯标记触发事件。你是在到达断点B后才设置的watchpoint,而此时从断点A到B的执行历史已经记录完成,这段历史中的内存写入操作没有被关联到新设置的watchpoint上。反向调试时,GDB只会检查watchpoint设置之后产生的新执行记录,不会扫描已存在的历史来匹配watchpoint的触发条件。
解决方法
方法1:提前在记录启动前设置watchpoint(适配地址可提前确定的场景)
如果能在启动record前确定目标内存的地址表达式(比如基于寄存器的相对地址),可以提前设置watchpoint:
- 在断点A(
*main+0)处启动程序后,执行stepi到*main+1(此时rbp已完成初始化) - 设置watchpoint:
watch *(int*)($rbp-0x4) - 启动
record,再继续执行到断点B - 执行
reverse-continue,此时会触发watchpoint并停在*main+4处
方法2:重置执行记录(适配地址仅在断点B处可知的场景)
如果目标内存地址只有到达断点B才能确定,可通过重置记录来关联watchpoint:
- 到达断点B后,先执行
record stop停止当前记录 - 执行
reverse-continue回到断点A - 执行
stepi到*main+1,设置watchpoint:watch *(int*)($rbp-0x4)(栈变量地址可能变化,需重新基于寄存器确定) - 重新启动
record,然后继续执行到断点B - 执行
reverse-continue,即可触发watchpoint停在内存写入位置
补充说明
这个场景的核心是:watchpoint需要和record记录的执行过程绑定,要么在记录开始前设置,要么在记录过程中设置,才能在反向调试时被正确检测到。
内容的提问来源于stack exchange,提问作者mathway
相关产品推荐
相关产品推荐

