Use dwarf unwind info on MIPS.
authorZoltan Varga <vargaz@gmail.com>
Mon, 28 Nov 2011 03:51:40 +0000 (03:51 +0000)
committerZoltan Varga <vargaz@gmail.com>
Mon, 28 Nov 2011 03:51:40 +0000 (03:51 +0000)
configure.in
mono/mini/exceptions-mips.c
mono/mini/mini-mips.c
mono/mini/mini-mips.h
mono/mini/mini-unwind.h
mono/mini/unwind.c

index 34ee9292fb210ee525b9db38c27593217ce1b371..6cf9f416d4aa7c963aa4fda6de5379a44b4e1f49 100644 (file)
@@ -2474,6 +2474,9 @@ POWERPC64)
 S390x)
        AC_DEFINE(TARGET_S390X, 1, [...])
        ;;
+MIPS)
+       AC_DEFINE(TARGET_MIPS, 1, [...])
+       ;;
 esac
 
 if test "x$sizeof_register" = "x4"; then
index 232ce3df87d84645011bcc0e494432a58f913c4c..da90482edbbf24fa2b03b5f3bb0619cac06da680 100644 (file)
@@ -419,18 +419,43 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
        *new_ctx = *ctx;
 
        if (ji != NULL) {
-               gint32 address;
+               int i;
                gpointer ip = MONO_CONTEXT_GET_IP (ctx);
-               gpointer fp = MONO_CONTEXT_GET_BP (ctx);
-               guint32 sp;
+               mgreg_t regs [MONO_MAX_IREGS + 1];
+               guint8 *cfa;
+               guint32 unwind_info_len;
+               guint8 *unwind_info;
 
                frame->type = FRAME_TYPE_MANAGED;
 
-               if (*lmf && (fp >= (gpointer)(*lmf)->ebp)) {
+               if (ji->from_aot)
+                       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);
+
+               for (i = 0; i < MONO_MAX_IREGS; ++i)
+                       regs [i] = new_ctx->sc_regs [i];
+
+               mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
+                                                  (guint8*)ji->code_start + ji->code_size,
+                                                  ip, regs, MONO_MAX_IREGS,
+                                                  save_locations, MONO_MAX_IREGS, &cfa);
+
+               for (i = 0; i < MONO_MAX_IREGS; ++i)
+                       new_ctx->sc_regs [i] = regs [i];
+               new_ctx->sc_pc = regs [mips_ra];
+               new_ctx->sc_regs [mips_sp] = (mgreg_t)cfa;
+
+               if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
                        /* remove any unused lmf */
                        *lmf = (*lmf)->previous_lmf;
                }
 
+               /* we substract 8, so that the IP points into the call instruction */
+               MONO_CONTEXT_SET_IP (new_ctx, new_ctx->sc_pc - 8);
+
+#if 0
+
                address = (char *)ip - (char *)ji->code_start;
 
                /* Compute the previous stack frame, assuming method
@@ -482,6 +507,7 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls,
                }
                /* we substract 8, so that the IP points into the call instruction */
                MONO_CONTEXT_SET_IP (new_ctx, new_ctx->sc_regs[mips_ra] - 8);
+#endif
 
                /* Sanity check -- we should have made progress here */
                g_assert (MONO_CONTEXT_GET_BP (new_ctx) != MONO_CONTEXT_GET_BP (ctx));
index d2ebb7bc3925e2dc27d8791df78743414f5bcc4a..713598d51be2c5d860aa3fbccdceefd8785b36d5 100644 (file)
@@ -4765,6 +4765,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        /* lmf_offset is the offset of the LMF from our stack pointer. */
        guint32 lmf_offset = cfg->arch.lmf_offset;
 #endif
+       int cfa_offset = 0;
 
        if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
                tracing = 1;
@@ -4789,6 +4790,10 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        /* adjust stackframe assignments for spillvars if needed */
        mips_adjust_stackframe (cfg);
 
+       /* Offset between current sp and the CFA */
+       cfa_offset = 0;
+       mono_emit_unwind_op_def_cfa (cfg, code, mips_sp, cfa_offset);
+
        /* stack_offset should not be changed here. */
        alloc_size = cfg->stack_offset;
        cfg->stack_usage = alloc_size;
