GDB使用指南 [ZZ]
使用GDB:
本文描述GDB,GNU的原代碼調(diào)試器。(這是4.12版1994年一月,GDB版本4。16)
目錄:
* 摘要: GDB的摘要
* 實(shí)例: 一個(gè)使用實(shí)例
* 入門: 進(jìn)入和退出GDB
* 命令: GDB 的命令
* 運(yùn)行: 在GDB下運(yùn)行程序
* 停止: 暫停和繼續(xù)執(zhí)行
* 棧: 檢查堆棧
* 原文件: 檢查原文件
* 數(shù)據(jù): 檢查數(shù)據(jù)
* 語言: 用不同的語言來使用GDB
* 符號(hào): 檢查符號(hào)表
* 更改: 更改執(zhí)行
* GDB的文件 文件
* 對(duì)象 指定調(diào)試對(duì)象
* 控制GDB 控制
* 執(zhí)行序列: 執(zhí)行一序列命令
* Emacs: 使GDB和Emacs一起工作
* GDB的bug:
* 命令行編輯: 行編輯
* 使用歷史記錄交互:
* 格式化文檔: 如何格式化和打印GDB文檔
* 安裝GDB :
* 索引:
GDB簡介:
**************
調(diào)試器(比如象GDB)能讓你觀察另一個(gè)程序在執(zhí)行時(shí)的內(nèi)部活動(dòng),或程序出錯(cuò)時(shí)
發(fā)生了什么。
GDB主要能為你做四件事(包括為了完成這些事而附加的功能),幫助你找出程序
中的錯(cuò)誤。
* 運(yùn)行你的程序,設(shè)置所有的能影響程序運(yùn)行的東西。
* 保證你的程序在指定的條件下停止。
* 當(dāng)你程序停止時(shí),讓你檢查發(fā)生了什么。
* 改變你的程序。那樣你可以試著修正某個(gè)bug引起的問題,然后繼續(xù)查找另一
個(gè)bug.
你可以用GDB來調(diào)試C和C++寫的程序。(參考 *C 和C++)
部分支持Modula-2和chill,但現(xiàn)在還沒有這方面的文檔。
調(diào)試Pascal程序時(shí),有一些功能還不能使用。
GDB還可以用來調(diào)試FORTRAN程序,盡管現(xiàn)在還不支持表達(dá)式的輸入,輸出變量,
或類FORTRAN的詞法。
* GDB是"free software",大家都可以免費(fèi)拷貝。也可以為GDB增加新的功能,不
過可要遵守GNU的許可協(xié)議幺。反正我認(rèn)為GNU還是比較不錯(cuò)的:-)
就這句話:
Fundamentally, the General Public License is a license which says
that you have these freedoms and that you cannot take these freedoms
away from anyone else.
GDB的作者:
Richard Stallman是GDB的始作俑者,另外還有許多別的GNU的成員。許多人
為此作出了貢獻(xiàn)。(都是老外不提也罷,但愿他們不要來找我麻煩:-))
這里是GDB的一個(gè)例子:
原文中是使用一個(gè)叫m4的程序。但很遺憾我找不到這個(gè)程序的原代碼,
所以沒有辦法來按照原文來說明。不過反正是個(gè)例子,我就拿一個(gè)操作系統(tǒng)的
進(jìn)程調(diào)度原碼來說明把,原代碼我會(huì)附在后面。
首先這個(gè)程序叫os.c是一個(gè)模擬進(jìn)程調(diào)度的原程序(也許是個(gè)老古董了:-))。
先說明一下如何取得包括原代碼符號(hào)的可執(zhí)行代碼。大家有心的話可以去看一下gcc的
man文件(在shell下打man gcc)。gcc -g <原文件.c> -o <要生成的文件名>
-g 的意思是生成帶原代碼調(diào)試符號(hào)的可執(zhí)行文件。
-o 的意思是指定可執(zhí)行文件名。
(gcc 的命令行參數(shù)有一大堆,有興趣可以自己去看看。)
(忍不住要加個(gè)注,現(xiàn)在應(yīng)該用gcc -ggdb指定吧!因?yàn)橛泻芏嗳硕荚趩枺驗(yàn)槌薵db
還有別的工具:-)
反正在linux下把os.c用以上方法編譯連接以后就產(chǎn)生了可供gdb使用的可執(zhí)行文件。
我用gcc -g os.c -o os,產(chǎn)生的可執(zhí)行文檔叫os.
然后打gdb os,就可進(jìn)入gdb,屏幕提示:
GDB is free software and you are welcome to 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.
GDB 4.16, Copyright 1995 Free Software Foundation, Inc...
(gdb)
(gdb)是提示符,在這提示符下可以輸入命令,直到退出。(退出命令是q/Q)
為了盡量和原文檔說明的命令相符,即使在本例子中沒用的命令我也將演示。
首先我們可以設(shè)置gdb的屏幕大小。鍵入:
(gdb)set width 70
就是把標(biāo)準(zhǔn)屏幕設(shè)為70列。
然后讓我們來設(shè)置斷點(diǎn)。設(shè)置方法很簡單:break或簡單打b后面加行號(hào)或函數(shù)名
比如我們可以在main 函數(shù)上設(shè)斷點(diǎn):
(gdb)break main
或(gdb)b main
系統(tǒng)提示:Breakpoint 1 at 0x8049552: file os.c, line 455.
然后我們可以運(yùn)行這個(gè)程序,當(dāng)程序運(yùn)行到main函數(shù)時(shí)程序就會(huì)停止返回到gdb的
提示符下。運(yùn)行的命令是run或r(gdb中有不少alias,可以看一下help,在gdb下打help)
run 后面可以跟參數(shù),就是為程序指定命令行參數(shù)。
比如r abcd,則程序就會(huì)abcd以作為參數(shù)。(這里要說明的是可以用set args來指定參
數(shù))。打入r或run后,程序就開始運(yùn)行直到進(jìn)入main的入口停止,顯示:
Starting program: <路徑>/os
Breakpoint 1, main () at os.c:455
455 Initial();
這里455 Initial();是將要執(zhí)行的命令或函數(shù)。
gdb提供兩種方式:1.單步進(jìn)入,step into就是跟蹤到函數(shù)內(nèi)啦。命令是step或s
2.單步,next,就是簡單的單步,不會(huì)進(jìn)入函數(shù)。命令是next或n
這兩個(gè)命令還有別的用法以后再說。
我們用n命令,鍵入:
(gdb)n
Success forking process# 1 ,pid is 31474
Success forking process# 2 ,pid is 31475
Success forking process# 3 ,pid is 31476
Success forking process# 4 ,pid is 31477
Success forking process# 5 ,pid is 31478
Success forking process# 6 ,pid is 31479
Dispatching Algorithm : FIFO
********************************************************************************
PCB# PID Priority PC State
1 31474 24 0 WAITING
2 31475 19 0 WAITING
3 31476 16 0 WAITING
4 31477 23 0 WAITING
5 31478 22 0 WAITING
6 31479 20 0 WAITING
******************************************************************************
CPU : NO process running
IO : No process
Waiting CPU!!! 31474 31475 31476 31477 31478 31479
Waiting IO NONE
456 State=WAITING;
最后的一行就是下一句要執(zhí)行的命令。我們現(xiàn)在在另一個(gè)函數(shù)上加斷點(diǎn)。注意我們
可以用l/list命令來顯示原代碼。這里我們鍵入
(gdb)l
451 main()
452 {
453 int message;
454
455 Initial();
456 State=WAITING;
457 printf("Use Control-C to halt \n");
458 signal(SIGALRM,AlarmMessage);
459 signal(SIGINT,InteruptMessage);
460 signal(SIGUSR2,IoMessage);
(gdb) l
461 alarm(TimeSlot);
462 for(;;)
463 {
464 message=GetMessage();
465 switch(message)
466 {
467 case INTERRUPT : printf("Use
Control-C t;
468 break;
469 case CHILD_IO: WaitingIo();
470 break;
顯示了原代碼,現(xiàn)在在AlarmMessage上加斷點(diǎn)。
(gdb) b AlarmMessage
Breakpoint 2 at 0x8048ee3: file os.c, line 259.
(gdb)
然后我們繼續(xù)運(yùn)行程序。
(gdb)c
c或continue命令讓我們繼續(xù)被中斷的程序。 顯示:
Continuing.
Use Control-C to halt
Breakpoint 2, AlarmMessage () at os.c:259
259 ClearSignal();
注意我們下一句語句就是ClearSignal();
我們用s/step跟蹤進(jìn)入這個(gè)函數(shù)看看它是干什么的。
(gdb) s
ClearSignal () at os.c:227
227 signal(SIGINT,SIG_IGN);
用l命令列出原代碼:
(gdb) l
222 }
223
224
225 void ClearSignal() /* Clear other signals */
226 {
227 signal(SIGINT,SIG_IGN);
228 signal(SIGALRM,SIG_IGN);
229 signal(SIGUSR2,SIG_IGN);
230 }
231
(gdb)
我們可以用s命令繼續(xù)跟蹤。現(xiàn)在讓我們來試試bt或backtrace命令。這個(gè)命令可以
顯示棧中的內(nèi)容。
(gdb) bt
#0 ClearSignal () at os.c:227
#1 0x8048ee8 in AlarmMessage () at os.c:259
#2 0xbffffaec in ?? ()
#3 0x80486ae in ___crt_dummy__ ()
(gdb)
大家一定能看懂顯示的意思。棧頂是AlarmMessage,接下來的函數(shù)沒有名字--就是
沒有原代碼符號(hào)。這顯示了函數(shù)調(diào)用的嵌套。
好了,我們跟蹤了半天還沒有檢查過變量的值呢。檢查表達(dá)式的值的命令是p或print
格式是p <表達(dá)式>
444444讓我們來找一個(gè)變量來看看。:-)
(gdb)l 1
還記得l的作用嗎?l或list顯示原代碼符號(hào),l或list加<行號(hào)>就顯示從<行號(hào)>開始的
原代碼。好了找到一個(gè)讓我們來看看WaitingQueue的內(nèi)容
(gdb) p WaitingQueue
= {1, 2, 3, 4, 5, 6, 0}
(gdb)
WaitingQueue是一個(gè)數(shù)組,gdb還支持結(jié)構(gòu)的顯示,
(gdb) p Pcb
= {{Pid = 0, State = 0, Prior = 0, pc = 0}, {Pid = 31474, State = 2,
Prior = 24, pc = 0}, {Pid = 31475, State = 2, Prior = 19, pc = 0}, {
Pid = 31476, State = 2, Prior = 16, pc = 0}, {Pid = 31477, State = 2,
Prior = 23, pc = 0}, {Pid = 31478, State = 2, Prior = 22, pc = 0}, {
Pid = 31479, State = 2, Prior = 20, pc = 0}}
(gdb)
這里可以對(duì)照原程序看看。
原文檔里是一個(gè)調(diào)試過程,不過我想這里我已經(jīng)把gdb的常用功能介紹了一遍,基本上
可以用來調(diào)試程序了。:-)
運(yùn)行GDB(一些詳細(xì)的說明):
前面已經(jīng)提到過如何運(yùn)行GDB了,現(xiàn)在讓我們來看一些更有趣的東西。你可以在運(yùn)行
GDB時(shí)通過許多命令行參數(shù)指定大量的參數(shù)和選項(xiàng),通過這個(gè)你可以在一開始就設(shè)置好
程序運(yùn)行的環(huán)境。
這里將要描述的命令行參數(shù)覆蓋了大多數(shù)的情況,事實(shí)上在一定環(huán)境下有的并沒有
什么大用處。最通常的命令就是使用一個(gè)參數(shù):
$gdb <可執(zhí)行文檔名>
你還可以同時(shí)為你的執(zhí)行文件指定一個(gè)core文件:
$gdb <可執(zhí)行文件名> core
你也可以為你要執(zhí)行的文件指定一個(gè)進(jìn)程號(hào):
$gdb <可執(zhí)行文件名> <進(jìn)程號(hào)> 如:&gdb os 1234將使gdb與進(jìn)程1234相聯(lián)系
(attach)
除非你還有一個(gè)文件叫1234的。gdb首先檢查一個(gè)core文件。
如果你是使用一個(gè)遠(yuǎn)程終端進(jìn)行遠(yuǎn)程調(diào)試的話,那如果你的終端不支持的話,你將無法
使用第二個(gè)參數(shù)甚至沒有core dump。如果你覺得開頭的提示信息比較礙眼的話,你可
以
用gdb -silent。你還可以用命令行參數(shù)更加詳細(xì)的控制GDB的行為。
打入gdb -help或-h 可以得到這方面的提示。所有的參數(shù)都被按照排列的順序傳給gdb
除非你用了-x參數(shù)。
當(dāng)gdb開始運(yùn)行時(shí),它把任何一個(gè)不帶選項(xiàng)前綴的參數(shù)都當(dāng)作為一個(gè)可執(zhí)行文件或
core
文件(或進(jìn)程號(hào))。就象在前面加了-se或-c選項(xiàng)。gdb把第一個(gè)前面沒有選項(xiàng)說明的參數(shù)
看作前面加了-se 選項(xiàng),而第二個(gè)(如果有的話)看作是跟著-c選項(xiàng)后面的。
許多選項(xiàng)有縮寫,用gdb -h可以看到。在gdb中你也可以任意的把選項(xiàng)名掐頭去尾,
只
要保證gdb能判斷唯一的一個(gè)參數(shù)就行。
在這里我們說明一些最常用的參數(shù)選項(xiàng)
-symbols <文件名>(-s <文件名>)------從<文件名>中讀去符號(hào)。
-exec <文件名>(-e <文件名>)----在合適的時(shí)候執(zhí)行<文件名>來做用正確的數(shù)據(jù)與
core
dump的作比較。
-se <文件名>------從<文件名>中讀取符號(hào)并把它作為可執(zhí)行文件。
-core <文件名>(-c <文件名>)--指定<文件名>為一個(gè)core dump 文件。
-c <數(shù)字>----連接到進(jìn)程號(hào)為<數(shù)字>,與attach命令相似。
-command <文件名>
-x <文件名>-----執(zhí)行g(shù)db命令,在<文件名>指定的文件中存放著一序列的gdb命令,就
象一個(gè)批處理。
-directory(-d) <路徑>---指定路徑。把<路徑>加入到搜索原文件的路徑中。
-m
-mapped----
注意這個(gè)命令不是在所有的系統(tǒng)上都能用。如果你可以通過mmap系統(tǒng)調(diào)用來獲得內(nèi)
存
映象文件,你可以用這個(gè)命令來使gdb把你當(dāng)前文件里的符號(hào)寫入一個(gè)文件中,這個(gè)文
件
將存放在你的當(dāng)前路徑中。如果你調(diào)試的程序叫/temp/fred那么map文件就叫
./fred.syms這樣當(dāng)你以后再調(diào)試這個(gè)程序時(shí),gdb會(huì)認(rèn)識(shí)到這個(gè)文件的存在,從而從這
個(gè)文件中讀取符號(hào),而不是從可執(zhí)行文件中讀取。.syms與主機(jī)有關(guān)不能共享。
-r
-readnow---馬上從符號(hào)文件中讀取整個(gè)符號(hào)表,而不是使用缺省的。缺省的符號(hào)表是
調(diào)入一部分符號(hào),當(dāng)需要時(shí)再讀入一部分。這會(huì)使開始進(jìn)入gdb慢一些,但可以加快以
后
的調(diào)試速度。
-m和-r一般在一起使用來建立.syms文件
接下來再談?wù)勀J降脑O(shè)置(請(qǐng)聽下回分解 :-))
附:在gdb文檔里使用的調(diào)試?yán)游艺业搅嗽趍inix下有這個(gè)程序,叫m4有興趣的
可以自己去看看
模式的選擇
--------------
現(xiàn)在我們來聊聊gdb運(yùn)行模式的選擇。我們可以用許多模式來運(yùn)行g(shù)db,例如在“批模式
”
或“安靜模式”。這些模式都是在gdb運(yùn)行時(shí)在命令行作為選項(xiàng)指定的。
`-nx'
`-n'
不執(zhí)行任何初始化文件中的命令。(一般初始化文件叫做`.gdbinit').一般情況下
在
這些文件中的命令會(huì)在所有的命令行參數(shù)都被傳給gdb后執(zhí)行。
`-quiet'
`-q'
“安靜模式”。不輸出介紹和版權(quán)信息。這些信息在“批模式”中也被跳過。
`-batch'
“批模式”。在“批模式”下運(yùn)行。當(dāng)在命令文件中的所有命令都被成功的執(zhí)行
后
gdb返回狀態(tài)“0”,如果在執(zhí)行過程中出錯(cuò),gdb返回一個(gè)非零值。
“批模式”在把gdb作為一個(gè)過濾器運(yùn)行時(shí)很有用。比如在一臺(tái)遠(yuǎn)程計(jì)算機(jī)上下載
且
執(zhí)行一個(gè)程序。信息“ Program exited normally”(一般是當(dāng)運(yùn)行的程序正常結(jié)
束
時(shí)出現(xiàn))不會(huì)在這種模式中出現(xiàn)。
`-cd DIRECTORY'
把DIRECTORY作為gdb的工作目錄,而非當(dāng)前目錄(一般gdb缺省把當(dāng)前目錄作為工
作目
錄)。
`-fullname'
`-f'
GNU Emacs 設(shè)置這個(gè)選項(xiàng),當(dāng)我們?cè)贓macs下,把gdb作為它的一個(gè)子進(jìn)程來運(yùn)行
時(shí),
Emacs告訴gdb按標(biāo)準(zhǔn)輸出完整的文件名和行號(hào),一個(gè)可視的棧內(nèi)容。這個(gè)格式跟
在
文件名的后面。行號(hào)和字符重新按列排,Emacs-to-GDB界面使用2字符作為一個(gè)
顯示一頁原文件的信號(hào)。
`-b BPS'
為遠(yuǎn)程調(diào)試設(shè)置波特率。
`-tty DEVICE'
使用DEVICE來作為你程序的標(biāo)準(zhǔn)輸入輸出
`quit'
使用'quit'命令來退出gdb,或打一個(gè)文件結(jié)束符(通常是' CTROL-D')。如果
你沒有使用表達(dá)式,gdb會(huì)正常退出,否則它會(huì)把表達(dá)式的至作為error code
返回。
一個(gè)中斷(通常是'CTROL-c)不會(huì)導(dǎo)致從gdb中退出,而是結(jié)束任何一個(gè)gdb的命
令,返回gdb的命令輸入模式。一般在任何時(shí)候使用'CTROL-C'是安全的,因?yàn)?
gdb會(huì)截獲它,只有當(dāng)安全時(shí),中斷才會(huì)起作用。
如果你正在用gdb控制一個(gè)被連接的進(jìn)程或設(shè)備,你可以用'detach'命令來釋放
它。
Shell命令
==============
當(dāng)你偶爾要運(yùn)行一些shell命令時(shí),你不必退出調(diào)試過程,也不需要掛起它;你
可以使用'shell'命令。
`shell COMMAND STRING'
調(diào)用標(biāo)準(zhǔn)shell來執(zhí)行'COMMAND STRING'.環(huán)境變量'SHELL'決定了那個(gè)shell被
運(yùn)行。否則gdb使用'/bin/sh'.
'make'工具經(jīng)常在開發(fā)環(huán)境中使用,所以你可以不用'shell'命令而直接打
'make'
`make MAKE-ARGS'
用指定的命令行變量來運(yùn)行'make'程序,這等于使用'shell make MAKE-ARGS'
GDB 命令
************
我們可以把一個(gè)gdb命令縮寫成開頭幾個(gè)字母,如果這沒有二意性你可以直接回車來
運(yùn)行。你還可以使用TAB鍵讓gdb給你完成接下來的鍵入,或向你顯示可選擇的命令
,
如果有不止一個(gè)選擇的話。
Command語法
==============
一個(gè)gdb命令是一個(gè)單行的輸入。長度沒有限制。它一個(gè)命令開頭,后面可以跟參
量。
比如命令'step'接受一個(gè)參量表示單步執(zhí)行多少步。你也可以不用參量。有的命令
不接受任何參量。
gdb命令只要沒有二意性的話就可以被縮寫。另外一些縮寫作為一個(gè)命令列出。在某
些
情況下二意也是允許的。比如's'是指定'step'的縮寫,但還有命令'start'。你可
以把
這些縮寫作為'help'命令的參量來測(cè)試它們。
空行(直接回車)表示重復(fù)上一個(gè)命令。但有些命令不能重復(fù)比如象'run',就不會(huì)以
這
種方式重復(fù),另外一些當(dāng)不小心重復(fù)會(huì)產(chǎn)生嚴(yán)重后果的命令也不能用這種方法重
復(fù)。
'list'和'x'命令當(dāng)你簡單的打回車時(shí),會(huì)建立新的變量,而不是簡單的重復(fù)上一個(gè)
命
令。這樣你可以方便的瀏覽原代碼和內(nèi)存。
gdb還有一種解釋RET的方法:分割長輸出。這種方法就和'more'命令相似。由于這
時(shí)經(jīng)
常會(huì)不小心多打回車,gdb將禁止重復(fù)當(dāng)一個(gè)命令產(chǎn)生很長的輸出時(shí)。
任何用'#'開頭一直到行尾的命令行被看作是注釋。主要在命令文件中使用。
輸入命令的技巧
==================
前面已經(jīng)提到過TAB鍵的使用。使用TAB鍵能讓你方便的得到所要的命令。比如
在gdb中:
(gdb)info bre <TAB>(鍵入info bre,后按TAB鍵)
gdb能為你完成剩下的輸入。它還能萎蔫提供選擇的可能性。如果有兩個(gè)以上可
能的話,第一次按<TAB>鍵,gdb會(huì)響鈴提示,第二次則顯示可能的選擇。同樣gdb
也可以為一些子命令提供快速的訪問。用法與上相同。
上例中顯示
(gdb)info breakepoints
你也可以直接打回車,gdb就將你輸入的作為命令的可能的縮寫。來判斷執(zhí)行。
如果你打入的縮寫不足以判斷,那么gdb會(huì)顯示一個(gè)列表,列出可能的命令。同樣的
情況對(duì)于命令的參數(shù)。在顯示完后gdb把你的輸入拷貝到當(dāng)前行以便讓你繼續(xù)輸入。
如果你只想看看命令的列表或選項(xiàng),你可以在命令行下打M-?(就是按著ESC鍵
同時(shí)按SHIFT和?鍵)。你可以直接在命令行下打試試。
(gdb)<M-?>
gdb會(huì)響鈴并顯示所有的命令。不過這種方式好象在遠(yuǎn)程調(diào)試是不行。當(dāng)有的命令
使用一個(gè)字符串時(shí),你可以用" ' "將其括起來。這種方法在調(diào)試C++程序時(shí)特別有用。
因?yàn)镃++支持函數(shù)的重載。當(dāng)你要在某個(gè)有重載函數(shù)上設(shè)斷點(diǎn)時(shí),不得不給出函數(shù)參數(shù)
以區(qū)分不同的重載函數(shù)。這時(shí)你就應(yīng)該把整個(gè)函數(shù)用" ' "括起來。比如,你要在一個(gè)
叫name的函數(shù)上設(shè)斷點(diǎn),而這個(gè)函數(shù)被重載了(name(int)和name(float))。你將不得
不給出參變量以區(qū)分不同的函數(shù)。使用'name(int)'和'name(float)'。這里有個(gè)技巧,
你可以在函數(shù)名前加一個(gè)" ' "符號(hào)。然后打M-?.
你可以使用help命令來得到gdb的在線幫助。
`help'
`h'
你可以使用help或h后面不加任何參數(shù)來得到一個(gè)gdb命令類的列表。
(gdb) help
List of classes of commands:
running -- Running the program
stack -- Examining the stack
data -- Examining data
breakpoints -- Making program stop at certain points
files -- Specifying and examining files
status -- Status inquiries
support -- Support facilities
user-defined -- User-defined commands
aliases -- Aliases of other commands
obscure -- Obscure features
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)
`help CLASS'
使用上面列出的help class作為help或h的參量,你可以得到單一的命令列表。
例如顯示一個(gè)'status'類的列表。
(gdb) help status
Status inquiries.
List of commands:
show -- Generic command for showing things set
with "set"
info -- Generic command for printing status
Type "help" followed by command name for full
documentation.
Command name abbreviations are allowed if unambiguous.
(gdb)
`help COMMAND'
詳細(xì)列出單個(gè)命令的資料。
`complete ARGS'
列出所有以ARGS開頭的命令。例如:
complete i
results in:
info
inspect
ignore
This is intended for use by GNU Emacs.
除了使用'help'你還可以使用gdb的命令'info'和'show'來查詢你程序的
狀態(tài),每個(gè)命令可以查詢一系列的狀態(tài)。這些命令以恰當(dāng)?shù)姆绞斤@示所有的
子命令。
`info'
此命令(可以縮寫為'i')用來顯示你程序的狀態(tài)。比如,你可以使用info
args 列出你程序所接受的命令行參數(shù)。使用info registers列出寄存器的狀態(tài)。
或用info breakpoint列出在程序中設(shè)的斷點(diǎn)。要獲得詳細(xì)的關(guān)于info的信息打
help info.
`set'
這個(gè)命令用來為你的程序設(shè)置一個(gè)運(yùn)行環(huán)境(使用一個(gè)表達(dá)式)。比如你
可以用set prompt $來把gdb的提示符設(shè)為$.
`show'
與'info'相反,'show'命令用來顯示gdb自身的狀態(tài)。你使用'set'命令來
可以改變絕大多數(shù)由'show'顯示的信息。比如使用show radix命令來顯示基數(shù)。
用不帶任何參變量的'set'命令你可以顯示所有你可以設(shè)置的變量的值。
有三個(gè)變量是不可以用'set'命令來設(shè)置的。
`show version'
顯示gdb的版本號(hào)。如果你發(fā)現(xiàn)gdb有bug的話你應(yīng)該在bug-reports里加
入gdb的版本號(hào)。
`show copying'
顯示版權(quán)信息。
`show warranty'
顯示擔(dān)保信息。
在gdb下運(yùn)行你的程序
**************************
當(dāng)你在gdb下運(yùn)行程序時(shí),你必須先為gdb準(zhǔn)備好帶有調(diào)試信息的可執(zhí)行文檔。
還可以在gdb中為你的程序設(shè)置參變量,重定向你程序的輸入/輸出,設(shè)置環(huán)境變
量,調(diào)試一個(gè)已經(jīng)執(zhí)行的程序或kill掉一個(gè)子進(jìn)程。
這里許多內(nèi)容在早先的例子中都已經(jīng)用到過,可以參見gdb(二)。
目錄:
* 編譯:: 為調(diào)試編譯帶調(diào)試信息的代碼
* 運(yùn)行:: 運(yùn)行你的程序
* 參變量:: 為你的程序設(shè)置參變量
* 運(yùn)行環(huán)境:: 為你的程序設(shè)置運(yùn)行時(shí)環(huán)境
* 設(shè)置工作目錄:: 在gdb中設(shè)置程序的工作目錄。
* 輸入/輸出:: 設(shè)定你程序的輸入和輸出
* 連接:: 調(diào)試一個(gè)已經(jīng)運(yùn)行的程序
* 結(jié)束子進(jìn)程:: Kill子進(jìn)程
* 進(jìn)程信息:: 附加的進(jìn)程信息
* 線程:: 調(diào)試帶多線程的程序
* 多進(jìn)程:: 調(diào)試帶多進(jìn)程的程序
為調(diào)試準(zhǔn)備帶調(diào)試信息的代碼
===========================
為了高效的調(diào)試一個(gè)程序,你需要使用編譯器來產(chǎn)生附帶調(diào)試信息的可執(zhí)行代碼
這些調(diào)試信息存儲(chǔ)在目標(biāo)文件中;描述了變量數(shù)據(jù)類型和函數(shù)聲明,在原文件代碼行
和執(zhí)行代碼之間建立聯(lián)系。
為產(chǎn)生調(diào)試信息,當(dāng)你使用編譯器時(shí)指定'-g'選項(xiàng),就可以為你的程序產(chǎn)生帶有
調(diào)試信息的可執(zhí)行代碼。
有些c編譯器不支持'-g'選項(xiàng)和'-O'選項(xiàng),那你就有麻煩了,或者有別的方法產(chǎn)生
帶調(diào)試信息的可執(zhí)行代碼,要不就沒辦法了。
gcc,GNU的c語言編譯器支持'-g'和'-O'選項(xiàng)。這樣你就可以產(chǎn)生帶調(diào)試信息的且
優(yōu)化過的可執(zhí)行代碼.
當(dāng)你使用gdb來調(diào)試一個(gè)使用'-g','-O'選項(xiàng)產(chǎn)生的程序時(shí),千萬記住編譯器為了優(yōu)
化你的程序重新安排了你的程序。不要為運(yùn)行次序與你原來設(shè)想的不同,最簡單的例子
就是當(dāng)你定義了一個(gè)變量但從未使用過它時(shí),gdb中是看不到這個(gè)變量的--因?yàn)樗呀?jīng)
被優(yōu)化掉了。
所以有時(shí)你不要使用'-O'選項(xiàng),如果當(dāng)你不用優(yōu)化時(shí)產(chǎn)生的程序是正確的,而優(yōu)化
過后變的不正確了,那么這是編譯器的bug你可以向開發(fā)者提供bug-reports(包括出錯(cuò)
的例子)。
早期的GUN C語言編譯器允許'-gg'選項(xiàng),也用來產(chǎn)生調(diào)試信息,gdb不再支持這種格
式的調(diào)試信息,如果你的編譯器支持'-gg'選項(xiàng),請(qǐng)不要使用它。
`run'
`r'
使用'run'命令在gdb下啟動(dòng)你的程序。你必須先指定你程序的名字(用gdb的命令
行
參數(shù))或使用'file'命令,來指定文件名。如果你在一個(gè)支持多進(jìn)程的環(huán)境下運(yùn)行你的
程
序'run'命令創(chuàng)建一個(gè)子進(jìn)程然后加載你的程序。如果環(huán)境不支持進(jìn)程,則gdb直接調(diào)到
程序的第一條命令。
一些父進(jìn)程設(shè)置的參量可以決定程序的運(yùn)行。gdb提供了指定參量的途徑,但你必須
在程序執(zhí)行前設(shè)置好他們。你也可以在運(yùn)行過程中改變它們,但每次改變只有在下一次
運(yùn)行中才會(huì)體現(xiàn)出來。這些參量可以分為四類:
---參數(shù)
你可以在使用'run'命令時(shí)設(shè)置,如果shell支持的話,你還可以使用通配符,或
變量代換。在UNIX系統(tǒng)中你可以使用'shell環(huán)境變量'來控制shell。
---環(huán)境:
你的程序一般直接從gdb那里繼承環(huán)境變量。但是你可以使用'set environment'
命令來設(shè)置專門的環(huán)境變量。
---工作目錄
你的程序還同時(shí)從gdb那里繼承了工作目錄,你可以使用'cd'命令在gdb中改變工作
目錄。
---標(biāo)準(zhǔn)輸入/輸出
你的程序一般使用與gdb所用的相似的設(shè)備來輸入/輸出。不過你可以為你的程序
的
輸入/輸出進(jìn)行重定向。使用'run'或'tty'命令來設(shè)置于gdb所用不同的設(shè)備。
*注意:當(dāng)你使用輸入/輸出重定向時(shí),你將不能使用無名管道來把你所調(diào)試的程序的輸
出
傳給另一個(gè)程序。這樣gdb會(huì)認(rèn)為調(diào)試程序出錯(cuò)。
當(dāng)你發(fā)出'run'命令后,你的程序就開始運(yùn)行。
如果你的符號(hào)文件的時(shí)間與gdb上一次讀入的不同,gdb會(huì)廢棄原來的符號(hào)表并重新
讀
入。當(dāng)前的斷點(diǎn)不變。
程序環(huán)境
==========================
“環(huán)境”包括了一系列的環(huán)境變量和它們的值。環(huán)境變量一般記錄了一些常用的信
息,
比如你的用戶名,主目錄,你的終端型號(hào)和你的運(yùn)行程序的搜索路徑。一般你可以在
shell
下設(shè)置環(huán)境變量,然后這些變量被所有你所運(yùn)行的程序所共享。在調(diào)試中,可以設(shè)置恰
當(dāng)
的環(huán)境變量而不用退出gdb.
`path DIRECTORY'
在'PATH'環(huán)境變量前加入新的內(nèi)容('PATH'提供了搜索執(zhí)行文件的路徑)。對(duì)于gdb
和
你的程序來說你也許要設(shè)置一些專門的路徑。使用':'或空格來分隔。如果DIRECTORY已
經(jīng)
在路徑中了,這個(gè)操作將會(huì)把它移到前面。
你可以使用串'$cmd'來代表當(dāng)前路徑,如果你用'.'的話,它代表你使用'path'命
令
時(shí)的路徑,gdb將在把DIRECTORY加入搜索路徑前用'.'代替當(dāng)前路徑
`show paths'
顯示當(dāng)前路徑變量的設(shè)置情況。
`show environment [VARNAME]'
顯示某個(gè)環(huán)境變量的值。如果你不指明變量名,則gdb會(huì)顯示所有的變量名和它們
的
內(nèi)容。environment可以被縮寫成'env'
`set environment VARNAME [=] VALUE'
設(shè)置某個(gè)環(huán)境變量的值。不過只對(duì)你所調(diào)試的程序有效。對(duì)gdb本身是不起作用
的。
值可以是任何串。如果未指定值,則該變量值將被設(shè)為NULL.
看一個(gè)例子:
set env USER = foo
告訴一個(gè)linux程序,當(dāng)它下一次運(yùn)行是用戶名將是'foo'
`unset environment VARNAME'
刪除某環(huán)境變量。
注意:gdb使用'shell'環(huán)境變量所指定的shell來運(yùn)行你的程序。
工作路徑
================================
當(dāng)你每次用'run'命令來運(yùn)行你的程序時(shí),你的程序?qū)⒗^承g(shù)db的
當(dāng)前工作目錄。而gdb的工作目錄是從它的父進(jìn)程繼承而來的(一般是
shell)。但你可以自己使用'cd'命令指定工作目錄。
gdb的工作目錄就是它去尋找某些文件或信息的途徑。
`cd DIRECTORY'
把gdb的工作目錄設(shè)為DIRECTORY
`pwd'
打印輸出當(dāng)前目錄。
你程序的輸入/輸出
===============================
缺省時(shí),你的程序的輸入/輸出和gdb的輸入/輸出使用同一個(gè)終端。
gdb在它自己和你的程序之間切換來和你交互,但這會(huì)引起混亂。
`info terminal'
顯示你當(dāng)前所使用的終端的類型信息。
你可以把你程序的輸入/輸出重定向。
例如:
run > outfile
運(yùn)行你的程序并把你程序的標(biāo)準(zhǔn)輸出寫入文件outfile中。
另一個(gè)為你程序指定輸入/輸出的方法是使用'tty'命令,這個(gè)命令
接受一個(gè)文件名作為參量把這個(gè)文件作為以后使用'run'命令的缺省命
令文件。它還重新為子進(jìn)程設(shè)置控制終端。
例如:
tty /dev/ttyb
指定以后用'run'命令啟動(dòng)的進(jìn)程使用終端'/dev/ttyb'作為程序的輸入
/輸出,而且把這個(gè)終端設(shè)為你進(jìn)程的控制終端。
一個(gè)清楚的使用'run'命令的重定向?qū)⒅匦略O(shè)置'tty'所設(shè)置的內(nèi)容
,但不影響控制終端。 當(dāng)你使用'tty'命令或在'run'命令中對(duì)輸入
/輸出進(jìn)行重定向時(shí),只有你當(dāng)前調(diào)試的程序的輸入/輸出被改變了,
并不會(huì)影響到別的程序。
調(diào)試一個(gè)已經(jīng)運(yùn)行的程序:
====================================
`attach PROCESS-ID'
這個(gè)命令把一個(gè)已經(jīng)運(yùn)行的進(jìn)程(在gdb外啟動(dòng))連接入gdb,以便
調(diào)試。PROCESS-ID是進(jìn)程號(hào)。(UNIX中使用'ps'或'jobs -l'來查看進(jìn)程)
'attach'一般不重復(fù)。(當(dāng)你打了一個(gè)以上的回車時(shí))
當(dāng)然要使用'attach'命令的話,你的操作系統(tǒng)環(huán)境必須支持進(jìn)程。
另外你還要有向此進(jìn)程發(fā)信號(hào)的權(quán)力。
當(dāng)使用'attach'命令時(shí),你應(yīng)該先使用'file'命令來指定進(jìn)程所
聯(lián)系的程序源代碼和符號(hào)表。 當(dāng)gdb接到'attach'命令后第一件
事就是停止進(jìn)程的運(yùn)行,你可以使用所有g(shù)db的命令來調(diào)試一個(gè)“連接”
的進(jìn)程,就象你用'run'命令在gdb中啟動(dòng)它一樣。如果你要進(jìn)程繼續(xù)運(yùn)
行,使用'continue'或'c'命令就行了。
`detach'
當(dāng)你結(jié)束調(diào)試后可以使用此命令來斷開進(jìn)程和gdb的連接。(解除gdb
對(duì)它的控制)在這個(gè)命令執(zhí)行后進(jìn)程將繼續(xù)執(zhí)行。
如果你在用'attach'連接一個(gè)進(jìn)程后退出了gdb,或使用'run'命令執(zhí)
行了另一個(gè)進(jìn)程,這個(gè)被'attach'的進(jìn)程將被kill掉。但缺省時(shí),gdb會(huì)
要求你確認(rèn)你是否要退出或執(zhí)行一個(gè)新的進(jìn)程。
結(jié)束子進(jìn)程
=========================
`kill'
Kill命令結(jié)束你程序在gdb下開的子進(jìn)程
這個(gè)命令當(dāng)你想要調(diào)試(檢查)一個(gè)core dump文件時(shí)更有用。gdb在調(diào)試過程中
會(huì)忽略所有的core dump。
在一些操作系統(tǒng)上,一個(gè)程序當(dāng)你在上面加了斷點(diǎn)以后就不能離開gdb獨(dú)立運(yùn)行。
你可以用kill命令來解決這個(gè)問題。
'kill'命令當(dāng)你想重新編譯和連接你的程序時(shí)也很有用。因?yàn)橛行┫到y(tǒng)不允許修改
正在執(zhí)行的可執(zhí)行程序。這樣當(dāng)你再一次使用'run'命令時(shí)gdb會(huì)知道你的程序已經(jīng)被改
變了,那么gdb會(huì)重新load新的符號(hào)。(而且盡量保持你當(dāng)前的斷點(diǎn)設(shè)置。
附加的進(jìn)程信息
==============================
一些操作系統(tǒng)提供了一個(gè)設(shè)備目錄叫做'/proc'的,供檢查進(jìn)程映象。如果gdb被在
這
樣的操作系統(tǒng)下運(yùn)行,你可以使用命令'info proc'來查詢進(jìn)程的信息。('info proc'
命
令只在支持'procfs'的SVR4系統(tǒng)上有用。
`info proc'
顯示進(jìn)程的概要信息。
`info proc mappings'
報(bào)告你進(jìn)程所能訪問的地址范圍。
`info proc times'
你進(jìn)程和子進(jìn)程的開始時(shí)間,用戶時(shí)間(user CPU time),和系統(tǒng)CPU時(shí)間。
`info proc id'
報(bào)告有關(guān)進(jìn)程id的信息。
`info proc status'
報(bào)告你進(jìn)程的一般狀態(tài)信息。如果進(jìn)程停止了。這個(gè)報(bào)告還包括停止的原因和收
到的
信號(hào)。
`info proc all'
顯示上面這些命令返回的所有信息。
對(duì)多線程程序的調(diào)試
========================================
一些操作系統(tǒng)中,一個(gè)單獨(dú)的程序可以有一個(gè)以上的線程在運(yùn)行。線程和進(jìn)程精確
的定?
?
?
?
有自己的寄存器,運(yùn)行時(shí)堆棧或許還會(huì)有私有內(nèi)存。
gdb提供了以下供調(diào)試多線程的進(jìn)程的功能:
* 自動(dòng)通告新線程。
* 'thread THREADNO',一個(gè)用來在線程之間切換的命令。
* 'info threads',一個(gè)用來查詢現(xiàn)存線程的命令。
* 'thread apply [THREADNO] [ALL] ARGS',一個(gè)用來向線程提供命令的命令。
* 線程有關(guān)的斷點(diǎn)設(shè)置。
注意:這些特性不是在所有g(shù)db版本都能使用,歸根結(jié)底要看操作系統(tǒng)是否支持。
如果你的gdb不支持這些命令,會(huì)顯示出錯(cuò)信息:
(gdb) info threads
(gdb) thread 1
Thread ID 1 not known. Use the "info threads" command to
see the IDs of currently known threads.
gdb的線程級(jí)調(diào)試功能允許你觀察你程序運(yùn)行中所有的線程,但無論什么時(shí)候
gdb控制,總有一個(gè)“當(dāng)前”線程。調(diào)試命令對(duì)“當(dāng)前”進(jìn)程起作用。
一旦gdb發(fā)現(xiàn)了你程序中的一個(gè)新的線程,它會(huì)自動(dòng)顯示有關(guān)此線程的系統(tǒng)信
息。比如:
[New process 35 thread 27]
不過格式和操作系統(tǒng)有關(guān)。
為了調(diào)試的目的,gdb自己設(shè)置線程號(hào)。
`info threads'
顯示進(jìn)程中所有的線程的概要信息。gdb按順序顯示:
1.線程號(hào)(gdb設(shè)置)
2.目標(biāo)系統(tǒng)的線程標(biāo)識(shí)。
3.此線程的當(dāng)前堆棧。
一前面打'*'的線程表示是當(dāng)前線程。
例如:
(gdb) info threads
3 process 35 thread 27 0x34e5 in sigpause ()
2 process 35 thread 23 0x34e5 in sigpause ()
* 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8)
at threadtest.c:68
`thread THREADNO'
把線程號(hào)為THREADNO的線程設(shè)為當(dāng)前線程。命令行參數(shù)THREADNO是gdb內(nèi)定的
線程號(hào)。你可以用'info threads'命令來查看gdb內(nèi)設(shè)置的線程號(hào)。gdb顯示該線程
的系統(tǒng)定義的標(biāo)識(shí)號(hào)和線程對(duì)應(yīng)的堆棧。比如:
(gdb) thread 2
[Switching to process 35 thread 23]
0x34e5 in sigpause ()
"Switching后的內(nèi)容取決于你的操作系統(tǒng)對(duì)線程標(biāo)識(shí)的定義。
`thread apply [THREADNO] [ALL] ARGS'
此命令讓你對(duì)一個(gè)以上的線程發(fā)出相同的命令"ARGS",[THREADNO]的含義同上。
如果你要向你進(jìn)程中的所有的線程發(fā)出命令使用[ALL]選項(xiàng)。
無論gdb何時(shí)中斷了你的程序(因?yàn)橐粋€(gè)斷點(diǎn)或是一個(gè)信號(hào)),它自動(dòng)選擇信號(hào)或
斷點(diǎn)發(fā)生的線程為當(dāng)前線程。gdb將用一個(gè)格式為'[Switching to SYSTAG]'的消息
來向你報(bào)告。
*參見:運(yùn)行和停止多線程程序。
*參見:設(shè)置觀察點(diǎn)
調(diào)試多進(jìn)程的程序
==========================================
gdb對(duì)調(diào)試使用'fork'系統(tǒng)調(diào)用產(chǎn)生新進(jìn)程的程序沒有很多支持。當(dāng)一個(gè)程序開始
一個(gè)新進(jìn)程時(shí),gdb將繼續(xù)對(duì)父進(jìn)程進(jìn)行調(diào)試,子進(jìn)程將不受影響的運(yùn)行。如果你在子
進(jìn)程可能會(huì)執(zhí)行到的地方設(shè)了斷點(diǎn),那么子進(jìn)程將收到'SIGTRAP'信號(hào),如果子進(jìn)程沒
有對(duì)這個(gè)信號(hào)進(jìn)行處理的話那么缺省的處理就是使子進(jìn)程終止。
然而,如果你要一定要調(diào)試子進(jìn)程的話,這兒有一個(gè)不是很麻煩的折衷的辦法。在
子進(jìn)程被運(yùn)行起來的開頭幾句語句前加上一個(gè)'sleep'命令。這在調(diào)試過程中并不會(huì)引
起程序中很大的麻煩(不過你要自己注意例外的情況幺:-))。然后再使用'ps'命令列出
新開的子進(jìn)程號(hào),最后使用'attach'命令。這樣就沒有問題了。
關(guān)于這一段,本人覺得實(shí)際使用上并不全是這樣。我在調(diào)試程中就試過,好象不一定
能起作用,要看gdb的版本和你所使用的操作系統(tǒng)了。
停止和繼續(xù)
***********************
調(diào)試器的基本功能就是讓你能夠在程序運(yùn)行時(shí)在終止之前在某些條件下停止下來,
然
后再繼續(xù)運(yùn)行,這樣的話你就可以檢查當(dāng)你的程序出錯(cuò)時(shí)你的程序究竟做了些什么。
在gdb內(nèi)部,你的程序會(huì)由于各種原因而暫時(shí)停止,比如一個(gè)信號(hào),一個(gè)斷點(diǎn),或是
由于你用了'step'命令。在程序停止的時(shí)候你就可以檢查和改變變量的值,設(shè)置或去掉
斷點(diǎn),然后繼續(xù)你程序的運(yùn)行。一般當(dāng)程序停下來時(shí)gdb都會(huì)顯示一些有關(guān)程序狀態(tài)的
信
息。比如象程序停止的原因,堆棧等等。如果你要了解更詳細(xì)的信息,你可以使用
'info
program'命令。另外,在任何時(shí)候你輸入這條命令,gdb都會(huì)顯示當(dāng)前程序運(yùn)行的狀態(tài)
信
息。
`info program'
顯示有關(guān)你程序狀態(tài)的信息:你的程序是在運(yùn)行還是停止,是什么進(jìn)程,為什么
停
止。
斷點(diǎn),觀察點(diǎn)和異常
========================================
斷點(diǎn)的作用是當(dāng)你程序運(yùn)行到斷點(diǎn)時(shí),無論它在做什么都會(huì)被停止下來。對(duì)于每個(gè)
斷點(diǎn)
你都可以設(shè)置一些更高級(jí)的信息以決定斷點(diǎn)在什么時(shí)候起作用。你可以使用'break’命
令
來在你的程序中設(shè)置斷點(diǎn),在前面的例子中我們已經(jīng)提到過一些這個(gè)命令的使用方法
了。
你可以在行上,函數(shù)上,甚至在確切的地址上設(shè)置斷點(diǎn)。在含有異常處理的語言(比如
象
c++)中,你還可以在異常發(fā)生的地方設(shè)置斷點(diǎn)。
在SunOS 4.x,SVR4和Alpha OSF/1的設(shè)置中,你還可以在共享庫中設(shè)置斷點(diǎn)。
觀察點(diǎn)是一種特殊的斷點(diǎn)。它們?cè)谀愠绦蛑心硞€(gè)表達(dá)式的值發(fā)生變化時(shí)起作用。你
必
須使用另外一些命令來設(shè)置觀察點(diǎn)。除了這個(gè)特性以外,你可以象對(duì)普通斷點(diǎn)一樣對(duì)觀
察
點(diǎn)進(jìn)行操作--使用和普通斷點(diǎn)操作一樣的命令來對(duì)觀察點(diǎn)使能,使不能,刪除。
你可以安排當(dāng)你程序被中斷時(shí)顯示的程序變量。
當(dāng)你在程序中設(shè)置斷點(diǎn)或觀察點(diǎn)時(shí)gdb為每個(gè)斷點(diǎn)或觀察點(diǎn)賦一個(gè)數(shù)值.在許多對(duì)斷
點(diǎn)
操作的命令中都要使用這個(gè)數(shù)值。
設(shè)置斷點(diǎn)
=============
使用'break'或簡寫成'b'來設(shè)置斷點(diǎn)。gdb使用環(huán)境變量$bpnum來記錄你最新設(shè)置的
斷點(diǎn)。
你有不少方法來設(shè)置斷點(diǎn)。
`break FUNCTION'
此命令用來在某個(gè)函數(shù)上設(shè)置斷點(diǎn)。當(dāng)你使用允許函數(shù)重載的語言比如C++時(shí),有
可
能同時(shí)在幾個(gè)重載的函數(shù)上設(shè)置了斷點(diǎn)。
`break +OFFSET'
`break -OFFSET'
在當(dāng)前程序運(yùn)行到的前幾行或后幾行設(shè)置斷點(diǎn)。OFFSET為行號(hào)。
`break LINENUM'
在行號(hào)為LINENUM的行上設(shè)置斷點(diǎn)。程序在運(yùn)行到此行之前停止。
`break FILENAME:LINENUM'
在文件名為FILENAME的原文件的第LINENUM行設(shè)置斷點(diǎn)。
`break FILENAME:FUNCTION'
在文件名為FILENAME的原文件的名為FUNCTION的函數(shù)上設(shè)置斷點(diǎn)。
當(dāng)你的多個(gè)文件中可能含有相同的函數(shù)名時(shí)必須給出文件名。
`break *ADDRESS'
在地址ADDRESS上設(shè)置斷點(diǎn),這個(gè)命令允許你在沒有調(diào)試信息的程
序中設(shè)置斷點(diǎn)。
`break'
當(dāng)'break'命令不包含任何參數(shù)時(shí),'break'命令在當(dāng)前執(zhí)行到的程
序運(yùn)行棧中的下一條指令上設(shè)置一個(gè)斷點(diǎn)。除了棧底以外,這個(gè)命令使
程序在一旦從當(dāng)前函數(shù)返回時(shí)停止。相似的命令是'finish',但'finish'
并不設(shè)置斷點(diǎn)。這一點(diǎn)在循環(huán)語句中很有用。
gdb在恢復(fù)執(zhí)行時(shí),至少執(zhí)行一條指令。
`break ... if COND'
這個(gè)命令設(shè)置一個(gè)條件斷點(diǎn),條件由COND指定;在gdb每次執(zhí)行到此
斷點(diǎn)時(shí)COND都被計(jì)算當(dāng)COND的值為非零時(shí),程序在斷點(diǎn)處停止。這意味著
COND的值為真時(shí)程序停止。...可以為下面所說的一些參量。
`tbreak ARGS'
設(shè)置斷點(diǎn)為只有效一次。ARGS的使用同'break'中的參量的使用。
`hbreak ARGS'
設(shè)置一個(gè)由硬件支持的斷點(diǎn)。ARGS同'break'命令,設(shè)置方法也和
'break'相同。但這種斷點(diǎn)需要由硬件支持,所以不是所有的系統(tǒng)上這個(gè)
命令都有效。這個(gè)命令的主要目的是用于對(duì)EPROM/ROM程序的調(diào)試。因?yàn)?
這條命令可以在不改變代碼的情況下設(shè)置斷點(diǎn)。這可以同SPARCLite DSU
一起使用。當(dāng)程序訪問某些變量和代碼時(shí),DSU將設(shè)置“陷井”。注意:
你只能一次使用一個(gè)斷點(diǎn),在新設(shè)置斷點(diǎn)時(shí),先刪除原斷點(diǎn)。
thbreak ARGS'
設(shè)置只有一次作用的硬件支持?jǐn)帱c(diǎn)。ARGS用法同'hbreak'命令。這個(gè)命令
和'tbreak'命令相似,它所設(shè)置的斷點(diǎn)只起一次作用,然后就被自動(dòng)的刪除。這
個(gè)命令所設(shè)置的斷點(diǎn)需要有硬件支持。
`rbreak REGEX'
在所有滿足表達(dá)式REGEX的函數(shù)上設(shè)置斷點(diǎn)。這個(gè)命令在所有相匹配的函數(shù)
上設(shè)置無條件斷點(diǎn),當(dāng)這個(gè)命令完成時(shí)顯示所有被設(shè)置的斷點(diǎn)信息。這個(gè)命令設(shè)
置的斷點(diǎn)和'break'命令設(shè)置的沒有什么不同。這樣你可以象操作一般的斷點(diǎn)一
樣對(duì)這個(gè)命令設(shè)置的斷點(diǎn)進(jìn)行刪除,使能,使不能等操作。當(dāng)調(diào)試C++程序時(shí)這
個(gè)命令在重載函數(shù)上設(shè)置斷點(diǎn)時(shí)非常有用。
`info breakpoints [N]'
`info break [N]'
`info watchpoints [N]'
顯示所有的斷點(diǎn)和觀察點(diǎn)的設(shè)置表,有下列一些列
*Breakpoint Numbers*----斷點(diǎn)號(hào)
*Type*----斷點(diǎn)類型(斷點(diǎn)或是觀察點(diǎn))
*Disposition*---顯示斷點(diǎn)的狀態(tài)。
*Enabled or Disabled*---使能或不使能。'y'表示使能,'n'表示不使能。
*Address*----地址,斷點(diǎn)在你程序中的地址(內(nèi)存地址)
*What*---地址,斷點(diǎn)在你程序中的行號(hào)。
如果斷點(diǎn)是條件斷點(diǎn),此命令還顯示斷點(diǎn)所需要的條件。
帶參數(shù)N的'info break'命令只顯示由N指定的斷點(diǎn)的信息。
此命令還顯示斷點(diǎn)的運(yùn)行信息(被執(zhí)行過幾次),這個(gè)功能在使用'ignore'
命令時(shí)很有用。你可以'ignore'一個(gè)斷點(diǎn)許多次。使用這個(gè)命令可以查看斷點(diǎn)
被執(zhí)行了多少次。這樣可以更快的找到錯(cuò)誤。
gdb允許你在一個(gè)地方設(shè)置多個(gè)斷點(diǎn)。但設(shè)置相同的斷點(diǎn)無疑是弱智的。不過
你可以使用條件斷點(diǎn),這樣就非常有用。
gdb有時(shí)會(huì)自動(dòng)在你的程序中加入斷點(diǎn)。這主要是gdb自己的需要。比如為了正
確的處理C語言中的'longjmp'。這些內(nèi)部斷點(diǎn)都是負(fù)值,以'-1'開始。'info
breakpoints'不會(huì)顯示它們。
不過你可以使用命令’maint info breakpoints'來查看這些斷點(diǎn)。
`maint info breakpoints'
使用格式和'info breakpoints'相同,顯示所有的斷點(diǎn),無論是你設(shè)置的還是
gdb自動(dòng)設(shè)置的。
以下列的含義:
`breakpoint'
斷點(diǎn),普通斷點(diǎn)。
`watchpoint'
普通觀察點(diǎn)。
`longjmp'
內(nèi)部斷點(diǎn),用于處理'longjmp'調(diào)用。
`longjmp resume'
內(nèi)部斷點(diǎn),設(shè)置在'longjmp'調(diào)用的目標(biāo)上。
`until'
'until'命令所使用的內(nèi)部斷點(diǎn)。
`finish'
'finish'命令所使用的內(nèi)部斷點(diǎn)。
設(shè)置觀察點(diǎn)
==============
你可以使用觀察點(diǎn)來停止一個(gè)程序,當(dāng)某個(gè)表達(dá)式的值改變時(shí),觀察點(diǎn)會(huì)將程序
停止。而不需要先指定在某個(gè)地方設(shè)置一個(gè)斷點(diǎn)。
由于觀察點(diǎn)的這個(gè)特性,使觀察點(diǎn)的使用時(shí)開銷比較大,但在捕捉錯(cuò)誤時(shí)非常有
用。特別是你不知道你的程序什么地方出了問題時(shí)。
`watch EXPR'
這個(gè)命令使用EXPR作為表達(dá)式設(shè)置一個(gè)觀察點(diǎn)。GDB將把表達(dá)式加入到程序中
并監(jiān)視程序的運(yùn)行,當(dāng)表達(dá)式的值被改變時(shí)GDB就使程序停止。這個(gè)也可以被用在
SPARClite DSU提供的新的自陷工具中。當(dāng)程序存取某個(gè)地址或某條指令時(shí)(這個(gè)地
址在調(diào)試寄存器中指定),DSU將產(chǎn)生自陷。對(duì)于數(shù)據(jù)地址DSU支持'watch'命令,然而
硬件斷點(diǎn)寄存器只能存儲(chǔ)兩個(gè)斷點(diǎn)地址,而且斷點(diǎn)的類型必須相同。就是兩個(gè)
'rwatch'型斷點(diǎn),或是兩個(gè)'awatch'型斷點(diǎn)。
`rwatch EXPR'
設(shè)置一個(gè)觀察點(diǎn),當(dāng)EXPR被程序讀時(shí),程序被暫停。
`awatch EXPR'
設(shè)置一個(gè)觀察點(diǎn),當(dāng)EXPR被讀出然后被寫入時(shí)程序被暫停。這個(gè)命令和'awatch'
命令合用。
`info watchpoints'
顯示所設(shè)置的觀察點(diǎn)的列表,和'info break'命令相似。
*注意:*在多線程的程序中,觀察點(diǎn)的作用很有限,GDB只能觀察在一個(gè)線程中
的表達(dá)式的值如果你確信表達(dá)式只被當(dāng)前線程所存取,那么使用觀察點(diǎn)才有效。GDB
不能注意一個(gè)非當(dāng)前線程對(duì)表達(dá)式值的改變。
斷點(diǎn)和異常
==============
在一些語言中比如象GNU C++,實(shí)現(xiàn)了異常處理。你可以使用GDB來檢查異常發(fā)生的
原因。而且GDB還可以列出在某個(gè)點(diǎn)上異常處理的所有過程。
`catch EXCEPTIONS'
你可以使用這個(gè)命令來在一個(gè)被激活的異常處理句柄中設(shè)置斷點(diǎn)。EXCEPTIONS是
一個(gè)你要抓住的異常。
你一樣可以使用'info catch'命令來列出活躍的異常處理句柄。
現(xiàn)在GDB中對(duì)于異常處理由以下情況不能處理。
* 如果你使用一個(gè)交互的函數(shù),當(dāng)函數(shù)運(yùn)行結(jié)束時(shí),GDB將象普通情況一樣把控制返
回給你。如果在調(diào)用中發(fā)生了異常,這個(gè)函數(shù)將繼續(xù)運(yùn)行直到遇到一個(gè)斷點(diǎn),一個(gè)信號(hào)
或是退出運(yùn)行。
* 你不能手工產(chǎn)生一個(gè)異常( 即異常只能由程序運(yùn)行中產(chǎn)生 )
* 你不能手工設(shè)置一個(gè)異常處理句柄。
有時(shí)'catch'命令不一定是調(diào)試異常處理的最好的方法。如果你需要知道異常產(chǎn)生的
確切位置,最好在異常處理句柄被調(diào)用以前設(shè)置一個(gè)斷點(diǎn),這樣你可以檢查棧的內(nèi)容。
如果你在一個(gè)異常處理句柄上設(shè)置斷點(diǎn),那么你就不容易知道異常發(fā)生的位置和原因。
要僅僅只在異常處理句柄被喚醒之前設(shè)置斷點(diǎn),你必須了解一些語言的實(shí)現(xiàn)細(xì)節(jié)。
比如在GNU C++中異常被一個(gè)叫'__raise_exception'的庫函數(shù)所調(diào)用。這個(gè)函數(shù)的原
型是:
/* ADDR is where the exception identifier is stored.
ID is the exception identifier. */
void __raise_exception (void **ADDR, void *ID);
要使GDB在棧展開之前抓住所有的句柄,你可以在函數(shù)'__raise_exception'上設(shè)置斷
點(diǎn)。
對(duì)于一個(gè)條件斷點(diǎn),由于它取決于ID的值,你可以在你程序中設(shè)置斷點(diǎn),當(dāng)某個(gè)特
別的異常被喚醒。當(dāng)有一系列異常被喚醒時(shí),你可以使用多重條件斷點(diǎn)來停止你的程
序。
刪除斷點(diǎn)
===================
很自然當(dāng)一個(gè)斷點(diǎn)或是一個(gè)觀察點(diǎn)完成了它的使命后,你需要把它從程序中刪去。
不然你的程序還會(huì)在相同的地方停主,給你造成干擾。使用'clear'命令來從程序中刪
去
一個(gè)斷點(diǎn)。
使用'clear'命令你可以刪除指定位置的斷點(diǎn)。使用'delete'命令你可以使用斷點(diǎn)號(hào)
來指定要?jiǎng)h去的斷點(diǎn)或觀察點(diǎn)。
在刪除斷點(diǎn)時(shí)不需要先運(yùn)行過它,GDB會(huì)忽略你剛才刪去的斷點(diǎn)。所以你可以繼續(xù)運(yùn)
行
你的程序而不必管斷點(diǎn)。
`clear'
在當(dāng)前選擇的棧幀上清除下一個(gè)所要執(zhí)行到的斷點(diǎn)(指令級(jí))。當(dāng)你當(dāng)前選擇幀是
棧中
最內(nèi)層時(shí)使用這個(gè)命令可以很方便的刪去剛才程序停止處的斷點(diǎn)。
`clear FUNCTION'
`clear FILENAME:FUNCTION'
刪除名為FUNCITON的函數(shù)上的斷點(diǎn)。
`clear LINENUM'
`clear FILENAME:LINENUM'
刪除以LINENUM為行號(hào)上的斷點(diǎn)。
`delete [breakpoints] [BNUMS...]'
刪除參數(shù)所指定的斷點(diǎn),如果沒有指定參數(shù)則刪去程序中所有的斷點(diǎn)。這個(gè)命令
可以
縮寫成為'd'
使斷點(diǎn)暫時(shí)不起作用。
========================
如果你只是想讓斷點(diǎn)一時(shí)失去作用以方便調(diào)試的話,你可以先使斷點(diǎn)不起作用。
當(dāng)你以后又想使用時(shí)可以用'enable'命令激活它們。
你使用'enable'命令來激活斷點(diǎn)或是觀察點(diǎn),使用'disable'命令來使斷點(diǎn)或觀察點(diǎn)
不起作用。使用'info break'或'info watch'來查看那些斷點(diǎn)是活躍的。
斷點(diǎn)或觀察點(diǎn)有四種狀態(tài):
* 使能。當(dāng)程序運(yùn)行到斷點(diǎn)處時(shí),程序停止。使用'break'命令設(shè)置的斷點(diǎn)一開始缺
省
是使能的。
*不使能。斷點(diǎn)對(duì)你程序的運(yùn)行沒有什么影響。
*使能一次后變?yōu)椴皇鼓堋帱c(diǎn)對(duì)你的程序運(yùn)行只有一次影響,然后就自動(dòng)變成不使
能
狀態(tài)。使用'tbreak'設(shè)置的斷點(diǎn)一開始缺省是這個(gè)狀態(tài)。
* 使能一次自動(dòng)刪除。斷點(diǎn)在起了一次作用后自動(dòng)被刪除。
你可以使用以下的命令來使能或使不能一個(gè)斷點(diǎn)或觀察點(diǎn)。
`disable [breakpoints] [BNUMS...]'
使由參數(shù)指定的斷點(diǎn)或觀察點(diǎn)變?yōu)椴皇鼓埽绻麤]有參數(shù)的話缺省使所有斷點(diǎn)和
觀察
點(diǎn)變?yōu)椴皇鼓堋.?dāng)一個(gè)斷點(diǎn)或觀察點(diǎn)被不使能后在被不使能前的狀態(tài)被記錄下來,在斷
點(diǎn)或
觀察點(diǎn)再次被激活時(shí),原來的狀態(tài)得到繼續(xù)。比如一個(gè)條件斷點(diǎn)或一個(gè)設(shè)置了
'ignore-counts'的斷點(diǎn)在被使不能后記錄活躍時(shí)斷點(diǎn)被執(zhí)行的次數(shù),在不使能狀態(tài)下
,斷
點(diǎn)的執(zhí)行次數(shù)(ignore-counts)不增加,直到斷點(diǎn)再次被激活時(shí),再繼續(xù)計(jì)算條件
(ignore-counts)。你可以使用'disable'命令的縮寫'dis'
`enable [breakpoints] [BNUMS...]'
使能由參數(shù)指定的斷點(diǎn)或全部斷點(diǎn)。
`enable [breakpoints] once BNUMS...'
功能同上條命令,只是這條命令使斷點(diǎn)只使能一次。
`enable [breakpoints] delete BNUMS...'
功能同上條命令,只是這條命令使被使能的斷點(diǎn)起作用一次然后自動(dòng)被刪除。
除了使用'tbreak'命令所設(shè)置的斷點(diǎn)以外,斷點(diǎn)被設(shè)置時(shí)都是使能的。
斷點(diǎn)條件
===========
最簡單的斷點(diǎn)就是當(dāng)你的程序每次執(zhí)行到的時(shí)候就簡單將程序掛起。你也可以為斷
點(diǎn)
設(shè)置“條件”。條件只是你所使用的編程語言的一個(gè)布爾表達(dá)式,帶有條件表達(dá)式的斷
點(diǎn)
在每次執(zhí)行時(shí)判斷計(jì)算表達(dá)式的值,當(dāng)表達(dá)式值為真時(shí)才掛起程序。
這是使用“斷言”的一中形式,在這種形式中你只有在斷言為真時(shí)才掛起程序。如
果
在C語言中你要使斷言為假時(shí)掛起程序則使用:“!表達(dá)式”。
條件表達(dá)式對(duì)觀察點(diǎn)也同樣有效,但你并不需要它,因?yàn)橛^察點(diǎn)本身就計(jì)算一個(gè)表
達(dá)式?
?
但它也許會(huì)簡單一些。比如只在一個(gè)變量名上設(shè)置觀察點(diǎn)然后設(shè)置一個(gè)條件來測(cè)試新的
賦
值。
斷點(diǎn)條件可能有副作用(side effects)會(huì)影響程序的運(yùn)行。這一點(diǎn)有時(shí)也是很有用的
比如來激活一個(gè)顯示程序完成情況的的函數(shù),或使用你自己的打印函數(shù)來格式化特殊的
數(shù)據(jù)結(jié)構(gòu)。當(dāng)在同一位置沒有另一個(gè)斷點(diǎn)設(shè)置時(shí),結(jié)果是可預(yù)見的。(在gdb中如果在同
一
個(gè)地方使用了一個(gè)斷點(diǎn)和一個(gè)條件斷點(diǎn)則普通斷點(diǎn)可能先被激活。)在條件斷點(diǎn)的應(yīng)用
上
有很多技巧。
斷點(diǎn)條件可以在設(shè)置斷點(diǎn)的同時(shí)被設(shè)置。使用'if'命令作為'break'命令的參數(shù)。斷
點(diǎn)
條件也可以在任何時(shí)候使用'condition'命令來設(shè)置。'watch'命令不能以'if'作為參數(shù)
所以使用'condition'命令是在觀察點(diǎn)上設(shè)置條件的唯一方法。
`condition BNUM EXPRESSION'
把'EXPRESSIN'作為斷點(diǎn)條件。斷點(diǎn)用'BNUM'來指定。在你為BNUM號(hào)斷點(diǎn)設(shè)置了條
件
后,只有在條件為真時(shí)程序才被暫停。當(dāng)你使用'condition'命令GDB馬上同步的檢查
'EXPRESSION'的值判斷表達(dá)式中的符號(hào)在斷點(diǎn)處是否有效,但GDB并不真正計(jì)算表達(dá)式
的值。
`condition BNUM'
刪除在'BNUM'號(hào)斷點(diǎn)處的條件。使之成為一個(gè)普通斷點(diǎn)。
一個(gè)條件斷點(diǎn)的特殊例子是時(shí)一個(gè)程序在執(zhí)行了某句語句若干次后停止。由于這
個(gè)功能非常常用,你可以使用一個(gè)命令來直接設(shè)置它那就是'ignore count'。每個(gè)
斷點(diǎn)都有'ignore count',缺省是零。如果'ignore count'是正的那么你的程序在
運(yùn)行過斷點(diǎn)處'count'次后被暫停。
`ignore BNUM COUNT'
設(shè)置第BNUM號(hào)斷點(diǎn)的'ignore count'為'COUNT'。
如果要讓斷點(diǎn)在下次執(zhí)行到時(shí)就暫停程序,那么把'COUNT'設(shè)為0.
當(dāng)你使用'continue'命令來繼續(xù)你程序的執(zhí)行時(shí),你可以直接把'ignore count'
作為'continue'的參數(shù)使用。你只要直接在'continue'命令后直接跟要"ignore"的
次數(shù)就行。
如果一個(gè)斷點(diǎn)同時(shí)有一個(gè)ignore count和一個(gè)條件時(shí),條件不被檢查。只有當(dāng)
'ignore count'為零時(shí)GDB才開始檢查條件的真假。
另外你可以用'condition'命令來獲得與用‘ignore count'同樣效果的斷點(diǎn)。用
法
是用類似于'$foo--<=0'的參量作為'condition'命令的參數(shù)(使用一個(gè)不停減量的變量
作為條件表達(dá)式的成員)。
斷點(diǎn)命令列表
==================
你可以為任一個(gè)斷點(diǎn)或觀察點(diǎn)指定一系列命令,當(dāng)你程序執(zhí)行到斷點(diǎn)時(shí),GDB自動(dòng)執(zhí)
行
這些命令。例如:你可以打印一些表達(dá)式的值,或使能其他的斷點(diǎn)。
`commands [BNUM]'
`... COMMAND-LIST ...'
`end'
為斷點(diǎn)號(hào)為BNUM的斷點(diǎn)設(shè)置一個(gè)命令列表。這些命令在'...COMMAND-LIST...'中
列
出使用'end'命令來表示列表的結(jié)束。
要?jiǎng)h除斷點(diǎn)上設(shè)置的命令序列,你只需在'command'命令后直接跟'end'命令就可以
了。
當(dāng)不指定BNUM時(shí),GDB缺省為最近遇到的斷點(diǎn)或是觀察點(diǎn)設(shè)置命令列表。
使用回車來表示重復(fù)使用命令的特性在'...command list...'中不能使用。
你可以使用命令列表中的命令來再次使你的程序進(jìn)入運(yùn)行狀態(tài)。簡單的在命令列表
中使用'continue'命令,或'step'命令。
在使程序恢復(fù)執(zhí)行的命令后的命令都被忽略。這是因?yàn)橐坏┠愕某绦蛑匦逻\(yùn)行就可
能遇到新的命令列表,那么就應(yīng)該執(zhí)行新的命令。防止了二義。
如果你在命令列表中使用了'silent'命令,那么你程序在斷點(diǎn)處停止的信息將不被
顯示。這對(duì)于用一個(gè)斷點(diǎn)然后顯示一些信息,接著再繼續(xù)執(zhí)行很有用。但'silent'命令
只有在命令列表的開頭有效。
命令'echo','output'和'printf'允許你精確的控制顯示信息,這些命令在
"silent"
斷點(diǎn)中很有用。
例如:這個(gè)例子演示了使用斷點(diǎn)命令列表來打印'x'的值.
break foo if x>0
commands
silent
printf "x is %d\n",x
cont
end
斷點(diǎn)命令列表的一個(gè)應(yīng)用是在遇到一個(gè)buf之后改正數(shù)據(jù)然后繼續(xù)調(diào)試的過程。
使用命令來修改含有錯(cuò)誤值的變量,然后使用'continue'命令繼續(xù)程序的運(yùn)行。
使用'silent'命令屏蔽輸出:
break 403
commands
silent
set x = y + 4
cont
end
斷點(diǎn)菜單
==============
一些編程語言(比如象C++)允許一個(gè)函數(shù)名被多次使用(重載),以方便應(yīng)用的使用。
當(dāng)一個(gè)函數(shù)名被重載時(shí),'break FUNCITON'命令向GDB提供的信息不夠GDB了解你要設(shè)置
斷點(diǎn)的確切位置。如果你了解到這個(gè)問題,你可以使用'break FUNCITONS(TYPES)'命令
來指定斷點(diǎn)的確切位置。否則GDB會(huì)提供一個(gè)函數(shù)的選擇的菜單供你選擇。使用提示符
'>'來等待你的輸入。開始的兩個(gè)選擇一般是'[0] cancel'和'[1] all'輸入1則在所有
同名函數(shù)上加入斷點(diǎn)。輸入0則退出選擇。
下例為企圖在重載的函數(shù)符號(hào)'String::after'上設(shè)置斷點(diǎn)。
(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.