1. 程式人生 > >生成程式崩潰的dump檔案,使用windbg除錯

生成程式崩潰的dump檔案,使用windbg除錯

1,目的

有時候程式在客戶那裡崩潰了,你程式也沒有什麼有效的log日誌能記錄到崩潰的細節,那這實在是一件很麻煩的事情。

你得向客戶反覆瞭解操作內容並希望能在自己這裡重現,這個過程想想都很痛苦吧。。

使用下面的方法,能在程式崩潰時生成一個自己的dump檔案,記錄了崩潰時的一些有用的資訊,一般能幫你容易地找到出錯的地方。

2,原理

簡單地說,就是windows程式崩潰時會調一個對話方塊顯示一些沒什麼用的資訊。

XP下:

WIN7中:

①設定崩潰時的回撥函式。

有一個方法可以讓我們設定程式崩潰時先執行的回撥函式,這裡面可以彈我們自己的對話方塊,比如讓使用者輸入一些有用的內容然後傳送給我們。

這個函式是SetUnhandledExceptionFilter . 

原型:

WINBASEAPI
LPTOP_LEVEL_EXCEPTION_FILTER
WINAPI
SetUnhandledExceptionFilter(
    __in_opt LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter
    );
它的引數是你要設定的回撥函式:PTOP_LEVEL_EXCEPTION_FILTER
typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(
    __in struct _EXCEPTION_POINTERS *ExceptionInfo
    );
typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;

系統調起你的回撥函式時,會給你傳一個代表異常資訊的結構:EXCEPTION_POINTERS
typedef struct _EXCEPTION_POINTERS {
    PEXCEPTION_RECORD ExceptionRecord;
    PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

我們現在要做的就是在回撥函式里根據這個系統給我們的資訊,記錄到一個dump檔案中去。供我們使用windbg分析。

通過SetUnhandledExceptionFilter 函式的返回值我們可以選擇在回撥結束後不再彈原來預設的對話方塊而直接結束程式、或者再彈那個預設的再結束程式、不彈對話方塊繼續執行。

如下:

#define EXCEPTION_EXECUTE_HANDLER       1         	//在回撥結束後不再彈原來預設的對話方塊而直接結束程式
#define EXCEPTION_CONTINUE_SEARCH       0		//再彈那個預設的再結束程式
#define EXCEPTION_CONTINUE_EXECUTION    -1		//繼續執行

②在回撥函式中輸出崩潰資訊到dump檔案。

往dump檔案寫內容用到一個API:MiniDumpWriteDump。

在DbgHelp.h標頭檔案中,且需包含 DbgHelp.lib庫。

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

函式形式:

BOOL
WINAPI
MiniDumpWriteDump(
    __in HANDLE hProcess,
    __in DWORD ProcessId,
    __in HANDLE hFile,
    __in MINIDUMP_TYPE DumpType,
    __in_opt PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
    __in_opt PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
    __in_opt PMINIDUMP_CALLBACK_INFORMATION CallbackParam
    );
說明:

hProcess  ——程序控制代碼,使用GetCurrentProcess()獲得即可。
ProcessID——程序ID,GetCurrentProcessId()。

hFile          ——我們建立的dump檔案控制代碼。

DumpType——dump型別,一般填MiniDumpNormal 即可,具體內容參看DbgHelp.h和MSDN。

ExceptionParam——  1)ThreadId:GetCurrentThreadId()。

2)ExceptionPointers:即回撥函式的引數。

3)ClientPointers:一般填TRUE即可。

UserStreamParam—— 一般設NULL。

CallbackParam      —— 一般設NULL。

3,演示程式程式碼

如果是release版,需要在工程配置中設定生成除錯檔案和生成對映檔案。

如圖:


win32控制檯程式:

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

//我們的回撥函式
LONG __stdcall ExceptCallBack( EXCEPTION_POINTERS *pExcPointer)
{
	MessageBox(NULL,"程式崩潰!相關資訊記錄在C:\\Test.dmp檔案中。",NULL,MB_OK);

	//建立dump檔案
	HANDLE hFile = CreateFile("C:\\Test.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL ,NULL);
	
	//向檔案寫下當前程式崩潰相關資訊
	MINIDUMP_EXCEPTION_INFORMATION loExceptionInfo;
	loExceptionInfo.ExceptionPointers = pExcPointer;
	loExceptionInfo.ThreadId = GetCurrentThreadId();
	loExceptionInfo.ClientPointers = TRUE;
	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),hFile, MiniDumpNormal, &loExceptionInfo, NULL, NULL);
	CloseHandle(hFile);

	return EXCEPTION_EXECUTE_HANDLER;
}

void WrongFun()
{
	//crash
    int * p = NULL;
	*p = 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//設定崩潰回撥函式
	SetUnhandledExceptionFilter(ExceptCallBack);

	WrongFun();

	return 0;
}


4,效果。

crash後先彈出一個對話方塊:


之後不再調windows自帶的崩潰對話方塊了。程式結束。

5,使用windbg檢視dmp檔案


用windbg 選單 File->Open Crash File 開啟這個Test.dmp檔案,在下方編輯框輸入 “!analyze -v” 命令執行自動分析。

稍等一會,就會出現一些內容,大致找到如下:

就能看到程式崩潰的一些細節甚至程式碼。