Gdb調試器(讀書筆記)

Gdb調試器

調試是所有程序員都會面臨的問題。如何提高程序員的調試效率,更好更快地定位程序中的問題從而加快程序開發的進度,是大家共同面對的。就如讀者熟知的Windows下的一些調試工具,如VC自帶的如設置斷點、單步跟蹤等,都受到了廣大用戶的讚賞。那麼,在Linux下有什麼很好的調試工具呢?

本文所介紹的Gdb調試器是一款GNU開發組織併發布的UNIX/Linux下的程序調試工具。雖然,它沒有圖形化的友好界面,但是它強大的功能也足以與微軟的VC工具等媲美。下面就請跟隨筆者一步步學習Gdb調試器。

 

1  Gdb使用流程

首先,筆者給出了一個短小的程序,由此帶領讀者熟悉一下Gdb的使用流程。強烈建議讀者能夠實際動手操作。

首先,打開Linux下的編輯器Vi或者Emacs,編輯如下代碼。(由於爲了更好地熟悉Gdb的操作,筆者在此使用Vi編輯,希望讀者能夠參見3.3節中對Vi的介紹,並熟練使用Vi)。

 

/*test.c*/

#include <stdio.h>

int sum(int m);

int main()

{

      int i,n=0;

      sum(50);

      for(i=1; i<=50; i++)

       {

         n += i;

       }

      printf("The sum of 1-50 is %d /n", n );

 

}

int sum(int m)

{

         int i,n=0;

         for(i=1; i<=m;i++)

            n += i;

         printf("The sum of 1-m is %d/n", n);

}

 

在保存退出後首先使用Gcctest.c進行編譯,注意一定要加上選項”-g”,這樣編譯出的可執行代碼中才包含調試信息,否則之後Gdb無法載入該可執行文件。

 

[root@localhost Gdb]# gcc -g test.c -o test

 

雖然這段程序沒有錯誤,但調試完全正確的程序可以更加了解Gdb的使用流程。接下來就啓動Gdb進行調試。注意,Gdb進行調試的是可執行文件,而不是如”.c”的源代碼,因此,需要先通過Gcc編譯生成可執行文件才能用Gdb進行調試。

 

[root@localhost Gdb]# gdb test

GNU Gdb Red Hat Linux (6.3.0.0-1.21rh)

Copyright 2004 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".

(gdb)

 

可以看出,在Gdb的啓動畫面中指出了Gdb的版本號、使用的庫文件等信息,接下來就進入了由“(gdb)”開頭的命令行界面了。

1)查看文件

Gdb中鍵入”l”(list)就可以查看所載入的文件,如下所示:

 

*

注意

Gdb的命令中都可使用縮略形式的命令,如“l”代便“list”,“b”代表“breakpoint”,“p”代表“print”等,讀者也可使用“help”命令查看幫助信息。

 

(Gdb) l

1       #include <stdio.h>

2       int sum(int m);

3       int main()

4       {

5             int i,n=0;

6             sum(50);

7             for(i=1; i<=50; i++)

8              {

9                n += i;

10             }

(Gdb) l

11            printf("The sum of 150 is %d /n", n );

12      

13      }

14      int sum(int m)

15      {

16                 int i,n=0;

17                 for(i=1; i<=m;i++)

18                      n += i;

19                 printf("The sum of 1m is = %d/n", n);

20      }

 

可以看出,Gdb列出的源代碼中明確地給出了對應的行號,這樣就可以大大地方便代碼的定位。

2)設置斷點

設置斷點是調試程序中是一個非常重要的手段,它可以使程序到一定位置暫停它的運行。因此,程序員在該位置處可以方便地查看變量的值、堆棧情況等,從而找出代碼的癥結所在。

Gdb中設置斷點非常簡單,只需在”b”後加入對應的行號即可(這是最常用的方式,另外還有其他方式設置斷點)。如下所示:

 

(Gdb) b 6

Breakpoint 1 at 0x804846d: file test.c, line 6.

 

要注意的是,在Gdb中利用行號設置斷點是指代碼運行到對應行之前將其停止,如上例中,代碼運行到第五行之前暫停(並沒有運行第五行)。

3)查看斷點情況

在設置完斷點之後,用戶可以鍵入”info b”來查看設置斷點情況,在Gdb中可以設置多個斷點。

 

(Gdb) info b

Num Type           Disp Enb Address    What

1   breakpoint     keep y   0x0804846d in main at test.c:6

 

4)運行代碼

接下來就可運行代碼了,Gdb默認從首行開始運行代碼,可鍵入”r”(run)即可(若想從程序中指定行開始運行,可在r後面加上行號)。

 

(Gdb) r

Starting program: /root/workplace/Gdb/test

Reading symbols from shared object read from target memory...done.

Loaded system supplied DSO at 0x5fb000

 

Breakpoint 1, main () at test.c:6

