您的位置:首页 > 其它

MiniDumpWriteDump

2016-03-01 15:03 447 查看
MiniDumpWriteDump是MS DbgHelp.dll 中一个API, 用于导出当前运行的程序的Dump. 这个dll程序系统中就有, 但是很多软件, 都在自己的安装目录下保存了这个.dll的最新的版本.

为了测试这个API, 参考网上一些资料, 写了一个简单的C++ 程序. 目的是当有异常发生的时候, 自动生成Dump文件供之后的分析. 有了Dump文件, 我们就可以使用WinDBG等调试器来分析异常发生时的情况. 其实这个功能很多软件都有, 比如QQ, 魔兽世界, 等等. 它们在出现了异常的时候会弹出一个对话框, 让用户输入异常发生时的情况, 然后把异常的dump文件用email发回, 供开发者们分析修改bug.

不过有一点, 这里需要程序的调试符号文件(pdb文件). 对于Debug版来说, 是生成的, 但是Release版来说默认是不生成的. 可以设置VC的编译器, 让它在Release版的时候也生成调试信息. 这带来一个新的问题, 因为.pdb里面是保存了源文件的信息的, 为了避免泄密, 可以采用VS中的CVPack工具, 从中去除敏感的信息.

程序需要使用Dbghelp.h 和 Dbghelp.lib . 它们可以从MSDN找到.

 

//最主要的函数, 生成Dump

static void DumpMiniDump(HANDLE hFile, PEXCEPTION_POINTERS excpInfo)

