X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fexceptions-x86.c;h=d3f09813c202f29cb035745f6decaa09f8302f80;hb=5b558abeeb255a3179d4ca6a85617e051c6abd38;hp=e23316b416f4b114c956e2a1164354204f88924a;hpb=c858c7f7ca8de1d74057da91a6611992b584f91f;p=mono.git diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c index e23316b416f..d3f09813c20 100644 --- a/mono/mini/exceptions-x86.c +++ b/mono/mini/exceptions-x86.c @@ -41,6 +41,10 @@ static MonoW32ExceptionHandler segv_handler; static LPTOP_LEVEL_EXCEPTION_FILTER old_handler; +#ifndef PROCESS_CALLBACK_FILTER_ENABLED +# define PROCESS_CALLBACK_FILTER_ENABLED 1 +#endif + #define W32_SEH_HANDLE_EX(_ex) \ if (_ex##_handler) _ex##_handler(0, er, sctx) @@ -138,7 +142,7 @@ win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) do { MonoContext new_ctx; - mono_arch_find_jit_info_ext (domain, jit_tls, &rji, &ctx, &new_ctx, &lmf, &frame); + mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, &lmf, NULL, &frame); if (!frame.ji) { g_warning ("Exception inside function without unwind info"); g_assert_not_reached (); @@ -304,8 +308,17 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) /* 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); + else { + GSList *l; + + for (l = unwind_ops; l; l = l->next) + g_free (l->data); + g_slist_free (unwind_ops); + } return start; } @@ -324,9 +337,10 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) guint8 *code; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; + guint kMaxCodeSize = NACL_SIZE (64, 128); /* call_filter (MonoContext *ctx, unsigned long eip) */ - start = code = mono_global_codeman_reserve (64); + start = code = mono_global_codeman_reserve (kMaxCodeSize); x86_push_reg (code, X86_EBP); x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4); @@ -371,10 +385,19 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) x86_leave (code); x86_ret (code); + 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); + else { + GSList *l; + + for (l = unwind_ops; l; l = l->next) + g_free (l->data); + g_slist_free (unwind_ops); + } - g_assert ((code - start) < 64); + g_assert ((code - start) < kMaxCodeSize); return start; } @@ -452,11 +475,33 @@ mono_x86_throw_corlib_exception (mgreg_t *regs, guint32 ex_token_index, eip -= pc_offset; + /* Negate the ip adjustment done in mono_x86_throw_exception () */ + eip += 1; + mono_x86_throw_exception (regs, (MonoObject*)ex, eip, FALSE); } +static void +mono_x86_resume_unwind (mgreg_t *regs, MonoObject *exc, + mgreg_t eip, gboolean rethrow) +{ + MonoContext ctx; + + ctx.esp = regs [X86_ESP]; + ctx.eip = eip; + ctx.ebp = regs [X86_EBP]; + ctx.edi = regs [X86_EDI]; + ctx.esi = regs [X86_ESI]; + ctx.ebx = regs [X86_EBX]; + ctx.edx = regs [X86_EDX]; + ctx.ecx = regs [X86_ECX]; + ctx.eax = regs [X86_EAX]; + + mono_resume_unwind (&ctx); +} + /* - * get_throw_exception: + * get_throw_trampoline: * * Generate a call to mono_x86_throw_exception/ * mono_x86_throw_corlib_exception. @@ -464,14 +509,15 @@ mono_x86_throw_corlib_exception (mgreg_t *regs, guint32 ex_token_index, * which doesn't push the arguments. */ static guint8* -get_throw_exception (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, MonoTrampInfo **info, gboolean aot) +get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, gboolean llvm_abs, gboolean resume_unwind, MonoTrampInfo **info, gboolean aot) { guint8 *start, *code; int i, stack_size, stack_offset, arg_offsets [5], regs_offset; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; + guint kMaxCodeSize = NACL_SIZE (128, 256); - start = code = mono_global_codeman_reserve (128); + start = code = mono_global_codeman_reserve (kMaxCodeSize); stack_size = 128; @@ -520,11 +566,14 @@ get_throw_exception (const char *name, gboolean rethrow, gboolean llvm, gboolean /* We don't generate stack alignment code on osx to save space */ #endif } else { - /* One argument */ + /* One argument + stack alignment */ stack_offset = stack_size + 4 + 4; #ifdef __APPLE__ /* Pop the alignment added by OP_THROW too */ stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4; +#else + if (mono_do_x86_stack_align) + stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4; #endif } } @@ -535,18 +584,33 @@ get_throw_exception (const char *name, gboolean rethrow, gboolean llvm, gboolean /* Set arg1 == regs */ x86_lea_membase (code, X86_EAX, X86_ESP, regs_offset); x86_mov_membase_reg (code, X86_ESP, arg_offsets [0], X86_EAX, 4); - /* Set arg2 == exc */ - x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4); + /* Set arg2 == exc/ex_token_index */ + if (resume_unwind) + x86_mov_reg_imm (code, X86_EAX, 0); + else + x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [1], X86_EAX, 4); /* Set arg3 == eip */ - x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4); + if (llvm_abs) + x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX); + else + x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4); x86_mov_membase_reg (code, X86_ESP, arg_offsets [2], X86_EAX, 4); - if (corlib) { - /* Set arg4 == offset */ + /* Set arg4 == rethrow/pc_offset */ + if (resume_unwind) { + x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], 0, 4); + } else if (corlib) { x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4); + if (llvm_abs) { + /* + * The caller is LLVM code which passes the absolute address not a pc offset, + * so compensate by passing 0 as 'ip' and passing the negated abs address as + * the pc offset. + */ + x86_neg_reg (code, X86_EAX); + } x86_mov_membase_reg (code, X86_ESP, arg_offsets [3], X86_EAX, 4); } else { - /* Set arg4 == rethrow */ x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4); } /* Make the call */ @@ -558,16 +622,23 @@ get_throw_exception (const char *name, gboolean rethrow, gboolean llvm, gboolean 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, corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception); + x86_call_code (code, resume_unwind ? (mono_x86_resume_unwind) : (corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception)); } x86_breakpoint (code); - g_assert ((code - start) < 128); + nacl_global_codeman_validate(&start, kMaxCodeSize, &code); - mono_save_trampoline_xdebug_info (corlib ? "llvm_throw_corlib_exception_trampoline" : "llvm_throw_exception_trampoline", start, code - start, unwind_ops); + g_assert ((code - start) < kMaxCodeSize); if (info) - *info = mono_tramp_info_create (g_strdup_printf (corlib ? "throw_corlib_exception" : (rethrow ? "rethrow_exception" : "throw_exception")), start, code - start, ji, unwind_ops); + *info = mono_tramp_info_create (g_strdup (name), start, code - start, ji, unwind_ops); + else { + GSList *l; + + for (l = unwind_ops; l; l = l->next) + g_free (l->data); + g_slist_free (unwind_ops); + } return start; } @@ -587,13 +658,13 @@ get_throw_exception (const char *name, gboolean rethrow, gboolean llvm, gboolean gpointer mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) { - return get_throw_exception ("throw_exception_trampoline", FALSE, FALSE, FALSE, info, aot); + return get_throw_trampoline ("throw_exception", FALSE, FALSE, FALSE, FALSE, FALSE, info, aot); } gpointer mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) { - return get_throw_exception ("rethow_exception_trampoline", TRUE, FALSE, FALSE, info, aot); + return get_throw_trampoline ("rethrow_exception", TRUE, FALSE, FALSE, FALSE, FALSE, info, aot); } /** @@ -609,7 +680,7 @@ mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { - return get_throw_exception ("throw_corlib_exception_trampoline", FALSE, FALSE, TRUE, info, aot); + return get_throw_trampoline ("throw_corlib_exception", FALSE, FALSE, TRUE, FALSE, FALSE, info, aot); } void @@ -617,32 +688,61 @@ mono_arch_exceptions_init (void) { guint8 *tramp; +/* + * If we're running WoW64, we need to set the usermode exception policy + * for SEHs to behave. This requires hotfix http://support.microsoft.com/kb/976038 + * or (eventually) Windows 7 SP1. + */ +#ifdef HOST_WIN32 + DWORD flags; + FARPROC getter; + FARPROC setter; + HMODULE kernel32 = LoadLibraryW (L"kernel32.dll"); + + if (kernel32) { + getter = GetProcAddress (kernel32, "GetProcessUserModeExceptionPolicy"); + setter = GetProcAddress (kernel32, "SetProcessUserModeExceptionPolicy"); + if (getter && setter) { + if (getter (&flags)) + setter (flags & ~PROCESS_CALLBACK_FILTER_ENABLED); + } + } +#endif + if (mono_aot_only) { signal_exception_trampoline = mono_aot_get_trampoline ("x86_signal_exception_trampoline"); return; } /* LLVM needs different throw trampolines */ - tramp = get_throw_exception ("llvm_throw_exception_trampoline", FALSE, TRUE, FALSE, NULL, FALSE); + tramp = get_throw_trampoline ("llvm_throw_exception_trampoline", FALSE, TRUE, FALSE, FALSE, FALSE, NULL, FALSE); + mono_register_jit_icall (tramp, "llvm_throw_exception_trampoline", NULL, TRUE); + + tramp = get_throw_trampoline ("llvm_rethrow_exception_trampoline", FALSE, TRUE, FALSE, FALSE, FALSE, NULL, FALSE); + mono_register_jit_icall (tramp, "llvm_rethrow_exception_trampoline", NULL, TRUE); - mono_register_jit_icall (tramp, "mono_arch_llvm_throw_exception", NULL, TRUE); + tramp = get_throw_trampoline ("llvm_throw_corlib_exception_trampoline", FALSE, TRUE, TRUE, FALSE, FALSE, NULL, FALSE); + mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE); - tramp = get_throw_exception ("llvm_throw_corlib_exception_trampoline", FALSE, TRUE, TRUE, NULL, FALSE); + tramp = get_throw_trampoline ("llvm_throw_corlib_exception_abs_trampoline", FALSE, TRUE, TRUE, TRUE, FALSE, NULL, FALSE); + mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_abs_trampoline", NULL, TRUE); - mono_register_jit_icall (tramp, "mono_arch_llvm_throw_corlib_exception", NULL, TRUE); + tramp = get_throw_trampoline ("llvm_resume_unwind_trampoline", FALSE, FALSE, FALSE, FALSE, TRUE, NULL, FALSE); + mono_register_jit_icall (tramp, "llvm_resume_unwind_trampoline", NULL, TRUE); signal_exception_trampoline = mono_x86_get_signal_exception_trampoline (NULL, FALSE); } /* - * mono_arch_find_jit_info_ext: + * mono_arch_find_jit_info: * * See exceptions-amd64.c for docs. */ gboolean -mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, +mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *ctx, - MonoContext *new_ctx, MonoLMF **lmf, + MonoContext *new_ctx, MonoLMF **lmf, + mgreg_t **save_locations, StackFrameInfo *frame) { gpointer ip = MONO_CONTEXT_GET_IP (ctx); @@ -681,7 +781,8 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, (guint8*)ji->code_start + ji->code_size, - ip, regs, MONO_MAX_IREGS + 1, &cfa); + ip, regs, MONO_MAX_IREGS + 1, + save_locations, MONO_MAX_IREGS, &cfa); new_ctx->eax = regs [X86_EAX]; new_ctx->ebx = regs [X86_EBX]; @@ -744,6 +845,7 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, if (!((guint32)((*lmf)->previous_lmf) & 1)) /* Top LMF entry */ return FALSE; + g_assert_not_reached (); /* Trampoline lmf frame */ frame->method = (*lmf)->method; } @@ -754,6 +856,9 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, new_ctx->ebp = (*lmf)->ebp; new_ctx->eip = (*lmf)->eip; + /* Adjust IP */ + new_ctx->eip --; + frame->ji = ji; frame->type = FRAME_TYPE_MANAGED_TO_NATIVE; @@ -766,7 +871,7 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, /* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */ /* FIXME: Handle the IMT/vtable case too */ #ifndef ENABLE_LLVM - if ((*lmf)->method && (*lmf)->method != MONO_FAKE_IMT_METHOD && (*lmf)->method != MONO_FAKE_VTABLE_METHOD) { + if ((*lmf)->method) { MonoMethod *method = (*lmf)->method; MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1); @@ -803,6 +908,18 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, void mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) { +#if defined (__native_client__) + printf("WARNING: mono_arch_sigctx_to_monoctx() called!\n"); + mctx->eax = 0xDEADBEEF; + mctx->ebx = 0xDEADBEEF; + mctx->ecx = 0xDEADBEEF; + mctx->edx = 0xDEADBEEF; + mctx->ebp = 0xDEADBEEF; + mctx->esp = 0xDEADBEEF; + mctx->esi = 0xDEADBEEF; + mctx->edi = 0xDEADBEEF; + mctx->eip = 0xDEADBEEF; +#else #ifdef MONO_ARCH_USE_SIGACTION ucontext_t *ctx = (ucontext_t*)sigctx; @@ -828,11 +945,15 @@ mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) mctx->edi = ctx->SC_EDI; mctx->eip = ctx->SC_EIP; #endif +#endif /* if defined(__native_client__) */ } void mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) { +#if defined(__native_client__) + printf("WARNING: mono_arch_monoctx_to_sigctx() called!\n"); +#else #ifdef MONO_ARCH_USE_SIGACTION ucontext_t *ctx = (ucontext_t*)sigctx; @@ -858,18 +979,24 @@ mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx) ctx->SC_EDI = mctx->edi; ctx->SC_EIP = mctx->eip; #endif +#endif /* __native_client__ */ } gpointer mono_arch_ip_from_context (void *sigctx) { +#if defined(__native_client__) + printf("WARNING: mono_arch_ip_from_context() called!\n"); + return (NULL); +#else #ifdef MONO_ARCH_USE_SIGACTION ucontext_t *ctx = (ucontext_t*)sigctx; return (gpointer)UCONTEXT_REG_EIP (ctx); #else struct sigcontext *ctx = sigctx; return (gpointer)ctx->SC_EIP; -#endif +#endif +#endif /* __native_client__ */ } /* @@ -931,10 +1058,15 @@ mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < 128); - mono_save_trampoline_xdebug_info ("x86_signal_exception_trampoline", start, code - start, unwind_ops); - if (info) *info = mono_tramp_info_create (g_strdup ("x86_signal_exception_trampoline"), start, code - start, ji, unwind_ops); + else { + GSList *l; + + for (l = unwind_ops; l; l = l->next) + g_free (l->data); + g_slist_free (unwind_ops); + } return start; } @@ -943,16 +1075,44 @@ gboolean mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) { #if defined(MONO_ARCH_USE_SIGACTION) + ucontext_t *ctx = (ucontext_t*)sigctx; + /* * Handling the exception in the signal handler is problematic, since the original * 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); - guint64 sp = UCONTEXT_REG_ESP (sigctx); + guint64 sp = UCONTEXT_REG_ESP (ctx); /* Pass the ctx parameter in TLS */ + mono_arch_sigctx_to_monoctx (ctx, &jit_tls->ex_ctx); + /* + * Can't pass the obj on the stack, since we are executing on the + * same stack. Can't save it into MonoJitTlsData, since it needs GC tracking. + * So put it into a register, and branch to a trampoline which + * pushes it. + */ + g_assert (!test_only); + UCONTEXT_REG_EAX (ctx) = (gsize)obj; + UCONTEXT_REG_ECX (ctx) = UCONTEXT_REG_EIP (ctx); + UCONTEXT_REG_EDX (ctx) = (gsize)handle_signal_exception; + + /* Allocate a stack frame, align it to 16 bytes which is needed on apple */ + sp -= 16; + sp &= ~15; + UCONTEXT_REG_ESP (ctx) = sp; + + UCONTEXT_REG_EIP (ctx) = (gsize)signal_exception_trampoline; + + return TRUE; +#elif defined (TARGET_WIN32) + MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); + struct sigcontext *ctx = (struct sigcontext *)sigctx; + guint64 sp = ctx->SC_ESP; + mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx); + /* * Can't pass the obj on the stack, since we are executing on the * same stack. Can't save it into MonoJitTlsData, since it needs GC tracking. @@ -960,16 +1120,16 @@ mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) * pushes it. */ g_assert (!test_only); - UCONTEXT_REG_EAX (sigctx) = (gsize)obj; - UCONTEXT_REG_ECX (sigctx) = UCONTEXT_REG_EIP (sigctx); - UCONTEXT_REG_EDX (sigctx) = (gsize)handle_signal_exception; + ctx->SC_EAX = (gsize)obj; + ctx->SC_ECX = ctx->SC_EIP; + ctx->SC_EDX = (gsize)handle_signal_exception; /* Allocate a stack frame, align it to 16 bytes which is needed on apple */ sp -= 16; sp &= ~15; - UCONTEXT_REG_ESP (sigctx) = sp; + ctx->SC_ESP = sp; - UCONTEXT_REG_EIP (sigctx) = (gsize)signal_exception_trampoline; + ctx->SC_EIP = (gsize)signal_exception_trampoline; return TRUE; #else @@ -1097,6 +1257,9 @@ mono_tasklets_arch_restore (void) static guint8* saved = NULL; guint8 *code, *start; +#ifdef __native_client_codegen__ + g_print("mono_tasklets_arch_restore needs to be aligned for Native Client\n"); +#endif if (saved) return (MonoContinuationRestore)saved; code = start = mono_global_codeman_reserve (48);