AutoDmp.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. #include "AutoDmp.h"
  2. #include <iostream>
  3. #include <sstream>
  4. #include <fstream>
  5. #include <iomanip>
  6. #include <chrono>
  7. #include <algorithm>
  8. #include <vector>
  9. #include <cstring>
  10. #include <ctime>
  11. #include <sys/stat.h>
  12. #include <sys/types.h>
  13. #include <dirent.h>
  14. #include <errno.h>
  15. #include <dlfcn.h>
  16. // 静态成员初始化
  17. AutoDmp* AutoDmp::instance_ = nullptr;
  18. // Linux 信号处理列表
  19. const int AutoDmp::handledSignals_[] = {
  20. SIGSEGV, // 段错误
  21. SIGABRT, // 异常终止
  22. SIGFPE, // 浮点异常
  23. SIGILL, // 非法指令
  24. SIGBUS, // 总线错误
  25. SIGSYS, // 系统调用错误
  26. SIGPIPE, // 管道错误
  27. SIGQUIT // 退出信号
  28. };
  29. const size_t AutoDmp::handledSignalCount_ = sizeof(handledSignals_) / sizeof(handledSignals_[0]);
  30. // 构造函数
  31. AutoDmp::AutoDmp(const CrashConfig& config) : config_(config) {
  32. if (instance_ == nullptr) {
  33. instance_ = this;
  34. if (initializeHandlers()) {
  35. initialized_.store(true);
  36. }
  37. }
  38. }
  39. // 析构函数
  40. AutoDmp::~AutoDmp() {
  41. if (instance_ == this) {
  42. cleanupHandlers();
  43. instance_ = nullptr;
  44. initialized_.store(false);
  45. }
  46. }
  47. // Linux 信号处理器
  48. void AutoDmp::signalHandler(int sig, siginfo_t* info, void* context) {
  49. // 防止重入
  50. static volatile sig_atomic_t handling = 0;
  51. if (handling || !instance_ || instance_->crashInProgress_.exchange(true)) {
  52. return;
  53. }
  54. handling = 1;
  55. const CrashConfig* config = getInstanceConfig();
  56. if (!config) {
  57. // 恢复默认处理并重新触发
  58. signal(sig, SIG_DFL);
  59. raise(sig);
  60. return;
  61. }
  62. // 使用异步安全的方式输出基本信息
  63. if (config->enableConsoleOutput) {
  64. safeWriteToFd(STDERR_FILENO, "\n*** LINUX CRASH DETECTED ***\n");
  65. safeWriteToFd(STDERR_FILENO, "Signal: ");
  66. safeWriteNumber(STDERR_FILENO, sig);
  67. safeWriteToFd(STDERR_FILENO, " (");
  68. safeWriteToFd(STDERR_FILENO, getSignalName(sig).c_str());
  69. safeWriteToFd(STDERR_FILENO, ")\n");
  70. if (info->si_addr) {
  71. safeWriteToFd(STDERR_FILENO, "Fault Address: ");
  72. safeWritePointer(STDERR_FILENO, info->si_addr);
  73. safeWriteToFd(STDERR_FILENO, "\n");
  74. }
  75. safeWriteToFd(STDERR_FILENO, "Process ID: ");
  76. safeWriteNumber(STDERR_FILENO, getpid());
  77. safeWriteToFd(STDERR_FILENO, "\n");
  78. safeWriteToFd(STDERR_FILENO, "Thread ID: ");
  79. safeWriteNumber(STDERR_FILENO, syscall(SYS_gettid));
  80. safeWriteToFd(STDERR_FILENO, "\n");
  81. // 输出调用栈到stderr(异步安全)
  82. if (config->enableBacktrace) {
  83. safeWriteToFd(STDERR_FILENO, "\nBacktrace:\n");
  84. void* frames[128];
  85. int numFrames = backtrace(frames, 128);
  86. if (numFrames > 0) {
  87. backtrace_symbols_fd(frames, numFrames, STDERR_FILENO);
  88. }
  89. }
  90. safeWriteToFd(STDERR_FILENO, "****************************\n\n");
  91. }
  92. // 设置 core dump
  93. if (config->enableCoreDump) {
  94. setupCoreDump();
  95. }
  96. // 恢复默认信号处理并重新触发
  97. struct sigaction sa;
  98. sa.sa_handler = SIG_DFL;
  99. sigemptyset(&sa.sa_mask);
  100. sa.sa_flags = 0;
  101. sigaction(sig, &sa, nullptr);
  102. // 如果不是在异步安全模式,尝试写入详细日志
  103. if (!config->asyncSafeOnly) {
  104. try {
  105. // 收集详细崩溃信息
  106. CrashInfo crashInfo;
  107. crashInfo.timestamp = getCurrentTimestamp();
  108. crashInfo.processName = getProcessName();
  109. crashInfo.processId = getpid();
  110. crashInfo.threadId = syscall(SYS_gettid);
  111. crashInfo.buildInfo = std::string(__DATE__) + " " + __TIME__;
  112. crashInfo.signalNumber = sig;
  113. crashInfo.signalName = getSignalName(sig);
  114. crashInfo.faultAddress = info->si_addr;
  115. crashInfo.signalDescription = getSignalDescription(sig, info);
  116. crashInfo.backtrace = getBacktrace(context, config->maxBacktraceDepth);
  117. // 确保目录存在
  118. createDirectory(config->crashDirectory);
  119. // 写入详细日志
  120. if (config->enableLogFile) {
  121. std::string logFileName = "crash_" + crashInfo.timestamp + ".log";
  122. std::string logPath = config->crashDirectory + "/" + logFileName;
  123. writeCrashLog(crashInfo, logPath);
  124. cleanupOldFiles(config->crashDirectory, config->maxCrashFiles);
  125. }
  126. // 输出详细信息到控制台
  127. if (config->enableDetailedInfo && config->enableConsoleOutput) {
  128. outputDetailedInfo(crashInfo);
  129. }
  130. } catch (...) {
  131. // 在信号处理器中不抛出异常
  132. safeWriteToFd(STDERR_FILENO, "Warning: Failed to write detailed crash log\n");
  133. }
  134. }
  135. // 触发默认处理(生成core dump并终止进程)
  136. raise(sig);
  137. }
  138. // 异步安全的写入函数
  139. void AutoDmp::safeWriteToFd(int fd, const char* msg) {
  140. if (msg) {
  141. size_t len = strlen(msg);
  142. write(fd, msg, len);
  143. }
  144. }
  145. void AutoDmp::safeWriteNumber(int fd, long number) {
  146. char buffer[32];
  147. char* p = buffer + sizeof(buffer) - 1;
  148. *p = '\0';
  149. bool negative = number < 0;
  150. if (negative) number = -number;
  151. if (number == 0) {
  152. *--p = '0';
  153. } else {
  154. while (number > 0) {
  155. *--p = '0' + (number % 10);
  156. number /= 10;
  157. }
  158. }
  159. if (negative) {
  160. *--p = '-';
  161. }
  162. safeWriteToFd(fd, p);
  163. }
  164. void AutoDmp::safeWritePointer(int fd, void* ptr) {
  165. char buffer[32];
  166. snprintf(buffer, sizeof(buffer), "%p", ptr);
  167. safeWriteToFd(fd, buffer);
  168. }
  169. // 获取调用栈
  170. std::string AutoDmp::getBacktrace(void* context, size_t maxDepth) {
  171. void* frames[maxDepth];
  172. int numFrames = backtrace(frames, maxDepth);
  173. if (numFrames <= 0) {
  174. return "Unable to get backtrace";
  175. }
  176. // 获取符号信息
  177. char** symbols = backtrace_symbols(frames, numFrames);
  178. if (!symbols) {
  179. return "Unable to get symbol information";
  180. }
  181. std::ostringstream oss;
  182. for (int i = 0; i < numFrames; ++i) {
  183. oss << "#" << std::setw(2) << std::setfill('0') << i
  184. << ": " << symbols[i] << "\n";
  185. }
  186. free(symbols);
  187. return oss.str();
  188. }
  189. // 设置 core dump
  190. bool AutoDmp::setupCoreDump() {
  191. struct rlimit coreLimit;
  192. coreLimit.rlim_cur = RLIM_INFINITY;
  193. coreLimit.rlim_max = RLIM_INFINITY;
  194. return setrlimit(RLIMIT_CORE, &coreLimit) == 0;
  195. }
  196. // 获取信号名
  197. std::string AutoDmp::getSignalName(int sig) {
  198. switch (sig) {
  199. case SIGSEGV: return "SIGSEGV";
  200. case SIGABRT: return "SIGABRT";
  201. case SIGFPE: return "SIGFPE";
  202. case SIGILL: return "SIGILL";
  203. case SIGBUS: return "SIGBUS";
  204. case SIGSYS: return "SIGSYS";
  205. case SIGPIPE: return "SIGPIPE";
  206. case SIGQUIT: return "SIGQUIT";
  207. default: return "UNKNOWN";
  208. }
  209. }
  210. // 获取信号描述
  211. std::string AutoDmp::getSignalDescription(int sig, siginfo_t* info) {
  212. std::ostringstream oss;
  213. oss << getSignalName(sig) << " - ";
  214. switch (sig) {
  215. case SIGSEGV:
  216. oss << "Segmentation fault";
  217. if (info) {
  218. switch (info->si_code) {
  219. case SEGV_MAPERR: oss << " (address not mapped)"; break;
  220. case SEGV_ACCERR: oss << " (invalid permissions)"; break;
  221. default: break;
  222. }
  223. }
  224. break;
  225. case SIGABRT:
  226. oss << "Abort signal";
  227. break;
  228. case SIGFPE:
  229. oss << "Floating point exception";
  230. if (info) {
  231. switch (info->si_code) {
  232. case FPE_INTDIV: oss << " (integer divide by zero)"; break;
  233. case FPE_INTOVF: oss << " (integer overflow)"; break;
  234. case FPE_FLTDIV: oss << " (floating point divide by zero)"; break;
  235. case FPE_FLTOVF: oss << " (floating point overflow)"; break;
  236. case FPE_FLTUND: oss << " (floating point underflow)"; break;
  237. case FPE_FLTRES: oss << " (floating point inexact result)"; break;
  238. case FPE_FLTINV: oss << " (floating point invalid operation)"; break;
  239. default: break;
  240. }
  241. }
  242. break;
  243. case SIGILL:
  244. oss << "Illegal instruction";
  245. if (info) {
  246. switch (info->si_code) {
  247. case ILL_ILLOPC: oss << " (illegal opcode)"; break;
  248. case ILL_ILLOPN: oss << " (illegal operand)"; break;
  249. case ILL_ILLADR: oss << " (illegal addressing mode)"; break;
  250. case ILL_ILLTRP: oss << " (illegal trap)"; break;
  251. default: break;
  252. }
  253. }
  254. break;
  255. case SIGBUS:
  256. oss << "Bus error";
  257. if (info) {
  258. switch (info->si_code) {
  259. case BUS_ADRALN: oss << " (invalid address alignment)"; break;
  260. case BUS_ADRERR: oss << " (non-existent physical address)"; break;
  261. case BUS_OBJERR: oss << " (object specific hardware error)"; break;
  262. default: break;
  263. }
  264. }
  265. break;
  266. case SIGSYS:
  267. oss << "Bad system call";
  268. break;
  269. case SIGPIPE:
  270. oss << "Broken pipe";
  271. break;
  272. case SIGQUIT:
  273. oss << "Quit signal";
  274. break;
  275. default:
  276. oss << "Unknown signal (" << sig << ")";
  277. break;
  278. }
  279. return oss.str();
  280. }
  281. // 获取当前时间戳
  282. std::string AutoDmp::getCurrentTimestamp() {
  283. auto now = std::chrono::system_clock::now();
  284. auto time_t = std::chrono::system_clock::to_time_t(now);
  285. auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
  286. now.time_since_epoch()) % 1000;
  287. std::tm* tm = std::localtime(&time_t);
  288. std::ostringstream oss;
  289. oss << std::put_time(tm, "%Y%m%d-%H%M%S")
  290. << "." << std::setfill('0') << std::setw(3) << ms.count();
  291. return oss.str();
  292. }
  293. // 获取进程名
  294. std::string AutoDmp::getProcessName() {
  295. std::string processName = "Unknown";
  296. char buffer[PATH_MAX];
  297. ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1);
  298. if (len > 0) {
  299. buffer[len] = '\0';
  300. std::string fullPath = buffer;
  301. size_t pos = fullPath.find_last_of('/');
  302. if (pos != std::string::npos) {
  303. processName = fullPath.substr(pos + 1);
  304. }
  305. }
  306. return processName;
  307. }
  308. // 创建目录
  309. bool AutoDmp::createDirectory(const std::string& path) {
  310. if (path.empty()) return false;
  311. return (mkdir(path.c_str(), 0755) == 0) || (errno == EEXIST);
  312. }
  313. // 清理旧文件
  314. void AutoDmp::cleanupOldFiles(const std::string& directory, size_t maxFiles) {
  315. if (maxFiles == 0) return;
  316. std::vector<std::pair<std::string, std::time_t>> files;
  317. DIR* dir = opendir(directory.c_str());
  318. if (dir) {
  319. struct dirent* entry;
  320. while ((entry = readdir(dir)) != nullptr) {
  321. std::string filename = entry->d_name;
  322. if (filename.find("crash_") == 0 && filename.find(".log") != std::string::npos) {
  323. std::string fullPath = directory + "/" + filename;
  324. struct stat fileStat;
  325. if (stat(fullPath.c_str(), &fileStat) == 0) {
  326. files.emplace_back(fullPath, fileStat.st_mtime);
  327. }
  328. }
  329. }
  330. closedir(dir);
  331. }
  332. // 按时间排序,最新的在前
  333. std::sort(files.begin(), files.end(),
  334. [](const auto& a, const auto& b) { return a.second > b.second; });
  335. // 删除超过限制的文件
  336. for (size_t i = maxFiles; i < files.size(); ++i) {
  337. std::remove(files[i].first.c_str());
  338. }
  339. }
  340. // 写入崩溃日志
  341. void AutoDmp::writeCrashLog(const CrashInfo& crashInfo, const std::string& filePath) {
  342. std::ofstream logFile(filePath, std::ios::app);
  343. if (!logFile.is_open()) return;
  344. logFile << "==================== LINUX CRASH REPORT ====================\n";
  345. logFile << "Timestamp: " << crashInfo.timestamp << "\n";
  346. logFile << "Process: " << crashInfo.processName << " (PID: " << crashInfo.processId << ")\n";
  347. logFile << "Thread ID: " << crashInfo.threadId << "\n";
  348. logFile << "Build Info: " << crashInfo.buildInfo << "\n";
  349. logFile << "Signal: " << crashInfo.signalName << " (" << crashInfo.signalNumber << ")\n";
  350. logFile << "Signal Description: " << crashInfo.signalDescription << "\n";
  351. logFile << "Fault Address: " << crashInfo.faultAddress << "\n";
  352. logFile << "\nDetailed Backtrace:\n";
  353. logFile << crashInfo.backtrace << "\n";
  354. logFile << "============================================================\n\n";
  355. logFile.close();
  356. }
  357. // 输出详细信息
  358. void AutoDmp::outputDetailedInfo(const CrashInfo& crashInfo) {
  359. std::cerr << "\n========== DETAILED CRASH INFORMATION ==========\n";
  360. std::cerr << "Timestamp: " << crashInfo.timestamp << "\n";
  361. std::cerr << "Process: " << crashInfo.processName << " (PID: " << crashInfo.processId << ")\n";
  362. std::cerr << "Thread: " << crashInfo.threadId << "\n";
  363. std::cerr << "Build: " << crashInfo.buildInfo << "\n";
  364. std::cerr << "Signal: " << crashInfo.signalDescription << "\n";
  365. std::cerr << "Address: " << crashInfo.faultAddress << "\n";
  366. std::cerr << "\nBacktrace:\n" << crashInfo.backtrace;
  367. std::cerr << "===============================================\n\n";
  368. }
  369. // 初始化处理器
  370. bool AutoDmp::initializeHandlers() {
  371. if (!createDirectory(config_.crashDirectory)) {
  372. return false;
  373. }
  374. // 设置 core dump
  375. if (config_.enableCoreDump) {
  376. setupCoreDump();
  377. }
  378. // 安装信号处理器
  379. struct sigaction sa;
  380. sa.sa_sigaction = signalHandler;
  381. sigemptyset(&sa.sa_mask);
  382. sa.sa_flags = SA_SIGINFO | SA_RESTART;
  383. bool success = true;
  384. for (size_t i = 0; i < handledSignalCount_; ++i) {
  385. if (sigaction(handledSignals_[i], &sa, &oldActions_[i]) != 0) {
  386. success = false;
  387. }
  388. }
  389. return success;
  390. }
  391. // 清理处理器
  392. void AutoDmp::cleanupHandlers() {
  393. for (size_t i = 0; i < handledSignalCount_; ++i) {
  394. sigaction(handledSignals_[i], &oldActions_[i], nullptr);
  395. }
  396. }
  397. // 获取实例配置
  398. const CrashConfig* AutoDmp::getInstanceConfig() {
  399. return instance_ ? &instance_->config_ : nullptr;
  400. }
  401. // 生成测试崩溃
  402. bool AutoDmp::generateTestCrash() const {
  403. if (!initialized_.load()) {
  404. return false;
  405. }
  406. // 触发一个安全的测试信号
  407. raise(SIGUSR1);
  408. return true;
  409. }
  410. // 更新配置
  411. void AutoDmp::updateConfig(const CrashConfig& newConfig) {
  412. config_ = newConfig;
  413. createDirectory(config_.crashDirectory);
  414. }
  415. // 获取支持的信号列表
  416. const int* AutoDmp::getSupportedSignals() {
  417. return handledSignals_;
  418. }
  419. size_t AutoDmp::getSupportedSignalCount() {
  420. return handledSignalCount_;
  421. }