GDB 反向调试(Reverse Debugging)

    技术2022-06-09  71

    使用调试器时最常用的功能就是step, next, continue,这几个调试命令都是“往下执行”的, 但是很多时候会有这种需求:你在调试的过程中多跳过了几步而错过中间过程,这时候不得不重头调试一遍,非常麻烦。而GDB从7.0版本开始支持反向调试功能,也就是允许你倒退着运行程序,或者说撤销程序执行的步骤从而会到以前的状态。 直观地来看,加入你正在使用GDB7.0以上版本的调试器并且运行在支持反向调试的平台,你就可以用以下几条命令来调试程序: reverse-continue 反向运行程序知道遇到一个能使程序中断的事件(比如断点,观察点,异常)。 reverse-step 反向运行程序到上一次被执行的源代码行。 reverse-stepi 反向运行程序到上一条机器指令 reverse-next 反向运行到上一次被执行的源代码行,但是不进入函数。 reverse-nexti 反向运行到上一条机器指令,除非这条指令用来返回一个函数调用、整个函数将会被反向执行。 reverse-finish 反向运行程序回到调用当前函数的地方。 set exec-direction [forward | reverse] 设置程序运行方向,可以用平常的命令step和continue等来执行反向的调试命令。 上面的反向运行也可以理解为撤销后面运行的语句所产生的效果,回到以前的状态。 好的,接下来我们来试试看如何反向调试。 首先确认自己的平台支持进程记录回放(Process Record and Replay),当在调试器启用进程记录回放功能时,调试器会记录下子进程,也就是被调试进程的每一步的运行状态与上一步运行状态的差异,需要撤销的时候就可以很方便回到上一步。 假设我们有以下C程序: view plaincopy to clipboardprint?int main(int argc, const char *argv[])   {     int a = 0;     a = 1;     a = 2;     return 0;   }  int main(int argc, const char *argv[]){  int a = 0;  a = 1;  a = 2;  return 0;} 将它编译并加上调试符号: view plaincopy to clipboardprint?$ gcc -Wall -g a.c  $ gcc -Wall -g a.c 开始调试: view plaincopy to clipboardprint?$ gdb a.out  $ gdb a.out 查看一下源代码: view plaincopy to clipboardprint?(gdb) l   1   int main(int argc, const char *argv[])   2   {   3     int a = 0;   4     a = 1;   5     a = 2;   6     return 0;   7   }  (gdb) l1 int main(int argc, const char *argv[])2 {3   int a = 0;4   a = 1;5   a = 2;6   return 0;7 } 接下来设置一个断点在第三行: view plaincopy to clipboardprint?(gdb) b 3  Breakpoint 1 at 0x804839a: file a.c, line 3.  (gdb) b 3Breakpoint 1 at 0x804839a: file a.c, line 3. 运行,程序会在第三行的地方停下来: view plaincopy to clipboardprint?(gdb) r   Starting program: /home/cheryl/a.out    Breakpoint 1, main (argc=1, argv=0xbffff3e4) at a.c:3  3     int a = 0;  (gdb) rStarting program: /home/cheryl/a.out Breakpoint 1, main (argc=1, argv=0xbffff3e4) at a.c:33   int a = 0; 给变量a设置监视点方便我们观察: view plaincopy to clipboardprint?(gdb) watch a   Hardware watchpoint 2: a  (gdb) watch aHardware watchpoint 2: a 启动进程记录回放: view plaincopy to clipboardprint?(gdb) record  (gdb) record 现在每运行一步调试器都会记录下变化,以便回溯。我们连续执行3条语句。 view plaincopy to clipboardprint?(gdb) n   4     a = 1;   (gdb)    Hardware watchpoint 2: a   Old value = 0  New value = 1  main (argc=1, argv=0xbffff3e4) at a.c:5  5     a = 2;   (gdb)    Hardware watchpoint 2: a   Old value = 1  New value = 2  main (argc=1, argv=0xbffff3e4) at a.c:6  6     return 0;  (gdb) n4   a = 1;(gdb) Hardware watchpoint 2: aOld value = 0New value = 1main (argc=1, argv=0xbffff3e4) at a.c:55   a = 2;(gdb) Hardware watchpoint 2: aOld value = 1New value = 2main (argc=1, argv=0xbffff3e4) at a.c:66   return 0; 可以看到,a的值先是从0变为了1,然后变为2,如果想让程序倒退回到以前的状态怎么办?可以用reverse-next命令: view plaincopy to clipboardprint?(gdb) reverse-next   Hardware watchpoint 2: a   Old value = 2  New value = 1  main (argc=1, argv=0xbffff3e4) at a.c:5  5     a = 2;   (gdb)    Hardware watchpoint 2: a   Old value = 1  New value = 0  main (argc=1, argv=0xbffff3e4) at a.c:4  4     a = 1;   (gdb)    No more reverse-execution history.   main (argc=1, argv=0xbffff3e4) at a.c:3  3     int a = 0;   (gdb)   (gdb) reverse-nextHardware watchpoint 2: aOld value = 2New value = 1main (argc=1, argv=0xbffff3e4) at a.c:55   a = 2;(gdb) Hardware watchpoint 2: aOld value = 1New value = 0main (argc=1, argv=0xbffff3e4) at a.c:44   a = 1;(gdb) No more reverse-execution history.main (argc=1, argv=0xbffff3e4) at a.c:33   int a = 0;(gdb)  这样程序就倒退到了我们启动进程记录回放的地方,a的值经过两步回到了最初的状态。 若需要关闭进程记录回放,可以使用record stop: view plaincopy to clipboardprint?(gdb) record stop   Process record is stoped and all execution log is deleted.


    最新回复(0)