2010-06-02 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / unwind.c
index 1eee23b487f3e804323c4d7385b8eddf32bae887..2b128dedf759eb4e37e800e2134c665be4677679 100644 (file)
@@ -11,6 +11,7 @@
 #include "mini-unwind.h"
 
 #include <mono/utils/mono-counters.h>
+#include <mono/utils/freebsd-dwarf.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/mono-endian.h>
 
@@ -117,7 +118,7 @@ init_reg_map (void)
        dwarf_reg_to_hw_reg_inited = TRUE;
 }
 
-static inline int
+int
 mono_dwarf_reg_to_hw_reg (int reg)
 {
        if (!dwarf_reg_to_hw_reg_inited)
@@ -654,7 +655,7 @@ read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
  *   Decode the Language Specific Data Area generated by LLVM.
  */
 static void
-decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info)
+decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
 {
        gint32 ttype_offset, call_site_length;
        gint32 ttype_encoding, call_site_encoding;
@@ -667,9 +668,34 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
         */
        p = lsda;
 
-       /* Read @LPStart */
-       g_assert (*p == DW_EH_PE_omit);
-       p ++;
+       if (*p == DW_EH_PE_udata4) {
+               /* This is the modified LSDA generated by the LLVM mono branch */
+               guint32 mono_magic, version;
+               gint32 op, reg, offset;
+
+               p ++;
+               mono_magic = decode_uleb128 (p, &p);
+               g_assert (mono_magic == 0x4d4fef4f);
+               version = decode_uleb128 (p, &p);
+               g_assert (version == 1);
+
+               /* 'this' location */
+               op = *p;
+               g_assert (op == DW_OP_bregx);
+               p ++;
+               reg = decode_uleb128 (p, &p);
+               offset = decode_sleb128 (p, &p);
+
+               *this_reg = mono_dwarf_reg_to_hw_reg (reg);
+               *this_offset = offset;
+       } else {
+               /* Read @LPStart */
+               g_assert (*p == DW_EH_PE_omit);
+               p ++;
+
+               *this_reg = -1;
+               *this_offset = -1;
+       }
 
        /* Read @TType */
        ttype_encoding = *p;
@@ -765,7 +791,7 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
  * LSDA.
  */
 guint8*
-mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info)
+mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
 {
        guint8 *p, *cie, *fde_current, *fde_aug, *code, *fde_cfi, *cie_cfi;
        gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
@@ -779,6 +805,9 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi
         * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
         */
 
+       *this_reg = -1;
+       *this_offset = -1;
+
        /* Decode FDE */
 
        p = fde;
@@ -879,7 +908,7 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi
                if (lsda_offset != 0) {
                        lsda = fde_aug + *(gint32*)fde_aug;
 
-                       decode_lsda (lsda, code, ex_info, ex_info_len, type_info);
+                       decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
                }
        }