Use signals for activation injection on macOS (#46657)
authorJan Vorlicek <janvorli@microsoft.com>
Fri, 8 Jan 2021 16:34:37 +0000 (17:34 +0100)
committerGitHub <noreply@github.com>
Fri, 8 Jan 2021 16:34:37 +0000 (17:34 +0100)
This change moves macOS activation injection to the signal plan like it
works on other Unix platforms. The reason is that the activation injection
using thread suspension and thread redirection with helper frame can
collide with signal handlers on the same thread and result in a corrupted
stack frame. The issue can be reproduced by sending signals to the
.NET process from some other process while the .NET process is doing
a lot of GCs.

src/coreclr/pal/src/CMakeLists.txt
src/coreclr/pal/src/configure.cmake
src/coreclr/pal/src/exception/machexception.cpp
src/coreclr/pal/src/exception/signal.cpp
src/coreclr/pal/src/include/pal/context.h
src/coreclr/pal/src/thread/context.cpp

index 890d440..c93bb25 100644 (file)
@@ -61,7 +61,6 @@ if(CLR_CMAKE_TARGET_OSX)
     add_definitions(-DXSTATE_SUPPORTED)
   endif()
   set(PLATFORM_SOURCES
-    arch/${PAL_ARCH_SOURCES_DIR}/activationhandlerwrapper.S
     arch/${PAL_ARCH_SOURCES_DIR}/context.S
     arch/${PAL_ARCH_SOURCES_DIR}/dispatchexceptionwrapper.S
     exception/machexception.cpp
index dfa14fa..45d1b69 100644 (file)
@@ -156,7 +156,7 @@ check_type_size("struct pt_regs" PT_REGS)
 set(CMAKE_EXTRA_INCLUDE_FILES)
 set(CMAKE_EXTRA_INCLUDE_FILES signal.h)
 set(CMAKE_EXTRA_INCLUDE_FILES)
-set(CMAKE_EXTRA_INCLUDE_FILES ucontext.h)
+set(CMAKE_EXTRA_INCLUDE_FILES sys/ucontext.h)
 check_type_size(ucontext_t UCONTEXT_T)
 set(CMAKE_EXTRA_INCLUDE_FILES)
 set(CMAKE_EXTRA_INCLUDE_FILES pthread.h)
index e27a7a4..f9973b7 100644 (file)
@@ -1422,192 +1422,4 @@ SEHInitializeMachExceptions(DWORD flags)
     return TRUE;
 }
 
-extern "C"
-void
-ActivationHandler(CONTEXT* context)
-{
-    if (g_activationFunction != NULL)
-    {
-        g_activationFunction(context);
-    }
-
-#ifdef TARGET_ARM64
-    // RtlRestoreContext assembly corrupts X16 & X17, so it cannot be
-    // used for Activation restore
-    MachSetThreadContext(context);
-#else
-    RtlRestoreContext(context, NULL);
-#endif
-    DebugBreak();
-}
-
-extern "C" void ActivationHandlerWrapper();
-extern "C" int ActivationHandlerReturnOffset;
-extern "C" unsigned int XmmYmmStateSupport();
-
-#if defined(HOST_AMD64)
-bool IsHardwareException(x86_exception_state64_t exceptionState)
-{
-    static const int MaxHardwareExceptionVector = 31;
-    return exceptionState.__trapno <= MaxHardwareExceptionVector;
-}
-#elif defined(HOST_ARM64)
-bool IsHardwareException(arm_exception_state64_t exceptionState)
-{
-    // Infer exception state from the ESR_EL* register value.
-    // Bits 31-26 represent the ESR.EC field
-    const int ESR_EC_SHIFT = 26;
-    const int ESR_EC_MASK = 0x3f;
-    const int esr_ec = (exceptionState.__esr >> ESR_EC_SHIFT) & ESR_EC_MASK;
-
-    const int ESR_EC_SVC = 0x15; // Supervisor Call exception from aarch64.
-
-    // Assume only supervisor calls from aarch64 are not hardware exceptions
-    return (esr_ec != ESR_EC_SVC);
-}
-#else
-#error Unexpected architecture
-#endif
-
-/*++
-Function :
-    InjectActivationInternal
-
-    Sets up the specified thread to call the ActivationHandler.
-
-Parameters:
-    pThread - PAL thread instance
-
-Return value :
-    PAL_ERROR
---*/
-PAL_ERROR
-InjectActivationInternal(CPalThread* pThread)
-{
-    PAL_ERROR palError;
-
-    mach_port_t threadPort = pThread->GetMachPortSelf();
-
-    kern_return_t MachRet = SuspendMachThread(threadPort);
-    palError = (MachRet == KERN_SUCCESS) ? NO_ERROR : ERROR_GEN_FAILURE;
-
-    if (palError == NO_ERROR)
-    {
-#if defined(HOST_AMD64)
-        x86_exception_state64_t ExceptionState;
-        const thread_state_flavor_t exceptionFlavor = x86_EXCEPTION_STATE64;
-        const mach_msg_type_number_t exceptionCount = x86_EXCEPTION_STATE64_COUNT;
-
-        x86_thread_state64_t ThreadState;
-        const thread_state_flavor_t threadFlavor = x86_THREAD_STATE64;
-        const mach_msg_type_number_t threadCount = x86_THREAD_STATE64_COUNT;
-#elif defined(HOST_ARM64)
-        arm_exception_state64_t ExceptionState;
-        const thread_state_flavor_t exceptionFlavor = ARM_EXCEPTION_STATE64;
-        const mach_msg_type_number_t exceptionCount = ARM_EXCEPTION_STATE64_COUNT;
-
-        arm_thread_state64_t ThreadState;
-        const thread_state_flavor_t threadFlavor = ARM_THREAD_STATE64;
-        const mach_msg_type_number_t threadCount = ARM_THREAD_STATE64_COUNT;
-#else
-#error Unexpected architecture
-#endif
-        mach_msg_type_number_t count = exceptionCount;
-
-        MachRet = thread_get_state(threadPort,
-                                   exceptionFlavor,
-                                   (thread_state_t)&ExceptionState,
-                                   &count);
-        _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_get_state for *_EXCEPTION_STATE64\n");
-
-        // Inject the activation only if the thread doesn't have a pending hardware exception
-        if (!IsHardwareException(ExceptionState))
-        {
-            count = threadCount;
-            MachRet = thread_get_state(threadPort,
-                                       threadFlavor,
-                                       (thread_state_t)&ThreadState,
-                                       &count);
-            _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_get_state for *_THREAD_STATE64\n");
-
-#if defined(HOST_AMD64)
-            if ((g_safeActivationCheckFunction != NULL) && g_safeActivationCheckFunction(ThreadState.__rip, /* checkingCurrentThread */ FALSE))
-            {
-                // TODO: it would be nice to preserve the red zone in case a jitter would want to use it
-                // Do we really care about unwinding through the wrapper?
-                size_t* sp = (size_t*)ThreadState.__rsp;
-                *(--sp) = ThreadState.__rip;
-                *(--sp) = ThreadState.__rbp;
-                size_t rbpAddress = (size_t)sp;
-#elif defined(HOST_ARM64)
-            if ((g_safeActivationCheckFunction != NULL) && g_safeActivationCheckFunction((size_t)arm_thread_state64_get_pc_fptr(ThreadState), /* checkingCurrentThread */ FALSE))
-            {
-                // TODO: it would be nice to preserve the red zone in case a jitter would want to use it
-                // Do we really care about unwinding through the wrapper?
-                size_t* sp = (size_t*)arm_thread_state64_get_sp(ThreadState);
-                *(--sp) = (size_t)arm_thread_state64_get_pc_fptr(ThreadState);
-                *(--sp) = arm_thread_state64_get_fp(ThreadState);
-                size_t fpAddress = (size_t)sp;
-#else
-#error Unexpected architecture
-#endif
-                size_t contextAddress = (((size_t)sp) - sizeof(CONTEXT)) & ~15;
-
-                // Fill in the context in the helper frame with the full context of the suspended thread.
-                // The ActivationHandler will use the context to resume the execution of the thread
-                // after the activation function returns.
-                CONTEXT *pContext = (CONTEXT *)contextAddress;
-#if defined(HOST_AMD64)
-                pContext->ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS;
-#else
-                pContext->ContextFlags = CONTEXT_FULL;
-#endif
-#ifdef XSTATE_SUPPORTED
-                if (XmmYmmStateSupport() == 1)
-                {
-                    pContext->ContextFlags |= CONTEXT_XSTATE;
-                }
-#endif
-                MachRet = CONTEXT_GetThreadContextFromPort(threadPort, pContext);
-                _ASSERT_MSG(MachRet == KERN_SUCCESS, "CONTEXT_GetThreadContextFromPort\n");
-
-#if defined(HOST_AMD64)
-                size_t returnAddressAddress = contextAddress - sizeof(size_t);
-                *(size_t*)(returnAddressAddress) =  ActivationHandlerReturnOffset + (size_t)ActivationHandlerWrapper;
-
-                // Make the instruction register point to ActivationHandler
-                ThreadState.__rip = (size_t)ActivationHandler;
-                ThreadState.__rsp = returnAddressAddress;
-                ThreadState.__rbp = rbpAddress;
-                ThreadState.__rdi = contextAddress;
-#elif defined(HOST_ARM64)
-                // Make the call to ActivationHandler
-                arm_thread_state64_set_lr_fptr(ThreadState, ActivationHandlerReturnOffset + (size_t)ActivationHandlerWrapper);
-                arm_thread_state64_set_pc_fptr(ThreadState, ActivationHandler);
-                arm_thread_state64_set_sp(ThreadState, contextAddress);
-                arm_thread_state64_set_fp(ThreadState, fpAddress);
-                ThreadState.__x[0] = contextAddress;
-#else
-#error Unexpected architecture
-#endif
-
-                MachRet = thread_set_state(threadPort,
-                                           threadFlavor,
-                                           (thread_state_t)&ThreadState,
-                                           threadCount);
-                _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_set_state\n");
-            }
-        }
-
-        MachRet = thread_resume(threadPort);
-        palError = (MachRet == ERROR_SUCCESS) ? NO_ERROR : ERROR_GEN_FAILURE;
-    }
-    else
-    {
-        printf("Suspension failed with error 0x%x\n", palError);
-    }
-
-    return palError;
-}
-
 #endif // HAVE_MACH_EXCEPTIONS
index de7ab13..ddc41ac 100644 (file)
@@ -46,16 +46,19 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do
 #include <unistd.h>
 #include <sys/mman.h>
 
+
+#endif // !HAVE_MACH_EXCEPTIONS
 #include "pal/context.h"
 
 #ifdef SIGRTMIN
 #define INJECT_ACTIVATION_SIGNAL SIGRTMIN
+#else
+#define INJECT_ACTIVATION_SIGNAL SIGUSR1
 #endif
 
 #if !defined(INJECT_ACTIVATION_SIGNAL) && defined(FEATURE_HIJACK)
 #error FEATURE_HIJACK requires INJECT_ACTIVATION_SIGNAL to be defined
 #endif
-#endif // !HAVE_MACH_EXCEPTIONS
 
 using namespace CorUnix;
 
@@ -66,6 +69,9 @@ typedef void (*SIGFUNC)(int, siginfo_t *, void *);
 /* internal function declarations *********************************************/
 
 static void sigterm_handler(int code, siginfo_t *siginfo, void *context);
+#ifdef INJECT_ACTIVATION_SIGNAL
+static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
+#endif
 #if !HAVE_MACH_EXCEPTIONS
 static void sigill_handler(int code, siginfo_t *siginfo, void *context);
 static void sigfpe_handler(int code, siginfo_t *siginfo, void *context);
@@ -77,9 +83,6 @@ static void sigquit_handler(int code, siginfo_t *siginfo, void *context);
 
 static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...);
 
-#ifdef INJECT_ACTIVATION_SIGNAL
-static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
-#endif
 #endif // !HAVE_MACH_EXCEPTIONS
 
 static void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags = 0, bool skipIgnored = false);
