C++ 获取 Linux x64 "Segmentation Fault"的文件名和行号

C++ Get File Name and Line Number of "Segmentation Fault" Linux x64

本文关键字:文件名 Segmentation 获取 Linux x64 C++ Fault      更新时间:2023-10-16

不运行GDB,只运行程序本身

编辑:我已经看过这样的程序,但我不知道如何做到自己:(

Tommie解决了这个问题。

我已经把他的答案从GDB中分离出来,使用<execinfo.h>中有点标准的backtrace实用程序。

static void dumpstack(void){
    static void *backbuf[ 50 ];
    int levels;
    levels = backtrace( backbuf, 50 );
    backtrace_symbols_fd( backbuf, levels, STDERR_FILENO );
    return;
}

你可以试着打开一个文件,而不是写STDERR_FILENO,但我会避免在崩溃的过程中这样繁重的工作。

在我的系统上,输出看起来像这样:

Shadow:code dkrauss$ ./dumpy 
0   dumpy                               0x0000000100000d81 dumpstack + 25
1   dumpy                               0x0000000100000d18 signal_handler + 47
2   libSystem.B.dylib                   0x00007fff86b1766a _sigtramp + 26
3   ???                                 0x0000000000000000 0x0 + 0
4   dumpy                               0x0000000100000a18 start + 52
FATAL: Segmentation Fault

所以,它没有给出文件名+行号,但它给出了函数名+代码偏移量,你可以很容易地翻译。

嗯…你可以试试这样做…

struct sigaction g_sigact;
void panic(const char *fmt, ...){
    char buf[PANICBUF_LEN];
    va_list argptr;
    va_start(argptr, fmt);
    vsprintf(buf, fmt, argptr);
    va_end(argptr);
    fprintf(stderr, "%sn", buf);
    exit(-1);
}
void init_signals(void){
    g_sigact.sa_handler = signal_handler;
    sigemptyset(&g_sigact.sa_mask);
    g_sigact.sa_flags = 0;
    sigaction(SIGINT, &g_sigact, (struct sigaction *)NULL);
    sigaddset(&g_sigact.sa_mask, SIGSEGV);
    sigaction(SIGSEGV, &g_sigact, (struct sigaction *)NULL);
    sigaddset(&g_sigact.sa_mask, SIGBUS);
    sigaction(SIGBUS, &g_sigact, (struct sigaction *)NULL);
    sigaddset(&g_sigact.sa_mask, SIGQUIT);
    sigaction(SIGQUIT, &g_sigact, (struct sigaction *)NULL);
    sigaddset(&g_sigact.sa_mask, SIGHUP);
    sigaction(SIGHUP, &g_sigact, (struct sigaction *)NULL);
    sigaddset(&g_sigact.sa_mask, SIGKILL);
    sigaction(SIGKILL, &g_sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig){
    if (sig == SIGHUP) g_keepRunning = 0;
    if (sig == SIGSEGV || sig == SIGBUS){
        dumpstack();
        panic("FATAL: %s Faultn", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
    }
    if ((sig == SIGQUIT || (sig == SIGKILL) || (sig == SIGINT)) ;
}
static void dumpstack(void){
    /* Got this routine from http://www.whitefang.com/unix/faq_toc.html
    ** Section 6.5. Modified to redirect to file to prevent clutter
    */
    char dbx[160];
    sprintf(dbx, "echo -ne 'detachn' | gdb --eval-command=where --pid=%d > %d.dump", getpid(), getpid());
    system(dbx);
    return;
}

当分割错误被捕获时,dumpstack被调用并打印最近的堆栈跟踪,直到它分割错误并被重定向到具有进程数值pid的文件....

为什么你不想运行gdb?如果您使用它,您可以很容易地检测到分段故障的位置。