gcc和gdb詳解_第1頁(yè)
gcc和gdb詳解_第2頁(yè)
gcc和gdb詳解_第3頁(yè)
gcc和gdb詳解_第4頁(yè)
gcc和gdb詳解_第5頁(yè)
已閱讀5頁(yè),還剩42頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、gdb調(diào)試調(diào)試命令:gdb 【可執(zhí)行文件】退出gdb:quit(q)(在gdb中大部分命令都可以用縮寫(xiě)表示)顯示源代碼:list (l)查看某行代碼:list 【行號(hào)n】 (縮寫(xiě)l 行號(hào)n)程序會(huì)顯示n行上下共十行的代碼查看函數(shù)代碼:list 【函數(shù)名】 (縮寫(xiě) l 函數(shù)名)顯示當(dāng)前行后面的代碼:list顯示當(dāng)前行前面的代碼:list 一般是顯示當(dāng)前行的上5行和下5行,或者顯示當(dāng)前行的上2行和下8行,默認(rèn)共顯示10行。也可以自己設(shè)置顯示的范圍。set listsize : 設(shè)置一次顯示源代碼的行數(shù)show listsize:查看當(dāng)前l(fā)istsize的設(shè)置。顯示first到last行之間的代碼:

2、list ,顯示從前行到last行的代碼:list ,向后顯示源代碼:list +設(shè)置斷點(diǎn):break 【行號(hào)n】(縮寫(xiě)b 行號(hào)n)break 【函數(shù)名】 (縮寫(xiě)b 函數(shù)名)break if 條件成立時(shí)停止查看斷點(diǎn):info break (縮寫(xiě) i b)斷點(diǎn)都有斷點(diǎn)號(hào)單步跟蹤并進(jìn)入函數(shù):step (s)單步跟蹤,但不進(jìn)入函數(shù):next (n)運(yùn)行到下一斷點(diǎn):continue (c)不設(shè)置斷點(diǎn),直接運(yùn)行程序:run (r)finish:運(yùn)行程序,知道當(dāng)前函數(shù)完成返回,并打印函數(shù)返回時(shí)的堆棧地址及參數(shù)值等信息跳出循環(huán): until查看變量值:print 【變量名】(p 變量名)delete 【斷點(diǎn)

3、號(hào)】:刪除斷點(diǎn)clear命令:clear命令是用來(lái)清除斷點(diǎn)的的命令clear 要清楚的斷點(diǎn)所在的行號(hào)clear命令與delete命令不同,delete命令后跟斷點(diǎn)編號(hào),而clear命令后面跟的是斷點(diǎn)所在的行號(hào),另外,使用clear命令,gdb會(huì)給出提示,而delete命令沒(méi)有。enable命令:enable可以恢復(fù)暫時(shí)失效的斷點(diǎn)enable 斷點(diǎn)標(biāo)號(hào)要恢復(fù)多個(gè)斷點(diǎn)時(shí),可用空格將斷點(diǎn)編號(hào)隔開(kāi)disable命令:disable命令可是剛設(shè)置的的斷點(diǎn)失效,失效后用命令cont繼續(xù)程序的執(zhí)行disable 斷點(diǎn)編號(hào)ptype 【變量名】:查看變量類(lèi)型print 數(shù)組名標(biāo)號(hào):查看數(shù)組元素的值print

4、【變量1】=n:將變量1的值改為nprint 命令詳解:形式1:print 表達(dá)式表達(dá)式中與兩種特殊符號(hào)要注意,$,$,用print查看表達(dá)式時(shí),表達(dá)式的值都會(huì)被記錄下來(lái),并會(huì)以$1,$2,$3等編上號(hào),這樣就可以通過(guò)print $n,命令查看系統(tǒng)記錄的 $n的值,而要查看從當(dāng)前記錄的值開(kāi)始往后推n個(gè)的記錄值時(shí)應(yīng)該用$符號(hào),如現(xiàn)在記錄到$5,要看看$3,則可用print $2命令查看。另外如果$后邊不加數(shù)字,相當(dāng)于print當(dāng)前標(biāo)號(hào)之前的print值,同時(shí),如果$加不加數(shù)字,則表示print當(dāng)前標(biāo)號(hào)倒數(shù)的第二個(gè)print記錄。形式2:print 變量=表達(dá)式形式3:打印內(nèi)存某個(gè)部分開(kāi)始的一塊連

5、續(xù)空間的內(nèi)容Print 開(kāi)始表達(dá)式要打印內(nèi)存空間的大小開(kāi)始表達(dá)式應(yīng)該是內(nèi)存中的一個(gè)表達(dá)式,他的輸入結(jié)果以數(shù)組的形式,其中第0個(gè)元素師開(kāi)始表達(dá)式的值,第1個(gè)元素是在內(nèi)存中緊挨著開(kāi)始表達(dá)式的空間中存放的值,以此類(lèi)推。display命令:display用來(lái)顯示一些表達(dá)式的值,使用該命令后,每當(dāng)程序運(yùn)行到斷點(diǎn)處就會(huì)顯示該表達(dá)式的值,可以用它來(lái)觀察一些表達(dá)式的值,它與print的區(qū)別是,display命令每次調(diào)試中斷程序,掛起指令都要顯示變量的值。形式:display 要顯示值的表達(dá)式set 命令:set除了可以顯示數(shù)據(jù)外,還可以修改變量的值使用觀察窗口使用觀察窗口與在程序的特定位置設(shè)置斷點(diǎn)實(shí)現(xiàn)的功能相

