X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fexceptions-x86.c;h=d3f09813c202f29cb035745f6decaa09f8302f80;hb=5b558abeeb255a3179d4ca6a85617e051c6abd38;hp=46b8e62ad11364d527e7da04b37e103a41f1a53a;hpb=6c035e225abc36a15501a03f574744824225350b;p=mono.git diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c index 46b8e62ad11..d3f09813c20 100644 --- a/mono/mini/exceptions-x86.c +++ b/mono/mini/exceptions-x86.c @@ -27,7 +27,12 @@ #include "tasklets.h" #include "debug-mini.h" -#ifdef PLATFORM_WIN32 +static gpointer signal_exception_trampoline; + +gpointer +mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) MONO_INTERNAL; + +#ifdef TARGET_WIN32 static void (*restore_stack) (void *); static MonoW32ExceptionHandler fpe_handler; @@ -36,8 +41,12 @@ 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((int)sctx) + if (_ex##_handler) _ex##_handler(0, er, sctx) /* * mono_win32_get_handle_stackoverflow (void): @@ -103,21 +112,22 @@ mono_win32_get_handle_stackoverflow (void) static void win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) { - SYSTEM_INFO si; - DWORD page_size; + SYSTEM_INFO si; + DWORD page_size; MonoDomain *domain = mono_domain_get (); - MonoJitInfo *ji, rji; + MonoJitInfo rji; MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id); MonoLMF *lmf = jit_tls->lmf; MonoContext initial_ctx; MonoContext ctx; guint32 free_stack = 0; + StackFrameInfo frame; /* convert sigcontext to MonoContext (due to reuse of stack walking helpers */ mono_arch_sigctx_to_monoctx (sctx, &ctx); /* get our os page size */ - GetSystemInfo(&si); + GetSystemInfo(&si); page_size = si.dwPageSize; /* Let's walk the stack to recover @@ -132,19 +142,19 @@ win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) do { MonoContext new_ctx; - ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, &ctx, &new_ctx, &lmf, NULL); - if (!ji) { + 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 (); } - if (ji != (gpointer)-1) { + if (frame.ji != (gpointer)-1) { free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx)); } /* todo: we should call abort if ji is -1 */ ctx = new_ctx; - } while (free_stack < 64 * 1024 && ji != (gpointer) -1); + } while (free_stack < 64 * 1024 && frame.ji != (gpointer) -1); /* convert into sigcontext to be used in mono_arch_handle_exception */ mono_arch_monoctx_to_sigctx (&ctx, sctx); @@ -252,7 +262,7 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler) } } -#endif /* PLATFORM_WIN32 */ +#endif /* TARGET_WIN32 */ /* * mono_arch_get_restore_context: @@ -260,24 +270,22 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler) * Returns a pointer to a method which restores a previously saved sigcontext. */ gpointer -mono_arch_get_restore_context (void) +mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { - static guint8 *start = NULL; + guint8 *start = NULL; guint8 *code; - - if (start) - return start; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; /* restore_contect (MonoContext *ctx) */ - /* we do not restore X86_EAX, X86_EDX */ start = code = mono_global_codeman_reserve (128); /* load ctx */ x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); - /* get return address, stored in EDX */ - x86_mov_reg_membase (code, X86_EDX, X86_EAX, G_STRUCT_OFFSET (MonoContext, eip), 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 */ @@ -286,11 +294,31 @@ mono_arch_get_restore_context (void) 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); /* jump to the saved IP */ - x86_jump_reg (code, X86_EDX); + 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; } @@ -303,18 +331,16 @@ mono_arch_get_restore_context (void) * @exc object in this case). */ gpointer -mono_arch_get_call_filter (void) +mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) { - static guint8* start; - static int inited = 0; + guint8* start; guint8 *code; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; + guint kMaxCodeSize = NACL_SIZE (64, 128); - if (inited) - return start; - - inited = 1; /* 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); @@ -359,31 +385,51 @@ mono_arch_get_call_filter (void) x86_leave (code); x86_ret (code); - g_assert ((code - start) < 64); + 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) < kMaxCodeSize); return start; } -static void -throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx, - unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc, - unsigned long eip, unsigned long esp, gboolean rethrow) +/* + * mono_x86_throw_exception: + * + * C function called from the throw trampolines. + */ +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_arch_get_restore_context (); + restore_context = mono_get_restore_context (); - /* Pop argument and return address */ - ctx.esp = esp + (2 * sizeof (gpointer)); + ctx.esp = regs [X86_ESP]; ctx.eip = eip; - ctx.ebp = ebp; - ctx.edi = edi; - ctx.esi = esi; - ctx.ebx = ebx; - ctx.edx = edx; - ctx.ecx = ecx; - ctx.eax = eax; + 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]; + +#ifdef __APPLE__ + /* The OSX ABI specifies 16 byte alignment at call sites */ + g_assert ((ctx.esp % MONO_ARCH_FRAME_ALIGNMENT) == 0); +#endif if (mono_object_isinst (exc, mono_defaults.exception_class)) { MonoException *mono_ex = (MonoException*)exc; @@ -412,108 +458,213 @@ throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsign ctx.eip -= 1; mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE); + restore_context (&ctx); g_assert_not_reached (); } -static guint8* -get_throw_exception (gboolean rethrow) +void +mono_x86_throw_corlib_exception (mgreg_t *regs, guint32 ex_token_index, + mgreg_t eip, gint32 pc_offset) { - guint8 *start, *code; + guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index; + MonoException *ex; - start = code = mono_global_codeman_reserve (64); + ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token); - x86_push_reg (code, X86_ESP); - x86_push_membase (code, X86_ESP, 4); /* IP */ - x86_push_membase (code, X86_ESP, 12); /* exception */ - x86_push_reg (code, X86_EBP); - x86_push_reg (code, X86_EDI); - x86_push_reg (code, X86_ESI); - x86_push_reg (code, X86_EBX); - x86_push_reg (code, X86_EDX); - x86_push_reg (code, X86_ECX); - x86_push_reg (code, X86_EAX); - x86_call_code (code, throw_exception); - /* we should never reach this breakpoint */ - x86_breakpoint (code); + eip -= pc_offset; - g_assert ((code - start) < 64); + /* Negate the ip adjustment done in mono_x86_throw_exception () */ + eip += 1; - return start; + mono_x86_throw_exception (regs, (MonoObject*)ex, eip, FALSE); } -/** - * mono_arch_get_throw_exception: - * - * Returns a function pointer which can be used to raise - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); - * For example to raise an arithmetic exception you can use: - * - * x86_push_imm (code, mono_get_exception_arithmetic ()); - * x86_call_code (code, arch_get_throw_exception ()); +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_trampoline: * + * Generate a call to mono_x86_throw_exception/ + * mono_x86_throw_corlib_exception. + * If LLVM is true, generate code which assumes the caller is LLVM generated code, + * which doesn't push the arguments. */ -gpointer -mono_arch_get_throw_exception (void) +static guint8* +get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, gboolean llvm_abs, gboolean resume_unwind, MonoTrampInfo **info, gboolean aot) { - static guint8 *start; - static int inited = 0; + 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); - if (inited) - return start; + start = code = mono_global_codeman_reserve (kMaxCodeSize); - start = get_throw_exception (FALSE); + stack_size = 128; - inited = 1; + /* + * On apple, the stack is misaligned by the pushing of the return address. + */ + if (!llvm && corlib) + /* On OSX, we don't generate alignment code to save space */ + stack_size += 4; + else + stack_size += MONO_ARCH_FRAME_ALIGNMENT - 4; - return start; -} + /* + * The stack looks like this: + * (only if corlib is TRUE) + * / + * <- esp (unaligned on apple) + */ -gpointer -mono_arch_get_rethrow_exception (void) -{ - static guint8 *start; - static int inited = 0; + mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4); + mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4); + + /* Alloc frame */ + x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4); + + arg_offsets [0] = 0; + arg_offsets [1] = 4; + arg_offsets [2] = 8; + arg_offsets [3] = 12; + regs_offset = 16; + + /* Save registers */ + for (i = 0; i < X86_NREG; ++i) + if (i != X86_ESP) + x86_mov_membase_reg (code, X86_ESP, regs_offset + (i * 4), i, 4); + /* Calculate the offset between the current sp and the sp of the caller */ + if (llvm) { + /* LLVM doesn't push the arguments */ + stack_offset = stack_size + 4; + } else { + if (corlib) { + /* Two arguments */ + stack_offset = stack_size + 4 + 8; +#ifdef __APPLE__ + /* We don't generate stack alignment code on osx to save space */ +#endif + } else { + /* 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 + } + } + /* Save ESP */ + x86_lea_membase (code, X86_EAX, X86_ESP, stack_offset); + x86_mov_membase_reg (code, X86_ESP, regs_offset + (X86_ESP * 4), X86_EAX, 4); + + /* 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/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 */ + 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); + /* 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 { + x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4); + } + /* Make the call */ + if (aot) { + // This can be called from runtime code, which can't guarantee that + // ebx contains the got address. + // So emit the got address loading code too + code = mono_arch_emit_load_got_addr (start, code, NULL, &ji); + 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_breakpoint (code); - if (inited) - return start; + nacl_global_codeman_validate(&start, kMaxCodeSize, &code); + + g_assert ((code - start) < kMaxCodeSize); - start = get_throw_exception (TRUE); + if (info) + *info = mono_tramp_info_create (g_strdup (name), start, code - start, ji, unwind_ops); + else { + GSList *l; - inited = 1; + for (l = unwind_ops; l; l = l->next) + g_free (l->data); + g_slist_free (unwind_ops); + } return start; } /** - * mono_arch_get_throw_exception_by_name: + * mono_arch_get_throw_exception: * * Returns a function pointer which can be used to raise - * corlib exceptions. The returned function has the following - * signature: void (*func) (gpointer ip, char *exc_name); + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); * For example to raise an arithmetic exception you can use: * - * x86_push_imm (code, "ArithmeticException"); - * x86_push_imm (code, ) - * x86_jump_code (code, arch_get_throw_exception_by_name ()); + * x86_push_imm (code, mono_get_exception_arithmetic ()); + * x86_call_code (code, arch_get_throw_exception ()); * */ gpointer -mono_arch_get_throw_exception_by_name (void) +mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) { - guint8* start; - guint8 *code; - - start = code = mono_global_codeman_reserve (32); - - /* Not used */ - x86_breakpoint (code); - - mono_arch_flush_icache (start, code - start); + return get_throw_trampoline ("throw_exception", FALSE, FALSE, FALSE, FALSE, FALSE, info, aot); +} - return start; +gpointer +mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) +{ + return get_throw_trampoline ("rethrow_exception", TRUE, FALSE, FALSE, FALSE, FALSE, info, aot); } /** @@ -527,65 +678,78 @@ mono_arch_get_throw_exception_by_name (void) * needs no relocations in the caller. */ gpointer -mono_arch_get_throw_corlib_exception (void) +mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { - static guint8* start; - static int inited = 0; - guint8 *code; + return get_throw_trampoline ("throw_corlib_exception", FALSE, FALSE, TRUE, FALSE, FALSE, info, aot); +} - if (inited) - return start; +void +mono_arch_exceptions_init (void) +{ + guint8 *tramp; - inited = 1; - code = start = mono_global_codeman_reserve (64); +/* + * 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 - x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); /* token */ - x86_alu_reg_imm (code, X86_ADD, X86_EAX, MONO_TOKEN_TYPE_DEF); - x86_push_reg (code, X86_EAX); - x86_push_imm (code, mono_defaults.exception_class->image); - x86_call_code (code, mono_exception_from_token); - x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8); - /* Compute caller ip */ - x86_pop_reg (code, X86_ECX); - /* Pop token */ - x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4); - x86_pop_reg (code, X86_EDX); - x86_alu_reg_reg (code, X86_SUB, X86_ECX, X86_EDX); - /* Push exception object */ - x86_push_reg (code, X86_EAX); - /* Push throw IP */ - x86_push_reg (code, X86_ECX); - x86_jump_code (code, mono_arch_get_throw_exception ()); + if (mono_aot_only) { + signal_exception_trampoline = mono_aot_get_trampoline ("x86_signal_exception_trampoline"); + return; + } - g_assert ((code - start) < 64); + /* LLVM needs different throw trampolines */ + 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); - return start; + 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); + + 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_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); + + 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: +/* + * mono_arch_find_jit_info: * - * This function is used to gather information from @ctx. It return the - * MonoJitInfo of the corresponding function, unwinds one stack frame and - * stores the resulting context into @new_ctx. It also stores a string - * describing the stack location into @trace (if not NULL), and modifies - * the @lmf if necessary. @native_offset return the IP offset from the - * start of the function or -1 if that info is not available. + * See exceptions-amd64.c for docs. */ -MonoJitInfo * -mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, - MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed) +gboolean +mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, + MonoJitInfo *ji, MonoContext *ctx, + MonoContext *new_ctx, MonoLMF **lmf, + mgreg_t **save_locations, + StackFrameInfo *frame) { - MonoJitInfo *ji; gpointer ip = MONO_CONTEXT_GET_IP (ctx); - /* Avoid costly table lookup during stack overflow */ - if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size))) - ji = prev_ji; - else - ji = mono_jit_info_table_find (domain, ip); - - if (managed) - *managed = FALSE; + memset (frame, 0, sizeof (StackFrameInfo)); + frame->ji = ji; + frame->managed = FALSE; *new_ctx = *ctx; @@ -595,9 +759,10 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf guint32 unwind_info_len; guint8 *unwind_info; - if (managed) - if (!ji->method->wrapper_type) - *managed = TRUE; + frame->type = FRAME_TYPE_MANAGED; + + if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) + frame->managed = TRUE; if (ji->from_aot) unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len); @@ -616,7 +781,8 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf 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]; @@ -636,30 +802,52 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) { /* remove any unused lmf */ - *lmf = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1); + *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. + */ +#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; } +#endif - return ji; + return TRUE; } else if (*lmf) { - - *new_ctx = *ctx; - if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) { + if (((guint64)(*lmf)->previous_lmf) & 2) { + /* + * This LMF entry is created by the soft debug code to mark transitions to + * managed code done during invokes. + */ + MonoLMFExt *ext = (MonoLMFExt*)(*lmf); + + g_assert (ext->debugger_invoke); + + memcpy (new_ctx, &ext->ctx, sizeof (MonoContext)); + + *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); + + frame->type = FRAME_TYPE_DEBUGGER_INVOKE; + + return TRUE; + } + + if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) { } else { if (!((guint32)((*lmf)->previous_lmf) & 1)) /* Top LMF entry */ - return (gpointer)-1; + return FALSE; + g_assert_not_reached (); /* Trampoline lmf frame */ - memset (res, 0, sizeof (MonoJitInfo)); - res->method = (*lmf)->method; + frame->method = (*lmf)->method; } new_ctx->esi = (*lmf)->esi; @@ -668,6 +856,12 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf 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; + /* Check if we are in a trampoline LMF frame */ if ((guint32)((*lmf)->previous_lmf) & 1) { /* lmf->esp is set by the trampoline code */ @@ -676,25 +870,27 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf /* Pop arguments off the stack */ /* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */ /* FIXME: Handle the IMT/vtable case too */ - if ((*lmf)->method && (*lmf)->method != MONO_FAKE_IMT_METHOD && (*lmf)->method != MONO_FAKE_VTABLE_METHOD) { +#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); new_ctx->esp += stack_to_pop; } +#endif } else /* the lmf is always stored on the stack, so the following * expression points to a stack location which can be used as ESP */ new_ctx->esp = (unsigned long)&((*lmf)->eip); - *lmf = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1); + *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); - return ji ? ji : res; + return TRUE; } - return NULL; + return FALSE; } #ifdef __sun @@ -712,6 +908,18 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf 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; @@ -737,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; @@ -767,23 +979,160 @@ 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__ */ +} + +/* + * handle_exception: + * + * Called by resuming from a signal handler. + */ +static void +handle_signal_exception (gpointer obj) +{ + MonoJitTlsData *jit_tls = TlsGetValue (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); + + restore_context (&ctx); +} + +/* + * mono_x86_get_signal_exception_trampoline: + * + * This x86 specific trampoline is used to call handle_signal_exception. + */ +gpointer +mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) +{ + guint8 *start, *code; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; + int stack_size; + + start = code = mono_global_codeman_reserve (128); + + /* Caller ip */ + x86_push_reg (code, X86_ECX); + + mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4); + mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4); + + /* Fix the alignment to be what apple expects */ + stack_size = 12; + + x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4); + + /* Arg1 */ + x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, 4); + /* Branch to target */ + x86_call_reg (code, X86_EDX); + + g_assert ((code - start) < 128); + + 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; } 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 (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. + * So put it into a register, and branch to a trampoline which + * pushes it. + */ + g_assert (!test_only); + 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; + ctx->SC_ESP = sp; + + ctx->SC_EIP = (gsize)signal_exception_trampoline; + + return TRUE; +#else MonoContext mctx; mono_arch_sigctx_to_monoctx (sigctx, &mctx); @@ -796,6 +1145,7 @@ mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) mono_arch_monoctx_to_sigctx (&mctx, sigctx); return TRUE; +#endif } static void @@ -830,7 +1180,7 @@ altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf) void (*restore_context) (MonoContext *); MonoContext mctx; - restore_context = mono_arch_get_restore_context (); + restore_context = mono_get_restore_context (); mono_arch_sigctx_to_monoctx (sigctx, &mctx); if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) { @@ -851,7 +1201,7 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean #ifdef MONO_ARCH_USE_SIGACTION MonoException *exc = NULL; ucontext_t *ctx = (ucontext_t*)sigctx; - MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx)); + MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx), NULL); gpointer *sp; int frame_size; @@ -861,7 +1211,7 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean */ if (!ji && fault_addr == (gpointer)UCONTEXT_REG_EIP (ctx)) { glong *sp = (gpointer)UCONTEXT_REG_ESP (ctx); - ji = mono_jit_info_table_find (mono_domain_get (), (gpointer)sp [0]); + ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)sp [0], NULL); if (ji) UCONTEXT_REG_EIP (ctx) = sp [0]; } @@ -907,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);