C++后台服务崩溃堆栈日志

C++后台服务崩溃堆栈日志

  C/C++后台服务运行过程中总会出现一些不容易重现的崩溃故障,由于重现频率低,同时运行在服务器上,导致无法调试,此外服务直接崩溃,常规日志无法截获到有用信息,这时如果能够保留服务崩溃现场,将对后期的Bug调试起到事半功倍的效果。打印出崩溃时刻服务的堆栈信息的需求应运而生。

前提条件

  编译程序服务的Debug版本,没有调试信息,神仙也没有办法。-rdynamic 为可选参数(会在打印的堆栈信息中增加调用函数名称)。

  gcc: gcc -g -rdynamic main.cpp

  cmake: set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -rdynamic -O0 -Wall -g")

运行结果:

trigger signal: 11
./test_cario(_Z14signal_handleri+0x5e) [0x400e4b]
/lib64/libc.so.6(+0x35270) [0x7fc0c1e59270]
./test_cario(_Z4add2PKc+0x1f) [0x400f04]
./test_cario(_Z3addPKc+0x18) [0x400f61]
./test_cario(main+0xbc) [0x40101f]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7fc0c1e45c05]
./test_cario() [0x400d29]

  上面信息显示了崩溃时的调用堆栈,输出的信息只打印了调用地址,还需要对这些地址进行可视化:

[root@localhost debug]$ addr2line -e a.out 0x400e4b
/home/root/test/main.cpp:13
[root@localhost debug]$ addr2line -e a.out 0x400f04
/home/root/test/main.cpp:30
[root@localhost debug]$ addr2line -e a.out 0x400f61
/home/root/test/main.cpp:36
[root@localhost debug]$ addr2line -e a.out 0x40101f
/home/root/test/main.cpp:56

示例程序

#include <iostream>
#include <zconf.h>
#include <signal.h>
#include <execinfo.h>

#include <stdio.h>
#include <stdlib.h>

void signal_handler( int s ) {
    fprintf( stderr, "trigger signal: %d
", s );

    void* pszstack[256] = {NULL};
    int stacknum = backtrace( pszstack, 256 );
    if ( stacknum > 0 ) {
        char** stacktrace = backtrace_symbols( pszstack, stacknum );
        for ( int i = 0; i < stacknum; ++i ) {
            fprintf( stderr, "%s
", stacktrace[i] );
        }
        free( stacktrace );
    } else {
       fprintf( stderr, "no stack trace: %d", stacknum );
    }
    exit(0);
}

void add2( const char* psz )
{
    int a = 0;
    int b = 1;
    std::cout << a+b << "data: " << psz[0] << std::endl;
}

void add( const char* psz )
{
    add2( psz );
}

int main() {

    signal( SIGPIPE, SIG_IGN );
    signal( SIGSEGV, signal_handler );
    signal( SIGABRT, signal_handler );
    signal( SIGFPE, signal_handler );
    signal( SIGSYS, signal_handler );
    signal( SIGIO, signal_handler );

    char* psztemp = NULL;
    for ( int i = 0; i < 5; ++i )
    {
        std::cout << "sleep: " << i << std::endl;
        sleep( 1 );
    }

    add(psztemp);

    for ( int i = 0; i < 5; ++i )
    {
        std::cout << "sleep2: " << i << std::endl;
        sleep( 1 );
    }
    
    return 0;
}
原文地址:https://www.cnblogs.com/wanghaiyang1930/p/8884848.html