@@ -94,8 +97,13 @@ bool g_enable_alternate_stack_check = false;
 #endif // !HAVE_MACH_EXCEPTIONS
 
 static bool g_registered_sigterm_handler = false;
+static bool g_registered_activation_handler = false;
 
 struct sigaction g_previous_sigterm;
+#ifdef INJECT_ACTIVATION_SIGNAL
+struct sigaction g_previous_activation;
+#endif
+
 #if !HAVE_MACH_EXCEPTIONS
 struct sigaction g_previous_sigill;
 struct sigaction g_previous_sigtrap;
@@ -105,10 +113,6 @@ struct sigaction g_previous_sigsegv;
 struct sigaction g_previous_sigint;
 struct sigaction g_previous_sigquit;
 
-#ifdef INJECT_ACTIVATION_SIGNAL
-struct sigaction g_previous_activation;
-#endif
-
 // Offset of the local variable containing pointer to windows style context in the common_signal_handler function.
 // This offset is relative to the frame pointer.
 int g_common_signal_handler_context_locvar_offset = 0;
@@ -174,9 +178,6 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
         handle_signal(SIGINT, sigint_handler, &g_previous_sigint, 0 /* additionalFlags */, true /* skipIgnored */);
         handle_signal(SIGQUIT, sigquit_handler, &g_previous_sigquit, 0 /* additionalFlags */, true /* skipIgnored */);
 
-#ifdef INJECT_ACTIVATION_SIGNAL
-        handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation);
-#endif
         if (!pthrCurrent->EnsureSignalAlternateStack())
         {
             return FALSE;
@@ -224,6 +225,11 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
         handle_signal(SIGTERM, sigterm_handler, &g_previous_sigterm);
     }
 
+#ifdef INJECT_ACTIVATION_SIGNAL
+    handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation);
+    g_registered_activation_handler = true;
+#endif
+
     return TRUE;
 }
 
@@ -257,11 +263,15 @@ void SEHCleanupSignals()
         restore_signal(SIGSEGV, &g_previous_sigsegv);
         restore_signal(SIGINT, &g_previous_sigint);
         restore_signal(SIGQUIT, &g_previous_sigquit);
+    }
+#endif // !HAVE_MACH_EXCEPTIONS
+
 #ifdef INJECT_ACTIVATION_SIGNAL
+    if (g_registered_activation_handler)
+    {
         restore_signal(INJECT_ACTIVATION_SIGNAL, &g_previous_activation);
-#endif
     }
-#endif // !HAVE_MACH_EXCEPTIONS
+#endif
 
     if (g_registered_sigterm_handler)
     {
@@ -686,7 +696,6 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
     }
 }
 
-#if !HAVE_MACH_EXCEPTIONS
 #ifdef INJECT_ACTIVATION_SIGNAL
 /*++
 Function :
@@ -703,7 +712,13 @@ Parameters :
 static void inject_activation_handler(int code, siginfo_t *siginfo, void *context)
 {
     // Only accept activations from the current process
-    if (g_activationFunction != NULL && siginfo->si_pid == getpid())
+    if (g_activationFunction != NULL && (siginfo->si_pid == getpid()
+#ifdef HOST_OSX
+    // On OSX si_pid is sometimes 0. It was confirmed by Apple to be expected, as the si_pid is tracked at the process level. So when multiple
+    // signals are in flight in the same process at the same time, it may be overwritten / zeroed.
+    || siginfo->si_pid == 0
+#endif
+    ))
     {
         _ASSERTE(g_safeActivationCheckFunction != NULL);
 
@@ -713,7 +728,7 @@ static void inject_activation_handler(int code, siginfo_t *siginfo, void *contex
         CONTEXTFromNativeContext(
             ucontext,
             &winContext,
-            CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
+            CONTEXT_CONTROL | CONTEXT_INTEGER);
 
         if (g_safeActivationCheckFunction(CONTEXTGetPC(&winContext), /* checkingCurrentThread */ TRUE))
         {
@@ -779,6 +794,8 @@ PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
 #endif
 }
 
