blob: af8ec6fb9820e5cf99d78533c4ebe9f021292401 [file] [log] [blame]
# Copyright 2003-2025 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/>.
# Find a pathname to a file that we would execute if the shell was asked
# to run $arg using the current PATH.
proc _selftest_find_gdb { arg } {
# If the arg directly specifies an existing executable file, then
# simply use it.
if {[file executable $arg]} {
return $arg
}
set result [which $arg]
if {[string match "/" [ string range $result 0 0 ]]} {
return $result
}
# If everything fails, just return the unqualified pathname as default
# and hope for best.
return $arg
}
# Return true if the GDB under test is installed (as opposed to a GDB in its
# build directory).
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
}
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 ""
}
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
}
gdb_start
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"} {
untested "no debug information, skipping testcase."
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 } {
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 -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
}
# 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.
proc selftest_prepare {} {
# Are we testing with a remote board? In that case, the target
# won't have access to the GDB's auxiliary data files
# (data-directory, etc.). It's simpler to just skip.
if { [is_remote target] || [is_remote host] } {
return
}
# ... or seemingly testing with a cross debugger? Likely GDB
# wouldn't be able to debug itself then...
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] {
return
}
return [_selftest_find_gdb $::GDB]
}
# A simple way to run some self-tests.
proc do_self_tests {body} {
set file [selftest_prepare]
if { $file eq "" } {
return
}
# 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]
if {$result == 0} {
set result [uplevel $body]
}
}
gdb_exit
if {$result == -1} {
warning "Couldn't test self"
}
}