diff options
author | Jan Vorlicek <janvorli@microsoft.com> | 2016-10-04 02:56:42 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-10-04 02:56:42 +0200 |
commit | 9c506048df2e03002eda612966977b739b585aba (patch) | |
tree | a3c044a33188139f08604a1e997e2f241a121b01 /src/pal/src/exception/seh-unwind.cpp | |
parent | 3c67761c09e029569466ef1e96a2b0d67873c8a3 (diff) | |
download | coreclr-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.cpp | 49 |
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) { |