19d4458238
- Update libraries opening performance fix from upstream. - Fix C++ lookups performance regression (Doug Evans, BZ 972677).
1108 lines
34 KiB
Diff
1108 lines
34 KiB
Diff
http://sourceware.org/ml/gdb-cvs/2013-06/msg00018.html
|
|
|
|
### src/gdb/ChangeLog 2013/06/04 13:10:53 1.15684
|
|
### src/gdb/ChangeLog 2013/06/04 13:17:05 1.15685
|
|
## -1,5 +1,58 @@
|
|
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
|
|
"to_augmented_libraries_svr4_read".
|
|
(target_augmented_libraries_svr4_read): New macro.
|
|
Index: gdb-7.6/gdb/breakpoint.h
|
|
===================================================================
|
|
--- gdb-7.6.orig/gdb/breakpoint.h 2013-06-10 14:44:37.455812656 +0200
|
|
+++ gdb-7.6/gdb/breakpoint.h 2013-06-10 14:44:37.709812579 +0200
|
|
@@ -1552,8 +1552,6 @@ extern int user_breakpoint_p (struct bre
|
|
/* 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 void breakpoints_relocate (struct objfile *objfile,
|
|
Index: gdb-7.6/gdb/infrun.c
|
|
===================================================================
|
|
--- gdb-7.6.orig/gdb/infrun.c 2013-06-10 14:44:37.427812664 +0200
|
|
+++ gdb-7.6/gdb/infrun.c 2013-06-10 14:44:37.711812579 +0200
|
|
@@ -370,6 +370,16 @@ static struct symbol *step_start_functio
|
|
/* 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)
|
|
@@ -7335,7 +7345,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);
|
|
|
|
Index: gdb-7.6/gdb/solib-svr4.c
|
|
===================================================================
|
|
--- gdb-7.6.orig/gdb/solib-svr4.c 2013-06-10 14:44:37.392812675 +0200
|
|
+++ gdb-7.6/gdb/solib-svr4.c 2013-06-10 14:44:37.712812578 +0200
|
|
@@ -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_lis
|
|
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);
|
|
}
|
|
|
|
@@ -982,6 +1074,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"
|
|
@@ -1097,23 +1217,30 @@ svr4_parse_libraries (const char *docume
|
|
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;
|
|
|
|
@@ -1127,7 +1254,8 @@ svr4_current_sos_via_xfer_libraries (str
|
|
#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;
|
|
}
|
|
@@ -1161,15 +1289,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)
|
|
{
|
|
@@ -1185,7 +1317,7 @@ svr4_read_so_list (CORE_ADDR lm, struct
|
|
if (new->lm_info == NULL)
|
|
{
|
|
do_cleanups (old_chain);
|
|
- break;
|
|
+ return 0;
|
|
}
|
|
|
|
next_lm = new->lm_info->l_next;
|
|
@@ -1196,7 +1328,7 @@ svr4_read_so_list (CORE_ADDR lm, struct
|
|
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
|
|
@@ -1291,17 +1423,21 @@ svr4_read_so_list (CORE_ADDR lm, struct
|
|
**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;
|
|
@@ -1314,19 +1450,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);
|
|
@@ -1349,7 +1482,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
|
|
@@ -1357,7 +1490,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);
|
|
|
|
@@ -1367,6 +1500,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
|
|
@@ -1449,6 +1598,476 @@ exec_entry_point (struct bfd *abfd, stru
|
|
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
|
|
@@ -1532,7 +2151,7 @@ enable_break (struct svr4_info *info, in
|
|
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
|
|
@@ -1570,7 +2189,7 @@ enable_break (struct svr4_info *info, in
|
|
+ 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;
|
|
}
|
|
}
|
|
@@ -1728,7 +2347,8 @@ enable_break (struct svr4_info *info, in
|
|
|
|
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;
|
|
}
|
|
@@ -1754,7 +2374,7 @@ enable_break (struct svr4_info *info, in
|
|
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;
|
|
}
|
|
}
|
|
@@ -1770,7 +2390,7 @@ enable_break (struct svr4_info *info, in
|
|
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;
|
|
}
|
|
}
|
|
@@ -2266,6 +2886,10 @@ svr4_solib_create_inferior_hook (int fro
|
|
|
|
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 ();
|
|
|
|
@@ -2507,4 +3131,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;
|
|
}
|
|
Index: gdb-7.6/gdb/solib.c
|
|
===================================================================
|
|
--- gdb-7.6.orig/gdb/solib.c 2013-06-10 14:44:37.392812675 +0200
|
|
+++ gdb-7.6/gdb/solib.c 2013-06-10 14:44:37.713812578 +0200
|
|
@@ -1221,6 +1221,37 @@ no_shared_libraries (char *ignored, int
|
|
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. */
|
|
|
|
Index: gdb-7.6/gdb/solib.h
|
|
===================================================================
|
|
--- gdb-7.6.orig/gdb/solib.h 2013-01-01 07:32:51.000000000 +0100
|
|
+++ gdb-7.6/gdb/solib.h 2013-06-10 14:44:37.713812578 +0200
|
|
@@ -90,4 +90,12 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_f
|
|
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 */
|
|
Index: gdb-7.6/gdb/solist.h
|
|
===================================================================
|
|
--- gdb-7.6.orig/gdb/solist.h 2013-01-01 07:32:51.000000000 +0100
|
|
+++ gdb-7.6/gdb/solist.h 2013-06-10 14:44:37.713812578 +0200
|
|
@@ -148,6 +148,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 *). */
|
|
Index: gdb-7.6/gdb/breakpoint.c
|
|
===================================================================
|
|
--- gdb-7.6.orig/gdb/breakpoint.c 2013-06-10 14:44:37.500812642 +0200
|
|
+++ gdb-7.6/gdb/breakpoint.c 2013-06-10 14:44:57.301806708 +0200
|
|
@@ -5348,25 +5348,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 ();
|
|
-#ifdef SOLIB_ADD
|
|
- SOLIB_ADD (NULL, 0, ¤t_target, auto_solib_add);
|
|
-#else
|
|
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
|
|
-#endif
|
|
- target_terminal_inferior ();
|
|
-}
|
|
-
|
|
/* Prepare WHAT final decision for infrun. */
|
|
|
|
/* Decide what infrun needs to do with this bpstat. */
|