1. 程式人生 > >GDB偵錯程式使用總結

GDB偵錯程式使用總結

概述:GDB是linux下除錯程式的神器,做為linux程式設計師,如果不能熟練的使用GDB進行程式除錯,那將是很失敗的事情。強大的功能使GDB的使用也變得比較複雜,如果是初學者肯定會比繁雜的命令嚇到。下面是整理的一些我認為會比較有幫助的部分。下文中以">"開頭的命令是linux的shell命令,以"(GDB)"開頭的則是GDB內部命令。

0.轉儲功能(core dump):

    (1).開啟轉儲功能:首先用 >ulimit -c 檢視是否開啟轉儲功能,如果命令返回不是0則已經開啟,否則就是未開啟。>ulimit -c unlimited 命令可以開啟轉儲功能。也可以用 >ulimit -c 1024來設定轉儲檔案的大小。     (2).設定轉儲檔案生成地址:
編輯/etc/sysctl.conf檔案,在檔案最後加入下列兩行:         kernel.core_pattern = /var/core/%t-%e-%p.core         kernel.core_uses_pid = 0     然後將檔案儲存起來,儲存完成之後執行:>sysctl -p命令(注意:執行這個命令需要root許可權。)。此時執行一個會當機的程式,會在/var/core/資料夾下面生成轉儲檔案(例如:1432378356-a.out-4821.core)。上面設定的檔名是有固定格式的,core_pattern中設定的就是檔案儲存目錄和檔案的名字格式。其中%t是轉儲時的unix時間戳,%e是當前執行的檔名,%p是crash程序的PID。格式符說明如下:
格式符號 說明
%% %字元本身
%p 被轉儲程序的程序ID(PID)
%u 被轉儲程序的真是使用者ID(UID)
%g 被轉儲程序的真是組(GID)
%s 引發轉儲的訊號編號
%t 轉儲時間,unix時間戳(從1970年1月1日0時開始的秒數)
%h 主機名
%e 可執行檔案的名稱
%c 轉儲檔案的大小上限(核心版本2.6.24以後可使用)
    (3).轉儲檔案的壓縮:通過在/etc/sysctl.conf檔案的core_pattern中加入壓縮指令碼以及管道命令,可以對生成的轉儲檔案進行壓縮。首先在/etc/sysctl.conf檔案中加入下列兩行(如果已經存在則修改成下面的形式):         kernel.core_pattern = |/usr/localsbin/zipsh %t %e %p         kernel.core_uses_pid = 0     儲存檔案,然後執行:>sysctl -p命令。     /usr/local/sbin/zipsh檔案的內容如下:         #!/bin/sh         exec gzip - > /var/core/$1-$2-$3.core.gz     這樣的話,以後都會在/var/core下生成壓縮的轉儲檔案。
1.基本資訊檢視:
    (1).棧資訊:不管是操作轉儲檔案還是用GDB設定斷點進行除錯,都可以輸入(GDB)bt列印棧內容進行檢視。一般的當機BUG,看下當機的位置,然後看下原始碼基本就可以解決了。但是很多情況下簡單的(GDB)bt還查不到問題,這時候就要涉及到比較複雜的操作。下面羅列了一些對棧的操作:         (GDB) bt:顯示所有棧幀。         (GDB) bt 10:顯示前面10個棧幀。         (GDB) bt -10:顯示後面10個棧幀。         (GDB) bt full:顯示棧幀以及區域性變數。         (GDB) bt full 10:顯示前面10個棧幀以及區域性變數。         (GDB) bt full -10:顯示後面10個棧幀以及區域性變數。         (GDB) frame <棧幀編號>:進入指定的棧幀中,然後可以檢視當前棧幀中的區域性變數,以及棧幀內容等資訊。         (GDB) info frame <棧幀編號>:可以檢視指定棧幀的詳細資訊。         (GDB) up:進入上層棧幀。         (GDB) down:進入下層棧幀。     (2).變數:除錯BUG過程中檢視變數資訊是很有幫助的操作,檢視方式如下:         (GDB) p <變數名>     (3).暫存器:對於除錯來說暫存器中的值也很重要,可以檢視到當前正在執行的指令的地址等。具體操作羅列如下:            (GDB) info reg:顯示所有暫存器。可以簡寫為:i r。如果要檢視具體的暫存器可以這樣:i $ebx         (GDB) p $eax:顯示eax暫存器內容。         (GDB) p/c $eax:用字元顯示eax暫存器內容,反斜槓後面的是顯示格式,可使用的格式見下表:該表在顯示記憶體內容的x命令中也是通用的。
格式 說明
x 顯示為十六進位制數
d 顯示為十進位制數
u 顯示為無符號十進位制數
o 顯示為八進位制數
t 顯示為二進位制數
a 顯示為地址
c 顯示為字元(ASCII)
f 顯示為浮點小數
s 顯示為字串
i 顯示為機器語言(僅在顯示記憶體的x命令中可用)
    (4).記憶體:可以檢視具體記憶體地址中的內容,比如:目前執行的彙編指令,以及棧中內容等。         (GDB) x $pc:顯示程式指標指向位置的內容。         (GDB) x/i $pc:顯示程式當前位置的彙編指令。         (GDB) x/10i $pc:顯示程式當前位置開始往後的10條彙編指令。         (GDB) disassem $pc:反彙編當前函式。簡寫為:disas $pc。 2.除錯:     (1).斷點:除錯程式中,設定斷點進行除錯是最方便有效的手段,因此學會如果靈活設定斷點是除錯的基本功。:         A.設定斷點:             (GDB) break <函式名>:對當前正在執行的檔案中的指定函式設定斷點。可簡寫為:(GDB) b <函式名>             (GDB) break <行號>:對當前正在執行的檔案中的特定行設定斷點。可簡寫為:(GDB) b <行號>             (GDB) break <檔名:行號>:對指定檔案的指定行設定斷點。最常用的設定斷點方式。可簡寫為:(GDB) b <檔名:行號>             (GDB) break <檔名:函式名>:對指定檔案的指定函式設定斷點。C++類中的方法似乎不好使。可簡寫為:(GDB) b <檔名:函式名>             (GDB) break <+/-偏移量>:當前指令行+/-偏移量出設定斷點。可簡寫為:b <+/-偏移量>             (GDB) break <*地址>:指定地址處設定斷點。可簡寫為:b <*地址>         B.檢視、刪除斷點:                         (GDB) info break :顯示所有斷點以及監視點。可簡寫為:(GDB) i b             (GDB) delete <編號>:刪除編號指向的斷點或者監視點。可簡寫為:(GDB) d <編號>             (GDB) clear <行號>:刪除改行的斷點。             (GDB) clear <檔名:行號>:刪除改行的斷點。         C.設定無效、有效斷點:             (GDB) disable <斷點編號> : 當前斷點設定為無效。             (GDB) enable <斷點編號>:當前斷點設定為有效。                  (2).監視點:可以監視某個變數,在變數被訪問或者被修改時程式會在當前點進入斷點。刪除,檢視監視點的方式與斷點相同。設定監視點方式如下:                     (GDB) watch <表示式>:表示式發生變化時暫停。         (GDB) awatch <表示式>:表示式訪問或者改變時暫停。         (GDB) rwatch <表示式>:表示式被訪問時暫停。     (3).條件斷點:在除錯程式過程中,有時候我們只想在某個條件下停止程式,然後進行單步除錯,而條件斷點就是為此而設計。下面是條件斷點的操作方式:             (GDB) b <斷點> if <條件表示式> : 例如:b main.cpp:8 if x=10 && y=10         (GDB) condition <斷點編號>:刪除該斷點的條件。         (GDB) condition <斷點編號> <條件表示式>:修改斷點條件。例如:condition 1 x=10 && y=10     (4).斷點命令:每次斷點發生時候,想要檢視的變數很多時,如果每個變數都手動print則需要浪費很多時間。斷點命令可以在斷點發生時批量執行GDB命令。下面是斷點命令的設定方式:         (GDB) commands <斷點編號>         (GDB) >print x         (GDB) >print y         (GDB) >end         首先輸入GDB命令commands <斷點編號>然後回車,這時候會出現>提示符。出現>提示符後可以輸入斷點發生時需要執行的GDB命令,每行一條,全部輸入完成後輸入end結束斷點命令。     (5).反覆執行:單步執行時如果進入了你不關心的函式,你想立即跳出函式;或者進入了大迴圈中,你想立即迴圈。下面的命令可以幫到你:             (GDB) ignore <斷點編號> <次數>:忽略N次斷點。         (GDB) c N: 執行N次指令,會忽略斷點。         (GDB) s/stepi/n/nexti N:往後執行N行,不會忽略斷點。         (GDB) finish:執行完當前函式後停止,不會忽略斷點。         (GDB) until:執行完當前迴圈後停止,不會忽略斷點。         (GDB) until <地址>:執行到指定地址停止。     (6).設定變數值:對變數的值進行控制,可以更快的除錯自己的程式。下面就是設定變數值的方法:          (GDB) set variable <變數> = <表示式>:將變數的值設定為指定表示式的值。例如 set variable x=10     (7).手動生成轉儲檔案:         (GDB) generate-core-file 簡寫為:(GDB) gcore 3.除錯線上程序:     (1).啟動GDB時連結目標程序:在啟動GDB的時候,通過引數-p指定目標程序,就可以進入除錯狀態。剛連結成功後,程式是暫停執行狀態,你可以進行設定斷點等操作,然後輸入(GDB) c 命令繼續執行。命令如下:         >gdb -p <PID>:PID是程序ID,可以通過>ps aux | grep <程式名> 獲得。或者直接 >gdb -p  `pidof <程式名>`也可以。>pidof <程式名>是通過名字獲取程序ID的命令。     (2).GDB中連結目標程序:         (GDB) attach <PID>     (3).斷開連結:         (GDB) detach 4.除錯多執行緒程式:     (1).檢視執行緒:         (GDB) info thread:檢視所有執行緒資訊,可簡寫為:i thr     (2).切換到指定執行緒:          (GDB) thread <執行緒編號>:選中出現問題的執行緒,可簡寫為:thr <執行緒編號>     (3).除錯守護者程序:守護者程序在啟動好子程序後,會自動關閉主程序,如果沒有設定監控模式的話,GDB會提示斷開與程序的連結。所以必須設定監控物件,設定方式如下:         (GDB) set follow-fork-mode child/parent