diff options
author | Simon Marchi <simon.marchi@efficios.com> | 2025-08-27 15:55:45 -0400 |
---|---|---|
committer | Simon Marchi <simon.marchi@efficios.com> | 2025-08-27 15:57:29 -0400 |
commit | d6340aa42e2573297c93fe86d27b28ae0de0ecb0 (patch) | |
tree | 83713dc390b976e1182e54e11adede59c1ec5014 | |
parent | 15b3c1756339dfc00c61a8ad1390222ce4bbca4f (diff) | |
download | binutils-d6340aa42e2573297c93fe86d27b28ae0de0ecb0.zip binutils-d6340aa42e2573297c93fe86d27b28ae0de0ecb0.tar.gz binutils-d6340aa42e2573297c93fe86d27b28ae0de0ecb0.tar.bz2 |
gdb/testsuite: use libtool to launch selftests
When building GDB on Cygwin, gdb/gdb.exe is a libtool wrapper (which
happens to be a PE executable). The real executable is at
gdb/.libs/gdb.exe. The "does gdb have debug info test" that
_selftest_setup does is bogus, because it loads the libtool wrapper
(which doesn't have debug info), doesn't see any debug info, and thus
the test is skipped.
The "correct" way to deal with libtool wrappers is to run the shell
command you want to run under `libtool --mode=execute`. That will
replace any path resembling to a libtool wrapper with the real
executable path. But it will also add to the environment the library
paths necessary for this executable to find the libraries it needs.
Therefore, modify the `do_self_tests` proc to:
- run the top-level GDB commands under `libtool --mode=execute`
- pass the path to the inferior GDB on the command-line of the
top-level, so that it gets replaced with the real executable's path
However, the "file" command was previously used to detect the presence
of debug info in the GDB executable. It's not easy to implement this
check when loading the executable directly on the command line. So, add
a separate proc, _selftest_check_executable_debug_info, that spawns a
temporary GDB and does the debug info check through the file command.
This proc uses libtool to obtain the path to the real executable.
When building, we use the bundled libtool.m4 at the top of the tree.
This means that the libtool system package, and therefore the libtool
binary, might not be available. Check for the presence of the libtool
binary first, and only do the conversion if it is found. If it is not
found, the test should still work on platforms that don't require the
conversion.
With this commit, the test runs on Cygwin, even though there are
failures later.
Change-Id: Ie7b712cdc84671a5a017655a7e41687ff23f906c
Reviewed-By: Keith Seitz <keiths@redhat.com>
-rw-r--r-- | gdb/testsuite/lib/selftest-support.exp | 104 |
1 files changed, 87 insertions, 17 deletions
diff --git a/gdb/testsuite/lib/selftest-support.exp b/gdb/testsuite/lib/selftest-support.exp index eb31b55..a8a33c8 100644 --- a/gdb/testsuite/lib/selftest-support.exp +++ b/gdb/testsuite/lib/selftest-support.exp @@ -36,31 +36,82 @@ proc _selftest_find_gdb { arg } { return $arg } -# A helper proc that sets up for self-testing. -# EXECUTABLE is the gdb to use. -# Return 0 in case of success, -1 in case of failure, and -2 in case of -# skipping the test-case. +# Return true if the GDB under test is installed (as opposed to a GDB in its +# build directory). -proc _selftest_setup { executable } { - global gdb_prompt - global INTERNAL_GDBFLAGS +proc _selftest_gdb_is_installed {} { + # If GDB_DATA_DIRECTORY is empty, assume that it is an installed GDB. It is + # not a perfectly accurate check, but should be good enough. + return [expr {"$::GDB_DATA_DIRECTORY" == ""}] +} - # load yourself into the debugger +# Return true if the libtool binary is present on the host. - global gdb_file_cmd_debug_info - set gdb_file_cmd_debug_info "unset" +proc _selftest_has_libtool {} { + lassign [remote_exec host "sh -c \"command -v libtool\""] status output + return [expr {$status == 0}] +} - set result [gdb_load $executable] +# Return true if EXECUTABLE has debug info. +# +# If it doesn't, or if it's not possible to determine, issue an UNTESTED test +# result and return false. + +proc _selftest_check_executable_debug_info { executable } { + set ::gdb_file_cmd_debug_info "unset" + set result true + + # On Cygwin (at least), gdb/gdb.exe is a libtool wrapper (which happens to + # be a PE executable). The real binary is gdb/.libs/gdb.exe. If we load + # gdb/gdb.exe, we won't see any debug info and conclude that we can't run + # the test. Obtain the real executable path using libtool. + # + # At the time of writing, we don't see a libtool wrapper generated on Linux. + # But if there was one, it would be a shell script, and it would not be + # possible to load it in gdb. This conversion would therefore also be + # necessary. + # + # If testing against an installed GDB, then there won't be a libtool + # wrapper, no need to convert. + if { ![_selftest_gdb_is_installed] && [_selftest_has_libtool] } { + lassign [remote_exec host libtool \ + "--mode=execute echo -n $executable"] \ + status executable + + if { $status != 0 } { + untested "failed to run libtool" + return false + } + } + + gdb_start - if {$result != 0} { - return -1 + if {[gdb_load $executable] != 0} { + untested "failed to load executable when checking for debug info" + set result false } - if {$gdb_file_cmd_debug_info != "debug"} { + if {$::gdb_file_cmd_debug_info != "debug"} { untested "no debug information, skipping testcase." - return -2 + set result false } + gdb_exit + + return $result +} + +# A helper proc that sets up for self-testing. +# +# Assumes that the inferior GDB is already loaded in the top-level GDB. +# +# Return 0 in case of success, -1 in case of failure, and -2 in case of +# skipping the test-case. + +proc _selftest_setup { } { + global gdb_prompt + global INTERNAL_GDBFLAGS + # Set a breakpoint at main set function main if { [gdb_breakpoint $function "no-message"] != 1 } { @@ -145,13 +196,32 @@ proc do_self_tests {body} { return } - gdb_start + # Check if the gdb executable has debug info. + if { ![_selftest_check_executable_debug_info $file] } { + return + } + + # FILE might be a libtool wrapper. In order to debug the real thing, pass + # FILE on the command-line of the top-level gdb, and run under + # `libtool --mode=execute. libtool will replace FILE with the path to the + # real executable and set any path required for it to find its dependent + # libraries. + # + # If testing against an installed GDB, there won't be a libtool wrapper. + save_vars { ::GDB ::GDBFLAGS } { + if { ![_selftest_gdb_is_installed] && [_selftest_has_libtool] } { + set ::GDB "libtool --mode=execute $::GDB" + } + + set ::GDBFLAGS "$::GDBFLAGS $file" + gdb_start + } # When debugging GDB with GDB, some operations can take a relatively long # time, especially if the build is non-optimized. Bump the timeout for the # duration of the test. with_timeout_factor 10 { - set result [_selftest_setup $file] + set result [_selftest_setup] if {$result == 0} { set result [uplevel $body] } |