#include "AutoDmp.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 静态成员初始化 AutoDmp* AutoDmp::instance_ = nullptr; // Linux 信号处理列表 const int AutoDmp::handledSignals_[] = { SIGSEGV, // 段错误 SIGABRT, // 异常终止 SIGFPE, // 浮点异常 SIGILL, // 非法指令 SIGBUS, // 总线错误 SIGSYS, // 系统调用错误 SIGPIPE, // 管道错误 SIGQUIT // 退出信号 }; const size_t AutoDmp::handledSignalCount_ = sizeof(handledSignals_) / sizeof(handledSignals_[0]); // 构造函数 AutoDmp::AutoDmp(const CrashConfig& config) : config_(config) { if (instance_ == nullptr) { instance_ = this; if (initializeHandlers()) { initialized_.store(true); } } } // 析构函数 AutoDmp::~AutoDmp() { if (instance_ == this) { cleanupHandlers(); instance_ = nullptr; initialized_.store(false); } } // Linux 信号处理器 void AutoDmp::signalHandler(int sig, siginfo_t* info, void* context) { // 防止重入 static volatile sig_atomic_t handling = 0; if (handling || !instance_ || instance_->crashInProgress_.exchange(true)) { return; } handling = 1; const CrashConfig* config = getInstanceConfig(); if (!config) { // 恢复默认处理并重新触发 signal(sig, SIG_DFL); raise(sig); return; } // 使用异步安全的方式输出基本信息 if (config->enableConsoleOutput) { safeWriteToFd(STDERR_FILENO, "\n*** LINUX CRASH DETECTED ***\n"); safeWriteToFd(STDERR_FILENO, "Signal: "); safeWriteNumber(STDERR_FILENO, sig); safeWriteToFd(STDERR_FILENO, " ("); safeWriteToFd(STDERR_FILENO, getSignalName(sig).c_str()); safeWriteToFd(STDERR_FILENO, ")\n"); if (info->si_addr) { safeWriteToFd(STDERR_FILENO, "Fault Address: "); safeWritePointer(STDERR_FILENO, info->si_addr); safeWriteToFd(STDERR_FILENO, "\n"); } safeWriteToFd(STDERR_FILENO, "Process ID: "); safeWriteNumber(STDERR_FILENO, getpid()); safeWriteToFd(STDERR_FILENO, "\n"); safeWriteToFd(STDERR_FILENO, "Thread ID: "); safeWriteNumber(STDERR_FILENO, syscall(SYS_gettid)); safeWriteToFd(STDERR_FILENO, "\n"); // 输出调用栈到stderr(异步安全) if (config->enableBacktrace) { safeWriteToFd(STDERR_FILENO, "\nBacktrace:\n"); void* frames[128]; int numFrames = backtrace(frames, 128); if (numFrames > 0) { backtrace_symbols_fd(frames, numFrames, STDERR_FILENO); } } safeWriteToFd(STDERR_FILENO, "****************************\n\n"); } // 设置 core dump if (config->enableCoreDump) { setupCoreDump(); } // 恢复默认信号处理并重新触发 struct sigaction sa; sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(sig, &sa, nullptr); // 如果不是在异步安全模式,尝试写入详细日志 if (!config->asyncSafeOnly) { try { // 收集详细崩溃信息 CrashInfo crashInfo; crashInfo.timestamp = getCurrentTimestamp(); crashInfo.processName = getProcessName(); crashInfo.processId = getpid(); crashInfo.threadId = syscall(SYS_gettid); crashInfo.buildInfo = std::string(__DATE__) + " " + __TIME__; crashInfo.signalNumber = sig; crashInfo.signalName = getSignalName(sig); crashInfo.faultAddress = info->si_addr; crashInfo.signalDescription = getSignalDescription(sig, info); crashInfo.backtrace = getBacktrace(context, config->maxBacktraceDepth); // 确保目录存在 createDirectory(config->crashDirectory); // 写入详细日志 if (config->enableLogFile) { std::string logFileName = "crash_" + crashInfo.timestamp + ".log"; std::string logPath = config->crashDirectory + "/" + logFileName; writeCrashLog(crashInfo, logPath); cleanupOldFiles(config->crashDirectory, config->maxCrashFiles); } // 输出详细信息到控制台 if (config->enableDetailedInfo && config->enableConsoleOutput) { outputDetailedInfo(crashInfo); } } catch (...) { // 在信号处理器中不抛出异常 safeWriteToFd(STDERR_FILENO, "Warning: Failed to write detailed crash log\n"); } } // 触发默认处理(生成core dump并终止进程) raise(sig); } // 异步安全的写入函数 void AutoDmp::safeWriteToFd(int fd, const char* msg) { if (msg) { size_t len = strlen(msg); write(fd, msg, len); } } void AutoDmp::safeWriteNumber(int fd, long number) { char buffer[32]; char* p = buffer + sizeof(buffer) - 1; *p = '\0'; bool negative = number < 0; if (negative) number = -number; if (number == 0) { *--p = '0'; } else { while (number > 0) { *--p = '0' + (number % 10); number /= 10; } } if (negative) { *--p = '-'; } safeWriteToFd(fd, p); } void AutoDmp::safeWritePointer(int fd, void* ptr) { char buffer[32]; snprintf(buffer, sizeof(buffer), "%p", ptr); safeWriteToFd(fd, buffer); } // 获取调用栈 std::string AutoDmp::getBacktrace(void* context, size_t maxDepth) { void* frames[maxDepth]; int numFrames = backtrace(frames, maxDepth); if (numFrames <= 0) { return "Unable to get backtrace"; } // 获取符号信息 char** symbols = backtrace_symbols(frames, numFrames); if (!symbols) { return "Unable to get symbol information"; } std::ostringstream oss; for (int i = 0; i < numFrames; ++i) { oss << "#" << std::setw(2) << std::setfill('0') << i << ": " << symbols[i] << "\n"; } free(symbols); return oss.str(); } // 设置 core dump bool AutoDmp::setupCoreDump() { struct rlimit coreLimit; coreLimit.rlim_cur = RLIM_INFINITY; coreLimit.rlim_max = RLIM_INFINITY; return setrlimit(RLIMIT_CORE, &coreLimit) == 0; } // 获取信号名 std::string AutoDmp::getSignalName(int sig) { switch (sig) { case SIGSEGV: return "SIGSEGV"; case SIGABRT: return "SIGABRT"; case SIGFPE: return "SIGFPE"; case SIGILL: return "SIGILL"; case SIGBUS: return "SIGBUS"; case SIGSYS: return "SIGSYS"; case SIGPIPE: return "SIGPIPE"; case SIGQUIT: return "SIGQUIT"; default: return "UNKNOWN"; } } // 获取信号描述 std::string AutoDmp::getSignalDescription(int sig, siginfo_t* info) { std::ostringstream oss; oss << getSignalName(sig) << " - "; switch (sig) { case SIGSEGV: oss << "Segmentation fault"; if (info) { switch (info->si_code) { case SEGV_MAPERR: oss << " (address not mapped)"; break; case SEGV_ACCERR: oss << " (invalid permissions)"; break; default: break; } } break; case SIGABRT: oss << "Abort signal"; break; case SIGFPE: oss << "Floating point exception"; if (info) { switch (info->si_code) { case FPE_INTDIV: oss << " (integer divide by zero)"; break; case FPE_INTOVF: oss << " (integer overflow)"; break; case FPE_FLTDIV: oss << " (floating point divide by zero)"; break; case FPE_FLTOVF: oss << " (floating point overflow)"; break; case FPE_FLTUND: oss << " (floating point underflow)"; break; case FPE_FLTRES: oss << " (floating point inexact result)"; break; case FPE_FLTINV: oss << " (floating point invalid operation)"; break; default: break; } } break; case SIGILL: oss << "Illegal instruction"; if (info) { switch (info->si_code) { case ILL_ILLOPC: oss << " (illegal opcode)"; break; case ILL_ILLOPN: oss << " (illegal operand)"; break; case ILL_ILLADR: oss << " (illegal addressing mode)"; break; case ILL_ILLTRP: oss << " (illegal trap)"; break; default: break; } } break; case SIGBUS: oss << "Bus error"; if (info) { switch (info->si_code) { case BUS_ADRALN: oss << " (invalid address alignment)"; break; case BUS_ADRERR: oss << " (non-existent physical address)"; break; case BUS_OBJERR: oss << " (object specific hardware error)"; break; default: break; } } break; case SIGSYS: oss << "Bad system call"; break; case SIGPIPE: oss << "Broken pipe"; break; case SIGQUIT: oss << "Quit signal"; break; default: oss << "Unknown signal (" << sig << ")"; break; } return oss.str(); } // 获取当前时间戳 std::string AutoDmp::getCurrentTimestamp() { auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); auto ms = std::chrono::duration_cast( now.time_since_epoch()) % 1000; std::tm* tm = std::localtime(&time_t); std::ostringstream oss; oss << std::put_time(tm, "%Y%m%d-%H%M%S") << "." << std::setfill('0') << std::setw(3) << ms.count(); return oss.str(); } // 获取进程名 std::string AutoDmp::getProcessName() { std::string processName = "Unknown"; char buffer[PATH_MAX]; ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1); if (len > 0) { buffer[len] = '\0'; std::string fullPath = buffer; size_t pos = fullPath.find_last_of('/'); if (pos != std::string::npos) { processName = fullPath.substr(pos + 1); } } return processName; } // 创建目录 bool AutoDmp::createDirectory(const std::string& path) { if (path.empty()) return false; return (mkdir(path.c_str(), 0755) == 0) || (errno == EEXIST); } // 清理旧文件 void AutoDmp::cleanupOldFiles(const std::string& directory, size_t maxFiles) { if (maxFiles == 0) return; std::vector> files; DIR* dir = opendir(directory.c_str()); if (dir) { struct dirent* entry; while ((entry = readdir(dir)) != nullptr) { std::string filename = entry->d_name; if (filename.find("crash_") == 0 && filename.find(".log") != std::string::npos) { std::string fullPath = directory + "/" + filename; struct stat fileStat; if (stat(fullPath.c_str(), &fileStat) == 0) { files.emplace_back(fullPath, fileStat.st_mtime); } } } closedir(dir); } // 按时间排序,最新的在前 std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); // 删除超过限制的文件 for (size_t i = maxFiles; i < files.size(); ++i) { std::remove(files[i].first.c_str()); } } // 写入崩溃日志 void AutoDmp::writeCrashLog(const CrashInfo& crashInfo, const std::string& filePath) { std::ofstream logFile(filePath, std::ios::app); if (!logFile.is_open()) return; logFile << "==================== LINUX CRASH REPORT ====================\n"; logFile << "Timestamp: " << crashInfo.timestamp << "\n"; logFile << "Process: " << crashInfo.processName << " (PID: " << crashInfo.processId << ")\n"; logFile << "Thread ID: " << crashInfo.threadId << "\n"; logFile << "Build Info: " << crashInfo.buildInfo << "\n"; logFile << "Signal: " << crashInfo.signalName << " (" << crashInfo.signalNumber << ")\n"; logFile << "Signal Description: " << crashInfo.signalDescription << "\n"; logFile << "Fault Address: " << crashInfo.faultAddress << "\n"; logFile << "\nDetailed Backtrace:\n"; logFile << crashInfo.backtrace << "\n"; logFile << "============================================================\n\n"; logFile.close(); } // 输出详细信息 void AutoDmp::outputDetailedInfo(const CrashInfo& crashInfo) { std::cerr << "\n========== DETAILED CRASH INFORMATION ==========\n"; std::cerr << "Timestamp: " << crashInfo.timestamp << "\n"; std::cerr << "Process: " << crashInfo.processName << " (PID: " << crashInfo.processId << ")\n"; std::cerr << "Thread: " << crashInfo.threadId << "\n"; std::cerr << "Build: " << crashInfo.buildInfo << "\n"; std::cerr << "Signal: " << crashInfo.signalDescription << "\n"; std::cerr << "Address: " << crashInfo.faultAddress << "\n"; std::cerr << "\nBacktrace:\n" << crashInfo.backtrace; std::cerr << "===============================================\n\n"; } // 初始化处理器 bool AutoDmp::initializeHandlers() { if (!createDirectory(config_.crashDirectory)) { return false; } // 设置 core dump if (config_.enableCoreDump) { setupCoreDump(); } // 安装信号处理器 struct sigaction sa; sa.sa_sigaction = signalHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO | SA_RESTART; bool success = true; for (size_t i = 0; i < handledSignalCount_; ++i) { if (sigaction(handledSignals_[i], &sa, &oldActions_[i]) != 0) { success = false; } } return success; } // 清理处理器 void AutoDmp::cleanupHandlers() { for (size_t i = 0; i < handledSignalCount_; ++i) { sigaction(handledSignals_[i], &oldActions_[i], nullptr); } } // 获取实例配置 const CrashConfig* AutoDmp::getInstanceConfig() { return instance_ ? &instance_->config_ : nullptr; } // 生成测试崩溃 bool AutoDmp::generateTestCrash() const { if (!initialized_.load()) { return false; } // 触发一个安全的测试信号 raise(SIGUSR1); return true; } // 更新配置 void AutoDmp::updateConfig(const CrashConfig& newConfig) { config_ = newConfig; createDirectory(config_.crashDirectory); } // 获取支持的信号列表 const int* AutoDmp::getSupportedSignals() { return handledSignals_; } size_t AutoDmp::getSupportedSignalCount() { return handledSignalCount_; }