2006-07-02 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / exceptions-amd64.c
index 31c7a7a212e683593b7d00d0194da820aeb01a73..22c0f5f0250a36996144a69589acf4ac3f79d493 100644 (file)
@@ -246,8 +246,8 @@ mono_arch_get_call_filter (void)
 
 static void
 throw_exception (MonoObject *exc, guint64 rip, guint64 rsp,
-                                guint64 rbx, guint64 rbp, guint64 r12, guint64 r13, 
-                                guint64 r14, guint64 r15, guint64 rethrow)
+                guint64 rbx, guint64 rbp, guint64 r12, guint64 r13, 
+                guint64 r14, guint64 r15, guint64 rethrow)
 {
        static void (*restore_context) (MonoContext *);
        MonoContext ctx;
@@ -255,9 +255,6 @@ throw_exception (MonoObject *exc, guint64 rip, guint64 rsp,
        if (!restore_context)
                restore_context = mono_arch_get_restore_context ();
 
-       /* adjust eip so that it point into the call instruction */
-       rip -= 1;
-
        ctx.rsp = rsp;
        ctx.rip = rip;
        ctx.rbx = rbx;
@@ -267,12 +264,38 @@ throw_exception (MonoObject *exc, guint64 rip, guint64 rsp,
        ctx.r14 = r14;
        ctx.r15 = r15;
 
+       if (!rethrow && mono_debugger_throw_exception ((gpointer)(rip - 8), (gpointer)rsp, exc)) {
+               /*
+                * The debugger wants us to stop on the `throw' instruction.
+                * By the time we get here, it already inserted a breakpoint on
+                * eip - 8 (which is the address of the `mov %r15,%rdi ; callq throw').
+                */
+
+               /* FIXME FIXME
+                *
+                * In case of a rethrow, the JIT is emitting code like this:
+                *
+                *    mov    0xffffffffffffffd0(%rbp),%rax'
+                *    mov    %rax,%rdi
+                *    callq  throw
+                *
+                * Here, restore_context() wouldn't restore the %rax register correctly.
+                */
+               ctx.rip = rip - 8;
+               ctx.rsp = rsp + 8;
+               restore_context (&ctx);
+               g_assert_not_reached ();
+       }
+
+       /* adjust eip so that it point into the call instruction */
+       ctx.rip -= 1;
+
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
                if (!rethrow)
                        mono_ex->stack_trace = NULL;
        }
-       mono_handle_exception (&ctx, exc, (gpointer)(rip + 1), FALSE);
+       mono_handle_exception (&ctx, exc, (gpointer)rip, FALSE);
        restore_context (&ctx);
 
        g_assert_not_reached ();
@@ -458,6 +481,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
 
        if (ji != NULL) {
                int offset;
+               gboolean omit_fp = (ji->used_regs & (1 << 31)) > 0;
 
                *new_ctx = *ctx;
 
@@ -475,8 +499,10 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                         * We only need to do this if the exception was raised in managed
                         * code, since otherwise the lmf was already popped of the stack.
                         */
-                       if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+                       if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
+                               new_ctx->rbp = (*lmf)->ebp;
                                new_ctx->rbx = (*lmf)->rbx;
+                               new_ctx->rsp = (*lmf)->rsp;
                                new_ctx->r12 = (*lmf)->r12;
                                new_ctx->r13 = (*lmf)->r13;
                                new_ctx->r14 = (*lmf)->r14;
@@ -484,12 +510,21 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                        }
                }
                else {
-                       offset = -1;
+                       offset = omit_fp ? 0 : -1;
                        /* restore caller saved registers */
                        for (i = 0; i < AMD64_NREG; i ++)
                                if (AMD64_IS_CALLEE_SAVED_REG (i) && (ji->used_regs & (1 << i))) {
-                                       guint64 reg = *((guint64 *)ctx->SC_EBP + offset);
-                                       offset --;
+                                       guint64 reg;
+
+                                       if (omit_fp) {
+                                               reg = *((guint64*)ctx->rsp + offset);
+                                               offset ++;
+                                       }
+                                       else {
+                                               reg = *((guint64 *)ctx->SC_EBP + offset);
+                                               offset --;
+                                       }
+
                                        switch (i) {
                                        case AMD64_RBX:
                                                new_ctx->rbx = reg;
@@ -506,22 +541,34 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                                        case AMD64_R15:
                                                new_ctx->r15 = reg;
                                                break;
+                                       case AMD64_RBP:
+                                               new_ctx->rbp = reg;
+                                               break;
                                        default:
                                                g_assert_not_reached ();
                                        }
                                }
                }
 
-               if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+               if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
                        /* remove any unused lmf */
                        *lmf = (*lmf)->previous_lmf;
                }
 
-               /* Pop EBP and the return address */
-               new_ctx->SC_ESP = ctx->SC_EBP + (2 * sizeof (gpointer));
-               /* we substract 1, so that the IP points into the call instruction */
-               new_ctx->SC_EIP = *((guint64 *)ctx->SC_EBP + 1) - 1;
-               new_ctx->SC_EBP = *((guint64 *)ctx->SC_EBP);
+               if (omit_fp) {
+                       /* Pop frame */
+                       new_ctx->rsp += (ji->used_regs >> 16) & (0x7fff);
+                       new_ctx->SC_EIP = *((guint64 *)new_ctx->rsp) - 1;
+                       /* Pop return address */
+                       new_ctx->rsp += 8;
+               }
+               else {
+                       /* Pop EBP and the return address */
+                       new_ctx->SC_ESP = ctx->SC_EBP + (2 * sizeof (gpointer));
+                       /* we substract 1, so that the IP points into the call instruction */
+                       new_ctx->SC_EIP = *((guint64 *)ctx->SC_EBP + 1) - 1;
+                       new_ctx->SC_EBP = *((guint64 *)ctx->SC_EBP);
+               }
 
                /* Pop arguments off the stack */
                {
@@ -547,6 +594,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
 
                new_ctx->SC_RIP = (*lmf)->rip;
                new_ctx->SC_RBP = (*lmf)->ebp;
+               new_ctx->SC_ESP = (*lmf)->rsp;
 
                new_ctx->SC_RBX = (*lmf)->rbx;
                new_ctx->SC_R12 = (*lmf)->r12;
@@ -554,10 +602,6 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                new_ctx->SC_R14 = (*lmf)->r14;
                new_ctx->SC_R15 = (*lmf)->r15;
 
-               /* 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->SC_ESP = ALIGN_TO ((guint64)&((*lmf)->rip), 16);
-
                *lmf = (*lmf)->previous_lmf;
 
                return ji ? ji : res;