软件崩溃时 将堆栈信息写入dump文件, 并使用VS2010定位程序崩溃位置

本文详细介绍在程序中加入存储dump的代码,利用SetUnhandledExceptionFilter捕获未处理的异常,通过MiniDumpWriteDump生成dump文件,以及如何防止C运行时库清除异常处理程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haimianjie2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值