mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-04-12 14:33:06 +08:00
gdb: Introduce user-friendly namespace identifier for "info shared"
GDB has had basic support for linkage namespaces for some time already, but only in the sense of managing multiple copies of the same shared object being loaded, and a very fragile way to find the correct copy of a symbol (see PR shlibs/32054). This commit is the first step in improving the user experience around multiple namespace support. It introduces a user-friendly identifier for namespaces, in the format [[<number>]], that will keep consistent between dlmopen and dlclose calls. The plan is for this identifier to be usable in expressions like `print [[1]]::var` to find a specific instance of a symbol, and so the identifier must not be a valid C++ or Ada namespace identifier, otherwise disambiguation becomes a problem. Support for those expressions has not been implemented yet, it is only mentioned to explain why the identifier looks like this. This syntax was chosen based on the C attributes, since nothing in GDB uses a similar syntax that could confuse users. Other syntax options that were explored were "#<number>" and "@<number>". The former was abandoned because when printing a frame, the frame number is also printed with #<number>, so in a lot of the context in which that the identifier would show up, it appears in a confusing way. The latter clashes with the array printing syntax, and I believe that the having "@N::foo" working completely differently to "foo@2" would also lead to a bad user experience. The namespace identifiers are stored via a vector inside svr4_info object. The vector stores the address of the r_debug objects used by glibc to identify each namespace, and the user-friendly ID is the index of the r_debug in the vector. This commit also introduces a set storing the indices of active namespaces. The glibc I used to develop this patch (glibc 2.40 on Fedora 41) doesn't allow an SO to be loaded into a deactivated namespace, and requesting a new namespace when a namespace was previously closed will reuse that namespace. Because of how this is implemented, this patch lets GDB easily track the exact namespace IDs that the inferior will see. Finally, two new solib_ops function pointers were added, find_solib_ns and num_active_namespaces, to allow code outside of solib-svr4 to find and use the namespace identifiers and the number of namespaces, respectively. As a sanity check, the command `info sharedlibrary` has been changed to display the namespace identifier when the inferior has more than one active namespace. With this final change, a couple of tests had to be tweaked to handle the possible new column, and a new test has been created to make sure that the column appears and disappears as needed, and that GDB can track the value of the LMID for namespaces. Approved-by: Kevin Buettner <kevinb@redhat.com>
This commit is contained in:
parent
fcdce14251
commit
29bff2380e
5
gdb/NEWS
5
gdb/NEWS
@ -35,6 +35,11 @@
|
||||
a -h or --help option, which prints each options and a brief
|
||||
description.
|
||||
|
||||
* On systems that support linkage namespaces, the output of the command
|
||||
"info sharedlibraries" may add one more column, NS, which identifies the
|
||||
namespace into which the library was loaded, if more than one namespace
|
||||
is active.
|
||||
|
||||
* New commands
|
||||
|
||||
maintenance check psymtabs
|
||||
|
@ -22172,6 +22172,11 @@ be determined then the address range for the @code{.text} section from
|
||||
the library will be listed. If the @code{.text} section cannot be
|
||||
found then no addresses will be listed.
|
||||
|
||||
On systems that support linkage namespaces, the output includes an
|
||||
additional column @code{NS} if the inferior has more than one active
|
||||
namespace when the command is used. This column the linkage namespace
|
||||
that the shared library was loaded into.
|
||||
|
||||
@kindex info dll
|
||||
@item info dll @var{regex}
|
||||
This is an alias of @code{info sharedlibrary}.
|
||||
|
108
gdb/solib-svr4.c
108
gdb/solib-svr4.c
@ -405,11 +405,54 @@ struct svr4_info
|
||||
The special entry zero is reserved for a linear list to support
|
||||
gdbstubs that do not support namespaces. */
|
||||
std::map<CORE_ADDR, std::vector<svr4_so>> solib_lists;
|
||||
|
||||
/* Mapping between r_debug[_ext] addresses and a user-friendly
|
||||
identifier for the namespace. A vector is used to make it
|
||||
easy to assign new internal IDs to namespaces.
|
||||
|
||||
For gdbservers that don't support namespaces, the first (and only)
|
||||
entry of the vector will be 0.
|
||||
|
||||
A note on consistency. We can't make the IDs be consistent before
|
||||
and after the initial relocation of the inferior (when the global
|
||||
_r_debug is relocated, as mentioned in the previous comment). It is
|
||||
likely that this is a non-issue, since the inferior can't have called
|
||||
dlmopen yet, but I think it is worth noting.
|
||||
|
||||
The only issue I am aware at this point is that, if when parsing an
|
||||
XML file, we read an LMID that given by an XML file (and read in
|
||||
library_list_start_library) is the identifier obtained with dlinfo
|
||||
instead of the address of r_debug[_ext], and after attaching the
|
||||
inferior adds another SO to that namespace, we might double-count it
|
||||
since we won't have access to the LMID later on. However, this is
|
||||
already a problem with the existing solib_lists code. */
|
||||
std::vector<CORE_ADDR> namespace_id;
|
||||
|
||||
/* This identifies which namespaces are active. A namespace is considered
|
||||
active when there is at least one shared object loaded into it. */
|
||||
std::set<size_t> active_namespaces;
|
||||
};
|
||||
|
||||
/* Per-program-space data key. */
|
||||
static const registry<program_space>::key<svr4_info> solib_svr4_pspace_data;
|
||||
|
||||
/* Check if the lmid address is already assigned an ID in the svr4_info,
|
||||
and if not, assign it one and add it to the list of known namespaces. */
|
||||
static void
|
||||
svr4_maybe_add_namespace (svr4_info *info, CORE_ADDR lmid)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < info->namespace_id.size (); i++)
|
||||
{
|
||||
if (info->namespace_id[i] == lmid)
|
||||
break;
|
||||
}
|
||||
if (i == info->namespace_id.size ())
|
||||
info->namespace_id.push_back (lmid);
|
||||
|
||||
info->active_namespaces.insert (i);
|
||||
}
|
||||
|
||||
/* Return whether DEBUG_BASE is the default namespace of INFO. */
|
||||
|
||||
static bool
|
||||
@ -1041,14 +1084,18 @@ library_list_start_library (struct gdb_xml_parser *parser,
|
||||
/* 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);
|
||||
if (at_lmid == nullptr)
|
||||
solist = list->cur_list;
|
||||
{
|
||||
solist = list->cur_list;
|
||||
svr4_maybe_add_namespace (info, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULONGEST lmid = *(ULONGEST *) at_lmid->value.get ();
|
||||
solist = &list->solib_lists[lmid];
|
||||
svr4_maybe_add_namespace (info, lmid);
|
||||
}
|
||||
|
||||
solist->emplace_back (name, std::move (li));
|
||||
}
|
||||
|
||||
@ -1286,6 +1333,8 @@ svr4_current_sos_direct (struct svr4_info *info)
|
||||
/* Remove any old libraries. We're going to read them back in again. */
|
||||
info->solib_lists.clear ();
|
||||
|
||||
info->active_namespaces.clear ();
|
||||
|
||||
/* 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
|
||||
@ -1333,7 +1382,10 @@ svr4_current_sos_direct (struct svr4_info *info)
|
||||
ignore_first = true;
|
||||
|
||||
auto cleanup = make_scope_exit ([info] ()
|
||||
{ info->solib_lists.clear (); });
|
||||
{
|
||||
info->solib_lists.clear ();
|
||||
info->active_namespaces.clear ();
|
||||
});
|
||||
|
||||
/* Collect the sos in each namespace. */
|
||||
CORE_ADDR debug_base = info->debug_base;
|
||||
@ -1343,8 +1395,11 @@ svr4_current_sos_direct (struct svr4_info *info)
|
||||
/* Walk the inferior's link map list, and build our so_list list. */
|
||||
lm = solib_svr4_r_map (debug_base);
|
||||
if (lm != 0)
|
||||
svr4_read_so_list (info, lm, 0, info->solib_lists[debug_base],
|
||||
ignore_first);
|
||||
{
|
||||
svr4_maybe_add_namespace (info, debug_base);
|
||||
svr4_read_so_list (info, lm, 0, info->solib_lists[debug_base],
|
||||
ignore_first);
|
||||
}
|
||||
}
|
||||
|
||||
/* On Solaris, the dynamic linker is not in the normal list of
|
||||
@ -1361,8 +1416,11 @@ svr4_current_sos_direct (struct svr4_info *info)
|
||||
{
|
||||
/* Add the dynamic linker's namespace unless we already did. */
|
||||
if (info->solib_lists.find (debug_base) == info->solib_lists.end ())
|
||||
svr4_read_so_list (info, debug_base, 0, info->solib_lists[debug_base],
|
||||
0);
|
||||
{
|
||||
svr4_maybe_add_namespace (info, debug_base);
|
||||
svr4_read_so_list (info, debug_base, 0, info->solib_lists[debug_base],
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup.release ();
|
||||
@ -1778,6 +1836,10 @@ solist_update_incremental (svr4_info *info, CORE_ADDR debug_base,
|
||||
return 0;
|
||||
|
||||
prev_lm = 0;
|
||||
|
||||
/* If the list is empty, we are seeing a new namespace for the
|
||||
first time, so assign it an internal ID. */
|
||||
svr4_maybe_add_namespace (info, debug_base);
|
||||
}
|
||||
else
|
||||
prev_lm = solist.back ().lm_info->lm_addr;
|
||||
@ -1845,6 +1907,8 @@ disable_probes_interface (svr4_info *info)
|
||||
|
||||
free_probes_table (info);
|
||||
info->solib_lists.clear ();
|
||||
info->namespace_id.clear ();
|
||||
info->active_namespaces.clear ();
|
||||
}
|
||||
|
||||
/* Update the solib list as appropriate when using the
|
||||
@ -3042,6 +3106,8 @@ svr4_solib_create_inferior_hook (int from_tty)
|
||||
/* Clear the probes-based interface's state. */
|
||||
free_probes_table (info);
|
||||
info->solib_lists.clear ();
|
||||
info->namespace_id.clear ();
|
||||
info->active_namespaces.clear ();
|
||||
|
||||
/* Relocate the main executable if necessary. */
|
||||
svr4_relocate_main_executable ();
|
||||
@ -3460,6 +3526,32 @@ svr4_find_solib_addr (solib &so)
|
||||
return li->l_addr_inferior;
|
||||
}
|
||||
|
||||
/* See solib_ops::find_solib_ns in solist.h. */
|
||||
|
||||
static int
|
||||
svr4_find_solib_ns (const solib &so)
|
||||
{
|
||||
CORE_ADDR debug_base = find_debug_base_for_solib (&so);
|
||||
svr4_info *info = get_svr4_info (current_program_space);
|
||||
for (int i = 0; i < info->namespace_id.size (); i++)
|
||||
{
|
||||
if (info->namespace_id[i] == debug_base)
|
||||
{
|
||||
gdb_assert (info->active_namespaces.count (i) == 1);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
error (_("No namespace found"));
|
||||
}
|
||||
|
||||
/* see solib_ops::num_active_namespaces in solist.h. */
|
||||
static int
|
||||
svr4_num_active_namespaces ()
|
||||
{
|
||||
svr4_info *info = get_svr4_info (current_program_space);
|
||||
return info->active_namespaces.size ();
|
||||
}
|
||||
|
||||
const struct solib_ops svr4_so_ops =
|
||||
{
|
||||
svr4_relocate_section_addresses,
|
||||
@ -3475,6 +3567,8 @@ const struct solib_ops svr4_so_ops =
|
||||
svr4_update_solib_event_breakpoints,
|
||||
svr4_handle_solib_event,
|
||||
svr4_find_solib_addr,
|
||||
svr4_find_solib_ns,
|
||||
svr4_num_active_namespaces,
|
||||
};
|
||||
|
||||
void _initialize_svr4_solib ();
|
||||
|
27
gdb/solib.c
27
gdb/solib.c
@ -1051,12 +1051,24 @@ info_sharedlibrary_command (const char *pattern, int from_tty)
|
||||
}
|
||||
}
|
||||
|
||||
/* How many columns the table should have. If the inferior has
|
||||
more than one namespace active, we need a column to show that. */
|
||||
int num_cols = 4;
|
||||
const solib_ops *ops = gdbarch_so_ops (gdbarch);
|
||||
if (ops->num_active_namespaces != nullptr
|
||||
&& ops->num_active_namespaces () > 1)
|
||||
num_cols++;
|
||||
|
||||
{
|
||||
ui_out_emit_table table_emitter (uiout, 4, nr_libs, "SharedLibraryTable");
|
||||
ui_out_emit_table table_emitter (uiout, num_cols, nr_libs,
|
||||
"SharedLibraryTable");
|
||||
|
||||
/* The "- 1" is because ui_out adds one space between columns. */
|
||||
uiout->table_header (addr_width - 1, ui_left, "from", "From");
|
||||
uiout->table_header (addr_width - 1, ui_left, "to", "To");
|
||||
if (ops->num_active_namespaces != nullptr
|
||||
&& ops->num_active_namespaces () > 1)
|
||||
uiout->table_header (5, ui_left, "namespace", "NS");
|
||||
uiout->table_header (12 - 1, ui_left, "syms-read", "Syms Read");
|
||||
uiout->table_header (0, ui_noalign, "name", "Shared Object Library");
|
||||
|
||||
@ -1083,6 +1095,19 @@ info_sharedlibrary_command (const char *pattern, int from_tty)
|
||||
uiout->field_skip ("to");
|
||||
}
|
||||
|
||||
if (ops->num_active_namespaces != nullptr
|
||||
&& ops->num_active_namespaces ()> 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
uiout->field_fmt ("namespace", "[[%d]]", ops->find_solib_ns (so));
|
||||
}
|
||||
catch (const gdb_exception_error &er)
|
||||
{
|
||||
uiout->field_skip ("namespace");
|
||||
}
|
||||
}
|
||||
|
||||
if (!top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ()
|
||||
&& so.symbols_loaded && !objfile_has_symbols (so.objfile))
|
||||
{
|
||||
|
14
gdb/solist.h
14
gdb/solist.h
@ -180,6 +180,20 @@ struct solib_ops
|
||||
name). */
|
||||
|
||||
std::optional<CORE_ADDR> (*find_solib_addr) (solib &so);
|
||||
|
||||
/* Return which linker namespace contains the current so.
|
||||
If the linker or libc does not support linkage namespaces at all
|
||||
(which is basically all of them but solib-svr4), this function should
|
||||
be set to nullptr, so that "info shared" won't add an unnecessary
|
||||
column.
|
||||
|
||||
If the namespace can not be determined (such as when we're stepping
|
||||
though the dynamic linker), this function should throw a
|
||||
gdb_exception_error. */
|
||||
int (*find_solib_ns) (const solib &so);
|
||||
|
||||
/* Returns the number of active namespaces in the inferior. */
|
||||
int (*num_active_namespaces) ();
|
||||
};
|
||||
|
||||
/* A unique pointer to a so_list. */
|
||||
|
@ -35,7 +35,7 @@ if ![runto_main] {
|
||||
}
|
||||
set test "sanity check info shared"
|
||||
gdb_test_multiple "info shared" $test {
|
||||
-re "From\[ \t\]+To\[ \t\]+Syms Read\[ \t\]+Shared Object Library\r\n0x.*\r\n$gdb_prompt $" {
|
||||
-re "From\[ \t\]+To(\\s+NS)?\[ \t\]+Syms Read\[ \t\]+Shared Object Library\r\n0x.*\r\n$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
-re "No shared libraries loaded at this time\\.\r\n$gdb_prompt $" {
|
||||
@ -62,6 +62,6 @@ if { ![gdb_attach $testpid] } {
|
||||
return
|
||||
}
|
||||
gdb_test "set architecture $arch" "The target architecture is set to \"$arch\"\\."
|
||||
gdb_test "info shared" "From\[ \t\]+To\[ \t\]+Syms Read\[ \t\]+Shared Object Library\r\n0x.*"
|
||||
gdb_test "info shared" "From\[ \t\]+To(\\s+NS)?\[ \t\]+Syms Read\[ \t\]+Shared Object Library\r\n0x.*"
|
||||
|
||||
kill_wait_spawned_process $test_spawn_id
|
||||
|
28
gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
Normal file
28
gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
Normal file
@ -0,0 +1,28 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2025 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
int gdb_dlmopen_glob = 0;
|
||||
|
||||
__attribute__((visibility ("default")))
|
||||
int
|
||||
inc (int n)
|
||||
{
|
||||
int amount = gdb_dlmopen_glob;
|
||||
return n + amount; /* bp.inc. */
|
||||
}
|
54
gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
Normal file
54
gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
Normal file
@ -0,0 +1,54 @@
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2025 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
void *handle[4];
|
||||
int (*fun) (int);
|
||||
Lmid_t lmid;
|
||||
int dl;
|
||||
|
||||
handle[0] = dlmopen (LM_ID_NEWLM, DSO_NAME, RTLD_LAZY | RTLD_LOCAL);
|
||||
assert (handle[0] != NULL);
|
||||
|
||||
handle[1] = dlmopen (LM_ID_NEWLM, DSO_NAME, RTLD_LAZY | RTLD_LOCAL);
|
||||
assert (handle[1] != NULL);
|
||||
|
||||
handle[2] = dlmopen (LM_ID_NEWLM, DSO_NAME, RTLD_LAZY | RTLD_LOCAL);
|
||||
assert (handle[2] != NULL);
|
||||
|
||||
dlclose (handle[0]); /* TAG: first dlclose */
|
||||
dlclose (handle[1]); /* TAG: second dlclose */
|
||||
dlclose (handle[2]); /* TAG: third dlclose */
|
||||
|
||||
handle[3] = dlmopen (LM_ID_NEWLM, DSO_NAME, RTLD_LAZY | RTLD_LOCAL);
|
||||
dlinfo (handle[3], RTLD_DI_LMID, &lmid);
|
||||
|
||||
dlclose (handle[3]); /* TAG: fourth dlclose */
|
||||
|
||||
return 0;
|
||||
}
|
106
gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
Normal file
106
gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
Normal file
@ -0,0 +1,106 @@
|
||||
# This testcase is part of GDB, the GNU debugger.
|
||||
#
|
||||
# Copyright 2025 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
#
|
||||
# Test several things related to handling linker namespaces:
|
||||
# * That the user-facing namespace ID is consistent;
|
||||
|
||||
require allow_dlmopen_tests
|
||||
|
||||
standard_testfile -main.c -lib.c
|
||||
|
||||
set srcfile_lib $srcfile2
|
||||
set binfile_lib [standard_output_file dlmopen-lib.so]
|
||||
|
||||
if { [build_executable "build shlib" $binfile_lib $srcfile_lib \
|
||||
[list debug shlib]] == -1 } {
|
||||
return
|
||||
}
|
||||
|
||||
if { [build_executable "failed to build" $testfile $srcfile \
|
||||
[list additional_flags=-DDSO_NAME=\"$binfile_lib\" \
|
||||
shlib_load debug]] } {
|
||||
return
|
||||
}
|
||||
|
||||
# Run the command "info sharedlibrary" and get the first namespace
|
||||
# for the so
|
||||
proc get_first_so_ns {} {
|
||||
set ns -1
|
||||
gdb_test_multiple "info sharedlibrary" "get SO namespace" -lbl {
|
||||
-re "From\\s+To\\s+\(NS\\s+\)?Syms\\s+Read\\s+Shared Object Library\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
-re "^$::hex\\s+$::hex\\s+\\\[\\\[($::decimal)\\\]\\\]\\s+\[^\r\n]+$::binfile_lib.*" {
|
||||
set ns $expect_out(1,string)
|
||||
}
|
||||
-re "^$::gdb_prompt $" {
|
||||
}
|
||||
-re "^\[^\r\n\]+\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
}
|
||||
return $ns
|
||||
}
|
||||
|
||||
# Run the tests relating to the command "info sharedlibrary", to
|
||||
# verify that the namespace ID is consistent.
|
||||
proc test_info_shared {} {
|
||||
clean_restart $::binfile
|
||||
|
||||
if { ![runto_main] } {
|
||||
return
|
||||
}
|
||||
|
||||
# First test that we don't print a namespace column at the start.
|
||||
gdb_test "info sharedlibrary" \
|
||||
"From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library.*" \
|
||||
"before loading anything"
|
||||
|
||||
gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"]
|
||||
gdb_continue_to_breakpoint "TAG: first dlclose"
|
||||
|
||||
# Next, test that we *do* print a namespace column after loading SOs.
|
||||
gdb_test "info sharedlibrary" \
|
||||
"From\\s+To\\s+NS\\s+Syms\\s+Read\\s+Shared Object Library.*" \
|
||||
"after loading everything"
|
||||
|
||||
gdb_assert {[get_first_so_ns] == 1} "before closing any library"
|
||||
|
||||
gdb_test "next" ".*second dlclose.*" "close first library"
|
||||
gdb_assert {[get_first_so_ns] == 2} "after closing one library"
|
||||
|
||||
gdb_test "next" ".*third dlclose.*" "close second library"
|
||||
gdb_assert {[get_first_so_ns] == 3} "before closing two libraries"
|
||||
|
||||
gdb_breakpoint [gdb_get_line_number "TAG: fourth dlclose"]
|
||||
gdb_continue_to_breakpoint "TAG: fourth dlclose"
|
||||
# As of writing this test, glibc's LMID is just an index on an array of
|
||||
# namespaces. After closing a namespace, requesting a new one will
|
||||
# return the index of the lowest-closed namespace, so this will likely
|
||||
# be namespace 1, and because of glibc's reuse of the r_debug object,
|
||||
# GDB should be able to assign the same number.
|
||||
gdb_assert {[get_first_so_ns] == [get_integer_valueof "lmid" "-1"]} \
|
||||
"reopen a namespace"
|
||||
|
||||
gdb_test "next" ".*return 0.*" "final namespace inactive"
|
||||
gdb_test "info sharedlibrary" \
|
||||
"From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library.*" \
|
||||
"after unloading everything"
|
||||
}
|
||||
|
||||
test_info_shared
|
@ -106,7 +106,7 @@ proc check_dso_count { dso num } {
|
||||
|
||||
set count 0
|
||||
gdb_test_multiple "info shared" "info shared" {
|
||||
-re "$hex $hex Yes \[^\r\n\]*$dso\r\n" {
|
||||
-re "$hex $hex \(\[\[$::decimal\]\]\\s+\)\?Yes \[^\r\n\]*$dso\r\n" {
|
||||
# use longer form so debug remote does not interfere
|
||||
set count [expr $count + 1]
|
||||
exp_continue
|
||||
@ -233,12 +233,12 @@ proc get_dyld_info {} {
|
||||
set dyld_count 0
|
||||
set dyld_start_addr ""
|
||||
gdb_test_multiple "info sharedlibrary" "" {
|
||||
-re "From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library\r\n" {
|
||||
-re "From\\s+To\\s+\(NS\\s+\)?Syms\\s+Read\\s+Shared Object Library\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
-re "^($::hex)\\s+$::hex\\s+\[^/\]+(/\[^\r\n\]+)\r\n" {
|
||||
-re "^($::hex)\\s+$::hex\\s+\(\#$::decimal\\s+\)?\[^/\]+(/\[^\r\n\]+)\r\n" {
|
||||
set addr $expect_out(1,string)
|
||||
set lib $expect_out(2,string)
|
||||
set lib $expect_out(3,string)
|
||||
|
||||
if { [is_dyln $lib] } {
|
||||
# This looks like it might be the dynamic linker.
|
||||
|
@ -81,12 +81,12 @@ proc get_dyld_info {} {
|
||||
set dyld_count 0
|
||||
set dyld_start_addr ""
|
||||
gdb_test_multiple "info sharedlibrary" "" {
|
||||
-re "~\"From\\s+To\\s+Syms\\s+Read\\s+Shared Object Library\\\\n\"\r\n" {
|
||||
-re "~\"From\\s+To(\\s+NS)?\\s+Syms\\s+Read\\s+Shared Object Library\\\\n\"\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
-re "^~\"($::hex)\\s+$::hex\\s+\[^/\]+(/\[^\r\n\]+)\\\\n\"\r\n" {
|
||||
-re "^~\"($::hex)\\s+${::hex}(\\s+$::decimal)?\\s+\[^/\]+(/\[^\r\n\]+)\\\\n\"\r\n" {
|
||||
set addr $expect_out(1,string)
|
||||
set lib $expect_out(2,string)
|
||||
set lib $expect_out(3,string)
|
||||
|
||||
if { [is_dyln $lib] } {
|
||||
# This looks like it might be the dynamic linker.
|
||||
|
Loading…
x
Reference in New Issue
Block a user