public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Allow debugging of runtime loader / dynamic linker
@ 2022-10-08  3:57 Kevin Buettner
  2022-10-08  3:57 ` [PATCH 1/2] " Kevin Buettner
  2022-10-08  3:57 ` [PATCH 2/2] Test stepping within a " Kevin Buettner
  0 siblings, 2 replies; 6+ messages in thread
From: Kevin Buettner @ 2022-10-08  3:57 UTC (permalink / raw)
  To: gdb-patches

This series contains a small change to gdb/infrun.c which allows
stepping within the runtime loader / dynamic linker.  It also adds a
test case for testing this functionality.

Kevin Buettner (2):
  Allow debugging of runtime loader / dynamic linker
  Test stepping within a runtime loader / dynamic linker

 gdb/infrun.c                            |   5 +-
 gdb/testsuite/gdb.base/rtld-step-main.c |  22 ++++
 gdb/testsuite/gdb.base/rtld-step-rtld.c |  65 +++++++++++
 gdb/testsuite/gdb.base/rtld-step.exp    | 140 ++++++++++++++++++++++++
 4 files changed, 231 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.base/rtld-step-main.c
 create mode 100644 gdb/testsuite/gdb.base/rtld-step-rtld.c
 create mode 100644 gdb/testsuite/gdb.base/rtld-step.exp

-- 
2.37.3


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] Allow debugging of runtime loader / dynamic linker
  2022-10-08  3:57 [PATCH 0/2] Allow debugging of runtime loader / dynamic linker Kevin Buettner
@ 2022-10-08  3:57 ` Kevin Buettner
  2022-11-03 15:52   ` Lancelot SIX
  2022-10-08  3:57 ` [PATCH 2/2] Test stepping within a " Kevin Buettner
  1 sibling, 1 reply; 6+ messages in thread
From: Kevin Buettner @ 2022-10-08  3:57 UTC (permalink / raw)
  To: gdb-patches

At present, GDB does not allow for the debugging of the runtime loader
and/or dynamic linker.  Much of the time, this makes sense.  An
application programmer doesn't normally want to see symbol resolution
code when stepping into a function that hasn't been resolved yet.

But someone who wishes to debug the runtime loader / dynamic linker
might place a breakpoint in that code and then wish to debug it
as normal.  At the moment, this is not possible.  Attempting to step
will cause GDB to internally step (and not stop) until code
unrelated to the dynamic linker is reached.

This commit makes a minor change to infrun.c which allows the dynamic
loader / linker to be debugged in the case where a step, next, etc.
is initiated from within that code.

While developing this fix, I tried some approaches which weren't quite
right.  The GDB testusite definitely contains tests which FAIL when
it's done incorrectly.  (At one point, I saw 17 regressions!) This
commit has been tested on x86-64 linux with no regressions.
---
 gdb/infrun.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 1957e8020dd..52441b7ab5c 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6961,7 +6961,10 @@ process_event_stop_test (struct execution_control_state *ecs)
 
   if (execution_direction != EXEC_REVERSE
       && ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
-      && in_solib_dynsym_resolve_code (ecs->event_thread->stop_pc ()))
+      && in_solib_dynsym_resolve_code (ecs->event_thread->stop_pc ())
+      && !in_solib_dynsym_resolve_code (
+	  ecs->event_thread->control.step_start_function->value_block ()
+	      ->entry_pc ()))
     {
       CORE_ADDR pc_after_resolver =
 	gdbarch_skip_solib_resolver (gdbarch, ecs->event_thread->stop_pc ());
-- 
2.37.3


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/2] Test stepping within a runtime loader / dynamic linker
  2022-10-08  3:57 [PATCH 0/2] Allow debugging of runtime loader / dynamic linker Kevin Buettner
  2022-10-08  3:57 ` [PATCH 1/2] " Kevin Buettner
@ 2022-10-08  3:57 ` Kevin Buettner
  2022-10-10 18:45   ` John Baldwin
  1 sibling, 1 reply; 6+ messages in thread
From: Kevin Buettner @ 2022-10-08  3:57 UTC (permalink / raw)
  To: gdb-patches

See the remarks in rtld-step.exp for a description of what this
test is about.

This test case has been tested using gcc on the following x86-64 Linux
distributions/releases:

    Fedora 28
    Fedora 32
    Fedora 33
    Fedora 34
    Fedora 35
    Fedora 36
    Fedora 37
    rawhide (f38)
    RHEL 9.1
    Ubuntu 22.04.1 LTS

It's also been tested (and found to be working) with
RUNTESTFLAGS="CC_FOR_TARGET=clang" on all of the above expect for
Fedora 28.  The (old) version of clang available on F28 did not
accept the -static-pie option.

I also tried to make this test work on FreeBSD 13.1.  While I think I
made significant progress, I was ultimately stymied by this message
which occurs when attempting to run the main program which has been
set to use the fake/pretend RTLD as the ELF interpreter:

ELF interpreter /path/to/rtld-step-rtld not found, error 22

I have left one of the flags (-static) in place which I believe
to be needed for FreeBSD (though since I never got it to work, I
don't know for sure.)  I've also left some declarations needed
for FreeBSD in rtld-step-rtld.c.  They're currently disabled via
a #if 0; you'll need to enable them if you want to try to make
it work on FreeBSD.
---
 gdb/testsuite/gdb.base/rtld-step-main.c |  22 ++++
 gdb/testsuite/gdb.base/rtld-step-rtld.c |  65 +++++++++++
 gdb/testsuite/gdb.base/rtld-step.exp    | 140 ++++++++++++++++++++++++
 3 files changed, 227 insertions(+)
 create mode 100644 gdb/testsuite/gdb.base/rtld-step-main.c
 create mode 100644 gdb/testsuite/gdb.base/rtld-step-rtld.c
 create mode 100644 gdb/testsuite/gdb.base/rtld-step.exp

diff --git a/gdb/testsuite/gdb.base/rtld-step-main.c b/gdb/testsuite/gdb.base/rtld-step-main.c
new file mode 100644
index 00000000000..6b3984dc7d2
--- /dev/null
+++ b/gdb/testsuite/gdb.base/rtld-step-main.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2022 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
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/rtld-step-rtld.c b/gdb/testsuite/gdb.base/rtld-step-rtld.c
new file mode 100644
index 00000000000..e234ebf9ead
--- /dev/null
+++ b/gdb/testsuite/gdb.base/rtld-step-rtld.c
@@ -0,0 +1,65 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2022 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/>.  */
+
+#include <unistd.h>
+
+/* The declarations below are needed if you try to make this test case
+   work on FreeBSD.  They're disabled because there are other problems
+   with this test on FreeBSD.  See the .exp file for more info.  If
+   those other problems can be resolved, it may be worth reenabling
+   these declarations.  */
+#if 0
+__attribute__((weak))
+char *__progname = "fake-rtld";
+
+__attribute__((weak))
+char **environ = 0;
+#endif
+
+void
+baz (int i)
+{
+}
+
+void
+foo (int a)
+{
+  baz (a);
+}
+
+void
+bar ()
+{
+  foo (1);
+  baz (99);
+  foo (2);
+}
+
+int
+main ()
+{
+  foo (0);
+  bar ();
+  return 0;
+}
+
+void
+_start ()
+{
+  main ();
+  _exit (0);
+}
diff --git a/gdb/testsuite/gdb.base/rtld-step.exp b/gdb/testsuite/gdb.base/rtld-step.exp
new file mode 100644
index 00000000000..4773fa8de3d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/rtld-step.exp
@@ -0,0 +1,140 @@
+# Copyright 2022 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 stepping through a runtime loader / dynamic linker (RTLD):
+#
+# While it'd be nice to have a test which steps through an actual
+# runtime loader / dynamic linker, constructing such a test would be
+# non-portable; we would need to know implementation details such
+# as the names of some of the symbols and the order of calls to
+# various functions that implement the RTLD.  So, instead, we'll use a
+# program which doesn't even pretend to implement this functionality,
+# but which will instead be invoked in the same fashion (for ELF
+# binaries anyway) as would be expected for an ELF-based RTLD.
+#
+# To that end, we have two programs, one which will pretend to be an
+# RTLD and the other which will be caused to use the pretend RTLD.
+#
+# When the main program is run, the pretend/fake RTLD is run instead,
+# due to it being specified as the ELF interpreter for the main
+# program.  Within GDB, we then attempt to do some simple debugging
+# involving 'step', 'next', and 'finish'.
+
+# This test can't be run on targets lacking shared library support
+# or for non-ELF targets.  (We're not really testing or building
+# shared libraries here, but having a RTLD implies having shared
+# libraries on the target.)
+if { [skip_shlib_tests] || ![is_elf_target] } {
+    return 0
+}
+
+# (Pretend) RTLD file names and flags:
+set rtld_basename ${::gdb_test_file_name}-rtld
+set srcfile_rtld ${srcdir}/${subdir}/${rtld_basename}.c
+set binfile_rtld [standard_output_file ${rtld_basename}]
+
+# Placing 'pie' in the flag list (for rtld_flags) doesn't work, but
+# using -static-pie -FPIE in additional_flags does.  Apparently, when
+# 'pie' is listed, gdb_compile will (on Linux) use both -fPIE and
+# -pie.	 Testing shows that use of -pie creates a dynamically linked
+# executable when either a static or static-pie executable is desired
+# instead.  (This is probably fragile.)
+#
+# While developing this code on Fedora Linux, it was found that (only)
+# the flags -static-pie -fPIE were needed for Fedora 35 through Fedora
+# 38.  The source file rtld-step-rtld.c didn't need the _start()
+# function either.  And, better still, it was possible to call
+# printf() to output progress messages in the pretend/fake RTLD. 
+# Sadly, these output statements had to be removed in order to obtain
+# code which would work on other Linux distributions / releases.
+#
+# When testing against earlier versions of Fedora, RHEL 9, and
+# also Ubuntu 22.04, that short flag list didn't work.	For these
+# linux releases, it was found that -nostdlib -lc were also required.
+# Due to the use of -nostdlib, a _start() function had to be added
+# to the RTLD code.
+#
+# Finally, on FreeBSD, it was found that in order to end up with a
+# statically linked executable, -static was also needed.
+# Unfortunately, when attempting to run the rtld-step-main under GDB
+# on FreeBSD 13.1, this message was/is encountered:
+#
+# ELF interpreter /path/to/rtld-step-rtld not found, error 22
+#
+# So, sadly, this test does not currently work on FreeBSD.  If you try
+# to make it work on FreeBSD, you'll probably need to enable the
+# declarations for __progname and environ in rtld-step-rtld.c.
+#
+# If this test becomes broken at some point in the future, you might
+# try removing -static from the flags below as it is not needed for
+# Linux.
+#
+# Also, because the RTLD is static, you'll need static versions of
+# libc/glibc installed on your system.  (A message such as "cannot
+# find -lc" is a clue that you're missing a static version of libc.)
+
+set rtld_flags [list debug additional_flags=[list -static-pie -fPIE \
+						  -nostdlib -static -lc]]
+
+# Main program file names and flags:
+set main_basename ${::gdb_test_file_name}-main
+set srcfile_main ${srcdir}/${subdir}/${main_basename}.c
+set binfile_main [standard_output_file ${main_basename}]
+set main_flags [list debug additional_flags="-Wl,--dynamic-linker=${binfile_rtld}"]
+
+# Compile pretend RTLD:
+if { [gdb_compile ${srcfile_rtld} ${binfile_rtld} executable $rtld_flags] != "" } {
+    untested "failed to compile"
+    return -1
+}
+
+# Compile main program:
+if { [gdb_compile ${srcfile_main} ${binfile_main} executable $main_flags] != "" } {
+    untested "failed to compile"
+    return -1
+}
+
+clean_restart ${binfile_main}
+
+if {![runto_main]} {
+    return 0
+}
+
+# Running the command 'info sharedlibrary' should output a path to
+# the pretend/fake RTLD along with the address range.  Check that
+# this path is present and, if so, extract the address range.
+gdb_test_multiple "info sharedlibrary" "" {
+    -re -wrap "($hex)\[ \t\]+($hex)\[ \t\]+Yes\[ \t\]+$fullname_syntax$rtld_basename" {
+	set rtld_lower $expect_out(1,string)
+	set rtld_upper $expect_out(2,string)
+	pass $gdb_test_name
+    }
+}
+
+# Fetch PC value.
+set pc [get_hexadecimal_valueof "\$pc" 0]
+
+# Verify that PC is in the address range of the pretend/fake RTLD.
+gdb_assert { $rtld_lower <= $pc && $pc < $rtld_upper } "pc is in rtld"
+
+gdb_test "next" {bar \(\);} "next over foo 0"
+gdb_test "step" {bar \(\) at.*foo \(1\);.*} "step into bar"
+gdb_test "step" {baz \(.*?\);} "step into foo 1"
+gdb_test "finish" {Run till exit.*bar \(\).*baz.*} "finish out of foo 1"
+gdb_test "next" {foo \(2\);} "next over baz in bar"
+gdb_test "step" {baz \(.*?\);} "step into foo 2"
+gdb_test "next" "\}\[\r\n\]+" "next over baz in foo"
+gdb_test "step" "bar \\(\\).*}\[\r\n\]+.*" "step out of foo back into bar"
+
+gdb_continue_to_end
-- 
2.37.3


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] Test stepping within a runtime loader / dynamic linker
  2022-10-08  3:57 ` [PATCH 2/2] Test stepping within a " Kevin Buettner
@ 2022-10-10 18:45   ` John Baldwin
  2022-10-20  2:42     ` Kevin Buettner
  0 siblings, 1 reply; 6+ messages in thread
From: John Baldwin @ 2022-10-10 18:45 UTC (permalink / raw)
  To: Kevin Buettner, gdb-patches

On 10/7/22 8:57 PM, Kevin Buettner via Gdb-patches wrote:
> See the remarks in rtld-step.exp for a description of what this
> test is about.
> 
> This test case has been tested using gcc on the following x86-64 Linux
> distributions/releases:
> 
>      Fedora 28
>      Fedora 32
>      Fedora 33
>      Fedora 34
>      Fedora 35
>      Fedora 36
>      Fedora 37
>      rawhide (f38)
>      RHEL 9.1
>      Ubuntu 22.04.1 LTS
> 
> It's also been tested (and found to be working) with
> RUNTESTFLAGS="CC_FOR_TARGET=clang" on all of the above expect for
> Fedora 28.  The (old) version of clang available on F28 did not
> accept the -static-pie option.
> 
> I also tried to make this test work on FreeBSD 13.1.  While I think I
> made significant progress, I was ultimately stymied by this message
> which occurs when attempting to run the main program which has been
> set to use the fake/pretend RTLD as the ELF interpreter:
> 
> ELF interpreter /path/to/rtld-step-rtld not found, error 22
> 
> I have left one of the flags (-static) in place which I believe
> to be needed for FreeBSD (though since I never got it to work, I
> don't know for sure.)  I've also left some declarations needed
> for FreeBSD in rtld-step-rtld.c.  They're currently disabled via
> a #if 0; you'll need to enable them if you want to try to make
> it work on FreeBSD.

Hmm, thanks for testing on FreeBSD.  FreeBSD currently doesn't support
static PIE binaries, so I think the failure you ran into is not
unexpected.

In terms of the feature, this is indeed useful (I sometimes need to
step inside rtld myself).  I think your implementation in patch 1 makes
sense.

-- 
John Baldwin

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] Test stepping within a runtime loader / dynamic linker
  2022-10-10 18:45   ` John Baldwin
@ 2022-10-20  2:42     ` Kevin Buettner
  0 siblings, 0 replies; 6+ messages in thread
From: Kevin Buettner @ 2022-10-20  2:42 UTC (permalink / raw)
  To: John Baldwin; +Cc: gdb-patches

On Mon, 10 Oct 2022 11:45:03 -0700
John Baldwin <jhb@FreeBSD.org> wrote:

> In terms of the feature, this is indeed useful (I sometimes need to
> step inside rtld myself).  I think your implementation in patch 1 makes
> sense.

Thanks for looking it over.

I've pushed this series.

Kevin


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] Allow debugging of runtime loader / dynamic linker
  2022-10-08  3:57 ` [PATCH 1/2] " Kevin Buettner
@ 2022-11-03 15:52   ` Lancelot SIX
  0 siblings, 0 replies; 6+ messages in thread
From: Lancelot SIX @ 2022-11-03 15:52 UTC (permalink / raw)
  To: Kevin Buettner; +Cc: gdb-patches

Hi Kevin,

We have recently encountered a bug with the master branch.  Simon have
opened https://sourceware.org/bugzilla/show_bug.cgi?id=29747 to track
it.

By running `git bisect`, it seems that this problem appeared with this
patch.

Do you think you would have time to investigate this issue?  I have not
looked at the actual problem yet.  I have just been looking at when the
regression got introduced.

I do not expect it to be too long to fix, but I am not familiar with
this part of the code.

Please let me know if you do not have time to investigate this.

Best,
Lancelot.

On Fri, Oct 07, 2022 at 08:57:15PM -0700, Kevin Buettner via Gdb-patches wrote:
> At present, GDB does not allow for the debugging of the runtime loader
> and/or dynamic linker.  Much of the time, this makes sense.  An
> application programmer doesn't normally want to see symbol resolution
> code when stepping into a function that hasn't been resolved yet.
> 
> But someone who wishes to debug the runtime loader / dynamic linker
> might place a breakpoint in that code and then wish to debug it
> as normal.  At the moment, this is not possible.  Attempting to step
> will cause GDB to internally step (and not stop) until code
> unrelated to the dynamic linker is reached.
> 
> This commit makes a minor change to infrun.c which allows the dynamic
> loader / linker to be debugged in the case where a step, next, etc.
> is initiated from within that code.
> 
> While developing this fix, I tried some approaches which weren't quite
> right.  The GDB testusite definitely contains tests which FAIL when
> it's done incorrectly.  (At one point, I saw 17 regressions!) This
> commit has been tested on x86-64 linux with no regressions.
> ---
>  gdb/infrun.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 1957e8020dd..52441b7ab5c 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -6961,7 +6961,10 @@ process_event_stop_test (struct execution_control_state *ecs)
>  
>    if (execution_direction != EXEC_REVERSE
>        && ecs->event_thread->control.step_over_calls == STEP_OVER_UNDEBUGGABLE
> -      && in_solib_dynsym_resolve_code (ecs->event_thread->stop_pc ()))
> +      && in_solib_dynsym_resolve_code (ecs->event_thread->stop_pc ())
> +      && !in_solib_dynsym_resolve_code (
> +	  ecs->event_thread->control.step_start_function->value_block ()
> +	      ->entry_pc ()))
>      {
>        CORE_ADDR pc_after_resolver =
>  	gdbarch_skip_solib_resolver (gdbarch, ecs->event_thread->stop_pc ());
> -- 
> 2.37.3
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2022-11-03 15:52 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-08  3:57 [PATCH 0/2] Allow debugging of runtime loader / dynamic linker Kevin Buettner
2022-10-08  3:57 ` [PATCH 1/2] " Kevin Buettner
2022-11-03 15:52   ` Lancelot SIX
2022-10-08  3:57 ` [PATCH 2/2] Test stepping within a " Kevin Buettner
2022-10-10 18:45   ` John Baldwin
2022-10-20  2:42     ` Kevin Buettner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).