GDB高级技巧—反向调试,让代码回退的方法

发布时间:2023-09-18 22:33:15 作者:yexindonglai@163.com 阅读(2012)

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文件内容如下

  1. #include <iostream>
  2. int getAge(){
  3. int count=0;
  4. count ++;
  5. std::cout <<"getAge function" << std::endl;
  6. return 1;
  7. }
  8. int main() {
  9. std::cout << "Hello, World! yeindong" << std::endl;
  10. std::cout << "getAge:"<<getAge() << std::endl;
  11. return 0;
  12. }
2、打包
  1. g++ ./main.cpp -g -o main_gdb
3、开启gdb调试
  1. gdb main_gdb
4、在第5行打上断点
  1. break 5

5、运行到断点处
  1. run

此时就已经运行到指定位置了,并且停住了

6、record 开始记录程序的执行轨迹
  1. record
7、next 单步执行
  1. next

执行2次next,在打印count的值,会发现已经从0变为1了;

8、reverse-next 回退

这条指令可以回退一步

  1. reverse-next

回退后再打印count的值,会发现已经回到0值了;

9、总览
  1. (gdb) break 5 #第5打上断点
  2. Breakpoint 1 at 0x400825: file ./main.cpp, line 5. # 断点所在位置
  3. (gdb) run # 运行
  4. Starting program: /tmp/main_gdb
  5. Hello, World! yeindong # cout 打印的内容
  6. Breakpoint 1, getAge () at ./main.cpp:5 # 运行到断点处
  7. 5 int count=0; # 当前断点所在位置,未执行这行代码
  8. (gdb) record # 开启记录轨迹
  9. (gdb) next # 单步执行
  10. 6 count ++; # 当前断点所在位置,未执行这行代码
  11. (gdb) print count # 打印count的值
  12. $1 = 0
  13. (gdb) next # 单步执行
  14. 7 std::cout <<"getAge function" << std::endl;# 当前断点所在位置,未执行这行代码
  15. (gdb) print count # 打印count的值
  16. $2 = 1
  17. (gdb) reverse-next # 回退一步
  18. 6 count ++; # 当前断点所在位置,未执行这行代码
  19. (gdb) print count # 打印count的值
  20. $3 = 0

关键字c++