X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fexceptions-x86.c;h=531b556e8c0442a9a7ac261fdafd9c5f2d5879e1;hb=d0c24d73e54472274711fa814dfd8082d8a924ec;hp=bfeca805c35ad5781b81d4ea246aa0ae9863c203;hpb=423b8a676f4cb106853a529f21861bda1be81b81;p=mono.git diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c index bfeca805c35..531b556e8c0 100644 --- a/mono/mini/exceptions-x86.c +++ b/mono/mini/exceptions-x86.c @@ -8,6 +8,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 @@ -25,7 +32,6 @@ #include "mini.h" #include "mini-x86.h" #include "tasklets.h" -#include "debug-mini.h" static gpointer signal_exception_trampoline; @@ -40,8 +46,9 @@ 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; +gpointer mono_win_vectored_exception_handle; +extern gboolean mono_win_chained_exception_needs_run; +extern int (*gUnhandledExceptionHandler)(EXCEPTION_POINTERS*); #ifndef PROCESS_CALLBACK_FILTER_ENABLED # define PROCESS_CALLBACK_FILTER_ENABLED 1 @@ -50,6 +57,19 @@ gboolean mono_win_chained_exception_filter_didrun; #define W32_SEH_HANDLE_EX(_ex) \ if (_ex##_handler) _ex##_handler(0, ep, sctx) +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; +} + /* * mono_win32_get_handle_stackoverflow (void): * @@ -83,8 +103,7 @@ mono_win32_get_handle_stackoverflow (void) /* get stack overflow exception from domain object */ x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoDomain, stack_overflow_ex), 4); - /* call mono_arch_handle_exception (sctx, stack_overflow_exception_obj, FALSE) */ - x86_push_imm (code, 0); + /* call mono_arch_handle_exception (sctx, stack_overflow_exception_obj) */ x86_push_reg (code, X86_EAX); x86_push_reg (code, X86_EBX); x86_call_code (code, mono_arch_handle_exception); @@ -118,7 +137,7 @@ win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) DWORD page_size; MonoDomain *domain = mono_domain_get (); MonoJitInfo rji; - MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); + MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); MonoLMF *lmf = jit_tls->lmf; MonoContext initial_ctx; MonoContext ctx; @@ -171,14 +190,14 @@ win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) * Unhandled Exception Filter * Top-level per-process exception handler. */ -LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep) +LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) { EXCEPTION_RECORD* er; CONTEXT* ctx; struct sigcontext* sctx; LONG res; - mono_win_chained_exception_filter_didrun = FALSE; + mono_win_chained_exception_needs_run = FALSE; res = EXCEPTION_CONTINUE_EXECUTION; er = ep->ExceptionRecord; @@ -218,21 +237,30 @@ LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep) break; } - /* Copy context back */ - ctx->Eax = sctx->eax; - ctx->Ebx = sctx->ebx; - ctx->Ecx = sctx->ecx; - ctx->Edx = sctx->edx; - ctx->Ebp = sctx->ebp; - ctx->Esp = sctx->esp; - ctx->Esi = sctx->esi; - ctx->Edi = sctx->edi; - ctx->Eip = sctx->eip; - - g_free (sctx); + 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 */ + ctx->Eax = sctx->eax; + ctx->Ebx = sctx->ebx; + ctx->Ecx = sctx->ecx; + ctx->Edx = sctx->edx; + ctx->Ebp = sctx->ebp; + ctx->Esp = sctx->esp; + ctx->Esi = sctx->esi; + ctx->Edi = sctx->edi; + ctx->Eip = sctx->eip; + } - if (mono_win_chained_exception_filter_didrun) - res = mono_win_chained_exception_filter_result; + /* TODO: Find right place to free this in stack overflow case */ + if (er->ExceptionCode != EXCEPTION_STACK_OVERFLOW) + g_free (sctx); return res; } @@ -243,12 +271,14 @@ void win32_seh_init() if (!restore_stack) restore_stack = mono_win32_get_handle_stackoverflow (); - 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() { if (mono_old_win_toplevel_exception_filter) SetUnhandledExceptionFilter(mono_old_win_toplevel_exception_filter); + RemoveVectoredExceptionHandler (seh_unhandled_exception_filter); } void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler) @@ -290,34 +320,60 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) /* load ctx */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); - /* get return address, stored in ECX */ - x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoContext, eip), 4); /* restore EBX */ x86_mov_reg_membase (code, X86_EBX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebx), 4); + /* restore EDI */ x86_mov_reg_membase (code, X86_EDI, X86_EAX, G_STRUCT_OFFSET (MonoContext, edi), 4); + /* restore ESI */ x86_mov_reg_membase (code, X86_ESI, X86_EAX, G_STRUCT_OFFSET (MonoContext, esi), 4); - /* restore ESP */ - x86_mov_reg_membase (code, X86_ESP, X86_EAX, G_STRUCT_OFFSET (MonoContext, esp), 4); - /* save the return addr to the restored stack */ - x86_push_reg (code, X86_ECX); - /* restore EBP */ - x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebp), 4); - /* restore ECX */ - x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ecx), 4); + /* restore EDX */ x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (MonoContext, edx), 4); - /* restore EAX */ - x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoContext, eax), 4); + /* + * 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. + */ + + /* load ESP into EBP */ + x86_mov_reg_membase (code, X86_EBP, X86_EAX, G_STRUCT_OFFSET (MonoContext, esp), 4); + /* load return address into ECX */ + x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoContext, eip), 4); + /* save the return addr to the restored stack - 4 */ + x86_mov_membase_reg (code, X86_EBP, -4, X86_ECX, 4); + + /* load EBP into ECX */ + x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ebp), 4); + /* save EBP to the restored stack - 8 */ + x86_mov_membase_reg (code, X86_EBP, -8, X86_ECX, 4); + + /* load EAX into ECX */ + x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoContext, eax), 4); + /* save EAX to the restored stack - 12 */ + x86_mov_membase_reg (code, X86_EBP, -12, X86_ECX, 4); + + /* restore ECX */ + x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoContext, ecx), 4); + + /* restore ESP - 12 */ + x86_lea_membase (code, X86_ESP, X86_EBP, -12); + /* restore EAX */ + x86_pop_reg (code, X86_EAX); + /* restore EBP */ + x86_pop_reg (code, X86_EBP); /* jump to the saved IP */ x86_ret (code); nacl_global_codeman_validate(&start, 128, &code); 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); else { GSList *l; @@ -394,7 +450,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) nacl_global_codeman_validate(&start, kMaxCodeSize, &code); 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); else { GSList *l; @@ -416,12 +472,8 @@ void mono_x86_throw_exception (mgreg_t *regs, MonoObject *exc, mgreg_t eip, gboolean rethrow) { - static void (*restore_context) (MonoContext *); MonoContext ctx; - if (!restore_context) - restore_context = mono_get_restore_context (); - ctx.esp = regs [X86_ESP]; ctx.eip = eip; ctx.ebp = regs [X86_EBP]; @@ -443,29 +495,12 @@ mono_x86_throw_exception (mgreg_t *regs, MonoObject *exc, mono_ex->stack_trace = NULL; } - if (mono_debug_using_mono_debugger ()) { - guint8 buf [16], *code; - - mono_breakpoint_clean_code (NULL, (gpointer)eip, 8, buf, sizeof (buf)); - code = buf + 8; - - if (buf [3] == 0xe8) { - MonoContext ctx_cp = ctx; - ctx_cp.eip = eip - 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.eip -= 1; - mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE); + mono_handle_exception (&ctx, exc); - restore_context (&ctx); + mono_restore_context (&ctx); g_assert_not_reached (); } @@ -628,7 +663,7 @@ get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolea code = mono_arch_emit_load_aotconst (start, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? "mono_x86_throw_corlib_exception" : "mono_x86_throw_exception"); x86_call_reg (code, X86_EAX); } else { - x86_call_code (code, resume_unwind ? (mono_x86_resume_unwind) : (corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception)); + x86_call_code (code, resume_unwind ? (gpointer)(mono_x86_resume_unwind) : (corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception)); } x86_breakpoint (code); @@ -637,7 +672,7 @@ get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolea g_assert ((code - start) < kMaxCodeSize); if (info) - *info = mono_tramp_info_create (g_strdup (name), start, code - start, ji, unwind_ops); + *info = mono_tramp_info_create (name, start, code - start, ji, unwind_ops); else { GSList *l; @@ -802,23 +837,29 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, /* Adjust IP */ new_ctx->eip --; - if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) { - /* remove any unused lmf */ - *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); + if (*lmf && ((*lmf) != jit_tls->first_lmf)) { + gboolean is_tramp = ((guint32)((*lmf)->previous_lmf) & 1); + gpointer lmf_esp; + + if (is_tramp) + /* lmf->esp is only set in trampoline frames */ + lmf_esp = (gpointer)(*lmf)->esp; + else + /* In non-trampoline frames, ebp is the frame pointer */ + lmf_esp = (gpointer)(*lmf)->ebp; + if (MONO_CONTEXT_GET_SP (ctx) >= lmf_esp) + /* remove any unused lmf */ + *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); } /* Pop arguments off the stack */ /* * FIXME: LLVM doesn't push these, we can't use ji->from_llvm as it describes - * the caller. + * the callee. */ #ifndef ENABLE_LLVM - { - MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1); - - guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info); - new_ctx->esp += stack_to_pop; - } + if (ji->has_arch_eh_info) + new_ctx->esp += mono_jit_info_get_arch_eh_info (ji)->stack_size; #endif return TRUE; @@ -872,14 +913,16 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, /* Pop arguments off the stack */ /* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */ /* FIXME: Handle the IMT/vtable case too */ +#if 0 #ifndef ENABLE_LLVM if ((*lmf)->method) { MonoMethod *method = (*lmf)->method; MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1); - guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (method), mono_method_signature (method)->param_count, arg_info); + guint32 stack_to_pop = mono_arch_get_argument_info (NULL, mono_method_signature (method), mono_method_signature (method)->param_count, arg_info); new_ctx->esp += stack_to_pop; } +#endif #endif } else @@ -932,21 +975,14 @@ mono_arch_ip_from_context (void *sigctx) static void handle_signal_exception (gpointer obj) { - MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); + 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, MONO_CONTEXT_GET_IP (&ctx), FALSE); + mono_handle_exception (&ctx, obj); - restore_context (&ctx); + mono_restore_context (&ctx); } /* @@ -984,7 +1020,7 @@ mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < 128); if (info) - *info = mono_tramp_info_create (g_strdup ("x86_signal_exception_trampoline"), start, code - start, ji, unwind_ops); + *info = mono_tramp_info_create ("x86_signal_exception_trampoline", start, code - start, ji, unwind_ops); else { GSList *l; @@ -1016,7 +1052,7 @@ mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), g } gboolean -mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) +mono_arch_handle_exception (void *sigctx, gpointer obj) { #if defined(MONO_ARCH_USE_SIGACTION) MonoContext mctx; @@ -1027,12 +1063,11 @@ mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) * signal is disabled, and we could run arbitrary code though the debugger. So * resume into the normal stack and do most work there if possible. */ - MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); + MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); /* Pass the ctx parameter in TLS */ mono_arch_sigctx_to_monoctx (ctx, &jit_tls->ex_ctx); - g_assert (!test_only); mctx = jit_tls->ex_ctx; mono_setup_async_callback (&mctx, handle_signal_exception, obj); mono_monoctx_to_sigctx (&mctx, sigctx); @@ -1040,12 +1075,11 @@ mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) return TRUE; #elif defined (TARGET_WIN32) MonoContext mctx; - MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); + MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); struct sigcontext *ctx = (struct sigcontext *)sigctx; mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx); - g_assert (!test_only); mctx = jit_tls->ex_ctx; mono_setup_async_callback (&mctx, handle_signal_exception, obj); mono_monoctx_to_sigctx (&mctx, sigctx); @@ -1056,10 +1090,7 @@ mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) mono_arch_sigctx_to_monoctx (sigctx, &mctx); - if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) - return TRUE; - - mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only); + mono_handle_exception (&mctx, obj); mono_arch_monoctx_to_sigctx (&mctx, sigctx); @@ -1070,7 +1101,7 @@ mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) static void restore_soft_guard_pages (void) { - MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); + MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); if (jit_tls->stack_ovf_guard_base) mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_NONE); } @@ -1094,24 +1125,16 @@ prepare_for_guard_pages (MonoContext *mctx) } static void -altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf) +altstack_handle_and_restore (MonoContext *ctx, gpointer obj, gboolean stack_ovf) { - void (*restore_context) (MonoContext *); MonoContext mctx; - restore_context = mono_get_restore_context (); - mono_arch_sigctx_to_monoctx (sigctx, &mctx); + mctx = *ctx; - if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) { - if (stack_ovf) - prepare_for_guard_pages (&mctx); - restore_context (&mctx); - } - - mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, FALSE); + mono_handle_exception (&mctx, obj); if (stack_ovf) prepare_for_guard_pages (&mctx); - restore_context (&mctx); + mono_restore_context (&mctx); } void @@ -1149,7 +1172,8 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean * ctx arg * return ip */ - frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 4; + // FIXME: test_only is no more. + frame_size = sizeof (MonoContext) + sizeof (gpointer) * 4; frame_size += 15; frame_size &= ~15; sp = (gpointer)(UCONTEXT_REG_ESP (ctx) & ~15); @@ -1161,8 +1185,7 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean sp [0] = sp + 4; sp [1] = exc; sp [2] = (gpointer)stack_ovf; - /* may need to adjust pointers in the new struct copy, depending on the OS */ - memcpy (sp + 4, ctx, sizeof (ucontext_t)); + mono_sigctx_to_monoctx (sigctx, (MonoContext*)(sp + 4)); /* at the return form the signal handler execution starts in altstack_handle_and_restore() */ UCONTEXT_REG_EIP (ctx) = (unsigned long)altstack_handle_and_restore; UCONTEXT_REG_ESP (ctx) = (unsigned long)(sp - 1); @@ -1185,6 +1208,9 @@ mono_tasklets_arch_restore (void) /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */ /* put cont in edx */ x86_mov_reg_membase (code, X86_EDX, X86_ESP, 4, 4); + /* state in eax, so it's setup as the return value */ + x86_mov_reg_membase (code, X86_EAX, X86_ESP, 8, 4); + /* setup the copy of the stack */ x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, stack_used_size), 4); x86_shift_reg_imm (code, X86_SHR, X86_ECX, 2); @@ -1205,8 +1231,6 @@ mono_tasklets_arch_restore (void) /*x86_mov_reg_membase (code, X86_ECX, X86_ESP, 12, 4); x86_mov_membase_reg (code, X86_ECX, 0, X86_EDX, 4);*/ - /* state in eax, so it's setup as the return value */ - x86_mov_reg_membase (code, X86_EAX, X86_ESP, 8, 4); x86_jump_membase (code, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_ip)); g_assert ((code - start) <= 48); saved = start;