首页 > 学院 > 开发设计 > 正文

Windbg dump分析 学习总结

2019-11-06 07:08:57
字体:
来源:转载
供稿:网友

Windbg核心调试之dump分析

http://www.pediy.com/kssd/pediy08/pediy8-428.htm标 题: Windbg核心调试之dump分析作 者:Lvg时 间:2006-11-17 12:56 链 接:http://bbs.pediy.com/showthread.php?threadid=35044调试环境:winxp sp2+windbg ver:6.6.0007.5+vmware 5.5.2附件:点击下载

一.Dump文件的产生,意义和类型

    当系统发生错误是,最常见的就是蓝屏(Blue screen),这时就会在系统目录下产生一个Dump文件,如MEMORY.DMP 。这个文件的主要意义在于分析系统错误发生的原因,以作出解决的方法。   它可分为三种类型:   1.完全内存转储。这个文件比较大,和物理内存相当,包含了程序崩溃前系统及用户模式下的所有信息。   2.核心内存转储。这个文件大小约物理内存的三分之一,主要包含崩溃前系统内核的运行情况。一般为了分析内核错误,就选用这种文件。   3.小内存转储。这个文件小,只有64k,刚好一个页面文件大小。它包含了相对比较少的信息,主要可用于微软的在线分析。   以上三种形式的文件可以在我的电脑——〉鼠标右键——〉属性——〉高级——〉故障及恢复中设置。如下图:

二 Dump文件的强迫产生

   由于我们也不知道何时会产生一个系统错误,从而得到dump文件,所以当练习分析时,可认为强迫产生一个。一般有以下两个办法。   1.双机联调。这里的双机可以是物理上的两台电脑,也可以是用虚拟机模拟。我想这里的大多数人应该选择后者,为啥?还不是money的问题~_^。当用windbg把被调试机联上以后,就可以用.crash命令产生一个蓝屏,当然之前要在被调试机里把dump产生的路径和类型设定好。还有另外一张办法,是通过修改注册表后,用键盘产生dump,但这种方法哪有第一种来的快,所以就不说了,感兴趣的可以查查windbg帮助文档看看。   2.单机驱动产生。这种方法,不必用双机联调,在本机上就可以办到。由于驱动深入到了内核,它的要求非常苛刻,一个简单的除零操作就可引发蓝屏。但是驱动的编写与普通win32 api是有很大不同的,为了减轻负担,我直接运用一个现成的程序,是《Microsoft Windows Internals》作者写的Notmyfault(见附件)。它由Notmyfault.exe和Myfault.sys两部分组成。正如名字一样,引发蓝屏的不是Notmyfault.exe而是由他加载到内核中的Myfault.sys。如图:    我在这里两种方法都同时用了,先在虚拟机里执行Notmyfault,接着windbg立刻检测到了系统崩溃,并输出相关信息。 

三 Dump文件的分析

    当按上面的方法运行后,windbg输出了以下内容:*** Fatal System Error: 0x000000d1                       (0xE1147008,0x0000001C,0x00000000,0xFBE93403)  Break instruction exception - code 80000003 (first chance)  A fatal system error has occurred.  Debugger entered on first try; Bugcheck callbacks have not been   invoked.  A fatal system error has occurred.********************************************************************************                                                                             **                        Bugcheck Analysis                                    **                                                                             ********************************************************************************Use !analyze -v to get detailed debugging information.2.BugCheck D1, {e1147008, 1c, 0, fbe93403}*** ERROR: Module load completed but symbols could not be loaded for myfault.sys3.PRobably caused by : myfault.sys ( myfault+403 )Followup: MachineOwner---------nt!RtlpBreakWithStatusInstruction:80527da8 cc              int     3Kd:>  上面这一段,有用的信息,如1和2两段,说明的是一个问题,都指明了BugCheck是D1,并给了四个参数,这里的D1可以在windbg文档的Bug Check Code Reference中查出其具体含义,也可用!analyze –show D1命令查出。3说明引起的原因是myfault.sys模块。接着在kd后输入!analyze –v命令,这个命令是详细列出dump文件的信息。windbg输出如下:kd> !analyze -v********************************************************************************                                                                             **                        Bugcheck Analysis                                    **                                                                             ********************************************************************************DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)  //指明Bugcheck D1,我们已看见过了An attempt was made to access a pageable (or completely invalid) address at aninterrupt request level (IRQL) that is too high.  This is usuallycaused by drivers using improper addresses.      //解释了错误的原因If kernel debugger is available get stack backtrace.Arguments:Arg1: e1147008, memory referencedArg2: 0000001c, IRQLArg3: 00000000, value 0 = read Operation, 1 = write operationArg4: fbe93403, address which referenced memory                 //给出了相应的四个参数,第二列是代号,第三列是解释Debugging Details:------------------READ_ADDRESS:  e1147008 Paged pool       //上面的Arg1.CURRENT_IRQL:  1c       //上面的Arg2FAULTING_ip:     //指出发生错误时所执行的指令myfault+403fbe93403 8b06            mov     eax,dWord ptr [esi]DEFAULT_BUCKET_ID:  DRIVER_FAULT   //指出错误类型,是驱动错误BUGCHECK_STR:  0xD1   //bugcheck索引,可查windbg文档,也可!analyze –show D1PROCESS_NAME:  NotMyfault.exe  //错误所属进程TRAP_FRAME:  f9357b80 --(trap fffffffff9357b80)//错误时各寄存器的内容ErrCode = 00000000eax=00000000 ebx=8111f330 ecx=000000d1 edx=0000001c esi=e1147008 edi=00000000eip=fbe93403 esp=f9357bf4 ebp=f9357c58 iopl=0         nv up ei pl zr na pe nccs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010246myfault+0x403:fbe93403 8b06            mov     eax,dword ptr [esi]  ds:0023:e1147008=????????Resetting default scopeLAST_CONTROL_TRANSFER:  from 804f880d to 80527da8STACK_TEXT: //反映了错误前堆栈中函数调用情况,最下面的0x7c801671处函数调用ntdll中的ZwDeviceIoControlFile,接着调用了ntdll中的KiFastSystemCallRet,再接着调用了nt(这里的nt指Ntoskrnl)中的KiFastCallEntry,一直到myfault+0x403,发生异常。f9357734 804f880d 00000003 f9357a90 00000000 nt!RtlpBreakWithStatusInstructionf9357780 804f93fa 00000003 e1147008 fbe93403 nt!KiBugCheckDebugBreak+0x19f9357b60 80540853 0000000a e1147008 0000001c nt!KeBugCheck2+0x574f9357b60 fbe93403 0000000a e1147008 0000001c nt!KiTrap0E+0x233WARNING: Stack unwind information not available. Following frames may be wrong.f9357c58 805759d1 ffb5c3b0 8111f318 811d9130 myfault+0x403f9357d00 8056e33c 00000090 00000000 00000000 nt!IopXxxControlFile+0x5e7f9357d34 8053d808 00000090 00000000 00000000 nt!NtDeviceIoControlFile+0x2af9357d34 7c92eb94 00000090 00000000 00000000 nt!KiFastCallEntry+0xf80012f9f0 7c92d8ef 7c801671 00000090 00000000 ntdll!KiFastSystemCallRet0012f9f4 7c801671 00000090 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc0012fa54 004018c2 00000090 83360018 00000000 0x7c801671STACK_COMMAND:  kbFOLLOWUP_IP: //反汇编了发生错误指令的代码myfault+403fbe93403 8b06            mov     eax,dword ptr [esi]SYMBOL_STACK_INDEX:  4FOLLOWUP_NAME:  MachineOwnerMODULE_NAME: myfaultIMAGE_NAME:  myfault.sysDEBUG_FLR_IMAGE_TIMESTAMP:  43774e1dSYMBOL_NAME:  myfault+403FAILURE_BUCKET_ID:  0xD1_myfault+403BUCKET_ID:  0xD1_myfault+403Followup: MachineOwner//以上几段看名字就知道了,是以上信息的重复没有多大价值。

