summaryrefslogtreecommitdiff
path: root/src/pal/src
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
parent4b11dc566a5bbfa1378d6266525c281b028abcc8 (diff)
downloadcoreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.tar.gz
coreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.tar.bz2
coreclr-a56e30c8d33048216567753d9d3fefc2152af8ac.zip
Imported Upstream version 2.0.0.11353upstream/2.0.0.11353
Diffstat (limited to 'src/pal/src')
-rw-r--r--src/pal/src/CMakeLists.txt70
-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
-rw-r--r--src/pal/src/config.h.in3
-rw-r--r--src/pal/src/configure.cmake31
-rw-r--r--src/pal/src/cruntime/math.cpp34
-rw-r--r--src/pal/src/cruntime/misctls.cpp308
-rw-r--r--src/pal/src/exception/seh-unwind.cpp2
-rw-r--r--src/pal/src/exception/seh.cpp11
-rw-r--r--src/pal/src/exception/signal.cpp206
-rw-r--r--src/pal/src/exception/signal.hpp52
-rw-r--r--src/pal/src/file/filetime.cpp28
-rw-r--r--src/pal/src/include/pal/context.h18
-rw-r--r--src/pal/src/include/pal/module.h2
-rw-r--r--src/pal/src/include/pal/signal.hpp140
-rw-r--r--src/pal/src/init/pal.cpp302
-rw-r--r--src/pal/src/init/sxs.cpp15
-rw-r--r--src/pal/src/loader/module.cpp20
-rw-r--r--src/pal/src/locale/unicode.cpp2
-rw-r--r--src/pal/src/misc/cgroup.cpp335
-rw-r--r--src/pal/src/misc/dbgmsg.cpp4
-rw-r--r--src/pal/src/misc/environ.cpp8
-rw-r--r--src/pal/src/misc/errorstrings.cpp2
-rw-r--r--src/pal/src/misc/sysinfo.cpp75
-rw-r--r--src/pal/src/misc/time.cpp32
-rw-r--r--src/pal/src/misc/utils.cpp7
-rw-r--r--src/pal/src/misc/version.cpp119
-rw-r--r--src/pal/src/thread/context.cpp36
-rw-r--r--src/pal/src/thread/process.cpp9
-rw-r--r--src/pal/src/thread/thread.cpp13
43 files changed, 1659 insertions, 1148 deletions
diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt
index 16c9d8bd6f..5314cdf86b 100644
--- a/src/pal/src/CMakeLists.txt
+++ b/src/pal/src/CMakeLists.txt
@@ -45,6 +45,9 @@ else()
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
set(PAL_CMAKE_PLATFORM_ARCH_ARM 1)
add_definitions(-D_ARM_)
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL arm)
+ set(PAL_CMAKE_PLATFORM_ARCH_ARM 1)
+ add_definitions(-D_ARM_)
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
set(PAL_CMAKE_PLATFORM_ARCH_ARM64 1)
add_definitions(-D_ARM64_)
@@ -77,13 +80,17 @@ add_definitions(-D_FILE_OFFSET_BITS=64)
if(PAL_CMAKE_PLATFORM_ARCH_AMD64)
add_definitions(-DBIT64=1)
add_definitions(-D_WIN64=1)
+ set(PAL_ARCH_SOURCES_DIR amd64)
elseif(PAL_CMAKE_PLATFORM_ARCH_ARM)
add_definitions(-DBIT32=1)
+ set(PAL_ARCH_SOURCES_DIR arm)
elseif(PAL_CMAKE_PLATFORM_ARCH_ARM64)
add_definitions(-DBIT64=1)
add_definitions(-D_WIN64=1)
+ set(PAL_ARCH_SOURCES_DIR arm64)
elseif(PAL_CMAKE_PLATFORM_ARCH_I386)
add_definitions(-DBIT32=1)
+ set(PAL_ARCH_SOURCES_DIR i386)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT CLR_CMAKE_PLATFORM_ALPINE_LINUX)
@@ -101,35 +108,19 @@ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -Wl,--no
add_compile_options(-fPIC)
-if(PAL_CMAKE_PLATFORM_ARCH_AMD64)
- set(ARCH_SOURCES
- arch/amd64/context2.S
- arch/amd64/debugbreak.S
- arch/amd64/exceptionhelper.S
- arch/amd64/processor.cpp
- )
-elseif(PAL_CMAKE_PLATFORM_ARCH_ARM)
- set(ARCH_SOURCES
- arch/arm/context2.S
- arch/arm/debugbreak.S
- arch/arm/exceptionhelper.S
- arch/arm/processor.cpp
- )
-elseif(PAL_CMAKE_PLATFORM_ARCH_ARM64)
- set(ARCH_SOURCES
- arch/arm64/context2.S
- arch/arm64/debugbreak.S
- arch/arm64/exceptionhelper.S
- arch/arm64/processor.cpp
- )
-elseif(PAL_CMAKE_PLATFORM_ARCH_I386)
- set(ARCH_SOURCES
- arch/i386/context2.S
- arch/i386/debugbreak.S
- arch/i386/exceptionhelper.S
- arch/i386/processor.cpp
+set(ARCH_SOURCES
+ arch/${PAL_ARCH_SOURCES_DIR}/context2.S
+ arch/${PAL_ARCH_SOURCES_DIR}/debugbreak.S
+ arch/${PAL_ARCH_SOURCES_DIR}/exceptionhelper.S
+ arch/${PAL_ARCH_SOURCES_DIR}/processor.cpp
+)
+
+if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ list(APPEND PLATFORM_SOURCES
+ arch/${PAL_ARCH_SOURCES_DIR}/callsignalhandlerwrapper.S
+ arch/${PAL_ARCH_SOURCES_DIR}/signalhandlerhelper.cpp
)
-endif()
+endif(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
if(PAL_CMAKE_PLATFORM_ARCH_ARM)
set_source_files_properties(exception/seh.cpp PROPERTIES COMPILE_FLAGS -Wno-error=inline-asm)
@@ -177,6 +168,7 @@ set(SOURCES
map/virtual.cpp
memory/heap.cpp
memory/local.cpp
+ misc/cgroup.cpp
misc/dbgmsg.cpp
misc/environ.cpp
misc/error.cpp
@@ -189,7 +181,6 @@ set(SOURCES
misc/sysinfo.cpp
misc/time.cpp
misc/utils.cpp
- misc/version.cpp
objmgr/palobjbase.cpp
objmgr/shmobject.cpp
objmgr/shmobjectmanager.cpp
@@ -303,21 +294,26 @@ if(CMAKE_SYSTEM_NAME STREQUAL Linux)
endif()
if(CLR_CMAKE_PLATFORM_ANDROID)
+ find_library(LZMA NAMES lzma)
+
+ if(LZMA STREQUAL LZMA-NOTFOUND)
+ message(FATAL_ERROR "Cannot find liblzma.")
+ endif(LZMA STREQUAL LZMA-NOTFOUND)
+
target_link_libraries(coreclrpal
gnustl_shared
android-support
- android-glob)
+ android-glob
+ ${LZMA})
endif()
- if(NOT CLR_CMAKE_PLATFORM_ANDROID)
- find_library(UNWIND NAMES unwind)
+ find_library(UNWIND NAMES unwind)
- if(UNWIND STREQUAL UNWIND-NOTFOUND)
- message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8-dev and libunwind8.")
- endif(UNWIND STREQUAL UNWIND-NOTFOUND)
+ if(UNWIND STREQUAL UNWIND-NOTFOUND)
+ message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8-dev and libunwind8.")
+ endif(UNWIND STREQUAL UNWIND-NOTFOUND)
- target_link_libraries(coreclrpal ${UNWIND})
- endif()
+ target_link_libraries(coreclrpal ${UNWIND})
if(CLR_MAKE_PLATFORM_ANDROID)
find_library(ANDROID_SUPPORT NAMES android-support)
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);
+}
diff --git a/src/pal/src/config.h.in b/src/pal/src/config.h.in
index 77d7bfaf5a..ab5fa0341d 100644
--- a/src/pal/src/config.h.in
+++ b/src/pal/src/config.h.in
@@ -40,6 +40,7 @@
#cmakedefine01 HAVE_UTIMES
#cmakedefine01 HAVE_SYSCTL
#cmakedefine01 HAVE_SYSCONF
+#cmakedefine01 HAVE_SYSINFO
#cmakedefine01 HAVE_LOCALTIME_R
#cmakedefine01 HAVE_GMTIME_R
#cmakedefine01 HAVE_TIMEGM
@@ -57,6 +58,8 @@
#cmakedefine01 HAVE_TTRACE
#cmakedefine HAVE_UNW_GET_SAVE_LOC
#cmakedefine HAVE_UNW_GET_ACCESSORS
+#cmakedefine01 HAVE_XSWDEV
+#cmakedefine01 HAVE_XSW_USAGE
#cmakedefine01 HAVE_STAT_TIMESPEC
#cmakedefine01 HAVE_STAT_NSEC
diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake
index 4f2bc5739b..4d78f54423 100644
--- a/src/pal/src/configure.cmake
+++ b/src/pal/src/configure.cmake
@@ -78,6 +78,7 @@ check_function_exists(fsync HAVE_FSYNC)
check_function_exists(futimes HAVE_FUTIMES)
check_function_exists(utimes HAVE_UTIMES)
check_function_exists(sysctl HAVE_SYSCTL)
+check_function_exists(sysinfo HAVE_SYSINFO)
check_function_exists(sysconf HAVE_SYSCONF)
check_function_exists(localtime_r HAVE_LOCALTIME_R)
check_function_exists(gmtime_r HAVE_GMTIME_R)
@@ -122,6 +123,7 @@ check_struct_has_member ("struct stat" st_atimensec "sys/types.h;sys/stat.h" HAV
check_struct_has_member ("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
check_struct_has_member ("ucontext_t" uc_mcontext.gregs[0] ucontext.h HAVE_GREGSET_T)
check_struct_has_member ("ucontext_t" uc_mcontext.__gregs[0] ucontext.h HAVE___GREGSET_T)
+check_struct_has_member ("struct sysinfo" mem_unit "sys/sysinfo.h" HAVE_SYSINFO_WITH_MEM_UNIT)
set(CMAKE_EXTRA_INCLUDE_FILES machine/reg.h)
check_type_size("struct reg" BSD_REGS_T)
@@ -728,9 +730,9 @@ check_cxx_source_runs("
int main(void) {
double infinity = 1.0 / 0.0;
if (pow(1.0, infinity) != 1.0 || pow(1.0, -infinity) != 1.0) {
- exit(1)
+ exit(1);
}
- if (!isnan(pow(-1.0, infinity)) || !isnan(pow(-1.0, -infinity))) {
+ if (pow(-1.0, infinity) != 1.0 || pow(-1.0, -infinity) != 1.0) {
exit(1);
}
if (pow(0.0, infinity) != 0.0) {
@@ -742,7 +744,7 @@ int main(void) {
if (pow(-1.1, infinity) != infinity || pow(1.1, infinity) != infinity) {
exit(1);
}
- if (pow(-1.1, -infinity) != 0.0 || pow(1.1, infinity) != 0.0) {
+ if (pow(-1.1, -infinity) != 0.0 || pow(1.1, -infinity) != 0.0) {
exit(1);
}
if (pow(-0.0, -1) != -infinity) {
@@ -982,6 +984,29 @@ int main(int argc, char **argv)
return 0;
}" UNWIND_CONTEXT_IS_UCONTEXT_T)
+check_cxx_source_compiles("
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <vm/vm_param.h>
+
+int main(int argc, char **argv)
+{
+ struct xswdev xsw;
+
+ return 0;
+}" HAVE_XSWDEV)
+
+check_cxx_source_compiles("
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+int main(int argc, char **argv)
+{
+ struct xsw_usage xsu;
+
+ return 0;
+}" HAVE_XSW_USAGE)
+
set(CMAKE_REQUIRED_LIBRARIES pthread)
check_cxx_source_compiles("
#include <errno.h>
diff --git a/src/pal/src/cruntime/math.cpp b/src/pal/src/cruntime/math.cpp
index d53dbe7982..7b5175a526 100644
--- a/src/pal/src/cruntime/math.cpp
+++ b/src/pal/src/cruntime/math.cpp
@@ -343,7 +343,7 @@ PALIMPORT double __cdecl PAL_pow(double x, double y)
}
else if (x == -1.0)
{
- ret = PAL_NAN_DBL; // NaN
+ ret = 1.0;
}
else if ((x > -1.0) && (x < 1.0))
{
@@ -362,7 +362,7 @@ PALIMPORT double __cdecl PAL_pow(double x, double y)
}
else if (x == -1.0)
{
- ret = PAL_NAN_DBL; // NaN
+ ret = 1.0;
}
else if ((x > -1.0) && (x < 1.0))
{
@@ -384,17 +384,7 @@ PALIMPORT double __cdecl PAL_pow(double x, double y)
else
#endif // !HAVE_COMPATIBLE_POW
- if ((y == 0.0) && isnan(x))
- {
- // Windows returns NaN for pow(NaN, 0), but POSIX specifies
- // a return value of 1 for that case. We need to return
- // the same result as Windows.
- ret = PAL_NAN_DBL;
- }
- else
- {
- ret = pow(x, y);
- }
+ ret = pow(x, y);
#if !HAVE_VALID_NEGATIVE_INF_POW
if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2)))
@@ -706,7 +696,7 @@ PALIMPORT float __cdecl PAL_powf(float x, float y)
}
else if (x == -1.0f)
{
- ret = PAL_NAN_FLT; // NaN
+ ret = 1.0f;
}
else if ((x > -1.0f) && (x < 1.0f))
{
@@ -725,7 +715,7 @@ PALIMPORT float __cdecl PAL_powf(float x, float y)
}
else if (x == -1.0f)
{
- ret = PAL_NAN_FLT; // NaN
+ ret = 1.0f;
}
else if ((x > -1.0f) && (x < 1.0f))
{
@@ -747,18 +737,8 @@ PALIMPORT float __cdecl PAL_powf(float x, float y)
else
#endif // !HAVE_COMPATIBLE_POW
- if ((y == 0.0f) && isnan(x))
- {
- // Windows returns NaN for powf(NaN, 0), but POSIX specifies
- // a return value of 1 for that case. We need to return
- // the same result as Windows.
- ret = PAL_NAN_FLT;
- }
- else
- {
- ret = powf(x, y);
- }
-
+ ret = powf(x, y);
+
#if !HAVE_VALID_NEGATIVE_INF_POW
if ((ret == PAL_POSINF_FLT) && (x < 0) && isfinite(x) && (ceilf(y / 2) != floorf(y / 2)))
{
diff --git a/src/pal/src/cruntime/misctls.cpp b/src/pal/src/cruntime/misctls.cpp
index e46582ec17..2df32fe115 100644
--- a/src/pal/src/cruntime/misctls.cpp
+++ b/src/pal/src/cruntime/misctls.cpp
@@ -128,6 +128,11 @@ done:
return retval;
}
+UINT GetExponent(double d)
+{
+ return (*((UINT*)&d + 1) >> 20) & 0x000007ff;
+}
+
/**
Function:
@@ -150,250 +155,143 @@ NOTES:
char * __cdecl
_ecvt( double value, int count, int * dec, int * sign )
{
- CONST CHAR * FORMAT_STRING = "%.348e";
- CHAR TempBuffer[ ECVT_MAX_BUFFER_SIZE ];
- CPalThread *pThread = NULL;
- LPSTR lpReturnBuffer = NULL;
- LPSTR lpStartOfReturnBuffer = NULL;
- LPSTR lpTempBuffer = NULL;
- LPSTR lpEndOfTempBuffer = NULL;
- INT nTempBufferLength = 0;
- CHAR ExponentBuffer[ 6 ];
- INT nExponentValue = 0;
- INT LoopIndex = 0;
-
PERF_ENTRY(_ecvt);
ENTRY( "_ecvt( value=%.30g, count=%d, dec=%p, sign=%p )\n",
value, count, dec, sign );
+
+ _ASSERTE(dec != nullptr && sign != nullptr);
+ CPalThread *pThread = InternalGetCurrentThread();
+ LPSTR lpStartOfReturnBuffer = pThread->crtInfo.ECVTBuffer;
- /* Get the per-thread buffer from the thread structure. */
- pThread = InternalGetCurrentThread();
-
- lpStartOfReturnBuffer = lpReturnBuffer = pThread->crtInfo.ECVTBuffer;
-
- /* Sanity checks */
- if ( !dec || !sign )
- {
- ERROR( "dec and sign have to be valid pointers.\n" );
- *lpReturnBuffer = '\0';
- goto done;
- }
- else
+ if (count > ECVT_MAX_COUNT_SIZE)
{
- *dec = *sign = 0;
+ count = ECVT_MAX_COUNT_SIZE;
}
- if ( value < 0.0 )
- {
- *sign = 1;
- }
+ // the caller of _ecvt should already checked the Infinity and NAN values
+ _ASSERTE(GetExponent(value) != 0x7ff);
- if ( count > ECVT_MAX_COUNT_SIZE )
+ CHAR TempBuffer[ECVT_MAX_BUFFER_SIZE];
+
+ *dec = *sign = 0;
+
+ if (value < 0.0)
{
- count = ECVT_MAX_COUNT_SIZE;
+ *sign = 1;
}
-
- /* Get the string to work with. */
- sprintf_s( TempBuffer, sizeof(TempBuffer), FORMAT_STRING, value );
-
- /* Check to see if value was a valid number. */
- if ( strcmp( "NaN", TempBuffer ) == 0 || strcmp( "-NaN", TempBuffer ) == 0 )
+
{
- TRACE( "value was not a number!\n" );
- if (strcpy_s( lpStartOfReturnBuffer, ECVT_MAX_BUFFER_SIZE, "1#QNAN0" ) != SAFECRT_SUCCESS)
+ // we have issue #10290 tracking fixing the sign of 0.0 across the platforms
+ if (value == 0.0)
{
- ERROR( "strcpy_s failed!\n" );
- *lpStartOfReturnBuffer = '\0';
+ for (int j = 0; j < count; j++)
+ {
+ lpStartOfReturnBuffer[j] = '0';
+ }
+ lpStartOfReturnBuffer[count] = '\0';
goto done;
+ }
+
+ int tempBufferLength = snprintf(TempBuffer, ECVT_MAX_BUFFER_SIZE, "%.40e", value);
+ _ASSERTE(tempBufferLength > 0 && ECVT_MAX_BUFFER_SIZE > tempBufferLength);
+
+ //
+ // Calculate the exponent value
+ //
+
+ int exponentIndex = strrchr(TempBuffer, 'e') - TempBuffer;
+ _ASSERTE(exponentIndex > 0 && (exponentIndex < tempBufferLength - 1));
+
+ int i = exponentIndex + 1;
+ int exponentSign = 1;
+ if (TempBuffer[i] == '-')
+ {
+ exponentSign = -1;
+ i++;
}
-
- *dec = 1;
- goto done;
- }
-
- /* Check to see if it is infinite. */
- if ( strcmp( "Inf", TempBuffer ) == 0 || strcmp( "-Inf", TempBuffer ) == 0 )
- {
- TRACE( "value is infinite!\n" );
- if (strcpy_s( lpStartOfReturnBuffer, ECVT_MAX_BUFFER_SIZE, "1#INF00" ) != SAFECRT_SUCCESS)
+ else if (TempBuffer[i] == '+')
{
- ERROR( "strcpy_s failed!\n" );
- *lpStartOfReturnBuffer = '\0';
- goto done;
+ i++;
}
- *dec = 1;
- if ( *TempBuffer == '-' )
+ int exponentValue = 0;
+ while (i < tempBufferLength)
{
- *sign = 1;
+ _ASSERTE(TempBuffer[i] >= '0' && TempBuffer[i] <= '9');
+ exponentValue = exponentValue * 10 + ((BYTE) TempBuffer[i] - (BYTE) '0');
+ i++;
}
- goto done;
- }
-
- nTempBufferLength = strlen( TempBuffer );
- lpEndOfTempBuffer = &(TempBuffer[ nTempBufferLength ]);
-
- /* Extract the exponent, and convert it to integer. */
- while ( *lpEndOfTempBuffer != 'e' && nTempBufferLength > 0 )
- {
- nTempBufferLength--;
- lpEndOfTempBuffer--;
- }
-
- ExponentBuffer[ 0 ] = '\0';
- if (strncat_s( ExponentBuffer, sizeof(ExponentBuffer), lpEndOfTempBuffer + 1, 5 ) != SAFECRT_SUCCESS)
- {
- ERROR( "strncat_s failed!\n" );
- *lpStartOfReturnBuffer = '\0';
- goto done;
- }
-
- nExponentValue = atoi( ExponentBuffer );
+ exponentValue *= exponentSign;
+
+ //
+ // Determine decimal location.
+ //
- /* End the string at the 'e' */
- *lpEndOfTempBuffer = '\0';
- nTempBufferLength--;
+ if (exponentValue == 0)
+ {
+ *dec = 1;
+ }
+ else
+ {
+ *dec = exponentValue + 1;
+ }
+
+ //
+ // Copy the string from the temp buffer upto precision characters, removing the sign, and decimal as required.
+ //
+
+ i = 0;
+ int mantissaIndex = 0;
+ while (i < count && mantissaIndex < exponentIndex)
+ {
+ if (TempBuffer[mantissaIndex] >= '0' && TempBuffer[mantissaIndex] <= '9')
+ {
+ lpStartOfReturnBuffer[i] = TempBuffer[mantissaIndex];
+ i++;
+ }
+ mantissaIndex++;
+ }
- /* Determine decimal location. */
- if ( nExponentValue == 0 )
- {
- *dec = 1;
- }
- else
- {
- *dec = nExponentValue + 1;
- }
+ while (i < count)
+ {
+ lpStartOfReturnBuffer[i] = '0'; // append zeros as needed
+ i++;
+ }
- if ( value == 0.0 )
- {
- *dec = 0;
- }
- /* Copy the string from the temp buffer upto count characters,
- removing the sign, and decimal as required. */
- lpTempBuffer = TempBuffer;
- *lpReturnBuffer = '0';
- lpReturnBuffer++;
+ lpStartOfReturnBuffer[i] = '\0';
+
+ //
+ // Round if needed
+ //
- while ( LoopIndex < ECVT_MAX_COUNT_SIZE )
- {
- if ( isdigit(*lpTempBuffer) )
+ if (mantissaIndex >= exponentIndex || TempBuffer[mantissaIndex] < '5')
{
- *lpReturnBuffer = *lpTempBuffer;
- LoopIndex++;
- lpReturnBuffer++;
+ goto done;
}
- lpTempBuffer++;
- if ( LoopIndex == count + 1 )
+ i = count - 1;
+ while (lpStartOfReturnBuffer[i] == '9' && i > 0)
{
- break;
+ lpStartOfReturnBuffer[i] = '0';
+ i--;
}
- }
- *lpReturnBuffer = '\0';
-
- /* Round if needed. If count is less then 0
- then windows does not round for some reason.*/
- nTempBufferLength = strlen( lpStartOfReturnBuffer ) - 1;
-
- /* Add one for the preceeding zero. */
- lpReturnBuffer = ( lpStartOfReturnBuffer + 1 );
-
- if ( nTempBufferLength >= count && count >= 0 )
- {
- /* Determine whether I need to round up. */
- if ( *(lpReturnBuffer + count) >= '5' )
+ if (i == 0 && lpStartOfReturnBuffer[i] == '9')
{
- CHAR cNumberToBeRounded;
- if ( count != 0 )
- {
- cNumberToBeRounded = *(lpReturnBuffer + count - 1);
- }
- else
- {
- cNumberToBeRounded = *lpReturnBuffer;
- }
-
- if ( cNumberToBeRounded < '9' )
- {
- if ( count > 0 )
- {
- /* Add one to the character. */
- (*(lpReturnBuffer + count - 1))++;
- }
- else
- {
- if ( cNumberToBeRounded >= '5' )
- {
- (*dec)++;
- }
- }
- }
- else
- {
- LPSTR lpRounding = NULL;
-
- if ( count > 0 )
- {
- lpRounding = lpReturnBuffer + count - 1;
- }
- else
- {
- lpRounding = lpReturnBuffer + count;
- }
-
- while ( cNumberToBeRounded == '9' )
- {
- cNumberToBeRounded = *lpRounding;
-
- if ( cNumberToBeRounded == '9' )
- {
- *lpRounding = '0';
- lpRounding--;
- }
- }
-
- if ( lpRounding == lpStartOfReturnBuffer )
- {
- /* Overflow. number is a whole number now. */
- *lpRounding = '1';
- memset( ++lpRounding, '0', count);
-
- /* The decimal has moved. */
- (*dec)++;
- }
- else
- {
- *lpRounding = ++cNumberToBeRounded;
- }
- }
+ lpStartOfReturnBuffer[i] = '1';
+ (*dec)++;
}
else
{
- /* Get rid of the preceding 0 */
- lpStartOfReturnBuffer++;
- }
- }
-
- if ( *lpStartOfReturnBuffer == '0' )
- {
- lpStartOfReturnBuffer++;
- }
-
- if ( count >= 0 )
- {
- *(lpStartOfReturnBuffer + count) = '\0';
- }
- else
- {
- *lpStartOfReturnBuffer = '\0';
+ lpStartOfReturnBuffer[i]++;
+ }
}
done:
LOGEXIT( "_ecvt returning %p (%s)\n", lpStartOfReturnBuffer , lpStartOfReturnBuffer );
PERF_EXIT(_ecvt);
-
+
return lpStartOfReturnBuffer;
}
diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
index e3fa09f7c8..1f20ee0cad 100644
--- a/src/pal/src/exception/seh-unwind.cpp
+++ b/src/pal/src/exception/seh-unwind.cpp
@@ -155,6 +155,7 @@ static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
#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_REG_SP, (unw_word_t *) &winContext->ResumeEsp);
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);
@@ -243,6 +244,7 @@ static void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext,
GetContextPointer(cursor, unwContext, UNW_AARCH64_X26, &contextPointers->X26);
GetContextPointer(cursor, unwContext, UNW_AARCH64_X27, &contextPointers->X27);
GetContextPointer(cursor, unwContext, UNW_AARCH64_X28, &contextPointers->X28);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X29, &contextPointers->Fp);
#else
#error unsupported architecture
#endif
diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
index ad09e02884..2d1c18218a 100644
--- a/src/pal/src/exception/seh.cpp
+++ b/src/pal/src/exception/seh.cpp
@@ -27,7 +27,7 @@ Abstract:
#include "pal/init.h"
#include "pal/process.h"
#include "pal/malloc.hpp"
-#include "signal.hpp"
+#include "pal/signal.hpp"
#if HAVE_MACH_EXCEPTIONS
#include "machexception.h"
@@ -111,14 +111,12 @@ Return value :
BOOL
SEHInitialize (CPalThread *pthrCurrent, DWORD flags)
{
-#if !HAVE_MACH_EXCEPTIONS
if (!SEHInitializeSignals(flags))
{
ERROR("SEHInitializeSignals failed!\n");
SEHCleanup();
return FALSE;
}
-#endif
return TRUE;
}
@@ -142,9 +140,8 @@ SEHCleanup()
#if HAVE_MACH_EXCEPTIONS
SEHCleanupExceptionPort();
-#else
- SEHCleanupSignals();
#endif
+ SEHCleanupSignals();
}
/*++
@@ -226,7 +223,11 @@ Parameters:
PAL_SEHException* ex - the exception to throw.
--*/
extern "C"
+#ifdef _X86_
+void __fastcall ThrowExceptionHelper(PAL_SEHException* ex)
+#else // _X86_
void ThrowExceptionHelper(PAL_SEHException* ex)
+#endif // !_X86_
{
throw std::move(*ex);
}
diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
index 26e2a012c5..57ae62ea21 100644
--- a/src/pal/src/exception/signal.cpp
+++ b/src/pal/src/exception/signal.cpp
@@ -27,24 +27,28 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do
#include "pal/threadinfo.hpp"
#include "pal/threadsusp.hpp"
#include "pal/seh.hpp"
+#include "pal/signal.hpp"
#include "pal/palinternal.h"
+
+#include <errno.h>
+#include <signal.h>
+
#if !HAVE_MACH_EXCEPTIONS
#include "pal/init.h"
#include "pal/process.h"
#include "pal/debug.h"
+#include "pal/virtual.h"
+#include "pal/utils.h"
-#include <signal.h>
-#include <errno.h>
#include <string.h>
#include <sys/ucontext.h>
#include <sys/utsname.h>
#include <unistd.h>
+#include <sys/mman.h>
#include "pal/context.h"
-using namespace CorUnix;
-
#ifdef SIGRTMIN
#define INJECT_ACTIVATION_SIGNAL SIGRTMIN
#endif
@@ -52,6 +56,9 @@ using namespace CorUnix;
#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;
/* local type definitions *****************************************************/
@@ -63,8 +70,19 @@ typedef void *siginfo_t;
#endif /* !HAVE_SIGINFO_T */
typedef void (*SIGFUNC)(int, siginfo_t *, void *);
+#if !HAVE_MACH_EXCEPTIONS
+// Return context and status for the signal_handler_worker.
+struct SignalHandlerWorkerReturnPoint
+{
+ bool returnFromHandler;
+ CONTEXT context;
+};
+#endif // !HAVE_MACH_EXCEPTIONS
+
/* internal function declarations *********************************************/
+static void sigterm_handler(int code, siginfo_t *siginfo, void *context);
+#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);
static void sigsegv_handler(int code, siginfo_t *siginfo, void *context);
@@ -72,19 +90,23 @@ static void sigtrap_handler(int code, siginfo_t *siginfo, void *context);
static void sigbus_handler(int code, siginfo_t *siginfo, void *context);
static void sigint_handler(int code, siginfo_t *siginfo, void *context);
static void sigquit_handler(int code, siginfo_t *siginfo, void *context);
-static void sigterm_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);
+static void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags = 0);
static void restore_signal(int signal_id, struct sigaction *previousAction);
/* internal data declarations *********************************************/
+static bool registered_sigterm_handler = false;
+
+struct sigaction g_previous_sigterm;
+#if !HAVE_MACH_EXCEPTIONS
struct sigaction g_previous_sigill;
struct sigaction g_previous_sigtrap;
struct sigaction g_previous_sigfpe;
@@ -92,9 +114,6 @@ struct sigaction g_previous_sigbus;
struct sigaction g_previous_sigsegv;
struct sigaction g_previous_sigint;
struct sigaction g_previous_sigquit;
-struct sigaction g_previous_sigterm;
-
-static bool registered_sigterm_handler = false;
#ifdef INJECT_ACTIVATION_SIGNAL
struct sigaction g_previous_activation;
@@ -103,9 +122,94 @@ struct sigaction g_previous_activation;
// 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;
+#endif // !HAVE_MACH_EXCEPTIONS
/* public function definitions ************************************************/
+#if !HAVE_MACH_EXCEPTIONS
+/*++
+Function :
+ EnsureSignalAlternateStack
+
+ Ensure that alternate stack for signal handling is allocated for the current thread
+
+Parameters :
+ None
+
+Return :
+ TRUE in case of a success, FALSE otherwise
+--*/
+BOOL EnsureSignalAlternateStack()
+{
+ stack_t oss;
+
+ // Query the current alternate signal stack
+ int st = sigaltstack(NULL, &oss);
+
+ if ((st == 0) && (oss.ss_flags == SS_DISABLE))
+ {
+ // There is no alternate stack for SIGSEGV handling installed yet so allocate one
+
+ // We include the size of the SignalHandlerWorkerReturnPoint in the alternate stack size since the
+ // context contained in it is large and the SIGSTKSZ was not sufficient on ARM64 during testing.
+ int altStackSize = SIGSTKSZ + ALIGN_UP(sizeof(SignalHandlerWorkerReturnPoint), 16) + VIRTUAL_PAGE_SIZE;
+ void* altStack;
+ int st = posix_memalign(&altStack, VIRTUAL_PAGE_SIZE, altStackSize);
+ if (st == 0)
+ {
+ // create a guard page for the alternate stack
+ st = mprotect(altStack, VIRTUAL_PAGE_SIZE, PROT_NONE);
+ if (st == 0)
+ {
+ stack_t ss;
+ ss.ss_sp = (char*)altStack;
+ ss.ss_size = altStackSize;
+ ss.ss_flags = 0;
+ st = sigaltstack(&ss, NULL);
+ if (st != 0)
+ {
+ // Installation of the alternate stack failed, so revert the guard page protection
+ int st2 = mprotect(altStack, VIRTUAL_PAGE_SIZE, PROT_READ | PROT_WRITE);
+ _ASSERTE(st2 == 0);
+ }
+ }
+
+ if (st != 0)
+ {
+ free(altStack);
+ }
+ }
+ }
+
+ return (st == 0);
+}
+
+/*++
+Function :
+ FreeSignalAlternateStack
+
+ Free alternate stack for signal handling
+
+Parameters :
+ None
+
+Return :
+ None
+--*/
+void FreeSignalAlternateStack()
+{
+ stack_t ss, oss;
+ ss.ss_flags = SS_DISABLE;
+ int st = sigaltstack(&ss, &oss);
+ if ((st == 0) && (oss.ss_flags != SS_DISABLE))
+ {
+ int st = mprotect(oss.ss_sp, VIRTUAL_PAGE_SIZE, PROT_READ | PROT_WRITE);
+ _ASSERTE(st == 0);
+ free(oss.ss_sp);
+ }
+}
+#endif // !HAVE_MACH_EXCEPTIONS
+
/*++
Function :
SEHInitializeSignals
@@ -122,6 +226,7 @@ BOOL SEHInitializeSignals(DWORD flags)
{
TRACE("Initializing signal handlers\n");
+#if !HAVE_MACH_EXCEPTIONS
/* we call handle_signal for every possible signal, even
if we don't provide a signal handler.
@@ -139,16 +244,24 @@ BOOL SEHInitializeSignals(DWORD flags)
handle_signal(SIGTRAP, sigtrap_handler, &g_previous_sigtrap);
handle_signal(SIGFPE, sigfpe_handler, &g_previous_sigfpe);
handle_signal(SIGBUS, sigbus_handler, &g_previous_sigbus);
- handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv);
+ // SIGSEGV handler runs on a separate stack so that we can handle stack overflow
+ handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv, SA_ONSTACK);
handle_signal(SIGINT, sigint_handler, &g_previous_sigint);
handle_signal(SIGQUIT, sigquit_handler, &g_previous_sigquit);
+ if (!EnsureSignalAlternateStack())
+ {
+ return FALSE;
+ }
+#endif // !HAVE_MACH_EXCEPTIONS
+
if (flags & PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER)
{
handle_signal(SIGTERM, sigterm_handler, &g_previous_sigterm);
registered_sigterm_handler = true;
}
+#if !HAVE_MACH_EXCEPTIONS
#ifdef INJECT_ACTIVATION_SIGNAL
handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation);
#endif
@@ -162,6 +275,7 @@ BOOL SEHInitializeSignals(DWORD flags)
issued a SIGPIPE will, instead, report an error and set errno to EPIPE.
*/
signal(SIGPIPE, SIG_IGN);
+#endif // !HAVE_MACH_EXCEPTIONS
return TRUE;
}
@@ -186,6 +300,7 @@ void SEHCleanupSignals()
{
TRACE("Restoring default signal handlers\n");
+#if !HAVE_MACH_EXCEPTIONS
restore_signal(SIGILL, &g_previous_sigill);
restore_signal(SIGTRAP, &g_previous_sigtrap);
restore_signal(SIGFPE, &g_previous_sigfpe);
@@ -193,19 +308,23 @@ void SEHCleanupSignals()
restore_signal(SIGSEGV, &g_previous_sigsegv);
restore_signal(SIGINT, &g_previous_sigint);
restore_signal(SIGQUIT, &g_previous_sigquit);
+#endif // !HAVE_MACH_EXCEPTIONS
if (registered_sigterm_handler)
{
restore_signal(SIGTERM, &g_previous_sigterm);
}
+#if !HAVE_MACH_EXCEPTIONS
#ifdef INJECT_ACTIVATION_SIGNAL
restore_signal(INJECT_ACTIVATION_SIGNAL, &g_previous_activation);
#endif
+#endif // !HAVE_MACH_EXCEPTIONS
}
/* internal function definitions **********************************************/
+#if !HAVE_MACH_EXCEPTIONS
/*++
Function :
sigill_handler
@@ -276,6 +395,28 @@ static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
/*++
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)
+--*/
+extern "C" void signal_handler_worker(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+{
+ // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
+ // fault. We must disassemble the instruction at record.ExceptionAddress
+ // to correctly fill in this value.
+ returnPoint->returnFromHandler = common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr);
+ RtlRestoreContext(&returnPoint->context, NULL);
+}
+
+/*++
+Function :
sigsegv_handler
handle SIGSEGV signal (EXCEPTION_ACCESS_VIOLATION, others)
@@ -289,10 +430,38 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
{
if (PALIsInitialized())
{
- // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
- // fault. We must disassemble the instruction at record.ExceptionAddress
- // to correctly fill in this value.
- if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
+ // First check if we have a stack overflow
+ size_t sp = (size_t)GetNativeContextSP((native_context_t *)context);
+ size_t failureAddress = (size_t)siginfo->si_addr;
+
+ // If the failure address is at most one page above or below the stack pointer,
+ // we have a stack overflow.
+ if ((failureAddress - (sp - VIRTUAL_PAGE_SIZE)) < 2 * VIRTUAL_PAGE_SIZE)
+ {
+ (void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
+ PROCAbort();
+ }
+
+ // Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common
+ // hardware signal handler on the original stack.
+
+ // Establish a return point in case the common_signal_handler returns
+
+ volatile bool contextInitialization = true;
+
+ SignalHandlerWorkerReturnPoint returnPoint;
+ RtlCaptureContext(&returnPoint.context);
+
+ // When the signal handler worker completes, it uses setcontext to return to this point
+
+ if (contextInitialization)
+ {
+ contextInitialization = false;
+ ExecuteHandlerOnOriginalStack(code, siginfo, context, &returnPoint);
+ _ASSERTE(FALSE); // The ExecuteHandlerOnOriginalStack should never return
+ }
+
+ if (returnPoint.returnFromHandler)
{
return;
}
@@ -422,6 +591,7 @@ static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
restore_signal(code, &g_previous_sigquit);
kill(gPID, code);
}
+#endif // !HAVE_MACH_EXCEPTIONS
/*++
Function :
@@ -452,6 +622,7 @@ static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
}
}
+#if !HAVE_MACH_EXCEPTIONS
#ifdef INJECT_ACTIVATION_SIGNAL
/*++
Function :
@@ -650,6 +821,7 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
return false;
}
+#endif // !HAVE_MACH_EXCEPTIONS
/*++
Function :
@@ -666,11 +838,11 @@ Parameters :
note : if sigfunc is NULL, the default signal handler is restored
--*/
-void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction)
+void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags)
{
struct sigaction newAction;
- newAction.sa_flags = SA_RESTART;
+ newAction.sa_flags = SA_RESTART | additionalFlags;
#if HAVE_SIGINFO_T
newAction.sa_handler = NULL;
newAction.sa_sigaction = sigfunc;
@@ -707,5 +879,3 @@ void restore_signal(int signal_id, struct sigaction *previousAction)
errno, strerror(errno));
}
}
-
-#endif // !HAVE_MACH_EXCEPTIONS
diff --git a/src/pal/src/exception/signal.hpp b/src/pal/src/exception/signal.hpp
deleted file mode 100644
index cd019e676b..0000000000
--- a/src/pal/src/exception/signal.hpp
+++ /dev/null
@@ -1,52 +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:
-
- exception/signal.hpp
-
-Abstract:
- Private signal handling utilities for SEH
-
-
-
---*/
-
-#ifndef _PAL_SIGNAL_HPP_
-#define _PAL_SIGNAL_HPP_
-
-#if !HAVE_MACH_EXCEPTIONS
-
-/*++
-Function :
- SEHInitializeSignals
-
- Set-up signal handlers to catch signals and translate them to exceptions
-
-Parameters :
- flags: PAL initialization flags
-
-Return :
- TRUE in case of a success, FALSE otherwise
---*/
-BOOL SEHInitializeSignals(DWORD flags);
-
-/*++
-Function :
- SEHCleanupSignals
-
- Restore default signal handlers
-
- (no parameters, no return value)
---*/
-void SEHCleanupSignals();
-
-#endif // !HAVE_MACH_EXCEPTIONS
-
-#endif /* _PAL_SIGNAL_HPP_ */
-
diff --git a/src/pal/src/file/filetime.cpp b/src/pal/src/file/filetime.cpp
index a8666b0dff..ca36e04d9d 100644
--- a/src/pal/src/file/filetime.cpp
+++ b/src/pal/src/file/filetime.cpp
@@ -81,8 +81,8 @@ SET_DEFAULT_DEBUG_CHANNEL(FILE);
Both epochs are Gregorian. 1970 - 1601 = 369. Assuming a leap
year every four years, 369 / 4 = 92. However, 1700, 1800, and 1900
were NOT leap years, so 89 leap years, 280 non-leap years.
- 89 * 366 + 280 * 365 = 134744 days between epochs. Of course
- 60 * 60 * 24 = 86400 seconds per day, so 134744 * 86400 =
+ 89 * 366 + 280 * 365 = 134774 days between epochs. Of course
+ 60 * 60 * 24 = 86400 seconds per day, so 134774 * 86400 =
11644473600 = SECS_BETWEEN_1601_AND_1970_EPOCHS.
To 2001:
@@ -504,23 +504,29 @@ PALAPI
GetSystemTimeAsFileTime(
OUT LPFILETIME lpSystemTimeAsFileTime)
{
- struct timeval Time;
-
PERF_ENTRY(GetSystemTimeAsFileTime);
ENTRY("GetSystemTimeAsFileTime(lpSystemTimeAsFileTime=%p)\n",
lpSystemTimeAsFileTime);
- if ( gettimeofday( &Time, NULL ) != 0 )
+#if HAVE_WORKING_CLOCK_GETTIME
+ struct timespec Time;
+ if (clock_gettime(CLOCK_REALTIME, &Time) == 0)
{
- ASSERT("gettimeofday() failed");
- /* no way to indicate failure, so set time to zero */
- *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( 0, 0 );
+ *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( Time.tv_sec, Time.tv_nsec );
}
- else
+#else
+ struct timeval Time;
+ if (gettimeofday(&Time, NULL) == 0)
{
/* use (tv_usec * 1000) because 2nd arg is in nanoseconds */
- *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( Time.tv_sec,
- Time.tv_usec * 1000 );
+ *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( Time.tv_sec, Time.tv_usec * 1000);
+ }
+#endif
+ else
+ {
+ /* no way to indicate failure, so set time to zero */
+ ASSERT("clock_gettime or gettimeofday failed");
+ *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( 0, 0 );
}
LOGEXIT("GetSystemTimeAsFileTime returns.\n");
diff --git a/src/pal/src/include/pal/context.h b/src/pal/src/include/pal/context.h
index 6857c130ee..db6d69579a 100644
--- a/src/pal/src/include/pal/context.h
+++ b/src/pal/src/include/pal/context.h
@@ -248,8 +248,7 @@ inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc)
#define MCREG_Sp(mc) ((mc).sp)
#define MCREG_Pc(mc) ((mc).pc)
-#define MCREG_PState(mc) ((mc).pstate)
-#define MCREG_Cpsr(mc) ((mc).cpsr)
+#define MCREG_Cpsr(mc) ((mc).pstate)
#else
// For FreeBSD, as found in x86/ucontext.h
#define MCREG_Rbp(mc) ((mc).mc_rbp)
@@ -640,6 +639,21 @@ LPVOID GetNativeContextPC(const native_context_t *context);
/*++
Function :
+ GetNativeContextSP
+
+ Returns the stack pointer from the native context.
+
+Parameters :
+ const native_context_t *native : native context
+
+Return value :
+ The stack pointer from the native context.
+
+--*/
+LPVOID GetNativeContextSP(const native_context_t *context);
+
+/*++
+Function :
CONTEXTGetExceptionCodeForSignal
Translates signal and context information to a Win32 exception code.
diff --git a/src/pal/src/include/pal/module.h b/src/pal/src/include/pal/module.h
index 95fa605c21..72df268d3c 100644
--- a/src/pal/src/include/pal/module.h
+++ b/src/pal/src/include/pal/module.h
@@ -25,7 +25,7 @@ extern "C"
{
#endif // __cplusplus
-typedef BOOL (__stdcall *PDLLMAIN)(HINSTANCE, DWORD, LPVOID); /* entry point of module */
+typedef BOOL (PALAPI *PDLLMAIN)(HINSTANCE, DWORD, LPVOID); /* entry point of module */
typedef HINSTANCE (PALAPI *PREGISTER_MODULE)(LPCSTR); /* used to create the HINSTANCE for above DLLMain entry point */
typedef VOID (PALAPI *PUNREGISTER_MODULE)(HINSTANCE); /* used to cleanup the HINSTANCE for above DLLMain entry point */
diff --git a/src/pal/src/include/pal/signal.hpp b/src/pal/src/include/pal/signal.hpp
new file mode 100644
index 0000000000..dfe21f10fb
--- /dev/null
+++ b/src/pal/src/include/pal/signal.hpp
@@ -0,0 +1,140 @@
+// 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:
+
+ include/pal/signal.hpp
+
+Abstract:
+ Private signal handling utilities for SEH
+
+
+
+--*/
+
+#ifndef _PAL_SIGNAL_HPP_
+#define _PAL_SIGNAL_HPP_
+
+#if !HAVE_MACH_EXCEPTIONS
+
+struct SignalHandlerWorkerReturnPoint;
+
+/*++
+Function :
+ CallSignalHandlerWrapperX
+
+ These functions are never called, only a fake stack frame will be setup to have a return
+ address set to SignalHandlerWorkerReturnX during SIGSEGV handling.
+ It enables the unwinder to unwind stack from the handling code to the actual failure site.
+
+ There are four variants of this function based on what stack alignment needs to be done
+ to ensure properly aligned stack pointer at the call site of the signal_handler_worker.
+
+Parameters :
+ none
+
+ (no return value)
+--*/
+extern "C" void CallSignalHandlerWrapper0();
+extern "C" void CallSignalHandlerWrapper4();
+extern "C" void CallSignalHandlerWrapper8();
+extern "C" void CallSignalHandlerWrapper12();
+
+// Offset of the return address from the signal_handler_worker in the CallSignalHandlerWrapperX
+// relative to the start of the function.
+// There are four offsets matching the stack alignments as described in the function header above.
+extern "C" int SignalHandlerWorkerReturnOffset0;
+extern "C" int SignalHandlerWorkerReturnOffset4;
+extern "C" int SignalHandlerWorkerReturnOffset8;
+extern "C" int SignalHandlerWorkerReturnOffset12;
+
+/*++
+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)
+--*/
+extern "C" void signal_handler_worker(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint);
+
+/*++
+Function :
+ ExecuteHandlerOnOriginalStack
+
+ Executes signal_handler_worker on the original stack where the signal occured.
+ It installs fake stack frame to enable stack unwinding to the signal source location.
+
+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);
+
+/*++
+Function :
+ EnsureSignalAlternateStack
+
+ Ensure that alternate stack for signal handling is allocated for the current thread
+
+Parameters :
+ None
+
+Return :
+ TRUE in case of a success, FALSE otherwise
+--*/
+BOOL EnsureSignalAlternateStack();
+
+/*++
+Function :
+ FreeSignalAlternateStack
+
+ Free alternate stack for signal handling
+
+Parameters :
+ None
+
+Return :
+ None
+--*/
+void FreeSignalAlternateStack();
+
+#endif // !HAVE_MACH_EXCEPTIONS
+
+/*++
+Function :
+ SEHInitializeSignals
+
+ Set-up signal handlers to catch signals and translate them to exceptions
+
+Parameters :
+ flags: PAL initialization flags
+
+Return :
+ TRUE in case of a success, FALSE otherwise
+--*/
+BOOL SEHInitializeSignals(DWORD flags);
+
+/*++
+Function :
+ SEHCleanupSignals
+
+ Restore default signal handlers
+
+ (no parameters, no return value)
+--*/
+void SEHCleanupSignals();
+
+#endif /* _PAL_SIGNAL_HPP_ */
diff --git a/src/pal/src/init/pal.cpp b/src/pal/src/init/pal.cpp
index e6db7dca2e..fa94922325 100644
--- a/src/pal/src/init/pal.cpp
+++ b/src/pal/src/init/pal.cpp
@@ -105,7 +105,7 @@ static PCRITICAL_SECTION init_critsec = NULL;
static int Initialize(int argc, const char *const argv[], DWORD flags);
static BOOL INIT_IncreaseDescriptorLimit(void);
static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv);
-static LPWSTR INIT_FindEXEPath(LPCSTR exe_name);
+static LPWSTR INIT_ConvertEXEPath(LPCSTR exe_name);
#ifdef _DEBUG
extern void PROCDumpThreadList(void);
@@ -406,7 +406,7 @@ Initialize(
}
/* find out the application's full path */
- exe_path = INIT_FindEXEPath(argv[0]);
+ exe_path = INIT_ConvertEXEPath(argv[0]);
if (NULL == exe_path)
{
ERROR("Unable to find exe path\n");
@@ -1130,14 +1130,13 @@ static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv)
/*++
Function:
- INIT_FindEXEPath
+ INIT_ConvertEXEPath
Abstract:
- Determine the full, canonical path of the current executable by searching
- $PATH.
+ Check whether the executable path is valid, and convert its type (LPCSTR -> LPWSTR)
Parameters:
- LPCSTR exe_name : file to search for
+ LPCSTR exe_name : full path of the current executable
Return:
pointer to buffer containing the full path. This buffer must be released
@@ -1145,299 +1144,33 @@ Return:
Notes :
this function assumes that "exe_name" is in Unix style (no \)
-
-Notes 2:
- This doesn't handle the case of directories with the desired name
- (and directories are usually executable...)
--*/
-static LPWSTR INIT_FindEXEPath(LPCSTR exe_name)
+static LPWSTR INIT_ConvertEXEPath(LPCSTR exe_path)
{
-#ifndef __APPLE__
PathCharString real_path;
- LPSTR env_path;
- LPSTR path_ptr;
- LPSTR cur_dir;
- INT exe_name_length;
- BOOL need_slash;
LPWSTR return_value;
INT return_size;
struct stat theStats;
- /* if a path is specified, only search there */
- if (strchr(exe_name, '/'))
- {
- if ( -1 == stat( exe_name, &theStats ) )
- {
- ERROR( "The file does not exist\n" );
- return NULL;
- }
-
- if ( UTIL_IsExecuteBitsSet( &theStats ) )
- {
- if (!CorUnix::RealPathHelper(exe_name, real_path))
- {
- ERROR("realpath() failed!\n");
- return NULL;
- }
-
- return_size=MultiByteToWideChar(CP_ACP,0,real_path,-1,NULL,0);
- if ( 0 == return_size )
- {
- ASSERT("MultiByteToWideChar failure\n");
- return NULL;
- }
-
- return_value = reinterpret_cast<LPWSTR>(InternalMalloc((return_size*sizeof(WCHAR))));
- if ( NULL == return_value )
- {
- ERROR("Not enough memory to create full path\n");
- return NULL;
- }
- else
- {
- if (!MultiByteToWideChar(CP_ACP, 0, real_path, -1,
- return_value, return_size))
- {
- ASSERT("MultiByteToWideChar failure\n");
- free(return_value);
- return_value = NULL;
- }
- else
- {
- TRACE("full path to executable is %s\n", real_path.GetString());
- }
- }
- return return_value;
- }
- }
-
- /* no path was specified : search $PATH */
-
- env_path = EnvironGetenv("PATH");
- if (!env_path || *env_path=='\0')
- {
- WARN("$PATH isn't set.\n");
- if (env_path != NULL)
- {
- free(env_path);
- }
- goto last_resort;
- }
-
- exe_name_length=strlen(exe_name);
-
- cur_dir=env_path;
-
- while (cur_dir)
+ if (!strchr(exe_path, '/'))
{
- LPSTR full_path;
- struct stat theStats;
-
- /* skip all leading ':' */
- while (*cur_dir==':')
- {
- cur_dir++;
- }
- if (*cur_dir=='\0')
- {
- break;
- }
-
- /* cut string at next ':' */
- path_ptr = strchr(cur_dir, ':');
- if (path_ptr)
- {
- /* check if we need to add a '/' between the path and filename */
- need_slash=(*(path_ptr-1))!='/';
-
- /* NULL_terminate path element */
- *path_ptr++='\0';
- }
- else
- {
- /* check if we need to add a '/' between the path and filename */
- need_slash=(cur_dir[strlen(cur_dir)-1])!='/';
- }
-
- TRACE("looking for %s in %s\n", exe_name, cur_dir);
-
- /* build tentative full file name */
- int iLength = (strlen(cur_dir)+exe_name_length+2);
- full_path = reinterpret_cast<LPSTR>(InternalMalloc(iLength));
- if (!full_path)
- {
- ERROR("Not enough memory!\n");
- break;
- }
-
- if (strcpy_s(full_path, iLength, cur_dir) != SAFECRT_SUCCESS)
- {
- ERROR("strcpy_s failed!\n");
- free(full_path);
- free(env_path);
- return NULL;
- }
-
- if (need_slash)
- {
- if (strcat_s(full_path, iLength, "/") != SAFECRT_SUCCESS)
- {
- ERROR("strcat_s failed!\n");
- free(full_path);
- free(env_path);
- return NULL;
- }
- }
-
- if (strcat_s(full_path, iLength, exe_name) != SAFECRT_SUCCESS)
- {
- ERROR("strcat_s failed!\n");
- free(full_path);
- free(env_path);
- return NULL;
- }
-
- /* see if file exists AND is executable */
- if ( -1 != stat( full_path, &theStats ) )
- {
- if( UTIL_IsExecuteBitsSet( &theStats ) )
- {
- /* generate canonical path */
- if (!CorUnix::RealPathHelper(full_path, real_path))
- {
- ERROR("realpath() failed!\n");
- free(full_path);
- free(env_path);
- return NULL;
- }
- free(full_path);
-
- return_size = MultiByteToWideChar(CP_ACP,0,real_path,-1,NULL,0);
- if ( 0 == return_size )
- {
- ASSERT("MultiByteToWideChar failure\n");
- free(env_path);
- return NULL;
- }
-
- return_value = reinterpret_cast<LPWSTR>(InternalMalloc((return_size*sizeof(WCHAR))));
- if ( NULL == return_value )
- {
- ERROR("Not enough memory to create full path\n");
- free(env_path);
- return NULL;
- }
-
- if (!MultiByteToWideChar(CP_ACP, 0, real_path, -1, return_value,
- return_size))
- {
- ASSERT("MultiByteToWideChar failure\n");
- free(return_value);
- return_value = NULL;
- }
- else
- {
- TRACE("found %s in %s; real path is %s\n", exe_name,
- cur_dir,real_path.GetString());
- }
-
- free(env_path);
- return return_value;
- }
- }
-
- /* file doesn't exist : keep searching */
- free(full_path);
-
- /* path_ptr is NULL if there's no ':' after this directory */
- cur_dir=path_ptr;
- }
-
- free(env_path);
- TRACE("No %s found in $PATH (%s)\n", exe_name, EnvironGetenv("PATH", FALSE));
-
-last_resort:
- /* last resort : see if the executable is in the current directory. This is
- possible if it comes from a exec*() call. */
- if (0 == stat(exe_name,&theStats))
- {
- if ( UTIL_IsExecuteBitsSet( &theStats ) )
- {
- if (!CorUnix::RealPathHelper(exe_name, real_path))
- {
- ERROR("realpath() failed!\n");
- return NULL;
- }
-
- return_size = MultiByteToWideChar(CP_ACP,0,real_path,-1,NULL,0);
- if (0 == return_size)
- {
- ASSERT("MultiByteToWideChar failure\n");
- return NULL;
- }
-
- return_value = reinterpret_cast<LPWSTR>(InternalMalloc((return_size*sizeof(WCHAR))));
- if (NULL == return_value)
- {
- ERROR("Not enough memory to create full path\n");
- return NULL;
- }
- else
- {
- if (!MultiByteToWideChar(CP_ACP, 0, real_path, -1,
- return_value, return_size))
- {
- ASSERT("MultiByteToWideChar failure\n");
- free(return_value);
- return_value = NULL;
- }
- else
- {
- TRACE("full path to executable is %s\n", real_path.GetString());
- }
- }
-
- return return_value;
- }
- else
- {
- ERROR("found %s in current directory, but it isn't executable!\n",
- exe_name);
- }
- }
- else
- {
- TRACE("last resort failed : executable %s is not in the current "
- "directory\n",exe_name);
+ ERROR( "The exe path is not fully specified\n" );
+ return NULL;
}
- ERROR("executable %s not found anywhere!\n", exe_name);
- return NULL;
-#else // !__APPLE__
- // On the Mac we can just directly ask the OS for the executable path.
-
- LPWSTR return_value;
- INT return_size;
-
- PathCharString exec_pathPS;
- LPSTR exec_path = exec_pathPS.OpenStringBuffer(MAX_PATH);
- uint32_t bufsize = exec_pathPS.GetCount();
-
- if (-1 == _NSGetExecutablePath(exec_path, &bufsize))
+ if (-1 == stat(exe_path, &theStats))
{
- exec_pathPS.CloseBuffer(exec_pathPS.GetCount());
- exec_path = exec_pathPS.OpenStringBuffer(bufsize);
+ ERROR( "The file does not exist\n" );
+ return NULL;
}
- if (_NSGetExecutablePath(exec_path, &bufsize))
+ if (!CorUnix::RealPathHelper(exe_path, real_path))
{
- ASSERT("_NSGetExecutablePath failure\n");
+ ERROR("realpath() failed!\n");
return NULL;
}
- exec_pathPS.CloseBuffer(bufsize);
-
- return_size = MultiByteToWideChar(CP_ACP,0,exec_path,-1,NULL,0);
+ return_size = MultiByteToWideChar(CP_ACP, 0, real_path, -1, NULL, 0);
if (0 == return_size)
{
ASSERT("MultiByteToWideChar failure\n");
@@ -1452,7 +1185,7 @@ last_resort:
}
else
{
- if (!MultiByteToWideChar(CP_ACP, 0, exec_path, -1,
+ if (!MultiByteToWideChar(CP_ACP, 0, real_path, -1,
return_value, return_size))
{
ASSERT("MultiByteToWideChar failure\n");
@@ -1461,10 +1194,9 @@ last_resort:
}
else
{
- TRACE("full path to executable is %s\n", exec_path);
+ TRACE("full path to executable is %s\n", real_path.GetString());
}
}
return return_value;
-#endif // !__APPLE__
}
diff --git a/src/pal/src/init/sxs.cpp b/src/pal/src/init/sxs.cpp
index 225f91684b..3f323c6a6e 100644
--- a/src/pal/src/init/sxs.cpp
+++ b/src/pal/src/init/sxs.cpp
@@ -16,6 +16,7 @@
#include "pal/module.h"
#include "pal/process.h"
#include "pal/seh.hpp"
+#include "pal/signal.hpp"
using namespace CorUnix;
@@ -106,8 +107,20 @@ PAL_ERROR
AllocatePalThread(CPalThread **ppThread)
{
CPalThread *pThread = NULL;
+ PAL_ERROR palError;
- PAL_ERROR palError = CreateThreadData(&pThread);
+#if !HAVE_MACH_EXCEPTIONS
+ // Ensure alternate stack for SIGSEGV handling. Our SIGSEGV handler is set to
+ // run on an alternate stack and the stack needs to be allocated per thread.
+ if (!EnsureSignalAlternateStack())
+ {
+ ERROR("Cannot allocate alternate stack for SIGSEGV handler!\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto exit;
+ }
+#endif // !HAVE_MACH_EXCEPTIONS
+
+ palError = CreateThreadData(&pThread);
if (NO_ERROR != palError)
{
goto exit;
diff --git a/src/pal/src/loader/module.cpp b/src/pal/src/loader/module.cpp
index 63a65ffb61..bbe8b9ddcc 100644
--- a/src/pal/src/loader/module.cpp
+++ b/src/pal/src/loader/module.cpp
@@ -280,6 +280,16 @@ GetProcAddress(
module = (MODSTRUCT *) hModule;
+ /* try to assert on attempt to locate symbol by ordinal */
+ /* this can't be an exact test for HIWORD((DWORD)lpProcName) == 0
+ because of the address range reserved for ordinals contain can
+ be a valid string address on non-Windows systems
+ */
+ if ((DWORD_PTR)lpProcName < VIRTUAL_PAGE_SIZE)
+ {
+ ASSERT("Attempt to locate symbol by ordinal?!\n");
+ }
+
/* parameter validation */
if ((lpProcName == nullptr) || (*lpProcName == '\0'))
@@ -295,16 +305,6 @@ GetProcAddress(
SetLastError(ERROR_INVALID_HANDLE);
goto done;
}
-
- /* try to assert on attempt to locate symbol by ordinal */
- /* this can't be an exact test for HIWORD((DWORD)lpProcName) == 0
- because of the address range reserved for ordinals contain can
- be a valid string address on non-Windows systems
- */
- if ((DWORD_PTR)lpProcName < VIRTUAL_PAGE_SIZE)
- {
- ASSERT("Attempt to locate symbol by ordinal?!\n");
- }
// Get the symbol's address.
diff --git a/src/pal/src/locale/unicode.cpp b/src/pal/src/locale/unicode.cpp
index 3c119744b0..69214735d1 100644
--- a/src/pal/src/locale/unicode.cpp
+++ b/src/pal/src/locale/unicode.cpp
@@ -42,7 +42,7 @@ Revision History:
#endif // __APPLE__
#include <errno.h>
#if HAVE_COREFOUNDATION
-#include <corefoundation/corefoundation.h>
+#include <CoreFoundation/CoreFoundation.h>
#endif // HAVE_COREFOUNDATION
#include <debugmacrosext.h>
diff --git a/src/pal/src/misc/cgroup.cpp b/src/pal/src/misc/cgroup.cpp
new file mode 100644
index 0000000000..40178032e3
--- /dev/null
+++ b/src/pal/src/misc/cgroup.cpp
@@ -0,0 +1,335 @@
+// 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:
+
+ cgroup.cpp
+
+Abstract:
+ Read memory limits for the current process
+--*/
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+#include "pal/palinternal.h"
+#include <sys/resource.h>
+#include "pal/virtual.h"
+
+#define PROC_MOUNTINFO_FILENAME "/proc/self/mountinfo"
+#define PROC_CGROUP_FILENAME "/proc/self/cgroup"
+#define PROC_STATM_FILENAME "/proc/self/statm"
+#define MEM_LIMIT_FILENAME "/memory.limit_in_bytes"
+
+class CGroup
+{
+ char *m_memory_cgroup_path;
+public:
+ CGroup()
+ {
+ m_memory_cgroup_path = nullptr;
+ char* memoryHierarchyMount = nullptr;
+ char *cgroup_path_relative_to_mount = nullptr;
+ size_t len;
+ memoryHierarchyMount = FindMemoryHierarchyMount();
+ if (memoryHierarchyMount == nullptr)
+ goto done;
+
+ cgroup_path_relative_to_mount = FindCGroupPathForMemorySubsystem();
+ if (cgroup_path_relative_to_mount == nullptr)
+ goto done;
+
+ len = strlen(memoryHierarchyMount);
+ len += strlen(cgroup_path_relative_to_mount);
+ m_memory_cgroup_path = (char*)PAL_malloc(len+1);
+ if (m_memory_cgroup_path == nullptr)
+ goto done;
+
+ strcpy_s(m_memory_cgroup_path, len+1, memoryHierarchyMount);
+ strcat_s(m_memory_cgroup_path, len+1, cgroup_path_relative_to_mount);
+
+ done:
+ PAL_free(memoryHierarchyMount);
+ PAL_free(cgroup_path_relative_to_mount);
+ }
+ ~CGroup()
+ {
+ PAL_free(m_memory_cgroup_path);
+ }
+
+ bool GetPhysicalMemoryLimit(size_t *val)
+ {
+ char *mem_limit_filename = nullptr;
+ bool result = false;
+
+ if (m_memory_cgroup_path == nullptr)
+ return result;
+
+ size_t len = strlen(m_memory_cgroup_path);
+ len += strlen(MEM_LIMIT_FILENAME);
+ mem_limit_filename = (char*)PAL_malloc(len+1);
+ if (mem_limit_filename == nullptr)
+ return result;
+
+ strcpy_s(mem_limit_filename, len+1, m_memory_cgroup_path);
+ strcat_s(mem_limit_filename, len+1, MEM_LIMIT_FILENAME);
+ result = ReadMemoryValueFromFile(mem_limit_filename, val);
+ PAL_free(mem_limit_filename);
+ return result;
+ }
+private:
+ char* FindMemoryHierarchyMount()
+ {
+ char *line = nullptr;
+ size_t lineLen = 0, maxLineLen = 0;
+ char *filesystemType = nullptr;
+ char *options = nullptr;
+ char* mountpath = nullptr;
+
+ FILE *mountinfofile = fopen(PROC_MOUNTINFO_FILENAME, "r");
+ if (mountinfofile == nullptr)
+ goto done;
+
+ while (getline(&line, &lineLen, mountinfofile) != -1)
+ {
+ if (filesystemType == nullptr || lineLen > maxLineLen)
+ {
+ PAL_free(filesystemType);
+ PAL_free(options);
+ filesystemType = (char*)PAL_malloc(lineLen+1);
+ if (filesystemType == nullptr)
+ goto done;
+ options = (char*)PAL_malloc(lineLen+1);
+ if (options == nullptr)
+ goto done;
+ maxLineLen = lineLen;
+ }
+ char* separatorChar = strchr(line, '-');
+
+ // See man page of proc to get format for /proc/self/mountinfo file
+ int sscanfRet = sscanf_s(separatorChar,
+ "- %s %*s %s",
+ filesystemType, lineLen+1,
+ options, lineLen+1);
+ if (sscanfRet != 2)
+ {
+ _ASSERTE(!"Failed to parse mount info file contents with sscanf_s.");
+ goto done;
+ }
+
+ if (strncmp(filesystemType, "cgroup", 6) == 0)
+ {
+ char* context = nullptr;
+ char* strTok = strtok_s(options, ",", &context);
+ while (strTok != nullptr)
+ {
+ if (strncmp("memory", strTok, 6) == 0)
+ {
+ mountpath = (char*)PAL_malloc(lineLen+1);
+ if (mountpath == nullptr)
+ goto done;
+
+ sscanfRet = sscanf_s(line,
+ "%*s %*s %*s %*s %s ",
+ mountpath, lineLen+1);
+ if (sscanfRet != 1)
+ {
+ PAL_free(mountpath);
+ mountpath = nullptr;
+ _ASSERTE(!"Failed to parse mount info file contents with sscanf_s.");
+ }
+ goto done;
+ }
+ strTok = strtok_s(nullptr, ",", &context);
+ }
+ }
+ }
+ done:
+ PAL_free(filesystemType);
+ PAL_free(options);
+ free(line);
+ if (mountinfofile)
+ fclose(mountinfofile);
+ return mountpath;
+ }
+
+ char* FindCGroupPathForMemorySubsystem()
+ {
+ char *line = nullptr;
+ size_t lineLen = 0;
+ size_t maxLineLen = 0;
+ char *subsystem_list = nullptr;
+ char *cgroup_path = nullptr;
+ bool result = false;
+
+ FILE *cgroupfile = fopen(PROC_CGROUP_FILENAME, "r");
+ if (cgroupfile == nullptr)
+ goto done;
+
+ while (!result && getline(&line, &lineLen, cgroupfile) != -1)
+ {
+ if (subsystem_list == nullptr || lineLen > maxLineLen)
+ {
+ PAL_free(subsystem_list);
+ PAL_free(cgroup_path);
+ subsystem_list = (char*)PAL_malloc(lineLen+1);
+ if (subsystem_list == nullptr)
+ goto done;
+ cgroup_path = (char*)PAL_malloc(lineLen+1);
+ if (cgroup_path == nullptr)
+ goto done;
+ maxLineLen = lineLen;
+ }
+
+ // See man page of proc to get format for /proc/self/cgroup file
+ int sscanfRet = sscanf_s(line,
+ "%*[^:]:%[^:]:%s",
+ subsystem_list, lineLen+1,
+ cgroup_path, lineLen+1);
+ if (sscanfRet != 2)
+ {
+ _ASSERTE(!"Failed to parse cgroup info file contents with sscanf_s.");
+ goto done;
+ }
+
+ char* context = nullptr;
+ char* strTok = strtok_s(subsystem_list, ",", &context);
+ while (strTok != nullptr)
+ {
+ if (strncmp("memory", strTok, 6) == 0)
+ {
+ result = true;
+ break;
+ }
+ strTok = strtok_s(nullptr, ",", &context);
+ }
+ }
+ done:
+ PAL_free(subsystem_list);
+ if (!result)
+ {
+ PAL_free(cgroup_path);
+ cgroup_path = nullptr;
+ }
+ free(line);
+ if (cgroupfile)
+ fclose(cgroupfile);
+ return cgroup_path;
+ }
+
+ bool ReadMemoryValueFromFile(const char* filename, size_t* val)
+ {
+ bool result = false;
+ char *line = nullptr;
+ size_t lineLen = 0;
+ char* endptr = nullptr;
+ size_t num = 0, l, multiplier;
+
+ if (val == nullptr)
+ return false;
+
+ FILE* file = fopen(filename, "r");
+ if (file == nullptr)
+ goto done;
+
+ if (getline(&line, &lineLen, file) == -1)
+ goto done;
+
+ errno = 0;
+ num = strtoull(line, &endptr, 0);
+ if (errno != 0)
+ goto done;
+
+ multiplier = 1;
+ switch(*endptr)
+ {
+ case 'g':
+ case 'G': multiplier = 1024;
+ case 'm':
+ case 'M': multiplier = multiplier*1024;
+ case 'k':
+ case 'K': multiplier = multiplier*1024;
+ }
+
+ *val = num * multiplier;
+ result = true;
+ if (*val/multiplier != num)
+ result = false;
+ done:
+ if (file)
+ fclose(file);
+ free(line);
+ return result;
+ }
+};
+
+
+size_t
+PALAPI
+PAL_GetRestrictedPhysicalMemoryLimit()
+{
+ CGroup cgroup;
+ size_t physical_memory_limit;
+
+ if (!cgroup.GetPhysicalMemoryLimit(&physical_memory_limit))
+ physical_memory_limit = SIZE_T_MAX;
+
+ struct rlimit curr_rlimit;
+ size_t rlimit_soft_limit = (size_t)RLIM_INFINITY;
+ if (getrlimit(RLIMIT_AS, &curr_rlimit) == 0)
+ {
+ rlimit_soft_limit = curr_rlimit.rlim_cur;
+ }
+ physical_memory_limit = min(physical_memory_limit, rlimit_soft_limit);
+
+ // Ensure that limit is not greater than real memory size
+ long pages = sysconf(_SC_PHYS_PAGES);
+ if (pages != -1)
+ {
+ long pageSize = sysconf(_SC_PAGE_SIZE);
+ if (pageSize != -1)
+ {
+ physical_memory_limit = min(physical_memory_limit,
+ (size_t)pages * pageSize);
+ }
+ }
+
+ if(physical_memory_limit == SIZE_T_MAX)
+ physical_memory_limit = 0;
+ return physical_memory_limit;
+}
+
+BOOL
+PALAPI
+PAL_GetWorkingSetSize(size_t* val)
+{
+ BOOL result = false;
+ size_t linelen;
+ char* line = nullptr;
+
+ if (val == nullptr)
+ return FALSE;
+
+ FILE* file = fopen(PROC_STATM_FILENAME, "r");
+ if (file != nullptr && getline(&line, &linelen, file) != -1)
+ {
+ char* context = nullptr;
+ char* strTok = strtok_s(line, " ", &context);
+ strTok = strtok_s(nullptr, " ", &context);
+
+ errno = 0;
+ *val = strtoull(strTok, nullptr, 0);
+ if(errno == 0)
+ {
+ *val = *val * VIRTUAL_PAGE_SIZE;
+ result = true;
+ }
+ }
+
+ if (file)
+ fclose(file);
+ free(line);
+ return result;
+}
diff --git a/src/pal/src/misc/dbgmsg.cpp b/src/pal/src/misc/dbgmsg.cpp
index d6f173f160..5eb5ebf9ba 100644
--- a/src/pal/src/misc/dbgmsg.cpp
+++ b/src/pal/src/misc/dbgmsg.cpp
@@ -50,11 +50,7 @@ using namespace CorUnix;
/* append mode file I/O is safer */
#define _PAL_APPEND_DBG_OUTPUT_
-#if defined(_PAL_APPEND_DBG_OUTPUT_)
static const char FOPEN_FLAGS[] = "at";
-#else
-static const char FOPEN_FLAGS[] = "wt";
-#endif
/* number of ENTRY nesting levels to indicate with a '.' */
#define MAX_NESTING 50
diff --git a/src/pal/src/misc/environ.cpp b/src/pal/src/misc/environ.cpp
index fed7b69f38..9fc13467c5 100644
--- a/src/pal/src/misc/environ.cpp
+++ b/src/pal/src/misc/environ.cpp
@@ -218,7 +218,13 @@ GetEnvironmentVariableW(
}
else if (size == 0)
{
- // handle error in GetEnvironmentVariableA
+ // If size is 0, it either means GetEnvironmentVariableA failed, or that
+ // it succeeded and the value of the variable is empty. Check GetLastError
+ // to determine which. If the call failed, we won't touch the buffer.
+ if (GetLastError() == ERROR_SUCCESS)
+ {
+ *lpBuffer = '\0';
+ }
}
else
{
diff --git a/src/pal/src/misc/errorstrings.cpp b/src/pal/src/misc/errorstrings.cpp
index 22443114ee..2c5243945c 100644
--- a/src/pal/src/misc/errorstrings.cpp
+++ b/src/pal/src/misc/errorstrings.cpp
@@ -76,7 +76,7 @@ ErrorString palErrorStrings[] =
{ ERROR_SEM_TIMEOUT, W("The semaphore timeout period has expired.\n") },
{ ERROR_INSUFFICIENT_BUFFER, W("The data area passed to a system call is too small.\n") },
{ ERROR_INVALID_NAME, W("The filename, directory name, or volume label syntax is incorrect.\n") },
- { ERROR_MOD_NOT_FOUND, W("The specified module could not be found.\n") },
+ { ERROR_MOD_NOT_FOUND, W("The specified module or one of its dependencies could not be found.\n") },
{ ERROR_PROC_NOT_FOUND, W("The specified procedure could not be found.\n") },
{ ERROR_WAIT_NO_CHILDREN, W("There are no child processes to wait for.\n") },
{ ERROR_NEGATIVE_SEEK, W("An attempt was made to move the file pointer before the beginning of the file.\n") },
diff --git a/src/pal/src/misc/sysinfo.cpp b/src/pal/src/misc/sysinfo.cpp
index 3ccb35ab81..fff051818f 100644
--- a/src/pal/src/misc/sysinfo.cpp
+++ b/src/pal/src/misc/sysinfo.cpp
@@ -32,12 +32,20 @@ Revision History:
#error Either sysctl or sysconf is required for GetSystemInfo.
#endif
+#if HAVE_SYSINFO
+#include <sys/sysinfo.h>
+#endif
+
#include <sys/param.h>
#if HAVE_SYS_VMPARAM_H
#include <sys/vmparam.h>
#endif // HAVE_SYS_VMPARAM_H
+#if HAVE_XSWDEV
+#include <vm/vm_param.h>
+#endif // HAVE_XSWDEV
+
#if HAVE_MACH_VM_TYPES_H
#include <mach/vm_types.h>
#endif // HAVE_MACH_VM_TYPES_H
@@ -216,6 +224,8 @@ GlobalMemoryStatusEx(
lpBuffer->ullAvailExtendedVirtual = 0;
BOOL fRetVal = FALSE;
+ int mib[3];
+ int rc;
// Get the physical memory size
#if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
@@ -226,7 +236,6 @@ GlobalMemoryStatusEx(
lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
fRetVal = TRUE;
#elif HAVE_SYSCTL
- int mib[2];
int64_t physical_memory;
size_t length;
@@ -234,7 +243,7 @@ GlobalMemoryStatusEx(
mib[0] = CTL_HW;
mib[1] = HW_MEMSIZE;
length = sizeof(INT64);
- int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0);
+ rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0);
if (rc != 0)
{
ASSERT("sysctl failed for HW_MEMSIZE (%d)\n", errno);
@@ -244,11 +253,65 @@ GlobalMemoryStatusEx(
lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
fRetVal = TRUE;
}
-#elif // HAVE_SYSINFO
- // TODO: implement getting memory details via sysinfo. On Linux, it provides swap file details that
- // we can use to fill in the xxxPageFile members.
-#endif // HAVE_SYSCONF
+#endif // HAVE_SYSCTL
+
+ // Get swap file size, consider the ability to get the values optional
+ // (don't return FALSE from the GlobalMemoryStatusEx)
+#if HAVE_XSW_USAGE
+ // This is available on OSX
+ struct xsw_usage xsu;
+ mib[0] = CTL_VM;
+ mib[1] = VM_SWAPUSAGE;
+ size_t length = sizeof(xsu);
+ rc = sysctl(mib, 2, &xsu, &length, NULL, 0);
+ if (rc == 0)
+ {
+ lpBuffer->ullTotalPageFile = xsu.xsu_total;
+ lpBuffer->ullAvailPageFile = xsu.xsu_avail;
+ }
+#elif HAVE_XSWDEV
+ // E.g. FreeBSD
+ struct xswdev xsw;
+
+ size_t length = 2;
+ rc = sysctlnametomib("vm.swap_info", mib, &length);
+ if (rc == 0)
+ {
+ int pagesize = getpagesize();
+ // Aggregate the information for all swap files on the system
+ for (mib[2] = 0; ; mib[2]++)
+ {
+ length = sizeof(xsw);
+ rc = sysctl(mib, 3, &xsw, &length, NULL, 0);
+ if ((rc < 0) || (xsw.xsw_version != XSWDEV_VERSION))
+ {
+ // All the swap files were processed or coreclr was built against
+ // a version of headers not compatible with the current XSWDEV_VERSION.
+ break;
+ }
+
+ DWORDLONG avail = xsw.xsw_nblks - xsw.xsw_used;
+ lpBuffer->ullTotalPageFile += (DWORDLONG)xsw.xsw_nblks * pagesize;
+ lpBuffer->ullAvailPageFile += (DWORDLONG)avail * pagesize;
+ }
+ }
+#elif HAVE_SYSINFO
+ // Linux
+ struct sysinfo info;
+ rc = sysinfo(&info);
+ if (rc == 0)
+ {
+ lpBuffer->ullTotalPageFile = info.totalswap;
+ lpBuffer->ullAvailPageFile = info.freeswap;
+#if HAVE_SYSINFO_WITH_MEM_UNIT
+ // A newer version of the sysinfo structure represents all the sizes
+ // in mem_unit instead of bytes
+ lpBuffer->ullTotalPageFile *= info.mem_unit;
+ lpBuffer->ullAvailPageFile *= info.mem_unit;
+#endif // HAVE_SYSINFO_WITH_MEM_UNIT
+ }
+#endif // HAVE_SYSINFO
// Get the physical memory in use - from it, we can get the physical memory available.
// We do this only when we have the total physical memory available.
diff --git a/src/pal/src/misc/time.cpp b/src/pal/src/misc/time.cpp
index 918f92a90f..d16fb587ba 100644
--- a/src/pal/src/misc/time.cpp
+++ b/src/pal/src/misc/time.cpp
@@ -394,3 +394,35 @@ EXIT:
return retval;
}
+/*++
+Function:
+ PAL_nanosleep
+
+Sleeps for the time specified in timeInNs.
+Returns 0 on successful completion of the operation.
+--*/
+PALAPI
+INT
+PAL_nanosleep(
+ IN long timeInNs
+ )
+{
+ struct timespec req;
+ struct timespec rem;
+ int result;
+
+ req.tv_sec = 0;
+ req.tv_nsec = timeInNs;
+
+ do
+ {
+ // Sleep for the requested time.
+ result = nanosleep(&req, &rem);
+
+ // Save the remaining time (used if the loop runs another iteration).
+ req = rem;
+ }
+ while(result == -1 && errno == EINTR);
+
+ return result;
+}
diff --git a/src/pal/src/misc/utils.cpp b/src/pal/src/misc/utils.cpp
index f0ff63439f..4eefd749ed 100644
--- a/src/pal/src/misc/utils.cpp
+++ b/src/pal/src/misc/utils.cpp
@@ -124,7 +124,12 @@ BOOL UTIL_IsExecuteBitsSet( struct stat * stat_data )
}
/* Check for read permissions. */
- if ( stat_data->st_uid == geteuid() )
+ if ( 0 == geteuid() )
+ {
+ /* The process owner is root */
+ bRetVal = TRUE;
+ }
+ else if ( stat_data->st_uid == geteuid() )
{
/* The process owner is the file owner as well. */
if ( ( stat_data->st_mode & S_IXUSR ) )
diff --git a/src/pal/src/misc/version.cpp b/src/pal/src/misc/version.cpp
deleted file mode 100644
index 7a9f90a320..0000000000
--- a/src/pal/src/misc/version.cpp
+++ /dev/null
@@ -1,119 +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:
-
- version.c
-
-Abstract:
-
- Implementation of functions for getting platform.OS versions.
-
-Revision History:
-
-
-
---*/
-
-#include "pal/palinternal.h"
-#include "pal/dbgmsg.h"
-
-SET_DEFAULT_DEBUG_CHANNEL(MISC);
-
-/*++
-Function:
- GetVersionExA
-
-
-
-GetVersionEx
-
-The GetVersionEx function obtains extended information about the
-version of the operating system that is currently running.
-
-Parameters
-
-lpVersionInfo
- [in/out] Pointer to an OSVERSIONINFO data structure that the
- function fills with operating system version information.
-
- Before calling the GetVersionEx function, set the
- dwOSVersionInfoSize member of the OSVERSIONINFO data structure
- to sizeof(OSVERSIONINFO).
-
-Return Values
-
-If the function succeeds, the return value is a nonzero value.
-
-If the function fails, the return value is zero. To get extended error
-information, call GetLastError. The function fails if you specify an
-invalid value for the dwOSVersionInfoSize member of the OSVERSIONINFO
-structure.
-
---*/
-BOOL
-PALAPI
-GetVersionExA(
- IN OUT LPOSVERSIONINFOA lpVersionInformation)
-{
- BOOL bRet = TRUE;
- PERF_ENTRY(GetVersionExA);
- ENTRY("GetVersionExA (lpVersionInformation=%p)\n", lpVersionInformation);
-
- if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA))
- {
- lpVersionInformation->dwMajorVersion = 5; /* same as WIN2000 */
- lpVersionInformation->dwMinorVersion = 0; /* same as WIN2000 */
- lpVersionInformation->dwBuildNumber = 0;
- lpVersionInformation->dwPlatformId = VER_PLATFORM_UNIX;
- lpVersionInformation->szCSDVersion[0] = '\0'; /* no service pack */
- }
- else
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- bRet = FALSE;
- }
- LOGEXIT("GetVersionExA returning BOOL %d\n", bRet);
- PERF_EXIT(GetVersionExA);
- return bRet;
-}
-
-
-/*++
-Function:
- GetVersionExW
-
-See GetVersionExA
---*/
-BOOL
-PALAPI
-GetVersionExW(
- IN OUT LPOSVERSIONINFOW lpVersionInformation)
-{
- BOOL bRet = TRUE;
-
- PERF_ENTRY(GetVersionExW);
- ENTRY("GetVersionExW (lpVersionInformation=%p)\n", lpVersionInformation);
-
- if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOW))
- {
- lpVersionInformation->dwMajorVersion = 5; /* same as WIN2000 */
- lpVersionInformation->dwMinorVersion = 0; /* same as WIN2000 */
- lpVersionInformation->dwBuildNumber = 0;
- lpVersionInformation->dwPlatformId = VER_PLATFORM_UNIX;
- lpVersionInformation->szCSDVersion[0] = '\0'; /* no service pack */
- }
- else
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- bRet = FALSE;
- }
- LOGEXIT("GetVersionExW returning BOOL %d\n", bRet);
- PERF_EXIT(GetVersionExW);
- return bRet;
-}
diff --git a/src/pal/src/thread/context.cpp b/src/pal/src/thread/context.cpp
index 0449df568b..04a6fe5aaf 100644
--- a/src/pal/src/thread/context.cpp
+++ b/src/pal/src/thread/context.cpp
@@ -127,6 +127,8 @@ typedef int __ptrace_request;
ASSIGN_REG(R12)
#elif defined(_ARM64_)
#define ASSIGN_CONTROL_REGS \
+ ASSIGN_REG(Cpsr) \
+ ASSIGN_REG(Fp) \
ASSIGN_REG(Sp) \
ASSIGN_REG(Lr) \
ASSIGN_REG(Pc)
@@ -499,11 +501,13 @@ void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContex
if ((contextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
{
ASSIGN_CONTROL_REGS
-#ifdef _ARM_
+#if defined(_ARM_)
// WinContext assumes that the least bit of Pc is always 1 (denoting thumb)
// although the pc value retrived from native context might not have set the least bit.
// This becomes especially problematic if the context is on the JIT_WRITEBARRIER.
lpContext->Pc |= 0x1;
+#elif defined(_X86_)
+ lpContext->ResumeEsp = MCREG_Esp(native->uc_mcontext);
#endif
}
@@ -613,6 +617,35 @@ LPVOID GetNativeContextPC(const native_context_t *context)
/*++
Function :
+ GetNativeContextSP
+
+ Returns the stack pointer from the native context.
+
+Parameters :
+ const native_context_t *native : native context
+
+Return value :
+ The stack pointer from the native context.
+
+--*/
+LPVOID GetNativeContextSP(const native_context_t *context)
+{
+#ifdef _AMD64_
+ return (LPVOID)MCREG_Rsp(context->uc_mcontext);
+#elif defined(_X86_)
+ return (LPVOID) MCREG_Esp(context->uc_mcontext);
+#elif defined(_ARM_)
+ return (LPVOID) MCREG_Sp(context->uc_mcontext);
+#elif defined(_ARM64_)
+ return (LPVOID) MCREG_Sp(context->uc_mcontext);
+#else
+# error implement me for this architecture
+#endif
+}
+
+
+/*++
+Function :
CONTEXTGetExceptionCodeForSignal
Translates signal and context information to a Win32 exception code.
@@ -945,6 +978,7 @@ CONTEXT_GetThreadContextFromThreadState(
lpContext->Esi = pState->esi;
lpContext->Ebp = pState->ebp;
lpContext->Esp = pState->esp;
+ lpContext->ResumeEsp = pState->esp;
lpContext->SegSs = pState->ss;
lpContext->EFlags = pState->eflags;
lpContext->Eip = pState->eip;
diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp
index ae069aec86..050665ce7c 100644
--- a/src/pal/src/thread/process.cpp
+++ b/src/pal/src/thread/process.cpp
@@ -2666,6 +2666,12 @@ CreateProcessModules(
// VM_ALLOCATE 0000000105bac000-0000000105bad000 [ 4K] r--/rw- SM=SHM
// MALLOC (admin) 0000000105bad000-0000000105bae000 [ 4K] r--/rwx SM=ZER
// MALLOC 0000000105bae000-0000000105baf000 [ 4K] rw-/rwx SM=ZER
+
+ // OS X Sierra (10.12.4 Beta)
+ // REGION TYPE START - END [ VSIZE RSDNT DIRTY SWAP] PRT/MAX SHRMOD PURGE REGION DETAIL
+ // Stack 00007fff5a930000-00007fff5b130000 [ 8192K 32K 32K 0K] rw-/rwx SM=PRV thread 0
+ // __TEXT 00007fffa4a0b000-00007fffa4a0d000 [ 8K 8K 0K 0K] r-x/r-x SM=COW /usr/lib/libSystem.B.dylib
+ // __TEXT 00007fffa4bbe000-00007fffa4c15000 [ 348K 348K 0K 0K] r-x/r-x SM=COW /usr/lib/libc++.1.dylib
char *line = NULL;
size_t lineLen = 0;
int count = 0;
@@ -2686,9 +2692,8 @@ CreateProcessModules(
{
void *startAddress, *endAddress;
char moduleName[PATH_MAX];
- int size;
- if (sscanf_s(line, "__TEXT %p-%p [ %dK] %*[-/rwxsp] SM=%*[A-Z] %s\n", &startAddress, &endAddress, &size, moduleName, _countof(moduleName)) == 4)
+ if (sscanf_s(line, "__TEXT %p-%p [ %*[0-9K ]] %*[-/rwxsp] SM=%*[A-Z] %s\n", &startAddress, &endAddress, moduleName, _countof(moduleName)) == 3)
{
bool dup = false;
for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
diff --git a/src/pal/src/thread/thread.cpp b/src/pal/src/thread/thread.cpp
index 53283320c5..df42ebcc96 100644
--- a/src/pal/src/thread/thread.cpp
+++ b/src/pal/src/thread/thread.cpp
@@ -28,6 +28,7 @@ SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do
#include "pal/handlemgr.hpp"
#include "pal/cs.hpp"
#include "pal/seh.hpp"
+#include "pal/signal.hpp"
#include "procprivate.hpp"
#include "pal/process.h"
@@ -177,6 +178,10 @@ static void InternalEndCurrentThreadWrapper(void *arg)
// in InternalEndCurrentThread.
InternalEndCurrentThread(pThread);
pthread_setspecific(thObjKey, NULL);
+
+#if !HAVE_MACH_EXCEPTIONS
+ FreeSignalAlternateStack();
+#endif // !HAVE_MACH_EXCEPTIONS
}
/*++
@@ -1659,6 +1664,14 @@ CPalThread::ThreadEntry(
goto fail;
}
+#if !HAVE_MACH_EXCEPTIONS
+ if (!EnsureSignalAlternateStack())
+ {
+ ASSERT("Cannot allocate alternate stack for SIGSEGV!\n");
+ goto fail;
+ }
+#endif // !HAVE_MACH_EXCEPTIONS
+
#if defined(FEATURE_PAL_SXS) && defined(_DEBUG)
// We cannot assert yet, as we haven't set in this thread into the TLS, and so __ASSERT_ENTER
// will fail if the assert fails and we'll crash.