6、似,但使用觀察窗口值在表達(dá)式為真時(shí)中斷程序的運(yùn)行。watch命令:使用watch命令設(shè)置觀察窗口例如程序段如下:for(counter=0;counter15則程序會(huì)在表達(dá)式counter15為真時(shí)中斷程序搜索源代碼向前搜索:forward-search 或search 反向搜索:reverse-search 其中就是正則表達(dá)式,也是一個(gè)字符串的匹配模式在輸入gdb命令時(shí),直接點(diǎn)擊回車(chē),執(zhí)行上條命令編譯錯(cuò)誤:編譯程序時(shí)沒(méi)有符合語(yǔ)法規(guī)范導(dǎo)致編譯錯(cuò)誤運(yùn)行錯(cuò)誤:編譯器檢查不出這種錯(cuò)誤,但在運(yùn)行時(shí)可能會(huì)出現(xiàn)這種錯(cuò)誤邏輯錯(cuò)誤:編譯和運(yùn)行都很順利,但是程序沒(méi)有干他該干的事段錯(cuò)誤:由于訪問(wèn)非法地址發(fā)生的錯(cuò)誤

7、訪問(wèn)系統(tǒng)數(shù)據(jù)區(qū),尤其是往系統(tǒng)保護(hù)的內(nèi)存地址寫(xiě)數(shù)據(jù),最常見(jiàn)的是一個(gè)內(nèi)存以0地址內(nèi)存越界(數(shù)組越界,數(shù)據(jù)類(lèi)型不一致等),訪問(wèn)不到屬于你的內(nèi)存區(qū)域 。查看棧信息當(dāng)程序被停止的時(shí)候,需要做的第一件事是查看程序是在哪里停止的。當(dāng)程序調(diào)用了一個(gè)函數(shù)時(shí),函數(shù)的地址,函數(shù)的參數(shù),函數(shù)內(nèi)部的局部變量都會(huì)被壓入“棧”(stack)中,棧是內(nèi)存中的一段連續(xù)空間。查看棧信息命令1:backtrace 或者bt例如:(gdb)bt#0 func (n=250) at tst.c:6#1 0x08048524 in main (argc=1,argv=0xbffff674) at tst.c:30#2 0x400409e

8、d in _libc_start_main () from /lib/lib/libc.so.6從中可以看出函數(shù)的調(diào)用棧信息: _libc_start_main 到main()到func(),因?yàn)闂J呛筮M(jìn)先出,一次輸出的棧信息和函數(shù)調(diào)用順序剛好相反。命令2:Backtrace 或者bt 其中n是一個(gè)正整數(shù),表示只打印棧頂上n層的棧信息。命令3:backtrace 或者bt -n是個(gè)負(fù)整數(shù),表示只打印棧底下你層的棧信息。命令4:frame 或者 f 其中n是一個(gè)從零開(kāi)始的整數(shù),是棧中的層編號(hào)。frame 0表示棧頂,frame 1表示棧的第二層。命令5:up 表示向棧底移動(dòng)n層,不輸入n,表示想

9、棧底方向移動(dòng)一層。因?yàn)闂5自趦?nèi)存的高地址區(qū)域,棧頂處于低地址區(qū)域,所以命令用up,反之用down。命令6:down 表示向棧頂方向移動(dòng)n層命令7:frame 或者f產(chǎn)看當(dāng)前棧的信息顯示的信息包括:棧的層編號(hào),當(dāng)前的函數(shù)名,函數(shù)的參數(shù)值,函數(shù)所在文件及行號(hào),函數(shù)執(zhí)行到的語(yǔ)句。命令8:info frame 或者info f該命令會(huì)顯示出更加詳細(xì)的當(dāng)前棧層的信息,只不過(guò)大多數(shù)都是運(yùn)行時(shí)的內(nèi)地址。命令9:Info args顯示出當(dāng)前函數(shù)的參數(shù)及值。命令10:Info locals顯示出當(dāng)前函數(shù)的參數(shù)名及值。命令11:info catch顯示出當(dāng)前函數(shù)中的異常處理信息。Linux core dump詳解

10、有的程序可以通過(guò)編譯,但在運(yùn)行時(shí)會(huì)出現(xiàn)Segment fault(段錯(cuò)誤).這通常都是指針錯(cuò)誤引起的.以下是我們?cè)敿?xì)的對(duì)Linux core dump的調(diào)試技術(shù)進(jìn)行的介紹:1.Linux core dump前言:有的程序可以通過(guò)編譯,但在運(yùn)行時(shí)會(huì)出現(xiàn)Segment fault(段錯(cuò)誤).這通常都是指針錯(cuò)誤引起的.但這不像編譯錯(cuò)誤一樣會(huì)提示到文件-行,而是沒(méi)有任何信息,使得我們的調(diào)試變得困難起來(lái).2. Linux core dump gdb:有一種辦法是,我們用gdb的step,一步一步尋找.這放在短小的代碼中是可行的,但要讓你step一個(gè)上萬(wàn)行的代碼,我想你會(huì)從此厭惡程序員這個(gè)名字,而把他叫做

