summaryrefslogtreecommitdiff
path: root/src/pal/src/exception/seh-unwind.cpp
diff options
context:
space:
mode:
authorJan Vorlicek <janvorli@microsoft.com>2016-10-04 02:56:42 +0200
committerGitHub <noreply@github.com>2016-10-04 02:56:42 +0200
commit9c506048df2e03002eda612966977b739b585aba (patch)
treea3c044a33188139f08604a1e997e2f241a121b01 /src/pal/src/exception/seh-unwind.cpp
parent3c67761c09e029569466ef1e96a2b0d67873c8a3 (diff)
downloadcoreclr-9c506048df2e03002eda612966977b739b585aba.tar.gz
coreclr-9c506048df2e03002eda612966977b739b585aba.tar.bz2
coreclr-9c506048df2e03002eda612966977b739b585aba.zip
Add support for Alpine Linux (#7440)
This change enables build of CoreCLR on Alpine Linux. Here is the list of changes: - Disable asserts checking RSP in arbitrary threads against cached stack limit for the respective thread. The stack on Alpine obviously grows over the limit reported by the pthread functions. - Disable using XSTATE. This should be re-enabled after MUSL gets the _xstate, _fpx_sw_bytes and related data structures added to the signal.h header. - Disable setting rlimit of RLIMIT_NOFILE to the max value, since it breaks debugging for some reason. - Add skipping over the hardware signal trampoline in the PAL_VirtualUnwind. While we were not trying to walk over it in a simple case, in a case where an exception was thrown from a catch handler of a hardware exception, we still attempted to walk over it and it fails on Alpine. - Fix detection of Alpine Linux in the PAL's CMakeLists.txt so that it works in Docker containers too. - Modified PAL_VirtualUnwind to make the check for unwinding past the bottom of the stack unconditional. We had a long list of platforms where we were doing this check and it doesn't hurt to do it on platforms where it is not needed. I have done that rather than adding a check for Alpine Linux as another platform that needs it.
Diffstat (limited to 'src/pal/src/exception/seh-unwind.cpp')
-rw-r--r--src/pal/src/exception/seh-unwind.cpp49
1 files changed, 31 insertions, 18 deletions
diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
index 24eebbbf94..6f552bd81c 100644
--- a/src/pal/src/exception/seh-unwind.cpp
+++ b/src/pal/src/exception/seh-unwind.cpp
@@ -221,15 +221,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 +259,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 +283,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 +310,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)
{