/* Handle JIT code generation in the inferior for GDB, the GNU Debugger.
- Copyright (C) 2009-2020 Free Software Foundation, Inc.
+ Copyright (C) 2009-2022 Free Software Foundation, Inc.
This file is part of GDB.
static const char jit_descriptor_name[] = "__jit_debug_descriptor";
-static void jit_inferior_init (struct gdbarch *gdbarch);
+static void jit_inferior_created_hook (inferior *inf);
static void jit_inferior_exit_hook (struct inferior *inf);
/* An unwinder is registered for every gdbarch. This key is used to
static struct gdbarch_data *jit_gdbarch_data;
-/* Non-zero if we want to see trace of jit level stuff. */
+/* True if we want to see trace of jit level stuff. */
-static unsigned int jit_debug = 0;
+static bool jit_debug = false;
+
+/* Print a "jit" debug statement. */
+
+#define jit_debug_printf(fmt, ...) \
+ debug_prefixed_printf_cond (jit_debug, "jit", fmt, ##__VA_ARGS__)
static void
show_jit_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("JIT debugging is %s.\n"), value);
-}
-
-struct target_buffer
-{
- CORE_ADDR base;
- ULONGEST size;
-};
-
-/* Opening the file is a no-op. */
-
-static void *
-mem_bfd_iovec_open (struct bfd *abfd, void *open_closure)
-{
- return open_closure;
-}
-
-/* Closing the file is just freeing the base/size pair on our side. */
-
-static int
-mem_bfd_iovec_close (struct bfd *abfd, void *stream)
-{
- xfree (stream);
-
- /* Zero means success. */
- return 0;
+ gdb_printf (file, _("JIT debugging is %s.\n"), value);
}
-/* For reading the file, we just need to pass through to target_read_memory and
- fix up the arguments and return values. */
+/* Implementation of the "maintenance info jit" command. */
-static file_ptr
-mem_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
- file_ptr nbytes, file_ptr offset)
+static void
+maint_info_jit_cmd (const char *args, int from_tty)
{
- int err;
- struct target_buffer *buffer = (struct target_buffer *) stream;
-
- /* If this read will read all of the file, limit it to just the rest. */
- if (offset + nbytes > buffer->size)
- nbytes = buffer->size - offset;
-
- /* If there are no more bytes left, we've reached EOF. */
- if (nbytes == 0)
- return 0;
-
- err = target_read_memory (buffer->base + offset, (gdb_byte *) buf, nbytes);
- if (err)
- return -1;
+ inferior *inf = current_inferior ();
+ bool printed_header = false;
- return nbytes;
-}
+ gdb::optional<ui_out_emit_table> table_emitter;
-/* For statting the file, we only support the st_size attribute. */
-
-static int
-mem_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
-{
- struct target_buffer *buffer = (struct target_buffer*) stream;
+ /* Print a line for each JIT-ed objfile. */
+ for (objfile *obj : inf->pspace->objfiles ())
+ {
+ if (obj->jited_data == nullptr)
+ continue;
- memset (sb, 0, sizeof (struct stat));
- sb->st_size = buffer->size;
- return 0;
-}
+ if (!printed_header)
+ {
+ table_emitter.emplace (current_uiout, 3, -1, "jit-created-objfiles");
+
+ /* The +2 allows for the leading '0x', then one character for
+ every 4-bits. */
+ int addr_width = 2 + (gdbarch_ptr_bit (obj->arch ()) / 4);
+
+ /* The std::max here selects between the width of an address (as
+ a string) and the width of the column header string. */
+ current_uiout->table_header (std::max (addr_width, 22), ui_left,
+ "jit_code_entry-address",
+ "jit_code_entry address");
+ current_uiout->table_header (std::max (addr_width, 15), ui_left,
+ "symfile-address", "symfile address");
+ current_uiout->table_header (20, ui_left,
+ "symfile-size", "symfile size");
+ current_uiout->table_body ();
+
+ printed_header = true;
+ }
-/* Open a BFD from the target's memory. */
+ ui_out_emit_tuple tuple_emitter (current_uiout, "jit-objfile");
-static gdb_bfd_ref_ptr
-bfd_open_from_target_memory (CORE_ADDR addr, ULONGEST size,
- const char *target)
-{
- struct target_buffer *buffer = XNEW (struct target_buffer);
-
- buffer->base = addr;
- buffer->size = size;
- return gdb_bfd_openr_iovec ("<in-memory>", target,
- mem_bfd_iovec_open,
- buffer,
- mem_bfd_iovec_pread,
- mem_bfd_iovec_close,
- mem_bfd_iovec_stat);
+ current_uiout->field_core_addr ("jit_code_entry-address", obj->arch (),
+ obj->jited_data->addr);
+ current_uiout->field_core_addr ("symfile-address", obj->arch (),
+ obj->jited_data->symfile_addr);
+ current_uiout->field_unsigned ("symfile-size",
+ obj->jited_data->symfile_size);
+ current_uiout->text ("\n");
+ }
}
struct jit_reader
reader_init_fn_type *init_fn;
struct gdb_reader_funcs *funcs = NULL;
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog, _("Opening shared object %s.\n"),
- file_name);
+ jit_debug_printf ("Opening shared object %s", file_name);
+
gdb_dlhandle_up so = gdb_dlopen (file_name);
init_fn = (reader_init_fn_type *) gdb_dlsym (so, reader_init_fn_sym);
error (_("JIT reader already loaded. Run jit-reader-unload first."));
if (!IS_ABSOLUTE_PATH (file.get ()))
- file.reset (xstrprintf ("%s%s%s", jit_reader_dir.c_str (), SLASH_STRING,
- file.get ()));
+ file = xstrprintf ("%s%s%s", jit_reader_dir.c_str (),
+ SLASH_STRING, file.get ());
loaded_jit_reader = jit_reader_load (file.get ());
reinit_frame_cache ();
- jit_inferior_created_hook ();
+ jit_inferior_created_hook (current_inferior ());
}
/* Provides the jit-reader-unload command. */
at inferior address ENTRY. */
static void
-add_objfile_entry (struct objfile *objfile, CORE_ADDR entry)
+add_objfile_entry (struct objfile *objfile, CORE_ADDR entry,
+ CORE_ADDR symfile_addr, ULONGEST symfile_size)
{
gdb_assert (objfile->jited_data == nullptr);
- objfile->jited_data.reset (new jited_objfile_data (entry));
+ objfile->jited_data.reset (new jited_objfile_data (entry, symfile_addr,
+ symfile_size));
}
/* Helper function for reading the global JIT descriptor from remote
CORE_ADDR addr = MSYMBOL_VALUE_ADDRESS (jiter, objf_data->descriptor);
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog,
- "jit_read_descriptor, descriptor_addr = %s\n",
- paddress (gdbarch, addr));
+ jit_debug_printf ("descriptor_addr = %s", paddress (gdbarch, addr));
/* Figure out how big the descriptor is on the remote and how to read it. */
ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
err = target_read_memory (addr, desc_buf, desc_size);
if (err)
{
- printf_unfiltered (_("Unable to read JIT descriptor from "
- "remote memory\n"));
+ gdb_printf (gdb_stderr, _("Unable to read JIT descriptor from "
+ "remote memory\n"));
return false;
}
/* The type of the `private' data passed around by the callback
functions. */
-typedef CORE_ADDR jit_dbg_reader_data;
+struct jit_dbg_reader_data
+{
+ /* Address of the jit_code_entry in the inferior's address space. */
+ CORE_ADDR entry_addr;
+
+ /* The code entry, copied in our address space. */
+ const jit_code_entry &entry;
+
+ struct gdbarch *gdbarch;
+};
/* The reader calls into this function to read data off the targets
address space. */
});
cust = allocate_compunit_symtab (objfile, stab->file_name.c_str ());
- allocate_symtab (cust, stab->file_name.c_str ());
+ symtab *filetab = allocate_symtab (cust, stab->file_name.c_str ());
add_compunit_symtab_to_objfile (cust);
/* JIT compilers compile in memory. */
- COMPUNIT_DIRNAME (cust) = NULL;
+ cust->set_dirname (nullptr);
/* Copy over the linetable entry if one was provided. */
if (stab->linetable)
size_t size = ((stab->linetable->nitems - 1)
* sizeof (struct linetable_entry)
+ sizeof (struct linetable));
- SYMTAB_LINETABLE (COMPUNIT_FILETABS (cust))
- = (struct linetable *) obstack_alloc (&objfile->objfile_obstack, size);
- memcpy (SYMTAB_LINETABLE (COMPUNIT_FILETABS (cust)),
- stab->linetable.get (), size);
+ filetab->set_linetable ((struct linetable *)
+ obstack_alloc (&objfile->objfile_obstack, size));
+ memcpy (filetab->linetable (), stab->linetable.get (), size);
}
blockvector_size = (sizeof (struct blockvector)
+ (actual_nblocks - 1) * sizeof (struct block *));
bv = (struct blockvector *) obstack_alloc (&objfile->objfile_obstack,
blockvector_size);
- COMPUNIT_BLOCKVECTOR (cust) = bv;
+ cust->set_blockvector (bv);
/* At the end of this function, (begin, end) will contain the PC range this
entire blockvector spans. */
BLOCK_END (new_block) = (CORE_ADDR) gdb_block_iter.end;
/* The name. */
- SYMBOL_DOMAIN (block_name) = VAR_DOMAIN;
- SYMBOL_ACLASS_INDEX (block_name) = LOC_BLOCK;
- symbol_set_symtab (block_name, COMPUNIT_FILETABS (cust));
- SYMBOL_TYPE (block_name) = lookup_function_type (block_type);
+ block_name->set_domain (VAR_DOMAIN);
+ block_name->set_aclass_index (LOC_BLOCK);
+ symbol_set_symtab (block_name, filetab);
+ block_name->set_type (lookup_function_type (block_type));
SYMBOL_BLOCK_VALUE (block_name) = new_block;
block_name->m_name = obstack_strdup (&objfile->objfile_obstack,
jit_object_close_impl (struct gdb_symbol_callbacks *cb,
struct gdb_object *obj)
{
- struct objfile *objfile;
- jit_dbg_reader_data *priv_data;
-
- priv_data = (jit_dbg_reader_data *) cb->priv_data;
+ jit_dbg_reader_data *priv_data = (jit_dbg_reader_data *) cb->priv_data;
+ std::string objfile_name
+ = string_printf ("<< JIT compiled code at %s >>",
+ paddress (priv_data->gdbarch,
+ priv_data->entry.symfile_addr));
- objfile = objfile::make (nullptr, "<< JIT compiled code >>",
- OBJF_NOT_FILENAME);
- objfile->per_bfd->gdbarch = target_gdbarch ();
+ objfile *objfile = objfile::make (nullptr, objfile_name.c_str (),
+ OBJF_NOT_FILENAME);
+ objfile->per_bfd->gdbarch = priv_data->gdbarch;
for (gdb_symtab &symtab : obj->symtabs)
finalize_symtab (&symtab, objfile);
- add_objfile_entry (objfile, *priv_data);
+ add_objfile_entry (objfile, priv_data->entry_addr,
+ priv_data->entry.symfile_addr,
+ priv_data->entry.symfile_size);
delete obj;
}
inferior address space. */
static int
-jit_reader_try_read_symtab (struct jit_code_entry *code_entry,
+jit_reader_try_read_symtab (gdbarch *gdbarch, jit_code_entry *code_entry,
CORE_ADDR entry_addr)
{
int status;
- jit_dbg_reader_data priv_data;
+ jit_dbg_reader_data priv_data
+ {
+ entry_addr,
+ *code_entry,
+ gdbarch
+ };
struct gdb_reader_funcs *funcs;
struct gdb_symbol_callbacks callbacks =
{
&priv_data
};
- priv_data = entry_addr;
-
if (!loaded_jit_reader)
return 0;
status = 0;
}
- if (jit_debug && status == 0)
- fprintf_unfiltered (gdb_stdlog,
- "Could not read symtab using the loaded JIT reader.\n");
+ if (status == 0)
+ jit_debug_printf ("Could not read symtab using the loaded JIT reader.");
+
return status;
}
struct objfile *objfile;
const struct bfd_arch_info *b;
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog,
- "jit_bfd_try_read_symtab, symfile_addr = %s, "
- "symfile_size = %s\n",
- paddress (gdbarch, code_entry->symfile_addr),
- pulongest (code_entry->symfile_size));
+ jit_debug_printf ("symfile_addr = %s, symfile_size = %s",
+ paddress (gdbarch, code_entry->symfile_addr),
+ pulongest (code_entry->symfile_size));
- gdb_bfd_ref_ptr nbfd (bfd_open_from_target_memory (code_entry->symfile_addr,
- code_entry->symfile_size,
- gnutarget));
+ gdb_bfd_ref_ptr nbfd (gdb_bfd_open_from_target_memory
+ (code_entry->symfile_addr, code_entry->symfile_size, gnutarget));
if (nbfd == NULL)
{
- puts_unfiltered (_("Error opening JITed symbol file, ignoring it.\n"));
+ gdb_puts (_("Error opening JITed symbol file, ignoring it.\n"),
+ gdb_stderr);
return;
}
We would segfault later without this line. */
if (!bfd_check_format (nbfd.get (), bfd_object))
{
- printf_unfiltered (_("\
+ gdb_printf (gdb_stderr, _("\
JITed symbol file is not an object file, ignoring it.\n"));
return;
}
&sai,
OBJF_SHARED | OBJF_NOT_FILENAME, NULL);
- add_objfile_entry (objfile, entry_addr);
+ add_objfile_entry (objfile, entry_addr, code_entry->symfile_addr,
+ code_entry->symfile_size);
}
/* This function registers code associated with a JIT code entry. It uses the
{
int success;
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog,
- "jit_register_code, symfile_addr = %s, "
- "symfile_size = %s\n",
- paddress (gdbarch, code_entry->symfile_addr),
- pulongest (code_entry->symfile_size));
+ jit_debug_printf ("symfile_addr = %s, symfile_size = %s",
+ paddress (gdbarch, code_entry->symfile_addr),
+ pulongest (code_entry->symfile_size));
- success = jit_reader_try_read_symtab (code_entry, entry_addr);
+ success = jit_reader_try_read_symtab (gdbarch, code_entry, entry_addr);
if (!success)
jit_bfd_try_read_symtab (code_entry, entry_addr, gdbarch);
if (b->type != bp_jit_event)
return;
- for (bp_location *iter = b->loc; iter != nullptr; iter = iter->next)
+ for (bp_location *iter : b->locations ())
{
for (objfile *objf : iter->pspace->objfiles ())
{
{
for (objfile *the_objfile : pspace->objfiles ())
{
+ /* Skip separate debug objects. */
+ if (the_objfile->separate_debug_objfile_backlink != nullptr)
+ continue;
+
if (the_objfile->skip_jit_symbol_lookup)
continue;
}
jiter_objfile_data *objf_data
- = get_jiter_objfile_data (reg_symbol.objfile);
+ = get_jiter_objfile_data (the_objfile);
objf_data->register_code = reg_symbol.minsym;
objf_data->descriptor = desc_symbol.minsym;
CORE_ADDR addr = MSYMBOL_VALUE_ADDRESS (the_objfile,
objf_data->register_code);
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog,
- "jit_breakpoint_re_set_internal, "
- "breakpoint_addr = %s\n",
- paddress (gdbarch, addr));
+ jit_debug_printf ("breakpoint_addr = %s", paddress (gdbarch, addr));
/* Check if we need to re-create the breakpoint. */
if (objf_data->cached_code_address == addr)
dwarf_regnum);
if (gdb_reg == -1)
{
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog,
- _("Could not recognize DWARF regnum %d"),
- dwarf_regnum);
+ jit_debug_printf ("Could not recognize DWARF regnum %d", dwarf_regnum);
value->free (value);
return;
}
/* Try to coax the provided unwinder to unwind the stack */
if (funcs->unwind (funcs, &callbacks) == GDB_SUCCESS)
{
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog, _("Successfully unwound frame using "
- "JIT reader.\n"));
+ jit_debug_printf ("Successfully unwound frame using JIT reader.");
return 1;
}
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog, _("Could not unwind frame using "
- "JIT reader.\n"));
+
+ jit_debug_printf ("Could not unwind frame using JIT reader.");
jit_dealloc_cache (this_frame, *cache);
*cache = NULL;
static const struct frame_unwind jit_frame_unwind =
{
+ "jit",
NORMAL_FRAME,
default_frame_unwind_stop_reason,
jit_frame_this_id,
/* Register any already created translations. */
static void
-jit_inferior_init (struct gdbarch *gdbarch)
+jit_inferior_init (inferior *inf)
{
struct jit_descriptor descriptor;
struct jit_code_entry cur_entry;
CORE_ADDR cur_entry_addr;
+ struct gdbarch *gdbarch = inf->gdbarch;
+ program_space *pspace = inf->pspace;
- if (jit_debug)
- fprintf_unfiltered (gdb_stdlog, "jit_inferior_init\n");
+ jit_debug_printf ("called");
jit_prepend_unwinder (gdbarch);
- jit_breakpoint_re_set_internal (gdbarch, current_program_space);
+ jit_breakpoint_re_set_internal (gdbarch, pspace);
- for (objfile *jiter : current_program_space->objfiles ())
+ for (objfile *jiter : pspace->objfiles ())
{
if (jiter->jiter_data == nullptr)
continue;
/* Check that the version number agrees with that we support. */
if (descriptor.version != 1)
{
- printf_unfiltered (_("Unsupported JIT protocol version %ld "
- "in descriptor (expected 1)\n"),
- (long) descriptor.version);
+ gdb_printf (gdb_stderr,
+ _("Unsupported JIT protocol version %ld "
+ "in descriptor (expected 1)\n"),
+ (long) descriptor.version);
continue;
}
}
}
-/* inferior_created observer. */
+/* Looks for the descriptor and registration symbols and breakpoints
+ the registration function. If it finds both, it registers all the
+ already JITed code. If it has already found the symbols, then it
+ doesn't try again. */
static void
-jit_inferior_created (inferior *inf)
-{
- jit_inferior_created_hook ();
-}
-
-/* Exported routine to call when an inferior has been created. */
-
-void
-jit_inferior_created_hook (void)
+jit_inferior_created_hook (inferior *inf)
{
- jit_inferior_init (target_gdbarch ());
+ jit_inferior_init (inf);
}
/* Exported routine to call to re-set the jit breakpoints,
{
objfile *jited = jit_find_objf_with_entry_addr (entry_addr);
if (jited == nullptr)
- printf_unfiltered (_("Unable to find JITed code "
- "entry at address: %s\n"),
- paddress (gdbarch, entry_addr));
+ gdb_printf (gdb_stderr,
+ _("Unable to find JITed code "
+ "entry at address: %s\n"),
+ paddress (gdbarch, entry_addr));
else
jited->unlink ();
{
jit_reader_dir = relocate_gdb_directory (JIT_READER_DIR,
JIT_READER_DIR_RELOCATABLE);
- add_setshow_zuinteger_cmd ("jit", class_maintenance, &jit_debug,
- _("Set JIT debugging."),
- _("Show JIT debugging."),
- _("When non-zero, JIT debugging is enabled."),
- NULL,
- show_jit_debug,
- &setdebuglist, &showdebuglist);
-
- gdb::observers::inferior_created.attach (jit_inferior_created);
- gdb::observers::inferior_exit.attach (jit_inferior_exit_hook);
- gdb::observers::breakpoint_deleted.attach (jit_breakpoint_deleted);
+ add_setshow_boolean_cmd ("jit", class_maintenance, &jit_debug,
+ _("Set JIT debugging."),
+ _("Show JIT debugging."),
+ _("When set, JIT debugging is enabled."),
+ NULL,
+ show_jit_debug,
+ &setdebuglist, &showdebuglist);
+
+ add_cmd ("jit", class_maintenance, maint_info_jit_cmd,
+ _("Print information about JIT-ed code objects."),
+ &maintenanceinfolist);
+
+ gdb::observers::inferior_created.attach (jit_inferior_created_hook, "jit");
+ gdb::observers::inferior_execd.attach (jit_inferior_created_hook, "jit");
+ gdb::observers::inferior_exit.attach (jit_inferior_exit_hook, "jit");
+ gdb::observers::breakpoint_deleted.attach (jit_breakpoint_deleted, "jit");
jit_gdbarch_data = gdbarch_data_register_pre_init (jit_gdbarch_data_init);
if (is_dl_available ())