{

if (excpInfo == NULL) //如果没有传入异常, 比如是在程序里面调用的, 生成一个异常

{

// Generate exception to get proper context in dump

__try 

{

OutputDebugString(_T("raising exception\r\n"));

RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);



__except(DumpMiniDump(hFile, GetExceptionInformation()),

EXCEPTION_CONTINUE_EXECUTION) 

{

}



else

{

OutputDebugString(_T("writing minidump\r\n"));

MINIDUMP_EXCEPTION_INFORMATION eInfo;

eInfo.ThreadId = GetCurrentThreadId(); //把需要的信息添进去

eInfo.ExceptionPointers = excpInfo;

eInfo.ClientPointers = FALSE;

    // 调用, 生成Dump. 98不支持

// Dump的类型是小型的, 节省空间. 可以参考MSDN生成更详细的Dump.

MiniDumpWriteDump(

GetCurrentProcess(),

GetCurrentProcessId(),

hFile,

MiniDumpNormal,

excpInfo ? &eInfo : NULL,

NULL,

NULL);

}

}

下面的是程序部分:

int _tmain(int argc, _TCHAR* argv[])

{
// 创建一个Dump文件

HANDLE hFile = CreateFile( _T("MiniDump.dmp"), GENERIC_READ | GENERIC_WRITE, 

0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); 

int code;

__try 

{   
// 把自己实现的main函数包装一下, 放在try .. except 块中. 这样出现了异常可以自动生成dump

main_wrapper(argc, argv); 

}

__except( code=GetExceptionCode(), DumpMiniDump(hFile, GetExceptionInformation() ),       EXCEPTION_EXECUTE_HANDLER ) //出现了异常, 记录异常的code, 生成dump!!

{

printf("%x\n", code);

wchar_t msg[512];

wsprintf(msg, L"Exception happened. Exception code is %x", code);

MessageBox(NULL, msg, L"Exception", MB_OK); //显示消息给用户

}

CloseHandle( hFile ); //关闭Dump文件

getchar();

return 0; 

}

最下面是两个测试的函数, main_wrapper函数将调用test1, test1将会生成一个异常(非法内存写)

void test1() {

int *p;

p = (int*)0x100; 

*p = 0; //写0x100地址, 这个是非法的

}

void main_wrapper(int argc, _TCHAR* argv[]) {

test1();

}

运行, 异常被捕获了:



同时, dump文件也生成了:



用WinDBG打开Dump文件, 可以清楚的看出异常出现的情况:



从中可以比较清楚的看到异常发生的情况(Exception code), 异常出现的地址(test1函数, 偏移0x28). 因为这次测试的是Debug版, 有保存了源代码的.pdb文件, 所以WinDbg把源代码也列出来了. 这样可以非常容易的发现问题.

============================================

摘录自msdn

/****************************** Module Header ******************************\

Module Name:  CppExceptionHandling.cpp

Project:      CppExceptionHandling

Copyright (c) Microsoft Corporation.

- to be finished.

This source is subject to the Microsoft Public License.

See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.

All other rights reserved.

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 

EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 

WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

\**************************************************************
4000
*************/

#include <stdio.h>

#include <tchar.h>

#include <windows.h>

#include <stdio.h>

#include <strsafe.h>

#include <shlwapi.h>

#include <dbghelp.h>

#pragma comment(lib, "Dbghelp.lib")

#pragma comment(lib, "shlwapi.lib")

// This method is to write mini dump of current process to 

// CppExceptionHandling.dmp file. 

LONG WINAPI WriteMiniDump(struct _EXCEPTION_POINTERS *ExceptionInfo)

{

 // EXCEPTION_CONTINUE_SEARCH means it continue to 

 // execute subsequent exception handlers.

 LONG rc = EXCEPTION_CONTINUE_SEARCH;

 HMODULE hDll = NULL;

 TCHAR szDumpFile[MAX_PATH];

 StringCchPrintf(szDumpFile, MAX_PATH, _T("CppExceptionHandling.dmp"));

 HANDLE hDumpFile;

 hDumpFile = CreateFile(szDumpFile, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, 

  CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

 if (hDumpFile != INVALID_HANDLE_VALUE)

 {

  MINIDUMP_EXCEPTION_INFORMATION ExInfo;

  ExInfo.ThreadId = GetCurrentThreadId();

  ExInfo.ExceptionPointers = ExceptionInfo;

  ExInfo.ClientPointers = TRUE;

  // Write the information into the dump

  if (MiniDumpWriteDump(

   GetCurrentProcess(), // Handle of process

   GetCurrentProcessId(), // Process Id

   hDumpFile,    // Handle of dump file

   MiniDumpNormal,   // Dump Level: Mini

   &ExInfo,    // Exception information

   NULL,     // User stream parameter

   NULL))     // Callback Parameter

  {

   rc = EXCEPTION_CONTINUE_SEARCH;

  }

  else

  {

   _tprintf(_T("MiniDumpWriteDump failed w/err 0x%08lx\n"), GetLastError());

  }

  CloseHandle(hDumpFile);

 }

 else

 {

  _tprintf(_T("CreateFile failed w/err 0x%08lx\n"), GetLastError());

 }

 return rc;

}

#pragma region Structured Exception

void ThrowStructuredException()

{

}

void ThrowAndHandleStructuredException()

{

}

#pragma endregion

#pragma region Vectored Exception

// The registered exception handler

LONG WINAPI VectoredExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)

{    

 WriteMiniDump (ExceptionInfo);

 printf("This vectored handler is always called first\n");

 return EXCEPTION_CONTINUE_SEARCH;

}

void ThrowAndHandleVectoredException()

{

 // Registers a vectored exception handler

 PVOID handler = AddVectoredExceptionHandler(0, VectoredExceptionHandler);

 // Raise a fake exception for demo

 __try

 {

  printf("RaiseException: Raise an exception\n");

  RaiseException(1,0,0,NULL); 

 }  

 __except(EXCEPTION_EXECUTE_HANDLER)

 {

  printf("This is a exception handler\n");

 }

 // Remove the vectored exception handler

 RemoveVectoredExceptionHandler(handler);

}

#pragma endregion

int _tmain(int argc, _TCHAR* argv[])

{

 ThrowAndHandleVectoredException();

 return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: