很久之前,在https://blog.csdn.net/fengbingchun/article/details/41413381中簡單整理過gdb中常用的一些命令,不齊全,這里按照《軟體除錯的藝術》一書中關于gdb的介紹再做次整理,《軟體除錯的藝術》于2009年由人民郵電出版社出版,
1. 預備知識
GDB:Unix程式員最常用的除錯工具,是由Richard Stallman開發的GNU專案除錯器(GNU Project Debugger),
DDD:Data Display Debugger,資料顯示除錯器,GDB的GUI(圖形用戶界面)前端:用戶通過GUI發出命令,GUI將這些命令傳遞給GDB,
Eclipse:IDE(集成開發環境),
GDB的命令允許在不產生歧義的情況下使用縮寫,
從版本6.1以來,GDB已經以名為TUI(Terminal User Interface, 終端用戶界面)的模式提供了基于文本互動和圖形用戶互動之間的折中方法,在這一模式中,GDB將終端螢屏劃分為類似于DDD的源文本視窗和控制臺的多個子視窗:可以在類似于源文本視窗的子視窗中跟蹤程式執行的進展程序,同時在類似于控制臺的子視窗中發出GDB命令,也可以使用另一個程式CGDB,該程式也提供了類似的功能,
為了以TUI模式運行GDB,可以在呼叫GDB時在命令列上指定-tui選型,如gdb -tui main,或者處于非TUI模式時在GDB中使用Ctrl+X+A組合鍵,如果當前處于TUI模式,后一種命令方式就會使你離開TUI模式,在TUI模式中,GDB視窗劃分為兩個子視窗:一個用于輸入GDB命令,而另一個用于查看源代碼,需要注意的是,在一些情況下TUI可能不能按照用戶所需要的方式運作,
1.5 主要除錯器操作:
單步除錯源代碼:
(1).斷點:除錯工具會在指定斷點處暫停程式的執行,在GDB中是通過break命令及其行號完成的,
(2).單步除錯:GDB的next命令讓GDB執行下一行,然后暫停,step命令的作用與此類似,只是在函式呼叫時step命令會進入函式,而next導致程式執行的暫停出現在下次呼叫函式時,
(3).恢復操作:在GDB中,continue命令通知除錯器恢復執行并繼續,直到遇到斷點為止,
(4).臨時斷點:在GDB中,tbreak命令與break相似,但是這一命令設定的斷點的有效期限只到首次到達指定行時為止,GDB中還有創建特殊型別的一次性斷點的命令until和finish,
檢查變數:當除錯器暫停了程式的執行后,可以執行一些命令來顯示程式變數的值,這些變數可以是區域變數、全域變數、陣列的元素和C語言的struct、C++類中的成員變數等,如果發現某個變數有一個出乎意料的值,那往往是找出某個程式錯誤的位置和性質的重要線索,最基本的變數顯示型別是僅僅輸出當前值,在GDB中使用print命令輸出當前值,如查看變數j的當前值執行”(gdb) print j”,
設定監視點以應對變數值的改變:監視點結合了斷點和變數檢查的概念,最基本形式的監視點通知除錯器,每當指定變數的值發生變化時都暫停程式的執行,例如,在程式執行期間,假設要在變數z改變值時查看程式的狀態,在GDB中,可以執行如下命令:”(gdb) watch z”,當運行程式時,每當z的值發生變化,GDB都會暫停執行,更好的方法是,可以基于條件運算式來設定監視點,例如,假設要查找程式執行期間z的值大于28的第一個位置,在GDB中,輸入”(gdb) watch (z>28)”,監視點對區域變數的用途一般沒有對作用域更寬的變數的用途大,因為一旦變數超出作用域(即當在其中定義變數的函式結束時),在區域變數上設定的監視點就會被取消,
上下移動呼叫堆疊:在函式呼叫期間,與呼叫關聯的運行時資訊存盤在稱為堆疊幀(stack frame)的記憶體區域中,幀中包含函式的區域變數的值、其形參,以及呼叫該函式的位置的記錄,每次發生函式呼叫時,都會創建一個新幀,并將其推到一個系統維護的堆疊上;堆疊最上方的幀表示當前正在執行的函式,當函式退出時,這個幀被彈出堆疊,并且被釋放,在GDB中可用用如下命令查看以前的幀:“(gdb) frame 1”,當執行GDB的frame命令時,當前正在執行的函式的幀被編號為0,其父幀(即該函式的呼叫者的堆疊幀)被編號為1,父幀的父幀被編號為2,以此類推,GDB的up命令將你帶到呼叫堆疊中的下一個父幀(例如,從幀0到幀1),down則引向相反反向,這樣的操作非常有用,因為根據以前的一部分堆疊幀中的區域變數的值,可能發現一些關于引起程式錯誤的代碼的線索,遍歷呼叫堆疊不會修改執行路徑,但是它確實允許查看幀的祖先幀,因此可以檢查通向當前幀的函式呼叫的區域變數的值,GDB的backtrace命令會顯示整個堆疊,即當前存在的所有幀的集合,
在GDB中,可以通過help命令訪問檔案,例如,”(gdb) help breakpoints”,將顯示關于斷點的檔案,不帶引數的GDB命令help提供了一個可用來作為help的引數的命令類別的選單,
1.7 初涉除錯會話:
注意,在GCC中可以用-g選項讓編譯器將符號表(即對應于程式的變數和代碼行的記憶體地址串列)保存在生成的可執行檔案中,這是一個絕對必要的步驟,這樣才能在除錯會話程序中參考源代碼中的變數名和行號,
與接受行號(或函式名)的break命令不同,condition接受斷點號,總是可以用命令info break來查詢要查找的斷點的編號,用break if可以將break和condition命令組合成一個步驟,如下所示”(gdb) break 30 if num_y==1”,然后用run命令再次運行程式,如果要重用老的命令列引數,就不必再次指定命令列引數,可以簡單地輸入run,
我們在重新編譯程式之前仍然不必退出GDB,這樣做提供了很大的方便,第一,不需要重新指出命令列引數,只要鍵入run重新運行程式即可,其次,GDB保留了你設定的斷點,因此不需要再次鍵入它,同樣,在除錯會話期間不要退出再重啟文本編輯器,這件事也會分心而且浪費時間,只要將文本編輯器放在一個視窗中,GDB放在另一個視窗中,用第三個視窗除錯程式即可,
當運行程式試圖訪問不允許訪問的記憶體時發生了段錯誤,原因通常是由于陣列索引超出了邊界,或者采用了錯誤的指標值,段錯誤也可能由每月顯式地包含指標或陣列變數的記憶體參考產生,
1.8 啟動檔案的使用:
在重新編譯代碼時,最好不要退出GDB,這樣,你的斷點和建立的其它各種動作都會保留,要是退出GDB,就不得不再次重復鍵入所有這些內容,為了不丟失它們,可以將斷點和設定的其它命令放在一個GDB啟動檔案中,然后每次啟動GDB時會自動加載它們,
GDB的啟動檔案默認名為.gdbinit,可以將一個檔案放在主目錄中用于一般用途,另一個檔案放在包含該專案特有用途的特定專案的目錄中,GDB在加載可執行檔案之前會讀取主目錄中的啟動檔案,在呼叫GDB時可以指定啟動檔案,例如”$ gdb -command=z x”,表示要在可執行檔案x上運行GDB,首先要從檔案z中讀取命令,
2. 停下來環顧程式
2.1 暫停機制:有3種方式可以通知GDB暫停程式的執行:
(1).斷點:通知GDB在程式中的特定位置暫停執行,
(2).監視點:通知GDB當特定記憶體位置(或者涉及一個或多個位置的運算式)的值發生變化時暫停執行,
(3).捕獲點:通知GDB當特定事件發生時暫停執行,
2.2 斷點概述:在程式中的特定”位置”設定斷點,當到達那一點時,除錯器會暫停程式的執行(在GDB這樣的基于文本的除錯器的情況下,會出現命令列提示符),GDB中關于”位置”的含義是非常靈活的,它可以指各種源代碼行、代碼地址、源代碼檔案中的行號或者函式的入口等,
GDB命令列提示符上面顯式的陳述句資訊是將要執行的代碼行,而不是GDB最后執行的代碼行,如下圖所示,接下來將要執行的是Messy_Test.cpp的第6行,GDB的作業針對的是機器語言指令,而不是源代碼行,一行代碼可能對應于數行機器語言,GDB之所以可以使用源代碼,是因為可執行檔案中包含了額外的資訊,

