Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Markus Metzger via Gdb-patches <gdb-patches@sourceware.org>
To: gdb-patches@sourceware.org
Subject: [PATCH v4] gdb, gdbserver: support dlmopen()
Date: Wed, 17 Nov 2021 15:28:12 +0100	[thread overview]
Message-ID: <20211117142812.3685162-1-markus.t.metzger@intel.com> (raw)

This patch was originally developed by H.J.  Last version:
https://sourceware.org/pipermail/gdb-patches/2021-October/182353.html

Changes in v4:

1. add gdb.base/dlmopen.exp
2. extend svr4_same() to compare the load offset in addition to the name
3. supply l_addr_inferior for default DSO to make it work with #2
4. fix bugs in gdbserver/linux-low.cc

Changes in v3:

1. Fix gdbserver support.

Changes in v2:

1. Don't check shared libraries in other namespaces when updating shared
libraries in a new namespace.

Regression-tested on x86-64 linux.

---

In glibc, the r_debug structure contains (amongst others) the following
fields:

  int r_version:
    Version number for this protocol.  It should be greater than 0.

If r_version is 2, struct r_debug is extended to struct r_debug_extended
with one additional field:

  struct r_debug_extended *r_next;
    Link to the next r_debug_extended structure.  Each r_debug_extended
    structure represents a different namespace.  The first r_debug_extended
    structure is for the default namespace.

1. Change solib_svr4_r_map argument to take the debug base.
2. Add solib_svr4_r_next to find the link map in the next namespace from
the r_next field.
3. Update svr4_current_sos_direct to get the link map in the next namespace
from the r_next field.
4. Don't check shared libraries in other namespaces when updating shared
libraries in a new namespace.
5. Update svr4_same to check the load offset in addition to the name
6. Update svr4_default_sos to also set l_addr_inferior

Add gdb.base/dlmopen.exp to test this.

This fixes PR 11839.
---
 gdb/linux-tdep.c                     |   2 +
 gdb/mips-fbsd-tdep.c                 |   2 +
 gdb/mips-netbsd-tdep.c               |   2 +
 gdb/solib-svr4.c                     |  89 ++++++++--
 gdb/solib-svr4.h                     |   3 +
 gdb/testsuite/gdb.base/dlmopen-lib.c |  25 +++
 gdb/testsuite/gdb.base/dlmopen.c     |  56 +++++++
 gdb/testsuite/gdb.base/dlmopen.exp   | 141 ++++++++++++++++
 gdbserver/linux-low.cc               | 242 ++++++++++++++++-----------
 9 files changed, 450 insertions(+), 112 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/dlmopen-lib.c
 create mode 100644 gdb/testsuite/gdb.base/dlmopen.c
 create mode 100644 gdb/testsuite/gdb.base/dlmopen.exp

diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index e2cff83086a..cb8e52d760a 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -2739,6 +2739,7 @@ linux_ilp32_fetch_link_map_offsets ()
       lmo.r_map_offset = 4;
       lmo.r_brk_offset = 8;
       lmo.r_ldsomap_offset = -1;
+      lmo.r_next_offset = 20;
 
       /* Everything we need is in the first 20 bytes.  */
       lmo.link_map_size = 20;
@@ -2767,6 +2768,7 @@ linux_lp64_fetch_link_map_offsets ()
       lmo.r_map_offset = 8;
       lmo.r_brk_offset = 16;
       lmo.r_ldsomap_offset = -1;
+      lmo.r_next_offset = 40;
 
       /* Everything we need is in the first 40 bytes.  */
       lmo.link_map_size = 40;
diff --git a/gdb/mips-fbsd-tdep.c b/gdb/mips-fbsd-tdep.c
index 0b7c97c445f..00e38a8f1c4 100644
--- a/gdb/mips-fbsd-tdep.c
+++ b/gdb/mips-fbsd-tdep.c
@@ -495,6 +495,7 @@ mips_fbsd_ilp32_fetch_link_map_offsets (void)
       lmo.r_map_offset = 4;
       lmo.r_brk_offset = 8;
       lmo.r_ldsomap_offset = -1;
+      lmo.r_next_offset = -1;
 
       lmo.link_map_size = 24;
       lmo.l_addr_offset = 0;
@@ -522,6 +523,7 @@ mips_fbsd_lp64_fetch_link_map_offsets (void)
       lmo.r_map_offset = 8;
       lmo.r_brk_offset = 16;
       lmo.r_ldsomap_offset = -1;
+      lmo.r_next_offset = -1;
 
       lmo.link_map_size = 48;
       lmo.l_addr_offset = 0;
diff --git a/gdb/mips-netbsd-tdep.c b/gdb/mips-netbsd-tdep.c
index a32ae5e3a29..12d702ef359 100644
--- a/gdb/mips-netbsd-tdep.c
+++ b/gdb/mips-netbsd-tdep.c
@@ -308,6 +308,7 @@ mipsnbsd_ilp32_fetch_link_map_offsets (void)
       lmo.r_map_offset = 4;
       lmo.r_brk_offset = 8;
       lmo.r_ldsomap_offset = -1;
+      lmo.r_next_offset = -1;
 
       /* Everything we need is in the first 24 bytes.  */
       lmo.link_map_size = 24;
@@ -336,6 +337,7 @@ mipsnbsd_lp64_fetch_link_map_offsets (void)
       lmo.r_map_offset = 8;
       lmo.r_brk_offset = 16;
       lmo.r_ldsomap_offset = -1;
+      lmo.r_next_offset = -1;
 
       /* Everything we need is in the first 40 bytes.  */
       lmo.link_map_size = 48;
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 3de1bb9c7f7..d57a3c1ffdb 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -174,7 +174,16 @@ svr4_same_1 (const char *gdb_so_name, const char *inferior_so_name)
 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>
@@ -767,7 +776,7 @@ locate_base (struct svr4_info *info)
    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;
@@ -775,7 +784,7 @@ solib_svr4_r_map (struct svr4_info *info)
 
   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)
@@ -829,6 +838,35 @@ solib_svr4_r_ldsomap (struct svr4_info *info)
 				    ptr_type);
 }
 
+/* Find the next namespace from the r_next field.  */
+
+static CORE_ADDR
+solib_svr4_r_next (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;
+  enum 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
@@ -886,7 +924,7 @@ open_symbol_file_object (int from_tty)
     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...  */
 
@@ -1178,7 +1216,7 @@ svr4_default_sos (svr4_info *info)
   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);
@@ -1323,7 +1361,7 @@ svr4_current_sos_direct (struct svr4_info *info)
 
   /* Walk the inferior's link map list, and build our list of
      `struct so_list' nodes.  */
-  lm = solib_svr4_r_map (info);
+  lm = solib_svr4_r_map (info->debug_base);
   if (lm)
     svr4_read_so_list (info, lm, 0, &link_ptr, ignore_first);
 
@@ -1335,6 +1373,18 @@ svr4_current_sos_direct (struct svr4_info *info)
   if (lm)
     svr4_read_so_list (info, lm, 0, &link_ptr, 0);
 
+  /* Get the next namespace from the r_next field.  */
+  lm = solib_svr4_r_next (info->debug_base);
+  while (lm != 0)
+    {
+      /* Get the link map in this namespace.  */
+      CORE_ADDR link_map = solib_svr4_r_map (lm);
+      if (link_map != 0)
+	svr4_read_so_list (info, link_map, 0, &link_ptr, 0);
+      /* Go to the next namespace.  */
+      lm = solib_svr4_r_next (lm);
+    }
+
   cleanup.release ();
 
   if (head == NULL)
@@ -1706,7 +1756,8 @@ solist_update_full (struct svr4_info *info)
    failure.  */
 
 static int
-solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
+solist_update_incremental (struct svr4_info *info, CORE_ADDR debug_base,
+			   CORE_ADDR lm)
 {
   struct so_list *tail;
   CORE_ADDR prev_lm;
@@ -1727,8 +1778,15 @@ solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
   for (tail = info->solib_list; tail->next != NULL; tail = tail->next)
     /* Nothing.  */;
 
-  lm_info_svr4 *li = (lm_info_svr4 *) tail->lm_info;
-  prev_lm = li->lm_addr;
+  /* Don't check shared libraries in other namespaces when updating
+     shared libraries in a new namespace.  */
+  if (debug_base == info->debug_base)
+    {
+      lm_info_svr4 *li = (lm_info_svr4 *) tail->lm_info;
+      prev_lm = li->lm_addr;
+    }
+  else
+    prev_lm = 0;
 
   /* Read the new objects.  */
   if (info->using_xfer)
@@ -1869,13 +1927,6 @@ svr4_handle_solib_event (void)
 	  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
@@ -1901,7 +1952,7 @@ svr4_handle_solib_event (void)
 
   if (action == UPDATE_OR_RELOAD)
     {
-      if (!solist_update_incremental (info, lm))
+      if (!solist_update_incremental (info, debug_base, lm))
 	action = FULL_RELOAD;
     }
 
@@ -2136,7 +2187,7 @@ enable_break (struct svr4_info *info, int from_tty)
 
   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)
@@ -3087,6 +3138,7 @@ svr4_ilp32_fetch_link_map_offsets (void)
       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;
@@ -3118,6 +3170,7 @@ svr4_lp64_fetch_link_map_offsets (void)
       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;
diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h
index 8d94d9cb26e..64854e2edd9 100644
--- a/gdb/solib-svr4.h
+++ b/gdb/solib-svr4.h
@@ -66,6 +66,9 @@ struct link_map_offsets
     /* Offset of r_debug.r_ldsomap.  */
     int r_ldsomap_offset;
 
+    /* Offset of r_debug_extended.r_next.  */
+    int r_next_offset;
+
     /* Size of struct link_map (or equivalent), or at least enough of it
        to be able to obtain the fields below.  */
     int link_map_size;