+#if !HAVE_MACH_EXCEPTIONS
+
 /*++
 Function :
     signal_ignore_handler
index 73de448..3ba1b45 100644 (file)
@@ -28,17 +28,18 @@ extern "C"
 #include <signal.h>
 #include <pthread.h>
 
-#if !HAVE_MACH_EXCEPTIONS
 /* A type to wrap the native context type, which is ucontext_t on some
  * platforms and another type elsewhere. */
 #if HAVE_UCONTEXT_T
-#include <ucontext.h>
+#include <sys/ucontext.h>
 
 typedef ucontext_t native_context_t;
 #else   // HAVE_UCONTEXT_T
 #error Native context type is not known on this platform!
 #endif  // HAVE_UCONTEXT_T
 
+#if !HAVE_MACH_EXCEPTIONS
+
 #if defined(XSTATE_SUPPORTED) && !HAVE_PUBLIC_XSTATE_STRUCT
 namespace asm_sigcontext
 {
@@ -268,6 +269,9 @@ inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc)
 #ifdef HOST_64BIT
 
 #if defined(HOST_ARM64)
+
+#ifndef TARGET_OSX
+
 #define MCREG_X0(mc)      ((mc).regs[0])
 #define MCREG_X1(mc)      ((mc).regs[1])
 #define MCREG_X2(mc)      ((mc).regs[2])
