gcc -g -O0 main.c -o app # 必須 -g 生成調試信息,-O0 關閉優化
gdb ./app # 進入 GDB
(gdb) set args arg1 arg2 # 設置程序參數
(gdb) show args # 查看參數
(gdb) run # 運行 (r)
| 命令 | 縮寫 | 功能 |
|---|---|---|
break | b | 設置斷點 |
continue | c | 繼續運行 |
next | n | 單步跳過函數調用 |
step | s | 單步進入函數 |
finish | fin | 運行完當前函數返回 |
print | p | 打印表達式值 |
display | disp | 每次停下自動打印 |
backtrace | bt | 查看調用棧 |
info break | i b | 列出所有斷點 |
info locals | i lo | 當前幀局部變量 |
info registers | i r | 寄存器值 |
list | l | 顯示源碼 |
set variable | set var | 修改變量值 |
watch | 設置數據觀察點 | |
handle | 配置信號處理 |
# 設置斷點
(gdb) break 10 # 第 10 行
(gdb) break func_name # 函數入口
(gdb) break file.c:20 # 指定文件行
(gdb) break *0x4005d6 # 地址
(gdb) break 10 if i == 5 # 條件斷點
# 管理
(gdb) info break # 列表
(gdb) disable 1 # 禁用 1 號
(gdb) enable 1 # 啟用
(gdb) delete 1 # 刪除 1 號
(gdb) delete # 刪除所有 (確認)
(gdb) clear 10 # 刪除第 10 行所有斷點
# 基本打印
(gdb) p i # 變量
(gdb) p arr[3] # 數組元素
(gdb) p *ptr # 解引用指針
(gdb) p/x addr # 十六進制
(gdb) p/t val # 二進制
(gdb) p struct_var # 結構體全字段
# 類型檢查
(gdb) whatis i # 類型
(gdb) ptype struct Node # 結構體定義
# 修改值
(gdb) set var i = 100
(gdb) set {int}0x7fff... = 42 # 修改任意地址
# 自動顯示
(gdb) display i
(gdb) undisplay 1 # 取消 1 號 display
# 內存檢查
(gdb) x/10xw 0x7fff... # 10 個 4 字節十六進制
(gdb) x/5s 0x... # 5 個字符串
(gdb) bt # 完整棧跟蹤
(gdb) bt full # 含局部變量
(gdb) frame 2 # 切換到第 2 幀 (0 為最頂)
(gdb) up / down # 向上/向下移動幀
(gdb) info frame # 當前幀詳情
(gdb) handle SIGSEGV stop print # 捕獲 SIGSEGV:停止、打印信息、不傳給程序
(gdb) handle SIGPIPE nostop noprint # 忽略 SIGPIPE
(gdb) handle SIGUSR1 pass # 透傳給程序
(gdb) signal SIGINT # 手動發送信號給程序
(gdb) info threads # 列出所有線程
(gdb) thread 3 # 切換到線程 3
(gdb) thread apply all bt # 所有線程回溯
(gdb) set scheduler-locking on/off/step # 控制單步時其他線程是否運行
ulimit -c unlimited # 允許生成 core 文件
./app # 運行至崩潰
gdb ./app core # 載入 core 分析
(gdb) bt # 直接看崩潰棧
現象:無斷點時 readlink 失敗,有斷點單步時成功。
代碼:
char *buf = "123456789";
printf("%d:%s\n", strlen(buf), buf);
int n = readlink("1", buf, 9); // buf 同時作輸入輸出!
if (n == -1) printf("error!\n");
else printf("%d:%d:%s\n", n, strlen(buf), buf);
根因:buf 指向字符串常量區(只讀),readlink 嘗試寫入導致 SIGSEGV。無斷點直接崩潰輸出 error;有斷點單步時,GDB 捕獲信號停下,手動 continue 可能跳過寫入或內存映射恰好可寫(調試器修改頁屬性)。
修正:
char buf[256]; // 可寫數組
strcpy(buf, "123456789");
int n = readlink("1", buf, sizeof(buf)-1);
break 10 if i==5\n commands\n silent\n p var\n continue\n end 實現自動化監控。python print(gdb.parse_and_eval("var")) 實現複雜邏輯。record full + reverse-next (需硬件/記錄支持)。.gdbinit 定義常用宏、斷點、pretty-printer。GDB 是 Linux/Unix 下 C/C++ 開發者最強大的武器。熟練掌握斷點條件、數據觀察點、棧幀切換、多線程/信號控制、core 分析,能將調試效率提升數倍。養成編譯加 -g、善用 core 文件、編寫 .gdbinit 的習慣,讓調試成為可控、可重現的工程過程而非運氣遊戲。