在root用戶權限下:html
root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get update ...... ...... ...... root@iZ2zeeailqvwws5dcuivdbZ:~# apt-get install gdb ...... ...... ...... Do you want to continue? [Y/n] y ...... ...... ...... root@iZ2zeeailqvwws5dcuivdbZ:~#
安裝好gdb了。linux
用root權限的Terminal(或通常權限的Terminal)的vi編輯器編寫一個C程序a.c:redis
1 #include <stdio.h> 2 3 int main() 4 { 5 int a = 1; 6 int b = a; 7 8 printf("a = %d, b =%d\n", a, b); 9 10 return 0; 11 }
這個過程經過gcc來完成:ubuntu
gcc –o a a.c -g sass
-o選項的做用是:對命令輸出結果進行導入操做,這裏是把gcc –o a a.c -g的操做結果輸出到文件a(文件名能夠自定義)中進行保存。session
-g選項的做用是:在可執行文件中加入源碼信息,好比:可執行文件中第幾條機器指令對應源代碼的第幾行,但並非把整個源文件都嵌入到可執行文件中,而是在調試時必須保證gdb能找到源文件。編輯器
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gcc -o a a.c -g root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from a...done. (gdb)
以下圖所示:函數
gdb提供一個相似Shell的命令行環境,上面的(gdb)就是提示符,在提示符後面輸入gdb的相應命令就能夠實現其對應的功能。ui
用start命令開始執行程序:spa
(gdb) start Temporary breakpoint 1 at 0x40052e: file a.c, line 5. Starting program: /root/2/02/a Temporary breakpoint 1, main () at a.c:5 5 int a = 1; (gdb)
gdb提示準備執行a.c程序的第六行代碼。而後繼續用(gdb)提示須要輸入的命令。
(gdb) start Temporary breakpoint 1 at 0x40052e: file a.c, line 5. Starting program: /root/2/02/a Temporary breakpoint 1, main () at a.c:5 5 int a = 1; (gdb) n 6 int b = a; (gdb) n 8 printf("a = %d, b = %d\n", a, b); (gdb) n a = 1, b = 1 9 return 0; (gdb) quit A debugging session is active. Inferior 1 [process 22935] will be killed. Quit anyway? (y or n) y root@iZ2zeeailqvwws5dcuivdbZ:~/2/02#
在start命令後,每輸入一個n就可以單步執行一條語句(輸入一個命令後,直接回車表示最近輸入命令的含義)。當程序執行完時,能夠輸入quit命令來退出gdb模式。
[ breakpoint,continue和display ]
(gdb) start Temporary breakpoint 1 at 0x40052e: file a.c, line 5. Starting program: /root/2/02/a Temporary breakpoint 1, main () at a.c:5 5 int a = 1; (gdb) b 8 Breakpoint 2 at 0x40053b: file a.c, line 8. (gdb) c Continuing. Breakpoint 2, main () at a.c:8 8 printf("a = %d, b = %d\n", a, b); (gdb) display b 1: b = 1 (gdb) n a = 1, b = 1 9 return 0; 1: b = 1 (gdb) 10 } 1: b = 1 (gdb) quit root@iZ2zeeailqvwws5dcuivdbZ:~/2/02#
gdb a會進入a可執行程序的gdb模式,start命令就使程序準備運行程序中的第一條語句。b 8是breakpoint 8的簡寫(breakpoint的參數也能夠以是某個函數名,表示在此函數處設置一個斷點),表示在程序第八行設置一個斷點。c是continue的縮寫,表示繼續運行程序,程序會在設置斷點處停下來。displayb表示將b的值顯示出來(undisplay取消對變量的跟蹤),而後再輸入單步調試命令n(next)就可使程序繼續運行。
可見斷點有助於快速跳過沒有問題的代碼,而後在有問題的代碼上慢慢走慢慢分析,「斷點加單步」是使用調試器的基本方法。至於應該在哪裏設置斷點,怎麼知道哪些代碼能夠跳過,而哪些代碼要慢慢走,也要經過對錯誤現象的分析和假設來肯定,之前咱們用printf打印中間結果時,也要分析應該在哪裏插入printf,打印哪些中間結果,調試的基本思路是同樣的。
[4]info
一次調試能夠設置多個斷點,用info命令能夠查看已經設置的斷點:
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from a...done. (gdb) start Temporary breakpoint 1 at 0x40052e: file a.c, line 5. Starting program: /root/2/02/a Temporary breakpoint 1, main () at a.c:5 5 int a = 1; (gdb) b 7 Breakpoint 2 at 0x40053b: file a.c, line 7. (gdb) b 8 Note: breakpoint 2 also set at pc 0x40053b. Breakpoint 3 at 0x40053b: file a.c, line 8. (gdb) i breakpoints Num Type Disp Enb Address What 2 breakpoint keep y 0x000000000040053b in main at a.c:7 3 breakpoint keep y 0x000000000040053b in main at a.c:8 (gdb)
[5]delete
每一個斷點都有一個編號(有的斷點行數不同,但地址卻同樣,有的地方不可以設置斷點或者說與上一個設置的斷點等效),能夠用編號指定刪除某個斷點。
......
(gdb) b 7 Breakpoint 2 at 0x40053b: file a.c, line 7. (gdb) b 8 Note: breakpoint 2 also set at pc 0x40053b. Breakpoint 3 at 0x40053b: file a.c, line 8. (gdb) i breakpoints Num Type Disp Enb Address What 2 breakpoint keep y 0x000000000040053b in main at a.c:7 3 breakpoint keep y 0x000000000040053b in main at a.c:8 (gdb) delete 3 (gdb) i breakpoints Num Type Disp Enb Address What 2 breakpoint keep y 0x000000000040053b in main at a.c:7 (gdb)
有時候一個斷點暫時不用能夠禁用掉而沒必要刪除,這樣之後想用的時候能夠直接啓用,而沒必要從新從代碼裏找應該在哪一行設斷點,這個過程用 disable 和 enable 來完成。
[6]條件斷點 (break 和run)
gdb的斷點功能很是靈活,還能夠設置斷點在知足某個條件時才激活,例如:
......
//先把其他的斷點刪掉。
(gdb) b 9 if a == 2 Breakpoint 5 at 0x400552: file a.c, line 9. (gdb) i breakpoints Num Type Disp Enb Address What 5 breakpoint keep y 0x0000000000400552 in main at a.c:9 stop only if a == 2 (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /root/2/02/a a = 1, b = 1 [Inferior 1 (process 22968) exited normally] (gdb)
r表示從頭開始運行程序,在a==2的條件下中斷纔有效。a不等於2,因此中斷無效。
斷點是當程序執行到某一代碼行時中斷,而觀察點是當程序訪問某個存儲單元時中斷,若是咱們不知道某個存儲單元是在哪裏被改動的,這時候觀察點尤爲有用。
root@iZ2zeeailqvwws5dcuivdbZ:~/2/02# gdb a GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from a...done. (gdb) start Temporary breakpoint 1 at 0x40052e: file a.c, line 5. Starting program: /root/2/02/a Temporary breakpoint 1, main () at a.c:5 5 int a = 1; (gdb) watch b Hardware watchpoint 2: b (gdb) c Continuing. Hardware watchpoint 2: b Old value = 0 New value = 1 main () at a.c:8 8 printf("a = %d, b = %d\n", a, b); (gdb)
程序執行到b存儲單元,將此執行單元執行先後的值都顯示出來。
若是程序運行時出現段錯誤,用gdb能夠很容易定位到到底是哪一行引起的段錯誤。在gdb中運行,遇到段錯誤會自動停下來,這時能夠用命令查看當前執行到哪一行代碼了。
gdb顯示段錯誤出如今 _IO_vfscanf 函數中,用bt命令能夠看到是哪個函數調用了它。
gdb有許多有用的命令如list(顯示源代碼),這樣就能夠結合源碼與調試信息更好的進行調試。將gdb經常使用命令摘抄以下表:
命令 |
描述 |
backtrace(bt) |
查看各級函數調用及參數 |
finish |
連續運行到當前函數返回爲止,而後停下來等待命令 |
frame(f) 幀編號 |
選擇棧幀 |
info(i) locals |
查看當前棧幀局部變量的值 |
list(l) |
列出源代碼,接着上次的位置往下列,每次列十行 |
list 行號 |
列出第幾行開始的源代碼 |
list 函數名 |
列出某個函數的源代碼 |
next(n) |
執行下一行語句 |
print(p) |
打印表達式的值,經過表達式的值能夠修改變量的值或者調用函數 |
quit(q) |
退出gdb調試環境 |
set var |
修改變量的值 |
start |
開始執行程序,停在main函數第一行語句前面等待命令 |
step(s) |
執行下一行語句,若是有函數則進入到函數中 |
break(b) 行號 |
在某一行設置斷點 |
break 函數名 |
在某個函數開頭設置斷點 |
break(b)… if… |
設置條件斷點 |
continue(c) |
從當前位置開始連續運行程序 |
delete breakpoints 斷點號 |
刪掉此號的斷點 |
display 變量名 |
跟蹤查看某個變量,每次停下來都顯示它的值 |
disable breakpoints 斷點號 |
禁用此斷點 |
enable 斷點號 |
啓用此斷點 |
info(i) breakpoints |
查看當前設置了哪些斷點 |
run(r) |
從頭開始連續運行程序 |
undisplay 跟蹤顯示行號 |
取消跟蹤顯示 |
watch |
設置觀察點 |
info(i) watchpoints |
查看當前設置了哪些觀察點 |
x |
從某個位置開始打印存儲單元的內容,所有當成字節來看,而不區分哪一個字節屬於哪一個變量 |
disassemble |
反彙編當前函數或者指定的函數,單獨用disassemble命令是反彙編當前函數,若是disassemble命令後面跟函數名或地址則反彙編指定的函數。 |
si |
能夠一條指令一條指令地單步調試。 |
info registers |
能夠顯示全部寄存器的當前值。在gdb中表示寄存器名時前面要加個$,例如p $esp能夠打印esp寄存器的值。 |
set follow-fork-mode child/parent | 設置gdb在fork以後跟蹤子進程/父進程 |
set args 'command-line' | 給執行的程序傳命令行參數 |
s(stepin) | 進入子函數 |