* dcrt0.cc (dll_crt0_0): Install myfault exception handler on x86_64.

* exception.h (exception_list): Typedef as void on x86_64.
	(exception::handler_installed): Remove.
	(exception::handle_while_being_debugged): Remove.
	(exception::myfault_handle): Declare for x86_64.
	(exception::handle): Declare as ordinary exception handler on x86_64
	as well.
	(exception::exception): Drop previous code (again).  Install
	exception::handle as SEH handler.
	(exception::install_myfault_handler): New x86_64-only method to
	install exception::myfault_handle as VEH handler.  Explain why.
	(exception::~exception): For x86_64, define frame end label (again).
	* exceptions.cc (CYG_EXC_CONTINUE_EXECUTION): Drop definition.
	(CYG_EXC_CONTINUE_SEARCH): Ditto.
	(exception::myfault_handle): New x86_64-only method, VEH handler to
	handle myfault exceptions.
	(exception::handle): Define as ordinary exception handler on x86_64
	as well.  Use ExceptionContinueExecution and ExceptionContinueSearch
	throughout instead of deleted Cygwin macros.  Don't handle myfault
	exceptions on x86_64.
This commit is contained in:
Corinna Vinschen 2014-03-28 22:31:53 +00:00
parent 58cc7a6498
commit 20738749f6
4 changed files with 103 additions and 47 deletions

View File

@ -1,3 +1,26 @@
2014-03-28 Corinna Vinschen <corinna@vinschen.de>
* dcrt0.cc (dll_crt0_0): Install myfault exception handler on x86_64.
* exception.h (exception_list): Typedef as void on x86_64.
(exception::handler_installed): Remove.
(exception::handle_while_being_debugged): Remove.
(exception::myfault_handle): Declare for x86_64.
(exception::handle): Declare as ordinary exception handler on x86_64
as well.
(exception::exception): Drop previous code (again). Install
exception::handle as SEH handler.
(exception::install_myfault_handler): New x86_64-only method to
install exception::myfault_handle as VEH handler. Explain why.
(exception::~exception): For x86_64, define frame end label (again).
* exceptions.cc (CYG_EXC_CONTINUE_EXECUTION): Drop definition.
(CYG_EXC_CONTINUE_SEARCH): Ditto.
(exception::myfault_handle): New x86_64-only method, VEH handler to
handle myfault exceptions.
(exception::handle): Define as ordinary exception handler on x86_64
as well. Use ExceptionContinueExecution and ExceptionContinueSearch
throughout instead of deleted Cygwin macros. Don't handle myfault
exceptions on x86_64.
2014-03-28 Corinna Vinschen <corinna@vinschen.de> 2014-03-28 Corinna Vinschen <corinna@vinschen.de>
* sec_auth.cc (create_token): Initialize lsa handle to NULL, rather than * sec_auth.cc (create_token): Initialize lsa handle to NULL, rather than

View File

@ -795,6 +795,10 @@ dll_crt0_0 ()
_main_tls = &_my_tls; _main_tls = &_my_tls;
#ifdef __x86_64__
exception::install_myfault_handler ();
#endif
/* Initialize signal processing here, early, in the hopes that the creation /* Initialize signal processing here, early, in the hopes that the creation
of a thread early in the process will cause more predictability in memory of a thread early in the process will cause more predictability in memory
layout for the main thread. */ layout for the main thread. */

View File