6                 sum(50);

 

可以看到,程序運行到斷點處就停止了。

5)查看變量值

在程序停止運行之後,程序員所要做的工作是查看斷點處的相關變量值。在Gdb中只需鍵入”p”+變量值即可,如下所示:

 

(Gdb) p n

$1 = 0

(Gdb) p i

$2 = 134518440

 

在此處,爲什麼變量”i”的值爲如此奇怪的一個數字呢?原因就在於程序是在斷點設置的對應行之前停止的,那麼在此時,並沒有把”i”的數值賦爲零,而只是一個隨機的數字。但變量”n”是在第四行賦值的,故在此時已經爲零。

 

*小技巧

Gdb在顯示變量值時都會在對應值之前加上”$N”標記,它是當前變量值的引用標記,所以以後若想再次引用此變量就可以直接寫作”$N”,而無需寫冗長的變量名。

 

6)單步運行

單步運行可以使用命令”n”(next)或”s”(step),它們之間的區別在於:若有函數調用的時候,”s”會進入該函數而”n”不會進入該函數。因此,”s”就類似於VC等工具中的”step in”,”n”類似與VC等工具中的”step over”。它們的使用如下所示:

 

(Gdb) n

The sum of 1-m is 1275

7            for(i=1; i<=50; i++)

(Gdb) s

sum (m=50) at test.c:16

16              int i,n=0;

 

可見,使用”n”後,程序顯示函數sum的運行結果並向下執行,而使用”s”後則進入到sum函數之中單步運行。

7)恢復程序運行

在查看完所需變量及堆棧情況後,就可以使用命令”c”(continue)恢復程序的正常運行了。這時,它會把剩餘還未執行的程序執行完,並顯示剩餘程序中的執行結果。以下是之前使用”n”命令恢復後的執行結果:

 

(Gdb) c

Continuing.

The sum of 1-50 is :1275

 

Program exited with code 031.

 

可以看出,程序在運行完後退出,之後程序處於“停止狀態”。

 

*小知識

Gdb中,程序的運行狀態有“運行”、“暫停”和“停止”三種,其中“暫停”狀態爲程序遇到了斷點或觀察點之類的,程序暫時停止運行,而此時函數的地址、函數參數、函數內的局部變量都會被壓入“棧”(Stack)中。故在這種狀態下可以查看函數的變量值等各種屬性。但在函數處於“停止”狀態之後,“棧”就會自動撤銷,它也就無法查看各種信息了。

 

2  Gdb基本命令

Gdb的命令可以通過查看help進行查找,由於Gdb的命令很多,因此Gdbhelp將其分成了很多種類(class),用戶可以通過進一步查看相關class找到相應命令。如下所示:

 

(gdb) help

List of classes of commands:

 

aliases -- Aliases of other commands

breakpoints -- Making program stop at certain points

data -- Examining data

files -- Specifying and examining files

internals -- Maintenance commands

Type "help" followed by a class name for a list of commands in that class.

Type "help" followed by command name for full documentation.

Command name abbreViations are allowed if unambiguous.

 

上述列出了Gdb各個分類的命令,注意底部的加粗部分說明其爲分類命令。接下來可以具體查找各分類種的命令。如下所示:

 

(gdb) help data

Examining data.

 

List of commands:

 

call -- Call a function in the program

delete display -- Cancel some expressions to be displayed when program stops

delete mem -- Delete memory region

disable display -- Disable some expressions to be displayed when program stops

Type "help" followed by command name for full documentation.

Command name abbreViations are allowed if unambiguous.

 

至此,若用戶想要查找call命令,就可鍵入“help call”。

 

(gdb) help call

Call a function in the program.

The argument is the function name and arguments, in the notation of the

current working language.  The result is printed and saved in the value

history, if it is not void.

 

當然,若用戶已知命令名,直接鍵入“help [command]”也是可以的。

Gdb中的命令主要分爲以下幾類:工作環境相關命令、設置斷點與恢復命令、源代碼查看命令、查看運行數據相關命令及修改運行參數命令。以下就分別對這幾類的命令進行講解。

1.工作環境相關命令

Gdb中不僅可以調試所運行的程序,而且還可以對程序相關的工作環境進行相應的設定,甚至還可以使用shell中的命令進行相關的操作,其功能極其強大。表3.10所示列出了Gdb常見工作環境相關命令。

3.10                                                     Gdb工作環境相關命令

   

set args運行時的參數

指定運行時參數,如:set args 2

show args

查看設置好的運行參數

path dir

設定程序的運行路徑

show paths

查看程序的運行路徑

set enVironment var [=value]

設置環境變量

show enVironment [var]

查看環境變量

cd dir

進入到dir目錄,相當於shell中的cd命令

pwd

顯示當前工作目錄

shell command

運行shellcommand命令

2.設置斷點與恢復命令

