aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/lib/selftest-support.exp
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/testsuite/lib/selftest-support.exp')
-rw-r--r--gdb/testsuite/lib/selftest-support.exp220
1 files changed, 160 insertions, 60 deletions
diff --git a/gdb/testsuite/lib/selftest-support.exp b/gdb/testsuite/lib/selftest-support.exp
index e037664..d0905eb 100644
--- a/gdb/testsuite/lib/selftest-support.exp
+++ b/gdb/testsuite/lib/selftest-support.exp
@@ -16,7 +16,7 @@
# Find a pathname to a file that we would execute if the shell was asked
# to run $arg using the current PATH.
-proc find_gdb { arg } {
+proc _selftest_find_gdb { arg } {
# If the arg directly specifies an existing executable file, then
# simply use it.
@@ -36,65 +36,163 @@ proc find_gdb { arg } {
return $arg
}
-# A helper proc that sets up for self-testing.
-# EXECUTABLE is the gdb to use.
-# FUNCTION is the function to break in, either captured_main
-# or captured_command_loop.
-# 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 function } {
- 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" == ""}]
+}
+
+# Return true if the libtool binary is present on the host.
+
+proc _selftest_has_libtool {} {
+ lassign [remote_exec host "sh -c \"command -v libtool\""] status output
+ return [expr {$status == 0}]
+}
+
+# If GDB is executed from a build tree, run libtool to obtain the real
+# executable path for EXECUTABLE, which may be a libtool wrapper. Return
+# the path on success. On failure, issue an UNTESTED test result and return
+# an empty string.
+#
+# If GDB is executed from an installed location, return EXECUTABLE unchanged.
+#
+# If libtool is not present on the host system, return EXECUTABLE unchanged.
+# The test might still work, because the GDB binary is not always a libtool
+# wrapper.
+
+proc selftest_libtool_get_real_gdb_executable { executable } {
+ if {[_selftest_gdb_is_installed]} {
+ return $executable
+ }
- # load yourself into the debugger
+ if {![_selftest_has_libtool]} {
+ return $executable
+ }
+
+ lassign [remote_exec host libtool "--mode=execute echo -n $executable"] \
+ status executable
+
+ if { $status != 0 } {
+ untested "failed to run libtool"
+ return ""
+ }
- global gdb_file_cmd_debug_info
- set gdb_file_cmd_debug_info "unset"
+ return $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.
+ set executable [selftest_libtool_get_real_gdb_executable $executable]
+
+ if { $executable == "" } {
+ # selftest_libtool_get_real_gdb_executable already records an UNTESTED
+ # on failure.
+ return false
+ }
- set result [gdb_load $executable]
+ 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
}
- # Set a breakpoint at $function.
+ 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 } {
untested "Cannot set breakpoint at $function, skipping testcase."
return -2
}
+ # Debugging on Windows shows random threads starting and exiting,
+ # interfering with the tests. Disable them, since they are not useful here.
+ gdb_test_no_output "set print thread-events off"
+
# run yourself
set description "run until breakpoint at $function"
+ set re_hs {[^\r\n]+}
+ set re_args [string cat \
+ [string_to_regexp "("] \
+ $re_hs \
+ [string_to_regexp ")"]]
+ set re_pass \
+ [multi_line \
+ "Starting program: $re_hs" \
+ ".*" \
+ [string cat "Breakpoint $::decimal, $function $re_args at" \
+ " ${re_hs}gdb.c:$re_hs"] \
+ ".*"]
+ set re_xfail \
+ [multi_line \
+ "Starting program: $re_hs" \
+ ".*" \
+ "Breakpoint $::decimal, $function $re_args$re_hs" \
+ ".*"]
gdb_test_multiple "run $INTERNAL_GDBFLAGS" "$description" {
- -re "Starting program.*Breakpoint \[0-9\]+,.*$function \\(.*\\).* at .*main.c:.*$gdb_prompt $" {
- pass "$description"
- }
- -re "Starting program.*Breakpoint \[0-9\]+,.*$function \\(.*\\).*$gdb_prompt $" {
- xfail "$description (line numbers scrambled?)"
- }
- -re "vfork: No more processes.*$gdb_prompt $" {
- fail "$description (out of virtual memory)"
- return -1
- }
- -re ".*$gdb_prompt $" {
- fail "$description"
- return -1
- }
+ -re -wrap $re_pass {
+ pass $description
+ }
+ -re -wrap $re_xfail {
+ xfail "$description (line numbers scrambled?)"
+ }
+ -re -wrap "vfork: No more processes.*" {
+ fail "$description (out of virtual memory)"
+ return -1
+ }
+ -re -wrap "" {
+ fail $description
+ return -1
+ }
}
return 0
}
-# Prepare for running a self-test by moving the GDB executable to a
-# location where we can use it as the inferior. Return the filename
-# of the new location.
+# Return the location of the gdb executable to test.
#
# If the current testing setup is not suitable for running a
# self-test, then return an empty string.
@@ -108,58 +206,60 @@ proc selftest_prepare {} {
# ... or seemingly testing with a cross debugger? Likely GDB
# wouldn't be able to debug itself then...
- if ![isnative] {
+ if {![isnative]} {
return
}
# ... or with a stub-like server? I.e., gdbserver + "target
# remote"? In that case we won't be able to pass command line
- # arguments to GDB, and selftest_setup wants to do exactly that.
- if [use_gdb_stub] {
+ # arguments to GDB, and _selftest_setup wants to do exactly that.
+ if {[use_gdb_stub]} {
return
}
- # Run the test with self. Copy the file executable file in case
- # this OS doesn't like to edit its own text space.
-
- set gdb_fullpath [find_gdb $::GDB]
-
- if {[is_remote host]} {
- set xgdb x$::tool
- } else {
- set xgdb [standard_output_file x$::tool]
- }
-
- # Remove any old copy lying around.
- remote_file host delete $xgdb
-
- set filename [remote_download host $gdb_fullpath $xgdb]
-
- return $filename
+ return [_selftest_find_gdb $::GDB]
}
# A simple way to run some self-tests.
-proc do_self_tests {function body} {
+proc do_self_tests {body} {
set file [selftest_prepare]
if { $file eq "" } {
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 $function]
+ set result [_selftest_setup]
if {$result == 0} {
set result [uplevel $body]
}
}
gdb_exit
- catch "remote_file host delete $file"
if {$result == -1} {
warning "Couldn't test self"