11、調(diào)試員.我們還有更好的辦法,這就是core file.3. Linux core dump ulimit:如果想讓系統(tǒng)在信號(hào)中斷造成的錯(cuò)誤時(shí)產(chǎn)生core文件,我們需要在shell中按如下設(shè)置:#設(shè)置core大小為無(wú)限ulimit -c unlimited#設(shè)置文件大小為無(wú)限ulimit unlimited這些需要有root權(quán)限,在ubuntu下每次重新打開(kāi)中斷都需要重新輸入上面的第一條命令,來(lái)設(shè)置core大小為無(wú)限.4. Linux core dump用gdb查看core文件:下面我們可以在發(fā)生運(yùn)行時(shí)信號(hào)引起的錯(cuò)誤時(shí)發(fā)生core dump了.發(fā)生core dump之后,用gdb進(jìn)行查看core

12、文件的內(nèi)容,以定位文件中引發(fā)core dump的行.gdb exec file core file如:gdb ./test test.core在進(jìn)入gdb后,用bt命令查看backtrace以檢查發(fā)生程序運(yùn)行到哪里,來(lái)定位core dump的文件-行.5.要怎麼才不會(huì)讓core文件出現(xiàn)?如果用的是tcsh的話,以試著在.tcshrc里加一行:limit coredumpsize 0如果用的是bash的話,在/etc/profile里加上(或者修改)一條:ulimit -c 06.何謂Linux core dump?我們?cè)陂_(kāi)發(fā)(或使用)一個(gè)程序時(shí),最怕的就是程序莫明其妙地當(dāng)?shù)簟km然系統(tǒng)沒(méi)事,但我

13、們下次仍可能遇到相同的問(wèn)題。于是這時(shí)操作系統(tǒng)就會(huì)把程序當(dāng)?shù)魰r(shí)的內(nèi)存內(nèi)容dump出來(lái),讓我們或是debugger做為參考。這個(gè)動(dòng)作就叫作core dump。7.有一招,可以讓你看出core最好用的地方gdb -c core進(jìn)去后打where,就可以show出你是在程序哪一行當(dāng)?shù)舻?還有在當(dāng)?shù)魰r(shí)在哪個(gè)function里,這個(gè)function是被哪個(gè)function所call的,而這個(gè)function又是被哪個(gè)function所call的.一直到main()由這個(gè)信息,可以找出五六成的bug.屢試不爽,但先決條件,當(dāng)你在compile時(shí)必須把debug information的選項(xiàng)打開(kāi)不然,就會(huì)出現(xiàn)

14、一大堆你看不懂的東西,而不是你喜歡的源程序。8.System Dump和Core Dump的區(qū)別許多沒(méi)有做過(guò)UNIX系統(tǒng)級(jí)軟件開(kāi)發(fā)的人士,可能只聽(tīng)說(shuō)過(guò)Dump,而并不知道系統(tǒng)Dump和Core Dump的區(qū)別,甚至混為一談。1)系統(tǒng)Dump(System Dump)所有開(kāi)放式操作系統(tǒng),都存在系統(tǒng)DUMP問(wèn)題。產(chǎn)生原因:由于系統(tǒng)關(guān)鍵/核心進(jìn)程,產(chǎn)生嚴(yán)重的無(wú)法恢復(fù)的錯(cuò)誤,為了避免系統(tǒng)相關(guān)資源受到更大損害,操作系統(tǒng)都會(huì)強(qiáng)行停止運(yùn)行,并將當(dāng)前內(nèi)存中的各種結(jié)構(gòu),核心進(jìn)程出錯(cuò)位置及其代碼狀態(tài),保存下來(lái),以便以后分析。最常見(jiàn)的原因是指令走飛,或者緩沖區(qū)溢出,或者內(nèi)存訪問(wèn)越界。走飛就是說(shuō)代碼流有問(wèn)題,導(dǎo)致執(zhí)行

15、到某一步指令混亂,跳轉(zhuǎn)到一些不屬于它的指令位置去執(zhí)行一些莫名其妙的東西(沒(méi)人知道那些地方本來(lái)是代碼還是數(shù)據(jù),而且是不是正確的代碼開(kāi)始位置),或者調(diào)用到不屬于此進(jìn)程的內(nèi)存空間。寫(xiě)過(guò)C程序及匯編程序的人士,對(duì)這些現(xiàn)象應(yīng)當(dāng)是很清楚的。系統(tǒng)DUMP生成過(guò)程的特點(diǎn):在生成DUMP過(guò)程中,為了避免過(guò)多的操作結(jié)構(gòu),導(dǎo)致問(wèn)題所在位置正好也在生成DUMP過(guò)程所涉及的資源中,造成DUMP不能正常生成,操作系統(tǒng)都用盡量簡(jiǎn)單的代碼來(lái)完成,所以避開(kāi)了一切復(fù)雜的管理結(jié)構(gòu),如文件系統(tǒng))LVM等等,所以這就是為什么幾乎所有開(kāi)放系統(tǒng),都要求DUMP設(shè)備空間是物理連續(xù)的不用定位一個(gè)個(gè)數(shù)據(jù)塊,從DUMP設(shè)備開(kāi)頭一直寫(xiě)直到完成,這個(gè)

