当前位置: 首页 > news >正文

基于SEH的异常捕获与MiniDumpWriteDump深度解析

基于SEH的异常捕获与MiniDumpWriteDump深度解析

本文将深入探讨SEH异常捕获与MiniDumpWriteDump的结合使用,重点分析其原理、实现机制、常见问题及解决方案。

1. 整体架构与工作原理

1.1 异常捕获与Dump生成流程

程序执行↓
发生异常(硬件/软件)↓
SEH异常分发机制↓
自定义异常过滤器被调用↓
调用MiniDumpWriteDump生成Dump↓
决定异常处理结果(继续执行/终止)

1.2 核心组件交互

// 关键数据结构关系
EXCEPTION_POINTERS├── EXCEPTION_RECORD* ExceptionRecord└── CONTEXT* ContextRecord↓
MINIDUMP_EXCEPTION_INFORMATION├── DWORD ThreadId├── PEXCEPTION_POINTERS ExceptionPointers  └── BOOL ClientPointers↓
MiniDumpWriteDump(...)

2. SEH异常捕获详细实现

2.1 完整的异常处理框架

#include <Windows.h>
#include <DbgHelp.h>
#include <TlHelp32.h>
#include <iostream>
#include <string>#pragma comment(lib, "DbgHelp.lib")class CrashDumper {
private:static std::string m_dumpPath;static MINIDUMP_TYPE m_dumpType;public:// 初始化异常处理static bool Initialize(const std::string& dumpDirectory = "") {// 设置Dump文件路径if (dumpDirectory.empty()) {char modulePath[MAX_PATH];GetModuleFileNameA(NULL, modulePath, MAX_PATH);m_dumpPath = std::string(modulePath) + ".dmp";} else {m_dumpPath = dumpDirectory + "\\CrashDump.dmp";}// 设置Dump类型(包含尽可能多的信息)m_dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory |              // 完整内存MiniDumpWithHandleData |              // 句柄信息MiniDumpWithUnloadedModules |         // 未加载模块MiniDumpWithProcessThreadData |       // 进程线程数据MiniDumpWithThreadInfo |              // 线程详细信息MiniDumpWithCodeSegs |                // 代码段MiniDumpWithDataSegs                  // 数据段);// 设置全局异常过滤器SetUnhandledExceptionFilter(UnhandledExceptionHandler);// 设置C++异常处理(可选)SetPureCallHandler(PureCallHandler);SetInvalidParameterHandler(InvalidParameterHandler);// 初始化符号处理(用于更好的堆栈信息)SymInitialize(GetCurrentProcess(), NULL, TRUE);return true;}private:// 未处理异常过滤器(核心函数)static LONG WINAPI UnhandledExceptionHandler(PEXCEPTION_POINTERS exceptionInfo) {// 立即记录异常基本信息LogExceptionInfo(exceptionInfo);// 生成Dump文件bool dumpSuccess = GenerateCrashDump(exceptionInfo);// 记录处理结果LogCrashResult(dumpSuccess, exceptionInfo);// 额外措施:尝试保存应用程序状态SaveApplicationState();// 返回异常处理结果return GetExceptionHandlingResult(exceptionInfo);}// 生成崩溃Dump文件static bool GenerateCrashDump(PEXCEPTION_POINTERS exceptionInfo) {HANDLE hDumpFile = INVALID_HANDLE_VALUE;bool success = false;__try {// 创建Dump文件hDumpFile = CreateFileA(m_dumpPath.c_str(),GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);if (hDumpFile == INVALID_HANDLE_VALUE) {LogError("无法创建Dump文件: " + std::to_string(GetLastError()));return false;}// 准备异常信息结构MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo;dumpExceptionInfo.ThreadId = GetCurrentThreadId();dumpExceptionInfo.ExceptionPointers = exceptionInfo;dumpExceptionInfo.ClientPointers = FALSE;  // 使用调用进程的地址空间// 生成MiniDumpsuccess = MiniDumpWriteDump(GetCurrentProcess(),           // 目标进程GetCurrentProcessId(),         // 目标进程IDhDumpFile,                     // 输出文件m_dumpType,                    // Dump类型&dumpExceptionInfo,            // 异常信息NULL,                          // 用户流信息NULL                           // 回调函数);if (!success) {DWORD error = GetLastError();LogError("MiniDumpWriteDump失败: " + std::to_string(error));// 尝试使用更简单的Dump类型success = FallbackDumpGeneration(hDumpFile, exceptionInfo);}} __except(EXCEPTION_EXECUTE_HANDLER) {// 如果在生成Dump过程中发生异常,记录错误LogError("在生成Dump过程中发生异常");success = false;}if (hDumpFile != INVALID_HANDLE_VALUE) {CloseHandle(hDumpFile);}return success;}// 备用Dump生成方案static bool FallbackDumpGeneration(HANDLE hFile, PEXCEPTION_POINTERS exceptionInfo) {// 尝试使用基本Dump类型MINIDUMP_TYPE basicDumpType = MiniDumpNormal;MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo;dumpExceptionInfo.ThreadId = GetCurrentThreadId();dumpExceptionInfo.ExceptionPointers = exceptionInfo;dumpExceptionInfo.ClientPointers = FALSE;return MiniDumpWriteDump(GetCurrentProcess(),GetCurrentProcessId(),hFile,basicDumpType,&dumpExceptionInfo,NULL,NULL);}// C++纯虚函数调用处理static void PureCallHandler() {// 生成一个特殊的异常记录EXCEPTION_RECORD exceptionRecord = {};exceptionRecord.ExceptionCode = 0xE06D7363; // C++异常代码exceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;EXCEPTION_POINTERS exceptionPointers = {};exceptionPointers.ExceptionRecord = &exceptionRecord;UnhandledExceptionHandler(&exceptionPointers);}// 无效参数处理static void InvalidParameterHandler(const wchar_t* expression,const wchar_t* function, const wchar_t* file,unsigned int line,uintptr_t reserved) {// 记录参数错误信息LogError("无效参数调用: " + std::string(function) + " in " + std::string(file));// 触发访问违规以生成Dumpint* p = nullptr;*p = 0;}// 记录异常信息static void LogExceptionInfo(PEXCEPTION_POINTERS exceptionInfo) {PEXCEPTION_RECORD record = exceptionInfo->ExceptionRecord;std::string logMsg = "异常信息:\n";logMsg += "  代码: 0x" + ToHexString(record->ExceptionCode) + "\n";logMsg += "  地址: 0x" + ToHexString((DWORD)record->ExceptionAddress) + "\n";logMsg += "  标志: 0x" + ToHexString(record->ExceptionFlags) + "\n";LogToFile(logMsg);}// 工具函数static std::string ToHexString(DWORD value) {char buffer[16];sprintf_s(buffer, "%08X", value);return std::string(buffer);}static void LogError(const std::string& message) {LogToFile("错误: " + message);}static void LogToFile(const std::string& message) {// 简化实现 - 实际应用中应该写入日志文件OutputDebugStringA(message.c_str());}static void LogCrashResult(bool dumpSuccess, PEXCEPTION_POINTERS exceptionInfo) {std::string result = dumpSuccess ? "Dump文件生成成功: " + m_dumpPath : "Dump文件生成失败";LogToFile(result);}static void SaveApplicationState() {// 保存应用程序状态的简化实现// 实际应用中可以保存用户数据、配置等LogToFile("尝试保存应用程序状态...");}static LONG GetExceptionHandlingResult(PEXCEPTION_POINTERS exceptionInfo) {// 根据异常类型决定处理方式switch (exceptionInfo->ExceptionRecord->ExceptionCode) {case EXCEPTION_STACK_OVERFLOW:case EXCEPTION_ACCESS_VIOLATION:// 严重异常,终止程序return EXCEPTION_EXECUTE_HANDLER;case EXCEPTION_BREAKPOINT:// 断点异常,可能希望继续调试return EXCEPTION_CONTINUE_SEARCH;default:// 其他异常,终止程序return EXCEPTION_EXECUTE_HANDLER;}}
};// 静态成员初始化
std::string CrashDumper::m_dumpPath;
MINIDUMP_TYPE CrashDumper::m_dumpType;

