GDB跟蹤調試

GDB 調試

要進行調試程序首先要生成一個含有調試信息的執行程序命令如下:

  • gcc(g++) -g -o 文件名 源文件.c(源文件.cpp)
  • gcc(g++) -ggdb3 -o 文件名 源文件.c(源文件.cpp)

此時便會生成一個含有調試信息的可執行文件,然後便可以用 gdb 去調試這個程序了,進入調試程序命令,但是如果用 gdb 去調試一個未包含調試信息的可執行文件則會發生錯誤

  • gdb 執行文件名(含調試信息)

運行 GDB

運行 gdb

  • gdb <program> -- program也就是你的執行文件,一般在當然目錄下.
  • gdb <program> core -- 用 gdb 同時調試一個運行程序和 core 文件,core 是程序非法執行後 core dump 後產生的文件.
  • gdb <program> <PID> -- 調試正在運行的程序. program 爲需要調試的程序文件, PID 爲當前正在運行的程序.或是先用 gdb <program> 關聯上源代碼進入 gdb,後用 attach 命令來掛接進程的 PID.並用 detach 來取消掛接的進程

gdb 啓動常用的參數

  • 從指定文件中讀取符號表
    • -symbols <file>
    • -s <file>
  • 從指定文件中讀取符號表信息,並把他用在可執行文件中
    • -se file
  • 調試時 core dump 的 core 文件
    • -core <file>
    • -c <file>
  • 加入一個源文件的搜索路徑.默認搜索路徑是環境變量中 PATH 所定義的路徑
    • -directory <directory>
    • -d <directory>
  • 設置啓動時候參數
    • --args arglist

gdb 幫助文檔

  • help -- 查看 gdb 的命令種類
  • help <CmdType> -- 查看 CmdType 種類的 gdb 命令
  • apropos <keyWord> -- 查看關鍵字 keyWord 的相關命令
  • info <keyWord> -- 查看關鍵字 keyWord 調試信息
  • show <keyWord> -- 查看關鍵字 keyWord gdb 本身設置信息

gdb 中運行 unix 的 shell 程序

  • shell <command string> -- 調用 unix 的 shell 來執行 <command string>,環境變量 shell 中定義的 unix 的 shell 將會被用來執行 <command string>,如果 shell 沒有定義,那就使用 unix 的標準 shell:/bin/sh.(在 windows 中使用 command.com 或 cmd.exe)
  • make <make-args> -- 等價於 “shell make <make-args>”

歷史記錄

  • 當你用 gdb 的 print 查看程序運行時的數據時,你每一個 print 都會被 gdb 記錄下來.gdb 會以 $1, $2, $3 ...這樣的方式爲你每一個 print 命令編上號.於是,你可以使用這個編號訪問以前的表達式,如 $1.這個功能所帶來的好處是,如果你先前輸入了一個比較長的表達式,如果你還想查看這個表達式的值,你可以使用歷史記錄來訪問,省去了重複輸入.

啓動程序

  • run <arg ...> -- 啓動程序,<arg ...> 爲程序運行時候需要輸入的參數.也可用 set args 命令去設置運行參數.簡寫爲 r

GDB 環境設置

