2013-06-04 Gary Benson <gbenson@redhat.com>
* breakpoint.h (handle_solib_event): Moved function declaration to solib.h. * breakpoint.c (handle_solib_event): Moved function to solib.c. (bpstat_stop_status): Pass new argument to handle_solib_event. * solib.h (update_solib_breakpoints): New function declaration. (handle_solib_event): Moved function declaration from breakpoint.h. * solib.c (update_solib_breakpoints): New function. (handle_solib_event): Moved function from breakpoint.c. Updated to call solib_ops->handle_event if not NULL. * solist.h (target_so_ops): New fields "update_breakpoints" and "handle_event". * infrun.c (set_stop_on_solib_events): New function. (_initialize_infrun): Use the above for "set stop-on-solib-events". (handle_inferior_event): Pass new argument to handle_solib_event. * solib-svr4.c (probe.h): New include. (svr4_free_library_list): New forward declaration. (probe_action): New enum. (probe_info): New struct. (probe_info): New static variable. (NUM_PROBES): New definition. (svr4_info): New fields "using_xfer", "probes_table" and "solib_list". (free_probes_table): New function. (free_solib_list): New function. (svr4_pspace_data_cleanup): Free probes table and solib list. (svr4_copy_library_list): New function. (svr4_current_sos_via_xfer_libraries): New parameter "annex". (svr4_read_so_list): New parameter "prev_lm". (svr4_current_sos_direct): Renamed from "svr4_current_sos". (svr4_current_sos): New function. (probe_and_action): New struct. (hash_probe_and_action): New function. (equal_probe_and_action): Likewise. (register_solib_event_probe): Likewise. (solib_event_probe_at): Likewise. (solib_event_probe_action): Likewise. (solist_update_full): Likewise. (solist_update_incremental): Likewise. (disable_probes_interface_cleanup): Likewise. (svr4_handle_solib_event): Likewise. (svr4_update_solib_event_breakpoint): Likewise. (svr4_update_solib_event_breakpoints): Likewise. (svr4_create_solib_event_breakpoints): Likewise. (enable_break): Free probes table before creating breakpoints. Use svr4_create_solib_event_breakpoints to create breakpoints. (svr4_solib_create_inferior_hook): Free the solib list. (_initialize_svr4_solib): Initialise svr4_so_ops.handle_solib_event and svr4_so_ops.update_breakpoints.
This commit is contained in:
parent
ced63ec087
commit
f9e148520a
|
@ -1,3 +1,56 @@
|
|||
2013-06-04 Gary Benson <gbenson@redhat.com>
|
||||
|
||||
* breakpoint.h (handle_solib_event): Moved function declaration
|
||||
to solib.h.
|
||||
* breakpoint.c (handle_solib_event): Moved function to solib.c.
|
||||
(bpstat_stop_status): Pass new argument to handle_solib_event.
|
||||
* solib.h (update_solib_breakpoints): New function declaration.
|
||||
(handle_solib_event): Moved function declaration from
|
||||
breakpoint.h.
|
||||
* solib.c (update_solib_breakpoints): New function.
|
||||
(handle_solib_event): Moved function from breakpoint.c.
|
||||
Updated to call solib_ops->handle_event if not NULL.
|
||||
* solist.h (target_so_ops): New fields "update_breakpoints" and
|
||||
"handle_event".
|
||||
* infrun.c (set_stop_on_solib_events): New function.
|
||||
(_initialize_infrun): Use the above for "set
|
||||
stop-on-solib-events".
|
||||
(handle_inferior_event): Pass new argument to handle_solib_event.
|
||||
* solib-svr4.c (probe.h): New include.
|
||||
(svr4_free_library_list): New forward declaration.
|
||||
(probe_action): New enum.
|
||||
(probe_info): New struct.
|
||||
(probe_info): New static variable.
|
||||
(NUM_PROBES): New definition.
|
||||
(svr4_info): New fields "using_xfer", "probes_table" and
|
||||
"solib_list".
|
||||
(free_probes_table): New function.
|
||||
(free_solib_list): New function.
|
||||
(svr4_pspace_data_cleanup): Free probes table and solib list.
|
||||
(svr4_copy_library_list): New function.
|
||||
(svr4_current_sos_via_xfer_libraries): New parameter "annex".
|
||||
(svr4_read_so_list): New parameter "prev_lm".
|
||||
(svr4_current_sos_direct): Renamed from "svr4_current_sos".
|
||||
(svr4_current_sos): New function.
|
||||
(probe_and_action): New struct.
|
||||
(hash_probe_and_action): New function.
|
||||
(equal_probe_and_action): Likewise.
|
||||
(register_solib_event_probe): Likewise.
|
||||
(solib_event_probe_at): Likewise.
|
||||
(solib_event_probe_action): Likewise.
|
||||
(solist_update_full): Likewise.
|
||||
(solist_update_incremental): Likewise.
|
||||
(disable_probes_interface_cleanup): Likewise.
|
||||
(svr4_handle_solib_event): Likewise.
|
||||
(svr4_update_solib_event_breakpoint): Likewise.
|
||||
(svr4_update_solib_event_breakpoints): Likewise.
|
||||
(svr4_create_solib_event_breakpoints): Likewise.
|
||||
(enable_break): Free probes table before creating breakpoints.
|
||||
Use svr4_create_solib_event_breakpoints to create breakpoints.
|
||||
(svr4_solib_create_inferior_hook): Free the solib list.
|
||||
(_initialize_svr4_solib): Initialise
|
||||
svr4_so_ops.handle_solib_event and svr4_so_ops.update_breakpoints.
|
||||
|
||||
2013-06-04 Gary Benson <gbenson@redhat.com>
|
||||
|
||||
* target.h (target_ops): New field
|
||||
|
|
|
@ -5352,21 +5352,6 @@ handle_jit_event (void)
|
|||
target_terminal_inferior ();
|
||||
}
|
||||
|
||||
/* Handle an solib event by calling solib_add. */
|
||||
|
||||
void
|
||||
handle_solib_event (void)
|
||||
{
|
||||
clear_program_space_solib_cache (current_inferior ()->pspace);
|
||||
|
||||
/* Check for any newly added shared libraries if we're supposed to
|
||||
be adding them automatically. Switch terminal for any messages
|
||||
produced by breakpoint_re_set. */
|
||||
target_terminal_ours_for_output ();
|
||||
solib_add (NULL, 0, ¤t_target, auto_solib_add);
|
||||
target_terminal_inferior ();
|
||||
}
|
||||
|
||||
/* Prepare WHAT final decision for infrun. */
|
||||
|
||||
/* Decide what infrun needs to do with this bpstat. */
|
||||
|
|
|
@ -1554,8 +1554,6 @@ extern int user_breakpoint_p (struct breakpoint *);
|
|||
/* Attempt to determine architecture of location identified by SAL. */
|
||||
extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
|
||||
|
||||
extern void handle_solib_event (void);
|
||||
|
||||
extern void breakpoint_free_objfile (struct objfile *objfile);
|
||||
|
||||
extern char *ep_parse_optional_if_clause (char **arg);
|
||||
|
|
12
gdb/infrun.c
12
gdb/infrun.c
|
@ -370,6 +370,16 @@ static struct symbol *step_start_function;
|
|||
/* Nonzero if we want to give control to the user when we're notified
|
||||
of shared library events by the dynamic linker. */
|
||||
int stop_on_solib_events;
|
||||
|
||||
/* Enable or disable optional shared library event breakpoints
|
||||
as appropriate when the above flag is changed. */
|
||||
|
||||
static void
|
||||
set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
|
||||
{
|
||||
update_solib_breakpoints ();
|
||||
}
|
||||
|
||||
static void
|
||||
show_stop_on_solib_events (struct ui_file *file, int from_tty,
|
||||
struct cmd_list_element *c, const char *value)
|
||||
|
@ -7333,7 +7343,7 @@ Show stopping for shared library events."), _("\
|
|||
If nonzero, gdb will give control to the user when the dynamic linker\n\
|
||||
notifies gdb of shared library events. The most common event of interest\n\
|
||||
to the user would be loading/unloading of a new library."),
|
||||
NULL,
|
||||
set_stop_on_solib_events,
|
||||
show_stop_on_solib_events,
|
||||
&setlist, &showlist);
|
||||
|
||||
|
|
688
gdb/solib-svr4.c
688
gdb/solib-svr4.c
|
@ -46,10 +46,12 @@
|
|||
#include "auxv.h"
|
||||
#include "exceptions.h"
|
||||
#include "gdb_bfd.h"
|
||||
#include "probe.h"
|
||||
|
||||
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
|
||||
static int svr4_have_link_map_offsets (void);
|
||||
static void svr4_relocate_main_executable (void);
|
||||
static void svr4_free_library_list (void *p_list);
|
||||
|
||||
/* Link map info to include in an allocated so_list entry. */
|
||||
|
||||
|
@ -106,6 +108,55 @@ static const char * const main_name_list[] =
|
|||
NULL
|
||||
};
|
||||
|
||||
/* What to do when a probe stop occurs. */
|
||||
|
||||
enum probe_action
|
||||
{
|
||||
/* Something went seriously wrong. Stop using probes and
|
||||
revert to using the older interface. */
|
||||
PROBES_INTERFACE_FAILED,
|
||||
|
||||
/* No action is required. The shared object list is still
|
||||
valid. */
|
||||
DO_NOTHING,
|
||||
|
||||
/* The shared object list should be reloaded entirely. */
|
||||
FULL_RELOAD,
|
||||
|
||||
/* Attempt to incrementally update the shared object list. If
|
||||
the update fails or is not possible, fall back to reloading
|
||||
the list in full. */
|
||||
UPDATE_OR_RELOAD,
|
||||
};
|
||||
|
||||
/* A probe's name and its associated action. */
|
||||
|
||||
struct probe_info
|
||||
{
|
||||
/* The name of the probe. */
|
||||
const char *name;
|
||||
|
||||
/* What to do when a probe stop occurs. */
|
||||
enum probe_action action;
|
||||
};
|
||||
|
||||
/* A list of named probes and their associated actions. If all
|
||||
probes are present in the dynamic linker then the probes-based
|
||||
interface will be used. */
|
||||
|
||||
static const struct probe_info probe_info[] =
|
||||
{
|
||||
{ "init_start", DO_NOTHING },
|
||||
{ "init_complete", FULL_RELOAD },
|
||||
{ "map_start", DO_NOTHING },
|
||||
{ "map_failed", DO_NOTHING },
|
||||
{ "reloc_complete", UPDATE_OR_RELOAD },
|
||||
{ "unmap_start", DO_NOTHING },
|
||||
{ "unmap_complete", FULL_RELOAD },
|
||||
};
|
||||
|
||||
#define NUM_PROBES ARRAY_SIZE (probe_info)
|
||||
|
||||
/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
|
||||
the same shared library. */
|
||||
|
||||
|
@ -313,17 +364,58 @@ struct svr4_info
|
|||
CORE_ADDR interp_text_sect_high;
|
||||
CORE_ADDR interp_plt_sect_low;
|
||||
CORE_ADDR interp_plt_sect_high;
|
||||
|
||||
/* Nonzero if the list of objects was last obtained from the target
|
||||
via qXfer:libraries-svr4:read. */
|
||||
int using_xfer;
|
||||
|
||||
/* Table of struct probe_and_action instances, used by the
|
||||
probes-based interface to map breakpoint addresses to probes
|
||||
and their associated actions. Lookup is performed using
|
||||
probe_and_action->probe->address. */
|
||||
htab_t probes_table;
|
||||
|
||||
/* List of objects loaded into the inferior, used by the probes-
|
||||
based interface. */
|
||||
struct so_list *solib_list;
|
||||
};
|
||||
|
||||
/* Per-program-space data key. */
|
||||
static const struct program_space_data *solib_svr4_pspace_data;
|
||||
|
||||
/* Free the probes table. */
|
||||
|
||||
static void
|
||||
free_probes_table (struct svr4_info *info)
|
||||
{
|
||||
if (info->probes_table == NULL)
|
||||
return;
|
||||
|
||||
htab_delete (info->probes_table);
|
||||
info->probes_table = NULL;
|
||||
}
|
||||
|
||||
/* Free the solib list. */
|
||||
|
||||
static void
|
||||
free_solib_list (struct svr4_info *info)
|
||||
{
|
||||
svr4_free_library_list (&info->solib_list);
|
||||
info->solib_list = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
|
||||
{
|
||||
struct svr4_info *info;
|
||||
|
||||
info = program_space_data (pspace, solib_svr4_pspace_data);
|
||||
if (info == NULL)
|
||||
return;
|
||||
|
||||
free_probes_table (info);
|
||||
free_solib_list (info);
|
||||
|
||||
xfree (info);
|
||||
}
|
||||
|
||||
|
@ -991,6 +1083,34 @@ svr4_free_library_list (void *p_list)
|
|||
}
|
||||
}
|
||||
|
||||
/* Copy library list. */
|
||||
|
||||
static struct so_list *
|
||||
svr4_copy_library_list (struct so_list *src)
|
||||
{
|
||||
struct so_list *dst = NULL;
|
||||
struct so_list **link = &dst;
|
||||
|
||||
while (src != NULL)
|
||||
{
|
||||
struct so_list *new;
|
||||
|
||||
new = xmalloc (sizeof (struct so_list));
|
||||
memcpy (new, src, sizeof (struct so_list));
|
||||
|
||||
new->lm_info = xmalloc (sizeof (struct lm_info));
|
||||
memcpy (new->lm_info, src->lm_info, sizeof (struct lm_info));
|
||||
|
||||
new->next = NULL;
|
||||
*link = new;
|
||||
link = &new->next;
|
||||
|
||||
src = src->next;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBEXPAT
|
||||
|
||||
#include "xml-support.h"
|
||||
|
@ -1106,23 +1226,30 @@ svr4_parse_libraries (const char *document, struct svr4_library_list *list)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Attempt to get so_list from target via qXfer:libraries:read packet.
|
||||
/* Attempt to get so_list from target via qXfer:libraries-svr4:read packet.
|
||||
|
||||
Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
|
||||
case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
|
||||
empty, caller is responsible for freeing all its entries. */
|
||||
empty, caller is responsible for freeing all its entries.
|
||||
|
||||
Note that ANNEX must be NULL if the remote does not explicitly allow
|
||||
qXfer:libraries-svr4:read packets with non-empty annexes. Support for
|
||||
this can be checked using target_augmented_libraries_svr4_read (). */
|
||||
|
||||
static int
|
||||
svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
|
||||
svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
|
||||
const char *annex)
|
||||
{
|
||||
char *svr4_library_document;
|
||||
int result;
|
||||
struct cleanup *back_to;
|
||||
|
||||
gdb_assert (annex == NULL || target_augmented_libraries_svr4_read ());
|
||||
|
||||
/* Fetch the list of shared libraries. */
|
||||
svr4_library_document = target_read_stralloc (¤t_target,
|
||||
TARGET_OBJECT_LIBRARIES_SVR4,
|
||||
NULL);
|
||||
annex);
|
||||
if (svr4_library_document == NULL)
|
||||
return 0;
|
||||
|
||||
|
@ -1136,7 +1263,8 @@ svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
|
|||
#else
|
||||
|
||||
static int
|
||||
svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
|
||||
svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
|
||||
const char *annex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1170,15 +1298,19 @@ svr4_default_sos (void)
|
|||
return new;
|
||||
}
|
||||
|
||||
/* Read the whole inferior libraries chain starting at address LM. Add the
|
||||
entries to the tail referenced by LINK_PTR_PTR. Ignore the first entry if
|
||||
IGNORE_FIRST and set global MAIN_LM_ADDR according to it. */
|
||||
/* Read the whole inferior libraries chain starting at address LM.
|
||||
Expect the first entry in the chain's previous entry to be PREV_LM.
|
||||
Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
|
||||
first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
|
||||
to it. Returns nonzero upon success. If zero is returned the
|
||||
entries stored to LINK_PTR_PTR are still valid although they may
|
||||
represent only part of the inferior library list. */
|
||||
|
||||
static void
|
||||
svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
|
||||
int ignore_first)
|
||||
static int
|
||||
svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
|
||||
struct so_list ***link_ptr_ptr, int ignore_first)
|
||||
{
|
||||
CORE_ADDR prev_lm = 0, next_lm;
|
||||
CORE_ADDR next_lm;
|
||||
|
||||
for (; lm != 0; prev_lm = lm, lm = next_lm)
|
||||
{
|
||||
|
@ -1194,7 +1326,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
|
|||
if (new->lm_info == NULL)
|
||||
{
|
||||
do_cleanups (old_chain);
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
next_lm = new->lm_info->l_next;
|
||||
|
@ -1205,7 +1337,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
|
|||
paddress (target_gdbarch (), prev_lm),
|
||||
paddress (target_gdbarch (), new->lm_info->l_prev));
|
||||
do_cleanups (old_chain);
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For SVR4 versions, the first entry in the link map is for the
|
||||
|
@ -1251,17 +1383,21 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
|
|||
**link_ptr_ptr = new;
|
||||
*link_ptr_ptr = &new->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Implement the "current_sos" target_so_ops method. */
|
||||
/* Read the full list of currently loaded shared objects directly
|
||||
from the inferior, without referring to any libraries read and
|
||||
stored by the probes interface. Handle special cases relating
|
||||
to the first elements of the list. */
|
||||
|
||||
static struct so_list *
|
||||
svr4_current_sos (void)
|
||||
svr4_current_sos_direct (struct svr4_info *info)
|
||||
{
|
||||
CORE_ADDR lm;
|
||||
struct so_list *head = NULL;
|
||||
struct so_list **link_ptr = &head;
|
||||
struct svr4_info *info;
|
||||
struct cleanup *back_to;
|
||||
int ignore_first;
|
||||
struct svr4_library_list library_list;
|
||||
|
@ -1274,19 +1410,16 @@ svr4_current_sos (void)
|
|||
Unfortunately statically linked inferiors will also fall back through this
|
||||
suboptimal code path. */
|
||||
|
||||
if (svr4_current_sos_via_xfer_libraries (&library_list))
|
||||
info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
|
||||
NULL);
|
||||
if (info->using_xfer)
|
||||
{
|
||||
if (library_list.main_lm)
|
||||
{
|
||||
info = get_svr4_info ();
|
||||
info->main_lm_addr = library_list.main_lm;
|
||||
}
|
||||
info->main_lm_addr = library_list.main_lm;
|
||||
|
||||
return library_list.head ? library_list.head : svr4_default_sos ();
|
||||
}
|
||||
|
||||
info = get_svr4_info ();
|
||||
|
||||
/* Always locate the debug struct, in case it has moved. */
|
||||
info->debug_base = 0;
|
||||
locate_base (info);
|
||||
|
@ -1309,7 +1442,7 @@ svr4_current_sos (void)
|
|||
`struct so_list' nodes. */
|
||||
lm = solib_svr4_r_map (info);
|
||||
if (lm)
|
||||
svr4_read_so_list (lm, &link_ptr, ignore_first);
|
||||
svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
|
||||
|
||||
/* On Solaris, the dynamic linker is not in the normal list of
|
||||
shared objects, so make sure we pick it up too. Having
|
||||
|
@ -1317,7 +1450,7 @@ svr4_current_sos (void)
|
|||
for skipping dynamic linker resolver code. */
|
||||
lm = solib_svr4_r_ldsomap (info);
|
||||
if (lm)
|
||||
svr4_read_so_list (lm, &link_ptr, 0);
|
||||
svr4_read_so_list (lm, 0, &link_ptr, 0);
|
||||
|
||||
discard_cleanups (back_to);
|
||||
|
||||
|
@ -1327,6 +1460,22 @@ svr4_current_sos (void)
|
|||
return head;
|
||||
}
|
||||
|
||||
/* Implement the "current_sos" target_so_ops method. */
|
||||
|
||||
static struct so_list *
|
||||
svr4_current_sos (void)
|
||||
{
|
||||
struct svr4_info *info = get_svr4_info ();
|
||||
|
||||
/* If the solib list has been read and stored by the probes
|
||||
interface then we return a copy of the stored list. */
|
||||
if (info->solib_list != NULL)
|
||||
return svr4_copy_library_list (info->solib_list);
|
||||
|
||||
/* Otherwise obtain the solib list directly from the inferior. */
|
||||
return svr4_current_sos_direct (info);
|
||||
}
|
||||
|
||||
/* Get the address of the link_map for a given OBJFILE. */
|
||||
|
||||
CORE_ADDR
|
||||
|
@ -1409,6 +1558,476 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
|
|||
return gdbarch_addr_bits_remove (target_gdbarch (), addr);
|
||||
}
|
||||
|
||||
/* A probe and its associated action. */
|
||||
|
||||
struct probe_and_action
|
||||
{
|
||||
/* The probe. */
|
||||
struct probe *probe;
|
||||
|
||||
/* The action. */
|
||||
enum probe_action action;
|
||||
};
|
||||
|
||||
/* Returns a hash code for the probe_and_action referenced by p. */
|
||||
|
||||
static hashval_t
|
||||
hash_probe_and_action (const void *p)
|
||||
{
|
||||
const struct probe_and_action *pa = p;
|
||||
|
||||
return (hashval_t) pa->probe->address;
|
||||
}
|
||||
|
||||
/* Returns non-zero if the probe_and_actions referenced by p1 and p2
|
||||
are equal. */
|
||||
|
||||
static int
|
||||
equal_probe_and_action (const void *p1, const void *p2)
|
||||
{
|
||||
const struct probe_and_action *pa1 = p1;
|
||||
const struct probe_and_action *pa2 = p2;
|
||||
|
||||
return pa1->probe->address == pa2->probe->address;
|
||||
}
|
||||
|
||||
/* Register a solib event probe and its associated action in the
|
||||
probes table. */
|
||||
|
||||
static void
|
||||
register_solib_event_probe (struct probe *probe, enum probe_action action)
|
||||
{
|
||||
struct svr4_info *info = get_svr4_info ();
|
||||
struct probe_and_action lookup, *pa;
|
||||
void **slot;
|
||||
|
||||
/* Create the probes table, if necessary. */
|
||||
if (info->probes_table == NULL)
|
||||
info->probes_table = htab_create_alloc (1, hash_probe_and_action,
|
||||
equal_probe_and_action,
|
||||
xfree, xcalloc, xfree);
|
||||
|
||||
lookup.probe = probe;
|
||||
slot = htab_find_slot (info->probes_table, &lookup, INSERT);
|
||||
gdb_assert (*slot == HTAB_EMPTY_ENTRY);
|
||||
|
||||
pa = XCNEW (struct probe_and_action);
|
||||
pa->probe = probe;
|
||||
pa->action = action;
|
||||
|
||||
*slot = pa;
|
||||
}
|
||||
|
||||
/* Get the solib event probe at the specified location, and the
|
||||
action associated with it. Returns NULL if no solib event probe
|
||||
was found. */
|
||||
|
||||
static struct probe_and_action *
|
||||
solib_event_probe_at (struct svr4_info *info, CORE_ADDR address)
|
||||
{
|
||||
struct probe lookup_probe;
|
||||
struct probe_and_action lookup;
|
||||
void **slot;
|
||||
|
||||
lookup_probe.address = address;
|
||||
lookup.probe = &lookup_probe;
|
||||
slot = htab_find_slot (info->probes_table, &lookup, NO_INSERT);
|
||||
|
||||
if (slot == NULL)
|
||||
return NULL;
|
||||
|
||||
return (struct probe_and_action *) *slot;
|
||||
}
|
||||
|
||||
/* Decide what action to take when the specified solib event probe is
|
||||
hit. */
|
||||
|
||||
static enum probe_action
|
||||
solib_event_probe_action (struct probe_and_action *pa)
|
||||
{
|
||||
enum probe_action action;
|
||||
unsigned probe_argc;
|
||||
|
||||
action = pa->action;
|
||||
if (action == DO_NOTHING || action == PROBES_INTERFACE_FAILED)
|
||||
return action;
|
||||
|
||||
gdb_assert (action == FULL_RELOAD || action == UPDATE_OR_RELOAD);
|
||||
|
||||
/* Check that an appropriate number of arguments has been supplied.
|
||||
We expect:
|
||||
arg0: Lmid_t lmid (mandatory)
|
||||
arg1: struct r_debug *debug_base (mandatory)
|
||||
arg2: struct link_map *new (optional, for incremental updates) */
|
||||
probe_argc = get_probe_argument_count (pa->probe);
|
||||
if (probe_argc == 2)
|
||||
action = FULL_RELOAD;
|
||||
else if (probe_argc < 2)
|
||||
action = PROBES_INTERFACE_FAILED;
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
/* Populate the shared object list by reading the entire list of
|
||||
shared objects from the inferior. Handle special cases relating
|
||||
to the first elements of the list. Returns nonzero on success. */
|
||||
|
||||
static int
|
||||
solist_update_full (struct svr4_info *info)
|
||||
{
|
||||
free_solib_list (info);
|
||||
info->solib_list = svr4_current_sos_direct (info);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Update the shared object list starting from the link-map entry
|
||||
passed by the linker in the probe's third argument. Returns
|
||||
nonzero if the list was successfully updated, or zero to indicate
|
||||
failure. */
|
||||
|
||||
static int
|
||||
solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
|
||||
{
|
||||
struct so_list *tail;
|
||||
CORE_ADDR prev_lm;
|
||||
|
||||
/* svr4_current_sos_direct contains logic to handle a number of
|
||||
special cases relating to the first elements of the list. To
|
||||
avoid duplicating this logic we defer to solist_update_full
|
||||
if the list is empty. */
|
||||
if (info->solib_list == NULL)
|
||||
return 0;
|
||||
|
||||
/* Fall back to a full update if we are using a remote target
|
||||
that does not support incremental transfers. */
|
||||
if (info->using_xfer && !target_augmented_libraries_svr4_read ())
|
||||
return 0;
|
||||
|
||||
/* Walk to the end of the list. */
|
||||
for (tail = info->solib_list; tail->next != NULL; tail = tail->next)
|
||||
/* Nothing. */;
|
||||
prev_lm = tail->lm_info->lm_addr;
|
||||
|
||||
/* Read the new objects. */
|
||||
if (info->using_xfer)
|
||||
{
|
||||
struct svr4_library_list library_list;
|
||||
char annex[64];
|
||||
|
||||
xsnprintf (annex, sizeof (annex), "start=%s;prev=%s",
|
||||
phex_nz (lm, sizeof (lm)),
|
||||
phex_nz (prev_lm, sizeof (prev_lm)));
|
||||
if (!svr4_current_sos_via_xfer_libraries (&library_list, annex))
|
||||
return 0;
|
||||
|
||||
tail->next = library_list.head;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct so_list **link = &tail->next;
|
||||
|
||||
/* IGNORE_FIRST may safely be set to zero here because the
|
||||
above check and deferral to solist_update_full ensures
|
||||
that this call to svr4_read_so_list will never see the
|
||||
first element. */
|
||||
if (!svr4_read_so_list (lm, prev_lm, &link, 0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Disable the probes-based linker interface and revert to the
|
||||
original interface. We don't reset the breakpoints as the
|
||||
ones set up for the probes-based interface are adequate. */
|
||||
|
||||
static void
|
||||
disable_probes_interface_cleanup (void *arg)
|
||||
{
|
||||
struct svr4_info *info = get_svr4_info ();
|
||||
|
||||
warning (_("Probes-based dynamic linker interface failed.\n"
|
||||
"Reverting to original interface.\n"));
|
||||
|
||||
free_probes_table (info);
|
||||
free_solib_list (info);
|
||||
}
|
||||
|
||||
/* Update the solib list as appropriate when using the
|
||||
probes-based linker interface. Do nothing if using the
|
||||
standard interface. */
|
||||
|
||||
static void
|
||||
svr4_handle_solib_event (void)
|
||||
{
|
||||
struct svr4_info *info = get_svr4_info ();
|
||||
struct probe_and_action *pa;
|
||||
enum probe_action action;
|
||||
struct cleanup *old_chain, *usm_chain;
|
||||
struct value *val;
|
||||
CORE_ADDR pc, debug_base, lm = 0;
|
||||
int is_initial_ns;
|
||||
|
||||
/* Do nothing if not using the probes interface. */
|
||||
if (info->probes_table == NULL)
|
||||
return;
|
||||
|
||||
/* If anything goes wrong we revert to the original linker
|
||||
interface. */
|
||||
old_chain = make_cleanup (disable_probes_interface_cleanup, NULL);
|
||||
|
||||
pc = regcache_read_pc (get_current_regcache ());
|
||||
pa = solib_event_probe_at (info, pc);
|
||||
if (pa == NULL)
|
||||
{
|
||||
do_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
|
||||
action = solib_event_probe_action (pa);
|
||||
if (action == PROBES_INTERFACE_FAILED)
|
||||
{
|
||||
do_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == DO_NOTHING)
|
||||
{
|
||||
discard_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
|
||||
/* evaluate_probe_argument looks up symbols in the dynamic linker
|
||||
using find_pc_section. find_pc_section is accelerated by a cache
|
||||
called the section map. The section map is invalidated every
|
||||
time a shared library is loaded or unloaded, and if the inferior
|
||||
is generating a lot of shared library events then the section map
|
||||
will be updated every time svr4_handle_solib_event is called.
|
||||
We called find_pc_section in svr4_create_solib_event_breakpoints,
|
||||
so we can guarantee that the dynamic linker's sections are in the
|
||||
section map. We can therefore inhibit section map updates across
|
||||
these calls to evaluate_probe_argument and save a lot of time. */
|
||||
inhibit_section_map_updates (current_program_space);
|
||||
usm_chain = make_cleanup (resume_section_map_updates_cleanup,
|
||||
current_program_space);
|
||||
|
||||
val = evaluate_probe_argument (pa->probe, 1);
|
||||
if (val == NULL)
|
||||
{
|
||||
do_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
|
||||
debug_base = value_as_address (val);
|
||||
if (debug_base == 0)
|
||||
{
|
||||
do_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Always locate the debug struct, in case it moved. */
|
||||
info->debug_base = 0;
|
||||
if (locate_base (info) == 0)
|
||||
{
|
||||
do_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
|
||||
/* GDB does not currently support libraries loaded via dlmopen
|
||||
into namespaces other than the initial one. We must ignore
|
||||
any namespace other than the initial namespace here until
|
||||
support for this is added to GDB. */
|
||||
if (debug_base != info->debug_base)
|
||||
action = DO_NOTHING;
|
||||
|
||||
if (action == UPDATE_OR_RELOAD)
|
||||
{
|
||||
val = evaluate_probe_argument (pa->probe, 2);
|
||||
if (val != NULL)
|
||||
lm = value_as_address (val);
|
||||
|
||||
if (lm == 0)
|
||||
action = FULL_RELOAD;
|
||||
}
|
||||
|
||||
/* Resume section map updates. */
|
||||
do_cleanups (usm_chain);
|
||||
|
||||
if (action == UPDATE_OR_RELOAD)
|
||||
{
|
||||
if (!solist_update_incremental (info, lm))
|
||||
action = FULL_RELOAD;
|
||||
}
|
||||
|
||||
if (action == FULL_RELOAD)
|
||||
{
|
||||
if (!solist_update_full (info))
|
||||
{
|
||||
do_cleanups (old_chain);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
discard_cleanups (old_chain);
|
||||
}
|
||||
|
||||
/* Helper function for svr4_update_solib_event_breakpoints. */
|
||||
|
||||
static int
|
||||
svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
|
||||
{
|
||||
struct bp_location *loc;
|
||||
|
||||
if (b->type != bp_shlib_event)
|
||||
{
|
||||
/* Continue iterating. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (loc = b->loc; loc != NULL; loc = loc->next)
|
||||
{
|
||||
struct svr4_info *info;
|
||||
struct probe_and_action *pa;
|
||||
|
||||
info = program_space_data (loc->pspace, solib_svr4_pspace_data);
|
||||
if (info == NULL || info->probes_table == NULL)
|
||||
continue;
|
||||
|
||||
pa = solib_event_probe_at (info, loc->address);
|
||||
if (pa == NULL)
|
||||
continue;
|
||||
|
||||
if (pa->action == DO_NOTHING)
|
||||
{
|
||||
if (b->enable_state == bp_disabled && stop_on_solib_events)
|
||||
enable_breakpoint (b);
|
||||
else if (b->enable_state == bp_enabled && !stop_on_solib_events)
|
||||
disable_breakpoint (b);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Continue iterating. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Enable or disable optional solib event breakpoints as appropriate.
|
||||
Called whenever stop_on_solib_events is changed. */
|
||||
|
||||
static void
|
||||
svr4_update_solib_event_breakpoints (void)
|
||||
{
|
||||
iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL);
|
||||
}
|
||||
|
||||
/* Create and register solib event breakpoints. PROBES is an array
|
||||
of NUM_PROBES elements, each of which is vector of probes. A
|
||||
solib event breakpoint will be created and registered for each
|
||||
probe. */
|
||||
|
||||
static void
|
||||
svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
|
||||
VEC (probe_p) **probes)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_PROBES; i++)
|
||||
{
|
||||
enum probe_action action = probe_info[i].action;
|
||||
struct probe *probe;
|
||||
int ix;
|
||||
|
||||
for (ix = 0;
|
||||
VEC_iterate (probe_p, probes[i], ix, probe);
|
||||
++ix)
|
||||
{
|
||||
create_solib_event_breakpoint (gdbarch, probe->address);
|
||||
register_solib_event_probe (probe, action);
|
||||
}
|
||||
}
|
||||
|
||||
svr4_update_solib_event_breakpoints ();
|
||||
}
|
||||
|
||||
/* Both the SunOS and the SVR4 dynamic linkers call a marker function
|
||||
before and after mapping and unmapping shared libraries. The sole
|
||||
purpose of this method is to allow debuggers to set a breakpoint so
|
||||
they can track these changes.
|
||||
|
||||
Some versions of the glibc dynamic linker contain named probes
|
||||
to allow more fine grained stopping. Given the address of the
|
||||
original marker function, this function attempts to find these
|
||||
probes, and if found, sets breakpoints on those instead. If the
|
||||
probes aren't found, a single breakpoint is set on the original
|
||||
marker function. */
|
||||
|
||||
static void
|
||||
svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch,
|
||||
CORE_ADDR address)
|
||||
{
|
||||
struct obj_section *os;
|
||||
|
||||
os = find_pc_section (address);
|
||||
if (os != NULL)
|
||||
{
|
||||
int with_prefix;
|
||||
|
||||
for (with_prefix = 0; with_prefix <= 1; with_prefix++)
|
||||
{
|
||||
VEC (probe_p) *probes[NUM_PROBES];
|
||||
int all_probes_found = 1;
|
||||
int i;
|
||||
|
||||
memset (probes, 0, sizeof (probes));
|
||||
for (i = 0; i < NUM_PROBES; i++)
|
||||
{
|
||||
const char *name = probe_info[i].name;
|
||||
char buf[32];
|
||||
|
||||
/* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
|
||||
shipped with an early version of the probes code in
|
||||
which the probes' names were prefixed with "rtld_"
|
||||
and the "map_failed" probe did not exist. The
|
||||
locations of the probes are otherwise the same, so
|
||||
we check for probes with prefixed names if probes
|
||||
with unprefixed names are not present. */
|
||||
if (with_prefix)
|
||||
{
|
||||
xsnprintf (buf, sizeof (buf), "rtld_%s", name);
|
||||
name = buf;
|
||||
}
|
||||
|
||||
probes[i] = find_probes_in_objfile (os->objfile, "rtld", name);
|
||||
|
||||
/* The "map_failed" probe did not exist in early
|
||||
versions of the probes code in which the probes'
|
||||
names were prefixed with "rtld_". */
|
||||
if (strcmp (name, "rtld_map_failed") == 0)
|
||||
continue;
|
||||
|
||||
if (VEC_empty (probe_p, probes[i]))
|
||||
{
|
||||
all_probes_found = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_probes_found)
|
||||
svr4_create_probe_breakpoints (gdbarch, probes);
|
||||
|
||||
for (i = 0; i < NUM_PROBES; i++)
|
||||
VEC_free (probe_p, probes[i]);
|
||||
|
||||
if (all_probes_found)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
create_solib_event_breakpoint (gdbarch, address);
|
||||
}
|
||||
|
||||
/* Helper function for gdb_bfd_lookup_symbol. */
|
||||
|
||||
static int
|
||||
|
@ -1492,7 +2111,7 @@ enable_break (struct svr4_info *info, int from_tty)
|
|||
That knowledge is encoded in the address, if it's Thumb the low bit
|
||||
is 1. However, we've stripped that info above and it's not clear
|
||||
what all the consequences are of passing a non-addr_bits_remove'd
|
||||
address to create_solib_event_breakpoint. The call to
|
||||
address to svr4_create_solib_event_breakpoints. The call to
|
||||
find_pc_section verifies we know about the address and have some
|
||||
hope of computing the right kind of breakpoint to use (via
|
||||
symbol info). It does mean that GDB needs to be pointed at a
|
||||
|
@ -1530,7 +2149,7 @@ enable_break (struct svr4_info *info, int from_tty)
|
|||
+ bfd_section_size (tmp_bfd, interp_sect);
|
||||
}
|
||||
|
||||
create_solib_event_breakpoint (target_gdbarch (), sym_addr);
|
||||
svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -1688,7 +2307,8 @@ enable_break (struct svr4_info *info, int from_tty)
|
|||
|
||||
if (sym_addr != 0)
|
||||
{
|
||||
create_solib_event_breakpoint (target_gdbarch (), load_addr + sym_addr);
|
||||
svr4_create_solib_event_breakpoints (target_gdbarch (),
|
||||
load_addr + sym_addr);
|
||||
xfree (interp_name);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1714,7 +2334,7 @@ enable_break (struct svr4_info *info, int from_tty)
|
|||
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
|
||||
sym_addr,
|
||||
¤t_target);
|
||||
create_solib_event_breakpoint (target_gdbarch (), sym_addr);
|
||||
svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -1730,7 +2350,7 @@ enable_break (struct svr4_info *info, int from_tty)
|
|||
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
|
||||
sym_addr,
|
||||
¤t_target);
|
||||
create_solib_event_breakpoint (target_gdbarch (), sym_addr);
|
||||
svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -2226,6 +2846,10 @@ svr4_solib_create_inferior_hook (int from_tty)
|
|||
|
||||
info = get_svr4_info ();
|
||||
|
||||
/* Clear the probes-based interface's state. */
|
||||
free_probes_table (info);
|
||||
free_solib_list (info);
|
||||
|
||||
/* Relocate the main executable if necessary. */
|
||||
svr4_relocate_main_executable ();
|
||||
|
||||
|
@ -2468,4 +3092,6 @@ _initialize_svr4_solib (void)
|
|||
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
|
||||
svr4_so_ops.same = svr4_same;
|
||||
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
|
||||
svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
|
||||
svr4_so_ops.handle_event = svr4_handle_solib_event;
|
||||
}
|
||||
|
|
31
gdb/solib.c
31
gdb/solib.c
|
@ -1209,6 +1209,37 @@ no_shared_libraries (char *ignored, int from_tty)
|
|||
objfile_purge_solibs ();
|
||||
}
|
||||
|
||||
/* See solib.h. */
|
||||
|
||||
void
|
||||
update_solib_breakpoints (void)
|
||||
{
|
||||
const struct target_so_ops *ops = solib_ops (target_gdbarch ());
|
||||
|
||||
if (ops->update_breakpoints != NULL)
|
||||
ops->update_breakpoints ();
|
||||
}
|
||||
|
||||
/* See solib.h. */
|
||||
|
||||
void
|
||||
handle_solib_event (void)
|
||||
{
|
||||
const struct target_so_ops *ops = solib_ops (target_gdbarch ());
|
||||
|
||||
if (ops->handle_event != NULL)
|
||||
ops->handle_event ();
|
||||
|
||||
clear_program_space_solib_cache (current_inferior ()->pspace);
|
||||
|
||||
/* Check for any newly added shared libraries if we're supposed to
|
||||
be adding them automatically. Switch terminal for any messages
|
||||
produced by breakpoint_re_set. */
|
||||
target_terminal_ours_for_output ();
|
||||
solib_add (NULL, 0, ¤t_target, auto_solib_add);
|
||||
target_terminal_inferior ();
|
||||
}
|
||||
|
||||
/* Reload shared libraries, but avoid reloading the same symbol file
|
||||
we already have loaded. */
|
||||
|
||||
|
|
|
@ -90,4 +90,12 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
|
|||
void *),
|
||||
void *data);
|
||||
|
||||
/* Enable or disable optional solib event breakpoints as appropriate. */
|
||||
|
||||
extern void update_solib_breakpoints (void);
|
||||
|
||||
/* Handle an solib event by calling solib_add. */
|
||||
|
||||
extern void handle_solib_event (void);
|
||||
|
||||
#endif /* SOLIB_H */
|
||||
|
|
13
gdb/solist.h
13
gdb/solist.h
|
@ -153,6 +153,19 @@ struct target_so_ops
|
|||
core file (in particular, for readonly sections). */
|
||||
int (*keep_data_in_core) (CORE_ADDR vaddr,
|
||||
unsigned long size);
|
||||
|
||||
/* Enable or disable optional solib event breakpoints as
|
||||
appropriate. This should be called whenever
|
||||
stop_on_solib_events is changed. This pointer can be
|
||||
NULL, in which case no enabling or disabling is necessary
|
||||
for this target. */
|
||||
void (*update_breakpoints) (void);
|
||||
|
||||
/* Target-specific processing of solib events that will be
|
||||
performed before solib_add is called. This pointer can be
|
||||
NULL, in which case no specific preprocessing is necessary
|
||||
for this target. */
|
||||
void (*handle_event) (void);
|
||||
};
|
||||
|
||||
/* Free the memory associated with a (so_list *). */
|
||||
|
|
Loading…
Reference in New Issue