从C程序中调用调试器

从C程序中调用调试器,c,linux,gdb,systems-programming,C,Linux,Gdb,Systems Programming,我正在读David Hanson写的《C接口和实现》一书。此练习问题似乎很有趣,我无法找到解决方案: 在某些系统上,程序可以在运行时调用自身的调试器 检测到一个错误。这项设施在工作期间特别有用 开发时,断言失败可能很常见 您能否提供一个关于如何调用调试器的简短示例 void handle_seg_fault(int arg) { /* how to invoke debugger from within here */ } int main() { int *ptr = NUL

我正在读David Hanson写的《C接口和实现》一书。此练习问题似乎很有趣,我无法找到解决方案:

在某些系统上,程序可以在运行时调用自身的调试器 检测到一个错误。这项设施在工作期间特别有用 开发时,断言失败可能很常见

您能否提供一个关于如何调用调试器的简短示例

void handle_seg_fault(int arg)
{
    /* how to invoke debugger from within here */
}

int main()
{
    int *ptr = NULL;
    signal(SIGSEGV, handle_seg_fault);
    /* generate segmentation fault */
    *ptr = 1;
}
我得到了这个:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>

void exception_handler(int)
{
    int pid = getpid();
    if (fork() != 0) {
        while(true) sleep(1000);
    }
    char buf[20];
    sprintf(buf, "--pid=%u", pid);
    execlp("gdb", "gdb", buf, NULL);
    exit(-1);
}

int init()
{
    if (signal(SIGSEGV, exception_handler) < 0) {
       return errno;
    }
    if (signal(SIGILL, exception_handler) < 0) {
        return errno;
    }
    if (signal(SIGFPE, exception_handler) < 0) {
        return errno;
    }
    return 0;
}

int main()
{
    if (int rc = init()) {
       fprintf(stderr, "init error: %s\n", strerror(rc));
       return 1;
    }
    *((char*)(0)) = 1;
}
#包括
#包括
#包括
#包括
#包括
#包括
无效异常处理程序(int)
{
int pid=getpid();
如果(fork()!=0){
而(真实)睡眠(1000);
}
char-buf[20];
sprintf(buf,“--pid=%u”,pid);
execlp(“gdb”、“gdb”、buf、NULL);
出口(-1);
}
int init()
{
if(信号(SIGSEGV,异常处理程序)<0){
返回errno;
}
if(信号(信号,异常处理程序)<0){
返回errno;
}
if(信号(SIGFPE,异常处理程序)<0){
返回errno;
}
返回0;
}
int main()
{
if(int rc=init()){
fprintf(stderr,“初始错误:%s\n”,strerror(rc));
返回1;
}
*((字符*)(0))=1;
}

详细阐述Christian.K的评论,
fork()
面对SIGFPE或SIGSEGV这样的东西使用调试器可能不是最好的主意,因为

  • 首先,您的程序可能已损坏,使
    fork()
    不安全
  • 您可能希望使用与程序硬编码不同的东西进行调试
  • 一般应用程序用户不知道如何处理调试器
  • 任何有调试器能力的人通常会更喜欢coredump而不是自动调用的调试器

  • 我可以复制到测试床上的coredump在一天中的任何时候都胜过客户工作场所的调试器实例。调试器界面会产生糟糕的最终用户错误消息。

    无论您做什么,请确保仅从信号处理程序中使用。例如,在所有
    exec
    变体中,只有
    execve
    execle
    可以在(异步信号捕获)信号处理程序的上下文中安全执行。现在,不管这样做是否明智(面对像SIGSEGV这样的“国家腐败信号”),这是另一回事。我会使用(a)一个外部调试器,或者(b)事后检查coredump。我认为使用调试器attach只用于调试是个好主意。