2010-05-30 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / dwarfwriter.c
index e3021549e16ee6897d3120836cc3a7dfe9a6ad21..1541629d4d12047459c7ade7ef7c1fd09a24905f 100644 (file)
@@ -23,7 +23,7 @@
 #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
@@ -42,7 +42,7 @@ struct _MonoDwarfWriter
        GSList *cie_program;
        FILE *fp;
        const char *temp_prefix;
-       gboolean emit_line;
+       gboolean emit_line, appending;
 };
 
 /*
@@ -51,14 +51,32 @@ struct _MonoDwarfWriter
  *   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)
 {
        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->fp = img_writer_get_fp (w->w);
        w->temp_prefix = img_writer_get_temp_label_prefix (w->w);
@@ -72,6 +90,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
@@ -357,7 +381,7 @@ 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));
+       emit_alignment (w, sizeof (mgreg_t));
        emit_label (w, symbol2);
 }
 
@@ -378,6 +402,7 @@ emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbo
 #define ABBREV_REFERENCE_TYPE 14
 #define ABBREV_PARAM_LOCLIST 15
 #define ABBREV_INHERITANCE 16
+#define ABBREV_STRUCT_TYPE_NOCHILDREN 17
 
 static int compile_unit_attr [] = {
        DW_AT_producer     ,DW_FORM_string,
@@ -639,8 +664,11 @@ emit_line_number_info_begin (MonoDwarfWriter *w)
 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
@@ -670,6 +698,8 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
                                           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, 
@@ -694,15 +724,16 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
 
        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 */
 
-       if (img_writer_subsections_supported (w->w)) {
+       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_int32 (w, 0); /* close everything */
+               emit_byte (w, 0); /* close COMPILE_UNIT */
                emit_label (w, ".Ldebug_info_end");
                emit_section_change (w, ".debug_info", 0);
        }
@@ -720,10 +751,7 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
        emit_pointer_value (w, 0);
        emit_pointer_value (w, 0);
        /* offset into .debug_line section */
-       if (w->emit_line)
-               emit_symbol_diff (w, ".Ldebug_line_start", ".Ldebug_line_section_start", 0);
-       else
-               emit_int32 (w, 0);
+       emit_symbol_diff (w, ".Ldebug_line_start", ".Ldebug_line_section_start", 0);
 
        /* Base types */
        for (i = 0; i < G_N_ELEMENTS (basic_types); ++i) {
@@ -741,12 +769,30 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
        emit_label (w, ".Ldebug_loc_start");
 
        /* debug_line section */
-       if (w->emit_line)
-               emit_line_number_info_begin (w);
+       /*
+        * 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);
 
        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");
+       }
+}
+
 static const char* emit_type (MonoDwarfWriter *w, MonoType *t);
 
 /* Returns the local symbol pointing to the emitted debug info */
@@ -759,7 +805,7 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
        MonoClassField *field;
        const char *fdie;
        int k;
-       gboolean emit_namespace = FALSE;
+       gboolean emit_namespace = FALSE, has_children;
        GHashTable *cache;
 
        // FIXME: Appdomains
@@ -876,6 +922,8 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
                                g_assert_not_reached ();
                        }
                }
+
+               has_children = TRUE;
        } else {
                guint8 buf [128];
                guint8 *p;
@@ -895,9 +943,12 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
                        emit_type (w, field->type);
                }
 
+               iter = NULL;
+               has_children = parent_die || mono_class_get_fields (klass, &iter);
+
                emit_label (w, die);
 
-               emit_uleb128 (w, ABBREV_STRUCT_TYPE);
+               emit_uleb128 (w, has_children ? ABBREV_STRUCT_TYPE : ABBREV_STRUCT_TYPE_NOCHILDREN);
                emit_string (w, full_name);
                emit_uleb128 (w, klass->instance_size);
 
@@ -938,7 +989,8 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
        }
 
        /* 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);
@@ -1016,6 +1068,9 @@ emit_type (MonoDwarfWriter *w, MonoType *t)
                                tdie = ".LDIE_I4";
                        }
                        break;
+               case MONO_TYPE_PTR:
+                       tdie = ".LDIE_I";
+                       break;
                default:
                        tdie = ".LDIE_I4";
                        break;
@@ -1203,6 +1258,7 @@ disasm_ins (MonoMethod *method, const guchar *ip, const guint8 **endip)
        token_handler_ip = NULL;
 
        *endip = ip;
+       mono_metadata_free_mh (header);
        return dis;
 }
 
@@ -1281,11 +1337,13 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
        char *prev_file_name = NULL;
        MonoMethodHeader *header = mono_method_get_header (method);
        MonoDebugMethodInfo *minfo;
-       GArray *ln_array;
+       MonoDebugLineNumberEntry *ln_array;
        int *native_to_il_offset = NULL;
 
-       if (!w->emit_line)
+       if (!w->emit_line) {
+               mono_metadata_free_mh (header);
                return;
+       }
 
        minfo = mono_debug_lookup_method (method);
 
@@ -1293,34 +1351,33 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
 
        g_assert (code_size);
 
-#ifndef _EGLIB_MAJOR
-       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);
+       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);
-#endif
+       g_free (ln_array);
 
        prev_line = 1;
        prev_il_offset = -1;
@@ -1353,7 +1410,10 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
 
                loc = mono_debug_symfile_lookup_location (minfo, il_offset);
 
-               if (loc) {
+               // 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;
 
@@ -1399,10 +1459,12 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
                        }
 
                        first = FALSE;
-                       g_free (loc);
+
+                       mono_debug_symfile_free_location (loc);
                }
        }
 
+       g_free (native_to_il_offset);
        g_free (prev_file_name);
 
        if (!first) {
@@ -1494,6 +1556,7 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method,
                fflush (w->il_file);
                g_free (il_to_line);
        }
+       mono_metadata_free_mh (header);
 }
 
 static MonoMethodVar*
@@ -1521,7 +1584,7 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
        char *name;
        MonoMethodSignature *sig;
        MonoMethodHeader *header;
-       char **names, **tdies, **local_tdies;
+       char **names;
        char **local_names;
        int *local_indexes;
        int i, num_locals;
@@ -1534,7 +1597,6 @@ 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;
 
@@ -1551,7 +1613,6 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
        }
 
        /* Local types */
-       local_tdies = g_new0 (char *, header->num_locals);
        for (i = 0; i < header->num_locals; ++i) {
                emit_type (w, header->locals [i]);
        }
@@ -1700,6 +1761,7 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
                emit_line_number_info (w, method, start_symbol, end_symbol, code, code_size, debug_info);
 
        emit_line (w);
+       mono_metadata_free_mh (header);
 }
 
 void