Correctly link the seq point for ENDFINALLY with its successors. Fixes #5566.
[mono.git] / mono / mini / dwarfwriter.c
index 8c0f736c86112238bc0112fea8112bc92ff8b1c7..b6057cdd1044658fe87cec4d0452caf98ac070ab 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,18 +51,41 @@ 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);
 
+       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);
+
        return w;
 }
 
@@ -72,6 +95,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
@@ -349,7 +378,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 */     
@@ -357,7 +387,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 +408,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 +670,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 +704,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 +730,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);
        }
@@ -747,7 +784,36 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
        emit_cie (w);
 }
 
-static const char* emit_type (MonoDwarfWriter *w, MonoType *t);
+/*
+ * 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 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*
@@ -759,19 +825,9 @@ 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
-       if (!w->class_to_die)
-               w->class_to_die = g_hash_table_new (NULL, NULL);
-       if (!w->class_to_vtype_die)
-               w->class_to_vtype_die = g_hash_table_new (NULL, NULL);
-       if (!w->class_to_pointer_die)
-               w->class_to_pointer_die = g_hash_table_new (NULL, NULL);
-       if (!w->class_to_reference_die)
-               w->class_to_reference_die = g_hash_table_new (NULL, NULL);
-
        if (vtype)
                cache = w->class_to_vtype_die;
        else
@@ -781,7 +837,8 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
        if (die)
                return die;
 
-       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)))
+       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;
 
        /*
@@ -876,6 +933,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 +954,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);
 
@@ -918,7 +980,7 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
                        if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
                                continue;
 
-                       fdie = emit_type (w, field->type);
+                       fdie = get_type_die (w, field->type);
                        if (fdie) {
                                emit_uleb128 (w, ABBREV_DATA_MEMBER);
                                emit_string (w, field->name);
@@ -938,7 +1000,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);
@@ -967,8 +1030,10 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
        return die;
 }
 
+static gboolean base_types_emitted [64];
+
 static const char*
-emit_type (MonoDwarfWriter *w, MonoType *t)
+get_type_die (MonoDwarfWriter *w, MonoType *t)
 {
        MonoClass *klass = mono_class_from_mono_type (t);
        int j;
@@ -976,12 +1041,10 @@ emit_type (MonoDwarfWriter *w, MonoType *t)
 
        if (t->byref) {
                if (t->type == MONO_TYPE_VALUETYPE) {
-                       tdie = emit_class_dwarf_info (w, klass, TRUE);
-                       if (tdie)
-                               return g_hash_table_lookup (w->class_to_pointer_die, klass);
+                       tdie = g_hash_table_lookup (w->class_to_pointer_die, klass);
                }
                else {
-                       tdie = emit_class_dwarf_info (w, klass, FALSE);
+                       tdie = get_class_die (w, klass, FALSE);
                        /* Should return a pointer type to a reference */
                }
                // FIXME:
@@ -990,12 +1053,11 @@ emit_type (MonoDwarfWriter *w, MonoType *t)
        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:
-                       emit_class_dwarf_info (w, klass, FALSE);
                        tdie = g_hash_table_lookup (w->class_to_reference_die, klass);
                        //tdie = ".LDIE_OBJECT";
                        break;
@@ -1004,33 +1066,88 @@ emit_type (MonoDwarfWriter *w, MonoType *t)
                        break;
                case MONO_TYPE_VALUETYPE:
                        if (klass->enumtype)
-                               tdie = emit_class_dwarf_info (w, klass, FALSE);
+                               tdie = get_class_die (w, klass, FALSE);
                        else
                                tdie = ".LDIE_I4";
                        break;
                case MONO_TYPE_GENERICINST:
                        if (!MONO_TYPE_ISSTRUCT (t)) {
-                               emit_class_dwarf_info (w, klass, FALSE);
                                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;
                }
        }
 
+       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:
+               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 = emit_type (w, t);
+       tdie = get_type_die (w, t);
 
        emit_symbol_diff (w, tdie, ".Ldebug_info_start", 0);
 }
@@ -1203,6 +1320,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 +1399,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 +1413,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 +1472,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 +1521,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 +1618,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,10 +1646,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;
 
@@ -1534,7 +1658,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;
 
@@ -1549,9 +1672,9 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
 
                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_type (w, header->locals [i]);
        }
@@ -1629,7 +1752,7 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
        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];
@@ -1637,6 +1760,7 @@ 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 */
                vmv = find_vmv (cfg, ins);
@@ -1649,11 +1773,16 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
 
                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);
@@ -1678,8 +1807,8 @@ 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);
@@ -1700,6 +1829,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