https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=0cbf19283b1d82a6ad2bed51674cea56cea5c31c

commit 0cbf19283b1d82a6ad2bed51674cea56cea5c31c
Author: Corinna Vinschen <[email protected]>
Date:   Sat Jun 20 20:21:02 2015 +0200

    Implement using alternate signal stack in Cygwin
    
        * exceptions.cc (_cygtls::call_signal_handler): Implement alternate
        signal stack handling.
    
    Signed-off-by: Corinna Vinschen <[email protected]>

Diff:
---
 winsup/cygwin/exceptions.cc | 121 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 108 insertions(+), 13 deletions(-)

diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 112d792..895d57f 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -1537,19 +1537,26 @@ _cygtls::call_signal_handler ()
              RtlCaptureContext ((CONTEXT *) &context.uc_mcontext);
            }
 
-         /* FIXME: If/when sigaltstack is implemented, this will need to do
-            something more complicated */
-         context.uc_stack.ss_sp = NtCurrentTeb ()->Tib.StackBase;
-         context.uc_stack.ss_flags = 0;
-         if (!NtCurrentTeb ()->DeallocationStack)
-           context.uc_stack.ss_size
-             = (uintptr_t) NtCurrentTeb ()->Tib.StackLimit
-               - (uintptr_t) NtCurrentTeb ()->Tib.StackBase;
+         if (this_sa_flags & SA_ONSTACK
+             && !_my_tls.altstack.ss_flags
+             && _my_tls.altstack.ss_sp)
+           {
+             context.uc_stack = _my_tls.altstack;
+             context.uc_stack.ss_flags = SS_ONSTACK;
+           }
          else
-           context.uc_stack.ss_size
-             = (uintptr_t) NtCurrentTeb ()->DeallocationStack
-               - (uintptr_t) NtCurrentTeb ()->Tib.StackBase;
-
+           {
+             context.uc_stack.ss_sp = NtCurrentTeb ()->Tib.StackBase;
+             context.uc_stack.ss_flags = 0;
+             if (!NtCurrentTeb ()->DeallocationStack)
+               context.uc_stack.ss_size
+                 = (uintptr_t) NtCurrentTeb ()->Tib.StackLimit
+                   - (uintptr_t) NtCurrentTeb ()->Tib.StackBase;
+             else
+               context.uc_stack.ss_size
+                 = (uintptr_t) NtCurrentTeb ()->DeallocationStack
+                   - (uintptr_t) NtCurrentTeb ()->Tib.StackBase;
+           }
          context.uc_sigmask = context.uc_mcontext.oldmask = this_oldmask;
 
          context.uc_mcontext.cr2 = (thissi.si_signo == SIGSEGV
@@ -1565,7 +1572,95 @@ _cygtls::call_signal_handler ()
       sig = 0;         /* Flag that we can accept another signal */
       unlock ();       /* unlock signal stack */
 
-      thisfunc (thissig, &thissi, thiscontext);
+      /* Alternate signal stack requested for this signal and alternate signal
+        stack set up for this thread? */
+      if (this_sa_flags & SA_ONSTACK
+         && !_my_tls.altstack.ss_flags
+         && _my_tls.altstack.ss_sp)
+       {
+         /* Yes, use alternate signal stack.
+
+           NOTE:
+
+           We DO NOT change the TEB's stack addresses and we DO NOT move the
+           _cygtls area to the alternate stack.  This seems to work fine on
+           32 and 64 bit, but there may be Windows functions not working
+           correctly under these circumstances.  Especially 32 bit exception
+           handling may be broken.
+
+           On the other hand, if a Windows function crashed and we're handling
+           this here, moving the TEB stack addresses may be fatal.
+
+           If the current code does not work as expected in the "usual"
+           POSIX circumstances, this problem must be revisited. */
+
+         /* Compute new stackbase.  We start from the high address, subtract
+            16 bytes (safe/sorry) and align to 16 byte. */
+         uintptr_t new_sp = (uintptr_t) _my_tls.altstack.ss_sp
+                            + _my_tls.altstack.ss_size - 0x10;
+         new_sp &= ~0xf;
+         /* Mark alternate stack as used. */
+         _my_tls.altstack.ss_flags = SS_ONSTACK;
+         /* Move to alternate stack, call thisfunc, revert stack regs. */
+#ifdef __x86_64__
+         __asm__ ("\n\
+                  movq  %[NEW_SP], %%r10  # Load alt stack into r10    \n\
+                  movl  %[SIG], %%ecx     # thissig to 1st arg reg     \n\
+                  movq  %[SI], %%rdx      # &thissi to 2nd arg reg     \n\
+                  movq  %[CTX], %%r8      # thiscontext to 3rd arg reg \n\
+                  movq  %[FUNC], %%rax    # thisfunc to rax            \n\
+                  movq  %%rbp, %%r12      # Save rbp in r12            \n\
+                  movq  %%rsp, %%r13      # Store rsp in r13           \n\
+                  movq  %%r10, %%rsp      # Move alt stack into rsp    \n\
+                  xorq  %%rbp, %%rbp      # Set rbp to 0               \n\
+                  subq  $32, %%rsp        # Setup shadow space         \n\
+                  call  *%%rax            # Call thisfunc              \n\
+                  movq  %%r12, %%rbp      # Restore rbp                \n\
+                  movq  %%r13, %%rsp      # Restore rsp                \n"
+                  : : [NEW_SP] "o" (new_sp),
+                      [SIG]    "o" (thissig),
+                      [SI]     "p" (&thissi),
+                      [CTX]    "o" (thiscontext),
+                      [FUNC]   "o" (thisfunc)
+                  : "memory");
+#else
+         __asm__ ("\n\
+                  push  %%ecx             # Save ecx on orig stack     \n\
+                  push  %%edx             # Save edx on orig stack     \n\
+                  movl  %[NEW_SP], %%ecx  # Load alt stack into ecx    \n\
+                  subl  $20, %%ecx        # Make room on new stack     \n\
+                  movl  %[SIG], %%edx     # thissig to 1st arg slot    \n\
+                  movl  %%edx, (%%ecx)                                 \n\
+                  movl  %[SI], %%edx      # &thissi to 2nd arg slot    \n\
+                  movl  %%edx, 4(%%ecx)                                \n\
+                  movl  %[CTX], %%edx     # thiscontext to 3rd arg slot\n\
+                  movl  %%edx, 8(%%ecx)                                \n\
+                  movl  %[FUNC], %%eax    # thisfunc to eax            \n\
+                  movl  %%ebp, 12(%%ecx)  # Save ebp on alt stack      \n\
+                  movl  %%esp, 16(%%ecx)  # Save esp on alt stack      \n\
+                  movl  %%ecx, %%esp      # Move stackbase into esp    \n\
+                  xorl  %%ebp, %%ebp      # Set ebp to 0               \n\
+                  call  *%%eax            # Call thisfunc              \n\
+                  movl  %%esp, %%ecx      # Move alt stack to ecx      \n\
+                  movl  12(%%ecx), %%ebp  # Restore ebp                \n\
+                  movl  16(%%ecx), %%esp  # Restore esp                \n\
+                  popl  %%edx             # Restore edx from orig stack\n\
+                  popl  %%ecx             # Restore ecx from orig stack\n"
+                  : : [NEW_SP] "o" (new_sp),
+                      [SIG]    "o" (thissig),
+                      [SI]     "p" (&thissi),
+                      [CTX]    "o" (thiscontext),
+                      [FUNC]   "o" (thisfunc)
+                  : "memory");
+#endif
+         /* Revert altstack info to normal. */
+         _my_tls.altstack.ss_flags = 0;
+       }
+      else
+       /* No alternate signal stack requested or available, just call
+          signal handler. */
+       thisfunc (thissig, &thissi, thiscontext);
+
       incyg = true;
 
       set_signal_mask (_my_tls.sigmask, this_oldmask);

Reply via email to