Getting stack trace from stored exception context in minidump (similar to .ecxr; k)

Dumps obtained from the Windows error report usually have a useless current context set in the error branch, with stack depth in WerpReportFault . The actual context during the exception can be obtained using .ecxr - which also sets the context so that subsequent commands in the same thread (for example, k ) return the "correct" information.

I am creating an automatic dump analysis tool that uses IDebugControl::GetStackTrace to get an error stream stack. I can get the saved exception context using IDebugControl4::GetStoredEventInformation . If I use the values ​​EBP / RBP, ESP / RSP, EIP / RIP from the saved context using GetStackTrace , I get the correct stack. However, I would rather repeat what the .ecxr command .ecxr , setting the β€œcorrect” state until the thread switches. I tried using IDebugAdvanced::SetThreadContext , but it seems to be an illegal operation for dump purposes and with error 0x8000FFFF.

I tried to figure out what .ecxr does by debugging a WinDbg instance and it looks like .ecxr implemented in dbgeng!DotEcxr . However, by tracking it (using wt ), I could not figure out how it resets the current context of the stream. In any case, it does not call any methods of the COM client debugging interface and does not use IDebugAdvanced::SetThreadContext .

Any suggestions on how to set the flow context in the dump file would be greatly appreciated. As a last resort, I can always use IDebugControl::Execute and just call the .ecxr command, but I would prefer a more programmatic approach.

+5
source share
2 answers

.ecxr memcopies context record

to set the scope you can use

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

after this call, if you do k, etc., it will be for the last specified context

 :\>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> 

full extension code including getstacktrace and 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); } 

done by kvf and 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 
+2
source

I think that in dbgeng there is no magic way to save the register and use it in all subsequent API calls, but if you get the exception context from IDebugControl4 :: GetStoredEventInformation (), I believe that you should prefer IDebugControl4 :: GetContextStackTrace () instead to spoof GetStackTrace ().

+1
source

All Articles