1. 程式人生 > >dump檔案,windbg

dump檔案,windbg

dump檔案,在VC中的除錯還是非常非常非常有用的,因為我們也不會經每一行程式碼都加上日誌,當然如果你願意,也可以每一行都加上日誌;

在Windows上,新增dump檔案有兩種方法:

方法一:一個是在程式中新增程式碼;

方法二:修改登錄檔(參考後面的bat檔案寫法,在win7上用管理員程式執行);建議用這個方法,方便實用;(http://blog.csdn.net/hgy413/article/details/7586957#)

from:

http://blog.csdn.net/byxdaz/article/details/25872151

http://blog.csdn.net/starlee/article/details/6630816

在Windows平臺下用C++開發應用程式,最不想見到的情況恐怕就是程式崩潰,而要想解決引起問題的bug,最困難的應該就是除錯release版本了。因為release版本來就少了很多除錯資訊,更何況一般都是釋出出去由使用者使用,crash的現場很難保留和重現。目前有一些方法可以解決:崩潰地址 + MAP檔案;MAP檔案;SetUnhandledExceptionFilter + Minidump。本文重點解決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檔案,即可實現需要的功能。

生成dump檔案類(minidump.h)

  1. #pragma once  
  2. #include <windows.h>  
  3. #include <imagehlp.h>  
  4. #include <stdlib.h>  
  5. #pragma comment(lib, "dbghelp.lib")  
  6. inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)  
  7. {  
  8.     if(pModuleName == 0)  
  9.     {  
  10.        return FALSE;  
  11.     }  
  12.     WCHAR szFileName[_MAX_FNAME] = L"";  
  13.     _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);  
  14.     if(wcsicmp(szFileName, L"ntdll") == 0)  
  15.        return TRUE;  
  16.     return FALSE;   
  17. }  
  18. inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,   
  19.                                   const PMINIDUMP_CALLBACK_INPUT   pInput,   
  20.                                   PMINIDUMP_CALLBACK_OUTPUT        pOutput)  
  21. {  
  22.     if(pInput == 0 || pOutput == 0)  
  23.        return FALSE;  
  24.     switch(pInput->CallbackType)  
  25.     {  
  26.     case ModuleCallback:   
  27.        if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)   
  28.            if(!IsDataSectionNeeded(pInput->Module.FullPath))   
  29.               pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);   
  30.     case IncludeModuleCallback:  
  31.     case IncludeThreadCallback:  
  32.     case ThreadCallback:  
  33.     case ThreadExCallback:  
  34.        return TRUE;  
  35.     default:;  
  36.     }  
  37.     return FALSE;  
  38. }  
  39. //建立Dump檔案  
  40. inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)  
  41. {  
  42.     HANDLE hFile = CreateFile(strFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
  43.     if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))  
  44.     {  
  45.        MINIDUMP_EXCEPTION_INFORMATION mdei;  
  46.        mdei.ThreadId           = GetCurrentThreadId();  
  47.        mdei.ExceptionPointers  = pep;  
  48.        mdei.ClientPointers     = FALSE;  
  49.        MINIDUMP_CALLBACK_INFORMATION mci;  
  50.        mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
  51.        mci.CallbackParam       = 0;  
  52.        MINIDUMP_TYPE mdt       = (MINIDUMP_TYPE)0x0000ffff;  
  53.        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci);  
  54.        CloseHandle(hFile);   
  55.     }  
  56. }  
  57. LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)  
  58. {  
  59.     return NULL;  
  60. }  
  61. BOOL PreventSetUnhandledExceptionFilter()  
  62. {  
  63.     HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));  
  64.     if (hKernel32 ==   NULL)  
  65.        return FALSE;  
  66.     void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");  
  67.     if(pOrgEntry == NULL)  
  68.        return FALSE;  
  69.     unsigned char newJump[ 100 ];  
  70.     DWORD dwOrgEntryAddr = (DWORD) pOrgEntry;  
  71.     dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far  
  72.     void *pNewFunc = &MyDummySetUnhandledExceptionFilter;  
  73.     DWORD dwNewEntryAddr = (DWORD) pNewFunc;  
  74.     DWORD dwRelativeAddr = dwNewEntryAddr -  dwOrgEntryAddr;  
  75.     newJump[ 0 ] = 0xE9;  // JMP absolute  
  76.     memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc));  
  77.     SIZE_T bytesWritten;  
  78.     BOOL bRet = WriteProcessMemory(GetCurrentProcess(),    pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);  
  79.     return bRet;  
  80. }  
  81. LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException)  
  82. {  
  83.     TCHAR szMbsFile[MAX_PATH] = { 0 };  
  84.     ::GetModuleFileName(NULL, szMbsFile, MAX_PATH);  
  85.     TCHAR* pFind = _tcsrchr(szMbsFile, '\\');  
  86.     if(pFind)  
  87.     {  
  88.        *(pFind+1) = 0;  
  89.        _tcscat(szMbsFile, _T("CreateMiniDump.dmp"));  
  90.        CreateMiniDump(pException,szMbsFile);  
  91.     }  
  92.     // TODO: MiniDumpWriteDump  
  93.     FatalAppExit(-1,  _T("Fatal Error"));  
  94.     return EXCEPTION_CONTINUE_SEARCH;  
  95. }  
  96. //執行異常處理  
  97. void RunCrashHandler()  
  98. {  
  99.     SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);  
  100.     PreventSetUnhandledExceptionFilter();  
  101. }  

