1. 程式人生 > >VS2010下使用dmp檔案和pdb檔案定位程式異常程式碼行號的注意事項

VS2010下使用dmp檔案和pdb檔案定位程式異常程式碼行號的注意事項

2018-01-12  建立人:Ruo_Xiao
2018-01-15  修改人:Ruo_Xiao
新增為dump、exe和pdb版本保持一致的原因。

一、minidump檔案

  1. 崩潰轉儲是建立一個應用程式崩潰瞬間的狀態映象。
  2. 初代的轉儲檔案是記錄了程序的虛擬空間中全部內容,但是這樣的檔案非常大,而且對於不太熟練使用的人員來說冗餘資訊太多。
  3. xp之後,MicroSoft發明了“minidump”的轉儲技術,即:小型的,只是包含了必要的執行緒呼叫堆疊等資訊檔案。該檔案很小,很容易通過網路傳送,同時也可以定製該檔案記錄的資訊,非常的靈活。
  4. 生成minidump的函式包含在DbgHelp.dll中。

二、pdb檔案

後續加入!

三、注意事項

1、 exe檔案、dmp檔案和pdb檔案必須保持一致!

在上篇部落格中,我們簡單的介紹瞭如何用dmp檔案和pdb檔案定位程式碼中崩潰位置。連結如下:
http://blog.csdn.net/itworld123/article/details/79041500
上述能夠成功定位的一個前提是exe檔案、dmp檔案和pdb檔案都是同時生成的,即:exe檔案和pdb檔案同時生成,dmp檔案是由當前exe生成的。若生成崩潰資訊之後,又重新編譯了exe,與此同時也重新生成了pdb檔案,那麼即使程式碼沒有任何改動,此時WinDbg也沒有辦法進行程式碼行號定位了,顯示的資訊如下:

WRITE_ADDRESS:  0000000c 

FOLLOWUP_IP: 
TEST11+100b
012b100b c7050c00000005000000 mov dword ptr ds:[0Ch],5

MOD_LIST: <ANALYSIS/>

FAULTING_THREAD:  0000139c

BUGCHECK_STR:  APPLICATION_FAULT_NULL_CLASS_PTR_DEREFERENCE_INVALID_POINTER_WRITE_WRONG_SYMBOLS

PRIMARY_PROBLEM_CLASS:  NULL_CLASS_PTR_DEREFERENCE

DEFAULT_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE

LAST_CONTROL_TRANSFER:  from 746b336a to 012b100b

STACK_TEXT:  
WARNING: Stack unwind information not available. Following frames may be wrong.
0029f934 746b336a 7efde000 0029f980 77139902 TEST11+0x100b
0029f940 77139902 7efde000 7735f926 00000000 kernel32!BaseThreadInitThunk+0x12
0029f980 771398d5 012b132d 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x63
0029f998 00000000 012b132d 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36


STACK_COMMAND:  ~0s; .ecxr ; kb

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  TEST11+100b

FOLLOWUP_NAME:  MachineOwner

IMAGE_NAME:  TEST11.exe

BUCKET_ID:  WRONG_SYMBOLS

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE_c0000005_TEST11.exe!Unknown

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/TEST11_exe/0_0_0_0/5a58a12a/TEST11_exe/0_0_0_0/5a58a12a/c0000005/0000100b.htm?Retriage=1

Followup: MachineOwner

上述資訊大家可以看到,定位原始碼的功能已經消失了。

2、關閉程式碼優化功能。

#include "stdafx.h"
#include <windows.h>


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

static long  __stdcall CrashInfocallback(_EXCEPTION_POINTERS *pexcp);

void ErrorFun(int *p)
{
	p[2] = 10;  //這裡崩潰
}

int _tmain(int argc, _TCHAR* argv[])
{
	::SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)CrashInfocallback);
	int *pi = NULL;  
	ErrorFun(pi);  
	return 0;
}

long  __stdcall CrashInfocallback( _EXCEPTION_POINTERS *pexcp)
{
	HANDLE hDumpFile = ::CreateFile(
										L"MEMORY.DMP",
										GENERIC_WRITE,
										0,
										NULL,
										CREATE_ALWAYS,
										FILE_ATTRIBUTE_NORMAL,
										NULL
									);
	if( hDumpFile != INVALID_HANDLE_VALUE)
	{
		MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
		dumpInfo.ExceptionPointers = pexcp;
		dumpInfo.ThreadId = ::GetCurrentThreadId();
		dumpInfo.ClientPointers = TRUE;
		::MiniDumpWriteDump(
								::GetCurrentProcess(),
								::GetCurrentProcessId(),
								hDumpFile,
								MiniDumpNormal,
								&dumpInfo,
								NULL,
								NULL
							);
	}
	::CloseHandle(hDumpFile);
	return 0;
}

上述程式碼在沒有關閉程式碼優化功能的情況下,按照上篇部落格的方法,生成的資訊如下:

WRITE_ADDRESS:  00000008 

FOLLOWUP_IP: 
TEST11!wmain+b [d:\huawei\projects\test11\test11\test11.cpp @ 22]
013e100b c705080000000a000000 mov dword ptr ds:[8],0Ah

MOD_LIST: <ANALYSIS/>

FAULTING_THREAD:  00000814

BUGCHECK_STR:  APPLICATION_FAULT_NULL_CLASS_PTR_DEREFERENCE_INVALID_POINTER_WRITE_WRONG_SYMBOLS

PRIMARY_PROBLEM_CLASS:  NULL_CLASS_PTR_DEREFERENCE

DEFAULT_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE

LAST_CONTROL_TRANSFER:  from 013e120c to 013e100b

STACK_TEXT:  
0038f9cc 013e120c 00000001 00032888 00033a40 TEST11!wmain+0xb [d:\huawei\projects\test11\test11\test11.cpp @ 22]
0038fa10 746b336a 7efde000 0038fa5c 77139902 TEST11!__tmainCRTStartup+0x122 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 552]
WARNING: Stack unwind information not available. Following frames may be wrong.
0038fa1c 77139902 7efde000 775e96bf 00000000 kernel32!BaseThreadInitThunk+0x12
0038fa5c 771398d5 013e132d 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x63
0038fa74 00000000 013e132d 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36


STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:  
    18: int _tmain(int argc, _TCHAR* argv[])
    19: {
    20: 	::SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)CrashInfocallback);
    21: 	int *pi = NULL;  
>   22: 	ErrorFun(pi);  
    23: 	return 0;
    24: }
    25: 
    26: long  __stdcall CrashInfocallback( _EXCEPTION_POINTERS *pexcp)
    27: {


SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  test11!wmain+b

FOLLOWUP_NAME:  MachineOwner

IMAGE_NAME:  TEST11.exe

BUCKET_ID:  WRONG_SYMBOLS

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE_c0000005_TEST11.exe!wmain

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/TEST11_exe/0_0_0_0/5a58a3c4/TEST11_exe/0_0_0_0/5a58a3c4/c0000005/0000100b.htm?Retriage=1

Followup: MachineOwner

大家可以發現,WinDbg確實定位到了原始碼位置,但是僅僅是函式外面,沒有進去。
後來上網查了很多資料,最後隱約感覺到可能是Release程式碼優化的原因,所以當我關閉程式碼優化的時候,成功地定位到了真正的位置。資訊如下:

WRITE_ADDRESS:  00000008 

FOLLOWUP_IP: 
TEST11!ErrorFun+6 [d:\huawei\projects\test11\test11\test11.cpp @ 15]
00df1006 c740080a000000  mov     dword ptr [eax+8],0Ah

MOD_LIST: <ANALYSIS/>

FAULTING_THREAD:  000013ac

BUGCHECK_STR:  APPLICATION_FAULT_NULL_CLASS_PTR_DEREFERENCE_INVALID_POINTER_WRITE_WRONG_SYMBOLS

PRIMARY_PROBLEM_CLASS:  NULL_CLASS_PTR_DEREFERENCE

DEFAULT_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE

LAST_CONTROL_TRANSFER:  from 00df102f to 00df1006

STACK_TEXT:  
0028fbfc 00df102f 00000000 00000000 0028fc50 TEST11!ErrorFun+0x6 [d:\huawei\projects\test11\test11\test11.cpp @ 15]
0028fc0c 00df1232 00000001 003b2888 003b3a40 TEST11!wmain+0x1f [d:\huawei\projects\test11\test11\test11.cpp @ 22]
0028fc50 746b336a 7efde000 0028fc9c 77139902 TEST11!__tmainCRTStartup+0x122 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 552]
WARNING: Stack unwind information not available. Following frames may be wrong.
0028fc5c 77139902 7efde000 77413872 00000000 kernel32!BaseThreadInitThunk+0x12
0028fc9c 771398d5 00df1353 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x63
0028fcb4 00000000 00df1353 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36


STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:  
    11: static long  __stdcall CrashInfocallback(_EXCEPTION_POINTERS *pexcp);
    12: 
    13: void ErrorFun(int *p)
    14: {
>   15: 	p[2] = 10;  //?a¨¤?¡À¨¤¨¤¡ê
    16: }
    17: 
    18: int _tmain(int argc, _TCHAR* argv[])
    19: {
    20: 	::SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)CrashInfocallback);


SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  test11!ErrorFun+6

FOLLOWUP_NAME:  MachineOwner

IMAGE_NAME:  TEST11.exe

BUCKET_ID:  WRONG_SYMBOLS

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE_c0000005_TEST11.exe!ErrorFun

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/TEST11_exe/0_0_0_0/5a58a4b0/TEST11_exe/0_0_0_0/5a58a4b0/c0000005/00001006.htm?Retriage=1

Followup: MachineOwner

拓展:VS2010關閉程式碼優化的方法:
專案 -> 工程名 + 屬性
彈出如下圖所示的框:
這裡寫圖片描述
對“優化”選擇“已禁用”,預設為“使速度最大化”,確定之後,重新編譯程式即可。

四、總結

  1. 禁用程式優化功能。
  2. exe、pdb和dmp檔案保持一致。
    解釋:exe檔案和pdb檔案同時生成,dmp檔案是由當前exe生成的。

五、原始碼