學習GDB(一)

1、停下來環顧程序程序員

一、暫停機制正則表達式

     三種方法能夠通知GDB暫停程序的執行:express

     - 斷點:通知GDB在特定位置暫停執行。sass

     - 監視點:通知GDB當特定內存(或者涉及一個或多個位置的表達式)的值發生變化時暫停執行。函數

     - 捕獲點:通知GDB當特定事件發生時暫停執行。優化

     GDB文檔中把這三種機制所有認爲是斷點,而delete命令也是刪除所有這三種類型。ui

二、暫停概述spa

     在程序特定「位置」設置斷點,到那一點時,調試器會暫停程序執行。GDB中的「位置」含義很是靈活,它能夠是各類源代碼行、代碼地址、源代碼文件中的行號或者函數入口等。線程

     GDB中設置斷點的那一行是將要執行的下一行源代碼(能夠認爲GDB在源代碼的斷點行和前一行之間等待)。調試

     GDB的工做針對的是機器語言指令,而不是源代碼行,一行代碼可能對應於數行機器語言。GDB之因此能夠在源代碼行工做,是由於可執行文件中包括了額外的信息。

三、斷點跟蹤

     程序員建立的每個斷點(包括三種類型)都被標識爲從1開始的惟一整數標識符。這個標識符用來執行該斷點上的各類操做。調試器還有列出全部斷點及其屬性的方式。

     建立斷點:break  行號/函數名  ;

     GDB會告知你分配給該斷點的編號。

     查看斷點編號:info  breakpionts  ;

     刪除斷點: delete  編號  ;

四、設置斷點

     GDB指定斷點的方式:

     -break  function  ;在函數function()的入口(第一行可執行代碼)處設置斷點。

     -break  line_number  ;在當前活動源代碼文件的line_number處設置斷點。

     -break  filename:line_number  ;在源代碼文件filename的line_number處設置斷點,若是filename不在當前工做目錄中,則可給出相對路徑名或徹底路徑名來幫助GDB查找該文件。

     -break  filename:function  ;在文件filename中的函數function()的入口處設置斷點。

      在某個函數上設置斷點.當使用容許函數重載的語言(如:C++,若是使用static限定符聲明帶文件做用域,C語言中也能夠有重載函數)時,有可能同時在幾個重載的函數上設置了斷點;

      比 如:CLogManager類有三個重載的成員函數insert(const struct log_mo_simple&)、insert(const struct log_mt_simple&)、 insert(const struct log_st_simple&)

      設置斷點: break CLogManager::insert

      執行該命令以後,gdb會找到實現CLogManager類的源文件,而後在這三個重載的成員函數上都設置一個斷點;

      要沒有歧義,能夠經過如在源代碼行號設置斷點等方法。

     -tbreak  filename:function/line_number  ;臨時斷點設置,即首次到達後就會被自動刪除的斷點。

     -break  +offset/-offset  ;在當前選中棧幀中正在執行的源代碼行前面或後面設置斷點偏移行數。

     -break  *address  ;在虛擬內存地址處設置斷點。這對於程序沒有調試信息的部分(好比當源代碼不可用時,或者對於共享庫)是必須的。    

     GDB實際設置斷點的位置可能與請求斷點的位置不一樣,如:

int main(void)
{
  int i;
  i = 3;
  
  return 0;
}

     不加優化的編譯這個程序,並嘗試在main()的入口處設置斷點。覺得會放在第一行,而實際放在第四行。

     一個緣由是這一行是可執行代碼。GDB實際使用的是機器語言指令工做,有了加強的符號表後,會產生一種GDB使用源代碼行的錯覺。實際上,聲明i確實會產生機器碼,但GDB認爲這對於咱們的代碼調試沒用,因此直接在第四行設置斷點。

     其餘斷點類型

     -hbreak  ;設置硬件輔助斷點,能夠在內存中設置斷點,不須要修改該內存位置的內容。須要硬件支持,主要用於EEPROM/ROM調試。臨時斷點設置爲:-thbreak。

     -rbreak  ;採用grep風格的正則表達式,並在匹配該正則表達式的任何函數入口處設置斷點。

     優化編譯程序後,斷點設置更不明確,GDB扮演了一個更主動的角色,這是在調試完前永遠不該當優化代碼的緣由之一。

     在同一行設置多個斷點,GDB只會中斷一次。在具備多個斷點的代碼行上,觸發中斷的斷點將是編號最小的斷點。

     捕獲點

     -catch  ;設置捕獲點,這相似於斷點,但能經過如拋出異常、捕獲異常、發信號通知、調用fork()、加載和卸載庫以及其餘不少事件觸發。

五、展開GDB示例

    在任什麼時候間點上,GDB都有一個焦點,能夠將它看做當前「活動」文件。這意味着除非對命令作了限定,不然都是在GDB的焦點文件上執行命令。下面動做會使焦點會轉移到不一樣文件上;

     -向不一樣的源文件應用list命令。

     -進入位於不一樣的源代碼文件中的代碼。

     -當在不一樣源代碼文件中執行代碼時GDB遇到斷點。

    離開GDB的命令是:-quit  ;

六、斷點的持久性

     不用在修改和從新編譯代碼時退出GDB,由於這樣作很繁瑣,還會從新進入斷點。當不退出GDB修改編譯時,執行run命令,GDB會感知到代碼已修改,並自動從新加載新版本。

     修改代碼後,代碼會動,而斷點自己不會動。便可能會在那一行不包括原來其上設置斷點的語句。所以,須要經過刪除這個斷點並從新設置一個新的來移動斷點。

     保存斷點的方法是把斷點儲存在源代碼所在目錄(或者從中調用GDB的目錄)的.gdbinit啓動文件中。

七、在GDB中刪除斷點

     -delete  breakpoint-list  ;刪除斷點使用數值標識符。能夠是個數字,如delete 2;也能夠是一個數字列表,如:delete 2 4 6;

     -delete  ;刪除全部斷點。在.gdbinit啓動腳本文件中設置:set confirm off,可關閉GDB要確認刪除操做。

     -clear  ;清除GDB將要執行的下一個指令處的斷點。適用於要刪除GDB已經到達的斷點的狀況。

     -clear   function 、clear  filename:function、clear line_number和clear filename:line_number  ;根據具體位置清楚斷點,與break相似。

八、在GDB中禁用斷點

     要保留斷點以便之後使用,暫時又不但願GDB中止執行,就能夠禁用它們。

     -disable  breakpoint-list  ;禁用斷點。不帶參數則禁用全部斷點。

     -enable  breakpoint-list  ;啓用斷點。不帶參數則啓用全部斷點。

     -enable  once  breakpoint-list  ;使斷點下次引發GDB暫停執行後被禁用。

九、進一步瀏覽斷點的屬性

     每個斷點都有各個屬性--行號、加在斷點上的條件(若是有的話)、當前啓用/禁用狀態等。

     -info breakpoints  ;得到設置的全部斷點的清單,以及它們的屬性。詳細分析以下:

     (1)標識符(Num):斷點的惟一標識符。

     (2)類型(Typ):這個字段指出該斷點是斷點、監視點仍是捕獲點。

     (3)部署(Disp):每一個斷點都有一個部署,指示斷點下次引發GDB暫停程度的執行後該斷點上會發生什麼事情,可能的部署有如下3種:

              -保持(keep),下次到達斷點後不會改變斷點。這是新建斷點的默認部署。

              -刪除(del),下次到達斷點後刪除該斷點。使用tbreak命令建立的任何斷點都使這樣的斷點。

              -禁用(dis),下次到達斷點時會禁用該斷點。這是使用enable once命令設置的斷點。

     (4)啓用狀態(Enb):這個字段說明斷點當前是啓用仍是禁用。

     (5)地址(Address):這是內存中設置斷點的位置。這主要用於彙編語言程序員,或者試圖調試沒有擴充的符號表編譯的可執行文件的人。

     (6)位置(What):各個斷點位於源代碼中的特定行上。What字段顯示了斷點所在位置的行號和文件名。對於監視點,這個字段點表示正在監視哪一個位置。

十、恢復執行

     -next  ;執行下一行代碼,執行函數時不會在其中暫停,而後在調用以後的第一條語句處暫停。把函數調用看作一行代碼,並在一個操做中執行整個函數,這稱爲單步越過(stepping over)函數。後面可加一個可選數值參數:

-next line_number  ;表示next執行的額外行數。

     -step  ;執行下一行代碼,執行函數時會進入其中,在其中暫停,而後在函數的第一條語句處暫停。稱爲單步進入(stepping into)函數。後面可加一個可選數值參數:-step line_number  ;表示step執行的額外行數。

     GDB不會在不具備調試信息的代碼(即符號表)內中止,如C庫中的printf() 。

     -continue  ;恢復GDB程序執行,直到觸發斷點或程序結束。後面可加一個可選數值參數:-continue  number  ;這個數字要求GDB忽略下面n個斷點。

     -finish  ;簡稱fin,恢復GDB程序執行,直到剛好在當前棧幀完成以前爲止。例如,不在main()函數中,finish命令會致使GDB恢復執行,直到剛好在函數返回以後爲止。finish的另外一個常見用途是當不當心單步進入本來但願單步跨過的函數時,這種狀況下,finish能夠將你正好返回到使用next會位於的位置。若是在一個遞歸函數中,finish只會將你帶到遞歸的上一層。

     -until  ;執行程序,直到到達當前循環下一個源代碼。until實際上作的是執行程序直到它到達內存地址比當前內存地址更高的機器指令,而不是直到達到源代碼中的更大的行號。disassemble p/x $pc來輸出當前位置。until命令也能夠接受源代碼中的位置做爲參數:-until  line_number、-until  function、-until  filename:line_number、-until  filename:function。

十一、條件斷點

     -break  break-args if (condition)  ;其中break-args是能夠傳遞給break以指定斷點位置的任何參數。condition是下面定義的布爾表達式。括着condition的圓括號是可選的。中斷條件也極其靈活,包括:

            -相等、邏輯和不相等運算符(<、<=、==、!=、>、>=、&&、||等)。

            -按位和移位運算符(&、|、^、>>、<<等)。

            -算術運算符(+、-、*、/、%)。

            -你本身的函數,只要它們被連接到程序中,如,

break test.c:myfunc if !check_variable_sanity(i)

            -庫函數,只要該庫被連接到代碼中,如,

break 4 if strlen(mystring) == 0

     因爲優先級的次序規則在起做用,所以可能須要使用括號將一些結構括起來,如,

(x & y) == 0

     此外,若是在GDB表達式中使用不是用調試符號編譯(幾乎確定是這種狀況)的庫函數,那麼惟一能在條件中使用的返回值類型爲int。換而言之,若是沒有調試信息,GDB會假設函數的返回值是int類型。這種假設有時候會致使曲解:

(gdb) print cos(0.0)
$1 = 14368

     然而,強制類型轉換也不行:

(gdb) print (double)cos(0.0)
$1 = 14336

     實際上,有一種能夠在GDB表達式中使用不返回int的函數,但這種方法至關神祕,技巧在於使用指向函數的恰當數據類型定義GDB方便變量。

(gdb) set $p = (double (*) (double))cos
(gdb) ptype $p
type = double(*)()
(gdb) print cos(3.1415926)
$2 = 14368
(gdb) print $p(3.1415926)
$3 = -1

     能夠對正常斷點設置條件設置條件將它們變成條件斷點。例如,若是設置了斷點3做爲無條件斷點,但如今但願加入條件i==3,只要鍵入:

(gdb)cond 3 i==3

     若是之後要刪除條件,並保持該斷點,只需鍵入:

(gdb)con 3

十二、斷點命令列表

     -commands  ;使用commands命令設置命令列表:

commands breakpoint-number
...
commands
...
end

     其中breakpoint-number是要將命令添到其上的斷點的標識符,commands是用新行分隔的任何有效GDB命令列表。逐條鍵入命令,而後鍵入end表示輸入結束。從那之後,每當GDB在這個斷點處中斷時,它都會執行你輸入的任何命令。例如,

(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent
>printf "mimiasd was passed %d.\n",n
>continue
>end

     可用GDB的define命令建立宏,這樣能夠在其餘程序或者該程序的其餘代碼行中作這樣的事,

(gdb) define mimiasd_print_and_go
Type commands for definition of "mimiasd_print_and_go".
End with a line saying just "end".
>printf $arg0,$arg1
>continue
>end

     要像上述代碼那樣使用這個宏,應鍵入:

(gdb) commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent 
>mimiasd_print_and_go "mimiasd was passed %d\n" n
>end

     注意,mimiasd_print_and_go的參數之間沒有逗號。能夠將宏保存在.gdbinit文件中以便其餘程序使用。參數最多能夠有10個。-show user能夠獲得全部宏的列表。

     實際上,任何有效的GDB表達式均可以進入命令列表。可使用庫函數,甚至本身的函數,只要它被連接到執行文件便可。可使用它們的返回值,只要它們返回的值是int類型。例如:

(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>silent
>printf "mimiasd was passed %d.\n",strlen(string)
>continue
>end

1三、監視點

     監視點是一種特殊類型的斷點,它相似於正常斷點,是要求GDB會暫停程序執行的指令。區別在於監視點沒有「住在」某一行源代碼中。取而代之的是,監視點是指示GDB每當某個表達式改變原值就暫停執行的指令。一旦變量再也不存在於調用棧的任何幀中(當包含局部變量的函數返回時),GDB會自動刪除監視點。監視點只能監視單線程的變量。

     13.1  設置監視點

     -watch  var  ;該命令會致使每當var改變值時GDB都會中斷。

     -watch  var expression  ;當變量知足表達式expression,且發生變化時GDB會中斷。

相關文章
相關標籤/搜索