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
next 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