From 20738749f60c85f58329015b7285289f6eb2b7c9 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 28 Mar 2014 22:31:53 +0000 Subject: [PATCH] * 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. --- winsup/cygwin/ChangeLog | 23 ++++++++++++++ winsup/cygwin/dcrt0.cc | 4 +++ winsup/cygwin/exception.h | 63 ++++++++++++++++++++++++++++++------- winsup/cygwin/exceptions.cc | 60 ++++++++++++++--------------------- 4 files changed, 103 insertions(+), 47 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5bad8b00e..1713b984e 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,26 @@ +2014-03-28 Corinna Vinschen + + * 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 * sec_auth.cc (create_token): Initialize lsa handle to NULL, rather than diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index c27079b33..f72cbb0be 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -795,6 +795,10 @@ dll_crt0_0 () _main_tls = &_my_tls; +#ifdef __x86_64__ + exception::install_myfault_handler (); +#endif + /* Initialize signal processing here, early, in the hopes that the creation of a thread early in the process will cause more predictability in memory layout for the main thread. */ diff --git a/winsup/cygwin/exception.h b/winsup/cygwin/exception.h index 673f3b3b5..83cb21fcf 100644 --- a/winsup/cygwin/exception.h +++ b/winsup/cygwin/exception.h @@ -104,29 +104,33 @@ typedef struct _exception_list } exception_list; extern exception_list *_except_list asm ("%fs:0"); +#else +typedef void exception_list; #endif /* !__x86_64 */ class exception { #ifdef __x86_64__ - static bool handler_installed; - static int handle (LPEXCEPTION_POINTERS); - static int handle_while_being_debugged (LPEXCEPTION_POINTERS); + static LONG myfault_handle (LPEXCEPTION_POINTERS ep); #else exception_list el; exception_list *save; - static int handle (EXCEPTION_RECORD *, exception_list *, CONTEXT *, void *); #endif /* __x86_64__ */ + static int handle (EXCEPTION_RECORD *, exception_list *, CONTEXT *, void *); public: exception () __attribute__ ((always_inline)) { + /* Install SEH handler. */ #ifdef __x86_64__ - if (!handler_installed) - { - handler_installed = true; - SetUnhandledExceptionFilter (handle); - AddVectoredExceptionHandler (1, handle_while_being_debugged); - } + asm volatile ("\n\ + 1: \n\ + .seh_handler \ + _ZN9exception6handleEP17_EXCEPTION_RECORDPvP8_CONTEXTS2_, \ + @except \n\ + .seh_handlerdata \n\ + .long 1 \n\ + .rva 1b, 2f, 2f, 2f \n\ + .seh_code \n"); #else save = _except_list; el.handler = handle; @@ -134,7 +138,44 @@ public: _except_list = ⪙ #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; } #endif /* !__x86_64__ */ }; diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index d335a0807..c288913bd 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -545,55 +545,43 @@ rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e) popl %%ebx \n\ ": : "r" (frame), "r" (e)); } -#endif - -/* Main exception handler. */ +#endif /* __x86_64 */ #ifdef __x86_64__ -#define CYG_EXC_CONTINUE_EXECUTION EXCEPTION_CONTINUE_EXECUTION -#define CYG_EXC_CONTINUE_SEARCH EXCEPTION_CONTINUE_SEARCH - -bool exception::handler_installed NO_COPY; - -int -exception::handle_while_being_debugged (LPEXCEPTION_POINTERS ep) +/* myfault vectored exception handler */ +LONG +exception::myfault_handle (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; if (me.andreas) me.andreas->leave (); /* Return from a "san" caught fault */ + return EXCEPTION_CONTINUE_SEARCH; +} +#endif /* __x86_64 */ -#ifdef __x86_64__ - EXCEPTION_RECORD *e = ep->ExceptionRecord; - CONTEXT *in = ep->ContextRecord; +/* Main exception handler. */ +int +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 if (debugging && ++debugging < 500000) { SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL); - return CYG_EXC_CONTINUE_EXECUTION; + return ExceptionContinueExecution; } /* If we're exiting, tell Windows to keep looking for an exception handler. */ if (exit_state || e->ExceptionFlags) - return CYG_EXC_CONTINUE_SEARCH; + return ExceptionContinueSearch; siginfo_t si = {}; si.si_code = SI_KERNEL; @@ -662,7 +650,7 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void 1)) { case MMAP_NORESERVE_COMMITED: - return CYG_EXC_CONTINUE_EXECUTION; + return ExceptionContinueExecution; case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or access to mmap page beyond EOF. */ 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 if gcc ever supports Windows style structured exception handling. */ - return CYG_EXC_CONTINUE_EXECUTION; + return ExceptionContinueExecution; default: /* If we don't recognize the exception, we have to assume that we are doing structured exception handling, and we let 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)); @@ -738,7 +726,7 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void else { debugging = true; - return CYG_EXC_CONTINUE_EXECUTION; + return ExceptionContinueExecution; } /* 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 */ me.incyg--; e->ExceptionFlags = 0; - return CYG_EXC_CONTINUE_EXECUTION; + return ExceptionContinueExecution; } /* Utilities to call a user supplied exception handler. */