//測試實現檔案

// 一個有函式呼叫的類

//

class CrashTest

{

public:

    void Test()

    {

       Crash();

    }

private:

    void Crash()

    {

           strcpy(NULL,"adfadfg");

    }

};

int _tmain(int argc_TCHARargv[])

{

    //設定異常處理函式

    RunCrashHandler();

    CrashTest test;

    test.Test();

    getchar();

    return 0;

}

注意事項

1、需要配置debug選項,在C/C++選項à常規à除錯資訊格式(設定為程式資料庫(/Zi));在聯結器選項—>除錯à生成除錯資訊(設定為是);C/C++選項à優化à禁用。(參見下圖)

2、  可執行檔案(exe)必須找到dbghelp.dll,才能生成Dump檔案。這個DLL可以從除錯工具包中找到。

3、*.exe、*.pdb、*.dump、dbghelp.dll 這四個檔案需要放在同一目錄下才好除錯,雙擊dump檔案時,就可以自動關聯到出錯程式碼位置。

4、為了獲取更多更深入的除錯資訊,需要把程式優化開關設定成禁用。

5、 當異常程式碼定位成功以後,如果無法阻止異常的產生,可以用 __try 結構包裝異常程式碼,__try 和 try 不同,前者可以捕獲非法指標產生的異常。

__try {

// 會異常的函式

}

__except( EXCEPTION_EXECUTE_HANDLER ){

// 異常處理

}

二、除錯Minidump檔案

  1. 雙擊minidump檔案(*.dmp)。預設會啟動vs2008。
  2. 選單Tools/Options, Debugging/Symbols,增加PDB檔案路徑。注:如果minidump檔案與pdb檔案在同一目錄,就不用設定這個了。
  3. 若除錯的程式需要微軟基礎庫的PDB資訊,可以增加一個路徑為:
  4. 在介面下方Cache Symbol From symbol…選擇本地儲存這些Symbols的路徑。 注:如果本地已儲存過微軟基礎庫的pdb,就直接按照此步操作設定本地路徑,不必執行上一步操作了。
  5. 設定程式碼路徑:

設定程式碼路徑:

剛開啟的dmp工程,進入解決方案的屬性。在這裡輸入源程式的程式碼路徑。注:一定是sln所在的路徑,而不是vcproj的路徑!

按F5,debug吧。

//-

#pragma once






#include <windows.h>


#include <imagehlp.h>


#include <stdlib.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 far










void *pNewFunc = &MyDummySetUnhandledExceptionFilter;


DWORD dwNewEntryAddr = (DWORD) pNewFunc;


DWORD dwRelativeAddr = dwNewEntryAddr -  dwOrgEntryAddr;










newJump[ 0 ] = 0xE9;  // JMP absolute


