summaryrefslogtreecommitdiff
path: root/src/pal/src/exception
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/exception')
-rw-r--r--src/pal/src/exception/machexception.cpp7
-rw-r--r--src/pal/src/exception/machmessage.cpp2
-rw-r--r--src/pal/src/exception/machmessage.h4
-rw-r--r--src/pal/src/exception/seh-unwind.cpp76
-rw-r--r--src/pal/src/exception/seh.cpp8
-rw-r--r--src/pal/src/exception/signal.cpp6
6 files changed, 81 insertions, 22 deletions
diff --git a/src/pal/src/exception/machexception.cpp b/src/pal/src/exception/machexception.cpp
index 8b0d7f22a8..5328e1f329 100644
--- a/src/pal/src/exception/machexception.cpp
+++ b/src/pal/src/exception/machexception.cpp
@@ -1518,6 +1518,7 @@ ActivationHandler(CONTEXT* context)
extern "C" void ActivationHandlerWrapper();
extern "C" int ActivationHandlerReturnOffset;
+extern "C" unsigned int XmmYmmStateSupport();
/*++
Function :
@@ -1581,6 +1582,12 @@ InjectActivationInternal(CPalThread* pThread)
// 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");
diff --git a/src/pal/src/exception/machmessage.cpp b/src/pal/src/exception/machmessage.cpp
index a6f7e57484..b786960782 100644
--- a/src/pal/src/exception/machmessage.cpp
+++ b/src/pal/src/exception/machmessage.cpp
@@ -1069,7 +1069,7 @@ thread_act_t MachMessage::GetThreadFromState(thread_state_flavor_t eFlavor, thre
NONPAL_RETAIL_ASSERT("Failed to locate thread from state.");
}
-// Transform a exception handler behavior type into the corresponding Mach message ID for the notification.
+// Transform an exception handler behavior type into the corresponding Mach message ID for the notification.
mach_msg_id_t MachMessage::MapBehaviorToNotificationType(exception_behavior_t eBehavior)
{
switch ((uint)eBehavior)
diff --git a/src/pal/src/exception/machmessage.h b/src/pal/src/exception/machmessage.h
index 244396cd35..abc583f6c4 100644
--- a/src/pal/src/exception/machmessage.h
+++ b/src/pal/src/exception/machmessage.h
@@ -36,7 +36,7 @@ using namespace CorUnix;
if (machret != KERN_SUCCESS) \
{ \
char _szError[1024]; \
- sprintf(_szError, "%s: %u: %s", __FUNCTION__, __LINE__, _msg); \
+ snprintf(_szError, _countof(_szError), "%s: %u: %s", __FUNCTION__, __LINE__, _msg); \
mach_error(_szError, machret); \
abort(); \
} \
@@ -395,7 +395,7 @@ private:
// x86_THREAD_STATE and x86_THREAD_STATE32 state flavors are supported.
thread_act_t GetThreadFromState(thread_state_flavor_t eFlavor, thread_state_t pState);
- // Transform a exception handler behavior type into the corresponding Mach message ID for the
+ // Transform an exception handler behavior type into the corresponding Mach message ID for the
// notification.
mach_msg_id_t MapBehaviorToNotificationType(exception_behavior_t eBehavior);
diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
index 24eebbbf94..fa2f109875 100644
--- a/src/pal/src/exception/seh-unwind.cpp
+++ b/src/pal/src/exception/seh-unwind.cpp
@@ -73,6 +73,14 @@ Abstract:
ASSIGN_REG(X26) \
ASSIGN_REG(X27) \
ASSIGN_REG(X28)
+#elif defined(_X86_)
+#define ASSIGN_UNWIND_REGS \
+ ASSIGN_REG(Eip) \
+ ASSIGN_REG(Esp) \
+ ASSIGN_REG(Ebp) \
+ ASSIGN_REG(Ebx) \
+ ASSIGN_REG(Esi) \
+ ASSIGN_REG(Edi)
#else
#error unsupported architecture
#endif
@@ -122,6 +130,13 @@ static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor)
unw_set_reg(cursor, UNW_X86_64_R13, winContext->R13);
unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14);
unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15);
+#elif defined(_X86_)
+ unw_set_reg(cursor, UNW_REG_IP, winContext->Eip);
+ unw_set_reg(cursor, UNW_REG_SP, winContext->Esp);
+ unw_set_reg(cursor, UNW_X86_EBP, winContext->Ebp);
+ unw_set_reg(cursor, UNW_X86_EBX, winContext->Ebx);
+ unw_set_reg(cursor, UNW_X86_ESI, winContext->Esi);
+ unw_set_reg(cursor, UNW_X86_EDI, winContext->Edi);
#endif
}
#endif
@@ -137,6 +152,13 @@ static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
unw_get_reg(cursor, UNW_X86_64_R13, (unw_word_t *) &winContext->R13);
unw_get_reg(cursor, UNW_X86_64_R14, (unw_word_t *) &winContext->R14);
unw_get_reg(cursor, UNW_X86_64_R15, (unw_word_t *) &winContext->R15);
+#elif defined(_X86_)
+ unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Eip);
+ unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Esp);
+ unw_get_reg(cursor, UNW_X86_EBP, (unw_word_t *) &winContext->Ebp);
+ unw_get_reg(cursor, UNW_X86_EBX, (unw_word_t *) &winContext->Ebx);
+ unw_get_reg(cursor, UNW_X86_ESI, (unw_word_t *) &winContext->Esi);
+ unw_get_reg(cursor, UNW_X86_EDI, (unw_word_t *) &winContext->Edi);
#elif defined(_ARM_)
unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
@@ -196,6 +218,11 @@ static void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext,
GetContextPointer(cursor, unwContext, UNW_X86_64_R13, &contextPointers->R13);
GetContextPointer(cursor, unwContext, UNW_X86_64_R14, &contextPointers->R14);
GetContextPointer(cursor, unwContext, UNW_X86_64_R15, &contextPointers->R15);
+#elif defined(_X86_)
+ GetContextPointer(cursor, unwContext, UNW_X86_EBX, &contextPointers->Ebx);
+ GetContextPointer(cursor, unwContext, UNW_X86_EBP, &contextPointers->Ebp);
+ GetContextPointer(cursor, unwContext, UNW_X86_ESI, &contextPointers->Esi);
+ GetContextPointer(cursor, unwContext, UNW_X86_EDI, &contextPointers->Edi);
#elif defined(_ARM_)
GetContextPointer(cursor, unwContext, UNW_ARM_R4, &contextPointers->R4);
GetContextPointer(cursor, unwContext, UNW_ARM_R5, &contextPointers->R5);
@@ -221,15 +248,34 @@ static void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext,
#endif
}
+extern int g_common_signal_handler_context_locvar_offset;
+
BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
{
int st;
unw_context_t unwContext;
unw_cursor_t cursor;
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_ARM64_) || defined(_ARM_)
- DWORD64 curPc;
-#endif
+ DWORD64 curPc = CONTEXTGetPC(context);
+
+#ifndef __APPLE__
+ // Check if the PC is the return address from the SEHProcessException in the common_signal_handler.
+ // If that's the case, extract its local variable containing the native_context_t of the hardware
+ // exception and return that. This skips the hardware signal handler trampoline that the libunwind
+ // cannot cross on some systems.
+ if ((void*)curPc == g_SEHProcessExceptionReturnAddress)
+ {
+ ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_EXCEPTION_ACTIVE;
+
+ #if defined(_AMD64_)
+ contextFlags |= CONTEXT_XSTATE;
+ #endif
+ size_t nativeContext = *(size_t*)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset);
+ CONTEXTFromNativeContext((const native_context_t *)nativeContext, context, contextFlags);
+
+ return TRUE;
+ }
+#endif
if ((context->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) != 0)
{
@@ -240,7 +286,7 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
// So we compensate it by incrementing the PC before passing it to the unwinder.
// Without it, the unwinder would not find unwind info if the hardware exception
// happened in the first instruction of a function.
- CONTEXTSetPC(context, CONTEXTGetPC(context) + 1);
+ CONTEXTSetPC(context, curPc + 1);
}
#if !UNWIND_CONTEXT_IS_UCONTEXT_T
@@ -264,18 +310,6 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
WinContextToUnwindCursor(context, &cursor);
#endif
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_ARM64_) || defined(_ARM_)
- // FreeBSD, NetBSD and OSX appear to do two different things when unwinding
- // 1: If it reaches where it cannot unwind anymore, say a
- // managed frame. It wil return 0, but also update the $pc
- // 2: If it unwinds all the way to _start it will return
- // 0 from the step, but $pc will stay the same.
- // The behaviour of libunwind from nongnu.org is to null the PC
- // So we bank the original PC here, so we can compare it after
- // the step
- curPc = CONTEXTGetPC(context);
-#endif
-
st = unw_step(&cursor);
if (st < 0)
{
@@ -303,12 +337,18 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
// Update the passed in windows context to reflect the unwind
//
UnwindContextToWinContext(&cursor, context);
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_ARM64_) || defined(_ARM_)
+
+ // FreeBSD, NetBSD, OSX and Alpine appear to do two different things when unwinding
+ // 1: If it reaches where it cannot unwind anymore, say a
+ // managed frame. It will return 0, but also update the $pc
+ // 2: If it unwinds all the way to _start it will return
+ // 0 from the step, but $pc will stay the same.
+ // So we detect that here and set the $pc to NULL in that case.
+ // This is the default behavior of the libunwind on Linux.
if (st == 0 && CONTEXTGetPC(context) == curPc)
{
CONTEXTSetPC(context, 0);
}
-#endif
if (contextPointers != NULL)
{
diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
index 38779bf59b..ad09e02884 100644
--- a/src/pal/src/exception/seh.cpp
+++ b/src/pal/src/exception/seh.cpp
@@ -88,6 +88,10 @@ PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION g_safeExceptionCheckFunction = NULL;
PGET_GCMARKER_EXCEPTION_CODE g_getGcMarkerExceptionCode = NULL;
+// Return address of the SEHProcessException, which is used to enable walking over
+// the signal handler trampoline on some Unixes where the libunwind cannot do that.
+void* g_SEHProcessExceptionReturnAddress = NULL;
+
/* Internal function definitions **********************************************/
/*++
@@ -245,6 +249,8 @@ Return value:
BOOL
SEHProcessException(PAL_SEHException* exception)
{
+ g_SEHProcessExceptionReturnAddress = __builtin_return_address(0);
+
CONTEXT* contextRecord = exception->GetContextRecord();
EXCEPTION_RECORD* exceptionRecord = exception->GetExceptionRecord();
@@ -268,7 +274,7 @@ SEHProcessException(PAL_SEHException* exception)
{
// The exception happened in the page right below the stack limit,
// so it is a stack overflow
- write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
+ (void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
PROCAbort();
}
}
diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
index c2c217993a..26e2a012c5 100644
--- a/src/pal/src/exception/signal.cpp
+++ b/src/pal/src/exception/signal.cpp
@@ -100,6 +100,10 @@ static bool registered_sigterm_handler = false;
struct sigaction g_previous_activation;
#endif
+// Offset of the local variable containing native context in the common_signal_handler function.
+// This offset is relative to the frame pointer.
+int g_common_signal_handler_context_locvar_offset = 0;
+
/* public function definitions ************************************************/
/*++
@@ -582,6 +586,7 @@ Note:
the "pointers" parameter should contain a valid exception record pointer,
but the ContextRecord pointer will be overwritten.
--*/
+__attribute__((noinline))
static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
{
sigset_t signal_set;
@@ -590,6 +595,7 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
native_context_t *ucontext;
ucontext = (native_context_t *)sigcontext;
+ g_common_signal_handler_context_locvar_offset = (int)((char*)&ucontext - (char*)__builtin_frame_address(0));
AllocateExceptionRecords(&exceptionRecord, &contextRecord);