3. MiniDumpWriteDump深度解析

3.1 函数参数详细说明

// MiniDumpWriteDump 完整参数分析
BOOL MiniDumpWriteDump(HANDLE hProcess,                    // [in] 目标进程句柄DWORD ProcessId,                    // [in] 目标进程IDHANDLE hFile,                       // [in] 输出文件句柄MINIDUMP_TYPE DumpType,             // [in] Dump类型标志PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,     // [in] 异常信息PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,  // [in] 用户自定义数据流PMINIDUMP_CALLBACK_INFORMATION CallbackParam        // [in] 回调函数
);

3.2 MINIDUMP_TYPE 标志详解

// 常用Dump类型组合
enum DumpTypePresets {// 基本Dump(最小信息)BASIC_DUMP = MiniDumpNormal,// 标准Dump(调试常用)STANDARD_DUMP = (MINIDUMP_TYPE)(MiniDumpWithDataSegs |          // 数据段MiniDumpWithCodeSegs |          // 代码段MiniDumpWithIndirectlyReferencedMemory | // 间接引用内存MiniDumpWithProcessThreadData   // 进程线程数据),// 完整Dump(包含所有信息)COMPLETE_DUMP = (MINIDUMP_TYPE)(MiniDumpWithFullMemory |        // 完整内存MiniDumpWithHandleData |        // 句柄信息MiniDumpWithUnloadedModules |   // 未加载模块MiniDumpWithFullMemoryInfo |    // 完整内存信息MiniDumpWithThreadInfo |        // 线程信息MiniDumpWithCodeSegs |          // 代码段MiniDumpWithDataSegs |          // 数据段MiniDumpWithProcessThreadData   // 进程线程数据)
};// Dump类型选择策略
MINIDUMP_TYPE ChooseDumpType(bool includeFullMemory, bool forProduction) {if (forProduction) {// 生产环境:平衡信息量和文件大小return STANDARD_DUMP;} else if (includeFullMemory) {// 开发调试:需要完整信息return COMPLETE_DUMP;} else {// 默认情况return BASIC_DUMP;}
}

3.3 高级特性:自定义回调函数

// 自定义回调函数实现
class DumpCallback {
public:static BOOL CALLBACK MiniDumpCallback(PVOID CallbackParam,const PMINIDUMP_CALLBACK_INPUT CallbackInput,PMINIDUMP_CALLBACK_OUTPUT CallbackOutput) {switch (CallbackInput->CallbackType) {case IncludeModuleCallback:// 模块包含回调return HandleIncludeModule(CallbackInput, CallbackOutput);case IncludeThreadCallback:// 线程包含回调return HandleIncludeThread(CallbackInput, CallbackOutput);case ModuleCallback:// 模块信息回调return HandleModuleCallback(CallbackInput, CallbackOutput);case ThreadCallback:// 线程信息回调return HandleThreadCallback(CallbackInput, CallbackOutput);case ThreadExCallback:// 扩展线程回调return HandleThreadExCallback(CallbackInput, CallbackOutput);case MemoryCallback:// 内存区域回调return HandleMemoryCallback(CallbackInput, CallbackOutput);default:return TRUE;}}private:static BOOL HandleIncludeModule(const PMINIDUMP_CALLBACK_INPUT Input,PMINIDUMP_CALLBACK_OUTPUT Output) {// 包含所有模块Output->ModuleWriteFlags = ModuleWriteModule | ModuleWriteDataSeg;return TRUE;}static BOOL HandleIncludeThread(const PMINIDUMP_CALLBACK_INPUT Input,PMINIDUMP_CALLBACK_OUTPUT Output) {// 包含所有线程return TRUE;}static BOOL HandleMemoryCallback(const PMINIDUMP_CALLBACK_INPUT Input,PMINIDUMP_CALLBACK_OUTPUT Output) {// 可以在这里过滤或添加特定的内存区域// 例如排除包含敏感数据的内存区域return FALSE; // 不添加额外的内存区域}
};// 使用回调函数的Dump生成
bool GenerateDumpWithCallback(PEXCEPTION_POINTERS exceptionInfo, const std::string& filename) {HANDLE hFile = CreateFileA(filename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE) return false;MINIDUMP_EXCEPTION_INFORMATION exceptionParam = {};exceptionParam.ThreadId = GetCurrentThreadId();exceptionParam.ExceptionPointers = exceptionInfo;exceptionParam.ClientPointers = FALSE;MINIDUMP_CALLBACK_INFORMATION callbackInfo = {};callbackInfo.CallbackRoutine = DumpCallback::MiniDumpCallback;callbackInfo.CallbackParam = NULL;BOOL result = MiniDumpWriteDump(GetCurrentProcess(),GetCurrentProcessId(),hFile,COMPLETE_DUMP,&exceptionParam,NULL,&callbackInfo);CloseHandle(hFile);return result == TRUE;
}

4. 常见问题与解决方案

4.1 权限问题

// 权限检查与提升
class SecurityManager {
public:static bool CheckDumpPermissions(const std::string& dumpPath) {// 检查目标目录是否可写HANDLE hTest = CreateFileA(dumpPath.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (hTest != INVALID_HANDLE_VALUE) {CloseHandle(hTest);DeleteFileA(dumpPath.c_str()); // 删除测试文件return true;}return false;}static bool GetTempDumpPath(std::string& tempPath) {char tempDir[MAX_PATH];if (GetTempPathA(MAX_PATH, tempDir) == 0) {return false;}char tempFile[MAX_PATH];if (GetTempFileNameA(tempDir, "dump", 0, tempFile) == 0) {return false;}// 修改扩展名tempPath = std::string(tempFile);size_t dotPos = tempPath.find_last_of('.');if (dotPos != std::string::npos) {tempPath = tempPath.substr(0, dotPos) + ".dmp";}return true;}
};// 安全的Dump文件生成
bool SafeGenerateDump(PEXCEPTION_POINTERS exceptionInfo) {std::string dumpPath;// 首先尝试程序目录char modulePath[MAX_PATH];GetModuleFileNameA(NULL, modulePath, MAX_PATH);std::string exeDir = GetDirectory(modulePath);dumpPath = exeDir + "\\crash.dmp";if (!SecurityManager::CheckDumpPermissions(dumpPath)) {// 回退到临时目录if (!SecurityManager::GetTempDumpPath(dumpPath)) {return false; // 无法找到可写目录}}return GenerateCrashDump(exceptionInfo, dumpPath);
}std::string GetDirectory(const std::string& path) {size_t lastSlash = path.find_last_of("\\/");if (lastSlash != std::string::npos) {return path.substr(0, lastSlash);}return "";
}

4.2 栈溢出处理

// 栈溢出安全处理
class StackOverflowHandler {
private:static ULONG_PTR s_originalStackLimit;static bool s_stackGuardEnabled;public:static bool EnableStackProtection() {// 获取当前线程栈信息ULONG_PTR stackBase, stackLimit;GetCurrentThreadStackLimits(&stackBase, &stackLimit);// 设置栈保护页s_originalStackLimit = stackLimit;ULONG_PTR newStackLimit = stackLimit + 4096; // 保留1页作为缓冲if (SetThreadStackGuarantee((PULONG)&newStackLimit)) {s_stackGuardEnabled = true;return true;}return false;}static void HandleStackOverflow(PEXCEPTION_POINTERS exceptionInfo) {if (exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {// 栈溢出时使用独立的栈空间DWORD newStackSize = 64 * 1024; // 64KB应急栈PVOID emergencyStack = VirtualAlloc(NULL, newStackSize, MEM_COMMIT, PAGE_READWRITE);if (emergencyStack) {// 切换到应急栈生成DumpGenerateDumpOnEmergencyStack(exceptionInfo, emergencyStack, newStackSize);VirtualFree(emergencyStack, 0, MEM_RELEASE);}}}private:static void __declspec(naked) GenerateDumpOnEmergencyStack(PEXCEPTION_POINTERS exceptionInfo, PVOID stack, DWORD stackSize) {__asm {// 保存当前栈指针mov eax, esppush eax// 切换到应急栈mov esp, [stack]add esp, [stackSize]sub esp, 4  // 栈对齐// 调用Dump生成函数push [exceptionInfo]call GenerateCrashDumpadd esp, 4// 恢复原栈指针pop espret}}
};

4.3 死锁和超时处理

// 超时控制的Dump生成
class TimeoutProtectedDumper {
private:static const DWORD MAX_DUMP_TIME_MS = 10000; // 10秒超时public:static bool GenerateDumpWithTimeout(PEXCEPTION_POINTERS exceptionInfo, const std::string& filename) {HANDLE hThread = CreateThread(NULL, 0, DumpThreadProc, new DumpThreadParams{exceptionInfo, filename}, CREATE_SUSPENDED, NULL);if (!hThread) return false;// 设置线程优先级(避免被死锁影响)SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);// 启动线程ResumeThread(hThread);// 等待完成或超时DWORD result = WaitForSingleObject(hThread, MAX_DUMP_TIME_MS);if (result == WAIT_TIMEOUT) {// 超时,终止线程TerminateThread(hThread, 1);CloseHandle(hThread);return false;}CloseHandle(hThread);return result == WAIT_OBJECT_0;}private:struct DumpThreadParams {PEXCEPTION_POINTERS ExceptionInfo;std::string Filename;};static DWORD WINAPI DumpThreadProc(LPVOID param) {auto* pParams = static_cast<DumpThreadParams*>(param);bool success = GenerateCrashDump(pParams->ExceptionInfo, pParams->Filename);delete pParams;return success ? 0 : 1;}
};

4.4 符号和调试信息处理

// 符号处理增强
class SymbolEnhancer {
public:static bool InitializeSymbols() {SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME |SYMOPT_INCLUDE_32BIT_MODULES);return SymInitialize(GetCurrentProcess(), NULL, TRUE);}static void CleanupSymbols() {SymCleanup(GetCurrentProcess());}static bool AddSymbolSearchPath(const std::string& path) {return SymSetSearchPath(GetCurrentProcess(), path.c_str());}static std::string GetSymbolPath() {char symbolPath[4096];if (SymGetSearchPath(GetCurrentProcess(), symbolPath, sizeof(symbolPath))) {return std::string(symbolPath);}return "";}
};// 增强的Dump生成
bool GenerateEnhancedDump(PEXCEPTION_POINTERS exceptionInfo) {// 初始化符号支持SymbolEnhancer::InitializeSymbols();// 添加常用符号路径SymbolEnhancer::AddSymbolSearchPath("SRV*C:\\Symbols*http://msdl.microsoft.com/download/symbols");bool success = GenerateCrashDump(exceptionInfo);// 清理符号SymbolEnhancer::CleanupSymbols();return success;
}

5. 最佳实践总结

5.1 部署建议

// 生产环境配置
class ProductionCrashHandler {
public:static void ConfigureForProduction() {// 设置适当的Dump类型(平衡信息量和大小)MINIDUMP_TYPE productionDumpType = (MINIDUMP_TYPE)(MiniDumpWithProcessThreadData |MiniDumpWithThreadInfo |MiniDumpWithUnloadedModules);// 配置Dump文件位置std::string dumpDir = GetAppDataPath() + "\\CrashDumps";CreateDirectoryA(dumpDir.c_str(), NULL);// 初始化崩溃处理CrashDumper::Initialize(dumpDir);// 设置栈保护StackOverflowHandler::EnableStackProtection();}private:static std::string GetAppDataPath() {char appDataPath[MAX_PATH];if (SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, appDataPath) == S_OK) {return std::string(appDataPath);}return "";}
};

5.2 测试验证

// 测试异常处理系统
class CrashHandlerTester {
public:static void TestAccessViolation() {std::cout << "测试访问违规处理..." << std::endl;int* ptr = nullptr;*ptr = 42; // 触发访问违规}static void TestStackOverflow() {std::cout << "测试栈溢出处理..." << std::endl;StackOverflowTest(); // 递归函数导致栈溢出}static void TestDivideByZero() {std::cout << "测试除零处理..." << std::endl;int zero = 0;int result = 100 / zero;}private:static void StackOverflowTest(int depth = 0) {char buffer[1024]; // 消耗栈空间if (depth < 1000) { // 确保足够深度StackOverflowTest(depth + 1);}}
};

通过以上详细实现和分析,可以构建一个健壮的基于SEH的异常捕获和MiniDump生成系统,能够有效处理各种崩溃场景,为后续的问题诊断提供完整的信息。

http://www.dtcms.com/a/528147.html

相关文章:

  • C语言练习题
  • Postman应用实战
  • Vue-Loader 深度解析:原理、使用与最佳实践
  • HCIP第二次作业(VRRP/STP/VLAN/Eth-trunk/NAT)
  • 外国设计网站推荐自己学网站建设
  • ASP.NET Core中创建中间件的几种方式
  • Docker安装思源笔记使用指南
  • 需求登记网站怎么做免费高清图片素材网站推荐
  • SpringBoot集成Elasticsearch | Java High Level Rest Client(HLRC)方式
  • 《神领物流》day07-线路规划之线路管理_完整代码【简单易懂注释版】
  • 使用Ansys Polyflow对泡沫聚合物挤出进行建模
  • 【组成原理·硬件】6总线
  • Spring Boot3零基础教程,整合 SSM,笔记52
  • 序列化详解
  • 网站设计制作电影福建网站建设公司
  • 记录一次Oracle日志listener.log文件大小超过4G后出现Tomcat服务启动一直报错的原因【ORACLE】
  • Docker Desktop快速搭建本地k8s集群
  • LabVIEW超高分辨显微成像系统
  • 东莞建网站的公破解付费wordpress主题
  • 国产数据库破局:金仓数据库如何无缝替代MongoDB支撑2TB政务数据
  • Switch 20.5.0系统最新PSP模拟器懒人包
  • 怎么做网上直营店网站php素材网站源码免费下载
  • 巡检机器人户外视觉识别困境剖析与自动优化模式构建
  • C++ - 异常
  • C++笔记(面向对象)深赋值 浅赋值
  • 数据库在什么情况下会发生数据库死锁
  • 如何将Word文档精确转换为图片型PDF?
  • Auto CAD二次开发——封装事务处理函数并绘制直线函数
  • C4D域力场重要概念之点对象、粒子对象和通道转换
  • 车载诊断架构 ---关于Service 29证书认证与整车时间同步的问题带来的深思