2.3 跟蹤斷點:程式員創建的每個斷點(包括斷點、監視點和捕獲點)都被標識為從1開始的唯一整數識別符號,這個識別符號用來執行該斷點上的各種操作,除錯器還包括一種列出所有斷點及其屬性的方式,當創建斷點時,GDB會告知你分配給該斷點的編號,如果忘記了分配給哪個斷點的編號是什么,可以使用”(gdb) info breakpoints”命令來提示,通過使用delete命令以及斷點識別符號,可以洗掉斷點、監視點及捕獲點,
2.4 設定斷點:GDB中有許多指定斷點的方式,下面是一些最常見的方法:
(1).break funciton:在函式function的入口(第一行可執行代碼)處設定斷點,
(2).break line_number:在當前活動源代碼檔案的line_number處設定斷點,
(3).break filename:line_number:在源代碼檔案filename的line_number處設定斷點,如果filename不在當前作業目錄中,則可以給出相對路徑名或者完全路徑名來幫助GDB查找該檔案,
(4).break filename:function:在檔案filename中的函式function的入口處設定斷點,多載函式或者使用同名靜態函式的程式可能需要使用這種形式,
當設定一個斷點時,該斷點的有效性會持續到洗掉、禁用或退出GDB時,然而,臨時斷點是首次到達后就會被自動洗掉的斷點,臨時斷點使用tbreak命令設定,它與break采用相同型別的引數,GDB實際設定斷點的位置可能與請求將斷點放置的位置不同,當打開優化來編譯程式時,這個問題可能變得更糟糕,GDB最終使用的是機器指令,在除錯完成前不應當優化代碼,
當GDB使用多個斷點中斷一行源代碼時,它只會中斷一次,換言之,當它到達該行代碼時,如果恢復執行,會忽略恰好在同一行上的其它斷點,事實上,GDB知道是哪個斷點”觸發”了程式停止執行,在具有多個斷點的代碼行上,觸發中斷的斷點將是識別符號編號最小的斷點,
2.5 展開GDB示例:
啟動除錯會話時在main()中設定斷點是非常普遍的,這一操作在該函式的第一行上設定斷點:”(gdb) break main”,
在任何給定時間,GDB都有一個焦點,可以將它看作當前”活動”檔案,這意味著除非對命令做了限定,否則都是在具有GDB的焦點的檔案上執行命令,默認情況下,具有GDB的初始焦點的檔案是包含main()函式的檔案,但是當發生如下任一動作時,焦點會轉移到不同的檔案上:
(1).向不同的源檔案應用list命令,
(2).進入位于不同的源代碼檔案中的代碼,
(3).當在不同的源代碼檔案中執行代碼時GDB遇到斷點,
使用quit命令離開GDB,
2.6 斷點的持久性:如果在修改和重新編譯代碼時沒有退出GDB,那么在下次執行GDB的run命令時,GDB會感知到代碼已修改,并自動重新加載新版本,然而要注意,斷點是會”移動”的,
2.7 洗掉和禁用斷點:這里提到的一切方法都同樣適用于監視點,
GDB中有兩個用來洗掉斷點的命令:delete和clear,delete命令用來基于識別符號洗掉斷點,clear命令使用與創建斷點相同的語法洗掉斷點,
(1).delete breakpoint_list:洗掉斷點使用數值識別符號,斷點可以是一個數字,比如delete 2洗掉第二個斷點;也可以是數字串列,比如delete 2 4洗掉第二個和第四個斷點,
(2).delete:洗掉所有斷點,
(3).clear:清除GDB將執行的下一個指令處的斷點,這種方法適用于要洗掉GDB已經到達的斷點的情況,
(4).clear function、clear filename:funciton、clear line_number和clear filename:line_number:這些命令根據位置清除斷點,作業方式與對應的break命令相似,
每個斷點都可以被啟用或禁用,只有當GDB遇到啟用的斷點時,才會暫停程式的執行;它會忽略禁用的斷點,默認情況下,斷點的生命期從啟用時開始,在除錯會話期間,會遇到大量斷點,對于經常重復的回圈結構或函式,這種情況使得除錯極不方便,如果要保留斷點以便以后使用,暫時又不希望GDB停止執行,可以禁用它們,在以后需要時再啟用,
使用disable breakpoint-list命令禁用斷點,使用enable breakpoint-list命令啟用斷點,其中breakpoint-list是使用空格分隔的串列,其中有一個或多個斷點識別符號,不帶任何引數地執行disable命令將禁用所有現有斷點,類似地,不帶引數地執行enable命令會啟用所有現有斷點,還有一個enable once命令”enable once breakpoint-list”,在斷點下次引起GDB暫停執行后被禁用,這個命令與tbreak命令非常類似,但是當遇到斷點時,它是禁用斷點,而不是洗掉斷點,
2.8 進一步介紹瀏覽斷點屬性:每個斷點都有各種屬性----行號、加在斷點上的條件(如果有的話)、當前啟用/禁用狀態等,
創建的每個斷點都被賦予了唯一的整數識別符號,設定的第一個斷點被賦予”1”,其后的每個斷點都被賦予所賦的上一個識別符號加1.每個斷點也有一些控制調整其行為的屬性,使用唯一識別符號,可以分別調整各個斷點的屬性,可以使用”(gdb) info breakpoints”命令(簡寫為”i b”)來獲得設定的所有斷點的清單,以及它們的屬性,info breakpoints的輸出看上去或多或少類似于如下所示:

(1).識別符號(Num):斷點的唯一識別符號,
(2).型別(Type):這個欄位指出該斷點是斷點、監視點還是捕獲點,
(3).部署(Disp):每個斷點都有一個部署,指示斷點下次引起GDB暫停程式的執行后該斷點上會發生什么事情,可能的部署有3種:
a.保持(keep):下次到達斷點后不改變斷點,這是新建斷點的默認部署,
b.洗掉(del):下次到達斷點后洗掉該斷點,使用tbreak命令創建的任何斷點都是這樣的斷點,
c.禁用(dis):下次到達斷點時會禁用該斷點,這是使用enable once命令設定的斷點,
(4).啟用狀態(Enb):這個欄位說明斷點當前是啟用還是禁用的,
(5).地址(Address):這是記憶體中設定斷點的位置,它主要用于匯編語言程式員,或者試圖除錯沒有用擴充的符號表編譯的可執行檔案的人,
(6).位置(What):各個斷點位于源代碼中的特定行上,What欄位顯示了斷點所在位置的行號和檔案號,
2.9 恢復執行:方法有3類:
(1).使用step和next”單步”除錯程式,僅執行代碼的下一行然后再次暫停,一旦GDB在斷點處停止,可以使用next(簡寫為n)和step(簡寫為s)命令來單步除錯代碼,當觸發了斷點,并且GDB暫停后,可以使用next和step來執行緊接著的下一行代碼,當執行了這一行后,GDB會再次暫停,并給出一個命令列提示符,這兩個命令的區別是它們如何處理函式呼叫:next執行函式,不會在其中暫停,然后在呼叫之后的第一條陳述句處暫停,而step在函式中的第一個陳述句處暫停,next將函式呼叫看作一行代碼,并在一個操作中執行整個函式,這稱為單步越過(stepping over)函式,next和step命令都采用一個可選的數值引數,表示要使用next或step執行的額外行數,換言之,next 3與在一行中鍵入next三次(或者鍵入next一次,然后按下ENTER鍵兩次)的作用相同,如果是在沒有函式呼叫的那部分代碼中,那么使用next還是step并沒有關系,在這種情況下,兩個命令是完全相同的,
(2).由使用continue組成,使GDB無條件地恢復程式的執行,直到它遇到另一個斷點或者程式結束,簡寫為c,與僅執行一行代碼的step和next相反,這個命令使GDB恢復程式的執行,直到觸發斷點或者程式結束,continue命令可以接受一個可選的整數引數n,這個數字要求GDB忽略下面n個斷點,
(3).涉及條件,用finish或until命令恢復,在這種情況下,GDB會恢復執行,程式繼續運行直到遇到某個預先確定的條件(比如,到達函式的末尾),到達另一個斷點,或者程式完成,
使用finish恢復程式執行:想回傳到單步進入被呼叫函式之前GDB所在的呼叫函式,這時應該使用finish命令,finish命令(簡寫為fin)指示GDB恢復執行,直到恰好在當前堆疊幀完成之后為止,也就是說,這意味著如果你在一個不是main的函式中,finish命令會導致GDB恢復執行,直到恰好在函式回傳之后為止,finish的另一個常見用途是當不小心單步進入原本希望單步越過的函式時(換言之,當需要使用next時使用了step),在這種情況下,使用finish可以將你正好放回到使用next會位于的位置,
如果在一個遞回函式中,finish只會將你帶到遞回的上一層,這是因為每次呼叫都被看作在它自己權限內的函式呼叫,因為每個函式都有各自的堆疊幀,如果要在遞回層次較高時完全退出遞回函式,那么更適合使用臨時斷點及continue,或者用until命令,
使用until恢復程式執行:finish命令在不進一步在函式中暫停(除了中間斷點)的情況下完成當前函式的執行,類似地,until命令(簡寫為u)通常用來在不進一步在回圈中暫停(除了回圈中的中間斷點)的情況下完成正在執行的回圈,使用until會執行回圈的其余部分,讓GDB在回圈后面的第一行代碼處暫停,如果在回圈的末尾,執行until命令導致回跳到回圈頂部,這時只要再次執行until,就可以離開當前的回圈,until命令也可以接受源代碼中的位置作為引數,事實上,該命令接受的引數與break命令相同,
2.10 條件斷點:這類似于監視點的作業方式,但是有一個重要區別,如果懷疑某個變數得到了一個偽值,那么條件斷點相當適用于監視點,每當該變數的值發生變化時,監視點都會中斷,條件斷點只會在懷疑有問題的代碼處當變數呈現該懷疑值時才中斷,設定條件斷點的語法為”break break-args if (condition)”,其中break-args是可以傳遞給break以指定斷點位置的任何引數,condition是定義的布爾運算式,括著condition的圓括號是可選的,如”(gdb) break main if argc > 1”:說明了如果用戶向程式中鍵入一些命令列引數,則在main()處中斷,條件中斷極其有用,尤其適用于索引變數的特定值出了問題的回圈結構,條件中斷也極其靈活,不僅可以測驗相等或不相等的變數,在有效的C條件陳述句中幾乎可以使用任何運算式,無論使用什么運算式,都需要具有布林值,即真(非0)或假(0):
(1).相等、邏輯和不相等運算子(<、<=、==、!=、>、>=、&&、||等),如”(gdb) break 180 if string==nullptr && i < 0”
(2).按位和移位運算子(&、|、^、>>、<<等),如”(gdb) break test.c:34 if (x & y) == 1”
(3).算術運算子(+、-、*、/、%),如”(gdb) break myfunc if i % (j + 3) != 0”
(4).你自己的函式,只要它們被鏈接到程式中,如”(gdb) break test.c:myfunc if ! check_variable_sanity(i)”
(5).庫函式,只要該庫被鏈接到代碼中,例如:”(gdb) break 44 if strlen(mystring) == 0”
由于優先級的次序規則在起作用,因此可能需要使用圓括號將一些結構括起來,此外,如果在GDB運算式中使用庫函式,而該庫不是用除錯符號編譯的(幾乎肯定是這種情況),那么唯一能在斷點條件中使用的回傳值型別為int,換言之,如果沒有除錯資訊,GDB會假設函式的回傳值是int型別,當這種假設不正確時,函式的回傳值會被曲解,
可以對正常斷點設定條件以將它們轉變為條件斷點,例如,如果設定了斷點3作為無條件斷點,但是現在希望添加條件i==3,只要鍵入”(gdb) cond 3 i == 3”,如果以后要洗掉條件,但是保持該斷點,只要鍵入”(gdb) cond 3”,
2.11 斷點命令串列:使用”斷點命令串列”可以讓GDB在每次到達某個斷點時自動執行一組命令,從而自動完成反復查看相同的變數這一程序,使用commands命令設定命令串列,逐條輸入命令,然后鍵入end表示輸入命令完畢,從那以后,每當GDB在這個斷點處中斷時,它都會執行你輸入的任何命令,
可以使用GDB的define命令創建宏,可以將宏保存在.gdbinit檔案中,以便將它用于其它程式,鍵入”(gdb) show user”可以得到所有宏的串列,
2.12 監視點:是一種特殊型別的斷點,它類似于正常斷點,是要求GDB暫停程式執行的指令,區別在于監視點沒有”住在”某一行源代碼中,取而代之的是,監視點是指示GDB每當某個運算式改變了值就暫停執行的命令,如”(gdb) watch (i | j > 12) && i > 24 && strlen(name) > 6”,可以將監視點看作被”附加”在運算式上,當運算式的值改變時,GDB會暫停程式的執行,
雖然管理監視點和斷點的方式相同,但是兩者之間有一個重要區別,斷點與源代碼中的一個位置關聯,只要代碼沒有改變,就不存在某行代碼”超出作用域”的風險,因為C語言有嚴格的作用域規則,所以只能監視存在且在作用域內的變數,一旦變數不再存在于呼叫堆疊的任何幀中(當包含區域變數的函式回傳時),GDB會自動洗掉監視點,GDB只能監視單個執行緒中的變數,
當變數var存在且在作用域中時,可以通過使用如下命令來設定監視點:”(gdb) watch var”,該命令會導致每當var改變值時GDB都中斷,GDB實際上是在var的記憶體位置改變值時中斷,監視點不僅僅限于監視變數,事實上,可以監視涉及變數的運算式,每當運算式修改值時,GDB都會中斷,
GDB中的運算式可以包含:
(1).GDB方便變數(convenience variables),
(2).程式中的任何在作用域內的變數,
(3).任何種類的字串、數值或字符常量,
(4).前處理器宏(如果程式被編譯為包括前處理器除錯資訊),
(5).條件、函式呼叫、型別強制轉換和所用語言定義的運算子,
3. 檢查和設定變數
3.2 變數的高級檢查和設定:
GDB的display命令(簡寫為disp)在執行中每次有暫停(由于有斷點,使用next或step命令等)時就輸出指定條目的值,只有當變數在作用域中時才生效,
在GDB中可以輸出整個陣列的值,如”(gdb) p x”或”(gdb) *pointer@number_of_elements”,
在GDB中,可以通過呼叫info locals命令得到當前堆疊幀中所有區域變數的值串列,
在有些情況下,可能希望檢查給定地址的記憶體,而不是通過變數的名稱,GDB為這種目的提供了x命令,
print和display命令允許指定可選的格式,如”(gdb) p/x y”,會以十六進制格式顯示變數,而不是十進制格式,其它常用的格式為c表示字符(character),s表示字串(string),f表示浮點(floating-point),
可以臨時禁用某個顯示項,例如”(gdb) dis disp 1”,臨時禁用顯示串列中的條目1.如果不知道條目號,可以通過info disp命令檢查,要重新啟用條目,使用enable,例如”(gdb) enable disp 1”,要完全洗掉顯示的條目,使用undisplay,例如”(gdb) undisp 1”,
3.3 設定變數:如”(gdb) set x = 12”,會將x的當前值改成12,可以通過GDB的set args命令設定程式的命令列引數,如”(gdb) set args 1 52 19 11”,并不會立即將argv[1]改成1,argv[2]改成52,等等,直到下次執行run命令時才會發生這些變化,GDB有用來檢查當前函式引數的info args命令,
3.4 GDB自己的變數:
(1).使用值歷史:GDB的print命令的輸出值被標為$1、$2等,這些值統稱為值歷史,在將來執行print命令時使用這樣的值歷史會比較方便,如”(gdb) p *$1”,
(2).方便變數(convenience variable):會根據C規則改變值,
4. 程式崩潰處理
4.2 核心檔案:如果在程式運行期間創建了核心檔案(core file,俗稱轉儲核心),則可以打開除錯器(比如GDB)上的該檔案,然后開始常規GDB操作,
核心檔案包含程式崩潰時對程式狀態的詳細描述:堆疊的內容(或者,如果程式是多執行緒的,則是各個執行緒的堆疊),CPU暫存器的內容(同樣,如果程式是多執行緒的,則是每個執行緒上的一組暫存器值),程式的靜態分配變數的值(全域與static變數),等等,
大多數現代shell都會在一開始就防止撰寫核心檔案,在bash中,可以使用ulimit命令控制核心檔案的創建,”$ ulimit -c n”,其中n是核心檔案的最大大小,以千位元組為單位,超過nKB的任何核心檔案都不會被編寫,如果沒有指定n,shell就會顯示核心檔案上的當前限制,如果允許任意大小的核心檔案,可以使用:”$ ulimit -c unlimited”,
如果程式的源代碼不可用,或者可執行檔案不是用增強的符號表編譯的,啥訓當我們沒有計劃除錯可執行檔案,核心檔案可能都不會有太大的用處,
core file的使用示例可參考:https://blog.csdn.net/fengbingchun/article/details/97113451
4.3 擴展示例:
在除錯會話期間,修改代碼時永遠不要退出GDB,這樣就不必費時間來啟動,可以保留我們的斷點,等等,類似地,我們要保持文本編輯器打開,在除錯時的兩次編譯之間留在同一個編輯器會話中,我們可以充分利用編輯器的”撤銷”功能,例如,除錯程序中的一個常見策略是臨時洗掉部分代碼,以便集中精力于你認為存在程式錯誤的余下部分,完成檢查后,只要使用編輯器的撤銷功能恢復被洗掉的代碼行即可,因此,在螢屏上我們通常有一個GDB視窗,以及一個編輯器視窗,我們還打開了第三個視窗用于執行編譯器命令,甚至最好是通過編輯器執行命令,
記住,當GDB注意到重新編譯了程式后,它會自動加載新的可執行檔案,因此同樣不需要退出和重啟GDB,
5. 多活動背景關系中的除錯
5.1 除錯客戶/服務器網路程式:socket
5.2 除錯多執行緒代碼:
查看指定執行緒的堆疊,如執行緒3,可執行”(gdb) thread 3”,再執行”(gdb) bt”,多執行緒程式的運行有一定的隨機性,
下面是與執行緒相關的GDB命令用法匯總:
(1).info threads:給出關于當前所有執行緒的資訊,帶有”*”號表示當前執行緒;
(2).thread 3:改成執行緒3;
(3).break 88 thread 3:當執行緒3到達源代碼行88時停止執行;
(4).break 88 thread 3 if x == y:當執行緒3到達源代碼行88,并且變數x和y相等時停止執行,
5.3 除錯并行應用程式:共享記憶體和訊息傳遞、MPI
5.4 擴展示例:OpenMP
6. 特殊主題
6.1 根本無法編譯或加載:
6.2 除錯GUI程式:
7. 其它工具
8. 對其它語言使用GDB
GitHub:https://github.com/fengbingchun/Messy_Test
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/183467.html
標籤:其他
上一篇:2020.10自考總結
下一篇:關于第四次自考,在問題中成長
