Fix some FIXMEs.
[mono.git] / mono / mini / exceptions-amd64.c
index cf5dbf1fedfbcc05e984c2b7770ac34bc671d690..e683bf2a11fcf6080ab66869911056d967764151 100644 (file)
@@ -415,11 +415,13 @@ get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, g
 
        code = start;
 
-       unwind_ops = mono_arch_get_cie_program ();
+       if (info)
+               unwind_ops = mono_arch_get_cie_program ();
 
        /* Alloc frame */
        amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, stack_size);
-       mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 8);
+       if (info)
+               mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 8);
 
        /*
         * To hide linux/windows calling convention differences, we pass all arguments on
@@ -470,7 +472,7 @@ get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, g
        }
 
        if (aot) {
-               ji = mono_patch_info_list_prepend (ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? (llvm_abs ? "mono_amd64_throw_corlib_exception_abs" : "mono_amd64_throw_corlib_exception") : "mono_amd64_throw_exception");
+               ji = mono_patch_info_list_prepend (ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? "mono_amd64_throw_corlib_exception" : "mono_amd64_throw_exception");
                amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
        } else {
                amd64_mov_reg_imm (code, AMD64_R11, resume_unwind ? (mono_amd64_resume_unwind) : (corlib ? (gpointer)mono_amd64_throw_corlib_exception : (gpointer)mono_amd64_throw_exception));
@@ -482,10 +484,8 @@ get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, g
 
        g_assert ((code - start) < buf_size);
 
-       mono_save_trampoline_xdebug_info (tramp_name, start, code - start, unwind_ops);
-
        if (info)
-               *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops);
+               *info = mono_tramp_info_create (g_strdup (tramp_name), start, code - start, ji, unwind_ops);
 
        return start;
 }
@@ -527,19 +527,18 @@ mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
 }
 
 /*
- * mono_arch_find_jit_info_ext:
+ * mono_arch_find_jit_info:
  *
  * This function is used to gather information from @ctx, and store it in @frame_info.
  * It unwinds one stack frame, and stores the resulting context into @new_ctx. @lmf
  * is modified if needed.
  * Returns TRUE on success, FALSE otherwise.
- * This function is a version of mono_arch_find_jit_info () where all the results are
- * returned in a StackFrameInfo structure.
  */
 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);
@@ -565,6 +564,9 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
                        unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
                else
                        unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);
+
+               frame->unwind_info = unwind_info;
+               frame->unwind_info_len = unwind_info_len;
  
                regs [AMD64_RAX] = new_ctx->rax;
                regs [AMD64_RBX] = new_ctx->rbx;
@@ -582,7 +584,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->rax = regs [AMD64_RAX];
                new_ctx->rbx = regs [AMD64_RBX];
@@ -656,10 +659,14 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
                }
 
                ji = mini_jit_info_table_find (domain, (gpointer)rip, NULL);
-               if (!ji) {
-                       // FIXME: This can happen with multiple appdomains (bug #444383)
+               /*
+                * FIXME: ji == NULL can happen when a managed-to-native wrapper is interrupted
+                * in the soft debugger suspend code, since (*lmf)->rsp no longer points to the
+                * return address.
+                */
+               //g_assert (ji);
+               if (!ji)
                        return FALSE;
-               }
 
                /* Adjust IP */
                rip --;
@@ -723,29 +730,31 @@ handle_signal_exception (gpointer obj, gboolean test_only)
 gboolean
 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
 {
-#if defined(MONO_ARCH_USE_SIGACTION) && defined(UCONTEXT_GREGS)
+#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_RSP (sigctx);
+       guint64 sp = UCONTEXT_REG_RSP (ctx);
 
        /* Pass the ctx parameter in TLS */
-       mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
+       mono_arch_sigctx_to_monoctx (ctx, &jit_tls->ex_ctx);
        /* The others in registers */
-       UCONTEXT_REG_RDI (sigctx) = (guint64)obj;
-       UCONTEXT_REG_RSI (sigctx) = test_only;
+       UCONTEXT_REG_RDI (ctx) = (guint64)obj;
+       UCONTEXT_REG_RSI (ctx) = test_only;
 
        /* Allocate a stack frame below the red zone */
        sp -= 128;
        /* The stack should be unaligned */
        if (sp % 8 == 0)
                sp -= 8;
-       UCONTEXT_REG_RSP (sigctx) = sp;
+       UCONTEXT_REG_RSP (ctx) = sp;
 
-       UCONTEXT_REG_RIP (sigctx) = (guint64)handle_signal_exception;
+       UCONTEXT_REG_RIP (ctx) = (guint64)handle_signal_exception;
 
        return TRUE;
 #else
@@ -764,13 +773,6 @@ mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
 #endif
 }
 
-#if defined(MONO_ARCH_USE_SIGACTION) && defined(UCONTEXT_GREGS)
-static inline guint64*
-gregs_from_ucontext (ucontext_t *ctx)
-{
-       return (guint64 *) UCONTEXT_GREGS (ctx);
-}
-#endif
 void
 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
 {
@@ -913,8 +915,7 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean
 #if defined(MONO_ARCH_USE_SIGACTION) && defined(UCONTEXT_GREGS)
        MonoException *exc = NULL;
        ucontext_t *ctx = (ucontext_t*)sigctx;
-       guint64 *gregs = gregs_from_ucontext (ctx);
-       MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)gregs [REG_RIP], NULL);
+       MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_RIP (sigctx), NULL);
        gpointer *sp;
        int frame_size;
 
@@ -934,18 +935,18 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean
        frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 4 + 128;
        frame_size += 15;
        frame_size &= ~15;
-       sp = (gpointer)(gregs [REG_RSP] & ~15);
+       sp = (gpointer)(UCONTEXT_REG_RSP (sigctx) & ~15);
        sp = (gpointer)((char*)sp - frame_size);
        /* the arguments must be aligned */
-       sp [-1] = (gpointer)gregs [REG_RIP];
+       sp [-1] = (gpointer)UCONTEXT_REG_RIP (sigctx);
        /* may need to adjust pointers in the new struct copy, depending on the OS */
        memcpy (sp + 4, ctx, sizeof (ucontext_t));
        /* at the return form the signal handler execution starts in altstack_handle_and_restore() */
-       gregs [REG_RIP] = (unsigned long)altstack_handle_and_restore;
-       gregs [REG_RSP] = (unsigned long)(sp - 1);
-       gregs [REG_RDI] = (unsigned long)(sp + 4);
-       gregs [REG_RSI] = (guint64)exc;
-       gregs [REG_RDX] = stack_ovf;
+       UCONTEXT_REG_RIP (sigctx) = (unsigned long)altstack_handle_and_restore;
+       UCONTEXT_REG_RSP (sigctx) = (unsigned long)(sp - 1);
+       UCONTEXT_REG_RDI (sigctx) = (unsigned long)(sp + 4);
+       UCONTEXT_REG_RSI (sigctx) = (guint64)exc;
+       UCONTEXT_REG_RDX (sigctx) = stack_ovf;
 #endif
 }
 
@@ -1105,26 +1106,55 @@ mono_arch_notify_pending_exc (void)
        *(gpointer*)(lmf->rsp - 8) = throw_pending_exception;
 }
 
+GSList*
+mono_amd64_get_exception_trampolines (gboolean aot)
+{
+       MonoTrampInfo *info;
+       GSList *tramps = NULL;
+
+       mono_arch_get_throw_pending_exception (&info, aot);
+       tramps = g_slist_prepend (tramps, info);
+
+       /* LLVM needs different throw trampolines */
+       get_throw_trampoline (&info, FALSE, TRUE, FALSE, FALSE, "llvm_throw_corlib_exception_trampoline", aot);
+       tramps = g_slist_prepend (tramps, info);
+
+       get_throw_trampoline (&info, FALSE, TRUE, TRUE, FALSE, "llvm_throw_corlib_exception_abs_trampoline", aot);
+       tramps = g_slist_prepend (tramps, info);
+
+       get_throw_trampoline (&info, FALSE, TRUE, TRUE, TRUE, "llvm_resume_unwind_trampoline", FALSE);
+       tramps = g_slist_prepend (tramps, info);
+
+       return tramps;
+}
+
 void
 mono_arch_exceptions_init (void)
 {
-       guint8 *tramp;
+       GSList *tramps, *l;
+       gpointer tramp;
 
        if (mono_aot_only) {
                throw_pending_exception = mono_aot_get_trampoline ("throw_pending_exception");
+               tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_trampoline");
+               mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE);
+               tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_abs_trampoline");
+               mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_abs_trampoline", NULL, TRUE);
+               tramp = mono_aot_get_trampoline ("llvm_resume_unwind_trampoline");
+               mono_register_jit_icall (tramp, "llvm_resume_unwind_trampoline", NULL, TRUE);
        } else {
                /* Call this to avoid initialization races */
                throw_pending_exception = mono_arch_get_throw_pending_exception (NULL, FALSE);
 
-               /* LLVM needs different throw trampolines */
-               tramp = get_throw_trampoline (NULL, FALSE, TRUE, FALSE, FALSE, "llvm_throw_corlib_exception", FALSE);
-               mono_register_jit_icall (tramp, "mono_arch_llvm_throw_corlib_exception", NULL, TRUE);
-
-               tramp = get_throw_trampoline (NULL, FALSE, TRUE, TRUE, FALSE, "llvm_throw_corlib_exception_abs", FALSE);
-               mono_register_jit_icall (tramp, "mono_arch_llvm_throw_corlib_exception_abs", NULL, TRUE);
+               tramps = mono_amd64_get_exception_trampolines (FALSE);
+               for (l = tramps; l; l = l->next) {
+                       MonoTrampInfo *info = l->data;
 
-               tramp = get_throw_trampoline (NULL, FALSE, TRUE, TRUE, TRUE, "mono_llvm_resume_unwind_trampoline", FALSE);
-               mono_register_jit_icall (tramp, "mono_llvm_resume_unwind_trampoline", NULL, TRUE);
+                       mono_register_jit_icall (info->code, g_strdup (info->name), NULL, TRUE);
+                       mono_save_trampoline_xdebug_info (info);
+                       mono_tramp_info_free (info);
+               }
+               g_slist_free (tramps);
        }
 }
 
@@ -1425,3 +1455,19 @@ mono_tasklets_arch_restore (void)
 }
 #endif
 
+/*
+ * mono_arch_setup_resume_sighandler_ctx:
+ *
+ *   Setup CTX so execution continues at FUNC.
+ */
+void
+mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func)
+{
+       /* 
+        * When resuming from a signal handler, the stack should be misaligned, just like right after
+        * a call.
+        */
+       if ((((guint64)MONO_CONTEXT_GET_SP (ctx)) % 16) == 0)
+               MONO_CONTEXT_SET_SP (ctx, (guint64)MONO_CONTEXT_GET_SP (ctx) - 8);
+       MONO_CONTEXT_SET_IP (ctx, func);
+}