|
@@ -1,173 +1,483 @@
|
|
|
-#include "StdAfx.h"
|
|
|
#include "AutoDmp.h"
|
|
|
-
|
|
|
-#include <string>
|
|
|
+#include <iostream>
|
|
|
#include <sstream>
|
|
|
-
|
|
|
-//-----------------dmp文件生成相关--------------------------------------------
|
|
|
-using namespace std;
|
|
|
-
|
|
|
-#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS (0x00000004)
|
|
|
-#define MiniDumpWithThreadInfo 0x1000
|
|
|
-
|
|
|
-typedef BOOL(WINAPI *PGetModuleHandleEx)(DWORD dwFlags, LPCTSTR lpModuleName, HMODULE *phModule);
|
|
|
-
|
|
|
-string GetProcessDirectoryDump()
|
|
|
-{
|
|
|
- string ret = "";
|
|
|
- char szFilename[MAX_PATH] = { 0 };
|
|
|
- DWORD res = GetModuleFileNameA(0, szFilename, MAX_PATH);
|
|
|
- if (res == 0)
|
|
|
- {
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- string fullpath = szFilename;
|
|
|
- string::size_type firstHit = fullpath.find_last_of('\\');
|
|
|
- if (firstHit == string::npos || firstHit == 0)
|
|
|
- {
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- ret = fullpath.substr(0, firstHit);//kick last \
|
|
|
-
|
|
|
- return ret;
|
|
|
+#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);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-VOID CreateDump(struct _EXCEPTION_POINTERS *pExceptionPointers)
|
|
|
-{
|
|
|
- //收集信息
|
|
|
- string strBuild;
|
|
|
-
|
|
|
- unsigned int ret1 = 0;
|
|
|
-
|
|
|
- HANDLE hDumpFile;
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- std::stringstream strm;
|
|
|
- strm << "Build: " << __DATE__ << " " << __TIME__;
|
|
|
- strm >> strBuild;
|
|
|
-
|
|
|
- //strBuild.Format(L"Build: %s %s", __DATE__, __TIME__);
|
|
|
- string strError;
|
|
|
- HMODULE hModule;
|
|
|
- char szModuleName[MAX_PATH] = { 0 };
|
|
|
-
|
|
|
+// 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");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 瑙﹀彂榛樿�澶勭悊锛堢敓鎴恈ore dump骞剁粓姝㈣繘绋嬶級
|
|
|
+ raise(sig);
|
|
|
+}
|
|
|
|
|
|
- GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)pExceptionPointers->ExceptionRecord->ExceptionAddress, &hModule);
|
|
|
- GetModuleFileName(hModule, szModuleName, ARRAYSIZE(szModuleName));
|
|
|
+// 寮傛�瀹夊叏鐨勫啓鍏ュ嚱鏁�
|
|
|
+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';
|
|
|
|
|
|
- strm.clear();
|
|
|
- strm << szModuleName << ", " << pExceptionPointers->ExceptionRecord->ExceptionCode << ", " << pExceptionPointers->ExceptionRecord->ExceptionFlags << ", " << pExceptionPointers->ExceptionRecord->ExceptionAddress;
|
|
|
- strm >> strError;
|
|
|
+ bool negative = number < 0;
|
|
|
+ if (negative) number = -number;
|
|
|
|
|
|
- //生成 mini crash dump
|
|
|
- BOOL bMiniDumpSuccessful;
|
|
|
+ if (number == 0) {
|
|
|
+ *--p = '0';
|
|
|
+ } else {
|
|
|
+ while (number > 0) {
|
|
|
+ *--p = '0' + (number % 10);
|
|
|
+ number /= 10;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- DWORD dwBufferSize = MAX_PATH;
|
|
|
- SYSTEMTIME stLocalTime;
|
|
|
- MINIDUMP_EXCEPTION_INFORMATION ExpParam;
|
|
|
- GetLocalTime(&stLocalTime);
|
|
|
+ if (negative) {
|
|
|
+ *--p = '-';
|
|
|
+ }
|
|
|
|
|
|
- char szFileName[MAX_PATH] = { 0 };
|
|
|
- sprintf_s(szFileName, MAX_PATH, "%04d%02d%02d-%02d%02d%02d-ProcessID[%ld]-ThreadID[%ld].dmp",
|
|
|
- stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
|
|
|
- stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
|
|
|
- GetCurrentProcessId(), GetCurrentThreadId());
|
|
|
+ safeWriteToFd(fd, p);
|
|
|
+}
|
|
|
|
|
|
- std::string strDmppath = GetProcessDirectoryDump();
|
|
|
- strDmppath += string("\\");
|
|
|
- strDmppath.append(szFileName);
|
|
|
+void AutoDmp::safeWritePointer(int fd, void* ptr) {
|
|
|
+ char buffer[32];
|
|
|
+ snprintf(buffer, sizeof(buffer), "%p", ptr);
|
|
|
+ safeWriteToFd(fd, buffer);
|
|
|
+}
|
|
|
|
|
|
- hDumpFile = CreateFile(strDmppath.c_str(), GENERIC_READ | GENERIC_WRITE,
|
|
|
- FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
|
|
|
+// 鑾峰彇璋冪敤鏍�
|
|
|
+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();
|
|
|
+}
|
|
|
|
|
|
- MINIDUMP_USER_STREAM UserStream[2];
|
|
|
- MINIDUMP_USER_STREAM_INFORMATION UserInfo;
|
|
|
- UserInfo.UserStreamCount = 1;
|
|
|
- UserInfo.UserStreamArray = UserStream;
|
|
|
- UserStream[0].Type = CommentStreamA;
|
|
|
- UserStream[0].BufferSize = strBuild.size();
|
|
|
- UserStream[0].Buffer = (PVOID)strBuild.c_str();
|
|
|
- UserStream[1].Type = CommentStreamA;
|
|
|
- UserStream[1].BufferSize = strError.size();
|
|
|
- UserStream[1].Buffer = (PVOID)strError.c_str();
|
|
|
+// 璁剧疆 core dump
|
|
|
+bool AutoDmp::setupCoreDump() {
|
|
|
+ struct rlimit coreLimit;
|
|
|
+ coreLimit.rlim_cur = RLIM_INFINITY;
|
|
|
+ coreLimit.rlim_max = RLIM_INFINITY;
|
|
|
|
|
|
- ExpParam.ThreadId = GetCurrentThreadId();
|
|
|
- ExpParam.ExceptionPointers = pExceptionPointers;
|
|
|
- ExpParam.ClientPointers = TRUE;
|
|
|
+ return setrlimit(RLIMIT_CORE, &coreLimit) == 0;
|
|
|
+}
|
|
|
|
|
|
- MINIDUMP_TYPE MiniDumpWithDataSegs = (MINIDUMP_TYPE)(MiniDumpNormal
|
|
|
- | MiniDumpWithHandleData
|
|
|
- | MiniDumpWithUnloadedModules
|
|
|
- | MiniDumpWithIndirectlyReferencedMemory
|
|
|
- | MiniDumpScanMemory
|
|
|
- | MiniDumpWithProcessThreadData
|
|
|
- | MiniDumpWithThreadInfo);
|
|
|
+// 鑾峰彇淇″彿鍚�
|
|
|
+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";
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
|
|
|
- hDumpFile, MiniDumpWithDataSegs, &ExpParam, &UserInfo, NULL);
|
|
|
+// 鑾峰彇淇″彿鎻忚堪
|
|
|
+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();
|
|
|
+}
|
|
|
|
|
|
- return;
|
|
|
+// 鑾峰彇褰撳墠鏃堕棿鎴�
|
|
|
+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;
|
|
|
+}
|
|
|
|
|
|
-LONG WINAPI AutoDmp::NewUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *lpExceptionInfo)
|
|
|
-{
|
|
|
- CreateDump(lpExceptionInfo);
|
|
|
- return EXCEPTION_EXECUTE_HANDLER;
|
|
|
+// 鍒涘缓鐩�綍
|
|
|
+bool AutoDmp::createDirectory(const std::string& path) {
|
|
|
+ if (path.empty()) return false;
|
|
|
+ return (mkdir(path.c_str(), 0755) == 0) || (errno == EEXIST);
|
|
|
}
|
|
|
|
|
|
-AutoDmp::AutoDmp()
|
|
|
-{
|
|
|
- SetUnhandledExceptionFilter(NewUnhandledExceptionFilter);
|
|
|
+// 娓呯悊鏃ф枃浠�
|
|
|
+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());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-AutoDmp::~AutoDmp()
|
|
|
-{
|
|
|
+// 鍐欏叆宕╂簝鏃ュ織
|
|
|
+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";
|
|
|
}
|
|
|
|
|
|
-//dmp生成参考资料
|
|
|
-//http://www.sjsjw.com/kf_other/article/031086ABA018049.asp
|
|
|
+// 鍒濆�鍖栧�鐞嗗櫒
|
|
|
+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);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-//在win7 64bit + vs2008 + sdk v7.0的环境下编译Detours
|
|
|
-//http://blog.csdn.net/genesisbible/article/details/6771988
|
|
|
+// 鑾峰彇瀹炰緥閰嶇疆
|
|
|
+const CrashConfig* AutoDmp::getInstanceConfig() {
|
|
|
+ return instance_ ? &instance_->config_ : nullptr;
|
|
|
+}
|
|
|
|
|
|
-//下载编译好的Detours
|
|
|
-//http://download.csdn.net/download/staver102/7648875
|
|
|
+// 鐢熸垚娴嬭瘯宕╂簝
|
|
|
+bool AutoDmp::generateTestCrash() const {
|
|
|
+ if (!initialized_.load()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
+ // 瑙﹀彂涓€涓�畨鍏ㄧ殑娴嬭瘯淇″彿
|
|
|
+ raise(SIGUSR1);
|
|
|
+ return true;
|
|
|
+}
|
|
|
|
|
|
-//DMP文件的使用:
|
|
|
-//把dmp文件和exe, pdb文件放在同一目录下, 然后用编译器(如vc)打开, 然后开始调试就会中断到刚才中断的地方.
|
|
|
+// 鏇存柊閰嶇疆
|
|
|
+void AutoDmp::updateConfig(const CrashConfig& newConfig) {
|
|
|
+ config_ = newConfig;
|
|
|
+ createDirectory(config_.crashDirectory);
|
|
|
+}
|
|
|
|
|
|
-//使用符号服务器
|
|
|
-//您可以使用符号服务器自动下载用于调试 Visual Studio .NET 项目的正确符号。
|
|
|
-//Microsoft 在 http://msdl.microsoft.com/download/symbols 上为开发人员维护了一个公共符号服务器。
|
|
|
-//此服务器为各种操作系统(Windows NT 4.0、Windows 2000、Windows XP 和 Windows Server 2003)、MDAC、IIS、ISA 和 .NET Framework 提供符号。
|
|
|
-//
|
|
|
-//另外,您也可以将本地符号服务器安装在 Intranet 上或本地计算机上。
|
|
|
-//要使用符号服务器,必须在项目中指定正确的服务器路径。
|
|
|
-//
|
|
|
-//设置符号服务器的路径
|
|
|
-//1.在 Visual Studio 中打开该项目。
|
|
|
-//2.在“解决方案资源管理器”视图中选择解决方案的名称。
|
|
|
-//3.从“项目”菜单中选择“设置启动项目”。
|
|
|
-//4.在“解决方案 <项目> 属性页”对话框中,打开“通用属性”文件夹,单击“调试符号文件”。
|
|
|
-//5.在“在这些路径中搜索符号文件”框中创建新的行,方法是双击空的新行或单击“新建行”按钮。
|
|
|
-//6.在新行中输入符号服务器的路径。
|
|
|
-//若要使用 Microsoft 公共符号服务器,请输入:
|
|
|
-//srv*c:\cache*http://msdl.microsoft.com/download/symbols;
|
|
|
-//若要使用 Intranet 符号服务器,请输入:
|
|
|
-//srv*\\server\path\symbols;
|
|
|
-//若要使用本地计算机上的符号服务器,请输入:
|
|
|
-//c:\path\symbols;
|
|
|
-//7.不要单击“检查项”按钮。
|
|
|
-//8.单击“确定”按钮。
|
|
|
-//9.将 symsrv.dll 从 Visual Studio .NET 安装盘复制到 C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE。
|
|
|
+// 鑾峰彇鏀�寔鐨勪俊鍙峰垪琛�
|
|
|
+const int* AutoDmp::getSupportedSignals() {
|
|
|
+ return handledSignals_;
|
|
|
+}
|
|
|
|
|
|
-//-----------------dmp文件生成相关--------------------------------------------
|
|
|
+size_t AutoDmp::getSupportedSignalCount() {
|
|
|
+ return handledSignalCount_;
|
|
|
+}
|