您的位置:首页 > 其它

VS2010下使用dmp文件和pdb文件定位到dll中崩溃位置的方法

2018-01-15 17:42 2201 查看
2018-01-15  创建人:Ruo_Xiao
邮箱:xclsoftware@163.com


一、基础链接

http://blog.csdn.net/itworld123/article/details/79041500

http://blog.csdn.net/itworld123/article/details/79047788

http://blog.csdn.net/itworld123/article/details/79061296

二、源码

1、DLL代码(工程1)

#pragma once

#ifdef  __XError_Export__
#define __XError_DLL__  _declspec(dllexport)
#else
#define __XError_DLL__  _declspec(dllimport)
#endif

class __XError_DLL__ XError
{
public:
XError(void);
~XError(void);
public:
void ErrorFun(int *p);
};
--------------------------------------------------------------
void XError::ErrorFun(int *p)
{
p[2] = 10;  //崩溃位置,源码中显示第16行
}


2、测试代码(工程2)

#include "stdafx.h"
#include "source/ErrorDLL/XError.h"
#include <windows.h>

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

static long  __stdcall CrashInfocallback(_EXCEPTION_POINTERS *pexcp);

int _tmain(int argc, _TCHAR* argv[])
{
::SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)CrashInfocallback);

XError X;
int *p = NULL;
X.ErrorFun(p);   //调用dll中含有崩溃代码的函数,源码第19行
return 0;
}

long  __stdcall CrashInfocallback(_EXCEPTION_POINTERS *pexcp)
{
//创建 Dump 文件
HANDLE hDumpFile = ::CreateFile(
L"MEMORY.DMP",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if( hDumpFile != INVALID_HANDLE_VALUE)
{
//Dump信息
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ExceptionPointers = pexcp;
dumpInfo.ThreadId = GetCurrentThreadId();
dumpInfo.ClientPointers = TRUE;
//写入Dump文件内容
::MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hDumpFile,
MiniDumpNormal,
&dumpInfo,
NULL,
NULL
);
}
return 0;
}


三、要点

PE文件中包含了对应的pdb文件的校验码和路径,二者必须和pdb文件保持一致,即:PE文件和pdb文件必须同时生成,pdb文件必须在PE文件中记录的路径下。

pdb文件中记录了源码的位置,若该位置下有源码,则定位时不仅可以定位到行号而且还能显示对应的源码,反之只能显示行号。通常情况下不方便提供源码,故pdb文件必须在所属的PE文件下。

四、定位dll文件中崩溃位置行号步骤

1、修改工程1的pdb文件生成目录,如下所示。

项目 -> 工程名 + 属性,按照下图修改



将“生成程序数据库文件”改为上图所示,意思是dll对应的pdb文件的生成路径为C盘PDB文件下,名字为工程名.pdb,同时该路径会被记录在对应的PE文件中(重要!!!)。

2、将生成的dll文件copy到exe所在的目录下,如下所示:



双击exe,因为程序崩溃自动生成了“MEMORY.DMP”文件,如下图所示:



3、打开WinDbg软件,操作步骤如下:

(1)File -> Image File Path 下图所示的框:



选中“Browse…”按钮,选择TEST1.exe,如下图所示:



(2)File -> Open Crash Dump… 选择刚才生成的”MEMORY.DMP”文件。

(3)之后软件会弹出命令行窗口,如下图所示:



在下面命令行那里输入“!analyze -v”,WinDbg会自动根据信息分析出崩溃的代码行数,部分结果如下:

WRITE_ADDRESS:  00000008

FOLLOWUP_IP:
ErrorDLL!XError::ErrorFun+6 [d:\errordll\errordll\xerror.cpp @ 16]
70591036 c740080a000000  mov     dword ptr [eax+8],0Ah

MOD_LIST: <ANALYSIS/>

FAULTING_THREAD:  00001dac

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 01201054 to 70591036

STACK_TEXT:
0038fab8 01201054 00000000 4546f4ea 01203018 ErrorDLL!XError::ErrorFun+0x6 [d:\errordll\errordll\xerror.cpp @ 16]
WARNING: Stack unwind information not available. Following frames may be wrong.
0038fae0 01201268 00000001 00601ba8 00604150 TEST1+0x1054
0038fb24 74a2336a 7efde000 0038fb70 77039902 TEST1+0x1268
0038fb30 77039902 7efde000 7733d33e 00000000 kernel32!BaseThreadInitThunk+0x12
0038fb70 770398d5 01201389 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x63
0038fb88 00000000 01201389 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36

STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:
12: }
13:
14: void XError::ErrorFun(int *p)
15: {
>   16:     p[2] = 10;
17: }

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  errordll!XError::ErrorFun+6

FOLLOWUP_NAME:  MachineOwner

IMAGE_NAME:  ErrorDLL.dll

BUCKET_ID:  WRONG_SYMBOLS

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE_c0000005_ErrorDLL.dll!XError::ErrorFun

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/TEST1_exe/0_0_0_0/5a5c1877/ErrorDLL_dll/0_0_0_0/5a5d4b1a/c0000005/00001036.htm?Retriage=1