16、過(guò)程可以只用BIOS級(jí)別的操作就可以。這也是為什么在企業(yè)級(jí)UNIX普遍使用LVM的現(xiàn)狀下,DUMP設(shè)備只可能是裸設(shè)備而不可能是文件系統(tǒng)文件,而且b只/b用作DUMP的設(shè)備,做LVM鏡像是無(wú)用的系統(tǒng)此時(shí)根本沒(méi)有LVM操作,它不會(huì)管什么鏡像不鏡像,就用第一份連續(xù)寫(xiě)下去。所以UNIX系統(tǒng)也不例外,它會(huì)將DUMP寫(xiě)到一個(gè)裸設(shè)或磁帶設(shè)備。在重啟的時(shí)候,如果設(shè)置的DUMP轉(zhuǎn)存目錄(文件系統(tǒng)中的目錄)有足夠空間,它將會(huì)轉(zhuǎn)存成一個(gè)文件系統(tǒng)文件,缺省情況下,b對(duì)于AIX來(lái)說(shuō)是/var/adm/ras/下的vmcore*這樣的文件,對(duì)于HPUX來(lái)說(shuō)是/var/adm/crash下的目錄及文件。/b當(dāng)然,也可以選擇

17、將其轉(zhuǎn)存到磁帶設(shè)備。會(huì)造成系統(tǒng)DUMP的原因主要是:系統(tǒng)補(bǔ)丁級(jí)別不一致或缺少)系統(tǒng)內(nèi)核擴(kuò)展有BUG(例如Oracle就會(huì)安裝系統(tǒng)內(nèi)核擴(kuò)展)驅(qū)動(dòng)程序有BUG(因?yàn)樵O(shè)備驅(qū)動(dòng)程序一般是工作在內(nèi)核級(jí)別的),等等。所以一旦經(jīng)常發(fā)生類(lèi)似的系統(tǒng)DUMP,可以考慮將系統(tǒng)補(bǔ)丁包打到最新并一致化)升級(jí)微碼)升級(jí)設(shè)備驅(qū)動(dòng)程序(包括FC多路冗余軟件)升級(jí)安裝了內(nèi)核擴(kuò)展的軟件的補(bǔ)丁包等等。2)進(jìn)程Core Dump進(jìn)程Core Dump產(chǎn)生的技術(shù)原因,基本等同于系統(tǒng)DUMP,就是說(shuō)從程序原理上來(lái)說(shuō)是基本一致的。但進(jìn)程是運(yùn)行在低一級(jí)的優(yōu)先級(jí)上(此優(yōu)先級(jí)不同于系統(tǒng)中對(duì)進(jìn)程定義的優(yōu)先級(jí),而是指CPU代碼指令的優(yōu)先級(jí)),被操作

18、系統(tǒng)所控制,所以操作系統(tǒng)可以在一個(gè)進(jìn)程出問(wèn)題時(shí),不影響其他進(jìn)程的情況下,中止此進(jìn)程的運(yùn)行,并將相關(guān)環(huán)境保存下來(lái),這就是core dump文件,可供分析。如果進(jìn)程是用高級(jí)語(yǔ)言編寫(xiě)并編譯的,且用戶(hù)有源程序,那么可以通過(guò)在編譯時(shí)帶上診斷用符號(hào)表(所有高級(jí)語(yǔ)言編譯程序都有這種功能),通過(guò)系統(tǒng)提供的分析工具,加上core文件,能夠分析到哪一個(gè)源程序語(yǔ)句造成的問(wèn)題,進(jìn)而比較容易地修正問(wèn)題,當(dāng)然,要做到這樣,除非一開(kāi)始就帶上了符號(hào)表進(jìn)行編譯,否則只能重新編譯程序,并重新運(yùn)行程序,重現(xiàn)錯(cuò)誤,才能顯示出源程序出錯(cuò)位置。如果用戶(hù)沒(méi)有源程序,那么只能分析到匯編指令的級(jí)別,難于查找問(wèn)題所在并作出修正,所以這種情況下就

19、不必多費(fèi)心了,找到出問(wèn)題的地方也沒(méi)有辦法。進(jìn)程Core Dump的時(shí)候,操作系統(tǒng)會(huì)將進(jìn)程異常終止掉并釋放其占用的資源,不可能對(duì)系統(tǒng)本身的運(yùn)行造成危害。這是與系統(tǒng)DUMP根本區(qū)別的一點(diǎn),系統(tǒng)DUMP產(chǎn)生時(shí),一定伴隨著系統(tǒng)崩潰和停機(jī),進(jìn)程Core Dump時(shí),只會(huì)造成相應(yīng)的進(jìn)程被終止,系統(tǒng)本身不可能崩潰。當(dāng)然如果此進(jìn)程與其他進(jìn)程有關(guān)聯(lián),其他進(jìn)程也會(huì)受到影響,至于后果是什么,就看相關(guān)進(jìn)程對(duì)這種異常情況(與自己相關(guān)的進(jìn)程突然終止)的處理機(jī)制是什么了,沒(méi)有一概的定論。9.關(guān)于coredump文件的其它說(shuō)明:1)如何生成coredump文件?登陸LINUX服務(wù)器,任意位置鍵入echo ulimit -c

20、1024 /etc/profile退出LINUX重新登陸LINUX鍵入ulimit -c如果顯示1024那么說(shuō)明coredump已經(jīng)被開(kāi)啟。2). core文件的簡(jiǎn)單介紹在一個(gè)程序崩潰時(shí),它一般會(huì)在指定目錄下生成一個(gè)core文件。core文件僅僅是一個(gè)內(nèi)存映象(同時(shí)加上調(diào)試信息),主要是用來(lái)調(diào)試的。3).開(kāi)啟或關(guān)閉core文件的生成用以下命令來(lái)阻止系統(tǒng)生成core文件:ulimit -c 0下面的命令可以檢查生成core文件的選項(xiàng)是否打開(kāi):ulimit -a該命令將顯示所有的用戶(hù)定制,其中選項(xiàng)-a代表“all”。也可以修改系統(tǒng)文件來(lái)調(diào)整core選項(xiàng)在/etc/profile通常會(huì)有這樣一句話來(lái)

21、禁止產(chǎn)生core文件,通常這種設(shè)置是合理的:# No core files by defaultulimit -S -c 0 /dev/null 2&1但是在開(kāi)發(fā)過(guò)程中有時(shí)為了調(diào)試問(wèn)題,還是需要在特定的用戶(hù)環(huán)境下打開(kāi)core文件產(chǎn)生的設(shè)置。在用戶(hù)的/.bash_profile里加上ulimit -c unlimited來(lái)讓特定的用戶(hù)可以產(chǎn)生core文件。如果ulimit -c 0則也是禁止產(chǎn)生core文件,而ulimit -c 1024則限制產(chǎn)生的core文件的大小不能超過(guò)1024kb4).設(shè)置Core Dump的核心轉(zhuǎn)儲(chǔ)文件目錄和命名規(guī)則/proc/sys/kernel/core_uses_

22、pid可以控制產(chǎn)生的core文件的文件名中是否添加pid作為擴(kuò)展,如果添加則文件內(nèi)容為1,否則為0proc/sys/kernel/core_pattern可以設(shè)置格式化的core文件保存位置或文件名,比如原來(lái)文件內(nèi)容是core-%e可以這樣修改:echo /corefile/core-%e-%p-%t core_pattern將會(huì)控制所產(chǎn)生的core文件會(huì)存放到/corefile目錄下,產(chǎn)生的文件名為core-命令名-pid-時(shí)間戳以下是參數(shù)列表:%p - insert pid into filename添加pid%u - insert current uid into filename添加當(dāng)

23、前uid%g - insert current gid into filename添加當(dāng)前gid%s - insert signal that caused the coredump into the filename添加導(dǎo)致產(chǎn)生core的信號(hào)%t - insert UNIX time that the coredump occurred into filename添加core文件生成時(shí)的unix時(shí)間%h - insert hostname where the coredump happened into filename添加主機(jī)名%e - insert coredumping executa

24、ble name into filename添加命令名5).使用core文件在core文件所在目錄下鍵入:gdb -c core它會(huì)啟動(dòng)GNU的調(diào)試器,來(lái)調(diào)試core文件,并且會(huì)顯示生成此core文件的程序名,中止此程序的信號(hào)等等。如果你已經(jīng)知道是由什么程序生成此core文件的,比如MyServer崩潰了生成core.12345,那么用此指令調(diào)試:gdb -c core MyServer6).一個(gè)小方法來(lái)測(cè)試產(chǎn)生core文件直接輸入指令:kill -s SIGSEGV $core詳解2Core,又稱(chēng)之為Core Dump文件,是Unix/Linux操作系統(tǒng)的一種機(jī)制,對(duì)于線上服務(wù)而言,Core

25、令人聞之色變,因?yàn)槌鯟ore的過(guò)程意味著服務(wù)暫時(shí)不能正常響應(yīng),需要恢復(fù),并且隨著吐Core進(jìn)程的內(nèi)存空間越大,此過(guò)程可能持續(xù)很長(zhǎng)一段時(shí)間(例如當(dāng)進(jìn)程占用60G+以上內(nèi)存時(shí),完整Core文件需要15分鐘才能完全寫(xiě)到磁盤(pán)上),這期間產(chǎn)生的流量損失,不可估量。凡事皆有兩面性,OS在出Core的同時(shí),雖然會(huì)終止掉當(dāng)前進(jìn)程,但是也會(huì)保留下第一手的現(xiàn)場(chǎng)數(shù)據(jù),OS仿佛是一架被按下快門(mén)的相機(jī),而照片就是產(chǎn)出的Core文件。里面含有當(dāng)進(jìn)程被終止時(shí)內(nèi)存、CPU寄存器等信息,可以供后續(xù)開(kāi)發(fā)人員進(jìn)行調(diào)試。關(guān)于Core產(chǎn)生的原因很多,比如過(guò)去一些Unix的版本不支持現(xiàn)代Linux上這種GDB直接附著到進(jìn)程上進(jìn)行調(diào)試的機(jī)

26、制,需要先向進(jìn)程發(fā)送終止信號(hào),然后用工具閱讀core文件。在Linux上,我們就可以使用kill向一個(gè)指定的進(jìn)程發(fā)送信號(hào)或者使用gcore命令來(lái)使其主動(dòng)出Core并退出。如果從淺層次的原因上來(lái)講,出Core意味著當(dāng)前進(jìn)程存在BUG,需要程序員修復(fù)。從深層次的原因上講,是當(dāng)前進(jìn)程觸犯了某些OS層級(jí)的保護(hù)機(jī)制,逼迫OS向當(dāng)前進(jìn)程發(fā)送諸如SIGSEGV(即signal 11)之類(lèi)的信號(hào), 例如訪問(wèn)空指針或數(shù)組越界出Core,實(shí)際上是觸犯了OS的內(nèi)存管理,訪問(wèn)了非當(dāng)前進(jìn)程的內(nèi)存空間,OS需要通過(guò)出Core來(lái)進(jìn)行警示,這就好像一個(gè)人身體內(nèi)存在病毒,免疫系統(tǒng)就會(huì)通過(guò)發(fā)熱來(lái)警示,并導(dǎo)致人體發(fā)燒是一個(gè)道理(有

27、意思的是,并不是每次數(shù)組越界都會(huì)出Core,這和OS的內(nèi)存管理中虛擬頁(yè)面分配大小和邊界有關(guān),即使不出Core,也很有可能讀到臟數(shù)據(jù),引起后續(xù)程序行為紊亂,這是一種很難追查的BUG)。說(shuō)了這些,似乎感覺(jué)Core很強(qiáng)勢(shì),讓人感覺(jué)缺乏控制力,其實(shí)不然。控制Core產(chǎn)生的行為和方式,有兩個(gè)途徑:1.修改/proc/sys/kernel/core_pattern文件,此文件用于控制Core文件產(chǎn)生的文件名,默認(rèn)情況下,此文件內(nèi)容只有一行內(nèi)容:“core”,此文件支持定制,一般使用%配合不同的字符,這里羅列幾種:%p 出Core進(jìn)程的PID%u 出Core進(jìn)程的UID%s 造成Core的signal號(hào)%t

28、 出Core的時(shí)間,從1970-01-0100:00:00開(kāi)始的秒數(shù)%e 出Core進(jìn)程對(duì)應(yīng)的可執(zhí)行文件名2.Ulimit C命令,此命令可以顯示當(dāng)前OS對(duì)于Core文件大小的限制,如果為0,則表示不允許產(chǎn)生Core文件。如果想進(jìn)行修改,可以使用:Ulimit c n其中n為數(shù)字,表示允許Core文件體積的最大值,單位為Kb,如果想設(shè)為無(wú)限大,可以執(zhí)行:Ulimit c unlimited產(chǎn)生了Core文件之后,就是如何查看Core文件,并確定問(wèn)題所在,進(jìn)行修復(fù)。為此,我們不妨先來(lái)看看Core文件的格式,多了解一些Core文件。首先可以明確一點(diǎn),Core文件的格式ELF格式,這一點(diǎn)可以通過(guò)使用

29、readelf -h命令來(lái)證實(shí),如下圖:從讀出來(lái)的ELF頭信息可以看到,此文件類(lèi)型為Core文件,那么readelf是如何得知的呢?可以從下面的數(shù)據(jù)結(jié)構(gòu)中窺得一二:其中當(dāng)值為4的時(shí)候,表示當(dāng)前文件為Core文件。如此,整個(gè)過(guò)程就很清楚了。了解了這些之后,我們來(lái)看看如何閱讀Core文件,并從中追查BUG。在Linux下,一般讀取Core的命令為:gdb exec_file core_file使用GDB,先從可執(zhí)行文件中讀取符號(hào)表信息,然后讀取Core文件。如果不與可執(zhí)行文件攪合在一起可以嗎?答案是不行,因?yàn)镃ore文件中沒(méi)有符號(hào)表信息,無(wú)法進(jìn)行調(diào)試,可以使用如下命令來(lái)驗(yàn)證:Objdump x c

30、ore_file | tail我們看到如下兩行信息:SYMBOL TABLE:no symbols表明當(dāng)前的ELF格式文件中沒(méi)有符號(hào)表信息。為了解釋如何看Core中信息,我們來(lái)舉一個(gè)簡(jiǎn)單的例子:#include “stdio.h”int main()int stack_of100000000;int b=1;int* a;*a=b;這段程序使用gcc g a.c o a進(jìn)行編譯,運(yùn)行后直接會(huì)Core掉,使用gdb a core_file查看棧信息,可見(jiàn)其Core在了這行代碼:int stack_of100000000;原因很明顯,直接在棧上申請(qǐng)如此大的數(shù)組,導(dǎo)致棧空間溢出,觸犯了OS對(duì)于棧空間

31、大小的限制,所以出Core(這里是否出Core還和OS對(duì)棧空間的大小配置有關(guān),一般為8M)。但是這里要明確一點(diǎn),真正出Core的代碼不是分配棧空間的int stack_of100000000, 而是后面這句int b=1, 為何?出Core的一種原因是因?yàn)閷?duì)內(nèi)存的非法訪問(wèn),在上面的代碼中分配數(shù)組stack_of時(shí)并未訪問(wèn)它,但是在其后聲明變量并賦值,就相當(dāng)于進(jìn)行了越界訪問(wèn),繼而出Core。為了解釋得更詳細(xì)些,讓我們使用gdb來(lái)看一下出Core的地方,使用命令gdb a core_file可見(jiàn):可知程序出現(xiàn)了段錯(cuò)誤“Segmentation fault”, 代碼是int b=1這句。我們來(lái)查看一

32、下當(dāng)前的棧信息:其中可見(jiàn)指令指針rip指向地址為0400473, 我們來(lái)看下當(dāng)前的指令是什么:這條movl指令要把立即數(shù)1送到0xffffffffe8287bfc(%rbp)這個(gè)地址去,其中rbp存儲(chǔ)的是幀指針,而0xffffffffe8287bfc很明顯是一個(gè)負(fù)數(shù),結(jié)果計(jì)算為-400000004。這就可以解釋了:其中我們申請(qǐng)的int stack_of100000000占用400000000字節(jié),b是int類(lèi)型,占用4個(gè)字節(jié),且棧空間是由高地址向低地址延伸,那么b的棧地址就是0xffffffffe8287bfc(%rbp),也就是$rbp-400000004。當(dāng)我們嘗試訪問(wèn)此地址時(shí):可以看到無(wú)

33、法訪問(wèn)此內(nèi)存地址,這是因?yàn)樗呀?jīng)超過(guò)了OS允許的范圍。下面我們把程序進(jìn)行改進(jìn):#include “stdio.h”int main()int* stack_of = malloc(sizeof(int)*100000000);int b=1;int* a;*a=b;使用gcc O3 g a.c o a進(jìn)行編譯,運(yùn)行后會(huì)再次Core掉,使用gdb查看棧信息,請(qǐng)見(jiàn)下圖:可見(jiàn)BUG出在第7行,也就是*a=b這句,這時(shí)我們嘗試打印b的值,卻發(fā)現(xiàn)符號(hào)表中找不到b的信息。為何?原因在于gcc使用了-O3參數(shù),此參數(shù)可以對(duì)程序進(jìn)行優(yōu)化,一個(gè)負(fù)面效應(yīng)是優(yōu)化過(guò)程中會(huì)舍棄部分局部變量,導(dǎo)致調(diào)試時(shí)出現(xiàn)困難。在我們的

34、代碼中,b聲明時(shí)即賦值,隨后用于為*a賦值。優(yōu)化后,此變量不再需要,直接為*a賦值為1即可,如果匯編級(jí)代碼上講,此優(yōu)化可以減少一條MOV語(yǔ)句,節(jié)省一個(gè)寄存器。此時(shí)我們的調(diào)試信息已經(jīng)出現(xiàn)了一些扭曲,為此我們重新編譯源程序,去掉-O3參數(shù)(這就解釋了為何一些大型軟件都會(huì)有debug版本存在,因?yàn)閐ebug是未經(jīng)優(yōu)化的版本,包含了完整的符號(hào)表信息,易于調(diào)試),并重新運(yùn)行,得到新的core并查看,如下圖:這次就比較明顯了,b中的值沒(méi)有問(wèn)題,有問(wèn)題的是a,其指向的地址是非法區(qū)域,也就是a沒(méi)有分配內(nèi)存導(dǎo)致的Core。當(dāng)然,本例中的問(wèn)題其實(shí)非常明顯,幾乎一眼就能看出來(lái),但不妨礙它成為一個(gè)例子,用來(lái)解釋在看C

35、ore過(guò)程中,需要注意的一些問(wèn)題。 網(wǎng)上找的用GDB調(diào)試程序GDB是一個(gè)強(qiáng)大的命令行調(diào)試工具。大家知道命令行的強(qiáng)大就是在于,其可以形成執(zhí)行序列,形成腳本。UNIX下的軟件全是命令行的,這給程序開(kāi)發(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),尺有所短”,圖形化工具

36、還是有不如命令行的地方。用GDB調(diào)試程序GDB概述GDB是GNU開(kāi)源組織發(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è)道理。一般來(lái)說(shuō),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)境。從

37、上面看來(lái),GDB和一般的調(diào)試工具沒(méi)有什么兩樣,基本上也是完成這些功能,不過(guò)在細(xì)節(jié)上,你會(huì)發(fā)現(xiàn)GDB這個(gè)調(diào)試工具的強(qiáng)大,大家可能比較習(xí)慣了圖形化的調(diào)試工具,但有時(shí)候,命令行的調(diào)試工具卻有著圖形化工具所不能完成的功能。讓我們一一看來(lái)。一個(gè)調(diào)試示例源程序:tst.c1 #include23 int func(int n)4 5 int sum=0,i;6 for(i=0; i7; i+) 8 sum+=i;9 10 return sum;11 121314 main()15 16 int i;17 long result = 0;18 for(i=1; i cc -g tst.c -o tst使用G

38、DB調(diào)試:hchen/test gdb tst - 啟動(dòng)GDBGNU gdb 5.1.1Copyright 2002 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type show copying to see the conditions.There is absolutel

39、y no warranty for GDB. Type show warranty for details.This GDB was configured as i386-suse-linux.(gdb) l - l命令相當(dāng)于list,從第一行開(kāi)始例出原碼。1 #include23 int func(int n)4 5 int sum=0,i;6 for(i=0; i 7 8 sum+=i;9 10 return sum;(gdb) - 直接回車(chē)表示,重復(fù)上一次命令11 121314 main()15 16 int i;17 long result = 0;18 for(i=1; i=100;

40、 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 What1 breakpoint keep y 0x08048496 in main at tst.c:162 breakpoi

41、nt keep y 0x08048456 in func at tst.c:5(gdb) r - 運(yùn)行程序,run命令簡(jiǎn)寫(xiě)Starting program: /home/hchen/test/tstBreakpoint 1, main () at tst.c:17 - 在斷點(diǎn)處停住。17 long result = 0;(gdb) n - 單條語(yǔ)句執(zhí)行,next命令簡(jiǎn)寫(xiě)。18 for(i=1; i=100; i+)(gdb) n20 result += i;(gdb) n18 for(i=1; i=100; i+)(gdb) n20 result += i;(gdb) c - 繼續(xù)運(yùn)行程序,c

42、ontinue命令簡(jiǎn)寫(xiě)。Continuing.result1-100 = 5050 -程序輸出。Breakpoint 2, func (n=250) at tst.c:55 int sum=0,i;(gdb) n6 for(i=1; i=n; i+)(gdb) p i - 打印變量i的值,print命令簡(jiǎn)寫(xiě)。$1 = 134513808(gdb) n8 sum+=i;(gdb) n6 for(i=1; i=n; i+)(gdb) p sum$2 = 1(gdb) n8 sum+=i;(gdb) p i$3 = 2(gdb) n6 for(i=1; i=n; i+)(gdb) p sum$4 =

43、 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:50x080484e4 in main () at tst.c:2424 printf(result1-250 = %d /n, func(250) );Value returned is $6

44、= 31375(gdb) c - 繼續(xù)運(yùn)行。Continuing.result1-250 = 31375 -程序輸出。Program exited with code 027. -程序退出,調(diào)試結(jié)束。(gdb) q 好了,有了以上的感性認(rèn)識(shí),還是讓我們來(lái)系統(tǒng)地認(rèn)識(shí)一下gdb吧。使用GDB一般來(lái)說(shuō)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如果沒(méi)有-g,你將看不見(jiàn)程序的函數(shù)

45、名、變量名,所代替的全是運(yùn)行時(shí)的內(nèi)存地址。當(dāng)你用-g把調(diào)試信息加入之后,并成功編譯目標(biāo)代碼以后,讓我們來(lái)看看如何用gdb來(lái)調(diào)試他。啟動(dòng)GDB的方法有以下幾種:1、gdbprogram也就是你的執(zhí)行文件,一般在當(dāng)然目錄下。2、gdb core用gdb同時(shí)調(diào)試一個(gè)運(yùn)行程序和core文件,core是程序非法執(zhí)行后core dump后產(chǎn)生的文件。3、gdb如果你的程序是一個(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)開(kāi)關(guān),詳細(xì)的開(kāi)關(guān)可以用gdb -help查看。我在下

46、面只例舉一些比較常用的參數(shù):-symbols-s從指定文件中讀取符號(hào)表。-se file從指定文件中讀取符號(hào)表信息,并把他用在可執(zhí)行文件中。-core-c調(diào)試時(shí)core dump的core文件。-directory-d加入一個(gè)源文件的搜索路徑。默認(rèn)搜索路徑是環(huán)境變量中PATH所定義的路徑。GDB的命令概貌啟動(dòng)gdb后,就你被帶入gdb的調(diào)試環(huán)境中,就可以使用gdb的命令開(kāi)始調(diào)試程序了,gdb的命令可以使用help命令來(lái)查看,如下所示:/home/hchen gdbGNU gdb 5.1.1Copyright 2002 Free Software Foundation, Inc.GDB is f

47、ree software, covered by the GNU General Public License, and you arewelcome 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.

48、(gdb) helpList of classes of commands:aliases - Aliases of other commandsbreakpoints - Making program stop at certain pointsdata - Examining datafiles - Specifying and examining filesinternals - Maintenance commandsobscure - Obscure featuresrunning - Running the programstack - Examining the stacksta

49、tus - Status inquiriessupport - Support facilitiestracepoints - Tracing of program execution without stopping the programuser-defined - User-defined commandsType 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

50、abbreviations are allowed if unambiguous.(gdb)gdb的命令很多,gdb把之分成許多個(gè)種類(lèi)。help命令只是例出gdb的命令種類(lèi),如果要看種類(lèi)中的命令,可以使用help 命令,如:help breakpoints,查看設(shè)置斷點(diǎn)的所有命令。也可以直接help 來(lái)查看命令的幫助。gdb中,輸入命令時(shí),可以不用打全命令,只用打命令的前幾個(gè)字符就可以了,當(dāng)然,命令的前幾個(gè)字符應(yīng)該要標(biāo)志著一個(gè)唯一的命令,在Linux下,你可以敲擊兩次TAB鍵來(lái)補(bǔ)齊命令的全稱(chēng),如果有重復(fù)的,那么gdb會(huì)把其例出來(lái)。示例一:在進(jìn)入函數(shù)func時(shí),設(shè)置一個(gè)斷點(diǎn)。可以敲入break

51、func,或是直接就是b func(gdb) b funcBreakpoint 1 at 0x8048458: file hello.c, line 10.示例二:敲入b按兩次TAB鍵,你會(huì)看到所有b打頭的命令:(gdb) bbacktrace break bt(gdb)示例三:只記得函數(shù)的前綴,可以這樣:(gdb) b make_ (再按下一次TAB鍵,你會(huì)看到:)make_a_section_from_file make_environmake_abs_section make_function_typemake_blockvector make_pointer_typemake_clea

52、nup make_reference_typemake_command make_symbol_completion_list(gdb) b make_GDB把所有make開(kāi)頭的函數(shù)全部例出來(lái)給你查看。示例四:調(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)稱(chēng)q就行了。GDB中運(yùn)行UNIX的shell程序在gdb環(huán)境中,你可以執(zhí)行UNIX的shell的命令,使用gdb的shell命令來(lái)完成:shell調(diào)用UNIX的shell來(lái)執(zhí)行,環(huán)境變量SHELL中定義的UNIX的shell將會(huì)被用來(lái)執(zhí)行,如果SHELL沒(méi)有定義,那就使用UNIX的標(biāo)準(zhǔn)s

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論