Merge branch 'master' into msbuilddll2
[mono.git] / mono / mini / dwarfwriter.c
index 2c589d46980a415bbaa29bcd566d2602e12e8d91..c8acff20d24a44ea16ab5d8b7996f7680e76a118 100644 (file)
@@ -35,7 +35,6 @@ typedef struct {
        char *start_symbol, *end_symbol;
        guint8 *code;
        guint32 code_size;
-       MonoDebugMethodJitInfo *debug_info;
 } MethodLineNumberInfo;
 
 struct _MonoDwarfWriter
@@ -52,6 +51,7 @@ struct _MonoDwarfWriter
        const char *temp_prefix;
        gboolean emit_line, appending, collect_line_info;
        GSList *line_info;
+       int cur_file_index;
 };
 
 static void
@@ -72,7 +72,7 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
  * debug information.
  */
 MonoDwarfWriter*
-mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_start_line, gboolean appending)
+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);
        
@@ -104,6 +104,11 @@ mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_st
                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);
 
@@ -111,6 +116,7 @@ mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_st
        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;
 }
@@ -435,6 +441,7 @@ emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbo
 #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,
@@ -448,12 +455,20 @@ 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,
@@ -723,20 +738,44 @@ 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, "xdb.il", 0, 0);
+       add_line_number_file_name (w, "<unknown>", 0, 0);
 
        /* Collect files */
-       // FIXME: Revert list
-       for (l = w->line_info; l; l = l->next) {
+       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;
@@ -810,7 +849,7 @@ emit_all_line_number_info (MonoDwarfWriter *w)
        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, dir);
+               emit_string (w, mono_dwarf_escape_path (dir));
        }
        /* End of Includes */
        emit_byte (w, 0);
@@ -831,7 +870,7 @@ emit_all_line_number_info (MonoDwarfWriter *w)
                if (basename)
                        emit_string (w, basename);
                else
-                       emit_string (w, name);
+                       emit_string (w, mono_dwarf_escape_path (name));
                emit_uleb128 (w, dir_index);
                emit_byte (w, 0);
                emit_byte (w, 0);
@@ -843,11 +882,15 @@ emit_all_line_number_info (MonoDwarfWriter *w)
        emit_label (w, ".Ldebug_line_header_end");
 
        /* Emit line number table */
-       for (l = w->line_info; l; l = l->next) {
+       for (l = info_list; l; l = l->next) {
                MethodLineNumberInfo *info = l->data;
+               MonoDebugMethodJitInfo *dmji;
 
-               emit_line_number_info (w, info->method, info->start_symbol, info->end_symbol, info->code, info->code_size, info->debug_info);
+               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);
@@ -873,7 +916,7 @@ emit_debug_info_end (MonoDwarfWriter *w)
 }
 
 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;
@@ -915,6 +958,8 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
                                           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);
@@ -940,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) {
@@ -963,14 +1011,6 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
        emit_section_change (w, ".debug_loc", 0);
        emit_label (w, ".Ldebug_loc_start");
 
-       /* debug_line section */
-       /*
-        * We emit some info even if emit_line is FALSE, as the
-        * apple linker seems to require a .debug_line section.
-        */
-       if (!w->collect_line_info)
-               emit_line_number_info_begin (w);
-
        emit_cie (w);
 }
 
@@ -1561,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);
@@ -1594,7 +1635,7 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
        MonoDebugMethodInfo *minfo;
        MonoDebugLineNumberEntry *ln_array;
        int *native_to_il_offset = NULL;
-
+       
        if (!w->emit_line) {
                mono_metadata_free_mh (header);
                return;
@@ -1638,6 +1679,8 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
        prev_il_offset = -1;
 
        for (i = 0; i < code_size; ++i) {
+               int line_diff, addr_diff;
+
                if (!minfo)
                        continue;
 
@@ -1664,57 +1707,61 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
                prev_il_offset = il_offset;
 
                loc = mono_debug_symfile_lookup_location (minfo, il_offset);
-               if (loc && loc->source_file) {
-                       int line_diff = (gint32)loc->row - (gint32)prev_line;
-                       int addr_diff = i - prev_native_offset;
-
-                       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);
-                               if (start_symbol)
-                                       emit_pointer_unaligned (w, start_symbol);
-                               else
-                                       emit_pointer_value (w, code);
+               if (!(loc && loc->source_file))
+                       continue;
 
-                               /* 
-                                * 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;
-                       }
+               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 (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);
+                       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);
+                       //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 (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);
 
+                               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;
-
-                       mono_debug_symfile_free_location (loc);
+                       prev_line = loc->row;
+                       prev_native_offset = i;
                }
+
+               mono_debug_symfile_free_location (loc);
        }
 
        g_free (native_to_il_offset);
@@ -1877,7 +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);
@@ -2028,7 +2077,6 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
                        info->end_symbol = g_strdup (end_symbol);
                        info->code = code;
                        info->code_size = code_size;
-                       info->debug_info = debug_info;
                        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);
@@ -2045,14 +2093,10 @@ 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);