memcpy(&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: MiniDumpWriteDump


FatalAppExit(-1,  _T("Fatal Error"));


return EXCEPTION_CONTINUE_SEARCH;


}






//執行異常處理


void RunCrashHandler()


{


SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);


PreventSetUnhandledExceptionFilter();


}

除錯方法不用上述那麼麻煩,直接在Debug目錄下 或者 Release目錄下 exe + pdb + dmp 在同一目錄,然後雙擊dmp檔案VC2010就可以開啟,然後點選右上角的除錯按鈕就可以直接定位到崩潰的程式碼了;

參考這裡: http://blog.csdn.net/starlee/article/details/6630816

別人機器上的dump除錯:

http://blog.csdn.net/xhk456/article/details/7523150

這段時間突然發現,要一下做一個金剛不壞之身的程式是不太可能滴,至於對我來說吧。
這個程式也要經過千錘百煉才能夠練就一個強大的自信心。

我現在做系統就不考慮一下把程式做的足夠強壯了,因為我也做不到大哭,現在做系統時,總考慮的一個問題:

當系統異常的時候怎麼去處理?

我不怕系統程式出現異常,甚至直接Over,只要能在異常時處理異常後繼續運作,在崩潰重啟後能夠繼續把沒

乾的活給幹了,那麼這個在我能夠承受的範圍內,也在大多數客戶的承受範圍內,因為這樣就是我們所說的將

損失減小到最低,其實是不是最低只有自己能夠知道。

當然了,我更希望能夠做出一個健壯無比的牛逼程式,所以我想知道程式是在什麼情況下崩潰的,可是有些問題

你懂的,老在客戶機器上或者生產環境下出現,卻在自己的機器上和測試環境就他媽的不出現,遇見這種情況我是

跳樓或者殺人的心情都有了,偶爾我也犯過情緒,想提出辭職申請,換個行業去,告別這苦逼的程式設計師生涯,

可總不知道是什麼力量支援著我,讓我堅強依舊滴做著程式設計師,過著狗日的日子。

後來,不經意間,一位同事給我說了一個種在系統中異常或者崩潰的時候,來生成dump檔案,然後用偵錯程式來除錯。

這樣就可以在生產環境中的dmp檔案,拷貝到自己的開發機器上,除錯就可以找到錯誤的位置,配合程式除錯符號pdb檔案,

直接可以定位到原始碼中位置,真是太他媽的神奇了,雖然Release版本下的很多變數的值是不對滴,但並不影響我這個

這麼有執著心的coder來找bug。

同事給了我他寫的示例,往空指標拷貝資料,在非除錯下執行後,果然的崩了,果斷滴生成了一個副檔名為dmp的檔案,

然後他用vs2010開啟那個dmp檔案,vs2010很果斷滴定位到了那個往空指標拷貝資料那裡。

看他那嫻熟的操作,頓時感覺到了他的強大和微軟的牛逼。

後來我就學他,在程式中加入程式異常時產生dump檔案的功能,待系統釋出後,在一次不經意間一個程式掛掉了。

在客戶的謾罵中,我面帶笑容說:這個問題很好解決。我滿懷信心滴從伺服器上拷貝了程式崩潰產生dump檔案,

然後學著那個同事用vs2010開啟,我了個去,咋沒有定位到原始碼中內,只定位到了可執行檔案的一個地址,這讓哥

情何以堪吶!

還好,我對pdb瞭解還比較熟悉,想來應該是符號檔案的問題,於是就開始摸索的,不經意見的在

堆疊處右擊了下,發現選單裡竟然有“載入符號”,而且還有“符號路徑”,我想這大概就是讓我來選擇

對應的pdb檔案吧,頓時感覺曙光就在前面。

點選了“符號路徑”後如下圖:

才發現了,它並不是來選擇符號檔案,而是選擇對應的可執行程式的路徑,選擇了後果斷滴定位到了原始碼的位置,

才發現一個很簡單很美麗的bug,修改後,在測試後重現釋出,系統的健壯性又提高了一個臺階。

回頭想了想,我同事給我演示的時候,他程式執行的目錄和就是他直接用vs2010生成的目錄,所以此種情況下

