From: "Metzger, Markus T via Gdb-patches" <gdb-patches@sourceware.org>
To: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Subject: RE: [PATCH v4] gdb, gdbserver: support dlmopen()
Date: Fri, 21 Jan 2022 11:42:46 +0000 [thread overview]
Message-ID: <DM8PR11MB5749D144899C9D7DA82A7A21DE5B9@DM8PR11MB5749.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20211117142812.3685162-1-markus.t.metzger@intel.com>
Kindly pinging,
Markus.
>-----Original Message-----
>From: Metzger, Markus T <markus.t.metzger@intel.com>
>Sent: Wednesday, November 17, 2021 3:28 PM
>To: gdb-patches@sourceware.org
>Subject: [PATCH v4] gdb, gdbserver: support dlmopen()
>
>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 prev parent reply other threads:[~2022-01-21 11:43 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-17 14:28 Markus Metzger via Gdb-patches
2022-01-21 11:42 ` Metzger, Markus T via Gdb-patches [this message]
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=DM8PR11MB5749D144899C9D7DA82A7A21DE5B9@DM8PR11MB5749.namprd11.prod.outlook.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