转:用GDB调试程序
從CSDN的網(wǎng)站上找到的GDB使用說明。
????原文標(biāo)題:用GDB調(diào)試程序
????作者:haoel?(QQ是:753640,MSN是:?haoel@hotmail.com)
????關(guān)鍵字:gdb?調(diào)試?c?c++?gun
????這篇文章非常好,所以轉(zhuǎn)載了下來,作為收藏。
GDB概述
GDB?是GNU開源組織發(fā)布的一個(gè)強(qiáng)大的UNIX下的程序調(diào)試工具。或許
,各位比較喜歡那種圖形界面方式的,像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è)道理。
一般來說,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)境。
從上面看來,GDB和一般的調(diào)試工具沒有什么兩樣,基本上也是完成
這些功能,不過在細(xì)節(jié)上,你會(huì)發(fā)現(xiàn)GDB這個(gè)調(diào)試工具的強(qiáng)大,大家
可能比較習(xí)慣了圖形化的調(diào)試工具,但有時(shí)候,命令行的調(diào)試工具卻
有著圖形化工具所不能完成的功能。讓我們一一看來。
一個(gè)調(diào)試示例
源程序:tst.c
1?#include?<stdio.h>
2
3?int?func(int?n)
4?{
5?int?sum=0,i;
6?for(i=0;?i<n;?i++)
7?{
8?sum+=i;
9?}
10?return?sum;
11?}
12
13
14?main()
15?{
16?int?i;
17?long?result?=?0;
18?for(i=1;?i<=100;?i++)
19?{
20?result?+=?i;
21?}
22
23?printf("result[1-100]?=?%d?/n",?result?);
24?printf("result[1-250]?=?%d?/n",?func(250)?);
25?}
編譯生成執(zhí)行文件:(Linux下)
hchen/test>?cc?-g?tst.c?-o?tst
使用GDB調(diào)試:
hchen/test>?gdb?tst?<----------?啟動(dòng)GDB
GNU?gdb?5.1.1
Copyright?2002?Free?Software?Foundation,?Inc.
GDB?is?free?software,?covered?by?the?GNU?General?Public?******,?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)?l?<--------------------?l命令相當(dāng)于list,從第一行開始例出原碼。
1?#include?<stdio.h>
2
3?int?func(int?n)
4?{
5?int?sum=0,i;
6?for(i=0;?i<n;?i++)
7?{
8?sum+=i;
9?}
10?return?sum;
(gdb)?<--------------------?直接回車表示,重復(fù)上一次命令
11?}
12
13
14?main()
15?{
16?int?i;
17?long?result?=?0;
18?for(i=1;?i<=100;?i++)
19?{
20?result?+=?i;
(gdb)?break?16?<--------------------?設(shè)置斷點(diǎn),在源程序第16行處。
Breakpoint?1?at?0x8048496:?file?tst.c,?line?16.
(gdb)?break?func?<--------------------?設(shè)置斷點(diǎn),在函數(shù)func()入口處。
Breakpoint?2?at?0x8048456:?file?tst.c,?line?5.
(gdb)?info?break?<--------------------?查看斷點(diǎn)信息。
Num?Type?Disp?Enb?Address?What
1?breakpoint?keep?y?0x08048496?in?main?at?tst.c:16
2?breakpoint?keep?y?0x08048456?in?func?at?tst.c:5
(gdb)?r?<---------------------?運(yùn)行程序,run命令簡(jiǎn)寫
Starting?program:?/home/hchen/test/tst
Breakpoint?1,?main?()?at?tst.c:17?<----------?在斷點(diǎn)處停住。
17?long?result?=?0;
(gdb)?n?<---------------------?單條語句執(zhí)行,next命令簡(jiǎn)寫。
18?for(i=1;?i<=100;?i++)
(gdb)?n
20?result?+=?i;
(gdb)?n
18?for(i=1;?i<=100;?i++)
(gdb)?n
20?result?+=?i;
(gdb)?c?<---------------------?繼續(xù)運(yùn)行程序,continue命令簡(jiǎn)寫。
Continuing.
result[1-100]?=?5050?<----------程序輸出。
Breakpoint?2,?func?(n=250)?at?tst.c:5
5?int?sum=0,i;
(gdb)?n
6?for(i=1;?i<=n;?i++)
(gdb)?p?i?<---------------------?打印變量i的值,print命令簡(jiǎn)寫。
$1?=?134513808
(gdb)?n
8?sum+=i;
(gdb)?n
6?for(i=1;?i<=n;?i++)
(gdb)?p?sum
$2?=?1
(gdb)?n
8?sum+=i;
(gdb)?p?i
$3?=?2
(gdb)?n
6?for(i=1;?i<=n;?i++)
(gdb)?p?sum
$4?=?3
(gdb)?bt?<---------------------?查看函數(shù)堆棧。
#0?func?(n=250)?at?tst.c:5
#1?0x080484e4?in?main?()?at?tst.c:24
#2?0x400409ed?in?__libc_start_main?()?from?/lib/libc.so.6
(gdb)?finish?<---------------------?退出函數(shù)。
Run?till?exit?from?#0?func?(n=250)?at?tst.c:5
0x080484e4?in?main?()?at?tst.c:24
24?printf("result[1-250]?=?%d?/n",?func(250)?);
Value?returned?is?$6?=?31375
(gdb)?c?<---------------------?繼續(xù)運(yùn)行。
Continuing.
result[1-250]?=?31375?<----------程序輸出。
Program?exited?with?code?027.?<--------程序退出,調(diào)試結(jié)束。
(gdb)?q?<---------------------?退出gdb。
hchen/test>
好了,有了以上的感性認(rèn)識(shí),還是讓我們來系統(tǒng)地認(rèn)識(shí)一下gdb吧。
使用GDB
一般來說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
如果沒有-g,你將看不見程序的函數(shù)名、變量名,所代替的全是運(yùn)行
時(shí)的內(nèi)存地址。當(dāng)你用-g把調(diào)試信息加入之后,并成功編譯目標(biāo)代碼
以后,讓我們來看看如何用gdb來調(diào)試他。
啟動(dòng)GDB的方法有以下幾種:
1、gdb?<program>
program也就是你的執(zhí)行文件,一般在當(dāng)然目錄下。
2、gdb?<program>?core
用gdb同時(shí)調(diào)試一個(gè)運(yùn)行程序和core文件,core是程序非法執(zhí)行后core?dump后產(chǎn)生的文件。
3、gdb?<program>?<PID>
如果你的程序是一個(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)開關(guān),詳細(xì)的開關(guān)可以用gdb
-help查看。我在下面只例舉一些比較常用的參數(shù):
-symbols?<file>
-s?<file>
從指定文件中讀取符號(hào)表。
-se?file
從指定文件中讀取符號(hào)表信息,并把他用在可執(zhí)行文件中。
-core?<file>
-c?<file>
調(diào)試時(shí)core?dump的core文件。
-directory?<directory>
-d?<directory>
加入一個(gè)源文件的搜索路徑。默認(rèn)搜索路徑是環(huán)境變量中PATH所定義的路徑。
GDB的命令概貌
?啟動(dòng)gdb后,就你被帶入gdb的調(diào)試環(huán)境中,就可以使用
gdb的命令開始調(diào)試程序了,gdb的命令可以使用help命令來查看,如
下所示:
/home/hchen>?gdb
GNU?gdb?5.1.1
Copyright?2002?Free?Software?Foundation,?Inc.
GDB?is?free?software,?covered?by?the?GNU?General?Public?******,?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?<class>?命令,
如:help?breakpoints,查看設(shè)置斷點(diǎn)的所有命令。也可以直接help
<command>來查看命令的幫助。
gdb中,輸入命令時(shí),可以不用打全命令,只用打命令的前幾個(gè)字符
就可以了,當(dāng)然,命令的前幾個(gè)字符應(yīng)該要標(biāo)志著一個(gè)唯一的命令,
在Linux下,你可以敲擊兩次TAB鍵來補(bǔ)齊命令的全稱,如果有重復(fù)的
,那么gdb會(huì)把其例出來。
示例一:在進(jìn)入函數(shù)func時(shí),設(shè)置一個(gè)斷點(diǎn)。可以敲入break?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鍵>
(再按下一次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開頭的函數(shù)全部例出來給你查看。
示例四:調(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命令來完成:
shell?<command?string>
調(diào)用UNIX的shell來執(zhí)行<command?string>,環(huán)境變量SHELL中定義的
UNIX的shell將會(huì)被用來執(zhí)行<command?string>,如果SHELL沒有定義
,那就使用UNIX的標(biāo)準(zhǔn)shell:/bin/sh。(在Windows中使用
Command.com或?cmd.exe)
還有一個(gè)gdb命令是make:
make?<make-args>
可以在gdb中執(zhí)行make命令來重新build自己的程序。這個(gè)命令等價(jià)于“shell?make?<make-args>”。
在GDB中運(yùn)行程序
當(dāng)以gdb?<program>方式啟動(dòng)gdb后,gdb會(huì)在PATH路徑和當(dāng)前目錄中
搜索<program>的源文件。如要確認(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?<dir>?可設(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?<dir>?相當(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?<program>?PID格式掛接正在運(yùn)行的程序。
2、先用gdb?<program>關(guān)聯(lián)上源代碼,并進(jìn)行g(shù)db,在gdb中用attach命令來掛接進(jìn)程的PID。并用detach來取消掛接的進(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?來查看程序的是否在
運(yùn)行,進(jìn)程號(hào),被暫停的原因。
在gdb中,我們可以有以下幾種暫停方式:斷點(diǎn)(BreakPoint)、觀
察點(diǎn)(Watch?Point)、捕捉點(diǎn)(Catch?Point)、信號(hào)(Signals)、
線程停止(Thread?Stops)。如果要恢復(fù)程序運(yùn)行,可以使用c或是
continue命令。
一、設(shè)置斷點(diǎn)(Break?Points)
我們用break命令來設(shè)置斷點(diǎn)。正面有幾點(diǎn)設(shè)置斷點(diǎn)的方法:
break?<function>
在進(jìn)入指定函數(shù)時(shí)停住。C++中可以使用class::function或function(type,type)格式來指定函數(shù)名。
break?<linenum>
在指定行號(hào)停住。
break?+offset
break?-offset
在當(dāng)前行號(hào)的前面或后面的offset行停住。offiset為自然數(shù)。
break?filename:linenum
在源文件filename的linenum行處停住。
break?filename:function
在源文件filename的function函數(shù)的入口處停住。
break?*address
在程序運(yùn)行的內(nèi)存地址處停住。
break
break命令沒有參數(shù)時(shí),表示在下一條指令處停住。
break?...?if?<condition>
...可以是上述的參數(shù),condition表示條件,在條件成立時(shí)停住。比如在循環(huán)境體中,可以設(shè)置break?if?i=100,表示當(dāng)i為100時(shí)停住程序。
查看斷點(diǎn)時(shí),可使用info命令,如下所示:(注:n表示斷點(diǎn)號(hào))
info?breakpoints?[n]
info?break?[n]
二、設(shè)置觀察點(diǎn)(WatchPoint)
觀察點(diǎn)一般來觀察某個(gè)表達(dá)式(變量也是一種表達(dá)式)的值是否有變
化了,如果有變化,馬上停住程序。我們有下面的幾種方法來設(shè)置觀
察點(diǎn):
watch?<expr>
為表達(dá)式(變量)expr設(shè)置一個(gè)觀察點(diǎn)。一量表達(dá)式值有變化時(shí),馬上停住程序。
rwatch?<expr>
當(dāng)表達(dá)式(變量)expr被讀時(shí),停住程序。
awatch?<expr>
當(dāng)表達(dá)式(變量)的值被讀或被寫時(shí),停住程序。
info?watchpoints
列出當(dāng)前所設(shè)置了的所有觀察點(diǎn)。
三、設(shè)置捕捉點(diǎn)(CatchPoint)
你可設(shè)置捕捉點(diǎn)來補(bǔ)捉程序運(yùn)行時(shí)的一些事件。如:載入共享庫(動(dòng)
態(tài)鏈接庫)或是C++的異常。設(shè)置捕捉點(diǎn)的格式為:
catch?<event>
當(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?<libname>?載入共享庫(動(dòng)態(tài)鏈接庫)時(shí)。(load為關(guān)鍵字,目前此功能只在HP-UX下有用)
7、unload?或?unload?<libname>?卸載共享庫(動(dòng)態(tài)鏈接庫)時(shí)。(unload為關(guān)鍵字,目前此功能只在HP-UX下有用)
tcatch?<event>
只設(shè)置一次捕捉點(diǎn),當(dāng)程序停住以后,應(yīng)點(diǎn)被自動(dòng)刪除。
四、維護(hù)停止點(diǎn)
上面說了如何設(shè)置程序的停止點(diǎn),GDB中的停止點(diǎn)也就是上述的三類
。在GDB中,如果你覺得已定義好的停止點(diǎn)沒有用了,你可以使用
delete、clear、disable、enable這幾個(gè)命令來進(jìn)行維護(hù)。
clear
清除所有的已定義的停止點(diǎn)。
clear?<function>
clear?<filename:function>
清除所有設(shè)置在函數(shù)上的停止點(diǎn)。
clear?<linenum>
clear?<filename:linenum>
清除所有設(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ù)
前面在說到設(shè)置斷點(diǎn)時(shí),我們提到過可以設(shè)置一個(gè)條件,當(dāng)條件成立
時(shí),程序自動(dòng)停止,這是一個(gè)非常強(qiáng)大的功能,這里,我想專門說說
這個(gè)條件的相關(guān)維護(hù)命令。一般來說,為斷點(diǎn)設(shè)置一個(gè)條件,我們使
用?if關(guān)鍵詞,后面跟其斷點(diǎn)條件。并且,條件設(shè)置好后,我們可以
用condition命令來修改斷點(diǎn)的條件。(只有break和watch命令支持
if,?catch目前暫不支持if)
condition?<bnum>?<expression>
修改斷點(diǎn)號(hào)為bnum的停止條件為expression。
condition?<bnum>
清除斷點(diǎn)號(hào)為bnum的停止條件。
還有一個(gè)比較特殊的維護(hù)命令ignore,你可以指定程序運(yùn)行時(shí),忽略停止條件幾次。
ignore?<bnum>?<count>
表示忽略斷點(diǎn)號(hào)為bnum的停止條件count次。
六、為停止點(diǎn)設(shè)定運(yùn)行命令
?我們可以使用GDB提供的command命令來設(shè)置停止點(diǎn)的運(yùn)行
命令。也就是說,當(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?<function>不能告訴GDB要停在哪
個(gè)函數(shù)的入口。當(dāng)然,你可以使用break?<function(type)>也就是把
函數(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)
可見,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)到來。也可以使用step或next命令單步跟蹤程序。
continue?[ignore-count]
c?[ignore-count]
fg?[ignore-count]
恢復(fù)程序運(yùn)行,直到程序結(jié)束,或是下一個(gè)斷點(diǎn)到來。ignore-count
表示忽略其后的斷點(diǎn)次數(shù)。continue,c,fg三個(gè)命令都是一樣的意
思。
step?<count>?
單步跟蹤,如果有函數(shù)調(diào)用,他會(huì)進(jìn)入該函數(shù)。進(jìn)入
函數(shù)的前提是,此函數(shù)被編譯有debug信息。很像VC等工具中的step
in。后面可以加count也可以不加,不加表示一條條地執(zhí)行,加表示
執(zhí)行后面的count條指令,然后再停住。
next?<count>?
同樣單步跟蹤,如果有函數(shù)調(diào)用,他不會(huì)進(jìn)入該函數(shù)
。很像VC等工具中的step?over。后面可以加count也可以不加,不加
表示一條條地執(zhí)行,加表示執(zhí)行后面的count條指令,然后再停住。
set?step-mode
set?step-mode?on
打開step-mode模式,于是,在進(jìn)行單步跟蹤時(shí),程序不會(huì)因?yàn)闆]有
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)是一種軟中斷,是一種處理異步事件的方法。一般來說,操作系
統(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命令來
完成這一功能。
handle?<signal>?<keywords...>?
在GDB?中定義一個(gè)信號(hào)處理。信號(hào)
<signal>可以以SIG開頭或不以SIG開頭,可以用定義一個(gè)要處理信號(hào)
的范圍(如:SIGIO-?SIGKILL,表示處理從SIGIO信號(hào)到SIGKILL的信
號(hào),其中包括SIGIO,SIGIOT,SIGKILL三個(gè)信號(hào)),也可以使用關(guān)鍵
字?all來標(biāo)明要處理所有的信號(hào)。一旦被調(diào)試的程序接收到信號(hào),運(yùn)
行程序馬上會(huì)被GDB停住,以供調(diào)試。其<keywords>可以是以下幾種
關(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)試程序來處理這個(gè)信號(hào)。
info?signals
info?handle
查看有哪些信號(hào)在被GDB檢測(cè)中。
十、線程(Thread?Stops)
如果你程序是多線程的話,你可以定義你的斷點(diǎn)是否在所有的線程上
,或是在某個(gè)特定的線程。GDB很容易幫你完成這一工作。
break?<linespec>?thread?<threadno>
break?<linespec>?thread?<threadno>?if?...
linespec?指定了斷點(diǎn)設(shè)置在的源程序的行號(hào)。threadno指定了線程
的ID,注意,這個(gè)ID是GDB分配的,你可以通過“info?threads”命
令來查看正在運(yùn)行程序中的線程信息。如果你不指定thread
<threadno>則表示你的斷點(diǎn)設(shè)在所有線程上面。你還可以為某線程指
定斷點(diǎn)條件。如:
(gdb)?break?frik.c:13?thread?28?if?bartab?>?lim
當(dāng)你的程序被GDB停住時(shí),所有的運(yùn)行線程都會(huì)被停住。這方便你你
查看運(yùn)行程序的總體情況。而在你恢復(fù)程序運(yùn)行時(shí),所有的線程也會(huì)
被恢復(fù)運(yùn)行。那怕是主進(jìn)程在被單步調(diào)試時(shí)。
查看棧信息
當(dāng)程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的
。當(dāng)你的程序調(diào)用了一個(gè)函數(shù),函數(shù)的地址,函數(shù)參數(shù),函數(shù)內(nèi)的局
部變量都會(huì)被壓入“棧”(Stack)中。你可以用GDB命令來查看當(dāng)前
的棧中的信息。
下面是一些查看函數(shù)調(diào)用棧信息的GDB命令:
backtrace
bt
打印當(dāng)前的函數(shù)調(diào)用棧的所有信息。如:
(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
從上可以看出函數(shù)的調(diào)用棧信息:__libc_start_main?-->?main()?-->?func()
backtrace?<n>
bt?<n>
n是一個(gè)正整數(shù),表示只打印棧頂上n層的棧信息。
backtrace?<-n>
bt?<-n>
-n表一個(gè)負(fù)整數(shù),表示只打印棧底下n層的棧信息。
如果你要查看某一層的信息,你需要在切換當(dāng)前的棧,一般來說,程
序停止時(shí),最頂層的棧就是當(dāng)前棧,如果你要查看棧下面層的詳細(xì)信
息,首先要做的是切換當(dāng)前棧。
frame?<n>
f?<n>
n是一個(gè)從0開始的整數(shù),是棧中的層編號(hào)。比如:frame?0,表示棧頂,frame?1,表示棧的第二層。
up?<n>
表示向棧的上面移動(dòng)n層,可以不打n,表示向上移動(dòng)一層。
down?<n>
表示向棧的下面移動(dòng)n層,可以不打n,表示向下移動(dòng)一層。
上面的命令,都會(huì)打印出移動(dòng)到的棧層的信息。如果你不想讓其打出信息。你可以使用這三個(gè)命令:
select-frame?<n>?對(duì)應(yīng)于?frame?命令。
up-silently?<n>?對(duì)應(yīng)于?up?命令。
down-silently?<n>?對(duì)應(yīng)于?down?命令。
查看當(dāng)前棧層的信息,你可以用以下GDB命令:
frame?或?f
會(huì)打印出這些信息:棧的層編號(hào),當(dāng)前的函數(shù)名,函數(shù)參數(shù)值,函數(shù)所在文件及行號(hào),函數(shù)執(zhí)行到的語句。
info?frame
info?f
這個(gè)命令會(huì)打印出更為詳細(xì)的當(dāng)前棧層的信息,只不過,大多數(shù)都是
運(yùn)行時(shí)的內(nèi)內(nèi)地址。比如:函數(shù)地址,調(diào)用函數(shù)的地址,被調(diào)用函數(shù)
的地址,目前的函數(shù)是由什么樣的程序語言寫成的、函數(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)程序停下來以后,?GDB會(huì)報(bào)告程序停在了那個(gè)文件的第幾行上
。你可以用list命令來打印程序的源代碼。還是來看一看查看源代碼
的GDB命令吧。
list?<linenum>
顯示程序第linenum行的周圍的源程序。
list?<function>
顯示函數(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?<count>
設(shè)置一次顯示源代碼的行數(shù)。
show?listsize
查看當(dāng)前l(fā)istsize的設(shè)置。
list命令還有下面的用法:
list?<first>,?<last>
顯示從first行到last行之間的源代碼。
list?,?<last>
顯示從當(dāng)前行到last行之間的源代碼。
list?+
往后顯示源代碼。
一般來說在list后面可以跟以下這們的參數(shù):
<linenum>?行號(hào)。
<+offset>?當(dāng)前行號(hào)的正偏移量。
<-offset>?當(dāng)前行號(hào)的負(fù)偏移量。
<filename:linenum>?哪個(gè)文件的哪一行。
<function>?函數(shù)名。
<filename:function>?哪個(gè)文件中的哪個(gè)函數(shù)。
<*address>?程序運(yùn)行時(shí)的語句在內(nèi)存中的地址。
二、搜索源代碼
不僅如此,GDB還提供了源代碼搜索的命令:
forward-search?<regexp>
search?<regexp>
向前面搜索。
reverse-search?<regexp>
全部搜索。
其中,<regexp>就是正則表達(dá)式,也主一個(gè)字符串的匹配模式,關(guān)于正則表達(dá)式,我就不在這里講了,還請(qǐng)各位查看相關(guān)資料。
三、指定源文件的路徑
某些時(shí)候,用-g編譯過后的執(zhí)行程序中只是包括了源文件的名字,沒
有路徑名。GDB提供了可以讓你指定源文件的路徑的命令,以便GDB進(jìn)
行搜索。
directory?<dirname?...?>
dir?<dirname?...?>
加一個(gè)源文件路徑到當(dāng)前路徑的前面。如果你要指定多個(gè)路徑,UNIX下你可以使用“:”,Windows下你可以使用“;”。
directory
清除所有的自定義的源文件搜索路徑信息。
show?directories
顯示定義了的源文件搜索路徑。
四、源代碼的內(nèi)存
你可以使用info?line命令來查看源代碼在內(nèi)存中的地址。info?line
后面可以跟“行號(hào)”,“函數(shù)名”,“文件名:行號(hào)”,“文件名:函
數(shù)名”,這個(gè)命令會(huì)打印出所指定的源碼在運(yùn)行時(shí)的內(nèi)存地址,如:
(gdb)?info?line?tst.c:func
Line?5?of?"tst.c"?starts?at?address?0x8048456?<func+6>?and?ends?at?0x804845d?<func+13>.
還有一個(gè)命令(disassemble)你可以查看源程序的當(dāng)前執(zhí)行時(shí)的機(jī)
器碼,這個(gè)命令會(huì)把目前內(nèi)存中的指令dump出來。如下面的示例表示
查看函數(shù)func的匯編代碼。
(gdb)?disassemble?func
Dump?of?assembler?code?for?function?func:
0x8048450?<func>:?push?%ebp
0x8048451?<func+1>:?mov?%esp,%ebp
0x8048453?<func+3>:?sub?$0x18,%esp
0x8048456?<func+6>:?movl?$0x0,0xfffffffc(%ebp)
0x804845d?<func+13>:?movl?$0x1,0xfffffff8(%ebp)
0x8048464?<func+20>:?mov?0xfffffff8(%ebp),%eax
0x8048467?<func+23>:?cmp?0x8(%ebp),%eax
0x804846a?<func+26>:?jle?0x8048470?<func+32>
0x804846c?<func+28>:?jmp?0x8048480?<func+48>
0x804846e?<func+30>:?mov?%esi,%esi
0x8048470?<func+32>:?mov?0xfffffff8(%ebp),%eax
0x8048473?<func+35>:?add?%eax,0xfffffffc(%ebp)
0x8048476?<func+38>:?incl?0xfffffff8(%ebp)
0x8048479?<func+41>:?jmp?0x8048464?<func+20>
0x804847b?<func+43>:?nop
0x804847c?<func+44>:?lea?0x0(%esi,1),%esi
0x8048480?<func+48>:?mov?0xfffffffc(%ebp),%edx
0x8048483?<func+51>:?mov?%edx,%eax
0x8048485?<func+53>:?jmp?0x8048487?<func+55>
0x8048487?<func+55>:?mov?%ebp,%esp
0x8048489?<func+57>:?pop?%ebp
0x804848a?<func+58>:?ret
End?of?assembler?dump.
查看運(yùn)行時(shí)數(shù)據(jù)
?在你調(diào)試程序時(shí),當(dāng)程序被停住時(shí),你可以使用print命
令(簡(jiǎn)寫命令為p),或是同義命令inspect來查看當(dāng)前程序的運(yùn)行數(shù)
據(jù)。print命令的格式是:
print?<expr>
print?/<f>?<expr>
<expr>是表達(dá)式,是你所調(diào)試的程序的語言的表達(dá)式(GDB可以調(diào)試
多種編程語言),<f>是輸出的格式,比如,如果要把表達(dá)式按16進(jìn)
制的格式輸出,那么就是/x。
一、表達(dá)式
print和許多GDB的命令一樣,可以接受一個(gè)表達(dá)式,GDB會(huì)根據(jù)當(dāng)前
的程序運(yùn)行的數(shù)據(jù)來計(jì)算這個(gè)表達(dá)式,既然是表達(dá)式,那么就可以是
當(dāng)前程序運(yùn)行中的const常量、變量、函數(shù)等內(nèi)容。可惜的是GDB不能
使用你在程序中所定義的宏。
表達(dá)式的語法應(yīng)該是當(dāng)前所調(diào)試的語言的語法,由于C/C++是一種大
眾型的語言,所以,本文中的例子都是關(guān)于C/C++的。(而關(guān)于用GDB
調(diào)試其它語言的章節(jié),我將在后面介紹)
在表達(dá)式中,有幾種GDB所支持的操作符,它們可以用在任何一種語言中。
@
是一個(gè)和數(shù)組有關(guān)的操作符,在后面會(huì)有更詳細(xì)的說明。
::
指定一個(gè)在文件或是一個(gè)函數(shù)中的變量。
{<type>}?<addr>
表示一個(gè)指向內(nèi)存地址<addr>的類型為type的一個(gè)對(duì)象。
二、程序變量
在GDB中,你可以隨時(shí)查看以下三種變量的值:
1、全局變量(所有文件可見的)
2、靜態(tài)全局變量(當(dāng)前文件可見的)
3、局部變量(當(dāng)前Scope可見的)
如果你的局部變量和全局變量發(fā)生沖突(也就是重名),一般情況下
是局部變量會(huì)隱藏全局變量,也就是說,如果一個(gè)全局變量和一個(gè)函
數(shù)中的局部變量同名時(shí),如果當(dāng)前停止點(diǎn)在函數(shù)中,用print顯示出
的變量的值會(huì)是函數(shù)中的局部變量的值。如果此時(shí)你想查看全局變量
的值時(shí),你可以使用“::”操作符:
file::variable
function::variable
可以通過這種形式指定你所想查看的變量,是哪個(gè)文件中的或是哪個(gè)
函數(shù)中的。例如,查看文件f2.c中的全局變量x的值:
gdb)?p?'f2.c'::x
當(dāng)然,“::”操作符會(huì)和C++中的發(fā)生沖突,GDB能自動(dòng)識(shí)別“::”?
是否C++的操作符,所以你不必?fù)?dān)心在調(diào)試C++程序時(shí)會(huì)出現(xiàn)異常。
另外,需要注意的是,如果你的程序編譯時(shí)開啟了優(yōu)化選項(xiàng),那么在
用GDB調(diào)試被優(yōu)化過的程序時(shí),可能會(huì)發(fā)生某些變量不能訪問,或是
取值錯(cuò)誤碼的情況。這個(gè)是很正常的,因?yàn)閮?yōu)化程序會(huì)刪改你的程序
,整理你程序的語句順序,剔除一些無意義的變量等,所以在GDB調(diào)
試這種程序時(shí),運(yùn)行時(shí)的指令和你所編寫指令就有不一樣,也就會(huì)出
現(xiàn)你所想象不到的結(jié)果。對(duì)付這種情況時(shí),需要在編譯程序時(shí)關(guān)閉編
譯優(yōu)化。一般來說,幾乎所有的編譯器都支持編譯優(yōu)化的開關(guān),例如
,GNU?的C/C++編譯器GCC,你可以使用“-gstabs”選項(xiàng)來解決這個(gè)
問題。關(guān)于編譯器的參數(shù),還請(qǐng)查看編譯器的使用說明文檔。
三、數(shù)組
有時(shí)候,你需要查看一段連續(xù)的內(nèi)存空間的值。比如數(shù)組的一段,或
是動(dòng)態(tài)分配的數(shù)據(jù)的大小。你可以使用GDB的“@”操作符,“@”的
左邊是第一個(gè)內(nèi)存的地址的值,“@”的右邊則你你想查看內(nèi)存的長(zhǎng)
度。例如,你的程序中有這樣的語句:
int?*array?=?(int?*)?malloc?(len?*?sizeof?(int));
于是,在GDB調(diào)試過程中,你可以以如下命令顯示出這個(gè)動(dòng)態(tài)數(shù)組的取值:
p?*array@len
@的左邊是數(shù)組的首地址的值,也就是變量array所指向的內(nèi)容,右邊
則是數(shù)據(jù)的長(zhǎng)度,其保存在變量len中,其輸出結(jié)果,大約是下面這
個(gè)樣子的:
(gdb)?p?*array@len
$1?=?{2,?4,?6,?8,?10,?12,?14,?16,?18,?20,?22,?24,?26,?28,?30,?32,?34,?36,?38,?40}
如果是靜態(tài)數(shù)組的話,可以直接用print數(shù)組名,就可以顯示數(shù)組中所有數(shù)據(jù)的內(nèi)容了。
四、輸出格式
一般來說,GDB會(huì)根據(jù)變量的類型輸出變量的值。但你也可以自定義
GDB的輸出的格式。例如,你想輸出一個(gè)整數(shù)的十六進(jìn)制,或是二進(jìn)
制來查看這個(gè)整型變量的中的位的情況。要做到這樣,你可以使用
GDB的數(shù)據(jù)顯示格式:
x?按十六進(jìn)制格式顯示變量。
d?按十進(jìn)制格式顯示變量。
u?按十六進(jìn)制格式顯示無符號(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)來查看內(nèi)存地址中的值。x命令的語法如下所示:
x/<n/f/u>?<addr>
n、f、u是可選的參數(shù)。
n?是一個(gè)正整數(shù),表示顯示內(nèi)存的長(zhǎng)度,也就是說從當(dāng)前地址向后顯示幾個(gè)地址的內(nèi)容。
f?表示顯示的格式,參見上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
u?表示從當(dāng)前地址往后請(qǐng)求的字節(jié)數(shù),如果不指定的話,GDB默認(rèn)是4?
??個(gè)bytes。u參數(shù)可以用下面的字符來代替,b表示單字節(jié),h表示雙
??字節(jié),w表示四字節(jié),g表示八字節(jié)。當(dāng)我們指定了字節(jié)長(zhǎng)度后,
??GDB會(huì)從指內(nèi)存定的內(nèi)存地址開始,讀寫指定字節(jié),并把其當(dāng)作一
??個(gè)值取出來。
<addr>表示一個(gè)內(nèi)存地址。
n/f/u三個(gè)參數(shù)可以一起使用。例如:
命令:x/3uh?0x54320?表示,從內(nèi)存地址0x54320讀取內(nèi)容,h表示以
雙字節(jié)為一個(gè)單位,3表示三個(gè)單位,u表示按十六進(jìn)制顯示。
六、自動(dòng)顯示
你可以設(shè)置一些自動(dòng)顯示的變量,當(dāng)程序停住時(shí),或是在你單步跟蹤
時(shí),這些變量會(huì)自動(dòng)顯示。相關(guān)的GDB命令是display。
display?<expr>
display/<fmt>?<expr>
display/<fmt>?<addr>
expr是一個(gè)表達(dá)式,fmt表示顯示的格式,addr表示內(nèi)存地址,當(dāng)你
用display設(shè)定好了一個(gè)或多個(gè)表達(dá)式后,只要你的程序被停下來,
GDB會(huì)自動(dòng)顯示你所設(shè)置的這些表達(dá)式的值。
格式i和s同樣被display支持,一個(gè)非常有用的命令是:
display/i?$pc
$pc是GDB的環(huán)境變量,表示著指令的地址,/i則表示輸出格式為機(jī)器
指令碼,也就是匯編。于是當(dāng)程序停下后,就會(huì)出現(xiàn)源代碼和機(jī)器指
令碼相對(duì)應(yīng)的情形,這是一個(gè)很有意思的功能。
下面是一些和display相關(guān)的GDB命令:
undisplay?<dnums...>
delete?display?<dnums...>
刪除自動(dòng)顯示,dnums意為所設(shè)置好了的自動(dòng)顯式的編號(hào)。如果要同
時(shí)刪除幾個(gè),編號(hào)可以用空格分隔,如果要?jiǎng)h除一個(gè)范圍內(nèi)的編號(hào),
可以用減號(hào)表示(如:2-5)
disable?display?<dnums...>
enable?display?<dnums...>
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
打開地址輸出,當(dāng)程序顯示函數(shù)信息時(shí),GDB會(huì)顯出函數(shù)的參數(shù)地址。系統(tǒng)默認(rèn)為打開的,如:
(gdb)?f
#0?set_quotes?(lq=0x34c78?"<<",?rq=0x34c88?">>")
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="<<",?rq=">>")?at?input.c:530
530?if?(lquote?!=?def_lquote)
show?print?address
查看當(dāng)前地址顯示選項(xiàng)是否打開。
set?print?array
set?print?array?on
打開數(shù)組顯示,打開后當(dāng)數(shù)組顯示時(shí),每個(gè)元素占一行,如果不打開
的話,每個(gè)元素則以逗號(hào)分隔。這個(gè)選項(xiàng)默認(rèn)是關(guān)閉的。與之相關(guān)的
兩個(gè)命令如下,我就不再多說了。
set?print?array?off
show?print?array
set?print?elements?<number-of-elements>?
這個(gè)選項(xiàng)主要是設(shè)置數(shù)組的,如果你的數(shù)組太大了,那么就可以指定
一個(gè)<number-of-elements>來指定數(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?<on/off>
如果打開了這個(gè)選項(xiàng),那么當(dāng)顯示字符串時(shí),遇到結(jié)束符則停止顯示。這個(gè)選項(xiàng)默認(rèn)為off。
set?print?pretty?on
如果打開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ì)如下顯示:
$1?=?{next?=?0x0,?flags?=?{sweet?=?1,?sour?=?1},?meat?=?0x54?"Pork"}
show?print?pretty
查看GDB是如何顯示結(jié)構(gòu)體的。
set?print?sevenbit-strings?<on/off>
設(shè)置字符顯示,是否按“/nnn”的格式顯示,如果打開,則字符串或字符數(shù)據(jù)按/nnn顯示,如“/065”。
show?print?sevenbit-strings
查看字符顯示開關(guān)是否打開。
set?print?union?<on/off>
設(shè)置顯示結(jié)構(gòu)體時(shí),是否顯式其內(nèi)的聯(lián)合體數(shù)據(jù)。例如有以下數(shù)據(jù)結(jié)構(gòu):
typedef?enum?{Tree,?Bug}?Species;
typedef?enum?{Big_tree,?Acorn,?Seedling}?Tree_forms;
typedef?enum?{Caterpillar,?Cocoon,?Butterfly}
Bug_forms;
struct?thing?{
Species?it;
union?{
Tree_forms?tree;
Bug_forms?bug;
}?form;
};
struct?thing?foo?=?{Tree,?{Acorn}};
當(dāng)打開這個(gè)開關(guān)時(shí),執(zhí)行?p?foo?命令后,會(huì)如下顯示:
$1?=?{it?=?Tree,?form?=?{tree?=?Acorn,?bug?=?Cocoon}}
當(dāng)關(guān)閉這個(gè)開關(guān)時(shí),執(zhí)行?p?foo?命令后,會(huì)如下顯示:
$1?=?{it?=?Tree,?form?=?{...}}
show?print?union
查看聯(lián)合體數(shù)據(jù)的顯示方式
set?print?object?<on/off>
在C++中,如果一個(gè)對(duì)象指針指向其派生類,如果打開這個(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?<on/off>
這個(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?<on/off>
當(dāng)此選項(xiàng)打開時(shí),GDB將用比較規(guī)整的格式來顯示虛函數(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記錄下來。GDB會(huì)以$1,?$2,?$3?.....這樣的方式為你每一個(gè)
print命令編上號(hào)。于是,你可以使用這個(gè)編號(hào)訪問以前的表達(dá)式,
如$1。這個(gè)功能所帶來的好處是,如果你先前輸入了一個(gè)比較長(zhǎng)的表
達(dá)式,如果你還想查看這個(gè)表達(dá)式的值,你可以使用歷史記錄來訪問
,省去了重復(fù)輸入。
九、GDB環(huán)境變量
你可以在GDB的調(diào)試環(huán)境中定義自己的變量,用來保存一些調(diào)試程序
中的運(yùn)行數(shù)據(jù)。要定義一個(gè)GDB的變量很簡(jiǎn)單只需。使用GDB的set命
令。GDB的環(huán)境變量和UNIX一樣,也是以$起頭。如:
set?$foo?=?*object_ptr
使用環(huán)境變量時(shí),GDB會(huì)在你第一次使用時(shí)創(chuàng)建這個(gè)變量,而在以后
的使用中,則直接對(duì)其賦值。環(huán)境變量沒有類型,你可以給環(huán)境變量
定義任一的類型。包括結(jié)構(gòu)體和數(shù)組。
show?convenience
該命令查看當(dāng)前所設(shè)置的所有的環(huán)境變量。
這是一個(gè)比較強(qiáng)大的功能,環(huán)境變量和程序變量的交互使用,將使得程序調(diào)試更為靈活便捷。例如:
set?$i?=?0
print?bar[$i++]->contents
于是,當(dāng)你就不必,print?bar[0]->contents,?printbar[1]->contents地輸入命令了。
輸入這樣的命令后,只用敲回車,重復(fù)執(zhí)行上一條語句,環(huán)境變量會(huì)自動(dòng)累加,從而完成逐個(gè)輸出的功
能。
十、查看寄存器
要查看寄存器的值,很簡(jiǎn)單,可以使用如下命令:
info?registers
查看寄存器的情況。(除了浮點(diǎn)寄存器)
info?all-registers
查看所有寄存器的情況。(包括浮點(diǎn)寄存器)
info?registers?<regname?...>
查看所指定的寄存器的情況。
寄存器中放置了程序運(yùn)行時(shí)的數(shù)據(jù),比如程序當(dāng)前運(yùn)行的指令地址(
ip),程序的當(dāng)前堆棧地址(sp)等等。你同樣可以使用print命令
來訪問寄存器的情況,只需要在寄存器名字前加一個(gè)$符號(hào)就可以了
。如:p?$eip。
改變程序的執(zhí)行
一旦使用GDB掛上被調(diào)試程序,當(dāng)程序運(yùn)行起來后,你可以根據(jù)自己的調(diào)試思路來動(dòng)態(tài)地在GDB中更改當(dāng)前被調(diào)試程序的運(yùn)行線路或是其變量的值,這個(gè)強(qiáng)大的功能能夠讓你更好的調(diào)試你的程序,比如,你可以在程序的一次運(yùn)行中走遍程序的所有分支。
一、修改變量值
修改被調(diào)試程序運(yùn)行時(shí)的變量值,在GDB中很容易實(shí)現(xiàn),使用GDB的print命令即可完成。如:
(gdb)?print?x=4
x=4這個(gè)表達(dá)式是C/C++的語法,意為把變量x的值修改為4,如果你當(dāng)
前調(diào)試的語言是Pascal,那么你可以使用Pascal的語法:x:=4。
在某些時(shí)候,很有可能你的變量和GDB中的參數(shù)沖突,如:
(gdb)?whatis?width
type?=?double
(gdb)?p?width
$4?=?13
(gdb)?set?width=47
Invalid?syntax?in?expression.
因?yàn)?#xff0c;set?width是GDB的命令,所以,出現(xiàn)了“Invalid?syntax?in
expression”的設(shè)置錯(cuò)誤,此時(shí),你可以使用set?var命令來告訴GDB
,width不是你GDB的參數(shù),而是程序的變量名,如:
(gdb)?set?var?width=47
另外,還可能有些情況,GDB并不報(bào)告這種錯(cuò)誤,所以保險(xiǎn)起見,在
你改變程序變量取值時(shí),最好都使用set?var格式的GDB命令。
二、跳轉(zhuǎn)執(zhí)行
一般來說,被調(diào)試程序會(huì)按照程序代碼的運(yùn)行順序依次執(zhí)行。GDB提
供了亂序執(zhí)行的功能,也就是說,GDB可以修改程序的執(zhí)行順序,可
以讓程序執(zhí)行隨意跳躍。這個(gè)功能可以由GDB的jump命令來完:
jump?<linespec>
指定下一條語句的運(yùn)行點(diǎn)。<linespce>可以是文件的行號(hào),可以是
file:line格式,可以是+num這種偏移量格式。表式著下一條運(yùn)行語
句從哪里開始。
jump?<address>
這里的<address>是代碼行的內(nèi)存地址。
注意,jump命令不會(huì)改變當(dāng)前的程序棧中的內(nèi)容,所以,當(dāng)你從一個(gè)
函數(shù)跳到另一個(gè)函數(shù)時(shí),當(dāng)函數(shù)運(yùn)行完返回時(shí)進(jìn)行彈棧操作時(shí)必然會(huì)
發(fā)生錯(cuò)誤,可能結(jié)果還是非常奇怪的,甚至于產(chǎn)生程序Core?Dump。
所以最好是同一個(gè)函數(shù)中進(jìn)行跳轉(zhuǎn)。
熟悉匯編的人都知道,程序運(yùn)行時(shí),有一個(gè)寄存器用于保存當(dāng)前代碼
所在的內(nèi)存地址。所以,jump命令也就是改變了這個(gè)寄存器中的值。
于是,你可以使用“set?$pc”來更改跳轉(zhuǎn)執(zhí)行的地址。如:
set?$pc?=?0x485
三、產(chǎn)生信號(hào)量
?
使用singal命令,可以產(chǎn)生一個(gè)信號(hào)量給被調(diào)試的程序。如:中斷信
?號(hào)Ctrl+C。這非常方便于程序的調(diào)試,可以在程序運(yùn)行的任意位置
?設(shè)置斷點(diǎn),并在該斷點(diǎn)用GDB產(chǎn)生一個(gè)信號(hào)量,這種精確地在某處產(chǎn)
?生信號(hào)非常有利程序的調(diào)試。
語法是:signal?<singal>,UNIX的系統(tǒng)信號(hào)量通常從1到15。所以<singal>取值也在這個(gè)范圍。
single命令和shell的kill命令不同,系統(tǒng)的kill命令發(fā)信號(hào)給被調(diào)
試程序時(shí),是由GDB截獲的,而single命令所發(fā)出一信號(hào)則是直接發(fā)
給被調(diào)試程序的。
四、強(qiáng)制函數(shù)返回
如果你的調(diào)試斷點(diǎn)在某個(gè)函數(shù)中,并還有語句沒有執(zhí)行完。你可以使
用return命令強(qiáng)制函數(shù)忽略還沒有執(zhí)行的語句并返回。
return
return?<expression>
使用return命令取消當(dāng)前函數(shù)的執(zhí)行,并立即返回,如果指定了<expression>,那么該表達(dá)式的值會(huì)被認(rèn)作函數(shù)的返回值。
五、強(qiáng)制調(diào)用函數(shù)
call?<expr>
表達(dá)式中可以一是函數(shù),以此達(dá)到強(qiáng)制調(diào)用函數(shù)的目的。并顯示函數(shù)的返回值,如果函數(shù)返回值是void,那么就不顯示。
另一個(gè)相似的命令也可以完成這一功能——print,print后面可以跟
表達(dá)式,所以也可以用他來調(diào)用函數(shù),print和call的不同是,如果
函數(shù)返回void,call則不顯示,print則顯示函數(shù)返回值,并把該值
存入歷史數(shù)據(jù)中。
在不同語言中使用GDB
GDB?支持下列語言:C,?C++,?Fortran,?PASCAL,?Java,?Chill,
assembly,?和?Modula-2。一般說來,GDB會(huì)根據(jù)你所調(diào)試的程序來確
定當(dāng)然的調(diào)試語言,比如:發(fā)現(xiàn)文件名后綴為“.c”的,GDB會(huì)認(rèn)為
是C程序。文件名后綴為?“.C,?.cc,?.cp,?.cpp,?.cxx,?.c++”的,
GDB會(huì)認(rèn)為是C++程序。而后綴是“.f,?.F”的,GDB會(huì)認(rèn)為是Fortran
程序,還有,后綴為如果是“.s,?.S”的會(huì)認(rèn)為是匯編語言。
也就是說,GDB會(huì)根據(jù)你所調(diào)試的程序的語言,來設(shè)置自己的語言環(huán)
境,并讓GDB的命令跟著語言環(huán)境的改變而改變。比如一些GDB命令需
要用到表達(dá)式或變量時(shí),這些表達(dá)式或變量的語法,完全是根據(jù)當(dāng)前
的語言環(huán)境而改變的。例如C/C++中對(duì)指針的語法是*p,而在
Modula-2中則是p^。并且,如果你當(dāng)前的程序是由幾種不同語言一同
編譯成的,那到在調(diào)試過程中,GDB也能根據(jù)不同的語言自動(dòng)地切換
語言環(huán)境。這種跟著語言環(huán)境而改變的功能,真是體貼開發(fā)人員的一
種設(shè)計(jì)。
下面是幾個(gè)相關(guān)于GDB語言環(huán)境的命令:
show?language
查看當(dāng)前的語言環(huán)境。如果GDB不能識(shí)為你所調(diào)試的編程語言,那么,C語言被認(rèn)為是默認(rèn)的環(huán)境。
info?frame
查看當(dāng)前函數(shù)的程序語言。
info?source
查看當(dāng)前文件的程序語言。
如果GDB沒有檢測(cè)出當(dāng)前的程序語言,那么你也可以手動(dòng)設(shè)置當(dāng)前的程序語言。使用set?language命令即可做到。
當(dāng)set?language命令后什么也不跟的話,你可以查看GDB所支持的語言種類:
(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
于是你可以在set?language后跟上被列出來的程序語言名,來設(shè)置當(dāng)前的語言環(huán)境。
后記
GDB? 是一個(gè)強(qiáng)大的命令行調(diào)試工具。大家知道命令行的強(qiáng)大就是在于,其可以形成執(zhí)行序列,形成腳本。UNIX下的軟件全是命令行的,這給程序開發(fā)提代供了極大的 便利,命令行軟件的優(yōu)勢(shì)在于,它們可以非常容易的集成在一起,使用幾個(gè)簡(jiǎn)單的已有工具的命令,就可以做出一個(gè)非常強(qiáng)大的功能。
于 是?UNIX下的軟件比Windows下的軟件更能有機(jī)地結(jié)合,各自發(fā)揮各自的長(zhǎng)處,組合成更為強(qiáng)勁的功能。而Windows下的圖形軟件基本上是各自為 營(yíng),互相不能調(diào)用,很不利于各種軟件的相互集成。在這里并不是要和Windows做個(gè)什么比較,所謂“寸有所長(zhǎng),尺有所短”,圖形化工具還是有不如命令行 的地方。(看到這句話時(shí),希望各位千萬再也不要認(rèn)為我就是“鄙視圖形界面”,和我抬杠了?)
我是根據(jù)版本為5.1.1的GDB所寫的這篇文章,所以可能有些功能已被修改,或是又有更為強(qiáng)勁的功能。而且,我寫得非常倉促,寫得比較簡(jiǎn)略,并且,其中我已經(jīng)看到有許多錯(cuò)別字了(我用五筆,所以錯(cuò)字讓你看不懂),所以,我在這里對(duì)我文中的差錯(cuò)表示萬分的歉意。
文中所羅列的GDB的功能時(shí),我只是羅列了一些帶用的GDB的命令和使用方法,其實(shí),我這里只講述的功能大約只占GDB所有功能的60%吧,詳細(xì)的文檔,還是請(qǐng)查看GDB的幫助和使用手冊(cè)吧,或許,過段時(shí)間,如果我有空,我再寫一篇GDB的高級(jí)使用。
我 個(gè)人非常喜歡GDB的自動(dòng)調(diào)試的功能,這個(gè)功能真的很強(qiáng)大,試想,我在UNIX下寫個(gè)腳本,讓腳本自動(dòng)編譯我的程序,被自動(dòng)調(diào)試,并把結(jié)果報(bào)告出來,調(diào)試 成功,自動(dòng)checkin源碼庫。一個(gè)命令,編譯帶著調(diào)試帶著checkin,多爽啊。只是GDB對(duì)自動(dòng)化調(diào)試目前支持還不是很成熟,只能實(shí)現(xiàn)半自動(dòng)化, 真心期望著GDB的自動(dòng)化調(diào)試功能的成熟。
QQ是:?753640,MSN是:?haoel@hotmail.com)
轉(zhuǎn)載于:https://www.cnblogs.com/persist/p/3554637.html
總結(jié)
以上是生活随笔為你收集整理的转:用GDB调试程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS, JavaScript, jQu
- 下一篇: SCVMM 2012 R2---安装SC