diff options
Diffstat (limited to 'gdb/testsuite/lib/gdb.exp')
-rw-r--r-- | gdb/testsuite/lib/gdb.exp | 593 |
1 files changed, 570 insertions, 23 deletions
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index ead14bd..9970af6 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -269,6 +269,13 @@ if ![info exists INTERNAL_GDBFLAGS] { } set INTERNAL_GDBFLAGS [append_gdb_data_directory_option $INTERNAL_GDBFLAGS] + + # Handle the case that "interactive-mode auto" reports off. + append INTERNAL_GDBFLAGS { -iex "set interactive-mode on"} + + if { [ishost "*-*-mingw*"] } { + append INTERNAL_GDBFLAGS { -iex "maint set console-translation-mode binary"} + } } # The variable gdb_prompt is a regexp which matches the gdb prompt. @@ -280,10 +287,13 @@ if {![info exists gdb_prompt]} { set gdb_prompt "\\(gdb\\)" } -# A regexp that matches the pagination prompt. -set pagination_prompt \ +# The pagination prompt. +set pagination_prompt_str \ "--Type <RET> for more, q to quit, c to continue without paging--" +# A regexp that matches the pagination prompt. +set pagination_prompt [string_to_regexp $pagination_prompt_str] + # The variable fullname_syntax_POSIX is a regexp which matches a POSIX # absolute path ie. /foo/ set fullname_syntax_POSIX {/[^\n]*/} @@ -1026,7 +1036,10 @@ proc command_to_message { command } { # should not be anchored at the end of the buffer. This means that the # pattern can match even if there is stuff output after the prompt. Does not # have any effect if -prompt is specified. -# -lbl specifies that line-by-line matching will be used. +# -lbl specifies that line-by-line matching will be used. This means +# that lines from GDB not matched by any pattern will be consumed from +# the output buffer. This helps avoid buffer overflows and timeouts +# when testing verbose commands. # EXPECT_ARGUMENTS will be fed to expect in addition to the standard # patterns. Pattern elements will be evaluated in the caller's # context; action elements will be executed in the caller's context. @@ -1124,6 +1137,7 @@ proc gdb_test_multiple { command message args } { global any_spawn_id set line_by_line 0 + set lbl_anchor_re "" set prompt_regexp "" set prompt_anchor 1 for {set i 0} {$i < [llength $args]} {incr i} { @@ -1133,6 +1147,7 @@ proc gdb_test_multiple { command message args } { set prompt_regexp [lindex $args $i] } elseif { $arg == "-lbl" } { set line_by_line 1 + set lbl_anchor_re "^" } elseif { $arg == "-no-prompt-anchor" } { set prompt_anchor 0 } else { @@ -1391,7 +1406,7 @@ proc gdb_test_multiple { command message args } { fail "$errmsg" set result -1 } - -re "\r\n$prompt_regexp" { + -re "${lbl_anchor_re}\r\n$prompt_regexp" { if {![string match "" $message]} { fail "$message" } @@ -2237,6 +2252,177 @@ proc gdb_assert { condition {message ""} } { return $res } +# Comparison command for "lsort -command". Sorts two strings by +# descending file name length. + +proc compare_length_desc {a b} { + expr {[string length $b] - [string length $a]} +} + +# Fill in and return the global cache for Windows <=> Unix mount point +# mappings, for Windows. +# +# Calling external processes on MSYS2/Cygwin is expensive so instead +# of calling "cygpath -ua $FILENAME" or "cygpath -ma $FILENAME" for +# every file name, we extract the Windows and Unix file names of each +# mount point using the 'mount' command output, and cache the +# mappings, for both directions. + +gdb_caching_proc get_mount_point_map {} { + array set win_to_unix {} + array set unix_to_win {} + + # The 'mount' command provides all mappings. The general format + # is: 'WindowsFileName on UnixFileName type ...' + # + # For example: + # 'C:/msys64 on / type ntfs (binary,auto)' + # 'C: on /c type ntfs (binary,posix=0,user,noumount,auto)' + set mount_output [exec mount] + + foreach line [split $mount_output \n] { + if {[regexp {^(.+) on (.+) type } $line -> win_filename unix_filename]} { + set win_to_unix($win_filename) $unix_filename + set unix_to_win($unix_filename) $win_filename + } + } + + # Sort each mapping's keys by descending file name length, + # otherwise we wouldn't be able to look for '/foo' in '/' (for + # example). + + set sorted_win {} + foreach k [lsort -command compare_length_desc [array names win_to_unix]] { + lappend sorted_win $k $win_to_unix($k) + } + + set sorted_unix {} + foreach k [lsort -command compare_length_desc [array names unix_to_win]] { + lappend sorted_unix $k $unix_to_win($k) + } + + # Return both sorted lists: {win => unix} {unix => win} + return [list $sorted_win $sorted_unix] +} + +# Normalize backward slashes to forward slashes. + +proc normalize_slashes {filename} { + return [string map {\\ /} $filename] +} + +# Sanitize a host file name, without making it absolute or resolving +# symlinks. On native Windows, this normalizes slashes to forward +# slashes, and makes sure that if the file name starts with a drive +# letter, it is upper case. On other systems, it just returns the +# file name unmodified. + +proc host_file_sanitize {filename} { + if {[ishost *-*-mingw*]} { + set filename [normalize_slashes $filename] + + # If the file name starts with a drive letter, uppercase it. + if {[regexp {^([a-zA-Z]):(/.*)?} $filename -> drive rest]} { + set filename "[string toupper $drive]:$rest" + } + } + + return $filename +} + +# Normalize a file name for the build machine. If running native +# Windows GDB, this converts a Windows file name to the corresponding +# Unix filename, per the mount table. For example, this replaces +# 'c:/foo' with '/c/foo' (on MSYS2) or '/cygdrive/c/foo' (on Cygwin). +# On other systems, it just wraps "file normalize". + +proc build_file_normalize {filename} { + if {[ishost *-*-mingw*]} { + set filename [host_file_sanitize $filename] + + # Handle Windows => Unix mount point conversion. We assume + # there are no symlinks to resolve, which is a reasonable + # assumption for native Windows testing. + + # Get Windows => Unix map. + lassign [get_mount_point_map] win_to_unix _ + + foreach {win_filename unix_filename} $win_to_unix { + if {[string equal -length [string length $win_filename] \ + $win_filename $filename]} { + set rest [string range $filename \ + [string length $win_filename] end] + return "${unix_filename}$rest" + } + } + } + + return [file normalize $filename] +} + +# Normalize a file name for the host machine. If running native +# Windows GDB, this converts a Unix file name to a Windows filename, +# per the mount table. E.g., '/c/foo' (on MSYS2) or '/cygdrive/c/foo' +# (on Cygwin) is converted to 'c:/foo'. + +proc host_file_normalize {filename} { + if {[ishost *-*-mingw*]} { + set filename [host_file_sanitize $filename] + + # If the file name already starts with a drive letter (e.g., + # C:/foo), we're done. Don't let it fallthrough to "file + # normalize", which would misinterpret it as a relative file + # name. + if {[regexp {^[A-Z]:/} $filename]} { + return $filename + } + + # Get Unix => Windows map. + lassign [get_mount_point_map] _ unix_to_win + + foreach {unix_filename win_filename} $unix_to_win { + set mount_len [string length $unix_filename] + if {[string equal -length $mount_len $unix_filename $filename]} { + if {[string length $filename] == $mount_len} { + return "$win_filename/" + } elseif {[string index $filename $mount_len] eq "/"} { + set rest [string range $filename $mount_len end] + return "$win_filename$rest" + } + } + } + } + + return [file normalize $filename] +} + +# Wrapper around "file join" that handles host-specific details. +# +# For Cygwin/MSYS2's Tcl, file names that start with a drive letter +# are not considered absolute file names, thus 'file join "c:/" "d:/"' +# returns "c:/d:". This procedure thus detects absolute Windows-style +# file names, and treats them as absolute, bypassing "file join". + +proc host_file_join {args} { + if {[isbuild *-*-mingw*]} { + set result "" + foreach filename $args { + set filename [host_file_sanitize $filename] + + # If the file name starts with drive letter and colon + # (e.g., "C:/"), treat it as absolute. + if {[regexp {^[A-Z]:/} $filename]} { + set result $filename + } else { + set result [file join $result $filename] + } + } + return $result + } else { + return [file join {*}$args] + } +} + proc gdb_reinitialize_dir { subdir } { global gdb_prompt @@ -2251,7 +2437,8 @@ proc gdb_reinitialize_dir { subdir } { } gdb_expect 60 { -re "Source directories searched.*$gdb_prompt $" { - send_gdb "dir $subdir\n" + set dir [host_file_normalize $subdir] + send_gdb "dir $dir\n" gdb_expect 60 { -re "Source directories searched.*$gdb_prompt $" { verbose "Dir set to $subdir" @@ -2301,7 +2488,8 @@ proc default_gdb_exit {} { } } - if { [is_remote host] && [board_info host exists fileid] } { + if { ([is_remote host] && [board_info host exists fileid]) + || [istarget *-*-mingw*] } { send_gdb "quit\n" gdb_expect 10 { -re "y or n" { @@ -2314,7 +2502,9 @@ proc default_gdb_exit {} { } if ![is_remote host] { - remote_close host + if {[catch { remote_close host } message]} { + warning "closing gdb failed with: $message" + } } unset gdb_spawn_id unset ::gdb_tty_name @@ -2577,6 +2767,17 @@ proc default_gdb_start { } { # Output with -q, and bracketed paste mode enabled, see above. verbose "GDB initialized." } + -re "^\033\\\[6n$gdb_prompt $" { + # With MSYS2 and TERM={xterm,ansi}, I get: + # + # builtin_spawn gdb -q ... + # ^[[6n(gdb) + # + # We set TERM to dumb by default to avoid this, but some + # test-cases set TERM to xterm or ansi, in which case we get this + # output. + verbose "GDB initialized." + } -re "$gdb_prompt $" { perror "GDB never initialized." unset gdb_spawn_id @@ -4265,6 +4466,76 @@ gdb_caching_proc allow_tsx_tests {} { return $allow_tsx_tests } +# Run a test on the target to check if it supports x86 shadow stack. Return 1 +# if shadow stack is enabled, 0 otherwise. + +gdb_caching_proc allow_ssp_tests {} { + global srcdir subdir gdb_prompt hex + + set me "allow_ssp_tests" + + if { ![istarget i?86-*-*] && ![istarget x86_64-*-* ] } { + verbose "$me: target known to not support shadow stack." + return 0 + } + + # There is no need to check the actual HW in addition to ptrace support. + # We need both checks and ptrace will tell us about the HW state. + set compile_flags "{additional_flags=-fcf-protection=return}" + set src { int main() { return 0; } } + if {![gdb_simple_compile $me $src executable $compile_flags]} { + return 0 + } + + save_vars { ::env(GLIBC_TUNABLES) } { + + append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK" + + # No error message, compilation succeeded so now run it via gdb. + gdb_exit + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + gdb_load $obj + if {![runto_main]} { + remote_file build delete $obj + return 0 + } + set shadow_stack_disabled_re "(<unavailable>)" + if {[istarget *-*-linux*]} { + # Starting with v6.6, the Linux kernel supports CET shadow stack. + # Dependent on the target we can see a nullptr or "<unavailable>" + # when shadow stack is supported by HW and the Linux kernel but + # not enabled for the current thread (for example due to a lack + # of compiler or glibc support for -fcf-protection). + set shadow_stack_disabled_re "$shadow_stack_disabled_re|(.*0x0)" + } + + set allow_ssp_tests 0 + gdb_test_multiple "print \$pl3_ssp" "test shadow stack support" { + -re -wrap "(.*$hex)((?!(.*0x0)).)" { + verbose -log "$me: Shadow stack support detected." + set allow_ssp_tests 1 + } + -re -wrap $shadow_stack_disabled_re { + # In case shadow stack is not enabled (for example due to a + # lack of compiler or glibc support for -fcf-protection). + verbose -log "$me: Shadow stack is not enabled." + } + -re -wrap "void" { + # In case we don't have hardware or kernel support. + verbose -log "$me: No shadow stack support." + } + } + + gdb_exit + } + + remote_file build delete $obj + + verbose "$me: returning $allow_ssp_tests" 2 + return $allow_ssp_tests +} + # Run a test on the target to see if it supports avx512bf16. Return 1 if so, # 0 if it does not. Based on 'check_vmx_hw_available' from the GCC testsuite. @@ -5024,6 +5295,57 @@ gdb_caching_proc allow_aarch64_mops_tests {} { return $allow_mops_tests } +# Run a test on the target to see if it supports AArch64 GCS extensions. +# Return 1 if so, 0 if it does not. Note this causes a restart of GDB. + +gdb_caching_proc allow_aarch64_gcs_tests {} { + global srcdir subdir gdb_prompt inferior_exited_re + + set me "allow_aarch64_gcs_tests" + + if { ![is_aarch64_target]} { + return 0 + } + + # Compile a program that tests the GCS feature. + set src { + #include <stdbool.h> + #include <sys/auxv.h> + + /* Feature check for Guarded Control Stack. */ + #ifndef HWCAP_GCS + #define HWCAP_GCS (1UL << 32) + #endif + + int main (void) { + bool gcs_supported = getauxval (AT_HWCAP) & HWCAP_GCS; + + /* Return success if GCS is supported. */ + return !gcs_supported; + } + } + + if {![gdb_simple_compile $me $src executable]} { + return 0 + } + + # Compilation succeeded so now run it via gdb. + set allow_gcs_tests 0 + clean_restart $obj + gdb_run_cmd + gdb_expect { + -re ".*$inferior_exited_re normally.*${gdb_prompt} $" { + verbose -log "\n$me: gcs support detected" + set allow_gcs_tests 1 + } + } + gdb_exit + remote_file build delete $obj + + verbose "$me: returning $allow_gcs_tests" 2 + return $allow_gcs_tests +} + # A helper that compiles a test case to see if __int128 is supported. proc gdb_int128_helper {lang} { return [gdb_can_simple_compile "i128-for-$lang" { @@ -5087,6 +5409,40 @@ proc skip_inline_var_tests {} { return 0 } +# Return whether we allow running fork-related testcases. Targets +# that don't even have any concept of fork will just fail to compile +# the testcases and skip the tests that way if this returns true for +# them. Unix targets that do have a fork system call, but don't +# support intercepting forks will want to return false here, otherwise +# the testcases that exercise fork may hit a number of long cascading +# time out sequences. + +proc allow_fork_tests {} { + if {[istarget "*-*-cygwin*"] || [istarget "*-*-mingw*"]} { + return 0 + } + + return 1 +} + +# Return whether we allow running testcases that want to debug +# multiple inferiors with the same target. Not all targets support +# this. Note that some tests add a second inferior but never start +# it. Those tests should not be skipped due to this proc returning +# false. + +proc allow_multi_inferior_tests {} { + if {[istarget "*-*-cygwin*"] || [istarget "*-*-mingw*"]} { + return 0 + } + + if {[use_gdb_stub]} { + return 0 + } + + return 1 +} + # Return a 1 if we should run tests that require hardware breakpoints proc allow_hw_breakpoint_tests {} { @@ -5666,6 +6022,10 @@ proc gdb_simple_compile {name code {type object} {compile_flags {}} {object obj} set ext "d" break } + if { "$flag" eq "rust" } { + set ext "rs" + break + } } set src [standard_temp_file $name.$ext] set obj [standard_temp_file $name.$postfix] @@ -6244,6 +6604,9 @@ proc gdb_compile {source dest type options} { } } + # Automatically handle includes in testsuite/lib/. + auto_lappend_include_files options $source + cond_wrap [expr $pie != -1 || $nopie != -1] \ with_PIE_multilib_flags_filtered { set result [target_compile $source $dest $type $options] @@ -6779,7 +7142,20 @@ gdb_caching_proc can_spawn_for_attach {} { set me "can_spawn_for_attach" set src { - #include <unistd.h> + #ifdef _WIN32 + # include <windows.h> + #else + # include <unistd.h> + #endif + + #ifdef _WIN32 + unsigned + sleep (unsigned seconds) + { + Sleep (seconds * 1000); + return 0; + } + #endif int main (void) @@ -6920,7 +7296,7 @@ proc kill_wait_spawned_process { proc_spawn_id } { proc spawn_id_get_pid { spawn_id } { set testpid [exp_pid -i $spawn_id] - if { [istarget "*-*-cygwin*"] } { + if { [istarget "*-*-cygwin*"] || [istarget "*-*-mingw*"] } { # testpid is the Cygwin PID, GDB uses the Windows PID, which # might be different due to the way fork/exec works. set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ] @@ -7007,6 +7383,24 @@ proc gdb_load_cmd { args } { return -1 } +# Return non-zero if 'gcore' command is available. +gdb_caching_proc gcore_cmd_available { } { + gdb_exit + gdb_start + + # Does this gdb support gcore? + gdb_test_multiple "help gcore" "" { + -re -wrap "Undefined command: .*" { + return 0 + } + -re -wrap "Save a core file .*" { + return 1 + } + } + + return 0 +} + # Invoke "gcore". CORE is the name of the core file to write. TEST # is the name of the test case. This will return 1 if the core file # was created, 0 otherwise. If this fails to make a core file because @@ -7372,13 +7766,13 @@ proc clean_standard_output_dir {} { } # Directory containing the standard output files. - set standard_output_dir [file normalize [standard_output_file ""]] + set standard_output_dir [build_standard_output_file ""] # Ensure that standard_output_dir is clean, or only contains # gdb.log / gdb.sum. set log_file_info [split [log_file -info]] set log_file [file normalize [lindex $log_file_info end]] - if { $log_file == [file normalize [standard_output_file gdb.log]] } { + if { $log_file == [file normalize [build_standard_output_file gdb.log]] } { # Dir already contains active gdb.log. Don't remove the dir, but # check that it's clean otherwise. set res [glob -directory $standard_output_dir -tails *] @@ -7471,6 +7865,22 @@ proc default_gdb_init { test_file_name } { setenv LC_CTYPE C setenv LANG C + # With MSYS2 and TERM={xterm,ansi}, I get: + # + # builtin_spawn gdb -q ... + # ^[[6n(gdb) + # + # While we're addressing this in default_gdb_start, this is not specific + # to gdb, other tools produce the same CSI sequence, and consequently we + # run into trouble in other places (like get_compiler_info). + # + # Set TERM to dumb to prevent the '^[[6n' from occurring. + # + # We could do this only for ishost *-*-mingw*, but that introduces + # inconsistency between platforms, with test-cases passing on one platform + # but failing on the other. So, we do this for all platforms. + setenv TERM dumb + # Don't let a .inputrc file or an existing setting of INPUTRC mess # up the test results. Certain tests (style tests and TUI tests) # want to set the terminal to a non-"dumb" value, and for those we @@ -7617,22 +8027,39 @@ proc make_gdb_parallel_path { args } { } # Turn BASENAME into a full file name in the standard output -# directory. It is ok if BASENAME is the empty string; in this case -# the directory is returned. +# directory, as seen from the build machine. I.e., as seen from the +# system driving DejaGnu. (E.g., if DejaGnu is being driven by MSYS2 +# to test native Windows GDB, the "build" file names should be file +# names TCL understands, i.e., Unix file names.) It is OK if BASENAME +# is the empty string; in this case the directory is returned. -proc standard_output_file {basename} { +proc build_standard_output_file {basename} { global objdir subdir gdb_test_file_name set dir [make_gdb_parallel_path outputs $subdir $gdb_test_file_name] file mkdir $dir - # If running on MinGW, replace /c/foo with c:/foo - if { [ishost *-*-mingw*] } { - set dir [exec sh -c "cd ${dir} && pwd -W"] - } return [file join $dir $basename] } -# Turn BASENAME into a file name on host. +# Turn BASENAME into a full file name in the standard output +# directory, as seen from a non-remote host. I.e., assuming the build +# and the host share the filesystem. E.g., if DejaGnu is being driven +# by MSYS2 to test native Windows GDB, the "host" file names should be +# file names GDB understands, i.e., Windows file names. It is OK if +# BASENAME is the empty string; in this case the directory is +# returned. + +proc standard_output_file {basename} { + global objdir subdir gdb_test_file_name + + set dir [make_gdb_parallel_path outputs $subdir $gdb_test_file_name] + file mkdir $dir + set dir [host_file_normalize $dir] + return [host_file_join $dir $basename] +} + +# Like standard_output_file, but handles remote hosts. Turn BASENAME +# into a file name on (potentially remote) host. proc host_standard_output_file { basename } { if { [is_remote host] } { @@ -9262,7 +9689,13 @@ proc remove_core {pid {test ""}} { } } -proc core_find {binfile {deletefiles {}} {arg ""}} { +# Runs ${binfile} expecting it to crash and generate a core file. +# If DELETEFILES is provided, remove these files after running the program. +# If ARG is provided, pass it as a command line argument to the program. +# If OUTPUT_FILE is provided, save the program output to it. +# Returns the name of the core dump, or empty string if not found. + +proc core_find {binfile {deletefiles {}} {arg ""} {output_file "/dev/null"}} { global objdir subdir set destcore "$binfile.core" @@ -9284,9 +9717,14 @@ proc core_find {binfile {deletefiles {}} {arg ""}} { set found 0 set coredir [standard_output_file coredir.[getpid]] file mkdir $coredir - catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile} ${arg}; true) >/dev/null 2>&1\"" + catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile} ${arg}; true) >${output_file} 2>&1\"" # remote_exec host "${binfile}" - foreach i "${coredir}/core ${coredir}/core.coremaker.c ${binfile}.core" { + set binfile_basename [file tail $binfile] + foreach i [list \ + ${coredir}/core \ + ${coredir}/core.coremaker.c \ + ${coredir}/${binfile_basename}.core \ + ${coredir}/${binfile_basename}.exe.core] { if [remote_file build exists $i] { remote_exec build "mv $i $destcore" set found 1 @@ -9891,6 +10329,10 @@ proc gdb_stdin_log_init { } { set logfile [standard_output_file_with_gdb_instance gdb.in] set in_file [open $logfile w] + + verbose -log "" + verbose -log "Starting logfile: $logfile" + verbose -log "" } # Write to the file for logging gdb input. @@ -10324,7 +10766,11 @@ proc with_override { name override body } { proc with_ansi_styling_terminal { body } { save_vars { ::env(TERM) ::env(NO_COLOR) ::env(COLORTERM) } { # Set environment variables to allow styling. - setenv TERM ansi + if { [ishost *-*-*bsd*] } { + setenv TERM ansiw + } else { + setenv TERM ansi + } unset -nocomplain ::env(NO_COLOR) unset -nocomplain ::env(COLORTERM) @@ -11000,6 +11446,66 @@ proc lappend_include_file { flags file } { } } +# Helper for auto_lappend_include_files that handles one source file, +# and tracks the list of already-visited files. + +proc auto_lappend_include_files_1 {flags source {visited {}}} { + upvar $flags up_flags + upvar $visited up_visited + global srcdir + + set ext [string tolower [file extension $source]] + if {$ext ni {".c" ".cpp" ".cc" ".h" ".s"}} { + return + } + + if {[catch {open $source r} fh err]} { + error "Failed to open file '$source': $err" + } + set contents [read $fh] + close $fh + + lappend up_visited $source + + # Match lines like: + # #include "gdb_foo.h" + set re "^\\s*#include\\s+\"(.*)\"" + + foreach line [split $contents "\n"] { + if {[regexp $re $line -> basename]} { + set lib_file "$srcdir/lib/$basename" + + # If already processed, skip. + if {[lsearch -exact $up_visited $lib_file] != -1} { + continue + } + + if {![file exists $lib_file]} { + continue + } + + # Append to include list, and recurse into the included + # file. + lappend_include_file up_flags $lib_file + auto_lappend_include_files_1 up_flags $lib_file up_visited + } + } +} + +# Automatically handle includes under gdb/testsuite/lib/. +# +# For each source file in SOURCES, look for #include directives +# including files that live in testsuite/lib/. For each such included +# file, call lappend_include_file for it. + +proc auto_lappend_include_files {flags sources} { + upvar $flags up_flags + set visited {} + foreach src $sources { + auto_lappend_include_files_1 up_flags $src visited + } +} + # Return a list of supported host locales. gdb_caching_proc host_locales { } { @@ -11111,5 +11617,46 @@ gdb_caching_proc have_builtin_trap {} { } executable] } +# Return 1 if there is a startup shell. Return -1 if there's no startup shell. +# Return -1 otherwise. + +gdb_caching_proc have_startup_shell {} { + if { [is_remote target] } { + # For remote debugging targets, there is no guarantee that a "shell" + # is used. + return -1 + } + + + gdb_exit + gdb_start + + set re_on \ + [string_to_regexp "Use of shell to start subprocesses is on."] + set re_off \ + [string_to_regexp "Use of shell to start subprocesses is off."] + set re_cmd_unsupported \ + [string_to_regexp \ + {Undefined show command: "startup-with-shell". Try "help show".}] + + set supported -1 + gdb_test_multiple "show startup-with-shell" "" { + -re -wrap $re_on { + set supported 1 + } + -re -wrap $re_off { + set supported 0 + } + -re -wrap $re_cmd_unsupported { + } + -re -wrap "" { + } + } + + gdb_exit + + return $supported +} + # Always load compatibility stuff. load_lib future.exp |