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

2023-05-16

一、引言

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文件写异常信息

[cpp] view plain copy print ?
  1. inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)  
  2. {  
  3.     HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,  
  4.         FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
  5.   
  6.     if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))  
  7.     {  
  8.         MINIDUMP_EXCEPTION_INFORMATION mdei;  
  9.         mdei.ThreadId           = GetCurrentThreadId();  
  10.         mdei.ExceptionPointers  = pep;  
  11.         mdei.ClientPointers     = NULL;  
  12.   
  13.         MINIDUMP_CALLBACK_INFORMATION mci;  
  14.         mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
  15.         mci.CallbackParam       = 0;  
  16.   
  17.         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);  
  18.   
  19.         CloseHandle(hFile);  
  20.     }  
  21. }  
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中调用的

[cpp] view plain copy print ?
  1. LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)  
  2. {  
  3.     CreateMiniDump(pExceptionInfo, "core.dmp");  
  4.   
  5.     return EXCEPTION_EXECUTE_HANDLER;  
  6. }  
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
	CreateMiniDump(pExceptionInfo, "core.dmp");

	return EXCEPTION_EXECUTE_HANDLER;
}

3.将SetUnhandledExceptionFilter失效

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

SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

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

[cpp] view plain copy print ?
  1. // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效   
  2. void DisableSetUnhandledExceptionFilter()  
  3. {  
  4.     void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),  
  5.         "SetUnhandledExceptionFilter");  
  6.   
  7.     if (addr)  
  8.     {  
  9.         unsigned char code[16];  
  10.         int size = 0;  
  11.   
  12.         code[size++] = 0x33;  
  13.         code[size++] = 0xC0;  
  14.         code[size++] = 0xC2;  
  15.         code[size++] = 0x04;  
  16.         code[size++] = 0x00;  
  17.   
  18.         DWORD dwOldFlag, dwTempFlag;  
  19.         VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);  
  20.         WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);  
  21.         VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);  
  22.     }  
  23. }  
// 此函数一旦成功调用,之后对 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

[cpp] view plain copy print ?
  1. #pragma once   
  2. #include <windows.h>   
  3. #include <DbgHelp.h>   
  4. #include <stdlib.h>   
  5. #pragma comment(lib, "dbghelp.lib")   
  6.   
  7. #ifndef _M_IX86   
  8. #error "The following code only works for x86!"   
  9. #endif   
  10.   
  11. inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)  
  12. {  
  13.     if(pModuleName == 0)  
  14.     {  
  15.         return FALSE;  
  16.     }  
  17.   
  18.     WCHAR szFileName[_MAX_FNAME] = L"";  
  19.     _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);  
  20.   
  21.     if(wcsicmp(szFileName, L"ntdll") == 0)  
  22.         return TRUE;  
  23.   
  24.     return FALSE;  
  25. }  
  26.   
  27. inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,  
  28.                                       const PMINIDUMP_CALLBACK_INPUT   pInput,  
  29.                                       PMINIDUMP_CALLBACK_OUTPUT        pOutput)  
  30. {  
  31.     if(pInput == 0 || pOutput == 0)  
  32.         return FALSE;  
  33.   
  34.     switch(pInput->CallbackType)  
  35.     {  
  36.     case ModuleCallback:  
  37.         if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)  
  38.             if(!IsDataSectionNeeded(pInput->Module.FullPath))  
  39.                 pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);  
  40.     case IncludeModuleCallback:  
  41.     case IncludeThreadCallback:  
  42.     case ThreadCallback:  
  43.     case ThreadExCallback:  
  44.         return TRUE;  
  45.     default:;  
  46.     }  
  47.   
  48.     return FALSE;  
  49. }  
  50.   
  51. inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)  
  52. {  
  53.     HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,  
  54.         FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
  55.   
  56.     if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))  
  57.     {  
  58.         MINIDUMP_EXCEPTION_INFORMATION mdei;  
  59.         mdei.ThreadId           = GetCurrentThreadId();  
  60.         mdei.ExceptionPointers  = pep;  
  61.         mdei.ClientPointers     = NULL;  
  62.   
  63.         MINIDUMP_CALLBACK_INFORMATION mci;  
  64.         mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
  65.         mci.CallbackParam       = 0;  
  66.   
  67.         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);  
  68.   
  69.         CloseHandle(hFile);  
  70.     }  
  71. }  
  72.   
  73. LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)  
  74. {  
  75.     CreateMiniDump(pExceptionInfo, "core.dmp");  
  76.   
  77.     return EXCEPTION_EXECUTE_HANDLER;  
  78. }  
  79.   
  80. // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效   
  81. void DisableSetUnhandledExceptionFilter()  
  82. {  
  83.     void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),  
  84.         "SetUnhandledExceptionFilter");  
  85.   
  86.     if (addr)  
  87.     {  
  88.         unsigned char code[16];  
  89.         int size = 0;  
  90.   
  91.         code[size++] = 0x33;  
  92.         code[size++] = 0xC0;  
  93.         code[size++] = 0xC2;  
  94.         code[size++] = 0x04;  
  95.         code[size++] = 0x00;  
  96.   
  97.         DWORD dwOldFlag, dwTempFlag;  
  98.         VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);  
  99.         WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);  
  100.         VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);  
  101.     }  
  102. }  
  103.   
  104. void InitMinDump()  
  105. {  
  106.     //注册异常处理函数   
  107.     SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);  
  108.   
  109.     //使SetUnhandledExceptionFilter   
  110.     DisableSetUnhandledExceptionFilter();  
  111. }  
#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

[cpp] view plain copy print ?
  1. #include <iostream>   
  2. #include "minidump.h"   
  3. void test()  
  4. {  
  5.     std::string s = "abcd";  
  6.   
  7.     try{  
  8.         s[100] = 'b';  
  9.     }  
  10.     catch(std::exception& e)  
  11.     {  
  12.         std::cout << "with exception:[" << e.what() << "]" << std::endl;  
  13.     }  
  14.     catch(...)  
  15.     {  
  16.         std::cout << "with unknown exception" << std::endl;  
  17.     }  
  18. }  
  19.   
  20. void main()  
  21. {  
  22.     InitMinDump();  
  23.   
  24.     test();  
  25.   
  26.     system("pause");  
  27. }  
#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");
}


origin: http://blog.csdn.net/fhxpp_27/article/details/9701867
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • git 拉取指定的远程分支(三种方式)

    直接拉取 git clone b ants git 64 github com Ants double CareerJava git git clone b 远程分支名 仓库地址 本地已经有相关的仓库代码 查看远程分支 git branch
  • 左连接的左边为什么不全显示

    left join后面加上where条件浅析 select a b from table1 a left join table2 b on b X 61 a X where XXX 如上 xff1a 一旦使用了left join xff0c
  • 一次通过jvm排查堆内存不断增大最后导致docker容器自动重启的问题

    1 事件背景 xff1a 生产有个定时任务 xff0c 经常跑不出数据 xff0c 通过监控发现对应的那台机器内存一跑这个定时任务就会陡增 由于应用部署在容器中 xff0c 当内存跑满后会自动重启 xff0c 所以导致定时任务无法执行完毕
  • jvm 中的一些命令,方便排查jvm的一些状况

    1 ps ef grep xxx 找到应用的进程号 jmap heap pid 查看对应进程的jvm占用内存情况 命令 xff1a jmap histo live pid 描述 xff1a 显示堆中对象的统计信息 jmap histo pi
  • session如何在多用户中区分

    1 会话 客户端向服务端发送请求 xff0c 服务端接受请求并响应这样一次连续的过程 xff0c 称为一个会话 session 2 可实现登录访问控制功能 login jsp doLogin jsp index jsp 1 进入登录页面lo
  • 关于springboot 从controller返回到html页面

    一 不用模板引擎的时候 这里列出以下几种情况进行分析 1 yml配置 controller 静态文件目录 xff1a 结果 xff1a 结论 xff1a 此时访问的error12 html是static目录下的 spring配置视图为的时候
  • 【Kali_014】Kconsole虚拟终端设置半透明

    打开终端菜单 gt Settings gt Edit Current Profile gt Appearance gt Edit gt Background transparency
  • 用fastboot烧录system.img 出现remote: data too large解决办法

    用fastboot命令烧录 xff0c 提示如下错误信息 xff1a target reported max download size of 536870912 bytes erasing 39 system 39 OKAY 0 016s
  • MTK Android为某个APP单独添加selinux配置文件

    需求 MTK Android 11 test是一个system APP 涉及到许多个selinux的权限 xff0c 不想影响所有的system APP的权限 xff0c 需要单独为test设定selinux 方法 domain devic
  • 2012年展望

    由于各种原因 xff0c 客观的 主观的 不过归根结底还是主观的多一些 xff0c 2011年整体过的很颓废 xff0c 上班大多在上网 xff0c 工作上几乎没有一点成绩 xff0c 自己也是很不满意 2012年世界末日都快来了 xff0
  • http和ftp协议的区别

    项目中应用到ftp xff0c 将ftp的笔记上传一下 简单的说 xff1a HTTP是超文本传输协议 xff1b 面向网页的 FTP是File Transfer Protocol 文件传输协议 xff1b 面向文件的 1 FTP 1 FT
  • Python爬虫(4)获得所有Top250部电影的信息并存入数据库

    上次我们完成了单页电影的获取并保存到了Excel文件中 xff0c 不知道小伙伴们都完成了没 xff1f 有没有把Top250部电影都保存下来的 xff1f 在编写这些代码过程中遇到什么问题了没 xff1f 如果遇到但是没有解决 xff0c
  • c#笔记-模式匹配

    模式匹配 模式匹配可以判断一个值的类型和内容 可以判断嵌套的属性 xff0c 但只能和常量进行比较 模式匹配使用is表达式 xff0c 或是在switch选择 xff0c 和switch表达式的分支块中启用 模式匹配使用专有的关键字或运算符
  • typeScript+egg.js+node.js后台项目搭建(一)

    typeScript egg js node js后台项目搭建 一 1 安装node js 地址 https nodejs org en 下载安装后 打开控制台cmd 输入 node v 在安装ts 可以参考typeScript中文官网 n
  • CGroup 介绍、应用实例及原理描述(已发表于IBM开发者论坛)

    插播小广告 xff0c 本人的 大话 Java性能优化 一书已经在亚马逊 京东 当当 天猫出售 xff0c 提前谢谢大家支持 原文请查看 xff1a http www ibm com developerworks cn linux 1506
  • python + celery简例

    在网上找了半天 xff0c 也没找到完整的例子 xff0c 自己写吧 1 一个队列 自定义10个优先级 xff0c 修改默认celery队列名称 1 testcelery py from celery import Celery impor
  • java+selenium获取动态下拉列表元素

    做自动化的时候 xff0c 遇到这么一个闹心问题 xff1a 研发用html里的 lt div input gt 方式 xff0c 所以无法使用select获取列表元素 原本使用Robot也可以定位 xff0c 但是headless模式 x
  • Redis安装和配置

    网上有海量的Redis文章 xff0c 写的都很详细 这里就是简单记录一下自己查aof问题过程中遇到的问题 xff0c 主要是aof文件所在目录在redis conf里的位置 1 在ubuntu16上安装Redis sudo apt get
  • mysql 主从部署

    在ubuntu 16上 xff0c 配置mysql 主从服务器 查看mysql主从命令 show variables like 39 server id 39 show variables like 39 log bin 39 show m
  • 编写的windows程序,崩溃时产生crash dump文件的办法 .

    一 引言 dump文件是C 43 43 程序发生异常时 xff0c 保存当时程序运行状态的文件 xff0c 是调试异常程序重要的方法 xff0c 所以程序崩溃时 xff0c 除了日志文件 xff0c dump文件便成了我们查找错误的最后一根