@@ -305,7 +309,6 @@ inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc)
 #define MCREG_Cpsr(mc)    ((mc).pstate)
 
 
-#ifndef TARGET_OSX
 inline
 fpsimd_context* GetNativeSigSimdContext(native_context_t *mc)
 {
@@ -342,9 +345,110 @@ const fpsimd_context* GetConstNativeSigSimdContext(const native_context_t *mc)
     return GetNativeSigSimdContext(const_cast<native_context_t*>(mc));
 }
 
+#else // TARGET_OSX
+
+#define MCREG_X0(mc)      ((mc)->__ss.__x[0])
+#define MCREG_X1(mc)      ((mc)->__ss.__x[1])
+#define MCREG_X2(mc)      ((mc)->__ss.__x[2])
+#define MCREG_X3(mc)      ((mc)->__ss.__x[3])
+#define MCREG_X4(mc)      ((mc)->__ss.__x[4])
+#define MCREG_X5(mc)      ((mc)->__ss.__x[5])
+#define MCREG_X6(mc)      ((mc)->__ss.__x[6])
+#define MCREG_X7(mc)      ((mc)->__ss.__x[7])
+#define MCREG_X8(mc)      ((mc)->__ss.__x[8])
+#define MCREG_X9(mc)      ((mc)->__ss.__x[9])
+#define MCREG_X10(mc)     ((mc)->__ss.__x[10])
+#define MCREG_X11(mc)     ((mc)->__ss.__x[11])
+#define MCREG_X12(mc)     ((mc)->__ss.__x[12])
+#define MCREG_X13(mc)     ((mc)->__ss.__x[13])
+#define MCREG_X14(mc)     ((mc)->__ss.__x[14])
+#define MCREG_X15(mc)     ((mc)->__ss.__x[15])
+#define MCREG_X16(mc)     ((mc)->__ss.__x[16])
+#define MCREG_X17(mc)     ((mc)->__ss.__x[17])
+#define MCREG_X18(mc)     ((mc)->__ss.__x[18])
+#define MCREG_X19(mc)     ((mc)->__ss.__x[19])
+#define MCREG_X20(mc)     ((mc)->__ss.__x[20])
+#define MCREG_X21(mc)     ((mc)->__ss.__x[21])
+#define MCREG_X22(mc)     ((mc)->__ss.__x[22])
+#define MCREG_X23(mc)     ((mc)->__ss.__x[23])
+#define MCREG_X24(mc)     ((mc)->__ss.__x[24])
+#define MCREG_X25(mc)     ((mc)->__ss.__x[25])
+#define MCREG_X26(mc)     ((mc)->__ss.__x[26])
+#define MCREG_X27(mc)     ((mc)->__ss.__x[27])
+#define MCREG_X28(mc)     ((mc)->__ss.__x[28])
+#define MCREG_Fp(mc)      ((mc)->__ss.__fp)
+#define MCREG_Lr(mc)      ((mc)->__ss.__lr)
+
+#define MCREG_Sp(mc)      ((mc)->__ss.__sp)
+#define MCREG_Pc(mc)      ((mc)->__ss.__pc)
+#define MCREG_Cpsr(mc)    ((mc)->__ss.__cpsr)
+
+inline
+_STRUCT_ARM_NEON_STATE64* GetNativeSigSimdContext(native_context_t *mc)
+{
+    return &(mc)->uc_mcontext->__ns;
+}
+
+inline
+const _STRUCT_ARM_NEON_STATE64* GetConstNativeSigSimdContext(const native_context_t *mc)
+{
+    return GetNativeSigSimdContext(const_cast<native_context_t*>(mc));
+}
+
 #endif // TARGET_OSX
 
 #else // HOST_ARM64
