const lm_info_svr4 &gdb_lm_info,
const lm_info_svr4 &inferior_lm_info)
{
- if (!svr4_same_name (gdb_name, inferior_name))
+ /* There may be different instances of the same library, in different
+ namespaces. Each instance is typically loaded at a different address
+ so its relocation offset would be different. */
+ if (gdb_lm_info.l_addr_inferior != inferior_lm_info.l_addr_inferior)
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. */
- return gdb_lm_info.l_addr_inferior == inferior_lm_info.l_addr_inferior;
+ /* There may be multiple entries for the same dynamic linker instance (at
+ the same address) visible in different namespaces. Those are considered
+ different instances. */
+ if (gdb_lm_info.debug_base != inferior_lm_info.debug_base)
+ return false;
+
+ return svr4_same_name (gdb_name, inferior_name);
}
bool
}
lm_info_svr4_up
-svr4_solib_ops::read_lm_info (CORE_ADDR lm_addr) const
+svr4_solib_ops::read_lm_info (CORE_ADDR lm_addr, CORE_ADDR debug_base) const
{
link_map_offsets *lmo = this->fetch_link_map_offsets ();
lm_info_svr4_up lm_info;
type *ptr_type
= builtin_type (current_inferior ()->arch ())->builtin_data_ptr;
- lm_info = std::make_unique<lm_info_svr4> ();
+ lm_info = std::make_unique<lm_info_svr4> (debug_base);
lm_info->lm_addr = lm_addr;
lm_info->l_addr_inferior = extract_typed_address (&lm[lmo->l_addr_offset],
CORE_ADDR default_debug_base = locate_default_debug_base ();
if (changed != nullptr)
- *changed = default_debug_base == info->default_debug_base;
+ *changed = default_debug_base != info->default_debug_base;
- info->default_debug_base = default_debug_base;
- return default_debug_base;
+ if (default_debug_base != info->default_debug_base)
+ {
+ /* Update the debug base value for existing solibs. The only known case
+ where this is required is when a struct solib was created for the
+ dynamic linker itself by svr4_solib_ops::default_sos, before the
+ default debug base was known. */
+ for (const auto &solib : m_pspace->solibs ())
+ {
+ if (&solib.ops () != this)
+ continue;
+
+ if (auto &li = get_lm_info_svr4 (solib);
+ li.debug_base == info->default_debug_base)
+ li.debug_base = default_debug_base;
+ }
+
+ info->default_debug_base = default_debug_base;
+ }
+
+ return info->default_debug_base;
}
/* Find the first element in the inferior's dynamic link map, and
if (!ldsomap)
return false;
- std::unique_ptr<lm_info_svr4> li = this->read_lm_info (ldsomap);
+ std::unique_ptr<lm_info_svr4> li
+ = this->read_lm_info (ldsomap, info->default_debug_base);
name_lm = li != NULL ? li->l_name : 0;
return (name_lm >= vaddr && name_lm < vaddr + size);
ULONGEST *l_ldp
= (ULONGEST *) xml_find_attribute (attributes, "l_ld")->value.get ();
- lm_info_svr4_up li = std::make_unique<lm_info_svr4> ();
- li->lm_addr = *lmp;
- li->l_addr_inferior = *l_addrp;
- li->l_ld = *l_ldp;
-
std::vector<svr4_so> *solist;
/* 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");
svr4_info *info = get_svr4_info (current_program_space);
+ ULONGEST lmid;
+
if (at_lmid == nullptr)
{
solist = list->cur_list;
svr4_maybe_add_namespace (info, 0);
+ lmid = 0;
}
else
{
- ULONGEST lmid = *(ULONGEST *) at_lmid->value.get ();
+ lmid = *(ULONGEST *) at_lmid->value.get ();
solist = &list->solib_lists[lmid];
svr4_maybe_add_namespace (info, lmid);
}
+
+ lm_info_svr4_up li = std::make_unique<lm_info_svr4> (lmid);
+
+ li->lm_addr = *lmp;
+ li->l_addr_inferior = *l_addrp;
+ li->l_ld = *l_ldp;
+
solist->emplace_back (name, std::move (li));
}
if (!info->debug_loader_offset_p)
return {};
- auto li = std::make_unique<lm_info_svr4> ();
+ auto li = std::make_unique<lm_info_svr4> (0);
/* Nothing will ever check the other fields if we set l_addr_p. */
li->l_addr = li->l_addr_inferior = info->debug_loader_offset;
int
svr4_solib_ops::read_so_list (svr4_info *info, CORE_ADDR lm, CORE_ADDR prev_lm,
- std::vector<svr4_so> &sos, int ignore_first) const
+ CORE_ADDR debug_base, std::vector<svr4_so> &sos,
+ int ignore_first) const
{
CORE_ADDR first_l_name = 0;
CORE_ADDR next_lm;
for (; lm != 0; prev_lm = lm, lm = next_lm)
{
- lm_info_svr4_up li = this->read_lm_info (lm);
+ lm_info_svr4_up li = this->read_lm_info (lm, debug_base);
if (li == NULL)
return 0;
if (lm != 0)
{
svr4_maybe_add_namespace (info, debug_base);
- this->read_so_list (info, lm, 0, info->solib_lists[debug_base],
- ignore_first);
+ this->read_so_list (info, lm, 0, debug_base,
+ info->solib_lists[debug_base], ignore_first);
}
}
if (info->solib_lists.find (debug_base) == info->solib_lists.end ())
{
svr4_maybe_add_namespace (info, debug_base);
- this->read_so_list (info, debug_base, 0,
+ this->read_so_list (info, debug_base, 0, debug_base,
info->solib_lists[debug_base], 0);
}
}
above check and deferral to solist_update_full ensures
that this call to svr4_read_so_list will never see the
first element. */
- if (!this->read_so_list (info, lm, prev_lm, solist, 0))
+ if (!this->read_so_list (info, lm, prev_lm, debug_base, solist, 0))
return 0;
}
auto &lm_info = get_lm_info_svr4 (*solib);
- for (const auto &[debug_base, sos] : info->solib_lists)
- for (const svr4_so &so : sos)
- if (svr4_same (solib->original_name.c_str (), so.name.c_str (), lm_info,
- *so.lm_info))
- return debug_base;
-
- return 0;
+ return lm_info.debug_base;
}
/* Search order for ELF DSOs linked with -Bsymbolic. Those DSOs have a
struct lm_info_svr4 final : public lm_info
{
+ explicit lm_info_svr4 (CORE_ADDR debug_base)
+ : debug_base (debug_base)
+ {}
+
/* Amount by which addresses in the binary should be relocated to
match the inferior. The direct inferior value is L_ADDR_INFERIOR.
When prelinking is involved and the prelink base address changes,
/* Values read in from inferior's fields of the same name. */
CORE_ADDR l_ld = 0, l_next = 0, l_prev = 0, l_name = 0;
+
+ /* The address of the dynamic linker structure (r_debug) this solib comes
+ from. This identifies which namespace this library is in.
+
+ This field can be 0 in the following situations:
+
+ - we receive the libraries through XML from an old gdbserver that
+ doesn't include the "lmid" field
+ - the default debug base is not yet known
+
+ In other cases, this field should have a sensible value. */
+ CORE_ADDR debug_base;
};
using lm_info_svr4_up = std::unique_ptr<lm_info_svr4>;
CORE_ADDR find_r_ldsomap (svr4_info *info) const;
owning_intrusive_list<solib> default_sos (svr4_info *info) const;
int read_so_list (svr4_info *info, CORE_ADDR lm, CORE_ADDR prev_lm,
- std::vector<svr4_so> &sos, int ignore_first) const;
- lm_info_svr4_up read_lm_info (CORE_ADDR lm_addr) const;
+ CORE_ADDR debug_base, std::vector<svr4_so> &sos,
+ int ignore_first) const;
+ lm_info_svr4_up read_lm_info (CORE_ADDR lm_addr, CORE_ADDR debug_base) const;
int has_lm_dynamic_from_link_map () const;
CORE_ADDR lm_addr_check (const solib &so, bfd *abfd) const;
CORE_ADDR read_r_next (CORE_ADDR debug_base) const;
return
}
+# Return a list of shared libraries extract from the "info sharedlibrary"
+# command. Each item in the list is itself a list with the following items:
+#
+# - "from" address
+# - "to" address
+# - namespace ID
+# - name (file path)
+
+proc get_info_shared {{arg ""}} {
+ set from_re "($::hex)\\s+"
+ set to_re "($::hex)\\s+"
+ set ns_re "(?:($::decimal)\\s+)?"
+ set syms_read_re "(Yes( \\(\\*\\))?|No)\\s+"
+ set name_re "(\[^\r\n\]+)"
+ set libs {}
+
+ gdb_test_multiple "info sharedlibrary $arg" "" {
+ -re {From\s+To\s+(NS\s+)?Syms Read\s+Shared Object Library\r\n} {
+ exp_continue
+ }
+
+ -re "^${from_re}${to_re}${ns_re}${syms_read_re}${name_re}\r\n" {
+ set from $expect_out(1,string)
+ set to $expect_out(2,string)
+ set ns $expect_out(3,string)
+ set name $expect_out(4,string)
+
+ lappend libs [list $from $to $ns $name]
+ exp_continue
+ }
+
+ -re {^\(\*\): Shared library is missing debugging information\.\r\n} {
+ exp_continue
+ }
+
+ -re "^$::gdb_prompt " {
+ pass $gdb_test_name
+ }
+ }
+
+ return $libs
+}
+
+# Verify that "info sharedlibrary" does not contain duplicate entries.
+
+proc check_no_duplicates {} {
+ with_test_prefix "check no duplicates" {
+ set libs [get_info_shared]
+ array set seen {}
+ set seen_duplicate 0
+
+ foreach lib $libs {
+ if {[info exists seen($lib)]} {
+ verbose -log "already seen: $lib"
+ set seen_duplicate 1
+ }
+
+ set seen($lib) 1
+ }
+
+ gdb_assert {!$seen_duplicate} "no duplicates"
+ }
+}
+
# Run the command "info sharedlibrary" and get the first namespace
# for the so
proc get_first_so_ns {} {
"From\\s+To\\s+Linker NS\\s+Syms\\s+Read\\s+Shared Object Library.*" \
"after loading everything"
+ check_no_duplicates
+
gdb_assert {[get_first_so_ns] == 1} "before closing any library"
gdb_test "next" ".*second dlclose.*" "close first library"