0

我通过执行以下操作设置未处理的异常过滤器: SetUnhandledExceptionFilter(UnhandledException)

在我的 UnhandledException 函数中,我使用 MiniDumpWriteDump 写出一个 minidump:

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

当我查看 WinDbg 中的堆栈跟踪时,我看不到太多:

0:023> KB
ChildEBP RetAddr Args to Child              
警告:堆栈展开信息不可用。以下框架可能是错误的。
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

任何帮助表示赞赏!

4

2 回答 2

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 或多或少是正确的,那么您要做的是

  • 转储堆栈(x86 为“dds esp”,x64 为“dqs rsp”)
  • 尝试猜测异常之前的最后一个堆栈帧在哪里
  • 使用命令 'k BasePtr StackPtr InstructionPtr' 转储调用堆栈
于 2011-03-31T00:10:06.010 回答
1

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

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

于 2012-09-25T11:42:23.970 回答