From 9c7af7f2ce58d37976ea45cfbd94d037a89cfd8d Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Fri, 9 Oct 2009 14:48:04 +0000 Subject: [PATCH] 2009-10-09 Zoltan Varga * image-writer.c: Add support for emitting the image into a memory buffer. * dwarfwriter.c: Add support for sharing one IL file between multiple images. * aot-compiler.c: Add support for registering debug info with GDB using the new JIT debugging interface in GDB 7.0. It can be turned on by setting MONO_XDEBUG to 'gdb'. svn path=/trunk/mono/; revision=143873 --- mono/mini/ChangeLog | 10 +++ mono/mini/aot-compiler.c | 157 +++++++++++++++++++++++++++++++++++---- mono/mini/dwarfwriter.c | 9 ++- mono/mini/dwarfwriter.h | 4 +- mono/mini/image-writer.c | 138 +++++++++++++++++++++++----------- mono/mini/image-writer.h | 2 + mono/mini/mini.c | 3 +- mono/mini/mini.h | 2 +- 8 files changed, 264 insertions(+), 61 deletions(-) diff --git a/mono/mini/ChangeLog b/mono/mini/ChangeLog index 3c774a321c3..074334cf7eb 100644 --- a/mono/mini/ChangeLog +++ b/mono/mini/ChangeLog @@ -1,3 +1,13 @@ +2009-10-09 Zoltan Varga + + * image-writer.c: Add support for emitting the image into a memory buffer. + + * dwarfwriter.c: Add support for sharing one IL file between multiple images. + + * aot-compiler.c: Add support for registering debug info with GDB using the + new JIT debugging interface in GDB 7.0. It can be turned on by setting + MONO_XDEBUG to 'gdb'. + 2009-10-06 Zoltan Varga * aot-compiler.c (add_generic_class): Add an instance of GenericComparer for diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index f6ce0fcfe05..2355fc7f748 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -5415,7 +5415,7 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) acfg->temp_prefix = img_writer_get_temp_label_prefix (acfg->w); if (!acfg->aot_opts.nodebug) - acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, FALSE); + acfg->dwarf = mono_dwarf_writer_create (acfg->w, NULL, 0, FALSE); img_writer_emit_start (acfg->w); @@ -5529,8 +5529,11 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) * into the runtime to emit the shared library, which would cause all kinds of * complications, like threading issues, and the fact that the ELF writer's * emit_writeout () function cannot be called more than once. + * GDB 7.0 and later has a JIT interface. */ +#define USE_GDB_JIT_INTERFACE + /* The recommended gdb macro is: */ /* define xdb @@ -5539,26 +5542,80 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options) end */ +/* + * GDB JIT interface definitions. + * + * http://sources.redhat.com/gdb/onlinedocs/gdb_30.html + */ +typedef enum +{ + JIT_NOACTION = 0, + JIT_REGISTER_FN, + JIT_UNREGISTER_FN +} jit_actions_t; + +struct jit_code_entry +{ + struct jit_code_entry *next_entry; + struct jit_code_entry *prev_entry; + const char *symfile_addr; + uint64_t symfile_size; +}; + +struct jit_descriptor +{ + uint32_t version; + /* This type should be jit_actions_t, but we use uint32_t + to be explicit about the bitwidth. */ + uint32_t action_flag; + struct jit_code_entry *relevant_entry; + struct jit_code_entry *first_entry; +}; + +/* GDB puts a breakpoint in this function. */ +void __attribute__((noinline)) __jit_debug_register_code(void); + +void __attribute__((noinline)) __jit_debug_register_code(void) { }; + +/* Make sure to specify the version statically, because the + debugger may check the version before we can set it. */ +struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; + static MonoDwarfWriter *xdebug_writer; -static FILE *xdebug_fp; +static FILE *xdebug_fp, *il_file; +static gboolean use_gdb_interface, save_symfiles; +static int il_file_line_index; void -mono_xdebug_init (void) +mono_xdebug_init (char *options) { - FILE *il_file; MonoImageWriter *w; + char **args, **ptr; + + args = g_strsplit (options, ",", -1); + for (ptr = args; ptr && *ptr; ptr ++) { + char *arg = *ptr; + + if (!strcmp (arg, "gdb")) + use_gdb_interface = TRUE; + if (!strcmp (arg, "save-symfiles")) + save_symfiles = TRUE; + } + + /* This file will contain the IL code for methods which don't have debug info */ + il_file = fopen ("xdb.il", "w"); + + if (use_gdb_interface) + return; unlink ("xdb.s"); xdebug_fp = fopen ("xdb.s", "w"); - + w = img_writer_create (xdebug_fp, FALSE); img_writer_emit_start (w); - /* This file will contain the IL code for methods which don't have debug info */ - il_file = fopen ("xdb.il", "w"); - - xdebug_writer = mono_dwarf_writer_create (w, il_file, TRUE); + xdebug_writer = mono_dwarf_writer_create (w, il_file, 0, TRUE); /* Emit something so the file has a text segment */ img_writer_emit_section_change (w, ".text", 0); @@ -5577,13 +5634,83 @@ mono_xdebug_init (void) void mono_save_xdebug_info (MonoCompile *cfg) { - if (!xdebug_writer) - return; + if (use_gdb_interface) { + MonoImageWriter *w; + MonoDwarfWriter *dw; + guint8 *img; + guint32 img_size; + struct jit_code_entry *entry; - mono_loader_lock (); - mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ())); - fflush (xdebug_fp); - mono_loader_unlock (); + w = img_writer_create (NULL, TRUE); + + img_writer_emit_start (w); + + /* This file will contain the IL code for methods which don't have debug info */ + if (!il_file) + il_file = fopen ("xdb.il", "w"); + + mono_loader_lock (); + + dw = mono_dwarf_writer_create (w, il_file, il_file_line_index, FALSE); + + /* Emit something so the file has a text segment */ + img_writer_emit_section_change (w, ".text", 0); + img_writer_emit_string (w, ""); + + mono_dwarf_writer_emit_base_info (dw, arch_get_cie_program ()); + mono_dwarf_writer_emit_method (dw, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ())); + il_file_line_index = mono_dwarf_writer_get_il_file_line_index (dw); + mono_dwarf_writer_close (dw); + + img_writer_emit_writeout (w); + + img = img_writer_get_output (w, &img_size); + + img_writer_destroy (w); + + if (save_symfiles) { + /* Save the symbol files to help debugging */ + FILE *fp; + char *file_name; + static int file_counter; + + file_counter ++; + file_name = g_strdup_printf ("xdb-%d.o", file_counter); + printf ("%s -> %s\n", mono_method_full_name (cfg->method, TRUE), file_name); + + fp = fopen (file_name, "w"); + fwrite (img, img_size, 1, fp); + fclose (fp); + g_free (file_name); + } + + /* Register the image with GDB */ + + entry = g_malloc (sizeof (struct jit_code_entry)); + + entry->symfile_addr = (const char*)img; + entry->symfile_size = img_size; + + entry->next_entry = __jit_debug_descriptor.first_entry; + if (__jit_debug_descriptor.first_entry) + __jit_debug_descriptor.first_entry->prev_entry = entry; + __jit_debug_descriptor.first_entry = entry; + + __jit_debug_descriptor.relevant_entry = entry; + __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; + + __jit_debug_register_code (); + + mono_loader_unlock (); + } else { + if (!xdebug_writer) + return; + + mono_loader_lock (); + mono_dwarf_writer_emit_method (xdebug_writer, cfg, cfg->jit_info->method, NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, mono_debug_find_method (cfg->jit_info->method, mono_domain_get ())); + fflush (xdebug_fp); + mono_loader_unlock (); + } } /* diff --git a/mono/mini/dwarfwriter.c b/mono/mini/dwarfwriter.c index 66bed76adfc..e3de95a697d 100644 --- a/mono/mini/dwarfwriter.c +++ b/mono/mini/dwarfwriter.c @@ -57,7 +57,7 @@ struct _MonoDwarfWriter * debug information. */ MonoDwarfWriter* -mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, gboolean appending) +mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_start_line, gboolean appending) { MonoDwarfWriter *w = g_new0 (MonoDwarfWriter, 1); @@ -72,6 +72,7 @@ mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, gboolean appen w->w = writer; w->il_file = il_file; + w->il_file_line_index = il_file_start_line; w->appending = appending; if (appending) @@ -89,6 +90,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 diff --git a/mono/mini/dwarfwriter.h b/mono/mini/dwarfwriter.h index 319cc38acc6..a6b30ec2513 100644 --- a/mono/mini/dwarfwriter.h +++ b/mono/mini/dwarfwriter.h @@ -20,7 +20,7 @@ typedef struct _MonoDwarfWriter MonoDwarfWriter; -MonoDwarfWriter* mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, gboolean appending) MONO_INTERNAL; +MonoDwarfWriter* mono_dwarf_writer_create (MonoImageWriter *writer, FILE *il_file, int il_file_start_line, gboolean appending) MONO_INTERNAL; void mono_dwarf_writer_destroy (MonoDwarfWriter *w) MONO_INTERNAL; @@ -28,6 +28,8 @@ void mono_dwarf_writer_emit_base_info (MonoDwarfWriter *w, GSList *base_unwind_p void mono_dwarf_writer_close (MonoDwarfWriter *w) MONO_INTERNAL; +int mono_dwarf_writer_get_il_file_line_index (MonoDwarfWriter *w) MONO_INTERNAL; + void mono_dwarf_writer_emit_trampoline (MonoDwarfWriter *w, const char *tramp_name, char *start_symbol, char *end_symbol, guint8 *code, guint32 code_size, GSList *unwind_info) MONO_INTERNAL; void diff --git a/mono/mini/image-writer.c b/mono/mini/image-writer.c index 9fcbd03b6f3..5b294676e6a 100644 --- a/mono/mini/image-writer.c +++ b/mono/mini/image-writer.c @@ -152,6 +152,8 @@ struct _MonoImageWriter { BinReloc *relocations; GHashTable *labels; int num_relocs; + guint8 *out_buf; + int out_buf_size, out_buf_pos; #endif /* Asm writer */ char *tmpfname; @@ -990,6 +992,29 @@ resolve_relocations (MonoImageWriter *acfg) #endif /* USE_ELF_RELA */ +static void +bin_writer_fwrite (MonoImageWriter *acfg, void *val, size_t size, size_t nmemb) +{ + if (acfg->fp) + fwrite (val, size, nmemb, acfg->fp); + else { + g_assert (acfg->out_buf_pos + (size * nmemb) <= acfg->out_buf_size); + memcpy (acfg->out_buf + acfg->out_buf_pos, val, size * nmemb); + acfg->out_buf_pos += (size * nmemb); + } +} + +static void +bin_writer_fseek (MonoImageWriter *acfg, int offset) +{ + if (acfg->fp) + fseek (acfg->fp, offset, SEEK_SET); + else + acfg->out_buf_pos = offset; +} + +static int normal_sections [] = { SECT_DATA, SECT_DEBUG_FRAME, SECT_DEBUG_INFO, SECT_DEBUG_ABBREV, SECT_DEBUG_LINE, SECT_DEBUG_LOC }; + static int bin_writer_emit_writeout (MonoImageWriter *acfg) { @@ -1324,63 +1349,58 @@ bin_writer_emit_writeout (MonoImageWriter *acfg) reloc_symbols (acfg, symtab, secth, &str_table, FALSE); relocs = resolve_relocations (acfg); - fwrite (&header, sizeof (header), 1, file); - fwrite (&progh, sizeof (progh), 1, file); - fwrite (hash, sizeof (int) * (hash [0] + hash [1] + 2), 1, file); - fwrite (dynsym, sizeof (ElfSymbol) * hash [1], 1, file); - fwrite (dyn_str_table.data->str, dyn_str_table.data->len, 1, file); + if (!acfg->fp) { + acfg->out_buf_size = file_offset + sizeof (secth); + acfg->out_buf = g_malloc (acfg->out_buf_size); + } + + bin_writer_fwrite (acfg, &header, sizeof (header), 1); + bin_writer_fwrite (acfg, &progh, sizeof (progh), 1); + bin_writer_fwrite (acfg, hash, sizeof (int) * (hash [0] + hash [1] + 2), 1); + bin_writer_fwrite (acfg, dynsym, sizeof (ElfSymbol) * hash [1], 1); + bin_writer_fwrite (acfg, dyn_str_table.data->str, dyn_str_table.data->len, 1); /* .rel.dyn */ - fseek (file, secth [SECT_REL_DYN].sh_offset, SEEK_SET); - fwrite (relocs, sizeof (ElfReloc), acfg->num_relocs, file); + bin_writer_fseek (acfg, secth [SECT_REL_DYN].sh_offset); + bin_writer_fwrite (acfg, relocs, sizeof (ElfReloc), acfg->num_relocs); /* .rela.dyn */ - fseek (file, secth [SECT_RELA_DYN].sh_offset, SEEK_SET); - fwrite (relocs, secth [SECT_RELA_DYN].sh_size, 1, file); + bin_writer_fseek (acfg, secth [SECT_RELA_DYN].sh_offset); + bin_writer_fwrite (acfg, relocs, secth [SECT_RELA_DYN].sh_size, 1); /* .text */ if (sections [SECT_TEXT]) { - fseek (file, secth [SECT_TEXT].sh_offset, SEEK_SET); - fwrite (sections [SECT_TEXT]->data, sections [SECT_TEXT]->cur_offset, 1, file); + bin_writer_fseek (acfg, secth [SECT_TEXT].sh_offset); + bin_writer_fwrite (acfg, sections [SECT_TEXT]->data, sections [SECT_TEXT]->cur_offset, 1); } /* .dynamic */ - fwrite (dynamic, sizeof (dynamic), 1, file); + bin_writer_fwrite (acfg, dynamic, sizeof (dynamic), 1); /* .got.plt */ size = secth [SECT_DYNAMIC].sh_addr; - fwrite (&size, sizeof (size), 1, file); - - /* .data */ - if (sections [SECT_DATA]) { - fseek (file, secth [SECT_DATA].sh_offset, SEEK_SET); - fwrite (sections [SECT_DATA]->data, sections [SECT_DATA]->cur_offset, 1, file); + bin_writer_fwrite (acfg, &size, sizeof (size), 1); + + /* normal sections */ + for (i = 0; i < sizeof (normal_sections) / sizeof (normal_sections [0]); ++i) { + int sect = normal_sections [i]; + if (sections [sect]) { + bin_writer_fseek (acfg, secth [sect].sh_offset); + bin_writer_fwrite (acfg, sections [sect]->data, sections [sect]->cur_offset, 1); + } } - fseek (file, secth [SECT_DEBUG_FRAME].sh_offset, SEEK_SET); - if (sections [SECT_DEBUG_FRAME]) - fwrite (sections [SECT_DEBUG_FRAME]->data, sections [SECT_DEBUG_FRAME]->cur_offset, 1, file); - fseek (file, secth [SECT_DEBUG_INFO].sh_offset, SEEK_SET); - if (sections [SECT_DEBUG_INFO]) - fwrite (sections [SECT_DEBUG_INFO]->data, sections [SECT_DEBUG_INFO]->cur_offset, 1, file); - fseek (file, secth [SECT_DEBUG_ABBREV].sh_offset, SEEK_SET); - if (sections [SECT_DEBUG_ABBREV]) - fwrite (sections [SECT_DEBUG_ABBREV]->data, sections [SECT_DEBUG_ABBREV]->cur_offset, 1, file); - fseek (file, secth [SECT_DEBUG_LINE].sh_offset, SEEK_SET); - if (sections [SECT_DEBUG_LINE]) - fwrite (sections [SECT_DEBUG_LINE]->data, sections [SECT_DEBUG_LINE]->cur_offset, 1, file); - fseek (file, secth [SECT_DEBUG_LINE].sh_offset, SEEK_SET); - if (sections [SECT_DEBUG_LOC]) - fwrite (sections [SECT_DEBUG_LOC]->data, sections [SECT_DEBUG_LOC]->cur_offset, 1, file); - fseek (file, secth [SECT_SHSTRTAB].sh_offset, SEEK_SET); - fwrite (sh_str_table.data->str, sh_str_table.data->len, 1, file); - fseek (file, secth [SECT_SYMTAB].sh_offset, SEEK_SET); - fwrite (symtab, sizeof (ElfSymbol) * num_local_syms, 1, file); - fseek (file, secth [SECT_STRTAB].sh_offset, SEEK_SET); - fwrite (str_table.data->str, str_table.data->len, 1, file); + bin_writer_fseek (acfg, secth [SECT_SHSTRTAB].sh_offset); + bin_writer_fwrite (acfg, sh_str_table.data->str, sh_str_table.data->len, 1); + bin_writer_fseek (acfg, secth [SECT_SYMTAB].sh_offset); + bin_writer_fwrite (acfg, symtab, sizeof (ElfSymbol) * num_local_syms, 1); + bin_writer_fseek (acfg, secth [SECT_STRTAB].sh_offset); + bin_writer_fwrite (acfg, str_table.data->str, str_table.data->len, 1); /*g_print ("file_offset %d vs %d\n", file_offset, ftell (file));*/ /*g_assert (file_offset >= ftell (file));*/ - fseek (file, file_offset, SEEK_SET); - fwrite (§h, sizeof (secth), 1, file); - fclose (file); + bin_writer_fseek (acfg, file_offset); + bin_writer_fwrite (acfg, §h, sizeof (secth), 1); + + if (acfg->fp) + fclose (acfg->fp); return 0; } @@ -1957,6 +1977,30 @@ img_writer_emit_unset_mode (MonoImageWriter *acfg) asm_writer_emit_unset_mode (acfg); } +/* + * img_writer_get_output: + * + * Return the output buffer of a binary writer emitting to memory. The returned memory + * is from malloc, and it is owned by the caller. + */ +guint8* +img_writer_get_output (MonoImageWriter *acfg, guint32 *size) +{ +#ifdef USE_BIN_WRITER + guint8 *buf; + + g_assert (acfg->use_bin_writer); + + buf = acfg->out_buf; + *size = acfg->out_buf_size; + acfg->out_buf = NULL; + return buf; +#else + g_assert_not_reached (); + return NULL; +#endif +} + /* * Return whenever the binary writer is supported on this platform. */ @@ -1970,6 +2014,13 @@ bin_writer_supported (void) #endif } +/* + * img_writer_create: + * + * Create an image writer writing to FP. If USE_BIN_WRITER is TRUE, FP can be NULL, + * in this case the image writer will write to a memory buffer obtainable by calling + * img_writer_get_output (). + */ MonoImageWriter* img_writer_create (FILE *fp, gboolean use_bin_writer) { @@ -1979,6 +2030,9 @@ img_writer_create (FILE *fp, gboolean use_bin_writer) g_assert (!use_bin_writer); #endif + if (!use_bin_writer) + g_assert (fp); + w->fp = fp; w->use_bin_writer = use_bin_writer; w->mempool = mono_mempool_new (); diff --git a/mono/mini/image-writer.h b/mono/mini/image-writer.h index 01a2d1853dd..1b12ac4c2d6 100644 --- a/mono/mini/image-writer.h +++ b/mono/mini/image-writer.h @@ -36,6 +36,8 @@ void img_writer_emit_start (MonoImageWriter *w) MONO_INTERNAL; int img_writer_emit_writeout (MonoImageWriter *w) MONO_INTERNAL; +guint8* img_writer_get_output (MonoImageWriter *acfg, guint32 *size) MONO_INTERNAL; + void img_writer_emit_section_change (MonoImageWriter *w, const char *section_name, int subsection_index) MONO_INTERNAL; void img_writer_emit_push_section (MonoImageWriter *w, const char *section_name, int subsection) MONO_INTERNAL; diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 4bf6f6ce471..7773f9ac57a 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -4981,7 +4981,8 @@ mini_init (const char *filename, const char *runtime_version) mini_gc_init (); if (getenv ("MONO_XDEBUG")) { - mono_xdebug_init (); + char *xdebug_opts = getenv ("MONO_XDEBUG"); + mono_xdebug_init (xdebug_opts); /* So methods for multiple domains don't have the same address */ mono_dont_free_domains = TRUE; mono_using_xdebug = TRUE; diff --git a/mono/mini/mini.h b/mono/mini/mini.h index e32eb1a3fe4..99d20a14e26 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -1436,7 +1436,7 @@ void mono_aot_register_globals (gpointer *globals); /* This too */ void mono_aot_register_module (gpointer *aot_info); -void mono_xdebug_init (void) MONO_INTERNAL; +void mono_xdebug_init (char *xdebug_opts) MONO_INTERNAL; void mono_save_xdebug_info (MonoCompile *cfg) MONO_INTERNAL; void mono_save_trampoline_xdebug_info (const char *tramp_name, guint8 *code, guint32 code_size, GSList *unwind_info) MONO_INTERNAL; /* This is an exported function */ -- 2.25.1