Emit AOT line number information on osx/ios too.
authorZoltan Varga <vargaz@gmail.com>
Wed, 15 Aug 2012 04:47:28 +0000 (06:47 +0200)
committerZoltan Varga <vargaz@gmail.com>
Wed, 15 Aug 2012 04:47:28 +0000 (06:47 +0200)
mono/mini/aot-compiler.c
mono/mini/dwarfwriter.c
mono/utils/freebsd-dwarf.h

index 320f9d9d6b5dc95476eadb1125355c135edcf8eb..43eedc64d27704afbd9db3d8f4af402bb719a5dd 100644 (file)
@@ -7334,7 +7334,7 @@ compile_asm (MonoAotCompile *acfg)
        }
 
        g_free (command);
-       unlink (objfile);
+
        /*com = g_strdup_printf ("strip --strip-unneeded %s%s", acfg->image->name, SHARED_EXT);
        printf ("Stripping the binary: %s\n", com);
        system (com);
@@ -7358,6 +7358,17 @@ compile_asm (MonoAotCompile *acfg)
 
        rename (tmp_outfile_name, outfile_name);
 
+#if defined(__APPLE__)
+       command = g_strdup_printf ("dsymutil %s", outfile_name);
+       printf ("Generating debug symbols: %s\n", command);
+       if (system (command) != 0) {
+               return 1;
+       }
+#endif
+
+       if (!acfg->aot_opts.save_temps)
+               unlink (objfile);
+
        g_free (tmp_outfile_name);
        g_free (outfile_name);
        g_free (objfile);
index b6057cdd1044658fe87cec4d0452caf98ac070ab..2c589d46980a415bbaa29bcd566d2602e12e8d91 100644 (file)
 
 #include <mono/utils/freebsd-dwarf.h>
 
+typedef struct {
+       MonoMethod *method;
+       char *start_symbol, *end_symbol;
+       guint8 *code;
+       guint32 code_size;
+       MonoDebugMethodJitInfo *debug_info;
+} MethodLineNumberInfo;
+
 struct _MonoDwarfWriter
 {
        MonoImageWriter *w;
        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;
+       gboolean emit_line, appending, collect_line_info;
+       GSList *line_info;
 };
 
+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:
  *
@@ -78,6 +93,17 @@ mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_st
        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;
+       }
+
        w->fp = img_writer_get_fp (w->w);
        w->temp_prefix = img_writer_get_temp_label_prefix (w->w);
 
@@ -422,6 +448,7 @@ static int compile_unit_attr [] = {
 
 static int subprogram_attr [] = {
        DW_AT_name         , DW_FORM_string,
+       DW_AT_description  , DW_FORM_string,
     DW_AT_low_pc       , DW_FORM_addr,
     DW_AT_high_pc      , DW_FORM_addr,
        DW_AT_frame_base   , DW_FORM_block1
@@ -598,6 +625,41 @@ emit_line_number_file_name (MonoDwarfWriter *w, const char *name,
        return index;
 }
 
+static int
+get_line_number_file_name (MonoDwarfWriter *w, const char *name)
+{
+       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)
 {
@@ -661,6 +723,139 @@ emit_line_number_info_begin (MonoDwarfWriter *w)
        emit_label (w, ".Ldebug_line_end");
 }
 
+static void
+emit_all_line_number_info (MonoDwarfWriter *w)
+{
+       int i;
+       GHashTable *dir_to_index, *index_to_dir;
+       GSList *l;
+
+       g_assert (w->collect_line_info);
+
+       add_line_number_file_name (w, "xdb.il", 0, 0);
+
+       /* Collect files */
+       // FIXME: Revert list
+       for (l = w->line_info; 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, 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, 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 = w->line_info; l; l = l->next) {
+               MethodLineNumberInfo *info = l->data;
+
+               emit_line_number_info (w, info->method, info->start_symbol, info->end_symbol, info->code, info->code_size, info->debug_info);
+       }
+
+       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 
@@ -683,12 +878,6 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
        char *s, *build_info;
        int i;
 
-       if (!img_writer_subsections_supported (w->w))
-               /* Can't emit line number info without subsections */
-               w->emit_line = FALSE;
-       else
-               w->emit_line = TRUE;
-
        w->cie_program = base_unwind_program;
 
        emit_section_change (w, ".debug_abbrev", 0);
@@ -779,7 +968,8 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
         * We emit some info even if emit_line is FALSE, as the
         * apple linker seems to require a .debug_line section.
         */
-       emit_line_number_info_begin (w);
+       if (!w->collect_line_info)
+               emit_line_number_info_begin (w);
 
        emit_cie (w);
 }
@@ -797,6 +987,9 @@ mono_dwarf_writer_close (MonoDwarfWriter *w)
                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);
@@ -1471,10 +1664,6 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
                prev_il_offset = il_offset;
 
                loc = mono_debug_symfile_lookup_location (minfo, il_offset);
-
-               // Added the loc->source_file check as otherwise we can
-               // crash, see the sample in bug 553191 that makes this code
-               // crash when we call strcmp on loc->source_file below
                if (loc && loc->source_file) {
                        int line_diff = (gint32)loc->row - (gint32)prev_line;
                        int addr_diff = i - prev_native_offset;
@@ -1503,7 +1692,10 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
                                if (!prev_file_name || strcmp (loc->source_file, prev_file_name) != 0) {
                                        /* Add an entry to the file table */
                                        /* FIXME: Avoid duplicates */
-                                       file_index = emit_line_number_file_name (w, loc->source_file, 0, 0);
+                                       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);
 
@@ -1511,7 +1703,6 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
                                        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);
@@ -1686,6 +1877,7 @@ 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);
+       emit_string (w, name);
        g_free (name);
        if (start_symbol) {
                emit_pointer_unaligned (w, start_symbol);
@@ -1825,8 +2017,23 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
 
        /* Emit line number info */
        /* != could happen when using --regression */
-       if (debug_info && (debug_info->code_start == code))
-               emit_line_number_info (w, method, start_symbol, end_symbol, code, code_size, debug_info);
+       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;
+                       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);
+               }
+       }
 
        emit_line (w);
        mono_metadata_free_mh (header);
index 10eea49d94bb35672432113d87d45f7099d6430e..305f5e994c2d81cdd911300eeb21b2522e30f030 100644 (file)
 #define DW_AT_variable_parameter       0x4b
 #define DW_AT_virtuality               0x4c
 #define DW_AT_vtable_elem_location     0x4d
+#define DW_AT_description       0x5a
 
 #define DW_AT_lo_user                  0x2000