在了解GDB可以做什么,怎么做之前,讓我們先來看看為什么要用GDB,或者說對調試工具有什么期望。
一般我們使用GDB(或其他調試工具)是為了發現程序bug,更經常地是在已知程序有錯的情況下定位bug。既然這樣,我們就需要跟蹤程序的執行情況,查看程序執行是否正常,當然這就需要有個讓我們與執行程序交互的環境,調試工具提供一個能讓程序在你的掌控下執行,并讓你能夠查看一些執行過程中的“內幕信息”的環境。
為了查看程序運行過程中的狀態,我們就希望程序能在適當的位置或者在一定的條件下能夠暫停運行;為此,調試工具提供了斷點、查看變量/表達式、顯示程序棧等功能??戳四硞€點的“內幕”后,我們還期望更多,所以要能控制程序運行才行,這就要求斷點、繼續運行、單步(多步)運行、進入函數運行等功能,在某些情況下,還需要通過修改當前的執行環境(變量等)來達到期望的執行順序。也就是說,光看著是不夠的,還需要能改才行。
一、引言 | |
在了解GDB可以做什么,怎么做之前,讓我們先來看看為什么要用GDB,或者說對調試工具有什么期望。 一般我們使用GDB(或其他調試工具)是為了發現程序bug,更經常地是在已知程序有錯的情況下定位bug。既然這樣,我們就需要跟蹤程序的執行情況,查看程序執行是否正常,當然這就需要有個讓我們與執行程序交互的環境,調試工具提供一個能讓程序在你的掌控下執行,并讓你能夠查看一些執行過程中的“內幕信息”的環境。 為了查看程序運行過程中的狀態,我們就希望程序能在適當的位置或者在一定的條件下能夠暫停運行;為此,調試工具提供了斷點、查看變量/表達式、顯示程序棧等功能??戳四硞€點的“內幕”后,我們還期望更多,所以要能控制程序運行才行,這就要求斷點、繼續運行、單步(多步)運行、進入函數運行等功能,在某些情況下,還需要通過修改當前的執行環境(變量等)來達到期望的執行順序。也就是說,光看著是不夠的,還需要能改才行。 理解了這些問題后,我們就明白GDB的各個功能的用意了,自然也就明白該如何使用調試工具了。當然,要讓GDB有效的發揮作用,還是需要一定的經驗與技巧,而這主要靠實踐,學習資料(包括本文)充其量只能幫你一把(小心別讓它幫倒忙)。 總而言之,我們首先要明白使用調試工具的目的和用意,才能理解它的各項功能,才能借助它快速有效的發現問題;否則,即使工具再強大,你也不知道該如何使用才好。 | |
二、GDB能做什么 | |
GDB可以用來調試C、C++、Modula-2的程序。一般來說,GDB能做的事大致可以分為四類: 1、啟動程序,按指定的方式執行程序。 | |
三、GDB使用概述 | |
首先要了解的是gdb的help命令,因為你可能記不住各個命令的語法和用途,但只要能正確使用help命令,你就不需要任何其它的gdb資料。 啟動gdb后,輸入help [eric@linux eric]$ gdb aliases -- Aliases of other commands Type "help" followed by a class name for a list of commands in that class.
為調試編譯代碼 為了使 gdb 正常工作, 你必須使你的程序在編譯時包含調試信息. 調試信息包含你程序里的每個變量的類型和在可執行文件里的地址映射以及源代碼的行號. gdb 利用這些信息使源代碼和機器碼相關聯. 在GDB中運行程序 當以gdb <program>方式啟動gdb后,可以使用r或是run命令運行程序。在程序運行之前,你有可能需要設置下面四方面的事。 1、程序運行參數。 2、運行環境。 3、工作目錄。 4、程序的輸入輸出。
可以有兩種方法調試已運行程序: 暫停/恢復程序運行 你可以使用info program 來查看程序的當前的執行狀態。 在gdb中,我們可以有以下幾種暫停方式:斷點(BreakPoint)、觀察點(WatchPoint)、捕捉點(CatchPoint)、信號(Signals)、線程停止(Thread Stops)。如果要恢復程序運行,可以使用c或是continue命令。 查看變量/表達式的值 可以使用print expr(或p expr)來查看程序變量/表達式的值 顯示程序棧 可以使用backtrace(或bt)來顯示程序棧 單步跟蹤 next [n] 執行下一條(或n條)語句,不進入子程序 step [n] 執行下一條(或n條)語句,進入子程序,可用finish從子程序返回
| |
四、GDB常用命令 | |
backtrace 顯示程序中的當前位置和表示如何到達當前位置的棧跟蹤(同義詞:where) 命令的具體使用方法請用上面介紹的help查詢,看不明白的地方就多試試。 | |
五、用例子說話 | |
本文是打算寫個簡單的程序作為例子講解的,后來一想:“太假”,就講一個前幾天我的實際調試經歷吧,因為當時沒抓圖,這里就用文字描述了,請讀者注意其中的思路和方法,具體的一些操作就要勞煩自己去實踐了 背景:在將一個linux程序(姑且就叫A吧)重redhat 9.0移植到redhat es時發現程序core了 開始了,呵呵: 1、首先我查看了程序日志,找到引起程序core掉的數據(一個網頁);//所以說日志很重要 2、下載了那個網頁,用它作為輸入,結果必core;//確認出錯環境 3、用gdb啟動程序,然后觸發錯誤后,用bt查看程序棧,記錄棧中的函數調用鏈以及出錯的代碼行數 4、在用gdb啟動程序,在出錯行前設斷點,運行之,再觸發錯誤 5、使用next和step精確定位到出錯行 6、print一個指針變量,發現不是NULL,再看指針所指結構的各個變量也正常 7、好像沒錯呀,呵呵,此處是個循環,繼續單步便重復6 8、發現循環中指針遞減,懷疑指針所指數組越界,打印數組起始位置地址 9、繼續循環一直到出錯,打印指針變量,發現其指向的地址低于數組起始位置地址,真的越界了 10、初步算是找到了,查看程序源碼,發現循環中沒有判斷該指針是否低于數組起始位置地址 11、修改代碼后重新運行,程序不core了 12、將新程序放到正常執行環境下工作,長時間運行后沒有發現該問題重現,確認解決問題 13、通知出錯部分(一個功能函數庫)的作者問題找到、原因 注:為簡單起見省略了過程中的一些因系統特殊性引起的工作 |