WRITE_ADDRESS:  00000008
写入空指针,违规访问。
---------------------------------------------------------------
XError::ErrorFun+0x6 [d:\errordll\errordll\xerror.cpp @ 16]
dll源码中第16行异常。
---------------------------------------------------------------
STACK_COMMAND:  ~0s; .ecxr ; kb
FAULTING_SOURCE_CODE:
12: }
13:
14: void XError::ErrorFun(int *p)
15: {
>   16:     p[2] = 10;
17: }
WinDbg定位到了dll源码位置。


任务达成!

五、注意事项

exe、pdb和dmp文件保持版本一致。

在dll工程设置的 pdb生成目录下存在对应的pdb文件。

源码存在于原来的位置,路径没有改动。

六、分析

1、若源码位置改动,我这里把路径下的工程名改为“ErrorDLL00”,WinDbg的部分分析结果如下:

WRITE_ADDRESS:  00000008

FOLLOWUP_IP:
ErrorDLL!XError::ErrorFun+6 [d:\errordll\errordll\xerror.cpp @ 16]
70591036 c740080a000000  mov     dword ptr [eax+8],0Ah

MOD_LIST: <ANALYSIS/>

FAULTING_THREAD:  00001dac

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 01201054 to 70591036

STACK_TEXT:
0038fab8 01201054 00000000 4546f4ea 01203018 ErrorDLL!XError::ErrorFun+0x6 [d:\errordll\errordll\xerror.cpp @ 16]
WARNING: Stack unwind information not available. Following frames may be wrong.
0038fae0 01201268 00000001 00601ba8 00604150 TEST1+0x1054
0038fb24 74a2336a 7efde000 0038fb70 77039902 TEST1+0x1268
0038fb30 77039902 7efde000 7733d33e 00000000 kernel32!BaseThreadInitThunk+0x12
0038fb70 770398d5 01201389 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x63
0038fb88 00000000 01201389 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36

STACK_COMMAND:  ~0s; .ecxr ; kb

FAULTING_SOURCE_CODE:
No source found for 'd:\errordll\errordll\xerror.cpp'

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  errordll!XError::ErrorFun+6

FOLLOWUP_NAME:  MachineOwner

IMAGE_NAME:  ErrorDLL.dll

BUCKET_ID:  WRONG_SYMBOLS

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE_c0000005_ErrorDLL.dll!XError::ErrorFun

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/TEST1_exe/0_0_0_0/5a5c1877/ErrorDLL_dll/0_0_0_0/5a5d4b1a/c0000005/00001036.htm?Retriage=1


大家可以发现,虽然WinDbg仍然可以分析出源码异常行号,但是不能再显示出对应的源码。

在源码对应位置显示的内容如下:

FAULTING_SOURCE_CODE:
No source found for 'd:\errordll\errordll\xerror.cpp'


大家可以发现,WinDbg不能在该路径下发现源码文件,故无法显示对应的异常源码。那么这个源码路径哪来的呢?之前的文章介绍过,这个源码路径就是存储在ErrorDLL.dll指定的ErrorDLL.pdb中。

2、若源码位置没有改动,我将ErrorDLL工程中pdb文件生成目录下的pdb文件删除,部分结果如下:

WRITE_ADDRESS:  00000008

FOLLOWUP_IP:
ErrorDLL!XError::ErrorFun+6
70591036 c740080a000000  mov     dword ptr [eax+8],0Ah

MOD_LIST: <ANALYSIS/>

FAULTING_THREAD:  00001dac

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 01201054 to 70591036

STACK_TEXT:
WARNING: Stack unwind information not available. Following frames may be wrong.
0038fab8 01201054 00000000 4546f4ea 01203018 ErrorDLL!XError::ErrorFun+0x6
0038fae0 01201268 00000001 00601ba8 00604150 TEST1+0x1054
0038fb24 74a2336a 7efde000 0038fb70 77039902 TEST1+0x1268
0038fb30 77039902 7efde000 7733d33e 00000000 kernel32!BaseThreadInitThunk+0x12
0038fb70 770398d5 01201389 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x63
0038fb88 00000000 01201389 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36

STACK_COMMAND:  ~0s; .ecxr ; kb

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  errordll!XError::ErrorFun+6

FOLLOWUP_NAME:  MachineOwner

IMAGE_NAME:  ErrorDLL.dll

BUCKET_ID:  WRONG_SYMBOLS

FAILURE_BUCKET_ID:  NULL_CLASS_PTR_DEREFERENCE_c0000005_ErrorDLL.dll!XError::ErrorFun

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/TEST1_exe/0_0_0_0/5a5c1877/ErrorDLL_dll/0_0_0_0/5a5d4b1a/c0000005/00001036.htm?Retriage=1 
Followup: MachineOwner


大家可以发现,如果pdb文件不存在的话,WinDbg就无法分析出源码位置了。

七、总结

PE文件中会记录对应的pdb文件路径,pdb文件中会记录源码位置,若三者路径都是正确的,即:都存在,WinDbg不仅可以定位到行号,还可以显示源码。

若没有源码,则只能定位到行号,不能定位到源码!

若PE文件中记录的对应的pdb文件路径下没有pdb文件,则WinDbg就连行号也无法定位了,而且结果也是值得商榷了。

八、源码

http://download.csdn.net/download/itworld123/10207344
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: