]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: Introduce user-friendly namespace identifier for "info shared"
authorGuinevere Larsen <guinevere@redhat.com>
Thu, 13 Mar 2025 13:20:53 +0000 (10:20 -0300)
committerGuinevere Larsen <guinevere@redhat.com>
Mon, 7 Apr 2025 13:07:05 +0000 (10:07 -0300)
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>
gdb/NEWS
gdb/doc/gdb.texinfo
gdb/solib-svr4.c
gdb/solib.c
gdb/solist.h
gdb/testsuite/gdb.base/attach-pie-noexec.exp
gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c [new file with mode: 0644]
gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c [new file with mode: 0644]
gdb/testsuite/gdb.base/dlmopen-ns-ids.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/dlmopen.exp
gdb/testsuite/gdb.mi/mi-dlmopen.exp

index 6a557bb4af90e7d737ad2b410343d0be4a2e411e..99ec392d4c44f5384ea77de012adef5e4f3c388a 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
   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
index e034ac53295cd6c3cee24e04b91f6a6398c4b68b..4e4509a46498930da069c2af440bd0d9ec494cd6 100644 (file)
@@ -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}.
index 398123f7a520fee54dfd2720c1dedb4194272f25..2f839bd7b0bf8507199d893eac3865bb47d9721c 100644 (file)
@@ -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 ();
index 1d26970fab11f15bfa7d3c88284ea1f5d1b1270a..3ddd4f919c65d4f62cbffd6803cb35edde3547b2 100644 (file)
@@ -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))
          {
index 9a157a4bbae111b7a26943941d6a055b7e8f0f11..03d2392b19d1ccb5faf647a5044835f5d238870a 100644 (file)
@@ -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.  */
index 4e6ede12615c7986a950e93e221fce744c070d7e..20c93b5599adae6c9764df5783ebebd21dcc74f4 100644 (file)
@@ -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
diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-lib.c
new file mode 100644 (file)
index 0000000..86cbb0f
--- /dev/null
@@ -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.  */
+}
diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c b/gdb/testsuite/gdb.base/dlmopen-ns-ids-main.c
new file mode 100644 (file)
index 0000000..3bcd819
--- /dev/null
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp b/gdb/testsuite/gdb.base/dlmopen-ns-ids.exp
new file mode 100644 (file)
index 0000000..03b7a52
--- /dev/null
@@ -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
index a8e3b08c0168c166aeb8c6849742849d86b6483a..084c5bc193c1926014fdbba67720569880386d7a 100644 (file)
@@ -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.
index a5743f83bb8912431f6b13d15bd63fb9b62cc258..c0208ebcc5132e872c4dce593aa159997e54b486 100644 (file)
@@ -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.