青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

使用 GDB 調試 Linux 軟件

使用 GDB 調試 Linux 軟件

GNU 調試器簡介

developerWorks
文檔選項
將此頁作為電子郵件發送

將此頁作為電子郵件發送

未顯示需要 JavaScript 的文檔選項


拓展 Tomcat 應用

下載 IBM 開源 J2EE 應用服務器 WAS CE 新版本 V1.1


級別: 初級

David SeagerCICS/390 開發部,IBM Hursley

2001 年 2 月 01 日

Linux 的大部分特色源自于 shell 的 GNU 調試器,也稱作 gdb。gdb 可以讓您查看程序的內部結構、打印變量值、設置斷點,以及單步調試源代碼。它是功能極其強大的工具,適用于修復程序代碼中的問題。在本文中,David Seager 將嘗試說明 gdb 有多棒,多實用。

編譯

開始調試之前,必須用程序中的調試信息編譯要調試的程序。這樣,gdb 才能夠調試所使用的變量、代碼行和函數。如果要進行編譯,請在 gcc(或 g++)下使用額外的 '-g' 選項來編譯程序:

gcc -g eg.c -o eg





回頁首


運行 gdb

在 shell 中,可以使用 'gdb' 命令并指定程序名作為參數來運行 gdb,例如 'gdb eg';或者在 gdb 中,可以使用 file 命令來裝入要調試的程序,例如 'file eg'。這兩種方式都假設您是在包含程序的目錄中執行命令。裝入程序之后,可以用 gdb 命令 'run' 來啟動程序。





回頁首


調試會話示例

如果一切正常,程序將執行到結束,此時 gdb 將重新獲得控制。但如果有錯誤將會怎么樣?這種情況下,gdb 會獲得控制并中斷程序,從而可以讓您檢查所有事物的狀態,如果運氣好的話,可以找出原因。為了引發這種情況,我們將使用一個 示例程序:



代碼示例 eg1.c
#include
                        int wib(int no1, int no2)
                        {
                        int result, diff;
                        diff = no1 - no2;
                        result = no1 / diff;
                        return result;
                        }
                        int main(int argc, char *argv[])
                        {
                        int value, div, result, i, total;
                        value = 10;
                        div = 6;
                        total = 0;
                        for(i = 0; i < 10; i++)
                        {
                        result = wib(value, div);
                        total += result;
                        div++;
                        value--;
                        }
                        printf("%d wibed by %d equals %d\n", value, div, total);
                        return 0;
                        }
                        

這個程序將運行 10 次 for 循環,使用 'wib()" 函數計算出累積值,最后打印出結果。

在您喜歡的文本編輯器中輸入這個程序(要保持相同的行距),保存為 'eg1.c',使用 'gcc -g eg1.c -o eg1' 進行編譯,并用 'gdb eg1' 啟動 gdb。使用 'run' 運行程序可能會產生以下消息:

Program received signal SIGFPE, Arithmetic exception.
                        0x80483ea in wib (no1=8, no2=8) at eg1.c:7
                        7         result = no1 / diff;
                        (gdb)
                        

gdb 指出在程序第 7 行發生一個算術異常,通常它會打印這一行以及 wib() 函數的自變量值。要查看第 7 行前后的源代碼,請使用 'list' 命令,它通常會打印 10 行。再次輸入 'list'(或者按回車重復上一條命令)將列出程序的下 10 行。從 gdb 消息中可以看出,第 7 行中的除法運算出了錯,程序在這一行中將變量 "no1" 除以 "diff"。

要查看變量的值,使用 gdb 'print' 命令并指定變量名。輸入 'print no1' 和 'print diff',可以相應看到 "no1" 和 "diff" 的值,結果如下:

(gdb) print no1
                        $5 = 8
                        (gdb) print diff
                        $2 = 0
                        