@ -104,29 +104,33 @@ typedef struct _exception_list
} exception_list; } exception_list;
extern exception_list *_except_list asm ("%fs:0"); extern exception_list *_except_list asm ("%fs:0");
#else
typedef void exception_list;
#endif /* !__x86_64 */ #endif /* !__x86_64 */
class exception class exception
{ {
#ifdef __x86_64__ #ifdef __x86_64__
static bool handler_installed; static LONG myfault_handle (LPEXCEPTION_POINTERS ep);
static int handle (LPEXCEPTION_POINTERS);
static int handle_while_being_debugged (LPEXCEPTION_POINTERS);
#else #else
exception_list el; exception_list el;
exception_list *save; exception_list *save;
static int handle (EXCEPTION_RECORD *, exception_list *, CONTEXT *, void *);
#endif /* __x86_64__ */ #endif /* __x86_64__ */
static int handle (EXCEPTION_RECORD *, exception_list *, CONTEXT *, void *);
public: public:
exception () __attribute__ ((always_inline)) exception () __attribute__ ((always_inline))
{ {
/* Install SEH handler. */
#ifdef __x86_64__ #ifdef __x86_64__
if (!handler_installed) asm volatile ("\n\
{ 1: \n\
handler_installed = true; .seh_handler \
SetUnhandledExceptionFilter (handle); _ZN9exception6handleEP17_EXCEPTION_RECORDPvP8_CONTEXTS2_, \
AddVectoredExceptionHandler (1, handle_while_being_debugged); @except \n\
} .seh_handlerdata \n\
.long 1 \n\
.rva 1b, 2f, 2f, 2f \n\
.seh_code \n");
#else #else
save = _except_list; save = _except_list;
el.handler = handle; el.handler = handle;
@ -134,7 +138,44 @@ public:
_except_list = &el; _except_list = &el;
#endif /* __x86_64__ */ #endif /* __x86_64__ */
}; };
#ifndef __x86_64__ #ifdef __x86_64__
static void install_myfault_handler () __attribute__ ((always_inline))
{
/* Install myfault exception handler as VEH. Here's what happens:
Some Windows DLLs (advapi32, for instance) are using SEH to catch
exceptions inside its own functions. If we install a VEH handler
to catch all exceptions, our Cygwin VEH handler would illegitimatly
handle exceptions inside of Windows DLLs which are usually handled
by its own SEH handler. So, for standard exceptions we use an SEH
handler as installed in the constructor above so as not to override
the SEH handlers in Windows DLLs.
But we have a special case, myfault handling. The myfault handling
catches exceptions inside of the Cygwin DLL, some of them entirely
expected as in verifyable_object_isvalid. The ultimately right thing
to do would be to install SEH handlers for each of these cases.
But there are two problems with that:
1. It would be a massive and, partially unreliable change in the
calling functions due to the incomplete SEH support in GCC.
2. It doesn't always work. Certain DLLs appear to call Cygwin
functions during DLL initialization while the SEH handler is
not installed in the active call frame. For these cases we
need a more generic approach.
So, what we do here is to install a myfault VEH handler. This
function is called from dll_crt0_0, so the myfault handler is
available very early. */
AddVectoredExceptionHandler (1, myfault_handle);
}
~exception () __attribute__ ((always_inline))
{
asm volatile ("\n\
nop \n\
2: \n\
nop \n");
}
#else
~exception () __attribute__ ((always_inline)) { _except_list = save; } ~exception () __attribute__ ((always_inline)) { _except_list = save; }
#endif /* !__x86_64__ */ #endif /* !__x86_64__ */
}; };

View File

