GDB調試基礎知識

1. 什麼是GDB?

GDB主要用來調試C/C++程序,它允許我們在執行程序時查看程序的行爲和內存信息,以及幫助我們在程序崩潰時查看它之前進行了什麼操作。

GDB的命令行調試要遠比IDE的功能高級的多,如果只是通常的設置斷點,監測變量什麼的可能IDE比較方便,但是一旦上升到使用那些高級點的調試技巧,反而GDB在命令行的模式下更爲的方便和高效,起碼啓動速度和響應速度會高很多。

2. 調試必備知識

2.1 什麼是core文件?

core 文件是大多數UNIX 系統實現的一種特性,當進程崩潰時,操作系統會將進程當前的內存映像和一部分相關的調試信息寫入core 文件,方便開發者後面對問題進行定位。

2.2 開啓或關閉core文件的生成

使用ulimit -c命令可以查看當前的內核轉儲功能是否有效。

-c選項表示內核轉儲文件的大小限制,如果執行完後它的大小爲0,表示內核轉儲不會生效,即使程序出現段錯誤,也不會有core文件生成。

開啓內核轉儲:

ulimit -c unlimited

這個命令的意思是不限制內核轉儲文件的大小。設爲無限制之後,發生問題時進程的內存就可以全部轉儲到內核轉儲文件中。

2.3 設置/查看Core文件的存儲路徑和命名規則

cat /proc/sys/kernel/core_pattern

執行該命令便可知道core文件存儲路徑和它的命名規則。假設執行完該命令,輸出內容如下所示:

/mnt/sdcard/core-%e-%p-%t

該內容說明core文件生成後將被存放到SD卡目錄下,並且還說明了命名格式,其中格式的具體含義如下:

%e:可執行文件名
%p:被轉儲的進程/線程ID
%t:轉儲時刻
2.4 調試信息與調試原理

一般要調試某個程序,爲了能清晰地看到調試的每一行代碼、調用的堆棧信息、變量名和函數名等信息,需要調試程序含有調試符號信息。

使用gcc編譯程序時,如果加上-g選項即可在編譯後的程序中保留調試符號信息。舉個例子,以下命令將生成一個帶調試信息的程序 hello_server。

gcc -g -o hello_server hello_server.c

2.5 編譯器優化對調試的影響

編譯器的程序優化選項一般有五個級別,從 O0~O4 ( 注意第一個O0 ,是字母O加上數字0), O0表示不優化,從 O1~O4 優化級別越來越高,O4最高。

如果在編譯代碼時開啓編譯器優化選項,那麼在實際調試過程中可能和實際代碼存在差異,例如:在代碼中定義了某個全局變量,但是它在任何地方都沒有被使用,編譯器就會將它從代碼中優化掉,那麼在使用GDB調試時,就無法查看該變量的任何信息。

相機中的代碼被編譯時開啓了編譯器優化選項-O2,因此編譯器在編譯時會對代碼進行優化,在使用GDB調試時,可能存在有些變量的值等於 <optimized out>,說明它已經被優化掉了。

3. 啓動GDB調試

3.1 使用GDB調試程序的3種方式

按常用方式排列如下:

  1. gdb filename corefile

    調試core文件。使用場景:程序發生段錯誤,通過core文件定位異常情況所在位置。

  2. gdb -p pid|tid

    調試正在運行中的進程或者線程。使用場景:1. mwareserver進程正在運行,用GDB掛載到進程中查看某些全局變量的值;2. mwareserver中某個線程阻塞了,用gdb可以查看它阻塞的位置來分析原因。

  3. gdb filename

    直接調試目標程序。使用場景:1. 學習開源代碼時通過GDB調試更快地理解程序的架構和執行邏輯;2. 調試自己代碼Demo中的bug。

3.2 GDB實用功能設置
  1. 日誌功能

有時候輸出信息太多,直接顯示不方便看,則可以啓用GDB的日誌功能。

(gdb) set logging on,默認會將日誌輸出到gdb.txt文件中。

輸出文件也可以進行指定,(gdb) set logging file <file name>,然後再執行set logging on開啓日誌功能。

  1. 結構體格式化輸出

默認情況下,gdb以一種“緊湊的方式打印結構體。set print pretty on,打開這個選項,GDB顯示結構體時會比較漂亮,當結構體較大時這個功能非常有幫助。

3.3 GDB常用命令
命令名稱 命令縮寫 命令說明
backtrace bt 查看當前線程的調用堆棧
print p 打印變量或寄存器值
examine x 查看內存地址中的值
frame f 切換到當前調用線程的指定堆棧,具體堆棧通過堆棧序號指定
up/down / 向上/向下切換當前調用線程的堆棧
info i 查看斷點 / 線程等信息
dump / 將指定的一段地址中的內存數據寫入文件中

1. backtrace

bt,查看當前線程的調用堆棧,即函數間的調用關係。

2. print

p,查看變量的值。

例1:

typedef struct rect
{
    ULONG ulWidth;
    ULONG ulHeight;
}Rect;

Rect stRect = {1920, 1080};
Rect *pstRect = &stRect;
  1. 查看結構體stRect的內容

(gdb) p stRect

  1. 查看結構體stRect中ulWidth的值

(gdb) p stRect.ulWidth 或者 p pstRect->ulWidth

  1. 查看結構體stRect的地址

(gdb) p &stRect

例2:

#define MAX_SIZE 10
ULONG i = 0;
ULONG aulArray[MAX_SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};

ULONG *pulArrayCopy = malloc(MAX_SIZE);
for (i = 0; i < MAX_SIZE; i++)
{
    pulArrayCopy[i] = aulArray[i];
}

free(pulArrayCopy);
  1. 查看數組aulArray中第5個元素的值

    (gdb) p aulArray[4]

  2. 查看數組aulArray全部的元素

    (gdb) p aulArray

  3. 查看動態數組pulArrayCopy全部的元素

    (gdb) p *pulArrayCopy@MAX_SIZE

print輸出格式:

​ print默認是根據表達式的類型自動顯示的,在大多數情況下都可以工作的很好,但是在print中可以指定輸出格式得到個性化得顯示結果。

  1. p/x i,以十六進制打印變量i的值。

  2. p/d|u i,以有符號|無符號十進制整數打印。
  3. p/c cEnd,以十進制和字符的方式顯示。
  4. p/f fPos,以浮點數的方式顯示。
  5. p/s pHelloStr,以字符串的方式顯示pHelloStr。

3. examine

x,查看內存地址中的值。它與print作用類似,但適用性更廣。

x/nfu addr,x命令有三個可選參數。

​ n:顯示數目。

​ f:顯示格式,與print格式類似,默認以十六進制顯示。

​ u:顯示單位字節大小,b(bytes,1字節)、h(半字,2字節)、w(字,4字節)、g(gaint字,8字節)。

  1. 查看數組aulArray中第5個元素的值

    (gdb) x/u aulArray[4]等價於(gdb) x/1uw aulArray[4]

  2. 查看數組aulArray全部的元素

    (gdb) x/10u aulArray或者(gdb) x/10uw aulArray

  3. 查看字符串pHelloStr內容

    char acHelloStr[10] = "Hello gdb!";

    (gdb) x/10c acHelloStr或者(gdb) x/s acHelloStr

examine命令相較於print命令適用性更廣的地方在於它能夠直接查看內存地址中的內容。

假設已知數組aulArray的地址爲0x7fffffffde30,數組大小爲10,若想查看數組元素的值,那麼就可以這樣查看:

x/10uw 0x7fffffffde30或者p *0x7fffffffde30@10

4. frame

查看指定的棧幀,用法如:f n,查看編號爲n的棧幀。

5. up/down

基於當前的棧幀向上或者向下移動棧幀。

6. info

  1. info locals,查看當前棧幀當中全部的局部變量的數值。
  2. info threads,查看當前進程中運行的所有線程的信息,若需要查看某個線程的棧幀,則執行thread n切換到編號爲n的線程,然後執行bt命令即可查看棧幀。
  3. info args,查看當前函數的參數值。

7. dump

將指定的一段地址(從start_addr 到end_addr)中的內存數據寫入名爲filename 的文件中。

dump memory filename start_addr end_addr

4. 參考資料

  1. GNU GDB調試手冊
  2. Linux GDB調試指南
  3. 100個gdb小技巧
  4. 《Debug.Hacks中文版_深入調試的技術和工具》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章