gdb 設置

  • 設置顯示選項
    • 地址
      • set print address <on/off> -- 打開地址輸出,當程序顯示函數信息時,gdb會顯出函數的參數地址.系統默認爲打開.
      • show print address -- 查看 print address 選項信息
    • 數組元素單獨行顯示
      • set print array <on/off> -- 打開時數組顯示時,每個元素佔一行,如果不打開的話,每個元素則以逗號分隔.這個選項默認是關閉的.
      • show print array -- 查看 print array 選項信息
    • 顯示數組元素顯示
      • set print elements <number-of-elements> -- 設置數組的顯示的最大長度,設置爲 0,則表示不限制.
      • show print elements -- 查看 print elements 選項信息.
    • 設置字符串顯示
      • set print null-stop <on/off> -- 如果打開那麼當顯示字符串時,遇到結束符則停止顯示.這個選項默認爲 off.
      • show print null-stop -- 查看 print null-stop 選項信息
    • 設置結構體變量顯示
      • set print pretty <on/off> -- 結構體優雅顯示
      • show print pretty -- 查看 gdb 是如何顯示結構體的.
    • 設置字符顯示
      • set print sevenbit-strings <on/off> -- 符顯示,是否按“/nnn”的格式顯示,如果打開,則字符串或字符數據按/nnn顯示,如“/065”.
      • show print sevenbit-strings -- 查看字符顯示開關是否打開.
    • 設置聯合體顯示
      • set print union <on/off> -- 設置顯示結構體時,是否顯式其內的聯合體數據.
      • show print union -- 查看聯合體數據的顯示方式
    • 設置對象顯示
      • set print object <on/off> -- 在 C++ 中,如果一個對象指針指向其派生類,如果打開這個選項,gdb 會自動按照虛方法調用的規則顯示輸出,如果關閉這個選項的話,gdb 就不管虛函數表了.這個選項默認是 off.
      • show print object -- 查看對象選項的設置.
    • 設置靜態成員顯示
      • set print static-members <on/off> -- 這個選項表示,當顯示一個 C++ 對象中的內容是,是否顯示其中的靜態數據成員.默認是 on.
      • show print static-members -- 查看靜態數據成員選項設置.
    • 設置虛函數表顯示
      • set print vtbl <on/off> -- 當此選項打開時,gdb 將用比較規整的格式來顯示虛函數表時.其默認是關閉的.
      • show print vtbl -- 查看虛函數顯示格式的選項.
  • 設置運行程序的相關環境及其參數
    • 指定源文件的路徑
      • directory <dirname ... > -- 加一個源文件路徑到當前路徑的前面.如果你要指定多個路徑,UNIX 下你可以使用“:”,Windows 下你可以使用“;”.縮寫 dir
      • directory -- 清除所有的自定義的源文件搜索路徑信息.
      • show directories -- 顯示定義了的源文件搜索路徑.
    • 運行參數
      • set args -- 可指定運行時參數
      • show args -- 命令可以查看設置好的運行參數
    • 運行環境
      • path <dir> -- 可設定程序的運行路徑
      • show paths -- 查看程序的運行路徑
      • set environment varname=value -- 設置環境變量
      • show environment [varname] -- 查看環境變量
    • 工作目錄
      • cd <dir> -- 相當於shell的cd命令
      • pwd -- 顯示當前的所在目錄
    • 程序的輸入輸出
      • info terminal -- 顯示你程序用到的終端的模式
      • tty -- 命令可以指寫輸入輸出的終端設備
      • 重定向控制程序輸出
    • 堆棧幀設置
      • set backtrace <limit> -- 設置堆棧幀的最大顯示數量,默認是沒有限制
    • 調試模式
      • set step-mode [on | off] -- step-mode 模式,於是,在進行單步跟蹤時,程序不會因爲沒有debug信息而不停住.這個參數有很利於查看機器碼. 

GDB 源碼查看

顯示源代碼

  • list <linenum> -- 顯示程序第 linenum 行的周圍的源程序.
  • list <function> -- 顯示函數名爲 function 的函數的源程序.
  • list <filename:linenum> -- 哪個文件的哪一行.
  • list <filename:function> -- 哪個文件中的哪個函數.
  • list <offset> -- 當前行號的正/負 offset 偏移量那那行.
  • list -- 顯示當前行後面的源程序.
  • list - -- 顯示當前行前面的源程序.
  • list <first>, <last> -- 顯示從 first 行到 last 行之間的源代碼.若無 first 則顯示從當前行到 last 之間的源代碼.

設置和獲得顯示源碼的行數

  • set listsize <count> -- 設置一次顯示源代碼的行數.
  • show listsize -- 查看當前listsize的設置.

搜索源代碼

  • forward-search <regexp> -- 向後面搜索.正則表達式爲 regexp 的關鍵字
  • search <regexp> -- 向後面搜索.正則表達式爲 regexp 的關鍵字
  • reverse-search <regexp> -- 向前面搜索.正則表達式爲 regexp 的關鍵字

源代碼的內存

  • info line <linenum> -- 查看行號爲 linenum 源代碼在內存中的地址.
  • info line <function> -- 查看函數在源代碼在內存中的地址.
  • info line <filename:linenum> -- 查看 filename 文件的第 linenum 行源代碼在內存中的地址.
  • info line <filename:function> -- 查看 filename 文件的 function 函數在源代碼在內存中的地址.

查看彙編代碼

  • disassemble -- 查看源程序的當前執行時的機器碼,這個命令會把目前內存中的指令 dump 出來.

GDB 停止點設置及維護

斷點(BreakPoint)

  • 設置斷點:(threadno 指定了線程的 ID,注意,這個 ID 是 gdb 分配的,可以通過 "info threads" 命令來查看正在運行程序中的線程信息)
    • break thread <threadno> -- break命令沒有參數時,表示在下一條指令處停住.
    • break +offset thread <threadno> -- 在當前行號的後面的 offset 行停住.(offiset 爲自然數)
    • break -offset thread <threadno> -- 在當前行號的前面的 offset 行停住.(offiset 爲自然數)
    • break <linenum> thread <threadno> -- 在指定行號停住.
    • break filename:linenum thread <threadno> -- 在源文件filename的linenum行處停住.
    • break <function> thread <threadno> -- 在進入指定函數時停住.
    • break filename:function thread <threadno> --在源文件filename的function函數的入口處停住.
    • break *address -- 在程序運行的內存地址處停住.
    • break ... thread <threadno> if <condition> -- ...可以是上述的參數,condition表示條件,在條件成立時停住.比如在循環境體中,可以設置break if i=100,表示當i爲100時停住程序.
    • tbreak -- 設置只停止一次的斷點.用法和 break 類似
  • 查看斷點
    • info breakpoints [n]
    • info break [n]

觀察點(WatchPoint) -- 觀察點一般來觀察某個表達式(變量也是一種表達式)的值是否有變化了,如果有變化,馬上停住程序.

  • 設在觀察點
    • watch <expr> -- 爲表達式(變量)expr設置一個觀察點.一量表達式值有變化時,馬上停住程序.
    • rwatch <expr> -- 當表達式(變量)expr被讀時,停住程序.
    • awatch <expr> -- 當表達式(變量)的值被讀或被寫時,停住程序.
  • 查看觀察點
    • info watchpoints -- 列出當前所設置了的所有觀察點.

捕捉點(CatchPoint) -- 設置捕捉點來補捉程序運行時的一些事件.如:載入共享庫(動態鏈接庫)或是 C++ 的異常《/p>

  • 設置捕捉點
    • catch <event> -- 當event發生時,停住程序.event可以是下面的內容:
      • throw 一個 C++ 拋出的異常.(throw 爲關鍵字)
      • catch 一個 C++ 捕捉到的異常.(catch 爲關鍵字)
      • exec 調用系統調用 exec 時.(exec 爲關鍵字,目前此功能只在 HP-UX 下有用)
      • fork 調用系統調用 fork 時.(fork 爲關鍵字,目前此功能只在 HP-UX 下有用)
      • vfork 調用系統調用 vfork 時.(vfork 爲關鍵字,目前此功能只在 HP-UX 下有用)
      • load 或 load <libname> 載入共享庫(動態鏈接庫)時.(load 爲關鍵字,目前此功能只在 HP-UX 下有用)
      • unload 或 unload <libname> 卸載共享庫(動態鏈接庫)時.(unload 爲關鍵字,目前此功能只在 HP-UX 下有用)
    • tcatch <event> -- 只設置一次捕捉點,當程序停住以後,應點被自動刪除.

