From aee81acd99b9c0e6a406bad3b98c278669c7cc67 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 19 Nov 2020 11:05:53 +0100 Subject: [PATCH] Inject activation via signal on macOS older state --- src/coreclr/src/pal/src/CMakeLists.txt | 1 - src/coreclr/src/pal/src/configure.cmake | 2 +- .../src/pal/src/exception/machexception.cpp | 114 ---- src/coreclr/src/pal/src/exception/signal.cpp | 39 +- src/coreclr/src/pal/src/include/pal/context.h | 130 +++-- src/coreclr/src/pal/src/thread/context.cpp | 501 +++++++++--------- 6 files changed, 370 insertions(+), 417 deletions(-) diff --git a/src/coreclr/src/pal/src/CMakeLists.txt b/src/coreclr/src/pal/src/CMakeLists.txt index 712dabf46a3e6..ff661973c2e48 100644 --- a/src/coreclr/src/pal/src/CMakeLists.txt +++ b/src/coreclr/src/pal/src/CMakeLists.txt @@ -49,7 +49,6 @@ if(CLR_CMAKE_TARGET_OSX) add_definitions(-DTARGET_OSX) add_definitions(-DXSTATE_SUPPORTED) set(PLATFORM_SOURCES - arch/amd64/activationhandlerwrapper.S arch/amd64/context.S arch/amd64/dispatchexceptionwrapper.S exception/machexception.cpp diff --git a/src/coreclr/src/pal/src/configure.cmake b/src/coreclr/src/pal/src/configure.cmake index 893f88c44f3da..00745550ba57d 100644 --- a/src/coreclr/src/pal/src/configure.cmake +++ b/src/coreclr/src/pal/src/configure.cmake @@ -157,7 +157,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) diff --git a/src/coreclr/src/pal/src/exception/machexception.cpp b/src/coreclr/src/pal/src/exception/machexception.cpp index de50fd6be99da..12f49e04a9b85 100644 --- a/src/coreclr/src/pal/src/exception/machexception.cpp +++ b/src/coreclr/src/pal/src/exception/machexception.cpp @@ -1248,118 +1248,4 @@ SEHInitializeMachExceptions(DWORD flags) return TRUE; } -extern "C" -void -ActivationHandler(CONTEXT* context) -{ - if (g_activationFunction != NULL) - { - g_activationFunction(context); - } - - RtlRestoreContext(context, NULL); - DebugBreak(); -} - -extern "C" void ActivationHandlerWrapper(); -extern "C" int ActivationHandlerReturnOffset; -extern "C" unsigned int XmmYmmStateSupport(); - -/*++ -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) - { - mach_msg_type_number_t count; - - x86_exception_state64_t ExceptionState; - count = x86_EXCEPTION_STATE64_COUNT; - MachRet = thread_get_state(threadPort, - x86_EXCEPTION_STATE64, - (thread_state_t)&ExceptionState, - &count); - _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_get_state for x86_EXCEPTION_STATE64\n"); - - // Inject the activation only if the thread doesn't have a pending hardware exception - static const int MaxHardwareExceptionVector = 31; - if (ExceptionState.__trapno > MaxHardwareExceptionVector) - { - x86_thread_state64_t ThreadState; - count = x86_THREAD_STATE64_COUNT; - MachRet = thread_get_state(threadPort, - x86_THREAD_STATE64, - (thread_state_t)&ThreadState, - &count); - _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_get_state for x86_THREAD_STATE64\n"); - - 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; - size_t contextAddress = (((size_t)sp) - sizeof(CONTEXT)) & ~15; - size_t returnAddressAddress = contextAddress - sizeof(size_t); - *(size_t*)(returnAddressAddress) = ActivationHandlerReturnOffset + (size_t)ActivationHandlerWrapper; - - // 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; - pContext->ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS; -#ifdef XSTATE_SUPPORTED - if (XmmYmmStateSupport() == 1) - { - pContext->ContextFlags |= CONTEXT_XSTATE; - } -#endif - MachRet = CONTEXT_GetThreadContextFromPort(threadPort, pContext); - _ASSERT_MSG(MachRet == KERN_SUCCESS, "CONTEXT_GetThreadContextFromPort\n"); - - // Make the instruction register point to ActivationHandler - ThreadState.__rip = (size_t)ActivationHandler; - ThreadState.__rsp = returnAddressAddress; - ThreadState.__rbp = rbpAddress; - ThreadState.__rdi = contextAddress; - - MachRet = thread_set_state(threadPort, - x86_THREAD_STATE64, - (thread_state_t)&ThreadState, - count); - _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 diff --git a/src/coreclr/src/pal/src/exception/signal.cpp b/src/coreclr/src/pal/src/exception/signal.cpp index de2d0ad3b7008..30c14d05ad62d 100644 --- a/src/coreclr/src/pal/src/exception/signal.cpp +++ b/src/coreclr/src/pal/src/exception/signal.cpp @@ -46,16 +46,19 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do #include #include + +#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 : @@ -779,6 +788,8 @@ PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread) #endif } +#if !HAVE_MACH_EXCEPTIONS + /*++ Function : signal_ignore_handler diff --git a/src/coreclr/src/pal/src/include/pal/context.h b/src/coreclr/src/pal/src/include/pal/context.h index db0baec111919..7ab9ad7240ad3 100644 --- a/src/coreclr/src/pal/src/include/pal/context.h +++ b/src/coreclr/src/pal/src/include/pal/context.h @@ -28,17 +28,18 @@ extern "C" #include #include -#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 +#include 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 { @@ -342,6 +343,56 @@ const fpsimd_context* GetConstNativeSigSimdContext(const native_context_t *mc) } #else + +#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) +{ + // TODO: fixme + return true; +} + +inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc) +{ + return reinterpret_cast(&((_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) @@ -377,7 +428,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 @@ -694,42 +746,6 @@ CONTEXT_GetThreadContext( pthread_t self, LPCONTEXT lpContext); -#if HAVE_MACH_EXCEPTIONS -/*++ -Function: - CONTEXT_GetThreadContextFromPort - - Helper for GetThreadContext that uses a mach_port ---*/ -kern_return_t -CONTEXT_GetThreadContextFromPort( - mach_port_t Port, - LPCONTEXT lpContext); - -/*++ -Function: - SetThreadContextOnPort - - Helper for CONTEXT_SetThreadContext ---*/ -kern_return_t -CONTEXT_SetThreadContextOnPort( - mach_port_t Port, - IN CONST CONTEXT *lpContext); - -/*++ -Function: - GetThreadContextFromThreadState - - Helper for mach exception support ---*/ -void -CONTEXT_GetThreadContextFromThreadState( - thread_state_flavor_t stateFlavor, - thread_state_t threadState, - LPCONTEXT lpContext); - -#else // HAVE_MACH_EXCEPTIONS /*++ Function : CONTEXTToNativeContext @@ -767,6 +783,42 @@ Return value : void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext, ULONG contextFlags); +#if HAVE_MACH_EXCEPTIONS +/*++ +Function: + CONTEXT_GetThreadContextFromPort + + Helper for GetThreadContext that uses a mach_port +--*/ +kern_return_t +CONTEXT_GetThreadContextFromPort( + mach_port_t Port, + LPCONTEXT lpContext); + +/*++ +Function: + SetThreadContextOnPort + + Helper for CONTEXT_SetThreadContext +--*/ +kern_return_t +CONTEXT_SetThreadContextOnPort( + mach_port_t Port, + IN CONST CONTEXT *lpContext); + +/*++ +Function: + GetThreadContextFromThreadState + + Helper for mach exception support +--*/ +void +CONTEXT_GetThreadContextFromThreadState( + thread_state_flavor_t stateFlavor, + thread_state_t threadState, + LPCONTEXT lpContext); + +#else // HAVE_MACH_EXCEPTIONS /*++ Function : GetNativeContextPC diff --git a/src/coreclr/src/pal/src/thread/context.cpp b/src/coreclr/src/pal/src/thread/context.cpp index ca0b60e449252..b4998427f16da 100644 --- a/src/coreclr/src/pal/src/thread/context.cpp +++ b/src/coreclr/src/pal/src/thread/context.cpp @@ -66,6 +66,8 @@ typedef int __ptrace_request; #include #endif // HAVE_PT_REGS +#endif // !HAVE_MACH_EXCEPTIONS + #ifdef HOST_AMD64 #define ASSIGN_CONTROL_REGS \ ASSIGN_REG(Rbp) \ @@ -89,7 +91,7 @@ typedef int __ptrace_request; ASSIGN_REG(R13) \ ASSIGN_REG(R14) \ ASSIGN_REG(R15) \ - + #elif defined(HOST_X86) #define ASSIGN_CONTROL_REGS \ ASSIGN_REG(Ebp) \ @@ -175,6 +177,8 @@ typedef int __ptrace_request; ASSIGN_CONTROL_REGS \ ASSIGN_INTEGER_REGS \ +#if !HAVE_MACH_EXCEPTIONS + /*++ Function: CONTEXT_GetRegisters @@ -401,253 +405,6 @@ CONTEXT_SetThreadContext( return ret; } -/*++ -Function : - CONTEXTToNativeContext - - Converts a CONTEXT record to a native context. - -Parameters : - CONST CONTEXT *lpContext : CONTEXT to convert - native_context_t *native : native context to fill in - -Return value : - None - ---*/ -void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native) -{ -#define ASSIGN_REG(reg) MCREG_##reg(native->uc_mcontext) = lpContext->reg; - if ((lpContext->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) - { - ASSIGN_CONTROL_REGS - } - - if ((lpContext->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) - { - ASSIGN_INTEGER_REGS - } -#undef ASSIGN_REG - -#if !HAVE_FPREGS_WITH_CW -#if HAVE_GREGSET_T || HAVE_GREGSET_T -#if HAVE_GREGSET_T - if (native->uc_mcontext.fpregs == nullptr) -#elif HAVE___GREGSET_T - if (native->uc_mcontext.__fpregs == nullptr) -#endif // HAVE_GREGSET_T - { - // If the pointer to the floating point state in the native context - // is not valid, we can't copy floating point registers regardless of - // whether CONTEXT_FLOATING_POINT is set in the CONTEXT's flags. - return; - } -#endif // HAVE_GREGSET_T || HAVE_GREGSET_T -#endif // !HAVE_FPREGS_WITH_CW - - if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) - { -#ifdef HOST_AMD64 - FPREG_ControlWord(native) = lpContext->FltSave.ControlWord; - FPREG_StatusWord(native) = lpContext->FltSave.StatusWord; -#if HAVE_FPREGS_WITH_CW - FPREG_TagWord1(native) = lpContext->FltSave.TagWord >> 8; - FPREG_TagWord2(native) = lpContext->FltSave.TagWord & 0xff; -#else - FPREG_TagWord(native) = lpContext->FltSave.TagWord; -#endif - FPREG_ErrorOffset(native) = lpContext->FltSave.ErrorOffset; - FPREG_ErrorSelector(native) = lpContext->FltSave.ErrorSelector; - FPREG_DataOffset(native) = lpContext->FltSave.DataOffset; - FPREG_DataSelector(native) = lpContext->FltSave.DataSelector; - FPREG_MxCsr(native) = lpContext->FltSave.MxCsr; - FPREG_MxCsr_Mask(native) = lpContext->FltSave.MxCsr_Mask; - - for (int i = 0; i < 8; i++) - { - FPREG_St(native, i) = lpContext->FltSave.FloatRegisters[i]; - } - - for (int i = 0; i < 16; i++) - { - FPREG_Xmm(native, i) = lpContext->FltSave.XmmRegisters[i]; - } -#elif defined(HOST_ARM64) - fpsimd_context* fp = GetNativeSigSimdContext(native); - if (fp) - { - fp->fpsr = lpContext->Fpsr; - fp->fpcr = lpContext->Fpcr; - for (int i = 0; i < 32; i++) - { - *(NEON128*) &fp->vregs[i] = lpContext->V[i]; - } - } -#elif defined(HOST_ARM) - VfpSigFrame* fp = GetNativeSigSimdContext(native); - if (fp) - { - fp->Fpscr = lpContext->Fpscr; - for (int i = 0; i < 32; i++) - { - fp->D[i] = lpContext->D[i]; - } - } -#endif - } - - // TODO: Enable for all Unix systems -#if defined(HOST_AMD64) && defined(XSTATE_SUPPORTED) - if ((lpContext->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE) - { - _ASSERTE(FPREG_HasYmmRegisters(native)); - memcpy_s(FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16, lpContext->VectorRegister, sizeof(M128A) * 16); - } -#endif //HOST_AMD64 && XSTATE_SUPPORTED -} - -/*++ -Function : - CONTEXTFromNativeContext - - Converts a native context to a CONTEXT record. - -Parameters : - const native_context_t *native : native context to convert - LPCONTEXT lpContext : CONTEXT to fill in - ULONG contextFlags : flags that determine which registers are valid in - native and which ones to set in lpContext - -Return value : - None - ---*/ -void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext, - ULONG contextFlags) -{ - lpContext->ContextFlags = contextFlags; - -#define ASSIGN_REG(reg) lpContext->reg = MCREG_##reg(native->uc_mcontext); - if ((contextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) - { - ASSIGN_CONTROL_REGS -#if defined(HOST_ARM) - // WinContext assumes that the least bit of Pc is always 1 (denoting thumb) - // although the pc value retrived from native context might not have set the least bit. - // This becomes especially problematic if the context is on the JIT_WRITEBARRIER. - lpContext->Pc |= 0x1; -#endif - } - - if ((contextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) - { - ASSIGN_INTEGER_REGS - } -#undef ASSIGN_REG - -#if !HAVE_FPREGS_WITH_CW -#if HAVE_GREGSET_T || HAVE___GREGSET_T -#if HAVE_GREGSET_T - if (native->uc_mcontext.fpregs == nullptr) -#elif HAVE___GREGSET_T - if (native->uc_mcontext.__fpregs == nullptr) -#endif // HAVE_GREGSET_T - { - // Reset the CONTEXT_FLOATING_POINT bit(s) and the CONTEXT_XSTATE bit(s) so it's - // clear that the floating point and extended state data in the CONTEXT is not - // valid. Since these flags are defined as the architecture bit(s) OR'd with one - // or more other bits, we first get the bits that are unique to each by resetting - // the architecture bits. We determine what those are by inverting the union of - // CONTEXT_CONTROL and CONTEXT_INTEGER, both of which should also have the - // architecture bit(s) set. - const ULONG floatingPointFlags = CONTEXT_FLOATING_POINT & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); - const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); - - lpContext->ContextFlags &= ~(floatingPointFlags | xstateFlags); - - // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT or CONTEXT_XSTATE - return; - } -#endif // HAVE_GREGSET_T || HAVE___GREGSET_T -#endif // !HAVE_FPREGS_WITH_CW - - if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) - { -#ifdef HOST_AMD64 - lpContext->FltSave.ControlWord = FPREG_ControlWord(native); - lpContext->FltSave.StatusWord = FPREG_StatusWord(native); -#if HAVE_FPREGS_WITH_CW - lpContext->FltSave.TagWord = ((DWORD)FPREG_TagWord1(native) << 8) | FPREG_TagWord2(native); -#else - lpContext->FltSave.TagWord = FPREG_TagWord(native); -#endif - lpContext->FltSave.ErrorOffset = FPREG_ErrorOffset(native); - lpContext->FltSave.ErrorSelector = FPREG_ErrorSelector(native); - lpContext->FltSave.DataOffset = FPREG_DataOffset(native); - lpContext->FltSave.DataSelector = FPREG_DataSelector(native); - lpContext->FltSave.MxCsr = FPREG_MxCsr(native); - lpContext->FltSave.MxCsr_Mask = FPREG_MxCsr_Mask(native); - - for (int i = 0; i < 8; i++) - { - lpContext->FltSave.FloatRegisters[i] = FPREG_St(native, i); - } - - for (int i = 0; i < 16; i++) - { - lpContext->FltSave.XmmRegisters[i] = FPREG_Xmm(native, i); - } -#elif defined(HOST_ARM64) - const fpsimd_context* fp = GetConstNativeSigSimdContext(native); - if (fp) - { - lpContext->Fpsr = fp->fpsr; - lpContext->Fpcr = fp->fpcr; - for (int i = 0; i < 32; i++) - { - lpContext->V[i] = *(NEON128*) &fp->vregs[i]; - } - } -#elif defined(HOST_ARM) - const VfpSigFrame* fp = GetConstNativeSigSimdContext(native); - if (fp) - { - lpContext->Fpscr = fp->Fpscr; - for (int i = 0; i < 32; i++) - { - lpContext->D[i] = fp->D[i]; - } - } - else - { - // Floating point state is not valid - // Mark the context correctly - lpContext->ContextFlags &= ~(ULONG)CONTEXT_FLOATING_POINT; - } -#endif - } - -#ifdef HOST_AMD64 - if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE) - { - // TODO: Enable for all Unix systems -#if XSTATE_SUPPORTED - if (FPREG_HasYmmRegisters(native)) - { - memcpy_s(lpContext->VectorRegister, sizeof(M128A) * 16, FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16); - } - else -#endif // XSTATE_SUPPORTED - { - // Reset the CONTEXT_XSTATE bit(s) so it's clear that the extended state data in - // the CONTEXT is not valid. - const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); - lpContext->ContextFlags &= ~xstateFlags; - } - } -#endif // HOST_AMD64 -} - /*++ Function : GetNativeContextPC @@ -1385,6 +1142,254 @@ CONTEXT_SetThreadContext( #endif // !HAVE_MACH_EXCEPTIONS +/*++ +Function : + CONTEXTToNativeContext + + Converts a CONTEXT record to a native context. + +Parameters : + CONST CONTEXT *lpContext : CONTEXT to convert + native_context_t *native : native context to fill in + +Return value : + None + +--*/ +void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native) +{ +#define ASSIGN_REG(reg) MCREG_##reg(native->uc_mcontext) = lpContext->reg; + if ((lpContext->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + { + ASSIGN_CONTROL_REGS + } + + if ((lpContext->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + { + ASSIGN_INTEGER_REGS + } +#undef ASSIGN_REG + +#if !HAVE_FPREGS_WITH_CW +#if HAVE_GREGSET_T || HAVE_GREGSET_T +#if HAVE_GREGSET_T + if (native->uc_mcontext.fpregs == nullptr) +#elif HAVE___GREGSET_T + if (native->uc_mcontext.__fpregs == nullptr) +#endif // HAVE_GREGSET_T + { + // If the pointer to the floating point state in the native context + // is not valid, we can't copy floating point registers regardless of + // whether CONTEXT_FLOATING_POINT is set in the CONTEXT's flags. + return; + } +#endif // HAVE_GREGSET_T || HAVE_GREGSET_T +#endif // !HAVE_FPREGS_WITH_CW + + if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) + { +#ifdef HOST_AMD64 + FPREG_ControlWord(native) = lpContext->FltSave.ControlWord; + FPREG_StatusWord(native) = lpContext->FltSave.StatusWord; +#if HAVE_FPREGS_WITH_CW + FPREG_TagWord1(native) = lpContext->FltSave.TagWord >> 8; + FPREG_TagWord2(native) = lpContext->FltSave.TagWord & 0xff; +#else + FPREG_TagWord(native) = lpContext->FltSave.TagWord; +#endif + FPREG_ErrorOffset(native) = lpContext->FltSave.ErrorOffset; + FPREG_ErrorSelector(native) = lpContext->FltSave.ErrorSelector; + FPREG_DataOffset(native) = lpContext->FltSave.DataOffset; + FPREG_DataSelector(native) = lpContext->FltSave.DataSelector; + FPREG_MxCsr(native) = lpContext->FltSave.MxCsr; + FPREG_MxCsr_Mask(native) = lpContext->FltSave.MxCsr_Mask; + + for (int i = 0; i < 8; i++) + { + FPREG_St(native, i) = lpContext->FltSave.FloatRegisters[i]; + } + + for (int i = 0; i < 16; i++) + { + FPREG_Xmm(native, i) = lpContext->FltSave.XmmRegisters[i]; + } +#elif defined(HOST_ARM64) + fpsimd_context* fp = GetNativeSigSimdContext(native); + if (fp) + { + fp->fpsr = lpContext->Fpsr; + fp->fpcr = lpContext->Fpcr; + for (int i = 0; i < 32; i++) + { + *(NEON128*) &fp->vregs[i] = lpContext->V[i]; + } + } +#elif defined(HOST_ARM) + VfpSigFrame* fp = GetNativeSigSimdContext(native); + if (fp) + { + fp->Fpscr = lpContext->Fpscr; + for (int i = 0; i < 32; i++) + { + fp->D[i] = lpContext->D[i]; + } + } +#endif + } + + // TODO: Enable for all Unix systems +#if defined(HOST_AMD64) && defined(XSTATE_SUPPORTED) + if ((lpContext->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE) + { + _ASSERTE(FPREG_HasYmmRegisters(native)); + memcpy_s(FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16, lpContext->VectorRegister, sizeof(M128A) * 16); + } +#endif //HOST_AMD64 && XSTATE_SUPPORTED +} + +/*++ +Function : + CONTEXTFromNativeContext + + Converts a native context to a CONTEXT record. + +Parameters : + const native_context_t *native : native context to convert + LPCONTEXT lpContext : CONTEXT to fill in + ULONG contextFlags : flags that determine which registers are valid in + native and which ones to set in lpContext + +Return value : + None + +--*/ +void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext, + ULONG contextFlags) +{ + lpContext->ContextFlags = contextFlags; + +#define ASSIGN_REG(reg) lpContext->reg = MCREG_##reg(native->uc_mcontext); + if ((contextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + { + ASSIGN_CONTROL_REGS +#if defined(HOST_ARM) + // WinContext assumes that the least bit of Pc is always 1 (denoting thumb) + // although the pc value retrived from native context might not have set the least bit. + // This becomes especially problematic if the context is on the JIT_WRITEBARRIER. + lpContext->Pc |= 0x1; +#endif + } + + if ((contextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + { + ASSIGN_INTEGER_REGS + } +#undef ASSIGN_REG + +#if !HAVE_FPREGS_WITH_CW +#if HAVE_GREGSET_T || HAVE___GREGSET_T +#if HAVE_GREGSET_T + if (native->uc_mcontext.fpregs == nullptr) +#elif HAVE___GREGSET_T + if (native->uc_mcontext.__fpregs == nullptr) +#endif // HAVE_GREGSET_T + { + // Reset the CONTEXT_FLOATING_POINT bit(s) and the CONTEXT_XSTATE bit(s) so it's + // clear that the floating point and extended state data in the CONTEXT is not + // valid. Since these flags are defined as the architecture bit(s) OR'd with one + // or more other bits, we first get the bits that are unique to each by resetting + // the architecture bits. We determine what those are by inverting the union of + // CONTEXT_CONTROL and CONTEXT_INTEGER, both of which should also have the + // architecture bit(s) set. + const ULONG floatingPointFlags = CONTEXT_FLOATING_POINT & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); + const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); + + lpContext->ContextFlags &= ~(floatingPointFlags | xstateFlags); + + // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT or CONTEXT_XSTATE + return; + } +#endif // HAVE_GREGSET_T || HAVE___GREGSET_T +#endif // !HAVE_FPREGS_WITH_CW + + if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) + { +#ifdef HOST_AMD64 + lpContext->FltSave.ControlWord = FPREG_ControlWord(native); + lpContext->FltSave.StatusWord = FPREG_StatusWord(native); +#if HAVE_FPREGS_WITH_CW + lpContext->FltSave.TagWord = ((DWORD)FPREG_TagWord1(native) << 8) | FPREG_TagWord2(native); +#else + lpContext->FltSave.TagWord = FPREG_TagWord(native); +#endif + lpContext->FltSave.ErrorOffset = FPREG_ErrorOffset(native); + lpContext->FltSave.ErrorSelector = FPREG_ErrorSelector(native); + lpContext->FltSave.DataOffset = FPREG_DataOffset(native); + lpContext->FltSave.DataSelector = FPREG_DataSelector(native); + lpContext->FltSave.MxCsr = FPREG_MxCsr(native); + lpContext->FltSave.MxCsr_Mask = FPREG_MxCsr_Mask(native); + + for (int i = 0; i < 8; i++) + { + lpContext->FltSave.FloatRegisters[i] = FPREG_St(native, i); + } + + for (int i = 0; i < 16; i++) + { + lpContext->FltSave.XmmRegisters[i] = FPREG_Xmm(native, i); + } +#elif defined(HOST_ARM64) + const fpsimd_context* fp = GetConstNativeSigSimdContext(native); + if (fp) + { + lpContext->Fpsr = fp->fpsr; + lpContext->Fpcr = fp->fpcr; + for (int i = 0; i < 32; i++) + { + lpContext->V[i] = *(NEON128*) &fp->vregs[i]; + } + } +#elif defined(HOST_ARM) + const VfpSigFrame* fp = GetConstNativeSigSimdContext(native); + if (fp) + { + lpContext->Fpscr = fp->Fpscr; + for (int i = 0; i < 32; i++) + { + lpContext->D[i] = fp->D[i]; + } + } + else + { + // Floating point state is not valid + // Mark the context correctly + lpContext->ContextFlags &= ~(ULONG)CONTEXT_FLOATING_POINT; + } +#endif + } + +#ifdef HOST_AMD64 + if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE) + { + // TODO: Enable for all Unix systems +#if XSTATE_SUPPORTED + if (FPREG_HasYmmRegisters(native)) + { + memcpy_s(lpContext->VectorRegister, sizeof(M128A) * 16, FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16); + } + else +#endif // XSTATE_SUPPORTED + { + // Reset the CONTEXT_XSTATE bit(s) so it's clear that the extended state data in + // the CONTEXT is not valid. + const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER); + lpContext->ContextFlags &= ~xstateFlags; + } + } +#endif // HOST_AMD64 +} + + /*++ Function: DBG_FlushInstructionCache: processor-specific portion of