You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1107 lines
34 KiB
1107 lines
34 KiB
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. */
|
|
|