維護停止點

  • 清除停止點
    • clear -- 所有的已定義的停止點.
    • clear <function> -- 清除所有設置在函數上的停止點.
    • clear <filename:function> -- 清除所有設置在函數上的停止點.
    • clear <linenum> -- 清除所有設置在指定行上的停止點.
    • clear <filename:linenum> -- 清除所有設置在指定行上的停止點.
  • 刪除停止點
    • delete [range] -- 刪除停止點.其簡寫命令爲 d.
  • 禁用停止點
    • disable [range] -- 禁用停止點
  • 啓用停止點
    • enable [range] -- 啓用停止點.
    • enable once [rang] -- 啓用停止點一次,當程序停止後,該停止點馬上被 gdb 自動 disable.
    • enable count [rang] -- 啓用停止點 count 次,當程序停止後,該停止點馬上被 gdb 自動 disable.
    • enable delete [rang] -- 啓用停止點一次,當程序停止後,該停止點馬上被 gdb 自動刪除.
  • 停止條件維護 -- 以用 condition 命令來修改斷點的條件.(只有break和watch命令支持if,catch目前暫不支持if)
    • condition <bnum> <expression> -- 修改斷點號爲bnum的停止條件爲expression.
    • condition <bnum> -- 清除斷點號爲bnum的停止條件.
  • 忽略停止點 N 次
    • ignore <bnum> <count> -- 表示忽略斷點號爲 bnum 的停止條件 count 次.
  • 爲停止點設定運行命令
    • 格式:
      commands [bnum]
             ... command-list ...
             // 爲斷點號 bnumi寫一個命令列表.當程序被該斷點停住時,gdb 依次運行命令列表中的命令.
      end
    • 例如:
      break foo if x>0
        commands
             printf "x is %d/n",x
             continue
      end

信號(Signals)

添加信號處理

  • handle <signal> <keywords...>在 gdb 中定義一個信號處理.信號 <signal> 可以以 SIG 開頭或不以 SIG 開頭,可以用定義一個要處理信號的範圍(如:SIGIO-SIGKILL,表示處理從 SIGIO 信號到 SIGKILL 的信號,其中包括 SIGIO, SIGIOT, SIGKILL 三個信號),也可以使用關鍵字 all 來標明要處理所有的信號.一旦被調試的程序接收到信號,運行程序馬上會被 gdb 停住,以供調試.其 <keywords> 可以是以下幾種關鍵字的一個或多個.若沒有 keywords 則查看奇信號的處理狀態
    • nostop -- 當被調試的程序收到信號時,gdb 不會停住程序的運行,但會打出消息告訴你收到這種信號.
    • stop -- 當被調試的程序收到信號時,gdb 會停住你的程序.
    • print -- 當被調試的程序收到信號時,gdb 會顯示出一條信息.
    • noprint -- 當被調試的程序收到信號時,gdb 不會告訴你收到信號的信息.
    • pass -- 當被調試的程序收到信號時,gdb 不處理信號.這表示,gdb 會把這個信號交給被調試程序會處理.
    • noignore -- 當被調試的程序收到信號時,gdb 不處理信號.這表示,gdb 會把這個信號交給被調試程序會處理.
    • nopass -- 當被調試的程序收到信號時,gdb 不處理信號.這表示,gdb 會把這個信號交給被調試程序會處理.
    • 1gnore -- 當被調試的程序收到信號時,gdb 不會讓被調試程序來處理這個信號.

查看處理信號

  • info signals -- 查看有哪些信號在被 gdb 檢測中.
  • info handle -- 查看有哪些信號在被 gdb 檢測中.

GDB 程序調試

恢復執行

  • continue [ignore-count] -- ignore-count 表示忽略其後的斷點次數.恢復程序運行,直到程序結束,或是下一個斷點到來.縮寫 c
  • fg [ignore-count] -- ignore-count 表示忽略其後的斷點次數.恢復程序運行,直到程序結束,或是下一個斷點到來.縮寫 c

單步調試

  • step <count> -- 單步跟蹤,如果有函數調用,它會進入該函數.count 表示執行後面 count 條語句,不加則默認爲 1.
  • next <count> -- 同樣單步跟蹤,如果有函數調用,他不會進入該函數.count 表示執行後面 count 條語句,不加則默認爲 1.

跟蹤機器指令
       與之一樣有相同功能的命令是 “display/i $pc” ,當運行完這個命令後,單步跟蹤會在打出程序代碼的同時打出機器指令(也就是彙編代碼)

  • stepi 或 si -- 單步跟蹤一條機器指令,簡寫 si
  • nexti 或 ni -- 單步跟蹤一條機器指令,簡寫 ni

函數調試

  • finish -- 運行程序,直到當前函數完成返回.並打印函數返回時的堆棧地址和返回值及參數值等信息.
  • return <expression> -- 使函數以 expression 表達式返回出去,忽略還沒有執行的語句.若無返回 void 出去
  • call <expr> -- 表達式中可以一是函數,以此達到強制調用函數的目的.並顯示函數的返回值,如果函數返回值是void,那麼就不顯示.
  • print 與 printf 也可以做到類似的功能和 call 的不同是,如果函數返回 void,call 則不顯示,print 則顯示函數返回值,並把該值存入歷史數據中.

循環體調試

  • until -- 可以運行程序直到退出循環體.簡寫 u

修改變量值

  • print varname=var -- 修改被調試程序運行時的變量值
  • set var varname=value -- 修改被調試程序運行時的變變量
  • whatis varname -- 查看變量的類型

跳轉執行

  • jump <linespec> -- 指定下一條語句的運行點.<linespce> 可以是文件的行號,可以是 file:line 格式,可以是 +num 這種偏移量格式.表式着下一條運行語句從哪裏開始.
  • jump <address> -- 跳轉到指定的程序內存地址運行.<address> 是代碼行的內存地址.
  • 注意
    • jump 指令不會改變當前的程序棧中的內容,所以,當你從一個函數跳到另一個函數時,當函數運行完返回時進行彈棧操作時必然會發生錯誤.
    • jump 命令只是改變了指令寄存器中的值.於是可以使用 “set $pc” 來更改跳轉執行的地址.如: set $pc = 0x485

產生信號量

  • signal <signal> -- 產生一個 signal 信號.UNIX 的系統信號量通常從 1 到 15.所以 <signal> 取值也在這個範圍.

GDB 運行是數據

查看運行時數據

  • print /<f> <expr> -- 查看當前程序的運行數據.簡寫 p.
    • <expr> 是表達式
      • @ -- 是一個和數組有關的操作符,在後面會有更詳細的說明.在 @ 左邊是數組的地址,右邊是數組的長度,eg: array@len
      • :: -- 指定一個在文件或是一個函數中的變量.
      • {<type>} <addr> --表示一個指向內存地址<addr>的類型爲type的一個對象.
    • <f>是輸出的格式
      • d -- 按十進制格式顯示變量.
      • u -- 按十六進制格式顯示無符號整型.
      • o -- 按八進制格式顯示變量.
      • t -- 按二進制格式顯示變量.
      • a -- 按十六進制格式顯示變量.
      • c -- 按字符格式顯示變量.
      • f -- 按浮點數格式顯示變量.
    • 注意:
      • 1.若出現變量重名,局部變量會隱藏全局變量.若想查看全局變量的值時,可以使用“::”操作符.
      • 2.可以通過這種形式指定你所想查看的變量 eg:
            *'filename'::variable
            *function::variable
  • printf "fmt",arg,... -- 打印格式化字符燦 fmt.

查看內存

  • examine/<n/f/u> <addr> -- 來查看內存地址中的值.簡寫 x
    • <n/f/u>
      • n 是一個正整數,表示顯示內存的長度,也就是說從當前地址向後顯示幾個地址的內容.
      • f 表示顯示的格式
        • s -- 按字符串格式顯示內存地址內容.
        • i -- 查看內存地址的機器指令內容
        • x -- 按十六進制格式顯示地址內容.
        • d -- 按十進制格式顯示地址內容.
        • u -- 按十六進制格式顯示無符號整型.
        • o -- 按八進制格式顯示地址內容.
        • t -- 按二進制格式顯示地址內容.
        • a -- 按十六進制格式顯示地址內容.
        • c -- 按字符格式顯示地址內容.
        • f -- 按浮點數格式顯示地址內容.
      • u 表示從當前地址往後請求的字節數,如果不指定的話,gdb默認是 4 個 bytes.
        • b -- 表示單字節
        • h -- 表示雙字節
        • w -- 表示四字節
        • g -- 表示八字節
    • <addr> 表示一個內存地址.

自動顯示

  • 設置自動顯示
    • display/<fmt> <expr> -- 自動顯示 expr 表達式
    • display/<fmt> <addr> -- 自動顯示 addr 地址
      • fmt 表示顯示的格式
      • i -- 輸出格式爲機器指令碼,也就是彙編.
      • s -- 輸出格式爲字符串
  • 刪除自動顯示
    • undisplay <range> -- 刪除自動顯示
    • delete display <range> -- 刪除自動顯示
  • 啓用和禁自動顯示
    • sable display <range> -- 禁用自動顯示
    • enable display <range> -- 啓動自動顯示

查看棧信息

  • backtrace <n> -- 擦看函數棧信息,簡寫 bt
    • n 若是正數,只打印棧頂上 n 層的棧信息,
    • 若是負數,只打印棧頂下 n 層的棧信息,
    • 若無則打印當前的函數調用棧的所有信息
  • frame -- 會打印出這些信息:棧的層編號,當前的函數名,函數參數值,函數所在文件及行號,函數執行到的語句.
  • info frame -- 這個命令會打印出更爲詳細的當前棧層的信息,只不過,大多數都是運行時的內內地址.
  • info args -- 打印出當前函數的參數名及其值.
  • info locals -- 打印出當前函數中所有局部變量及其值.
  • info catch -- 打印出當前的函數中的異常處理信息.

切換函數棧位置

  • frame <n> -- 切換到第 n 層函數棧位置,簡寫 f.
  • p <n> -- 表示上面移動 n 層,可以不打 n,表示向上移動一層.
  • down <n> -- 表示向棧的下面移動 n 層,可以不打 n,表示向下移動一層.
  • select-frame <n> -- 類似 frame 命令.不打印出棧層信息.
  • up-silently <n> -- 類似 up 命令.不打印出棧層信息.
  • down-silently <n> -- 類似 down 命令.不打印出棧層信息.

查看寄存器

  • info registers -- 查看寄存器的情況.(除了浮點寄存器)
  • info all-registers -- 查看所有寄存器的情況.(包括浮點寄存器)
  • info registers <regname> -- 查看所指定的寄存器的情況.

線程查看與切換線程

  • info threads -- 查看當前線程
  • thread <threadno> -- 切換到 threadno 的線程,簡寫 t

自定義命令

定義一個命令

  • 格式
    define comdName
          ...
    end
  • 條件語句
    if cond_expr
          ...
    else
          ...
    end
  • 循環語句
    while cond_expr
          ...
    end

定義一個命令的文檔信息(在 help cmdName 的時候顯示)

  • document cmdName
          ...
    end

查看自定命令

  • help user-define -- 查看所有用戶自定義的命令
  • show user cmdName -- 查看用戶定義的 cmdName 的命令.
  • help cmdName -- 查看用戶自定義的 cmdName 的幫助文檔
  • show max-user-call-depth -- 查看用戶自定義命令的遞歸最大深度,缺省是 1024
  • set-user-call-depth <limit>-- 設置用戶自定義命令的遞歸最大深度.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章