四 总结

    通过以上的分析,知道了蓝屏的原因是Bugcheck D1引起的,是由于驱动程序读操作了过高的IRQL引起的。也知道了这个引发蓝屏的驱动程序是myfault.sys,属于notmyfaulf.exe的进程。还知道了蓝屏前bug程序myfault.sys的调用情况等多个有用信息,接着就可以在myfault.sys源程序中进行bug修改了。========

利用windbg分析dump文件  

http://blog.163.com/crazywolf_/blog/static/195231413201061794619624/这里主要记录利用windbg来分析windows蓝屏时所产生的内存转储文件*.dmp。1,下载:http://www.microsoft.com/whdc/devtools/debugging/default.mspx2,配置symbol path:windows程序在编译生成后,会产生一些.exe,dll文件。同时也会用到一些symbol文件,这些文件包含全局变量,局部变量等信息。在调试不同的系统的时候,用到的symbol是不同的,而且这些文件会很大,如果下载安装会占用很大的硬盘空间。如果下载,在上面提供的地址也可以下载。微软还提供了一个网络上的symbol服务器。其网络地址是:http://msdl.microsoft.com/download/symbols,设置symbol时可以在打开windbg后,file->symbol file path 设置如下:其d:/temp 是本地缓存的目录:SRV*d:/temp/*http://msdl.microsoft.com/download/symbols。也可以用命令如下设置:set _NT_SYMBOL_PATH=srv*DownstreamStore*http://msdl.microsoft.com/download/symbols利用windbg分析dump文件(二)基本调试1,打开dump文件,在正确设置了symbol路径后,会有如下的显示:Microsoft (R) Windows Debugger Version 6.5.0003.7Copyright (c) Microsoft Corporation. All rights reserved.Loading Dump File [D:/important/document/win系统/debug/Mini121605-01.dmp]Mini Kernel Dump File: Only registers and stack trace are availableSymbol search path is: SRV*d:/temp/*http://msdl.microsoft.com/download/symbolsExecutable search path is:Windows 2000 Kernel Version 2195 (Service Pack 4) UP Free x86 compatibleKernel base = 0x80400000 PsLoadedModuleList = 0x8046e8f0Debug session time: Fri Dec 16 13:30:21.203 2005 (GMT+8)System Uptime: not availableLoading Kernel Symbols....................................................................................................................Loading unloaded module list...................Loading User Symbols******************************************************************************** ** Bugcheck Analysis ** ********************************************************************************Use !analyze -v to get detailed debugging information.BugCheck 7F, {8, 0, 0, 0}c0000005 Exception in ext.Analyze debugger extension. PC: 77c16fa3 VA: 01fe8000 R/W: 0 Parameter: 0001003f2,关于调试窗口:view菜单下面有详细的列表:可以调出对应的窗口,默认的打开窗口是command窗口3,基本调试命令:r 可以显示系统崩溃时的寄存器,和最后的命令状态。dd 显示当前内存地址,dd 参数:显示参数处的内存。u 可以显示反汇编的指令!analyze -v 显示分析的详细信息。kb 显示call stack 内容kv.bugcheck 可以显示出错的代码========

 WinDBG 技巧:如何生成Dump 文件(.dump 命令)

http://wingeek.blog.51cto.com/1226974/273964程序崩溃(crash)的时候, 为了以后能够调试分析问题, 可以使用WinDBG要把当时程序内存空间数据都保存下来,生成的文件称为dump 文件。 步骤:1) 打开WinDBG并将之Attach 到crash的程序进程2) 输入产生dump 文件的命令WinDBG产生dump 文件的命令是 .dump ,可以选择不同的参数来生成不同类型的dump文件。选项(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能够得到的最多的信息。是一种折中方案。========

 WINDBG调试DUMP文件

http://blog.csdn.net/vah101/article/details/5916384    对于windows程序员来说,程序运行时蓝屏是最郁闷的事情,如何找到蓝屏的原因则是首要解决的事情,好在微软提供了一系列的方法,为我们调试蓝屏提供了便利。    首先要用的工具是windbg,可以到微软的官方网站下载    http://msdl.microsoft.com/download/symbols/debuggers/dbg_x86_6.11.1.402.msi    再需要下载并安装一个符号链接库,微软官方网站也有提供,这个要根据你所调试系统的版本来选择    http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx#d    也可以不下载这个符号库,直接让windbg自己去网上下符号链接信息。    工具软件准备好了,就可以开始设置了,首先进入 “我的电脑”->“属性”->“高级”,选择“启动和故障恢复”选项卡,在“写入调试信息”一栏选择dump文件的转储方式,在“转储文件”中填入dump文件的保存路径。当出现蓝屏时,系统就会保存现场,将dump时的运行信息保存起来,以便我们用windbg来分析。有一条要注意,如果选择了完全内存转储,系统将会把内存中的所有信息都存进文件中,这会相当缓慢,所以你能看到蓝色屏幕上有一个跳动的数字,那就是保存的进度,必须耐心等待它保存到100%。      当蓝屏再次发生的时候,我们手上就有了dump文件了,通常在windows目录下的MEMORY.DMP,或者在windows下的miniDump文件夹中,以*.dmp的形式保存。把.dmp文件拷贝出来,就可以用windbg来调试。      首先,需要设置一下windbg的符号库,进入windbg的"File"->"Symbol File Path",在对话框的“symbol path”里面输入刚才下载的符号库的安装目录,最省心的方法是在这里填入SRV*c:/temp*http://msdl.microsoft.com/download/symbols就可以让windbg自动去下载所需要的符号信息。      将这里设置完,就可以开始调试.dmp文件了,打开“File”->“Open Crase Dump”,选择一个.dmp文件,windbg就开始下载符号库并进行初步的分析,当出现********************************************************************************                                                                             **                        Bugcheck Analysis                                    **                                                                             ********************************************************************************Use !analyze -v to get detailed debugging information.BugCheck 1000007F, {8, f772ffe0, 0, 0}Probably caused by : bxnd52x.sys ( bxnd52x+365f )Followup: MachineOwner---------就可以在下面的输入框中敲入!analyze -v;r;kv;lmtn;.logclose;回车后就可以看到结果,比如我这里看到BUGCHECK_STR:  0x7f_8CUSTOMER_CRASH_COUNT:  3DEFAULT_BUCKET_ID:  DRIVER_FAULT_SERVER_MINIDUMPCURRENT_IRQL:  2LAST_CONTROL_TRANSFER:  from 00000000 to f759a65fSTACK_TEXT:  f78dc000 00000000 00000000 00000000 00000000 bxnd52x+0x365fSTACK_COMMAND:  kbFOLLOWUP_IP: bxnd52x+365ff759a65f 53              push    ebxSYMBOL_STACK_INDEX:  0SYMBOL_NAME:  bxnd52x+365fFOLLOWUP_NAME:  MachineOwnerMODULE_NAME: bxnd52xIMAGE_NAME:  bxnd52x.sysDEBUG_FLR_IMAGE_TIMESTAMP:  44a55446FAILURE_BUCKET_ID:  0x7f_8_bxnd52x+365fBUCKET_ID:  0x7f_8_bxnd52x+365fFollowup: MachineOwner---------  说明蓝屏可能是由于bxnd52x.sys驱动的问题造成的,上网百度了一下,这个 bxnd52x.sys是网卡驱动,下载了一个更高版本的驱动重新安装,蓝屏的问题就解决了。  ========

使用Windbg解析dump文件

http://blog.csdn.net/xuleilx/article/details/17622627

第一章 常用的Windbg指令

①!analyze -v ②kP                                               可以看函数的入参③!for_each_frame dv /t                            可以看函数中的局部变量④dc , db                                          产看某一内存中的值    可以直接接变量名 不过可能需要回溯栈⑤!threads                                         显示所有线程⑥~0s , ~1s                                       进入某个线程⑦!frame ProcessA!FunctionA                        查看某一变量有时需要。 回溯栈  ⑧!uniqstack                                       扩展命令显示当前进程中所有线程的调用堆栈,除开重复的那些。   ⑨!teb                                             扩展以的格式化后的形式显示线程环境块(TEB)的信息。 ⑩s-sa 和 s-su                                     命令搜索未指定的 ASCII 和 Unicode 字符串。这在检查某段内存是否包含可打印字符时有用。⑪dds、dps 和 dqs 命令显示给定范围内存的内容。     该内存被假定为符号表中的一连串地址。相应的符号也会被显示出来。命令显示给定范围内存的内容,它们是把内存区域转储出来,并把内存中每个元素都视为一个符号对其进行解析,dds是四字节视为一个符号,dqs是每8字节视为一个符号,dps是根据当前处理器架构来选择最合适的长度⑫.kframes                                        命令设置堆栈回溯显示的默认长度。默认20⑬k, kb, kd, kp, kP, kv (Display Stack Backtrace) k*命令显示给定线程的调用堆栈,以及其他相关信息。通常要结合12)使用否则显示出来的东西很少⑭.reload /i xxx.dll                              忽略.pdb 文件版本不匹配的情况。

第二章 Symbol的设置方法

2.1 将远程的系统函数的PDB文件拷贝到本地「D:/mysymbol」目录下    SRV*D:/mysymbol*http://msdl.microsoft.com/download/symbols2.2 加载设置的符号文件    .reload    可以使用菜单中的 Debug -> Modules 查看有没有加载进来

第三章 实例

实例1 如何调查堆被破坏问题。    错误代码:0xc0000374    错误含义:ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun第一步、先用「!analyze -v」分析出错误的地方以及由于什么原因导致程序Dump掉的。       无非是内存溢出,访问非法地址等几种。0:009> !analyze -v********************************************************************************                                                                             **                        Exception Analysis                                   **                                                                             ********************************************************************************GetPageUrlData failed, server returned HTTP status 404URL requested: http://watson.microsoft.com/StageOne/ProcessA_exe/1_0_0_1/5134aefd/ntdll_dll/6_1_7601_18229/51fb164a/c0000374/000c4102.htm?Retriage=1FAULTING_IP: ntdll!RtlReportCriticalFailure+6200000000`777b4102 eb00            jmp     ntdll!RtlReportCriticalFailure+0x64 (00000000`777b4104)EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)ExceptionAddress: 00000000777b4102 (ntdll!RtlReportCriticalFailure+0x0000000000000062)   ExceptionCode: c0000374  ExceptionFlags: 00000001NumberParameters: 1   Parameter[0]: 000000007782b4b0PROCESS_NAME:  ProcessA.exeERROR_CODE: (NTSTATUS) 0xc0000374 - <Unable to get error code text>EXCEPTION_CODE: (NTSTATUS) 0xc0000374 - <Unable to get error code text>EXCEPTION_PARAMETER1:  000000007782b4b0MOD_LIST: <ANALYSIS/>NTGLOBALFLAG:  0application_VERIFIER_FLAGS:  0FAULTING_THREAD:  0000000000002f8cDEFAULT_BUCKET_ID:  ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrunPRIMARY_PROBLEM_CLASS:  ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrunBUGCHECK_STR:  APPLICATION_FAULT_ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrunLAST_CONTROL_TRANSFER:  from 00000000777b4746 to 00000000777b4102STACK_TEXT:  00000000`0548e170 00000000`777b4746 : 00000000`00000002 00000000`00000023 00000000`00000000 00000000`00000003 : ntdll!RtlReportCriticalFailure+0x6200000000`0548e240 00000000`777b5952 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`1c01001d : ntdll!RtlpReportHeapFailure+0x2600000000`0548e270 00000000`777b7604 : 00000000`00c50000 00000000`00c50000 00000000`0000000a 00000000`00000000 : ntdll!RtlpHeapHandleError+0x1200000000`0548e2a0 00000000`777b79e8 : 00000000`00c50000 00000000`00000000 00000000`00100000 00000000`00000000 : ntdll!RtlpLogHeapFailure+0xa400000000`0548e2d0 00000000`7774fad6 : 00000000`00c50000 00000000`00c59e50 00000000`00c50000 00000000`00000000 : ntdll!RtlpAnalyzeHeapFailure+0x3a800000000`0548e330 00000000`777434d8 : 00000000`00c50000 00000000`00000003 00000000`000006cc 00000000`000006e0 : ntdll!RtlpAllocateHeap+0x1d2a00000000`0548e8d0 00000000`777247ea : 00000000`00000003 00000000`00c5ee80 00000000`00c50278 00000000`000006cc : ntdll!RtlAllocateHeap+0x16c00000000`0548e9e0 00000000`77723ff2 : 00000000`00c50000 00000000`00000003 00000000`00c5ee90 00000000`000006cc : ntdll!RtlpReAllocateHeap+0x64800000000`0548eca0 00000000`750c712f : 00000000`0548fbe8 00000000`00c5ee90 00000000`00000000 00000000`000005ac : ntdll!RtlReAllocateHeap+0xa200000000`0548edb0 00000001`40010f6f : 00000000`00000000 00000000`0548fbe8 00000000`00000000 00000000`00000661 : msvcr80!realloc+0x6f [f:/dd/vctools/crt_bld/self_64_amd64/crt/src/realloc.c @ 332]00000000`0548ede0 00000001`4000f63c : ffffffff`ffffffff 00000000`0548ff10 00000000`00c97fd0 00000000`0548fe48 : ProcessA!FunctionA_AnalyzeEventData+0xfcf [e:/ProcessA/FunctionA_sockserv.cpp @ 1666]00000000`0548f8a0 00000000`774e652d : 00000000`000002a0 00000000`00000000 00000000`00000000 00000000`00000000 : ProcessA!FunctionA_SockWork+0xe1c [e:/ProcessA/FunctionA_sockserv.cpp @ 1102]00000000`0548ff60 00000000`7771c541 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd00000000`0548ff90 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1dSTACK_COMMAND:  !heap ; ~9s; .ecxr ; kbFOLLOWUP_IP: msvcr80!realloc+6f [f:/dd/vctools/crt_bld/self_64_amd64/crt/src/realloc.c @ 332]00000000`750c712f 4885c0          test    rax,raxSYMBOL_STACK_INDEX:  9SYMBOL_NAME:  msvcr80!realloc+6fFOLLOWUP_NAME:  MachineOwnerMODULE_NAME: msvcr80IMAGE_NAME:  msvcr80.dllDEBUG_FLR_IMAGE_TIMESTAMP:  4ec3407eFAILURE_BUCKET_ID:  ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun_c0000374_msvcr80.dll!reallocBUCKET_ID:  X64_APPLICATION_FAULT_ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun_msvcr80!realloc+6fWATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/ProcessA_exe/1_0_0_1/5134aefd/ntdll_dll/6_1_7601_18229/51fb164a/c0000374/000c4102.htm?Retriage=1Followup: MachineOwner---------第二步、使用「!heap」找出出错的堆。分析出错的原因。       0000000000c59c80       0000000000c59e50  ←出错的堆地址。       0000000000c59fd0大家应该有这样的常识,在使用malloc()或者realloc()分配出来的空间的前面都有相应的管理情报,用来记录这块分配的内存的大小以及返回的时候用的情报。从这里很自然的猜想到,在写往0000000000c59c80里面写数据的时候写过了,写到0000000000c59e50上去了,导致它的管理情报被覆盖了。从而程序dump掉了。0:009> !heap***************************************************************                                                            **                  HEAP ERROR DETECTED                       **                                                            ***************************************************************

