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; }