diff --git a/CMakeLists.txt b/CMakeLists.txt index 1dbb3c85495d..543e4ffb239b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -545,9 +545,7 @@ if(WIN32) endif(WIN32) add_definitions(-DFEATURE_EXCEPTIONDISPATCHINFO) add_definitions(-DFEATURE_FRAMEWORK_INTERNAL) -if(WIN32 OR (CLR_CMAKE_PLATFORM_LINUX AND CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64)) - add_definitions(-DFEATURE_HIJACK) -endif(WIN32 OR (CLR_CMAKE_PLATFORM_LINUX AND CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64)) +add_definitions(-DFEATURE_HIJACK) add_definitions(-DFEATURE_HOST_ASSEMBLY_RESOLVER) add_definitions(-DFEATURE_HOSTED_BINDER) if(WIN32) diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index 26252c264260..6f88513d2909 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -5446,12 +5446,14 @@ PALAPI FlushProcessWriteBuffers(); typedef void (*PAL_ActivationFunction)(CONTEXT *context); +typedef BOOL (*PAL_SafeActivationCheckFunction)(SIZE_T ip); PALIMPORT VOID PALAPI PAL_SetActivationFunction( - IN PAL_ActivationFunction pActivationFunction); + IN PAL_ActivationFunction pActivationFunction, + IN PAL_SafeActivationCheckFunction pSafeActivationCheckFunction); PALIMPORT BOOL diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt index c814e10aac1d..854655621f53 100644 --- a/src/pal/src/CMakeLists.txt +++ b/src/pal/src/CMakeLists.txt @@ -40,6 +40,7 @@ endif() if(CMAKE_SYSTEM_NAME STREQUAL Darwin) add_definitions(-D_TARGET_MAC64) set(PLATFORM_SOURCES + arch/i386/activationhandlerwrapper.S arch/i386/context.S arch/i386/dispatchexceptionwrapper.S exception/machexception.cpp diff --git a/src/pal/src/arch/i386/activationhandlerwrapper.S b/src/pal/src/arch/i386/activationhandlerwrapper.S new file mode 100644 index 000000000000..06151b3d12f4 --- /dev/null +++ b/src/pal/src/arch/i386/activationhandlerwrapper.S @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +.intel_syntax noprefix +#include "unixasmmacros.inc" +#include "asmconstants.h" + +#ifdef BIT64 +// Offset of the return address from the ActivationHandler in the ActivationHandlerWrapper +.globl C_FUNC(ActivationHandlerReturnOffset) +C_FUNC(ActivationHandlerReturnOffset): + .int LOCAL_LABEL(ActivationHandlerReturn)-C_FUNC(ActivationHandlerWrapper) + +NESTED_ENTRY ActivationHandlerWrapper, _TEXT, NoHandler + push_nonvol_reg rbp + mov rbp, rsp + set_cfa_register rbp, 0 + alloc_stack (CONTEXT_Size) + mov rdi, rsp + int3 + call C_FUNC(ActivationHandler) +LOCAL_LABEL(ActivationHandlerReturn): + int3 + free_stack (CONTEXT_Size) + pop_nonvol_reg rbp + ret +NESTED_END ActivationHandlerWrapper, _TEXT + +#endif // BIT64 diff --git a/src/pal/src/arch/i386/asmconstants.h b/src/pal/src/arch/i386/asmconstants.h new file mode 100644 index 000000000000..575edc2308d0 --- /dev/null +++ b/src/pal/src/arch/i386/asmconstants.h @@ -0,0 +1,105 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifdef BIT64 + +#define CONTEXT_AMD64 0x100000 + +#define CONTEXT_CONTROL 1 // SegSs, Rsp, SegCs, Rip, and EFlags +#define CONTEXT_INTEGER 2 // Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, R8-R15 +#define CONTEXT_SEGMENTS 4 // SegDs, SegEs, SegFs, SegGs +#define CONTEXT_FLOATING_POINT 8 +#define CONTEXT_DEBUG_REGISTERS 16 // Dr0-Dr3 and Dr6-Dr7 + +#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) + +#define CONTEXT_ContextFlags 6*8 +#define CONTEXT_SegCs CONTEXT_ContextFlags+8 +#define CONTEXT_SegDs CONTEXT_SegCs+2 +#define CONTEXT_SegEs CONTEXT_SegDs+2 +#define CONTEXT_SegFs CONTEXT_SegEs+2 +#define CONTEXT_SegGs CONTEXT_SegFs+2 +#define CONTEXT_SegSs CONTEXT_SegGs+2 +#define CONTEXT_EFlags CONTEXT_SegSs+2 +#define CONTEXT_Dr0 CONTEXT_EFlags+4 +#define CONTEXT_Dr1 CONTEXT_Dr0+8 +#define CONTEXT_Dr2 CONTEXT_Dr1+8 +#define CONTEXT_Dr3 CONTEXT_Dr2+8 +#define CONTEXT_Dr6 CONTEXT_Dr3+8 +#define CONTEXT_Dr7 CONTEXT_Dr6+8 +#define CONTEXT_Rax CONTEXT_Dr7+8 +#define CONTEXT_Rcx CONTEXT_Rax+8 +#define CONTEXT_Rdx CONTEXT_Rcx+8 +#define CONTEXT_Rbx CONTEXT_Rdx+8 +#define CONTEXT_Rsp CONTEXT_Rbx+8 +#define CONTEXT_Rbp CONTEXT_Rsp+8 +#define CONTEXT_Rsi CONTEXT_Rbp+8 +#define CONTEXT_Rdi CONTEXT_Rsi+8 +#define CONTEXT_R8 CONTEXT_Rdi+8 +#define CONTEXT_R9 CONTEXT_R8+8 +#define CONTEXT_R10 CONTEXT_R9+8 +#define CONTEXT_R11 CONTEXT_R10+8 +#define CONTEXT_R12 CONTEXT_R11+8 +#define CONTEXT_R13 CONTEXT_R12+8 +#define CONTEXT_R14 CONTEXT_R13+8 +#define CONTEXT_R15 CONTEXT_R14+8 +#define CONTEXT_Rip CONTEXT_R15+8 +#define CONTEXT_FltSave CONTEXT_Rip+8 +#define FLOATING_SAVE_AREA_SIZE 4*8+24*16+96 +#define CONTEXT_Xmm0 CONTEXT_FltSave+FLOATING_SAVE_AREA_SIZE // was 10*16 +#define CONTEXT_Xmm1 CONTEXT_Xmm0+16 +#define CONTEXT_Xmm2 CONTEXT_Xmm1+16 +#define CONTEXT_Xmm3 CONTEXT_Xmm2+16 +#define CONTEXT_Xmm4 CONTEXT_Xmm3+16 +#define CONTEXT_Xmm5 CONTEXT_Xmm4+16 +#define CONTEXT_Xmm6 CONTEXT_Xmm5+16 +#define CONTEXT_Xmm7 CONTEXT_Xmm6+16 +#define CONTEXT_Xmm8 CONTEXT_Xmm7+16 +#define CONTEXT_Xmm9 CONTEXT_Xmm8+16 +#define CONTEXT_Xmm10 CONTEXT_Xmm9+16 +#define CONTEXT_Xmm11 CONTEXT_Xmm10+16 +#define CONTEXT_Xmm12 CONTEXT_Xmm11+16 +#define CONTEXT_Xmm13 CONTEXT_Xmm12+16 +#define CONTEXT_Xmm14 CONTEXT_Xmm13+16 +#define CONTEXT_Xmm15 CONTEXT_Xmm14+16 +#define CONTEXT_VectorRegister CONTEXT_Xmm15+16 +#define CONTEXT_VectorControl CONTEXT_VectorRegister+16*26 +#define CONTEXT_DebugControl CONTEXT_VectorControl+8 +#define CONTEXT_LastBranchToRip CONTEXT_DebugControl+8 +#define CONTEXT_LastBranchFromRip CONTEXT_LastBranchToRip+8 +#define CONTEXT_LastExceptionToRip CONTEXT_LastBranchFromRip+8 +#define CONTEXT_LastExceptionFromRip CONTEXT_LastExceptionToRip+8 +#define CONTEXT_Size CONTEXT_LastExceptionFromRip+8 + +#else // BIT64 + +#define CONTEXT_ContextFlags 0 +#define CONTEXT_FLOATING_POINT 8 +#define CONTEXT_FloatSave 7*4 +#define FLOATING_SAVE_AREA_SIZE 8*4+80 +#define CONTEXT_Edi CONTEXT_FloatSave + FLOATING_SAVE_AREA_SIZE + 4*4 +#define CONTEXT_Esi CONTEXT_Edi+4 +#define CONTEXT_Ebx CONTEXT_Esi+4 +#define CONTEXT_Edx CONTEXT_Ebx+4 +#define CONTEXT_Ecx CONTEXT_Edx+4 +#define CONTEXT_Eax CONTEXT_Ecx+4 +#define CONTEXT_Ebp CONTEXT_Eax+4 +#define CONTEXT_Eip CONTEXT_Ebp+4 +#define CONTEXT_SegCs CONTEXT_Eip+4 +#define CONTEXT_EFlags CONTEXT_SegCs+4 +#define CONTEXT_Esp CONTEXT_EFlags+4 +#define CONTEXT_SegSs CONTEXT_Esp+4 +#define CONTEXT_EXTENDED_REGISTERS 32 +#define CONTEXT_ExtendedRegisters CONTEXT_SegSs+4 +#define CONTEXT_Xmm0 CONTEXT_ExtendedRegisters+160 +#define CONTEXT_Xmm1 CONTEXT_Xmm0+16 +#define CONTEXT_Xmm2 CONTEXT_Xmm1+16 +#define CONTEXT_Xmm3 CONTEXT_Xmm2+16 +#define CONTEXT_Xmm4 CONTEXT_Xmm3+16 +#define CONTEXT_Xmm5 CONTEXT_Xmm4+16 +#define CONTEXT_Xmm6 CONTEXT_Xmm5+16 +#define CONTEXT_Xmm7 CONTEXT_Xmm6+16 + +#endif // BIT64 diff --git a/src/pal/src/arch/i386/context2.S b/src/pal/src/arch/i386/context2.S index 27875b722ae4..e6b0c2fe39dd 100644 --- a/src/pal/src/arch/i386/context2.S +++ b/src/pal/src/arch/i386/context2.S @@ -10,76 +10,10 @@ .intel_syntax noprefix #include "unixasmmacros.inc" +#include "asmconstants.h" #ifdef BIT64 -#define CONTEXT_AMD64 0x100000 - -#define CONTEXT_CONTROL 1 // SegSs, Rsp, SegCs, Rip, and EFlags -#define CONTEXT_INTEGER 2 // Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, R8-R15 -#define CONTEXT_SEGMENTS 4 // SegDs, SegEs, SegFs, SegGs -#define CONTEXT_FLOATING_POINT 8 -#define CONTEXT_DEBUG_REGISTERS 16 // Dr0-Dr3 and Dr6-Dr7 - -#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT) - -#define CONTEXT_ContextFlags 6*8 -#define CONTEXT_SegCs CONTEXT_ContextFlags+8 -#define CONTEXT_SegDs CONTEXT_SegCs+2 -#define CONTEXT_SegEs CONTEXT_SegDs+2 -#define CONTEXT_SegFs CONTEXT_SegEs+2 -#define CONTEXT_SegGs CONTEXT_SegFs+2 -#define CONTEXT_SegSs CONTEXT_SegGs+2 -#define CONTEXT_EFlags CONTEXT_SegSs+2 -#define CONTEXT_Dr0 CONTEXT_EFlags+4 -#define CONTEXT_Dr1 CONTEXT_Dr0+8 -#define CONTEXT_Dr2 CONTEXT_Dr1+8 -#define CONTEXT_Dr3 CONTEXT_Dr2+8 -#define CONTEXT_Dr6 CONTEXT_Dr3+8 -#define CONTEXT_Dr7 CONTEXT_Dr6+8 -#define CONTEXT_Rax CONTEXT_Dr7+8 -#define CONTEXT_Rcx CONTEXT_Rax+8 -#define CONTEXT_Rdx CONTEXT_Rcx+8 -#define CONTEXT_Rbx CONTEXT_Rdx+8 -#define CONTEXT_Rsp CONTEXT_Rbx+8 -#define CONTEXT_Rbp CONTEXT_Rsp+8 -#define CONTEXT_Rsi CONTEXT_Rbp+8 -#define CONTEXT_Rdi CONTEXT_Rsi+8 -#define CONTEXT_R8 CONTEXT_Rdi+8 -#define CONTEXT_R9 CONTEXT_R8+8 -#define CONTEXT_R10 CONTEXT_R9+8 -#define CONTEXT_R11 CONTEXT_R10+8 -#define CONTEXT_R12 CONTEXT_R11+8 -#define CONTEXT_R13 CONTEXT_R12+8 -#define CONTEXT_R14 CONTEXT_R13+8 -#define CONTEXT_R15 CONTEXT_R14+8 -#define CONTEXT_Rip CONTEXT_R15+8 -#define CONTEXT_FltSave CONTEXT_Rip+8 -#define FLOATING_SAVE_AREA_SIZE 4*8+24*16+96 -#define CONTEXT_Xmm0 CONTEXT_FltSave+10*16 -#define CONTEXT_Xmm1 CONTEXT_Xmm0+16 -#define CONTEXT_Xmm2 CONTEXT_Xmm1+16 -#define CONTEXT_Xmm3 CONTEXT_Xmm2+16 -#define CONTEXT_Xmm4 CONTEXT_Xmm3+16 -#define CONTEXT_Xmm5 CONTEXT_Xmm4+16 -#define CONTEXT_Xmm6 CONTEXT_Xmm5+16 -#define CONTEXT_Xmm7 CONTEXT_Xmm6+16 -#define CONTEXT_Xmm8 CONTEXT_Xmm7+16 -#define CONTEXT_Xmm9 CONTEXT_Xmm8+16 -#define CONTEXT_Xmm10 CONTEXT_Xmm9+16 -#define CONTEXT_Xmm11 CONTEXT_Xmm10+16 -#define CONTEXT_Xmm12 CONTEXT_Xmm11+16 -#define CONTEXT_Xmm13 CONTEXT_Xmm12+16 -#define CONTEXT_Xmm14 CONTEXT_Xmm13+16 -#define CONTEXT_Xmm15 CONTEXT_Xmm14+16 -#define CONTEXT_VectorRegister CONTEXT_Xmm15+16 -#define CONTEXT_VectorControl CONTEXT_VectorRegister+16*26 -#define CONTEXT_DebugControl CONTEXT_VectorControl+8 -#define CONTEXT_LastBranchToRip CONTEXT_DebugControl+8 -#define CONTEXT_LastBranchFromRip CONTEXT_LastBranchToRip+8 -#define CONTEXT_LastExceptionToRip CONTEXT_LastBranchFromRip+8 -#define CONTEXT_LastExceptionFromRip CONTEXT_LastExceptionToRip+8 - #define IRETFRAME_Rip 0 #define IRETFRAME_SegCs IRETFRAME_Rip+8 #define IRETFRAME_EFlags IRETFRAME_SegCs+8 @@ -198,7 +132,16 @@ LOCAL_LABEL(Done_Restore_CONTEXT_FLOATING_POINT): // The control registers are restored via the iret instruction // so we build the frame for the iret on the stack. +#ifdef __APPLE__ +.att_syntax + // On OSX, we cannot read SS via the thread_get_context and RtlRestoreContext + // needs to be used on context extracted by thread_get_context. So we + // don't change the SS. + mov %ss, %ax +.intel_syntax noprefix +#else mov ax, [rdi + CONTEXT_SegSs] +#endif mov [rsp + IRETFRAME_SegSs], ax mov rax, [rdi + CONTEXT_Rsp] mov [rsp + IRETFRAME_Rsp], rax @@ -249,33 +192,6 @@ LEAF_END RtlRestoreContext, _TEXT #else -#define CONTEXT_ContextFlags 0 -#define CONTEXT_FLOATING_POINT 8 -#define CONTEXT_FloatSave 7*4 -#define FLOATING_SAVE_AREA_SIZE 8*4+80 -#define CONTEXT_Edi CONTEXT_FloatSave + FLOATING_SAVE_AREA_SIZE + 4*4 -#define CONTEXT_Esi CONTEXT_Edi+4 -#define CONTEXT_Ebx CONTEXT_Esi+4 -#define CONTEXT_Edx CONTEXT_Ebx+4 -#define CONTEXT_Ecx CONTEXT_Edx+4 -#define CONTEXT_Eax CONTEXT_Ecx+4 -#define CONTEXT_Ebp CONTEXT_Eax+4 -#define CONTEXT_Eip CONTEXT_Ebp+4 -#define CONTEXT_SegCs CONTEXT_Eip+4 -#define CONTEXT_EFlags CONTEXT_SegCs+4 -#define CONTEXT_Esp CONTEXT_EFlags+4 -#define CONTEXT_SegSs CONTEXT_Esp+4 -#define CONTEXT_EXTENDED_REGISTERS 32 -#define CONTEXT_ExtendedRegisters CONTEXT_SegSs+4 -#define CONTEXT_Xmm0 CONTEXT_ExtendedRegisters+160 -#define CONTEXT_Xmm1 CONTEXT_Xmm0+16 -#define CONTEXT_Xmm2 CONTEXT_Xmm1+16 -#define CONTEXT_Xmm3 CONTEXT_Xmm2+16 -#define CONTEXT_Xmm4 CONTEXT_Xmm3+16 -#define CONTEXT_Xmm5 CONTEXT_Xmm4+16 -#define CONTEXT_Xmm6 CONTEXT_Xmm5+16 -#define CONTEXT_Xmm7 CONTEXT_Xmm6+16 - .globl C_FUNC(CONTEXT_CaptureContext) C_FUNC(CONTEXT_CaptureContext): push %eax diff --git a/src/pal/src/arch/i386/dispatchexceptionwrapper.S b/src/pal/src/arch/i386/dispatchexceptionwrapper.S index 952e5a0cbb3a..c8382e968d0f 100644 --- a/src/pal/src/arch/i386/dispatchexceptionwrapper.S +++ b/src/pal/src/arch/i386/dispatchexceptionwrapper.S @@ -13,10 +13,9 @@ // and PAL_DispatchException that throws an SEH exception for // the fault, to make the stack unwindable. // -// On Mac OS X 10.6, the unwinder fails to operate correctly -// on our original int3; int3 body. The workaround is to -// increase the size of the function to include a call statement, -// even though it will never be executed. + +.intel_syntax noprefix +#include "unixasmmacros.inc" #if defined(__x86_64__) #define PAL_DISPATCHEXCEPTION __Z21PAL_DispatchExceptionmmmmmmP8_CONTEXTP17_EXCEPTION_RECORD @@ -24,33 +23,16 @@ #define PAL_DISPATCHEXCEPTION __Z21PAL_DispatchExceptionP8_CONTEXTP17_EXCEPTION_RECORD #endif // defined(_AMD64_) - .text - .globl __Z21PAL_DispatchExceptionP8_CONTEXTP17_EXCEPTION_RECORD - .globl _PAL_DispatchExceptionWrapper -_PAL_DispatchExceptionWrapper: -LBegin: - int3 - call PAL_DISPATCHEXCEPTION - int3 -LEnd: +// Offset of the return address from the PAL_DISPATCHEXCEPTION in the PAL_DispatchExceptionWrapper +.globl C_FUNC(PAL_DispatchExceptionReturnOffset) +C_FUNC(PAL_DispatchExceptionReturnOffset): + .int LOCAL_LABEL(PAL_DispatchExceptionReturn)-C_FUNC(PAL_DispatchExceptionWrapper) // // PAL_DispatchExceptionWrapper will never be called; it only serves // to be referenced from a stack frame on the faulting thread. Its // unwinding behavior is equivalent to any standard function having -// an ebp frame. The FDE below is analogous to the one generated -// by "g++ -S" for the following source file. -// -// --- snip --- -// struct CONTEXT -// { -// char reserved[716]; -// }; -// -// struct EXCEPTION_RECORD -// { -// char reserved[80]; -// }; +// an ebp frame. It is analogous to the following source file. // // void PAL_DispatchException(CONTEXT *pContext, EXCEPTION_RECORD *pExceptionRecord); // @@ -60,74 +42,17 @@ LEnd: // EXCEPTION_RECORD ExceptionRecord; // PAL_DispatchException(&Context, &ExceptionRecord); // } -// --- snip --- // - .section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -CIE_DispatchExceptionPersonality: - .long LECIE1-LSCIE1 -LSCIE1: - .long 0x0 - .byte 0x1 - .ascii "zLR\0" - .byte 0x1 -#ifdef BIT64 - .byte 0x78 // data_align: -8 - .byte 16 // return address register: rip -#else // BIT64 - .byte 0x7c // data_align: -4 - .byte 0x8 // return address register: eip -#endif // BIT64 else - .byte 0x2 - .byte 0x10 - .byte 0x10 - .byte 0xc // DW_CFA_def_cfa -#ifdef BIT64 - .byte 0x7 // operand1 = rsp - .byte 0x8 // operand2 = offset 8 - .byte 0x80 | 16 // DW_CFA_offset of return address register -#else // BIT64 - .byte 0x5 // operand1 = esp - .byte 0x4 // operand2 = offset 4 - .byte 0x80 | 8 // DW_CFA_offset of return address register -#endif // BIT64 else - .byte 0x1 // operand1 = 1 word - .align 2 -LECIE1: +NESTED_ENTRY PAL_DispatchExceptionWrapper, _TEXT, NoHandler + push_nonvol_reg rbp + mov rbp, rsp + set_cfa_register rbp, 0 + int3 + call PAL_DISPATCHEXCEPTION +LOCAL_LABEL(PAL_DispatchExceptionReturn): + int3 + pop_nonvol_reg rbp + ret +NESTED_END PAL_DispatchExceptionWrapper, _TEXT - .globl _PAL_DispatchExceptionWrapper.eh -_PAL_DispatchExceptionWrapper.eh: -LSFDE1: - .set LLFDE1,LEFDE1-LASFDE1 - .set LLength,LEnd-LBegin - .long LLFDE1 -LASFDE1: - .long LASFDE1-CIE_DispatchExceptionPersonality -#ifdef BIT64 - .quad LBegin-. - .quad LLength - .byte 0x8 - .quad 0x0 -#else // BIT64 - .long LBegin-. - .long LLength - .byte 0x4 - .long 0x0 -#endif // BIT64 else - .byte 0xe // DW_CFA_def_cfa_offset -#ifdef BIT64 - .byte 0x10 - .byte 0x80 | 6 // DW_CFA_offset rbp -#else // BIT64 - .byte 0x8 - .byte 0x80 | 4 // DW_CFA_offset ebp -#endif // BIT64 else - .byte 0x2 - .byte 0xd // DW_CFA_def_cfa_register -#ifdef BIT64 - .byte 6 // operand1 = rbp -#else // BIT64 - .byte 4 // operand1 = ebp -#endif // BIT64 - .align 2 -LEFDE1: diff --git a/src/pal/src/debug/debug.cpp b/src/pal/src/debug/debug.cpp index f0376ce771ef..6c36011ecf91 100644 --- a/src/pal/src/debug/debug.cpp +++ b/src/pal/src/debug/debug.cpp @@ -435,7 +435,6 @@ GetThreadContext( ret = CONTEXT_GetThreadContext( GetCurrentProcessId(), pTargetThread->GetPThreadSelf(), - pTargetThread->GetLwpId(), lpContext ); } @@ -498,7 +497,6 @@ SetThreadContext( ret = CONTEXT_SetThreadContext( GetCurrentProcessId(), pTargetThread->GetPThreadSelf(), - pTargetThread->GetLwpId(), lpContext ); } diff --git a/src/pal/src/exception/machexception.cpp b/src/pal/src/exception/machexception.cpp index d4350c748943..201aa80b9c89 100644 --- a/src/pal/src/exception/machexception.cpp +++ b/src/pal/src/exception/machexception.cpp @@ -238,7 +238,7 @@ PAL_ERROR CorUnix::CPalThread::EnableMachExceptions() NONPAL_TRACE("Enabling %s handlers for thread %08X\n", hExceptionPort == s_TopExceptionPort ? "top" : "bottom", - pthread_mach_thread_np(GetPThreadSelf())); + GetMachPortSelf()); // Swap current handlers into temporary storage first. That's because it's possible (even likely) that // some or all of the handlers might still be ours. In those cases we don't want to overwrite the @@ -541,6 +541,7 @@ void PAL_DispatchException(DWORD64 dwRDI, DWORD64 dwRSI, DWORD64 dwRDX, DWORD64 #if defined(_X86_) || defined(_AMD64_) extern "C" void PAL_DispatchExceptionWrapper(); +extern "C" int PAL_DispatchExceptionReturnOffset; #endif // _X86_ || _AMD64_ /*++ @@ -932,7 +933,7 @@ catch_exception_raise( FramePointer[0] = pContext; FramePointer[1] = pExceptionRecord; // Place the return address to right after the fake call in PAL_DispatchExceptionWrapper - FramePointer[-1] = (void *)((ULONG_PTR)PAL_DispatchExceptionWrapper + 6); + FramePointer[-1] = (void *)((ULONG_PTR)PAL_DispatchExceptionWrapper + PAL_DispatchExceptionReturnOffset); // Make the instruction register point to DispatchException ThreadState.eip = (unsigned)PAL_DispatchException; @@ -1287,9 +1288,25 @@ void *SEHExceptionThread(void *args) CONTEXT sContext; hThread = sMessage.GetThreadContext(&sContext); - MachRet = thread_suspend(hThread); - CHECK_MACH("thread_suspend", MachRet); + while (true) + { + MachRet = thread_suspend(hThread); + CHECK_MACH("thread_suspend", MachRet); + + // Ensure that if the thread was running in the kernel, the kernel operation + // is safely aborted so that it can be restarted later. + MachRet = thread_abort_safely(hThread); + if (MachRet == KERN_SUCCESS) + { + break; + } + // The thread was running in the kernel executing a non-atomic operation + // that cannot be restarted, so we need to resume the thread and retry + MachRet = thread_resume(hThread); + CHECK_MACH("thread_resume", MachRet); + } + MachRet = CONTEXT_SetThreadContextOnPort(hThread, &sContext); CHECK_MACH("CONTEXT_SetThreadContextOnPort", MachRet); @@ -1757,4 +1774,90 @@ void SEHCleanupExceptionPort(void) s_DebugInitialized = FALSE; } +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; + +PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread) +{ + PAL_ERROR palError; + CPalThread *pCurrentThread = InternalGetCurrentThread(); + DWORD dwSuspendCount; + + palError = pCurrentThread->suspensionInfo.InternalSuspendThreadFromData( + pCurrentThread, + pThread, + &dwSuspendCount + ); + + if (palError == NO_ERROR) + { + mach_port_t thread = pThread->GetMachPortSelf(); + x86_thread_state64_t ThreadState; + mach_msg_type_number_t count = sizeof(ThreadState)/sizeof(natural_t); + kern_return_t MachRet; + + MachRet = thread_get_state(thread, + x86_THREAD_STATE64, + (thread_state_t)&ThreadState, + &count); + _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_get_state\n"); + + if ((g_safeActivationCheckFunction != NULL) && g_safeActivationCheckFunction(ThreadState.__rip)) + { + // 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; + MachRet = CONTEXT_GetThreadContextFromPort(thread, 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(thread, + x86_THREAD_STATE64, + (thread_state_t)&ThreadState, + count); + _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_set_state\n"); + } + + palError = pCurrentThread->suspensionInfo.InternalResumeThreadFromData( + pCurrentThread, + pThread, + &dwSuspendCount + ); + } + else + { + printf("Suspension failed with error 0x%x\n", palError); + } + + return palError; +} + #endif // HAVE_MACH_EXCEPTIONS diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp index 444639a9579d..d11d5ffd2cd6 100644 --- a/src/pal/src/exception/signal.cpp +++ b/src/pal/src/exception/signal.cpp @@ -101,9 +101,6 @@ int g_signalPipe[2] = { 0, 0 }; DWORD g_dwExternalSignalHandlerThreadId = 0; -// Activation function that gets called when an activation is injected into a thread. -PAL_ActivationFunction g_activationFunction = NULL; - /* public function definitions ************************************************/ /*++ @@ -568,28 +565,6 @@ static void sigbus_handler(int code, siginfo_t *siginfo, void *context) } } -/*++ -Function: - PAL_SetActivationFunction - - Register an activation function that gets called when an activation is injected - into a thread. - -Parameters: - pActivationFunction - activation function - -Return value: - None ---*/ -PALIMPORT -VOID -PALAPI -PAL_SetActivationFunction( - IN PAL_ActivationFunction pActivationFunction) -{ - g_activationFunction = pActivationFunction; -} - /*++ Function : inject_activation_handler @@ -609,6 +584,8 @@ static void inject_activation_handler(int code, siginfo_t *siginfo, void *contex { if (g_activationFunction != NULL) { + _ASSERTE(g_safeActivationCheckFunction != NULL); + native_context_t *ucontext = (native_context_t *)context; CONTEXT winContext; @@ -617,7 +594,10 @@ static void inject_activation_handler(int code, siginfo_t *siginfo, void *contex &winContext, CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT); - g_activationFunction(&winContext); + if (g_safeActivationCheckFunction(winContext.Rip)) + { + g_activationFunction(&winContext); + } // Activation function may have modified the context, so update it. CONTEXTToNativeContext(&winContext, ucontext); @@ -637,7 +617,7 @@ Parameters : (no return value) --*/ -void InjectActivationInternal(CorUnix::CPalThread* pThread) +PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread) { int status = pthread_kill(pThread->GetPThreadSelf(), INJECT_ACTIVATION_SIGNAL); if (status != 0) @@ -647,62 +627,8 @@ void InjectActivationInternal(CorUnix::CPalThread* pThread) // if the thread doesn't exist anymore. abort(); } -} - -/*++ -Function: -PAL_InjectActivation - -Interrupt the specified thread and have it call an activation function registered -using the PAL_SetActivationFunction - -Parameters: -hThread - handle of the target thread - -Return: -TRUE if it succeeded, FALSE otherwise. ---*/ -BOOL -PALAPI -PAL_InjectActivation( - IN HANDLE hThread) -{ - PERF_ENTRY(PAL_InjectActivation); - ENTRY("PAL_InjectActivation(hThread=%p)\n", hThread); - - CPalThread *pCurrentThread; - CPalThread *pTargetThread; - IPalObject *pobjThread = NULL; - - pCurrentThread = InternalGetCurrentThread(); - - PAL_ERROR palError = InternalGetThreadDataFromHandle( - pCurrentThread, - hThread, - 0, - &pTargetThread, - &pobjThread - ); - - if (palError == NO_ERROR) - { - InjectActivationInternal(pTargetThread); - } - else - { - pCurrentThread->SetLastError(palError); - } - - if (pobjThread != NULL) - { - pobjThread->ReleaseReference(pCurrentThread); - } - - BOOL success = (palError == NO_ERROR); - LOGEXIT("PAL_InjectActivation returns:d\n", success); - PERF_EXIT(PAL_InjectActivation); - return success; + return NO_ERROR; } /*++ diff --git a/src/pal/src/include/pal/context.h b/src/pal/src/include/pal/context.h index 5f0718725b63..51dcedfcd2fc 100644 --- a/src/pal/src/include/pal/context.h +++ b/src/pal/src/include/pal/context.h @@ -371,7 +371,6 @@ BOOL CONTEXT_SetThreadContext( DWORD dwProcessId, pthread_t self, - DWORD dwLwpId, CONST CONTEXT *lpContext ); @@ -393,7 +392,6 @@ BOOL CONTEXT_GetThreadContext( DWORD dwProcessId, pthread_t self, - DWORD dwLwpId, LPCONTEXT lpContext); #if HAVE_MACH_EXCEPTIONS diff --git a/src/pal/src/include/pal/thread.hpp b/src/pal/src/include/pal/thread.hpp index 24739eb56db0..f84ee6eadae1 100644 --- a/src/pal/src/include/pal/thread.hpp +++ b/src/pal/src/include/pal/thread.hpp @@ -314,6 +314,10 @@ namespace CorUnix DWORD m_dwLwpId; pthread_t m_pthreadSelf; +#if HAVE_MACH_THREADS + mach_port_t m_machPortSelf; +#endif + // // Start info // @@ -394,6 +398,9 @@ namespace CorUnix m_threadId(0), m_dwLwpId(0), m_pthreadSelf(0), +#if HAVE_MACH_THREADS + m_machPortSelf(0), +#endif m_lpStartAddress(NULL), m_lpStartParameter(NULL), m_bCreateSuspended(FALSE), @@ -548,6 +555,16 @@ namespace CorUnix return m_pthreadSelf; }; +#if HAVE_MACH_THREADS + mach_port_t + GetMachPortSelf( + void + ) + { + return m_machPortSelf; + }; +#endif + LPTHREAD_START_ROUTINE GetStartAddress( void @@ -746,6 +763,9 @@ WaitForEndingThreads( extern int free_threads_spinlock; +extern PAL_ActivationFunction g_activationFunction; +extern PAL_SafeActivationCheckFunction g_safeActivationCheckFunction; + /*++ Macro: THREADSilentGetCurrentThreadId diff --git a/src/pal/src/thread/context.cpp b/src/pal/src/thread/context.cpp index b8b343c96ac3..6006aad01c07 100644 --- a/src/pal/src/thread/context.cpp +++ b/src/pal/src/thread/context.cpp @@ -272,7 +272,6 @@ BOOL CONTEXT_GetThreadContext( DWORD dwProcessId, pthread_t self, - DWORD dwLwpId, LPCONTEXT lpContext) { BOOL ret = FALSE; @@ -343,7 +342,6 @@ BOOL CONTEXT_SetThreadContext( DWORD dwProcessId, pthread_t self, - DWORD dwLwpId, CONST CONTEXT *lpContext) { BOOL ret = FALSE; @@ -999,7 +997,6 @@ BOOL CONTEXT_GetThreadContext( DWORD dwProcessId, pthread_t self, - DWORD dwLwpId, LPCONTEXT lpContext) { BOOL ret = FALSE; @@ -1232,7 +1229,6 @@ BOOL CONTEXT_SetThreadContext( DWORD dwProcessId, pthread_t self, - DWORD dwLwpId, CONST CONTEXT *lpContext) { BOOL ret = FALSE; diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp index 0e177ff1fee1..fcca7e3b5832 100644 --- a/src/pal/src/thread/process.cpp +++ b/src/pal/src/thread/process.cpp @@ -4043,8 +4043,7 @@ CorUnix::CPalThread *PROCThreadFromMachPort(mach_port_t hTargetThread) pThread = pGThreadList; while (pThread) { - pthread_t pPThread = pThread->GetPThreadSelf(); - mach_port_t hThread = pthread_mach_thread_np(pPThread); + mach_port_t hThread = pThread->GetMachPortSelf(); if (hThread == hTargetThread) break; diff --git a/src/pal/src/thread/thread.cpp b/src/pal/src/thread/thread.cpp index 33dbfbc91416..a1c6eb6c1452 100644 --- a/src/pal/src/thread/thread.cpp +++ b/src/pal/src/thread/thread.cpp @@ -20,6 +20,7 @@ Module Name: --*/ #include "pal/corunix.hpp" +#include "pal/context.h" #include "pal/thread.hpp" #include "pal/mutex.hpp" #include "pal/handlemgr.hpp" @@ -85,6 +86,11 @@ pthread_mutex_t ptmEndThread; pthread_cond_t ptcEndThread; static int iEndingThreads = 0; +// Activation function that gets called when an activation is injected into a thread. +PAL_ActivationFunction g_activationFunction = NULL; +// Function to check if an activation can be safely injected at a specified context +PAL_SafeActivationCheckFunction g_safeActivationCheckFunction = NULL; + void ThreadCleanupRoutine( CPalThread *pThread, @@ -1364,7 +1370,7 @@ GetThreadTimes( pthrTarget->Lock(pthrCurrent); mach_port_t mhThread; - mhThread = pthread_mach_thread_np(pthrTarget->GetPThreadSelf()); + mhThread = pthrTarget->GetMachPortSelf(); kern_return_t status; status = thread_info( @@ -1466,6 +1472,9 @@ CPalThread::ThreadEntry( pThread->m_threadId = THREADSilentGetCurrentThreadId(); pThread->m_pthreadSelf = pthread_self(); +#if HAVE_MACH_THREADS + pThread->m_machPortSelf = pthread_mach_thread_np(pThread->m_pthreadSelf); +#endif #if HAVE_THREAD_SELF pThread->m_dwLwpId = (DWORD) thread_self(); #elif HAVE__LWP_SELF @@ -1638,6 +1647,9 @@ CorUnix::CreateThreadData( pThread->m_threadId = THREADSilentGetCurrentThreadId(); pThread->m_pthreadSelf = pthread_self(); +#if HAVE_MACH_THREADS + pThread->m_machPortSelf = pthread_mach_thread_np(pThread->m_pthreadSelf); +#endif #if HAVE_THREAD_SELF pThread->m_dwLwpId = (DWORD) thread_self(); #elif HAVE__LWP_SELF @@ -2491,7 +2503,92 @@ PAL_GetStackLimit() #endif } +PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread); + +/*++ +Function: + PAL_SetActivationFunction + + Register an activation function that gets called when an activation is injected + into a thread. + +Parameters: + pActivationFunction - activation function + pSafeActivationCheckFunction - function to check if an activation can be safely + injected at a specified context +Return value: + None +--*/ +PALIMPORT +VOID +PALAPI +PAL_SetActivationFunction( + IN PAL_ActivationFunction pActivationFunction, + IN PAL_SafeActivationCheckFunction pSafeActivationCheckFunction) +{ + g_activationFunction = pActivationFunction; + g_safeActivationCheckFunction = pSafeActivationCheckFunction; +} + +/*++ +Function: +PAL_InjectActivation + +Interrupt the specified thread and have it call an activation function registered +using the PAL_SetActivationFunction + +Parameters: +hThread - handle of the target thread + +Return: +TRUE if it succeeded, FALSE otherwise. +--*/ +BOOL +PALAPI +PAL_InjectActivation( + IN HANDLE hThread) +{ + PERF_ENTRY(PAL_InjectActivation); + ENTRY("PAL_InjectActivation(hThread=%p)\n", hThread); + + CPalThread *pCurrentThread; + CPalThread *pTargetThread; + IPalObject *pobjThread = NULL; + + pCurrentThread = InternalGetCurrentThread(); + + PAL_ERROR palError = InternalGetThreadDataFromHandle( + pCurrentThread, + hThread, + 0, + &pTargetThread, + &pobjThread + ); + + if (palError == NO_ERROR) + { + palError = InjectActivationInternal(pTargetThread); + } + + if (palError == NO_ERROR) + { + pCurrentThread->SetLastError(palError); + } + + if (pobjThread != NULL) + { + pobjThread->ReleaseReference(pCurrentThread); + } + + BOOL success = (palError == NO_ERROR); + LOGEXIT("PAL_InjectActivation returns:d\n", success); + PERF_EXIT(PAL_InjectActivation); + + return success; +} + #if HAVE_MACH_EXCEPTIONS + extern mach_port_t s_ExceptionPort; extern mach_port_t s_TopExceptionPort; diff --git a/src/pal/src/thread/threadsusp.cpp b/src/pal/src/thread/threadsusp.cpp index e20fc3f054ab..e3d1b01123e0 100644 --- a/src/pal/src/thread/threadsusp.cpp +++ b/src/pal/src/thread/threadsusp.cpp @@ -226,6 +226,14 @@ CThreadSuspensionInfo::InternalSuspendNewThreadFromData( palError = ERROR_INTERNAL_ERROR; } + if (palError == NO_ERROR) + { + AcquireSuspensionLock(pThread); + pThread->suspensionInfo.DecrSuspCount(); + pThread->suspensionInfo.SetSelfSusp(FALSE); + ReleaseSuspensionLock(pThread); + } + // Close the pipes regardless of whether we were successful. close(pipe_descs[0]); close(pipe_descs[1]); @@ -1087,7 +1095,7 @@ CThreadSuspensionInfo::WaitOnSuspendSemaphore() } // If the target has already acknowledged the suspend we shouldn't wait. - if (!m_fSuspended) + while (!m_fSuspended) { // We got here before the target could signal. Wait on them (which atomically releases // the mutex during the wait). @@ -1197,7 +1205,7 @@ CThreadSuspensionInfo::WaitOnResumeSemaphore() } // If the target has already acknowledged the resume we shouldn't wait. - if (!m_fResumed) + while (!m_fResumed) { // We got here before the target could signal. Wait on them (which atomically releases // the mutex during the wait). @@ -1840,43 +1848,62 @@ CThreadSuspensionInfo::THREADHandleSuspendNative(CPalThread *pthrTarget) { pthrTarget->SetStartStatus(TRUE); } - + + BOOL retry = FALSE; + do + { + #if HAVE_PTHREAD_SUSPEND - dwPthreadRet = pthread_suspend(pthrTarget->GetPThreadSelf()); + dwPthreadRet = pthread_suspend(pthrTarget->GetPThreadSelf()); #elif HAVE_MACH_THREADS - dwPthreadRet = thread_suspend(pthread_mach_thread_np(pthrTarget->GetPThreadSelf())); + mach_port_t threadPort = pthrTarget->GetMachPortSelf(); + dwPthreadRet = thread_suspend(threadPort); #elif HAVE_PTHREAD_SUSPEND_NP #if SELF_SUSPEND_FAILS_WITH_NATIVE_SUSPENSION - if (pthrTarget->suspensionInfo.GetSelfSusp()) - { - pthrTarget->suspensionInfo.WaitOnSuspendSemaphore(); - } - else + if (pthrTarget->suspensionInfo.GetSelfSusp()) + { + pthrTarget->suspensionInfo.WaitOnSuspendSemaphore(); + } + else #endif // SELF_SUSPEND_FAILS_WITH_NATIVE_SUSPENSION - { - dwPthreadRet = pthread_suspend_np(pthrTarget->GetPThreadSelf()); - } + { + dwPthreadRet = pthread_suspend_np(pthrTarget->GetPThreadSelf()); + } #else - #error "Don't know how to suspend threads on this platform!" - return FALSE; + #error "Don't know how to suspend threads on this platform!" + return FALSE; #endif - // A self suspending thread that reaches this point would have been resumed - // by a call to THREADHandleResumeNative. The self suspension has been - // completed so it can set its selfsusp flag to FALSE. Reset the selfsusp flag - // before checking the return value in case the suspend itself failed. - if (pthrTarget->suspensionInfo.GetSelfSusp()) - { - pthrTarget->suspensionInfo.SetSelfSusp(FALSE); - } + // A self suspending thread that reaches this point would have been resumed + // by a call to THREADHandleResumeNative. The self suspension has been + // completed so it can set its selfsusp flag to FALSE. Reset the selfsusp flag + // before checking the return value in case the suspend itself failed. + if (pthrTarget->suspensionInfo.GetSelfSusp()) + { + pthrTarget->suspensionInfo.SetSelfSusp(FALSE); + } - if (dwPthreadRet != 0) - { - ASSERT("[THREADHandleSuspendNative] native suspend_thread call failed [thread id=%d thread_state=%d errno=%d (%s)]\n", - pthrTarget->GetThreadId(), pthrTarget->synchronizationInfo.GetThreadState(), - dwPthreadRet, strerror(dwPthreadRet)); - return FALSE; + if (dwPthreadRet != 0) + { + ASSERT("[THREADHandleSuspendNative] native suspend_thread call failed [thread id=%d thread_state=%d errno=%d (%s)]\n", + pthrTarget->GetThreadId(), pthrTarget->synchronizationInfo.GetThreadState(), + dwPthreadRet, strerror(dwPthreadRet)); + return FALSE; + } + +#if HAVE_MACH_THREADS + dwPthreadRet = thread_abort_safely(threadPort); + if (dwPthreadRet != 0) + { + // The thread was suspended in a kernel non-atomic operation that cannot be safely + // restarted, so we need to resume the thread and retry + thread_resume(threadPort); + retry = TRUE; + } +#endif } + while (retry); + return TRUE; } @@ -1920,7 +1947,7 @@ CThreadSuspensionInfo::THREADHandleResumeNative(CPalThread *pthrTarget) #if HAVE_PTHREAD_CONTINUE dwPthreadRet = pthread_continue(pthrTarget->GetPThreadSelf()); #elif HAVE_MACH_THREADS - dwPthreadRet = thread_resume(pthread_mach_thread_np(pthrTarget->GetPThreadSelf())); + dwPthreadRet = thread_resume(pthrTarget->GetMachPortSelf()); #elif HAVE_PTHREAD_CONTINUE_NP dwPthreadRet = pthread_continue_np((pthrTarget->GetPThreadSelf()); #elif HAVE_PTHREAD_RESUME_NP diff --git a/src/vm/threadsuspend.cpp b/src/vm/threadsuspend.cpp index cc9080116d72..10ea699faa14 100644 --- a/src/vm/threadsuspend.cpp +++ b/src/vm/threadsuspend.cpp @@ -8252,6 +8252,13 @@ void ThreadSuspend::SuspendEE(SUSPEND_REASON reason) #if defined(FEATURE_HIJACK) && defined(PLATFORM_UNIX) +// This function is called by PAL to check if the specified instruction pointer +// is in a function where we can safely inject activation. +BOOL PALAPI CheckActivationSafePoint(SIZE_T ip) +{ + return ExecutionManager::IsManagedCode(ip); +} + // This function is called when a GC is pending. It tries to ensure that the current // thread is taken to a GC-safe place as quickly as possible. It does this by doing // one of the following: @@ -8276,8 +8283,9 @@ void PALAPI HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext) PCODE ip = GetIP(interruptedContext); - if (ExecutionManager::IsManagedCode(ip) != TRUE) - return; + // This function can only be called when the interrupted thread is in + // an activation safe point. + _ASSERTE(CheckActivationSafePoint(ip)); Thread::WorkingOnThreadContextHolder workingOnThreadContext(pThread); if (!workingOnThreadContext.Acquired()) @@ -8383,7 +8391,7 @@ bool Thread::InjectGcSuspension() void ThreadSuspend::Initialize() { #if defined(FEATURE_HIJACK) && defined(PLATFORM_UNIX) - ::PAL_SetActivationFunction(HandleGCSuspensionForInterruptedThread); + ::PAL_SetActivationFunction(HandleGCSuspensionForInterruptedThread, CheckActivationSafePoint); #endif }