使用圖形化介面#

作者認為除錯是少數幾個圖形化介面明顯優於命令列的工作之一。原因是除錯需要同時呈現多種資料:原始碼、local 變數、call stack、log 訊息等。

如果你使用 Eclipse 或 Visual Studio,已經具備了良好的圖形化除錯環境。如果使用 gdb,有幾個 GUI 前端可選:

  • DDD (DataDisplayDebugger) — 功能最完整的 Unix-based GUI 前端,不只支援 gdb,也支援 Perl (bashdb)、Bash (bashdb)、make (remake)、Python (pydb) 的 debugger,還提供資料結構視覺化
  • gdb -tui- — gdb 內建的文字介面模式
  • cgdb — 提供 vi 風格鍵盤綁定的介面

儲存除錯指令#

將常用的除錯指令儲存到檔案中,下次除錯時自動載入,可以大幅提升效率。

gdb 的設定檔層次#

Visual Studio 和 Eclipse 會自動儲存 breakpoints 和 watchpoints 等 session 設定。gdb 則透過 .gdbinit 檔案:

  • $HOME/.gdbinit — 全域設定,所有 gdb session 都會載入
  • myproject/.gdbinit — 專案特定設定,在該目錄啟動 gdb 時載入
  • issue-1234 — 特定問題的 breakpoints 和 watchpoints,用 -x 選項載入

實用的 gdb 設定#

  • set history save — 儲存指令歷史,下次可用方向鍵或搜尋回叫
  • .inputrc 設定 — set editing-mode viset editing-mode emacs 切換鍵盤綁定

自訂 gdb 指令#

可以用 define 定義新指令,例如:

define sf
  where
  info args
  info locals
end
document sf
Display current stack frame
end

GitHub 上的 gdbinit Gist 收集了許多實用的 gdb 自訂指令,值得參考。

用 gdb 腳本進行自動化檢查#

gdb 腳本可以實現一些程式碼中不方便加入的自動化檢查。書中示範了一個驗證 lock 順序的腳本:

  • 定義一個計數器變數 $nlock
  • lock 函式上設 breakpoint,命中時遞增計數器
  • unlock 函式上設 breakpoint,命中時遞減計數器
  • 用 conditional breakpoint 檢測 nested locklock$nlock > 0)和 duplicate unlockunlock$nlock <= 0
  • 檢測到問題時印出 backtrace 並暫停程式

gdb 的 compile 指令#

新版 gdb 提供 compile 指令,讓你直接在 gdb 中用應用程式的原生語言編譯和執行程式碼,可以存取 local 和 global 變數與函式。不過,複雜的除錯邏輯通常還是應該放在程式碼中。

在 gdb 內 build 程式#

在 gdb session 中執行 make 指令來重新編譯程式,可以保留你已輸入的所有設定。重新 run 時 gdb 會自動偵測執行檔已更新並重新載入。

重點回顧#

  • 盡量使用圖形化介面進行除錯
  • 設定 gdb 儲存指令歷史,並使用你慣用的鍵盤綁定
  • 將常用指令放入 gdb 腳本.gdbinit),實現自動化檢查
  • 在 gdb 內 build 程式,保留已建立的除錯設定