vs2010 利用DMP文件、pdb文件查找release下的异常行号的方法

2018-01-12  创建人:Ruo_Xiao
开发环境:Windows7,VS2010,WinDbg 6.12。

一、源码

#include "stdafx.h"
#include 


#include 
#pragma comment(lib,"Dbghelp.lib")

static long  __stdcall CrashInfocallback(_EXCEPTION_POINTERS *pexcp);

int _tmain(int argc, _TCHAR* argv[])
{
	::SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)CrashInfocallback);
	int *pi = NULL;
	pi[3] = 5;   //这里崩溃
	return 0;
}

long  __stdcall CrashInfocallback( _EXCEPTION_POINTERS *pexcp)
{
	HANDLE hDumpFile = ::CreateFile(
					L"MEMORY.DMP",
					GENERIC_WRITE,  //写入
					0, //不共享
					NULL,  //默认安全属性
					CREATE_ALWAYS,  //总是创建
					FILE_ATTRIBUTE_NORMAL, //默认属性
					NULL //为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
							);
	}
	return 0;
}

二、VS2010生成pdb文件

  1. 选择 项目 -> 工程名+属性,如下图所示。
    vs2010 利用DMP文件、pdb文件查找release下的异常行号的方法_第1张图片 2. 进去
  2. 之后选择 配置属性 -> 连接器 -> 调试,如下图所示。
    vs2010 利用DMP文件、pdb文件查找release下的异常行号的方法_第2张图片
  3. 右面选项如下图所示:
    vs2010 利用DMP文件、pdb文件查找release下的异常行号的方法_第3张图片
    上图中,“生成调试信息”为pdb文件生成与否的使能开关,“生成程序数据库文件”为该pdb文件的名字,默认即可。

三、生成DMP文件

两种方法:

  1. 利用资源管理器生成,即:程序崩溃之后会弹出“程序已停止运行对话框”,如下图所示:
    vs2010 利用DMP文件、pdb文件查找release下的异常行号的方法_第4张图片
    此时在资源管理器“进程页”中找到该程序,右击,弹出的下拉菜单中找到“创建转出文件”选项,单击即可生成,不过该文件会生成在系统目录,人工找到即可。
  2. 利用API在指定目录下生成,代码如上所示。
    (1)SetUnhandledExceptionFilter
    调用时机:当异常发生时,且程序不处于调试模式,则首先调用该函数。
    参数:lpTopLevelExceptionFilter ,函数指针。
    返回值:以前设置的回调函数。
    (2)CreateFile
HANDLE CreateFile(
 LPCTSTR lpFileName,    // 指向文件名的指针 
 DWORD dwDesiredAccess, // 访问模式(写 / 读) 
 DWORD dwShareMode,     // 共享模式,0就是不共享,反之共享。
 LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 指向安全属性的指针 
 DWORD dwCreationDisposition,   // 如何创建 
 DWORD dwFlagsAndAttributes,    // 文件属性 
 HANDLE hTemplateFile    // 用于复制文件句柄 
);

返回值:若成功,则返回一个句柄,若失败,则返回INVALID_HANDLE_VALUE,即:-1。
(3)MINIDUMP_EXCEPTION_INFORMATION
作用:该结构体包含将要通过 MiniDumpWriteDump函数写入Minidup文件中的崩溃信息。
原型:

typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
  DWORD ThreadId;
  PEXCEPTION_POINTERS ExceptionPointers;
  BOOL ClientPointers;
} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;

ThreadId:抛出异常的线程ID。
ExceptionPointers:指向_EXCEPTION_POINTERS结构体的首地址,该结构体指向了异常时处理器上下文和独立于计算机的异常描述。
ClientPointers:指定崩溃的内存位置。若为TRUE,则崩溃位置位于客户端自己的地址空间中。若为FALSE,则崩溃内存位于调用该程序的地址空间中。

(4)MiniDumpWriteDump
作用:向指定的文件中写入用户自己的minidump信息。
原型:

BOOL MiniDumpWriteDump ( 
HANDLE hProcess,
DWORD ProcessId,  
HANDLE hFile,
MINIDUMP_TYPE DumpType,  
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);

hProcess:生成当前信息文件的进程的句柄。
ProcessId:生成当前信息对文件的进程的ID。
hFile:被写入信息的文件的句柄。
DumpType:向文件中写入的信息的类型,可查看 MINIDUMP_TYPE 。
ExceptionParam:指向MINIDUMP_EXCEPTION_INFORMATION结构体指针,若为NULL,则没有信息写入文件中。
UserStreamParam:指向 MINIDUMP_USER_STREAM_INFORMATION 结构体指针,若为NULL,则文件中没有用户指定的信息。
CallbackParam:指向MINIDUMP_CALLBACK_INFORMATION结构的指针,指定要接收扩展小型转储信息的回调例程。如果此参数的值为NULL,则不执行回调。

四、寻找崩溃位置

  1. 执行程序,发现程序崩溃,如下图所示:
    vs2010 利用DMP文件、pdb文件查找release下的异常行号的方法_第5张图片
  2. release目录下生成了对应的DMP文件,如下图所示。
    这里写图片描述
  3. 打开WinDbg,依次进行下面操作:
    File -> Symbol File Path -> 选择pdb文件存放路径。
    File -> Image File Path -> 选择exe文件存放路径。
    File -> Open Crash Dump -> 选择DMP文件存放路径。
    最后会弹出WinDbg对崩溃文件的初步分析的结果,在下面的输入框中输入“!analyze -v”,意思是软件进行对崩溃文件进行分析,并显示出来,最后的结果如下所示:
PROCESS_NAME:  TEST11.exe

ADDITIONAL_DEBUG_TEXT:  
Use '!findthebuild' command to search for the target build information.
If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols.

FAULTING_MODULE: 75750000 kernel32

DEBUG_FLR_IMAGE_TIMESTAMP:  5a5820bb

MODULE_NAME: TEST11

ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

EXCEPTION_PARAMETER1:  00000001

EXCEPTION_PARAMETER2:  0000000c

WRITE_ADDRESS:  0000000c 

FOLLOWUP_IP: 
TEST11!wmain+b [d:\test11\test11\test11.cpp @ 17]
003d100b c7050c00000005000000 mov dword ptr ds:[0Ch],5

MOD_LIST: 

FAULTING_THREAD:  0000265c

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 003d1205 to 003d100b

STACK_TEXT:  
0032fa40 003d1205 00000001 005f1b20 005f1b70 TEST11!wmain+0xb [d:\test11\test11\test11.cpp @ 17]
0032fa84 7576336a 7efde000 0032fad0 77d19902 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.
0032fa90 77d19902 7efde000 767ba0cb 00000000 kernel32!BaseThreadInitThunk+0x12
0032fad0 77d198d5 003d1326 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x63
0032fae8 00000000 003d1326 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36


STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:  
    13: int _tmain(int argc, _TCHAR* argv[])
    14: {
    15: 	::SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)CrashInfocallback);
    16: 	int *pi = NULL;
>   17: 	pi[3] = 5;
    18: 	return 0;
    19: }
    20: 
    21: long  __stdcall CrashInfocallback( _EXCEPTION_POINTERS *pexcp)
    22: {


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/5a5820bb/TEST11_exe/0_0_0_0/5a5820bb/c0000005/0000100b.htm?Retriage=1

Followup: MachineOwner

由上述信息中

Attempt to write to address 0000000c

代表写空指针。

0032fa40 003d1205 00000001 005f1b20 005f1b70 TEST11!wmain+0xb [d:\test11\test11\test11.cpp @ 17]

和

    13: int _tmain(int argc, _TCHAR* argv[])
    14: {
    15: 	::SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)CrashInfocallback);
    16: 	int *pi = NULL;
>   17: 	pi[3] = 5;
    18: 	return 0;
    19: }
    20: 
    21: long  __stdcall CrashInfocallback( _EXCEPTION_POINTERS *pexcp)
    22: {

代表源码中第17行有异常。

上述就是简单地查找崩溃行数的方法。

五、源码工程

http://download.csdn.net/download/itworld123/10202793

(完)

你可能感兴趣的:(IDE,/,VS)