From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1028) id 40C8E3854172; Thu, 20 Oct 2022 02:41:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 40C8E3854172 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1666233682; bh=xvtzUP9bMyoz5utWKbszdmUcZSR+zVL0tvLdrqmOK5w=; h=From:To:Subject:Date:From; b=JUyYt8DQWU5UhLO1Yc/vPURlDJCPw2+VTr7cvw3cVWiGUzSSXBO8ocsNAg2Y4kQlL 5plMmYgY2fzw1IUgBe58e+GjnQe6TdCUe1RLe76GfKjaWFBPIIZYzdUyzq1VH8N+TL ANTMKVEbpKJFvhGw+8jlwYwSM4MJ7Zq+mWmPYE6M= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Kevin Buettner To: gdb-cvs@sourceware.org Subject: [binutils-gdb] Test stepping within a runtime loader / dynamic linker X-Act-Checkin: binutils-gdb X-Git-Author: Kevin Buettner X-Git-Refname: refs/heads/master X-Git-Oldrev: be6276e0aed1f2df8f771d9823b6c8fea29e6a66 X-Git-Newrev: 97df7412a183b73a1bfaeed55a4d951c2aede7d4 Message-Id: <20221020024122.40C8E3854172@sourceware.org> Date: Thu, 20 Oct 2022 02:41:22 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D97df7412a183= b73a1bfaeed55a4d951c2aede7d4 commit 97df7412a183b73a1bfaeed55a4d951c2aede7d4 Author: Kevin Buettner Date: Wed Oct 19 19:36:07 2022 -0700 Test stepping within a runtime loader / dynamic linker =20 See the remarks in rtld-step.exp for a description of what this test is about. =20 This test case has been tested using gcc on the following x86-64 Linux distributions/releases: =20 Fedora 28 Fedora 32 Fedora 33 Fedora 34 Fedora 35 Fedora 36 Fedora 37 rawhide (f38) RHEL 9.1 Ubuntu 22.04.1 LTS =20 It's also been tested (and found to be working) with RUNTESTFLAGS=3D"CC_FOR_TARGET=3Dclang" on all of the above expect for Fedora 28. The (old) version of clang available on F28 did not accept the -static-pie option. =20 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: =20 ELF interpreter /path/to/rtld-step-rtld not found, error 22 =20 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. Diff: --- 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(+) diff --git a/gdb/testsuite/gdb.base/rtld-step-main.c b/gdb/testsuite/gdb.ba= se/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 . = */ + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/rtld-step-rtld.c b/gdb/testsuite/gdb.ba= se/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 . = */ + +#include + +/* 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 =3D "fake-rtld"; + +__attribute__((weak)) +char **environ =3D 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 . + +# 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.=20 +# 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=3D[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=3D"-Wl,--dynamic-linker=3D${bi= nfile_rtld}"] + +# Compile pretend RTLD: +if { [gdb_compile ${srcfile_rtld} ${binfile_rtld} executable $rtld_flags] = !=3D "" } { + untested "failed to compile" + return -1 +} + +# Compile main program: +if { [gdb_compile ${srcfile_main} ${binfile_main} executable $main_flags] = !=3D "" } { + 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$rtl= d_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 <=3D $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