#include <stdio.h> #include <stdlib.h> #include <string.h> #include <libgen.h> #include <unistd.h> #include <execinfo.h> #include <sys/types.h> #include <sys/wait.h> #include <iostream> #include <thread> #include <functional> using namespace std; #define BACKTRACE_SIZE 16 // 获取当前运行进程的绝对路径 char *get_current_task_name() { static char task_name[1024] = {0}; char *pstr = NULL; readlink("/proc/self/exe", task_name, 1024); pstr = task_name; return pstr; } void addr2lineAnalyze(const char *paddress, const char *proName) { static char addr2line_str[256] = {0}; snprintf(addr2line_str, 256, "addr2line %s -e %s -f -p", paddress, proName); FILE *pFd = popen(addr2line_str, "r"); if ( pFd == nullptr ) { return ; } char buf[512] = {0}; fread(buf, sizeof(buf)/sizeof (buf[0]), 1, pFd); printf(" %s\n", buf); pclose(pFd); } void dump(void) { int j, nptrs; void *buffer[BACKTRACE_SIZE]; char **strings; nptrs = backtrace(buffer, BACKTRACE_SIZE); printf("backtrace() returned %d addresses\n", nptrs); strings = backtrace_symbols(buffer, nptrs); if (strings == NULL) { perror("backtrace_symbols"); exit(EXIT_FAILURE); } char *ptr = nullptr, *ptr_end = nullptr, *pstr = nullptr; // 打印堆栈信息, 并且使用addr2line进行分析 for (j = 0; j < nptrs; j++) { printf(" [%02d] %s\n", j, strings[j]); ptr = strstr(strings[j], "["); if (ptr != nullptr) { ptr++; ptr_end = strstr(ptr, "]"); if (ptr_end != nullptr) { *ptr_end = '\0'; } addr2lineAnalyze(ptr, get_current_task_name()); } } free(strings); } void signal_handler(int signo) { printf("<<<<<<<<<<<<<<<<<catch signal %d>>>>>>>>>>>>>>>>>>>>>>>>>\n", signo); printf("Dump stack start...\n"); dump(); printf("Dump stack end...\n"); signal(signo, SIG_DFL); /* 恢复信号默认处理 */ raise(signo); /* 重新发送信号 */ } int main(void) { // 注册信号 signal(SIGSEGV, signal_handler); signal(SIGINT, signal_handler); signal(SIGABRT, signal_handler); // 异常代码段, 抛越界操作 char *ptr = nullptr; memcpy(ptr, "123", 3 ); printf("ptr: %s\n", ptr); return 0; }
运行情况:
异常抛出进来后,信号注册函数进行回调,分析堆栈信息