簡單使用SetUnhandledExceptionFilter()函數讓程序優雅崩潰
雖然是大公司的產品,QQ它還是會在我們的折騰下崩潰的,但是它總是崩潰的很優雅,還要彈出自己的對話框來結束。並且發送報告,去掉了系統默認的發送報告的對話框。
所以一拍腦袋,想讓自己的程序崩潰的體面一點。
自己想了大概的思路,覺得可以用一個進程來監控目標程序。的確也可以拿到了目標程序崩潰的信息,知道它什么時候崩潰的,也可以做額外的操作,但是這樣是沒辦法把默認的發送錯誤的對話框去掉的。
然后又有人說是不是采用了類似鈎子的方法把這個東西在哪里勾掉了。
最后網上查了一番,發現SetUnhandledExceptionFilter這個函數解決了一切。
總結了下搜到的資料,這個函數的返回值有三種情況:
EXCEPTION_EXECUTE_HANDLER equ 1 表示我已經處理了異常,可以優雅地結束了
EXCEPTION_CONTINUE_SEARCH equ 0 表示我不處理,其他人來吧,於是windows調用默認的處理程序顯示一個錯誤框,並結束
EXCEPTION_CONTINUE_EXECUTION equ -1 表示錯誤已經被修復,請從異常發生處繼續執行
具體使用方法如下:
#include <windows.h>
long __stdcall callback(_EXCEPTION_POINTERS* excp)
{
MessageBox(0,"Error","error",MB_OK);
printf("Error address %x/n",excp->ExceptionRecord->ExceptionAddress);
printf("CPU register:/n");
printf("eax %x ebx %x ecx %x edx %x/n",excp->ContextRecord->Eax,
excp->ContextRecord->Ebx,excp->ContextRecord->Ecx,
excp->ContextRecord->Edx);
return EXCEPTION_EXECUTE_HANDLER;
}
int main(int argc,char* argv[])
{
SetUnhandledExceptionFilter(callback);
_asm int 3 //只是為了讓程序崩潰
return 0;
}
vs 調試dump
1. dump文件和pdb文件的匹配問題
>> 發布二進制文件時生成的pdb文件一定要保留,只有當發布的二進制文件和pdb文件是同時生成的才好正確調試。
2. dump文件和pdb文件放在哪里的問題
>> 如果dump文件和pdb文件放在同一個目錄,則可直接運行調試;當然也可以不是同一個目錄,那么在啟動dmp文件后,需要設置一下vs的符號文件路徑:Tools->Options->Debugging->Symbols. 如果需要調試windows自帶的一些dll或者exe,則可以在這里添加windows的pdb文件服務器:http://msdl.microsoft.com/download/symbols
3. 二進制文件放在哪里的問題
>> 現場恢復需要二進制文件,但不必所有的二進制文件都需要,所以即使你的機器和用戶的機器操作系統不一樣也沒關系;出問題的如果是你發布的二進制文件,則只需要你發布的二進制文件就可以了。vs在加載二進制的文件失敗的時候會打印出其詳細路徑,但這是用戶機器上的路徑,沒有必要一定要跟這個路徑一樣,把你發布的二進制文件放到dump文件目錄就可以了。
4. 顯示不了源代碼的問題
>> 首先需要設置源代碼目錄,右鍵solution:Properties->Common Properties->Debug Source Files,里邊加入你的本地源代碼目錄就是了;但是如果代碼已經改過了,恢復不到當時的狀態,vs顯示不了源碼怎么辦?只要設置:Tools->Options->Debugging->General->Require source files to exactly match the original version 這個復選框鈎掉就可以了
Minidump方式保留程序崩潰現場
在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)#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);
}
break; case IncludeModuleCallback: case IncludeThreadCallback: case ThreadCallback: case ThreadExCallback: return TRUE; default:
break; } 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(); }
//測試實現文件
// 一個有函數調用的類
class CrashTest { public: void Test() { Crash(); } private: void Crash() { strcpy(NULL,"adfadfg"); } }; int _tmain(int argc, _TCHAR* argv[]) { //設置異常處理函數 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文件
- 雙擊minidump文件(*.dmp)。默認會啟動vs2008。
- 菜單Tools/Options, Debugging/Symbols,增加PDB文件路徑。注:如果minidump文件與pdb文件在同一目錄,就不用設置這個了。
- 若調試的程序需要微軟基礎庫的PDB信息,可以增加一個路徑為:
- http://msdl.microsoft.com/download/symbols
- 在界面下方Cache Symbol From symbol…選擇本地存儲這些Symbols的路徑。 注:如果本地已存儲過微軟基礎庫的pdb,就直接按照此步操作設置本地路徑,不必執行上一步操作了。
設置代碼路徑:
設置代碼路徑:
剛打開的dmp工程,進入解決方案的屬性。在這里輸入源程序的代碼路徑。注:一定是sln所在的路徑,而不是vcproj的路徑!
按F5,debug吧。
demo代碼下載:http://download.csdn.net/detail/byxdaz/7349325
調試方法不用上述那么麻煩,直接在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文件才會好好工作,要不沒可執行文件,咋個調試嘛。
哎,這同事,居然還留了一手,坑爹啊。
不過還是要感謝他滴,我又掌握了一些東西,又增強了我這個苦逼程序員寫好程序的信心。
在寫這個之前看了相關文章,感覺比較好的推薦一哈:
http://www.cppblog.com/woaidongmao/archive/2011/05/10/146086.html
到這里,你就可以在你的工程中通過代碼的方式添加,在程序崩潰的時候回創建dump文件了;
.dump
.dump 命令創建一個用戶模式或內核模式崩潰轉儲文件。分析工具:https://msdn.microsoft.com/en-us/library/windows/desktop/ee416349(v=vs.85).aspx#writing_a_minidump
程序崩潰(crash)的時候, 為了以后能夠調試分析問題, 可以使用WinDBG要把當時程序內存空間數據都保存下來,生成的文件稱為dump 文件。 步驟:
1) 打開WinDBG並將之Attach 到crash的程序進程
2) 輸入產生dump 文件的命令
直接用.dump -?可以看到它的簡單說明:
- 0:000> .dump -?
- Usage: .dump [options] filename
- Options are:
- /a - Create dumps for all processes (requires -u)
- /b[a] - Package dump in a CAB and delete dump
- /c <comment> - Add a comment (not supported in all formats)
- /j <addr> - Provide a JIT_DEBUG_INFO address
- /f - Create a legacy style full dump
- /m[acdfFhiprRtuw] - Create a minidump (default)
- /o - Overwrite any existing file
- /u - Append unique identifier to dump name
/o :覆蓋具有相同名字的dump文件。如果沒有使用該選項又存在一個相同名字的文件,則dump文件不會被寫入:比如我的C盤原有一個myapp.dmp文件:
- 0:000> .dump c:/myapp.dmp
- Unable to create file 'c:/myapp.dmp' - Win32 error 0n80
- "文件存在。"
- 0:000> .dump /o c:/myapp.dmp
- Creating c:/myapp.dmp - mini user dump
- Dump successfully written
/f (用戶模式:) 創建一個完整用戶模式dump,這里要注意不要字面理解,
完整用戶模式dump是基本的用戶模式dump文件。這種dump文件包含進程的完整內存空間、程序本身的可執行映像、句柄表和其他對調試器有用的信息
注意 和名字無關,最大的"minidump"文件實際上可以提供比完整用戶模式dump更多的信息。例如,.dump /mf或.dump /ma將創建比.dump /f更大更完整的文件。
用戶模式下,使用.dump /m[MiniOptions] 是最好的選擇。通過這個開關創建的dump文件可以很小也可以很大。通過指定合適的MiniOptions 可以控制究竟需要包含哪些信息。
- 0:000> .dump /o/f c:/myapp.dmp
- *****************************************************************************
- * .dump /ma is the recommend method of creating a complete memory dump *
- * of a user mode process. *
- *****************************************************************************
- Creating c:/myapp.dmp - user full dump
- 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:
- @echo off
- echo 設置Dump...
- reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps"
- reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpFolder /t REG_EXPAND_SZ /d "C:\MyDump" /f
- reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpType /t REG_DWORD /d 2 /f
- reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /v DumpCount /t REG_DWORD /d 10 /f
- echo Dump已經設置
- pause
- @echo on
- @echo off
- echo 正在取消設置Dump...
- reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" /f
- echo Dump已經取消設置
- pause
- @echo on
LocalDumps是全局的,如果想針對指定進程單獨設置,如test1.exe,則在/LocalDumps下新建子項test1.exe,同時在test1目錄下復制上表的選項,這樣,系統就會先讀全局設置,再讀子項test1.exe的設置
在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,並放到特定的目錄下
- HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps
- Value Name = DumpType
- Data type: REG_DWORD
- Value Data = 1
其中Value Data=1代表的含義是:
- 0 = Create a custom dump
- 1 = Mini dump
- 2 = Full dump
設置完成后,crash發生時,操作系統生成dump,路徑在%LOCALAPPDATA%\CrashDumps下,詳細可以參考:
http://msdn.microsoft.com/en-us/library/bb787181%28v=VS.85%29.aspx
(完)
最簡單的方法,應用dump文件,就是修改注冊表,這樣每一個程序就自動回創建dump文件;
下面給出修改注冊表的reg文件:
注意修改cdb.exe路徑,和自己計算機上的一致;
將下面的內容保存到txt文本中,然后修修改txt為reg,然后保存,雙擊reg文件,導入到注冊表就可以了;
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug]
"Auto"="1"
"Debugger"="\"D:\\Program Files\\Debugging Tools for Windows (x86)\\cdb.exe\" -p %ld -e %ld -c \".dump /ma /u C:\\crash.dmp;q\""
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework]
"DbgJITDebugLaunchSetting"=dword:00000002
"DbgManagedDebugger"="\"D:\\Program Files\\Debugging Tools for Windows (x86)\\cdb.exe\" -p %ld -e %ld -c \".dump /ma /u C:\\crash.dmp;q\""