Windows下有三种生成dump文件的方式:
1.通过任务管理器和注册表;2.WinDbg抓取;3.程序中加入存储Dump的代码
具体生成方法参看:Windows下dump文件生成与分析
本文详细介绍如何在程序中加入存储dump的代码:
SetUnhandledExceptionFilter
SetUnhandledExceptionFilter设置自己的 Unhandled Exception Filter 用于捕获 Unhandled exceptions 并输出一些信息(例如,创建 mini-dump 或者输出调用栈到日志文件中)。该函数有三个返回值:
EXCEPTION_EXECUTE_HANDLER equ 1 表示我已经处理了异常,可以优雅地结束了
EXCEPTION_CONTINUE_SEARCH equ 0 表示我不处理,其他人来吧,于是windows调用默认的处理程序显示一个错误框,并结束
EXCEPTION_CONTINUE_EXECUTION equ -1 表示错误已经被修复,请从异常发生处继续执行
在程序开始处通过SetUnhandledExceptionFilter设置捕获dump的入口,然后通过MiniDumpWriteDump生成dump文件。
如下程序在程序异常时会自行转储一个名为Test.dmp的dump文件。
// My2019Study.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Shlwapi.h"
#include<Windows.h>
#include<DbgHelp.h>
#pragma comment(lib,"DbgHelp.lib")
// 创建Dump文件
void CreateDumpFile(LPCWSTR lpstrDumpFilePathName, EXCEPTION_POINTERS *pException)
{
HANDLE hDumpFile = CreateFile(lpstrDumpFilePathName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// Dump信息
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ExceptionPointers = pException;
dumpInfo.ThreadId = GetCurrentThreadId();
dumpInfo.ClientPointers = TRUE;
// 写入Dump文件内容
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
CloseHandle(hDumpFile);
}
// 处理Unhandled Exception的回调函数
LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)
{
CreateDumpFile(L"Test.dmp",pException);
return EXCEPTION_EXECUTE_HANDLER;
}
void fun(int *p)
{
p[0]=0;
}
int _tmain(int argc, _TCHAR* argv[])
{
//注册异常处理函数
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);
fun(NULL);
return 0;
}
DisableSetUnhandledExceptionFilter
为什么要讲DisableSetUnhandledExceptionFilter()?
如SetUnhandledExceptionFilter无法捕获异常原因及解决方法一文所说,从VS2015之后,微软CRT 通过调用 SetUnhandledExceptionFilter 并传递参数 NULL 来清除用户注册的 Unhandled Exception Filter。这样,SetUnhandledExceptionFilter就无法捕获程序的异常退出。
因此便有了DisableSetUnhandledExceptionFilter(),只需要在注册 Unhandled Exception Filter 之后调用 DisableSetUnhandledExceptionFilter() 函数,那么之后所有对 SetUnhandledExceptionFilter 的调用都将无效,自然 CRT 也无法通过调用 SetUnhandledExceptionFilter 来清除用户注册的 Unhandled Exception Filter。
改变 SetUnhandledExceptionFilter 的行为,使得 CRT 对 SetUnhandledExceptionFilter 的调用不起任何作用(更加详细的论述可以参考《Windows 核心编程》相关章节)。
DisableSetUnhandledExceptionFilter()的详细代码如下:
void DisableSetUnhandledExceptionFilter()
{
void *addr = (void*)::GetProcAddress(LoadLibraryW(L"kernel32.dll"),
"SetUnhandledExceptionFilter"); // The function is ANSI version.
if (addr)
{
unsigned char code[16];
int size = 0;
code[size++] = 0x33;
code[size++] = 0xC0;
code[size++] = 0xC2;
code[size++] = 0x04;
code[size++] = 0x00;
DWORD dwOldFlag, dwTempFlag;
::VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);
::WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
::VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
}
}
使用实例:
在程序入口调用
SetUnhandledExceptionFilter
DisableSetUnhandledExceptionFilter