Gdb中設置斷點與恢復的常見命令如表3.11所示。

3.11                                               Gdb設置斷點與恢複相關命令

   

bnfo b

查看所設斷點

break 行號或函數名 <條件表達式>

設置斷點

tbreak 行號或函數名 <條件表達式>

設置臨時斷點,到達後被自動刪除

delete [斷點號]

刪除指定斷點,其斷點號爲”info b”中的第一欄。若缺省斷點號則刪除所有斷點

disable [斷點號]]

停止指定斷點,使用”info b”仍能查看此斷點。同delete一樣,省斷點號則停止所有斷點

enable [斷點號]

激活指定斷點,即激活被disable停止的斷點

condition [斷點號] <條件表達式>

修改對應斷點的條件

ignore [斷點號]<num>

在程序執行中,忽略對應斷點num

step

單步恢復程序運行,且進入函數調用

next

單步恢復程序運行,但不進入函數調用

finish

運行程序,直到當前函數完成返回

c

繼續執行函數,直到函數結束或遇到新的斷點

 

由於設置斷點在Gdb的調試中非常重要,所以在此再着重講解一下Gdb中設置斷點的方法。

Gdb中設置斷點有多種方式:其一是按行設置斷點,設置方法在3.5.1節已經指出,在此就不重複了。另外還可以設置函數斷點和條件斷點,在此結合上一小節的代碼,具體介紹後兩種設置斷點的方法。

函數斷點

Gdb中按函數設置斷點只需把函數名列在命令”b”之後,如下所示:

 

(gdb) b sum

Breakpoint 1 at 0x80484ba: file test.c, line 16.

(gdb) info b

Num Type           Disp Enb Address    What

1   breakpoint     keep y   0x080484ba in sum at test.c:16

 

要注意的是,此時的斷點實際是在函數的定義處,也就是在16行處(注意第16行還未執行)。

條件斷點

Gdb中設置條件斷點的格式爲:b 行數或函數名 if 表達式。具體實例如下所示:

 

(gdb) b 8 if i==10

Breakpoint 1 at 0x804848c: file test.c, line 8.

(gdb) info b

Num Type           Disp Enb Address    What

1   breakpoint     keep y   0x0804848c in main at test.c:8

        stop only if i == 10

(gdb) r

Starting program: /home/yul/test

The sum of 1-m is 1275

 

Breakpoint 1, main () at test.c:9

9               n += i;

(gdb) p i

$1 = 10

 

可以看到,該例中在第8行(也就是運行完第7行的for循環)設置了一個“i==0”的條件斷點,在程序運行之後可以看出,程序確實在i10時暫停運行。

3Gdb中源碼查看相關命令

Gdb中可以查看源碼以方便其他操作,它的常見相關命令如表3.12所示:

3.12                                                 Gdb源碼查看相關相關命令

   

list <行號>|<函數名>

查看指定位置代碼

file [文件名]

加載指定文件

forward-search 正則表達式

源代碼前向搜索

reverse-search 正則表達式

源代碼後向搜索

dir dir

停止路徑名

show directories

顯示定義了的源文件搜索路徑

info line

顯示加載到Gdb內存中的代碼

4Gdb中查看運行數據相關命令

Gdb中查看運行數據是指當程序處於“運行”或“暫停”狀態時,可以查看的變量及表達式的信息,其常見命令如表3.13所示:

3.13                                                 Gdb查看運行數據相關命令

   

print 表達式|變量

查看程序運行時對應表達式和變量的值

x <n/f/u>

查看內存變量內容。其中n爲整數表示顯示內存的長度,f表示顯示的格式,u表示從當前地址往後請求顯示的字節數

display 表達式

設定在單步運行或其他情況中,自動顯示的對應表達式的內容

5Gdb中修改運行參數相關命令

Gdb還可以修改運行時的參數,並使該變量按照用戶當前輸入的值繼續運行。它的設置方法爲:在單步執行的過程中,鍵入命令“set 變量=設定值”。這樣,在此之後,程序就會按照該設定的值運行了。下面,筆者結合上一節的代碼將n的初始值設爲4,其代碼如下所示:

 

(Gdb) b 7

Breakpoint 5 at 0x804847a: file test.c, line 7.

(Gdb) r      

Starting program: /home/yul/test

The sum of 1-m is 1275

 

Breakpoint 5, main () at test.c:7

7                 for(i=1; i<=50; i++)

(Gdb) set n=4

(Gdb) c

Continuing.

The sum of 1-50 is 1279

 

Program exited with code 031.

 

可以看到,最後的運行結果確實比之前的值大了4

 

 

Gdb的使用切記點:

·  Gcc編譯選項中一定要加入”-g”。

·  只有在代碼處於“運行”或“暫停”狀態時才能查看變量值。

·  設置斷點後程序在指定行之前停止。

發佈了24 篇原創文章 · 獲贊 6 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章