多進程程式 (fork/exec) 調試是 Linux 系統程式開發的必修課。GDB 提供 follow-fork-mode、attach 與 wrapper 三種機制,配合 sleep() 同步技巧,可精準控制父/子進程調試流程。本文通過實戰範例逐一拆解。
進程 fork() 後產生父/子進程,GDB 預設繼續調試父進程,子進程自由運行。需透過設定決定跟蹤哪一側。
(gdb) set follow-fork-mode child # 切換調試子進程 (parent/child)
(gdb) set detach-on-fork off # 同時控制父子進程:被跟蹤者運行,另一者暫停
# on (預設):分離另一進程,不受 GDB 控制
# off:GDB 控制兩者,非當前跟蹤進程處於暫停狀態
適用場景:父子進程邏輯均需觀察,且不想修改程式碼。
適用於子進程隨後 exec() 執行新程式,或需在特定時機介入調試。
# 方案一:切換 root
sudo gdb ./program
# 方案二:賦予 gdb CAP_SYS_PTRACE (推薦)
sudo setcap cap_sys_ptrace=ep /usr/bin/gdb
volatile int pause_flag = 1;
while (pause_flag) sleep(1);
./test &ps -ef | grep test
# 輸出範例:
# user 12345 12344 0 10:00 pts/0 00:00:00 ./test ← 父進程
# user 12346 12345 0 10:00 pts/0 00:00:00 ./test ← 子進程 (PID=12346)
gdb -q ./test
(gdb) attach 12346
(gdb) set pause_flag = 0 # 釋放子進程繼續執行
(gdb) continue
子進程 fork() 後緊接 exec() 載入新程式映像,GDB 可透過 wrapper 腳本自動攔截。
gdb-wrapper.sh#!/bin/bash
# 由 GDB 呼叫: gdb --command=gdb-wrapper.sh --args ./parent_program
# 環境變數 GDB_WRAPPER=1 表示在 wrapper 內部
if [ -n "$GDB_WRAPPER" ]; then
exec "$@"
else
export GDB_WRAPPER=1
exec gdb --command="$0" --args "$@"
fi
優點:無需修改原始碼加入 sleep();缺點:設定較複雜,需熟悉 GDB 腳本化。
| 操作 | 指令 |
|---|---|
| 後台執行 | ./test & |
| 暫停前台進程 | Ctrl+Z |
| 恢復至後台 | bg %n (n 為 job number) |
| 調回前台 | fg %n |
| 查看任務 | jobs |

總結:三大技巧各有優勢:follow-fork-mode 最簡單適合邏輯共享;attach 靈活適合動態介入;wrapper 適合 exec 替換映像場景。實戰中常組合使用,掌握核心指令即可從容應對複雜多進程調試。