Linux 多進程程式除錯是開發者必備技能。GDB 作為最強大的除錯器,提供 follow-fork-mode、attach、wrapper 三大核心機制應對 fork/exec 複雜場景。本文深度解析三種方法的適用場景、操作步驟與實戰技巧。
典型多進程模型:父進程 fork() 子進程,子進程可能 exec() 載入新程式。除錯挑戰在於:
適用於 fork 後父子進程執行相同程式碼(未 exec)的場景。
(gdb) set follow-fork-mode parent|child
# parent(預設):fork 後繼續除錯父進程
# child:fork 後切換除錯子進程
(gdb) set detach-on-fork on|off
# on(預設):分離非除錯進程,讓其自由運行
# off:GDB 同時控制父子進程,非除錯進程處於暫停狀態
| 需求 | 配置 |
|---|---|
| 只除錯子進程,父進程自由跑 | set follow-fork-mode childset detach-on-fork on |
| 同時觀察父子進程,切換除錯焦點 | set follow-fork-mode childset detach-on-fork off |
| 除錯父進程,子進程暫停等待 | set follow-fork-mode parentset detach-on-fork off |
(gdb) catch fork
(gdb) catch exec
# 程式觸發 fork/exec 時自動中斷,方便動態調整策略
適用於 已在後台運行的程式,或需在特定時機介入子進程。
ptrace 權限,需:echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope(暫時)或修改 /etc/sysctl.d/10-ptrace.conf 永久生效。sleep(30) 或 while(pause_flag) sleep(1); 讓進程等待。./test &ps -ef | grep test,識別子進程 PID(PPID 為父進程 PID)。gdb -q ./test → (gdb) attach 子進程PID(gdb) set pause_flag=0#!/bin/bash
# auto_attach.sh
PARENT_PID=$1
CHILD_PID=$(pgrep -P $PARENT_PID)
gdb -q -ex "attach $CHILD_PID" -ex "set \$pause_flag=0" -ex "continue" ./test
適用於 子進程 exec 載入新程式 的場景,無需修改原始碼。
GDB 啟動時指定 wrapper 腳本,fork 後自動對子進程啟動新 GDB 實例。
gdb_wrapper.sh:
#!/bin/bash
# $1 = 程式路徑, $2+ = 參數
exec gdb -q -ex "set follow-fork-mode child" -ex "run" --args "$@"
chmod +x gdb_wrapper.shexport LD_PRELOAD=/usr/lib/gdb/gdb-wrapper.so(系統支援時)或直接用腳本啟動:./gdb_wrapper.sh ./parent_program arg1 arg2
#!/bin/bash
# 區分父子進程:父進程正常跑,子進程進 GDB
if [ "$GDB_WRAPPER_CHILD" = "1" ]; then
exec gdb -q -ex "run" --args "$@"
else
export GDB_WRAPPER_CHILD=1
exec "$@"
fi
# 啟動後台
./test &
# 暫停當前前台任務
Ctrl+Z
# 列出後台任務
jobs
# [1]+ Stopped ./test
# 恢復到後台運行
bg %1
# 恢復到前台
fg %1
| 場景 | 推薦方法 | 關鍵點 |
|---|---|---|
| fork 後同程式碼,需觀察父子交互 | follow-fork-mode + detach-on-fork off | 可隨時 inferior 1/2 切換進程 |
| 子進程 exec 新程式 | GDB Wrapper | 無需改碼,自動對新程式除錯 |
| 程式已在運行,需介入 | attach pid | 配合 sleep/pause 機制 |
| 嵌入式/無頭環境 | gdbserver + 遠端除錯 | 目標機跑 gdbserver,宿主機跑 GDB |
掌握這三大核心技巧,配合 catch、inferior、thread apply all bt 等進階命令,即可應對絕大多數 Linux 多進程除錯挑戰。