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>
This commit is contained in:
Corinna Vinschen
2015-07-07 20:45:06 +02:00
parent 29a1263227
commit 60f10c64aa
5 changed files with 71 additions and 2 deletions

View File

@ -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: