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);
* 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
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);
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 ();
+ }
}
/*
BinReloc *relocations;
GHashTable *labels;
int num_relocs;
+ guint8 *out_buf;
+ int out_buf_size, out_buf_pos;
#endif
/* Asm writer */
char *tmpfname;
#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)
{
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;
}
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.
*/
#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)
{
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 ();