summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/exceptions.cc
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2015-07-07 20:45:06 +0200
committerCorinna Vinschen <corinna@vinschen.de>2015-07-07 20:45:06 +0200
commit60f10c64aa57d613471446ea3ec1b3ce6d3b9500 (patch)
tree0d7e41c913bb1d547cf3512dd3314dc332ca0585 /winsup/cygwin/exceptions.cc
parent29a12632278368f197f3270532e2f6c19642512e (diff)
downloadcygnal-60f10c64aa57d613471446ea3ec1b3ce6d3b9500.tar.gz
cygnal-60f10c64aa57d613471446ea3ec1b3ce6d3b9500.tar.bz2
cygnal-60f10c64aa57d613471446ea3ec1b3ce6d3b9500.zip
x86_64: Handle myfault exceptions when running on alternate signal stack
x86_64 only: * cygtls.cc (san::leave): Restore _my_tls.andreas. * cygtls.h (class san): Add _clemente as in 32 bit case. Add ret and frame members. (san::san): Handle _my_tls.andreas as on 32 bit. Take parameter and write it to new member ret. Store current stack pointer in frame. (san::~san): New destructor to restore _my_tls.andreas. (__try): Use __l_except address as parameter to san::san. * dcrt0.cc (dll_crt0_0): Add myfault_altstack_handler as vectored continuation handler. * exception.h (myfault_altstack_handler): Declare. * exceptions.cc (myfault_altstack_handler): New function. Explain what it's good for. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup/cygwin/exceptions.cc')
-rw-r--r--winsup/cygwin/exceptions.cc46
1 files changed, 46 insertions, 0 deletions
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 0ce22d9b3..2ba2f4945 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -588,6 +588,50 @@ exception::myfault (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in,
/* NOTREACHED, make gcc happy. */
return ExceptionContinueSearch;
}
+
+/* If another exception occurs while running a signal handler on an alternate
+ signal stack, the normal SEH handlers are skipped, because the OS exception
+ handling considers the current (alternate) stack "broken". However, it
+ still calls vectored exception handlers.
+
+ TODO: What we do here is to handle only __try/__except blocks in Cygwin.
+ "Normal" exceptions will simply exit the process. Still, better
+ than nothing... */
+LONG WINAPI
+myfault_altstack_handler (EXCEPTION_POINTERS *exc)
+{
+ _cygtls& me = _my_tls;
+
+ if (me.andreas)
+ {
+ PRUNTIME_FUNCTION f;
+ ULONG64 imagebase;
+ UNWIND_HISTORY_TABLE hist;
+ DWORD64 establisher;
+ PVOID hdl;
+ CONTEXT *c = exc->ContextRecord;
+
+ /* Unwind the stack manually and call RtlRestoreContext. This
+ is necessary because RtlUnwindEx checks the stack for validity,
+ which, as outlined above, fails for the alternate stack. */
+ while (c->Rsp < me.andreas->frame)
+ {
+ f = RtlLookupFunctionEntry (c->Rip, &imagebase, &hist);
+ if (f)
+ RtlVirtualUnwind (0, imagebase, c->Rip, f, c, &hdl, &establisher,
+ NULL);
+ else
+ {
+ c->Rip = *(ULONG_PTR *) c->Rsp;
+ c->Rsp += 8;
+ }
+ }
+ c->Rip = me.andreas->ret;
+ RtlRestoreContext (c, NULL);
+ }
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
#endif
/* Main exception handler. */
@@ -697,11 +741,13 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in,
break;
case STATUS_STACK_OVERFLOW:
+#if 0
/* If we encounter a stack overflow, and if the thread has no alternate
stack, don't even try to call a signal handler. This is in line with
Linux behaviour and also makes a lot of sense on Windows. */
if (me.altstack.ss_flags)
global_sigs[SIGSEGV].sa_handler = SIG_DFL;
+#endif
/*FALLTHRU*/
case STATUS_ARRAY_BOUNDS_EXCEEDED:
case STATUS_IN_PAGE_ERROR: