類UNIX下C/C++開發,代碼調試比較麻煩,最原始的加跟蹤調試很土,也很費時,特別是一個龐大的項目,程式碼數非常大的時候調試起來非常費勁,當core dump時定位也不容易,這裡介紹幾個常用工具: gdb、dbx調試工具,valgrind記憶體檢查工具(Linux) 。
gdb(GNU DeBugger)是GNU的調試器,一般和gcc配搭使用。要使用GDB進行調試,編譯器時要指定-g或-ggdb的編譯選項。如: gcc –g main.c
gdb指令:f(file):指定可執行檔,l(list)列出源檔案,r(run)運行可執行檔,可帶執行參數,b(break)設定斷點,c(continue)繼續被中斷程式執行,直到下一個斷點或者程式結束,p(print)輸出變數的值,如p aa;n(next)逐步執行,s(step)程式執行到斷點時中斷執行,可以用s指令進行逐步執行進入某一函數。q(quit)退出。
當在gdb運行時想運行shell命令,不必退出,執行shell切換到shell模式,執行shell命令。
GDB有能力在你偵錯工具的時候處理任何一種訊號,你可以告訴GDB需要處理哪一種訊號。你可以要求GDB收到你所指定的訊號時,馬上停住正在啟動並執行程式,以供你進行調試。你可以用GDB的handle命令來完成這一功能。handle <signal> <keywords...>
在GDB中定義一個訊號處理。訊號<signal>可以以SIG開頭或不以SIG開頭,可以用定義一個要處理訊號的範圍(如:SIGIO-SIGKILL,表示處理從SIGIO訊號到SIGKILL的訊號,其中包括SIGIO,SIGIOT,SIGKILL三個訊號),也可以使用關鍵字all來標明要處理所有的訊號。一旦被調試的程式接收到訊號,運行程式馬上會被GDB停住,以供調試。其<keywords>可以是以下幾種關鍵字的一個或多個。 nostop 不停止運行,只輸出顯示訊號,stop:停住程式,print顯示一條資訊,noprint當被調試的程式收到訊號時,GDB不會告訴你收到訊號的資訊,noignore當被調試的程式收到訊號時,GDB不處理訊號。這表示,GDB會把這個訊號交給被偵錯工具會處理。nopass,ignore當被調試的程式收到訊號時,GDB不會讓被偵錯工具來處理這個訊號。
查看core檔案:運行gdb 執行檔案 core檔案 來載入core檔案,使用where來查看coredump位置。如果系統未產生core檔案,可使用ulimit -c 2048命令,後運行執行檔案產生。
多進程調試:在我們的測試程式在父進程fork後,子進程調用sleep睡了60秒。這就是關鍵,這個sleep本來是不該存在於子進程代碼中的,而是為了使用GDB調試後加入的,為什麼要讓子進程剛剛運行就開始sleep呢?因為我們要在子進程睡眠期間,利用shell命令擷取其process id,然後再利用gdb調試外部進程的方法attach到該process id上,調試該進程。
動態庫調試,運行執行程式載入動態庫來調試。
/***********************************************************************/
dbx(SUN studio)調試工具:在利用 dbx 對程式進行原始碼級調試前,必須使用 -g 選項
啟動:dbx program_name載入要調試的程式,調試JAVA程式dbx program_name.class|.jar,可以指定進程ID來串連正在啟動並執行進程進行調試。
也可以在dbx運行時載入偵錯工具:(dbx)debug program_name
運行偵錯工具:run [運行參數]
查看core檔案:可以dbx program_name core,或者dbx - core,再使用where命令顯示棧跟蹤,找到崩潰位置
設定斷點:stop in 函數;stop at file:line ; 也可以先通過file file-name設定當前檔案,list function查看源檔案,確定要設定斷點的行數。在C++中可以將關鍵字(inmember、inclass、infunction 或 inobject)在類,成員函數,對象中設定斷點。stop change variable可設定當變數改變時停止。條件停止斷點:stop cond condition。另外在動態庫中可以在動態共用程式庫的函數中以在程式啟動時在連結的庫中設定斷點的同樣方式來設定斷點。
列出所有斷點:status
刪除斷點:delete 斷點號
逐步執行:step、next,step 命令步入函數,而 next 命令步過函數。step up將一直執行,直至當前函數將控制返回調用它的函數為止。
繼續執行:cont
查看調用棧:where 調用棧代表那些已被調用但尚未返回各自調用程式的所有當前活動常式。在棧中,函數及其參數按調用的順序進行存放。棧跟蹤顯示程式流執行的停止位置以及執行如何到達此點。它提供者狀態的簡明描述。
檢查變數:print 變數名
退出:quit
串連已啟動並執行進程:attach pid
分離已串連的進程:detach pid
尋找符號:whereis symbol 列印指定符號所有具體值的列表
要列印輸出標識符的聲明whatis
對子進程使用運行時檢查,可通過attach 子進程ID串連到子進程進行調試。
要顯示當前進程的所有線程資訊:執行thread,切換到指定線程:thread thr_id
訊號處理:
cont -sig signal將訊號轉寄到進程;catch顯示當前正在捕獲的訊號列表;ignore顯示程式忽略訊號列表
shell方式切換:sh
------------------------------dbx調試跟蹤的常用子命令
dbx是UNIX下基於命令列介面的程式調試器。 dbx是通過互動執行dbx子命令來達到調試的目的的。在偵錯工具前,必須先將-g選項包含在編譯資訊中,編譯產生帶調試資訊的檔案,即:cc -o filename -g file.c。 進入dbx通常只需輸入"dbx filename"即可,filename為待調試的可執行程式名。dbx載入後就顯示提示符:(dbx),此時使用者就可以輸入dbx子命令進行調試了。
文法:
dbx [ -a ProcessID ] [ -c CommandFile ] [ -d NestingDepth ] [ -I Directory ] [ -E DebugEnvironment ] [ -p oldpath=newpath:...| pathfile ] [ -k ] [ -u ] [ -F ] [ -r ] [ -x ] [ ObjectFile [ CoreFile ] ]
-a ProcessID
將偵錯工具和正在啟動並執行進程串連起來。要串連偵錯工具,您需要擁有對該進程使用 kill 命令的許可權。使用 ps 命令來決定進程的 ID。如果您獲得許可,dbx 程式中斷該進程,決定對象檔案的完整名稱,讀入符號資訊和提示輸入命令。
-c CommandFile
讀入標準輸入之前,在檔案中運行 dbx 子命令。$HOME 目錄中指定的檔案將首先被處理;然後處理目前的目錄中的檔案。目前的目錄中的命令檔案將會覆蓋 $HOME 目錄中的命令檔案。如果指定的檔案既不存在於 $HOME 目錄也不存在於目前的目錄,將會顯示警告訊息。source 子命令可以在 dbx 程式運行後使用。
-d NestingDepth
設定程式塊的嵌套限制。預設的嵌套深度限制為 25。
-E DebugEnvironment
指定偵錯工具的環境變數。
-p oldpath=newpath:...| pathfile
以 oldpath=newpath 的格式在檢查核心檔案時指定替換的庫的路徑。oldpath 指定了將被替換的值(儲存在核心檔案中)而 newpath 指定了將要替換的新的值。這些可能是全部或者部分的,絕對路徑或者相對路徑。可以指定若干個替換,它們之間用冒號隔開。相反 -p 標誌可以指定檔案名稱,映射以前讀入的描述格式。每行中只允許有一個映射從檔案中讀出。
-F 可以用來關閉緩慢讀入模式並使 dbx 命令在啟動時就讀入全部符號。預設情況下,緩慢讀入模式是開啟的:它在 dbx 會話初始化時讀入需要的符號表資訊。。在該模式下,dbx 將不會讀入那些符號資訊尚未被讀入的變數和類型。因此,諸如 whereis i 等命令並不列出在所有函數中的變數 i 的全部執行個體。
-I Directory
(大寫 i)將 Directory 變數指定的目錄包含到搜尋源檔案目錄列表中。搜尋源檔案的預設目錄為:
- 檔案編譯時間該源檔案所在的目錄。只有編譯器設定了對象中的源路徑時才能搜尋目錄。
- 目前的目錄。
- 當前程式所在的目錄。
-k 映射記憶體位址;這對於核心調試是非常有用的。
-r 立即運行對象檔案。如果它成功結束,dbx 偵錯工具將會退出。否則,將會進入偵錯工具並報告中斷的原因。
注意:除非指定了 -r,dbx 命令將會提示使用者並等待命令輸入。
-u 讓 dbx 命令為檔案名稱加上 @ (at 符號) 首碼。該標誌減少符號名混淆的可能性。
-x 防止 dbx 命令跳過來自於 FORTRAN 原始碼的 _(底線)字元。該符號允許 dbx 在符號之間區別哪些除了底線以外都是相同的,例如 xxx 和xxx_。
下面是一些dbx的常用子命令:
1.基本操作命令
run arg1 arg2 ... :以arg1,arg2,...為參數開始運行現有進程。
r:用上次使用的參數再次運行現有進程。
source filename:從檔案名稱為filename的檔案中讀入dbx子命令並執行。
return:執行完目前的進程後返回。
sh command:不退出dbx,執行一條作業系統shell命令。
sh:暫時進入shell狀態。
quit:退出dbx,若程式未執行完則終止其執行。
2.置斷點與跟蹤點命令
stop var at n:置斷點命令,當第n行的變數var發生變化時將程式掛起。
stop var in proc:置斷點命令,當過程proc的變數var發生變化時將程式掛起。
stop at n:置斷點命令,當執行到第n行時將程式掛起。
stop in proc:置斷點命令,當執行到過程proc時將程式掛起。
trace var at n:置跟蹤點命令,當第n行的變數var改變時顯示跟蹤資訊。
trace var in proc:置跟蹤點命令,當過程proc的變數var改變時顯示跟蹤資訊。
trace n:置跟蹤點命令,當執行到第n行時顯示被跟蹤資訊。
trace proc:置跟蹤點命令,當執行到過程proc時顯示被跟蹤資訊。
trace expr at n:置跟蹤點命令,當執行到第n行時顯示var的值。
delete n|all:刪除第n行的/所有的斷點與跟蹤點。
3.調試命令
cont at n:運行直至第n行。
print var:列印變數var的值。
printf "string",expr,...:以C語言的格式列印。
where:列印當前調試狀態,包括當前進程的資訊。
func:查看當前啟動並執行進程名。
func proc:移至到調用proc進程的母進程處。
whatis name:顯示對變數名或過程名name的類型。
step [n]:逐步執行一行或n行,遇到線程調用時進入線程調用。
next [n]:逐步執行一行或n行,遇到線程調用時拒絕進入線程調用。
skip [n]:跳過一個或n個斷點,繼續往下執行
dump [proc] [>;file]:顯示當前或proc過程的所有變數名及其值
assign var=expr:給變數var賦以運算式expr的值
4.讀取被偵錯工具命令
list:列出從當前行開始的若干行來源程式。
list n,m:列出從第n行到第m行的來源程式。
/string:朝檔案尾方向尋找字串string
?string:朝檔案頭方向尋找字串string
file filename:將查看的檔案切換到檔案filename處。
(dbx)run——運行可執行二進位檔案
(dbx)list——列出代碼
(dbx)next——跳轉到下一步執行
(dbx)print <variable name>——列印輸出值
(dbx)stop at <filename: line n>——設定斷點
(dbx)stop at <funcname :line n>
(dbx)cont——繼續執行
(dbx)cont at <line n>——繼續執行指定行
(dbx)call——調用func()
(dbx)delete <breakpoint number>——刪除斷點
(dbx)quit——退出執行
Example1:
$cc -g -o test test.c
$dbx test
(dbx)stop at main
Example2:
$ cc -g looper.c -o looper
$ ps -u UserID
PID TTY TIME COMMAND
68 console 0:04 sh
467 lft3 10:48 looper
$ dbx -a 467
attached in main at line 5
5 for (i = 0; i < 10;);
(dbx)
更多命令參考:http://publib16.boulder.ibm.com/doc_link/zh_CN/a_doc_lib/cmds/aixcmds2/dbx.htm
Linux gdb調試
GDB是如今最廣為人知的著名的自由和開放源碼軟體之一。它被大量GNU軟體項目以及眾多與GNU沒有關聯但卻希望能有一個高品質調試器的第三方軟體所使用。事實上,許多第三方工具合并gdb並將其作為它們的調試功能的基礎,即便它們在gdb之上建立了各級圖形化抽象。你很可能已遇到過GDB——但可能根本沒有意識到這一點。
GDB建立在任何調試器都有兩個組成部分這一基本概念之上。首先,GDB的底層處理單獨進程或線程的啟動和關閉、跟蹤代碼執行以及在運行代碼中插入和刪除斷點。GDB支援大量不同的平台和機制以在各種架構上實現這些(看似簡單的)操作。其具體的功能可能會受底層硬體功能的影響而偶爾有所變動。
$ gcc -o hello -g hello.c
$ gdb ./hello
(gdb) help
(gdb) break main (或者 b main)
(gdb) run
(gdb) next (或者 next i,不進入函數內部)
(gdb) step (或者 step i,進入函數內部)
(gdb) print argv[1]
(gdb) bt (或者backtrace, 查看程式運行到當前位置之前所有的堆疊框架情況)
/********************************************************************************/
valgrind是Linux(x86)環境的記憶體調試工具,可以在此工具中運行程式來檢查記憶體使用量,可以自動檢測到記憶體流失及記憶體管理的BUG,使你的程式更加健壯。
1。valgrind安裝::www.valgrind.org,安裝很簡單,執行configure,make,make install
2。valgrind工具集:
memcheck:檢測程式中的記憶體管理BUG,所有的寫/讀操作都會被、malloc/free都會被截獲
cachegrind:cache剖析器,它類比 CPU中的一級緩衝I1,D1和L2二級緩衝,能夠精確地指出程式中 cache的丟失和命中。
Callgrind:同cachegrind一樣,但能跟蹤函數的調用返回關係,及有選擇的類比cache。
Massif:堆棧分析器,它能檢測程式在堆棧中使用了多少記憶體,以及堆塊,堆管理塊和棧的大小。協助我們減少程式對記憶體的使用。
Helgrind:檢測使用POSIX pthread多線程同步問題。
3。valgrind命令格式:
valgrind [valgrind-options] your-prog [your-prog-options]
valgrind-options選項:
--tool=<name> [default=memcheck]選擇工具
-h --help 協助
--version 顯示版本
-q --quiet 只顯示錯誤
-v --verbose 更多顯示
-d 顯示valgrind自身調試資訊
--trace-children=<yes|no> [default: no]跟蹤子進程通過exec系統調用,預設是no
--child-silent-after-fork=<yes|no> [default: no] ??
--track-fds=<yes|no> [default: no]退出時顯示所有開啟的檔案描述符列表
--time-stamp=<yes|no> [default: no] 運行加時間戳記
--log-fd=<number> [default: 2, stderr]輸出LOG到描述符檔案
--log-file=<filename>指定記錄檔
--log-socket=<ip-address:port-number>日誌通過SOCKET輸出到指定IP連接埠
與錯誤相關的選項:
--xml=<yes|no> [default: no]將資訊以xml格式輸出,只有memcheck可用
--num-callers=<number> [default: 12]預設valgrind顯示12級函數調用協助識別程式定位
--error-limit=<yes|no> [default: yes]如果錯誤總數超過1千萬,或不同的錯誤超過1000,則停止顯示新錯誤
--error-exitcode=<number> [default: 0]指定在運行時檢查到錯誤時返回的錯誤碼
--show-below-main=<yes|no> [default: no]預設不顯示棧跟蹤報告在main下層的函數錯誤
--db-attach=<yes|no> [default: no]設定為yes時valgrind會暫停提示是否轉入調試工具
--db-command=<command> [default: gdb -nw %f %p]指定調試工具預設為gdb
--leak-check=<no|summary|yes|full> [default: summary]記憶體檢測時,給出詳細的記憶體流失資訊
--show-reachable=<yes|no> [default: no]記憶體檢測時顯示不可達指標
其它選項不很常用。有些也不很理解,這裡就省略了。
在檢測前,確認使用-g選項編譯你的程式,這樣以便能報告錯誤的行數
4。valgrind錯誤報表例子:
memcheck
非法的讀寫訪問,數組越界
Invalid read of size 4 at 0x40F6BBCC:
(within /usr/lib/libpng.so.2.1.0.9) by 0x40F6B804:
(within /usr/lib/libpng.so.2.1.0.9) by 0x40B07FF4: read_png_image(QImageIO *)
(kernel/qpngio. by 0x40AC751B: QImageIO::read()
(kernel/qimage.cpp:3621) Address 0xBFFFF0E0 is not stack’d, malloc’d or free’d
使用未初始化指標
Conditional jump or move depends on uninitialised value(s) at 0x402DFA94:
_IO_vfprintf (_itoa.h:49) by 0x402E8476:
_IO_printf (printf.c:36) by 0x8048472: main (tests/manuel1.c:8)
非法釋放
Invalid free() at 0x4004FFDF: free (vg_clientmalloc.c:577) by 0x80484C7:
main (tests/doublefree.c:10) Address 0x3807F7B4 is 0 bytes
inside a block of size 177 free’d at 0x4004FFDF: free (vg_clientmalloc.c:577) by 0x80484C7:
main (tests/doublefree.c:10)
不適當的釋放
Mismatched free() / delete / delete [] at 0x40043249: free (vg_clientfuncs.c:171) by 0x4102BB4E:
QGArray::~QGArray(void) (tools/qgarray.cpp:149) by 0x4C261C41:
PptDoc::~PptDoc(void) (include/qmemarray.h:60) by 0x4C261F0E:
PptXml::~PptXml(void) (pptxml.cc:44) Address 0x4BB292A8 is 0 bytes
inside a block of size 64 alloc’d at 0x4004318C:
operator new[](unsigned int) (vg_clientfuncs.c:152) by 0x4C21BC15: KLaola::
readSBStream(int) const (klaola.cc:314) by 0x4C21C155: KLaola::
stream(KLaola::OLENode const *) (klaola.cc:416) by 0x4C21788F:
OLEFilter::convert(QCString const &) (olefilter.cc:272)
源與目的塊重疊
==27492== Source and destination overlap in memcpy(0xbffff294, 0xbffff280, 21)
==27492== at 0x40026CDC: memcpy (mc_replace_strmem.c:71)
==27492== by 0x804865A: main (overlap.c:40)
預設輸出報告檔案名稱:工具名.out.pid
Helgrind線程BUG偵查工具:能夠報告一些線程使用的常見問題。比如:
釋放一個無效mutex、釋放未加鎖的mutex、釋放一個被其它線程持有的mutex、銷毀一個無效的或者加鎖的mutex、遞迴加鎖一個非遞迴鎖、釋放記憶體包含加鎖的mutex、必須處理使用pthread函數失敗返回錯誤碼、當線程退出時仍持有著鎖,調用pthread_cond_wait時使用未申請的mutex或一個被其它線程加鎖的mutex
錯誤報表如下:
Thread #1 unlocked a not-locked lock at 0x7FEFFFA90 at 0x4C2408D: pthread_mutex_unlock (hg_intercepts.c:492) by 0x40073A: nearly_main (tc09_bad_unlock.c:27) by 0x40079B: main (tc09_bad_unlock.c:50) Lock at 0x7FEFFFA90 was first observed at 0x4C25D01: pthread_mutex_init (hg_intercepts.c:326) by 0x40071F: nearly_main (tc09_bad_unlock.c:23) by 0x40079B: main (tc09_bad_unlock.c:50)
比較常用的是memcheck、Helgrind工具。經常使用valgrind能使你的程式更加完美。
轉載聲明: 本文轉自 http://blog.csdn.net/cation/archive/2009/08/10/4431143.aspx
========================================================================
參考推薦:
DBX調試方法
GDB調試精粹及使用執行個體