@@ -4817,6 +4822,8 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        if (alloc_size) {
                g_assert (mips_is_imm16 (-alloc_size));
                mips_addiu (code, mips_sp, mips_sp, -alloc_size);
+               cfa_offset = alloc_size;
+               mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
        }
 
        if ((cfg->flags & MONO_CFG_HAS_CALLS) || ALWAYS_SAVE_RA) {
@@ -4826,6 +4833,8 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                else {
                        g_assert_not_reached ();
                }
+               /* sp = cfa - cfa_offset, so sp + offset = cfa - cfa_offset + offset */
+               mono_emit_unwind_op_offset (cfg, code, mips_ra, offset - cfa_offset);
        }
 
        /* XXX - optimize this later to not save all regs if LMF constructed */
@@ -4838,6 +4847,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                g_assert (pos < (int)(cfg->stack_usage - sizeof(gpointer)));
                                g_assert (mips_is_imm16(pos));
                                MIPS_SW (code, i, mips_sp, pos);
+                               mono_emit_unwind_op_offset (cfg, code, i, pos - cfa_offset);
                                pos += SIZEOF_REGISTER;
                        }
                }
@@ -4876,6 +4886,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
 #endif
        if (cfg->frame_reg != mips_sp) {
                MIPS_MOVE (code, cfg->frame_reg, mips_sp);
+               mono_emit_unwind_op_def_cfa (cfg, code, cfg->frame_reg, cfa_offset);
 #if SAVE_LMF
                if (method->save_lmf) {
                        int offset = lmf_offset + G_STRUCT_OFFSET(MonoLMF, iregs[cfg->frame_reg]);
@@ -5083,6 +5094,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        }
 #endif
        if (alloc2_size) {
+               /* The CFA is fp now, so this doesn't need unwind info */
                if (mips_is_imm16 (-alloc2_size)) {
                        mips_addu (code, mips_sp, mips_sp, -alloc2_size);
                }
index b5d3816d729e32bb02afbcfea6c99ff19cc3e958..35811101634844a35755bf13ac24e822284eb05d 100644 (file)
@@ -274,6 +274,7 @@ typedef struct MonoCompileArch {
 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
 #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
 #define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
+#define MONO_ARCH_HAVE_XP_UNWIND 1
 
 /* XXX - a mystery, but it works */
 #define MONO_GET_CONTEXT \
index 18cd299cd81e6086d7bbdc518487ddd380d16fc1..f93e9bcefb8827927e1f5623b48c940e29f9a730 100644 (file)
  * This is a platform-independent interface for unwinding through stack frames 
  * based on the Dwarf unwinding interface.
  * See http://dwarfstd.org/Dwarf3.pdf, section "Call Frame Information".
- * Currently, this is only used for emitting unwind info in AOT files.
  */
 
-/* CFA = Canonical Frame Address */
+/*
+ * CFA = Canonical Frame Address. By convention, this is the value of the stack pointer
+ * prior to the execution of the call instruction in the caller. I.e. on x86, it is
+ * esp + 4 on entry to a function. The value of the CFA does not change during execution
+ * of a function. There are two kinds of unwind directives:
+ * - those that describe how to compute the CFA at a given pc offset inside a function
+ * - those that describe where a given register is saved relative to the CFA.
+ */
 
 /* Unwind ops */
 
index d4f30251d0c74bc07732b09c1bd2926aaa488cd9..2ac1afeb07d55b0294652c8faf8dbde91c070174 100644 (file)
@@ -72,6 +72,17 @@ static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
 #define NUM_REGS 16
 #define DWARF_DATA_ALIGN (-8)
 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (14))
+#elif defined (TARGET_MIPS)
+/* FIXME: */
+static int map_hw_reg_to_dwarf_reg [32] = {
+       0, 1, 2, 3, 4, 5, 6, 7,
+       8, 9, 10, 11, 12, 13, 14, 15,
+       16, 17, 18, 19, 20, 21, 22, 23,
+       24, 25, 26, 27, 28, 29, 30, 31
+};
+#define NUM_REGS 32
+#define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
+#define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (mips_ra))
 #else
 static int map_hw_reg_to_dwarf_reg [16];
 #define NUM_REGS 16