*/
#include "config.h"
+
+#if !defined(DISABLE_AOT) && !defined(DISABLE_JIT)
#include "dwarfwriter.h"
#include <sys/types.h>
#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
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;
FILE *il_file;
int il_file_line_index, loclist_index;
GSList *cie_program;
+ FILE *fp;
+ const char *temp_prefix;
+ 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);
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
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 */
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 */
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 */
#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
static int compile_unit_attr [] = {
DW_AT_producer ,DW_FORM_string,
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,
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,
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;
static void
emit_line_number_info_begin (MonoDwarfWriter *w)
{
- 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;
- }
-
/* Line number info header */
/*
* GAS seems to emit its own data to the end of the first subsection, so we use
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)
{
char *s, *build_info;
int i;
+ if (!img_writer_subsections_supported (w->w))
+ /* Can't emit line number info without subsections */
+ w->emit_line = FALSE;
+ else
+ w->emit_line = TRUE;
+
w->cie_program = base_unwind_program;
emit_section_change (w, ".debug_abbrev", 0);
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,
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_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);
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 */
+ /*
+ * 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 */
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 (!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
+ 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)))
return NULL;
/*
}
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);
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 = 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);
/* 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);
}
/* 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 const char*
+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 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;
+ }
for (j = 0; j < G_N_ELEMENTS (basic_types); ++j)
if (basic_types [j].type == t->type)
break;
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;
case MONO_TYPE_VALUETYPE:
if (klass->enumtype)
- tdie = emit_class_dwarf_info (w, klass);
+ tdie = emit_class_dwarf_info (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;
}
}
- if (t->byref)
- // FIXME:
- tdie = ".LDIE_I4";
+
+ return tdie;
+}
+
+static void
+emit_var_type (MonoDwarfWriter *w, MonoType *t)
+{
+ const char *tdie;
+
+ tdie = emit_type (w, t);
+
emit_symbol_diff (w, tdie, ".Ldebug_info_start", 0);
}
char *res, *desc;
MonoMethod *cmethod;
MonoClass *klass;
+ MonoClassField *field;
gpointer data = NULL;
if (method->wrapper_type)
switch (*token_handler_ip) {
case CEE_ISINST:
+ case CEE_CASTCLASS:
case CEE_LDELEMA:
if (method->wrapper_type)
klass = data;
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;
token_handler_ip = NULL;
*endip = ip;
+ mono_metadata_free_mh (header);
return dis;
}
}
}
+static gint
+compare_lne (MonoDebugLineNumberEntry *a, MonoDebugLineNumberEntry *b)
+{
+ if (a->native_offset == b->native_offset)
+ return a->il_offset - b->il_offset;
+ else
+ return a->native_offset - b->native_offset;
+}
+
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;
char *prev_file_name = NULL;
MonoMethodHeader *header = mono_method_get_header (method);
MonoDebugMethodInfo *minfo;
+ MonoDebugLineNumberEntry *ln_array;
+ int *native_to_il_offset = NULL;
- if (!code)
- // FIXME: The set_address op below only works with xdebug
+ if (!w->emit_line) {
+ mono_metadata_free_mh (header);
return;
+ }
minfo = mono_debug_lookup_method (method);
- /* FIXME: Avoid quadratic behavior */
+ /* Compute the native->IL offset mapping */
+
+ 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 = &ln_array [i];
+
+ if (i == 0) {
+ 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 = &ln_array [i + 1];
+
+ 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;
+ }
+ }
+ g_free (ln_array);
prev_line = 1;
prev_il_offset = -1;
if (!debug_info->line_numbers)
continue;
- /*
- * FIXME: Its hard to optimize this, since the line number info is not
- * sorted by il offset or native offset
- */
+ 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;
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;
emit_byte (w, 0);
emit_byte (w, sizeof (gpointer) + 1);
emit_byte (w, DW_LNE_set_address);
- emit_pointer_value (w, code);
+ 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
}
first = FALSE;
- g_free (loc);
+
+ mono_debug_symfile_free_location (loc);
}
}
+ g_free (native_to_il_offset);
g_free (prev_file_name);
if (!first) {
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;
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) {
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
char *name;
MonoMethodSignature *sig;
MonoMethodHeader *header;
- char **names, **tdies, **local_tdies;
+ char **names;
char **local_names;
int *local_indexes;
int i, num_locals;
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);
}
/* 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 */
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);
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);
gboolean need_loclist = FALSE;
/* 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)
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))
+ emit_line_number_info (w, method, start_symbol, end_symbol, code, code_size, debug_info);
emit_line (w);
+ mono_metadata_free_mh (header);
}
void
/* 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) */