1. 程式人生 > >Linux下gdb的安裝及使用入門

Linux下gdb的安裝及使用入門

1、安裝gdb。

在root使用者許可權下:

[email protected]:~# apt-get update
......
......
......
[email protected]:~# apt-get install gdb 
......
......
......
Do you want to continue? [Y/n] y
......
......
......
[email protected]:~# 

安裝好gdb了。

2、gdb的簡單使用。

用root許可權的Terminal(或一般許可權的Terminal)的vi編輯器編寫一個C程式a.c:

 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 }

(1) 在可執行檔案中加入原始碼資訊

這個過程通過gcc來完成:

gcc –o a a.c -g

-o選項的作用是:對命令輸出結果進行匯入操作,這裡是把gcc –o a a.c -g的操作結果輸出到檔案a(檔名可以自定義)中進行儲存。

-g選項的作用是:在可執行檔案中加入原始碼資訊,比如:可執行檔案中第幾條機器指令對應原始碼的第幾行,但並不是把整個原始檔都嵌入到可執行檔案中,而是在除錯時必須保證gdb能找到原始檔。

(2) 進入gdb

[email protected]:~/2/02# gcc -o a a.c -g
[email protected]:~/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的相應命令就可以實現其對應的功能。

(3) gdb除錯常用命令

  [1] start

  用start命令開始執行程式:

(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)提示需要輸入的命令。

  [2] 單步執行(n)

複製程式碼

(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
[email protected]:~/2/02# 

複製程式碼

  在start命令後,每輸入一個n就能夠單步執行一條語句(輸入一個命令後,直接回車表示最近輸入命令的含義)。當程式執行完時,可以輸入quit命令來退出gdb模式。

  [3] 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
[email protected]:~/2/02# 

複製程式碼

  gdb  a會進入a可執行程式的gdb模式,start命令就使程式準備執行程式中的第一條語句。b 8是breakpoint  8的簡寫(breakpoint的引數也可以以是某個函式名,表示在此函式處設定一個斷點),表示在程式第八行設定一個斷點。c是continue的縮寫,表示繼續執行程式,程式會在設定斷點處停下來。displayb表示將b的值顯示出來(undisplay取消對變數的跟蹤),然後再輸入單步除錯命令n(next)就可以使程式繼續執行。

  可見斷點有助於快速跳過沒有問題的程式碼,然後在有問題的程式碼上慢慢走慢慢分析,“斷點加單步”是使用偵錯程式的基本方法。至於應該在哪裡設定斷點,怎麼知道哪些程式碼可以跳過,而哪些程式碼要慢慢走,也要通過對錯誤現象的分析和假設來確定,以前我們用printf列印中間結果時,也要分析應該在哪裡插入printf,列印哪些中間結果,除錯的基本思路是一樣的。

  [4]info

  一次除錯可以設定多個斷點,用info命令可以檢視已經設定的斷點:

複製程式碼

[email protected]:~/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,所以中斷無效。  

  [7] gdb的觀察點(watch 和c)

  斷點是當程式執行到某一程式碼行時中斷,而觀察點是當程式訪問某個儲存單元時中斷,如果我們不知道某個儲存單元是在哪裡被改動的,這時候觀察點尤其有用。

複製程式碼

[email protected]:~/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儲存單元,將此執行單元執行前後的值都顯示出來。

  [8] 段錯誤

  如果程式執行時出現段錯誤,用gdb可以很容易定位到究竟是哪一行引發的段錯誤。在gdb中執行,遇到段錯誤會自動停下來,這時可以用命令檢視當前執行到哪一行程式碼了。

  gdb顯示段錯誤出現在 _IO_vfscanf 函式中,用bt命令可以看到是哪一個函式呼叫了它。

  [9] gdb基本命令

  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) 進入子函式