123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- #include "AutoDmp.h"
- #include <iostream>
- #include <sstream>
- #include <fstream>
- #include <iomanip>
- #include <chrono>
- #include <algorithm>
- #include <vector>
- #include <cstring>
- #include <ctime>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <errno.h>
- #include <dlfcn.h>
- // 静态成员初始化
- 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<std::chrono::milliseconds>(
- 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<std::pair<std::string, std::time_t>> 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_;
- }
|