Details:

Error address: 0000000000c59e50Heap handle: 0000000000c50000Error type heap_failure_buffer_overrun (6)Parameter 1: 000000000000000aLast known valid blocks: before - 0000000000c59c80, after -0000000000c59fd0Stack trace:                00000000777b79e8: ntdll!RtlpAnalyzeHeapFailure+0x00000000000003a8                000000007774fad6: ntdll!RtlpAllocateHeap+0x0000000000001d2a                00000000777434d8: ntdll!RtlAllocateHeap+0x000000000000016c                00000000777247ea: ntdll!RtlpReAllocateHeap+0x0000000000000648                0000000077723ff2: ntdll!RtlReAllocateHeap+0x00000000000000a2                00000000750c712f: msvcr80!realloc+0x000000000000006f                0000000140010f6f: ProcessA!FunctionA_AnalyzeEventData+0x0000000000000fcf                000000014000f63c: ProcessA!FunctionA_SockWork+0x0000000000000e1c                00000000774e652d: kernel32!BaseThreadInitThunk+0x000000000000000d                000000007771c541: ntdll!RtlUserThreadStart+0x000000000000001dIndex   Address  Name      Debugging options enabled  1:   001f0000                  2:   00010000                  3:   00020000                  4:   00670000                  5:   00950000                  6:   00c50000                  7:   00910000                  8:   00bc0000                  9:   010e0000                 10:   01220000                 11:   01420000                 12:   00c30000                 13:   03660000                 14:   00ba0000                 15:   037b0000                 16:   01340000                 17:   039a0000                第三步、使用「!for_each_frame dv /t」打印出错函数的局部变量,找出元凶。       从下面的变量里面找到距离0000000000c59c80地址最近的变量,对了就是它:       char * pData_n = 0x00000000`00c59c90 "SE:Security: ???"       ※注意如果变量值指针的指针需要先用dc看一下该指针指向的地址。       之后看代码知道,程序在读取pData_n的数据的时候如果遇到是0a(Windos换行符)就自动在后面加上       0d变成0a0d。导致pData_n内存越界了。0:009> !for_each_frame dv /t_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _12 00000000`0548edb0 00000001`40010f6f msvcr80!realloc+0x6f [f:/dd/vctools/crt_bld/self_64_amd64/crt/src/realloc.c @ 332]void * pBlock = 0x00000000`00000000unsigned int64 newsize = 0x548fbe8_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _13 00000000`0548ede0 00000001`4000f63c ProcessA!FunctionA_AnalyzeEventData+0xfcf [e:/ProcessA/FunctionA_sockserv.cpp @ 1666]void * cd = 0xffffffff`ffffffffstruct _MpEvsHead * Head = 0x00000000`0548ff10char * pEventData = 0x00000000`00c97fd0 "???"char ** pNewData = 0x00000000`0548fe48char * SiteName = 0x00000000`0548fe18 ""int oval_check = 0n0char * pszHostIp = 0x00000000`0548fbf0 "192.168.1.1"int j = 0n469int NodeName_check = 0n0char [2068] eventtext = char [2068] "SE:Security: ???"unsigned long err = 0int NL_henkan = 0n1int Evttxt_check = 0n1char [129] nameWork = char [129] "`_???"int ret = 0n0struct NameObject_t * pNameObj_n = 0x00000000`00c5eee8char * pData_n = 0x00000000`00c59c90 "SE:Security: ???"long lWork = 0n9char [257] szTrcBuff = char [257] "safely divided text.([453]bytes --> [469]bytes)"long nNameNum = 0n44long nNewLen = 0n1740struct NameObject_t * pNameObj_o = 0x00000000`00c98028char * pData_o = 0x00000000`00c984c6 "SE:Security: ???"char * pt = 0x00000000`00c59e55 "[???"long i = 0n20int IpAddr_check = 0n0int res = 0n1_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _14 00000000`0548f8a0 00000000`774e652d ProcessA!FunctionA_SockWork+0xe1c [e:/ProcessA/FunctionA_sockserv.cpp @ 1102]void * ns = 0x00000000`000002a0char * pRead_str = 0x00000000`00c562f0 ","int bTableRegisterd = 0n0unsigned long err = 0char [3] traceflg = char [3] ""int ret = 0n0short sWork = 0n2int oval_check = 0n0char * pNewData = 0x00000000`00c5ee90 "???"char * wk = 0x00000000`0548f930 "192.168.1.1"char [33] SiteName = char [33] ""long lWork = 0n2032char [257] szTrcBuff = char [257] "recv event OK"int iLastSerchedIndex = 0n0char [256] HostIp = char [256] "192.168.1.1"int ret2 = 0n0struct _MpEvsHead Head = struct _MpEvsHeadlong nDataLen = 0n3char [257] szTrcBuff2 = char [257] ""char [20] szSendData = char [20] "OK"struct addrinfo hinst = struct addrinfoint conv_disc_set = 0n1long lRc = 0n0void * conv_disc = 0xffffffff`ffffffffint res = 0n1char * pData = 0x00000000`00c97fd0 "???"long nRead = 0n3726char [16] evttype = char [16] "Alarm.sys"char * lpszEventid = 0x00000000`00c5f180 ""long nSend = 0n12char [256] ipTmp = char [256] "192.168.1.1"char [20] szToCode = char [20] "sjis"char [20] szFromCode = char [20] "sjis"int bWriteEvent = 0n1_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _实例2  无效参数(STATUS_INVALID_PARAMETER)。    错误代码:0xc000000d    错误含义:STATUS_INVALID_PARAMETER第一步、先用「!analyze -v」分析出错误的地方以及由于什么原因导致程序Dump掉的。 0:000> !analyze -v********************************************************************************                                                                             **                        Exception Analysis                                   **                                                                             *********************************************************************************** ERROR: Symbol file could not be found.  Defaulted to export symbols for user32.dll - Unable to load image C:/Windows/Odsv.dll, Win32 error 0n2*** WARNING: Unable to verify timestamp for Odsv.dll*** ERROR: Module load completed but symbols could not be loaded for Odsv.dllGetPageUrlData failed, server returned HTTP status 404URL requested: http://watson.microsoft.com/StageOne/ProcessB_exe/1_0_0_1/4e362265/msvcr80_dll/8_0_50727_6195/4dcdd833/c000000d/0001d5fa.htm?Retriage=1FAULTING_IP: msvcr80!strncpy_s+10a [f:/dd/vctools/crt_bld/self_64_amd64/crt/src/tcsncpy_s.inl @ 62]00000000`74e6d5fa b822000000      mov     eax,22hEXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)ExceptionAddress: 0000000074e6d5fa (msvcr80!strncpy_s+0x000000000000010a)   ExceptionCode: c000000d  ExceptionFlags: 00000000NumberParameters: 0PROCESS_NAME:  ProcessB.exeERROR_CODE: (NTSTATUS) 0xc000000d - <Unable to get error code text>EXCEPTION_CODE: (NTSTATUS) 0xc000000d - <Unable to get error code text>MOD_LIST: <ANALYSIS/>

