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

Sas*_*ein 5 debugging windbg dump windows-error-reporting

从Windows错误报告中获取的转储通常在错误线程上设置无用的当前上下文,并且堆栈深入WerpReportFault.可以使用以下方式检索异常时的实际上下文.ecxr- 它还以相同线程(例如k)上的后续命令返回"正确"信息的方式设置上下文.

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

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

关于如何在转储文件中设置线程上下文的任何建议都将非常感激.作为最后的手段,我总是可以使用IDebugControl::Execute并简单地调用.ecxr命令,但我更喜欢更程序化的方法.

bla*_*abb 3

.ecxr mem复制上下文记录

要设置范围,您可以使用它

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

在此调用之后,如果您执行 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>
Run Code Online (Sandbox Code Playgroud)

完整的扩展代码,包括 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);
}
Run Code Online (Sandbox Code Playgroud)

执行 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
Run Code Online (Sandbox Code Playgroud)