1 # Copyright
2022-2023 Free Software Foundation
, Inc.
2 # This
program is free software
; you can redistribute it and
/or modify
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation
; either version
3 of the License
, or
5 #
(at your option
) any later version.
7 # This
program is distributed in the hope that it will be useful
,
8 # but WITHOUT
ANY WARRANTY
; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License
for more details.
12 # You should have received a copy of the GNU General Public License
13 # along with this
program.
If not
, see
<http
://www.gnu.org
/licenses
/>.
15 # Test stepping through a runtime loader
/ dynamic linker
(RTLD
):
17 #
While it
'd be nice to have a test which steps through an actual
18 # runtime loader / dynamic linker, constructing such a test would be
19 # non-portable; we would need to know implementation details such
20 # as the names of some of the symbols and the order of calls to
21 # various functions that implement the RTLD. So, instead, we'll use a
22 #
program which doesn
't even pretend to implement this functionality,
23 # but which will instead be invoked in the same fashion (for ELF
24 # binaries anyway) as would be expected for an ELF-based RTLD.
26 # To that end, we have two programs, one which will pretend to be an
27 # RTLD and the other which will be caused to use the pretend RTLD.
29 # When the main program is run, the pretend/fake RTLD is run instead,
30 # due to it being specified as the ELF interpreter for the main
31 # program. Within GDB, we then attempt to do some simple debugging
32 # involving 'step
', 'next
', and 'finish
'.
34 # This test can't be run
on targets lacking shared library support
35 # or
for non
-ELF targets.
(We
're not really testing or building
36 # shared libraries here, but having a RTLD implies having shared
37 # libraries on the target.)
38 require allow_shlib_tests is_elf_target
40 # (Pretend) RTLD file names and flags:
41 set rtld_basename ${::gdb_test_file_name}-rtld
42 set srcfile_rtld ${srcdir}/${subdir}/${rtld_basename}.c
43 set binfile_rtld [standard_output_file ${rtld_basename}]
45 # Placing 'pie
' in the flag list (for rtld_flags) doesn't work
, but
46 # using
-static
-pie
-FPIE in additional_flags does. Apparently
, when
47 #
'pie' is listed
, gdb_compile will
(on Linux
) use both
-fPIE and
48 #
-pie. Testing shows that use of
-pie creates a dynamically linked
49 # executable when either a static or static
-pie executable is desired
50 # instead.
(This is probably fragile.
)
52 #
While developing this code
on Fedora Linux
, it was found that
(only
)
53 # the flags
-static
-pie
-fPIE were needed
for Fedora
35 through Fedora
54 #
38. The source file rtld
-step
-rtld.c didn
't need the _start()
55 # function either. And, better still, it was possible to call
56 # printf() to output progress messages in the pretend/fake RTLD.
57 # Sadly, these output statements had to be removed in order to obtain
58 # code which would work on other Linux distributions / releases.
60 # When testing against earlier versions of Fedora, RHEL 9, and
61 # also Ubuntu 22.04, that short flag list didn't work.
For these
62 # linux releases
, it was found that
-nostdlib
-lc were also required.
63 # Due to the use of
-nostdlib
, a _start
() function had to be added
66 # Finally
, on FreeBSD
, it was found that in order to end up with a
67 # statically linked executable
, -static was also needed.
68 # Unfortunately
, when attempting to run the rtld
-step
-main under GDB
69 #
on FreeBSD
13.1, this message was
/is encountered
:
71 # ELF interpreter
/path
/to
/rtld
-step
-rtld not found
, error
22
73 # So
, sadly
, this test does not currently work
on FreeBSD.
If you try
74 # to make it work
on FreeBSD
, you
'll probably need to enable the
75 # declarations for __progname and environ in rtld-step-rtld.c.
77 # If this test becomes broken at some point in the future, you might
78 # try removing -static from the flags below as it is not needed for
81 # Also, because the RTLD is static, you'll need static versions of
82 # libc
/glibc installed
on your
system.
(A message such as
"cannot
83 # find
-lc
" is a clue that you're missing a static version of libc.)
85 set rtld_flags
[list debug additional_flags
=[list
-static
-pie
-fPIE \
86 -nostdlib
-static
-lc
]]
88 if { ![gdb_can_simple_compile static
-pie
-static
-libc \
89 "void _start (void) { _exit (0); }" \
90 executable $rtld_flags
] } {
91 set reason
"-static-pie not supported or static libc missing"
92 untested
"failed to compile ($reason)"
96 # Main
program file names and flags
:
97 set main_basename $
{::gdb_test_file_name
}-main
98 set srcfile_main $
{srcdir
}/$
{subdir
}/$
{main_basename
}.c
99 set binfile_main
[standard_output_file $
{main_basename
}]
100 set main_flags
[list debug additional_flags
="-Wl,--dynamic-linker=${binfile_rtld}"]
102 #
Compile pretend RTLD
:
103 if { [gdb_compile $
{srcfile_rtld
} $
{binfile_rtld
} executable $rtld_flags
] != "" } {
104 untested
"failed to compile"
108 #
Compile main
program:
109 if { [gdb_compile $
{srcfile_main
} $
{binfile_main
} executable $main_flags
] != "" } {
110 untested
"failed to compile"
114 clean_restart $
{binfile_main
}
120 # Running the command
'info sharedlibrary' should output a path to
121 # the pretend
/fake RTLD along with the address range. Check that
122 # this path is present and
, if so
, extract the address range.
123 gdb_test_multiple
"info sharedlibrary" "" {
124 -re
-wrap
"($hex)\[ \t\]+($hex)\[ \t\]+Yes\[ \t\]+$fullname_syntax$rtld_basename" {
125 set rtld_lower $expect_out
(1,string
)
126 set rtld_upper $expect_out
(2,string
)
132 set pc
[get_hexadecimal_valueof
"\$pc" 0]
134 # Verify that PC is in the address range of the pretend
/fake RTLD.
135 gdb_assert
{ $rtld_lower
<= $pc
&& $pc
< $rtld_upper
} "pc is in rtld"
137 gdb_test
"next" {bar \(\);} "next over foo 0"
138 gdb_test
"step" {bar \(\) at.*foo \(1\);.*} "step into bar"
139 gdb_test
"step" {baz \(.*?\);} "step into foo 1"
140 gdb_test
"finish" {Run till exit.*bar \(\).*baz.*} "finish out of foo 1"
141 gdb_test
"next" {foo \(2\);} "next over baz in bar"
142 gdb_test
"step" {baz \(.*?\);} "step into foo 2"
143 gdb_test
"next" "\}" "next over baz in foo"
144 gdb_test
"step" "bar \\(\\).*}" "step out of foo back into bar"