[newlib-cygwin] Implement using alternate signal stack in Cygwin
Corinna Vinschen
corinna@sourceware.org
Sat Jun 20 18:37:00 GMT 2015
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=0cbf19283b1d82a6ad2bed51674cea56cea5c31c
commit 0cbf19283b1d82a6ad2bed51674cea56cea5c31c
Author: Corinna Vinschen <corinna@vinschen.de>
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 <corinna@vinschen.de>
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);
More information about the Cygwin-cvs
mailing list