前言
遊戲開發的過程中,經常會出現用戶端當機的問題,這時候一個小小的dump檔案可以記錄當時的記憶體及堆棧情況,對于解決崩潰的問題有巨大的幫助,之前用VS2008的時候調試過dump檔案,但是最近用戶端更新為VS2015以後,調試dump檔案時經常會出現未找到xxx.exe或xxx.dll的情況,之前一直好使的方法現在卻行不通了,于是決定找找解決的辦法。
問題原因
起初嘗試過建立dump檔案所顯示的路徑,複制exe或dll到指定路徑下,複制dump檔案到exe所在路徑下都提示找不到,甚至是手動指定dll或者exe檔案都無法打開,這就很奇怪了,原來隻要把dump檔案放在exe所在目錄就可以啊,怎麼這次不行了呢?終于,經過多次試驗之後發現,原來在VS2015上調試dump檔案,要求dump檔案的版本與産生dump檔案的exe或者dll必須一緻,也就是說你要調試一個dump檔案,就必須找到找到對應版本dll和exe,否則就會提示無法找到xxx.exe或xxx.dll,下面我們來試驗一下。
産生dump檔案
産生dump檔案的方法網上很容易找到,如果想測試的話可以自己找一找,也可以使用下面的代碼:
#include "stdafx.h"
#include "Windows.h"
#include "DbgHelp.h"
int GenerateMiniDump(PEXCEPTION_POINTERS pExceptionPointers)
{
// 定義函數指針
typedef BOOL(WINAPI * MiniDumpWriteDumpT)(
HANDLE,
DWORD,
HANDLE,
MINIDUMP_TYPE,
PMINIDUMP_EXCEPTION_INFORMATION,
PMINIDUMP_USER_STREAM_INFORMATION,
PMINIDUMP_CALLBACK_INFORMATION
);
// 從 "DbgHelp.dll" 庫中擷取 "MiniDumpWriteDump" 函數
MiniDumpWriteDumpT pfnMiniDumpWriteDump = NULL;
HMODULE hDbgHelp = LoadLibrary(_T("DbgHelp.dll"));
if (NULL == hDbgHelp)
{
return EXCEPTION_CONTINUE_EXECUTION;
}
pfnMiniDumpWriteDump = (MiniDumpWriteDumpT)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
if (NULL == pfnMiniDumpWriteDump)
{
FreeLibrary(hDbgHelp);
return EXCEPTION_CONTINUE_EXECUTION;
}
// 建立 dmp 檔案件
TCHAR szFileName[MAX_PATH] = { };
TCHAR* szVersion = _T("dump_file_v1.0");
SYSTEMTIME stLocalTime;
GetLocalTime(&stLocalTime);
wsprintf(szFileName, L"%s-%04d%02d%02d-%02d%02d%02d.dmp",
szVersion, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond);
HANDLE hDumpFile = CreateFile(szFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, , CREATE_ALWAYS, , );
if (INVALID_HANDLE_VALUE == hDumpFile)
{
FreeLibrary(hDbgHelp);
return EXCEPTION_CONTINUE_EXECUTION;
}
// 寫入 dmp 檔案
MINIDUMP_EXCEPTION_INFORMATION expParam;
expParam.ThreadId = GetCurrentThreadId();
expParam.ExceptionPointers = pExceptionPointers;
expParam.ClientPointers = FALSE;
pfnMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hDumpFile, MiniDumpWithDataSegs, (pExceptionPointers ? &expParam : NULL), NULL, NULL);
// 釋放檔案
CloseHandle(hDumpFile);
FreeLibrary(hDbgHelp);
return EXCEPTION_EXECUTE_HANDLER;
}
LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS lpExceptionInfo)
{
// 這裡做一些異常的過濾或提示
if (IsDebuggerPresent())
{
return EXCEPTION_CONTINUE_SEARCH;
}
return GenerateMiniDump(lpExceptionInfo);
}
void create_dump()
{
// 給空指針指派,使程式崩潰産生 Dump 檔案
int *ptr = NULL;
*ptr = ;
}
int main()
{
// 加入崩潰dump檔案功能
SetUnhandledExceptionFilter(ExceptionFilter);
create_dump();
}
将上述代碼編譯成exe檔案,然後點選運作就會在exe所在目錄産生一個dump檔案,例如我産生的dump檔案為dump_file_v1.0-20180623-123940.dmp
調試dump檔案
輕按兩下打開剛剛生成的dump檔案,會出現如下界面:
點選右側 “使用 僅限本機 進行調試” 按鈕,就會顯示出程式崩潰時的堆棧資訊和記憶體情況以及崩潰位置的代碼,如下圖:
以上是正常的調試情況,接下來不需要改變代碼,重新編譯一下程式,得到新版本的exe檔案,然後輕按兩下剛剛的dump檔案dump_file_v1.0-20180623-123940.dmp,點選右側 “使用 僅限本機 進行調試” 按鈕,情況就會發生變化,顯示結果如下圖:
點選 “中斷” 按鈕,就會出現标題所說的未找到vsDump.exe。在小型轉儲中未找到 vsDump.exe。 您需要加載二進制檔案才能查找目前堆棧幀的源代碼。
看到了吧,隻要是dump檔案不是這個exe産生的,不管源代碼是不是一樣,結果都會提示找不到exe,至此我們就找到了“VS2015調試dump檔案時提示未找到xxx.exe或xxx.dll”的原因。
總結
- VS2015調試dump檔案時需要保證dump檔案和exe、dll版本一緻
- 遇到奇怪的問題可以手動模拟一下,往往可以重制,然後找到具體的原因