轉載:http://blog.csdn.net/horkychen
GDB使用介紹
在Linux下最強大的Debug工具就是GDB了,許多IDE都集成了GDB進行調試。使用源代碼級調試能夠更直接的進行調試,效率明顯高於輸出Log信息。但目前無論是Mac下的XCode,還是Linux下的其它集成工具,對於調試庫函數都是相當困難的,如果直接使用GDB這些問題就迎刃而解。我們首先來探討一下GDB的基礎知識。
GDB調試流程
GDB調試依賴於編譯器輸出的調試信息,所以進行調試前必須確定GCC輸出了調試信息。
1.生成符號文件
使用GCC編譯時需要生成相應的調試信息,編譯時可以使用-g選項:
<<詳細內容參GCC Manual>> Section 3.9
-g 表示將Symbol Table以系統原生格式直接生成到可執行文件中
-g選項最好不要同-O一起使用,因爲代碼經過優化後有時會同源代碼差異很大,可能找不到指定的變量等等。
-ggdb 表示將專門爲GDB調試使用生成調試信息,它會包括很多GDB的擴展信息
其它的Symbol Table的格式還有COFF,DWARF,Stabs等. (Mac OS默認爲DWARF. DWARF也是基於COFF實現[Common Object File Format])
輸出的調試信息的多少由三個等級:
-g[level] 默認爲2
0 表示不生成任何調試信息
1 表示生成最少的調試信息,不提供局部變量及源代碼行列等信息。
2 標準模式
3 較2而言,包含了宏定義等額外信息
其它同調試相關的編譯選項還有:
-p 生成額外的代碼用於輸出profile信息,用於另一個工具程序使用:prof
--coverage 用於統於代碼的覆蓋率.
--ftest-coverage 類似上面的--coverage
-d* 用於Dump一些有用的信息,詳細內容參GDB Manual.
2.啓動GDB進行調試
下面的過程,我都以下面的工程進行解釋:
目標程序: text2bin
源代碼:text2bin.c
功能: 將文本文件轉成二進制文件
使用方法: ./text2bin txt_file_name [offset]
txt_file_name爲源文本文件名
offset指定忽略左側多少字節
A.調試應用程序
(1)啓動
直接在命令行下輸入gdb ./text2bin 或者運行gdb後輸入file ./text2bin都可以加載指定的應用程序.
GDB會顯示加載Symbols的過程,注意如果沒有出現加載text2bin的調試信息的過程,就是表明無法獲取調試信息!
Reading symbols for shared libraries ... done
Reading symbols from /Horky/Project/WINBASE/WINBASE/TextToRaw/text2bin...
warning: UUID mismatch detected between:
/Horky/Project/WINBASE/WINBASE/TextToRaw/text2bin
(2)設置斷點
*除了斷點外還有Watchpoints(觀測點)及Catchpoints (異常捕捉點)
輸入b或break加上斷點位置或斷點函數名,如
b main #在main函數入口設置斷點
b text2bin.c:50 在源代碼第50行設置斷點
如果需要查看斷點信息可以使用指令:
info breakpoints
清除所有斷點使用指令:
clear
清除特定的斷點使用指令:
clear text2bin.c:50
或 clear main
在調試過程可以使用disable及enable開關某個特定的斷點.如enable 2及 disable 2開關第2個斷點。
在使用info b查看斷點時,注意其中Enb欄位的變化。
對於觀測點(Watchpoints),是指在某個條件下觸發的斷點,如text2bin中77行:
Buffer2[nCount++] = ConvertTextToInt(sData);
我們要查看當nCount爲10時的運行狀況,我們可以通過下面的步驟完成:
a. 執行b 77,返回這個斷點號是3
b. 執行condition 3 nCount=10
過程如下:
(gdb) b 77
Breakpoint 3 at 0x1c73: file text2bin.c, line 77.
(gdb) condition 3 nCount=10
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00001e1e in ConvertTextToInt at text2bin.c:124
breakpoint already hit 1 time
2 breakpoint keep y 0x00001e25 in ConvertTextToInt at text2bin.c:125
3 breakpoint keep y 0x00001c73 in main at text2bin.c:77
stop only if nCount = 10
這樣就可以控制當nCount爲10時在77行處中斷.
如果在調試時,需在下面若干行代碼後追加一個斷點,在指定位置可以使用偏移量來指定斷點,
如b +5 及b -5,即表示在當前行的後五行及前五行位置設置斷點
(3)控制調試過程
在開始時需要告訴GDB目標程序是哪一個,可以用gdb ./text2bin,也可以在啓動gdb後使用指令:
file ./text2bin來指定。
運行則使用r/run指令,可以同時帶上參數,如
r ./expert.txt 7
在調試過程中需要有一系列操作控制調試的過程:
c / continue /fg
*fg是foreground的縮寫
從斷點狀態恢復程序的執行.
s / step [count]
單步執行 (step in)
n / next [count]
單步執行,跳過函數 (step out)
u / until [location]
執行到某個位置。 當遇到循環時可以使用此指令方便地跳轉到指定的位置。
finish
執行到當前函數結束位置爲止,同時顯示函數返回值
backtrace
查看當前位置的被調用路徑
(4)監測變量及內存
簡單地顯示變量的值可以使用print指令直接輸出.
p / print [expression]
如輸出main函數中的文件名變量 p argv[1]
輸出ConvertTextToInt函數中n的值 p n或p ConvertTextToInt::n
查看內存內容時則使用x指令:
x /nfu addr 以指定格式顯示內存內容
x addr 顯示指定地址處理內存內容
x 顯示當前數據段內容
如以字串形顯示某內存內容的指令爲:
x /sb 0xbffff80e
以數據形式顯示某內存中5個字節的內容的指令爲:
x /5db 0xbffff80e
設定local variable watch,用來在每條執行後顯示某些變量的值,可以使用display指令來指定,如:
display S
display /sb 0xbffff707
去除時使用undisplay # (#爲display列表中的序號)
display後面所帶的參數同x指令:
n 表示repeat count
f 表示格式,分爲:
x 十六制數據
d 帶符號之整型數據
u 無符號整型數據
o 八進制整型數據
t 二進制數據
a 以地址格式顯示,包括十六進制及偏移量
c 以字符形式輸出
f 小數位輸出
s 以字串形式輸出
u表示大小單位:
b Bytes
h Halfwords
w Words
g Giant words (eight bytes)
(5)查看源代碼
使用l / list指令就可查看源代碼了,
如:
l 150 查看當前代碼的第150行
l text2bin.c:150 查看text2bin.c的150行.
l main 查看main函數內容
查看時如果需要翻頁,直接回車.
默認GDB一次顯示10行,我們也可以通過set linesize [count]進行調整。
B.如何調試動態庫或靜態庫
當調試庫函數時,需要透過主程序調用的形式來掛載,所以不能直接使用GDB對目標庫進行調試,而是需要attach指定的父進程,然後再進行測試.這裏有兩種情況:
(1)主程序啓動時自動加載庫,此時使用GDB掛載時也會自動加載相應的調試信息.
(2)主程序動態加載庫,對於這種情況則需要另外使用symbol filename來加載特定的調試信息。
*提醒:當進行多線程調試時,一定要確保能找出真正的主線程。
*斷開主線程時,使用detach指令來完成
C.如何調試多線程的程序
我們在寫程序時常常會有多線程的運用, 比如有些程序中讀取數據及數據處理,就是通過兩個線程來完成的。對
多線程進行調試最大的難點在於線程的同步問題.
GDB提供了一套指令針對多線程:
info threads
查看當前有多少線程
thread #
切換到指定線程
set print thread-events on/off
設定是否打印線程狀態
當設置中斷時,也可以專爲某個線程設置,如
b/break [location] thread #
即表示爲#線程在location處設置斷點,這樣就可以進行線程別的調試。
3. 技巧
(1)在GDB中如果需要調用外部程序可以使用shell [command]來完成
(2)當源代碼目錄被移動了,或者在另一臺PC上調試,GDB不能通過Debug信息找到源代碼時,可以使用directory/dir來指搜索的目錄
4.GDB的前臺程序(GDB frontend)
使用命令行是顯得不方便了,所以我們可以選擇一些GDB前端程序:
DDD [GNU] (http://www.gnu.org/software/ddd 目前功能最爲強大的GDB前端程序)
Nemiver [GNOME] (http://home.gna.org/nemiver/)
Kdbg [KDE] (www.kdbg.org)
Insight [Wirte in Tcl/Tk] (http://sourceware.org/insight)
Emacs (不用介紹了!)
一般的IDE也帶有GDB frontend程序,如XCode,KDevelop,Anjuta,Eclipse.
*GDB Frontend都是通過僞終端(pseudo-terminal)的方式來實現,有興趣可以瞭解一下.
擴展GDB的功能
已經有人在通GDB進行代碼覆蓋率測試,事實上我們也可以通過類似GDB的方式讀取Debug信息中的符號表來進行語法檢查。有關Debug信息的存放,可以使用objdump -x或readelf -a來查看其中的不同,這有助更好的理解程序的結構.
需求是多樣的,GDB本身提供了兩種方式來擴展GDB,一種爲組合GDB的指令,類似宏的方式,另一種方式則是功能強大的python腳本。
(1)在GDB環境下使用define指令來定義一個指令,如
define localv
info scope $arg0
end
這樣我們在使用時,想查看main函數中的所有的變量,就可以通過下面的指令完成:
(gdb) localv main
Scope for main:
Symbol argc is at the address (reg 5 + 8), length 4.
Symbol argv is at the address (reg 5 + 12), length 4.
Symbol fpSrc is at the address (reg 5 + -44), length 4.
......
如果這樣的指令非常好用,每次調試時都定義一次不太現實。所以GDB允許將這些操作定義在一個文本文件中,然後在GDB中使用source [command_file]來執行,如source /TestData/localv.cmd 。
在執行過程中GDB不會顯示每個指令的執行結果,如果需要顯示就在source加-v來打開。
除了組織指令集外,還有另一種有用的自定義指令: Hooks. GDB允許用戶指定在特定的GDB指令執行前後執行一段自定義指令。比如,如果希望在設置斷點前後都顯示當前斷點狀況,就可以定義兩個如下指令:
(gdb) define hook-break
Type commands for definition of "hook-break".
End with a line saying just "end".
>info b
>end
(gdb) define hookpost-break
Type commands for definition of "hookpost-break".
End with a line saying just "end".
>info b
>end
然後執行break / b指令時就可以看到類似下面的輸出:
(gdb) b GetFileSize
Num Type Disp Enb Address What
1 breakpoint keep y 0x00001a68 in main at text2bin.c:25
2 breakpoint keep y 0x00001e1e in ConvertTextToInt at text2bin.c:124
Breakpoint 3 at 0x1d86: file text2bin.c, line 108.
Num Type Disp Enb Address What
1 breakpoint keep y 0x00001a68 in main at text2bin.c:25
2 breakpoint keep y 0x00001e1e in ConvertTextToInt at text2bin.c:124
3 breakpoint keep y 0x00001d86 in GetFileSize at text2bin.c:108
hook及hookpost即表示在某個指令的前後。後面的指令一定要使用GDB指令的全寫,如上面就不能寫成define hook-b或define hookpost-b。
*如果需要更爲詳細的資料,請參考GDB Manual,20. Extending GDB
(2)在GDB環境可以直接調用python,如在GDB環境下執行python print 23
使用Python編寫腳本同上面定義指令集是類似的,可以執行指令python, GDB就會要求輸入python腳本,並以end爲結束標誌。
GDB爲編寫Python提供了一個新的模塊gdb,在腳本中可以進行引用,其中包括了幾個主要的指令:
execute command command是GDB CLI(Command Line Interface)指令字串.
get_parameter parameter 獲取一項GDB的參數,諸如上面提到的linesize.
write string 輸出一個字串到GDB輸出窗口
flush Flush當前GDB輸出流
*只有當編譯GDB時指定了—with-python時,GDB纔會支持python指令.
參考文檔:
(1) 使用GDB進行代碼覆蓋率測試
http://www.ibm.com/developerworks/cn/linux/l-cn-gdb/
(2) 使用 GDB 調試 Linux軟件
http://www.ibm.com/developerworks/cn/linux/sdk/gdb/
(3) 掌握 Linux 調試技術
http://www.ibm.com/developerworks/cn/linux/sdk/l-debug/
(4) 用GDB調試程序
http://docs.chinalinuxpub.com/doc/pro/gdb.html
(5) GDB調試精粹及使用實例
http://fanqiang.chinaunix.net/program/other/2006-07-14/4834.shtml
(6) GDB的官方文檔
http://www.gnu.org/software/gdb/documentation/
(7) GDB指令參考 (可以打出來方便查詢)
http://users.ece.utexas.edu/~adnan/gdb-refcard.pdf