GDB 反向調試(Reverse Debugging)
使用調試器時最常用的功能就是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程序:
int main(int argc, const char* argv[])
{
int a = 0;
a = 1;
a = 2;
return 0;
}
將它編譯並加上調試符號:
gcc -Wall -g a.c
開始調試:
gdb a.out
查看一下源代碼:
(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 }
接下來設置一個斷點在第三行:
```sh
(gdb) b 3
Breakpoint 1 at 0x804839a: file a.c, line 3.
運行,程序會在第三行的地方停下來:
(gdb) r
Starting program: /home/cheryl/a.out
Breakpoint 1, main (argc=1, argv=0xbffff3e4) at a.c:3
3 int a = 0;
給變量a設置監視點方便我們觀察:
(gdb) watch a
Hardware watchpoint 2: a
啟動進程記錄回放:
(gdb) record
現在每運行一步調試器都會記錄下變化,以便回溯。我們連續執行3條語句。
(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;
可以看到,a的值先是從0變為了1,然後變為2,如果想讓程序倒退回到以前的狀態怎麼辦?可以用reverse-next命令:
(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)
這樣程序就倒退到了我們啟動進程記錄回放的地方,a的值經過兩步回到了最初的狀態。 若需要關閉進程記錄回放,可以使用record stop:
(gdb) record stop
Process record is stoped and all execution log is deleted.