2011-03-30 56 views
0

创建转储我设置未处理的异常过滤器通过做: SetUnhandledExceptionFilter(UnhandledException)WinDbg的:越来越堆栈跟踪在UnhandledExceptionFilter的

,并在我的UnhandledException功能,我写出来的使用MiniDumpWriteDump一个小型转储:

MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),hFile, MiniDumpNormal,excpInfo?& eInfo: NULL,NULL,NULL);

当我看在WinDbg中的堆栈跟踪,我看不出有:

 
0:023> kb 
ChildEBP RetAddr Args to Child    
WARNING: Stack unwind information not available. Following frames may be wrong. 
15e7e7dc 08f00150 08f00a78 08f00000 08f00150 ntdll!ZwGetContextThread+0x12 
15e7e7fc 777d301e 6f00016e 00000044 627e056a 0x8f00150 
15e7e890 777d2ffa 777d2bf2 00000000 00650000 ntdll!RtlInterlockedFlushSList+0x889 
15e7e894 777d2bf2 00000000 00650000 077e1b88 ntdll!RtlInterlockedFlushSList+0x865 
15e7e8b4 772b14d1 08f00000 00000000 077e0c48 ntdll!RtlInterlockedFlushSList+0x45d 
15e7e8d0 777ce023 077e1b88 08f00138 00000001 kernel32!HeapFree+0x14 
15e7e8e8 777d48c6 777bfafa 777d419a ffffffff ntdll!RtlFreeHeap+0x7e 
15e7e914 777e9ed7 ffffffff 15e7e938 15e7e944 ntdll!RtlImageNtHeader+0xe2 
15e7e93c 777e9e49 00010000 00000000 08c70000 ntdll!RtlDestroyHeap+0x139 
15e7e958 75d5458e 08f00000 00000000 08ccfe46 ntdll!RtlDestroyHeap+0xab 
15e7e9c4 777ce023 104d9250 104d91f0 104d9250 KERNELBASE!HeapDestroy+0xe 
00000000 00000000 00000000 00000000 00000000 ntdll!RtlFreeHeap+0x7e 

的MiniDumpWriteDump文档中提到的STRACK跟踪可能不太好,但我真的不明白我应该做些什么: http://msdn.microsoft.com/en-us/library/ms680360%28v=vs.85%29.aspx

任何帮助赞赏!

回答

2

您无法从当前正在执行的线程获取可靠的调用堆栈。为了从转储文件中获取调用堆栈,WinDbg从转储文件(CONTEXT结构,这基本上是线程的所有寄存器的快照)中提取线程上下文记录。基于寄存器(特别是RIP和RSP)和符号,它可以遍历堆栈并提取调用堆栈。对于运行线程,没有办法获得一致的CONTEXT结构,因为它改变了每条指令。

您在MSDN上看到的链接提到了获取当前正在执行的线程的一致性CONTEXT的简单方法。代码如下所示:

__try 
    { 
     RaiseException(0, 0, 0, 0); 
    } 
    __except (
     MyStackTraceFilter(GetExceptionInformation()->ContextRecord))) 
    { 
     // do nothing in the handler 
    } 

这里的工作是做MyStackTraceFilter - 你必须提供此功能。输入参数将是您可以依赖的CONTEXT记录 - 当除了引发之后的特定时间的当前线程的快照。您实际上可以编写代码来将堆栈放入MyStackTraceFilter中,并获得运行线程的良好调用堆栈。如果你只对调用堆栈感兴趣,这可能是解决方法。

在大多数情况下,可以从不一致的CONTEXT结构中获得“更好”的调用栈。如果你能依靠的是RSP/ESP或多或少是正确的,那么你要做的就是

  • 转储栈(“DDS ESP”为x86或“DQS RSP”针对x64)
  • 尝试猜测哪里是异常前的最后一个堆栈帧
  • 使用命令“K BasePtr StackPtr InstructionPtr”转储调用堆栈
+0

我很好奇 - 堆栈行走是否也可以在没有任何PDB文件的发布模式下工作? – Warpin 2011-03-31 00:52:39

+1

如果DbgHelp库没有符号(PDB文件),它假定方法调用使用一些默认调用约定(可能是stdcall,但我不确定)。这使得堆栈走得很近,大多数情况下无用。你实际上需要符号。但是,您可以创建完全优化的二进制文件(即发布模式)并生成PDB。你会得到正确的调用堆栈。使用完全优化的二进制文件时唯一会遗漏的是函数参数和局部变量 - 其中很多会被优化掉或重用。 – 2011-03-31 01:38:16

1

如果你从一个未处理的异常过滤器调用MinidumpWriteDump那么你应该有一个有效的EXCEPTION_POINTERS通过在MINIDUMP_EXCEPTION_INFORMATION参数。如果你这样做了,那么minidump将包含一个异常流,它包含一个特殊的CONTEXT,它表示崩溃线程的状态。当你在WinDBG中加载这样一个转储时,它会显示消息: 这个转储文件有一个存储在它中的兴趣异常。 存储的异常信息可以通过.ecxr访问。

您需要输入。ecxr命令加载该上下文,以便可以显示从该点开始的堆栈跟踪。