Skip to content

Commit

Permalink
Inject activation via signal on macOS older state
Browse files Browse the repository at this point in the history
  • Loading branch information
janvorli committed Nov 19, 2020
1 parent 38017c3 commit aee81ac
Show file tree
Hide file tree
Showing 6 changed files with 370 additions and 417 deletions.
1 change: 0 additions & 1 deletion src/coreclr/src/pal/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/src/pal/src/configure.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
114 changes: 0 additions & 114 deletions src/coreclr/src/pal/src/exception/machexception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
39 changes: 25 additions & 14 deletions src/coreclr/src/pal/src/exception/signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -686,7 +696,6 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
}
}

#if !HAVE_MACH_EXCEPTIONS
#ifdef INJECT_ACTIVATION_SIGNAL
/*++
Function :
Expand Down Expand Up @@ -779,6 +788,8 @@ PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
#endif
}

#if !HAVE_MACH_EXCEPTIONS

/*++
Function :
signal_ignore_handler
Expand Down
Loading

0 comments on commit aee81ac

Please sign in to comment.