summaryrefslogtreecommitdiff
path: root/src/pal/src/arch
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2017-04-13 14:17:19 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2017-04-13 14:17:19 +0900
commita56e30c8d33048216567753d9d3fefc2152af8ac (patch)
tree7e5d979695fc4a431740982eb1cfecc2898b23a5 /src/pal/src/arch
parent4b11dc566a5bbfa1378d6266525c281b028abcc8 (diff)
downloadcoreclr-upstream/2.0.0.11353.tar.gz
coreclr-upstream/2.0.0.11353.tar.bz2
coreclr-upstream/2.0.0.11353.zip
Imported Upstream version 2.0.0.11353upstream/2.0.0.11353
Diffstat (limited to 'src/pal/src/arch')
-rw-r--r--src/pal/src/arch/amd64/callsignalhandlerwrapper.S31
-rw-r--r--src/pal/src/arch/amd64/optimizedtls.cpp237
-rw-r--r--src/pal/src/arch/amd64/signalhandlerhelper.cpp70
-rw-r--r--src/pal/src/arch/arm/callsignalhandlerwrapper.S32
-rw-r--r--src/pal/src/arch/arm/signalhandlerhelper.cpp70
-rw-r--r--src/pal/src/arch/arm64/asmconstants.h95
-rw-r--r--src/pal/src/arch/arm64/callsignalhandlerwrapper.S32
-rw-r--r--src/pal/src/arch/arm64/context2.S114
-rw-r--r--src/pal/src/arch/arm64/exceptionhelper.S25
-rw-r--r--src/pal/src/arch/arm64/signalhandlerhelper.cpp67
-rw-r--r--src/pal/src/arch/i386/asmconstants.h1
-rw-r--r--src/pal/src/arch/i386/callsignalhandlerwrapper.S47
-rw-r--r--src/pal/src/arch/i386/context2.S5
-rw-r--r--src/pal/src/arch/i386/exceptionhelper.S19
-rw-r--r--src/pal/src/arch/i386/signalhandlerhelper.cpp78
15 files changed, 568 insertions, 355 deletions
diff --git a/src/pal/src/arch/amd64/callsignalhandlerwrapper.S b/src/pal/src/arch/amd64/callsignalhandlerwrapper.S
new file mode 100644
index 0000000000..8260591c30
--- /dev/null
+++ b/src/pal/src/arch/amd64/callsignalhandlerwrapper.S
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+.macro CALL_SIGNAL_HANDLER_WRAPPER Alignment
+
+.globl C_FUNC(SignalHandlerWorkerReturnOffset\Alignment)
+C_FUNC(SignalHandlerWorkerReturnOffset\Alignment):
+ .int LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment)-C_FUNC(CallSignalHandlerWrapper\Alignment)
+
+// This function is never called, only a fake stack frame will be setup to have a return
+// address set to SignalHandlerWorkerReturn during SIGSEGV handling.
+// It enables the unwinder to unwind stack from the handling code to the actual failure site.
+NESTED_ENTRY CallSignalHandlerWrapper\Alignment, _TEXT, NoHandler
+ .cfi_def_cfa_offset (128 + 8 + \Alignment) // red zone + return address + alignment
+ .cfi_offset rip, -(128 + 8 + \Alignment)
+ push_nonvol_reg rbp
+ call EXTERNAL_C_FUNC(signal_handler_worker)
+LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment):
+ pop rbp
+ ret
+NESTED_END CallSignalHandlerWrapper\Alignment, _TEXT
+
+.endm
+
+CALL_SIGNAL_HANDLER_WRAPPER 0
+CALL_SIGNAL_HANDLER_WRAPPER 8
diff --git a/src/pal/src/arch/amd64/optimizedtls.cpp b/src/pal/src/arch/amd64/optimizedtls.cpp
deleted file mode 100644
index cd89db6b0a..0000000000
--- a/src/pal/src/arch/amd64/optimizedtls.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-/*++
-
-
-
-Module Name:
-
- optimizedtls.cpp
-
-Abstract:
-
- Implementation of platform-specific Thread local storage functions.
-
-
-
---*/
-
-#include "pal/thread.hpp"
-#include "pal/malloc.hpp"
-
-#include <pthread.h>
-
-#include "pal/dbgmsg.h"
-#include "pal/misc.h"
-#include "pal/debug.h"
-
-#include <stddef.h>
-
-using namespace CorUnix;
-
-SET_DEFAULT_DEBUG_CHANNEL(THREAD);
-
-#if defined(USE_OPTIMIZEDTLSGETTER)
-
-#define PAL_safe_offsetof(s,m) ((size_t)((ptrdiff_t)&(char&)(((s *)64)->m))-64)
-
-/*++
-Function:
- CorUnix::TLSMakeOptimizedGetter
-
- Creates a platform-optimized version of TlsGetValue compiled
- for a particular index.
-
- Generates the hot part of CorUnix::InternalGetCurrentThread
- as a chunk of highly optimized machine-specific code at runtime.
-
- Check the difference between CorUnix::InternalGetCurrentThread and
- CorUnix::InternalGetCurrentThreadSlow to see the C/C++ code that matches
- the code generated by this function.
---*/
-PAL_POPTIMIZEDTLSGETTER
-CorUnix::TLSMakeOptimizedGetter(
- IN CPalThread* pThread,
- IN DWORD dwTlsIndex)
-{
-#ifdef BIT64
-#pragma unused(pThread, dwTlsIndex)
- ERROR("TLSMakeOptimizedGetter not rewritten for amd64 yet.");
- return NULL;
-#else
- PAL_POPTIMIZEDTLSGETTER Ret = NULL;
- BYTE* p;
- int i = 0;
-
-#ifdef __APPLE__
-#define TLS_OPTIMIZED_GETTER_SIZE 118
-#else
-#define TLS_OPTIMIZED_GETTER_SIZE 115
-#endif
-
- p = (BYTE*)InternalMalloc(pThread, TLS_OPTIMIZED_GETTER_SIZE * sizeof(BYTE));
-
- if (p == NULL)
- {
- return Ret;
- }
-
- // Need to preserve %ecx, %edx, and %esi registers as specified in
- // GetThreadGeneric(void) in vm/amd64/asmhelpers.s
- p[i++] = 0x51; // push %ecx
- p[i++] = 0x52; // push %edx
- p[i++] = 0x89; // mov %esp,%eax // %eax = sp;
- p[i++] = 0xe0;
- p[i++] = 0xc1; // shr $0x11,%eax // sp >> 17;
- p[i++] = 0xe8;
- p[i++] = 0x11;
- p[i++] = 0x89; // mov %eax,%edx // key = sp >> 17;
- p[i++] = 0xc2;
- p[i++] = 0xc1; // sar $0x7,%edx // key >> 7;
- p[i++] = 0xfa;
- p[i++] = 0x07;
- p[i++] = 0x29; // sub %edx,%eax // key -= key >> 7;
- p[i++] = 0xd0;
- p[i++] = 0x89; // mov %eax,%edx
- p[i++] = 0xc2;
- p[i++] = 0xc1; // sar $0x5,%edx // key >> 5;
- p[i++] = 0xfa;
- p[i++] = 0x05;
- p[i++] = 0x29; // sub %edx,%eax // key -= key >> 5;
- p[i++] = 0xd0;
- p[i++] = 0x89; // mov %eax,%edx
- p[i++] = 0xc2;
- p[i++] = 0xc1; // sar $0x3,%edx // key >> 3;
- p[i++] = 0xfa;
- p[i++] = 0x03;
- p[i++] = 0x29; // sub %edx,%eax // key -= key >> 3;
- p[i++] = 0xd0;
- p[i++] = 0x25; // and $0xff,%eax // key &= 0xFF;
- p[i++] = 0xff;
- p[i++] = 0x00;
- p[i++] = 0x00;
- p[i++] = 0x00;
- p[i++] = 0x8b; // mov (flush_counter),%ecx // %ecx = counter = flush_counter;
- p[i++] = 0x0d;
- *((DWORD*) &p[i]) = (DWORD)&flush_counter;
- i += sizeof(DWORD);
- p[i++] = 0x8b; // mov (thread_hints,%eax,4),%eax // %edx = pThread = thread_hints[key];
- p[i++] = 0x14;
- p[i++] = 0x85;
- *((DWORD*) &p[i]) = (DWORD)&thread_hints;
- i += sizeof(DWORD);
- p[i++] = 0x39; // cmp %esp,offsetof(CPalThread,tlsInfo)+offsetof(CThreadTLSInfo,minStack)(%edx)
- // if ((size_t)pThread->tlsInfo.minStack <= sp)
- p[i++] = 0xa2;
- *((DWORD*) &p[i]) = (DWORD)(PAL_safe_offsetof(CPalThread,tlsInfo)+PAL_safe_offsetof(CThreadTLSInfo,minStack));
- i += sizeof(DWORD);
- p[i++] = 0x77; // ja CallInternalGetCurrentThreadSlow:
- p[i++] = 0x19;
- p[i++] = 0x3b; // cmp offsetof(CPalThread,tlsInfo)+offsetof(CThreadTLSInfo,maxStack)(%edx),%esp
- // if (sp < (size_t)pThread->tlsInfo.maxStack)
- p[i++] = 0xa2;
- *((DWORD*) &p[i]) = (DWORD)(PAL_safe_offsetof(CPalThread,tlsInfo)+PAL_safe_offsetof(CThreadTLSInfo,maxStack));
- i += sizeof(DWORD);
- p[i++] = 0x73; // jae CallInternalGetCurrentThreadSlow:
- p[i++] = 0x11;
- p[i++] = 0x39; // cmp (flush_counter),%ecx // if (counter == flush_counter)
- p[i++] = 0x0d;
- *((DWORD*) &p[i]) = (DWORD)&flush_counter;
- i += sizeof(DWORD);
- p[i++] = 0x75; // jne CallInternalGetCurrentThreadSlow:
- p[i++] = 0x09;
- if (dwTlsIndex != THREAD_OBJECT_TLS_INDEX)
- {
- p[i++] = 0x8b; // mov offsetof(pThread->tlsSlots[dwTlsIndex])(%edx),%eax // %eax = pThread->tlsSlots[dwTlsIndex];
- p[i++] = 0x82;
- *((DWORD*) &p[i]) = (DWORD)(PAL_safe_offsetof(CPalThread,tlsInfo)+PAL_safe_offsetof(CThreadTLSInfo,tlsSlots[dwTlsIndex]));
- i += sizeof(DWORD);
- }
- else
- {
- p[i++] = 0x89; // mov %edx,%eax // %eax = pThread;
- p[i++] = 0xd0;
- p[i++] = 0x90; // nop
- p[i++] = 0x90; // nop
- p[i++] = 0x90; // nop
- p[i++] = 0x90; // nop
- }
- p[i++] = 0x5a; // pop %edx
- p[i++] = 0x59; // pop %ecx
- p[i++] = 0xc3; // ret
- // CallInternalGetCurrentThreadSlow:
- p[i++] = 0x5a; // pop %edx
- p[i++] = 0x59; // pop %ecx
- p[i++] = 0x8d; // lea (thread_hints,%eax,4),%eax // %eax = &thread_hints[key];
- p[i++] = 0x04;
- p[i++] = 0x85;
- *((DWORD*) &p[i]) = (DWORD)&thread_hints;
- i += sizeof(DWORD);
- p[i++] = 0x55; // push %ebp
- p[i++] = 0x89; // mov %esp,%ebp
- p[i++] = 0xe5;
- p[i++] = 0x51; // push %ecx
- p[i++] = 0x89; // mov %esp,%ecx // this is the reference esp - need to match the reference esp used in the fast path.
- p[i++] = 0xe1;
- p[i++] = 0x52; // push %edx
-#ifdef __APPLE__
- // establish 16-byte stack alignment
- p[i++] = 0x83; // subl $8,%esp
- p[i++] = 0xec;
- p[i++] = 0x08;
-#endif
- p[i++] = 0x50; // push %eax // store &thread_hints[key] on stack as 2nd argument;
- p[i++] = 0x51; // push %ecx // reference esp - The 1st argument for call to InternalGetCurrentThreadSlow.
- p[i++] = 0xe8; // call InternalGetCurrentThreadSlow
- *((DWORD*) &p[i]) = (DWORD)&InternalGetCurrentThreadSlow - (DWORD)(&p[i+sizeof(DWORD)]);
- i += sizeof(DWORD);
-#ifdef __APPLE__
- p[i++] = 0x83; // addl $16,%esp
- p[i++] = 0xc4;
- p[i++] = 0x10;
-#else
- p[i++] = 0x83; // addl $8,%esp
- p[i++] = 0xc4;
- p[i++] = 0x08;
-#endif
- if (dwTlsIndex != THREAD_OBJECT_TLS_INDEX)
- {
- p[i++] = 0x8b; // mov offsetof(pThread->tlsSlots[dwTlsIndex])(%eax),%eax // %eax = pThread->tlsSlots[dwTlsIndex];
- p[i++] = 0x80;
- *((DWORD*) &p[i]) = (DWORD)(PAL_safe_offsetof(CPalThread,tlsInfo)+PAL_safe_offsetof(CThreadTLSInfo,tlsSlots[dwTlsIndex]));
- i += sizeof(DWORD);
- }
- p[i++] = 0x5a; // pop %edx
- p[i++] = 0x59; // pop %ecx
- p[i++] = 0xc9; // leave
- p[i++] = 0xc3; // ret
-
- if (i > TLS_OPTIMIZED_GETTER_SIZE)
- {
- ASSERT("Invalid TLS_OPTIMIZED_GETTER_SIZE %d\n", i);
- }
-
- DBG_FlushInstructionCache(p, TLS_OPTIMIZED_GETTER_SIZE * sizeof(BYTE));
-
- Ret = (PAL_POPTIMIZEDTLSGETTER)p;
-
- return Ret;
-#endif // BIT64 else
-}
-
-/*++
-Function:
- TLSFreeOptimizedGetter
-
- Frees a function created by MakeOptimizedTlsGetter().
---*/
-VOID
-CorUnix::TLSFreeOptimizedGetter(
- IN PAL_POPTIMIZEDTLSGETTER pOptimizedTlsGetter)
-{
- InternalFree(InternalGetCurrentThread(), (void *)pOptimizedTlsGetter);
-}
-
-#endif // USE_OPTIMIZEDTLSGETTER
diff --git a/src/pal/src/arch/amd64/signalhandlerhelper.cpp b/src/pal/src/arch/amd64/signalhandlerhelper.cpp
new file mode 100644
index 0000000000..8789f5a622
--- /dev/null
+++ b/src/pal/src/arch/amd64/signalhandlerhelper.cpp
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
+#include "pal/palinternal.h"
+#include "pal/context.h"
+#include "pal/signal.hpp"
+#include "pal/utils.h"
+#include <sys/ucontext.h>
+
+/*++
+Function :
+ signal_handler_worker
+
+ Handles signal on the original stack where the signal occured.
+ Invoked via setcontext.
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+ returnPoint - context to which the function returns if the common_signal_handler returns
+
+ (no return value)
+--*/
+void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+{
+ ucontext_t *ucontext = (ucontext_t *)context;
+ size_t faultSp = (size_t)MCREG_Rsp(ucontext->uc_mcontext);
+
+ _ASSERTE(IS_ALIGNED(faultSp, 8));
+
+ size_t fakeFrameReturnAddress;
+
+ if (IS_ALIGNED(faultSp, 16))
+ {
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset0 + (size_t)CallSignalHandlerWrapper0;
+ }
+ else
+ {
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset8 + (size_t)CallSignalHandlerWrapper8;
+ }
+
+ // preserve 128 bytes long red zone and align stack pointer
+ size_t* sp = (size_t*)ALIGN_DOWN(faultSp - 128, 16);
+
+ // Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction
+ *--sp = (size_t)MCREG_Rip(ucontext->uc_mcontext);
+ *--sp = (size_t)MCREG_Rbp(ucontext->uc_mcontext);
+ size_t fp = (size_t)sp;
+ *--sp = fakeFrameReturnAddress;
+
+ // Switch the current context to the signal_handler_worker and the original stack
+ CONTEXT context2;
+ RtlCaptureContext(&context2);
+
+ // We don't care about the other registers state since the stack unwinding restores
+ // them for the target frame directly from the signal context.
+ context2.Rsp = (size_t)sp;
+ context2.Rbx = (size_t)faultSp;
+ context2.Rbp = (size_t)fp;
+ context2.Rip = (size_t)signal_handler_worker;
+ context2.Rdi = code;
+ context2.Rsi = (size_t)siginfo;
+ context2.Rdx = (size_t)context;
+ context2.Rcx = (size_t)returnPoint;
+
+ RtlRestoreContext(&context2, NULL);
+}
diff --git a/src/pal/src/arch/arm/callsignalhandlerwrapper.S b/src/pal/src/arch/arm/callsignalhandlerwrapper.S
new file mode 100644
index 0000000000..266e4fdfe9
--- /dev/null
+++ b/src/pal/src/arch/arm/callsignalhandlerwrapper.S
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+.syntax unified
+.thumb
+
+.macro CALL_SIGNAL_HANDLER_WRAPPER Alignment
+
+.globl C_FUNC(SignalHandlerWorkerReturnOffset\Alignment)
+C_FUNC(SignalHandlerWorkerReturnOffset\Alignment):
+ .int LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment)-C_FUNC(CallSignalHandlerWrapper\Alignment)
+
+// This function is never called, only a fake stack frame will be setup to have a return
+// address set to SignalHandlerWorkerReturn during SIGSEGV handling.
+// It enables the unwinder to unwind stack from the handling code to the actual failure site.
+NESTED_ENTRY CallSignalHandlerWrapper\Alignment, _TEXT, NoHandler
+ sub sp, sp, #(8 + \Alignment) // red zone + alignment
+ stmfd sp!, {r7, lr}
+ bl EXTERNAL_C_FUNC(signal_handler_worker)
+LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment):
+ ldmfd sp!, {r7, lr}
+ bx lr
+NESTED_END CallSignalHandlerWrapper\Alignment, _TEXT
+
+.endm
+
+CALL_SIGNAL_HANDLER_WRAPPER 0
+CALL_SIGNAL_HANDLER_WRAPPER 4
diff --git a/src/pal/src/arch/arm/signalhandlerhelper.cpp b/src/pal/src/arch/arm/signalhandlerhelper.cpp
new file mode 100644
index 0000000000..e1ad460905
--- /dev/null
+++ b/src/pal/src/arch/arm/signalhandlerhelper.cpp
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
+#include "pal/palinternal.h"
+#include "pal/context.h"
+#include "pal/signal.hpp"
+#include "pal/utils.h"
+#include <sys/ucontext.h>
+
+/*++
+Function :
+ signal_handler_worker
+
+ Handles signal on the original stack where the signal occured.
+ Invoked via setcontext.
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+ returnPoint - context to which the function returns if the common_signal_handler returns
+
+ (no return value)
+--*/
+void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+{
+ ucontext_t *ucontext = (ucontext_t *)context;
+ size_t faultSp = (size_t)MCREG_Sp(ucontext->uc_mcontext);
+
+ _ASSERTE(IS_ALIGNED(faultSp, 4));
+
+ size_t fakeFrameReturnAddress;
+
+ if (IS_ALIGNED(faultSp, 8))
+ {
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset0 + (size_t)CallSignalHandlerWrapper0;
+ }
+ else
+ {
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset4 + (size_t)CallSignalHandlerWrapper4;
+ }
+
+ // preserve 8 bytes long red zone and align stack pointer
+ size_t* sp = (size_t*)ALIGN_DOWN(faultSp - 8, 8);
+
+ // Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction
+ // pushed LR
+ *--sp = (size_t)MCREG_Pc(ucontext->uc_mcontext);
+ // pushed frame pointer
+ *--sp = (size_t)MCREG_R7(ucontext->uc_mcontext);
+
+ // Switch the current context to the signal_handler_worker and the original stack
+ CONTEXT context2;
+ RtlCaptureContext(&context2);
+
+ // We don't care about the other registers state since the stack unwinding restores
+ // them for the target frame directly from the signal context.
+ context2.Sp = (size_t)sp;
+ context2.R7 = (size_t)sp; // Fp and Sp are the same
+ context2.Lr = fakeFrameReturnAddress;
+ context2.Pc = (size_t)signal_handler_worker;
+ context2.R0 = code;
+ context2.R1 = (size_t)siginfo;
+ context2.R2 = (size_t)context;
+ context2.R3 = (size_t)returnPoint;
+
+ RtlRestoreContext(&context2, NULL);
+}
diff --git a/src/pal/src/arch/arm64/asmconstants.h b/src/pal/src/arch/arm64/asmconstants.h
new file mode 100644
index 0000000000..b2bf74461f
--- /dev/null
+++ b/src/pal/src/arch/arm64/asmconstants.h
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __PAL_ARM64_ASMCONSTANTS_H__
+#define __PAL_ARM64_ASMCONSTANTS_H__
+
+#define CONTEXT_ARM64 0x00400000L
+
+#define CONTEXT_CONTROL_BIT (0)
+#define CONTEXT_INTEGER_BIT (1)
+#define CONTEXT_FLOATING_POINT_BIT (2)
+#define CONTEXT_DEBUG_REGISTERS_BIT (3)
+
+#define CONTEXT_CONTROL (CONTEXT_ARM64 | (1L << CONTEXT_CONTROL_BIT))
+#define CONTEXT_INTEGER (CONTEXT_ARM64 | (1 << CONTEXT_INTEGER_BIT))
+#define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | (1 << CONTEXT_FLOATING_POINT_BIT))
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARM64 | (1 << CONTEXT_DEBUG_REGISTERS_BIT))
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+
+
+#define CONTEXT_ContextFlags 0
+#define CONTEXT_Cpsr CONTEXT_ContextFlags+4
+#define CONTEXT_X0 CONTEXT_Cpsr+4
+#define CONTEXT_X1 CONTEXT_X0+8
+#define CONTEXT_X2 CONTEXT_X1+8
+#define CONTEXT_X3 CONTEXT_X2+8
+#define CONTEXT_X4 CONTEXT_X3+8
+#define CONTEXT_X5 CONTEXT_X4+8
+#define CONTEXT_X6 CONTEXT_X5+8
+#define CONTEXT_X7 CONTEXT_X6+8
+#define CONTEXT_X8 CONTEXT_X7+8
+#define CONTEXT_X9 CONTEXT_X8+8
+#define CONTEXT_X10 CONTEXT_X9+8
+#define CONTEXT_X11 CONTEXT_X10+8
+#define CONTEXT_X12 CONTEXT_X11+8
+#define CONTEXT_X13 CONTEXT_X12+8
+#define CONTEXT_X14 CONTEXT_X13+8
+#define CONTEXT_X15 CONTEXT_X14+8
+#define CONTEXT_X16 CONTEXT_X15+8
+#define CONTEXT_X17 CONTEXT_X16+8
+#define CONTEXT_X18 CONTEXT_X17+8
+#define CONTEXT_X19 CONTEXT_X18+8
+#define CONTEXT_X20 CONTEXT_X19+8
+#define CONTEXT_X21 CONTEXT_X20+8
+#define CONTEXT_X22 CONTEXT_X21+8
+#define CONTEXT_X23 CONTEXT_X22+8
+#define CONTEXT_X24 CONTEXT_X23+8
+#define CONTEXT_X25 CONTEXT_X24+8
+#define CONTEXT_X26 CONTEXT_X25+8
+#define CONTEXT_X27 CONTEXT_X26+8
+#define CONTEXT_X28 CONTEXT_X27+8
+#define CONTEXT_Fp CONTEXT_X28+8
+#define CONTEXT_Lr CONTEXT_Fp+8
+#define CONTEXT_Sp CONTEXT_Lr+8
+#define CONTEXT_Pc CONTEXT_Sp+8
+#define CONTEXT_NEON_OFFSET CONTEXT_Pc+8
+#define CONTEXT_V0 0
+#define CONTEXT_V1 CONTEXT_V0+16
+#define CONTEXT_V2 CONTEXT_V1+16
+#define CONTEXT_V3 CONTEXT_V2+16
+#define CONTEXT_V4 CONTEXT_V3+16
+#define CONTEXT_V5 CONTEXT_V4+16
+#define CONTEXT_V6 CONTEXT_V5+16
+#define CONTEXT_V7 CONTEXT_V6+16
+#define CONTEXT_V8 CONTEXT_V7+16
+#define CONTEXT_V9 CONTEXT_V8+16
+#define CONTEXT_V10 CONTEXT_V9+16
+#define CONTEXT_V11 CONTEXT_V10+16
+#define CONTEXT_V12 CONTEXT_V11+16
+#define CONTEXT_V13 CONTEXT_V12+16
+#define CONTEXT_V14 CONTEXT_V13+16
+#define CONTEXT_V15 CONTEXT_V14+16
+#define CONTEXT_V16 CONTEXT_V15+16
+#define CONTEXT_V17 CONTEXT_V16+16
+#define CONTEXT_V18 CONTEXT_V17+16
+#define CONTEXT_V19 CONTEXT_V18+16
+#define CONTEXT_V20 CONTEXT_V19+16
+#define CONTEXT_V21 CONTEXT_V20+16
+#define CONTEXT_V22 CONTEXT_V21+16
+#define CONTEXT_V23 CONTEXT_V22+16
+#define CONTEXT_V24 CONTEXT_V23+16
+#define CONTEXT_V25 CONTEXT_V24+16
+#define CONTEXT_V26 CONTEXT_V25+16
+#define CONTEXT_V27 CONTEXT_V26+16
+#define CONTEXT_V28 CONTEXT_V27+16
+#define CONTEXT_V29 CONTEXT_V28+16
+#define CONTEXT_V30 CONTEXT_V29+16
+#define CONTEXT_V31 CONTEXT_V30+16
+#define CONTEXT_FLOAT_CONTROL_OFFSET CONTEXT_V31
+#define CONTEXT_Fpcr 0
+#define CONTEXT_Fpsr CONTEXT_Fpcr+4
+
+#endif
diff --git a/src/pal/src/arch/arm64/callsignalhandlerwrapper.S b/src/pal/src/arch/arm64/callsignalhandlerwrapper.S
new file mode 100644
index 0000000000..90fb602479
--- /dev/null
+++ b/src/pal/src/arch/arm64/callsignalhandlerwrapper.S
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+.macro CALL_SIGNAL_HANDLER_WRAPPER Alignment
+
+.globl C_FUNC(SignalHandlerWorkerReturnOffset\Alignment)
+C_FUNC(SignalHandlerWorkerReturnOffset\Alignment):
+ .int LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment)-C_FUNC(CallSignalHandlerWrapper\Alignment)
+
+// This function is never called, only a fake stack frame will be setup to have a return
+// address set to SignalHandlerWorkerReturn during SIGSEGV handling.
+// It enables the unwinder to unwind stack from the handling code to the actual failure site.
+NESTED_ENTRY CallSignalHandlerWrapper\Alignment, _TEXT, NoHandler
+__StackAllocationSize = (128 + 8 + 8 + \Alignment) // red zone + fp + lr + alignment
+ PROLOG_STACK_ALLOC __StackAllocationSize
+ .cfi_adjust_cfa_offset __StackAllocationSize
+ PROLOG_SAVE_REG_PAIR fp, lr, 0
+ bl EXTERNAL_C_FUNC(signal_handler_worker)
+LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment):
+ EPILOG_RESTORE_REG_PAIR fp, lr, 0
+ EPILOG_STACK_FREE __StackAllocationSize
+ ret
+NESTED_END CallSignalHandlerWrapper\Alignment, _TEXT
+
+.endm
+
+CALL_SIGNAL_HANDLER_WRAPPER 0
+CALL_SIGNAL_HANDLER_WRAPPER 8
diff --git a/src/pal/src/arch/arm64/context2.S b/src/pal/src/arch/arm64/context2.S
index a64e62c94d..e62a9ac4d9 100644
--- a/src/pal/src/arch/arm64/context2.S
+++ b/src/pal/src/arch/arm64/context2.S
@@ -8,87 +8,7 @@
//
#include "unixasmmacros.inc"
-
-#define CONTEXT_ARM64 0x00400000L
-
-#define CONTEXT_CONTROL (CONTEXT_ARM64 | 0x1L)
-#define CONTEXT_INTEGER (CONTEXT_ARM64 | 0x2L)
-#define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | 0x4L)
-#define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARM64 | 0x8L)
-
-#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
-
-#define CONTEXT_ContextFlags 0
-#define CONTEXT_Cpsr CONTEXT_ContextFlags+4
-#define CONTEXT_X0 CONTEXT_Cpsr+4
-#define CONTEXT_X1 CONTEXT_X0+8
-#define CONTEXT_X2 CONTEXT_X1+8
-#define CONTEXT_X3 CONTEXT_X2+8
-#define CONTEXT_X4 CONTEXT_X3+8
-#define CONTEXT_X5 CONTEXT_X4+8
-#define CONTEXT_X6 CONTEXT_X5+8
-#define CONTEXT_X7 CONTEXT_X6+8
-#define CONTEXT_X8 CONTEXT_X7+8
-#define CONTEXT_X9 CONTEXT_X8+8
-#define CONTEXT_X10 CONTEXT_X9+8
-#define CONTEXT_X11 CONTEXT_X10+8
-#define CONTEXT_X12 CONTEXT_X11+8
-#define CONTEXT_X13 CONTEXT_X12+8
-#define CONTEXT_X14 CONTEXT_X13+8
-#define CONTEXT_X15 CONTEXT_X14+8
-#define CONTEXT_X16 CONTEXT_X15+8
-#define CONTEXT_X17 CONTEXT_X16+8
-#define CONTEXT_X18 CONTEXT_X17+8
-#define CONTEXT_X19 CONTEXT_X18+8
-#define CONTEXT_X20 CONTEXT_X19+8
-#define CONTEXT_X21 CONTEXT_X20+8
-#define CONTEXT_X22 CONTEXT_X21+8
-#define CONTEXT_X23 CONTEXT_X22+8
-#define CONTEXT_X24 CONTEXT_X23+8
-#define CONTEXT_X25 CONTEXT_X24+8
-#define CONTEXT_X26 CONTEXT_X25+8
-#define CONTEXT_X27 CONTEXT_X26+8
-#define CONTEXT_X28 CONTEXT_X27+8
-#define CONTEXT_Fp CONTEXT_X28+8
-#define CONTEXT_Lr CONTEXT_Fp+8
-#define CONTEXT_Sp CONTEXT_Lr+8
-#define CONTEXT_Pc CONTEXT_Sp+8
-#define CONTEXT_NEON_OFFSET CONTEXT_Pc+8
-#define CONTEXT_V0 0
-#define CONTEXT_V1 CONTEXT_V0+16
-#define CONTEXT_V2 CONTEXT_V1+16
-#define CONTEXT_V3 CONTEXT_V2+16
-#define CONTEXT_V4 CONTEXT_V3+16
-#define CONTEXT_V5 CONTEXT_V4+16
-#define CONTEXT_V6 CONTEXT_V5+16
-#define CONTEXT_V7 CONTEXT_V6+16
-#define CONTEXT_V8 CONTEXT_V7+16
-#define CONTEXT_V9 CONTEXT_V8+16
-#define CONTEXT_V10 CONTEXT_V9+16
-#define CONTEXT_V11 CONTEXT_V10+16
-#define CONTEXT_V12 CONTEXT_V11+16
-#define CONTEXT_V13 CONTEXT_V12+16
-#define CONTEXT_V14 CONTEXT_V13+16
-#define CONTEXT_V15 CONTEXT_V14+16
-#define CONTEXT_V16 CONTEXT_V15+16
-#define CONTEXT_V17 CONTEXT_V16+16
-#define CONTEXT_V18 CONTEXT_V17+16
-#define CONTEXT_V19 CONTEXT_V18+16
-#define CONTEXT_V20 CONTEXT_V19+16
-#define CONTEXT_V21 CONTEXT_V20+16
-#define CONTEXT_V22 CONTEXT_V21+16
-#define CONTEXT_V23 CONTEXT_V22+16
-#define CONTEXT_V24 CONTEXT_V23+16
-#define CONTEXT_V25 CONTEXT_V24+16
-#define CONTEXT_V26 CONTEXT_V25+16
-#define CONTEXT_V27 CONTEXT_V26+16
-#define CONTEXT_V28 CONTEXT_V27+16
-#define CONTEXT_V29 CONTEXT_V28+16
-#define CONTEXT_V30 CONTEXT_V29+16
-#define CONTEXT_V31 CONTEXT_V30+16
-#define CONTEXT_FLOAT_CONTROL_OFFSET CONTEXT_V31
-#define CONTEXT_Fpcr 0
-#define CONTEXT_Fpsr CONTEXT_Fpcr+4
+#include "asmconstants.h"
// Incoming:
// x0: Context*
@@ -115,10 +35,8 @@ LEAF_ENTRY CONTEXT_CaptureContext, _TEXT
ldr x2, [sp, 24]
str w2, [x0, CONTEXT_Cpsr]
stp fp, lr, [x0, CONTEXT_Fp]
- add sp, sp, #32
- mov x2, sp
+ add x2, sp, #32
stp x2, lr, [x0, CONTEXT_Sp]
- sub sp, sp, #32
LOCAL_LABEL(Done_CONTEXT_CONTROL):
// we dont clobber x1 in the CONTEXT_CONTROL case
@@ -224,14 +142,8 @@ LEAF_ENTRY RtlRestoreContext, _TEXT
// since we potentially clobber x0 below, we'll bank it in x16
mov x16, x0
- ldr w2, [x16, CONTEXT_ContextFlags]
- // clangs assembler doesn't seem to support the mov Wx, imm32 yet
- movz w3, #0x40, lsl #16
- movk w3, #0x4
- mov w4, w3
- and w3, w2, w3
- cmp w3, w4
- b.ne LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT)
+ ldr w17, [x16, CONTEXT_ContextFlags]
+ tbz w17, #CONTEXT_FLOATING_POINT_BIT, LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT)
add x16, x16, CONTEXT_NEON_OFFSET
ldp q0, q1, [x16, CONTEXT_V0]
@@ -256,12 +168,7 @@ LEAF_ENTRY RtlRestoreContext, _TEXT
sub x16, x16, CONTEXT_NEON_OFFSET
LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT):
- movz w2, #0x40, lsl #16
- movk w2, #0x2
- mov w3, w2
- and w2, w1, w2
- cmp w2, w3
- b.ne LOCAL_LABEL(No_Restore_CONTEXT_INTEGER)
+ tbz w17, #CONTEXT_INTEGER_BIT, LOCAL_LABEL(No_Restore_CONTEXT_INTEGER)
ldp x0, x1, [x16, CONTEXT_X0]
ldp x2, x3, [x16, CONTEXT_X2]
@@ -279,12 +186,7 @@ LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT):
ldr x28, [x16, CONTEXT_X28]
LOCAL_LABEL(No_Restore_CONTEXT_INTEGER):
- movz w2, #0x40, lsl #16
- movk w2, #0x2
- mov w3, w2
- and w2, w1, w2
- cmp w2, w3
- b.ne LOCAL_LABEL(No_Restore_CONTEXT_CONTROL)
+ tbz w17, #CONTEXT_CONTROL_BIT, LOCAL_LABEL(No_Restore_CONTEXT_CONTROL)
ldr w17, [x16, CONTEXT_Cpsr]
msr nzcv, x17
@@ -293,8 +195,8 @@ LOCAL_LABEL(No_Restore_CONTEXT_INTEGER):
mov sp, x17
ldr x17, [x16, CONTEXT_Pc]
br x17
-
+
LOCAL_LABEL(No_Restore_CONTEXT_CONTROL):
- ret
+ ret
LEAF_END RtlRestoreContext, _TEXT
diff --git a/src/pal/src/arch/arm64/exceptionhelper.S b/src/pal/src/arch/arm64/exceptionhelper.S
index 4fdcfc5eb1..480846eb61 100644
--- a/src/pal/src/arch/arm64/exceptionhelper.S
+++ b/src/pal/src/arch/arm64/exceptionhelper.S
@@ -3,7 +3,30 @@
// See the LICENSE file in the project root for more information.
#include "unixasmmacros.inc"
+#include "asmconstants.h"
+//////////////////////////////////////////////////////////////////////////
+//
+// This function creates a stack frame right below the target frame, restores all callee
+// saved registers, SP, and LR from the passed in context.
+// Then it uses the ThrowExceptionHelper to throw the passed in exception from that context.
+// EXTERN_C void ThrowExceptionFromContextInternal(CONTEXT* context, PAL_SEHException* ex);
LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT
- EMIT_BREAKPOINT
+ // Save the FP & LR to the stack so that the unwind can work at the instruction after
+ // loading the FP from the context, but before loading the SP from the context.
+ stp fp, lr, [sp, -16]!
+
+ ldp x19,x20, [x0, #(CONTEXT_X19)]
+ ldp x21,x22, [x0, #(CONTEXT_X21)]
+ ldp x23,x24, [x0, #(CONTEXT_X23)]
+ ldp x24,x25, [x0, #(CONTEXT_X24)]
+ ldp x26,x27, [x0, #(CONTEXT_X26)]
+ ldp x28,fp, [x0, #(CONTEXT_X28)]
+ ldr lr, [x0, #(CONTEXT_Pc)]
+ ldr x2, [x0, #(CONTEXT_Sp)]
+ mov sp, x2
+
+ // The PAL_SEHException pointer
+ mov x0, x1
+ b EXTERNAL_C_FUNC(ThrowExceptionHelper)
LEAF_END ThrowExceptionFromContextInternal, _TEXT
diff --git a/src/pal/src/arch/arm64/signalhandlerhelper.cpp b/src/pal/src/arch/arm64/signalhandlerhelper.cpp
new file mode 100644
index 0000000000..c35c629ab3
--- /dev/null
+++ b/src/pal/src/arch/arm64/signalhandlerhelper.cpp
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
+#include "pal/palinternal.h"
+#include "pal/context.h"
+#include "pal/signal.hpp"
+#include "pal/utils.h"
+#include <sys/ucontext.h>
+
+/*++
+Function :
+ signal_handler_worker
+
+ Handles signal on the original stack where the signal occured.
+ Invoked via setcontext.
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+ returnPoint - context to which the function returns if the common_signal_handler returns
+
+ (no return value)
+--*/
+void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+{
+ ucontext_t *ucontext = (ucontext_t *)context;
+ size_t faultSp = (size_t)MCREG_Sp(ucontext->uc_mcontext);
+ _ASSERTE(IS_ALIGNED(faultSp, 8));
+
+ size_t fakeFrameReturnAddress;
+
+ if (IS_ALIGNED(faultSp, 16))
+ {
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset0 + (size_t)CallSignalHandlerWrapper0;
+ }
+ else
+ {
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset8 + (size_t)CallSignalHandlerWrapper8;
+ }
+
+ // preserve 128 bytes long red zone and align stack pointer
+ size_t* sp = (size_t*)ALIGN_DOWN(faultSp - 128, 16);
+
+ // Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction
+ // pushed LR
+ *--sp = (size_t)MCREG_Pc(ucontext->uc_mcontext);
+ // pushed frame pointer
+ *--sp = (size_t)MCREG_Fp(ucontext->uc_mcontext);
+
+ // Switch the current context to the signal_handler_worker and the original stack
+ CONTEXT context2;
+ RtlCaptureContext(&context2);
+
+ context2.Sp = (size_t)sp;
+ context2.Fp = (size_t)sp;
+ context2.Lr = fakeFrameReturnAddress;
+ context2.Pc = (size_t)signal_handler_worker;
+ context2.X0 = code;
+ context2.X1 = (size_t)siginfo;
+ context2.X2 = (size_t)context;
+ context2.X3 = (size_t)returnPoint;
+
+ RtlRestoreContext(&context2, NULL);
+}
diff --git a/src/pal/src/arch/i386/asmconstants.h b/src/pal/src/arch/i386/asmconstants.h
index ff763ef16b..d947cb8bcd 100644
--- a/src/pal/src/arch/i386/asmconstants.h
+++ b/src/pal/src/arch/i386/asmconstants.h
@@ -28,3 +28,4 @@
#define CONTEXT_Xmm5 CONTEXT_Xmm4+16
#define CONTEXT_Xmm6 CONTEXT_Xmm5+16
#define CONTEXT_Xmm7 CONTEXT_Xmm6+16
+#define CONTEXT_ResumeEsp CONTEXT_ExtendedRegisters+512
diff --git a/src/pal/src/arch/i386/callsignalhandlerwrapper.S b/src/pal/src/arch/i386/callsignalhandlerwrapper.S
new file mode 100644
index 0000000000..26f06d9886
--- /dev/null
+++ b/src/pal/src/arch/i386/callsignalhandlerwrapper.S
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+.macro CALL_SIGNAL_HANDLER_WRAPPER Alignment
+
+.globl C_FUNC(SignalHandlerWorkerReturnOffset\Alignment)
+C_FUNC(SignalHandlerWorkerReturnOffset\Alignment):
+ .int LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment)-C_FUNC(CallSignalHandlerWrapper\Alignment)
+
+// This function is never called, only a fake stack frame will be setup to have a return
+// address set to SignalHandlerWorkerReturn during SIGSEGV handling.
+// It enables the unwinder to unwind stack from the handling code to the actual failure site.
+NESTED_ENTRY CallSignalHandlerWrapper\Alignment, _TEXT, NoHandler
+
+ .cfi_def_cfa_offset (4 + \Alignment) // return address + stack alignment
+ .cfi_offset eip, -(4 + \Alignment)
+ push ebp
+ .cfi_adjust_cfa_offset 4
+ .cfi_rel_offset ebp, 0
+ mov ebp, esp
+ .cfi_def_cfa_register ebp
+ // Align stack
+ sub esp, 8
+ // Simulate arguments pushing
+ push eax
+ push eax
+ push eax
+ push eax
+ call EXTERNAL_C_FUNC(signal_handler_worker)
+LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment):
+ add esp, 4 * 4 + 8
+ pop ebp
+ ret
+
+NESTED_END CallSignalHandlerWrapper\Alignment, _TEXT
+
+.endm
+
+CALL_SIGNAL_HANDLER_WRAPPER 0
+CALL_SIGNAL_HANDLER_WRAPPER 4
+CALL_SIGNAL_HANDLER_WRAPPER 8
+CALL_SIGNAL_HANDLER_WRAPPER 12
diff --git a/src/pal/src/arch/i386/context2.S b/src/pal/src/arch/i386/context2.S
index 11aba5e647..6c31b074cc 100644
--- a/src/pal/src/arch/i386/context2.S
+++ b/src/pal/src/arch/i386/context2.S
@@ -42,6 +42,7 @@ LEAF_ENTRY CONTEXT_CaptureContext, _TEXT
mov [eax + CONTEXT_Ebp], ebp
lea ebx, [esp + 12]
mov [eax + CONTEXT_Esp], ebx
+ mov [eax + CONTEXT_ResumeEsp], ebx
mov ebx, [esp + 8]
mov [eax + CONTEXT_Eip], ebx
@@ -82,7 +83,7 @@ LOCAL_LABEL(Done_CONTEXT_EXTENDED_REGISTERS):
// Restore
pop ebx
pop eax
- ret 4
+ ret
LEAF_END CONTEXT_CaptureContext, _TEXT
LEAF_ENTRY RtlCaptureContext, _TEXT
@@ -114,7 +115,7 @@ LOCAL_LABEL(Done_Restore_CONTEXT_FLOATING_POINT):
LOCAL_LABEL(Done_Restore_CONTEXT_EXTENDED_REGISTERS):
// Restore Stack
- mov esp, [eax + CONTEXT_Esp]
+ mov esp, [eax + CONTEXT_ResumeEsp]
// Create a minimal frame
push DWORD PTR [eax + CONTEXT_Eip]
diff --git a/src/pal/src/arch/i386/exceptionhelper.S b/src/pal/src/arch/i386/exceptionhelper.S
index 2061be26f8..bf44124479 100644
--- a/src/pal/src/arch/i386/exceptionhelper.S
+++ b/src/pal/src/arch/i386/exceptionhelper.S
@@ -19,11 +19,14 @@
LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT
push ebp
- mov eax, [esp + 12] // ebx: PAL_SEHException *
- mov ebx, [esp + 8] // eax: CONTEXT *
+ mov ecx, [esp + 12] // ecx: PAL_SEHException * (first argument for ThrowExceptionHelper)
+ mov eax, [esp + 8] // ebx: CONTEXT *
- mov ebp, [ebx + CONTEXT_Ebp]
- mov esp, [ebx + CONTEXT_Esp]
+ mov ebp, [eax + CONTEXT_Ebp]
+ mov esp, [eax + CONTEXT_ResumeEsp]
+ mov ebx, [eax + CONTEXT_Ebx]
+ mov esi, [eax + CONTEXT_Esi]
+ mov edi, [eax + CONTEXT_Edi]
// The ESP is re-initialized as the target frame's value, so the current function's
// CFA is now right at the ESP.
@@ -33,11 +36,9 @@ LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT
// the EBP is no longer saved in the current stack frame.
.cfi_restore ebp
- // Store PAL_SEHException as the first argument
- push eax
-
// Store return address to the stack
- mov ebx, [ebx + CONTEXT_Eip]
- push ebx
+ mov eax, [eax + CONTEXT_Eip]
+ push eax
jmp EXTERNAL_C_FUNC(ThrowExceptionHelper)
+
LEAF_END ThrowExceptionFromContextInternal, _TEXT
diff --git a/src/pal/src/arch/i386/signalhandlerhelper.cpp b/src/pal/src/arch/i386/signalhandlerhelper.cpp
new file mode 100644
index 0000000000..3369abe093
--- /dev/null
+++ b/src/pal/src/arch/i386/signalhandlerhelper.cpp
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
+#include "pal/palinternal.h"
+#include "pal/context.h"
+#include "pal/signal.hpp"
+#include "pal/utils.h"
+#include <sys/ucontext.h>
+
+/*++
+Function :
+ signal_handler_worker
+
+ Handles signal on the original stack where the signal occured.
+ Invoked via setcontext.
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+ returnPoint - context to which the function returns if the common_signal_handler returns
+
+ (no return value)
+--*/
+void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+{
+ ucontext_t *ucontext = (ucontext_t *)context;
+ size_t faultSp = (size_t)MCREG_Esp(ucontext->uc_mcontext);
+
+ _ASSERTE(IS_ALIGNED(faultSp, 4));
+
+ size_t fakeFrameReturnAddress;
+
+ switch (faultSp & 0xc)
+ {
+ case 0x0:
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset0 + (size_t)CallSignalHandlerWrapper0;
+ break;
+ case 0x4:
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset4 + (size_t)CallSignalHandlerWrapper4;
+ break;
+ case 0x8:
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset8 + (size_t)CallSignalHandlerWrapper8;
+ break;
+ case 0xc:
+ fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset12 + (size_t)CallSignalHandlerWrapper12;
+ break;
+ }
+
+ size_t* sp = (size_t*)ALIGN_DOWN(faultSp, 16);
+
+ // Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction
+ *--sp = (size_t)MCREG_Eip(ucontext->uc_mcontext);
+ *--sp = (size_t)MCREG_Ebp(ucontext->uc_mcontext);
+ size_t fp = (size_t)sp;
+ // Align stack
+ sp -= 2;
+ *--sp = (size_t)returnPoint;
+ *--sp = (size_t)context;
+ *--sp = (size_t)siginfo;
+ *--sp = code;
+ *--sp = fakeFrameReturnAddress;
+
+ // Switch the current context to the signal_handler_worker and the original stack
+ CONTEXT context2;
+ RtlCaptureContext(&context2);
+
+ // We don't care about the other registers state since the stack unwinding restores
+ // them for the target frame directly from the signal context.
+ context2.Esp = (size_t)sp;
+ context2.ResumeEsp = (size_t)sp;
+ context2.Ebp = (size_t)fp;
+ context2.Eip = (size_t)signal_handler_worker;
+
+ RtlRestoreContext(&context2, NULL);
+}