+
+#ifdef TARGET_OSX
+
+#define MCREG_Rbp(mc)      ((mc)->__ss.__rbp)
+#define MCREG_Rip(mc)      ((mc)->__ss.__rip)
+#define MCREG_Rsp(mc)      ((mc)->__ss.__rsp)
+#define MCREG_Rsi(mc)      ((mc)->__ss.__rsi)
+#define MCREG_Rdi(mc)      ((mc)->__ss.__rdi)
+#define MCREG_Rbx(mc)      ((mc)->__ss.__rbx)
+#define MCREG_Rdx(mc)      ((mc)->__ss.__rdx)
+#define MCREG_Rcx(mc)      ((mc)->__ss.__rcx)
+#define MCREG_Rax(mc)      ((mc)->__ss.__rax)
+#define MCREG_R8(mc)       ((mc)->__ss.__r8)
+#define MCREG_R9(mc)       ((mc)->__ss.__r9)
+#define MCREG_R10(mc)      ((mc)->__ss.__r10)
+#define MCREG_R11(mc)      ((mc)->__ss.__r11)
+#define MCREG_R12(mc)      ((mc)->__ss.__r12)
+#define MCREG_R13(mc)      ((mc)->__ss.__r13)
+#define MCREG_R14(mc)      ((mc)->__ss.__r14)
+#define MCREG_R15(mc)      ((mc)->__ss.__r15)
+#define MCREG_EFlags(mc)   ((mc)->__ss.__rflags)
+#define MCREG_SegCs(mc)    ((mc)->__ss.__cs)
+
+#define FPSTATE(uc)             ((uc)->uc_mcontext->__fs)
+#define FPREG_ControlWord(uc)   *((WORD*)&FPSTATE(uc).__fpu_fcw)
+#define FPREG_StatusWord(uc)    *((WORD*)&FPSTATE(uc).__fpu_fsw)
+#define FPREG_TagWord(uc)       FPSTATE(uc).__fpu_ftw
+#define FPREG_MxCsr(uc)         FPSTATE(uc).__fpu_mxcsr
+#define FPREG_MxCsr_Mask(uc)    FPSTATE(uc).__fpu_mxcsrmask
+#define FPREG_ErrorOffset(uc)   *(DWORD*) &(FPSTATE(uc).__fpu_ip)
+#define FPREG_ErrorSelector(uc) *((WORD*) &(FPSTATE(uc).__fpu_ip) + 2)
+#define FPREG_DataOffset(uc)    *(DWORD*) &(FPSTATE(uc).__fpu_dp)
+#define FPREG_DataSelector(uc)  *((WORD*) &(FPSTATE(uc).__fpu_dp) + 2)
+
+#define FPREG_Xmm(uc, index)    *(M128A*) &((&FPSTATE(uc).__fpu_xmm0)[index])
+#define FPREG_St(uc, index)     *(M128A*) &((&FPSTATE(uc).__fpu_stmm0)[index]) //.fp_acc)
+
+inline bool FPREG_HasYmmRegisters(const ucontext_t *uc)
+{
+    _ASSERTE((uc->uc_mcsize == sizeof(_STRUCT_MCONTEXT_AVX64)) || (uc->uc_mcsize == sizeof(_STRUCT_MCONTEXT_AVX512_64)));
+    return (uc->uc_mcsize == sizeof(_STRUCT_MCONTEXT_AVX64)) || (uc->uc_mcsize == sizeof(_STRUCT_MCONTEXT_AVX512_64));
+}
+
+static_assert_no_msg(offsetof(_STRUCT_X86_AVX_STATE64, __fpu_ymmh0) == offsetof(_STRUCT_X86_AVX512_STATE64, __fpu_ymmh0));
+inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc)
+{
+    return reinterpret_cast<void *>(&((_STRUCT_X86_AVX_STATE64&)FPSTATE(uc)).__fpu_ymmh0);
+}
+
+#else //TARGET_OSX
+
     // For FreeBSD, as found in x86/ucontext.h
 #define MCREG_Rbp(mc)      ((mc).mc_rbp)
 #define MCREG_Rip(mc)      ((mc).mc_rip)
