{"id":106687,"date":"2022-05-26T07:00:00","date_gmt":"2022-05-26T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106687"},"modified":"2022-05-26T07:19:51","modified_gmt":"2022-05-26T14:19:51","slug":"20220526-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220526-00\/?p=106687","title":{"rendered":"Rescuing a stack trace the lazy way on x86-64 (aka amd64) after the debugger gave up"},"content":{"rendered":"<p>Some time ago, I showed how to <a title=\"Rescuing a stack trace after the debugger gave up when it reached an FPO function\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190206-00\/?p=101034\"> rescue a stack trace on x86-32 after the debugger lost the frame chain<\/a>. The same basic idea works on x86-64, but it&#8217;s both easy and hard, depending on how good a job you want to do.<\/p>\n<p>It&#8217;s hard if you want to get a perfect stack trace because Windows on x86-64 does not use the frame pointer register, so you will have to disassembly prologues to find out the size of each frame, just like we did with x86-32.<\/p>\n<p>But the fact that x86-64 does not use the frame pointer register as part of the stack frame actually makes things easier if you just want to recover the trail and are okay with having a gap in coverage between where the debugger got lost and where you were able to pick things up. The fact that the code generation does not use the frame pointer for stack-walking purposes makes things easier because it&#8217;s one less thing you have to recover!<\/p>\n<p>So let&#8217;s do things the easy way.<\/p>\n<p>Here&#8217;s an x86-64 stack trace that the debugger couldn&#8217;t get to the bottom of:<\/p>\n<pre>Child-SP          RetAddr               Call Site\r\nffffb383`7a497690 fffff806`372910eb     nt!KiSwapContext+0x76\r\nffffb383`7a4977d0 fffff806`37292c49     nt!KiSwapThread+0x6db\r\nffffb383`7a4978b0 fffff806`372a8eec     nt!KiCommitThreadWait+0x159\r\nffffb383`7a497950 fffff806`376e13c0     nt!KeWaitForAlertByThreadId+0xc4\r\nffffb383`7a4979b0 fffff806`37425f75     nt!NtWaitForAlertByThreadId+0x30\r\nffffb383`7a4979e0 00007ff8`807c6814     nt!KiSystemServiceCopyEnd+0x25\r\n00000000`0a02ba38 00007ff8`8075a8fd     ntdll!ZwWaitForAlertByThreadId+0x14\r\n00000000`0a02ba40 00007ff8`1d5c6e72     ntdll!RtlAcquireSRWLockShared+0x15d\r\n(Inline Function) --------`--------     contoso!wil::AcquireSRWLockShared+0xa\r\n(Inline Function) --------`--------     contoso!wil::srwlock::lock_shared+0xa\r\n(Inline Function) --------`--------     contoso!WidgetController::GetControllerInstance+0x17\r\n00000000`0a02bab0 00007ff8`7fbe23e3     contoso!WidgetController::IsInitialized+0x32\r\n00000000`0a02bae0 00007ff8`7fc4b68c     RPCRT4!Invoke+0x73\r\n00000000`0a02bb30 00007ff8`7fbae5b2     RPCRT4!Ndr64StubWorker+0xb7c\r\n00000000`0a02c1d0 00007ff8`7f5db185     RPCRT4!NdrStubCall3+0xd2\r\n00000000`0a02c230 00007ff8`7fbc40a5     combase!CStdStubBuffer_Invoke+0x65\r\n00000000`0a02c270 00007ff8`7f5c89cd     RPCRT4!CStdStubBuffer_Invoke+0x45\r\n(Inline Function) --------`--------     combase!InvokeStubWithExceptionPolicyAndTracing::__l6::&lt;lambda&gt;::operator()+0x22\r\n00000000`0a02c2a0 00007ff8`7f5c8767     combase!ObjectMethodExceptionHandlingAction&lt;&lt;lambda&gt; &gt;+0x4d\r\n(Inline Function) --------`--------     combase!InvokeStubWithExceptionPolicyAndTracing+0xda\r\n00000000`0a02c300 00007ff8`7f5de5c8     combase!DefaultStubInvoke+0x257\r\n00000000`0a02c450 00007ff8`7f57feef     combase!SyncServerCall::StubInvoke+0x38\r\n(Inline Function) --------`--------     combase!StubInvoke+0x496\r\n00000000`0a02c490 00007ff8`7f55060f     combase!ServerCall::ContextInvoke+0x69f\r\n(Inline Function) --------`--------     combase!CServerChannel::ContextInvoke+0x16b\r\n(Inline Function) --------`--------     combase!DefaultInvokeInApartment+0x16b\r\n00000000`0a02c770 00007ff8`7f626128     combase!ReentrantSTAInvokeInApartment+0x1df\r\n00000000`0a02c7f0 00007ff8`7f57bfb9     combase!ComInvokeWithLockAndIPID+0x7c4\r\n00000000`0a02cad0 00007ff8`7f577b21     combase!ThreadDispatch+0x331\r\n00000000`0a02cbc0 00007ff8`7f31dd5c     combase!ThreadWndProc+0x1c1\r\n00000000`0a02cc50 00007ff8`7f31c9e9     user32!UserCallWinProcCheckWow+0x33c\r\n00000000`0a02cdc0 00007ff8`7f5df067     user32!DispatchMessageWorker+0x1c9\r\n(Inline Function) --------`--------     combase!CCliModalLoop::MyDispatchMessage+0xc\r\n00000000`0a02ce40 00007ff8`7f557627     combase!CCliModalLoop::PeekRPCAndDDEMessage+0x77\r\n00000000`0a02ceb0 00007ff8`7f557366     combase!CCliModalLoop::BlockFn+0x283\r\n00000000`0a02cf60 00007ff8`7f5e91c3     combase!ModalLoop+0xc2\r\n00000000`0a02cfb0 00007ff8`7f550c85     combase!ClassicSTAThreadDispatchCrossApartmentCall+0x63\r\n(Inline Function) --------`--------     combase!CSyncClientCall::SwitchAptAndDispatchCall+0x9b\r\n00000000`0a02cff0 00007ff8`7f555372     combase!CSyncClientCall::SendReceive2+0x415\r\n(Inline Function) --------`--------     combase!SyncClientCallRetryContext::SendReceiveWithRetry+0x2b\r\n(Inline Function) --------`--------     combase!CSyncClientCall::SendReceiveInRetryContext+0x2f\r\n00000000`0a02d540 00000000`00000000     combase!ClassicSTAThreadSendReceive+0xa2\r\n<\/pre>\n<p>We see that we are waiting to acquire a reader\/writer lock in shared mode. This came from an inbound request from another thread, as evidenced by the fact that the entry into the Contoso component came from <code>RPCRT4!Invoke<\/code>, the remote procedure call runtime.<\/p>\n<p>But the stack trace goes cold in the middle of the COM infrastructure. Can we try to repair it?<\/p>\n<p>Start by dumping the stack at the last known good address, namely the last stack pointer before the debugger gave up:<\/p>\n<pre><span style=\"border: solid 1px black;\">00000000`0a02cff0<\/span> 00007ff8`7f555372     combase!CSyncClientCall::SendReceive2+0x415\r\n\r\n0: kd&gt; dps 00000000`0a02cff0\r\n00000000`0a02cff0  00000000`077801f0\r\n00000000`0a02cff8  00000000`0a02d0f0\r\n00000000`0a02d000  00000000`00000000\r\n00000000`0a02d008  00000000`00000000\r\n00000000`0a02d010  00000000`00000000\r\n00000000`0a02d018  0000002a`00000000\r\n00000000`0a02d020  00000000`00000000\r\n00000000`0a02d028  00000000`00000000\r\n00000000`0a02d030  00000000`00000000\r\n00000000`0a02d038  00005dff`00002a78\r\n00000000`0a02d040  4054792b`5a44dc12\r\n00000000`0a02d048  6813c787`a838fdba\r\n00000000`0a02d050  00000000`00000000\r\n00000000`0a02d058  00000000`0a02dbd0\r\n00000000`0a02d060  00000000`00000000\r\n00000000`0a02d068  00000000`0a02d908\r\n0: kd&gt; d\r\n00000000`0a02d070  00000000`0a02dbd0\r\n00000000`0a02d078  00000000`00000000\r\n00000000`0a02d080  0000cd1c`00000000\r\n00000000`0a02d088  00007ff8`00000000\r\n00000000`0a02d090  00000000`ffffffff\r\n00000000`0a02d098  00000000`00000000\r\n00000000`0a02d0a0  00000000`00000000\r\n00000000`0a02d0a8  00007ff8`8074952d ntdll!RtlpLowFragHeapAllocFromContext+0x1cd\r\n00000000`0a02d0b0  00000000`00060007\r\n00000000`0a02d0b8  00000000`00000180\r\n00000000`0a02d0c0  00000000`07482f80\r\n00000000`0a02d0c8  00000000`05733dc0\r\n00000000`0a02d0d0  00000000`074f4300\r\n00000000`0a02d0d8  00000000`0a02d1f0\r\n00000000`0a02d0e0  01277f18`00000000\r\n00000000`0a02d0e8  00000000`ffffffff\r\n<\/pre>\n<p>We&#8217;re looking for return addresses that look like a stack frame that would plausibly lead to <code>combase!ClassicSTAThreadSendReceive<\/code>. I like to play it safe and just dump for a long time, to get out of the scary broken region (whatever it was that got the debugger confused), and not pay attention until we&#8217;ve dumped a screenful or two.<\/p>\n<pre>(a few dump commands skipped)\r\n0: kd&gt; d\r\n00000000`0a02d6f0  00000000`077801f0\r\n00000000`0a02d6f8  00007ff8`7f5d86b6 combase!CStdIdentity::CInternalUnk::AddRef+0xc6\r\n00000000`0a02d700  00000000`0737db01\r\n00000000`0a02d708  00007ff8`6e2d6150 OneCoreCommonProxyStub!IID_IServiceProvider\r\n00000000`0a02d710  00000000`074f4300\r\n00000000`0a02d718  00000000`07366790\r\n00000000`0a02d720  00000000`074f4300\r\n00000000`0a02d728  00007ff8`7f57e4fd combase!StandardComClientCall::GetBuffer+0x17d\r\n00000000`0a02d730  00000000`077801f0\r\n00000000`0a02d738  00000000`0a02db00\r\n00000000`0a02d740  00007ff8`00000001\r\n00000000`0a02d748  00000000`00000000\r\n00000000`0a02d750  00000000`00000000\r\n00000000`0a02d758  00000000`00000000\r\n00000000`0a02d760  00000000`0a02d7f0\r\n00000000`0a02d768  00000000`0a02d784\r\n0: kd&gt; d\r\n00000000`0a02d770  00000000`0a02d780\r\n00000000`0a02d778  42edc8cf`91b64ada\r\n00000000`0a02d780  00000000`b74f0a00\r\n00000000`0a02d788  00000000`00000000\r\n00000000`0a02d790  00000000`00000000\r\n00000000`0a02d798  00007ff8`7f7e1bbe combase!mega__MIDL_ProcFormatString+0x340e\r\n00000000`0a02d7a0  00000000`00000000\r\n00000000`0a02d7a8  00000000`00000062\r\n00000000`0a02d7b0  00000000`00000000\r\n00000000`0a02d7b8  00000028`00000001\r\n00000000`0a02d7c0  00007ff8`7f7a69c0 combase!IRundown_SyntaxInfo+0x50\r\n00000000`0a02d7c8  00007ff8`7df1a950 bcryptPrimitives!GetPtrPtrToPerCpuState+0x24\r\n00000000`0a02d7d0  00000000`00000010\r\n00000000`0a02d7d8  00007ff8`7df1a6da bcryptPrimitives!AesRNGState_generate+0x166\r\n00000000`0a02d7e0  11ce7436`6d5140c1\r\n00000000`0a02d7e8  fa096000`aa003480\r\n0: kd&gt; d\r\n00000000`0a02d7f0  00efe307`38512264\r\n00000000`0a02d7f8  d800ec24`1467b218\r\n00000000`0a02d800  00000000`00000000\r\n00000000`0a02d808  00007ff8`7f57ced5 combase!StandardComClientCall::NegotiateSyntax+0xf5\r\n00000000`0a02d810  0000cd1c`5d9cdd71\r\n00000000`0a02d818  00000000`00000000\r\n00000000`0a02d820  00000000`0a02da40\r\n00000000`0a02d828  00000000`0737db01\r\n00000000`0a02d830  00000000`00000000\r\n00000000`0a02d838  00000000`0a02dbd0\r\n00000000`0a02d840  00000000`0a02d908\r\n00000000`0a02d848  00000000`074f4300\r\n00000000`0a02d850  00000000`00000000\r\n00000000`0a02d858  00007ff8`7f5789e8 combase!CClientChannel::SendReceive+0x98\r\n00000000`0a02d860  00000000`0a02da40\r\n00000000`0a02d868  00000000`0737db01\r\n<\/pre>\n<p>Now the <code>bcrypt<\/code> stuff is almost certainly spurious, probably left over from earlier calls, because there&#8217;s no obvious reason for <code>Get\u00adPtr\u00adPtr\u00adTo\u00adPer\u00adCpu\u00adState<\/code> to be calling into the COM marshaling infrastructure. However, the <code>combase<\/code> functions <code>Standard\u00adCom\u00adClient\u00adCall::<wbr \/>Negotiate\u00adSyntax<\/code> and <code>CClient\u00adChannel::<wbr \/>Send\u00adReceive<\/code> look promising.<\/p>\n<p>Let&#8217;s tell the debugger to create a stack trace starting at a point that looks good: The parameters to the <code>k=<\/code> command vary from processor to processor, so I always have to go look them up.<\/p>\n<blockquote class=\"q\">\n<p>Kernel-Mode, x64 Processor<\/p>\n<pre>[Processor] k[b|p|P|v] [c] [n] [f] [L] [M] [FrameCount]\r\n[Processor] k[b|p|P|v] [c] [n] [f] [L] [M] = StackPtr FrameCount\r\n[Processor] k[b|p|P|v] [c] [n] [f] [L] [M] = StackPtr InstructionPtr FrameCount\r\n[Processor] kd [WordCount]\r\n<\/pre>\n<\/blockquote>\n<p>The one I want here is the one that takes a stack pointer, an instruction pointer, and a frame count.<\/p>\n<pre>00000000`0a02d808  00007ff8`7f57ced5 combase!StandardComClientCall::NegotiateSyntax+0xf5\r\n<\/pre>\n<p>From this line in the stack dump, we realize that if the stack pointer is <code>00000000`0a02d808<\/code> and the program executes a return instruction, then control will return to <code>00007ff8`7f57ced5<\/code> (<code>combase!<wbr \/>Standard\u00adCom\u00adClient\u00adCall::<wbr \/>Negotiate\u00adSyntax+0xf5i<\/code>) with the stack pointer equal to <code>00000000`0a02d810<\/code> (because returning will pop the 8-byte return address from the stack).<\/p>\n<p>So we give that to the debugger and see what we get.<\/p>\n<pre>0: kd&gt; k=00000000`0a02d810 00007ff8`7f57ced5 9\r\nChild-SP          RetAddr               Call Site\r\n00000000`0a02d810 00000000`0a02dcb0     combase!StandardComClientCall::NegotiateSyntax+0xf5\r\n00000000`0a02d890 00000000`06e80730     0xa02dcb0\r\n00000000`0a02d898 00007ff8`7f5ceb66     0x6e80730\r\n00000000`0a02d8a0 00007ff8`7f5db368     combase!CClientChannel::GetBuffer+0x96\r\n00000000`0a02d8d0 00007ff8`7fc4c2c3     combase!NdrExtpProxySendReceive+0x58\r\n(Inline Function) --------`--------     RPCRT4!Ndr64pSendReceive+0x39\r\n00000000`0a02d900 00007ff8`7fc4dd38     RPCRT4!NdrpClientCall3+0x403\r\n00000000`0a02dc80 00007ff8`6e2548e2     RPCRT4!NdrClientCall3+0xe8\r\n(Inline Function) --------`--------     OneCoreCommonProxyStub!IServiceProvider_RemoteQueryService_Proxy+0x2e\r\n<\/pre>\n<p>Those garbage frames at the top of the stack don&#8217;t look so good, but things seem to straighten themselves out. Let&#8217;s go a little further.<\/p>\n<pre>0: kd&gt; k=00000000`0a02d810 00007ff8`7f57ced5 99\r\nChild-SP          RetAddr               Call Site\r\n00000000`0a02d810 00000000`0a02dcb0     combase!StandardComClientCall::NegotiateSyntax+0xf5\r\n00000000`0a02d890 00000000`06e80730     0xa02dcb0\r\n00000000`0a02d898 00007ff8`7f5ceb66     0x6e80730\r\n00000000`0a02d8a0 00007ff8`7f5db368     combase!CClientChannel::GetBuffer+0x96\r\n00000000`0a02d8d0 00007ff8`7fc4c2c3     combase!NdrExtpProxySendReceive+0x58\r\n(Inline Function) --------`--------     RPCRT4!Ndr64pSendReceive+0x39\r\n00000000`0a02d900 00007ff8`7fc4dd38     RPCRT4!NdrpClientCall3+0x403\r\n00000000`0a02dc80 00007ff8`6e2548e2     RPCRT4!NdrClientCall3+0xe8\r\n(Inline Function) --------`--------     OneCoreCommonProxyStub!IServiceProvider_RemoteQueryService_Proxy+0x2e\r\n00000000`0a02e010 00007ff8`66d721e0     OneCoreCommonProxyStub!IServiceProvider_QueryService_Proxy+0x32\r\n00000000`0a02e060 00007ff8`66d72085     contoso!Doodad::QueryService+0x110\r\n00000000`0a02e0d0 00007ff8`1d5aecd7     contoso!Gadget::QueryService+0x55\r\n00000000`0a02e100 00007ff8`1d606e6a     contoso!WidgetControllerImpl::GetWidgetDirector+0x77\r\n(Inline Function) --------`--------     contoso!WidgetControllerImpl::UnregisterEndpoint::__l2::&lt;lambda&gt;::operator()+0x1a\r\n00000000`0a02e140 00007ff8`1d5fc4d0     contoso!WidgetControllerImpl::UnregisterEndpoint+0xba\r\n00000000`0a02e2e0 00007ff8`7fbe23e3     contoso!WidgetController::UnregisterEndpoint+0x40\r\n00000000`0a02e310 00007ff8`7fc4b68c     RPCRT4!Invoke+0x73\r\n00000000`0a02e360 00007ff8`7fbae5b2     RPCRT4!Ndr64StubWorker+0xb7c\r\n00000000`0a02ea00 00007ff8`7f5db185     RPCRT4!NdrStubCall3+0xd2\r\n00000000`0a02ea60 00007ff8`7fbc40a5     combase!CStdStubBuffer_Invoke+0x65\r\n00000000`0a02eaa0 00007ff8`7f5c89cd     RPCRT4!CStdStubBuffer_Invoke+0x45\r\n(Inline Function) --------`--------     combase!InvokeStubWithExceptionPolicyAndTracing::__l6::&lt;lambda&gt;::operator()+0x22\r\n00000000`0a02ead0 00007ff8`7f5c8767     combase!ObjectMethodExceptionHandlingAction&lt;&lt;lambda&gt; &gt;+0x4d\r\n(Inline Function) --------`--------     combase!InvokeStubWithExceptionPolicyAndTracing+0xda\r\n00000000`0a02eb30 00007ff8`7f5de5c8     combase!DefaultStubInvoke+0x257\r\n00000000`0a02ec80 00007ff8`7f57feef     combase!SyncServerCall::StubInvoke+0x38\r\n(Inline Function) --------`--------     combase!StubInvoke+0x496\r\n00000000`0a02ecc0 00007ff8`7f55060f     combase!ServerCall::ContextInvoke+0x69f\r\n(Inline Function) --------`--------     combase!CServerChannel::ContextInvoke+0x16b\r\n(Inline Function) --------`--------     combase!DefaultInvokeInApartment+0x16b\r\n00000000`0a02efa0 00007ff8`7f626128     combase!ReentrantSTAInvokeInApartment+0x1df\r\n00000000`0a02f020 00007ff8`7f57bfb9     combase!ComInvokeWithLockAndIPID+0x7c4\r\n00000000`0a02f300 00007ff8`7f577b21     combase!ThreadDispatch+0x331\r\n00000000`0a02f3f0 00007ff8`7f31dd5c     combase!ThreadWndProc+0x1c1\r\n00000000`0a02f480 00007ff8`7f31c9e9     user32!UserCallWinProcCheckWow+0x33c\r\n00000000`0a02f5f0 00007ff8`551912e8     user32!DispatchMessageWorker+0x1c9\r\n00000000`0a02f670 00007ff8`55191259     contoso!Session::s_RunMessageLoop+0x80\r\n00000000`0a02f6e0 00007ff8`7fa04e9f     contoso!Session::s_RunDirectorThread+0xe9\r\n00000000`0a02f810 00007ff8`8072485b     KERNEL32!BaseThreadInitThunk+0x10\r\n00000000`0a02f840 00000000`00000000     ntdll!RtlUserThreadStart+0x2b\r\n<\/pre>\n<p>This looks like a totally plausible stack trace if you ignore the instability at the top.<\/p>\n<p>If you&#8217;d rather get a totally clean stack trace, then try out different starting points. From this one<\/p>\n<pre>00000000`0a02d858  00007ff8`7f5789e8 combase!CClientChannel::SendReceive+0x98\r\n<\/pre>\n<p>we get<\/p>\n<pre>0: kd&gt;  k=00000000`0a02d860 00007ff8`7f5789e8 99\r\nChild-SP          RetAddr               Call Site\r\n00000000`0a02d860 00007ff8`7f5db368     combase!CClientChannel::SendReceive+0x98\r\n00000000`0a02d8d0 00007ff8`7fc4c2c3     combase!NdrExtpProxySendReceive+0x58\r\n(Inline Function) --------`--------     RPCRT4!Ndr64pSendReceive+0x39\r\n00000000`0a02d900 00007ff8`7fc4dd38     RPCRT4!NdrpClientCall3+0x403\r\n00000000`0a02dc80 00007ff8`6e2548e2     RPCRT4!NdrClientCall3+0xe8\r\n(Inline Function) --------`--------     OneCoreCommonProxyStub!IServiceProvider_RemoteQueryService_Proxy+0x2e\r\n00000000`0a02e010 00007ff8`66d721e0     OneCoreCommonProxyStub!IServiceProvider_QueryService_Proxy+0x32\r\n00000000`0a02e060 00007ff8`66d72085     contoso!Doodad::QueryService+0x110\r\n00000000`0a02e0d0 00007ff8`1d5aecd7     contoso!Gadget::QueryService+0x55\r\n00000000`0a02e100 00007ff8`1d606e6a     contoso!WidgetControllerImpl::GetWidgetDirector+0x77\r\n(Inline Function) --------`--------     contoso!WidgetControllerImpl::UnregisterEndpoint::__l2::&lt;lambda&gt;::operator()+0x1a\r\n00000000`0a02e140 00007ff8`1d5fc4d0     contoso!WidgetControllerImpl::UnregisterEndpoint+0xba\r\n00000000`0a02e2e0 00007ff8`7fbe23e3     contoso!WidgetController::UnregisterEndpoint+0x40\r\n00000000`0a02e310 00007ff8`7fc4b68c     RPCRT4!Invoke+0x73\r\n00000000`0a02e360 00007ff8`7fbae5b2     RPCRT4!Ndr64StubWorker+0xb7c\r\n00000000`0a02ea00 00007ff8`7f5db185     RPCRT4!NdrStubCall3+0xd2\r\n00000000`0a02ea60 00007ff8`7fbc40a5     combase!CStdStubBuffer_Invoke+0x65\r\n00000000`0a02eaa0 00007ff8`7f5c89cd     RPCRT4!CStdStubBuffer_Invoke+0x45\r\n(Inline Function) --------`--------     combase!InvokeStubWithExceptionPolicyAndTracing::__l6::&lt;lambda&gt;::operator()+0x22\r\n00000000`0a02ead0 00007ff8`7f5c8767     combase!ObjectMethodExceptionHandlingAction&lt;&lt;lambda&gt; &gt;+0x4d\r\n(Inline Function) --------`--------     combase!InvokeStubWithExceptionPolicyAndTracing+0xda\r\n00000000`0a02eb30 00007ff8`7f5de5c8     combase!DefaultStubInvoke+0x257\r\n00000000`0a02ec80 00007ff8`7f57feef     combase!SyncServerCall::StubInvoke+0x38\r\n(Inline Function) --------`--------     combase!StubInvoke+0x496\r\n00000000`0a02ecc0 00007ff8`7f55060f     combase!ServerCall::ContextInvoke+0x69f\r\n(Inline Function) --------`--------     combase!CServerChannel::ContextInvoke+0x16b\r\n(Inline Function) --------`--------     combase!DefaultInvokeInApartment+0x16b\r\n00000000`0a02efa0 00007ff8`7f626128     combase!ReentrantSTAInvokeInApartment+0x1df\r\n00000000`0a02f020 00007ff8`7f57bfb9     combase!ComInvokeWithLockAndIPID+0x7c4\r\n00000000`0a02f300 00007ff8`7f577b21     combase!ThreadDispatch+0x331\r\n00000000`0a02f3f0 00007ff8`7f31dd5c     combase!ThreadWndProc+0x1c1\r\n00000000`0a02f480 00007ff8`7f31c9e9     user32!UserCallWinProcCheckWow+0x33c\r\n00000000`0a02f5f0 00007ff8`551912e8     user32!DispatchMessageWorker+0x1c9\r\n00000000`0a02f670 00007ff8`55191259     contoso!Session::s_RunMessageLoop+0x80\r\n00000000`0a02f6e0 00007ff8`7fa04e9f     contoso!Session::s_RunDirectorThread+0xe9\r\n00000000`0a02f810 00007ff8`8072485b     KERNEL32!BaseThreadInitThunk+0x10\r\n00000000`0a02f840 00000000`00000000     ntdll!RtlUserThreadStart+0x2b\r\n<\/pre>\n<p>which is identical to our previous one, once you get past the initial instability.<\/p>\n<p>Next time, we&#8217;ll look at why there is often instability at the start of a recovered stack trace.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Looking for a good frame to start from.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-106687","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Looking for a good frame to start from.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106687","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=106687"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106687\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=106687"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106687"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106687"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}