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:
parent
29a1263227
commit
60f10c64aa
|
@ -224,5 +224,6 @@ void san::leave ()
|
||||||
{
|
{
|
||||||
/* Restore tls_pathbuf counters in case of error. */
|
/* Restore tls_pathbuf counters in case of error. */
|
||||||
_my_tls.locals.pathbufs._counters = _cnt;
|
_my_tls.locals.pathbufs._counters = _cnt;
|
||||||
|
_my_tls.andreas = _clemente;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -301,11 +301,26 @@ extern _cygtls *_sig_tls;
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
class san
|
class san
|
||||||
{
|
{
|
||||||
|
san *_clemente;
|
||||||
uint64_t _cnt;
|
uint64_t _cnt;
|
||||||
public:
|
public:
|
||||||
san () __attribute__ ((always_inline))
|
DWORD64 ret;
|
||||||
|
DWORD64 frame;
|
||||||
|
|
||||||
|
san (PVOID _ret) __attribute__ ((always_inline))
|
||||||
{
|
{
|
||||||
|
_clemente = _my_tls.andreas;
|
||||||
|
_my_tls.andreas = this;
|
||||||
_cnt = _my_tls.locals.pathbufs._counters;
|
_cnt = _my_tls.locals.pathbufs._counters;
|
||||||
|
/* myfault_altstack_handler needs the current stack pointer and the
|
||||||
|
address of the _except block to restore the context correctly.
|
||||||
|
See comment preceeding myfault_altstack_handler in exception.cc. */
|
||||||
|
ret = (DWORD64) _ret;
|
||||||
|
__asm__ volatile ("movq %%rsp,%0": "=o" (frame));
|
||||||
|
}
|
||||||
|
~san () __attribute__ ((always_inline))
|
||||||
|
{
|
||||||
|
_my_tls.andreas = _clemente;
|
||||||
}
|
}
|
||||||
/* This is the first thing called in the __except handler. The attribute
|
/* This is the first thing called in the __except handler. The attribute
|
||||||
"returns_twice" makes sure that GCC disregards any register value set
|
"returns_twice" makes sure that GCC disregards any register value set
|
||||||
|
@ -363,7 +378,7 @@ public:
|
||||||
{ \
|
{ \
|
||||||
__label__ __l_try, __l_except, __l_endtry; \
|
__label__ __l_try, __l_except, __l_endtry; \
|
||||||
__mem_barrier; \
|
__mem_barrier; \
|
||||||
san __sebastian; \
|
san __sebastian (&&__l_except); \
|
||||||
__asm__ goto ("\n" \
|
__asm__ goto ("\n" \
|
||||||
" .seh_handler _ZN9exception7myfaultEP17_EXCEPTION_RECORDPvP8_CONTEXTP19_DISPATCHER_CONTEXT, @except \n" \
|
" .seh_handler _ZN9exception7myfaultEP17_EXCEPTION_RECORDPvP8_CONTEXTP19_DISPATCHER_CONTEXT, @except \n" \
|
||||||
" .seh_handlerdata \n" \
|
" .seh_handlerdata \n" \
|
||||||
|
|
|
@ -800,6 +800,11 @@ dll_crt0_0 ()
|
||||||
if (!dynamically_loaded)
|
if (!dynamically_loaded)
|
||||||
sigproc_init ();
|
sigproc_init ();
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
/* See comment preceeding myfault_altstack_handler in exception.cc. */
|
||||||
|
AddVectoredContinueHandler (0, myfault_altstack_handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
debug_printf ("finished dll_crt0_0 initialization");
|
debug_printf ("finished dll_crt0_0 initialization");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LONG CALLBACK myfault_altstack_handler (EXCEPTION_POINTERS *);
|
||||||
|
|
||||||
#endif /* !__x86_64__ */
|
#endif /* !__x86_64__ */
|
||||||
|
|
||||||
class cygwin_exception
|
class cygwin_exception
|
||||||
|
|
|
@ -588,6 +588,50 @@ exception::myfault (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in,
|
||||||
/* NOTREACHED, make gcc happy. */
|
/* NOTREACHED, make gcc happy. */
|
||||||
return ExceptionContinueSearch;
|
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
|
#endif
|
||||||
|
|
||||||
/* Main exception handler. */
|
/* Main exception handler. */
|
||||||
|
@ -697,11 +741,13 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STATUS_STACK_OVERFLOW:
|
case STATUS_STACK_OVERFLOW:
|
||||||
|
#if 0
|
||||||
/* If we encounter a stack overflow, and if the thread has no alternate
|
/* 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
|
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. */
|
Linux behaviour and also makes a lot of sense on Windows. */
|
||||||
if (me.altstack.ss_flags)
|
if (me.altstack.ss_flags)
|
||||||
global_sigs[SIGSEGV].sa_handler = SIG_DFL;
|
global_sigs[SIGSEGV].sa_handler = SIG_DFL;
|
||||||
|
#endif
|
||||||
/*FALLTHRU*/
|
/*FALLTHRU*/
|
||||||
case STATUS_ARRAY_BOUNDS_EXCEEDED:
|
case STATUS_ARRAY_BOUNDS_EXCEEDED:
|
||||||
case STATUS_IN_PAGE_ERROR:
|
case STATUS_IN_PAGE_ERROR:
|
||||||
|
|
Loading…
Reference in New Issue