1. 程式人生 > >GDB常用命令使用

GDB常用命令使用

sig end 機制 機器 方式 行程 nbsp 運行時 step

GDB(GNU Debugger)是在Unix以及類Unix系統下的調試工具。功能極其強大,幾乎涵蓋了你所需要的全部功能。
GDB主要幫忙你完成下面四個方面的功能:
1.啟動你的程序,可以按照你的定制要求隨心所欲的運行程序。
2.可讓被調試的程序在你所指定的調置的斷點處停住。
3.當程序被停住時,可以檢查此時你的程序中所發生的事,以及內存狀態等。
4.動態的改變你程序的執行環境。

gdb使用總旨:help指令很強大!多用help!help裏面總會有你需要的信息。如果你不知道如何使用help,請在gdb裏面輸入:help all

一、gdb使用前置條件:編譯時加入debug信息。

gcc/g++是在編譯時加入-g,其他語言請自行百度。值得註意的是,-g分4個等級:

  1. -g0等於不加-g。即不包含任何信息
  2. -g1只包含最小信息,一般來說只有你不需要debug,只需要backtrace信息,並且真的很在意程序大小,或者有其他保密/特殊需求時才會使用-g1。
  3. –g2為gdb默認等級,包含絕大多數你需要的信息。
  4. –g3包含一些額外信息,例如包含宏定義信息。當你需要調試宏定義時,請使用-g3

二、gdb最常見的幾個用法:

1. 調試程序。有幾種方法可以在gdb下運行你的程序:

1) gdb ${你的程序} 進入gdb後,輸入run(簡寫r) ${arg1} ${arg2} … ${argN}

2) gdb --args ${你的程序} ${arg1} ${arg2} … ${argN} 進入gdb後,運行run。

3) gdb進入gdb後,輸入file ${你的程序}。然後使用set args ${arg1} ${arg2} … ${argN} 設定好你的程序參數,再運行run。

2. 調試正在運行的程序:

gdb ${你的程序} ${程序pid}

3. 查core:

gdb ${你的程序} ${core文件}

三、gdb常用命令:

1. backtrace:顯示棧信息。簡寫為bt。

2. frame x 切換到第x幀。其中x會在bt命令中顯示,從0開始。0表示棧頂。簡寫為f。

3. up/down x 往棧頂/棧底移動x幀。當不輸入x時,默認為1。

4. print x打印x的信息,x可以是變量,也可以是對象或者數組。簡寫為p。

5. print */&x 打印x的內容/地址。

6. call 調用函數。註意此命令需要一個正在運行的程序。

7. set substitute-path from_path to_path,替換源碼文件路徑。當編譯機與運行程序的機器代碼路徑不同時,需要使用該指令替換代碼路徑,否則你無法在gdb中看到源碼。

8. break x.cpp:n 在x.cpp的第n行設置斷點,然後gdb會給出斷點編號m。命令可簡寫為b。後面會對break命令進行更詳細的解釋。

9. command m 設置程序執行到斷點m時要看的內容,例如:

command n

>printf "x is %d\n",x

>c

>end

如果command後面沒有參數n,則命令被賦給最後一個breakpoint,這其實是說break和command連在一起用,在腳本裏用就非常方便了。gdb腳本會在後面詳細介紹

10. x /nfu ${addr} 打印addr的內容。addr可以是任何合法的地址表達式,例如0x562fb3d,一個當前有效的指針變量p,或者一個當前有效的變量var的地址&var。nfu是格式,n表示查看的長度,F表示格式(例如16進制或10進制),U表示單位(例如單字節b,雙字h,四字w等)。舉個栗子:

(gdb) x /3xw 0x562fb3d //這個指令的意思為:以16進制格式顯示地址0x562fb3d處3個單位,每個單位四字節的內容。你將得到下列數值:

0x562fb3d: 0x00282ff4 0x080484e0 0x00000000

11. continue 繼續運行程序。進入調試模式後,若你已經獲取了你需要的信息或者需要程序繼續運行時使用。可簡寫為c

12. until 執行到當前循環完成。可簡寫為u

13. step 單步調試,步入當前函數。可簡寫為s

14. next 單步調試,步過當前函數。可簡寫為n

15. finish 執行到當前函數返回

16. set var x=10 改變當前變量x的值。也可以這樣用:set {int}0x83040 = 10把內存地址0x83040的值強制轉換為int並賦值為10

17. info locals 打印當前棧幀的本地變量

18. jump使當前執行的程序跳轉到某一行,或者跳轉到某個地址。由於只會使程序跳轉而不會改變棧值,因此若跳出函數到另外的地方 會導致return出錯。另外,熟悉匯編的人都知道,程序運行時,有一個寄存器用於保存當前代碼所在的內存地址。所以,jump命令也就是改變了這個寄存器中的值。於是,你可以使用“set $pc”來更改跳轉執行的地址。如: set $pc = 0x485

19. return: 強制函數返回。可以指定返回值

四、程序中斷機制:監視點(watchpoint)、斷點(breakpoint)和捕捉點(catchpoint):

1. 監視點。監視點是監視內存中某個地址,當該地址的數據被改變(或者被讀取)時,程序交出控制權進入調試器。註意監視點分為軟件模式和硬件模式:GDB 使用軟件監視點的方式是在單步執行你的程序的同時測試變量的值,所以執行程序的速度會變慢。同時,軟件監視點僅在當前線程有效。幸運的是,32 位的 Intel x86 處理器提供了 4 個特殊的調試寄存器用來方便調試程序,GDB 可以使用這些寄存器建立硬件監視點。GDB 總是會優先使用硬件監視點,因為這樣不會減慢程序的執行速度。然而,可用的(enable的)硬件監視點的個數是有限的。如果你設置了過多的硬件監視點,當程序從中斷的狀態變為執行的狀態(例如continue,until或者finish)時,GDB 可能無法把它們全部激活。另外,活動的硬件監視點的數量只有在試圖繼續執行程序時才能知道,也就是說,即使你設置了過多的硬件監視點,gdb在你運行程序之前也不會警告你。

設置監視點的命令有3個,watch(寫監視),rwatch(讀監視)以及awatch(讀寫監視)。他們的使用方法一樣,皆為以下幾種:

1) (r/a)watch x。x是一個變量名。當x的值改變/被讀取時,程序交出控制權進入調試器。

2) (r/a)watch 0xN。N為一個有效地址。當該地址的內容變化/被讀取時,程序交出控制權進入調試器。

3) (r/a)watch *(int *)0xN。N為一個有效地址。當該地址的中的int指針指向的內容變化/被讀取時,程序交出控制權進入調試器。

4) (r/a)watch -l *(int *)0xN。N為一個有效地址。當該地址的中的int指針指向的內容變化/被讀取,或者該地址的內容變化/被讀取時,程序交出控制權進入調試器。

註意3)和4)的區別在於,當加入-l選項後,會同時監視表達式本身以及表達式指向的內容。

2. 斷點是指當執行到程序某一步時,程序交出控制權進入調試器。值得註意的是,break會有一些變體:tbreak,hbreak,thbreak與rbreak。tbreak與break功能相同,只是所設置的斷點在觸發一次後自動刪除。hbreak是一個硬件斷點。thbreak則既是一個臨時的硬件斷點。註意硬件斷點需要硬件支持,某些硬件可能不支持這種類型的斷點。rbreak稍微特殊一些,它會在匹配正則表達式的全部位置加上斷點,後面會有詳細講解。除去rbreak,其他break家族的使用方法如下:

1) (t/h)break x.cpp:y 。在代碼x.cpp的第y行加入斷點。x.cpp若不指定,則會以當前執行的文件作為斷點文件。若程序未執行,則以包含main函數的源代碼文件作為斷點文件。若x.cpp和y都不指定,則以當前debugger的點作為斷點處。

2) (t/h)break 0xN。在地址N處加入斷點。N必須為一個有效的代碼段(code segment)地址。

3) (t/h)break x.cpp:func。在x.cpp的func函數入口處加入斷點。x.cpp可以不提供直接使用break func。註意由於重載(overload)的存在,因此gdb可能會詢問你希望在哪個函數加上斷點。你也可以通過指定參數類型來避免該問題,例如break func(int ,char *)

4) (t/h)break +/-N。在當前運行處的第N行後/前加入斷點。

5) rbreak REGEXP。 在所有符合正則表達式REGEXP的函數入口加入斷點。例如rbeak EX_* 表示在所有符合以EX_開頭的函數入口處加入斷點。

註意break後面還有2個可選參數,線程id和條件。線程id指在info threads中的線程序號,而非系統提供的tid。例如break x.cpp:y 2 if (a==24),表示在2號線程的x.cpp的第y行加入斷點,並且只有當a的值為24時,程序才會交出控制權進入調試器。

另外,breakpoints可以通過save命令保存,以方便使用者下次再次進入程序調試時不需要重設斷點。

3. 捕捉點是當某些事件發生時,程序交出控制權進入調試器。例如catch一個exception,assert,signal,fork甚至syscall。tcatch與catch功能一樣,只是所設置的捕捉點在觸發一次後自動刪除。以後會詳細介紹catchpoint。

五、跟蹤點(tracepoint):

跟蹤點與上面三個斷點不同之處在於,它只是跟蹤記錄信息而不會中斷程序的運行。當你的程序是realtime程序,或者與其他的程序有交互時,你可能會希望使用跟蹤點達到監視程序而又不破壞程序自身行為的目的。與斷點相同的是,跟蹤點會保存下在跟蹤點時的一些內存信息供使用者查閱,例如數組或者對象。

另外,tracepoints可以通過save命令保存,以方便使用者下次再次進入程序調試時不需要重設這些跟蹤點。

六、檢查點(checkpoint):

gdb可以保存某一個時間點的程序狀態或者說是程序映像,並且稍後又可以返回到這個狀態。這個稱之為checkpoint。

每個檢查點是進程的一個拷貝。這樣當一個bug很難重現,而又擔心調試過頭了又要從頭開始重現時,可以在估計要重現這個bug之前,做一個checkpoint,這樣即使debug過頭了,也可以從這個checkpoint開始,而不用重啟整個程序並且期待它重現這個bug(也許需要很久!!)。

但是每個checkpoint有一個唯一的進程id,這個pid與原始程序的pid不同,因此如果程序需要使用pid的信息時,需要慎重考慮。

GDB常用命令使用