diff --git a/src/coreclr/pal/inc/unixasmmacrosarm64.inc b/src/coreclr/pal/inc/unixasmmacrosarm64.inc index 8b3c5803b7d71..976cc825f2eb4 100644 --- a/src/coreclr/pal/inc/unixasmmacrosarm64.inc +++ b/src/coreclr/pal/inc/unixasmmacrosarm64.inc @@ -359,3 +359,20 @@ $__RedirectionStubEndFuncName #endif .endm + +//----------------------------------------------------------------------------- +// Macro used to check (in debug builds only) whether the stack is 16-bytes aligned (a requirement before calling +// out into C++/OS code). Invoke this directly after your prolog (if the stack frame size is fixed) or directly +// before a call (if you have a frame pointer and a dynamic stack). A breakpoint will be invoked if the stack +// is misaligned. +// +.macro CHECK_STACK_ALIGNMENT + +#ifdef _DEBUG + add x9, sp, xzr + tst x9, #15 + beq 0f + EMIT_BREAKPOINT +0: +#endif +.endm diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 1756d35a86b21..16ae71c162a47 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -704,6 +704,7 @@ else(CLR_CMAKE_TARGET_WIN32) ${ARCH_SOURCES_DIR}/jithelpers_singleappdomain.S ${ARCH_SOURCES_DIR}/jithelpers_slow.S ${ARCH_SOURCES_DIR}/pinvokestubs.S + ${ARCH_SOURCES_DIR}/redirectedhandledjitcase.S ${ARCH_SOURCES_DIR}/theprestubamd64.S ${ARCH_SOURCES_DIR}/thunktemplates.S ${ARCH_SOURCES_DIR}/unixasmhelpers.S diff --git a/src/coreclr/vm/amd64/redirectedhandledjitcase.S b/src/coreclr/vm/amd64/redirectedhandledjitcase.S new file mode 100644 index 0000000000000..23de3d6fee93c --- /dev/null +++ b/src/coreclr/vm/amd64/redirectedhandledjitcase.S @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.intel_syntax noprefix +#include "unixasmmacros.inc" +#include "asmconstants.h" + +#define FaultingExceptionFrame_StackAlloc (SIZEOF__GSCookie + SIZEOF__FaultingExceptionFrame) +#define FaultingExceptionFrame_FrameOffset SIZEOF__GSCookie +#define OFFSET_OF_FRAME (8 + SIZEOF_GSCookie) + +.macro GenerateRedirectedStubWithFrame stub, target + + // + // This is the primary function to which execution will be redirected to. + // + NESTED_ENTRY \stub, _TEXT, NoHandler + + // + // IN: rdi: original IP before redirect + // rsi: Rip from the Thread::GetAbortContext() + // + + mov rdx, rsp + + // This push of the return address must not be recorded in the unwind + // info. After this push, unwinding will work. + push rdi + + test rsp, 0x0f + jnz C_FUNC(\stub\()_FixRsp) + +LOCAL_LABEL(\stub\()_RspAligned): + + // Any stack operations hereafter must be recorded in the unwind info, but + // only nonvolatile register locations are needed. Anything else is only + // a "sub rsp, 8" to the unwinder. + + alloc_stack OFFSET_OF_FRAME + SIZEOF__FaultingExceptionFrame + + END_PROLOGUE + + lea rdi, [rsp + OFFSET_OF_FRAME] + + mov dword ptr [rdi], 0 // Initialize vtbl (it is not strictly necessary) + mov dword ptr [rdi + OFFSETOF__FaultingExceptionFrame__m_fFilterExecuted], 0 // Initialize BOOL for personality routine + + call C_FUNC(\target) + + // Target should not return. + int 3 + + NESTED_END \stub, _TEXT + +// This function is used by the stub above to adjust the stack alignment. The +// stub can't conditionally push something on the stack because the unwind +// encodings have no way to express that. +// +// CONSIDER: we could move the frame pointer above the FaultingExceptionFrame, +// and detect the misalignment adjustment in +// GetFrameFromRedirectedStubStackFrame. This is probably less code and more +// straightforward. +LEAF_ENTRY \stub\()_FixRsp, _TEXT + + call LOCAL_LABEL(\stub\()_RspAligned) + + // Target should not return. + int 3 + +LEAF_END \stub\()_FixRsp, _TEXT + +.endm + +REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE = 8 + +NESTED_ENTRY RedirectForThrowControl2, _TEXT, NoHandler + + // On entry + // rdi -> FaultingExceptionFrame + // rsi -> Rip from the Thread::GetAbortContext() + // rdx -> Original RSP + + push_register rax // Align stack + + END_PROLOGUE + + mov [rdx - 8], rsi // Set return address slot to the Rip from the Thread::GetAbortContext() + + call C_FUNC(ThrowControlForThread) + + // ThrowControlForThread doesn't return. + int 3 + +NESTED_END RedirectForThrowControl2, _TEXT + +GenerateRedirectedStubWithFrame RedirectForThrowControl, RedirectForThrowControl2 diff --git a/src/coreclr/vm/amd64/unixstubs.cpp b/src/coreclr/vm/amd64/unixstubs.cpp index e818594f6aa51..0edb1aef92cc3 100644 --- a/src/coreclr/vm/amd64/unixstubs.cpp +++ b/src/coreclr/vm/amd64/unixstubs.cpp @@ -5,11 +5,6 @@ extern "C" { - void RedirectForThrowControl() - { - PORTABILITY_ASSERT("Implement for PAL"); - } - void STDMETHODCALLTYPE JIT_ProfilerEnterLeaveTailcallStub(UINT_PTR ProfilerHandle) { } diff --git a/src/coreclr/vm/arm/ehhelpers.S b/src/coreclr/vm/arm/ehhelpers.S index df6892cdc90d1..6f44931ebe2be 100644 --- a/src/coreclr/vm/arm/ehhelpers.S +++ b/src/coreclr/vm/arm/ehhelpers.S @@ -67,6 +67,31 @@ OFFSET_OF_FRAME=(4 + SIZEOF__GSCookie) .endm +// ------------------------------------------------------------------ +// +// Helpers for ThreadAbort exceptions +// + + NESTED_ENTRY RedirectForThreadAbort2, _TEXT, NoHandler + PROLOG_PUSH "{r7, lr}" + + // stack must be 8 byte aligned + CHECK_STACK_ALIGNMENT + + // On entry: + // + // r0 = address of FaultingExceptionFrame + // + // Invoke the helper to setup the FaultingExceptionFrame and raise the exception + bl C_FUNC(ThrowControlForThread) + + // ThrowControlForThread doesn't return. + EMIT_BREAKPOINT + + NESTED_END RedirectForThreadAbort2, _TEXT + +GenerateRedirectedStubWithFrame RedirectForThreadAbort, RedirectForThreadAbort2 + // ------------------------------------------------------------------ // This helper enables us to call into a funclet after applying the non-volatiles diff --git a/src/coreclr/vm/arm/unixstubs.cpp b/src/coreclr/vm/arm/unixstubs.cpp index 9b313f8475f68..878d5b003686b 100644 --- a/src/coreclr/vm/arm/unixstubs.cpp +++ b/src/coreclr/vm/arm/unixstubs.cpp @@ -2,16 +2,3 @@ // The .NET Foundation licenses this file to you under the MIT license. #include "common.h" - -extern "C" -{ - void RedirectForThrowControl() - { - PORTABILITY_ASSERT("Implement for PAL"); - } - - void RedirectForThreadAbort() - { - PORTABILITY_ASSERT("Implement for PAL"); - } -}; diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index cbe14485e8df4..cdbe24ec427a9 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -697,6 +697,30 @@ NESTED_END CallEHFilterFunclet, _TEXT .endm +// ------------------------------------------------------------------ +// +// Helpers for ThreadAbort exceptions +// + + NESTED_ENTRY RedirectForThreadAbort2, _TEXT, NoHandler + PROLOG_SAVE_REG_PAIR_INDEXED fp,lr, -16 + + // stack must be 16 byte aligned + CHECK_STACK_ALIGNMENT + + // On entry: + // + // x0 = address of FaultingExceptionFrame + // + // Invoke the helper to setup the FaultingExceptionFrame and raise the exception + bl C_FUNC(ThrowControlForThread) + + // ThrowControlForThread doesn't return. + EMIT_BREAKPOINT + + NESTED_END RedirectForThreadAbort2, _TEXT + +GenerateRedirectedStubWithFrame RedirectForThreadAbort, RedirectForThreadAbort2 // ------------------------------------------------------------------ // ResolveWorkerChainLookupAsmStub diff --git a/src/coreclr/vm/arm64/unixstubs.cpp b/src/coreclr/vm/arm64/unixstubs.cpp index 9b313f8475f68..878d5b003686b 100644 --- a/src/coreclr/vm/arm64/unixstubs.cpp +++ b/src/coreclr/vm/arm64/unixstubs.cpp @@ -2,16 +2,3 @@ // The .NET Foundation licenses this file to you under the MIT license. #include "common.h" - -extern "C" -{ - void RedirectForThrowControl() - { - PORTABILITY_ASSERT("Implement for PAL"); - } - - void RedirectForThreadAbort() - { - PORTABILITY_ASSERT("Implement for PAL"); - } -}; diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 79daadcb1b7a9..3fa96490a2e60 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -800,7 +800,7 @@ UINT_PTR ExceptionTracker::FinishSecondPass( { CopyOSContext(pThread->m_OSContext, pContextRecord); SetIP(pThread->m_OSContext, (PCODE)uResumePC); -#ifdef TARGET_UNIX +#if defined(TARGET_UNIX) && !(defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM)) uAbortAddr = NULL; #else uAbortAddr = (UINT_PTR)COMPlusCheckForAbort(uResumePC); @@ -833,7 +833,12 @@ UINT_PTR ExceptionTracker::FinishSecondPass( STRESS_LOG1(LF_EH, LL_INFO10, "resume under control: ip: %p\n", uResumePC); #ifdef TARGET_AMD64 +#ifdef TARGET_UNIX + pContextRecord->Rdi = uResumePC; + pContextRecord->Rsi = GetIP(pThread->GetAbortContext()); +#else pContextRecord->Rcx = uResumePC; +#endif #elif defined(TARGET_ARM) || defined(TARGET_ARM64) // On ARM & ARM64, we save off the original PC in Lr. This is the same as done // in HandleManagedFault for H/W generated exceptions. diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index 94b809e9f2ad4..1a454a8dc54c1 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -3956,7 +3956,9 @@ ThrowControlForThread( STRESS_LOG0(LF_SYNC, LL_INFO100, "ThrowControlForThread Aborting\n"); // Here we raise an exception. + INSTALL_MANAGED_EXCEPTION_DISPATCHER RaiseComPlusException(); + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER } #if defined(FEATURE_HIJACK) && !defined(TARGET_UNIX) diff --git a/src/libraries/System.Runtime/tests/System/Runtime/ControlledExecutionTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/ControlledExecutionTests.cs index 8aa28ad66522c..818b5606b65e2 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/ControlledExecutionTests.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/ControlledExecutionTests.cs @@ -97,13 +97,6 @@ void Test() _caughtException = true; } - if (!PlatformDetection.IsWindows) - { - // Rethrowing a ThreadAbortException at the end of catch blocks is not implemented, so force it - // here by calling native code (https://github.com/dotnet/runtime/issues/72703). - Thread.Sleep(0); - } - _finishedExecution = true; } }