NTGLOBALFLAG:  0

APPLICATION_VERIFIER_FLAGS:  0LAST_CONTROL_TRANSFER:  from 0000000000124250 to 0000000074e5b0ecFAULTING_THREAD:  ffffffffffffffffDEFAULT_BUCKET_ID:  STATUS_INVALID_PARAMETERPRIMARY_PROBLEM_CLASS:  STATUS_INVALID_PARAMETERBUGCHECK_STR:  APPLICATION_FAULT_STATUS_INVALID_PARAMETERIP_ON_STACK: +2e32faf01dedf5800000000`00124250 60              ???FRAME_ONE_INVALID: 1STACK_TEXT:  00000000`00124220 00000000`00124250 : 00000000`00000006 00000000`00000000 00000000`00000001 00000000`00000000 : msvcr80!_invalid_parameter+0x6c [f:/dd/vctools/crt_bld/self_64_amd64/crt/src/invarg.c @ 88]00000000`00124228 00000000`00000006 : 00000000`00000000 00000000`00000001 00000000`00000000 00000000`00000000 : 0x12425000000000`00124230 00000000`00000000 : 00000000`00000001 00000000`00000000 00000000`00000000 00000000`00124260 : 0x6STACK_COMMAND:  ~0s; .ecxr ; kb

FOLLOWUP_IP: 

msvcr80!strncpy_s+10a [f:/dd/vctools/crt_bld/self_64_amd64/crt/src/tcsncpy_s.inl @ 62]00000000`74e6d5fa b822000000      mov     eax,22hFAULTING_SOURCE_CODE:  No source found for 'f:/dd/vctools/crt_bld/self_64_amd64/crt/src/tcsncpy_s.inl'SYMBOL_STACK_INDEX:  0SYMBOL_NAME:  msvcr80!strncpy_s+10aFOLLOWUP_NAME:  MachineOwnerMODULE_NAME: msvcr80IMAGE_NAME:  msvcr80.dllDEBUG_FLR_IMAGE_TIMESTAMP:  4dcdd833FAILURE_BUCKET_ID:  STATUS_INVALID_PARAMETER_c000000d_msvcr80.dll!strncpy_sBUCKET_ID:  X64_APPLICATION_FAULT_STATUS_INVALID_PARAMETER_msvcr80!strncpy_s+10aWATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/ProcessB_exe/1_0_0_1/4e362265/msvcr80_dll/8_0_50727_6195/4dcdd833/c000000d/0001d5fa.htm?Retriage=1Followup: MachineOwner---------这次运气很不好,从「!analyze -v」打出来的结果来看看不出啥东西来,只知道在调用strncpy_s的时候dmp掉了,无法定位具体是哪个函数出错的原因很多,有可能客户采集的不是全dmp文件或者dmp文件中的栈被破坏了。   这的确很伤脑筋,就针对这个我可是花了3个星期一行行的解析栈里面的内容 才解决的。第二步、先用「!teb」看一下这个程序的栈是从哪里到哪里的。0:000>!tebTEB at 000007ffffeee000    ExceptionList:        0000000000000000    StackBase:            0000000008d50000    StackLimit:           0000000008d4d000    SubSystemTib:         0000000000000000    FiberData:            0000000000001e00    ArbitraryUserPointer: 0000000000000000    Self:                 000007ffffeee000    EnvironmentPointer:   0000000000000000    ClientId:             0000000000001bdc . 0000000000001868    RpcHandle:            0000000000000000    Tls Storage:          000007ffffeee058    PEB Address:          000007fffffd6000    LastErrorValue:       87    LastStatusValue:      c000000d    Count Owned Locks:    0    HardErrorMode:        0第三步、先用「dps」看一下这个程序的栈中的内存的内容。 下面截取其中比较重要的一段。-------------------------------------------------------------------------------------------------------------------------------00000000`001247d8  00000000`74e6d5fa msvcr80!strncpy_s+0x10a [f:/dd/vctools/crt_bld/self_64_amd64/crt/src/tcsncpy_s.inl @ 62]00000000`001247e0  00000000`009c01e000000000`001247e8  00000000`030f581000000000`001247f0  00000000`0057e310 ProcessB2!work   ★「ProcessB2!work」的内容本应该是像这样的数据「DNxxxxxxxx_150_109」但是现在「ProcessB2!work」中的内容却是「VIP_rtcrx00184-004a/b-y3b-d」这个。00000000`001247f8  00000000`005782c0 ProcessB2!trcData ▲「ProcessB2!trcData」的内容是「Function:testB call」。 函数List::testB の trace("testB", __FILE__, __LINE__, TRCLV_3);00000000`00124800  00000000`0000000000000000`00124808  00000000`0000000000000000`00124810  00000000`004a3150 ProcessB2!`string' ▲「 ProcessB2!`string'」的内容是「e:/ProcessB/FunctionB.cpp  __FILE__」。00000000`00124818  00000000`00455b65 ProcessB2!List::testB+0x55 [e:/ProcessB/Listset.cpp @ 719]00000000`00124820  00000000`009c01e000000000`00124828  00000000`030f581000000000`00124830  00000000`0057e310 ProcessB2!work00000000`00124838  00000000`001249e000000000`00124840  32322e35`322e300000000000`00124848  30614031`33312e3400000000`00124850  7097fb8e`bc92373000000000`00124858  5049565f`5753334c00000000`00124860  00000000`0000125f00000000`00124868  000082bd`b1200d5e00000000`00124870  00000000`009c01e000000000`00124878  00000000`00467bda ProcessB2!FunctionB+0x73a [e:/ProcessB/FunctionB.cpp @ 181]   -------------------------------------------------------------------------------------------------------------------------------这里终于定位到是哪个函数出问题。搞清楚这些函数的功能,然后打印出所有可能打印的内容,发现函数传递了一个不合法的数据。在这里要说一下为啥传的数据不合法就会Dmp掉。首先strncpy 这个函数在使用的时候只要有个宏定义(默认是有的)在编译的时候就会使用strncpy_s这个安全函数。详情可以参考下面微软的说明文档。http://msdn.microsoft.com/zh-cn/LIBRARY/ms175759(v=vs.80)其次说明一下为什么会dmp掉。strncpy在使用的时候如果转化成strncpy_s的时候是这样一种形式。char dst[5];strncpy(dst, "a long string", 5);    ---->  strncpy_s(dst, 5, "a long string", 5);而这样就会到时报STATUS_INVALID_PARAMETER这个错误这是strncpy_s的特性。具体使用方法可以参考下面的文档。http://msdn.microsoft.com/zh-cn/library/5dae5d43(v=vs.90).aspx节选:char dst[5];strncpy_s(dst, 5, "a long string", 5);means that we are asking strncpy_s to copy five characters into a buffer five bytes long; this would leave no space for the null terminator, hence strncpy_s zeroes out the string and calls the invalid parameter handler.If truncation behavior is needed, use _TRUNCATE or (size – 1):strncpy_s(dst, 5, "a long string", _TRUNCATE);strncpy_s(dst, 5, "a long string", 4);详细的ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun方法还可以参考以下的例子:http://blogs.msdn.com/b/jiangyue/archive/2010/03/16/windows-heap-overrun-monitoring.aspx========

 windbg分析dump文件

