對初學者來說, 最好有個針對常用情境的簡單指南, 之後有閒再看落落長的教學。這裡列一下最近常用的功能, 之後再慢慢更新。
前置動作
- 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
- i thr # 列出目前的 thread, 建議事先用 prctl / pthread_setname_np 設定 thread name, 比較好辨別
- thr NUM # 切換 thread
其它
- set var X = ... # 執行期間改變變數 X, 以在執行期驗證小修改是否有效, 簡省編譯時間
- handle SIGSTOP nostop noprint # 收到 SIGSTOP 時不要停且不要輸出訊息, 在 Android 環境有時 gdb 會莫明地一直收到 SIGSTOP
參考資料
- 《Debugging with GDB》: 待用一陣子後再來掃一遍, 挑出有用的東西
進階指令
- commands BREAKPOINT_ID: 定義在進入 breakpoint 後, 執行一系列指令, 比方 "p some_var; c"。
- define NEW_CMD: 類似函式, 定義由一堆指令組成的新指令。
沒有留言:
張貼留言