From 9fa5f1b27c576d8789f1a2c6d1ed7a4fdbc1d4d4 Mon Sep 17 00:00:00 2001 From: Tom McDonald Date: Fri, 22 May 2026 14:18:46 -0400 Subject: [PATCH] Restore E_NOTIMPL fallback in DacDbiInterfaceImpl::GetContext On platforms where ICorDebugDataTarget::GetThreadContext returns E_NOTIMPL, restore the fallback that walks the thread's Frame chain to reconstruct a register context from REGDISPLAY. This is needed for managed debugging stack walks on non-Windows platforms. The fallback was inadvertently removed in 5391e9ec4fb. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 51 +++++++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 93f85aa3a7e7cf..187bec38581ef2 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -5679,10 +5679,57 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, { // If the filter context is NULL, then we use the true context of the thread. pContextBuffer->ContextFlags = DT_CONTEXT_ALL; - IfFailThrow(m_pTarget->GetThreadContext(pThread->GetOSThreadId(), + HRESULT hrContext = m_pTarget->GetThreadContext(pThread->GetOSThreadId(), pContextBuffer->ContextFlags, sizeof(DT_CONTEXT), - reinterpret_cast(pContextBuffer))); + reinterpret_cast(pContextBuffer)); + if (hrContext == E_NOTIMPL) + { + // GetThreadContext is not implemented on this data target (e.g. Linux). + // That's why we have to make do with context we can obtain from Frames explicitly stored in Thread object. + // It suffices for managed debugging stackwalk. + REGDISPLAY tmpRd = {}; + T_CONTEXT tmpContext = {}; + FillRegDisplay(&tmpRd, &tmpContext); + + // Going through thread Frames and looking for first (deepest one) one that + // that has context available for stackwalking (SP and PC) + // For example: RedirectedThreadFrame, InlinedCallFrame, DynamicHelperFrame + Frame *frame = pThread->GetFrame(); + + while (frame != NULL && frame != FRAME_TOP) + { +#ifdef FEATURE_INTERPRETER + if (frame->GetFrameIdentifier() == FrameIdentifier::InterpreterFrame) + { + PTR_InterpreterFrame pInterpreterFrame = dac_cast(frame); + pInterpreterFrame->SetContextToInterpMethodContextFrame(&tmpContext); + CopyMemory(pContextBuffer, &tmpContext, sizeof(*pContextBuffer)); + return S_OK; + } +#endif // FEATURE_INTERPRETER + frame->UpdateRegDisplay(&tmpRd); + if (GetRegdisplaySP(&tmpRd) != 0 && GetControlPC(&tmpRd) != 0) + { + UpdateContextFromRegDisp(&tmpRd, &tmpContext); + CopyMemory(pContextBuffer, &tmpContext, sizeof(*pContextBuffer)); + pContextBuffer->ContextFlags = DT_CONTEXT_CONTROL + #if defined(TARGET_AMD64) || defined(TARGET_ARM) + | DT_CONTEXT_INTEGER + #endif + ; + return S_OK; + } + frame = frame->Next(); + } + + // It looks like this thread is not running managed code. + ZeroMemory(pContextBuffer, sizeof(*pContextBuffer)); + } + else + { + IfFailThrow(hrContext); + } } else {