+ 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;
+ struct frame_info *frame = get_current_frame ();
+
+ 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, frame);
+ 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;
+ struct frame_info *frame = get_current_frame ();
+
+ /* 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, frame);
+ 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, frame);
+ 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 ();