diff --git a/gdb/testsuite/gdb.base/dlmopen-lib.c b/gdb/testsuite/gdb.base/dlmopen-lib.c
new file mode 100644
index 00000000000..264659ec9de
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dlmopen-lib.c
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2021 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/>.
+
+*/
+
+__attribute__((visibility ("default")))
+int
+inc (int n)
+{
+  return n + 1;  /* bp.inc.  */
+}
diff --git a/gdb/testsuite/gdb.base/dlmopen.c b/gdb/testsuite/gdb.base/dlmopen.c
new file mode 100644
index 00000000000..49040dc8738
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dlmopen.c
@@ -0,0 +1,56 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2021 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>
+
+volatile int pause = 1;
+
+int
+main (void)
+{
+  void *handle[2];
+  int (*fun) (int);
+
+  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);
+
+  fun = dlsym (handle[0], "inc");
+  assert (fun != NULL);
+
+  while (pause != 0)
+    ;
+
+  fun (42);
+
+  dlclose (handle[0]);
+
+  fun = dlsym (handle[1], "inc");
+  assert (fun != NULL);
+
+  fun (42);
+
+  dlclose (handle[1]);
+  return 0;  /* bp.main  */
+}
diff --git a/gdb/testsuite/gdb.base/dlmopen.exp b/gdb/testsuite/gdb.base/dlmopen.exp
new file mode 100644
index 00000000000..fbf6fcb6b42
--- /dev/null
+++ b/gdb/testsuite/gdb.base/dlmopen.exp
@@ -0,0 +1,141 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2021 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/>.
+
+if { [skip_shlib_tests] } {
+    unsupported "target does not support dynamic libraries"
+    return -1
+}
+
+standard_testfile
+
+set basename_lib dlmopen-lib
+set srcfile_lib $srcdir/$subdir/$basename_lib.c
+set binfile_lib [standard_output_file $basename_lib.so]
+
+if { [gdb_compile_shlib $srcfile_lib $binfile_lib {debug}] != "" } {
+    untested "failed to prepare shlib"
+    return -1
+}
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile \
+	  [list additional_flags=-DDSO_NAME=\"$binfile_lib\" \
+	       libs=-ldl debug]] } {
+    return -1
+}
+
+if { ![runto_main] } {
+    return -1
+}
+
+# Check that 'info shared' show NUM occurrences of DSO.
+proc check_dso_count { dso num } {
+    global gdb_prompt
+
+    set count 0
+    gdb_test_multiple "info shared" "info shared" {
+	-re "$dso" {
+	    set count [expr $count + 1]
+	    exp_continue
+	}
+	-re "$gdb_prompt " {
+	    gdb_assert {$count == $num} $gdb_test_name
+	}
+    }
+}
+
+# The actual test.  We run it twice.
+proc test_dlmopen {} {
+    global srcfile srcfile_lib binfile_lib bp_main bp_inc
+
+    with_test_prefix "dso 1" {
+	# Try to reach the breakpoint in the dynamically loaded library.
+	gdb_continue_to_breakpoint "cont to bp.inc" \
+	    ".*$srcfile_lib:$bp_inc\r\n.*"
+
+	# The library should be listed twice.
+	check_dso_count $binfile_lib 2
+
+	# This might help debugging.
+	gdb_test "info breakpoints" ".*"
+	gdb_test "print \$pc" ".*"
+    }
+
+    with_test_prefix "dso 2" {
+	# Try to reach the breakpoint in the dynamically loaded library.
+	gdb_continue_to_breakpoint "cont to bp.inc" \
+	    ".*$srcfile_lib:$bp_inc\r\n.*"
+
+	# The library should be listed once.
+	check_dso_count $binfile_lib 1
+
+	# This might help debugging.
+	gdb_test "info breakpoints" ".*"
+	gdb_test "print \$pc" ".*"
+    }
+
+    with_test_prefix "main" {
+	# Try to reach the breakpoint in the dynamically loaded library.
+	gdb_continue_to_breakpoint "cont to bp.main" \
+	    ".*$srcfile:$bp_main\r\n.*"
+
+	# The library should not be listed.
+	check_dso_count $binfile_lib 0
+    }
+}
+
+# Remove the pause.  We only need it for the attach test.
+gdb_test "print pause = 0" "\\\$1 = 0"
+
+# The library is not yet loaded.  We need breakpoints to be pending.
+gdb_test_no_output "set breakpoint pending on"
+
+# Break in the to-be-loaded library and at the end of main.
+set bp_inc [gdb_get_line_number "bp.inc" $srcfile_lib]
+set bp_main [gdb_get_line_number "bp.main" $srcfile]
+
+delete_breakpoints
+gdb_breakpoint $srcfile_lib:$bp_inc allow-pending
+gdb_breakpoint $srcfile:$bp_main
+
+test_dlmopen
+
+# Try the same again when attaching after dlmopen().
+if { ![can_spawn_for_attach] } {
+    unsupported "target does not support attach"
+    return -1
+}
+
+clean_restart $binfile
+
+# Start the test program.
+set test_spawn_id [spawn_wait_for_attach $binfile]
+set testpid [spawn_id_get_pid $test_spawn_id]
+
+# Attach.
+gdb_test "attach $testpid" "Attaching to program.*, process $testpid.*"
+
+with_test_prefix "attach" {
+    # Remove the pause.  We no longer need it.
+    gdb_test "print pause = 0" "\\\$1 = 0"
+
+    # Set the same breakpoints again.  This time, however, we do not allow the
+    # breakpoint to be pending since the library has already been loaded.
+    gdb_breakpoint $srcfile_lib:$bp_inc
+    gdb_breakpoint $srcfile:$bp_main
+
+    test_dlmopen
+}
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 34ede238d19..4ad0f94526d 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -6727,6 +6727,9 @@ struct link_map_offsets
     /* Offset and size of r_debug.r_map.  */
     int r_map_offset;
 
+    /* Offset of r_debug_extended.r_next.  */
+    int r_next_offset;
+
     /* Offset to l_addr field in struct link_map.  */
     int l_addr_offset;
 
@@ -6743,6 +6746,98 @@ struct link_map_offsets
     int l_prev_offset;
   };
 
