你可以使用info line命令來查看源代碼在內(nèi)存中的地址。info line
后面可以跟“行號”,“函數(shù)名”,“文件名:行號”,“文件名:函
數(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>.
還有一個命令(disassemble)你可以查看源程序的當前執(zhí)行時的機
器碼,這個命令會把目前內(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.
在你調(diào)試程序時,當程序被停住時,你可以使用print命
令(簡寫命令為p),或是同義命令inspect來查看當前程序的運行數(shù)
據(jù)。print命令的格式是:
print <expr>
print /<f> <expr>
<expr>是表達式,是你所調(diào)試的程序的語言的表達式(GDB可以調(diào)試
多種編程語言),<f>是輸出的格式,比如,如果要把表達式按16進
制的格式輸出,那么就是/x。
print和許多GDB的命令一樣,可以接受一個表達式,GDB會根據(jù)當前
的程序運行的數(shù)據(jù)來計算這個表達式,既然是表達式,那么就可以是
當前程序運行中的const常量、變量、函數(shù)等內(nèi)容??上У氖荊DB不能
使用你在程序中所定義的宏。
表達式的語法應(yīng)該是當前所調(diào)試的語言的語法,由于C/C++是一種大
眾型的語言,所以,本文中的例子都是關(guān)于C/C++的。(而關(guān)于用GDB
調(diào)試其它語言的章節(jié),我將在后面介紹)
在表達式中,有幾種GDB所支持的操作符,它們可以用在任何一種語言中。
@
是一個和數(shù)組有關(guān)的操作符,在后面會有更詳細的說明。
::
指定一個在文件或是一個函數(shù)中的變量。
{<type>} <addr>
表示一個指向內(nèi)存地址<addr>的類型為type的一個對象。
在GDB中,你可以隨時查看以下三種變量的值:
1、全局變量(所有文件可見的)
2、靜態(tài)全局變量(當前文件可見的)
3、局部變量(當前Scope可見的)
如果你的局部變量和全局變量發(fā)生沖突(也就是重名),一般情況下
是局部變量會隱藏全局變量,也就是說,如果一個全局變量和一個函
數(shù)中的局部變量同名時,如果當前停止點在函數(shù)中,用print顯示出
的變量的值會是函數(shù)中的局部變量的值。如果此時你想查看全局變量
的值時,你可以使用“::”操作符:
file::variable
function::variable
可以通過這種形式指定你所想查看的變量,是哪個文件中的或是哪個
函數(shù)中的。例如,查看文件f2.c中的全局變量x的值:
gdb) p 'f2.c'::x
當然,“::”操作符會和C++中的發(fā)生沖突,GDB能自動識別“::”
是否C++的操作符,所以你不必擔心在調(diào)試C++程序時會出現(xiàn)異常。
另外,需要注意的是,如果你的程序編譯時開啟了優(yōu)化選項,那么在
用GDB調(diào)試被優(yōu)化過的程序時,可能會發(fā)生某些變量不能訪問,或是
取值錯誤碼的情況。這個是很正常的,因為優(yōu)化程序會刪改你的程序
,整理你程序的語句順序,剔除一些無意義的變量等,所以在GDB調(diào)
試這種程序時,運行時的指令和你所編寫指令就有不一樣,也就會出
現(xiàn)你所想象不到的結(jié)果。對付這種情況時,需要在編譯程序時關(guān)閉編
譯優(yōu)化。一般來說,幾乎所有的編譯器都支持編譯優(yōu)化的開關(guān),例如
,GNU 的C/C++編譯器GCC,你可以使用“-gstabs”選項來解決這個
問題。關(guān)于編譯器的參數(shù),還請查看編譯器的使用說明文檔。
有時候,你需要查看一段連續(xù)的內(nèi)存空間的值。比如數(shù)組的一段,或
是動態(tài)分配的數(shù)據(jù)的大小。你可以使用GDB的“@”操作符,“@”的
左邊是第一個內(nèi)存的地址的值,“@”的右邊則你你想查看內(nèi)存的長
度。例如,你的程序中有這樣的語句:
int *array = (int *) malloc (len * sizeof (int));
于是,在GDB調(diào)試過程中,你可以以如下命令顯示出這個動態(tài)數(shù)組的取值:
p *array@len
@的左邊是數(shù)組的首地址的值,也就是變量array所指向的內(nèi)容,右邊
則是數(shù)據(jù)的長度,其保存在變量len中,其輸出結(jié)果,大約是下面這
個樣子的:
(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會根據(jù)變量的類型輸出變量的值。但你也可以自定義
GDB的輸出的格式。例如,你想輸出一個整數(shù)的十六進制,或是二進
制來查看這個整型變量的中的位的情況。要做到這樣,你可以使用
GDB的數(shù)據(jù)顯示格式:
x 按十六進制格式顯示變量。
d 按十進制格式顯示變量。
u 按十六進制格式顯示無符號整型。
o 按八進制格式顯示變量。
t 按二進制格式顯示變量。
a 按十六進制格式顯示變量。
c 按字符格式顯示變量。
f 按浮點數(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
你可以使用examine命令(簡寫是x)來查看內(nèi)存地址中的值。x命令的語法如下所示:
x/<n/f/u> <addr>
n、f、u是可選的參數(shù)。
n 是一個正整數(shù),表示顯示內(nèi)存的長度,也就是說從當前地址向后顯示幾個地址的內(nèi)容。
f 表示顯示的格式,參見上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
u 表示從當前地址往后請求的字節(jié)數(shù),如果不指定的話,GDB默認是4
個bytes。u參數(shù)可以用下面的字符來代替,b表示單字節(jié),h表示雙
字節(jié),w表示四字節(jié),g表示八字節(jié)。當我們指定了字節(jié)長度后,
GDB會從指內(nèi)存定的內(nèi)存地址開始,讀寫指定字節(jié),并把其當作一
個值取出來。
<addr>表示一個內(nèi)存地址。
n/f/u三個參數(shù)可以一起使用。例如:
命令:x/3uh 0x54320 表示,從內(nèi)存地址0x54320讀取內(nèi)容,h表示以
雙字節(jié)為一個單位,3表示三個單位,u表示按十六進制顯示。
你可以設(shè)置一些自動顯示的變量,當程序停住時,或是在你單步跟蹤
時,這些變量會自動顯示。相關(guān)的GDB命令是display。
display <expr>
display/<fmt> <expr>
display/<fmt> <addr>
expr是一個表達式,fmt表示顯示的格式,addr表示內(nèi)存地址,當你
用display設(shè)定好了一個或多個表達式后,只要你的程序被停下來,
GDB會自動顯示你所設(shè)置的這些表達式的值。
格式i和s同樣被display支持,一個非常有用的命令是:
display/i $pc
$pc是GDB的環(huán)境變量,表示著指令的地址,/i則表示輸出格式為機器
指令碼,也就是匯編。于是當程序停下后,就會出現(xiàn)源代碼和機器指
令碼相對應(yīng)的情形,這是一個很有意思的功能。
下面是一些和display相關(guān)的GDB命令:
undisplay <dnums...>
delete display <dnums...>
刪除自動顯示,dnums意為所設(shè)置好了的自動顯式的編號。如果要同
時刪除幾個,編號可以用空格分隔,如果要刪除一個范圍內(nèi)的編號,
可以用減號表示(如:2-5)
disable display <dnums...>
enable display <dnums...>
disable和enalbe不刪除自動顯示的設(shè)置,而只是讓其失效和恢復(fù)。
info display
查看display設(shè)置的自動顯示的信息。GDB會打出一張
表格,向你報告當然調(diào)試中設(shè)置了多少個自動顯示設(shè)置,其中包括,
設(shè)置的編號,表達式,是否enable。
GDB中關(guān)于顯示的選項比較多,這里我只例舉大多數(shù)常用的選項。
set print address
set print address on
打開地址輸出,當程序顯示函數(shù)信息時,GDB會顯出函數(shù)的參數(shù)地址。系統(tǒng)默認為打開的,如:
(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
查看當前地址顯示選項是否打開。
set print array
set print array on
打開數(shù)組顯示,打開后當數(shù)組顯示時,每個元素占一行,如果不打開
的話,每個元素則以逗號分隔。這個選項默認是關(guān)閉的。與之相關(guān)的
兩個命令如下,我就不再多說了。
set print array off
show print array
set print elements <number-of-elements>
這個選項主要是設(shè)置數(shù)組的,如果你的數(shù)組太大了,那么就可以指定
一個<number-of-elements>來指定數(shù)據(jù)顯示的最大長度,當?shù)竭_這個
長度時,GDB就不再往下顯示了。如果設(shè)置為0,則表示不限制。
show print elements
查看print elements的選項信息。
set print null-stop <on/off>
如果打開了這個選項,那么當顯示字符串時,遇到結(jié)束符則停止顯示。這個選項默認為off。
set print pretty on
如果打開printf pretty這個選項,那么當GDB顯示結(jié)構(gòu)體時會比較漂亮。如:
$1 = {
next = 0x0,
flags = {
sweet = 1,
sour = 1
},
meat = 0x54 "Pork"
}
set print pretty off
關(guān)閉printf pretty這個選項,GDB顯示結(jié)構(gòu)體時會如下顯示:
$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)體時,是否顯式其內(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}};
當打開這個開關(guān)時,執(zhí)行 p foo 命令后,會如下顯示:
$1 = {it = Tree, form = {tree = Acorn, bug = Cocoon}}
當關(guān)閉這個開關(guān)時,執(zhí)行 p foo 命令后,會如下顯示:
$1 = {it = Tree, form = {...}}
show print union
查看聯(lián)合體數(shù)據(jù)的顯示方式
set print object <on/off>
在C++中,如果一個對象指針指向其派生類,如果打開這個選項,GDB
會自動按照虛方法調(diào)用的規(guī)則顯示輸出,如果關(guān)閉這個選項的話,
GDB就不管虛函數(shù)表了。這個選項默認是off。
show print object
查看對象選項的設(shè)置。
set print static-members <on/off>
這個選項表示,當顯示一個C++對象中的內(nèi)容是,是否顯示其中的靜態(tài)數(shù)據(jù)成員。默認是on。
show print static-members
查看靜態(tài)數(shù)據(jù)成員選項設(shè)置。
set print vtbl <on/off>
當此選項打開時,GDB將用比較規(guī)整的格式來顯示虛函數(shù)表時。其默認是關(guān)閉的。
show print vtbl
查看虛函數(shù)顯示格式的選項。
當你用GDB的print查看程序運行時的數(shù)據(jù)時,你每一個print都會被
GDB記錄下來。GDB會以$1, $2, $3 .....這樣的方式為你每一個
print命令編上號。于是,你可以使用這個編號訪問以前的表達式,
如$1。這個功能所帶來的好處是,如果你先前輸入了一個比較長的表
達式,如果你還想查看這個表達式的值,你可以使用歷史記錄來訪問
,省去了重復(fù)輸入。
你可以在GDB的調(diào)試環(huán)境中定義自己的變量,用來保存一些調(diào)試程序
中的運行數(shù)據(jù)。要定義一個GDB的變量很簡單只需。使用GDB的set命
令。GDB的環(huán)境變量和UNIX一樣,也是以$起頭。如:
set $foo = *object_ptr
使用環(huán)境變量時,GDB會在你第一次使用時創(chuàng)建這個變量,而在以后
的使用中,則直接對其賦值。環(huán)境變量沒有類型,你可以給環(huán)境變量
定義任一的類型。包括結(jié)構(gòu)體和數(shù)組。
show convenience
該命令查看當前所設(shè)置的所有的環(huán)境變量。
這是一個比較強大的功能,環(huán)境變量和程序變量的交互使用,將使得程序調(diào)試更為靈活便捷。例如:
set $i = 0
print bar[$i++]->contents
于是,當你就不必,print bar[0]->contents, printbar[1]->contents地輸入命令了。
輸入這樣的命令后,只用敲回車,重復(fù)執(zhí)行上一條語句,環(huán)境變量會自動累加,從而完成逐個輸出的功
能。
要查看寄存器的值,很簡單,可以使用如下命令:
info registers
查看寄存器的情況。(除了浮點寄存器)
info all-registers
查看所有寄存器的情況。(包括浮點寄存器)
info registers <regname ...>
查看所指定的寄存器的情況。
寄存器中放置了程序運行時的數(shù)據(jù),比如程序當前運行的指令地址(
ip),程序的當前堆棧地址(sp)等等。你同樣可以使用print命令
來訪問寄存器的情況,只需要在寄存器名字前加一個$符號就可以了
。如:p $eip。
一旦使用GDB掛上被調(diào)試程序,當程序運行起來后,你可以根據(jù)自己 的調(diào)試思路來動態(tài)地在GDB中更改當前被調(diào)試程序的運行線路或是其 變量的值,這個強大的功能能夠讓你更好的調(diào)試你的程序,比如,你 可以在程序的一次運行中走遍程序的所有分支。
修改被調(diào)試程序運行時的變量值,在GDB中很容易實現(xiàn),使用GDB的print命令即可完成。如:
(gdb) print x=4
x=4這個表達式是C/C++的語法,意為把變量x的值修改為4,如果你當
前調(diào)試的語言是Pascal,那么你可以使用Pascal的語法:x:=4。
在某些時候,很有可能你的變量和GDB中的參數(shù)沖突,如:
(gdb) whatis width
type = double
(gdb) p width
$4 = 13
(gdb) set width=47
Invalid syntax in expression.
因為,set width是GDB的命令,所以,出現(xiàn)了“Invalid syntax in
expression”的設(shè)置錯誤,此時,你可以使用set var命令來告訴GDB
,width不是你GDB的參數(shù),而是程序的變量名,如:
(gdb) set var width=47
另外,還可能有些情況,GDB并不報告這種錯誤,所以保險起見,在
你改變程序變量取值時,最好都使用set var格式的GDB命令。
一般來說,被調(diào)試程序會按照程序代碼的運行順序依次執(zhí)行。GDB提
供了亂序執(zhí)行的功能,也就是說,GDB可以修改程序的執(zhí)行順序,可
以讓程序執(zhí)行隨意跳躍。這個功能可以由GDB的jump命令來完:
jump <linespec>
指定下一條語句的運行點。<linespce>可以是文件的行號,可以是
file:line格式,可以是+num這種偏移量格式。表式著下一條運行語
句從哪里開始。
jump <address>
這里的<address>是代碼行的內(nèi)存地址。
注意,jump命令不會改變當前的程序棧中的內(nèi)容,所以,當你從一個
函數(shù)跳到另一個函數(shù)時,當函數(shù)運行完返回時進行彈棧操作時必然會
發(fā)生錯誤,可能結(jié)果還是非常奇怪的,甚至于產(chǎn)生程序Core Dump。
所以最好是同一個函數(shù)中進行跳轉(zhuǎn)。
熟悉匯編的人都知道,程序運行時,有一個寄存器用于保存當前代碼
所在的內(nèi)存地址。所以,jump命令也就是改變了這個寄存器中的值。
于是,你可以使用“set $pc”來更改跳轉(zhuǎn)執(zhí)行的地址。如:
set $pc = 0x485
使用singal命令,可以產(chǎn)生一個信號量給被調(diào)試的程序。如:中斷信
號Ctrl+C。這非常方便于程序的調(diào)試,可以在程序運行的任意位置
設(shè)置斷點,并在該斷點用GDB產(chǎn)生一個信號量,這種精確地在某處產(chǎn)
生信號非常有利程序的調(diào)試。
語法是:signal <singal>,UNIX的系統(tǒng)信號量通常從1到15。所以<singal>取值也在這個范圍。
single命令和shell的kill命令不同,系統(tǒng)的kill命令發(fā)信號給被調(diào)
試程序時,是由GDB截獲的,而single命令所發(fā)出一信號則是直接發(fā)
給被調(diào)試程序的。
如果你的調(diào)試斷點在某個函數(shù)中,并還有語句沒有執(zhí)行完。你可以使
用return命令強制函數(shù)忽略還沒有執(zhí)行的語句并返回。
return
return <expression>
使用return命令取消當前函數(shù)的執(zhí)行,并立即返回,如果指定了<expression>,那么該表達式的值會被認作函數(shù)的返回值。
call <expr>
表達式中可以一是函數(shù),以此達到強制調(diào)用函數(shù)的目的。并顯示函數(shù)的返回值,如果函數(shù)返回值是void,那么就不顯示。
另一個相似的命令也可以完成這一功能——print,print后面可以跟
表達式,所以也可以用他來調(diào)用函數(shù),print和call的不同是,如果
函數(shù)返回void,call則不顯示,print則顯示函數(shù)返回值,并把該值
存入歷史數(shù)據(jù)中。
GDB 支持下列語言:C, C++, Fortran, PASCAL, Java, Chill,
assembly, 和 Modula-2。一般說來,GDB會根據(jù)你所調(diào)試的程序來確
定當然的調(diào)試語言,比如:發(fā)現(xiàn)文件名后綴為“.c”的,GDB會認為
是C程序。文件名后綴為 “.C, .cc, .cp, .cpp, .cxx, .c++”的,
GDB會認為是C++程序。而后綴是“.f, .F”的,GDB會認為是Fortran
程序,還有,后綴為如果是“.s, .S”的會認為是匯編語言。
也就是說,GDB會根據(jù)你所調(diào)試的程序的語言,來設(shè)置自己的語言環(huán)
境,并讓GDB的命令跟著語言環(huán)境的改變而改變。比如一些GDB命令需
要用到表達式或變量時,這些表達式或變量的語法,完全是根據(jù)當前
的語言環(huán)境而改變的。例如C/C++中對指針的語法是*p,而在
Modula-2中則是p^。并且,如果你當前的程序是由幾種不同語言一同
編譯成的,那到在調(diào)試過程中,GDB也能根據(jù)不同的語言自動地切換
語言環(huán)境。這種跟著語言環(huán)境而改變的功能,真是體貼開發(fā)人員的一
種設(shè)計。
下面是幾個相關(guān)于GDB語言環(huán)境的命令:
show language
查看當前的語言環(huán)境。如果GDB不能識為你所調(diào)試的編程語言,那么,C語言被認為是默認的環(huán)境。
info frame
查看當前函數(shù)的程序語言。
info source
查看當前文件的程序語言。
如果GDB沒有檢測出當前的程序語言,那么你也可以手動設(shè)置當前的程序語言。使用set language命令即可做到。
當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è)置當前的語言環(huán)境。
GDB 是一個強大的命令行調(diào)試工具。大家知道命令行的強大就是在于 ,其可以形成執(zhí)行序列,形成腳本。UNIX下的軟件全是命令行的,這 給程序開發(fā)提代供了極大的便利,命令行軟件的優(yōu)勢在于,它們可以 非常容易的集成在一起,使用幾個簡單的已有工具的命令,就可以做 出一個非常強大的功能。
于是 UNIX下的軟件比Windows下的軟件更能有機地結(jié)合,各自發(fā)揮各 自的長處,組合成更為強勁的功能。而Windows下的圖形軟件基本上 是各自為營,互相不能調(diào)用,很不利于各種軟件的相互集成。在這里 并不是要和Windows做個什么比較,所謂“寸有所長,尺有所短”, 圖形化工具還是有不如命令行的地方。(看到這句話時,希望各位千 萬再也不要認為我就是“鄙視圖形界面”,和我抬杠了 )
我是根據(jù)版本為5.1.1的GDB所寫的這篇文章,所以可能有些功能已被 修改,或是又有更為強勁的功能。而且,我寫得非常倉促,寫得比較 簡略,并且,其中我已經(jīng)看到有許多錯別字了(我用五筆,所以錯字 讓你看不懂),所以,我在這里對我文中的差錯表示萬分的歉意。
文中所羅列的GDB的功能時,我只是羅列了一些帶用的GDB的命令和使 用方法,其實,我這里只講述的功能大約只占GDB所有功能的60%吧, 詳細的文檔,還是請查看GDB的幫助和使用手冊吧,或許,過段時間 ,如果我有空,我再寫一篇GDB的高級使用。
我個人非常喜歡GDB的自動調(diào)試的功能,這個功能真的很強大,試想 ,我在UNIX下寫個腳本,讓腳本自動編譯我的程序,被自動調(diào)試,并 把結(jié)果報告出來,調(diào)試成功,自動checkin源碼庫。一個命令,編譯 帶著調(diào)試帶著checkin,多爽啊。只是GDB對自動化調(diào)試目前支持還不 是很成熟,只能實現(xiàn)半自動化,真心期望著GDB的自動化調(diào)試功能的 成熟。
如果各位對GDB或是別的技術(shù)問題有興趣的話,歡迎和我討論交流。 本人目前主要在UNIX下做產(chǎn)品軟件的開發(fā),所以,對UNIX下的軟件開 發(fā)比較熟悉,當然,不單單是技術(shù),對軟件工程實施,軟件設(shè)計,系 統(tǒng)分析,項目管理我也略有心得。歡迎大家找我交流,(QQ是: 753640,MSN是: haoel@hotmail.com)
小結(jié):常用的gdb命令
backtrace 顯示程序中的當前位置和表示如何到達當前位置的棧跟蹤(同義詞:where)
breakpoint 在程序中設(shè)置一個斷點
cd 改變當前工作目錄
clear 刪除剛才停止處的斷點
commands 命中斷點時,列出將要執(zhí)行的命令
continue 從斷點開始繼續(xù)執(zhí)行
delete 刪除一個斷點或監(jiān)測點;也可與其他命令一起使用
display 程序停止時顯示變量和表達時
down 下移棧幀,使得另一個函數(shù)成為當前函數(shù)
frame 選擇下一條continue命令的幀
info 顯示與該程序有關(guān)的各種信息
jump 在源程序中的另一點開始運行
kill 異常終止在gdb 控制下運行的程序
list 列出相應(yīng)于正在執(zhí)行的程序的原文件內(nèi)容
next 執(zhí)行下一個源程序行,從而執(zhí)行其整體中的一個函數(shù)
print 顯示變量或表達式的值
pwd 顯示當前工作目錄
pype 顯示一個數(shù)據(jù)結(jié)構(gòu)(如一個結(jié)構(gòu)或C++類)的內(nèi)容
quit 退出gdb
reverse-search 在源文件中反向搜索正規(guī)表達式
run 執(zhí)行該程序
search 在源文件中搜索正規(guī)表達式
set variable 給變量賦值
signal 將一個信號發(fā)送到正在運行的進程
step 執(zhí)行下一個源程序行,必要時進入下一個函數(shù)
undisplay display命令的反命令,不要顯示表達式
until 結(jié)束當前循環(huán)
up 上移棧幀,使另一函數(shù)成為當前函數(shù)
watch 在程序中設(shè)置一個監(jiān)測點(即數(shù)據(jù)斷點)
whatis 顯示變量或函數(shù)類型
****************************************************
GNU的調(diào)試器稱為gdb,該程序是一個交互式工具,工作在字符模式。在 X Window 系統(tǒng)中,有一個gdb的前端圖形工具,稱為xxgdb。gdb 是功能強大的調(diào)試程序,可完成如下的調(diào)試任務(wù):
* 設(shè)置斷點;
* 監(jiān)視程序變量的值;
* 程序的單步執(zhí)行;
* 修改變量的值。
在可以使用 gdb 調(diào)試程序之前,必須使用 -g 選項編譯源文件??稍?makefile 中如下定義 CFLAGS 變量:
CFLAGS = -g
運行 gdb 調(diào)試程序時通常使用如下的命令:
gdb progname
在 gdb 提示符處鍵入help,將列出命令的分類,主要的分類有:
* aliases:命令別名
* breakpoints:斷點定義;
* data:數(shù)據(jù)查看;
* files:指定并查看文件;
* internals:維護命令;
* running:程序執(zhí)行;
* stack:調(diào)用棧查看;
* statu:狀態(tài)查看;
* tracepoints:跟蹤程序執(zhí)行。
鍵入 help 后跟命令的分類名,可獲得該類命令的詳細清單。
gdb 的常用命令
命令 解釋
break NUM 在指定的行上設(shè)置斷點。
bt 顯示所有的調(diào)用棧幀。該命令可用來顯示函數(shù)的調(diào)用順序。
clear 刪除設(shè)置在特定源文件、特定行上的斷點。其用法為clear FILENAME:NUM
continue 繼續(xù)執(zhí)行正在調(diào)試的程序。該命令用在程序由于處理信號或斷點而 導(dǎo)致停止運行時。
display EXPR 每次程序停止后顯示表達式的值。表達式由程序定義的變量組成。
file FILE 裝載指定的可執(zhí)行文件進行調(diào)試。
help NAME 顯示指定命令的幫助信息。
info break 顯示當前斷點清單,包括到達斷點處的次數(shù)等。
info files 顯示被調(diào)試文件的詳細信息。
info func 顯示所有的函數(shù)名稱。
info local 顯示當函數(shù)中的局部變量信息。
info prog 顯示被調(diào)試程序的執(zhí)行狀態(tài)。
info var 顯示所有的全局和靜態(tài)變量名稱。
kill 終止正被調(diào)試的程序。
list 顯示源代碼段。
make 在不退出 gdb 的情況下運行 make 工具。
next 在不單步執(zhí)行進入其他函數(shù)的情況下,向前執(zhí)行一行源代碼。
print EXPR 顯示表達式 EXPR 的值。
******gdb 使用范例************************
-----------------
清單 一個有錯誤的 C 源程序 bugging.c
代碼:
-----------------
1?。 nclude
2
3 static char buff [256];
4 static char* string;
5 int main ()
6 {
7 printf ("Please input a string: ");
8 gets (string);
9 printf ("\nYour string is: %s\n", string);
10 }
-----------------
上面這個程序非常簡單,其目的是接受用戶的輸入,然后將用戶的輸入打印出來。該程序使用了一個未經(jīng)過初始化的字符串地址 string,因此,編譯并運行之后,將出現(xiàn) Segment Fault 錯誤:
$ gcc -o bugging -g bugging.c
$ ./bugging
Please input a string: asfd
Segmentation fault (core dumped)
為了查找該程序中出現(xiàn)的問題,我們利用 gdb,并按如下的步驟進行:
1.運行 gdb bugging 命令,裝入 bugging 可執(zhí)行文件;
2.執(zhí)行裝入的 bugging 命令 run;
3.使用 where 命令查看程序出錯的地方;
4.利用 list 命令查看調(diào)用 gets 函數(shù)附近的代碼;
5.唯一能夠?qū)е?gets 函數(shù)出錯的因素就是變量 string。用print命令查看 string 的值;
6.在 gdb 中,我們可以直接修改變量的值,只要將 string 取一個合法的指針值就可以了,為此,我們在第8行處設(shè)置斷點 break 8;
7.程序重新運行到第 8行處停止,這時,我們可以用 set variable 命令修改 string 的取值;
8.然后繼續(xù)運行,將看到正確的程序運行結(jié)果。