X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fdwarfwriter.c;h=470ac5a1b3de710ede75a25e9fb8d70db925d8cd;hb=17183a6fbf75a5ca960d7541676aea7fd7b09d21;hp=635fe8a471ec8c1dfcafb74d89f3f090e14f7b32;hpb=186ca2bc95fd89fcece607b78ed73d418a341b24;p=mono.git diff --git a/mono/mini/dwarfwriter.c b/mono/mini/dwarfwriter.c index 635fe8a471e..c8acff20d24 100644 --- a/mono/mini/dwarfwriter.c +++ b/mono/mini/dwarfwriter.c @@ -8,6 +8,8 @@ */ #include "config.h" + +#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT) #include "dwarfwriter.h" #include @@ -21,38 +23,100 @@ #include #include -#ifndef PLATFORM_WIN32 +#ifndef HOST_WIN32 #include #include #endif #include +typedef struct { + MonoMethod *method; + char *start_symbol, *end_symbol; + guint8 *code; + guint32 code_size; +} MethodLineNumberInfo; + struct _MonoDwarfWriter { MonoImageWriter *w; - GHashTable *class_to_die; + 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, collect_line_info; + GSList *line_info; + int cur_file_index; }; +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: * * 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, gboolean emit_line_numbers) { 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->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; + } + + 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); + + 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); + w->cur_file_index = -1; return w; } @@ -63,6 +127,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 @@ -272,7 +342,8 @@ emit_cie (MonoDwarfWriter *w) emit_alignment (w, 8); /* Emit a CIE */ - emit_symbol_diff (w, ".Lcie0_end", ".", -4); /* length */ + emit_symbol_diff (w, ".Lcie0_end", ".Lcie0_start", 0); /* length */ + emit_label (w, ".Lcie0_start"); emit_int32 (w, 0xffffffff); /* CIE id */ emit_byte (w, 3); /* version */ emit_string (w, ""); /* augmention */ @@ -303,15 +374,18 @@ static void emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbol, guint8 *code, guint32 code_size, GSList *unwind_ops, gboolean use_cie) { - char symbol [128]; + char symbol1 [128]; + char symbol2 [128]; GSList *l; guint8 *uw_info; guint32 uw_info_len; emit_section_change (w, ".debug_frame", 0); - sprintf (symbol, ".Lfde%d_end", fde_index); - emit_symbol_diff (w, symbol, ".", -4); /* length */ + sprintf (symbol1, ".Lfde%d_start", fde_index); + sprintf (symbol2, ".Lfde%d_end", fde_index); + emit_symbol_diff (w, symbol2, symbol1, 0); /* length */ + emit_label (w, symbol1); emit_int32 (w, 0); /* CIE_pointer */ if (start_symbol) { emit_pointer (w, start_symbol); /* initial_location */ @@ -336,7 +410,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 */ @@ -344,9 +419,8 @@ 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)); - sprintf (symbol, ".Lfde%d_end", fde_index); - emit_label (w, symbol); + emit_alignment (w, sizeof (mgreg_t)); + emit_label (w, symbol2); } /* Abbrevations */ @@ -362,6 +436,12 @@ emit_fde (MonoDwarfWriter *w, int fde_index, char *start_symbol, char *end_symbo #define ABBREV_NAMESPACE 10 #define ABBREV_VARIABLE 11 #define ABBREV_VARIABLE_LOCLIST 12 +#define ABBREV_POINTER_TYPE 13 +#define ABBREV_REFERENCE_TYPE 14 +#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, @@ -375,17 +455,32 @@ 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, DW_AT_location, DW_FORM_block1 }; +static int param_loclist_attr [] = { + DW_AT_name, DW_FORM_string, + DW_AT_type, DW_FORM_ref4, + DW_AT_location, DW_FORM_data4 +}; + static int base_type_attr [] = { DW_AT_byte_size, DW_FORM_data1, DW_AT_encoding, DW_FORM_data1, @@ -408,6 +503,14 @@ static int typedef_attr [] = { DW_AT_type, DW_FORM_ref4 }; +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, @@ -434,6 +537,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; @@ -532,17 +640,44 @@ emit_line_number_file_name (MonoDwarfWriter *w, const char *name, return index; } -static void -emit_line_number_info_begin (MonoDwarfWriter *w) +static int +get_line_number_file_name (MonoDwarfWriter *w, const char *name) { - if (!w->il_file) { - /* FIXME: This doesn't seem to work with !xdebug */ - emit_section_change (w, ".debug_line", 0); - emit_label (w, ".Ldebug_line_start"); - emit_label (w, ".Ldebug_line_section_start"); - return; + 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) +{ /* Line number info header */ /* * GAS seems to emit its own data to the end of the first subsection, so we use @@ -603,8 +738,185 @@ 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, "", 0, 0); + + /* Collect files */ + 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; + 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, mono_dwarf_escape_path (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, mono_dwarf_escape_path (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 = info_list; l; l = l->next) { + MethodLineNumberInfo *info = l->data; + MonoDebugMethodJitInfo *dmji; + + 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); + 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 + * define it every time something gets added to the .debug_info section. + * The apple assember seems to use the last definition. + */ +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 -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; @@ -618,10 +930,14 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra subprogram_attr, G_N_ELEMENTS (subprogram_attr)); emit_dwarf_abbrev (w, ABBREV_PARAM, DW_TAG_formal_parameter, FALSE, param_attr, G_N_ELEMENTS (param_attr)); + emit_dwarf_abbrev (w, ABBREV_PARAM_LOCLIST, DW_TAG_formal_parameter, FALSE, + param_loclist_attr, G_N_ELEMENTS (param_loclist_attr)); emit_dwarf_abbrev (w, ABBREV_BASE_TYPE, DW_TAG_base_type, FALSE, 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, @@ -636,20 +952,31 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra variable_attr, G_N_ELEMENTS (variable_attr)); emit_dwarf_abbrev (w, ABBREV_VARIABLE_LOCLIST, DW_TAG_variable, FALSE, 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_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); 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 */ - /* 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_label (w, ".Ldebug_info_end"); - emit_section_change (w, ".debug_info", 0); + 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_byte (w, 0); /* close COMPILE_UNIT */ + emit_label (w, ".Ldebug_info_end"); + emit_section_change (w, ".debug_info", 0); + } /* Compilation unit */ emit_uleb128 (w, ABBREV_COMPILE_UNIT); @@ -658,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) { @@ -675,37 +1005,73 @@ mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_progra emit_string (w, basic_types [i].name); } + emit_debug_info_end (w); + /* debug_loc section */ emit_section_change (w, ".debug_loc", 0); emit_label (w, ".Ldebug_loc_start"); - /* 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"); + } + + if (w->collect_line_info) + emit_all_line_number_info (w); +} + +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* -emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass) +emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass, gboolean vtype) { - char *die; - char *full_name; + char *die, *pointer_die, *reference_die; + char *full_name, *p; gpointer iter; 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 (vtype) + cache = w->class_to_vtype_die; + else + cache = w->class_to_die; - die = g_hash_table_lookup (w->class_to_die, klass); + die = g_hash_table_lookup (cache, klass); if (die) return die; - if (!((klass->byval_arg.type == MONO_TYPE_CLASS) || klass->enumtype)) + 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; /* @@ -721,13 +1087,28 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass) } 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); @@ -785,33 +1166,65 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass) g_assert_not_reached (); } } + + has_children = TRUE; } else { - emit_uleb128 (w, ABBREV_STRUCT_TYPE); + 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); + } + + iter = NULL; + has_children = parent_die || mono_class_get_fields (klass, &iter); + + emit_label (w, die); + + emit_uleb128 (w, has_children ? ABBREV_STRUCT_TYPE : ABBREV_STRUCT_TYPE_NOCHILDREN); 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 = get_type_die (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); /* location */ p = buf; *p ++= DW_OP_plus_uconst; - encode_uleb128 (field->offset, p, &p); + if (klass->valuetype && vtype) + encode_uleb128 (field->offset - sizeof (MonoObject), p, &p); + else + encode_uleb128 (field->offset, p, &p); emit_byte (w, p - buf); emit_bytes (w, buf, p - buf); @@ -820,58 +1233,155 @@ emit_class_dwarf_info (MonoDwarfWriter *w, MonoClass *klass) } /* 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); emit_string (w, full_name); emit_symbol_diff (w, die, ".Ldebug_info_start", 0); - g_free (full_name); - w->tdie_index ++; + /* Add a pointer type */ + emit_label (w, pointer_die); + emit_uleb128 (w, ABBREV_POINTER_TYPE); + emit_symbol_diff (w, die, ".Ldebug_info_start", 0); + + /* 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); if (emit_namespace) { /* Namespace end */ emit_uleb128 (w, 0x0); } - g_hash_table_insert (w->class_to_die, klass, die); return die; } -static void -emit_var_type (MonoDwarfWriter *w, MonoType *t) +static gboolean base_types_emitted [64]; + +static const char* +get_type_die (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 = g_hash_table_lookup (w->class_to_pointer_die, klass); + } + else { + tdie = get_class_die (w, klass, FALSE); + /* Should return a pointer type to a reference */ + } + // 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)) + if (j < G_N_ELEMENTS (basic_types)) { tdie = basic_types [j].die_name; - else { + } else { switch (t->type) { case MONO_TYPE_CLASS: + tdie = g_hash_table_lookup (w->class_to_reference_die, klass); + //tdie = ".LDIE_OBJECT"; + break; case MONO_TYPE_ARRAY: tdie = ".LDIE_OBJECT"; break; case MONO_TYPE_VALUETYPE: if (klass->enumtype) - tdie = emit_class_dwarf_info (w, klass); + tdie = get_class_die (w, klass, FALSE); else tdie = ".LDIE_I4"; break; + case MONO_TYPE_GENERICINST: + if (!MONO_TYPE_ISSTRUCT (t)) { + 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; } } - if (t->byref) + + 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: - tdie = ".LDIE_I4"; + 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 = get_type_die (w, t); + emit_symbol_diff (w, tdie, ".Ldebug_info_start", 0); } @@ -932,6 +1442,7 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token) char *res, *desc; MonoMethod *cmethod; MonoClass *klass; + MonoClassField *field; gpointer data = NULL; if (method->wrapper_type) @@ -939,6 +1450,7 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token) switch (*token_handler_ip) { case CEE_ISINST: + case CEE_CASTCLASS: case CEE_LDELEMA: if (method->wrapper_type) klass = data; @@ -966,6 +1478,18 @@ token_handler (MonoDisHelper *dh, MonoMethod *method, guint32 token) res = g_strdup_printf ("<0x%08x>", token); } break; + case CEE_LDFLD: + case CEE_LDSFLD: + case CEE_STFLD: + case CEE_STSFLD: + if (method->wrapper_type) + field = data; + else + field = mono_field_from_token (method->klass->image, token, &klass, NULL); + desc = mono_field_full_name (field); + res = g_strdup_printf ("<%s>", desc); + g_free (desc); + break; default: res = g_strdup_printf ("<0x%08x>", token); break; @@ -1029,10 +1553,10 @@ disasm_ins (MonoMethod *method, const guchar *ip, const guint8 **endip) token_handler_ip = NULL; *endip = ip; + mono_metadata_free_mh (header); return dis; } -/* static gint32 il_offset_from_address (MonoMethod *method, MonoDebugMethodJitInfo *jit, guint32 native_offset) @@ -1051,7 +1575,6 @@ il_offset_from_address (MonoMethod *method, MonoDebugMethodJitInfo *jit, return -1; } -*/ static int max_special_addr_diff = 0; @@ -1078,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); @@ -1096,8 +1620,10 @@ compare_lne (MonoDebugLineNumberEntry *a, MonoDebugLineNumberEntry *b) } static void -emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code, - guint32 code_size, MonoDebugMethodJitInfo *debug_info) +emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, + char *start_symbol, char *end_symbol, + guint8 *code, guint32 code_size, + MonoDebugMethodJitInfo *debug_info) { guint32 prev_line = 0; guint32 prev_native_offset = 0; @@ -1107,59 +1633,70 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code, char *prev_file_name = NULL; MonoMethodHeader *header = mono_method_get_header (method); MonoDebugMethodInfo *minfo; - GArray *ln_array; - int *native_to_il_offset; - - if (!code) - // FIXME: The set_address op below only works with xdebug + MonoDebugLineNumberEntry *ln_array; + int *native_to_il_offset = NULL; + + if (!w->emit_line) { + mono_metadata_free_mh (header); return; + } minfo = mono_debug_lookup_method (method); /* Compute the native->IL offset mapping */ - 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); + g_assert (code_size); + + 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); + g_free (ln_array); prev_line = 1; prev_il_offset = -1; for (i = 0; i < code_size; ++i) { + int line_diff, addr_diff; + if (!minfo) continue; if (!debug_info->line_numbers) continue; + if (native_to_il_offset) + il_offset = native_to_il_offset [i]; + else + il_offset = il_offset_from_address (method, debug_info, i); /* il_offset = il_offset_from_address (method, debug_info, i); g_assert (il_offset == native_to_il_offset [i]); */ + il_offset = native_to_il_offset [i]; if (il_offset < 0) continue; @@ -1170,54 +1707,64 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code, prev_il_offset = il_offset; loc = mono_debug_symfile_lookup_location (minfo, il_offset); + if (!(loc && loc->source_file)) + continue; - if (loc) { - int line_diff = (gint32)loc->row - (gint32)prev_line; - int addr_diff = i - prev_native_offset; + 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 (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); + 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); - emit_sleb128 (w, (gint32)loc->row - (gint32)prev_line); - prev_line = loc->row; - } + /* + * 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 (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); + 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; - g_free (loc); + prev_line = loc->row; + prev_native_offset = i; } + + mono_debug_symfile_free_location (loc); } + g_free (native_to_il_offset); g_free (prev_file_name); if (!first) { @@ -1228,7 +1775,7 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code, emit_byte (w, 0); emit_byte (w, 1); emit_byte (w, DW_LNE_end_sequence); - } else if (code) { + } else if (!start_symbol) { /* No debug info, XDEBUG mode */ char *name, *dis; const guint8 *ip = header->code; @@ -1278,10 +1825,16 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code, continue; line = il_to_line [lne->il_offset]; if (!line) { - /* To help debugging */ + /* + * This seems to happen randomly, it looks like il_offset points + * into the middle of an instruction. + */ + continue; + /* printf ("%s\n", mono_method_full_name (method, TRUE)); printf ("%d %d\n", lne->il_offset, header->code_size); g_assert (line); + */ } if (line - prev_line != 0) { @@ -1303,6 +1856,26 @@ emit_line_number_info (MonoDwarfWriter *w, MonoMethod *method, guint8 *code, fflush (w->il_file); g_free (il_to_line); } + mono_metadata_free_mh (header); +} + +static MonoMethodVar* +find_vmv (MonoCompile *cfg, MonoInst *ins) +{ + int j; + + if (cfg->varinfo) { + for (j = 0; j < cfg->num_varinfo; ++j) { + if (cfg->varinfo [j] == ins) + break; + } + + if (j < cfg->num_varinfo) { + return MONO_VARINFO (cfg, j); + } + } + + return NULL; } void @@ -1311,10 +1884,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; @@ -1324,23 +1896,25 @@ 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; 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]; } - emit_class_dwarf_info (w, mono_class_from_mono_type (t)); + 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_class_dwarf_info (w, mono_class_from_mono_type (header->locals [i])); + emit_type (w, header->locals [i]); } /* Subprogram */ @@ -1350,6 +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); @@ -1369,16 +1946,25 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod MonoType *t; const char *pname; char pname_buf [128]; + MonoMethodVar *vmv = NULL; + gboolean need_loclist = FALSE; + + vmv = find_vmv (cfg, arg); + if (code && vmv && (vmv->live_range_start || vmv->live_range_end)) + need_loclist = TRUE; if (i == 0 && sig->hasthis) { - t = &mono_defaults.object_class->byval_arg; + if (method->klass->valuetype) + t = &method->klass->this_arg; + else + t = &method->klass->byval_arg; pname = "this"; } else { t = sig->params [i - sig->hasthis]; pname = names [i - sig->hasthis]; } - - emit_uleb128 (w, ABBREV_PARAM); + + emit_uleb128 (w, need_loclist ? ABBREV_PARAM_LOCLIST : ABBREV_PARAM); /* name */ if (pname[0] == '\0') { sprintf (pname_buf, "param%d", i - sig->hasthis); @@ -1393,13 +1979,21 @@ mono_dwarf_writer_emit_method (MonoDwarfWriter *w, MonoCompile *cfg, MonoMethod p = buf; encode_var_location (w, arg, p, &p); - emit_byte (w, p - buf); - emit_bytes (w, buf, p - buf); + if (need_loclist) { + vmv->live_range_start = 0; + if (vmv->live_range_end == 0) + /* FIXME: Uses made in calls are not recorded */ + vmv->live_range_end = code_size; + emit_loclist (w, arg, code + vmv->live_range_start, code + vmv->live_range_end, buf, p - buf); + } else { + emit_byte (w, p - buf); + emit_bytes (w, buf, p - buf); + } } 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]; @@ -1407,33 +2001,29 @@ 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 */ - if (cfg->varinfo) { - for (j = 0; j < cfg->num_varinfo; ++j) { - if (cfg->varinfo [j] == ins) - break; - } - - if (code && j < cfg->num_varinfo) { - vmv = MONO_VARINFO (cfg, j); - if (vmv->live_range_start) { - /* This variable has a precise live range */ - need_loclist = TRUE; - } + vmv = find_vmv (cfg, ins); + if (code && vmv) { + if (vmv->live_range_start) { + /* This variable has a precise live range */ + need_loclist = TRUE; } } - if (need_loclist) - emit_uleb128 (w, ABBREV_VARIABLE_LOCLIST); - else - emit_uleb128 (w, ABBREV_VARIABLE); + 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); @@ -1458,23 +2048,43 @@ 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); emit_line (w); + emit_debug_info_end (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) - emit_line_number_info (w, method, code, code_size, debug_info); + /* != could happen when using --regression */ + 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; + 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); } void @@ -1483,19 +2093,18 @@ 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); + emit_debug_info_end (w); + /* Emit unwind info */ emit_fde (w, w->fde_index, start_symbol, end_symbol, code, code_size, unwind_info, FALSE); w->fde_index ++; } +#endif /* End of: !defined(DISABLE_AOT) && !defined(DISABLE_JIT) */