参考文章:文章一,文章二,文章三,文章四
事情的起因是这样子的,一次在qq群里有人问了这么一个问题 ,“如果我的程序崩溃了,我想把崩溃时的地址和寄存器值显示出来用什么方法啊”,看到这个问题就想起了有时用vs调试器调试程序时弹出的一个什么提示都没有的警告框,只是说某某地址访问冲突了,但是这些信息对于找到是程序什么地方出问题基本没有什么帮助,要是程序恰好有一个指针形状的东西指向了程序的某行代码那还好说,可以在他附近仔细找找有什么问题,要是没有这个指针形状的东西基本上就是抓瞎了。
然后群里有大神回复了可以使用一个开源库“crashrpt”或者使用“ms的dbghelp”,基于我以往的认识,开源的东西往往文档很少,而且我最近的打算是把ms的一套东西都尽可能地多了解,于是想着看看dbghelp,至于crashrpt,虽然说上面那个大神更加推崇,只能暂时放弃。
在网上继续搜索,发现dbghelp原来只是ms里面的一个动态链接库,就是dbghelp.dll这个库,之前还以为它是一个可以执行的小工具。那么显然接下来就是搜寻这个库的使用方法了,一个我可以很容易理解的用法如下(来着这篇文章),它的基本思路是在程序出错时会将错误信息写入dump文件中,基于此,它自己定义了一个minidump.h文件,这个头文件非常小,使用时包含它就可以了。这个是下载链接。
#include <windows.h> #include "minidump.h" LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo) { CreateMiniDump(pExceptionInfo, "d://user.dmp"); return EXCEPTION_EXECUTE_HANDLER; } void main() { SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); *(int*)0=0; // AV }
上面的程序运行出错后会在d盘下生产一个user.dmp文件,接下来的操作就是对这个dmp文件的处理了。
windows处理dmp文件有一个工具叫做WinDbg,这个工具的内容好像非常多,这里仅就对上面生成的user.dmp文件的处理谈谈它的使用方法,在网上也找到了一个WinDbg的教程。
首先在ms的主页上下载WinDbg,最好在ms的主页上下载,上面有32位的和64位的。在http://www.windbg.org/上面可以看到一个一个快速链接,点击它就会下载你选择的版本,我下载的是64位的,名字为X64 Debuggers And Tools-x64_en-us.msi。
最上面还有一个Download and Install Debugging Tools for Windows的选项,进去这个里面后也发现了一些很有用的信息,里面还有一个东西是必须的,就是Windows symbols这一栏,后面会讲为什么。
下载好X64 Debuggers And Tools-x64_en-us.msi并安装后不会在桌面生成一个图标,但是在开始菜单中会生成WinDbg这个快捷菜单,它的图标是一个电脑和搜索的标记。
然后打开WinDbg,再选择菜单栏“File”下面的“Open Crash Dump...”,在弹出的对话框中选择之前在C盘下生成的“user.dmp”文件。会生成下面的东西。
Microsoft (R) Windows Debugger Version 6.2.9200.16384 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. Loading Dump File [D:\user.dmp] User Mini Dump File: Only registers, stack and portions of memory are available Symbol search path is: srv* Executable search path is: srv* Windows 7 Version 7601 (Service Pack 1) MP (8 procs) Free x86 compatible Product: WinNt, suite: SingleUserTS Machine Name: Debug session time: Wed Feb 12 11:07:43.000 2014 (UTC + 8:00) System Uptime: not available Process Uptime: 0 days 0:00:01.000 ......................... This dump file has an exception of interest stored in it. The stored exception information can be accessed via .ecxr. (1070.1598): Access violation - code c0000005 (first/second chance not available) eax=00000000 ebx=006e0aa8 ecx=9d110000 edx=0019e0e8 esi=006e0a68 edi=003ee814 eip=774e0c42 esp=003ee4d4 ebp=003ee4e4 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 ntdll!NtGetContextThread+0x12: 774e0c42 83c404 add esp,4
但是在在WinDbg中的命令行中键入!analyze –v这个命令后又弹出了下面的问题:
上面红色画笔圈注的地方是用来输入WinDbg命令的地方,这里输入!analyze –v,会出现下面的提示:
0:000> !analyze –v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* Use !analyze -v to get detailed debugging information. *** ERROR: Symbol file could not be found. Defaulted to export symbols for kernel32.dll - ***** OS symbols are WRONG. Please fix symbols to do analysis. ***** OS (WOW64 kernel32) symbols are WRONG. Please fix symbols to do analysis. ************************************************************************* *** *** *** *** *** Either you specified an unqualified symbol, or your debugger *** *** doesn't have full symbol information. Unqualified symbol *** *** resolution is turned off by default. Please either specify a *** *** fully qualified symbol module!symbolname, or enable resolution *** *** of unqualified symbols by typing ".symopt- 100". Note that *** *** enabling unqualified symbol resolution with network symbol *** *** server shares in the symbol path may cause the debugger to *** *** appear to hang for long periods of time when an incorrect *** *** symbol name is typed or the network symbol server is down. *** *** *** *** For some commands to work properly, your symbol path *** *** must point to .pdb files that have full type information. *** *** *** *** Certain .pdb files (such as the public OS symbols) do not *** *** contain the required information. Contact the group that *** *** provided you with these symbols if you need this command to *** *** work. *** *** *** *** Type referenced: ntdll!_PEB *** *** *** ************************************************************************* ************************************************************************* *** *** *** *** *** Either you specified an unqualified symbol, or your debugger *** *** doesn't have full symbol information. Unqualified symbol *** *** resolution is turned off by default. Please either specify a *** *** fully qualified symbol module!symbolname, or enable resolution *** *** of unqualified symbols by typing ".symopt- 100". Note that *** *** enabling unqualified symbol resolution with network symbol *** *** server shares in the symbol path may cause the debugger to *** *** appear to hang for long periods of time when an incorrect *** *** symbol name is typed or the network symbol server is down. *** *** *** *** For some commands to work properly, your symbol path *** *** must point to .pdb files that have full type information. *** *** *** *** Certain .pdb files (such as the public OS symbols) do not *** *** contain the required information. Contact the group that *** *** provided you with these symbols if you need this command to *** *** work. *** *** *** *** Type referenced: nt!IMAGE_NT_HEADERS32 *** *** *** ************************************************************************* ********************************************************************* * Symbols can not be loaded because symbol path is not initialized. * * * * The Symbol Path can be set by: * * using the _NT_SYMBOL_PATH environment variable. * * using the -y <symbol_path> argument when starting the debugger. * * using .sympath and .sympath+ * ********************************************************************* ********************************************************************* * Symbols can not be loaded because symbol path is not initialized. * * * * The Symbol Path can be set by: * * using the _NT_SYMBOL_PATH environment variable. * * using the -y <symbol_path> argument when starting the debugger. * * using .sympath and .sympath+ * ********************************************************************* Probably caused by : TestUnicode.exe ( testunicode!main+32 ) Followup: MachineOwner ---------
大概的意思就是符号表没有被加载,然后我在google上搜索Symbols can not be loaded because symbol path is not initialized,上面的第一个链接就给出了答案,是stackoverflow中的回答,里面有一个快速的解决方法,就是输入!symfix这个命令,但是这个命令只能影响当前的这个文件。由于这个最简单,于是用这个尝试了一下,先输入!symfix,等这个执行后再执行!analyze –v命令,输出结果如下:
0:000> !analyze -v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* ***** OS symbols are WRONG. Please fix symbols to do analysis. ***** OS (WOW64 kernel32) symbols are WRONG. Please fix symbols to do analysis. ************************************************************************* *** *** *** *** *** Either you specified an unqualified symbol, or your debugger *** *** doesn't have full symbol information. Unqualified symbol *** *** resolution is turned off by default. Please either specify a *** *** fully qualified symbol module!symbolname, or enable resolution *** *** of unqualified symbols by typing ".symopt- 100". Note that *** *** enabling unqualified symbol resolution with network symbol *** *** server shares in the symbol path may cause the debugger to *** *** appear to hang for long periods of time when an incorrect *** *** symbol name is typed or the network symbol server is down. *** *** *** *** For some commands to work properly, your symbol path *** *** must point to .pdb files that have full type information. *** *** *** *** Certain .pdb files (such as the public OS symbols) do not *** *** contain the required information. Contact the group that *** *** provided you with these symbols if you need this command to *** *** work. *** *** *** *** Type referenced: ntdll!_PEB *** *** *** ************************************************************************* ************************************************************************* *** *** *** *** *** Either you specified an unqualified symbol, or your debugger *** *** doesn't have full symbol information. Unqualified symbol *** *** resolution is turned off by default. Please either specify a *** *** fully qualified symbol module!symbolname, or enable resolution *** *** of unqualified symbols by typing ".symopt- 100". Note that *** *** enabling unqualified symbol resolution with network symbol *** *** server shares in the symbol path may cause the debugger to *** *** appear to hang for long periods of time when an incorrect *** *** symbol name is typed or the network symbol server is down. *** *** *** *** For some commands to work properly, your symbol path *** *** must point to .pdb files that have full type information. *** *** *** *** Certain .pdb files (such as the public OS symbols) do not *** *** contain the required information. Contact the group that *** *** provided you with these symbols if you need this command to *** *** work. *** *** *** *** Type referenced: nt!IMAGE_NT_HEADERS32 *** *** *** ************************************************************************* FAULTING_IP: TestUnicode!main+32 [c:\users\allan\desktop\minidump\minidump.cpp @ 13] 00fe1e72 c7050000000000000000 mov dword ptr ds:[0],0 EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff) ExceptionAddress: 00fe1e72 (TestUnicode!main+0x00000032) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 00000001 Parameter[1]: 00000000 Attempt to write to address 00000000 DEFAULT_BUCKET_ID: WRONG_SYMBOLS PROCESS_NAME: TestUnicode.exe ADDITIONAL_DEBUG_TEXT: You can run '.symfix; .reload' to try to fix the symbol path and load symbols. FAULTING_MODULE: 75e70000 kernel32 DEBUG_FLR_IMAGE_TIMESTAMP: 52fb3449 MODULE_NAME: TestUnicode ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx EXCEPTION_PARAMETER1: 00000001 EXCEPTION_PARAMETER2: 00000000 WRITE_ADDRESS: 00000000 FOLLOWUP_IP: TestUnicode!main+32 [c:\users\allan\desktop\minidump\minidump.cpp @ 13] 00fe1e72 c7050000000000000000 mov dword ptr ds:[0],0 APP: testunicode.exe PRIMARY_PROBLEM_CLASS: WRONG_SYMBOLS BUGCHECK_STR: APPLICATION_FAULT_WRONG_SYMBOLS LAST_CONTROL_TRANSFER: from 00fe9b68 to 00fe1e72 STACK_TEXT: 0019fa6c 00fe9b68 00000001 002f3ec8 002f24a0 TestUnicode!main+0x32 0019fabc 00fe99af 0019fad0 75e8336a 7efde000 TestUnicode!__tmainCRTStartup+0x1a8 0019fac4 75e8336a 7efde000 0019fb10 774f9f72 TestUnicode!mainCRTStartup+0xf WARNING: Stack unwind information not available. Following frames may be wrong. 0019fad0 774f9f72 7efde000 76190ee6 00000000 kernel32!BaseThreadInitThunk+0x12 0019fb10 774f9f45 00fe1398 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x63 0019fb28 00000000 00fe1398 7efde000 00000000 ntdll!RtlInitializeExceptionChain+0x36 STACK_COMMAND: ~0s; .ecxr ; kb FAULTING_SOURCE_LINE: c:\users\allan\desktop\minidump\minidump.cpp FAULTING_SOURCE_FILE: c:\users\allan\desktop\minidump\minidump.cpp FAULTING_SOURCE_LINE_NUMBER: 13 FAULTING_SOURCE_CODE: 9: 10: void main() 11: { 12: SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); > 13: *(int*)0=0; // AV 14: printf("hello"); 15: } SYMBOL_STACK_INDEX: 0 SYMBOL_NAME: testunicode!main+32 FOLLOWUP_NAME: MachineOwner IMAGE_NAME: TestUnicode.exe BUCKET_ID: WRONG_SYMBOLS FAILURE_BUCKET_ID: WRONG_SYMBOLS_c0000005_TestUnicode.exe!main WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/TestUnicode_exe/0_0_0_0/52fb3449/TestUnicode_exe/0_0_0_0/52fb3449/c0000005/00011e72.htm?Retriage=1 Followup: MachineOwner ---------
_NT_SYMBOL_PATH这个环境变量为
srv*C:\Windows\symbols*http://msdl.microsoft.com/download/symbols。
注意要是设置这个变量还是无效,可能是用户无权访问“C:\Windows\symbols”这个文件夹的原因,看下stackoverflow的回答:
I usually go to the System control panel, then Advanced tab, then Environment. You can then add the requisite_NT_SYMBOL_PATH variable. Then you don't have to do anything on the command-line before running WinDbg.
The setting of srv*C:\Windows\Symbols*http://msdl.microsoft.com/download/symbols as suggested by staffan is fine. I usually prefer to use my own profile for storing symbols though (so that I don't need to edit the permissions forC:\Windows\Symbols, since I intentionally run as a limited user, for good security hygiene). Thus (in my case) my_NT_SYMBOL_PATH is srv*C:\Documents and Settings\cky\symbols*http://msdl.microsoft.com/download/symbols.
其实中间这个路径设置成什么都是无所谓的,这个路径是用来存放从后面msdl中下载下来的东西的,但是一般用这个路径比较好,关于_NT_SYMBOL_PATH这个环境变量的具体含义ms有一篇很详细的文章,就是之前在下载WinDbg时谈到的windows symbol那个模块,点击其中的Use the Microsoft Symbol Server to get debug symbol files,会出现这个环境变量的详细解释。