@@ -380,7 +484,8 @@ const fpsimd_context* GetConstNativeSigSimdContext(const native_context_t *mc)
 
 #define FPREG_Xmm(uc, index)    *(M128A*) &(FPSTATE(uc)->sv_xmm[index])
 #define FPREG_St(uc, index)     *(M128A*) &(FPSTATE(uc)->sv_fp[index].fp_acc)
-#endif
+#endif // TARGET_OSX
+#endif // HOST_ARM64
 
 #else // HOST_64BIT
 
@@ -732,7 +837,8 @@ CONTEXT_GetThreadContextFromThreadState(
     thread_state_t threadState,
     LPCONTEXT lpContext);
 
-#else // HAVE_MACH_EXCEPTIONS
+#endif // HAVE_MACH_EXCEPTIONS
+
 /*++
 Function :
     CONTEXTToNativeContext
@@ -770,6 +876,8 @@ Return value :
 void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext,
                               ULONG contextFlags);
 
+#if !HAVE_MACH_EXCEPTIONS
+
 /*++
 Function :
     GetNativeContextPC
index 5ee0308..5bb3a60 100644 (file)
@@ -66,6 +66,8 @@ typedef int __ptrace_request;
 #include <asm/ptrace.h>
 #endif  // HAVE_PT_REGS
 
+#endif // !HAVE_MACH_EXCEPTIONS
+
 #ifdef HOST_AMD64
 #define ASSIGN_CONTROL_REGS \
         ASSIGN_REG(Rbp)     \
@@ -175,6 +177,8 @@ typedef int __ptrace_request;
         ASSIGN_CONTROL_REGS \
         ASSIGN_INTEGER_REGS \
 
+#if !HAVE_MACH_EXCEPTIONS
+
 /*++
 Function:
   CONTEXT_GetRegisters
@@ -401,6 +405,8 @@ CONTEXT_SetThreadContext(
      return ret;
 }
 
+#endif // !HAVE_MACH_EXCEPTIONS
+
 /*++
 Function :
     CONTEXTToNativeContext
@@ -473,6 +479,15 @@ void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native)
             FPREG_Xmm(native, i) = lpContext->FltSave.XmmRegisters[i];
         }
 #elif defined(HOST_ARM64)
+#ifdef TARGET_OSX
+        _STRUCT_ARM_NEON_STATE64* fp = GetNativeSigSimdContext(native);
+        fp->__fpsr = lpContext->Fpsr;
+        fp->__fpcr = lpContext->Fpcr;
+        for (int i = 0; i < 32; i++)
+        {
+            *(NEON128*) &fp->__v[i] = lpContext->V[i];
+        }
+#else // TARGET_OSX
         fpsimd_context* fp = GetNativeSigSimdContext(native);
         if (fp)
         {
@@ -483,6 +498,7 @@ void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native)
                 *(NEON128*) &fp->vregs[i] = lpContext->V[i];
             }
         }
+#endif // TARGET_OSX
 #elif defined(HOST_ARM)
         VfpSigFrame* fp = GetNativeSigSimdContext(native);
         if (fp)
@@ -598,6 +614,15 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex
             lpContext->FltSave.XmmRegisters[i] = FPREG_Xmm(native, i);
         }
 #elif defined(HOST_ARM64)
+#ifdef TARGET_OSX
+        const _STRUCT_ARM_NEON_STATE64* fp = GetConstNativeSigSimdContext(native);
+        lpContext->Fpsr = fp->__fpsr;
+        lpContext->Fpcr = fp->__fpcr;
+        for (int i = 0; i < 32; i++)
+        {
+            lpContext->V[i] = *(NEON128*) &fp->__v[i];
+        }
+#else // TARGET_OSX
         const fpsimd_context* fp = GetConstNativeSigSimdContext(native);
         if (fp)
         {
@@ -608,6 +633,7 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex
                 lpContext->V[i] = *(NEON128*) &fp->vregs[i];
             }
         }
+#endif // TARGET_OSX
 #elif defined(HOST_ARM)
         const VfpSigFrame* fp = GetConstNativeSigSimdContext(native);
         if (fp)
@@ -648,6 +674,8 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex
 #endif // HOST_AMD64
 }
 
+#if !HAVE_MACH_EXCEPTIONS
+
 /*++
 Function :
     GetNativeContextPC