热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Crash生成Minidump调试信息

在Windows平台下用C开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版

在Windows平台下用C++开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版本了。因为release版本来就少了很多调试信息,更何况一般都是发布出去由用户使用,crash的现场很难保留和重现。目前有一些方法可以解决:

崩溃地址 + MAP文件;MAP文件;

SetUnhandledExceptionFilter + Minidump。


本文重点解决Minidump方式。



 1、Minidump概念
        minidump(小存储器转储)可以理解为一个dump文件,里面记录了能够帮助调试crash的最小有用信息。实际上,如果你在系统属性 -> 高级 -> 启动和故障恢复 -> 设置 -> 写入调试信息中选择“小内存转储(64 KB)”的话,当系统意外停止时都会在C:\Windows\Minidump\路径下生成一个.dmp后缀的文件,这个文件就是minidump文件,只不过这个是内核态的minidump。
        我们要生成的是用户态的minidump,文件中包含了程序运行的模块信息、线程信息、堆栈调用信息等。而且为了符合其mini的特性,dump文件是压缩过的。


2、生成minidump文件
        通过drwtsn32、NTSD、CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD、CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD、CDB等调试工具。根据MiniDumpWriteDump接口,完全可以程序自动生成Dump文件。


 


3、  自动生成Minidump文件
        当程序遇到未处理异常(主要指非指针造成)导致程序崩溃死,如果在异常发生之前调用了SetUnhandledExceptionFilter()函数,异常交给函数处理。MSDN中描述为:


Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.


 因而,在程序开始处增加SetUnhandledExceptionFilter()函数,并在函数中利用适当的方法生成Dump文件,即可实现需要的功能。minidump(小存储器转储)可以理解为一个dump文件,里面记录了能够帮助调试crash的最小有用信息。实际上,如果你在系统属性 -> 高级 -> 启动和故障恢复 -> 设置 -> 写入调试信息中选择“小内存转储(64 KB)”的话,当系统意外停止时都会在C:\Windows\Minidump\路径下生成一个.dmp后缀的文件,这个文件就是minidump文件,只不过这个是内核态的minidump。

        我们要生成的是用户态的minidump,文件中包含了程序运行的模块信息、线程信息、堆栈调用信息等。而且为了符合其mini的特性,dump文件是压缩过的。


2、生成minidump文件
通过drwtsn32、NTSD、CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD、CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD、CDB等调试工具。根据MiniDumpWriteDump接口,完全可以程序自动生成Dump文件。


3、  自动生成Minidump文件
当程序遇到未处理异常(主要指非指针造成)导致程序崩溃死,如果在异常发生之前调用了SetUnhandledExceptionFilter()函数,异常交给函数处理。MSDN中描述为:

        Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.

        因而,在程序开始处增加SetUnhandledExceptionFilter()函数,并在函数中利用适当的方法生成Dump文件,即可实现需要的功能。

新建工程


下一步


下一步


Minidmp.h 

#pragma once#include
#include
#include inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName);inline BOOL CALLBACK MiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput);//创建Dump文件
inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName);LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);BOOL PreventSetUnhandledExceptionFilter();LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException);//运行异常处理
void RunCrashHandler();


Minidmp.cpp 

