如何分析gdb的使用技巧,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。
廣南網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián),廣南網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為廣南千余家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站制作要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的廣南做網(wǎng)站的公司定做!
GDB是一個(gè)由GNU開源組織發(fā)布的、UNIX/LINUX操作系統(tǒng)下的、基于命令行的、功能強(qiáng)大的程序調(diào)試工具。
在實(shí)際應(yīng)用中,有兩種調(diào)試方法:在線調(diào)試和離線調(diào)試。
離線調(diào)試適用于開發(fā)測(cè)試環(huán)境,可以自由啟停進(jìn)程,設(shè)置斷點(diǎn);在線調(diào)試一般用于現(xiàn)場問題分析,不能隨便啟停進(jìn)程,對(duì)于技術(shù)要求較高。
若想執(zhí)行g(shù)db調(diào)試,在Makefile文件中需要增加編譯調(diào)試選項(xiàng)-g,例如:
gdb dup_file.c –o dum_file_elf –g –lpthread
說明:-g選項(xiàng)的作用是在可執(zhí)行文件(ELF)中加入源代碼的相關(guān)信息,比如ELF中第幾條機(jī)器指令對(duì)應(yīng)源代碼的行數(shù)。但不是把整個(gè)源文件嵌入到可執(zhí)行文件中,所以在調(diào)試時(shí)必須保證gdb能找到源文件。
-g完整格式是-glevel,其中,level中指定了調(diào)試信息中包含了調(diào)試信息的多少,默認(rèn)的是2,level=1最少,level=3最多。
例如:
readelf -S helloWorld|grep debug
注:helloWorld為文件名,如果沒有任何debug信息,則不能被調(diào)試。
下面的情況也是不可調(diào)試的:
file helloWorld
helloWorld: (省略前面內(nèi)容) stripped
注:如果最后是stripped,則說明該文件的符號(hào)表信息和調(diào)試信息已被去除,不能使用gdb調(diào)試。但是not stripped的情況并不能說明能夠被調(diào)試。
在開發(fā)中可以將源碼和可執(zhí)行文件拷貝到某一目錄下,使用gdb啟動(dòng)進(jìn)程進(jìn)行調(diào)試,也可以不拷貝源碼和可執(zhí)行文件,使用NFS掛載到編譯環(huán)境執(zhí)行調(diào)試;在現(xiàn)場環(huán)境中使用ps獲取進(jìn)程的pid,然后gdb –p pid執(zhí)行在線調(diào)試。
離線調(diào)試:
gdb 進(jìn)程名
gdb –tui 進(jìn)程名
在線調(diào)試:
ps –A | grep 進(jìn)程名
gdb –p pid/gdb attach pid
說明:使用-tui參數(shù)可以將調(diào)試窗口分為兩部分:上面是源碼,下面是調(diào)試信息,使用Ctrl+n/Ctrl+p或者方向鍵進(jìn)行翻頁。
帶參數(shù)調(diào)試:
1、啟動(dòng)的時(shí)候帶上參數(shù)
gdb --args xxx 參數(shù)
2、啟動(dòng)之后 run 帶上參數(shù)
# gdb xxx
(gdb)run 參數(shù)
3、啟動(dòng)之后 set args 設(shè)置參數(shù)
# gdb xxx
(gdb)set args 參數(shù)
core文件調(diào)試
當(dāng)程序core dump時(shí),可能會(huì)產(chǎn)生core文件,它能夠很大程序幫助我們定位問題。但前提是系統(tǒng)沒有限制core文件的產(chǎn)生。可以使用命令limit -c查看:
$ ulimit -c
如果結(jié)果是0,即便程序core dump了也不會(huì)有core文件留下。我們需要讓core文件能夠產(chǎn)生:
ulimit -c unlimied #表示不限制core文件大小
ulimit -c 10 #設(shè)置最大大小,單位為塊,一塊默認(rèn)為512字節(jié)
上面兩種方式可選其一。第一種無限制,第二種指定最大產(chǎn)生的大小。
針對(duì)生成core文件進(jìn)行調(diào)試,可以采用在線加載和離線加載的方式,如下:
gdb 可執(zhí)行文件 core文件
注:有時(shí)候使用p打印調(diào)試信息不完整或者不便于閱讀,可以使用set print elelent 0和setprint pretty on設(shè)置。
handle命令
handle SIGUSR1 nostop noprint
handle SIGUSR2 nostop noprint
handle SIGPIPE nostop noprint
handle SIGALARM nostop
handle SIGHUP nostop
handle SIGTERM nostop noprint
注:設(shè)置GDB調(diào)試時(shí)對(duì)信號(hào)的相關(guān)動(dòng)作。
打斷點(diǎn)還是比較有技巧的,雖然有很多打斷點(diǎn)的方法,但是實(shí)際調(diào)試中一般就使用以下幾種:
函數(shù)打斷點(diǎn):b 函數(shù)名
某一行打斷點(diǎn):b 源文件:行號(hào)
條件斷點(diǎn):
break 斷點(diǎn) if 條件
continue 斷點(diǎn)編號(hào)(執(zhí)行一次表示設(shè)定,再次執(zhí)行表示取消)
continue 斷點(diǎn)編號(hào) 條件
注:條件斷點(diǎn)非常有用,實(shí)際調(diào)試中往往需要調(diào)試特定場景下函數(shù)調(diào)用關(guān)系,此時(shí)就需要設(shè)置斷點(diǎn)觸發(fā)的條件。
查看斷點(diǎn):info breakpoint/info break/info b
刪除斷點(diǎn):delete 斷點(diǎn)號(hào)/delete(刪除所有斷點(diǎn))
禁用/開啟斷點(diǎn):disable/enable breakpoint
ignore:
斷點(diǎn)條件的一個(gè)特殊用法是,程序只有在到達(dá)斷點(diǎn)一定次數(shù)之后才會(huì)停止,此時(shí)可以使用指令:
ignore 斷點(diǎn)編號(hào) 次數(shù)
ignore 2 10觸發(fā)斷點(diǎn)10次后才會(huì)停止,每次觸發(fā)斷點(diǎn)count自動(dòng)減1
說明:打完斷點(diǎn)是不是執(zhí)行continue就可以等待著運(yùn)行到斷點(diǎn)了呢?不一定,有時(shí)候斷點(diǎn)處代碼的執(zhí)行需要外部出發(fā),比如web發(fā)送特定消息后才可以觸發(fā)執(zhí)行,如果一直等待沒有消息出發(fā)永遠(yuǎn)執(zhí)行不到斷點(diǎn)處,此時(shí)就需要結(jié)合自己的業(yè)務(wù)邏輯,手動(dòng)設(shè)置出發(fā)條件。
執(zhí)行程序的方法有兩種:一種是從main函數(shù)開始執(zhí)行逐步分析,一種是執(zhí)行到斷點(diǎn)處。
重新運(yùn)行:r/run
繼續(xù)執(zhí)行:c/continue
單步執(zhí)行:n/next/next N(執(zhí)行N次next)
單步進(jìn)入:step(遇到函數(shù)進(jìn)入函數(shù)內(nèi)部,退出函數(shù)時(shí)使用finish)
結(jié)束函數(shù):finish
強(qiáng)制返回:return(忽略當(dāng)前未執(zhí)行的部分,強(qiáng)制返回)
(gbd) backstrace/bt
有時(shí)候跳轉(zhuǎn)的次數(shù)太多,不知道具體調(diào)用的層級(jí)關(guān)系了,可以使用bt查看堆棧,該命令會(huì)產(chǎn)生一張列表,包含著運(yùn)行過程和相關(guān)的參數(shù)。
設(shè)置變量:set 變量=表達(dá)式
在調(diào)試的時(shí)候,有時(shí)候需要設(shè)置一些假數(shù)據(jù)查看對(duì)應(yīng)輸出,比如根據(jù)布爾值查看流程執(zhí)行情況,此時(shí)就需要在執(zhí)行到指定位置時(shí)手動(dòng)設(shè)置一下數(shù)據(jù)的取值。
監(jiān)控變量:
watch 變量 (數(shù)值改變時(shí)暫停運(yùn)行)
awatch <表達(dá)式> (被訪問或改變時(shí)暫停運(yùn)行)
rwatch <表達(dá)式> (被訪問時(shí)暫停運(yùn)行)
有時(shí)候我們需要觀察一個(gè)變量的變化過程,比如一個(gè)全局變量如何初始化,如何調(diào)用的,這就需要使用watch監(jiān)控變量。
變量類型:
ptype var 變量類型
whatis var 顯示一個(gè)變量var的類型
打印變量/表達(dá)式:
打印變量:p 變量
打印字符/表達(dá)式:p “%s”,字符/表達(dá)式
格式化輸出:p/格式控制符 打印內(nèi)容
說明:
gdb可支持的變量顯示格式有:
x:按16進(jìn)制格式顯示變量
d:按10進(jìn)制格式顯示變量
u:按16進(jìn)制格式顯示無符號(hào)整型
o:按8進(jìn)制格式顯示變量
t:按2進(jìn)制格式顯示變量
c:按字符格式顯示變量
f:按浮點(diǎn)數(shù)格式顯示變量
也可以使用x(Examination)來打印需要顯示的字符信息,格式如下:
x/格式 地址
格式(可選)一般是NFU:
1、N表示重復(fù)次數(shù)(表示顯示內(nèi)存的長度,也就是說從當(dāng)前向后顯示幾個(gè)地址的內(nèi)容)
2、F表示顯示格式
3、U表示單位(b:字節(jié),h:半字[2字節(jié)],w:字[4字節(jié),默認(rèn)],g:雙字[8字節(jié)])。表示多少個(gè)字節(jié)作為一個(gè)值取出來,如果不指定的話,GDB默認(rèn)是1個(gè)byte,當(dāng)我們指定了字節(jié)長度后,GDB會(huì)從指定內(nèi)存的地址開始,讀取指定字節(jié),并把其作為一個(gè)值取出來。
參數(shù)u可使用下面字符代替:
b:表示單字節(jié)
h:表示雙字節(jié)
w:表示四字節(jié)
g:表示八字節(jié)
disassemble
可以使用反匯編的指令disassemble去探究究竟在函數(shù)中發(fā)生了哪些操作,具體如下:
1、disassemble
2、disassemble 程序計(jì)數(shù)器
3、disassemble 開始地址 結(jié)束地址
格式1表示反匯編當(dāng)前整個(gè)函數(shù),格式2表示反匯編計(jì)數(shù)器所在函數(shù)的整個(gè)函數(shù),格式3表示反匯編從開始地址到結(jié)束地址的部分。
call
強(qiáng)制調(diào)用函數(shù):call 表達(dá)式
q/quit
在執(zhí)行到斷點(diǎn)后,采用q/quit指令退出。
detach-on-fork
該屬性決定了gdb是同時(shí)調(diào)試父子進(jìn)程,還是在fork了子進(jìn)程之后,將子進(jìn)程分離出去。
on:子進(jìn)程(或者父進(jìn)程,取決于gdb在初始時(shí),要調(diào)試的進(jìn)程,也就是follow-fork-mode的值)
off:同時(shí)調(diào)試父子進(jìn)程,一個(gè)進(jìn)程處于被調(diào)試的狀態(tài),而另一個(gè)則被gdb掛起
設(shè)置:set detach-on-fork on/off
follow-fork-mode
該屬性決定了gdb在進(jìn)程調(diào)用fork之后的行為。
set follow-fork-mode parent:默認(rèn)情況下,在調(diào)用fork之后,gdb選擇跟隨(也就是調(diào)試)父進(jìn)程,而子進(jìn)程則在處于運(yùn)行的狀態(tài)(此時(shí)父進(jìn)程處于阻塞的狀態(tài))。
set follow-fork-mode child:fork之后gdb選擇調(diào)試子進(jìn)程,而父進(jìn)程處于運(yùn)行的狀態(tài)。
查看當(dāng)前調(diào)試的進(jìn)程:info inferiors
查看線程:info threads
注:輸出信息前面有“*”表示調(diào)試的當(dāng)前線程(一般thread切換線程后查看)。
有的程序會(huì)在運(yùn)行過程中主線程創(chuàng)建多個(gè)子線程,所以前后執(zhí)行info threads顯示的線程數(shù)是會(huì)動(dòng)態(tài)變化的。
查看所有線程堆棧:thread apply all bt
查看指定線程堆棧:thread apply thread1 thread2... bt
切換線程:thread N
注:通過打印counter,可以看到多個(gè)線程都是在運(yùn)行的,如果想要讓其他線程處于停止?fàn)顟B(tài),只有當(dāng)前調(diào)試的線程執(zhí)行,可以采用set scheduler-locking on。
阻塞其他線程,僅調(diào)試當(dāng)前線程工作:
set scheduler-locking [on|off|step]
運(yùn)行指定線程并允許其他線程并行執(zhí)行:
thread apply N command
關(guān)于如何分析gdb的使用技巧問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。