一. gdb編譯選項(xiàng)(gcc/g++ 在編譯時(shí)加入-g來加入debug信息)
- -g0等于不加-g跟伏,即不包含任何調(diào)試信息
- -g1包含最小的調(diào)試信息鸠删,一般來說只有在你不需要調(diào)試信息,之需要backtrack信息嚎杨,并且很在意程序大小,或者有其他保密/特殊需求是才會(huì)使用-g1
- -g2為gdb默認(rèn)崇猫,包含絕大多數(shù)你需要的調(diào)試信息
- -g3包含額外的調(diào)試信息诅福,例如包含宏定義信息
二. gdb常見用法
- 調(diào)試程序
1.gdb ${application} 進(jìn)入gdb后匾委,輸入run(簡(jiǎn)寫r) ${arg1} ${arg2}...${argN}
2.gdb --args ${application} ${arg1}${arg2}...${argN},進(jìn)入gdb后運(yùn)行run
3.gdb進(jìn)入gdb,輸入file ${application}氓润。然后使用set args ${arg1}${arg2}...${argN}設(shè)定好程序的參數(shù)然后再run - 調(diào)試正在運(yùn)行的程序
gdb ${application} ${pid} - 調(diào)試core文件
gdb ${application} ${core文件}
三. 常用命令 - backtrack:顯示棧信息赂乐,簡(jiǎn)寫為bt
- frame x: 切換到第x幀。其中x會(huì)在bt命令中顯示咖气,從0開始挨措,0表示棧頂,簡(jiǎn)寫為f
- up/down x往棧頂/棧底移動(dòng)x幀崩溪,當(dāng)省略x時(shí)默認(rèn)為1
4 print x打印x信息浅役,x可以是變量、對(duì)象或者數(shù)組伶唯,簡(jiǎn)寫為p - print */&x打印出x的內(nèi)容或者地址
- call調(diào)用函數(shù)觉既,注意該命令需要一個(gè)正在運(yùn)行的程序
- set substitute-path from_path to_path替換源代碼文件。當(dāng)編譯機(jī)與運(yùn)行機(jī)代碼路徑不同是需要用該命令替換代碼路徑乳幸,否則你無法看到源代碼
- break x.cpp:n在x.cpp第n行設(shè)置斷點(diǎn)瞪讼,然后gdb會(huì)給出斷點(diǎn)編號(hào)m。命令看簡(jiǎn)寫為b后面會(huì)有break命令的詳細(xì)解釋
- command m設(shè)置程序執(zhí)行到斷點(diǎn)m處要查看的內(nèi)容如:
command n
>printf "x is %d \n", x
>c
>end
//如果command命令后面沒有n則默認(rèn)為最后一 個(gè)breakpoint - x /nfu ${addr}打印addr的內(nèi)容粹断。addr可以是任何合法的地址表達(dá)式符欠,如0x562fb3d、一個(gè)有效的指針p或者有效的變量地址(&var)姿染,/nfu是格式n表示要查看的長(zhǎng)度背亥,f表示格式(例如16進(jìn)制/10進(jìn)制),u表示單位(例如單字節(jié)b悬赏,雙字h狡汉,四字w)一個(gè)例子:
(gdb) x /3xw 0x562fb3d //即以16進(jìn)制顯示地址0x562fb3d處的3個(gè)單位,每個(gè)單位4字節(jié)內(nèi)容 - continue繼續(xù)運(yùn)行程序闽颇,可簡(jiǎn)寫為c
- until直到當(dāng)前循環(huán)完成盾戴,可簡(jiǎn)寫為u
- step單步調(diào)試,步入當(dāng)前函數(shù)兵多,可簡(jiǎn)寫為s
- next單步調(diào)試尖啡,布過當(dāng)前函數(shù)橄仆,可簡(jiǎn)寫為n
- finish執(zhí)行到當(dāng)前函數(shù)返回,步出當(dāng)前函數(shù)
- set var x=2改變變量x的值衅斩,也可以這樣使用:set {int}0x32075598 = 2把內(nèi)存0x32075598的內(nèi)容解釋為int并修改其內(nèi)容為2
- info locals打印當(dāng)前棧幀的本地變量
- jump使當(dāng)前執(zhí)行程序調(diào)整到某一行盆顾,或者跳轉(zhuǎn)到某個(gè)地址。由于只會(huì)使程序跳轉(zhuǎn)而不會(huì)改變棧值畏梆,因此若跳出函數(shù)到另外的地方 會(huì)導(dǎo)致return出錯(cuò)您宪。另外,熟悉匯編的人都知道奠涌,程序運(yùn)行時(shí)宪巨,有一個(gè)寄存器用于保存當(dāng)前代碼所在的內(nèi)存地址。所以溜畅,jump命令也就是改變了這個(gè)寄存器中的值捏卓。于是,你可以使用“set $pc”來更改跳轉(zhuǎn)執(zhí)行的地址慈格。如: set $pc = 0x485
- return強(qiáng)制函數(shù)返回可以指定返回值
四. 程序中斷機(jī)制:監(jiān)視點(diǎn)(watchpoint)和捕捉點(diǎn)(catchpoint)
- 監(jiān)視點(diǎn):監(jiān)視內(nèi)存某個(gè)地址怠晴,一旦該地址的內(nèi)容被改變,程序就進(jìn)入調(diào)試器峦椰。監(jiān)視點(diǎn)又分為軟件模式和硬件模式:軟件監(jiān)視是gdb單步執(zhí)行程序的同時(shí)測(cè)試變量的值龄寞,所以速度會(huì)變慢。同時(shí)軟件監(jiān)視只在當(dāng)前線程有效汤功,幸運(yùn)的是32位intelx86提供了4個(gè)特殊的調(diào)試寄存器用來方便調(diào)試程序物邑,gdb可以使用這些寄存器建立硬件監(jiān)視然而,可用的(enable的)硬件監(jiān)視點(diǎn)的個(gè)數(shù)是有限的滔金。如果你設(shè)置了過多的硬件監(jiān)視點(diǎn)色解,當(dāng)程序從中斷的狀態(tài)變?yōu)閳?zhí)行的狀態(tài)(例如continue,until或者finish)時(shí)餐茵,GDB 可能無法把它們?nèi)考せ羁蒲帧A硗猓顒?dòng)的硬件監(jiān)視點(diǎn)的數(shù)量只有在試圖繼續(xù)執(zhí)行程序時(shí)才能知道忿族,也就是說锣笨,即使你設(shè)置了過多的硬件監(jiān)視點(diǎn),gdb在你運(yùn)行程序之前也不會(huì)警告你道批。設(shè)置監(jiān)視點(diǎn)的命令有3個(gè):watch(寫監(jiān)視)错英、rwatch(讀監(jiān)視)以及awatch(讀寫監(jiān)視),他們的使用方法一樣都為以下幾種:
1.(r/a)watch x:x為變量隆豹,當(dāng)x的值改變/被讀取時(shí)椭岩,程序進(jìn)入調(diào)試器
2.(r/a)watch 0xN:N為有效地址
3.(r/a)watch (int)0xN:N為有效地址當(dāng)該地址int型指針指向的內(nèi)容改變時(shí)進(jìn)入調(diào)試器
4.(r/a)watch -l (int)0xN:較上一個(gè),該地址本身變化也會(huì)進(jìn)入調(diào)試器 - 斷點(diǎn),斷點(diǎn)break有一些變體:tbreak判哥、hbreak献雅、thbreak與rbreak。tbreak和break功能相同塌计,只是所設(shè)置的斷點(diǎn)在觸發(fā)一次后自動(dòng)刪除挺身,hbreak是一個(gè)硬件斷點(diǎn),thbreak是一個(gè)臨時(shí)硬件斷點(diǎn)夺荒。注意硬件斷點(diǎn)需要硬件支持瞒渠,某些硬件可能不支持這類斷點(diǎn)。rbreak稍稍特殊些技扼,它會(huì)在匹配正則表達(dá)式的全部位置加上斷點(diǎn),該斷點(diǎn)后面還有詳述嫩痰。非rbreak斷點(diǎn)的用法:
1.(t/h)break x.cpp:y:在文件x.cpp第y行加斷點(diǎn)剿吻,x.cpp若不指定則在當(dāng)前文件第y行加斷點(diǎn),若程序未執(zhí)行則以包含main函數(shù)的文件設(shè)置斷點(diǎn)串纺,若x.cpp和y都不指定則以當(dāng)前debuger的點(diǎn)作為斷點(diǎn)
2.(t/h)break 0xN:在地址0xN處加斷點(diǎn)丽旅,N為有效的代碼段地址
3.(t/h)break x.cpp:func:在x.cpp的函數(shù)func入口處加斷點(diǎn)
4.(t/h)break +/-N:在當(dāng)前運(yùn)行處第N行后/前加斷點(diǎn)
5.rbreak REGEXP:在所有符合正則表達(dá)式的函數(shù)入口處加斷點(diǎn),如:rbreak EX_*表示所有符合以EX_開頭的函數(shù)入口處加斷點(diǎn)纺棺。注意break后面還有兩個(gè)可選參數(shù):線程id和條件榄笙,線程id指在info threads中的線程序號(hào),而非系統(tǒng)提供的tid祷蝌,例如break x.cpp:y 2 if(a == 24)表示在2號(hào)線程的x.cpp文件第y行加入斷點(diǎn)并且只有當(dāng)a==24茅撞,程序才會(huì)觸發(fā)斷點(diǎn)另外,breakpoint可以通過save命令保存巨朦,方便下次再次進(jìn)入程序調(diào)試時(shí)不再需要需要重新設(shè)置斷點(diǎn) - 捕捉點(diǎn)是當(dāng)某些事件發(fā)生時(shí)米丘,程序進(jìn)入調(diào)試狀態(tài),如catch一個(gè)exception糊啡、assert拄查、signal,fork甚至syscall棚蓄。tcatch和catch功能一樣堕扶,區(qū)別是tcatch是臨時(shí)的,catch一次后就會(huì)自動(dòng)刪除
五. 跟蹤點(diǎn)(tracepoint)
跟蹤點(diǎn)與上面介紹的不同之處在于梭依,他只是跟蹤記錄信息而不會(huì)中斷程序的運(yùn)行稍算。tracepoint可以通過save保存,方便下次繼續(xù)使用睛挚。
六. 檢查點(diǎn)
gdb可以保存程序某個(gè)時(shí)間點(diǎn)的程序狀態(tài)或者程序映像邪蛔,并且稍后又可以返回到這個(gè)狀態(tài),這稱為checkpoint。每個(gè)檢查點(diǎn)是進(jìn)程的一份拷貝侧到,這樣當(dāng)一個(gè)bug很難重現(xiàn)勃教,而又擔(dān)心調(diào)試過了頭時(shí)又要重頭開始,這時(shí)候可以設(shè)置checkpoint匠抗,這樣即使調(diào)試過頭了故源,也可以直接從該checkpoint開始,而不用重新重啟整個(gè)程序(也許需要很久9场I!)矢腻。但是每個(gè)checkpoint有自己的唯一進(jìn)程id门驾,這個(gè)pid與原程序的pid是不同的,因此程序需要使用pid信息時(shí)需要慎重考慮多柑。