/* Handle SVR4 shared libraries for GDB, the GNU Debugger.
- Copyright (C) 1990-2022 Free Software Foundation, Inc.
+ Copyright (C) 1990-2023 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdb_bfd.h"
#include "probe.h"
+#include <map>
+
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);
+static void svr4_free_library_list (so_list *solist);
static void probes_table_remove_objfile_probes (struct objfile *objfile);
-static void svr4_iterate_over_objfiles_in_search_order (
- struct gdbarch *gdbarch, iterate_over_objfiles_in_search_order_cb_ftype *cb,
- void *cb_data, struct objfile *objfile);
+static void svr4_iterate_over_objfiles_in_search_order
+ (gdbarch *gdbarch, iterate_over_objfiles_in_search_order_cb_ftype cb,
+ objfile *current_objfile);
/* On SVR4 systems, a list of symbols in the dynamic linker where
static int
svr4_same (struct so_list *gdb, struct so_list *inferior)
{
- return (svr4_same_1 (gdb->so_original_name, inferior->so_original_name));
+ if (!svr4_same_1 (gdb->so_original_name, inferior->so_original_name))
+ return false;
+
+ /* There may be different instances of the same library, in different
+ namespaces. Each instance, however, must have been loaded at a
+ different address so its relocation offset would be different. */
+ const lm_info_svr4 *lmg = (const lm_info_svr4 *) gdb->lm_info;
+ const lm_info_svr4 *lmi = (const lm_info_svr4 *) inferior->lm_info;
+
+ return (lmg->l_addr_inferior == lmi->l_addr_inferior);
}
static std::unique_ptr<lm_info_svr4>
svr4_info () = default;
~svr4_info ();
- /* Base of dynamic linker structures. */
+ /* Base of dynamic linker structures in default namespace. */
CORE_ADDR debug_base = 0;
/* Validity flag for debug_loader_offset. */
/* Name of the dynamic linker, valid if debug_loader_offset_p. */
char *debug_loader_name = nullptr;
- /* Load map address for the main executable. */
+ /* Load map address for the main executable in default namespace. */
CORE_ADDR main_lm_addr = 0;
CORE_ADDR interp_text_sect_low = 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
+ /* True if the list of objects was last obtained from the target
via qXfer:libraries-svr4:read. */
- int using_xfer = 0;
+ bool using_xfer = false;
/* Table of struct probe_and_action instances, used by the
probes-based interface to map breakpoint addresses to probes
probe_and_action->prob->address. */
htab_up probes_table;
- /* List of objects loaded into the inferior, used by the probes-
- based interface. */
- struct so_list *solib_list = nullptr;
+ /* List of objects loaded into the inferior per namespace, used by the
+ probes-based interface.
+
+ The namespace is represented by the address of its corresponding
+ r_debug[_ext] object. We get the namespace id as argument to the
+ 'reloc_complete' probe but we don't get it when scanning the load map
+ on attach.
+
+ The r_debug[_ext] objects may move when ld.so itself moves. In that
+ case, we expect also the global _r_debug to move so we can detect
+ this and reload everything. The r_debug[_ext] objects are not
+ expected to move individually.
+
+ The special entry zero is reserved for a linear list to support
+ gdbstubs that do not support namespaces. */
+ std::map<CORE_ADDR, so_list *> solib_lists;
};
/* Per-program-space data key. */
-static const struct program_space_key<svr4_info> solib_svr4_pspace_data;
+static const registry<program_space>::key<svr4_info> solib_svr4_pspace_data;
+
+/* Return whether DEBUG_BASE is the default namespace of INFO. */
+
+static bool
+svr4_is_default_namespace (const svr4_info *info, CORE_ADDR debug_base)
+{
+ return (debug_base == info->debug_base);
+}
/* Free the probes table. */
info->probes_table.reset (nullptr);
}
-/* Free the solib list. */
+/* Free the solib lists for all namespaces. */
static void
-free_solib_list (struct svr4_info *info)
+free_solib_lists (svr4_info *info)
{
- svr4_free_library_list (&info->solib_list);
- info->solib_list = NULL;
+ for (const std::pair<CORE_ADDR, so_list *> tuple
+ : info->solib_lists)
+ svr4_free_library_list (tuple.second);
+
+ info->solib_lists.clear ();
}
svr4_info::~svr4_info ()
{
- free_solib_list (this);
+ free_solib_lists (this);
}
/* Get the svr4 data for program space PSPACE. If none is found yet, add it now.
int pt_phdr_p = 0;
/* Get required auxv elements from target. */
- if (target_auxv_search (current_inferior ()->top_target (),
- AT_PHDR, &at_phdr) <= 0)
+ if (target_auxv_search (AT_PHDR, &at_phdr) <= 0)
return {};
- if (target_auxv_search (current_inferior ()->top_target (),
- AT_PHENT, &at_phent) <= 0)
+ if (target_auxv_search (AT_PHENT, &at_phent) <= 0)
return {};
- if (target_auxv_search (current_inferior ()->top_target (),
- AT_PHNUM, &at_phnum) <= 0)
+ if (target_auxv_search (AT_PHNUM, &at_phnum) <= 0)
return {};
if (!at_phdr || !at_phnum)
return {};
int sect_size = bfd_section_size (interp_sect);
gdb::byte_vector buf (sect_size);
- bfd_get_section_contents (current_program_space->exec_bfd (),
- interp_sect, buf.data (), 0, sect_size);
- return buf;
+ bool res
+ = bfd_get_section_contents (current_program_space->exec_bfd (),
+ interp_sect, buf.data (), 0, sect_size);
+ if (res)
+ return buf;
}
}
struct bound_minimal_symbol msymbol;
CORE_ADDR dyn_ptr, dyn_ptr_addr;
+ if (!svr4_have_link_map_offsets ())
+ return 0;
+
/* Look for DT_MIPS_RLD_MAP first. MIPS executables use this
instead of DT_DEBUG, although they sometimes contain an unused
DT_DEBUG. */
{
struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
gdb_byte *pbuf;
- int pbuf_size = TYPE_LENGTH (ptr_type);
+ int pbuf_size = ptr_type->length ();
pbuf = (gdb_byte *) alloca (pbuf_size);
/* DT_MIPS_RLD_MAP contains a pointer to the address
{
struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
gdb_byte *pbuf;
- int pbuf_size = TYPE_LENGTH (ptr_type);
+ int pbuf_size = ptr_type->length ();
pbuf = (gdb_byte *) alloca (pbuf_size);
/* DT_MIPS_RLD_MAP_REL contains an offset from the address of the
msymbol = lookup_minimal_symbol ("_r_debug", NULL,
current_program_space->symfile_object_file);
if (msymbol.minsym != NULL)
- return BMSYMBOL_VALUE_ADDRESS (msymbol);
+ return msymbol.value_address ();
/* DT_DEBUG entry not found. */
return 0;
}
-/* Locate the base address of dynamic linker structs.
-
- For both the SunOS and SVR4 shared library implementations, if the
- inferior executable has been linked dynamically, there is a single
- address somewhere in the inferior's data space which is the key to
- locating all of the dynamic linker's runtime structures. This
- address is the value of the debug base symbol. The job of this
- function is to find and return that address, or to return 0 if there
- is no such address (the executable is statically linked for example).
-
- For SunOS, the job is almost trivial, since the dynamic linker and
- all of it's structures are statically linked to the executable at
- link time. Thus the symbol for the address we are looking for has
- already been added to the minimal symbol table for the executable's
- objfile at the time the symbol file's symbols were read, and all we
- have to do is look it up there. Note that we explicitly do NOT want
- to find the copies in the shared library.
-
- The SVR4 version is a bit more complicated because the address
- is contained somewhere in the dynamic info section. We have to go
- to a lot more work to discover the address of the debug base symbol.
- Because of this complexity, we cache the value we find and return that
- value on subsequent invocations. Note there is no copy in the
- executable symbol tables. */
-
-static CORE_ADDR
-locate_base (struct svr4_info *info)
-{
- /* Check to see if we have a currently valid address, and if so, avoid
- doing all this work again and just return the cached address. If
- we have no cached address, try to locate it in the dynamic info
- section for ELF executables. There's no point in doing any of this
- though if we don't have some link map offsets to work with. */
-
- if (info->debug_base == 0 && svr4_have_link_map_offsets ())
- info->debug_base = elf_locate_base ();
- return info->debug_base;
-}
-
/* Find the first element in the inferior's dynamic link map, and
return its address in the inferior. Return zero if the address
could not be determined.
RT_CONSISTENT. */
static CORE_ADDR
-solib_svr4_r_map (struct svr4_info *info)
+solib_svr4_r_map (CORE_ADDR debug_base)
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
try
{
- addr = read_memory_typed_address (info->debug_base + lmo->r_map_offset,
+ addr = read_memory_typed_address (debug_base + lmo->r_map_offset,
ptr_type);
}
catch (const gdb_exception_error &ex)
ptr_type);
}
+/* Find the next namespace from the r_next field. */
+
+static CORE_ADDR
+solib_svr4_r_next (CORE_ADDR debug_base)
+{
+ link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
+ type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
+ bfd_endian byte_order = type_byte_order (ptr_type);
+ ULONGEST version = 0;
+
+ try
+ {
+ version
+ = read_memory_unsigned_integer (debug_base + lmo->r_version_offset,
+ lmo->r_version_size, byte_order);
+ }
+ catch (const gdb_exception_error &ex)
+ {
+ exception_print (gdb_stderr, ex);
+ }
+
+ /* The r_next field is added with r_version == 2. */
+ if (version < 2 || lmo->r_next_offset == -1)
+ return 0;
+
+ return read_memory_typed_address (debug_base + lmo->r_next_offset,
+ ptr_type);
+}
+
/* On Solaris systems with some versions of the dynamic linker,
ld.so's l_name pointer points to the SONAME in the string table
rather than into writable memory. So that GDB can find shared
info = get_svr4_info (current_program_space);
- info->debug_base = 0;
- locate_base (info);
- if (!info->debug_base)
+ info->debug_base = elf_locate_base ();
+ if (info->debug_base == 0)
return 0;
ldsomap = solib_svr4_r_ldsomap (info);
CORE_ADDR lm, l_name;
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
- int l_name_size = TYPE_LENGTH (ptr_type);
+ int l_name_size = ptr_type->length ();
gdb::byte_vector l_name_buf (l_name_size);
struct svr4_info *info = get_svr4_info (current_program_space);
symfile_add_flags add_flags = 0;
return 0;
/* Always locate the debug struct, in case it has moved. */
- info->debug_base = 0;
- if (locate_base (info) == 0)
+ info->debug_base = elf_locate_base ();
+ if (info->debug_base == 0)
return 0; /* failed somehow... */
/* First link map member should be the executable. */
- lm = solib_svr4_r_map (info);
+ lm = solib_svr4_r_map (info->debug_base);
if (lm == 0)
return 0; /* failed somehow... */
struct svr4_library_list
{
- struct so_list *head, **tailp;
+ /* The tail pointer of the current namespace. This is internal to XML
+ parsing. */
+ so_list **tailp;
/* Inferior address of struct link_map used for the main executable. It is
NULL if not known. */
CORE_ADDR main_lm;
+
+ /* List of objects loaded into the inferior per namespace. This does
+ not include any default sos.
+
+ See comment on struct svr4_info.solib_lists. */
+ std::map<CORE_ADDR, so_list *> solib_lists;
};
/* This module's 'free_objfile' observer. */
li->l_addr_p = 0;
}
-/* Free so_list built so far (called via cleanup). */
+/* Free so_list built so far. */
static void
-svr4_free_library_list (void *p_list)
+svr4_free_library_list (so_list *list)
{
- struct so_list *list = *(struct so_list **) p_list;
-
while (list != NULL)
{
struct so_list *next = list->next;
new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0;
strcpy (new_elem->so_original_name, new_elem->so_name);
- *list->tailp = new_elem;
- list->tailp = &new_elem->next;
+ /* Older versions did not supply lmid. Put the element into the flat
+ list of the special namespace zero in that case. */
+ gdb_xml_value *at_lmid = xml_find_attribute (attributes, "lmid");
+ if (at_lmid == nullptr)
+ {
+ *list->tailp = new_elem;
+ list->tailp = &new_elem->next;
+ }
+ else
+ {
+ ULONGEST lmid = *(ULONGEST *) at_lmid->value.get ();
+
+ /* Ensure that the element is actually initialized. */
+ if (list->solib_lists.find (lmid) == list->solib_lists.end ())
+ list->solib_lists[lmid] = nullptr;
+
+ so_list **psolist = &list->solib_lists[lmid];
+ so_list **pnext = psolist;
+
+ /* Walk to the end of the list if we have one. */
+ so_list *solist = *psolist;
+ if (solist != nullptr)
+ {
+ for (; solist->next != nullptr; solist = solist->next)
+ /* Nothing. */;
+
+ pnext = &solist->next;
+ }
+
+ *pnext = new_elem;
+ }
}
/* Handle the start of a <library-list-svr4> element. */
if (main_lm)
list->main_lm = *(ULONGEST *) main_lm->value.get ();
+
+ /* Older gdbserver do not support namespaces. We use the special
+ namespace zero for a linear list of libraries. */
+ so_list **solist = &list->solib_lists[0];
+ *solist = nullptr;
+ list->tailp = solist;
}
/* The allowed elements and attributes for an XML library list.
{ "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "lmid", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
static int
svr4_parse_libraries (const char *document, struct svr4_library_list *list)
{
- auto cleanup = make_scope_exit ([&] ()
+ auto cleanup = make_scope_exit ([list] ()
{
- svr4_free_library_list (&list->head);
+ for (const std::pair<CORE_ADDR, so_list *> tuple
+ : list->solib_lists)
+ svr4_free_library_list (tuple.second);
});
- memset (list, 0, sizeof (*list));
- list->tailp = &list->head;
+ list->tailp = nullptr;
+ list->main_lm = 0;
+ list->solib_lists.clear ();
if (gdb_xml_parse_quick (_("target library list"), "library-list-svr4.dtd",
svr4_library_list_elements, document, list) == 0)
{
newobj->lm_info = li;
/* Nothing will ever check the other fields if we set l_addr_p. */
- li->l_addr = info->debug_loader_offset;
+ li->l_addr = li->l_addr_inferior = info->debug_loader_offset;
li->l_addr_p = 1;
strncpy (newobj->so_name, info->debug_loader_name, SO_NAME_MAX_PATH_SIZE - 1);
/* 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. */
+ to the first elements of the list in default namespace. */
-static struct so_list *
+static void
svr4_current_sos_direct (struct svr4_info *info)
{
CORE_ADDR lm;
- struct so_list *head = NULL;
- struct so_list **link_ptr = &head;
- int ignore_first;
+ bool ignore_first;
struct svr4_library_list library_list;
+ /* Remove any old libraries. We're going to read them back in again. */
+ free_solib_lists (info);
+
/* Fall back to manual examination of the target if the packet is not
supported or gdbserver failed to find DT_DEBUG. gdb.server/solib-list.exp
tests a case where gdbserver cannot find the shared libraries list while
if (library_list.main_lm)
info->main_lm_addr = library_list.main_lm;
- return library_list.head ? library_list.head : svr4_default_sos (info);
+ /* Remove an empty special zero namespace so we know that when there
+ is one, it is actually used, and we have a flat list without
+ namespace information. */
+ if ((library_list.solib_lists.find (0)
+ != library_list.solib_lists.end ())
+ && (library_list.solib_lists[0] == nullptr))
+ library_list.solib_lists.erase (0);
+
+ /* Replace the (empty) solib_lists in INFO with the one generated
+ from the target. We don't want to copy it on assignment and then
+ delete the original afterwards, so let's just swap the
+ internals. */
+ std::swap (info->solib_lists, library_list.solib_lists);
+ return;
}
- /* Always locate the debug struct, in case it has moved. */
- info->debug_base = 0;
- locate_base (info);
-
/* 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 (info);
+ info->debug_base = elf_locate_base ();
+ if (info->debug_base == 0)
+ return;
/* Assume that everything is a library if the dynamic loader was loaded
late by a static executable. */
if (current_program_space->exec_bfd ()
&& bfd_get_section_by_name (current_program_space->exec_bfd (),
".dynamic") == NULL)
- ignore_first = 0;
+ ignore_first = false;
else
- ignore_first = 1;
+ ignore_first = true;
- auto cleanup = make_scope_exit ([&] ()
+ auto cleanup = make_scope_exit ([info] ()
{
- svr4_free_library_list (&head);
+ free_solib_lists (info);
});
- /* 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 (info, lm, 0, &link_ptr, ignore_first);
+ /* Collect the sos in each namespace. */
+ CORE_ADDR debug_base = info->debug_base;
+ for (; debug_base != 0;
+ ignore_first = false, debug_base = solib_svr4_r_next (debug_base))
+ {
+ /* Walk the inferior's link map list, and build our so_list list. */
+ lm = solib_svr4_r_map (debug_base);
+ if (lm != 0)
+ {
+ so_list **sos = &info->solib_lists[debug_base];
+ *sos = nullptr;
+
+ svr4_read_so_list (info, lm, 0, &sos, 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
symbol information for the dynamic linker is quite crucial
- for skipping dynamic linker resolver code. */
- lm = solib_svr4_r_ldsomap (info);
- if (lm)
- svr4_read_so_list (info, lm, 0, &link_ptr, 0);
+ for skipping dynamic linker resolver code.
+
+ Note that we interpret the ldsomap load map address as 'virtual'
+ r_debug object. If we added it to the default namespace (as it was),
+ we would probably run into inconsistencies with the load map's
+ prev/next links (I wonder if we did). */
+ debug_base = solib_svr4_r_ldsomap (info);
+ if (debug_base != 0)
+ {
+ /* Add the dynamic linker's namespace unless we already did. */
+ if (info->solib_lists.find (debug_base) == info->solib_lists.end ())
+ {
+ so_list **sos = &info->solib_lists[debug_base];
+ *sos = nullptr;
+ svr4_read_so_list (info, debug_base, 0, &sos, 0);
+ }
+ }
cleanup.release ();
+}
+
+/* Collect sos read and stored by the probes interface. */
- if (head == NULL)
- return svr4_default_sos (info);
+static so_list *
+svr4_collect_probes_sos (svr4_info *info)
+{
+ so_list *sos = nullptr;
+ so_list **pnext = &sos;
+
+ for (const std::pair<CORE_ADDR, so_list *> tuple
+ : info->solib_lists)
+ {
+ so_list *solist = tuple.second;
+
+ /* Allow the linker to report empty namespaces. */
+ if (solist == nullptr)
+ continue;
+
+ *pnext = svr4_copy_library_list (solist);
+
+ /* Update PNEXT to point to the next member of the last element. */
+ gdb_assert (*pnext != nullptr);
+ for (;;)
+ {
+ so_list *next = *pnext;
+ if (next == nullptr)
+ break;
+
+ pnext = &next->next;
+ }
+ }
- return head;
+ return sos;
}
/* Implement the main part of the "current_sos" target_so_ops
static struct so_list *
svr4_current_sos_1 (svr4_info *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);
+ so_list *sos = nullptr;
- /* Otherwise obtain the solib list directly from the inferior. */
- return svr4_current_sos_direct (info);
+ /* If we're using the probes interface, we can use the cache as it will
+ be maintained by probe update/reload actions. */
+ if (info->probes_table != nullptr)
+ sos = svr4_collect_probes_sos (info);
+
+ /* If we're not using the probes interface or if we didn't cache
+ anything, read the sos to fill the cache, then collect them from the
+ cache. */
+ if (sos == nullptr)
+ {
+ svr4_current_sos_direct (info);
+
+ sos = svr4_collect_probes_sos (info);
+ if (sos == nullptr)
+ sos = svr4_default_sos (info);
+ }
+
+ return sos;
}
/* Implement the "current_sos" target_so_ops method. */
{
enum probe_action action;
unsigned probe_argc = 0;
- struct frame_info *frame = get_current_frame ();
+ frame_info_ptr frame = get_current_frame ();
action = pa->action;
if (action == DO_NOTHING || action == PROBES_INTERFACE_FAILED)
static int
solist_update_full (struct svr4_info *info)
{
- free_solib_list (info);
- info->solib_list = svr4_current_sos_direct (info);
+ svr4_current_sos_direct (info);
return 1;
}
failure. */
static int
-solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
+solist_update_incremental (svr4_info *info, CORE_ADDR debug_base,
+ 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. */;
+ /* Fall back to a full update if we used the special namespace zero. We
+ wouldn't be able to find the last item in the DEBUG_BASE namespace
+ and hence get the prev link wrong. */
+ if (info->solib_lists.find (0) != info->solib_lists.end ())
+ return 0;
+
+ /* Ensure that the element is actually initialized. */
+ if (info->solib_lists.find (debug_base) == info->solib_lists.end ())
+ info->solib_lists[debug_base] = nullptr;
- lm_info_svr4 *li = (lm_info_svr4 *) tail->lm_info;
- prev_lm = li->lm_addr;
+ so_list **psolist = &info->solib_lists[debug_base];
+ so_list **pnext = nullptr;
+ so_list *solist = *psolist;
+ CORE_ADDR prev_lm;
+
+ if (solist == nullptr)
+ {
+ /* svr4_current_sos_direct contains logic to handle a number of
+ special cases relating to the first elements of the list in
+ default namespace. To avoid duplicating this logic we defer to
+ solist_update_full in this case. */
+ if (svr4_is_default_namespace (info, debug_base))
+ return 0;
+
+ prev_lm = 0;
+ pnext = psolist;
+ }
+ else
+ {
+ /* Walk to the end of the list. */
+ for (; solist->next != nullptr; solist = solist->next)
+ /* Nothing. */;
+
+ lm_info_svr4 *li = (lm_info_svr4 *) solist->lm_info;
+ prev_lm = li->lm_addr;
+ pnext = &solist->next;
+ }
/* 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",
+ /* Unknown key=value pairs are ignored by the gdbstub. */
+ xsnprintf (annex, sizeof (annex), "lmid=%s;start=%s;prev=%s",
+ phex_nz (debug_base, sizeof (debug_base)),
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;
+ /* Get the so list from the target. We replace the list in the
+ target response so we can easily check that the response only
+ covers one namespace.
+
+ We expect gdbserver to provide updates for the namespace that
+ contains LM, which would be this namespace... */
+ so_list *sos = nullptr;
+ if (library_list.solib_lists.find (debug_base)
+ != library_list.solib_lists.end ())
+ std::swap (sos, library_list.solib_lists[debug_base]);
+ if (sos == nullptr)
+ {
+ /* ...or for the special zero namespace for earlier versions... */
+ if (library_list.solib_lists.find (0)
+ != library_list.solib_lists.end ())
+ std::swap (sos, library_list.solib_lists[0]);
+ }
+
+ /* ...but nothing else. */
+ for (const std::pair<CORE_ADDR, so_list *> tuple
+ : library_list.solib_lists)
+ gdb_assert (tuple.second == nullptr);
+
+ *pnext = sos;
}
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 (info, lm, prev_lm, &link, 0))
+ if (!svr4_read_so_list (info, lm, prev_lm, &pnext, 0))
return 0;
}
"Reverting to original interface."));
free_probes_table (info);
- free_solib_list (info);
+ free_solib_lists (info);
}
/* Update the solib list as appropriate when using the
enum probe_action action;
struct value *val = NULL;
CORE_ADDR pc, debug_base, lm = 0;
- struct frame_info *frame = get_current_frame ();
+ frame_info_ptr frame = get_current_frame ();
/* Do nothing if not using the probes interface. */
if (info->probes_table == NULL)
return;
+ pc = regcache_read_pc (get_current_regcache ());
+ pa = solib_event_probe_at (info, pc);
+ if (pa == nullptr)
+ {
+ /* When some solib ops sits above us, it can respond to a solib event
+ by calling in here. This is done assuming that if the current event
+ is not an SVR4 solib event, calling here should be a no-op. */
+ return;
+ }
+
/* If anything goes wrong we revert to the original linker
interface. */
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)
- return;
-
action = solib_event_probe_action (pa);
if (action == PROBES_INTERFACE_FAILED)
return;
if (debug_base == 0)
return;
- /* Always locate the debug struct, in case it moved. */
- info->debug_base = 0;
- if (locate_base (info) == 0)
+ /* If the global _r_debug object moved, we need to reload everything
+ since we cannot identify namespaces (by the location of their
+ r_debug_ext object) anymore. */
+ CORE_ADDR global_debug_base = elf_locate_base ();
+ if (global_debug_base != info->debug_base)
+ {
+ info->debug_base = global_debug_base;
+ action = FULL_RELOAD;
+ }
+
+ if (info->debug_base == 0)
{
/* It's possible for the reloc_complete probe to be triggered before
the linker has set the DT_DEBUG pointer (for example, when the
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)
{
try
if (action == UPDATE_OR_RELOAD)
{
- if (!solist_update_incremental (info, lm))
+ if (!solist_update_incremental (info, debug_base, lm))
action = FULL_RELOAD;
}
return false;
}
- for (bp_location *loc : b->locations ())
+ for (bp_location &loc : b->locations ())
{
struct svr4_info *info;
struct probe_and_action *pa;
- info = solib_svr4_pspace_data.get (loc->pspace);
+ info = solib_svr4_pspace_data.get (loc.pspace);
if (info == NULL || info->probes_table == NULL)
continue;
- pa = solib_event_probe_at (info, loc->address);
+ pa = solib_event_probe_at (info, loc.address);
if (pa == NULL)
continue;
static void
svr4_update_solib_event_breakpoints (void)
{
- for (breakpoint *bp : all_breakpoints_safe ())
- svr4_update_solib_event_breakpoint (bp);
+ for (breakpoint &bp : all_breakpoints_safe ())
+ svr4_update_solib_event_breakpoint (&bp);
}
/* Create and register solib event breakpoints. PROBES is an array
{
CORE_ADDR address = p->get_relocated_address (objfile);
+ solib_debug_printf ("name=%s, addr=%s", probe_info[i].name,
+ paddress (gdbarch, address));
+
create_solib_event_breakpoint (gdbarch, address);
register_solib_event_probe (info, objfile, p, address, action);
}
struct obj_section *os,
bool with_prefix)
{
+ SOLIB_SCOPED_DEBUG_START_END ("objfile=%s, with_prefix=%d",
+ os->objfile->original_name, with_prefix);
+
std::vector<probe *> probes[NUM_PROBES];
for (int i = 0; i < NUM_PROBES; i++)
}
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 (with_prefix && streq (name, "rtld_map_failed"))
- continue;
+ solib_debug_printf ("probe=%s, num found=%zu", name, probes[i].size ());
/* Ensure at least one probe for the current name was found. */
if (probes[i].empty ())
- return false;
+ {
+ /* The "map_failed" probe did not exist in early versions of the
+ probes code in which the probes' names were prefixed with
+ "rtld_".
+
+ Additionally, the "map_failed" probe was accidentally removed
+ from glibc 2.35 and 2.36, when changes in glibc meant the
+ probe could no longer be reached, and the compiler optimized
+ the probe away. In this case the probe name doesn't have the
+ "rtld_" prefix.
+
+ To handle this, and give GDB as much flexibility as possible,
+ we make the rule that, if a probe isn't required for the
+ correct operation of GDB (i.e. its action is DO_NOTHING), then
+ we will still use the probes interface, even if that probe is
+ missing.
+
+ The only (possible) downside of this is that, if the user has
+ 'set stop-on-solib-events on' in effect, then they might get
+ fewer events using the probes interface than with the classic
+ non-probes interface. */
+ if (probe_info[i].action == DO_NOTHING)
+ continue;
+ else
+ return false;
+ }
/* Ensure probe arguments can be evaluated. */
for (probe *p : probes[i])
}
/* All probes found. Now create them. */
+ solib_debug_printf ("using probes interface");
svr4_create_probe_breakpoints (info, gdbarch, probes, os->objfile);
return true;
}
if (os == nullptr
|| (!svr4_find_and_create_probe_breakpoints (info, gdbarch, os, false)
&& !svr4_find_and_create_probe_breakpoints (info, gdbarch, os, true)))
- create_solib_event_breakpoint (gdbarch, address);
+ {
+ solib_debug_printf ("falling back to r_brk breakpoint: addr=%s",
+ paddress (gdbarch, address));
+ create_solib_event_breakpoint (gdbarch, address);
+ }
}
-/* Helper function for gdb_bfd_lookup_symbol. */
-
-static int
-cmp_name_and_sec_flags (const asymbol *sym, const void *data)
-{
- return (strcmp (sym->name, (const char *) data) == 0
- && (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0);
-}
/* Arrange for dynamic linker to hit breakpoint.
Both the SunOS and the SVR4 dynamic linkers have, as part of their
set to 1. When the dynamic linker sees this flag set, it will set
a breakpoint at a location known only to itself, after saving the
original contents of that place and the breakpoint address itself,
- in it's own internal structures. When we resume the inferior, it
+ in its own internal structures. When we resume the inferior, it
will eventually take a SIGTRAP when it runs into the breakpoint.
We handle this (in a different place) by restoring the contents of
the breakpointed location (which is only known after it stops),
solib_add (NULL, from_tty, auto_solib_add);
sym_addr = 0;
- if (info->debug_base && solib_svr4_r_map (info) != 0)
+ if (info->debug_base && solib_svr4_r_map (info->debug_base) != 0)
sym_addr = solib_svr4_r_brk (info);
if (sym_addr != 0)
bfd *tmp_bfd;
CORE_ADDR load_addr;
- tmp_bfd = os->objfile->obfd;
+ tmp_bfd = os->objfile->obfd.get ();
load_addr = os->objfile->text_section_offset ();
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
CORE_ADDR load_addr = 0;
int load_addr_found = 0;
int loader_found_in_list = 0;
- struct target_ops *tmp_bfd_target;
+ target_ops_up tmp_bfd_target;
sym_addr = 0;
/* If we were not able to find the base address of the loader
from our so_list, then try using the AT_BASE auxilliary entry. */
if (!load_addr_found)
- if (target_auxv_search (current_inferior ()->top_target (),
- AT_BASE, &load_addr) > 0)
+ if (target_auxv_search (AT_BASE, &load_addr) > 0)
{
int addr_bit = gdbarch_addr_bit (target_gdbarch ());
if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
{
CORE_ADDR space_size = (CORE_ADDR) 1 << addr_bit;
- CORE_ADDR tmp_entry_point = exec_entry_point (tmp_bfd.get (),
- tmp_bfd_target);
+ CORE_ADDR tmp_entry_point
+ = exec_entry_point (tmp_bfd.get (), tmp_bfd_target.get ());
gdb_assert (load_addr < space_size);
inferior_ptid, target_gdbarch ());
load_addr = (regcache_read_pc (regcache)
- - exec_entry_point (tmp_bfd.get (), tmp_bfd_target));
+ - exec_entry_point (tmp_bfd.get (),
+ tmp_bfd_target.get ()));
}
if (!loader_found_in_list)
/* Now try to set a breakpoint in the dynamic linker. */
for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++)
{
- sym_addr = gdb_bfd_lookup_symbol (tmp_bfd.get (),
- cmp_name_and_sec_flags,
- *bkpt_namep);
+ sym_addr
+ = (gdb_bfd_lookup_symbol
+ (tmp_bfd.get (),
+ [=] (const asymbol *sym)
+ {
+ return (strcmp (sym->name, *bkpt_namep) == 0
+ && ((sym->section->flags & (SEC_CODE | SEC_DATA))
+ != 0));
+ }));
if (sym_addr != 0)
break;
}
target, this will always produce an unrelocated value. */
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
- tmp_bfd_target);
-
- /* We're done with both the temporary bfd and target. Closing
- the target closes the underlying bfd, because it holds the
- only remaining reference. */
- target_close (tmp_bfd_target);
+ tmp_bfd_target.get ());
if (sym_addr != 0)
{
{
msymbol = lookup_minimal_symbol (*bkpt_namep, NULL, objf);
if ((msymbol.minsym != NULL)
- && (BMSYMBOL_VALUE_ADDRESS (msymbol) != 0))
+ && (msymbol.value_address () != 0))
{
- sym_addr = BMSYMBOL_VALUE_ADDRESS (msymbol);
+ sym_addr = msymbol.value_address ();
sym_addr = gdbarch_convert_from_func_ptr_addr
(target_gdbarch (), sym_addr, current_inferior ()->top_target ());
svr4_create_solib_event_breakpoints (info, target_gdbarch (),
{
msymbol = lookup_minimal_symbol (*bkpt_namep, NULL, objf);
if ((msymbol.minsym != NULL)
- && (BMSYMBOL_VALUE_ADDRESS (msymbol) != 0))
+ && (msymbol.value_address () != 0))
{
- sym_addr = BMSYMBOL_VALUE_ADDRESS (msymbol);
+ sym_addr = msymbol.value_address ();
sym_addr = gdbarch_convert_from_func_ptr_addr
(target_gdbarch (), sym_addr,
current_inferior ()->top_target ());
gdb::byte_vector buf (phdrs_size);
if (bfd_seek (abfd, ehdr->e_phoff, SEEK_SET) != 0
- || bfd_bread (buf.data (), phdrs_size, abfd) != phdrs_size)
+ || bfd_read (buf.data (), phdrs_size, abfd) != phdrs_size)
return {};
return buf;
whose e_type member in the ELF header is not ET_DYN. There may
be a time in the future when it is desirable to do relocations
on other types of files as well in which case this condition
- should either be removed or modified to accomodate the new file
+ should either be removed or modified to accommodate the new file
type. - Kevin, Nov 2000. ] */
static int
if ((bfd_get_file_flags (current_program_space->exec_bfd ()) & DYNAMIC) == 0)
return 0;
- if (target_auxv_search (current_inferior ()->top_target (),
- AT_ENTRY, &entry_point) <= 0)
+ if (target_auxv_search (AT_ENTRY, &entry_point) <= 0)
return 0;
exec_displacement
/* Clear the probes-based interface's state. */
free_probes_table (info);
- free_solib_list (info);
+ free_solib_lists (info);
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
/* Architecture-specific operations. */
-/* Per-architecture data key. */
-static struct gdbarch_data *solib_svr4_data;
-
struct solib_svr4_ops
{
/* Return a description of the layout of `struct link_map'. */
- struct link_map_offsets *(*fetch_link_map_offsets)(void);
+ struct link_map_offsets *(*fetch_link_map_offsets)(void) = nullptr;
};
+/* Per-architecture data key. */
+static const registry<gdbarch>::key<struct solib_svr4_ops> solib_svr4_data;
+
/* Return a default for the architecture-specific operations. */
-static void *
-solib_svr4_init (struct obstack *obstack)
+static struct solib_svr4_ops *
+get_ops (struct gdbarch *gdbarch)
{
- struct solib_svr4_ops *ops;
-
- ops = OBSTACK_ZALLOC (obstack, struct solib_svr4_ops);
- ops->fetch_link_map_offsets = NULL;
+ struct solib_svr4_ops *ops = solib_svr4_data.get (gdbarch);
+ if (ops == nullptr)
+ ops = solib_svr4_data.emplace (gdbarch);
return ops;
}
set_solib_svr4_fetch_link_map_offsets (struct gdbarch *gdbarch,
struct link_map_offsets *(*flmo) (void))
{
- struct solib_svr4_ops *ops
- = (struct solib_svr4_ops *) gdbarch_data (gdbarch, solib_svr4_data);
+ struct solib_svr4_ops *ops = get_ops (gdbarch);
ops->fetch_link_map_offsets = flmo;
- set_solib_ops (gdbarch, &svr4_so_ops);
+ set_gdbarch_so_ops (gdbarch, &svr4_so_ops);
set_gdbarch_iterate_over_objfiles_in_search_order
(gdbarch, svr4_iterate_over_objfiles_in_search_order);
}
static struct link_map_offsets *
svr4_fetch_link_map_offsets (void)
{
- struct solib_svr4_ops *ops
- = (struct solib_svr4_ops *) gdbarch_data (target_gdbarch (),
- solib_svr4_data);
+ struct solib_svr4_ops *ops = get_ops (target_gdbarch ());
gdb_assert (ops->fetch_link_map_offsets);
return ops->fetch_link_map_offsets ();
static int
svr4_have_link_map_offsets (void)
{
- struct solib_svr4_ops *ops
- = (struct solib_svr4_ops *) gdbarch_data (target_gdbarch (),
- solib_svr4_data);
+ struct solib_svr4_ops *ops = get_ops (target_gdbarch ());
return (ops->fetch_link_map_offsets != NULL);
}
lmo.r_map_offset = 4;
lmo.r_brk_offset = 8;
lmo.r_ldsomap_offset = 20;
+ lmo.r_next_offset = -1;
/* Everything we need is in the first 20 bytes. */
lmo.link_map_size = 20;
lmo.r_map_offset = 8;
lmo.r_brk_offset = 16;
lmo.r_ldsomap_offset = 40;
+ lmo.r_next_offset = -1;
/* Everything we need is in the first 40 bytes. */
lmo.link_map_size = 40;
}
\f
-struct target_so_ops svr4_so_ops;
+/* Return the DSO matching OBJFILE or nullptr if none can be found. */
+
+static so_list *
+find_solib_for_objfile (struct objfile *objfile)
+{
+ if (objfile == nullptr)
+ return nullptr;
+
+ /* If OBJFILE is a separate debug object file, look for the original
+ object file. */
+ if (objfile->separate_debug_objfile_backlink != nullptr)
+ objfile = objfile->separate_debug_objfile_backlink;
+
+ for (so_list *so : current_program_space->solibs ())
+ if (so->objfile == objfile)
+ return so;
+
+ return nullptr;
+}
+
+/* Return the address of the r_debug object for the namespace containing
+ SOLIB or zero if it cannot be found. This may happen when symbol files
+ are added manually, for example, or with the main executable.
+
+ Current callers treat zero as initial namespace so they are doing the
+ right thing for the main executable. */
+
+static CORE_ADDR
+find_debug_base_for_solib (so_list *solib)
+{
+ if (solib == nullptr)
+ return 0;
+
+ svr4_info *info = get_svr4_info (current_program_space);
+ gdb_assert (info != nullptr);
+ for (const std::pair<CORE_ADDR, so_list *> tuple
+ : info->solib_lists)
+ {
+ CORE_ADDR debug_base = tuple.first;
+ so_list *solist = tuple.second;
+
+ for (; solist != nullptr; solist = solist->next)
+ if (svr4_same (solib, solist))
+ return debug_base;
+ }
+
+ return 0;
+}
/* Search order for ELF DSOs linked with -Bsymbolic. Those DSOs have a
- different rule for symbol lookup. The lookup begins here in the DSO, not in
- the main executable. */
+ different rule for symbol lookup. The lookup begins here in the DSO,
+ not in the main executable. When starting from CURRENT_OBJFILE, we
+ stay in the same namespace as that file. Otherwise, we only consider
+ the initial namespace. */
static void
svr4_iterate_over_objfiles_in_search_order
- (struct gdbarch *gdbarch,
- iterate_over_objfiles_in_search_order_cb_ftype *cb,
- void *cb_data, struct objfile *current_objfile)
+ (gdbarch *gdbarch, iterate_over_objfiles_in_search_order_cb_ftype cb,
+ objfile *current_objfile)
{
bool checked_current_objfile = false;
if (current_objfile != nullptr)
if (current_objfile == current_program_space->symfile_object_file)
abfd = current_program_space->exec_bfd ();
else
- abfd = current_objfile->obfd;
+ abfd = current_objfile->obfd.get ();
if (abfd != nullptr
&& gdb_bfd_scan_elf_dyntag (DT_SYMBOLIC, abfd, nullptr, nullptr) == 1)
{
checked_current_objfile = true;
- if (cb (current_objfile, cb_data) != 0)
+ if (cb (current_objfile))
return;
}
}
+ /* The linker namespace to iterate identified by the address of its
+ r_debug object, defaulting to the initial namespace. */
+ CORE_ADDR initial = elf_locate_base ();
+ so_list *curr_solib = find_solib_for_objfile (current_objfile);
+ CORE_ADDR debug_base = find_debug_base_for_solib (curr_solib);
+ if (debug_base == 0)
+ debug_base = initial;
+
for (objfile *objfile : current_program_space->objfiles ())
{
if (checked_current_objfile && objfile == current_objfile)
continue;
- if (cb (objfile, cb_data) != 0)
+
+ /* Try to determine the namespace into which objfile was loaded.
+
+ If we fail, e.g. for manually added symbol files or for the main
+ executable, we assume that they were added to the initial
+ namespace. */
+ so_list *solib = find_solib_for_objfile (objfile);
+ CORE_ADDR solib_base = find_debug_base_for_solib (solib);
+ if (solib_base == 0)
+ solib_base = initial;
+
+ /* Ignore objfiles that were added to a different namespace. */
+ if (solib_base != debug_base)
+ continue;
+
+ if (cb (objfile))
return;
}
}
+const struct target_so_ops svr4_so_ops =
+{
+ svr4_relocate_section_addresses,
+ svr4_free_so,
+ svr4_clear_so,
+ svr4_clear_solib,
+ svr4_solib_create_inferior_hook,
+ svr4_current_sos,
+ open_symbol_file_object,
+ svr4_in_dynsym_resolve_code,
+ solib_bfd_open,
+ nullptr,
+ svr4_same,
+ svr4_keep_data_in_core,
+ svr4_update_solib_event_breakpoints,
+ svr4_handle_solib_event,
+};
+
void _initialize_svr4_solib ();
void
_initialize_svr4_solib ()
{
- solib_svr4_data = gdbarch_data_register_pre_init (solib_svr4_init);
-
- svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses;
- svr4_so_ops.free_so = svr4_free_so;
- svr4_so_ops.clear_so = svr4_clear_so;
- svr4_so_ops.clear_solib = svr4_clear_solib;
- svr4_so_ops.solib_create_inferior_hook = svr4_solib_create_inferior_hook;
- svr4_so_ops.current_sos = svr4_current_sos;
- svr4_so_ops.open_symbol_file_object = open_symbol_file_object;
- svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code;
- svr4_so_ops.bfd_open = solib_bfd_open;
- 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;
-
gdb::observers::free_objfile.attach (svr4_free_objfile_observer,
"solib-svr4");
}