使用MiniDumpWriteDump API 來生成程序的Dump


 

from:

http://www.cnblogs.com/lzjsky/archive/2010/12/01/1893660.html

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.hDbghelp.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.
\***************************************************************************/

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM