aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/NEWS5
-rw-r--r--gdb/doc/gdb.texinfo16
-rw-r--r--gdb/solib-svr4.c49
-rw-r--r--gdb/solib.c93
-rw-r--r--gdb/solist.h4
-rw-r--r--gdb/testsuite/gdb.base/dlmopen-ns-ids.exp78
6 files changed, 245 insertions, 0 deletions
diff --git a/gdb/NEWS b/gdb/NEWS
index a47a1b8..164e872 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -62,6 +62,11 @@ show riscv numeric-register-names
(e.g 'x1') or their abi names (e.g. 'ra').
Defaults to 'off', matching the old behaviour (abi names).
+info linker-namespaces
+info linker-namespaces [[N]]
+ Print information about the given linker namespace (identified as N),
+ or about all the namespaces if no argument is given.
+
* Changed commands
info sharedlibrary
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b423bb3..48b193b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22224,6 +22224,22 @@ less useful than setting a catchpoint, because it does not allow for
conditions or commands as a catchpoint does.
@table @code
+@kindex info linker-namespaces
+@item info linker-namespaces
+@item info linker-namespaces @code{[[@var{n}]]}
+
+With no argument, print the number of linker namespaces which are
+currently active --- that is, namespaces that have libraries loaded
+into them. Then, it prints the number of libraries loaded into each
+namespace, and all the libraries loaded into them, in the same way
+as @code{info sharedlibrary}.
+
+If an argument @code{[[@var{n}]]} is provided, only prints the
+library count and the libraried for the provided namespace @var{n}.
+The surrounding square brackets are optional.
+@end table
+
+@table @code
@item set stop-on-solib-events
@kindex set stop-on-solib-events
This command controls whether @value{GDBN} should give you control
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 148359a..2a2745d 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -3558,6 +3558,54 @@ svr4_num_active_namespaces ()
return info->active_namespaces.size ();
}
+/* See solib_ops::get_solibs_in_ns in solist.h. */
+static std::vector<const solib *>
+svr4_get_solibs_in_ns (int nsid)
+{
+ std::vector<const solib*> ns_solibs;
+ svr4_info *info = get_svr4_info (current_program_space);
+
+ /* If the namespace ID is inactive, there will be no active
+ libraries, so we can have an early exit, as a treat. */
+ if (info->active_namespaces.count (nsid) != 1)
+ return ns_solibs;
+
+ /* Since we only have the names of solibs in a given namespace,
+ we'll need to walk through the solib list of the inferior and
+ find which solib objects correspond to which svr4_so. We create
+ an unordered map with the names and lm_info to check things
+ faster, and to be able to remove SOs from the map, to avoid
+ returning the dynamic linker multiple times. */
+ CORE_ADDR debug_base = info->namespace_id[nsid];
+ std::unordered_map<std::string, const lm_info_svr4 *> namespace_solibs;
+ for (svr4_so &so : info->solib_lists[debug_base])
+ {
+ namespace_solibs[so.name]
+ = gdb::checked_static_cast<const lm_info_svr4 *>
+ (so.lm_info.get ());
+ }
+ for (const solib &so: current_program_space->solibs ())
+ {
+ auto *lm_inferior
+ = gdb::checked_static_cast<const lm_info_svr4 *> (so.lm_info.get ());
+
+ /* This is inspired by the svr4_same, by finding the svr4_so object
+ in the map, and then double checking if the lm_info is considered
+ the same. */
+ if (namespace_solibs.count (so.so_original_name) > 0
+ && namespace_solibs[so.so_original_name]->l_addr_inferior
+ == lm_inferior->l_addr_inferior)
+ {
+ ns_solibs.push_back (&so);
+ /* Remove the SO from the map, so that we don't end up
+ printing the dynamic linker multiple times. */
+ namespace_solibs.erase (so.so_original_name);
+ }
+ }
+
+ return ns_solibs;
+}
+
const struct solib_ops svr4_so_ops =
{
svr4_relocate_section_addresses,
@@ -3575,6 +3623,7 @@ const struct solib_ops svr4_so_ops =
svr4_find_solib_addr,
svr4_find_solib_ns,
svr4_num_active_namespaces,
+ svr4_get_solibs_in_ns,
};
void _initialize_svr4_solib ();
diff --git a/gdb/solib.c b/gdb/solib.c
index 5ed3ffb..5c5cfbd 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1149,6 +1149,96 @@ info_sharedlibrary_command (const char *pattern, int from_tty)
}
}
+/* Implement the "info linker-namespaces" command. If the current
+ gdbarch's solib_ops object does not support multiple namespaces,
+ this command would just look like "info sharedlibrary", so point
+ the user to that command instead.
+ If solib_ops does support multiple namespaces, this command
+ will group the libraries by linker namespace, or only print the
+ libraries in the supplied namespace. */
+static void
+info_linker_namespace_command (const char *pattern, int from_tty)
+{
+ const solib_ops *ops = gdbarch_so_ops (current_inferior ()->arch ());
+ /* This command only really makes sense for inferiors that support
+ linker namespaces, so we can leave early. */
+ if (ops->num_active_namespaces == nullptr)
+ error (_("Current inferior does not support linker namespaces." \
+ "Use \"info sharedlibrary\" instead"));
+
+ struct ui_out *uiout = current_uiout;
+ std::vector<std::pair<int, std::vector<const solib *>>> all_solibs_to_print;
+
+ if (pattern != nullptr)
+ while (*pattern == ' ')
+ pattern++;
+
+ if (pattern == nullptr || pattern[0] == '\0')
+ {
+ uiout->message (_ ("There are %d linker namespaces loaded\n"),
+ ops->num_active_namespaces ());
+
+ int printed = 0;
+ for (int i = 0; printed < ops->num_active_namespaces (); i++)
+ {
+ std::vector<const solib *> solibs_to_print
+ = ops->get_solibs_in_ns (i);
+ if (solibs_to_print.size () > 0)
+ {
+ all_solibs_to_print.push_back (std::make_pair
+ (i, solibs_to_print));
+ printed++;
+ }
+ }
+ }
+ else
+ {
+ int ns;
+ /* Check if the pattern includes the optional [[ and ]] decorators.
+ To match multiple occurrences, '+' needs to be escaped, and every
+ escape sequence must be doubled to survive the compiler pass. */
+ re_comp ("^\\[\\[[0-9]\\+\\]\\]$");
+ if (re_exec (pattern))
+ ns = strtol (pattern+2, nullptr, 10);
+ else
+ {
+ char * end = nullptr;
+ ns = strtol (pattern, &end, 10);
+ if (end[0] != '\0')
+ error (_ ("Invalid linker namespace identifier: %s"), pattern);
+ }
+
+ all_solibs_to_print.push_back
+ (std::make_pair (ns, ops->get_solibs_in_ns (ns)));
+ }
+
+ bool ns_separator = false;
+
+ for (auto &solibs_pair : all_solibs_to_print)
+ {
+ if (ns_separator)
+ uiout->message ("\n\n");
+ else
+ ns_separator = true;
+ int ns = solibs_pair.first;
+ std::vector<const solib *> solibs_to_print = solibs_pair.second;
+ if (solibs_to_print.size () == 0)
+ {
+ uiout->message (_("Linker namespace [[%d]] is not active.\n"), ns);
+ /* If we got here, a specific namespace was requested, so there
+ will only be one vector. We can leave early. */
+ break;
+ }
+ uiout->message
+ (_ ("There are %ld libraries loaded in linker namespace [[%d]]\n"),
+ solibs_to_print.size (), ns);
+ uiout->message
+ (_ ("Displaying libraries for linker namespace [[%d]]:\n"), ns);
+
+ print_solib_list_table (solibs_to_print, false);
+ }
+}
+
/* See solib.h. */
bool
@@ -1793,6 +1883,9 @@ _initialize_solib ()
add_com ("nosharedlibrary", class_files, no_shared_libraries_command,
_ ("Unload all shared object library symbols."));
+ add_info ("linker-namespaces", info_linker_namespace_command,
+ _ ("Get information about linker namespaces in the inferior."));
+
add_setshow_boolean_cmd ("auto-solib-add", class_support, &auto_solib_add,
_ ("\
Set autoloading of shared library symbols."),
diff --git a/gdb/solist.h b/gdb/solist.h
index 0b7bbf9..6ab5a06 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -194,6 +194,10 @@ struct solib_ops
/* Returns the number of active namespaces in the inferior. */
int (*num_active_namespaces) ();
+
+ /* Returns all solibs for a given namespace. If the namespace is not
+ active, returns an empty vector. */
+ std::vector<const solib *> (*get_solibs_in_ns) (int ns);
};
/* A unique pointer to a so_list. */
diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
index 1af57d1..8f52199 100644
--- a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
+++ b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
@@ -159,5 +159,83 @@ proc_with_prefix test_conv_vars {} {
gdb_continue_to_end "" continue 1
}
+# Run several tests relating to the command "info namespaces".
+proc test_info_linker_namespaces {} {
+ clean_restart $::binfile
+
+ if { ![runto_main] } {
+ return
+ }
+
+ with_test_prefix "info linker-namespaces" {
+ gdb_breakpoint [gdb_get_line_number "TAG: first dlclose"]
+ gdb_continue_to_breakpoint "TAG: first dlclose"
+ }
+
+ # First, test printing a single namespace, and ensure all of
+ # them are correct, using both syntaxes.
+ set found_all_libs false
+ gdb_test_multiple "info linker-namespaces \[\[0\]\]" "print namespace 0" -lbl {
+ -re "^\r\nThere are ($::decimal) libraries loaded in linker namespace \\\[\\\[0\\\]\\\]" {
+ # Some systems may add libc and libm to every loaded namespace,
+ # others may load only one or neither, because the SO doesn't
+ # actually use either library. The best we can do is check if
+ # we found the dynamic linker, and up to 2 more libraries.
+ set libs $expect_out(1,string)
+ set found_all_libs [expr $libs - 1 <= 2]
+ exp_continue
+ }
+ -re "^\r\n$::gdb_prompt $" {
+ gdb_assert $found_all_libs "the correct number of libraries was reported"
+ }
+ -re "(^\r\n)?\[^\r\n\]+(?=\r\n)" {
+ exp_continue
+ }
+ }
+ foreach_with_prefix ns {1 2 3} {
+ set found_test_so false
+ set found_all_libs false
+ gdb_test_multiple "info linker-namespaces $ns" "print namespace $ns" -lbl {
+ -re "^\r\nThere are ($::decimal) libraries loaded in linker namespace \\\[\\\[$ns\\\]\\\]" {
+ set libs $expect_out(1,string)
+ # Some systems may add libc and libm to every loaded namespace,
+ # others may load only one or neither, because the SO doesn't
+ # actually use either library. The best we can do is check if
+ # we found the dynamic linker, the test SO, and maybe up to 2
+ # more libraries.
+ set found_all_libs [expr $libs - 2 <= 2]
+ exp_continue
+ }
+ -re "^\r\n\[^\r\n\]+${::binfile_lib}\[^\r\n\]*(?=\r\n)" {
+ set found_test_so true
+ exp_continue
+ }
+ -re "^\r\n$::gdb_prompt $" {
+ gdb_assert $found_test_so "this testfle's SO was reported"
+ gdb_assert $found_all_libs "the correct number of libraries was reported"
+ }
+ -re "(^\r\n)?\[^\r\n\]+(?=\r\n)" {
+ exp_continue
+ }
+ }
+ }
+
+ # These patterns are simpler, and purposefully glob multiple lines.
+ # The point is to ensure that we find and display all the namespaces,
+ # without worrying about the libraries printed, since that was tested
+ # above.
+ gdb_test "info linker-namespaces" \
+ [multi_line "There are 4 linker namespaces loaded" \
+ "There are $::decimal libraries loaded in linker namespace ..0.." \
+ ".*" \
+ "There are $::decimal libraries loaded in linker namespace ..1.." \
+ ".*" \
+ "There are $::decimal libraries loaded in linker namespace ..2.." \
+ ".*" \
+ "There are $::decimal libraries loaded in linker namespace ..3.." \
+ ".*" ] "print namespaces with no argument"
+}
+
test_info_shared
test_conv_vars
+test_info_linker_namespaces