#include "stdafx.h"#include "Minidmp.h"#pragma comment(lib, "dbghelp.lib")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;
}//创建Dump文件
inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)
{HANDLE hFile = CreateFile(strFileName, GENERIC_WRITE, 0, 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 = FALSE;MINIDUMP_CALLBACK_INFORMATION mci;mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;mci.CallbackParam = 0;MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)0x0000ffff;MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci);CloseHandle(hFile); }
}LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{return NULL;
}BOOL PreventSetUnhandledExceptionFilter()
{HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));if (hKernel32 == NULL)return FALSE;void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");if(pOrgEntry == NULL)return FALSE;unsigned char newJump[ 100 ];DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp farvoid *pNewFunc = &MyDummySetUnhandledExceptionFilter;DWORD dwNewEntryAddr = (DWORD) pNewFunc;DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;newJump[ 0 ] = 0xE9; // JMP absolutememcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));SIZE_T bytesWritten;BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);return bRet;
}LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException)
{TCHAR szMbsFile[MAX_PATH] = { 0 };::GetModuleFileName(NULL, szMbsFile, MAX_PATH);TCHAR* pFind = _tcsrchr(szMbsFile, '\\');if(pFind){*(pFind+1) = 0;_tcscat(szMbsFile, _T("CreateMiniDump.dmp"));CreateMiniDump(pException,szMbsFile);}// TODO: MiniDumpWriteDumpFatalAppExit(-1, _T("Fatal Error"));return EXCEPTION_CONTINUE_SEARCH;
}//运行异常处理
void RunCrashHandler()
{SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);PreventSetUnhandledExceptionFilter();
}


CrashTest.h 

#pragma once
#include "Minidmp.h"class CCrashTest
{
public:CCrashTest(void);~CCrashTest(void);public:void Test();private:void Crash();
};



CrashTest.cpp 

#include "StdAfx.h"
#include "CrashTest.h"CCrashTest::CCrashTest(void)
{
}CCrashTest::~CCrashTest(void)
{
}void CCrashTest::Test()
{Crash();
}void CCrashTest::Crash()
{// 除零,人为的使程序崩溃//int i = 13;int j = 0;//int m = i / j;strcpy(NULL,"adfadfg");
}


CrashMinidumpTest.cpp 

// CrashMinidumpTest.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include "CrashTest.h"int _tmain(int argc, _TCHAR* argv[])
{//设置异常处理回调函数RunCrashHandler();CCrashTest test;test.Test();getchar();return 0;
}


配置工程目录



下一步


下一步


下一步


下一步



推荐阅读
  • java多线程获取线程返回结果
    我们在使用java多线程编写相关业务代码时,往往有这样一种情况,某个线程依赖于其他线程执行结果。也就是说,我们需要在一个线程中获取另一个线程的信息。可以分为两种情况,一种是轮询,一 ... [详细]
  • C语言的经典程序有哪些
    本篇内容介绍了“C语言的经典程序有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • 微软评估和规划(MAP)的工具包介绍及应用实验手册
    本文介绍了微软评估和规划(MAP)的工具包,该工具包是一个无代理工具,旨在简化和精简通过网络范围内的自动发现和评估IT基础设施在多个方案规划进程。工具包支持库存和使用用于SQL Server和Windows Server迁移评估,以及评估服务器的信息最广泛使用微软的技术。此外,工具包还提供了服务器虚拟化方案,以帮助识别未被充分利用的资源和硬件需要成功巩固服务器使用微软的Hyper - V技术规格。 ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • 总结一下C中string的操作,来自〈CPrimer〉第四版。1.string对象的定义和初始化:strings1;空串strings2(s1);将s2初始 ... [详细]
  • 本文介绍了使用C++Builder实现获取USB优盘序列号的方法,包括相关的代码和说明。通过该方法,可以获取指定盘符的USB优盘序列号,并将其存放在缓冲中。该方法可以在Windows系统中有效地获取USB优盘序列号,并且适用于C++Builder开发环境。 ... [详细]
  • 利用空间换时间减少时间复杂度以及以C语言字符串处理为例减少空间复杂度
    在处理字符串的过程当中,通常情况下都会逐个遍历整个字符串数组,在多个字符串的处理中,处理不同,时间复杂度不同,这里通过利用空间换时间等不同方法,以字符串处理为例来讨论几种情况:1: ... [详细]
  • 使用这个技巧要达到的目标:一般来说,模型和控制器你都不会有相同的类名字。让我先创建一个取名为post的model。classPostextendsModel{}现在 ... [详细]
  • 在 IMDB 情感分类任务上训练双向 LSTM
    代码如下在这里插入代码片from__future__importprint_functionimportnumpyasnpfromkeras.preprocessingimpo ... [详细]
author-avatar
mizrke
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有