+static const struct link_map_offsets lmo_32bit_offsets =
+  {
+    0,     /* r_version offset. */
+    4,     /* r_debug.r_map offset.  */
+    20,    /* r_debug_extended.r_next.  */
+    0,     /* l_addr offset in link_map.  */
+    4,     /* l_name offset in link_map.  */
+    8,     /* l_ld offset in link_map.  */
+    12,    /* l_next offset in link_map.  */
+    16     /* l_prev offset in link_map.  */
+  };
+
+static const struct link_map_offsets lmo_64bit_offsets =
+  {
+    0,     /* r_version offset. */
+    8,     /* r_debug.r_map offset.  */
+    40,    /* r_debug_extended.r_next.  */
+    0,     /* l_addr offset in link_map.  */
+    8,     /* l_name offset in link_map.  */
+    16,    /* l_ld offset in link_map.  */
+    24,    /* l_next offset in link_map.  */
+    32     /* l_prev offset in link_map.  */
+  };
+
+/* Get the loaded shared libraries from one namespace.  */
+
+static void
+read_link_map (std::string &document, CORE_ADDR lm_addr, CORE_ADDR lm_prev,
+	       int ptr_size, const struct link_map_offsets *lmo,
+	       bool ignore_first, int &header_done)
+{
+  CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
+
+  while (lm_addr
+	 && read_one_ptr (lm_addr + lmo->l_name_offset,
+			  &l_name, ptr_size) == 0
+	 && read_one_ptr (lm_addr + lmo->l_addr_offset,
+			  &l_addr, ptr_size) == 0
+	 && read_one_ptr (lm_addr + lmo->l_ld_offset,
+			  &l_ld, ptr_size) == 0
+	 && read_one_ptr (lm_addr + lmo->l_prev_offset,
+			  &l_prev, ptr_size) == 0
+	 && read_one_ptr (lm_addr + lmo->l_next_offset,
+			  &l_next, ptr_size) == 0)
+    {
+      unsigned char libname[PATH_MAX];
+
+      if (lm_prev != l_prev)
+	{
+	  warning ("Corrupted shared library list: 0x%lx != 0x%lx",
+		   (long) lm_prev, (long) l_prev);
+	  break;
+	}
+
+      /* Ignore the first entry even if it has valid name as the first entry
+	 corresponds to the main executable.  The first entry should not be
+	 skipped if the dynamic loader was loaded late by a static executable
+	 (see solib-svr4.c parameter ignore_first).  But in such case the main
+	 executable does not have PT_DYNAMIC present and this function already
+	 exited above due to failed get_r_debug.  */
+      if (ignore_first && lm_prev == 0)
+	string_appendf (document, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
+      else
+	{
+	  /* Not checking for error because reading may stop before
+	     we've got PATH_MAX worth of characters.  */
+	  libname[0] = '\0';
+	  linux_read_memory (l_name, libname, sizeof (libname) - 1);
+	  libname[sizeof (libname) - 1] = '\0';
+	  if (libname[0] != '\0')
+	    {
+	      if (!header_done)
+		{
+		  /* Terminate `<library-list-svr4'.  */
+		  document += '>';
+		  header_done = 1;
+		}
+
+	      string_appendf (document, "<library name=\"");
+	      xml_escape_text_append (&document, (char *) libname);
+	      string_appendf (document, "\" lm=\"0x%lx\" "
+			      "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
+			      (unsigned long) lm_addr, (unsigned long) l_addr,
+			      (unsigned long) l_ld);
+	    }
+	}
+
+      lm_prev = lm_addr;
+      lm_addr = l_next;
+    }
+}
+
 /* Construct qXfer:libraries-svr4:read reply.  */
 
 int
@@ -6754,33 +6849,8 @@ linux_process_target::qxfer_libraries_svr4 (const char *annex,
   struct process_info_private *const priv = current_process ()->priv;
   char filename[PATH_MAX];
   int pid, is_elf64;
-
-  static const struct link_map_offsets lmo_32bit_offsets =
-    {
-      0,     /* r_version offset. */
-      4,     /* r_debug.r_map offset.  */
-      0,     /* l_addr offset in link_map.  */
-      4,     /* l_name offset in link_map.  */
-      8,     /* l_ld offset in link_map.  */
-      12,    /* l_next offset in link_map.  */
-      16     /* l_prev offset in link_map.  */
-    };
-
-  static const struct link_map_offsets lmo_64bit_offsets =
-    {
-      0,     /* r_version offset. */
-      8,     /* r_debug.r_map offset.  */
-      0,     /* l_addr offset in link_map.  */
-      8,     /* l_name offset in link_map.  */
-      16,    /* l_ld offset in link_map.  */
-      24,    /* l_next offset in link_map.  */
-      32     /* l_prev offset in link_map.  */
-    };
-  const struct link_map_offsets *lmo;
   unsigned int machine;
-  int ptr_size;
   CORE_ADDR lm_addr = 0, lm_prev = 0;
-  CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
   int header_done = 0;
 
   if (writebuf != NULL)
@@ -6791,8 +6861,18 @@ linux_process_target::qxfer_libraries_svr4 (const char *annex,
   pid = lwpid_of (current_thread);
   xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
   is_elf64 = elf_64_file_p (filename, &machine);
-  lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
-  ptr_size = is_elf64 ? 8 : 4;
+  const struct link_map_offsets *lmo;
+  int ptr_size;
+  if (is_elf64)
+    {
+      lmo = &lmo_64bit_offsets;
+      ptr_size = 8;
+    }
+  else
+    {
+      lmo = &lmo_32bit_offsets;
+      ptr_size = 4;
+    }
 
   while (annex[0] != '\0')
     {
@@ -6821,95 +6901,69 @@ linux_process_target::qxfer_libraries_svr4 (const char *annex,
       annex = decode_address_to_semicolon (addrp, sep + 1);
     }
 
-  if (lm_addr == 0)
-    {
-      int r_version = 0;
+  std::string document = "<library-list-svr4 version=\"1.0\"";
 
-      if (priv->r_debug == 0)
-	priv->r_debug = get_r_debug (pid, is_elf64);
+  /* When the starting LM_ADDR is passed in the annex, only traverse that
+     namespace.
+
+     Otherwise, start with R_DEBUG and traverse all namespaces we find.  */
+  if (lm_addr != 0)
+    read_link_map (document, lm_addr, lm_prev, ptr_size, lmo, false,
+		   header_done);
+  else
+    {
+      CORE_ADDR lm = priv->r_debug;
+      if (lm == 0)
+	lm = priv->r_debug = get_r_debug (pid, is_elf64);
 
       /* We failed to find DT_DEBUG.  Such situation will not change
 	 for this inferior - do not retry it.  Report it to GDB as
 	 E01, see for the reasons at the GDB solib-svr4.c side.  */
-      if (priv->r_debug == (CORE_ADDR) -1)
+      if (lm == (CORE_ADDR) -1)
 	return -1;
 
-      if (priv->r_debug != 0)
+      bool ignore_first = true;
+      while (lm != 0)
 	{
-	  if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
+	  int r_version = 0;
+	  if (linux_read_memory (lm + lmo->r_version_offset,
 				 (unsigned char *) &r_version,
-				 sizeof (r_version)) != 0
-	      || r_version < 1)
+				 sizeof (r_version)) != 0)
+	    {
+	      warning ("unable to read r_version from 0x%lx",
+		       (long) lm + lmo->r_version_offset);
+	      break;
+	    }
+
+	  if (r_version < 1)
 	    {
 	      warning ("unexpected r_debug version %d", r_version);
+	      break;
 	    }
-	  else if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
-				 &lm_addr, ptr_size) != 0)
+
+	  if (read_one_ptr (lm + lmo->r_map_offset, &lm_addr, ptr_size) != 0)
 	    {
 	      warning ("unable to read r_map from 0x%lx",
-		       (long) priv->r_debug + lmo->r_map_offset);
+		       (long) lm + lmo->r_map_offset);
+	      break;
 	    }
-	}
-    }
 
-  std::string document = "<library-list-svr4 version=\"1.0\"";
+	  read_link_map (document, lm_addr, lm_prev, ptr_size, lmo,
+			 ignore_first, header_done);
 
-  while (lm_addr
-	 && read_one_ptr (lm_addr + lmo->l_name_offset,
-			  &l_name, ptr_size) == 0
-	 && read_one_ptr (lm_addr + lmo->l_addr_offset,
-			  &l_addr, ptr_size) == 0
-	 && read_one_ptr (lm_addr + lmo->l_ld_offset,
-			  &l_ld, ptr_size) == 0
-	 && read_one_ptr (lm_addr + lmo->l_prev_offset,
-			  &l_prev, ptr_size) == 0
-	 && read_one_ptr (lm_addr + lmo->l_next_offset,
-			  &l_next, ptr_size) == 0)
-    {
-      unsigned char libname[PATH_MAX];
+	  if (r_version < 2)
+	    break;
 
-      if (lm_prev != l_prev)
-	{
-	  warning ("Corrupted shared library list: 0x%lx != 0x%lx",
-		   (long) lm_prev, (long) l_prev);
-	  break;
-	}
+	  /* Only applies to the default namespace.  */
+	  ignore_first = false;
 
-      /* Ignore the first entry even if it has valid name as the first entry
-	 corresponds to the main executable.  The first entry should not be
-	 skipped if the dynamic loader was loaded late by a static executable
-	 (see solib-svr4.c parameter ignore_first).  But in such case the main
-	 executable does not have PT_DYNAMIC present and this function already
-	 exited above due to failed get_r_debug.  */
-      if (lm_prev == 0)
-	string_appendf (document, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
-      else
-	{
-	  /* Not checking for error because reading may stop before
-	     we've got PATH_MAX worth of characters.  */
-	  libname[0] = '\0';
-	  linux_read_memory (l_name, libname, sizeof (libname) - 1);
-	  libname[sizeof (libname) - 1] = '\0';
-	  if (libname[0] != '\0')
+	  if (read_one_ptr (lm + lmo->r_next_offset, &lm, ptr_size) != 0)
 	    {
-	      if (!header_done)
-		{
-		  /* Terminate `<library-list-svr4'.  */
-		  document += '>';
-		  header_done = 1;
-		}
-
-	      string_appendf (document, "<library name=\"");
-	      xml_escape_text_append (&document, (char *) libname);
-	      string_appendf (document, "\" lm=\"0x%lx\" "
-			      "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
-			      (unsigned long) lm_addr, (unsigned long) l_addr,
-			      (unsigned long) l_ld);
+	      warning ("unable to read r_next from 0x%lx",
+		       (long) lm + lmo->r_next_offset);
+	      break;
 	    }
 	}
-
-      lm_prev = lm_addr;
-      lm_addr = l_next;
     }
 
   if (!header_done)
-- 
2.31.1

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928


             reply	other threads:[~2021-11-17 14:30 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-17 14:28 Markus Metzger via Gdb-patches [this message]
2022-01-21 11:42 ` Metzger, Markus T via Gdb-patches
2022-03-01 19:10 ` Tom Tromey
2022-03-09 12:23   ` Metzger, Markus T via Gdb-patches
2022-03-03 18:32 ` Pedro Alves
2022-03-09 12:24   ` Metzger, Markus T via Gdb-patches
2022-03-09 14:15     ` Pedro Alves
2022-03-29 16:13       ` Metzger, Markus T via Gdb-patches
2022-04-08 12:40         ` Metzger, Markus T via Gdb-patches
2022-05-25 17:12 ` Kevin Buettner via Gdb-patches
2022-05-31  9:29   ` Metzger, Markus T via Gdb-patches
2022-05-31 18:44     ` Ben Woodard via Gdb-patches
2022-05-24 18:40 Ben Woodard via Gdb-patches

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211117142812.3685162-1-markus.t.metzger@intel.com \
    --to=gdb-patches@sourceware.org \
    --cc=markus.t.metzger@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox