gdb 初步心得

對初學者來說, 最好有個針對常用情境的簡單指南, 之後有閒再看落落長的教學。這裡列一下最近常用的功能, 之後再慢慢更新。

前置動作

  • gcc/g++ 編譯時要加 -g
  • 要觀察用到的函式庫, 則要裝 x-dbg 版 (如 libjpeg62 -> libjpeg62-dbg), gdb 會優先載入 debug 版函式庫。並且需要用 directory 載入原始碼, 詳情見《追踪 glibc 裡的程式》的說明。
  • 若原始碼的位置和當初編 binary 時的位置不同 (常有的事), 可用 set substitute-path from to 做路徑字串取代。
  • 可用 objdump --source FILE 確認是否真的有編到 -g。有的話可以在輸出裡看到程式碼。

雖說通篇我都寫 gdb, 但是 cgdb 好用許多, 推薦使用。聽 command 說 vimgdb 更好用, 不過要 patch vim 後才能用, 就 ... 先備忘吧。

執行方式

從頭執行

  • bash> gdb --args PROGRAM PROGRAM-ARG1 ...
  • gdb> start # 進入 main 後停下來

檢查掛點原因 (參考《產生 core dump 的方法》確保有 core dump)

  • bash> gdb PROGRAM CORE
  • gdb> bt 20 # 看掛掉的 call stack 最底層 20 個 function call

通常載入 PROGRAM 讀 debug symbol 較花時間, 我習慣用 gdb PROGRAM 進 gdb 後, 再用 core CORE 指令看不同的 core dump。

若希望從頭重來, 有設好中斷點就用 r, 沒有則繼續用 start, 不用離開 gdb, 可簡省載入 PROG 的時間。

設中斷點

  • b LOC # 設中斷點, 或用 cgdb 直接在程式視窗按空白鍵
  • i b # 列出全部中斷點
  • d NUM # 移除編號 NUM 的中斷點
  • save breakpoints FILE # 存下目前設的中斷點到檔案 FILE
  • so FILE # 載入之前設的中斷點
  • dis 1-10: 暫停使用 breakpoints 1-10。
  • ena 1-10: 恢復使用 breakpoints 1-10。

關於 LOC: 見《Specify Location - Debugging with GDB》。我比較常用 filename:linenum、linenum 或 +N。因為不易對到 C++ 的函式名稱, 所以我都用行號。

我還沒有適當情境試 conditional break, 但應該很有用, 備忘。

移動

  • n # 跳下行
  • s # 若有函式, 跳進去; 反之則同 n
  • fin # 執行到函式結尾, 返回上一層
  • until LOC # 執行到 LOC 再停, 我以前都傻傻的先設中斷再按 c ...
  • c # 執行到下個中斷點
  • 跳過下一行程式 (ref.), 記得要設中斷點才行
    • b +1
    • j +1
  • ret # 不執行函式剩下的程式, 直接返回上層 frame
  • ps. 按 Enter 可重覆上個指令, 在移動指令時和切 stack frame (後述) 時特別好用

在 call stack 之間移動

  • up # 往上移一個
  • do # 往下移一個
  • f N # 跳到 stack frame N

觀察值

  • p EXPRESSION # 印出 EXPRESSION 的值, 可是變數、函式等
  • 印出 smart pointer 的值 (ref.): 得先取出裡面的 pointer 再取出它的 member function / field
  • whatis VAR # 看型別
  • ptype VAR # 看型別的宣告內容, 了解有那些欄位可讀
  • p P@N # 印出位置 P 開始 N 個變數的值
  • p *P@N # 印出對位置 P 開始 N 個變數取值後的值
  • p *argv@argc # 在 main() 函式裡執行這指令, 會印出命令列參數內容

thread

其它

  • set var X = ... # 執行期間改變變數 X, 以在執行期驗證小修改是否有效, 簡省編譯時間
  • handle SIGSTOP nostop noprint # 收到 SIGSTOP 時不要停且不要輸出訊息, 在 Android 環境有時 gdb 會莫明地一直收到 SIGSTOP

參考資料

進階指令

  • commands BREAKPOINT_ID: 定義在進入 breakpoint 後, 執行一系列指令, 比方 "p some_var; c"。
  • define NEW_CMD: 類似函式, 定義由一堆指令組成的新指令。

留言

這個網誌中的熱門文章

(C/C++ ) 如何在 Linux 上使用自行編譯的第三方函式庫

熟悉系統工具好處多多

virtualbox 使用 USB 裝置