用vs2010開啟dmp檔案即可定位到原始碼檔案。而釋出後的程式,一般情況下你根本不知道別人放在什麼地方去執行的,

因此除錯時還並必須選相同版本的可執行檔案,然後pdb檔案才會好好工作,要不沒可執行檔案,咋個除錯嘛。

哎,這同事,居然還留了一手,坑爹啊。

不過還是要感謝他滴,我又掌握了一些東西,又增強了我這個苦逼程式設計師寫好程式的信心。

在寫這個之前看了相關文章,感覺比較好的推薦一哈:

到這裡,你就可以在你的工程中通過程式碼的方式新增,在程式崩潰的時候回建立dump檔案了;

.dump

程式崩潰(crash)的時候, 為了以後能夠除錯分析問題, 可以使用WinDBG要把當時程式記憶體空間資料都儲存下來,生成的檔案稱為dump 檔案。 步驟:

1) 開啟WinDBG並將之Attach 到crash的程式程序

2) 輸入產生dump 檔案的命令

直接用.dump -?可以看到它的簡單說明:

  1. 0:000> .dump -?  
  2. Usage: .dump [options] filename  
  3. Options are:  
  4.   /a - Create dumps for all processes (requires -u)  
  5.   /b[a] - Package dump in a CAB and delete dump  
  6.   /c <comment> - Add a comment (not supported in all formats)  
  7.   /j <addr> - Provide a JIT_DEBUG_INFO address  
  8.   /f - Create a legacy style full dump  
  9.   /m[acdfFhiprRtuw] - Create a minidump (default)  
  10.   /o - Overwrite any existing file  
  11.   /u - Append unique identifier to dump name  

/o :覆蓋具有相同名字的dump檔案。如果沒有使用該選項又存在一個相同名字的檔案,則dump檔案不會被寫入:比如我的C盤原有一個myapp.dmp檔案:

  1. 0:000> .dump c:/myapp.dmp  
  2. Unable to create file 'c:/myapp.dmp' - Win32 error 0n80  
  3.     "檔案存在。"  
  4. 0:000> .dump /o c:/myapp.dmp  
  5. Creating c:/myapp.dmp - mini user dump  
  6. Dump successfully written  

/f (使用者模式:) 建立一個完整使用者模式dump,這裡要注意不要字面理解,

完整使用者模式dump是基本的使用者模式dump檔案。這種dump檔案包含程序的完整記憶體空間、程式本身的可執行映像、控制代碼表和其他對偵錯程式有用的資訊

注意 和名字無關,最大的"minidump"檔案實際上可以提供比完整使用者模式dump更多的資訊。例如,.dump /mf.dump /ma將建立比.dump /f更大更完整的檔案。

使用者模式下,使用.dump /m[MiniOptions] 是最好的選擇。通過這個開關建立的dump檔案可以很小也可以很大。通過指定合適的MiniOptions 可以控制究竟需要包含哪些資訊。

  1. 0:000> .dump /o/f c:/myapp.dmp  
  2. *****************************************************************************  
  3. * .dump /ma is the recommend method of creating a complete memory dump      *  
  4. * of a user mode process.                                                   *  
  5. *****************************************************************************  
  6. Creating c:/myapp.dmp - user full dump  
  7. Dump successfully written  


我們看到了,系統給出了提示:.dump /ma是建立完整dump的推薦方式(使用者模式下)

/m[MiniOptions] 建立一個小記憶體dump(核心模式)或者 minidump (使用者模式)。如果沒有指定 /f /m ,/m 是預設選項。

使用者模式下,/m 後面可以跟附加的MiniOptions 用來指定dump檔案中包含的資料。如果沒有使用MiniOptions ,dump檔案包含模組、執行緒和呼叫堆疊資訊,但是沒有其他附加資訊

MiniOption 作用
a 建立一個包含所有附加選項的minidump。/ma選項相當於/mfFhut —它會在minidump中新增完整的記憶體資料、控制代碼資料、已解除安裝模組資訊、基本記憶體資訊和執行緒時間資訊。
f 在minidump中包含完整記憶體資料。目標程式擁有的所有 可訪問的已交付的頁面(committed pages)都會包含進去。
F 在minidump中新增所有基本記憶體資訊。這會將一個流加入到包含完整基本記憶體資訊的minidump中,而不單是可使用的記憶體。這樣可以使得偵錯程式能夠重建minidump生成時程序的完整虛擬記憶體佈局。
h 在minidump中包含和目標程序相關的控制代碼資訊。
u 在minidump中包含已解除安裝模組資訊。僅在Windows Server 2003和之後版本的Windows中可用。
t 在minidump中包含附加的執行緒資訊。包括可以在除錯minidump時使用!runaway擴充套件命令或.ttime (Display Thread Times)命令進行顯示的執行緒時間。
i 在minidump中包含次級記憶體(secondary memory)。次級記憶體是由堆疊中的指標或備份儲存(backing store)中引用到的任何記憶體,加上該地址周圍的一小段區域。
p 在minidump中包含程序環境塊(PEB)和執行緒環境塊(TEB)。這在想訪問程式的程序和執行緒相關的Windows系統資訊時很有用。
w 將所有已交付的可讀寫的私有頁面包含進minidump。
d 在minidump中包含可執行映像中所有可讀寫的資料段。
c 加入映像中的程式碼段。
r 從minidump中去掉對重建呼叫堆疊無用的堆疊和儲存記憶體部分。區域性變數和其他資料型別值也被刪除。這個選項不會使得minidump變小(因為這些記憶體節僅僅是變成0),但是當想保護其他程式中的機密資訊時有用。
R 在minidump中去掉完整的模組路徑。僅包含模組名。如果想保護使用者的目錄結構時該選項有用。

選項(1): /m

命令列示例:.dump /m C:/dumps/myapp.dmp

註解: 預設選項,生成標準的minidump, 轉儲檔案通常較小,便於在網路上通過郵件或其他方式傳輸。 這種檔案的資訊量較少,只包含系統資訊、載入的模組(DLL)資訊、 程序資訊和執行緒資訊。

選項(2): /ma

命令列示例:.dump /ma C:/dumps/myapp.dmp

註解: 帶有儘量多選項的minidump(包括完整的記憶體內容、控制代碼、未載入的模組,等等),檔案很大,如果條件允許(本機除錯,區域網環境), 推薦使用這中dump。

選項(3):/mFhutwd

命令列示例:.dump /mFhutwd C:/dumps/myapp.dmp

註解:帶有資料段、非共享的讀/寫記憶體頁和其他有用的資訊的minidump。包含了通過minidump能夠得到的最多的資訊。是一種折中方案。

Fhutwd按字母對應上面的MiniOptions表示

//-xp自動生成dump-----------------------------------------------------------------------------------------------------------------------------------------------------------------

那怎麼自動生成dump檔案呢,比如對方的電腦沒有windbg,這裡用到一個window XP系統自帶工具,Dr.Watson

執行方式很簡單:

直接run-輸入drwtsn32 -i就可以了,會提示這樣的:

這個命令真難記,實話,記華生醫生吧,福爾摩斯中的

如果有程式崩潰,會自動生成dump,這時再輸入drwtsn32就會執行這個程式:

找到對應路徑的DMP檔案就行了,一般放在如下路徑:
C:\Documents and Settings\All Users\Application Data\Microsoft\Dr Watson

 //-win7自動生成dump-----------------------------------------------------------------------------------------------------------------------------------------------------------------

win7下需開啟regedit--> 找到:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting]

在它下面加一項LocalDumps,並做如下項配置:

Value 描述 Type 預設值
DumpFolder 檔案儲存路徑 REG_EXPAND_SZ %LOCALAPPDATA%CrashDumps
DumpCount dump檔案的最大數目 REG_DWORD 10
DumpType 指定生成的dump型別:
0:Custom dump
1:Mini dump
2:Full dump
REG_DWORD 1
CustomDumpFlags 僅在DumpType為0時使用
為MINIDUMP_TYPE的組合
REG_DWORD
MiniDumpWithDataSegs|
MiniDumpWithUnloadedModules|
MiniDumpWithProcessThreadData

可以寫成.bat:

  1. @echo off  
  2. echo 設定Dump...  
  3. reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps"  
  4. reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d "C:\MyDump" /f  
  5. reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f  
  6. reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpCount /t REG_DWORD /d 10 /f  
  7. echo Dump已經設定  
  8. pause  
  9. @echo on  
  1. @echo off  
  2. echo 正在取消設定Dump...  
  3. reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /f  
  4. echo Dump已經取消設定  
  5. pause  
  6. @echo on  

LocalDumps是全域性的,如果想針對指定程序單獨設定,如test1.exe,則在/LocalDumps下新建子項test1.exe,同時在test1目錄下複製上表的選項,這樣,系統就會先讀全域性設定,再讀子項test1.exe的設定

簡單測試:

void CtMFC5Dlg::OnBnClickedButton1()
{
// TODO: 在此新增控制元件通知處理程式程式碼
char * pstr = NULL;

int n = strlen( pstr );

}

在Windows 7上可以由多個方法產生dump檔案:

轉一篇文章:

如何使用dump檔案

我最近在開發一個windows下的程式(win7/win8),有一些case下會crash,如果在自己開發機器上除錯比較簡單:執行程式,然後vs attach到程序上即可,但是在每臺QA的機器上安裝vs時不現實的,因此我們要用到dump檔案。

微軟網站有一篇文章講述如何建立dump檔案:

http://support.microsoft.com/kb/931673

第一種: 通過工作管理員:這種適用在程式掛了(crash)的時候程序還未退出,比如我執行程式,出現了下面的錯:

此時開啟工作管理員,右擊相應程序,點選"Create Dump File“:

一會建立完成:

然後把這個DMP檔案拷到開發機器上,用VS開啟: 會出現下面的介面,要想知道發生錯誤時候的呼叫棧,需要設定symbol的路徑,點選”Set Symbol Paths“:

注意這個pdb要對應於crash的exe,否則呼叫棧沒法顯示:

設定完成後,點選”Debug with Native Only“ 你就可以看到呼叫棧了。

第二種: 改登錄檔

如果程式crash的時候沒有框蹦出來,可以通過改登錄檔的設定讓作業系統在程式crash的時候自動生成dump,並放到特定的目錄下

  1. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps  
  2. Value Name = DumpType  
  3. Data type: REG_DWORD  
  4. Value Data = 1  


其中Value Data=1代表的含義是:

  1. 0 = Create a custom dump  
  2. 1 = Mini dump  
  3. 2 = Full dump  


設定完成後,crash發生時,作業系統生成dump,路徑在%LOCALAPPDATA%\CrashDumps下,詳細可以參考:

http://msdn.microsoft.com/en-us/library/bb787181%28v=VS.85%29.aspx

(完)

這裡再介紹一個dump工具:

procdump.exe / procdump64.exe; 

通過命令列執行,這裡簡化,寫到bat檔案中;

procdump.exe -l -ma -b -e -t -n 1 36280 -o ./testtestdump.dump

36280 :指的是 程序的PID,可以從人物管理器獲取;

更多引數,可以直接cmd執行procdump.exe檢視;

這裡要說明一個問題,這個產生的dmp檔案,在VS2017中除錯的時候,定位不準確,但是我已經將pdb檔案路徑設定了;

不過用windbg.exe,可以很好的定位;

《windgb的簡單應用》  定位,和資訊更清楚;

簡單說明:

1:設定pdb檔案路徑:File -》 Symbol file path...

2:File -》Open Crash Dump

3:等待載入完成後,執行命令:

      !analyze -v // 詳細顯示當前異常資訊

4:檢視輸出資訊;

5:View -》 Call Stack

6:雙擊可以直接定位原始碼檔案,所以,前面不需要設定原始檔路徑;

windgb命令:

!analyze -v // 詳細顯示當前異常資訊

!peb // 格式化輸出PEB資訊(process's environment block)

!gle  // 列印當前執行緒最近的錯誤資訊

!gle -all  // 列印所有執行緒的最近的錯誤資訊

!error  897// 顯示錯誤碼為897的詳細描述資訊