@ -545,55 +545,43 @@ rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e)
popl %%ebx \n\ popl %%ebx \n\
": : "r" (frame), "r" (e)); ": : "r" (frame), "r" (e));
} }
#endif #endif /* __x86_64 */
/* Main exception handler. */
#ifdef __x86_64__ #ifdef __x86_64__
#define CYG_EXC_CONTINUE_EXECUTION EXCEPTION_CONTINUE_EXECUTION /* myfault vectored exception handler */
#define CYG_EXC_CONTINUE_SEARCH EXCEPTION_CONTINUE_SEARCH LONG
exception::myfault_handle (LPEXCEPTION_POINTERS ep)
bool exception::handler_installed NO_COPY;
int
exception::handle_while_being_debugged (LPEXCEPTION_POINTERS ep)
{ {
if (being_debugged ())
return handle (ep);
return EXCEPTION_CONTINUE_SEARCH;
}
int
exception::handle (LPEXCEPTION_POINTERS ep)
#else
#define CYG_EXC_CONTINUE_EXECUTION ExceptionContinueExecution
#define CYG_EXC_CONTINUE_SEARCH ExceptionContinueSearch
int
exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *)
#endif
{
static bool NO_COPY debugging;
_cygtls& me = _my_tls; _cygtls& me = _my_tls;
if (me.andreas) if (me.andreas)
me.andreas->leave (); /* Return from a "san" caught fault */ me.andreas->leave (); /* Return from a "san" caught fault */
return EXCEPTION_CONTINUE_SEARCH;
}
#endif /* __x86_64 */
#ifdef __x86_64__ /* Main exception handler. */
EXCEPTION_RECORD *e = ep->ExceptionRecord; int
CONTEXT *in = ep->ContextRecord; exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *)
{
static bool NO_COPY debugging;
_cygtls& me = _my_tls;
#ifndef __x86_64__
if (me.andreas)
me.andreas->leave (); /* Return from a "san" caught fault */
#endif #endif
if (debugging && ++debugging < 500000) if (debugging && ++debugging < 500000)
{ {
SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL); SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL);
return CYG_EXC_CONTINUE_EXECUTION; return ExceptionContinueExecution;
} }
/* If we're exiting, tell Windows to keep looking for an /* If we're exiting, tell Windows to keep looking for an
exception handler. */ exception handler. */
if (exit_state || e->ExceptionFlags) if (exit_state || e->ExceptionFlags)
return CYG_EXC_CONTINUE_SEARCH; return ExceptionContinueSearch;
siginfo_t si = {}; siginfo_t si = {};
si.si_code = SI_KERNEL; si.si_code = SI_KERNEL;
@ -662,7 +650,7 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void
1)) 1))
{ {
case MMAP_NORESERVE_COMMITED: case MMAP_NORESERVE_COMMITED:
return CYG_EXC_CONTINUE_EXECUTION; return ExceptionContinueExecution;
case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or
access to mmap page beyond EOF. */ access to mmap page beyond EOF. */
si.si_signo = SIGBUS; si.si_signo = SIGBUS;
@ -696,13 +684,13 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void
want CloseHandle to return an error. This can be revisited want CloseHandle to return an error. This can be revisited
if gcc ever supports Windows style structured exception if gcc ever supports Windows style structured exception
handling. */ handling. */
return CYG_EXC_CONTINUE_EXECUTION; return ExceptionContinueExecution;
default: default:
/* If we don't recognize the exception, we have to assume that /* If we don't recognize the exception, we have to assume that
we are doing structured exception handling, and we let we are doing structured exception handling, and we let
something else handle it. */ something else handle it. */
return CYG_EXC_CONTINUE_SEARCH; return ExceptionContinueSearch;
} }
debug_printf ("In cygwin_except_handler exception %y at %p sp %p", e->ExceptionCode, in->_GR(ip), in->_GR(sp)); debug_printf ("In cygwin_except_handler exception %y at %p sp %p", e->ExceptionCode, in->_GR(ip), in->_GR(sp));
@ -738,7 +726,7 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void
else else
{ {
debugging = true; debugging = true;
return CYG_EXC_CONTINUE_EXECUTION; return ExceptionContinueExecution;
} }
/* FIXME: Probably should be handled in signal processing code */ /* FIXME: Probably should be handled in signal processing code */
@ -773,7 +761,7 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void
sig_send (NULL, si, &me); /* Signal myself */ sig_send (NULL, si, &me); /* Signal myself */
me.incyg--; me.incyg--;
e->ExceptionFlags = 0; e->ExceptionFlags = 0;
return CYG_EXC_CONTINUE_EXECUTION; return ExceptionContinueExecution;
} }
/* Utilities to call a user supplied exception handler. */ /* Utilities to call a user supplied exception handler. */