2009-04-11 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / dwarfwriter.c
index 198f4ed41a0b8c65b8b99c4626955eb527572c3d..91afa785c9fe60f24eacea5dad7aa0be75afca21 100644 (file)
@@ -32,6 +32,7 @@ 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;
        FILE *il_file;
@@ -363,7 +364,9 @@ emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbo
 #define ABBREV_VARIABLE 11
 #define ABBREV_VARIABLE_LOCLIST 12
 #define ABBREV_POINTER_TYPE 13
-#define ABBREV_PARAM_LOCLIST 14
+#define ABBREV_REFERENCE_TYPE 14
+#define ABBREV_PARAM_LOCLIST 15
+#define ABBREV_INHERITANCE 16
 
 static int compile_unit_attr [] = {
        DW_AT_producer     ,DW_FORM_string,
@@ -420,6 +423,10 @@ 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,
@@ -446,6 +453,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;
@@ -652,6 +664,10 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
                                           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_byte (w, 0);
 
        emit_section_change (w, ".debug_info", 0);
@@ -701,12 +717,14 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra
        emit_cie (w);
 }
 
+static const char* emit_type (MonoDwarfWriter *w, MonoType *t);
+
 /* Returns the local symbol pointing to the emitted debug info */
 static char*
 emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
 {
-       char *die, *pointer_die;
-       char *full_name;
+       char *die, *pointer_die, *reference_die;
+       char *full_name, *p;
        gpointer iter;
        MonoClassField *field;
        const char *fdie;
@@ -721,6 +739,8 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
                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;
@@ -731,7 +751,7 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
        if (die)
                return die;
 
-       if (!((klass->byval_arg.type == MONO_TYPE_CLASS) || 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->enumtype || (klass->byval_arg.type == MONO_TYPE_VALUETYPE && vtype)))
                return NULL;
 
        /*
@@ -747,13 +767,28 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
        }
 
        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);
@@ -812,25 +847,49 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
                        }
                }
        } else {
+               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);
+               }
+
+               emit_label (w, die);
+
                emit_uleb128 (w, ABBREV_STRUCT_TYPE);
                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 = emit_type (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);
@@ -857,23 +916,24 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype)
        emit_symbol_diff (w, die, ".Ldebug_info_start", 0);
 
        /* Add a pointer type */
-       pointer_die = g_strdup_printf (".LTDIE_%d_POINTER", w->tdie_index);
        emit_label (w, pointer_die);
 
        emit_uleb128 (w, ABBREV_POINTER_TYPE);
        emit_symbol_diff (w, die, ".Ldebug_info_start", 0);
 
-       g_hash_table_insert (w->class_to_pointer_die, klass, pointer_die);
+       /* 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);
-       w->tdie_index ++;
 
        if (emit_namespace) {
                /* Namespace end */
                emit_uleb128 (w, 0x0);
        }
 
-       g_hash_table_insert (cache, klass, die);
        return die;
 }
 
@@ -890,6 +950,10 @@ emit_type (MonoDwarfWriter *w, MonoType *t)
                        if (tdie)
                                return g_hash_table_lookup (w->class_to_pointer_die, klass);
                }
+               else {
+                       tdie = emit_class_dwarf_info (w, klass, FALSE);
+                       /* Should return a pointer type to a reference */
+               }
                // FIXME:
                t = &mono_defaults.int_class->byval_arg;
        }
@@ -901,6 +965,10 @@ emit_type (MonoDwarfWriter *w, MonoType *t)
        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;
                case MONO_TYPE_ARRAY:
                        tdie = ".LDIE_OBJECT";
                        break;
@@ -1427,7 +1495,10 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
                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];
                }
@@ -1478,7 +1549,7 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
                        if (method->klass->valuetype)
                                t = &method->klass->this_arg;
                        else
-                               t = &mono_defaults.object_class->byval_arg;
+                               t = &method->klass->byval_arg;
                        pname = "this";
                } else {
                        t = sig->params [i - sig->hasthis];
@@ -1526,7 +1597,6 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
                /* ins->dreg no longer contains the original vreg */
                vmv = find_vmv (cfg, ins);
                if (code && vmv) {
-                       vmv = MONO_VARINFO (cfg, j);
                        if (vmv->live_range_start) {
                                /* This variable has a precise live range */
                                need_loclist = TRUE;
@@ -1573,8 +1643,10 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod
        emit_line (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)