From 4cde96264b9580dc55562075640086163f00d12a Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 8 Jan 2024 23:30:58 +0100 Subject: [PATCH 01/17] Test --- src/coreclr/inc/clrconfigvalues.h | 2 +- src/coreclr/inc/vptr_list.h | 1 + src/coreclr/vm/exceptionhandling.cpp | 16 +++++++++++----- src/coreclr/vm/exinfo.cpp | 13 ++++++++++--- src/coreclr/vm/frames.h | 21 +++++++++++++++++++++ src/coreclr/vm/stackwalk.cpp | 13 ++++++++++++- 6 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 12a1e706602cc5..657c8f16914c13 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -259,7 +259,7 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_legacyCorruptedStateExceptionsPolicy, W("le CONFIG_DWORD_INFO(INTERNAL_SuppressLostExceptionTypeAssert, W("SuppressLostExceptionTypeAssert"), 0, "") RETAIL_CONFIG_DWORD_INFO(INTERNAL_UseEntryPointFilter, W("UseEntryPointFilter"), 0, "") RETAIL_CONFIG_DWORD_INFO(INTERNAL_Corhost_Swallow_Uncaught_Exceptions, W("Corhost_Swallow_Uncaught_Exceptions"), 0, "") -RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableNewExceptionHandling, W("EnableNewExceptionHandling"), 0, "Enable new exception handling."); +RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableNewExceptionHandling, W("EnableNewExceptionHandling"), 1, "Enable new exception handling."); /// diff --git a/src/coreclr/inc/vptr_list.h b/src/coreclr/inc/vptr_list.h index 0070c5867aa358..671d3497fa3a3c 100644 --- a/src/coreclr/inc/vptr_list.h +++ b/src/coreclr/inc/vptr_list.h @@ -58,6 +58,7 @@ VPTR_CLASS(DebuggerSecurityCodeMarkFrame) VPTR_CLASS(DebuggerExitFrame) VPTR_CLASS(DebuggerU2MCatchHandlerFrame) VPTR_CLASS(FaultingExceptionFrame) +VPTR_CLASS(NativeToManagedExceptionFrame) VPTR_CLASS(FuncEvalFrame) VPTR_CLASS(HelperMethodFrame) VPTR_CLASS(HelperMethodFrame_1OBJ) diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 4d28ed16a5e71c..0a8d2df6f5bc33 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -899,8 +899,8 @@ ProcessCLRExceptionNew(IN PEXCEPTION_RECORD pExceptionRecord, else { GCX_COOP(); - FrameWithCookie frameWithCookie; - FaultingExceptionFrame *frame = &frameWithCookie; + FrameWithCookie frameWithCookie; + NativeToManagedExceptionFrame *frame = &frameWithCookie; #if defined(FEATURE_EH_FUNCLETS) *frame->GetGSCookiePtr() = GetProcessGSCookie(); #endif // FEATURE_EH_FUNCLETS @@ -8041,7 +8041,6 @@ static void NotifyExceptionPassStarted(StackFrameIterator *pThis, Thread *pThrea GCX_COOP(); pThread->SafeSetThrowables(pExInfo->m_exception); EEToProfilerExceptionInterfaceWrapper::ExceptionThrown(pThread); - UpdatePerformanceMetrics(&pThis->m_crawl, false, ((uint8_t)pExInfo->m_kind & (uint8_t)ExKind::RethrowFlag) == 0); } else // pExInfo->m_passNumber == 2 { @@ -8167,6 +8166,13 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk new (pThis) StackFrameIterator(); result = pThis->Init(pThread, pFrame, pRD, THREAD_EXECUTING_MANAGED_CODE) != FALSE; + if (result && (pExInfo->m_passNumber == 1)) + { + // TODO: is this coop mode needed? + GCX_COOP(); + UpdatePerformanceMetrics(&pThis->m_crawl, false, ((uint8_t)pExInfo->m_kind & (uint8_t)ExKind::RethrowFlag) == 0); + } + // Walk the stack until it finds the first managed method while (result && pThis->GetFrameState() != StackFrameIterator::SFITER_FRAMELESS_METHOD) { @@ -8214,7 +8220,7 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk if (result) { TADDR controlPC = pThis->m_crawl.GetRegisterSet()->ControlPC; - if (!pThis->m_crawl.HasFaulted()) + if (!pThis->m_crawl.HasFaulted() && !pThis->m_crawl.IsIPadjusted()) { controlPC -= STACKWALK_CONTROLPC_ADJUST_OFFSET; } @@ -8457,7 +8463,7 @@ Exit:; if (retVal != SWA_FAILED) { TADDR controlPC = pThis->m_crawl.GetRegisterSet()->ControlPC; - if (!pThis->m_crawl.HasFaulted()) + if (!pThis->m_crawl.HasFaulted() && !pThis->m_crawl.IsIPadjusted()) { controlPC -= STACKWALK_CONTROLPC_ADJUST_OFFSET; } diff --git a/src/coreclr/vm/exinfo.cpp b/src/coreclr/vm/exinfo.cpp index 741bae687d81da..254cd120bd12fb 100644 --- a/src/coreclr/vm/exinfo.cpp +++ b/src/coreclr/vm/exinfo.cpp @@ -326,12 +326,19 @@ ExInfo::ExInfo(Thread *pThread, EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pEx m_propagateExceptionContext(NULL), #endif // HOST_UNIX m_CurrentClause({}), - m_pMDToReportFunctionLeave(NULL), - m_exContext({}) + m_pMDToReportFunctionLeave(NULL) { m_StackTraceInfo.AllocateStackTrace(); pThread->GetExceptionState()->m_pCurrentTracker = this; - m_exContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + memcpy(&m_exContext, pExceptionContext, sizeof(CONTEXT)); + if (pThread->GetFrame() != FRAME_TOP) + { + Thread::VirtualUnwindToFirstManagedCallFrame(&m_exContext); + } + SetIP(&m_exContext, 0); + // m_exContext.ContextFlags = CONTEXT_FLOATING_POINT; + // ClrCaptureContext(&m_exContext); + // m_exContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT; } #if defined(TARGET_UNIX) diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 907cc2e0e3eb74..24157e6c572b1c 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -190,6 +190,7 @@ FRAME_TYPE_NAME(ResumableFrame) FRAME_TYPE_NAME(RedirectedThreadFrame) #endif // FEATURE_HIJACK FRAME_TYPE_NAME(FaultingExceptionFrame) +FRAME_TYPE_NAME(NativeToManagedExceptionFrame) #ifdef DEBUGGING_SUPPORTED FRAME_TYPE_NAME(FuncEvalFrame) #endif // DEBUGGING_SUPPORTED @@ -1120,6 +1121,26 @@ class FaultingExceptionFrame : public Frame DEFINE_VTABLE_GETTER_AND_DTOR(FaultingExceptionFrame) }; +class NativeToManagedExceptionFrame : public FaultingExceptionFrame +{ + VPTR_VTABLE_CLASS(NativeToManagedExceptionFrame, FaultingExceptionFrame) +public: +#ifndef DACCESS_COMPILE + NativeToManagedExceptionFrame() { + LIMITED_METHOD_CONTRACT; + } +#endif + + unsigned GetFrameAttribs() + { + LIMITED_METHOD_DAC_CONTRACT; + return FRAME_ATTR_EXCEPTION; + } + + // Keep as last entry in class + DEFINE_VTABLE_GETTER_AND_DTOR(NativeToManagedExceptionFrame) +}; + //----------------------------------------------------------------------- // Frame for debugger function evaluation // diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp index 92a0cd9dc76b47..8e93b0c7cbda9d 100644 --- a/src/coreclr/vm/stackwalk.cpp +++ b/src/coreclr/vm/stackwalk.cpp @@ -1401,7 +1401,12 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, } m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD); - +#ifdef FEATURE_EH_FUNCLETS + if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) + { + m_crawl.hasFaulted = false; + } +#endif // FEATURE_EH_FUNCLETS _ASSERTE(curPc == GetControlPC(m_crawl.pRD)); } @@ -2722,6 +2727,12 @@ StackWalkAction StackFrameIterator::NextRaw(void) if (m_crawl.isFrameless) { m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD); +#ifdef FEATURE_EH_FUNCLETS + if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) + { + m_crawl.hasFaulted = false; + } +#endif // FEATURE_EH_FUNCLETS #if defined(RECORD_RESUMABLE_FRAME_SP) CONSISTENCY_CHECK(NULL == m_pvResumableFrameTargetSP); From c4182035dc6c474ce062149ddb8edda512cc02d2 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Sat, 13 Jan 2024 02:02:30 +0100 Subject: [PATCH 02/17] added unwinds --- src/coreclr/debug/inc/amd64/primitives.h | 6 +- src/coreclr/vm/arm/asmhelpers.S | 3 +- src/coreclr/vm/excep.cpp | 6 +- src/coreclr/vm/exceptionhandling.cpp | 120 ++++++++++++++++++++--- src/coreclr/vm/exceptionhandling.h | 1 + src/coreclr/vm/exinfo.cpp | 23 +++-- src/coreclr/vm/frames.h | 7 +- src/coreclr/vm/jithelpers.cpp | 6 +- src/coreclr/vm/stackwalk.cpp | 30 +++--- src/coreclr/vm/threadsuspend.cpp | 3 +- 10 files changed, 166 insertions(+), 39 deletions(-) diff --git a/src/coreclr/debug/inc/amd64/primitives.h b/src/coreclr/debug/inc/amd64/primitives.h index 83afbbbba7d327..1b32ce21b146b9 100644 --- a/src/coreclr/debug/inc/amd64/primitives.h +++ b/src/coreclr/debug/inc/amd64/primitives.h @@ -80,7 +80,11 @@ constexpr CorDebugRegister g_JITToCorDbgReg[] = inline CorDebugRegister ConvertRegNumToCorDebugRegister(ICorDebugInfo::RegNum reg) { _ASSERTE(reg >= 0); - _ASSERTE(static_cast(reg) < ARRAY_SIZE(g_JITToCorDbgReg)); + //_ASSERTE(static_cast(reg) < ARRAY_SIZE(g_JITToCorDbgReg)); + if (static_cast(reg) >= ARRAY_SIZE(g_JITToCorDbgReg)) + { + reg = ICorDebugInfo::REGNUM_RAX; + } return g_JITToCorDbgReg[reg]; } diff --git a/src/coreclr/vm/arm/asmhelpers.S b/src/coreclr/vm/arm/asmhelpers.S index 91e18dc81faf21..27a44b62c119b3 100644 --- a/src/coreclr/vm/arm/asmhelpers.S +++ b/src/coreclr/vm/arm/asmhelpers.S @@ -127,7 +127,8 @@ LOCAL_LABEL(LReturnDone): EPILOG_STACK_RESTORE_OFFSET r7, #8 EPILOG_POP "{r4,r5,r7,pc}" -PATCH_LABEL CallDescrWorkerInternalReturnAddressOffset +CallDescrWorkerInternalReturnAddressOffset: + .global CallDescrWorkerInternalReturnAddressOffset .word LOCAL_LABEL(CallDescrWorkerInternalReturnAddress) - C_FUNC(CallDescrWorkerInternal) NESTED_END CallDescrWorkerInternal,_TEXT diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index 245909f7a72f70..b684180a152f7b 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -6563,7 +6563,7 @@ void HandleManagedFaultNew(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext #if defined(FEATURE_EH_FUNCLETS) *frame->GetGSCookiePtr() = GetProcessGSCookie(); #endif // FEATURE_EH_FUNCLETS - pContext->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; + //pContext->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; frame->InitAndLink(pContext); Thread *pThread = GetThread(); @@ -7103,12 +7103,14 @@ VEH_ACTION WINAPI CLRVectoredExceptionHandlerPhase3(PEXCEPTION_POINTERS pExcepti // // On 64-bit, some additional work is required.. #ifdef FEATURE_EH_FUNCLETS + pContext->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE; return VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION; #endif // defined(FEATURE_EH_FUNCLETS) } else if (AdjustContextForVirtualStub(pExceptionRecord, pContext)) { #ifdef FEATURE_EH_FUNCLETS + pContext->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE; return VEH_EXECUTE_HANDLE_MANAGED_EXCEPTION; #endif } @@ -7445,6 +7447,8 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) return EXCEPTION_CONTINUE_SEARCH; } + pExceptionInfo->ContextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; + // WARNING // // We must preserve this so that GCStress=4 eh processing doesnt kill last error. diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 0a8d2df6f5bc33..6cc0b126f7e29c 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -899,15 +899,15 @@ ProcessCLRExceptionNew(IN PEXCEPTION_RECORD pExceptionRecord, else { GCX_COOP(); - FrameWithCookie frameWithCookie; - NativeToManagedExceptionFrame *frame = &frameWithCookie; - #if defined(FEATURE_EH_FUNCLETS) - *frame->GetGSCookiePtr() = GetProcessGSCookie(); - #endif // FEATURE_EH_FUNCLETS - frame->InitAndLink(pContextRecord); + // FrameWithCookie frameWithCookie; + // NativeToManagedExceptionFrame *frame = &frameWithCookie; + // #if defined(FEATURE_EH_FUNCLETS) + // *frame->GetGSCookiePtr() = GetProcessGSCookie(); + // #endif // FEATURE_EH_FUNCLETS + // frame->InitAndLink(pContextRecord); OBJECTREF oref = ExceptionTracker::CreateThrowable(pExceptionRecord, FALSE); - DispatchManagedException(oref); + DispatchManagedException(oref, pContextRecord); } #endif // !HOST_UNIX EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, _T("SEH exception leaked into managed code")); @@ -4930,9 +4930,13 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar { if (g_isNewExceptionHandlingEnabled) { + if (!isHardwareException) + { + RtlCaptureContext(ex.GetContextRecord()); + } GCX_COOP(); OBJECTREF throwable = ExceptionTracker::CreateThrowable(ex.GetExceptionRecord(), FALSE); - DispatchManagedException(throwable); + DispatchManagedException(throwable, ex.GetContextRecord()); } do @@ -5544,7 +5548,7 @@ BOOL HandleHardwareException(PAL_SEHException* ex) #endif // TARGET_UNIX -VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, bool preserveStackTrace) +VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, CONTEXT* pExceptionContext, bool preserveStackTrace) { STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_TRIGGERS; @@ -5554,13 +5558,15 @@ VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, bool preser _ASSERTE(IsException(throwable->GetMethodTable())); + Thread *pThread = GetThread(); + if (preserveStackTrace) { + pThread->IncPreventAbort(); ExceptionPreserveStackTrace(throwable); + pThread->DecPreventAbort(); } - Thread *pThread = GetThread(); - ULONG_PTR hr = GetHRFromThrowable(throwable); EXCEPTION_RECORD exceptionRecord; @@ -5570,10 +5576,7 @@ VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, bool preser exceptionRecord.NumberParameters = MarkAsThrownByUs(exceptionRecord.ExceptionInformation, hr); exceptionRecord.ExceptionRecord = NULL; - CONTEXT exceptionContext; - RtlCaptureContext(&exceptionContext); - - ExInfo exInfo(pThread, &exceptionRecord, &exceptionContext, ExKind::Throw); + ExInfo exInfo(pThread, &exceptionRecord, pExceptionContext, ExKind::Throw); if (pThread->IsAbortInitiated () && IsExceptionOfType(kThreadAbortException,&throwable)) { @@ -5605,6 +5608,28 @@ VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, bool preser UNREACHABLE(); } +VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, bool preserveStackTrace) +{ + STATIC_CONTRACT_THROWS; + STATIC_CONTRACT_GC_TRIGGERS; + STATIC_CONTRACT_MODE_COOPERATIVE; + + CONTEXT exceptionContext; + RtlCaptureContext(&exceptionContext); +// Thread::VirtualUnwindToFirstManagedCallFrame(&exceptionContext); + +// GCX_COOP(); +// FrameWithCookie frameWithCookie; +// NativeToManagedExceptionFrame *frame = &frameWithCookie; +// #if defined(FEATURE_EH_FUNCLETS) +// *frame->GetGSCookiePtr() = GetProcessGSCookie(); +// #endif // FEATURE_EH_FUNCLETS +// frame->InitAndLink(&exceptionContext); + + DispatchManagedException(throwable, &exceptionContext, preserveStackTrace); + UNREACHABLE(); +} + VOID DECLSPEC_NORETURN DispatchManagedException(RuntimeExceptionKind reKind) { STATIC_CONTRACT_THROWS; @@ -8126,6 +8151,62 @@ static void NotifyFunctionEnter(StackFrameIterator *pThis, Thread *pThread, ExIn pExInfo->m_pMDToReportFunctionLeave = pMD; } +static void UnwindPastFrame(REGDISPLAY* pRD, Frame* pFrame) +{ + if (pFrame->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr()) + { + if (InlinedCallFrame::FrameHasActiveCall(pFrame)) + { + InlinedCallFrame* pInlinedCallFrame = (InlinedCallFrame*)pFrame; + while (GetRegdisplaySP(pRD) < (TADDR)pInlinedCallFrame->GetCallSiteSP()) + { +#ifdef TARGET_UNIX + PAL_VirtualUnwind(pRD->pCurrentContext, NULL); + SyncRegDisplayToCurrentContext(pRD); +#else + Thread::VirtualUnwindCallFrame(pRD); +#endif + } + } + } + else + { + while (GetRegdisplaySP(pRD) < (TADDR)pFrame) + { +#ifdef TARGET_UNIX + PAL_VirtualUnwind(pRD->pCurrentContext, NULL); + SyncRegDisplayToCurrentContext(pRD); +#else + Thread::VirtualUnwindCallFrame(pRD); +#endif + } + if ((pFrame->GetFrameAttribs() & Frame::FRAME_ATTR_CAPTURE_DEPTH_2) != 0) + { +#ifdef TARGET_UNIX + PAL_VirtualUnwind(pRD->pCurrentContext, NULL); + SyncRegDisplayToCurrentContext(pRD); +#else + Thread::VirtualUnwindCallFrame(pRD); +#endif + } + } + +#ifdef TARGET_UNIX + pRD->IsCallerContextValid = FALSE; + pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. +#endif + + // EECodeManager::EnsureCallerContextIsValid(pRD, NULL); + // while (GetSP(pRD->pCallerContext) < (TADDR)pFrame) + // { + // // TODO: reuse EEInfo?? + // Thread::VirtualUnwindCallFrame(pRD); + // EECodeManager::EnsureCallerContextIsValid(pRD, NULL); + // } + // TODO: see if we can get rid of this. Maybe adding a reset to cached codeInfo in the stack frame iterator would do + //EECodeManager::EnsureCallerContextIsValid(pRD, NULL); +} + extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalkCtx, bool instructionFault, bool* pfIsExceptionIntercepted) { QCALL_CONTRACT; @@ -8203,6 +8284,9 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk } } } + + UnwindPastFrame(pThis->m_crawl.GetRegisterSet(), pFrame); + StackWalkAction retVal = pThis->Next(); result = (retVal != SWA_FAILED); } @@ -8239,6 +8323,11 @@ static StackWalkAction MoveToNextNonSkippedFrame(StackFrameIterator* pStackFrame do { + if (pStackFrameIterator->GetFrameState() == StackFrameIterator::SFITER_FRAME_FUNCTION || pStackFrameIterator->GetFrameState() == StackFrameIterator::SFITER_SKIPPED_FRAME_FUNCTION) + { + Frame* pFrame = pStackFrameIterator->m_crawl.GetFrame(); + UnwindPastFrame(pStackFrameIterator->m_crawl.GetRegisterSet(), pFrame); + } retVal = pStackFrameIterator->Next(); if (retVal == SWA_FAILED) { @@ -8381,6 +8470,7 @@ extern "C" bool QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollideCla { // Detect collided unwind pFrame = pThis->m_crawl.GetFrame(); + UnwindPastFrame(pThis->m_crawl.GetRegisterSet(), pFrame); if (InlinedCallFrame::FrameHasActiveCall(pFrame)) { diff --git a/src/coreclr/vm/exceptionhandling.h b/src/coreclr/vm/exceptionhandling.h index 74818b9485b6ca..f7277f45cea260 100644 --- a/src/coreclr/vm/exceptionhandling.h +++ b/src/coreclr/vm/exceptionhandling.h @@ -22,6 +22,7 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord, IN OUT PT_CONTEXT pContextRecord, IN OUT PT_DISPATCHER_CONTEXT pDispatcherContext); +VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, CONTEXT *pExceptionContext, bool preserveStackTrace = true); VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, bool preserveStackTrace = true); VOID DECLSPEC_NORETURN DispatchManagedException(RuntimeExceptionKind reKind); diff --git a/src/coreclr/vm/exinfo.cpp b/src/coreclr/vm/exinfo.cpp index 254cd120bd12fb..1a7bca3b134d9a 100644 --- a/src/coreclr/vm/exinfo.cpp +++ b/src/coreclr/vm/exinfo.cpp @@ -331,14 +331,25 @@ ExInfo::ExInfo(Thread *pThread, EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pEx m_StackTraceInfo.AllocateStackTrace(); pThread->GetExceptionState()->m_pCurrentTracker = this; memcpy(&m_exContext, pExceptionContext, sizeof(CONTEXT)); - if (pThread->GetFrame() != FRAME_TOP) - { - Thread::VirtualUnwindToFirstManagedCallFrame(&m_exContext); - } - SetIP(&m_exContext, 0); + // HACK + // if (!(pExceptionContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE)) + // { + // memcpy(&m_exContext, pExceptionContext, sizeof(CONTEXT)); + // } + // else + // { + // m_exContext = {}; + // m_exContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT; + // } + // if (pThread->GetFrame() != FRAME_TOP) + // { + // Thread::VirtualUnwindToFirstManagedCallFrame(&m_exContext); + // } + // SetIP(&m_exContext, 0); // m_exContext.ContextFlags = CONTEXT_FLOATING_POINT; // ClrCaptureContext(&m_exContext); - // m_exContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT; + //m_exContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | (m_exContext.ContextFlags & CONTEXT_EXCEPTION_ACTIVE); + m_exContext.ContextFlags = m_exContext.ContextFlags & (CONTEXT_ALL | CONTEXT_EXCEPTION_ACTIVE); } #if defined(TARGET_UNIX) diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 24157e6c572b1c..b2af0ebcbb6cb0 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -1053,7 +1053,7 @@ class FaultingExceptionFrame : public Frame TADDR m_ReturnAddress; T_CONTEXT m_ctx; #endif // !FEATURE_EH_FUNCLETS - + VPTR_VTABLE_CLASS(FaultingExceptionFrame, Frame) public: @@ -1081,7 +1081,11 @@ class FaultingExceptionFrame : public Frame unsigned GetFrameAttribs() { LIMITED_METHOD_DAC_CONTRACT; +#ifdef FEATURE_EH_FUNCLETS + return FRAME_ATTR_EXCEPTION | (!!(m_ctx.ContextFlags & CONTEXT_EXCEPTION_ACTIVE) ? FRAME_ATTR_FAULTED : 0); +#else return FRAME_ATTR_EXCEPTION | FRAME_ATTR_FAULTED; +#endif } #ifndef FEATURE_EH_FUNCLETS @@ -1108,6 +1112,7 @@ class FaultingExceptionFrame : public Frame LIMITED_METHOD_CONTRACT; return &m_fFilterExecuted; } + #endif // FEATURE_EH_FUNCLETS virtual BOOL NeedsUpdateRegDisplay() diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index d41861f6c3567e..657d9f72f4769f 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -4305,7 +4305,11 @@ void RethrowNew() ExInfo *pActiveExInfo = (ExInfo*)pThread->GetExceptionState()->GetCurrentExceptionTracker(); - ExInfo exInfo(pThread, pActiveExInfo->m_ptrs.ExceptionRecord, pActiveExInfo->m_ptrs.ContextRecord, ExKind::None); + CONTEXT exceptionContext; + RtlCaptureContext(&exceptionContext); + //Thread::VirtualUnwindToFirstManagedCallFrame(&exceptionContext); + + ExInfo exInfo(pThread, pActiveExInfo->m_ptrs.ExceptionRecord, &exceptionContext, ExKind::None); GCPROTECT_BEGIN(exInfo.m_exception); PREPARE_NONVIRTUAL_CALLSITE(METHOD__EH__RH_RETHROW); diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp index 8e93b0c7cbda9d..d736cded2e1051 100644 --- a/src/coreclr/vm/stackwalk.cpp +++ b/src/coreclr/vm/stackwalk.cpp @@ -1234,6 +1234,12 @@ BOOL StackFrameIterator::Init(Thread * pThread, // process the REGDISPLAY and stop at the first frame ProcessIp(GetControlPC(m_crawl.pRD)); +#ifdef FEATURE_EH_FUNCLETS + if (m_crawl.isFrameless && !!(m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE)) + { + m_crawl.hasFaulted = true; + } +#endif // FEATURE_EH_FUNCLETS ProcessCurrentFrame(); // advance to the next frame which matches the stackwalk flags @@ -1401,12 +1407,12 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, } m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD); -#ifdef FEATURE_EH_FUNCLETS - if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) - { - m_crawl.hasFaulted = false; - } -#endif // FEATURE_EH_FUNCLETS +// #ifdef FEATURE_EH_FUNCLETS +// if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) +// { +// m_crawl.hasFaulted = false; +// } +// #endif // FEATURE_EH_FUNCLETS _ASSERTE(curPc == GetControlPC(m_crawl.pRD)); } @@ -2727,12 +2733,12 @@ StackWalkAction StackFrameIterator::NextRaw(void) if (m_crawl.isFrameless) { m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD); -#ifdef FEATURE_EH_FUNCLETS - if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) - { - m_crawl.hasFaulted = false; - } -#endif // FEATURE_EH_FUNCLETS +// #ifdef FEATURE_EH_FUNCLETS +// if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) +// { +// m_crawl.hasFaulted = false; +// } +// #endif // FEATURE_EH_FUNCLETS #if defined(RECORD_RESUMABLE_FRAME_SP) CONSISTENCY_CHECK(NULL == m_pvResumableFrameTargetSP); diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index 84d1ade6037be2..ed6d740f1f9022 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -3973,7 +3973,8 @@ ThrowControlForThread( exceptionRecord.ExceptionFlags = 0; OBJECTREF throwable = ExceptionTracker::CreateThrowable(&exceptionRecord, TRUE); - DispatchManagedException(throwable); + pfef->GetExceptionContext()->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; + DispatchManagedException(throwable, pfef->GetExceptionContext()); } else #endif // FEATURE_EH_FUNCLETS From 98c6fd57d3c715ab3cf04c386a12b4f2816ff494 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 19 Jan 2024 16:07:41 +0000 Subject: [PATCH 03/17] Fix of mdbg tests --- src/coreclr/vm/exceptionhandling.cpp | 9 +++++++-- src/coreclr/vm/exinfo.cpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 6cc0b126f7e29c..f8209ed9cf9704 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -7802,8 +7802,6 @@ extern "C" void QCALLTYPE ResumeAtInterceptionLocation(REGDISPLAY* pvRegDisplay) BOOL fIntercepted = pThread->GetExceptionState()->GetFlags()->DebuggerInterceptInfo(); _ASSERTE(fIntercepted); - ExInfo::PopExInfos(pThread, (void*)targetSp); - // retrieve the interception information MethodDesc *pInterceptMD = NULL; StackFrame sfInterceptStackFrame; @@ -7812,6 +7810,8 @@ extern "C" void QCALLTYPE ResumeAtInterceptionLocation(REGDISPLAY* pvRegDisplay) pThread->GetExceptionState()->GetDebuggerState()->GetDebuggerInterceptInfo(&pInterceptMD, NULL, (PBYTE*)&(sfInterceptStackFrame.SP), &ulRelOffset, NULL); + ExInfo::PopExInfos(pThread, (void*)targetSp); + PCODE pStartAddress = pInterceptMD->GetNativeCode(); EECodeInfo codeInfo(pStartAddress); @@ -8241,6 +8241,11 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk #endif } + while ((pFrame != FRAME_TOP) && (pFrame < (void*)GetSP(pStackwalkCtx))) + { + pFrame = pFrame->PtrNextFrame(); + } + REGDISPLAY* pRD = &pExInfo->m_regDisplay; pThread->FillRegDisplay(pRD, pStackwalkCtx); diff --git a/src/coreclr/vm/exinfo.cpp b/src/coreclr/vm/exinfo.cpp index 1a7bca3b134d9a..da47de68a712cc 100644 --- a/src/coreclr/vm/exinfo.cpp +++ b/src/coreclr/vm/exinfo.cpp @@ -349,7 +349,7 @@ ExInfo::ExInfo(Thread *pThread, EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pEx // m_exContext.ContextFlags = CONTEXT_FLOATING_POINT; // ClrCaptureContext(&m_exContext); //m_exContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | (m_exContext.ContextFlags & CONTEXT_EXCEPTION_ACTIVE); - m_exContext.ContextFlags = m_exContext.ContextFlags & (CONTEXT_ALL | CONTEXT_EXCEPTION_ACTIVE); + m_exContext.ContextFlags = m_exContext.ContextFlags & (CONTEXT_FULL | CONTEXT_EXCEPTION_ACTIVE); } #if defined(TARGET_UNIX) From e1eaae93321eb363f8cbb7e5d2f3269718e51607 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Tue, 23 Jan 2024 20:46:17 +0100 Subject: [PATCH 04/17] Fix the mdbg issue with unhandled exceptions --- src/coreclr/vm/exceptionhandling.cpp | 7 +------ src/coreclr/vm/exinfo.cpp | 18 ------------------ 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index f8209ed9cf9704..3eaf9948ac4043 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -8241,11 +8241,6 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk #endif } - while ((pFrame != FRAME_TOP) && (pFrame < (void*)GetSP(pStackwalkCtx))) - { - pFrame = pFrame->PtrNextFrame(); - } - REGDISPLAY* pRD = &pExInfo->m_regDisplay; pThread->FillRegDisplay(pRD, pStackwalkCtx); @@ -8437,7 +8432,7 @@ extern "C" bool QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollideCla else { #ifdef HOST_WINDOWS - RaiseFailFastException(pTopExInfo->m_ptrs.ExceptionRecord, pTopExInfo->m_ptrs.ContextRecord, 0); + RaiseFailFastException(NULL, NULL, 0); #else CrashDumpAndTerminateProcess(pTopExInfo->m_ExceptionCode); #endif diff --git a/src/coreclr/vm/exinfo.cpp b/src/coreclr/vm/exinfo.cpp index da47de68a712cc..2c7a896d541418 100644 --- a/src/coreclr/vm/exinfo.cpp +++ b/src/coreclr/vm/exinfo.cpp @@ -331,24 +331,6 @@ ExInfo::ExInfo(Thread *pThread, EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pEx m_StackTraceInfo.AllocateStackTrace(); pThread->GetExceptionState()->m_pCurrentTracker = this; memcpy(&m_exContext, pExceptionContext, sizeof(CONTEXT)); - // HACK - // if (!(pExceptionContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE)) - // { - // memcpy(&m_exContext, pExceptionContext, sizeof(CONTEXT)); - // } - // else - // { - // m_exContext = {}; - // m_exContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT; - // } - // if (pThread->GetFrame() != FRAME_TOP) - // { - // Thread::VirtualUnwindToFirstManagedCallFrame(&m_exContext); - // } - // SetIP(&m_exContext, 0); - // m_exContext.ContextFlags = CONTEXT_FLOATING_POINT; - // ClrCaptureContext(&m_exContext); - //m_exContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | (m_exContext.ContextFlags & CONTEXT_EXCEPTION_ACTIVE); m_exContext.ContextFlags = m_exContext.ContextFlags & (CONTEXT_FULL | CONTEXT_EXCEPTION_ACTIVE); } From 72ad82950616cbedd29d46e6a58b1fe1e595d458 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 24 Jan 2024 02:47:29 +0100 Subject: [PATCH 05/17] Fix stack overflow due to the floats unwinding --- src/coreclr/vm/exceptionhandling.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 3eaf9948ac4043..30f81b08de6fbe 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -3567,6 +3567,7 @@ void ExceptionTracker::PopTrackerIfEscaping( } CONTRACTL_END; + _ASSERTE(!g_isNewExceptionHandlingEnabled); Thread* pThread = GetThread(); ThreadExceptionState* pExState = pThread->GetExceptionState(); ExceptionTracker* pTracker = (ExceptionTracker*)pExState->m_pCurrentTracker; @@ -6101,7 +6102,7 @@ void CleanUpForSecondPass(Thread* pThread, bool fIsSO, LPVOID MemoryStackFpForFr // Instead, we rely on the END_SO_TOLERANT_CODE macro to call ClearExceptionStateAfterSO(). Of course, // we may leak in the UMThunkStubCommon() case where we don't have this macro lower on the stack // (stack grows up). - if (!fIsSO) + if (!fIsSO && !g_isNewExceptionHandlingEnabled) { ExceptionTracker::PopTrackerIfEscaping(MemoryStackFp); } @@ -8432,7 +8433,7 @@ extern "C" bool QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollideCla else { #ifdef HOST_WINDOWS - RaiseFailFastException(NULL, NULL, 0); + RaiseFailFastException(pTopExInfo->m_ptrs.ExceptionRecord, NULL, 0); #else CrashDumpAndTerminateProcess(pTopExInfo->m_ExceptionCode); #endif @@ -8507,7 +8508,7 @@ extern "C" bool QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollideCla { retVal = MoveToNextNonSkippedFrame(pThis); } - while ((retVal == SWA_CONTINUE) && pThis->m_crawl.GetRegisterSet()->SP != pPrevExInfo->m_regDisplay.SP); + while ((retVal == SWA_CONTINUE) && !(pThis->GetFrameState() == StackFrameIterator::SFITER_FRAMELESS_METHOD && pThis->m_crawl.GetRegisterSet()->SP == pPrevExInfo->m_regDisplay.SP)); _ASSERTE(retVal != SWA_FAILED); pThis->ResetNextExInfoForSP(pThis->m_crawl.GetRegisterSet()->SP); From 39cf81fb8a8a1b942fd86150e1db9af15f4abb10 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 24 Jan 2024 22:21:25 +0100 Subject: [PATCH 06/17] Fix unhandled exception report in first pass --- src/coreclr/vm/exceptionhandling.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 30f81b08de6fbe..11c35b41c1bbe4 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -8236,7 +8236,7 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk LONG disposition = InternalUnhandledExceptionFilter_Worker((EXCEPTION_POINTERS *)&pExInfo->m_ptrs); #ifdef HOST_WINDOWS CreateCrashDumpIfEnabled(/* fSOException */ FALSE); - RaiseFailFastException(pExInfo->m_ptrs.ExceptionRecord, pExInfo->m_ptrs.ContextRecord, 0); + RaiseFailFastException(pExInfo->m_ptrs.ExceptionRecord, NULL, 0); #else CrashDumpAndTerminateProcess(pExInfo->m_ExceptionCode); #endif From 4c05e526edf6d31d849d41f34d81b995cc4e17ab Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 25 Jan 2024 01:19:33 +0100 Subject: [PATCH 07/17] Move FP updating into the Frame derived classes --- src/coreclr/debug/ee/debugger.inl | 2 +- src/coreclr/vm/amd64/cgenamd64.cpp | 35 +++++++++++++++++++++++----- src/coreclr/vm/arm/stubs.cpp | 35 +++++++++++++++++++++++----- src/coreclr/vm/arm64/stubs.cpp | 35 +++++++++++++++++++++++----- src/coreclr/vm/exceptionhandling.cpp | 4 +++- src/coreclr/vm/frames.cpp | 12 ++++++++++ src/coreclr/vm/frames.h | 30 +++++++++++++----------- src/coreclr/vm/loongarch64/stubs.cpp | 35 +++++++++++++++++++++++----- src/coreclr/vm/riscv64/stubs.cpp | 35 +++++++++++++++++++++++----- src/coreclr/vm/stackwalk.cpp | 6 ++--- src/coreclr/vm/threads.h | 2 ++ 11 files changed, 183 insertions(+), 48 deletions(-) diff --git a/src/coreclr/debug/ee/debugger.inl b/src/coreclr/debug/ee/debugger.inl index 61b44c9466e584..8b7a973f48efff 100644 --- a/src/coreclr/debug/ee/debugger.inl +++ b/src/coreclr/debug/ee/debugger.inl @@ -213,7 +213,7 @@ inline TADDR FuncEvalFrame::GetReturnAddressPtr() // // This updates the register display for a FuncEvalFrame. // -inline void FuncEvalFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +inline void FuncEvalFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { SUPPORTS_DAC; DebuggerEval * pDE = GetDebuggerEval(); diff --git a/src/coreclr/vm/amd64/cgenamd64.cpp b/src/coreclr/vm/amd64/cgenamd64.cpp index 26c22810260668..942bb493b46786 100644 --- a/src/coreclr/vm/amd64/cgenamd64.cpp +++ b/src/coreclr/vm/amd64/cgenamd64.cpp @@ -58,10 +58,18 @@ void ClearRegDisplayArgumentAndScratchRegisters(REGDISPLAY * pRD) pContextPointers->R11 = NULL; } -void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_CONTRACT; +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, GetSP()); + _ASSERTE(pRD->pCurrentContext->Rip == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -76,7 +84,7 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); } -void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { @@ -97,6 +105,13 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) return; } +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, *(DWORD64 *)&m_pCallSiteSP); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -117,7 +132,7 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK InlinedCallFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); } -void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { @@ -129,6 +144,14 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) } CONTRACTL_END; +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, m_MachState.m_Rsp); + _ASSERTE(pRD->pCurrentContext->Rip == m_MachState.m_Rip); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -196,7 +219,7 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) ClearRegDisplayArgumentAndScratchRegisters(pRD); } -void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_DAC_CONTRACT; @@ -233,7 +256,7 @@ TADDR ResumableFrame::GetReturnAddressPtr() return dac_cast(m_Regs) + offsetof(CONTEXT, Rip); } -void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -273,7 +296,7 @@ void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) } // The HijackFrame has to know the registers that are pushed by OnHijackTripThread -void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { NOTHROW; diff --git a/src/coreclr/vm/arm/stubs.cpp b/src/coreclr/vm/arm/stubs.cpp index 771d2440967022..65e5f2ea1ab6d1 100644 --- a/src/coreclr/vm/arm/stubs.cpp +++ b/src/coreclr/vm/arm/stubs.cpp @@ -629,7 +629,7 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, unwoundstate->_isValid = true; } -void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { @@ -640,6 +640,14 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) } CONTRACTL_END; +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, m_MachState._sp); + _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -1500,8 +1508,16 @@ void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegis pRD->pCurrentContextPointers->Lr = NULL; } -void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, GetSP()); + _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -1529,7 +1545,7 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(rip:%p, rsp:%p)\n", pRD->ControlPC, pRD->SP)); } -void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_DAC_CONTRACT; @@ -1555,7 +1571,7 @@ void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. } -void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -1581,6 +1597,13 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) return; } +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, *(DWORD *)&m_pCallSiteSP); + } +#endif // DACCESS_COMPILE + // reset pContext; it's only valid for active (top-most) frame pRD->pContext = NULL; @@ -1613,7 +1636,7 @@ TADDR ResumableFrame::GetReturnAddressPtr(void) return dac_cast(m_Regs) + offsetof(T_CONTEXT, Pc); } -void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -1649,7 +1672,7 @@ void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. } -void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { NOTHROW; diff --git a/src/coreclr/vm/arm64/stubs.cpp b/src/coreclr/vm/arm64/stubs.cpp index cc5dbf7d66b8d5..499fd895f05e7e 100644 --- a/src/coreclr/vm/arm64/stubs.cpp +++ b/src/coreclr/vm/arm64/stubs.cpp @@ -426,7 +426,7 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, unwoundstate->_isValid = TRUE; } -void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { @@ -437,6 +437,14 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) } CONTRACTL_END; +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, m_MachState._sp); + _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -601,8 +609,16 @@ void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegis } -void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, GetSP()); + _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -626,7 +642,7 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) -void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_DAC_CONTRACT; @@ -659,7 +675,7 @@ void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); } -void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -680,6 +696,13 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) return; } +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, *(DWORD64 *)&m_pCallSiteSP); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; @@ -722,7 +745,7 @@ TADDR ResumableFrame::GetReturnAddressPtr(void) return dac_cast(m_Regs) + offsetof(T_CONTEXT, Pc); } -void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -762,7 +785,7 @@ void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) RETURN; } -void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 11c35b41c1bbe4..d1990326d45ffc 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -8154,6 +8154,8 @@ static void NotifyFunctionEnter(StackFrameIterator *pThis, Thread *pThread, ExIn static void UnwindPastFrame(REGDISPLAY* pRD, Frame* pFrame) { + return; + if (pFrame->GetVTablePtr() == InlinedCallFrame::GetMethodFrameVPtr()) { if (InlinedCallFrame::FrameHasActiveCall(pFrame)) @@ -8246,7 +8248,7 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk pThread->FillRegDisplay(pRD, pStackwalkCtx); new (pThis) StackFrameIterator(); - result = pThis->Init(pThread, pFrame, pRD, THREAD_EXECUTING_MANAGED_CODE) != FALSE; + result = pThis->Init(pThread, pFrame, pRD, THREAD_EXECUTING_MANAGED_CODE | UNWIND_FLOATS) != FALSE; if (result && (pExInfo->m_passNumber == 1)) { diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index 90c21e54aa813b..0c1535ffc37cbc 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -464,6 +464,18 @@ void Frame::PopIfChained() } #endif // TARGET_UNIX && !DACCESS_COMPILE +void Frame::UpdateFloatingPointRegisters(const PREGDISPLAY pRD, TADDR targetSP) +{ + while (GetSP(pRD->pCurrentContext) != targetSP) + { +#ifdef TARGET_UNIX + PAL_VirtualUnwind(pRD->pCurrentContext, NULL); +#else + Thread::VirtualUnwindCallFrame(pRD); +#endif + } +} + //----------------------------------------------------------------------- #endif // #ifndef DACCESS_COMPILE //--------------------------------------------------------------- diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index b2af0ebcbb6cb0..647d2227af5ab6 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -513,7 +513,7 @@ class Frame : public FrameBase // UpdateRegDisplay is generally used to fill out the REGDISPLAY parameter, some // overrides (e.g., code:ResumableFrame::UpdateRegDisplay) will actually READ what // you pass in. So be sure to pass in a valid or zeroed out REGDISPLAY. - virtual void UpdateRegDisplay(const PREGDISPLAY) + virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false) { LIMITED_METHOD_DAC_CONTRACT; return; @@ -755,6 +755,10 @@ class Frame : public FrameBase LIMITED_METHOD_CONTRACT; } +#ifndef DACCESS_COMPILE + void UpdateFloatingPointRegisters(const PREGDISPLAY pRD, TADDR targetSP); +#endif // DACCESS_COMPILE + #if defined(TARGET_UNIX) && !defined(DACCESS_COMPILE) virtual ~Frame() { LIMITED_METHOD_CONTRACT; } @@ -796,7 +800,7 @@ class ResumableFrame : public Frame return TRUE; } - virtual void UpdateRegDisplay(const PREGDISPLAY pRD); + virtual void UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats = false); virtual unsigned GetFrameAttribs() { LIMITED_METHOD_DAC_CONTRACT; @@ -1001,7 +1005,7 @@ class TransitionFrame : public Frame return TRUE; } - virtual void UpdateRegDisplay(const PREGDISPLAY); + virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false); #ifdef TARGET_X86 void UpdateRegDisplayHelper(const PREGDISPLAY, UINT cbStackPop); #endif @@ -1120,7 +1124,7 @@ class FaultingExceptionFrame : public Frame return TRUE; } - virtual void UpdateRegDisplay(const PREGDISPLAY); + virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false); // Keep as last entry in class DEFINE_VTABLE_GETTER_AND_DTOR(FaultingExceptionFrame) @@ -1202,7 +1206,7 @@ class FuncEvalFrame : public Frame return TRUE; } - virtual void UpdateRegDisplay(const PREGDISPLAY); + virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false); virtual DebuggerEval * GetDebuggerEval(); @@ -1289,7 +1293,7 @@ class HelperMethodFrame : public Frame return TRUE; } - virtual void UpdateRegDisplay(const PREGDISPLAY); + virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false); virtual Interception GetInterception() { @@ -2063,7 +2067,7 @@ class PInvokeCalliFrame : public FramedMethodFrame } #ifdef TARGET_X86 - virtual void UpdateRegDisplay(const PREGDISPLAY); + virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false); #endif // TARGET_X86 BOOL TraceFrame(Thread *thread, BOOL fromPatch, @@ -2107,7 +2111,7 @@ class HijackFrame : public Frame return TRUE; } - virtual void UpdateRegDisplay(const PREGDISPLAY); + virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false); virtual void GcScanRoots(promote_func *fn, ScanContext* sc); // HijackFrames are created by trip functions. See OnHijackTripThread() @@ -2202,7 +2206,7 @@ class StubDispatchFrame : public FramedMethodFrame PTR_BYTE GetGCRefMap(); #ifdef TARGET_X86 - virtual void UpdateRegDisplay(const PREGDISPLAY pRD); + virtual void UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats = false); virtual PCODE GetReturnAddress(); #endif // TARGET_X86 @@ -2345,7 +2349,7 @@ class ExternalMethodFrame : public FramedMethodFrame Interception GetInterception(); #ifdef TARGET_X86 - virtual void UpdateRegDisplay(const PREGDISPLAY pRD); + virtual void UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats = false); #endif // Keep as last entry in class @@ -2367,7 +2371,7 @@ class DynamicHelperFrame : public FramedMethodFrame virtual void GcScanRoots(promote_func *fn, ScanContext* sc); #ifdef TARGET_X86 - virtual void UpdateRegDisplay(const PREGDISPLAY pRD); + virtual void UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats = false); #endif virtual ETransitionType GetTransitionType() @@ -2894,7 +2898,7 @@ class InlinedCallFrame : public Frame #endif // defined(TARGET_X86) || defined(TARGET_ARM) } - virtual void UpdateRegDisplay(const PREGDISPLAY); + virtual void UpdateRegDisplay(const PREGDISPLAY, bool updateFloats = false); // m_Datum contains MethodDesc ptr or // - on 64 bit host: CALLI target address (if lowest bit is set) @@ -3060,7 +3064,7 @@ class TailCallFrame : public Frame return TRUE; } - virtual void UpdateRegDisplay(const PREGDISPLAY pRD); + virtual void UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats = false); private: // Keep as last entry in class diff --git a/src/coreclr/vm/loongarch64/stubs.cpp b/src/coreclr/vm/loongarch64/stubs.cpp index 5fe3599d0dc507..9f00012812fdc2 100644 --- a/src/coreclr/vm/loongarch64/stubs.cpp +++ b/src/coreclr/vm/loongarch64/stubs.cpp @@ -450,7 +450,7 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, unwoundstate->_isValid = TRUE; } -void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { @@ -461,6 +461,14 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) } CONTRACTL_END; +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, m_MachState._sp); + _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -620,8 +628,16 @@ void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegis pContextPointers->Ra = (PDWORD64)&pCalleeSaved->ra; } -void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, GetSP()); + _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -643,7 +659,7 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); } -void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_DAC_CONTRACT; @@ -676,7 +692,7 @@ void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); } -void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -697,6 +713,13 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) return; } +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, *(DWORD64 *)&m_pCallSiteSP); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; @@ -739,7 +762,7 @@ TADDR ResumableFrame::GetReturnAddressPtr(void) return dac_cast(m_Regs) + offsetof(T_CONTEXT, Pc); } -void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -796,7 +819,7 @@ void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) RETURN; } -void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/riscv64/stubs.cpp b/src/coreclr/vm/riscv64/stubs.cpp index 42c0230509d70c..c37fc5b589e599 100644 --- a/src/coreclr/vm/riscv64/stubs.cpp +++ b/src/coreclr/vm/riscv64/stubs.cpp @@ -344,7 +344,7 @@ void LazyMachState::unwindLazyState(LazyMachState* baseState, unwoundstate->_isValid = TRUE; } -void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { @@ -355,6 +355,14 @@ void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) } CONTRACTL_END; +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, m_MachState._sp); + _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -534,8 +542,16 @@ void UpdateRegDisplayFromCalleeSavedRegisters(REGDISPLAY * pRD, CalleeSavedRegis pContextPointers->Ra = (PDWORD64)&pCalleeSaved->ra; } -void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, GetSP()); + _ASSERTE(pRD->pCurrentContext->Pc == GetReturnAddress()); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; // Don't add usage of this field. This is only temporary. @@ -557,7 +573,7 @@ void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK TransitionFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); } -void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_DAC_CONTRACT; @@ -593,7 +609,7 @@ void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK FaultingExceptionFrame::UpdateRegDisplay(pc:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); } -void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -614,6 +630,13 @@ void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) return; } +#ifndef DACCESS_COMPILE + if (updateFloats) + { + UpdateFloatingPointRegisters(pRD, *(DWORD64 *)&m_pCallSiteSP); + } +#endif // DACCESS_COMPILE + pRD->IsCallerContextValid = FALSE; pRD->IsCallerSPValid = FALSE; @@ -659,7 +682,7 @@ TADDR ResumableFrame::GetReturnAddressPtr(void) return dac_cast(m_Regs) + offsetof(T_CONTEXT, Pc); } -void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -716,7 +739,7 @@ void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) RETURN; } -void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp index d736cded2e1051..14981b1613fa23 100644 --- a/src/coreclr/vm/stackwalk.cpp +++ b/src/coreclr/vm/stackwalk.cpp @@ -1379,7 +1379,7 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, else { // unwind the REGDISPLAY using the transition frame and check the EBP - m_crawl.pFrame->UpdateRegDisplay(&tmpRD); + m_crawl.pFrame->UpdateRegDisplay(&tmpRD, m_flags & UNWIND_FLOATS); if (GetRegdisplayFP(&tmpRD) != curEBP) { break; @@ -1406,7 +1406,7 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, m_crawl.isIPadjusted = false; } - m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD); + m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD, m_flags & UNWIND_FLOATS); // #ifdef FEATURE_EH_FUNCLETS // if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) // { @@ -2732,7 +2732,7 @@ StackWalkAction StackFrameIterator::NextRaw(void) if (m_crawl.isFrameless) { - m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD); + m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD, m_flags & UNWIND_FLOATS); // #ifdef FEATURE_EH_FUNCLETS // if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) // { diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index bfb154b0e539de..ef5ba294a1582f 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -2768,6 +2768,8 @@ class Thread // may still execute GS cookie tracking/checking code paths. #define SKIP_GSCOOKIE_CHECK 0x10000 + #define UNWIND_FLOATS 0x20000 + StackWalkAction StackWalkFramesEx( PREGDISPLAY pRD, // virtual register set at crawl start PSTACKWALKFRAMESCALLBACK pCallback, From 018328bebacad3d2ca160ebcc44acf4bcf7bc393 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 25 Jan 2024 02:47:07 +0100 Subject: [PATCH 08/17] Fix ARM context flags bug --- src/coreclr/pal/src/arch/arm/context2.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/pal/src/arch/arm/context2.S b/src/coreclr/pal/src/arch/arm/context2.S index 32983c196969fb..e292ca26fe2adc 100644 --- a/src/coreclr/pal/src/arch/arm/context2.S +++ b/src/coreclr/pal/src/arch/arm/context2.S @@ -18,9 +18,8 @@ #define CONTEXT_CONTROL 1 // Sp, Lr, Pc, Cpsr #define CONTEXT_INTEGER 2 // R0-R12 -#define CONTEXT_SEGMENTS 4 // -#define CONTEXT_FLOATING_POINT 8 -#define CONTEXT_DEBUG_REGISTERS 16 // +#define CONTEXT_FLOATING_POINT 4 +#define CONTEXT_DEBUG_REGISTERS 8 // #define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) From 8b33658a9bdaee60b5f374a5daf9087efc4c2350 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 25 Jan 2024 17:33:35 +0100 Subject: [PATCH 09/17] Fix InlinedCallFrame GetFunction --- src/coreclr/vm/exceptionhandling.h | 5 +++++ src/coreclr/vm/frames.cpp | 1 + src/coreclr/vm/frames.h | 5 +++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/exceptionhandling.h b/src/coreclr/vm/exceptionhandling.h index f7277f45cea260..7be99adfd2021f 100644 --- a/src/coreclr/vm/exceptionhandling.h +++ b/src/coreclr/vm/exceptionhandling.h @@ -51,8 +51,13 @@ typedef DPTR(ExInfo) PTR_ExInfo; // InlinedCallFrame::m_Datum field for details). enum class InlinedCallFrameMarker { +#ifdef HOST_64BIT ExceptionHandlingHelper = 2, SecondPassFuncletCaller = 4, +#else // HOST_64BIT + ExceptionHandlingHelper = 1, + SecondPassFuncletCaller = 2, +#endif // HOST_64BIT Mask = ExceptionHandlingHelper | SecondPassFuncletCaller }; diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index 0c1535ffc37cbc..6365bf85f939dd 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -466,6 +466,7 @@ void Frame::PopIfChained() void Frame::UpdateFloatingPointRegisters(const PREGDISPLAY pRD, TADDR targetSP) { + _ASSERTE(!ExecutionManager::IsManagedCode(::GetIP(pRD->pCurrentContext))); while (GetSP(pRD->pCurrentContext) != targetSP) { #ifdef TARGET_UNIX diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 647d2227af5ab6..98cbd66f3be121 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -2830,7 +2830,8 @@ class InlinedCallFrame : public Frame { WRAPPER_NO_CONTRACT; if (FrameHasActiveCall(this) && HasFunction()) - return PTR_MethodDesc(m_Datum); + // Mask off marker bits + return PTR_MethodDesc((dac_cast(m_Datum) & ~(sizeof(TADDR) - 1))); else return NULL; } @@ -2841,7 +2842,7 @@ class InlinedCallFrame : public Frame #ifdef HOST_64BIT // See code:GenericPInvokeCalliHelper - return ((m_Datum != NULL) && !(dac_cast(m_Datum) & 0x3)); + return ((m_Datum != NULL) && !(dac_cast(m_Datum) & 0x1)); #else // HOST_64BIT return ((dac_cast(m_Datum) & ~0xffff) != 0); #endif // HOST_64BIT From 7526f17014596db9ebd970b5016a165ea5453686 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 26 Jan 2024 00:32:14 +0100 Subject: [PATCH 10/17] Fix x86 build --- src/coreclr/vm/frames.cpp | 2 ++ src/coreclr/vm/frames.h | 2 ++ src/coreclr/vm/i386/cgenx86.cpp | 22 +++++++++++----------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index 6365bf85f939dd..7eac4fda5a2196 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -464,6 +464,7 @@ void Frame::PopIfChained() } #endif // TARGET_UNIX && !DACCESS_COMPILE +#if !defined(TARGET_X86) || defined(TARGET_UNIX) void Frame::UpdateFloatingPointRegisters(const PREGDISPLAY pRD, TADDR targetSP) { _ASSERTE(!ExecutionManager::IsManagedCode(::GetIP(pRD->pCurrentContext))); @@ -476,6 +477,7 @@ void Frame::UpdateFloatingPointRegisters(const PREGDISPLAY pRD, TADDR targetSP) #endif } } +#endif // !TARGET_X86 || TARGET_UNIX //----------------------------------------------------------------------- #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 98cbd66f3be121..9ccd744efd1636 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -756,7 +756,9 @@ class Frame : public FrameBase } #ifndef DACCESS_COMPILE +#if !defined(TARGET_X86) || defined(TARGET_UNIX) void UpdateFloatingPointRegisters(const PREGDISPLAY pRD, TADDR targetSP); +#endif // !TARGET_X86 || TARGET_UNIX #endif // DACCESS_COMPILE #if defined(TARGET_UNIX) && !defined(DACCESS_COMPILE) diff --git a/src/coreclr/vm/i386/cgenx86.cpp b/src/coreclr/vm/i386/cgenx86.cpp index 496c7c3f34366b..9bbc1046e806a2 100644 --- a/src/coreclr/vm/i386/cgenx86.cpp +++ b/src/coreclr/vm/i386/cgenx86.cpp @@ -139,7 +139,7 @@ void EHContext::UpdateFrame(PREGDISPLAY regs) } #endif // FEATURE_EH_FUNCLETS -void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void TransitionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -211,7 +211,7 @@ void TransitionFrame::UpdateRegDisplayHelper(const PREGDISPLAY pRD, UINT cbStack RETURN; } -void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HelperMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -391,7 +391,7 @@ EXTERN_C MachState* STDCALL HelperMethodFrameConfirmState(HelperMethodFrame* fra } #endif -void ExternalMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void ExternalMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -411,7 +411,7 @@ void ExternalMethodFrame::UpdateRegDisplay(const PREGDISPLAY pRD) } -void StubDispatchFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void StubDispatchFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -468,7 +468,7 @@ PCODE StubDispatchFrame::GetReturnAddress() return retAddress; } -void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -521,7 +521,7 @@ void FaultingExceptionFrame::UpdateRegDisplay(const PREGDISPLAY pRD) RETURN; } -void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void InlinedCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -615,7 +615,7 @@ TADDR ResumableFrame::GetReturnAddressPtr() return dac_cast(m_Regs) + offsetof(CONTEXT, Eip); } -void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -696,7 +696,7 @@ void ResumableFrame::UpdateRegDisplay(const PREGDISPLAY pRD) // The HijackFrame has to know the registers that are pushed by OnHijackTripThread // -> HijackFrame::UpdateRegDisplay should restore all the registers pushed by OnHijackTripThread -void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACTL { NOTHROW; @@ -753,7 +753,7 @@ void HijackFrame::UpdateRegDisplay(const PREGDISPLAY pRD) #endif // FEATURE_HIJACK -void PInvokeCalliFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void PInvokeCalliFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -774,7 +774,7 @@ void PInvokeCalliFrame::UpdateRegDisplay(const PREGDISPLAY pRD) } #ifndef UNIX_X86_ABI -void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { CONTRACT_VOID { @@ -822,7 +822,7 @@ void TailCallFrame::UpdateRegDisplay(const PREGDISPLAY pRD) #endif // !UNIX_X86_ABI #ifdef FEATURE_READYTORUN -void DynamicHelperFrame::UpdateRegDisplay(const PREGDISPLAY pRD) +void DynamicHelperFrame::UpdateRegDisplay(const PREGDISPLAY pRD, bool updateFloats) { WRAPPER_NO_CONTRACT; UpdateRegDisplayHelper(pRD, 0); From 73540eac0b0663303ee35c0470ebd7e9b6ca9398 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Sat, 27 Jan 2024 01:38:40 +0100 Subject: [PATCH 11/17] Fix unwinding of frames The InlinedCallFrame has PC/SP that differs based on whether JIT_PinvokeBegin is used or not and also on stuff pushed on stack between the frame creation and the call. So there is no reliable way to figure out we've unwound to the caller other than detecting managed frame. --- src/coreclr/vm/frames.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index 7eac4fda5a2196..ce6234b8024351 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -468,7 +468,8 @@ void Frame::PopIfChained() void Frame::UpdateFloatingPointRegisters(const PREGDISPLAY pRD, TADDR targetSP) { _ASSERTE(!ExecutionManager::IsManagedCode(::GetIP(pRD->pCurrentContext))); - while (GetSP(pRD->pCurrentContext) != targetSP) + //while (GetSP(pRD->pCurrentContext) != targetSP) + while (!ExecutionManager::IsManagedCode(::GetIP(pRD->pCurrentContext))) { #ifdef TARGET_UNIX PAL_VirtualUnwind(pRD->pCurrentContext, NULL); From 6be56b1864fd34564a149744f48f6b929f5c6892 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Sat, 27 Jan 2024 22:44:40 +0100 Subject: [PATCH 12/17] Modify unhandled exception processing to work with host tests --- src/coreclr/vm/exceptionhandling.cpp | 63 ++++++++++++++++++---------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index d1990326d45ffc..d698a9b8fbe389 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -866,6 +866,24 @@ UINT_PTR ExceptionTracker::FinishSecondPass( void CleanUpForSecondPass(Thread* pThread, bool fIsSO, LPVOID MemoryStackFpForFrameChain, LPVOID MemoryStackFp); +static void PopExplicitFrames(Thread *pThread, void *targetSp) +{ + Frame* pFrame = pThread->GetFrame(); + while (pFrame < targetSp) + { + pFrame->ExceptionUnwind(); + pFrame->Pop(pThread); + pFrame = pThread->GetFrame(); + } + + GCFrame* pGCFrame = pThread->GetGCFrame(); + while (pGCFrame && pGCFrame < targetSp) + { + pGCFrame->Pop(); + pGCFrame = pThread->GetGCFrame(); + } +} + EXTERN_C EXCEPTION_DISPOSITION ProcessCLRExceptionNew(IN PEXCEPTION_RECORD pExceptionRecord, IN PVOID pEstablisherFrame, @@ -881,6 +899,19 @@ ProcessCLRExceptionNew(IN PEXCEPTION_RECORD pExceptionRecord, STATIC_CONTRACT_GC_TRIGGERS; STATIC_CONTRACT_THROWS; + Thread* pThread = GetThread(); + + if (pThread->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException)) + { + if ((pExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)) + { + GCX_COOP(); + PopExplicitFrames(pThread, (void*)GetSP(pContextRecord)); + ExInfo::PopExInfos(pThread, (void*)GetSP(pContextRecord)); + } + return ExceptionContinueSearch; + } + #ifndef HOST_UNIX if (!(pExceptionRecord->ExceptionFlags & EXCEPTION_UNWINDING)) { @@ -890,7 +921,6 @@ ProcessCLRExceptionNew(IN PEXCEPTION_RECORD pExceptionRecord, EEPOLICY_HANDLE_FATAL_ERROR(pExceptionRecord->ExceptionCode); } - Thread* pThread = GetThread(); ClrUnwindEx(pExceptionRecord, (UINT_PTR)pThread, INVALID_RESUME_ADDRESS, @@ -931,8 +961,8 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord, if (g_isNewExceptionHandlingEnabled) { - ProcessCLRExceptionNew(pExceptionRecord, pEstablisherFrame, pContextRecord, pDispatcherContext); - UNREACHABLE(); + return ProcessCLRExceptionNew(pExceptionRecord, pEstablisherFrame, pContextRecord, pDispatcherContext); + //UNREACHABLE(); } // We must preserve this so that GCStress=4 eh processing doesnt kill last error. @@ -3616,6 +3646,11 @@ void ExceptionTracker::PopTrackers( } CONTRACTL_END; + if (g_isNewExceptionHandlingEnabled) + { + return; + } + Thread* pThread = GetThreadNULLOk(); ExceptionTracker* pTracker = (pThread ? (ExceptionTracker*)pThread->GetExceptionState()->m_pCurrentTracker : NULL); @@ -7545,24 +7580,6 @@ extern "C" void QCALLTYPE AppendExceptionStackFrame(QCall::ObjectHandleOnStack e END_QCALL; } -static void PopExplicitFrames(Thread *pThread, void *targetSp) -{ - Frame* pFrame = pThread->GetFrame(); - while (pFrame < targetSp) - { - pFrame->ExceptionUnwind(); - pFrame->Pop(pThread); - pFrame = pThread->GetFrame(); - } - - GCFrame* pGCFrame = pThread->GetGCFrame(); - while (pGCFrame && pGCFrame < targetSp) - { - pGCFrame->Pop(); - pGCFrame = pThread->GetGCFrame(); - } -} - UINT_PTR GetEstablisherFrame(REGDISPLAY* pvRegDisplay, ExInfo* exInfo) { #ifdef HOST_AMD64 @@ -8435,7 +8452,9 @@ extern "C" bool QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollideCla else { #ifdef HOST_WINDOWS - RaiseFailFastException(pTopExInfo->m_ptrs.ExceptionRecord, NULL, 0); + //RaiseFailFastException(pTopExInfo->m_ptrs.ExceptionRecord, NULL, 0); + GetThread()->SetThreadStateNC(Thread::TSNC_ProcessedUnhandledException); + RaiseException(pTopExInfo->m_ExceptionCode, EXCEPTION_NONCONTINUABLE_EXCEPTION, pTopExInfo->m_ptrs.ExceptionRecord->NumberParameters, pTopExInfo->m_ptrs.ExceptionRecord->ExceptionInformation); #else CrashDumpAndTerminateProcess(pTopExInfo->m_ExceptionCode); #endif From 75f7b216020d169d13eadbfc3fb674d327753f6a Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 29 Jan 2024 20:07:31 +0100 Subject: [PATCH 13/17] Fix offset adjustment for thumb --- src/coreclr/vm/debugdebugger.cpp | 2 +- src/coreclr/vm/excep.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/debugdebugger.cpp b/src/coreclr/vm/debugdebugger.cpp index fc6e7a5019e725..bb5bed368de9fe 100644 --- a/src/coreclr/vm/debugdebugger.cpp +++ b/src/coreclr/vm/debugdebugger.cpp @@ -1245,7 +1245,7 @@ void DebugStackTrace::DebugStackTraceElement::InitPass2() bRes = g_pDebugInterface->GetILOffsetFromNative( pFunc, (LPCBYTE)this->ip, - fAdjustOffset ? this->dwOffset - 1 : this->dwOffset, + fAdjustOffset ? this->dwOffset - STACKWALK_CONTROLPC_ADJUST_OFFSET : this->dwOffset, &this->dwILOffset); } diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index b684180a152f7b..c0001e50dc7047 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -3383,7 +3383,7 @@ BOOL StackTraceInfo::AppendElement(BOOL bAllowAllocMem, UINT_PTR currentIP, UINT } else if (!pCf->HasFaulted() && pStackTraceElem->ip != 0) { - pStackTraceElem->ip -= 1; + pStackTraceElem->ip -= STACKWALK_CONTROLPC_ADJUST_OFFSET; pStackTraceElem->flags |= STEF_IP_ADJUSTED; } From 373564a887a8bc71be53b0ef8c174a5e11e61ebd Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 1 Feb 2024 01:20:23 +0100 Subject: [PATCH 14/17] Revert libunwind 1.8 commit that introduced a race --- .../libunwind/src/mi/Gaddress_validator.c | 231 ++++++++++-------- 1 file changed, 125 insertions(+), 106 deletions(-) diff --git a/src/native/external/libunwind/src/mi/Gaddress_validator.c b/src/native/external/libunwind/src/mi/Gaddress_validator.c index aaf5a0941214fa..257d1dca93ea8c 100644 --- a/src/native/external/libunwind/src/mi/Gaddress_validator.c +++ b/src/native/external/libunwind/src/mi/Gaddress_validator.c @@ -24,7 +24,6 @@ */ #include "libunwind_i.h" - #ifdef UNW_REMOTE_ONLY bool unw_address_is_valid(UNUSED unw_word_t addr, UNUSED size_t len) @@ -35,17 +34,19 @@ unw_address_is_valid(UNUSED unw_word_t addr, UNUSED size_t len) #else /* !UNW_REMOTE_ONLY */ -#include +static pthread_once_t _unw_address_validator_init_once = PTHREAD_ONCE_INIT; +static sig_atomic_t _unw_address_validator_initialized = 0; +static int _mem_validate_pipe[2] = {-1, -1}; +static bool (*_mem_validate_func) (unw_word_t, size_t); +#pragma weak pthread_once -static atomic_flag _unw_address_validator_initialized = ATOMIC_FLAG_INIT; -static int _mem_validate_pipe[2] = {-1, -1}; #ifdef HAVE_PIPE2 -static int +static void _do_pipe2 (int pipefd[2]) { - return pipe2 (pipefd, O_CLOEXEC | O_NONBLOCK); + int result UNUSED = pipe2 (pipefd, O_CLOEXEC | O_NONBLOCK); } #else static void @@ -53,80 +54,54 @@ _set_pipe_flags (int fd) { int fd_flags = fcntl (fd, F_GETFD, 0); int status_flags = fcntl (fd, F_GETFL, 0); - fd_flags |= FD_CLOEXEC; fcntl (fd, F_SETFD, fd_flags); - status_flags |= O_NONBLOCK; fcntl (fd, F_SETFL, status_flags); } - -static int +static void _do_pipe2 (int pipefd[2]) { - if (pipe (pipefd) < 0) - { - return -1; - } + pipe (pipefd); _set_pipe_flags(pipefd[0]); _set_pipe_flags(pipefd[1]); } #endif - - -static int +static void _open_pipe (void) { if (_mem_validate_pipe[0] != -1) close (_mem_validate_pipe[0]); if (_mem_validate_pipe[1] != -1) close (_mem_validate_pipe[1]); - - return _do_pipe2 (_mem_validate_pipe); + _do_pipe2 (_mem_validate_pipe); } - - /** * Test is a memory address is valid by trying to write from it * @param[in] addr The address to validate * - * @returns true if the memory address is valid (readable), false otherwise. + * @returns true of the memory address is valid (readable), false otherwise. * * This check works by using the address as a (one-byte) buffer in a * write-to-pipe operation. The write will fail if the memory is not in the - * process's address space and marked as readable. The read will force the page - * to be swapped in if it's not already there. + * process's address space and marked as readable. */ static bool _write_validate (unw_word_t addr) { int ret = -1; ssize_t bytes = 0; - - if (unlikely (!atomic_flag_test_and_set(&_unw_address_validator_initialized))) - { - if (_open_pipe () != 0) - { - return false; - } - } - do { char buf; bytes = read (_mem_validate_pipe[0], &buf, 1); } while ( errno == EINTR ); - if (!(bytes > 0 || errno == EAGAIN || errno == EWOULDBLOCK)) { // re-open closed pipe - if (_open_pipe () != 0) - { - return false; - } + _open_pipe (); } - do { #ifdef HAVE_SYS_SYSCALL_H @@ -137,11 +112,71 @@ _write_validate (unw_word_t addr) #endif } while ( errno == EINTR ); - return ret > 0; } +static bool +_msync_validate (unw_word_t addr, size_t len) +{ + if (msync ( (void *)unw_page_start (addr), len, MS_ASYNC) != 0) + { + return false; + } + + return _write_validate (addr); +} + + +#ifdef HAVE_MINCORE +static bool +_mincore_validate (unw_word_t addr, size_t len) +{ + unsigned char mvec[2]; /* Unaligned access may cross page boundary */ + + /* mincore could fail with EAGAIN but we conservatively return false + instead of looping. */ + if (mincore ((void *)unw_page_start (addr), len, mvec) != 0) + { + return false; + } + + return _write_validate (addr); +} +#endif + + +static void +_unw_address_validator_init(void) +{ + _open_pipe (); + + /* Work out dynamically what memory validation function to use. */ +#ifdef HAVE_MINCORE + unsigned char present = 1; + size_t len = unw_page_size; + unw_word_t addr = unw_page_start((unw_word_t)&present); + unsigned char mvec[1]; + int ret; + do + { + ret = mincore ((void*)addr, len, mvec); + } + while (ret == -1 && errno == EAGAIN); + if (ret == 0) + { + Debug(1, "using mincore to validate memory\n"); + _mem_validate_func = _mincore_validate; + } + else +#endif + { + Debug(1, "using msync to validate memory\n"); + _mem_validate_func = _msync_validate; + } + _unw_address_validator_initialized = ~0; +} + /* Cache of already validated addresses */ enum { NLGA = 4 }; @@ -149,99 +184,90 @@ enum { NLGA = 4 }; // thread-local variant static _Thread_local unw_word_t last_good_addr[NLGA]; static _Thread_local int lga_victim; - - static bool -_is_cached_valid_mem(unw_word_t page_addr) +_is_cached_valid_mem(unw_word_t addr) { + addr = unw_page_start (addr); int i; for (i = 0; i < NLGA; i++) { - if (page_addr == last_good_addr[i]) + if (addr == last_good_addr[i]) return true; } return false; } - - static void -_cache_valid_mem(unw_word_t page_addr) +_cache_valid_mem(unw_word_t addr) { + addr = unw_page_start (addr); int i, victim; victim = lga_victim; for (i = 0; i < NLGA; i++) { if (last_good_addr[victim] == 0) { - last_good_addr[victim] = page_addr; + last_good_addr[victim] = addr; return; } victim = (victim + 1) % NLGA; } - /* All slots full. Evict the victim. */ - last_good_addr[victim] = page_addr; + last_good_addr[victim] = addr; victim = (victim + 1) % NLGA; lga_victim = victim; } - #else // global, thread safe variant static _Atomic unw_word_t last_good_addr[NLGA]; static _Atomic int lga_victim; - - static bool -_is_cached_valid_mem(unw_word_t page_addr) +_is_cached_valid_mem(unw_word_t addr) { int i; + addr = unw_page_start (addr); for (i = 0; i < NLGA; i++) { - if (page_addr == atomic_load(&last_good_addr[i])) + if (addr == atomic_load(&last_good_addr[i])) return true; } return false; } - - /** * Adds a known-valid page address to the cache. * * This implementation is racy as all get-out but the worst case is that cached * address get lost, forcing extra unnecessary validation checks. All of the - * atomic operations don't matter because of TOCTOU races. + * atomic operatrions don't matter because of TOCTOU races. */ static void -_cache_valid_mem(unw_word_t page_addr) +_cache_valid_mem(unw_word_t addr) { + int i, victim; + victim = atomic_load(&lga_victim); unw_word_t zero = 0; - int victim = atomic_load(&lga_victim); - for (int i = 0; i < NLGA; i++) + addr = unw_page_start (addr); + for (i = 0; i < NLGA; i++) { - if (atomic_compare_exchange_strong(&last_good_addr[victim], &zero, page_addr)) + if (atomic_compare_exchange_strong(&last_good_addr[victim], &zero, addr)) { return; } victim = (victim + 1) % NLGA; } - /* All slots full. Evict the victim. */ - atomic_store(&last_good_addr[victim], page_addr); + atomic_store(&last_good_addr[victim], addr); victim = (victim + 1) % NLGA; atomic_store(&lga_victim, victim); } #endif - - /** * Validate an address is readable - * @param[in] addr The (starting) address of the memory range to validate - * @param[in] len The size of the memory range to validate in bytes + * @param[in] addr The (starting) address of the memory to validate + * @param[in] len The size of the memory to validate in bytes * - * Validates the memory range from @p addr to (@p addr + @p len - 1) is - * readable. Since the granularity of memory readability is the page, only one - * byte needs to be validated per page for each page starting at @p addr and - * encompassing @p len bytes. Only the first address of each page is checked. + * Validates the memory at address @p addr is readable. Since the granularity of + * memory readability is the page, only one byte needs to be validated per page + * for each page starting at @p addr and encompassing @p len bytes. * * @returns true if the memory is readable, false otherwise. */ @@ -250,53 +276,46 @@ unw_address_is_valid(unw_word_t addr, size_t len) { if (len == 0) return true; - - /* - * Find the starting address of the page containing the start of the range. - */ - unw_word_t start_page_addr = unw_page_start (addr); - - /* - * Bounds check on bottom of memory: first page is always deemed inaccessible. - * This is potentially incorrect on an embedded system, especially one running - * on bare metal with no VMM, but the check has always been here and no one - * has complained. - */ - if (start_page_addr == 0) - return false; - - /* - * Bounds check on top of memory. Unsigned wraparound could be hazardous. - */ - if (addr > (UNW_WORD_MAX - len - unw_page_size)) + if (unw_page_start (addr) == 0) return false; /* - * Find the starting address of the page containing the end of the range. + * First time through initialize everything: once case if linked with pthreads + * and another when pthreads are not linked (which assumes the single-threaded + * case). + * + * There is a potential race condition in the second case if multiple signals + * are raised at exactly the same time but the worst case is that several + * unnecessary validations get done. */ - unw_word_t end_page_addr = unw_page_start (addr + (len - 1)) + unw_page_size; + if (likely (pthread_once != NULL)) + { + pthread_once (&_unw_address_validator_init_once, _unw_address_validator_init); + } + else if (unlikely (_unw_address_validator_initialized == 0)) + { + _unw_address_validator_init(); + } - /* - * Step through each page and check if the first address in each is readable. - * The first non-readable page encountered means none of them in the given - * range can be considered readable. - */ - for (unw_word_t page_addr = start_page_addr; - page_addr < end_page_addr; - page_addr += unw_page_size) + unw_word_t lastbyte = addr + (len - 1); // highest addressed byte of data to access + while (1) { - if (!_is_cached_valid_mem(page_addr)) + if (!_is_cached_valid_mem(addr)) { - if (!_write_validate (page_addr)) + if (!_mem_validate_func (addr, len)) { Debug(1, "returning false\n"); return false; } - _cache_valid_mem(page_addr); + _cache_valid_mem(addr); } + // If we're still on the same page, we're done. + size_t stride = len-1 < (size_t) unw_page_size ? len-1 : (size_t) unw_page_size; + len -= stride; + addr += stride; + if (unw_page_start (addr) == unw_page_start (lastbyte)) + break; } - return true; } - #endif /* !UNW_REMOTE_ONLY */ From 2cd44c256f236e513e72944b25d8d6627efe1eae Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 1 Feb 2024 22:50:23 +0100 Subject: [PATCH 15/17] Fix wrapped exception handling The handling was backwards - we were first checking the wrapped exception and then the unwrapped when matching handler type and the exception type. But we should not try to match the wrapped ones if the module doesn't have the flag set to handle wrapped exceptions. --- .../src/System/Runtime/ExceptionHandling.cs | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index c29e68d1c050a8..c8d9a0a74c2645 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -1084,27 +1084,21 @@ private static bool ShouldTypedClauseCatchThisException(object exception, Method return TypeCast.IsInstanceOfException(pClauseType, exception); #else - bool retry = false; - do + if (tryUnwrapException && exception is RuntimeWrappedException ex) { - MethodTable* mt = RuntimeHelpers.GetMethodTable(exception); - while (mt != null) - { - if (pClauseType == mt) - { - return true; - } - - mt = mt->ParentMethodTable; - } + exception = ex.WrappedException; + } - if (tryUnwrapException && exception is RuntimeWrappedException ex) + MethodTable* mt = RuntimeHelpers.GetMethodTable(exception); + while (mt != null) + { + if (pClauseType == mt) { - exception = ex.WrappedException; - retry = true; + return true; } + + mt = mt->ParentMethodTable; } - while (retry); return false; #endif From 421922d5cadbe3d2cd0d0add55c0dd5bd4c361fe Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 2 Feb 2024 01:15:33 +0100 Subject: [PATCH 16/17] Attempt to fix Win7 x86 crash And a bit of cleanup --- src/coreclr/vm/excep.cpp | 3 ++- src/coreclr/vm/stackwalk.cpp | 12 ------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/coreclr/vm/excep.cpp b/src/coreclr/vm/excep.cpp index c0001e50dc7047..e723e087d57f4c 100644 --- a/src/coreclr/vm/excep.cpp +++ b/src/coreclr/vm/excep.cpp @@ -6563,7 +6563,6 @@ void HandleManagedFaultNew(EXCEPTION_RECORD* pExceptionRecord, CONTEXT* pContext #if defined(FEATURE_EH_FUNCLETS) *frame->GetGSCookiePtr() = GetProcessGSCookie(); #endif // FEATURE_EH_FUNCLETS - //pContext->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; frame->InitAndLink(pContext); Thread *pThread = GetThread(); @@ -7447,7 +7446,9 @@ LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo) return EXCEPTION_CONTINUE_SEARCH; } +#ifdef FEATURE_EH_FUNCLETS pExceptionInfo->ContextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE; +#endif // FEATURE_EH_FUNCLETS // WARNING // diff --git a/src/coreclr/vm/stackwalk.cpp b/src/coreclr/vm/stackwalk.cpp index 14981b1613fa23..cd971db4236f28 100644 --- a/src/coreclr/vm/stackwalk.cpp +++ b/src/coreclr/vm/stackwalk.cpp @@ -1407,12 +1407,6 @@ BOOL StackFrameIterator::ResetRegDisp(PREGDISPLAY pRegDisp, } m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD, m_flags & UNWIND_FLOATS); -// #ifdef FEATURE_EH_FUNCLETS -// if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) -// { -// m_crawl.hasFaulted = false; -// } -// #endif // FEATURE_EH_FUNCLETS _ASSERTE(curPc == GetControlPC(m_crawl.pRD)); } @@ -2733,12 +2727,6 @@ StackWalkAction StackFrameIterator::NextRaw(void) if (m_crawl.isFrameless) { m_crawl.pFrame->UpdateRegDisplay(m_crawl.pRD, m_flags & UNWIND_FLOATS); -// #ifdef FEATURE_EH_FUNCLETS -// if ((m_crawl.pRD->pCurrentContext->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) == 0) -// { -// m_crawl.hasFaulted = false; -// } -// #endif // FEATURE_EH_FUNCLETS #if defined(RECORD_RESUMABLE_FRAME_SP) CONSISTENCY_CHECK(NULL == m_pvResumableFrameTargetSP); From c53ef58a75dfb6d85082d9ceba0e1effd7ce3d6d Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 12 Feb 2024 10:44:57 +0100 Subject: [PATCH 17/17] Fix GC hole in hardware exception handling --- src/coreclr/vm/exinfo.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/coreclr/vm/exinfo.cpp b/src/coreclr/vm/exinfo.cpp index 2c7a896d541418..4ee3b03345452e 100644 --- a/src/coreclr/vm/exinfo.cpp +++ b/src/coreclr/vm/exinfo.cpp @@ -332,6 +332,11 @@ ExInfo::ExInfo(Thread *pThread, EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pEx pThread->GetExceptionState()->m_pCurrentTracker = this; memcpy(&m_exContext, pExceptionContext, sizeof(CONTEXT)); m_exContext.ContextFlags = m_exContext.ContextFlags & (CONTEXT_FULL | CONTEXT_EXCEPTION_ACTIVE); + if (exceptionKind == ExKind::HardwareFault) + { + // Hardware exception handling needs to start on the FaultingExceptionFrame + SetIP(&m_exContext, 0); + } } #if defined(TARGET_UNIX)