Skip to content

问题场景

在调试处理信号(如 SIGHUPSIGTERMSIGUSR1 等)的程序时,GDB 默认会在收到信号时暂停程序执行,这可能干扰正常的信号处理流程调试。

GDB 信号处理命令对照

1. 查看信号处理设置

环境 命令 说明
GDB 命令行 info signals 查看所有信号的处理设置
VSCode Debug Console -exec info signals 在 VSCode 中执行 GDB 命令
bash
# GDB 命令行
(gdb) info signals

# VSCode Debug Console
-exec info signals

输出示例

Signal        Stop   Print   Pass to program   Description
SIGHUP        Yes    Yes     Yes               Hangup
SIGINT        Yes    Yes     No                Interrupt
SIGQUIT       Yes    Yes     Yes               Quit
...

2. 查看特定信号

bash
# GDB 命令行
(gdb) info signal SIGHUP

# VSCode Debug Console
-exec info signal SIGHUP

3. 设置信号处理行为

bash
# GDB 命令行
(gdb) handle SIGHUP nostop noprint pass

# VSCode Debug Console
-exec handle SIGHUP nostop noprint pass

信号处理参数详解

handle 命令语法

bash
handle <signal> <keywords>

关键字说明

关键字 作用 说明
stop / nostop 是否暂停 stop: 收到信号时暂停程序
nostop: 不暂停
print / noprint 是否打印 print: 在控制台显示信号信息
noprint: 不显示
pass / nopass 是否传递 pass: 将信号传递给程序处理
nopass: 拦截信号
ignore / noignore 是否忽略 等同于 nopass / pass

常用组合

bash
# 1. 让程序正常处理信号,不中断调试
handle SIGHUP nostop noprint pass

# 2. 捕获信号但让程序继续运行
handle SIGUSR1 stop print pass

# 3. 完全忽略信号
handle SIGPIPE nostop noprint nopass

# 4. 恢复默认设置
handle SIGHUP stop print pass

VSCode 配置文件集成

launch.json 中预设信号处理

json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "C++ Debug with Signal Handling",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/bin/your_program",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "Handle SIGHUP without stopping",
                    "text": "-exec handle SIGHUP nostop noprint pass",
                    "ignoreFailures": false
                },
                {
                    "description": "Handle SIGUSR1 without stopping",
                    "text": "-exec handle SIGUSR1 nostop noprint pass",
                    "ignoreFailures": false
                },
                {
                    "description": "Ignore SIGPIPE",
                    "text": "-exec handle SIGPIPE nostop noprint nopass",
                    "ignoreFailures": false
                }
            ],
            "preLaunchTask": "build",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}

实战示例

场景:调试信号重载配置的程序

程序代码

cpp
#include <signal.h>
#include <unistd.h>
#include <iostream>

void signal_handler(int signum) {
    std::cout << "Received signal: " << signum << std::endl;
    // 重新加载配置...
}

int main() {
    signal(SIGHUP, signal_handler);
    
    while (true) {
        std::cout << "Running... (PID: " << getpid() << ")" << std::endl;
        sleep(5);
    }
    return 0;
}

调试步骤

  1. 启动调试会话

  2. 在 VSCode Debug Console 设置信号处理

    -exec handle SIGHUP nostop print pass
  3. signal_handler 函数设置断点

  4. 在终端发送信号

    bash
    # 获取进程 PID(程序会打印)
    kill -SIGHUP <pid>
  5. 观察结果

    • GDB 不会暂停在信号接收时
    • 会在 signal_handler 断点处停下
    • 可以正常单步调试信号处理逻辑

发送信号的方法

1. 使用 kill 命令

bash
# 发送 SIGHUP (信号编号 1)
kill -SIGHUP <pid>
kill -1 <pid>

# 发送 SIGUSR1 (信号编号 10)
kill -SIGUSR1 <pid>

# 发送 SIGTERM (信号编号 15,默认)
kill <pid>

2. 在 GDB 中发送信号

bash
# GDB 命令行
(gdb) signal SIGHUP

# VSCode Debug Console
-exec signal SIGHUP

3. 使用 pkill 按进程名发送

bash
pkill -SIGHUP process_name

常见信号参考

信号 编号 默认行为 典型用途
SIGHUP 1 终止 重新加载配置
SIGINT 2 终止 Ctrl+C 中断
SIGQUIT 3 终止+Core Ctrl+\ 退出
SIGKILL 9 终止 强制杀死(不可捕获)
SIGUSR1 10 终止 用户自定义
SIGUSR2 12 终止 用户自定义
SIGTERM 15 终止 优雅终止
SIGCHLD 17 忽略 子进程状态改变

调试技巧总结

✅ 推荐做法

  1. 调试信号处理器时

    bash
    handle <SIGNAL> nostop noprint pass

    在信号处理函数内设置断点

  2. 排查信号相关 Bug 时

    bash
    handle <SIGNAL> stop print pass

    捕获信号但仍传递给程序

  3. 忽略干扰信号

    bash
    handle SIGPIPE nostop noprint nopass

⚠️ 注意事项

  • SIGKILLSIGSTOP 无法被捕获或处理
  • 设置 nopass 会阻止程序的信号处理函数执行
  • 在 VSCode 中需要使用 -exec 前缀执行 GDB 命令

🔍 调试流程

1. 查看当前信号设置
   -exec info signals

2. 配置需要的信号行为
   -exec handle SIGHUP nostop noprint pass

3. 在信号处理函数设置断点

4. 发送信号触发
   kill -SIGHUP <pid>

5. 单步调试信号处理逻辑

相关资源

基于 VitePress 构建