天天看點

[轉]使用GDB 調試多程序程式

DB 是 linux 系統上常用的調試工具,本文介紹了使用 GDB 調試多程序程式的幾種方法,并對各種方法進行比較。

GDB 是 linux 系統上常用的 c/c++ 調試工具,功能十分強大。對于較為複雜的系統,比如多程序系統,如何使用 GDB 調試呢?考慮下面這個三程序系統:

<a><b>程序</b></a>

[轉]使用GDB 調試多程式程式

Proc2 是 Proc1 的子程序,Proc3 又是 Proc2 的子程序。如何使用 GDB 調試 proc2 或者 proc3 呢?

實際上,GDB 沒有對多程序程式調試提供直接支援。例如,使用GDB調試某個程序,如果該程序fork了子程序,GDB會繼續調試該程序,子程序會不受幹擾地運作下去。如果你事先在子程序代碼裡設定了斷點,子程序會收到SIGTRAP信号并終止。那麼該如何調試子程序呢?其實我們可以利用GDB的特點或者其他一些輔助手段來達到目的。此外,GDB 也在較新核心上加入一些多程序調試支援。

接下來我們詳細介紹幾種方法,分别是 follow-fork-mode 方法,attach 子程序方法和 GDB wrapper 方法。

<a><b>follow-fork-mode</b></a>

在2.5.60版Linux核心及以後,GDB對使用fork/vfork建立子程序的程式提供了follow-fork-mode選項來支援多程序調試。

follow-fork-mode的用法為:

<code>set follow-fork-mode [parent|child]</code>

parent: fork之後繼續調試父程序,子程序不受影響。

child: fork之後調試子程序,父程序不受影響。

是以如果需要調試子程序,在啟動gdb後:

并在子程序代碼設定斷點。

此外還有detach-on-fork參數,訓示GDB在fork之後是否斷開(detach)某個程序的調試,或者都交由GDB控制:

<code>set detach-on-fork [on|off]</code>

on: 斷開調試follow-fork-mode指定的程序。

off: gdb将控制父程序和子程序。follow-fork-mode指定的程序将被調試,另一個程序置于暫停(suspended)狀态。

注意,最好使用GDB 6.6或以上版本,如果你使用的是GDB6.4,就隻有follow-fork-mode模式。

follow-fork-mode/detach-on-fork的使用還是比較簡單的,但由于其系統核心/gdb版本限制,我們隻能在符合要求的系統上才能使用。而且,由于follow-fork-mode的調試必然是從父程序開始的,對于fork多次,以至于出現孫程序或曾孫程序的系統,例如上圖3程序系統,調試起來并不友善。

<a><b>Attach子程序</b></a>

衆所周知,GDB有附着(attach)到正在運作的程序的功能,即attach &lt;pid&gt;指令。是以我們可以利用該指令attach到子程序然後進行調試。

例如我們要調試某個程序RIM_Oracle_Agent.9i,首先得到該程序的pid

通過pstree可以看到,這是一個三程序系統,oserv是RIM_Oracle_prog的父程序,RIM_Oracle_prog又是RIM_Oracle_Agent.9i的父程序。

[轉]使用GDB 調試多程式程式

現在就可以調試了。一個新的問題是,子程序一直在運作,attach上去後都不知道運作到哪裡了。有沒有辦法解決呢?

一個辦法是,在要調試的子程序初始代碼中,比如main函數開始處,加入一段特殊代碼,使子程序在某個條件成立時便循環睡眠等待,attach到程序後在該代碼段後設上斷點,再把成立的條件取消,使代碼可以繼續執行下去。

至于這段代碼所采用的條件,看你的偏好了。比如我們可以檢查一個指定的環境變量的值,或者檢查一個特定的檔案存不存在。以檔案為例,其形式可以如下:

當attach到程序後,在該段代碼之後設上斷點,再把該檔案删除就OK了。當然你也可以采用其他的條件或形式,隻要這個條件可以設定/檢測即可。

Attach程序方法還是很友善的,它能夠應付各種各樣複雜的程序系統,比如孫子/曾孫程序,比如守護程序(daemon process),唯一需要的就是加入一小段代碼。

<a><b>GDB wrapper</b></a>

很多時候,父程序 fork 出子程序,子程序會緊接着調用 exec族函數來執行新的代碼。對于這種情況,我們也可以使用gdb wrapper 方法。它的優點是不用添加額外代碼。

其基本原理是以gdb調用待執行代碼作為一個新的整體來被exec函數執行,使得待執行代碼始終處于gdb的控制中,這樣我們自然能夠調試該子程序代碼。

還是上面那個例子,RIM_Oracle_prog fork出子程序後将緊接着執行RIM_Oracle_Agent.9i的二進制代碼檔案。我們将該檔案重命名為RIM_Oracle_Agent.9i.binary,并建立一個名為RIM_Oracle_Agent.9i的shell腳本檔案,其内容如下:

當fork的子程序執行名為RIM_Oracle_Agent.9i的檔案時,gdb會被首先啟動,使得要調試的代碼處于gdb控制之下。

新的問題來了。子程序是在gdb的控制下了,但還是不能調試:如何與gdb互動呢?我們必須以某種方式啟動gdb,以便能在某個視窗/終端與gdb互動。具體來說,可以使用xterm生成這個視窗。

xterm是X window系統下的模拟終端程式。比如我們在Linux桌面環境GNOME中敲入xterm指令:

[轉]使用GDB 調試多程式程式

Vncserver是一個Perl腳本,用來啟動Xvnc(X VNC server)。X client應用,比如xterm,VNC viewer都是和它通信的。如上所示,我們可以使用的DISPLAY值為tivf09:1。現在就可以從本地機器使用VNC viewer連接配接過去:

[轉]使用GDB 調試多程式程式

如果你的程式在exec的時候還傳入了參數,可以改成:

最後加上執行權限

現在就可以調試了。運作啟動子程序的程式:

程式停住了。從VNC viewer中可以看到,一個新的gdb xterm視窗在伺服器端打開了

<a><b>gdb xterm 視窗</b></a>

[轉]使用GDB 調試多程式程式

運作的正是要調試的程式。設定好斷點,開始調試吧!

注意,下面的錯誤一般是權限的問題,使用 xhost 指令來修改權限:

<a><b>xterm 錯誤</b></a>

[轉]使用GDB 調試多程式程式

xhost + 禁止了通路控制,從任何機器都可以連接配接過來。考慮到安全問題,你也可以使用xhost + &lt;你的機器名&gt;。

<a><b>小結</b></a>

上述三種方法各有特點和優劣,是以适應于不同的場合和環境:

follow-fork-mode方法:友善易用,對系統核心和GDB版本有限制,适合于較為簡單的多程序系統

attach子程序方法:靈活強大,但需要添加額外代碼,适合于各種複雜情況,特别是守護程序

GDB wrapper方法:專用于fork+exec模式,不用添加額外代碼,但需要X環境支援(xterm/VNC)。

<a>參考資料</a>

本文轉自feisky部落格園部落格,原文連結:http://www.cnblogs.com/feisky/archive/2010/03/11/1683761.html,如需轉載請自行聯系原作者

繼續閱讀