1 前言

cpp项目中,我们除了使用GDB-生产环境如何兼顾效率与排错这种方式定位问题之外,还有一种在不损失性能的基础上尽可能帮助我们找到问题的方法:在收到SIGNINTER信号后调用backtrace方法,并输出调用栈信息。

再通过addr2line命令工具定位到具体代码行。

2 示例

下面我们举个简单的例子,我们准备一个段错误代码:

 
#include <execinfo.h>
#include <iostream>
#include <signal.h>
 
using namespace std;
 
void stage2()
{
    int *a = nullptr;
    *a = 1;
}
 
void stage1()
{
    stage2();
}
 
#define BACKTRACE_SIZE 16
 
void dump(void)
{
    int i = 0, nptrs = 0;
    void *buf[BACKTRACE_SIZE];
    char **strings;
    nptrs = backtrace(buf, BACKTRACE_SIZE);
 
    printf("backtrace() returned %d addresses\n", nptrs);
    strings = backtrace_symbols(buf, nptrs);
    if (strings == NULL)
    {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }
    for (i = 0; i < nptrs; i++)
    {
        printf(" [%02d] %s\n", i, strings[i]);
    }
    free(strings);
}
 
void signal_handler(int signo)
{
    printf("\n=================>>>catch signal %d<<<=====================\n", signo);
    printf("Dump stack start...\n");
    dump();
    printf("Dump stack end...\n");
    signal(signo, SIG_DFL);
    raise(signo);
}
 
int main(int argc, char const *argv[])
{
    signal(SIGSEGV, signal_handler);
    stage1();
    return 0;
}

运行后输出:

=================>>>catch signal 11<<<=====================
Dump stack start...
backtrace() returned 7 addresses
 [00] ./test(+0x1386) [0x56279566e386]
 [01] ./test(+0x145d) [0x56279566e45d]
 [02] /lib/x86_64-linux-gnu/libc.so.6(+0x42520) [0x7ff5e5a3f520]
 [03] ./test(+0x11db) [0x56279566e1db]
 [04] /lib/x86_64-linux-gnu/libc.so.6(+0x29d90) [0x7ff5e5a26d90]
 [05] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x7ff5e5a26e40]
 [06] ./test(+0x1245) [0x56279566e245]
Dump stack end...
Segmentation fault

我们可以看到,输出的都是地址,仅凭这些我们是无法定位到问题的。

这个时候我们可以使用addr2line确定行号:

addr2line -Cif -e ${program_path} ${addr}

示例:

wzq@WZQ-Laptop:~/cpp_test/build$ addr2line -Cif -e ./test 0x11db
stage2()
/home/wzq/cpp_test/test.cpp:11
stage1()
/home/wzq/cpp_test/test.cpp:16
main
/home/wzq/cpp_test/test.cpp:55

可以看到,它帮助我们定位到了第11行*a = 1;这里。这样我们可以大致确定问题所在了。