用GDB調(diào)試程序 GDB概述 2
使用GDB 5 GDB中運(yùn)行UNIX的shell程序 8
在GDB中運(yùn)行程序 8
調(diào)試已運(yùn)行的程序 兩種方法: 9
暫停 / 恢復(fù)程序運(yùn)行 9
一、設(shè)置斷點(diǎn)(BreakPoint) 9
二、設(shè)置觀察點(diǎn)(WatchPoint) 10
三、設(shè)置捕捉點(diǎn)(CatchPoint) 10
四、維護(hù)停止點(diǎn) 11
五、停止條件維護(hù) 12
六、為停止點(diǎn)設(shè)定運(yùn)行命令 12
七、斷點(diǎn)菜單 13
八、恢復(fù)程序運(yùn)行和單步調(diào)試 13
九、信號(hào)(Signals) 14
十、線程(Thread Stops) 15
查看棧信息 16
查看源程序 18
一、顯示源代碼 18
二、搜索源代碼 19
三、指定源文件的路徑 19
四、源代碼的內(nèi)存 20
查看運(yùn)行時(shí)數(shù)據(jù) 21
一、表達(dá)式 21
二、程序變量 21
三、數(shù)組 22
四、輸出格式 23
五、查看內(nèi)存 23
六、自動(dòng)顯示 24
七、設(shè)置顯示選項(xiàng) 25 GDB中關(guān)于顯示的選項(xiàng)比較多,這里我只例舉大多數(shù)常用的選項(xiàng)。 25
八、歷史記錄 27
九、GDB環(huán)境變量 28
十、查看寄存器 28
改變程序的執(zhí)行 29
一、修改變量值 29
二、跳轉(zhuǎn)執(zhí)行 29
三、產(chǎn)生信號(hào)量 30
四、強(qiáng)制函數(shù)返回 30
五、強(qiáng)制調(diào)用函數(shù) 30
在不同語(yǔ)言中使用GDB 31
后記 32 GDB概述 GDB是GNU開(kāi)源組織發(fā)布的一個(gè)強(qiáng)大的UNIX下的程序調(diào)試工具;蛟S,各位比較喜歡那種圖形界面方式的,像VC、BCB等IDE的調(diào)試,但如果你是在UNIX平臺(tái)下做軟件,你會(huì)發(fā)現(xiàn)GDB這個(gè)調(diào)試工具有比VC、BCB的圖形化調(diào)試器更強(qiáng)大的功能。所謂“寸有所長(zhǎng),尺有所短”就是這個(gè)道理。
一般來(lái)說(shuō),GDB主要幫忙你完成下面四個(gè)方面的功能:
1、啟動(dòng)你的程序,可以按照你的自定義的要求隨心所欲的運(yùn)行程序。
2、可讓被調(diào)試的程序在你所指定的調(diào)置的斷點(diǎn)處停住。(斷點(diǎn)可以是條件表達(dá)式)
3、當(dāng)程序被停住時(shí),可以檢查此時(shí)你的程序中所發(fā)生的事。
4、動(dòng)態(tài)的改變你程序的執(zhí)行環(huán)境。
從上面看來(lái),GDB和一般的調(diào)試工具沒(méi)有什么兩樣,基本上也是完成這些功能,不過(guò)在細(xì)節(jié)上,你會(huì)發(fā)現(xiàn)GDB這個(gè)調(diào)試工具的強(qiáng)大,大家可能比較習(xí)慣了圖形化的調(diào)試工具,但有時(shí)候,命令行的調(diào)試工具卻有著圖形化工具所不能完成的功能。讓我們一一看來(lái)。
一個(gè)調(diào)試示例
——————
源程序:tst.c
1 #include ;
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i; cc -g tst.c -o tst
使用GDB調(diào)試:
hchen/test>; gdb tst ;
2
3 int func(int n)
4 {
5 int sum=0,i;
6 for(i=0; i;
好了,有了以上的感性認(rèn)識(shí),還是讓我們來(lái)系統(tǒng)地認(rèn)識(shí)一下gdb吧。
使用GDB
一般來(lái)說(shuō)GDB主要調(diào)試的是C/C++的程序。要調(diào)試C/C++的程序,首先在編譯時(shí),我們必須要把調(diào)試信息加到可執(zhí)行文件中。使用編譯器(cc/gcc/g++)的 -g 參數(shù)可以做到這一點(diǎn)。如:
>; cc -g hello.c -o hello
>; g++ -g hello.cpp -o hello
如果沒(méi)有-g,你將看不見(jiàn)程序的函數(shù)名、變量名,所代替的全是運(yùn)行時(shí)的內(nèi)存地址。當(dāng)你用-g把調(diào)試信息加入之后,并成功編譯目標(biāo)代碼以后,讓我們來(lái)看看如何用gdb來(lái)調(diào)試他。
啟動(dòng)GDB的方法有以下幾種:
1、gdb ;
program也就是你的執(zhí)行文件,一般在當(dāng)然目錄下。
2、gdb ; core
用gdb同時(shí)調(diào)試一個(gè)運(yùn)行程序和core文件,core是程序非法執(zhí)行后core dump后產(chǎn)生的文件。
3、gdb ; ;
如果你的程序是一個(gè)服務(wù)程序,那么你可以指定這個(gè)服務(wù)程序運(yùn)行時(shí)的進(jìn)程ID。gdb會(huì)自動(dòng)attach上去,并調(diào)試他。program應(yīng)該在PATH環(huán)境變量中搜索得到。 GDB啟動(dòng)時(shí),可以加上一些GDB的啟動(dòng)開(kāi)關(guān),詳細(xì)的開(kāi)關(guān)可以用gdb -help查看。我在下面只例舉一些比較常用的參數(shù):
-symbols ;
-s ;
從指定文件中讀取符號(hào)表。
-se file
從指定文件中讀取符號(hào)表信息,并把他用在可執(zhí)行文件中。
-core ;
-c ;
調(diào)試時(shí)core dump的core文件。
-directory ;
-d ;
加入一個(gè)源文件的搜索路徑。默認(rèn)搜索路徑是環(huán)境變量中PATH所定義的路徑。
啟動(dòng)gdb后,就你被帶入gdb的調(diào)試環(huán)境中,就可以使用gdb的命令開(kāi)始調(diào)試程序了,gdb的命令可以使用help命令來(lái)查看,如下所示:
/home/hchen>; gdb
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-suse-linux".
(gdb) help
List of classes of commands:
aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands
Type "help" followed by a class name for a list of commands in that class.
Type "help" followed by command name for full documentation.
Command name abbreviations are allowed if unambiguous.
(gdb) gdb的命令很多,gdb把之分成許多個(gè)種類。help命令只是例出gdb的命令種類,如果要看種類中的命令,可以使用help ; 命令,如:help breakpoints,查看設(shè)置斷點(diǎn)的所有命令。也可以直接help ;來(lái)查看命令的幫助。 gdb中,輸入命令時(shí),可以不用打全命令,只用打命令的前幾個(gè)字符就可以了,當(dāng)然,命令的前幾個(gè)字符應(yīng)該要標(biāo)志著一個(gè)唯一的命令,在Linux下,你可以敲擊兩次TAB鍵來(lái)補(bǔ)齊命令的全稱,如果有重復(fù)的,那么gdb會(huì)把其例出來(lái)。
示例一:在進(jìn)入函數(shù)func時(shí),設(shè)置一個(gè)斷點(diǎn)?梢郧萌隻reak func,或是直接就是b func
(gdb) b func
Breakpoint 1 at 0x8048458: file hello.c, line 10.
示例二:敲入b按兩次TAB鍵,你會(huì)看到所有b打頭的命令:
(gdb) b
backtrace break bt
(gdb)
示例三:只記得函數(shù)的前綴,可以這樣:
(gdb) b make_ ;
(再按下一次TAB鍵,你會(huì)看到:)
make_a_section_from_file make_environ
make_abs_section make_function_type
make_blockvector make_pointer_type
make_cleanup make_reference_type
make_command make_symbol_completion_list
(gdb) b make_ GDB把所有make開(kāi)頭的函數(shù)全部例出來(lái)給你查看。
示例四:調(diào)試C++的程序時(shí),有可以函數(shù)名一樣。如:
(gdb) b 'bubble( M-?
bubble(double,double) bubble(int,int)
(gdb) b 'bubble(
你可以查看到C++中的所有的重載函數(shù)及參數(shù)。(注:M-?和“按兩次TAB鍵”是一個(gè)意思)
要退出gdb時(shí),只用發(fā)quit或命令簡(jiǎn)稱q就行了。 GDB中運(yùn)行UNIX的shell程序
在gdb環(huán)境中,你可以執(zhí)行UNIX的shell的命令,使用gdb的shell命令來(lái)完成:
shell ;
調(diào)用UNIX的shell來(lái)執(zhí)行;,環(huán)境變量SHELL中定義的UNIX的shell將會(huì)被用來(lái)執(zhí)行;,如果SHELL沒(méi)有定義,那就使用UNIX的標(biāo)準(zhǔn)shell:/bin/sh。(在Windows中使用Command.com 或cmd.exe)
還有一個(gè)gdb命令是make:
make ;
可以在gdb中執(zhí)行make命令來(lái)重新build自己的程序。這個(gè)命令等價(jià)于“shell make ;”。
在GDB中運(yùn)行程序
當(dāng)以gdb ;方式啟動(dòng)gdb后,gdb會(huì)在PATH路徑和當(dāng)前目錄中搜索;的源文件。如要確認(rèn)gdb是否讀到源文件,可使用l或list命令,看看gdb是否能列出源代碼。
在gdb中,運(yùn)行程序使用r或是run命令。程序的運(yùn)行,你有可能需要設(shè)置下面四方面的事。
1、程序運(yùn)行參數(shù)。
set args 可指定運(yùn)行時(shí)參數(shù)。(如:set args 10 20 30 40 50)
show args 命令可以查看設(shè)置好的運(yùn)行參數(shù)。
2、運(yùn)行環(huán)境。
path ; 可設(shè)定程序的運(yùn)行路徑。
show paths 查看程序的運(yùn)行路徑。
set environment varname [=value] 設(shè)置環(huán)境變量。如:set env USER=hchen
show environment [varname] 查看環(huán)境變量。
3、工作目錄。
cd ; 相當(dāng)于shell的cd命令。
pwd 顯示當(dāng)前的所在目錄。
4、程序的輸入輸出。
info terminal 顯示你程序用到的終端的模式。
使用重定向控制程序輸出。如:run >; outfile
tty命令可以指寫輸入輸出的終端設(shè)備。如:tty /dev/ttyb
調(diào)試已運(yùn)行的程序 兩種方法:
1、在UNIX下用ps查看正在運(yùn)行的程序的PID(進(jìn)程ID),然后用gdb ; PID格式掛接正在運(yùn)行的程序。
2、先用gdb ;關(guān)聯(lián)上源代碼,并進(jìn)行gdb,在gdb中用attach命令來(lái)掛接進(jìn)程的PID。并用detach來(lái)取消掛接的進(jìn)程。
暫停 / 恢復(fù)程序運(yùn)行
調(diào)試程序中,暫停程序運(yùn)行是必須的,GDB可以方便地暫停程序的運(yùn)行。你可以設(shè)置程序的在哪行停住,在什么條件下停住,在收到什么信號(hào)時(shí)停往等等。以便于你查看運(yùn)行時(shí)的變量,以及運(yùn)行時(shí)的流程。
當(dāng)進(jìn)程被gdb停住時(shí),你可以使用info program 來(lái)查看程序的是否在運(yùn)行,進(jìn)程號(hào),被暫停的原因。
在gdb中,我們可以有以下幾種暫停方式:斷點(diǎn)(BreakPoint)、觀察點(diǎn)(WatchPoint)、捕捉點(diǎn)(CatchPoint)、信號(hào)(Signals)、線程停止(Thread Stops)。如果要恢復(fù)程序運(yùn)行,可以使用c或是continue命令。
一、設(shè)置斷點(diǎn)(BreakPoint)
info watchpoints
列出當(dāng)前所設(shè)置了的所有觀察點(diǎn)。
三、設(shè)置捕捉點(diǎn)(CatchPoint)
你可設(shè)置捕捉點(diǎn)來(lái)補(bǔ)捉程序運(yùn)行時(shí)的一些事件。如:載入共享庫(kù)(動(dòng)態(tài)鏈接庫(kù))或是C++的異常。設(shè)置捕捉點(diǎn)的格式為:
catch ;
當(dāng)event發(fā)生時(shí),停住程序。event可以是下面的內(nèi)容:
1、throw 一個(gè)C++拋出的異常。(throw為關(guān)鍵字)
2、catch 一個(gè)C++捕捉到的異常。(catch為關(guān)鍵字)
3、exec 調(diào)用系統(tǒng)調(diào)用exec時(shí)。(exec為關(guān)鍵字,目前此功能只在HP-UX下有用)
4、fork 調(diào)用系統(tǒng)調(diào)用fork時(shí)。(fork為關(guān)鍵字,目前此功能只在HP-UX下有用)
5、vfork 調(diào)用系統(tǒng)調(diào)用vfork時(shí)。(vfork為關(guān)鍵字,目前此功能只在HP-UX下有用)
6、load 或 load ; 載入共享庫(kù)(動(dòng)態(tài)鏈接庫(kù))時(shí)。(load為關(guān)鍵字,目前此功能只在HP-UX下有用)
7、unload 或 unload ; 卸載共享庫(kù)(動(dòng)態(tài)鏈接庫(kù))時(shí)。(unload為關(guān)鍵字,目前此功能只在HP-UX下有用)
tcatch ;
只設(shè)置一次捕捉點(diǎn),當(dāng)程序停住以后,應(yīng)點(diǎn)被自動(dòng)刪除。
四、維護(hù)停止點(diǎn)
上面說(shuō)了如何設(shè)置程序的停止點(diǎn),GDB中的停止點(diǎn)也就是上述的三類。在GDB中,如果你覺(jué)得已定義好的停止點(diǎn)沒(méi)有用了,你可以使用delete、clear、disable、enable這幾個(gè)命令來(lái)進(jìn)行維護(hù)。
clear
清除所有的已定義的停止點(diǎn)。
clear ;
clear ;
清除所有設(shè)置在函數(shù)上的停止點(diǎn)。
clear ;
clear ;
清除所有設(shè)置在指定行上的停止點(diǎn)。
delete [breakpoints] [range...]
刪除指定的斷點(diǎn),breakpoints為斷點(diǎn)號(hào)。如果不指定斷點(diǎn)號(hào),則表示刪除所有的斷點(diǎn)。range 表示斷點(diǎn)號(hào)的范圍(如:3-7)。其簡(jiǎn)寫命令為d。
比刪除更好的一種方法是disable停止點(diǎn),disable了的停止點(diǎn),GDB不會(huì)刪除,當(dāng)你還需要時(shí),enable即可,就好像回收站一樣。
disable [breakpoints] [range...]
disable所指定的停止點(diǎn),breakpoints為停止點(diǎn)號(hào)。如果什么都不指定,表示disable所有的停止點(diǎn)。簡(jiǎn)寫命令是dis.
enable [breakpoints] [range...]
enable所指定的停止點(diǎn),breakpoints為停止點(diǎn)號(hào)。
enable [breakpoints] once range...
enable所指定的停止點(diǎn)一次,當(dāng)程序停止后,該停止點(diǎn)馬上被GDB自動(dòng)disable。
enable [breakpoints] delete range...
enable所指定的停止點(diǎn)一次,當(dāng)程序停止后,該停止點(diǎn)馬上被GDB自動(dòng)刪除。
五、停止條件維護(hù)
前面在說(shuō)到設(shè)置斷點(diǎn)時(shí),我們提到過(guò)可以設(shè)置一個(gè)條件,當(dāng)條件成立時(shí),程序自動(dòng)停止,這是一個(gè)非常強(qiáng)大的功能,這里,我想專門說(shuō)說(shuō)這個(gè)條件的相關(guān)維護(hù)命令。一般來(lái)說(shuō),為斷點(diǎn)設(shè)置一個(gè)條件,我們使用if關(guān)鍵詞,后面跟其斷點(diǎn)條件。并且,條件設(shè)置好后,我們可以用condition命令來(lái)修改斷點(diǎn)的條件。(只有 break和watch命令支持if,catch目前暫不支持if)
condition ; ;
修改斷點(diǎn)號(hào)為bnum的停止條件為expression。
condition ;
清除斷點(diǎn)號(hào)為bnum的停止條件。
還有一個(gè)比較特殊的維護(hù)命令ignore,你可以指定程序運(yùn)行時(shí),忽略停止條件幾次。
ignore ; ;
表示忽略斷點(diǎn)號(hào)為bnum的停止條件count次。
六、為停止點(diǎn)設(shè)定運(yùn)行命令
我們可以使用GDB提供的command命令來(lái)設(shè)置停止點(diǎn)的運(yùn)行命令。也就是說(shuō),當(dāng)運(yùn)行的程序在被停止住時(shí),我們可以讓其自動(dòng)運(yùn)行一些別的命令,這很有利行自動(dòng)化調(diào)試。對(duì)基于GDB的自動(dòng)化調(diào)試是一個(gè)強(qiáng)大的支持。
commands [bnum]
... command-list ...
end
為斷點(diǎn)號(hào)bnum指寫一個(gè)命令列表。當(dāng)程序被該斷點(diǎn)停住時(shí),gdb會(huì)依次運(yùn)行命令列表中的命令。
例如:
break foo if x>;0
commands
printf "x is %d\n",x
continue
end
斷點(diǎn)設(shè)置在函數(shù)foo中,斷點(diǎn)條件是x>;0,如果程序被斷住后,也就是,一旦x的值在foo函數(shù)中大于0,GDB會(huì)自動(dòng)打印出x的值,并繼續(xù)運(yùn)行程序。
如果你要清除斷點(diǎn)上的命令序列,那么只要簡(jiǎn)單的執(zhí)行一下commands命令,并直接在打個(gè)end就行了。
七、斷點(diǎn)菜單
在C++中,可能會(huì)重復(fù)出現(xiàn)同一個(gè)名字的函數(shù)若干次(函數(shù)重載),在這種情況下,break ;不能告訴GDB要停在哪個(gè)函數(shù)的入口。當(dāng)然,你可以使用break ;也就是把函數(shù)的參數(shù)類型告訴GDB,以指定一個(gè)函數(shù)。否則的話,GDB會(huì)給你列出一個(gè)斷點(diǎn)菜單供你選擇你所需要的斷點(diǎn)。你只要輸入你菜單列表中的編號(hào)就可以了。如:
(gdb) b String::after
[0] cancel
[1] all
[2] file:String.cc; line number:867
[3] file:String.cc; line number:860
[4] file:String.cc; line number:875
[5] file:String.cc; line number:853
[6] file:String.cc; line number:846
[7] file:String.cc; line number:735
>; 2 4 6
Breakpoint 1 at 0xb26c: file String.cc, line 867.
Breakpoint 2 at 0xb344: file String.cc, line 875.
Breakpoint 3 at 0xafcc: file String.cc, line 846.
Multiple breakpoints were set.
Use the "delete" command to delete unwanted
breakpoints.
(gdb)
可見(jiàn),GDB列出了所有after的重載函數(shù),你可以選一下列表編號(hào)就行了。0表示放棄設(shè)置斷點(diǎn),1表示所有函數(shù)都設(shè)置斷點(diǎn)。
八、恢復(fù)程序運(yùn)行和單步調(diào)試
當(dāng)程序被停住了,你可以用continue命令恢復(fù)程序的運(yùn)行直到程序結(jié)束,或下一個(gè)斷點(diǎn)到來(lái)。也可以使用step或next命令單步跟蹤程序。
continue [ignore-count]
c [ignore-count]
fg [ignore-count]
恢復(fù)程序運(yùn)行,直到程序結(jié)束,或是下一個(gè)斷點(diǎn)到來(lái)。ignore-count表示忽略其后的斷點(diǎn)次數(shù)。continue,c,fg三個(gè)命令都是一樣的意思。
step ;
單步跟蹤,如果有函數(shù)調(diào)用,他會(huì)進(jìn)入該函數(shù)。進(jìn)入函數(shù)的前提是,此函數(shù)被編譯有debug信息。很像VC等工具中的step in。后面可以加count也可以不加,不加表示一條條地執(zhí)行,加表示執(zhí)行后面的count條指令,然后再停住。
next ;
同樣單步跟蹤,如果有函數(shù)調(diào)用,他不會(huì)進(jìn)入該函數(shù)。很像VC等工具中的step over。后面可以加count也可以不加,不加表示一條條地執(zhí)行,加表示執(zhí)行后面的count條指令,然后再停住。
set step-mode
set step-mode on
打開(kāi)step-mode模式,于是,在進(jìn)行單步跟蹤時(shí),程序不會(huì)因?yàn)闆](méi)有debug信息而不停住。這個(gè)參數(shù)有很利于查看機(jī)器碼。
set step-mod off
關(guān)閉step-mode模式。
finish
運(yùn)行程序,直到當(dāng)前函數(shù)完成返回。并打印函數(shù)返回時(shí)的堆棧地址和返回值及參數(shù)值等信息。
until 或 u
當(dāng)你厭倦了在一個(gè)循環(huán)體內(nèi)單步跟蹤時(shí),這個(gè)命令可以運(yùn)行程序直到退出循環(huán)體。
stepi 或 si
nexti 或 ni
單步跟蹤一條機(jī)器指令!一條程序代碼有可能由數(shù)條機(jī)器指令完成,stepi和nexti可以單步執(zhí)行機(jī)器指令。與之一樣有相同功能的命令是 “display/i $pc” ,當(dāng)運(yùn)行完這個(gè)命令后,單步跟蹤會(huì)在打出程序代碼的同時(shí)打出機(jī)器指令(也就是匯編代碼)
九、信號(hào)(Signals)
信號(hào)是一種軟中斷,是一種處理異步事件的方法。一般來(lái)說(shuō),操作系統(tǒng)都支持許多信號(hào)。尤其是UNIX,比較重要應(yīng)用程序一般都會(huì)處理信號(hào)。UNIX定義了許多信號(hào),比如SIGINT表示中斷字符信號(hào),也就是Ctrl+C的信號(hào),SIGBUS表示硬件故障的信號(hào);SIGCHLD表示子進(jìn)程狀態(tài)改變信號(hào); SIGKILL表示終止程序運(yùn)行的信號(hào),等等。信號(hào)量編程是UNIX下非常重要的一種技術(shù)。 GDB有能力在你調(diào)試程序的時(shí)候處理任何一種信號(hào),你可以告訴GDB需要處理哪一種信號(hào)。你可以要求GDB收到你所指定的信號(hào)時(shí),馬上停住正在運(yùn)行的程序,以供你進(jìn)行調(diào)試。你可以用GDB的handle命令來(lái)完成這一功能。
handle ; ;
在GDB中定義一個(gè)信號(hào)處理。信號(hào);可以以SIG開(kāi)頭或不以SIG開(kāi)頭,可以用定義一個(gè)要處理信號(hào)的范圍(如:SIGIO- SIGKILL,表示處理從SIGIO信號(hào)到SIGKILL的信號(hào),其中包括SIGIO,SIGIOT,SIGKILL三個(gè)信號(hào)),也可以使用關(guān)鍵字 all來(lái)標(biāo)明要處理所有的信號(hào)。一旦被調(diào)試的程序接收到信號(hào),運(yùn)行程序馬上會(huì)被GDB停住,以供調(diào)試。其;可以是以下幾種關(guān)鍵字的一個(gè)或多個(gè)。
nostop
當(dāng)被調(diào)試的程序收到信號(hào)時(shí),GDB不會(huì)停住程序的運(yùn)行,但會(huì)打出消息告訴你收到這種信號(hào)。
stop
當(dāng)被調(diào)試的程序收到信號(hào)時(shí),GDB會(huì)停住你的程序。
print
當(dāng)被調(diào)試的程序收到信號(hào)時(shí),GDB會(huì)顯示出一條信息。
noprint
當(dāng)被調(diào)試的程序收到信號(hào)時(shí),GDB不會(huì)告訴你收到信號(hào)的信息。
pass
noignore
當(dāng)被調(diào)試的程序收到信號(hào)時(shí),GDB不處理信號(hào)。這表示,GDB會(huì)把這個(gè)信號(hào)交給被調(diào)試程序會(huì)處理。
nopass
ignore
當(dāng)被調(diào)試的程序收到信號(hào)時(shí),GDB不會(huì)讓被調(diào)試程序來(lái)處理這個(gè)信號(hào)。
info signals
info handle
查看有哪些信號(hào)在被GDB檢測(cè)中。
十、線程(Thread Stops)
如果你程序是多線程的話,你可以定義你的斷點(diǎn)是否在所有的線程上,或是在某個(gè)特定的線程。GDB很容易幫你完成這一工作。
break ; thread ;
break ; thread ; if ...
linespec指定了斷點(diǎn)設(shè)置在的源程序的行號(hào)。threadno指定了線程的ID,注意,這個(gè)ID是GDB分配的,你可以通過(guò)“info threads”命令來(lái)查看正在運(yùn)行程序中的線程信息。如果你不指定thread ;則表示你的斷點(diǎn)設(shè)在所有線程上面。你還可以為某線程指定斷點(diǎn)條件。如:
(gdb) bt
#0 func (n=250) at tst.c:6
#1 0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6
如果你要查看某一層的信息,你需要在切換當(dāng)前的棧,一般來(lái)說(shuō),程序停止時(shí),最頂層的棧就是當(dāng)前棧,如果你要查看棧下面層的詳細(xì)信息,首先要做的是切換當(dāng)前棧。
frame ;
f ;
n是一個(gè)從0開(kāi)始的整數(shù),是棧中的層編號(hào)。比如:frame 0,表示棧頂,frame 1,表示棧的第二層。
up ;
表示向棧的上面移動(dòng)n層,可以不打n,表示向上移動(dòng)一層。
down ;
表示向棧的下面移動(dòng)n層,可以不打n,表示向下移動(dòng)一層。
上面的命令,都會(huì)打印出移動(dòng)到的棧層的信息。如果你不想讓其打出信息。你可以使用這三個(gè)命令:
select-frame ; 對(duì)應(yīng)于 frame 命令。
up-silently ; 對(duì)應(yīng)于 up 命令。
down-silently ; 對(duì)應(yīng)于 down 命令。
查看當(dāng)前棧層的信息,你可以用以下GDB命令:
frame 或 f
會(huì)打印出這些信息:棧的層編號(hào),當(dāng)前的函數(shù)名,函數(shù)參數(shù)值,函數(shù)所在文件及行號(hào),函數(shù)執(zhí)行到的語(yǔ)句。
info frame
info f
這個(gè)命令會(huì)打印出更為詳細(xì)的當(dāng)前棧層的信息,只不過(guò),大多數(shù)都是運(yùn)行時(shí)的內(nèi)內(nèi)地址。比如:函數(shù)地址,調(diào)用函數(shù)的地址,被調(diào)用函數(shù)的地址,目前的函數(shù)是由什么樣的程序語(yǔ)言寫成的、函數(shù)參數(shù)地址及值、局部變量的地址等等。如:
(gdb) info f
Stack level 0, frame at 0xbffff5d4:
eip = 0x804845d in func (tst.c:6); saved eip 0x8048524
called by frame at 0xbffff60c
source language c.
Arglist at 0xbffff5d4, args: n=250
Locals at 0xbffff5d4, Previous frame's sp is 0x0
Saved registers:
ebp at 0xbffff5d4, eip at 0xbffff5d8
info args
打印出當(dāng)前函數(shù)的參數(shù)名及其值。
info locals
打印出當(dāng)前函數(shù)中所有局部變量及其值。
info catch
打印出當(dāng)前的函數(shù)中的異常處理信息。
查看源程序
一、顯示源代碼 GDB 可以打印出所調(diào)試程序的源代碼,當(dāng)然,在程序編譯時(shí)一定要加上-g的參數(shù),把源程序信息編譯到執(zhí)行文件中。不然就看不到源程序了。當(dāng)程序停下來(lái)以后,GDB會(huì)報(bào)告程序停在了那個(gè)文件的第幾行上。你可以用list命令來(lái)打印程序的源代碼。還是來(lái)看一看查看源代碼的GDB命令吧。
list ;
顯示程序第linenum行的周圍的源程序。
list ;
顯示函數(shù)名為function的函數(shù)的源程序。
list
顯示當(dāng)前行后面的源程序。
list -
顯示當(dāng)前行前面的源程序。
一般是打印當(dāng)前行的上5行和下5行,如果顯示函數(shù)是是上2行下8行,默認(rèn)是10行,當(dāng)然,你也可以定制顯示的范圍,使用下面命令可以設(shè)置一次顯示源程序的行數(shù)。
set listsize ;
設(shè)置一次顯示源代碼的行數(shù)。
于是,在GDB調(diào)試過(guò)程中,你可以以如下命令顯示出這個(gè)動(dòng)態(tài)數(shù)組的取值:
p *array@len
@的左邊是數(shù)組的首地址的值,也就是變量array所指向的內(nèi)容,右邊則是數(shù)據(jù)的長(zhǎng)度,其保存在變量len中,其輸出結(jié)果,大約是下面這個(gè)樣子的:
x 按十六進(jìn)制格式顯示變量。
d 按十進(jìn)制格式顯示變量。
u 按十六進(jìn)制格式顯示無(wú)符號(hào)整型。
o 按八進(jìn)制格式顯示變量。
t 按二進(jìn)制格式顯示變量。
a 按十六進(jìn)制格式顯示變量。
c 按字符格式顯示變量。
f 按浮點(diǎn)數(shù)格式顯示變量。
(gdb) p i
$21 = 101
(gdb) p/a i
$22 = 0x65
(gdb) p/c i
$23 = 101 'e'
(gdb) p/f i
$24 = 1.41531145e-43
(gdb) p/x i
$25 = 0x65
(gdb) p/t i
$26 = 1100101
五、查看內(nèi)存
你可以使用examine命令(簡(jiǎn)寫是x)來(lái)查看內(nèi)存地址中的值。x命令的語(yǔ)法如下所示:
x/; ;
n、f、u是可選的參數(shù)。
n 是一個(gè)正整數(shù),表示顯示內(nèi)存的長(zhǎng)度,也就是說(shuō)從當(dāng)前地址向后顯示幾個(gè)地址的內(nèi)容。
f 表示顯示的格式,參見(jiàn)上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
u 表示從當(dāng)前地址往后請(qǐng)求的字節(jié)數(shù),如果不指定的話,GDB默認(rèn)是4個(gè)bytes。u參數(shù)可以用下面的字符來(lái)代替,b表示單字節(jié),h表示雙字節(jié),w表示四字節(jié),g表示八字節(jié)。當(dāng)我們指定了字節(jié)長(zhǎng)度后,GDB會(huì)從指內(nèi)存定的內(nèi)存地址開(kāi)始,讀寫指定字節(jié),并把其當(dāng)作一個(gè)值取出來(lái)。
disable display ;
enable display ;
disable和enalbe不刪除自動(dòng)顯示的設(shè)置,而只是讓其失效和恢復(fù)。
info display
查看display設(shè)置的自動(dòng)顯示的信息。GDB會(huì)打出一張表格,向你報(bào)告當(dāng)然調(diào)試中設(shè)置了多少個(gè)自動(dòng)顯示設(shè)置,其中包括,設(shè)置的編號(hào),表達(dá)式,是否enable。
七、設(shè)置顯示選項(xiàng) GDB中關(guān)于顯示的選項(xiàng)比較多,這里我只例舉大多數(shù)常用的選項(xiàng)。
set print address
set print address on
打開(kāi)地址輸出,當(dāng)程序顯示函數(shù)信息時(shí),GDB會(huì)顯出函數(shù)的參數(shù)地址。系統(tǒng)默認(rèn)為打開(kāi)的,如:
(gdb) f
#0 set_quotes (lq=0x34c78 ";>;")
at input.c:530
530 if (lquote != def_lquote)
set print address off
關(guān)閉函數(shù)的參數(shù)地址顯示,如:
(gdb) set print addr off
(gdb) f
#0 set_quotes (lq=";>;") at input.c:530
530 if (lquote != def_lquote)
show print address
查看當(dāng)前地址顯示選項(xiàng)是否打開(kāi)。
set print array
set print array on
打開(kāi)數(shù)組顯示,打開(kāi)后當(dāng)數(shù)組顯示時(shí),每個(gè)元素占一行,如果不打開(kāi)的話,每個(gè)元素則以逗號(hào)分隔。這個(gè)選項(xiàng)默認(rèn)是關(guān)閉的。與之相關(guān)的兩個(gè)命令如下,我就不再多說(shuō)了。
set print array off
show print array
set print elements ;
這個(gè)選項(xiàng)主要是設(shè)置數(shù)組的,如果你的數(shù)組太大了,那么就可以指定一個(gè);來(lái)指定數(shù)據(jù)顯示的最大長(zhǎng)度,當(dāng)?shù)竭_(dá)這個(gè)長(zhǎng)度時(shí),GDB就不再往下顯示了。如果設(shè)置為0,則表示不限制。
show print elements
查看print elements的選項(xiàng)信息。
set print null-stop ;
如果打開(kāi)了這個(gè)選項(xiàng),那么當(dāng)顯示字符串時(shí),遇到結(jié)束符則停止顯示。這個(gè)選項(xiàng)默認(rèn)為off。
set print pretty on
如果打開(kāi)printf pretty這個(gè)選項(xiàng),那么當(dāng)GDB顯示結(jié)構(gòu)體時(shí)會(huì)比較漂亮。如:
$1 = {
next = 0x0,
flags = {
sweet = 1,
sour = 1
},
meat = 0x54 "Pork"
}
set print pretty off
關(guān)閉printf pretty這個(gè)選項(xiàng),GDB顯示結(jié)構(gòu)體時(shí)會(huì)如下顯示:
當(dāng)關(guān)閉這個(gè)開(kāi)關(guān)時(shí),執(zhí)行 p foo 命令后,會(huì)如下顯示:
$1 = {it = Tree, form = {...}}
show print union
查看聯(lián)合體數(shù)據(jù)的顯示方式
set print object ;
在C++中,如果一個(gè)對(duì)象指針指向其派生類,如果打開(kāi)這個(gè)選項(xiàng),GDB會(huì)自動(dòng)按照虛方法調(diào)用的規(guī)則顯示輸出,如果關(guān)閉這個(gè)選項(xiàng)的話,GDB就不管虛函數(shù)表了。這個(gè)選項(xiàng)默認(rèn)是off。
show print object
查看對(duì)象選項(xiàng)的設(shè)置。
set print static-members ;
這個(gè)選項(xiàng)表示,當(dāng)顯示一個(gè)C++對(duì)象中的內(nèi)容是,是否顯示其中的靜態(tài)數(shù)據(jù)成員。默認(rèn)是on。
show print static-members
查看靜態(tài)數(shù)據(jù)成員選項(xiàng)設(shè)置。
set print vtbl ;
當(dāng)此選項(xiàng)打開(kāi)時(shí),GDB將用比較規(guī)整的格式來(lái)顯示虛函數(shù)表時(shí)。其默認(rèn)是關(guān)閉的。
show print vtbl
查看虛函數(shù)顯示格式的選項(xiàng)。
八、歷史記錄
當(dāng)你用GDB的print查看程序運(yùn)行時(shí)的數(shù)據(jù)時(shí),你每一個(gè)print都會(huì)被GDB記錄下來(lái)。GDB會(huì)以$1, $2, $3 .....這樣的方式為你每一個(gè)print命令編上號(hào)。于是,你可以使用這個(gè)編號(hào)訪問(wèn)以前的表達(dá)式,如$1。這個(gè)功能所帶來(lái)的好處是,如果你先前輸入了一個(gè)比較長(zhǎng)的表達(dá)式,如果你還想查看這個(gè)表達(dá)式的值,你可以使用歷史記錄來(lái)訪問(wèn),省去了重復(fù)輸入。
(gdb) whatis width
type = double
(gdb) p width
$4 = 13
(gdb) set width=47
Invalid syntax in expression.
因?yàn)椋瑂et width是GDB的命令,所以,出現(xiàn)了“Invalid syntax in expression”的設(shè)置錯(cuò)誤,此時(shí),你可以使用set var命令來(lái)告訴GDB,width不是你GDB的參數(shù),而是程序的變量名,如:
(gdb) set language
The currently understood settings are:
local or auto Automatic setting based on source file
c Use the C language
c++ Use the C++ language
asm Use the Asm language
chill Use the Chill language
fortran Use the Fortran language
java Use the Java language
modula-2 Use the Modula-2 language
pascal Use the Pascal language
scheme Use the Scheme language