2011-01-31 Paul Pluzhnikov <ppluzhnikov@google.com>

* breakpoint.h (remove_jit_event_breakpoints): New prototype.
	* breakpoint.c (remove_jit_event_breakpoints): New function.
	* jit.c (jit_descriptor_addr): Delete.
	(registering_code): Delete.
	(clear_int): Delete.
	(jit_inferior_data): New variable.
	(struct jit_inferior_data): New type.
	(get_jit_inferior_data): New function.
	(jit_inferior_data_cleanup): New function.
	(jit_read_descriptor): Adjust.
	(jit_register_code): Adjust.
	(jit_breakpoint_re_set_internal): New function; move code here ...
	(jit_inferior_init): ... from here.
	(jit_breakpoint_re_set): Adjust.
	(jit_reset_inferior_data_and_breakpoints): New function.
	(jit_inferior_created_observer): Adjust.
	(jit_inferior_exit_hook): Adjust.
	(jit_executable_changed_observer): New function.
	(jit_event_handler): Adjust.
	(_initialize_jit): Adjust.
This commit is contained in:
Paul Pluzhnikov
2011-01-31 21:37:01 +00:00
parent e839132de9
commit 03673fc718
3 changed files with 141 additions and 73 deletions

View File

@ -5958,6 +5958,19 @@ create_jit_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
return b;
}
/* Remove JIT code registration and unregistration breakpoint(s). */
void
remove_jit_event_breakpoints (void)
{
struct breakpoint *b, *b_tmp;
ALL_BREAKPOINTS_SAFE (b, b_tmp)
if (b->type == bp_jit_event
&& b->loc->pspace == current_program_space)
delete_breakpoint (b);
}
void
remove_solib_event_breakpoints (void)
{

View File

@ -1083,6 +1083,8 @@ extern struct breakpoint *create_solib_event_breakpoint (struct gdbarch *,
extern struct breakpoint *create_thread_event_breakpoint (struct gdbarch *,
CORE_ADDR);
extern void remove_jit_event_breakpoints (void);
extern void remove_solib_event_breakpoints (void);
extern void remove_thread_event_breakpoints (void);

193
gdb/jit.c
View File

@ -24,6 +24,7 @@
#include "command.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "inferior.h"
#include "observer.h"
#include "objfiles.h"
#include "symfile.h"
@ -37,18 +38,7 @@ static const char *const jit_break_name = "__jit_debug_register_code";
static const char *const jit_descriptor_name = "__jit_debug_descriptor";
/* This is the address of the JIT descriptor in the inferior. */
static CORE_ADDR jit_descriptor_addr = 0;
/* This is a boolean indicating whether we're currently registering code. This
is used to avoid re-entering the registration code. We want to check for
new JITed every time a new object file is loaded, but we want to avoid
checking for new code while we're registering object files for JITed code.
Therefore, we flip this variable to 1 before registering new object files,
and set it to 0 before returning. */
static int registering_code = 0;
static const struct inferior_data *jit_inferior_data = NULL;
/* Non-zero if we want to see trace of jit level stuff. */
@ -61,14 +51,6 @@ show_jit_debug (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("JIT debugging is %s.\n"), value);
}
/* Helper cleanup function to clear an integer flag like the one above. */
static void
clear_int (void *int_addr)
{
*((int *) int_addr) = 0;
}
struct target_buffer
{
CORE_ADDR base;
@ -146,12 +128,47 @@ bfd_open_from_target_memory (CORE_ADDR addr, ULONGEST size, char *target)
mem_bfd_iovec_stat);
}
/* Per-inferior structure recording the addresses in the inferior. */
struct jit_inferior_data
{
CORE_ADDR breakpoint_addr; /* &__jit_debug_register_code() */
CORE_ADDR descriptor_addr; /* &__jit_debug_descriptor */
};
/* Return jit_inferior_data for current inferior. Allocate if not already
present. */
static struct jit_inferior_data *
get_jit_inferior_data (void)
{
struct inferior *inf;
struct jit_inferior_data *inf_data;
inf = current_inferior ();
inf_data = inferior_data (inf, jit_inferior_data);
if (inf_data == NULL)
{
inf_data = XZALLOC (struct jit_inferior_data);
set_inferior_data (inf, jit_inferior_data, inf_data);
}
return inf_data;
}
static void
jit_inferior_data_cleanup (struct inferior *inf, void *arg)
{
xfree (arg);
}
/* Helper function for reading the global JIT descriptor from remote
memory. */
static void
jit_read_descriptor (struct gdbarch *gdbarch,
struct jit_descriptor *descriptor)
struct jit_descriptor *descriptor,
CORE_ADDR descriptor_addr)
{
int err;
struct type *ptr_type;
@ -167,7 +184,7 @@ jit_read_descriptor (struct gdbarch *gdbarch,
desc_buf = alloca (desc_size);
/* Read the descriptor. */
err = target_read_memory (jit_descriptor_addr, desc_buf, desc_size);
err = target_read_memory (descriptor_addr, desc_buf, desc_size);
if (err)
error (_("Unable to read JIT descriptor from remote memory!"));
@ -278,17 +295,9 @@ JITed symbol file is not an object file, ignoring it.\n"));
++i;
}
/* Raise this flag while we register code so we won't trigger any
re-registration. */
registering_code = 1;
my_cleanups = make_cleanup (clear_int, &registering_code);
/* This call takes ownership of sai. */
objfile = symbol_file_add_from_bfd (nbfd, 0, sai, OBJF_SHARED);
/* Clear the registering_code flag. */
do_cleanups (my_cleanups);
/* Remember a mapping from entry_addr to objfile. */
entry_addr_ptr = xmalloc (sizeof (CORE_ADDR));
*entry_addr_ptr = entry_addr;
@ -323,68 +332,86 @@ jit_find_objf_with_entry_addr (CORE_ADDR entry_addr)
return NULL;
}
/* (Re-)Initialize the jit breakpoint handler, and register any already
created translations. */
/* (Re-)Initialize the jit breakpoint if necessary.
Return 0 on success. */
static int
jit_breakpoint_re_set_internal (struct gdbarch *gdbarch,
struct jit_inferior_data *inf_data)
{
if (inf_data->breakpoint_addr == 0)
{
struct minimal_symbol *reg_symbol;
/* Lookup the registration symbol. If it is missing, then we assume
we are not attached to a JIT. */
reg_symbol = lookup_minimal_symbol (jit_break_name, NULL, NULL);
if (reg_symbol == NULL)
return 1;
inf_data->breakpoint_addr = SYMBOL_VALUE_ADDRESS (reg_symbol);
if (inf_data->breakpoint_addr == 0)
return 2;
}
else
return 0;
if (jit_debug)
fprintf_unfiltered (gdb_stdlog,
"jit_breakpoint_re_set_internal, "
"breakpoint_addr = %s\n",
paddress (gdbarch, inf_data->breakpoint_addr));
/* Put a breakpoint in the registration symbol. */
create_jit_event_breakpoint (gdbarch, inf_data->breakpoint_addr);
return 0;
}
/* Register any already created translations. */
static void
jit_inferior_init (struct gdbarch *gdbarch)
{
struct minimal_symbol *reg_symbol;
struct minimal_symbol *desc_symbol;
CORE_ADDR reg_addr;
struct jit_descriptor descriptor;
struct jit_code_entry cur_entry;
struct jit_inferior_data *inf_data;
CORE_ADDR cur_entry_addr;
if (jit_debug)
fprintf_unfiltered (gdb_stdlog,
"jit_inferior_init, registering_code = %d\n",
registering_code);
fprintf_unfiltered (gdb_stdlog, "jit_inferior_init\n");
/* When we register code, GDB resets its breakpoints in case symbols have
changed. That in turn calls this handler, which makes us look for new
code again. To avoid being re-entered, we check this flag. */
if (registering_code)
inf_data = get_jit_inferior_data ();
if (jit_breakpoint_re_set_internal (gdbarch, inf_data) != 0)
return;
/* Lookup the registration symbol. If it is missing, then we assume we are
not attached to a JIT. */
reg_symbol = lookup_minimal_symbol (jit_break_name, NULL, NULL);
if (reg_symbol == NULL)
return;
reg_addr = SYMBOL_VALUE_ADDRESS (reg_symbol);
if (reg_addr == 0)
return;
if (inf_data->descriptor_addr == 0)
{
struct minimal_symbol *desc_symbol;
if (jit_debug)
fprintf_unfiltered (gdb_stdlog, "jit_inferior_init, reg_addr = %s\n",
paddress (gdbarch, reg_addr));
/* Lookup the descriptor symbol and cache the addr. If it is missing, we
assume we are not attached to a JIT and return early. */
/* Lookup the descriptor symbol and cache the addr. If it is
missing, we assume we are not attached to a JIT and return early. */
desc_symbol = lookup_minimal_symbol (jit_descriptor_name, NULL, NULL);
if (desc_symbol == NULL)
return;
jit_descriptor_addr = SYMBOL_VALUE_ADDRESS (desc_symbol);
if (jit_descriptor_addr == 0)
inf_data->descriptor_addr = SYMBOL_VALUE_ADDRESS (desc_symbol);
if (inf_data->descriptor_addr == 0)
return;
}
if (jit_debug)
fprintf_unfiltered (gdb_stdlog,
"jit_inferior_init, jit_descriptor_addr = %s\n",
paddress (gdbarch, jit_descriptor_addr));
"jit_inferior_init, descriptor_addr = %s\n",
paddress (gdbarch, inf_data->descriptor_addr));
/* Read the descriptor so we can check the version number and load
any already JITed functions. */
jit_read_descriptor (gdbarch, &descriptor);
jit_read_descriptor (gdbarch, &descriptor, inf_data->descriptor_addr);
/* Check that the version number agrees with that we support. */
if (descriptor.version != 1)
error (_("Unsupported JIT protocol version in descriptor!"));
/* Put a breakpoint in the registration symbol. */
create_jit_event_breakpoint (gdbarch, reg_addr);
/* If we've attached to a running program, we need to check the descriptor
to register any functions that were already generated. */
for (cur_entry_addr = descriptor.first_entry;
@ -416,6 +443,26 @@ jit_inferior_created_hook (void)
void
jit_breakpoint_re_set (void)
{
jit_breakpoint_re_set_internal (target_gdbarch,
get_jit_inferior_data ());
}
/* Reset inferior_data, so sybols will be looked up again, and jit_breakpoint
will be reset. */
static void
jit_reset_inferior_data_and_breakpoints (void)
{
struct jit_inferior_data *inf_data;
/* Force jit_inferior_init to re-lookup of jit symbol addresses. */
inf_data = get_jit_inferior_data ();
inf_data->breakpoint_addr = 0;
inf_data->descriptor_addr = 0;
/* Remove any existing JIT breakpoint(s). */
remove_jit_event_breakpoints ();
jit_inferior_init (target_gdbarch);
}
@ -424,7 +471,7 @@ jit_breakpoint_re_set (void)
static void
jit_inferior_created_observer (struct target_ops *objfile, int from_tty)
{
jit_inferior_init (target_gdbarch);
jit_reset_inferior_data_and_breakpoints ();
}
/* This function cleans up any code entries left over when the
@ -437,15 +484,17 @@ jit_inferior_exit_hook (struct inferior *inf)
struct objfile *objf;
struct objfile *temp;
/* We need to reset the descriptor addr so that next time we load up the
inferior we look for it again. */
jit_descriptor_addr = 0;
ALL_OBJFILES_SAFE (objf, temp)
if (objfile_data (objf, jit_objfile_data) != NULL)
jit_unregister_code (objf);
}
static void
jit_executable_changed_observer (void)
{
jit_reset_inferior_data_and_breakpoints ();
}
void
jit_event_handler (struct gdbarch *gdbarch)
{
@ -455,7 +504,8 @@ jit_event_handler (struct gdbarch *gdbarch)
struct objfile *objf;
/* Read the descriptor from remote memory. */
jit_read_descriptor (gdbarch, &descriptor);
jit_read_descriptor (gdbarch, &descriptor,
get_jit_inferior_data ()->descriptor_addr);
entry_addr = descriptor.relevant_entry;
/* Do the corresponding action. */
@ -500,5 +550,8 @@ _initialize_jit (void)
observer_attach_inferior_created (jit_inferior_created_observer);
observer_attach_inferior_exit (jit_inferior_exit_hook);
observer_attach_executable_changed (jit_executable_changed_observer);
jit_objfile_data = register_objfile_data ();
jit_inferior_data =
register_inferior_data_with_cleanup (jit_inferior_data_cleanup);
}