X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fexceptions-amd64.c;h=342920f1afe1a95942687b26ecedf6bdfbcaae6d;hb=17183a6fbf75a5ca960d7541676aea7fd7b09d21;hp=e5bee78641eba585aedfb69484cfa5fb62ee664b;hpb=3e8658be5c7f37fcecc77f2d9b9ff62abc0bc6b4;p=mono.git diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c index e5bee78641e..342920f1afe 100644 --- a/mono/mini/exceptions-amd64.c +++ b/mono/mini/exceptions-amd64.c @@ -9,6 +9,13 @@ */ #include + +#if _WIN32_WINNT < 0x0501 +/* Required for Vectored Exception Handling. */ +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif /* _WIN32_WINNT < 0x0501 */ + #include #include #include @@ -30,7 +37,6 @@ #include "mini.h" #include "mini-amd64.h" #include "tasklets.h" -#include "debug-mini.h" #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) @@ -40,24 +46,37 @@ static MonoW32ExceptionHandler ill_handler; static MonoW32ExceptionHandler segv_handler; LPTOP_LEVEL_EXCEPTION_FILTER mono_old_win_toplevel_exception_filter; -guint64 mono_win_chained_exception_filter_result; -gboolean mono_win_chained_exception_filter_didrun; +void *mono_win_vectored_exception_handle; +extern gboolean mono_win_chained_exception_needs_run; #define W32_SEH_HANDLE_EX(_ex) \ if (_ex##_handler) _ex##_handler(0, ep, sctx) +static LONG CALLBACK seh_unhandled_exception_filter(EXCEPTION_POINTERS* ep) +{ +#ifndef MONO_CROSS_COMPILE + if (mono_old_win_toplevel_exception_filter) { + return (*mono_old_win_toplevel_exception_filter)(ep); + } +#endif + + mono_handle_native_sigsegv (SIGSEGV, NULL); + + return EXCEPTION_CONTINUE_SEARCH; +} + /* * Unhandled Exception Filter * Top-level per-process exception handler. */ -LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep) +static LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) { EXCEPTION_RECORD* er; CONTEXT* ctx; MonoContext* sctx; LONG res; - mono_win_chained_exception_filter_didrun = FALSE; + mono_win_chained_exception_needs_run = FALSE; res = EXCEPTION_CONTINUE_EXECUTION; er = ep->ExceptionRecord; @@ -98,40 +117,55 @@ LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep) break; } - /* Copy context back */ - /* Nonvolatile */ - ctx->Rsp = sctx->rsp; - ctx->Rdi = sctx->rdi; - ctx->Rsi = sctx->rsi; - ctx->Rbx = sctx->rbx; - ctx->Rbp = sctx->rbp; - ctx->R12 = sctx->r12; - ctx->R13 = sctx->r13; - ctx->R14 = sctx->r14; - ctx->R15 = sctx->r15; - ctx->Rip = sctx->rip; - - /* Volatile But should not matter?*/ - ctx->Rax = sctx->rax; - ctx->Rcx = sctx->rcx; - ctx->Rdx = sctx->rdx; - - g_free (sctx); - - if (mono_win_chained_exception_filter_didrun) - res = mono_win_chained_exception_filter_result; + if (mono_win_chained_exception_needs_run) { + /* Don't copy context back if we chained exception + * as the handler may have modfied the EXCEPTION_POINTERS + * directly. We don't pass sigcontext to chained handlers. + * Return continue search so the UnhandledExceptionFilter + * can correctly chain the exception. + */ + res = EXCEPTION_CONTINUE_SEARCH; + } else { + /* Copy context back */ + /* Nonvolatile */ + ctx->Rsp = sctx->rsp; + ctx->Rdi = sctx->rdi; + ctx->Rsi = sctx->rsi; + ctx->Rbx = sctx->rbx; + ctx->Rbp = sctx->rbp; + ctx->R12 = sctx->r12; + ctx->R13 = sctx->r13; + ctx->R14 = sctx->r14; + ctx->R15 = sctx->r15; + ctx->Rip = sctx->rip; + + /* Volatile But should not matter?*/ + ctx->Rax = sctx->rax; + ctx->Rcx = sctx->rcx; + ctx->Rdx = sctx->rdx; + } + + /* TODO: Find right place to free this in stack overflow case */ + if (er->ExceptionCode != EXCEPTION_STACK_OVERFLOW) + g_free (sctx); return res; } void win32_seh_init() { - mono_old_win_toplevel_exception_filter = SetUnhandledExceptionFilter(seh_handler); + mono_old_win_toplevel_exception_filter = SetUnhandledExceptionFilter(seh_unhandled_exception_filter); + mono_win_vectored_exception_handle = AddVectoredExceptionHandler (1, seh_vectored_exception_handler); } void win32_seh_cleanup() { + guint32 ret = 0; + if (mono_old_win_toplevel_exception_filter) SetUnhandledExceptionFilter(mono_old_win_toplevel_exception_filter); + + ret = RemoveVectoredExceptionHandler (mono_win_vectored_exception_handle); + g_assert (ret); } void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler) @@ -190,16 +224,17 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) amd64_mov_reg_membase (code, AMD64_R15, AMD64_R11, G_STRUCT_OFFSET (MonoContext, r15), 8); #endif - if (mono_running_on_valgrind ()) { - /* Prevent 'Address 0x... is just below the stack ptr.' errors */ - amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsp), 8); - amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rip), 8); - amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8); - } else { - amd64_mov_reg_membase (code, AMD64_RSP, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsp), 8); - /* get return address */ - amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rip), 8); - } + /* + * The context resides on the stack, in the stack frame of the + * caller of this function. The stack pointer that we need to + * restore is potentially many stack frames higher up, so the + * distance between them can easily be more than the red zone + * size. Hence the stack pointer can be restored only after + * we have finished loading everything from the context. + */ + amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rsp), 8); + amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, G_STRUCT_OFFSET (MonoContext, rip), 8); + amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8); /* jump to the saved IP */ amd64_jump_reg (code, AMD64_R11); @@ -209,7 +244,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) mono_arch_flush_icache (start, code - start); if (info) - *info = mono_tramp_info_create (g_strdup_printf ("restore_context"), start, code - start, ji, unwind_ops); + *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); return start; } @@ -296,7 +331,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) mono_arch_flush_icache (start, code - start); if (info) - *info = mono_tramp_info_create (g_strdup_printf ("call_filter"), start, code - start, ji, unwind_ops); + *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops); return start; } @@ -311,12 +346,8 @@ mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guin mgreg_t *regs, mgreg_t rip, MonoObject *exc, gboolean rethrow) { - static void (*restore_context) (MonoContext *); MonoContext ctx; - if (!restore_context) - restore_context = mono_get_restore_context (); - ctx.rsp = regs [AMD64_RSP]; ctx.rip = rip; ctx.rbx = regs [AMD64_RBX]; @@ -337,28 +368,11 @@ mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guin mono_ex->stack_trace = NULL; } - if (mono_debug_using_mono_debugger ()) { - guint8 buf [16]; - - mono_breakpoint_clean_code (NULL, (gpointer)rip, 8, buf, sizeof (buf)); - - if (buf [3] == 0xe8) { - MonoContext ctx_cp = ctx; - ctx_cp.rip = rip - 5; - - if (mono_debugger_handle_exception (&ctx_cp, exc)) { - restore_context (&ctx_cp); - g_assert_not_reached (); - } - } - } - /* adjust eip so that it point into the call instruction */ ctx.rip -= 1; mono_handle_exception (&ctx, exc); - restore_context (&ctx); - + mono_restore_context (&ctx); g_assert_not_reached (); } @@ -508,7 +522,7 @@ get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, g nacl_global_codeman_validate(&start, kMaxCodeSize, &code); if (info) - *info = mono_tramp_info_create (g_strdup (tramp_name), start, code - start, ji, unwind_ops); + *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops); return start; } @@ -586,6 +600,11 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, frame->unwind_info = unwind_info; frame->unwind_info_len = unwind_info_len; + + /* + printf ("%s %p %p\n", ji->d.method->name, ji->code_start, ip); + mono_print_unwind_info (unwind_info, unwind_info_len); + */ regs [AMD64_RAX] = new_ctx->rax; regs [AMD64_RBX] = new_ctx->rbx; @@ -628,7 +647,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) { /* remove any unused lmf */ - *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3); + *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~7); } #ifndef MONO_AMD64_NO_PUSHES @@ -652,7 +671,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, memcpy (new_ctx, &ext->ctx, sizeof (MonoContext)); - *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3); + *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~7); frame->type = FRAME_TYPE_DEBUGGER_INVOKE; @@ -693,17 +712,36 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, new_ctx->rbp = (*lmf)->rbp; new_ctx->rsp = (*lmf)->rsp; - new_ctx->rbx = (*lmf)->rbx; - new_ctx->r12 = (*lmf)->r12; - new_ctx->r13 = (*lmf)->r13; - new_ctx->r14 = (*lmf)->r14; - new_ctx->r15 = (*lmf)->r15; + if (((guint64)(*lmf)->previous_lmf) & 4) { + MonoLMFTramp *ext = (MonoLMFTramp*)(*lmf); + + /* Trampoline frame */ + new_ctx->rbx = ext->regs [AMD64_RBX]; + new_ctx->r12 = ext->regs [AMD64_R12]; + new_ctx->r13 = ext->regs [AMD64_R13]; + new_ctx->r14 = ext->regs [AMD64_R14]; + new_ctx->r15 = ext->regs [AMD64_R15]; #ifdef TARGET_WIN32 - new_ctx->rdi = (*lmf)->rdi; - new_ctx->rsi = (*lmf)->rsi; + new_ctx->rdi = ext->regs [AMD64_RDI]; + new_ctx->rsi = ext->regs [AMD64_RSI]; #endif + } else { + /* + * The registers saved in the LMF will be restored using the normal unwind info, + * when the wrapper frame is processed. + */ + new_ctx->rbx = 0; + new_ctx->r12 = 0; + new_ctx->r13 = 0; + new_ctx->r14 = 0; + new_ctx->r15 = 0; +#ifdef TARGET_WIN32 + new_ctx->rdi = 0; + new_ctx->rsi = 0; +#endif + } - *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3); + *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~7); return TRUE; } @@ -721,19 +759,12 @@ handle_signal_exception (gpointer obj) { MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); MonoContext ctx; - static void (*restore_context) (MonoContext *); - - if (!restore_context) - restore_context = mono_get_restore_context (); memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext)); - if (mono_debugger_handle_exception (&ctx, (MonoObject *)obj)) - return; - mono_handle_exception (&ctx, obj); - restore_context (&ctx); + mono_restore_context (&ctx); } void @@ -748,6 +779,10 @@ mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), g /* The stack should be unaligned */ if ((sp % 16) == 0) sp -= 8; +#ifdef __linux__ + /* Preserve the call chain to prevent crashes in the libgcc unwinder (#15969) */ + *(guint64*)sp = ctx->rip; +#endif ctx->rsp = sp; ctx->rip = (guint64)async_cb; } @@ -784,9 +819,6 @@ mono_arch_handle_exception (void *sigctx, gpointer obj) mono_arch_sigctx_to_monoctx (sigctx, &mctx); - if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) - return TRUE; - mono_handle_exception (&mctx, obj); mono_arch_monoctx_to_sigctx (&mctx, sigctx); @@ -849,22 +881,14 @@ prepare_for_guard_pages (MonoContext *mctx) static void altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf) { - void (*restore_context) (MonoContext *); MonoContext mctx; - restore_context = mono_get_restore_context (); mono_arch_sigctx_to_monoctx (sigctx, &mctx); - if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) { - if (stack_ovf) - prepare_for_guard_pages (&mctx); - restore_context (&mctx); - } - mono_handle_exception (&mctx, obj); if (stack_ovf) prepare_for_guard_pages (&mctx); - restore_context (&mctx); + mono_restore_context (&mctx); } void @@ -1042,7 +1066,7 @@ mono_arch_get_throw_pending_exception (MonoTrampInfo **info, gboolean aot) nacl_global_codeman_validate(&start, kMaxCodeSize, &code); if (info) - *info = mono_tramp_info_create (g_strdup_printf ("throw_pending_exception"), start, code - start, ji, unwind_ops); + *info = mono_tramp_info_create ("throw_pending_exception", start, code - start, ji, unwind_ops); return start; } @@ -1125,8 +1149,7 @@ mono_arch_exceptions_init (void) MonoTrampInfo *info = l->data; mono_register_jit_icall (info->code, g_strdup (info->name), NULL, TRUE); - mono_save_trampoline_xdebug_info (info); - mono_tramp_info_free (info); + mono_tramp_info_register (info); } g_slist_free (tramps); } @@ -1321,7 +1344,7 @@ mono_arch_unwindinfo_get_size (gpointer monoui) (sizeof (UNWIND_CODE) * (MONO_MAX_UNWIND_CODES - unwindinfo->unwindInfo.CountOfCodes)); } -PRUNTIME_FUNCTION +static PRUNTIME_FUNCTION MONO_GET_RUNTIME_FUNCTION_CALLBACK ( DWORD64 ControlPc, IN PVOID Context ) { MonoJitInfo *ji;