*/
#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
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_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_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);
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 */
- /* 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 */
MonoClassField *field;
const char *fdie;
int k;
- gboolean emit_namespace = FALSE;
+ gboolean emit_namespace = FALSE, has_children;
GHashTable *cache;
// FIXME: Appdomains
if (die)
return die;
- 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)))
+ 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;
/*
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);
}
/* 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);
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;
default:
tdie = ".LDIE_I4";
break;
}
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;
GArray *ln_array;
int *native_to_il_offset = NULL;
- if (!code)
- // FIXME: The set_address op below only works with xdebug
+ if (!w->emit_line)
return;
minfo = mono_debug_lookup_method (method);
/* Compute the native->IL offset mapping */
+ g_assert (code_size);
+
#ifndef _EGLIB_MAJOR
ln_array = g_array_sized_new (FALSE, FALSE, sizeof (MonoDebugLineNumberEntry),
debug_info->num_line_numbers);
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
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;
emit_line (w);
+ emit_debug_info_end (w);
+
/* Emit unwind info */
if (unwind_info) {
emit_fde (w, w->fde_index, start_symbol, end_symbol, code, code_size, unwind_info, TRUE);
}
/* Emit line number info */
- if (code && debug_info)
- /* != could happen when using --regression */
- if (debug_info->code_start == code)
- 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);
}
/* 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) */