#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
GSList *cie_program;
FILE *fp;
const char *temp_prefix;
- gboolean emit_line;
+ gboolean emit_line, appending;
};
/*
* 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;
}
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
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 */
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);
}
#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,
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
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,
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);
}
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*
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
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;
/*
g_assert_not_reached ();
}
}
+
+ has_children = TRUE;
} else {
guint8 buf [128];
guint8 *p;
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);
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);
}
/* 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);
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;
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:
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;
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);
}
token_handler_ip = NULL;
*endip = ip;
+ mono_metadata_free_mh (header);
return dis;
}
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);
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;
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;
}
first = FALSE;
- g_free (loc);
+
+ mono_debug_symfile_free_location (loc);
}
}
+ g_free (native_to_il_offset);
g_free (prev_file_name);
if (!first) {
fflush (w->il_file);
g_free (il_to_line);
}
+ mono_metadata_free_mh (header);
}
static MonoMethodVar*
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;
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;
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]);
}
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];
int j;
MonoMethodVar *vmv = NULL;
gboolean need_loclist = FALSE;
+ char *lname;
/* ins->dreg no longer contains the original vreg */
vmv = find_vmv (cfg, ins);
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);
}
}
- 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_number_info (w, method, start_symbol, end_symbol, code, code_size, debug_info);
emit_line (w);
+ mono_metadata_free_mh (header);
}
void