1、什么是反向调试
反向调试是一种高级调试技术,可以让程序已经执行了一段时间后,回退到过去的状态并重新执行。这意味着你可以回到程序执行中的任何点,查看变量的值、堆栈跟踪以及程序执行路径。反向调试可以让我们快速、准确地定位出程序中的错误或异常的根本原因。
简单来说,就是一种可以让程序逻辑逆序执行的调试技术。通过它,你可以随时中断程序的正常执行,然后逆序执行,让程序回到过去,并可以查看任意时间点的任意信息。
2、reverse指令
- reverse-next(rc): 参考next(n), 逆向执行一行代码,遇函数调用不进入
- reverse-nexti(rni): 参考nexti(ni), 逆向执行一条指令,与函数调用不进入
- reverse-step(rs): 参考step(s), 逆向执行一行代码,遇函数调用则进入
- reverse-stepi(rsi): 参考setpi(si), 逆向执行一条指令,与函数调用则进入
- reverse-continue(rc): 参考continue(c), 逆向继续执行
- reverse-finish: 参考finish,逆向执行,一直到函数入口处
- reverse-search(): 参考search,逆向搜索
- set exec-direction reverse: 设置程序逆向执行,执行完此命令后,所有常用命令如next, nexti, step, stepi, continue、finish等全部都变成逆向执行
- set exec-direction forward: 设置程序正向执行,这也是默认的设置
3、record指令
- record: 记录程序执行过程中所有状态信息
- record stop: 停止记录状态信息
- record goto: 让程序跳转到指定的位置, 如record goto start、record goto end、record goto n
- record save filename: 把程序执行历史状态信息保存到文件,默认名字是gdb_record.process_id
- record restore filename: 从历史记录文件中恢复状态信息
- show record full insn-number-max:查看可以记录执行状态信息的最大指令个数,默认是200000
- set record full insn-number-max limit:设置可以记录执行状态信息的最大指令个数
- set record full insn-number-max unlimited:记录所有指令的执行状态信息
3、实战
首先准备c++代码,以下操作都在centos7系统上进行,尝试了下windows不支持反向调试,也许是我没找到方法;
1、调试代码
main.cpp文件内容如下
#include <iostream>
int getAge(){
int count=0;
count ++;
std::cout <<"getAge function" << std::endl;
return 1;
}
int main() {
std::cout << "Hello, World! yeindong" << std::endl;
std::cout << "getAge:"<<getAge() << std::endl;
return 0;
}
2、打包
g++ ./main.cpp -g -o main_gdb
3、开启gdb调试
gdb main_gdb
4、在第5行打上断点
break 5
5、运行到断点处
run
此时就已经运行到指定位置了,并且停住了
6、record 开始记录程序的执行轨迹
record
7、next 单步执行
next
执行2次next,在打印count的值,会发现已经从0变为1了;
8、reverse-next 回退
这条指令可以回退一步
reverse-next
回退后再打印count的值,会发现已经回到0值了;
9、总览
(gdb) break 5 #第5打上断点
Breakpoint 1 at 0x400825: file ./main.cpp, line 5. # 断点所在位置
(gdb) run # 运行
Starting program: /tmp/main_gdb
Hello, World! yeindong # cout 打印的内容
Breakpoint 1, getAge () at ./main.cpp:5 # 运行到断点处
5 int count=0; # 当前断点所在位置,未执行这行代码
(gdb) record # 开启记录轨迹
(gdb) next # 单步执行
6 count ++; # 当前断点所在位置,未执行这行代码
(gdb) print count # 打印count的值
$1 = 0
(gdb) next # 单步执行
7 std::cout <<"getAge function" << std::endl;# 当前断点所在位置,未执行这行代码
(gdb) print count # 打印count的值
$2 = 1
(gdb) reverse-next # 回退一步
6 count ++; # 当前断点所在位置,未执行这行代码
(gdb) print count # 打印count的值
$3 = 0