轉自:http://blog.csdn.net/yanook/article/details/6585648
GDB的功能很強大,本文主要介紹用GDB來調試訊號、多進程、多線程,具體如下:
(一)訊號
GDB有能力在你偵錯工具的時候處理任何一種訊號,你可以告訴GDB需要處理哪一種訊號。你可以要求GDB收到你所指定的訊號時,馬上停住正在啟動並執行程式,以供你進行調試。你可以用GDB的handle命令來完成這一功能。
handle <signal> <keywords...>
在GDB中定義一個訊號處理。訊號<signal>可以以SIG開頭或不以SIG開頭,可以用定義一個要處理訊號的範圍(如:SIGIO- SIGKILL,表示處理從SIGIO訊號到SIGKILL的訊號,其中包括SIGIO, SIGIOT,SIGKILL三個訊號),也可以使用關鍵字 all來標明要處理所有的訊號。一旦被調試的程式接收到訊號,運行程式馬上會被GDB停住,以供調試。其<keywords>可以是以下幾種關鍵字的一個或多個。
nostop
當被調試的程式收到訊號時,GDB不會停住程式的運行,但會打出訊息告訴你收到這種訊號。
stop
當被調試的程式收到訊號時,GDB會停住你的程式。
print
當被調試的程式收到訊號時,GDB會顯示出一條資訊。
noprint
當被調試的程式收到訊號時,GDB不會告訴你收到訊號的資訊。
pass
noignore
當被調試的程式收到訊號時,GDB不處理訊號。這表示,GDB會把這個訊號交給被偵錯工具會處理。
nopass
ignore
當被調試的程式收到訊號時,GDB不會讓被偵錯工具來處理這個訊號。
info signals
info handle
查看有哪些訊號在被GDB檢測中。
(二)線程
如果你程式是多線程的話,你可以定義你的斷點是否在所有的線程上,或是在某個特定的線程。GDB很容易幫你完成這一工作。
break <linespec> thread <threadno>
break <linespec> thread <threadno> if ...
linespec指定了斷點設定在的來源程式的行號。threadno指定了線程的ID,注意,這個ID是GDB分配的,你可以通過“info threads”命令來查看正在運行程式中的線程資訊。如果你不指定
thread <threadno>則表示你的斷點設在所有線程上面。你還可以為某線程指定斷點條件。如:
(gdb) break frik.c:13 thread 28 if bartab > lim
當你的程式被GDB停住時,所有的運行線程都會被停住。這方便你你查看運行程式的總體情況。而在你恢複程式運行時,所有的線程也會被恢複運行。那怕是主進程在被單步調試時。
線程有自己的寄存器,運行時堆棧或許還會有私人記憶體。
gdb提供了以下供調試多線程的進程的功能:
* 自動通告新線程。
* \ "thread THREADNO\ ",一個用來線上程之間切換的命令。
* \ "info threads\ ",一個用來查詢現存線程的命令。
* \ "thread apply [THREADNO] [ALL] ARGS\ ",一個用來向線程提供命令的命令。
* 線程有關的斷點設定。
注意:這些特性不是在所有gdb版本都能使用,歸根結底要看作業系統是否支援。
如果你的gdb不支援這些命令,會顯示出錯資訊:
(gdb) info threads
(gdb) thread 1
Thread ID 1 not known. Use the \ "info threads\ " command to
see the IDs of currently known threads.
gdb的線程級調試功能允許你觀察你程式運行中所有的線程,但無論什麼時候
gdb控制,總有一個“當前”線程。調試命令對“當前”進程起作用。
一旦gdb發現了你程式中的一個新的線程,它會自動顯示有關此線程的系統信
息。比如:
[New process 35 thread 27]
不過格式和作業系統有關。
為了調試的目的,gdb自己設定線程號。
`info threads\ "
顯示進程中所有的線程的概要資訊。gdb按順序顯示:
1.線程號(gdb設定)
2.目標系統的線程標識。
3.此線程的當前堆棧。
一前面打\ "*\ "的線程表示是當前線程。
例如:
(gdb) info threads
3 process 35 thread 27 0x34e5 in sigpause ()
2 process 35 thread 23 0x34e5 in sigpause ()
* 1 process 35 thread 13 main (argc=1, argv=0x7ffffff8)
at threadtest.c:68
`thread THREADNO\ "
把線程號為THREADNO的線程設為當前線程。命令列參數THREADNO是gdb內定的
線程號。你可以用\ "info threads\ "命令來查看gdb內設定的線程號。gdb顯示該線程
的系統定義的標識號和線程對應的堆棧。比如:
(gdb) thread 2
[Switching to process 35 thread 23]
0x34e5 in sigpause ()
\ "Switching後的內容取決於你的作業系統對線程標識的定義。
`thread apply [THREADNO] [ALL] ARGS\ "
此命令讓你對一個以上的線程發出相同的命令\ "ARGS\ ",[THREADNO]的含義同上。
如果你要向你進程中的所有的線程發出命令使用[ALL]選項。
無論gdb何時中斷了你的程式(因為一個斷點或是一個訊號),它自動選擇訊號或
斷點發生的線程為當前線程。gdb將用一個格式為\ "[Switching to SYSTAG]\ "的訊息
來向你報告。
(三)進程
1. 用的是attach子進程的方法
attach到正在啟動並執行進程的功能,即attach <pid>命令。因此我們可以利用該命令attach到子進程然後進行調試。
一般的步驟是 1.首先要在要調試的子進程初始代碼中,加入一段特殊代碼,使子進程睡眠等待,然後運行待調試的程式
2.用ps -ef |grep 查看產生的子進程pid
3. 然後gdb啟動,attach <pid>到進程後在該程式碼片段後設上斷點,就可以調試了
eg.
pid = fork();
if (pid <0) {
printf("fork err\n");
exit(-1);
} else if (pid == 0) {
/* in child */
sleep(60); ------------------ (!)
int value = 10;
**********
} /**in parent****/
執行程式(比如說是 examp)
examp & --- 讓examp後台運行吧。(不後台運行也可以);
尋找進程id:
ps -ef
運行gdb:
gdb
(gdb) attach xxxxx --- xxxxx為利用ps命令獲得的子進程 id
(gdb) stop --- 這點很重要,你需要先暫停那個子進程,然後設定一些斷點和一些Watch
(gdb) break xx
Breakpoint 1 at 0x10808: file eg1.c, line 37.
(gdb) c
Continuing.
2. 使用follow-fork-mode 的方法調試多進程
最好使用GDB 6.6或以上版本
使用follow-fork-mode 的方法調試多進程時的一般步驟是:
1.啟動gdb
2設定set follow-fork-mode [child/parent] 想調試child就使用child參數,如調試parent則使用parent
3啟動程式檔案 file ./hello ----------當然路徑名自己要搞對哦
4.break num -----------如調試子進程則num是子進程代碼的行數,
還有個小技巧就是break fork也就是在fork函數處設定斷點,