程序崩溃时打印堆栈信息,方便定位
- 具体流程为:
- 编译程序时生成map文件
- 设置信号处理函数
- 打印程序在系统中maps映射
- 打印backtrace信息
- raise信号
- 也可以使用libunwind第三方库实现,该库最初在商业版hpux中提供,现在Linux平台下也可使用。利用这些调试信息来达到堆栈展开或者栈回溯的目的,则是libunwind做的事情。当然libunwind能做的也不仅仅局限于这些,利用libunwind还可以实现non-local goto和efficient setjmp 等。
- 优点:
- 系统未打开coredump时也能够捕获一些崩溃信息
- gcc版本不一致时,借助map文件,能够定位程序崩溃堆栈点
//设置信号处理函数
int setup_sigsegv(int signum)
{
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = signal_segv;
action.sa_flags = signum;
if (sigaction(signum, &action, NULL) < 0) {
return -1;
}
return 1;
}
#if defined(linux) || defined(__linux) || defined(__linux__)
void signal_segv(int signum, siginfo_t *info, void* ptr)
{
void *bt[0x40];
size_t sz;
char buff[0xff] = { 0x00 };
char filename[0xff] = { 0x00 };
struct tm* tm_ptr = NULL;
time_t t_time;
time(&t_time);
tm_ptr = localtime(&t_time);
sprintf(filename, "%s/%04d_%02d_%02d_%02d_%02d_%02d.dump",
getExePath().c_str(), //程序路径
tm_ptr->tm_year + 1900,
tm_ptr->tm_mon + 1,
tm_ptr->tm_mday,
tm_ptr->tm_hour,
tm_ptr->tm_min,
tm_ptr->tm_sec );
printf("filename =%s\n", filename);
sprintf(buff, "cat /proc/%d/maps >> %s", getpid(), filename);
system((const char*)buff);
int fd = open(filename, O_APPEND | O_RDWR);
const char* const split = "-------------------------------------------------------------------\n";
write(fd, "\n\n", 2);
write(fd, split, strlen(split));
sz = backtrace(bt, 0x40);
backtrace_symbols_fd(bt, sz, fd);
close(fd);
signal(signum, SIG_DFL);
raise(signum);
}
#endif
//hpux下利用系统自带libunwind.so库打印堆栈信息
//g++下直接调用_UNW_STACK_TRACE编译未通过,采取动态加载库方式
//gcc编译可以直接调用_UNW_STACK_TRACE,原因未知
#if defined(hpux) || defined(__hpux) || defined(__hpux__)
void signal_segv(int signum, siginfo_t *info, void* ptr)
{
char filename[0xff] = { 0x00 };
struct tm* tm_ptr = NULL;
time_t t_time;
time(&t_time);
tm_ptr = localtime(&t_time);
sprintf(filename, "%s/%04d_%02d_%02d_%02d_%02d_%02d.dump",
getExePath().c_str(),
tm_ptr->tm_year + 1900,
tm_ptr->tm_mon + 1,
tm_ptr->tm_mday,
tm_ptr->tm_hour,
tm_ptr->tm_min,
tm_ptr->tm_sec );
FILE* file = fopen(filename, "w+");
void* plib = NULL;
plib = dlopen("libunwind.so", RTLD_NOW | RTLD_GLOBAL);
if (plib) {
typedef uint32_t (*STACK_TRACE_FILE)(FILE*);
STACK_TRACE_FILE func_trace = (STACK_TRACE_FILE)dlsym(plib, "_UNW_STACK_TRACE");
if (func_trace) {
func_trace(file);
}
}
fclose(file);
signal(signum, SIG_DFL);
raise(signum);
}
- hpux下g++编译_UNW_STACK_TRACE未定义符号问题,见下篇