Remove getcontext and setcontext usage (#9759)
authorJan Vorlicek <janvorli@microsoft.com>
Fri, 24 Feb 2017 20:29:15 +0000 (21:29 +0100)
committerGitHub <noreply@github.com>
Fri, 24 Feb 2017 20:29:15 +0000 (21:29 +0100)
It turns out that the getcontext and setcontext that I have used in my stack
oveflow reporting change are not present e.g. on Alpine Linux or on Android.
So I am replacing their usage with RtlCaptureContext and RtlRestoreContext
instead.

I have also found that the addition of the .cfi_adjust_cfa_offset to the
PROLOG_SAVE_REG_PAIR has broken unwinding of all helpers that use
PROLOG_WITH_TRANSITION_BLOCK, because the PROLOG_STACK_ALLOC macro
updates the CFA offset. So I am fixing that by removing the CFA offset
updating from the PROLOG_STACK_ALLOC and adding explicit one to the
ARM64 CallSignalHandlerWrapper.

src/pal/inc/unixasmmacrosarm64.inc
src/pal/src/arch/amd64/signalhandlerhelper.cpp
src/pal/src/arch/arm/signalhandlerhelper.cpp
src/pal/src/arch/arm64/callsignalhandlerwrapper.S
src/pal/src/arch/arm64/signalhandlerhelper.cpp
src/pal/src/arch/i386/signalhandlerhelper.cpp
src/pal/src/exception/signal.cpp
src/pal/src/include/pal/context.h

index f391513..34509f3 100644 (file)
@@ -43,7 +43,6 @@ C_FUNC(\Name\()_End):
 
 .macro PROLOG_STACK_ALLOC Size
         sub sp, sp, \Size
-        .cfi_adjust_cfa_offset \Size
 .endm
 
 .macro EPILOG_STACK_FREE Size
index 5e37583..8789f5a 100644 (file)
@@ -52,19 +52,19 @@ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context,
     *--sp = fakeFrameReturnAddress;
 
     // Switch the current context to the signal_handler_worker and the original stack
-    ucontext_t ucontext2;
-    getcontext(&ucontext2);
+    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.
-    MCREG_Rsp(ucontext2.uc_mcontext) = (size_t)sp;
-    MCREG_Rbx(ucontext2.uc_mcontext) = (size_t)faultSp;
-    MCREG_Rbp(ucontext2.uc_mcontext) = (size_t)fp;
-    MCREG_Rip(ucontext2.uc_mcontext) = (size_t)signal_handler_worker;
-    MCREG_Rdi(ucontext2.uc_mcontext) = code;
-    MCREG_Rsi(ucontext2.uc_mcontext) = (size_t)siginfo;
-    MCREG_Rdx(ucontext2.uc_mcontext) = (size_t)context;
-    MCREG_Rcx(ucontext2.uc_mcontext) = (size_t)returnPoint;
+    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;
 
-    setcontext(&ucontext2);
+    RtlRestoreContext(&context2, NULL);
 }
index beda0b4..e1ad460 100644 (file)
@@ -52,19 +52,19 @@ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context,
     *--sp = (size_t)MCREG_R7(ucontext->uc_mcontext); 
 
     // Switch the current context to the signal_handler_worker and the original stack
-    ucontext_t ucontext2;
-    getcontext(&ucontext2);
+    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.
-    MCREG_Sp(ucontext2.uc_mcontext) = (size_t)sp;
-    MCREG_R7(ucontext2.uc_mcontext) = (size_t)sp; // Fp and Sp are the same
-    MCREG_Lr(ucontext2.uc_mcontext) = fakeFrameReturnAddress;
-    MCREG_Pc(ucontext2.uc_mcontext) = (size_t)signal_handler_worker;
-    MCREG_R0(ucontext2.uc_mcontext) = code;
-    MCREG_R1(ucontext2.uc_mcontext) = (size_t)siginfo;
-    MCREG_R2(ucontext2.uc_mcontext) = (size_t)context;
-    MCREG_R3(ucontext2.uc_mcontext) = (size_t)returnPoint;
+    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;
 
-    setcontext(&ucontext2);
+    RtlRestoreContext(&context2, NULL);
 }
index 6bff23b..90fb602 100644 (file)
@@ -15,12 +15,14 @@ C_FUNC(SignalHandlerWorkerReturnOffset\Alignment):
 // 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
-    PROLOG_STACK_ALLOC (128 + 8 + 8 + \Alignment) // red zone + fp + lr + alignment
+__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 (128 + 8 + 8 + \Alignment)
+    EPILOG_STACK_FREE __StackAllocationSize
     ret
 NESTED_END CallSignalHandlerWrapper\Alignment, _TEXT
 
index 3891b9e..c35c629 100644 (file)
@@ -51,19 +51,17 @@ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context,
     *--sp = (size_t)MCREG_Fp(ucontext->uc_mcontext); 
 
     // Switch the current context to the signal_handler_worker and the original stack
-    ucontext_t ucontext2;
-    getcontext(&ucontext2);
+    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.
-    MCREG_Sp(ucontext2.uc_mcontext) = (size_t)sp;
-    MCREG_Fp(ucontext2.uc_mcontext) = (size_t)sp; // Fp and Sp are the same
-    MCREG_Lr(ucontext2.uc_mcontext) = fakeFrameReturnAddress;
-    MCREG_Pc(ucontext2.uc_mcontext) = (size_t)signal_handler_worker;
-    MCREG_X0(ucontext2.uc_mcontext) = code;
-    MCREG_X1(ucontext2.uc_mcontext) = (size_t)siginfo;
-    MCREG_X2(ucontext2.uc_mcontext) = (size_t)context;
-    MCREG_X3(ucontext2.uc_mcontext) = (size_t)returnPoint;
+    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;
 
-    setcontext(&ucontext2);
+    RtlRestoreContext(&context2, NULL);
 }
index 5e7333a..3369abe 100644 (file)
@@ -64,14 +64,15 @@ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context,
     *--sp = fakeFrameReturnAddress;
 
     // Switch the current context to the signal_handler_worker and the original stack
-    ucontext_t ucontext2;
-    getcontext(&ucontext2);
+    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.
-    MCREG_Esp(ucontext2.uc_mcontext) = (size_t)sp;
-    MCREG_Ebp(ucontext2.uc_mcontext) = (size_t)fp;
-    MCREG_Eip(ucontext2.uc_mcontext) = (size_t)signal_handler_worker;
+    context2.Esp = (size_t)sp;
+    context2.ResumeEsp = (size_t)sp;
+    context2.Ebp = (size_t)fp;
+    context2.Eip = (size_t)signal_handler_worker;
 
-    setcontext(&ucontext2);
+    RtlRestoreContext(&context2, NULL);
 }
index ee7f7ce..18560eb 100644 (file)
@@ -47,33 +47,6 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do
 
 #include "pal/context.h"
 
-#ifdef __ANDROID__
-// getcontext and setcontext are not available natively on Android
-int getcontext(ucontext_t *ucp)
-{
-    CONTEXT context;
-    RtlCaptureContext(&context);
-    CONTEXTToNativeContext(&context, ucp);
-
-    return 0;
-}
-
-int setcontext(const ucontext_t *ucp)
-{
-    CONTEXT context;
-    ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
-
-#if defined(_AMD64_)
-    contextFlags |= CONTEXT_XSTATE;
-#endif
-
-    CONTEXTFromNativeContext(ucp, &context, contextFlags);
-    RtlRestoreContext(&context, NULL);
-
-    return 0;
-}
-#endif
-
 using namespace CorUnix;
 
 #ifdef SIGRTMIN
@@ -98,7 +71,7 @@ typedef void (*SIGFUNC)(int, siginfo_t *, void *);
 struct SignalHandlerWorkerReturnPoint
 {
     bool returnFromHandler;
-    ucontext_t context;
+    CONTEXT context;
 };
 
 /* internal function declarations *********************************************/
@@ -419,7 +392,7 @@ extern "C" void signal_handler_worker(int code, siginfo_t *siginfo, void *contex
     // 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);
-    setcontext(&returnPoint->context);
+    RtlRestoreContext(&returnPoint->context, NULL);
 }
 
 /*++
@@ -457,7 +430,7 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
         volatile bool contextInitialization = true;
 
         SignalHandlerWorkerReturnPoint returnPoint;
-        getcontext(&returnPoint.context);        
+        RtlCaptureContext(&returnPoint.context);
 
         // When the signal handler worker completes, it uses setcontext to return to this point
 
index 782a51b..db6d695 100644 (file)
@@ -29,12 +29,6 @@ extern "C"
 #include <signal.h>
 #include <pthread.h>
 
-#ifdef __ANDROID__
-// getcontext and setcontext are not available natively on Android
-int setcontext(const ucontext_t *ucp);
-int getcontext(ucontext_t* ucp);
-#endif
-
 #if !HAVE_MACH_EXCEPTIONS
 /* A type to wrap the native context type, which is ucontext_t on some
  * platforms and another type elsewhere. */