debugging - 从小型转储中存储的异常上下文中检索堆栈跟踪(类似于 .ecxr; k)

标签 debugging windbg dump windows-error-reporting

从 Windows 错误报告获取的转储通常在错误线程上设置了无用的当前上下文,并在 WerpReportFault 深处有一个堆栈。异常发生时的实际上下文可以使用 .ecxr 进行检索——它还设置上下文,以便同一线程上的后续命令(例如 k >) 返回“正确”的信息。

我正在构建一个用于自动转储分析的工具,它使用 IDebugControl::GetStackTrace 来获取错误线程的堆栈。我可以使用 IDebugControl4::GetStoredEventInformation 检索存储的异常上下文。如果我通过 GetStackTrace 使用存储上下文中的 EBP/RBP、ESP/RSP、EIP/RIP 值,我会得到正确的堆栈。但是,我更愿意复制 .ecxr 命令的作用,设置“正确”状态直到线程切换。我尝试使用 IDebugAdvanced::SetThreadContext,但这似乎是转储目标的非法操作,并且失败并显示 0x8000FFFF。

我试图通过调试 WinDbg 实例来弄清楚 .ecxr 的作用,看起来 .ecxr 是在 dbgeng!DotEcxr 中实现的>。然而,通过跟踪它(使用 wt),我无法理解它如何重置当前线程的上下文。无论如何,它似乎没有调用任何 COM 调试客户端接口(interface)方法,并且没有使用 IDebugAdvanced::SetThreadContext

任何有关如何在转储文件中设置线程上下文的建议将不胜感激。作为最后的手段,我始终可以使用 IDebugControl::Execute 并简单地调用 .ecxr 命令,但我更喜欢更编程的方法。

最佳答案

.ecxr mem复制上下文记录

要设置可以使用此的范围

EXT_COMMAND( setscope, "setscope", "{;e,d=@$ip;!setscope;}" )
{
    m_Symbols3->SetScopeFromStoredEvent();
}

在此调用之后,如果您执行 k 等操作,它将针对最后设置的上下文

:\>cdb -z oktest.dmp
Microsoft (R) Windows Debugger Version 10.0.10586.567 X86

This dump file has a breakpoint exception stored in it.
The stored exception information can be accessed via .ecxr.

0:000> k
ChildEBP RetAddr
0007fb1c 7c940442 ntdll!DbgBreakPoint
0007fc94 7c9210af ntdll!LdrpInitializeProcess+0xffa
0007fd1c 7c90e457 ntdll!_LdrpInitialize+0x183
00000000 00000000 ntdll!KiUserApcDispatcher+0x7


0:000> .load setscope
0:000> !setscope
0:000> k


  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr
0007fb1c 7c940442 ntdll!DbgBreakPoint
0007fc94 7c9210af ntdll!LdrpInitializeProcess+0xffa
0007fd1c 7c90e457 ntdll!_LdrpInitialize+0x183
00000000 00000000 ntdll!KiUserApcDispatcher+0x7
0:000>

完整的扩展代码,包括 getstacktrace 和 outputstacktrace

#include <codeanalysis\warnings.h>
#pragma warning( push )
#pragma warning ( disable : ALL_CODE_ANALYSIS_WARNINGS )
#include <engextcpp.cpp>
#pragma warning( pop )
class EXT_CLASS : public ExtExtension 
{
public:
    EXT_COMMAND_METHOD(setscope);
};
EXT_DECLARE_GLOBALS();
EXT_COMMAND( setscope, "setscope", "{;e,d=@$ip;!setscope;}" )
{
    m_Symbols3->SetScopeFromStoredEvent();
    DEBUG_STACK_FRAME Frames[0x20] = {0};
    ULONG FramesFilled = NULL;
    m_Control->GetStackTrace(0,0,0,Frames,0x20,&FramesFilled);
    m_Control->OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT,Frames,FramesFilled,0x1fff);
}

执行kvf和setscope

0:000> kVf
  *** Stack trace for last set context - .thread/.cxr resets it
 #   Memory  ChildEBP RetAddr  Args to Child              
00           0007fb1c 7c940442 00000000 00000000 00000000 ntdll!DbgBreakPoint (FPO: [0,0,0])
01       178 0007fc94 7c9210af 0007fd30 7c900000 0007fce0 ntdll!LdrpInitializeProcess+0xffa (FPO: [Non-Fpo])
02        88 0007fd1c 7c90e457 0007fd30 7c900000 00000000 ntdll!_LdrpInitialize+0x183 (FPO: [Non-Fpo])
03           00000000 00000000 00000000 00000000 00000000 ntdll!KiUserApcDispatcher+0x7
0:000> !setscope
 #   Memory  ChildEBP RetAddr  Args to Child              
00           0007fb1c 7c940442 00000000 00000000 00000000 ntdll!DbgBreakPoint (FPO: [0,0,0])
01       178 0007fc94 7c9210af 0007fd30 7c900000 0007fce0 ntdll!LdrpInitializeProcess+0xffa (FPO: [Non-Fpo])
02        88 0007fd1c 7c90e457 0007fd30 7c900000 00000000 ntdll!_LdrpInitialize+0x183 (FPO: [Non-Fpo])
03           00000000 00000000 00000000 00000000 00000000 ntdll!KiUserApcDispatcher+0x7

关于debugging - 从小型转储中存储的异常上下文中检索堆栈跟踪(类似于 .ecxr; k),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39230167/

相关文章:

dump - 如何转储 conftest.c?

java - IntelliJ 调试器卡住了

javascript - 如何在三星 galaxy S2 中查看控制台日志输出

debugging - "One or more breakpoints cannot be set and have been disabled. Execution will stop at the beginning of the program."

ruby-on-rails - Rails 应用程序和定位堆栈跟踪

.net - WinDbg 地址汇总

MySql Dump 输出条件注释?执行转储作为查询以恢复数据库

windbg - 获取WinDBG中公共(public)符号的参数

windows - 使用1394连接调试Windows XP内核

java - kill -3 获取java线程转储