http://blog.csdn.net/xiaoshahai/article/details/7284867/前言:WinDbg是微软开发的免费源代码级的调试工具。WinDbg可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件。本文的讨论是在安装了Debugging Tools for Windows 的前提下进行的,下载地址可以参考我之前的文章。WinDbg对于dump文件的调试可以通过菜单设置Symbol File Path、Source File Path ,并可设置多个路径。

1、  打开Dump格式文件

打开WinDbg,通过菜单[File] à [Open Crash dump] 选择dump文件打开,也可通过CMD打开Dos命令窗口,切换到WinDbg所在目录,利用命令:WinDbg –z “D:/Lines2009-7-25-22-20-33-900.dmp”-z表示路径clip_image001图1.1 利用WinDbg打开dump文件本文编写了一个简单能产生除数为0异常的程序,让其运行,产生崩溃,通过drwtsn产生dmp文件,然后通过windbg分析dmp文件,定位程序bug。目的:学习windbg基本功能使用。程序源代码:
void Crash(void){         int i = 1;         int j = 0;         i /= j;}void main(void){         Crash();}编译环境:vc++6.0编译器设置: 这一步设置,要求对release版本不使用优化,如果使用优化,上面源代码中Crash(void)函数将不被汇编。这一步设置,产生release版本的调试符号表,为后续定位错误准备。步骤:1、 安装drwtsn32用户可以通过drwtsn32命令,查看dmp文件会被保存在何处。2、 安装windbg,Windbg下载地址:http://www.microsoft.com/whdc/devtools/debugging/default.mspx3、 设置windbgA、符号表路径设置其中;srv*d:/symbolslocal*http://msdl.microsoft.com/download/symbols设置的目的是下载该程序用到的操作系统相关的库函数的符号表到本地。B、源代码路径设置C、dmp文件导入载入dump文件显示如图:clip_image002图1.2 WinDbg界面

2、  分析dump文件

若生成的dump文件在本机,dump文件中将包含调试需要的PDB文件及源代码路径,若不在本机,可以通过WinDbg菜单[File] à [Symbol File path] 及 [Source File Path] 分别设置PDB文件路径和源代码路径。如果程序涉及到DLL,需要将EXE、DLL所有涉及的PDB、源代码路径都包括。使用命令:!analyze –v将分析dump文件,并显示程序崩溃处于的代码行:clip_image003图1.3 分析dump 文件========

 调试技巧 —— 如何利用windbg + dump + map分析程序异常

