为 SIGSEGV 注册信号处理程序并且仍然能够从 OS 创建完整的故障转储

Both registering signal handler for SIGSEGV and still being able to create full crash dump from OS

我们使用标准模式为 SIGSEGV 注册自定义信号处理程序和 sigaction and then when segmentation fault occurs using the backtrace 函数来遍历堆栈并将其打印到某个文件。在日志中包含回溯是一个不错的功能,但它会禁用 OS 写入崩溃程序的完整转储,这非常有用。怎么可能既捕获 SIGSEGV,进行自定义处理,又导致 OS 创建完整转储,就像在默认操作的情况下一样?

例如,我可以调用记住指向默认处理程序的 oldact 指针(如 man 中所述),然后直接从自定义处理程序中调用它吗?不用说,我们需要崩溃来指示它发生的确切位置。因此,例如将处理程序重新注册到旧值并在其他地方隐式地使程序崩溃是行不通的。

您可以在处理完信号后重置 sigaction。那么出错的指令会在从handler返回后重新运行,再次出错,导致core dump。

这是一个例子:

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

struct sigaction oldSA;
void handler(int signal)
{
    const char msg[] = "Caught, should dump core now\n";
    write(STDERR_FILENO, msg, sizeof msg - 1);

    sigaction(SIGSEGV, &oldSA, NULL);
}

int main()
{
    struct sigaction sa={0};
    sa.sa_handler=handler;
    sigaction(SIGSEGV, &sa, &oldSA);

    int* volatile p=NULL;
    *p=5; // cause segfault
}

示例运行:

$ gcc test.c -o test && ./test
Caught, should dump core now
Segmentation fault (core dumped)