Merge branch 'master' into msbuilddll2
[mono.git] / mono / mini / dwarfwriter.c
index 635fe8a471ec8c1dfcafb74d89f3f090e14f7b32..c8acff20d24a44ea16ab5d8b7996f7680e76a118 100644 (file)
@@ -8,6 +8,8 @@
  */
 
 #include "config.h"
+
+#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
 #include "dwarfwriter.h"
 
 #include <sys/types.h>
 #include <mono/metadata/debug-mono-symfile.h>
 #include <mono/utils/mono-compiler.h>
 
-#ifndef PLATFORM_WIN32
+#ifndef HOST_WIN32
 #include <mono/utils/freebsd-elf32.h>
 #include <mono/utils/freebsd-elf64.h>
 #endif
 
 #include <mono/utils/freebsd-dwarf.h>
 
+typedef struct {
+       MonoMethod *method;
+       char *start_symbol, *end_symbol;
+       guint8 *code;
+       guint32 code_size;
+} MethodLineNumberInfo;
+
 struct _MonoDwarfWriter
 {
        MonoImageWriter *w;
-       GHashTable *class_to_die;
+       GHashTable *class_to_die, *class_to_vtype_die, *class_to_pointer_die;
+       GHashTable *class_to_reference_die;
        int fde_index, tdie_index, line_number_file_index, line_number_dir_index;
-       GHashTable *file_to_index, *dir_to_index;
+       GHashTable *file_to_index, *index_to_file, *dir_to_index;
        FILE *il_file;
        int il_file_line_index, loclist_index;
        GSList *cie_program;
+       FILE *fp;
+       const char *temp_prefix;
+       gboolean emit_line, appending, collect_line_info;
+       GSList *line_info;
+       int cur_file_index;
 };
 
+static void
+emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, 
+                                          char *start_symbol, char *end_symbol,
+                                          guint8 *code, guint32 code_size,
+                                          MonoDebugMethodJitInfo *debug_info);
+
 /*
  * mono_dwarf_writer_create:
  *
  *   Create a DWARF writer object. WRITER is the underlying image writer this 
  * writer will emit to. IL_FILE is the file where IL code will be dumped to for
  * methods which have no line number info. It can be NULL.
+ * If APPENDING is TRUE, the output file will be in assembleable state after each
+ * call to the _emit_ functions. This is used for XDEBUG. If APPENDING is FALSE,
+ * a separate mono_dwarf_writer_close () call is needed to finish the emission of
+ * debug information.
  */
 MonoDwarfWriter*
-mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file)
+mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_start_line, gboolean appending, gboolean emit_line_numbers)
 {
        MonoDwarfWriter *w = g_new0 (MonoDwarfWriter, 1);
        
+       /*
+        * The appending flag is needed because we use subsections to order things in 
+        * the debug info, and:
+        * - apple's assembler doesn't support them
+        * - the binary writer has problems with subsections+alignment
+        * So instead of subsections, we use the _close () function in AOT mode,
+        * which writes out things in order.
+        */
+
        w->w = writer;
        w->il_file = il_file;
+       w->il_file_line_index = il_file_start_line;
+       w->appending = appending;
+
+       if (appending)
+               g_assert (img_writer_subsections_supported (w->w));
+
+       w->emit_line = TRUE;
+
+       if (appending) {
+               if (!img_writer_subsections_supported (w->w))
+                       /* Can't emit line number info without subsections */
+                       w->emit_line = FALSE;
+       } else {
+               /* Collect line number info and emit it at once */
+               w->collect_line_info = TRUE;
+       }
+
+       if (!emit_line_numbers) {
+               w->emit_line = FALSE;
+               w->collect_line_info = FALSE;
+       }
+
+       w->fp = img_writer_get_fp (w->w);
+       w->temp_prefix = img_writer_get_temp_label_prefix (w->w);
+
+       w->class_to_die = g_hash_table_new (NULL, NULL);
+       w->class_to_vtype_die = g_hash_table_new (NULL, NULL);
+       w->class_to_pointer_die = g_hash_table_new (NULL, NULL);
+       w->class_to_reference_die = g_hash_table_new (NULL, NULL);
+       w->cur_file_index = -1;
 
        return w;
 }
@@ -63,6 +127,12 @@ mono_dwarf_writer_destroy (MonoDwarfWriter *w)
        g_free (w);
 }
 
+int
+mono_dwarf_writer_get_il_file_line_index (MonoDwarfWriter *w)
+{
+       return w->il_file_line_index;
+}
+
 /* Wrappers around the image writer functions */
 
 static inline void
@@ -272,7 +342,8 @@ emit_cie (MonoDwarfWriter *w)
        emit_alignment (w, 8);
 
        /* Emit a CIE */
-       emit_symbol_diff (w, ".Lcie0_end", ".", -4); /* length */
+       emit_symbol_diff (w, ".Lcie0_end", ".Lcie0_start", 0); /* length */
+       emit_label (w, ".Lcie0_start");
        emit_int32 (w, 0xffffffff); /* CIE id */
        emit_byte (w, 3); /* version */
        emit_string (w, ""); /* augmention */
@@ -303,15 +374,18 @@ static void
 emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbol,
                  guint8 *code, guint32 code_size, GSList *unwind_ops, gboolean use_cie)
 {
-       char symbol [128];
+       char symbol1 [128];
+       char symbol2 [128];
        GSList *l;
        guint8 *uw_info;
        guint32 uw_info_len;
 
        emit_section_change (w, ".debug_frame", 0);
 
-       sprintf (symbol, ".Lfde%d_end", fde_index);
-       emit_symbol_diff (w, symbol, ".", -4); /* length */
+       sprintf (symbol1, ".Lfde%d_start", fde_index);
+       sprintf (symbol2, ".Lfde%d_end", fde_index);
+       emit_symbol_diff (w, symbol2, symbol1, 0); /* length */
+       emit_label (w, symbol1);
        emit_int32 (w, 0); /* CIE_pointer */
        if (start_symbol) {
                emit_pointer (w, start_symbol); /* initial_location */
@@ -336,7 +410,8 @@ emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbo
                int i;
 
                for (i = 0; i < g_slist_length (w->cie_program); ++i)
-                       l = l->next;
+                       if (l)
+                               l = l->next;
        }
 
        /* Convert the list of MonoUnwindOps to the format used by DWARF */     
@@ -344,9 +419,8 @@ emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbo
        emit_bytes (w, uw_info, uw_info_len);
        g_free (uw_info);
 
-       emit_alignment (w, sizeof (gpointer));
-       sprintf (symbol, ".Lfde%d_end", fde_index);
-       emit_label (w, symbol);
+       emit_alignment (w, sizeof (mgreg_t));
+       emit_label (w, symbol2);
 }
 
 /* Abbrevations */
@@ -362,6 +436,12 @@ emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbo
 #define ABBREV_NAMESPACE 10
 #define ABBREV_VARIABLE 11
 #define ABBREV_VARIABLE_LOCLIST 12
+#define ABBREV_POINTER_TYPE 13
+#define ABBREV_REFERENCE_TYPE 14
+#define ABBREV_PARAM_LOCLIST 15
+#define ABBREV_INHERITANCE 16
+#define ABBREV_STRUCT_TYPE_NOCHILDREN 17
+#define ABBREV_TRAMP_SUBPROGRAM 18
 
 static int compile_unit_attr [] = {
        DW_AT_producer     ,DW_FORM_string,
@@ -375,17 +455,32 @@ static int compile_unit_attr [] = {
 
 static int subprogram_attr [] = {
        DW_AT_name         , DW_FORM_string,
+#ifndef TARGET_IOS
+       DW_AT_description  , DW_FORM_string,
+#endif
     DW_AT_low_pc       , DW_FORM_addr,
     DW_AT_high_pc      , DW_FORM_addr,
        DW_AT_frame_base   , DW_FORM_block1
 };
 
+static int tramp_subprogram_attr [] = {
+       DW_AT_name         , DW_FORM_string,
+    DW_AT_low_pc       , DW_FORM_addr,
+    DW_AT_high_pc      , DW_FORM_addr,
+};
+
 static int param_attr [] = {
        DW_AT_name,     DW_FORM_string,
        DW_AT_type,     DW_FORM_ref4,
        DW_AT_location, DW_FORM_block1
 };
 
+static int param_loclist_attr [] = {
+       DW_AT_name,     DW_FORM_string,
+       DW_AT_type,     DW_FORM_ref4,
+       DW_AT_location, DW_FORM_data4
+};
+
 static int base_type_attr [] = {
        DW_AT_byte_size,   DW_FORM_data1,
        DW_AT_encoding,    DW_FORM_data1,
@@ -408,6 +503,14 @@ static int typedef_attr [] = {
        DW_AT_type,        DW_FORM_ref4
 };
 
+static int pointer_type_attr [] = {
+       DW_AT_type,        DW_FORM_ref4,
+};
+
+static int reference_type_attr [] = {
+       DW_AT_type,        DW_FORM_ref4,
+};
+
 static int enum_type_attr [] = {
        DW_AT_name,        DW_FORM_string,
        DW_AT_byte_size,   DW_FORM_udata,
@@ -434,6 +537,11 @@ static int variable_loclist_attr [] = {
        DW_AT_type,     DW_FORM_ref4,
        DW_AT_location, DW_FORM_data4
 };
+static int inheritance_attr [] = {
+       DW_AT_type,        DW_FORM_ref4,
+       DW_AT_data_member_location, DW_FORM_block1
+};
 
 typedef struct DwarfBasicType {
        const char *die_name, *name;
@@ -532,17 +640,44 @@ emit_line_number_file_name (MonoDwarfWriter *w, const char *name,
        return index;
 }
 
-static void
-emit_line_number_info_begin (MonoDwarfWriter *w)
+static int
+get_line_number_file_name (MonoDwarfWriter *w, const char *name)
 {
-       if (!w->il_file) {
-               /* FIXME: This doesn't seem to work with !xdebug */
-               emit_section_change (w, ".debug_line", 0);
-               emit_label (w, ".Ldebug_line_start");
-               emit_label (w, ".Ldebug_line_section_start");
-               return;
+       int index;
+
+       g_assert (w->file_to_index);
+       index = GPOINTER_TO_UINT (g_hash_table_lookup (w->file_to_index, name));
+       g_assert (index > 0);
+       return index - 1;
+}
+
+static int
+add_line_number_file_name (MonoDwarfWriter *w, const char *name,
+                                                  gint64 last_mod_time, gint64 file_size)
+{
+       int index;
+       char *copy;
+
+       if (!w->file_to_index) {
+               w->file_to_index = g_hash_table_new (g_str_hash, g_str_equal);
+               w->index_to_file = g_hash_table_new (NULL, NULL);
        }
 
+       index = GPOINTER_TO_UINT (g_hash_table_lookup (w->file_to_index, name));
+       if (index > 0)
+               return index - 1;
+       index = w->line_number_file_index;
+       w->line_number_file_index ++;
+       copy = g_strdup (name);
+       g_hash_table_insert (w->file_to_index, copy, GUINT_TO_POINTER (index + 1));
+       g_hash_table_insert (w->index_to_file, GUINT_TO_POINTER (index + 1), copy);
+
+       return index;
+}
+
+static void
+emit_line_number_info_begin (MonoDwarfWriter *w)
+{
        /* Line number info header */
        /* 
         * GAS seems to emit its own data to the end of the first subsection, so we use
@@ -603,8 +738,185 @@ emit_line_number_info_begin (MonoDwarfWriter *w)
        emit_label (w, ".Ldebug_line_end");
 }
 
+char *
+mono_dwarf_escape_path (const char *name)
+{
+       if (strchr (name, '\\')) {
+               char *s;
+               int len, i, j;
+
+               len = strlen (name);
+               s = g_malloc0 ((len + 1) * 2);
+               j = 0;
+               for (i = 0; i < len; ++i) {
+                       if (name [i] == '\\') {
+                               s [j ++] = '\\';
+                               s [j ++] = '\\';
+                       } else {
+                               s [j ++] = name [i];
+                       }
+               }
+               return s;
+       }
+       return g_strdup (name);
+}
+
+static void
+emit_all_line_number_info (MonoDwarfWriter *w)
+{
+       int i;
+       GHashTable *dir_to_index, *index_to_dir;
+       GSList *l;
+       GSList *info_list;
+
+       g_assert (w->collect_line_info);
+
+       add_line_number_file_name (w, "<unknown>", 0, 0);
+
+       /* Collect files */
+       info_list = g_slist_reverse (w->line_info);
+       for (l = info_list; l; l = l->next) {
+               MethodLineNumberInfo *info = l->data;
+               MonoDebugMethodInfo *minfo;
+               char *source_file;
+               GPtrArray *source_file_list;
+
+               // FIXME: Free stuff
+               minfo = mono_debug_lookup_method (info->method);
+               if (!minfo)
+                       continue;
+
+               mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, NULL, NULL, NULL, NULL, NULL);
+               for (i = 0; i < source_file_list->len; ++i) {
+                       MonoDebugSourceInfo *sinfo = g_ptr_array_index (source_file_list, i);
+                       add_line_number_file_name (w, sinfo->source_file, 0, 0);
+               }
+       }               
+
+       /* Preprocess files */
+       dir_to_index = g_hash_table_new (g_str_hash, g_str_equal);
+       index_to_dir = g_hash_table_new (NULL, NULL);
+       for (i = 0; i < w->line_number_file_index; ++i) {
+               char *name = g_hash_table_lookup (w->index_to_file, GUINT_TO_POINTER (i + 1));
+               char *copy;
+               int dir_index = 0;
+
+               if (g_path_is_absolute (name)) {
+                       char *dir = g_path_get_dirname (name);
+
+                       dir_index = GPOINTER_TO_UINT (g_hash_table_lookup (dir_to_index, dir));
+                       if (dir_index == 0) {
+                               dir_index = w->line_number_dir_index;
+                               w->line_number_dir_index ++;
+                               copy = g_strdup (dir);
+                               g_hash_table_insert (dir_to_index, copy, GUINT_TO_POINTER (dir_index + 1));
+                               g_hash_table_insert (index_to_dir, GUINT_TO_POINTER (dir_index + 1), copy);
+                       } else {
+                               dir_index --;
+                       }
+
+                       g_free (dir);
+               }
+       }
+
+       /* Line number info header */
+       emit_section_change (w, ".debug_line", 0);
+       emit_label (w, ".Ldebug_line_section_start");
+       emit_label (w, ".Ldebug_line_start");
+       emit_symbol_diff (w, ".Ldebug_line_end", ".", -4); /* length */
+       emit_int16 (w, 0x2); /* version */
+       emit_symbol_diff (w, ".Ldebug_line_header_end", ".", -4); /* header_length */
+       emit_byte (w, 1); /* minimum_instruction_length */
+       emit_byte (w, 1); /* default_is_stmt */
+       emit_byte (w, LINE_BASE); /* line_base */
+       emit_byte (w, LINE_RANGE); /* line_range */
+       emit_byte (w, OPCODE_BASE); /* opcode_base */
+       emit_byte (w, 0); /* standard_opcode_lengths */
+       emit_byte (w, 1);
+       emit_byte (w, 1);
+       emit_byte (w, 1);
+       emit_byte (w, 1);
+       emit_byte (w, 0);
+       emit_byte (w, 0);
+       emit_byte (w, 0);
+       emit_byte (w, 1);
+       emit_byte (w, 0);
+       emit_byte (w, 0);
+       emit_byte (w, 1);
+
+       /* Includes */
+       emit_section_change (w, ".debug_line", 0);
+       for (i = 0; i < w->line_number_dir_index; ++i) {
+               char *dir = g_hash_table_lookup (index_to_dir, GUINT_TO_POINTER (i + 1));
+
+               emit_string (w, mono_dwarf_escape_path (dir));
+       }
+       /* End of Includes */
+       emit_byte (w, 0);
+
+       /* Files */
+       for (i = 0; i < w->line_number_file_index; ++i) {
+               char *name = g_hash_table_lookup (w->index_to_file, GUINT_TO_POINTER (i + 1));
+               char *basename = NULL, *dir;
+               int dir_index = 0;
+
+               if (g_path_is_absolute (name)) {
+                       dir = g_path_get_dirname (name);
+
+                       dir_index = GPOINTER_TO_UINT (g_hash_table_lookup (dir_to_index, dir));
+                       basename = g_path_get_basename (name);
+               }
+                                                                                        
+               if (basename)
+                       emit_string (w, basename);
+               else
+                       emit_string (w, mono_dwarf_escape_path (name));
+               emit_uleb128 (w, dir_index);
+               emit_byte (w, 0);
+               emit_byte (w, 0);
+       }
+
+       /* End of Files */
+       emit_byte (w, 0);
+
+       emit_label (w, ".Ldebug_line_header_end");
+
+       /* Emit line number table */
+       for (l = info_list; l; l = l->next) {
+               MethodLineNumberInfo *info = l->data;
+               MonoDebugMethodJitInfo *dmji;
+
+               dmji = mono_debug_find_method (info->method, mono_domain_get ());;
+               emit_line_number_info (w, info->method, info->start_symbol, info->end_symbol, info->code, info->code_size, dmji);
+               mono_debug_free_method_jit_info (dmji);
+       }
+       g_slist_free (info_list);
+
+       emit_byte (w, 0);
+       emit_byte (w, 1);
+       emit_byte (w, DW_LNE_end_sequence);
+
+       emit_label (w, ".Ldebug_line_end");
+}
+
+/*
+ * Some assemblers like apple's do not support subsections, so we can't place
+ * .Ldebug_info_end at the end of the section using subsections. Instead, we 
+ * define it every time something gets added to the .debug_info section.
+ * The apple assember seems to use the last definition.
+ */
+static void
+emit_debug_info_end (MonoDwarfWriter *w)
+{
+       /* This doesn't seem to work/required with recent iphone sdk versions */
+#if 0
+       if (!img_writer_subsections_supported (w->w))
+               fprintf (w->fp, "\n.set %sdebug_info_end,.\n", w->temp_prefix);
+#endif
+}
+
 void
-mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_program)
+mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, const char *cu_name, GSList *base_unwind_program)
 {
        char *s, *build_info;
        int i;
@@ -618,10 +930,14 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
                                           subprogram_attr, G_N_ELEMENTS (subprogram_attr));
        emit_dwarf_abbrev (w, ABBREV_PARAM, DW_TAG_formal_parameter, FALSE, 
                                           param_attr, G_N_ELEMENTS (param_attr));
+       emit_dwarf_abbrev (w, ABBREV_PARAM_LOCLIST, DW_TAG_formal_parameter, FALSE, 
+                                          param_loclist_attr, G_N_ELEMENTS (param_loclist_attr));
        emit_dwarf_abbrev (w, ABBREV_BASE_TYPE, DW_TAG_base_type, FALSE, 
                                           base_type_attr, G_N_ELEMENTS (base_type_attr));
        emit_dwarf_abbrev (w, ABBREV_STRUCT_TYPE, DW_TAG_class_type, TRUE, 
                                           struct_type_attr, G_N_ELEMENTS (struct_type_attr));
+       emit_dwarf_abbrev (w, ABBREV_STRUCT_TYPE_NOCHILDREN, DW_TAG_class_type, FALSE, 
+                                          struct_type_attr, G_N_ELEMENTS (struct_type_attr));
        emit_dwarf_abbrev (w, ABBREV_DATA_MEMBER, DW_TAG_member, FALSE, 
                                           data_member_attr, G_N_ELEMENTS (data_member_attr));
        emit_dwarf_abbrev (w, ABBREV_TYPEDEF, DW_TAG_typedef, FALSE, 
@@ -636,20 +952,31 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
                                           variable_attr, G_N_ELEMENTS (variable_attr));
        emit_dwarf_abbrev (w, ABBREV_VARIABLE_LOCLIST, DW_TAG_variable, FALSE,
                                           variable_loclist_attr, G_N_ELEMENTS (variable_loclist_attr));
+       emit_dwarf_abbrev (w, ABBREV_POINTER_TYPE, DW_TAG_pointer_type, FALSE,
+                                          pointer_type_attr, G_N_ELEMENTS (pointer_type_attr));
+       emit_dwarf_abbrev (w, ABBREV_REFERENCE_TYPE, DW_TAG_reference_type, FALSE,
+                                          reference_type_attr, G_N_ELEMENTS (reference_type_attr));
+       emit_dwarf_abbrev (w, ABBREV_INHERITANCE, DW_TAG_inheritance, FALSE,
+                                          inheritance_attr, G_N_ELEMENTS (inheritance_attr));
+       emit_dwarf_abbrev (w, ABBREV_TRAMP_SUBPROGRAM, DW_TAG_subprogram, FALSE,
+                                          tramp_subprogram_attr, G_N_ELEMENTS (tramp_subprogram_attr));
        emit_byte (w, 0);
 
        emit_section_change (w, ".debug_info", 0);
        emit_label (w, ".Ldebug_info_start");
-       emit_symbol_diff (w, ".Ldebug_info_end", ".", -4); /* length */
+       emit_symbol_diff (w, ".Ldebug_info_end", ".Ldebug_info_begin", 0); /* length */
+       emit_label (w, ".Ldebug_info_begin");
        emit_int16 (w, 0x2); /* DWARF version 2 */
        emit_int32 (w, 0); /* .debug_abbrev offset */
        emit_byte (w, sizeof (gpointer)); /* address size */
 
-       /* Emit this into a separate section so it gets placed at the end */
-       emit_section_change (w, ".debug_info", 1);
-       emit_int32 (w, 0); /* close everything */
-       emit_label (w, ".Ldebug_info_end");
-       emit_section_change (w, ".debug_info", 0);
+       if (img_writer_subsections_supported (w->w) && w->appending) {
+               /* Emit this into a separate section so it gets placed at the end */
+               emit_section_change (w, ".debug_info", 1);
+               emit_byte (w, 0); /* close COMPILE_UNIT */
+               emit_label (w, ".Ldebug_info_end");
+               emit_section_change (w, ".debug_info", 0);
+       }
 
        /* Compilation unit */
        emit_uleb128 (w, ABBREV_COMPILE_UNIT);
@@ -658,13 +985,16 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
        emit_string (w, s);
        g_free (build_info);
        g_free (s);
-       emit_string (w, "JITted code");
+       emit_string (w, cu_name);
        emit_string (w, "");
        emit_byte (w, DW_LANG_C);
        emit_pointer_value (w, 0);
        emit_pointer_value (w, 0);
        /* offset into .debug_line section */
-       emit_symbol_diff (w, ".Ldebug_line_start", ".Ldebug_line_section_start", 0);
+       if (w->emit_line)
+               emit_symbol_diff (w, ".Ldebug_line_start", ".Ldebug_line_section_start", 0);
+       else
+               emit_pointer_value (w, 0);
 
        /* Base types */
        for (i = 0; i < G_N_ELEMENTS (basic_types); ++i) {
@@ -675,37 +1005,73 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
                emit_string (w, basic_types [i].name);
        }
 
+       emit_debug_info_end (w);
+
        /* debug_loc section */
        emit_section_change (w, ".debug_loc", 0);
        emit_label (w, ".Ldebug_loc_start");
 
-       /* debug_line section */
-       emit_line_number_info_begin (w);
-
        emit_cie (w);
 }
 
+/*
+ * mono_dwarf_writer_close:
+ *
+ *   Finalize the emitted debugging info.
+ */
+void
+mono_dwarf_writer_close (MonoDwarfWriter *w)
+{
+       if (!w->appending) {
+               emit_section_change (w, ".debug_info", 0);
+               emit_byte (w, 0); /* close COMPILE_UNIT */
+               emit_label (w, ".Ldebug_info_end");
+       }
+
+       if (w->collect_line_info)
+               emit_all_line_number_info (w);
+}
+
+static void emit_type (MonoDwarfWriter *w, MonoType *t);
+static const char* get_type_die (MonoDwarfWriter *w, MonoType *t);
+
+static const char*
+get_class_die (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
+{
+       GHashTable *cache;
+
+       if (vtype)
+               cache = w->class_to_vtype_die;
+       else
+               cache = w->class_to_die;
+
+       return g_hash_table_lookup (cache, klass);
+}
+
 /* Returns the local symbol pointing to the emitted debug info */
 static char*
-emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass)
+emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
 {
-       char *die;
-       char *full_name;
+       char *die, *pointer_die, *reference_die;
+       char *full_name, *p;
        gpointer iter;
        MonoClassField *field;
        const char *fdie;
        int k;
-       gboolean emit_namespace = FALSE;
+       gboolean emit_namespace = FALSE, has_children;
+       GHashTable *cache;
 
-       // FIXME: Appdomains
-       if (!w->class_to_die)
-               w->class_to_die = g_hash_table_new (NULL, NULL);
+       if (vtype)
+               cache = w->class_to_vtype_die;
+       else
+               cache = w->class_to_die;
 
-       die = g_hash_table_lookup (w->class_to_die, klass);
+       die = g_hash_table_lookup (cache, klass);
        if (die)
                return die;
 
-       if (!((klass->byval_arg.type == MONO_TYPE_CLASS) || klass->enumtype))
+       if (!((klass->byval_arg.type == MONO_TYPE_CLASS) || (klass->byval_arg.type == MONO_TYPE_OBJECT) || klass->byval_arg.type == MONO_TYPE_GENERICINST || klass->enumtype || (klass->byval_arg.type == MONO_TYPE_VALUETYPE && vtype) ||
+                 (klass->byval_arg.type >= MONO_TYPE_BOOLEAN && klass->byval_arg.type <= MONO_TYPE_R8 && !vtype)))
                return NULL;
 
        /*
@@ -721,13 +1087,28 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass)
        }
 
        full_name = g_strdup_printf ("%s%s%s", klass->name_space, klass->name_space ? "." : "", klass->name);
+       /* 
+        * gdb doesn't support namespaces for non-C++ dwarf objects, so use _
+        * to separate components.
+        */
+       for (p = full_name; *p; p ++)
+               if (*p == '.')
+                       *p = '_';
 
        die = g_strdup_printf (".LTDIE_%d", w->tdie_index);
-       emit_label (w, die);
+       pointer_die = g_strdup_printf (".LTDIE_%d_POINTER", w->tdie_index);
+       reference_die = g_strdup_printf (".LTDIE_%d_REFERENCE", w->tdie_index);
+       w->tdie_index ++;
+
+       g_hash_table_insert (w->class_to_pointer_die, klass, pointer_die);
+       g_hash_table_insert (w->class_to_reference_die, klass, reference_die);
+       g_hash_table_insert (cache, klass, die);
 
        if (klass->enumtype) {
                int size = mono_class_value_size (mono_class_from_mono_type (mono_class_enum_basetype (klass)), NULL);
 
+               emit_label (w, die);
+
                emit_uleb128 (w, ABBREV_ENUM_TYPE);
                emit_string (w, full_name);
                emit_uleb128 (w, size);
@@ -785,33 +1166,65 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass)
                                g_assert_not_reached ();
                        }
                }
+
+               has_children = TRUE;
        } else {
-               emit_uleb128 (w, ABBREV_STRUCT_TYPE);
+               guint8 buf [128];
+               guint8 *p;
+               char *parent_die;
+
+               if (klass->parent)
+                       parent_die = emit_class_dwarf_info (w, klass->parent, FALSE);
+               else
+                       parent_die = NULL;
+
+               /* Emit field types */
+               iter = NULL;
+               while ((field = mono_class_get_fields (klass, &iter))) {
+                       if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
+                               continue;
+
+                       emit_type (w, field->type);
+               }
+
+               iter = NULL;
+               has_children = parent_die || mono_class_get_fields (klass, &iter);
+
+               emit_label (w, die);
+
+               emit_uleb128 (w, has_children ? ABBREV_STRUCT_TYPE : ABBREV_STRUCT_TYPE_NOCHILDREN);
                emit_string (w, full_name);
                emit_uleb128 (w, klass->instance_size);
 
+               if (parent_die) {
+                       emit_uleb128 (w, ABBREV_INHERITANCE);
+                       emit_symbol_diff (w, parent_die, ".Ldebug_info_start", 0);
+
+                       p = buf;
+                       *p ++= DW_OP_plus_uconst;
+                       encode_uleb128 (0, p, &p);
+                       emit_byte (w, p - buf);
+                       emit_bytes (w, buf, p - buf);
+               }
+
                /* Emit fields */
                iter = NULL;
                while ((field = mono_class_get_fields (klass, &iter))) {
-                       guint8 buf [128];
-                       guint8 *p;
-
                        if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
                                continue;
 
-                       for (k = 0; k < G_N_ELEMENTS (basic_types); ++k)
-                               if (basic_types [k].type == field->type->type)
-                                       break;
-                       if (k < G_N_ELEMENTS (basic_types) && field->type->type != MONO_TYPE_SZARRAY && field->type->type != MONO_TYPE_CLASS) {
-                               fdie = basic_types [k].die_name;
-
+                       fdie = get_type_die (w, field->type);
+                       if (fdie) {
                                emit_uleb128 (w, ABBREV_DATA_MEMBER);
                                emit_string (w, field->name);
                                emit_symbol_diff (w, fdie, ".Ldebug_info_start", 0);
                                /* location */
                                p = buf;
                                *p ++= DW_OP_plus_uconst;
-                               encode_uleb128 (field->offset, p, &p);
+                               if (klass->valuetype && vtype)
+                                       encode_uleb128 (field->offset - sizeof (MonoObject), p, &p);
+                               else
+                                       encode_uleb128 (field->offset, p, &p);
 
                                emit_byte (w, p - buf);
                                emit_bytes (w, buf, p - buf);
@@ -820,58 +1233,155 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass)
        }
 
        /* Type end */
-       emit_uleb128 (w, 0x0);
+       if (has_children)
+               emit_uleb128 (w, 0x0);
 
        /* Add a typedef, so we can reference the type without a 'struct' in gdb */
        emit_uleb128 (w, ABBREV_TYPEDEF);
        emit_string (w, full_name);
        emit_symbol_diff (w, die, ".Ldebug_info_start", 0);
 
-       g_free (full_name);
-       w->tdie_index ++;
+       /* Add a pointer type */
+       emit_label (w, pointer_die);
 
+       emit_uleb128 (w, ABBREV_POINTER_TYPE);
+       emit_symbol_diff (w, die, ".Ldebug_info_start", 0);
+
+       /* Add a reference type */
+       emit_label (w, reference_die);
+
+       emit_uleb128 (w, ABBREV_REFERENCE_TYPE);
+       emit_symbol_diff (w, die, ".Ldebug_info_start", 0);
+
+       g_free (full_name);
 
        if (emit_namespace) {
                /* Namespace end */
                emit_uleb128 (w, 0x0);
        }
 
-       g_hash_table_insert (w->class_to_die, klass, die);
        return die;
 }
 
-static void
-emit_var_type (MonoDwarfWriter *w, MonoType *t)
+static gboolean base_types_emitted [64];
+
+static const char*
+get_type_die (MonoDwarfWriter *w, MonoType *t)
 {
        MonoClass *klass = mono_class_from_mono_type (t);
        int j;
        const char *tdie;
 
+       if (t->byref) {
+               if (t->type == MONO_TYPE_VALUETYPE) {
+                       tdie = g_hash_table_lookup (w->class_to_pointer_die, klass);
+               }
+               else {
+                       tdie = get_class_die (w, klass, FALSE);
+                       /* Should return a pointer type to a reference */
+               }
+               // FIXME:
+               t = &mono_defaults.int_class->byval_arg;
+       }
        for (j = 0; j < G_N_ELEMENTS (basic_types); ++j)
                if (basic_types [j].type == t->type)
                        break;
-       if (j < G_N_ELEMENTS (basic_types))
+       if (j < G_N_ELEMENTS (basic_types)) {
                tdie = basic_types [j].die_name;
-       else {
+       else {
                switch (t->type) {
                case MONO_TYPE_CLASS:
+                       tdie = g_hash_table_lookup (w->class_to_reference_die, klass);
+                       //tdie = ".LDIE_OBJECT";
+                       break;
                case MONO_TYPE_ARRAY:
                        tdie = ".LDIE_OBJECT";
                        break;
                case MONO_TYPE_VALUETYPE:
                        if (klass->enumtype)
-                               tdie = emit_class_dwarf_info (w, klass);
+                               tdie = get_class_die (w, klass, FALSE);
                        else
                                tdie = ".LDIE_I4";
                        break;
+               case MONO_TYPE_GENERICINST:
+                       if (!MONO_TYPE_ISSTRUCT (t)) {
+                               tdie = g_hash_table_lookup (w->class_to_reference_die, klass);
+                       } else {
+                               tdie = ".LDIE_I4";
+                       }
+                       break;
+               case MONO_TYPE_PTR:
+                       tdie = ".LDIE_I";
+                       break;
                default:
                        tdie = ".LDIE_I4";
                        break;
                }
        }
-       if (t->byref)
+
+       g_assert (tdie);
+
+       return tdie;
+}
+
+static void
+emit_type (MonoDwarfWriter *w, MonoType *t)
+{
+       MonoClass *klass = mono_class_from_mono_type (t);
+       int j;
+       const char *tdie;
+
+       if (t->byref) {
+               if (t->type == MONO_TYPE_VALUETYPE) {
+                       tdie = emit_class_dwarf_info (w, klass, TRUE);
+                       if (tdie)
+                               return;
+               }
+               else {
+                       emit_class_dwarf_info (w, klass, FALSE);
+               }
                // FIXME:
-               tdie = ".LDIE_I4";
+               t = &mono_defaults.int_class->byval_arg;
+       }
+       for (j = 0; j < G_N_ELEMENTS (basic_types); ++j)
+               if (basic_types [j].type == t->type)
+                       break;
+       if (j < G_N_ELEMENTS (basic_types)) {
+               /* Emit a boxed version of base types */
+               if (j < 64 && !base_types_emitted [j]) {
+                       emit_class_dwarf_info (w, klass, FALSE);
+                       base_types_emitted [j] = TRUE;
+               }
+       } else {
+               switch (t->type) {
+               case MONO_TYPE_CLASS:
+                       emit_class_dwarf_info (w, klass, FALSE);
+                       break;
+               case MONO_TYPE_ARRAY:
+                       break;
+               case MONO_TYPE_VALUETYPE:
+                       if (klass->enumtype)
+                               emit_class_dwarf_info (w, klass, FALSE);
+                       break;
+               case MONO_TYPE_GENERICINST:
+                       if (!MONO_TYPE_ISSTRUCT (t))
+                               emit_class_dwarf_info (w, klass, FALSE);
+                       break;
+               case MONO_TYPE_PTR:
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void
+emit_var_type (MonoDwarfWriter *w, MonoType *t)
+{
+       const char *tdie;
+
+       tdie = get_type_die (w, t);
+
        emit_symbol_diff (w, tdie, ".Ldebug_info_start", 0);
 }
 
@@ -932,6 +1442,7 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token)
        char *res, *desc;
        MonoMethod *cmethod;
        MonoClass *klass;
+       MonoClassField *field;
        gpointer data = NULL;
 
        if (method->wrapper_type)
@@ -939,6 +1450,7 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token)
 
        switch (*token_handler_ip) {
        case CEE_ISINST:
+       case CEE_CASTCLASS:
        case CEE_LDELEMA:
                if (method->wrapper_type)
                        klass = data;
@@ -966,6 +1478,18 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token)
                        res = g_strdup_printf ("<0x%08x>", token);
                }
                break;
+       case CEE_LDFLD:
+       case CEE_LDSFLD:
+       case CEE_STFLD:
+       case CEE_STSFLD:
+               if (method->wrapper_type)
+                       field = data;
+               else
+                       field = mono_field_from_token (method->klass->image, token, &klass, NULL);
+               desc = mono_field_full_name (field);
+               res = g_strdup_printf ("<%s>", desc);
+               g_free (desc);
+               break;
        default:
                res = g_strdup_printf ("<0x%08x>", token);
                break;
@@ -1029,10 +1553,10 @@ disasm_ins (MonoMethod *method, const guchar *ip, const guint8 **endip)
        token_handler_ip = NULL;
 
        *endip = ip;
+       mono_metadata_free_mh (header);
        return dis;
 }
 
-/*
 static gint32
 il_offset_from_address (MonoMethod *method, MonoDebugMethodJitInfo *jit, 
                                                guint32 native_offset)
@@ -1051,7 +1575,6 @@ il_offset_from_address (MonoMethod *method, MonoDebugMethodJitInfo *jit,
 
        return -1;
 }
-*/
 
 static int max_special_addr_diff = 0;
 
@@ -1078,6 +1601,7 @@ emit_advance_op (MonoDwarfWriter *w, int line_diff, int addr_diff)
        if (opcode != 0) {
                emit_byte (w, opcode);
        } else {
+               //printf ("large: %d %d %d\n", line_diff, addr_diff, max_special_addr_diff);
                emit_byte (w, DW_LNS_advance_line);
                emit_sleb128 (w, line_diff);
                emit_byte (w, DW_LNS_advance_pc);
@@ -1096,8 +1620,10 @@ compare_lne (MonoDebugLineNumberEntry *a, MonoDebugLineNumberEntry *b)
 }
 
 static void
-emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code,
-                                          guint32 code_size, MonoDebugMethodJitInfo *debug_info)
+emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, 
+                                          char *start_symbol, char *end_symbol,
+                                          guint8 *code, guint32 code_size,
+                                          MonoDebugMethodJitInfo *debug_info)
 {
        guint32 prev_line = 0;
        guint32 prev_native_offset = 0;
@@ -1107,59 +1633,70 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code,
        char *prev_file_name = NULL;
        MonoMethodHeader *header = mono_method_get_header (method);
        MonoDebugMethodInfo *minfo;
-       GArray *ln_array;
-       int *native_to_il_offset;
-
-       if (!code)
-               // FIXME: The set_address op below only works with xdebug
+       MonoDebugLineNumberEntry *ln_array;
+       int *native_to_il_offset = NULL;
+       
+       if (!w->emit_line) {
+               mono_metadata_free_mh (header);
                return;
+       }
 
        minfo = mono_debug_lookup_method (method);
 
        /* Compute the native->IL offset mapping */
 
-       ln_array = g_array_sized_new (FALSE, FALSE, sizeof (MonoDebugLineNumberEntry), 
-                                                                 debug_info->num_line_numbers);
-       g_array_append_vals (ln_array, debug_info->line_numbers, debug_info->num_line_numbers);
-       g_array_sort (ln_array, (GCompareFunc)compare_lne);
+       g_assert (code_size);
+
+       ln_array = g_new0 (MonoDebugLineNumberEntry, debug_info->num_line_numbers);
+       memcpy (ln_array, debug_info->line_numbers, debug_info->num_line_numbers * sizeof (MonoDebugLineNumberEntry));
+
+       qsort (ln_array, debug_info->num_line_numbers, sizeof (MonoDebugLineNumberEntry), (gpointer)compare_lne);
+
        native_to_il_offset = g_new0 (int, code_size + 1);
 
        for (i = 0; i < debug_info->num_line_numbers; ++i) {
                int j;
-               MonoDebugLineNumberEntry lne = g_array_index (ln_array, MonoDebugLineNumberEntry, i);
+               MonoDebugLineNumberEntry *lne = &ln_array [i];
 
                if (i == 0) {
-                       for (j = 0; j < lne.native_offset; ++j)
+                       for (j = 0; j < lne->native_offset; ++j)
                                native_to_il_offset [j] = -1;
                }
 
                if (i < debug_info->num_line_numbers - 1) {
-                       MonoDebugLineNumberEntry lne_next = g_array_index (ln_array, MonoDebugLineNumberEntry, i + 1);
+                       MonoDebugLineNumberEntry *lne_next = &ln_array [i + 1];
 
-                       for (j = lne.native_offset; j < lne_next.native_offset; ++j)
-                               native_to_il_offset [j] = lne.il_offset;
+                       for (j = lne->native_offset; j < lne_next->native_offset; ++j)
+                               native_to_il_offset [j] = lne->il_offset;
                } else {
-                       for (j = lne.native_offset; j < code_size; ++j)
-                               native_to_il_offset [j] = lne.il_offset;
+                       for (j = lne->native_offset; j < code_size; ++j)
+                               native_to_il_offset [j] = lne->il_offset;
                }
        }
-       g_array_free (ln_array, TRUE);
+       g_free (ln_array);
 
        prev_line = 1;
        prev_il_offset = -1;
 
        for (i = 0; i < code_size; ++i) {
+               int line_diff, addr_diff;
+
                if (!minfo)
                        continue;
 
                if (!debug_info->line_numbers)
                        continue;
 
+               if (native_to_il_offset)
+                       il_offset = native_to_il_offset [i];
+               else
+                       il_offset = il_offset_from_address (method, debug_info, i);
                /*
                il_offset = il_offset_from_address (method, debug_info, i);
 
                g_assert (il_offset == native_to_il_offset [i]);
                */
+
                il_offset = native_to_il_offset [i];
                if (il_offset < 0)
                        continue;
@@ -1170,54 +1707,64 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code,
                prev_il_offset = il_offset;
 
                loc = mono_debug_symfile_lookup_location (minfo, il_offset);
+               if (!(loc && loc->source_file))
+                       continue;
 
-               if (loc) {
-                       int line_diff = (gint32)loc->row - (gint32)prev_line;
-                       int addr_diff = i - prev_native_offset;
+               line_diff = (gint32)loc->row - (gint32)prev_line;
+               addr_diff = i - prev_native_offset;
 
-                       if (first) {    
-                               emit_section_change (w, ".debug_line", LINE_SUBSECTION_DATA);
+               if (first) {    
+                       emit_section_change (w, ".debug_line", LINE_SUBSECTION_DATA);
 
-                               emit_byte (w, 0);
-                               emit_byte (w, sizeof (gpointer) + 1);
-                               emit_byte (w, DW_LNE_set_address);
+                       emit_byte (w, 0);
+                       emit_byte (w, sizeof (gpointer) + 1);
+                       emit_byte (w, DW_LNE_set_address);
+                       if (start_symbol)
+                               emit_pointer_unaligned (w, start_symbol);
+                       else
                                emit_pointer_value (w, code);
 
-                               /* 
-                                * The prolog+initlocals region does not have a line number, this
-                                * makes them belong to the first line of the method.
-                                */
-                               emit_byte (w, DW_LNS_advance_line);
-                               emit_sleb128 (w, (gint32)loc->row - (gint32)prev_line);
-                               prev_line = loc->row;
-                       }
+                       /* 
+                        * The prolog+initlocals region does not have a line number, this
+                        * makes them belong to the first line of the method.
+                        */
+                       emit_byte (w, DW_LNS_advance_line);
+                       //printf ("FIRST: %d %d %d\n", prev_line, loc->row, il_offset);
+                       emit_sleb128 (w, (gint32)loc->row - (gint32)prev_line);
+                       prev_line = loc->row;
+                       prev_native_offset = i;
+                       first = FALSE;
+               }
 
-                       if (loc->row != prev_line) {
-                               if (!prev_file_name || strcmp (loc->source_file, prev_file_name) != 0) {
-                                       /* Add an entry to the file table */
-                                       /* FIXME: Avoid duplicates */
+               if (loc->row != prev_line) {
+                       if (!prev_file_name || strcmp (loc->source_file, prev_file_name) != 0) {
+                               /* Add an entry to the file table */
+                               /* FIXME: Avoid duplicates */
+                               if (w->collect_line_info)
+                                       file_index = get_line_number_file_name (w, loc->source_file) + 1;
+                               else
                                        file_index = emit_line_number_file_name (w, loc->source_file, 0, 0);
-                                       g_free (prev_file_name);
-                                       prev_file_name = g_strdup (loc->source_file);
+                               g_free (prev_file_name);
+                               prev_file_name = g_strdup (loc->source_file);
 
+                               if (w->cur_file_index != file_index) {
                                        emit_byte (w, DW_LNS_set_file);
                                        emit_uleb128 (w, file_index);
                                        emit_byte (w, DW_LNS_copy);
-                               }
-
-                               //printf ("X: %p(+0x%x) %d %s:%d(+%d)\n", code + i, addr_diff, loc->il_offset, loc->source_file, loc->row, line_diff);
-
-                               emit_advance_op (w, line_diff, addr_diff);
-
-                               prev_line = loc->row;
-                               prev_native_offset = i;
+                                       w->cur_file_index = file_index;
+                               }                                       
                        }
+                       //printf ("X: %p(+0x%x) %d %s:%d(+%d)\n", code + i, addr_diff, loc->il_offset, loc->source_file, loc->row, line_diff);
+                       emit_advance_op (w, line_diff, addr_diff);
 
-                       first = FALSE;
-                       g_free (loc);
+                       prev_line = loc->row;
+                       prev_native_offset = i;
                }
+
+               mono_debug_symfile_free_location (loc);
        }
 
+       g_free (native_to_il_offset);
        g_free (prev_file_name);
 
        if (!first) {
@@ -1228,7 +1775,7 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code,
                emit_byte (w, 0);
                emit_byte (w, 1);
                emit_byte (w, DW_LNE_end_sequence);
-       } else if (code) {
+       } else if (!start_symbol) {
                /* No debug info, XDEBUG mode */
                char *name, *dis;
                const guint8 *ip = header->code;
@@ -1278,10 +1825,16 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code,
                                continue;
                        line = il_to_line [lne->il_offset];
                        if (!line) {
-                               /* To help debugging */
+                               /* 
+                                * This seems to happen randomly, it looks like il_offset points
+                                * into the middle of an instruction.
+                                */
+                               continue;
+                               /*
                                printf ("%s\n", mono_method_full_name (method, TRUE));
                                printf ("%d %d\n", lne->il_offset, header->code_size);
                                g_assert (line);
+                               */
                        }
 
                        if (line - prev_line != 0) {
@@ -1303,6 +1856,26 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code,
                fflush (w->il_file);
                g_free (il_to_line);
        }
+       mono_metadata_free_mh (header);
+}
+
+static MonoMethodVar*
+find_vmv (MonoCompile *cfg, MonoInst *ins)
+{
+       int j;
+
+       if (cfg->varinfo) {
+               for (j = 0; j < cfg->num_varinfo; ++j) {
+                       if (cfg->varinfo [j] == ins)
+                               break;
+               }
+
+               if (j < cfg->num_varinfo) {
+                       return MONO_VARINFO (cfg, j);
+               }
+       }
+
+       return NULL;
 }
 
 void
@@ -1311,10 +1884,9 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
        char *name;
        MonoMethodSignature *sig;
        MonoMethodHeader *header;
-       char **names, **tdies, **local_tdies;
-       char **local_names;
-       int *local_indexes;
-       int i, num_locals;
+       char **names;
+       MonoDebugLocalsInfo *locals_info;
+       int i;
        guint8 buf [128];
        guint8 *p;
 
@@ -1324,23 +1896,25 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
        header = mono_method_get_header (method);
 
        /* Parameter types */
-       tdies = g_new0 (char *, sig->param_count + sig->hasthis);
        for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
                MonoType *t;
 
                if (i == 0 && sig->hasthis) {
-                       t = &method->klass->this_arg;
+                       if (method->klass->valuetype)
+                               t = &method->klass->this_arg;
+                       else
+                               t = &method->klass->byval_arg;
                } else {
                        t = sig->params [i - sig->hasthis];
                }
 
-               emit_class_dwarf_info (w, mono_class_from_mono_type (t));
+               emit_type (w, t);
        }
+       //emit_type (w, &mono_defaults.int32_class->byval_arg);
 
        /* Local types */
-       local_tdies = g_new0 (char *, header->num_locals);
        for (i = 0; i < header->num_locals; ++i) {
-               emit_class_dwarf_info (w, mono_class_from_mono_type (header->locals [i]));
+               emit_type (w, header->locals [i]);
        }
 
        /* Subprogram */
@@ -1350,6 +1924,9 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
        emit_uleb128 (w, ABBREV_SUBPROGRAM);
        name = mono_method_full_name (method, FALSE);
        emit_string (w, name);
+#ifndef TARGET_IOS
+       emit_string (w, name);
+#endif
        g_free (name);
        if (start_symbol) {
                emit_pointer_unaligned (w, start_symbol);
@@ -1369,16 +1946,25 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
                MonoType *t;
                const char *pname;
                char pname_buf [128];
+               MonoMethodVar *vmv = NULL;
+               gboolean need_loclist = FALSE;
+
+               vmv = find_vmv (cfg, arg);
+               if (code && vmv && (vmv->live_range_start || vmv->live_range_end))
+                       need_loclist = TRUE;
 
                if (i == 0 && sig->hasthis) {
-                       t = &mono_defaults.object_class->byval_arg;
+                       if (method->klass->valuetype)
+                               t = &method->klass->this_arg;
+                       else
+                               t = &method->klass->byval_arg;
                        pname = "this";
                } else {
                        t = sig->params [i - sig->hasthis];
                        pname = names [i - sig->hasthis];
                }
-               
-               emit_uleb128 (w, ABBREV_PARAM);
+
+               emit_uleb128 (w, need_loclist ? ABBREV_PARAM_LOCLIST : ABBREV_PARAM);
                /* name */
                if (pname[0] == '\0') {
                        sprintf (pname_buf, "param%d", i - sig->hasthis);
@@ -1393,13 +1979,21 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
 
                p = buf;
                encode_var_location (w, arg, p, &p);
-               emit_byte (w, p - buf);
-               emit_bytes (w, buf, p - buf);
+               if (need_loclist) {
+                       vmv->live_range_start = 0;
+                       if (vmv->live_range_end == 0)
+                               /* FIXME: Uses made in calls are not recorded */
+                               vmv->live_range_end = code_size;
+                       emit_loclist (w, arg, code + vmv->live_range_start, code + vmv->live_range_end, buf, p - buf);
+               } else {
+                       emit_byte (w, p - buf);
+                       emit_bytes (w, buf, p - buf);
+               }
        }               
        g_free (names);
 
        /* Locals */
-       num_locals = mono_debug_lookup_locals (method, &local_names, &local_indexes);
+       locals_info = mono_debug_lookup_locals (method);
 
        for (i = 0; i < header->num_locals; ++i) {
                MonoInst *ins = locals [i];
@@ -1407,33 +2001,29 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
                int j;
                MonoMethodVar *vmv = NULL;
                gboolean need_loclist = FALSE;
+               char *lname;
 
                /* ins->dreg no longer contains the original vreg */
-               if (cfg->varinfo) {
-                       for (j = 0; j < cfg->num_varinfo; ++j) {
-                               if (cfg->varinfo [j] == ins)
-                                       break;
-                       }
-
-                       if (code && j < cfg->num_varinfo) {
-                               vmv = MONO_VARINFO (cfg, j);
-                               if (vmv->live_range_start) {
-                                       /* This variable has a precise live range */
-                                       need_loclist = TRUE;
-                               }
+               vmv = find_vmv (cfg, ins);
+               if (code && vmv) {
+                       if (vmv->live_range_start) {
+                               /* This variable has a precise live range */
+                               need_loclist = TRUE;
                        }
                }
 
-               if (need_loclist)
-                       emit_uleb128 (w, ABBREV_VARIABLE_LOCLIST);
-               else
-                       emit_uleb128 (w, ABBREV_VARIABLE);
+               emit_uleb128 (w, need_loclist ? ABBREV_VARIABLE_LOCLIST : ABBREV_VARIABLE);
                /* name */
-               for (j = 0; j < num_locals; ++j)
-                       if (local_indexes [j] == i)
-                               break;
-               if (j < num_locals) {
-                       emit_string (w, local_names [j]);
+               lname = NULL;
+               if (locals_info) {
+                       for (j = 0; j < locals_info->num_locals; ++j)
+                               if (locals_info->locals [j].index == i)
+                                       break;
+                       if (j < locals_info->num_locals)
+                               lname = locals_info->locals [j].name;
+               }
+               if (lname) {
+                       emit_string (w, lname);
                } else {
                        sprintf (name_buf, "V_%d", i);
                        emit_string (w, name_buf);
@@ -1458,23 +2048,43 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
                }
        }
 
-       g_free (local_names);
-       g_free (local_indexes);
+       if (locals_info)
+               mono_debug_symfile_free_locals (locals_info);
 
        /* Subprogram end */
        emit_uleb128 (w, 0x0);
 
        emit_line (w);
 
+       emit_debug_info_end (w);
+
        /* Emit unwind info */
-       emit_fde (w, w->fde_index, start_symbol, end_symbol, code, code_size, unwind_info, TRUE);
-       w->fde_index ++;
+       if (unwind_info) {
+               emit_fde (w, w->fde_index, start_symbol, end_symbol, code, code_size, unwind_info, TRUE);
+               w->fde_index ++;
+       }
 
        /* Emit line number info */
-       if (code && debug_info)
-               emit_line_number_info (w, method, code, code_size, debug_info);
+       /* != could happen when using --regression */
+       if (debug_info && (debug_info->code_start == code)) {
+               if (w->collect_line_info) {
+                       MethodLineNumberInfo *info;
+
+                       /* Save the information needed to emit the line number info later at once */
+                       info = g_new0 (MethodLineNumberInfo, 1);
+                       info->method = method;
+                       info->start_symbol = g_strdup (start_symbol);
+                       info->end_symbol = g_strdup (end_symbol);
+                       info->code = code;
+                       info->code_size = code_size;
+                       w->line_info = g_slist_prepend (w->line_info, info);
+               } else {
+                       emit_line_number_info (w, method, start_symbol, end_symbol, code, code_size, debug_info);
+               }
+       }
 
        emit_line (w);
+       mono_metadata_free_mh (header);
 }
 
 void
@@ -1483,19 +2093,18 @@ mono_dwarf_writer_emit_trampoline (MonoDwarfWriter *w, const char *tramp_name, c
        emit_section_change (w, ".debug_info", 0);
 
        /* Subprogram */
-       emit_uleb128 (w, ABBREV_SUBPROGRAM);
+       emit_uleb128 (w, ABBREV_TRAMP_SUBPROGRAM);
        emit_string (w, tramp_name);
        emit_pointer_value (w, code);
        emit_pointer_value (w, code + code_size);
-       /* frame_base */
-       emit_byte (w, 2);
-       emit_byte (w, DW_OP_breg6);
-       emit_byte (w, 16);
 
        /* Subprogram end */
        emit_uleb128 (w, 0x0);
 
+       emit_debug_info_end (w);
+
        /* Emit unwind info */
        emit_fde (w, w->fde_index, start_symbol, end_symbol, code, code_size, unwind_info, FALSE);
        w->fde_index ++;
 }
+#endif /* End of: !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */