/* Handle SVR4 shared libraries for GDB, the GNU Debugger.
- Copyright (C) 1990-2018 Free Software Foundation, Inc.
+ Copyright (C) 1990-2019 Free Software Foundation, Inc.
This file is part of GDB.
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
static void svr4_free_library_list (void *p_list);
+static void probes_table_remove_objfile_probes (struct objfile *objfile);
/* On SVR4 systems, a list of symbols in the dynamic linker where
GDB can try to place a breakpoint to monitor shared library
&& strcmp (inferior_so_name, "/lib/ld.so.1") == 0)
return 1;
- /* Similarly, we observed the same issue with sparc64, but with
+ /* Similarly, we observed the same issue with amd64 and sparcv9, but with
different locations. */
+ if (strcmp (gdb_so_name, "/usr/lib/amd64/ld.so.1") == 0
+ && strcmp (inferior_so_name, "/lib/amd64/ld.so.1") == 0)
+ return 1;
+
if (strcmp (gdb_so_name, "/usr/lib/sparcv9/ld.so.1") == 0
&& strcmp (inferior_so_name, "/lib/sparcv9/ld.so.1") == 0)
return 1;
struct svr4_info
{
- CORE_ADDR debug_base; /* Base of dynamic linker structures. */
+ svr4_info () = default;
+ ~svr4_info ();
+
+ /* Base of dynamic linker structures. */
+ CORE_ADDR debug_base = 0;
/* Validity flag for debug_loader_offset. */
- int debug_loader_offset_p;
+ int debug_loader_offset_p = 0;
/* Load address for the dynamic linker, inferred. */
- CORE_ADDR debug_loader_offset;
+ CORE_ADDR debug_loader_offset = 0;
/* Name of the dynamic linker, valid if debug_loader_offset_p. */
- char *debug_loader_name;
+ char *debug_loader_name = nullptr;
/* Load map address for the main executable. */
- CORE_ADDR main_lm_addr;
+ CORE_ADDR main_lm_addr = 0;
- CORE_ADDR interp_text_sect_low;
- CORE_ADDR interp_text_sect_high;
- CORE_ADDR interp_plt_sect_low;
- CORE_ADDR interp_plt_sect_high;
+ CORE_ADDR interp_text_sect_low = 0;
+ CORE_ADDR interp_text_sect_high = 0;
+ CORE_ADDR interp_plt_sect_low = 0;
+ CORE_ADDR interp_plt_sect_high = 0;
/* Nonzero if the list of objects was last obtained from the target
via qXfer:libraries-svr4:read. */
- int using_xfer;
+ int using_xfer = 0;
/* 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->prob->address. */
- htab_t probes_table;
+ htab_up probes_table;
/* List of objects loaded into the inferior, used by the probes-
based interface. */
- struct so_list *solib_list;
+ struct so_list *solib_list = nullptr;
};
/* Per-program-space data key. */
-static const struct program_space_data *solib_svr4_pspace_data;
+static const struct program_space_key<svr4_info> 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;
+ info->probes_table.reset (nullptr);
}
/* Free the solib list. */
info->solib_list = NULL;
}
-static void
-svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
+svr4_info::~svr4_info ()
{
- struct svr4_info *info = (struct svr4_info *) arg;
-
- free_probes_table (info);
- free_solib_list (info);
-
- xfree (info);
+ free_solib_list (this);
}
-/* Get the current svr4 data. If none is found yet, add it now. This
- function always returns a valid object. */
+/* Get the svr4 data for program space PSPACE. If none is found yet, add it now.
+ This function always returns a valid object. */
static struct svr4_info *
-get_svr4_info (void)
+get_svr4_info (program_space *pspace)
{
- struct svr4_info *info;
+ struct svr4_info *info = solib_svr4_pspace_data.get (pspace);
- info = (struct svr4_info *) program_space_data (current_program_space,
- solib_svr4_pspace_data);
- if (info != NULL)
- return info;
+ if (info == NULL)
+ info = solib_svr4_pspace_data.emplace (pspace);
- info = XCNEW (struct svr4_info);
- set_program_space_data (current_program_space, solib_svr4_pspace_data, info);
return info;
}
struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
CORE_ADDR addr = 0;
- TRY
+ try
{
addr = read_memory_typed_address (info->debug_base + lmo->r_map_offset,
ptr_type);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
exception_print (gdb_stderr, ex);
}
- END_CATCH
return addr;
}
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
ULONGEST version = 0;
- TRY
+ try
{
/* Check version, and return zero if `struct r_debug' doesn't have
the r_ldsomap member. */
= read_memory_unsigned_integer (info->debug_base + lmo->r_version_offset,
lmo->r_version_size, byte_order);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
exception_print (gdb_stderr, ex);
}
- END_CATCH
if (version < 2 || lmo->r_ldsomap_offset == -1)
return 0;
CORE_ADDR ldsomap;
CORE_ADDR name_lm;
- info = get_svr4_info ();
+ info = get_svr4_info (current_program_space);
info->debug_base = 0;
locate_base (info);
struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
int l_name_size = TYPE_LENGTH (ptr_type);
gdb::byte_vector l_name_buf (l_name_size);
- struct svr4_info *info = get_svr4_info ();
+ struct svr4_info *info = get_svr4_info (current_program_space);
symfile_add_flags add_flags = 0;
if (from_tty)
CORE_ADDR main_lm;
};
+/* This module's 'free_objfile' observer. */
+
+static void
+svr4_free_objfile_observer (struct objfile *objfile)
+{
+ probes_table_remove_objfile_probes (objfile);
+}
+
/* Implementation for target_so_ops.free_so. */
static void
static int
svr4_parse_libraries (const char *document, struct svr4_library_list *list)
{
- struct cleanup *back_to = make_cleanup (svr4_free_library_list,
- &list->head);
+ auto cleanup = make_scope_exit ([&] ()
+ {
+ svr4_free_library_list (&list->head);
+ });
memset (list, 0, sizeof (*list));
list->tailp = &list->head;
svr4_library_list_elements, document, list) == 0)
{
/* Parsed successfully, keep the result. */
- discard_cleanups (back_to);
+ cleanup.release ();
return 1;
}
- do_cleanups (back_to);
return 0;
}
linker, build a fallback list from other sources. */
static struct so_list *
-svr4_default_sos (void)
+svr4_default_sos (svr4_info *info)
{
- struct svr4_info *info = get_svr4_info ();
struct so_list *newobj;
if (!info->debug_loader_offset_p)
represent only part of the inferior library list. */
static int
-svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
+svr4_read_so_list (svr4_info *info, CORE_ADDR lm, CORE_ADDR prev_lm,
struct so_list ***link_ptr_ptr, int ignore_first)
{
CORE_ADDR first_l_name = 0;
decide when to ignore it. */
if (ignore_first && li->l_prev == 0)
{
- struct svr4_info *info = get_svr4_info ();
-
first_l_name = li->l_name;
info->main_lm_addr = li->lm_addr;
continue;
CORE_ADDR lm;
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
- struct cleanup *back_to;
int ignore_first;
struct svr4_library_list library_list;
if (library_list.main_lm)
info->main_lm_addr = library_list.main_lm;
- return library_list.head ? library_list.head : svr4_default_sos ();
+ return library_list.head ? library_list.head : svr4_default_sos (info);
}
/* Always locate the debug struct, in case it has moved. */
/* If we can't find the dynamic linker's base structure, this
must not be a dynamically linked executable. Hmm. */
if (! info->debug_base)
- return svr4_default_sos ();
+ return svr4_default_sos (info);
/* Assume that everything is a library if the dynamic loader was loaded
late by a static executable. */
else
ignore_first = 1;
- back_to = make_cleanup (svr4_free_library_list, &head);
+ auto cleanup = make_scope_exit ([&] ()
+ {
+ svr4_free_library_list (&head);
+ });
/* Walk the inferior's link map list, and build our list of
`struct so_list' nodes. */
lm = solib_svr4_r_map (info);
if (lm)
- svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
+ svr4_read_so_list (info, 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
for skipping dynamic linker resolver code. */
lm = solib_svr4_r_ldsomap (info);
if (lm)
- svr4_read_so_list (lm, 0, &link_ptr, 0);
+ svr4_read_so_list (info, lm, 0, &link_ptr, 0);
- discard_cleanups (back_to);
+ cleanup.release ();
if (head == NULL)
- return svr4_default_sos ();
+ return svr4_default_sos (info);
return head;
}
method. */
static struct so_list *
-svr4_current_sos_1 (void)
+svr4_current_sos_1 (svr4_info *info)
{
- 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)
static struct so_list *
svr4_current_sos (void)
{
- struct so_list *so_head = svr4_current_sos_1 ();
+ svr4_info *info = get_svr4_info (current_program_space);
+ struct so_list *so_head = svr4_current_sos_1 (info);
struct mem_range vsyscall_range;
/* Filter out the vDSO module, if present. Its symbol file would
svr4_fetch_objfile_link_map (struct objfile *objfile)
{
struct so_list *so;
- struct svr4_info *info = get_svr4_info ();
+ struct svr4_info *info = get_svr4_info (objfile->pspace);
/* Cause svr4_current_sos() to be run if it hasn't been already. */
if (info->main_lm_addr == 0)
if (objfile == symfile_objfile)
return info->main_lm_addr;
+ /* If OBJFILE is a separate debug object file, look for the
+ original object file. */
+ if (objfile->separate_debug_objfile_backlink != NULL)
+ objfile = objfile->separate_debug_objfile_backlink;
+
/* The other link map addresses may be found by examining the list
of shared libraries. */
for (so = master_so_list (); so; so = so->next)
int
svr4_in_dynsym_resolve_code (CORE_ADDR pc)
{
- struct svr4_info *info = get_svr4_info ();
+ struct svr4_info *info = get_svr4_info (current_program_space);
return ((pc >= info->interp_text_sect_low
&& pc < info->interp_text_sect_high)
/* The action. */
enum probe_action action;
+
+ /* The objfile where this probe was found. */
+ struct objfile *objfile;
};
/* Returns a hash code for the probe_and_action referenced by p. */
return pa1->address == pa2->address;
}
+/* Traversal function for probes_table_remove_objfile_probes. */
+
+static int
+probes_table_htab_remove_objfile_probes (void **slot, void *info)
+{
+ probe_and_action *pa = (probe_and_action *) *slot;
+ struct objfile *objfile = (struct objfile *) info;
+
+ if (pa->objfile == objfile)
+ htab_clear_slot (get_svr4_info (objfile->pspace)->probes_table.get (),
+ slot);
+
+ return 1;
+}
+
+/* Remove all probes that belong to OBJFILE from the probes table. */
+
+static void
+probes_table_remove_objfile_probes (struct objfile *objfile)
+{
+ svr4_info *info = get_svr4_info (objfile->pspace);
+ if (info->probes_table != nullptr)
+ htab_traverse_noresize (info->probes_table.get (),
+ probes_table_htab_remove_objfile_probes, objfile);
+}
+
/* Register a solib event probe and its associated action in the
probes table. */
static void
-register_solib_event_probe (probe *prob, CORE_ADDR address,
+register_solib_event_probe (svr4_info *info, struct objfile *objfile,
+ probe *prob, CORE_ADDR address,
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);
+ info->probes_table.reset (htab_create_alloc (1, hash_probe_and_action,
+ equal_probe_and_action,
+ xfree, xcalloc, xfree));
- lookup.prob = prob;
lookup.address = address;
- slot = htab_find_slot (info->probes_table, &lookup, INSERT);
+ slot = htab_find_slot (info->probes_table.get (), &lookup, INSERT);
gdb_assert (*slot == HTAB_EMPTY_ENTRY);
pa = XCNEW (struct probe_and_action);
pa->prob = prob;
pa->address = address;
pa->action = action;
+ pa->objfile = objfile;
*slot = pa;
}
void **slot;
lookup.address = address;
- slot = htab_find_slot (info->probes_table, &lookup, NO_INSERT);
+ slot = htab_find_slot (info->probes_table.get (), &lookup, NO_INSERT);
if (slot == NULL)
return NULL;
arg0: Lmid_t lmid (mandatory)
arg1: struct r_debug *debug_base (mandatory)
arg2: struct link_map *new (optional, for incremental updates) */
- TRY
+ try
{
probe_argc = pa->prob->get_argument_count (frame);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
exception_print (gdb_stderr, ex);
probe_argc = 0;
}
- END_CATCH
/* If get_argument_count throws an exception, probe_argc will be set
to zero. However, if pa->prob does not have arguments, then
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))
+ if (!svr4_read_so_list (info, lm, prev_lm, &link, 0))
return 0;
}
ones set up for the probes-based interface are adequate. */
static void
-disable_probes_interface_cleanup (void *arg)
+disable_probes_interface (svr4_info *info)
{
- struct svr4_info *info = get_svr4_info ();
-
warning (_("Probes-based dynamic linker interface failed.\n"
- "Reverting to original interface.\n"));
+ "Reverting to original interface."));
free_probes_table (info);
free_solib_list (info);
static void
svr4_handle_solib_event (void)
{
- struct svr4_info *info = get_svr4_info ();
+ struct svr4_info *info = get_svr4_info (current_program_space);
struct probe_and_action *pa;
enum probe_action action;
- struct cleanup *old_chain;
struct value *val = NULL;
CORE_ADDR pc, debug_base, lm = 0;
struct frame_info *frame = get_current_frame ();
/* If anything goes wrong we revert to the original linker
interface. */
- old_chain = make_cleanup (disable_probes_interface_cleanup, NULL);
+ auto cleanup = make_scope_exit ([info] ()
+ {
+ disable_probes_interface (info);
+ });
pc = regcache_read_pc (get_current_regcache ());
pa = solib_event_probe_at (info, pc);
if (pa == NULL)
- {
- do_cleanups (old_chain);
- return;
- }
+ return;
action = solib_event_probe_action (pa);
if (action == PROBES_INTERFACE_FAILED)
- {
- do_cleanups (old_chain);
- return;
- }
+ return;
if (action == DO_NOTHING)
{
- discard_cleanups (old_chain);
+ cleanup.release ();
return;
}
scoped_restore inhibit_updates
= inhibit_section_map_updates (current_program_space);
- TRY
+ try
{
val = pa->prob->evaluate_argument (1, frame);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
exception_print (gdb_stderr, ex);
val = NULL;
}
- END_CATCH
if (val == NULL)
- {
- do_cleanups (old_chain);
- return;
- }
+ return;
debug_base = value_as_address (val);
if (debug_base == 0)
- {
- do_cleanups (old_chain);
- return;
- }
+ return;
/* Always locate the debug struct, in case it moved. */
info->debug_base = 0;
if (locate_base (info) == 0)
- {
- do_cleanups (old_chain);
- return;
- }
+ return;
/* GDB does not currently support libraries loaded via dlmopen
into namespaces other than the initial one. We must ignore
if (action == UPDATE_OR_RELOAD)
{
- TRY
+ try
{
val = pa->prob->evaluate_argument (2, frame);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
exception_print (gdb_stderr, ex);
- do_cleanups (old_chain);
return;
}
- END_CATCH
if (val != NULL)
lm = value_as_address (val);
if (action == FULL_RELOAD)
{
if (!solist_update_full (info))
- {
- do_cleanups (old_chain);
- return;
- }
+ return;
}
- discard_cleanups (old_chain);
+ cleanup.release ();
}
/* Helper function for svr4_update_solib_event_breakpoints. */
struct svr4_info *info;
struct probe_and_action *pa;
- info = ((struct svr4_info *)
- program_space_data (loc->pspace, solib_svr4_pspace_data));
+ info = solib_svr4_pspace_data.get (loc->pspace);
if (info == NULL || info->probes_table == NULL)
continue;
probe. */
static void
-svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
+svr4_create_probe_breakpoints (svr4_info *info, struct gdbarch *gdbarch,
const std::vector<probe *> *probes,
struct objfile *objfile)
{
CORE_ADDR address = p->get_relocated_address (objfile);
create_solib_event_breakpoint (gdbarch, address);
- register_solib_event_probe (p, address, action);
+ register_solib_event_probe (info, objfile, p, address, action);
}
}
marker function. */
static void
-svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch,
+svr4_create_solib_event_breakpoints (svr4_info *info, struct gdbarch *gdbarch,
CORE_ADDR address)
{
struct obj_section *os;
}
if (all_probes_found)
- svr4_create_probe_breakpoints (gdbarch, probes, os->objfile);
+ svr4_create_probe_breakpoints (info, gdbarch, probes, os->objfile);
if (all_probes_found)
return;
+ bfd_section_size (tmp_bfd, interp_sect);
}
- svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (info, target_gdbarch (), sym_addr);
return 1;
}
}
mechanism to find the dynamic linker's base address. */
gdb_bfd_ref_ptr tmp_bfd;
- TRY
+ try
{
tmp_bfd = solib_bfd_open (interp_name);
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (const gdb_exception &ex)
{
}
- END_CATCH
if (tmp_bfd == NULL)
goto bkpt_at_symbol;
if (sym_addr != 0)
{
- svr4_create_solib_event_breakpoints (target_gdbarch (),
+ svr4_create_solib_event_breakpoints (info, target_gdbarch (),
load_addr + sym_addr);
return 1;
}
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
current_top_target ());
- svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (info, target_gdbarch (),
+ sym_addr);
return 1;
}
}
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
current_top_target ());
- svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (info, target_gdbarch (),
+ sym_addr);
return 1;
}
}
{
struct svr4_info *info;
- info = get_svr4_info ();
+ info = get_svr4_info (current_program_space);
/* Clear the probes-based interface's state. */
free_probes_table (info);
{
struct svr4_info *info;
- info = get_svr4_info ();
+ info = get_svr4_info (current_program_space);
info->debug_base = 0;
info->debug_loader_offset_p = 0;
info->debug_loader_offset = 0;
}
if (abfd == NULL || scan_dyntag (DT_SYMBOLIC, abfd, NULL, NULL) != 1)
- return (struct block_symbol) {NULL, NULL};
+ return {};
return lookup_global_symbol_from_objfile (objfile, name, domain);
}
_initialize_svr4_solib (void)
{
solib_svr4_data = gdbarch_data_register_pre_init (solib_svr4_init);
- solib_svr4_pspace_data
- = register_program_space_data_with_cleanup (NULL, svr4_pspace_data_cleanup);
svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses;
svr4_so_ops.free_so = svr4_free_so;
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;
+
+ gdb::observers::free_objfile.attach (svr4_free_objfile_observer);
}