#include <mono/utils/freebsd-dwarf.h>
+typedef struct {
+ MonoMethod *method;
+ char *start_symbol, *end_symbol;
+ guint8 *code;
+ guint32 code_size;
+ MonoDebugMethodJitInfo *debug_info;
+} MethodLineNumberInfo;
+
struct _MonoDwarfWriter
{
MonoImageWriter *w;
GHashTable *class_to_die, *class_to_vtype_die, *class_to_pointer_die;
GHashTable *class_to_reference_die;
int fde_index, tdie_index, line_number_file_index, line_number_dir_index;
- GHashTable *file_to_index, *dir_to_index;
+ 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;
+ gboolean emit_line, appending, collect_line_info;
+ GSList *line_info;
};
+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:
*
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;
+ }
+
w->fp = img_writer_get_fp (w->w);
w->temp_prefix = img_writer_get_temp_label_prefix (w->w);
static int subprogram_attr [] = {
DW_AT_name , DW_FORM_string,
+ DW_AT_description , DW_FORM_string,
DW_AT_low_pc , DW_FORM_addr,
DW_AT_high_pc , DW_FORM_addr,
DW_AT_frame_base , DW_FORM_block1
return index;
}
+static int
+get_line_number_file_name (MonoDwarfWriter *w, const char *name)
+{
+ 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)
{
emit_label (w, ".Ldebug_line_end");
}
+static void
+emit_all_line_number_info (MonoDwarfWriter *w)
+{
+ int i;
+ GHashTable *dir_to_index, *index_to_dir;
+ GSList *l;
+
+ g_assert (w->collect_line_info);
+
+ add_line_number_file_name (w, "xdb.il", 0, 0);
+
+ /* Collect files */
+ // FIXME: Revert list
+ for (l = w->line_info; 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, 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, 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 = w->line_info; l; l = l->next) {
+ MethodLineNumberInfo *info = l->data;
+
+ emit_line_number_info (w, info->method, info->start_symbol, info->end_symbol, info->code, info->code_size, info->debug_info);
+ }
+
+ 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
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);
* 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);
+ if (!w->collect_line_info)
+ emit_line_number_info_begin (w);
emit_cie (w);
}
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);
prev_il_offset = il_offset;
loc = mono_debug_symfile_lookup_location (minfo, il_offset);
-
- // 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;
if (!prev_file_name || strcmp (loc->source_file, prev_file_name) != 0) {
/* Add an entry to the file table */
/* FIXME: Avoid duplicates */
- file_index = emit_line_number_file_name (w, loc->source_file, 0, 0);
+ 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);
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);
emit_uleb128 (w, ABBREV_SUBPROGRAM);
name = mono_method_full_name (method, FALSE);
emit_string (w, name);
+ emit_string (w, name);
g_free (name);
if (start_symbol) {
emit_pointer_unaligned (w, start_symbol);
/* Emit line number 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);
+ 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;
+ info->debug_info = debug_info;
+ 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);