http://blog.csdn.net/xiaoshahai/article/details/7285103之前碰到论坛里有几个好友,说程序不时的崩溃,什么xxoo不能read的! 如果光要是这个内存地址,估计你会疯掉~~所以分享一下基本的调试技巧,需要准备的工具有WinDbg + VC6.0,下面是自己整理的一份自动生成DUMP文件的源代码,只需要添加到工程即可,源代码如下:MiniDump.h[cpp] view plaincopy #include <windows.h>  #include <tlhelp32.h>    //#include "dbghelp.h"  //#define DEBUG_DPRINTF     1   //allow d()  //#include "wfun.h"    #pragma optimize("y", off)      //generate stack frame pointers for all functions - same as /Oy- in the project  #pragma warning(disable: 4200)  //nonstandard extension used : zero-sized array in struct/union  #pragma warning(disable: 4100)  //unreferenced formal parameter    /*BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr); int  WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str); int  WINAPI Get_Version_Str(PCHAR Str); PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException); void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);*/    // In case you don't have dbghelp.h.  #ifndef _DBGHELP_    typedef struct _MINIDUMP_EXCEPTION_INFORMATION {      DWORD   ThreadId;      PEXCEPTION_POINTERS ExceptionPointers;      BOOL    ClientPointers;  } MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;    typedef enum _MINIDUMP_TYPE {      MiniDumpNormal =            0x00000000,          MiniDumpWithDataSegs =      0x00000001,  } MINIDUMP_TYPE;    typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)(                                              IN HANDLE           hProcess,                                              IN DWORD            ProcessId,                                              IN HANDLE           hFile,                                              IN MINIDUMP_TYPE    DumpType,                                              IN CONST PMINIDUMP_EXCEPTION_INFORMATION    ExceptionParam, OPTIONAL                                              IN PVOID                                    UserStreamParam, OPTIONAL                                              IN PVOID                                    CallbackParam OPTIONAL                                              );    #else    typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)(                                              IN HANDLE           hProcess,                                              IN DWORD            ProcessId,                                              IN HANDLE           hFile,                                              IN MINIDUMP_TYPE    DumpType,                                              IN CONST PMINIDUMP_EXCEPTION_INFORMATION    ExceptionParam, OPTIONAL                                              IN PMINIDUMP_USER_STREAM_INFORMATION        UserStreamParam, OPTIONAL                                              IN PMINIDUMP_CALLBACK_INFORMATION           CallbackParam OPTIONAL                                              );  #endif //#ifndef _DBGHELP_    // Tool Help functions.  typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);  typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);  typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);      extern void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);    extern HMODULE  hDbgHelp;  extern MINIDUMP_WRITE_DUMP  MiniDumpWriteDump_;    extern CREATE_TOOL_HELP32_SNAPSHOT  CreateToolhelp32Snapshot_;  extern MODULE32_FIRST   Module32First_;  extern MODULE32_NEST    Module32Next_;  MiniDump.cpp/*     Author: Vladimir Sedach.      Purpose: demo of Call Stack creation by our own means,     and with MiniDumpWriteDump() function of DbgHelp.dll. */    #include "StdAfx.h"  #include "MiniDump.h"  #include <Shlwapi.h>    #pragma comment(lib,"shlwapi.lib")    HMODULE hDbgHelp;  MINIDUMP_WRITE_DUMP MiniDumpWriteDump_;    CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_;  MODULE32_FIRST  Module32First_;  MODULE32_NEST   Module32Next_;    #define DUMP_SIZE_MAX   8000    //max size of our dump  #define CALL_TRACE_MAX  ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40))  //max number of traced calls  #define NL              "/r/n"  //new line    extern CString GetExePath();    //****************************************************************************************  BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr)  //****************************************************************************************  // Find module by Ret_Addr (address in the module).  // Return Module_Name (full path) and Module_Addr (start address).  // Return TRUE if found.  {      MODULEENTRY32   M = {sizeof(M)};      HANDLE  hSnapshot;        Module_Name[0] = 0;            if (CreateToolhelp32Snapshot_)      {          hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0);                    if ((hSnapshot != INVALID_HANDLE_VALUE) &&              Module32First_(hSnapshot, &M))          {              do              {                  if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize)                  {                      lstrcpyn(Module_Name, M.szExePath, MAX_PATH);                      Module_Addr = M.modBaseAddr;                      break;                  }              } while (Module32Next_(hSnapshot, &M));          }            CloseHandle(hSnapshot);      }        return !!Module_Name[0];  } //Get_Module_By_Ret_Addr    //******************************************************************  int WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str)  //******************************************************************  // Fill Str with call stack info.  // pException can be either GetExceptionInformation() or NULL.  // If pException = NULL - get current call stack.  {      CHAR    Module_Name[MAX_PATH];      PBYTE   Module_Addr = 0;      PBYTE   Module_Addr_1;      int     Str_Len;            typedef struct STACK      {          STACK * Ebp;          PBYTE   Ret_Addr;          DWORD   Param[0];      } STACK, * PSTACK;        STACK   Stack = {0, 0};      PSTACK  Ebp;        if (pException)     //fake frame for exception address      {          Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp;          Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress;          Ebp = &Stack;      }      else      {          Ebp = (PSTACK)&pException - 1;  //frame addr of Get_Call_Stack()            // Skip frame of Get_Call_Stack().          if (!IsBadReadPtr(Ebp, sizeof(PSTACK)))              Ebp = Ebp->Ebp;      //caller ebp      }        Str[0] = 0;      Str_Len = 0;        // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX.      // Break trace on wrong stack frame.      for (int Ret_Addr_I = 0;          (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr));          Ret_Addr_I++, Ebp = Ebp->Ebp)      {          // If module with Ebp->Ret_Addr found.          if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr_1))          {              if (Module_Addr_1 != Module_Addr)   //new module              {                  // Save module's address and full path.                  Module_Addr = Module_Addr_1;                  Str_Len += wsprintf(Str + Str_Len, NL "%08X  %s", Module_Addr, Module_Name);              }                // Save call offset.              Str_Len += wsprintf(Str + Str_Len,                  NL "  +%08X", Ebp->Ret_Addr - Module_Addr);                // Save 5 params of the call. We don't know the real number of params.              if (pException && !Ret_Addr_I)  //fake frame for exception address                  Str_Len += wsprintf(Str + Str_Len, "  Exception Offset");              else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD)))              {                  Str_Len += wsprintf(Str + Str_Len, "  (%X, %X, %X, %X, %X)",                      Ebp->Param[0], Ebp->Param[1], Ebp->Param[2], Ebp->Param[3], Ebp->Param[4]);              }          }          else              Str_Len += wsprintf(Str + Str_Len, NL "%08X", Ebp->Ret_Addr);      }        return Str_Len;  } //Get_Call_Stack    //***********************************  int WINAPI Get_Version_Str(PCHAR Str)  //***********************************  // Fill Str with Windows version.  {      OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)};  //EX for NT 5.0 and later        if (!GetVersionEx((POSVERSIONINFO)&V))      {          ZeroMemory(&V, sizeof(V));          V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);          GetVersionEx((POSVERSIONINFO)&V);      }        if (V.dwPlatformId != VER_PLATFORM_WIN32_NT)          V.dwBuildNumber = LOWORD(V.dwBuildNumber);  //for 9x HIWORD(dwBuildNumber) = 0x04xx       return wsprintf(Str,          NL "Windows:  %d.%d.%d, SP %d.%d, Product Type %d", //SP - service pack, Product Type - VER_NT_WORKSTATION,...          V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor/*, V.wProductType*/);  } //Get_Version_Str    //*************************************************************  PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException)  //*************************************************************  // Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str.  {      PCHAR       Str;      int         Str_Len;      int         i;      CHAR        Module_Name[MAX_PATH];      PBYTE       Module_Addr;      HANDLE      hFile;      FILETIME    Last_Write_Time;      FILETIME    Local_File_Time;      SYSTEMTIME  T;            Str = new CHAR[DUMP_SIZE_MAX];        if (!Str)          return NULL;        Str_Len = 0;      Str_Len += Get_Version_Str(Str + Str_Len);        Str_Len += wsprintf(Str + Str_Len, NL "Process:  ");      GetModuleFileName(NULL, Str + Str_Len, MAX_PATH);      Str_Len = lstrlen(Str);        // If exception occurred.      if (pException)      {          EXCEPTION_RECORD &  E = *pException->ExceptionRecord;          CONTEXT &           C = *pException->ContextRecord;            // If module with E.ExceptionAddress found - save its path and date.          if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr))          {              Str_Len += wsprintf(Str + Str_Len,                  NL "Module:  %s", Module_Name);                if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,                  FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)              {                  if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time))                  {                      FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time);                      FileTimeToSystemTime(&Local_File_Time, &T);                        Str_Len += wsprintf(Str + Str_Len,                          NL "Date Modified:  %02d/%02d/%d",                          T.wMonth, T.wDay, T.wYear);                  }                  CloseHandle(hFile);              }          }          else          {              Str_Len += wsprintf(Str + Str_Len,                  NL "Exception Addr:  %08X", E.ExceptionAddress);          }                    Str_Len += wsprintf(Str + Str_Len,              NL "Exception Code:  %08X", E.ExceptionCode);                    if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)          {              // Access violation type - Write/Read.              Str_Len += wsprintf(Str + Str_Len,                  NL "%s Address:  %08X",                  (E.ExceptionInformation[0]) ? "Write" : "Read", E.ExceptionInformation[1]);          }            // Save instruction that caused exception.          Str_Len += wsprintf(Str + Str_Len, NL "Instruction: ");          for (i = 0; i < 16; i++)              Str_Len += wsprintf(Str + Str_Len, " %02X", PBYTE(E.ExceptionAddress)[i]);            // Save registers at exception.          Str_Len += wsprintf(Str + Str_Len, NL "Registers:");          Str_Len += wsprintf(Str + Str_Len, NL "EAX: %08X  EBX: %08X  ECX: %08X  EDX: %08X", C.Eax, C.Ebx, C.Ecx, C.Edx);          Str_Len += wsprintf(Str + Str_Len, NL "ESI: %08X  EDI: %08X  ESP: %08X  EBP: %08X", C.Esi, C.Edi, C.Esp, C.Ebp);          Str_Len += wsprintf(Str + Str_Len, NL "EIP: %08X  EFlags: %08X", C.Eip, C.EFlags);      } //if (pException)            // Save call stack info.      Str_Len += wsprintf(Str + Str_Len, NL "Call Stack:");      Get_Call_Stack(pException, Str + Str_Len);        if (Str[0] == NL[0])          lstrcpy(Str, Str + sizeof(NL) - 1);        return Str;  } //Get_Exception_Info    //*************************************************************************************  void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag)  //*************************************************************************************  // Create dump.   // pException can be either GetExceptionInformation() or NULL.  // If File_Flag = TRUE - write dump files (.dmz and .dmp) with the name of the current process.  // If Show_Flag = TRUE - show message with Get_Exception_Info() dump.  {      HANDLE  hDump_File;      PCHAR   Str;      DWORD   Bytes;      DWORD   nLen = 0;        CString strDir,strTXTFile,strDMPFile;      CString strDate,strTotal;      CTime   tm = CTime::GetCurrentTime();            strDir.Format(_T("%s//Log"),GetExePath());      strTXTFile.Format(_T("%s//Log//%04d-%02d-%02d %02d%02d%02d.txt"),GetExePath(),tm.GetYear(),tm.GetMonth(),          tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond());      strDMPFile.Format(_T("%s//Log//%04d-%02d-%02d %02d%02d%02d.dmp"),GetExePath(),tm.GetYear(),tm.GetMonth(),          tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond());        if(!PathFileExists(strDir))          CreateDirectory(strDir,NULL);        Str = Get_Exception_Info(pException);        //if (Show_Flag && Str)      //  MessageBox(NULL, Str, "MiniDump", MB_ICONHAND | MB_OK);        if (File_Flag)      {          if (Str)          {              hDump_File = CreateFile(strTXTFile,                  GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);                            nLen = lstrlen(Str);              Str[nLen] = '/0';                WriteFile(hDump_File, Str, lstrlen(Str) + 1, &Bytes, NULL);                CloseHandle(hDump_File);          }            // If MiniDumpWriteDump() of DbgHelp.dll available.          if (MiniDumpWriteDump_)          {              MINIDUMP_EXCEPTION_INFORMATION  M;                M.ThreadId = GetCurrentThreadId();              M.ExceptionPointers = pException;              M.ClientPointers = 0;                hDump_File = CreateFile(strDMPFile,                  GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);                MiniDumpWriteDump_(GetCurrentProcess(), GetCurrentProcessId(), hDump_File,                  MiniDumpNormal, (pException) ? &M : NULL, NULL, NULL);                CloseHandle(hDump_File);          }      } //if (File_Flag)        delete Str;  } //Create_Dump  具体参考方法如下:1、在CXXDlg::OnInitDialog()中添加这样一段:SetUnhandledExceptionFilter(CrashReportEx);  HMODULE hKernel32;    // Try to get MiniDumpWriteDump() address.  hDbgHelp = LoadLibrary("DBGHELP.DLL");  MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");  //  d("hDbgHelp=%X, MiniDumpWriteDump_=%X", hDbgHelp, MiniDumpWriteDump_);    // Try to get Tool Help library functions.  hKernel32 = GetModuleHandle("KERNEL32");  CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot");  Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32First");  Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32Next");  测试代码如下:class CTestDlg : public CDialog  {  // Construction  public:      CTestDlg(CWnd* pParent = NULL); // standard constructor        void Fun1(char *pszBuffer);      void Fun2(char *pszBuffer);      void Fun3(char *pszBuffer);  };  void CTestDlg::Fun1(char *pszBuffer)  {      Fun2(pszBuffer);  }    void CTestDlg::Fun2(char *pszBuffer)  {      Fun3(pszBuffer);  }    void CTestDlg::Fun3(char *pszBuffer)  {      pszBuffer[1] = 0x00;  }  我们在双击确定按钮时的响应代码如下:void CTestDlg::OnOK()   {      // TODO: Add extra validation here      Fun1(NULL);  }  2、设置VC编译选项,勾选生成MAP和Debug Info:

3、将编译生成的Release目录中的pdb、map文件保存起来,以后调试会用到:

4、运行程序,单击确定按钮出现异常后自动重启,并创建一个Log文件夹,里面生成dump文件:5、我们打开WinDbg,设置一下pdb路径(File / Symbol File Path):6、用WiinDbg打开dump文件(File / Open Crash Dump)7、输入命令!analyze -v,等待几秒后会打印出错误信息,函数调用栈如下图:OK ,这样我们就能在发布版本的程序中,准确的定位到哪个函数出了问题,所以发布程序时,一定要记得生成pdb、map文件,不然客户运行出错的话,你不死也残!测试工程下载地址:http://download.csdn.NET/source/3575167========
上一篇:赛马练习

下一篇:0.C语言概述

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表