gdb 指出 "no1" 等于 8,"diff" 等于 0。根據這些值和第 7 行中的語句,我們可以推斷出算術異常是由除數為 0 的除法運算造成的。清單顯示了第 6 行計算的變量 "diff",我們可以打印 "diff" 表達式(使用 'print no1 - no2' 命令),來重新估計這個變量。gdb 告訴我們 wib 函數的這兩個自變量都等于 8,于是我們要檢查調用 wib() 函數的 main() 函數,以查看這是在什么時候發生的。在允許程序自然終止的同時,我們使用 'continue' 命令告訴 gdb 繼續執行。

(gdb) continue
                        Continuing.
                        Program terminated with signal SIGFPE, Arithmetic exception.
                        The program no longer exists.
                        





回頁首


使用斷點

為了查看在 main() 中發生了什么情況,可以在程序代碼中的某一特定行或函數中設置斷點,這樣 gdb 會在遇到斷點時中斷執行。可以使用命令 'break main' 在進入 main() 函數時設置斷點,或者可以指定其它任何感興趣的函數名來設置斷點。然而,我們只希望在調用 wib() 函數之前中斷執行。輸入 'list main' 將打印從 main() 函數開始的源碼清單,再次按回車將顯示第 21 行上的 wib() 函數調用。要在那一行上設置斷點,只需輸入 'break 21'。gdb 將發出以下響應:

(gdb) break 21
                        Breakpoint 1 at 0x8048428: file eg1.c, line 21.
                        

以顯示它已在我們請求的行上設置了 1 號斷點。'run' 命令將從頭重新運行程序,直到 gdb 中斷為止。發生這種情況時,gdb 會生成一條消息,指出它在哪個斷點上中斷,以及程序運行到何處:

Breakpoint 1, main (argc=1, argv=0xbffff954) at eg1.c:21
                        21          result = wib(value, div);
                        

發出 'print value' 和 'print div' 將會顯示在第一次調用 wib() 時,變量分別等于 10 和 6,而 'print i' 將會顯示 0。幸好,gdb 將顯示所有局部變量的值,并使用 'info locals' 命令保存大量輸入信息。

從以上的調查中可以看出,當 "value" 和 "div" 相等時就會出現問題,因此輸入 'continue' 繼續執行,直到下一次遇到 1 號斷點。對于這次迭代,'info locals' 顯示了 value=9 和 div=7。

與其再次繼續,還不如使用 'next' 命令單步調試程序,以查看 "value" 和 "div" 是如何改變的。gdb 將響應:

(gdb) next
                        22          total += result;
                        

再按兩次回車將顯示加法和減法表達式:

(gdb)
                        23          div++;
                        (gdb)
                        24          value--;
                        

再按兩次回車將顯示第 21 行,wib() 調用。'info locals' 將顯示目前 "div" 等于 "value",這就意味著將發生問題。如果有興趣,可以使用 'step' 命令(與 'next' 形成對比,'next' 將跳過函數調用)來繼續執行 wib() 函數,以再次查看除法錯誤,然后使用 'next' 來計算 "result"。

現在已完成了調試,可以使用 'quit' 命令退出 gdb。由于程序仍在運行,這個操作會終止它,gdb 將提示您確認。





回頁首


更多斷點和觀察點

由于我們想要知道在調用 wib() 函數之前 "value" 什么時候等于 "div",因此在上一示例中我們在第 21 行中設置斷點。我們必須繼續執行兩次程序才會發生這種情況,但是只要在斷點上設置一個條件就可以使 gdb 只在 "value" 與 "div" 真正相等時暫停。要設置條件,可以在定義斷點時指定 "break <line number> if <conditional expression>"。將 eg1 再次裝入 gdb,并輸入:

(gdb) break 21 if value==div
                        Breakpoint 1 at 0x8048428: file eg1.c, line 21.
                        

如果已經在第 21 行中設置了斷點,如 1 號斷點,則可以使用 'condition' 命令來代替在斷點上設置條件:

(gdb) condition 1 value==div
                        

使用 'run' 運行 eg1.c 時,如果 "value" 等于 "div",gdb 將中斷,從而避免了在它們相等之前必須手工執行 'continue'。調試 C 程序時,斷點條件可以是任何有效的 C 表達式,一定要是程序所使用語言的任意有效表達式。條件中指定的變量必須在設置了斷點的行中,否則表達式就沒有什么意義!

使用 'condition' 命令時,如果指定斷點編號但又不指定表達式,可以將斷點設置成無條件斷點,例如,'condition 1' 就將 1 號斷點設置成無條件斷點。

要查看當前定義了什么斷點及其條件,請發出命令 'info break':

(gdb) info break
                        Num Type           Disp Enb Address    What
                        1   breakpoint     keep y   0x08048428 in main at eg1.c:21
                        stop only if value == div
                        breakpoint already hit 1 time
                        

除了所有條件和已經遇到斷點多少次之外,斷點信息還在 'Enb' 列中指定了是否啟用該斷點。可以使用命令 'disable <breakpoint number>'、'enable <breakpoint number>' 或 'delete <breakpoint number>' 來禁用、啟用和徹底刪除斷點,例如 'disable 1' 將阻止在 1 號斷點處中斷。

如果我們對 "value" 什么時候變得與 "div" 相等更感興趣,那么可以使用另一種斷點,稱作監視。當指定表達式的值改變時,監視點將中斷程序執行,但必須在表達式中所使用的變量在作用域中時設置監視點。要獲取作用域中的 "value" 和 "div",可以在 main 函數上設置斷點,然后運行程序,當遇到 main() 斷點時設置監視點。重新啟動 gdb,并裝入 eg1,然后輸入:

(gdb) break main
                        Breakpoint 1 at 0x8048402: file eg1.c, line 15.
                        (gdb) run
                        ...
                        Breakpoint 1, main (argc=1, argv=0xbffff954) at eg1.c:15
                        15        value = 10;
                        

要了解 "div" 何時更改,可以使用 'watch div',但由于要在 "div" 等于 "value" 時中斷,那么應輸入:

(gdb) watch div==value
                        Hardware watchpoint 2: div == value
                        

如果繼續執行,那么當表達式 "div==value" 的值從 0(假)變成 1(真)時,gdb 將中斷:

(gdb) continue
                        Continuing.
                        Hardware watchpoint 2: div == value
                        Old value = 0
                        New value = 1
                        main (argc=1, argv=0xbffff954) at eg1.c:19
                        19        for(i = 0; i < 10; i++)
                        

'info locals' 命令將驗證 "value" 是否確實等于 "div"(再次聲明,是 8)。

'info watch' 命令將列出已定義的監視點和斷點(此命令等價于 'info break'),而且可以使用與斷點相同的語法來啟用、禁用和刪除監視點。





回頁首


core 文件

在 gdb 下運行程序可以使俘獲錯誤變得更容易,但在調試器外運行的程序通常會中止而只留下一個 core 文件。gdb 可以裝入 core 文件,并讓您檢查程序中止之前的狀態。

在 gdb 外運行示例程序 eg1 將會導致核心信息轉儲:

$ ./eg1
                        Floating point exception (core dumped)

要使用 core 文件啟動 gdb,在 shell 中發出命令 'gdb eg1 core' 或 'gdb eg1 -c core'。gdb 將裝入 core 文件,eg1 的程序清單,顯示程序是如何終止的,并顯示非常類似于我們剛才在 gdb 下運行程序時看到的消息:

...
                        Core was generated by `./eg1'.
                        Program terminated with signal 8, Floating point exception.
                        ...
                        #0  0x80483ea in wib (no1=8, no2=8) at eg1.c:7
                        7         result = no1 / diff;
                        

此時,可以發出 'info locals'、'print'、'info args' 和 'list' 命令來查看引起除數為零的值。'info variables' 命令將打印出所有程序變量的值,但這要進行很長時間,因為 gdb 將打印 C 庫和程序代碼中的變量。為了更容易地查明在調用 wib() 的函數中發生了什么情況,可以使用 gdb 的堆棧命令。





回頁首


堆棧跟蹤

程序“調用堆棧”是當前函數之前的所有已調用函數的列表(包括當前函數)。每個函數及其變量都被分配了一個“幀”,最近調用的函數在 0 號幀中(“底部”幀)。要打印堆棧,發出命令 'bt'('backtrace' [回溯] 的縮寫):

(gdb) bt
                        #0  0x80483ea in wib (no1=8, no2=8) at eg1.c:7
                        #1  0x8048435 in main (argc=1, argv=0xbffff9c4) at eg1.c:21
                        

此結果顯示了在 main() 的第 21 行中調用了函數 wib()(只要使用 'list 21' 就能證實這一點),而且 wib() 在 0 號幀中,main() 在 1 號幀中。由于 wib() 在 0 號幀中,那么它就是執行程序時發生算術錯誤的函數。

實際上,發出 'info locals' 命令時,gdb 會打印出當前幀中的局部變量,缺省情況下,這個幀中的函數就是被中斷的函數(0 號幀)。可以使用命令 'frame' 打印當前幀。要查看 main 函數(在 1 號幀中)中的變量,可以發出 'frame 1' 切換到 1 號幀,然后發出 'info locals' 命令:

(gdb) frame 1
                        #1  0x8048435 in main (argc=1, argv=0xbffff9c4) at eg1.c:21
                        21          result = wib(value, div);
                        (gdb) info locals
                        value = 8
                        div = 8
                        result = 4
                        i = 2
                        total = 6
                        

此信息顯示了在第三次執行 "for" 循環時(i 等于 2)發生了錯誤,此時 "value" 等于 "div"。

可以通過如上所示在 'frame' 命令中明確指定號碼,或者使用 'up' 命令在堆棧中上移以及 'down' 命令在堆棧中下移來切換幀。要獲取有關幀的進一步信息,如它的地址和程序語言,可以使用命令 'info frame'。

gdb 堆棧命令可以在程序執行期間使用,也可以在 core 文件中使用,因此對于復雜的程序,可以在程序運行時跟蹤它是如何轉到函數的。





回頁首


連接到其它進程

除了調試 core 文件或程序之外,gdb 還可以連接到已經運行的進程(它的程序已經過編譯,并加入了調試信息),并中斷該進程。只需用希望 gdb 連接的進程標識替換 core 文件名就可以執行此操作。以下是一個執行循環并睡眠的 示例程序



eg2 示例代碼
#include
                        int main(int argc, char *argv[])
                        {
                        int i;
                        for(i = 0; i < 60; i++)
                        {
                        sleep(1);
                        }
                        return 0;
                        }
                        

使用 'gcc -g eg2.c -o eg2' 編譯該程序并使用 './eg2 &' 運行該程序。請留意在啟動該程序時在背景上打印的進程標識,在本例中是 1283:

./eg2 &
                        [3] 1283
                        

啟動 gdb 并指定進程標識,在我舉的這個例子中是 'gdb eg2 1283'。gdb 會查找一個叫作 "1283" 的 core 文件。如果沒有找到,那么只要進程 1283 正在運行(在本例中可能在 sleep() 中),gdb 就會連接并中斷該進程:

...
                        /home/seager/gdb/1283: No such file or directory.
                        Attaching to program: /home/seager/gdb/eg2, Pid 1283
                        ...
                        0x400a87f1 in __libc_nanosleep () from /lib/libc.so.6
                        (gdb)
                        

此時,可以發出所有常用 gdb 命令。可以使用 'backtrace' 來查看當前位置與 main() 的相對關系,以及 mian() 的幀號是什么,然后切換到 main() 所在的幀,查看已經在 "for" 循環中運行了多少次:

(gdb) backtrace
                        #0  0x400a87f1 in __libc_nanosleep () from /lib/libc.so.6
                        #1  0x400a877d in __sleep (seconds=1) at ../sysdeps/unix/sysv/linux/sleep.c:78
                        #2  0x80483ef in main (argc=1, argv=0xbffff9c4) at eg2.c:7
                        (gdb) frame 2
                        #2  0x80483ef in main (argc=1, argv=0xbffff9c4) at eg2.c:7
                        7           sleep(1);
                        (gdb) print i
                        $1 = 50
                        

如果已經完成了對程序的修改,可以 'detach' 命令繼續執行程序,或者 'kill' 命令殺死進程。還可以首先使用 'file eg2' 裝入文件,然后發出 'attach 1283' 命令連接到進程標識 1283 下的 eg2。





回頁首


其它小技巧

gdb 可以讓您通過使用 shell 命令在不退出調試環境的情況下運行 shell 命令,調用形式是 'shell [commandline]',這有助于在調試時更改源代碼。

最后,在程序運行時,可以使用 'set ' 命令修改變量的值。在 gdb 下再次運行 eg1,使用命令 'break 7 if diff==0' 在第 7 行(將在此處計算結果)設置條件斷點,然后運行程序。當 gdb 中斷執行時,可以將 "diff" 設置成非零值,使程序繼續運行直至結束:

Breakpoint 1, wib (no1=8, no2=8) at eg1.c:7
                        7         result = no1 / diff;
                        (gdb) print diff
                        $1 = 0
                        (gdb) set diff=1
                        (gdb) continue
                        Continuing.
                        0 wibed by 16 equals 10
                        Program exited normally.
                        





回頁首


結束語

GNU 調試器是所有程序員工具庫中的一個功能非常強大的工具。在本文中,我只介紹了 gdb 的一小部分功能。要了解更多知識,建議您閱讀 GNU 調試器手冊。



參考資料



關于作者

 

David Seager 是 IBM 的軟件開發人員,他從事 Linux 和基于 Web 的應用工作已有兩年時間了。

posted on 2007-04-05 10:04 zmj 閱讀(629) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久精品成人| 一本色道88久久加勒比精品 | 欧美一二三区精品| 亚洲视频在线看| 亚洲淫片在线视频| 久久国产视频网| 美女网站在线免费欧美精品| 欧美a级在线| 欧美日韩精品一区二区天天拍小说| 欧美喷水视频| 国产欧美日韩亚洲| 狠狠入ady亚洲精品经典电影| 亚洲欧美日本伦理| 欧美日韩国产经典色站一区二区三区 | 亚洲欧洲日本国产| 亚洲国产精品一区二区尤物区| 亚洲人久久久| 性欧美暴力猛交另类hd| 女人天堂亚洲aⅴ在线观看| 亚洲黄色成人网| 亚洲国产精品www| 一区二区三区高清视频在线观看| 欧美一区二区在线免费播放| 欧美电影免费| 国产一区二区三区无遮挡| 亚洲日韩视频| 久久久久久久一区| 亚洲精品专区| 久久深夜福利| 国产欧美一区二区三区在线老狼| 亚洲精选成人| 另类天堂av| 亚洲深夜福利视频| 久久午夜激情| 国产人成一区二区三区影院| 99国产精品久久久久久久| 久久精品日产第一区二区三区| 亚洲老板91色精品久久| 麻豆精品视频在线| 国产精品一区二区在线观看不卡| 亚洲国产成人一区| 久久精品系列| 亚洲欧美激情视频| 欧美日韩亚洲一区| 最新亚洲视频| 欧美激情一区二区三区成人| 久久福利资源站| 国产午夜精品一区理论片飘花 | 浪潮色综合久久天堂| 亚洲精品免费在线| 欧美ed2k| 亚洲精品美女久久久久| 欧美成人a视频| 久久久久久久久久久成人| 国产欧美不卡| 久久精品成人一区二区三区| 亚洲综合日韩在线| 国产精品久久久久久久久动漫| 一区二区日韩免费看| 亚洲黄色成人久久久| 欧美国产丝袜视频| 99国产精品久久久久老师| 亚洲国产精品一区制服丝袜 | 蜜臀av国产精品久久久久| 一区二区三区四区蜜桃| 欧美日本免费| 国产精品99久久久久久久久| 日韩天堂在线观看| 欧美日韩在线观看一区二区| 亚洲午夜视频在线| 夜夜嗨av色一区二区不卡| 欧美午夜在线一二页| 亚洲欧美一区二区三区久久| 亚洲欧美春色| 精品动漫3d一区二区三区免费版 | 在线午夜精品| 亚洲视频视频在线| 国产一区二区三区免费观看| 久久一二三区| 欧美国产精品劲爆| 亚洲午夜电影网| 香蕉久久精品日日躁夜夜躁| 一区二区在线观看视频| 亚洲国产精品va在线看黑人动漫| 欧美日韩一区二区三区高清| 欧美一区二区三区四区在线观看 | 免费不卡视频| 99re6这里只有精品视频在线观看| 99精品福利视频| 国产精品乱人伦一区二区| 久久人人九九| 欧美日本一区二区高清播放视频| 午夜精品亚洲一区二区三区嫩草| 久久riav二区三区| 亚洲二区在线观看| 一区二区三区视频在线观看| 国产一区二区中文字幕免费看| 欧美黄色免费网站| 国产精品免费一区豆花| 欧美岛国激情| 国产精品乱码一区二区三区 | 亚洲乱码国产乱码精品精天堂| 国产精品一区二区在线| 亚洲成人在线视频网站| 欧美3dxxxxhd| 欧美日韩国产综合视频在线观看| 欧美亚洲免费在线| 欧美成人精品| 久久久久欧美精品| 欧美日韩亚洲国产精品| 欧美a级片网站| 国产九区一区在线| 亚洲免费高清视频| 亚洲激情一区| 久久久国产成人精品| 亚洲专区在线| 欧美成人免费在线观看| 麻豆精品视频| 国产一区在线免费观看| 中文欧美在线视频| 久久国产精品亚洲va麻豆| 亚洲精品偷拍| 亚洲高清三级视频| 久久aⅴ国产紧身牛仔裤| 亚洲尤物影院| 欧美日韩亚洲一区二区三区| 欧美黑人在线播放| 在线日韩日本国产亚洲| 欧美一区国产在线| 欧美自拍偷拍午夜视频| 国产精品久久久久久户外露出| 91久久国产综合久久| 亚洲激情网址| 欧美成人国产| 亚洲人成网站999久久久综合| 亚洲全部视频| 欧美国产日韩一二三区| 91久久久国产精品| 亚洲九九九在线观看| 欧美精品手机在线| 亚洲三级电影全部在线观看高清| 日韩视频中午一区| 欧美日韩成人一区二区三区| 91久久在线播放| 日韩午夜精品视频| 欧美日韩精品一二三区| 一区二区三区高清视频在线观看 | 亚洲欧洲一区| 欧美日韩国产色视频| 日韩亚洲精品在线| 亚洲网站在线播放| 国产精品porn| 欧美伊人久久久久久午夜久久久久| 久久亚洲视频| 亚洲免费观看高清在线观看 | 激情综合色综合久久综合| 久久精品国产清高在天天线| 欧美ab在线视频| 99精品热视频只有精品10| 欧美日韩一区二区国产| 午夜精品成人在线视频| 久久综合久久久| 99精品视频免费观看| 国产精品你懂的在线| 久久精品一区二区三区中文字幕| 欧美激情在线狂野欧美精品| 日韩一级黄色大片| 国产乱人伦精品一区二区 | 女人香蕉久久**毛片精品| 亚洲精品综合| 国产欧美一区二区白浆黑人| 麻豆视频一区二区| 一区二区三区精品| 久久久精品国产免费观看同学| 亚洲激情视频网| 国产精品一二三四区| 欧美a级片网站| 亚洲欧美激情视频在线观看一区二区三区| 蜜臀a∨国产成人精品| 亚洲免费在线播放| 亚洲国产精彩中文乱码av在线播放 | 亚洲视频久久| 久久综合狠狠综合久久综青草| 一本一本久久a久久精品牛牛影视| 国产精品美女主播| 美女精品自拍一二三四| 亚洲欧美国产毛片在线| 亚洲精品黄色| 欧美不卡视频一区发布| 久久av老司机精品网站导航| 亚洲美女少妇无套啪啪呻吟| 国产日韩精品一区二区浪潮av| 欧美激情视频给我| 久久久蜜桃一区二区人| 性感少妇一区| 亚洲男人第一av网站| 在线亚洲一区| 一本色道久久88亚洲综合88| 亚洲国产天堂久久综合| 免费一级欧美片在线观看|