* 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>
* 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;
#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. */

View File

@ -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 = &el;
#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__ */
};

View File

@ -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. */