GDB常用命令簡介[zz]


GDB的命令很多,本文不會全部介紹,僅會介紹一些最常用的。在介紹之前,先介紹GDB中的一個非常有用的功能:補齊功能。它就如同Linux下 SHELL中的命令補齊一樣。當你輸入一個命令的前幾個字符,然后輸入TAB鍵,如果沒有其它命令的前幾個字符與此相同,SHELL將補齊此命令。如果有其它命令的前幾個字符與此相同,你會聽到一聲警告聲,再輸入TAB鍵,SHELL將所有前幾個字符與此相同的命令全部列出。而GDB中的補齊功能不僅能補齊GDB命令,而且能補齊參數。
  本文將先介紹常用的命令,然后結合一個具體的例子來演示如何實際使用這些命令。下面的所有命令除了第一條啟動GDB命令是在SHELL下輸入的,其余都是GDB內的命令。大部分GDB內的命令都可以僅輸入前幾個字符,只要不與其它指令沖突。如quit可以簡寫為q,因為以q打頭的命令只有quit。 List可以簡寫為l,等等

3.1 啟動GDB
  你可以輸入GDB來啟動GDB程序。GDB程序有許多參數,在此沒有必要詳細介紹,但一個最為常用的還是要介紹的:如果你已經編譯好一個程序,我們假設文件名為hello,你想用GDB調試它,可以輸入gdb hello來啟動GDB並載入你的程序。如果你僅僅啟動了GDB,你必須在啟動后,在GDB中再載入你的程序。

3.2 載入程序 === file
  在GDB內,載入程序很簡單,使用file命令。如file hello。當然,程序的路徑名要正確。

  退出GDB === quit
  在GDB的命令方式下,輸入quit,你就可以退出GDB。你也可以輸入'C-d'來退出GDB。

3.3 運行程序 === run
  當你在GDB中已將要調試的程序載入后,你可以用run命令來執行。如果你的程序需要參數,你可以在run指令后接着輸入參數,就象你在SHELL下執行一個需要參數的命令一樣。

3.4 查看程序信息 === info
  info指令用來查看程序的信息,當你用help info查看幫助的話,info指令的參數足足占了兩個屏幕,它的參數非常多,但大部分不常用。我用info指令最多的是用它來查看斷點信息。

3.4.1 查看斷點信息
info br
br是斷點break的縮寫,記得GDB的補齊功能吧。用這條指令,你可以得到你所設置的所有斷點的詳細信息。包括斷點號,類型,狀態,內存地址,斷點在源程序中的位置等。

3.4.2 查看當前源程序
info source

3.4.3 查看堆棧信息
info stack
用這條指令你可以看清楚程序的調用層次關系。
3.4.4 查看當前的參數
info args

3.5 列出源一段源程序 === list

3.5.1 列出某個函數
list

3.5.2 以當前源文件的某行為中間顯示一段源程序
list LINENUM

3.5.3 接着前一次繼續顯示
list

3.5.4 顯示前一次之前的源程序
list -

3.5.5 顯示另一個文件的一段程序
list FILENAME: 或 list FILENAME:LINENUM

3.6 設置斷點 === break
  現在我們將要介紹的也許是最常用和最重要的命令:設置斷點。無論何時,只要你的程序已被載入,並且當前沒有正在運行,你就能設置,修改,刪除斷點。設置斷點的命令是break。有許多種設置斷點的方法。如下:

3.6.1 在函數入口設置斷點
break

3.6.2 在當前源文件的某一行上設置斷點
break LINENUM

3.6.3 在另一個源文件的某一行上設置斷點
break FILENAME:LINENUM

3.6.4 在某個地址上設置斷點,當你調試的程序沒有源程序是,這很有用
break *ADDRESS
  除此之外,設置一個斷點,讓它只有在某些特定的條件成立時程序才會停下,我們可以稱其為條件斷點。這個功能很有用,尤其是當你要在一個程序會很多次執行到的地方設置斷點時。如果沒有這個功能,你必須有極大的耐心,加上大量的時間,一次一次讓程序斷下,檢查一些值,接着再讓程序繼續執行。事實上,大部分的斷下並不是我們所希望的,我們只希望在某些條件下讓程序斷下。這時,條件斷點就可以大大提高你的效率,節省你的時間。條件斷點的命令如下,在后面的例子中會有示例。

3.6.5 條件斷點
break ...if COND
  COND是一個布爾條件表達式,語法與C語言中的一樣。條件斷點與一般的斷點不同之處是每當程序執行到斷點處,都要計算條件表達式,如果為真,程序才會斷下,否則程序會一直執行下去。

3.7 其它斷點操作
  GDB給每個斷點賦上一個整數數字,這個數字在操作斷點時起到重要作用,它實際上就代表相應的斷點。GDB中的斷點有四種狀態:
  有效(Enabled)
  禁止(Disabled)
  一次有效(Enabled once)
  有效后刪除(Enabled for deletion)
  在上面的四個狀態有效和禁止都很好理解,禁止就是讓斷點暫時失效。一次有效就是當程序在此斷點斷下后,斷點狀態自動變為禁止狀態。有效后刪除就是當程序在此斷點斷下后,斷點被刪除。實際上,后兩種狀態一般不會碰到。
  當你設置一個斷點后,它的確省狀態是有效。你可以用enable和disable指令來設置斷點的狀態為有效或禁止。例如,如果你想禁止2號斷點,可以用下面的指令:
disable 2
相應的,如果想刪除2號斷點,可以有下面的指令:
delete 2

3.8 設置監視點 === watch
  當你調試一個很大的程序,並且在跟蹤一個關鍵的變量時,發現這個變量不知在哪兒被改動過,如何才能找到改動它的地方。這時你可以使用watch命令。簡單地說,監視點可以讓你監視某個表達式或變量,當它被讀或被寫時讓程序斷下。watch命令的用法如下:
   watch EXPRESSION
  watch指令是監視被寫的,當你想監視某個表達式或變量被讀的話,需要使用rwatch指令,具體用法是一樣的。要注意的是,監視點有硬件和軟件兩種方式,如果可能Linux盡可能用硬件方式,因為硬件方式在速度上要大大快於軟件方式。軟件方式由於要在每次執行一條指令后都要檢查所要監視的值是否被改變,因此它的執行速度會大大降低。同時它也無法設置成被讀時讓程序斷下,因為讀操作不會改變值,所以GDB無法檢測到讀操作。幸運的是,目前的PC機基本都支持硬件方式。如果你想確認一下你的機器是否支持硬件,你可以在調試程序時用watch設置一個監視點,如果GDB向你顯示:
   Hardware watchpoint NUM: EXPR
  那么你可以放心了,你的機器支持硬件方式。

3.9 檢查數據
  最常用的檢查數據的方法是使用print命令。
   print exp
  print指令打印exp表達式的值。卻省情況下,表達式的值的打印格式依賴於它的數據類型。但你可以用一個參數/F來選擇輸出的打印格式。F是一個代表某種格式的字母,詳細可參考輸出格式一節。表達式可以是常量,變量,函數調用,條件表達式等。但不能打印宏定義的值。表達式exp中的變量必須是全局變量或當前堆棧區可見的變量。否則GDB會顯示象下面的一條信息:
   No symbol "varible" in current context

3.10 修改變量值
  在調試程序時,你可能想改變一個變量的值,看看在這種情況下會發生什么。用set指令可以修改變量的值:
   set varible=value
  例如你想將一個變量tmp的值賦為10,
set tmp=10

