编写的windows程序,崩溃时产生crash dump文件的办法

一、引言

dump文件是C++程序发生异常时,保存当时程序运行状态的文件,是调试异常程序重要的方法,所以程序崩溃时,除了日志文件,dump文件便成了我们查找错误的最后一根救命的稻草。windows程序产生dump文件和linux程序产生dump文件的方式不一样,linux默认是不让产生core dump文件,只要在用户自己的~/.bash_profile文件中增加

ulimit -S -c unlimited > /dev/null 2>&1

这样程序崩溃就可以产生可调试的core dump文件了。但是windows环境就得写代码才能实现了。

二、原理

windows程序当遇到异常,没有try-catch或者try-catch也无法捕获到的异常时,程序就会自动退出,如果这时候没有dump文件的话,我们是没有得到任何程序退出的信息。在windows程序异常退出之前,会预先调用一个在程序中注册的异常处理回调函数(默认是没有设置),只要我们在这个回调函数中调用MiniDumpWriteDump函数就可以产生我们想要的dump文件。

三、实现

1.调用SetUnhandledExceptionFilter注册一个自定义的异常处理回调函数

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

异常处理回调函数的原型

LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);

2.CreateFile创建dump文件,调用MiniDumpWriteDump函数往dump文件写异常信息

inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)
{
	HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
	{
		MINIDUMP_EXCEPTION_INFORMATION mdei;
		mdei.ThreadId           = GetCurrentThreadId();
		mdei.ExceptionPointers  = pep;
		mdei.ClientPointers     = NULL;

		MINIDUMP_CALLBACK_INFORMATION mci;
		mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
		mci.CallbackParam       = 0;

		::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);

		CloseHandle(hFile);
	}
}

CreateMiniDump函数是在异常处理回调函数MyUnhandledExceptionFilter中调用的

LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
	CreateMiniDump(pExceptionInfo, "core.dmp");

	return EXCEPTION_EXECUTE_HANDLER;
}

3.将SetUnhandledExceptionFilter失效

vs2005中,编译的过程中,编译器会自动给你的程序加上一句SetUnhandledExceptionFilter(NULL),这就会导致你之前自定义的

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

无效,就有可能不会产生dump文件,因此我们必须在自定义的SetUnhandledExceptionFilter之后,让之后调用的SetUnhandledExceptionFilter无效。增加以下代码:

// 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效
void DisableSetUnhandledExceptionFilter()
{
	void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),
		"SetUnhandledExceptionFilter");

	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);
	}
}

最终代码整理:

//minidump.h

#pragma once
#include <windows.h>
#include <DbgHelp.h>
#include <stdlib.h>
#pragma comment(lib, "dbghelp.lib")

#ifndef _M_IX86
#error "The following code only works for x86!"
#endif

inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
{
	if(pModuleName == 0)
	{
		return FALSE;
	}

	WCHAR szFileName[_MAX_FNAME] = L"";
	_wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);

	if(wcsicmp(szFileName, L"ntdll") == 0)
		return TRUE;

	return FALSE;
}

inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,
									  const PMINIDUMP_CALLBACK_INPUT   pInput,
									  PMINIDUMP_CALLBACK_OUTPUT        pOutput)
{
	if(pInput == 0 || pOutput == 0)
		return FALSE;

	switch(pInput->CallbackType)
	{
	case ModuleCallback:
		if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
			if(!IsDataSectionNeeded(pInput->Module.FullPath))
				pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
	case IncludeModuleCallback:
	case IncludeThreadCallback:
	case ThreadCallback:
	case ThreadExCallback:
		return TRUE;
	default:;
	}

	return FALSE;
}

inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)
{
	HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
	{
		MINIDUMP_EXCEPTION_INFORMATION mdei;
		mdei.ThreadId           = GetCurrentThreadId();
		mdei.ExceptionPointers  = pep;
		mdei.ClientPointers     = NULL;

		MINIDUMP_CALLBACK_INFORMATION mci;
		mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
		mci.CallbackParam       = 0;

		::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);

		CloseHandle(hFile);
	}
}

LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
	CreateMiniDump(pExceptionInfo, "core.dmp");

	return EXCEPTION_EXECUTE_HANDLER;
}

// 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效
void DisableSetUnhandledExceptionFilter()
{
	void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),
		"SetUnhandledExceptionFilter");

	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);
	}
}

void InitMinDump()
{
	//注册异常处理函数
	SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

	//使SetUnhandledExceptionFilter
	DisableSetUnhandledExceptionFilter();
}

4.测试代码

//test.cpp

#include <iostream>
#include "minidump.h"
void test()
{
	std::string s = "abcd";

	try{
		s[100] = 'b';
	}
	catch(std::exception& e)
	{
		std::cout << "with exception:[" << e.what() << "]" << std::endl;
	}
	catch(...)
	{
		std::cout << "with unknown exception" << std::endl;
	}
}

void main()
{
	InitMinDump();

	test();

	system("pause");
}



  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
Windows 平台上,应用程序崩溃可能会产生 Core Dump 文件,通常以 .dmp 后缀结尾。这个文件包含了应用程序崩溃的内存状态,可以帮助开发者定位和解决问题。以下是处理 Windows 应用程序崩溃产生 Core Dump 的一些方法: 1. 启用 Windows Core DumpWindows 上,默认情况下是不启用 Core Dump 的。使用以下命令可以启用 Core Dump: ``` reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f ``` 2. 使用 Visual Studio 调试 Core Dump Visual Studio 支持使用 Core Dump 进行调试。可以使用 Visual Studio 打开 Core Dump 文件,并分析崩溃的原因。具体的操作步骤可以参考 Microsoft 官方文档。 3. 使用 WinDbg 调试 Core Dump WinDbg 是一款微软开发的用于 Windows 平台上的调试器,支持分析 Core Dump 文件。可以使用 WinDbg 打开 Core Dump 文件,并分析崩溃的原因。具体的操作步骤可以参考微软官方文档。 4. 使用第三方工具分析 Core Dump 除了使用 Visual Studio 和 WinDbg,还有一些第三方工具可以用来分析 Core Dump 文件,比如 Process Explorer、GDB 等。这些工具都有各自的优缺点,开发者可以根据自己的需要选择合适的工具。 总的来说,处理 Windows 应用程序崩溃产生 Core Dump 的过程比较复杂,需要开发者具备一定的调试经验。建议在处理 Core Dump 之前先了解一下相关的调试工具和技术。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值