調試工具:
gdb
unix程式員最常用的調試工具是gdb,大多數linux系統應該預先安裝了gdb。如果沒有預先安裝該工具,則必須下載下傳gcc編譯器程式包。
ddd
随着gui(圖形使用者界面)越來越流行,大量的unix環境下運作的基于gui的調試器被開發出來。其中的大多數工具都是gdb的gui前端:使用者通過gui發出指令,gui将這些指令傳遞給gdb。ddd就是其中的一種工具。
如果你的系統還沒有安裝ddd,則可以下載下傳該工具。例如,centos系統上,指令
将自動處理整個安裝過程。
主要調試器操作
1 單步調試源代碼
可以安排程式的執行run在某個地方暫停,以便檢查變量的值,進而得到關于程式錯誤所在位置的線索。下面是可用來暫停程式執行的一些方法。
斷點
正如前面所說,調試工具會在指定斷電處暫停程式的執行。在gdb中是通過break指令及其行号完成的,在ddd中是在相關代碼行的任意空白處右擊并選擇set breakpoint來完成的。
單步調試
gdb的next指令讓gdb執行下一行,然後暫停。step指令的作用于此類似,隻是在函數調用時step指令會進入函數,而next導緻程式執行的暫停出現在下次調用函數時。ddd有對應的next和step菜單項。
恢複操作
在gdb中,continue指令通知調試其恢複執行并繼續,直到遇到斷點為止。ddd中有一個對應的菜單項。
臨時斷點
在gdb中,tbreak指令和break相似,但是這一指令設定的斷電的有效期隻到首次到達指定行時為止。在ddd中臨時斷點的設定方式為:在源文本視窗中要設定斷點的代碼行的任意空白處右擊,然後選擇set temporary breakpoint。
gdb中還有建立特殊類型的一次性斷點的指令:until和finish。ddd的指令工具中有對應的until和finish項。
程式執行的典型調試模式如下(以gdb為例):單擊一個斷點後,通過gdb的next指令一次移動一行代碼,或通過step指令單步調試一段時間,以便仔細檢查靠近斷點處的程式狀态和行為。做完這些操作後,可以用continue指令讓調試器繼續執行程式,直到遇到下一個斷點為止,其間不需要暫停。
gdb的暫停機制
有3種方式可以通知gdb的暫停程式的執行。
斷點:通知gdb在程式中的特定位置暫停執行。
監視點:通知gdb當特定記憶體位置(或者涉及一個或多個位置的表達式)的值發生變化時暫停執行
捕獲點:通知gdb當特定事件發生時暫停執行。
斷點概述
斷點就像程式中的絆網:在程式中的特定“位置”設定斷點,當到達那一點時,調試器會暫停程式的執行(在gdb這樣的基于文本的調試器的情況下,會出現指令行提示符)。
gdb中關于“位置”的含義是非常靈活的,它可以指各種源代碼行、代碼位址、源代碼檔案中的行号或者函數的入口等。
gdb執行到斷點行之前,gdb顯示的是将要執行的代碼行。
然而,gdb的工作針對的是機器語言指令,而不是源代碼行,一行代碼可能對應于數行機器語言。
可以使用info breakpoints指令獲得斷點資訊。使用delete + 斷點編号來删除斷點。
設定斷點
在gdb中設定斷點
gdb中有許多指定斷點的方式,下面是一些最常見的方法。
break function
在函數function()的入口(第一行可執行代碼)處設定斷點。
(gdb) break main
在main()的入口處設定斷點。
break line_number
在目前活動源代碼檔案的line_number處設定斷點。對于多行程式,這要麼是上次使用list指令檢視其内容的檔案,要麼是包含main()的檔案。
(gdb) break 35
它在檔案的第35行處設定了一個斷點。
break filename:line_number
在源代碼檔案filename的line_number處設定斷點。如果filename不在目前工作目錄中,則可以給出相對路徑名或者完全路徑名來幫助gdb查找該檔案,例如:
(gdb) break source/bed.c:35
break filename:function
在檔案filename中的函數function()的入口處設定斷點。重載函數或者使用同名靜态函數的程式可能需要使用這種方式,例如:
(gdb) break bed.c:parsearguments
正如我們看到的,當設定一個斷點時,該斷點的有效性會持續到删除、禁用或退出gdb時。然而,臨時斷點是首次到達後就會自動删除的斷點。臨時斷點使用tbreak指令設定,它與break采用相同類型的參數。例如,tbreak foo.c在檔案的第10行設定臨時斷點。
當同一行源代碼上有多個斷點時會發生什麼情況。當gdb使用多個斷點中斷一行源代碼時,它隻會中斷一次。換言之,當它到達該行代碼時,如果恢複執行,會忽略恰好在同一行的其他斷點。事實上,gdb知道是哪個斷點“觸發”了程式停止執行。在具有多個斷點的代碼行上,觸發中斷的斷點将是辨別符編号最小的斷點。
斷點的持久性
如果在重新修改編譯源代碼期間不退出gdb。例如,當發現并修複了一個程式錯誤,但是其他程式錯誤仍然存在時,不應當退出gdb然後重新進入來使用程式的新版本。這樣做有些不必要地繁瑣,而且還會不得不重新進入斷點。
如果在修改和重新編譯代碼時沒有退出gdb,那麼在下次執行gdb的run指令時,gdb會感覺到代碼已經修改,并自動重新加載新版本。
删除和禁用斷點
如果确認不再需要目前斷點,那麼可以删除該斷點。gdb中有兩個用來删除斷點的指令。delete指令用來基于辨別符删除斷點,clear指令使用建立斷點相同的文法删除斷點。
delete breakpoint_list
删除斷點使用數值辨別符。斷點可以是一個數字,比如delete 2删除第二個斷點;也可以是數字清單,比如delete 2 4 删除第二個和第四個斷點。
delete
删除所有斷點。除非執行也可以放在.gdbinit啟動檔案中的set confirm off指令,否則gdb會要求确認删除操作。
clear
清除gdb将執行的下一個指令處的斷點。這種方法适用于要删除gdb已經到達的斷點的情況。
clear function、clear filename:function、clear line_number和clear filename:line_number
這些指令根據位置清楚斷點,工作方式與對應的break指令相似。
在gdb中禁用斷點
每個斷點都可以被啟用或禁用。隻有當gdb遇到啟用的斷點時,才會暫停程式的執行;它會忽略禁用的斷點。預設情況下,斷點的生命期從啟用時開始。
使用disable breakppoint-list指令禁用斷點,使用enable breakpoint-list指令啟用斷點,其中breakpoint-list是使用空格分隔的清單,其中有一個或多個斷點辨別符。例如
(gdb) disble 3
将禁用第三個斷點。類似地,
(gdb) enable 1 5
将啟用第一個和第五個斷點。
不帶任何參數地執行disable指令将禁用所有現有斷點。類似地,不帶參數地執行enable指令會啟用所有現有斷點。
還有一個enable once指令。在斷點下次引起gdb暫停執行後被禁用。文法為:
enable once breakpoint-list