3.11 檢查內存值
檢查內存值的指令是x,x是examine的意思。用法如下:
x /NFU ADDR
其中N代表重復數,F代表輸出格式(見2.13),U代表每個數據單位的大小。U可以去如下值:
b :字節(byte)
h :雙字節數值
w :四字節數值
g :八字節數值
  因此,上面的指令可以這樣解釋:從ADDR地址開始,以F格式顯示N個U數值。例如:
   x/4ub 0x4000
  會以無符號十進制整數格式(u)顯示四個字節(b),0x4000,0x4001,0x4002,0x4003。

3.12 輸出格式
  缺省情況下,輸出格式依賴於它的數據類型。但你可以改變輸出格式。當你使用print命令時,可以用一個參數/F來選擇輸出的打印格式。F可以是以下的一些值:
  'x' 16進制整數格式
  'd' 有符號十進制整數格式
  'u' 無符號十進制整數格式
  'f' 浮點數格式

3.13 單步執行指令
  單步執行指令有兩個step和next。Step可以讓你跟蹤進入一個函數,而next指令則不會進入函數。

3.14 繼續執行指令
  當程序被斷下后,你查看了所需的信息后,你會希望程序執行下去,輸入 continue, 程序會繼續執行下去。

3.15 幫助指令help
  在GDB中,如果想知道一條指令的用法,最方便的方法是使用help。使用方法很簡單,在help后跟上指令名。例如,想知道list指令用法,輸入
help list

4.一個簡單的例子
  上面僅是GDB常用指令的簡單介紹。本節將結合一個簡單的例子,向大家演示這些常用指令的具體應用。這是一個冒泡排序算法的程序,這個例子的目的僅僅是演示,並不是實際調試。將下面的源程序存為bubble.c文件,並編譯好。
#i nclude <stdio.h>

#define MAX_RECORD_NUMBER 10

int record[MAX_RECORD_NUMBER] =
{12,76,48,62,94,17,37,52,69,32};

swap(int * x , int * y )
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}

int main()
{
int i,j;
for( i = 0 ; i < MAX_RECORD_NUMBER - 1; i++ )
{
for( j = MAX_RECORD_NUMBER - 1; j > i; j--)
if( record[j] < record[j-1] )
swap(&record[j],&record[j-1]);
}

for( i = 0; i < MAX_RECORD_NUMBER -1; i++)
printf("%d ",record[i]);

printf("\n");
return 1;
}
  記得在編譯時用-g開關。如:gcc -g -o bubble bubble.c。你能在當前子目錄下得到一個編譯好的文件bubble。我們下面將以這個程序為例子向大家演示上面的指令在實際中的應用。
  首先啟動GDB,可以在啟動的同時載入文件bubble,如:gdb bubble。也可以分兩步進行,先啟動GDB,執行gdb,進入GDB后,再執行file bubble。
  這時可以用list指令列出源程序,list的使用比較簡單,但其實在GDB中最不方便的就是看源程序,主要原因是因為GDB僅是一個文本方式的調試器,無法讓你用鼠標和光標鍵來翻閱源程序,在這方面ddd等窗口程序有巨大的優勢。
  我們先來查看一下當前源程序的信息,如下:
(gdb) info source
Current source file is bubble.c
Compilation directory is /root/sample/
Located in /root/sample/bubble.c
Contains 32 lines.
Source language is c.
Compiled with stabs debugging format.
  我們可以知道程序名,目錄,文件大小,語言等信息。
  下面我們來設置斷點,我們想在函數swap出設置一個斷點:
(gdb) br swap
Breakpoint 1 at 0x80483d6: file bubble.c, line 11.
  br是break的簡寫。上面的一行是GDB告訴我們這個斷點的信息,我們可以知道這個斷點的斷點號是1,地址是0x80483d6,它在文件bubble.c的11行。
  我們再在一個行號上設一個斷點,
(gdb) br 23
Breakpoint 2 at 0x804844a: file bubble.c, line 23.
  我們已經設了兩個斷點,許多時候你會想查看一下斷點的信息和狀態,因此你會用到你最常使用的info指令,info br。
(gdb) info br
Num Type Disp Enb Address What
1 breakpoint keep y 0x080483d6 in swap at bubble.c:11
2 breakpoint keep y 0x0804844a in main at bubble.c:23
  我用這條指令的大多數原因是想查看一下某個斷點的斷點號,就是第一列的數值。有時也會看一下斷點的狀態是enable還是disable。以上的兩個斷點都是y,也就是都處於enable狀態。type列顯示breakpoint,是因為info br指令同時也會顯示watch的信息,因此用type來識別是斷點breakpoint還是檢查點watch。
  如果你知道斷點號,想刪除斷點很簡單,例如想刪除斷點2,執行del 2就行了。
  在程序中,斷點2本來設在循環中,那樣程序會頻煩斷下,這也許不是我們希望的。也許我們僅想在某個條件下讓它斷下,如想當j=5時。
(gdb) br 23 if j==5
Breakpoint 3 at 0x804844a: file bubble.c, line 23.
(gdb) info br
Num Type Disp Enb Address What
1 breakpoint keep y 0x080483d6 in swap at bubble.c:11
3 breakpoint keep y 0x0804844a in main at bubble.c:23
stop only if j == 5
  注意現在的斷點信息,雖然斷點2被刪除了,但新設的斷點號沒有使用2號,而是使用了3號。新設的斷點是個條件斷點,這從"stop only if j == 5"可以清楚的看出。
  現在執行程序,輸入run指令。
(gdb) run
Starting program: /root/sample/bubble

Breakpoint 1, swap (x=0x80495a4, y=0x80495a0) at bubble.c:11
11 temp = *x;
  程序已經在斷點1停了下來。當斷點停下時,我們經常需要查看變量值。如查看x值。
(gdb) p x
$1 = (int *) 0x80495a4
GDB告訴我們x是一個指向整數的指針,指針值是0x80495a4。如果想查看指針指向的值。執行:
(gdb) p *x
$2 = 32
(gdb) p *y
$3 = 69
單步執行
(gdb) n
12 *x = *y;
查看變量temp值
(gdb) p temp
$4 = 32
(gdb) n
13 *y = temp;
(gdb) p *x
$5 = 69
現在刪除斷點1
(gdb) del 1
繼續執行
(gdb) cont
Continuing.

Breakpoint 3, main () at bubble.c:23
23 swap(&record[j],&record[j-1]);
程序在斷點3停下,記得斷點3是個條件斷點。要驗證很簡單,查看一下變量j的值是不是5。
(gdb) p j
$6 = 5
我們可以查看一下全局變量record的值,
(gdb) p record
$7 = {12, 76, 48, 62, 94, 17, 32, 37, 52, 69}
也可以查看一下變量record的地址,
(gdb) p &record
$8 = (int (*)[10]) 0x8049580
知道地址時,也可以x指令查看內存值。
(gdb) x/4uw 0x8049580
0x8049580 <record>: 12 76 48 62
上面的指令查看4個4字節數,以整數方式顯示。可以看到這與reocrd值是相附的。
(gdb) x/4bb record
0x8049580 <record>: 12 0 0 0
顯示4個單字節數,以字節當時顯示。上面的4個字節值正好是record數組第一個整數值,因為整數是4字節,而且intel機器的數值是低字節在前。
改變變量值也很簡單,如果想將reocrd數組第一個值該為1,
(gdb) set record[0]=1
看一下值是否改變了。
(gdb) p record
$10 = {1, 76, 48, 62, 94, 17, 32, 37, 52, 69}
第一個值以改成了1。

  以上簡單地介紹了一些常用的GDB指令,由於篇幅所限,我們無法涉及GDB所有指令及GDB其它許多功能,讀者應當自己在實踐中不斷地學習。Linux系統中會有詳細的GDB的資料,你可以用info gdb來查閱這些資料。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM