}
-# gdb_test_multiple COMMAND MESSAGE EXPECT_ARGUMENTS
+# gdb_test_multiple COMMAND MESSAGE EXPECT_ARGUMENTS PROMPT_REGEXP
# Send a command to gdb; test the result.
#
# COMMAND is the command to execute, send to GDB with send_gdb. If
# context; action elements will be executed in the caller's context.
# Unlike patterns for gdb_test, these patterns should generally include
# the final newline and prompt.
+# PROMPT_REGEXP is a regexp matching the expected prompt after the command
+# output. If empty, defaults to "$gdb_prompt $"
#
# Returns:
# 1 if the test failed, according to a built-in failure pattern
# expected from $gdb_spawn_id. IOW, callers do not need to worry
# about resetting "-i" back to $gdb_spawn_id explicitly.
#
-proc gdb_test_multiple { command message user_code } {
+proc gdb_test_multiple { command message user_code { prompt_regexp "" } } {
global verbose use_gdb_stub
global gdb_prompt pagination_prompt
global GDB
upvar expect_out expect_out
global any_spawn_id
+ if { "$prompt_regexp" == "" } {
+ set prompt_regexp "$gdb_prompt $"
+ }
+
if { $message == "" } {
set message $command
}
}
append code {
- -re "Ending remote debugging.*$gdb_prompt $" {
+ -re "Ending remote debugging.*$prompt_regexp" {
if ![isnative] then {
warning "Can`t communicate to remote target."
}
gdb_start
set result -1
}
- -re "Undefined\[a-z\]* command:.*$gdb_prompt $" {
+ -re "Undefined\[a-z\]* command:.*$prompt_regexp" {
perror "Undefined command \"$command\"."
fail "$message"
set result 1
}
- -re "Ambiguous command.*$gdb_prompt $" {
+ -re "Ambiguous command.*$prompt_regexp" {
perror "\"$command\" is not a unique command name."
fail "$message"
set result 1
}
- -re "$inferior_exited_re with code \[0-9\]+.*$gdb_prompt $" {
+ -re "$inferior_exited_re with code \[0-9\]+.*$prompt_regexp" {
if ![string match "" $message] then {
set errmsg "$message (the program exited)"
} else {
fail "$errmsg"
set result -1
}
- -re "$inferior_exited_re normally.*$gdb_prompt $" {
+ -re "$inferior_exited_re normally.*$prompt_regexp" {
if ![string match "" $message] then {
set errmsg "$message (the program exited)"
} else {
fail "$errmsg"
set result -1
}
- -re "The program is not being run.*$gdb_prompt $" {
+ -re "The program is not being run.*$prompt_regexp" {
if ![string match "" $message] then {
set errmsg "$message (the program is no longer running)"
} else {
fail "$errmsg"
set result -1
}
- -re "\r\n$gdb_prompt $" {
+ -re "\r\n$prompt_regexp" {
if ![string match "" $message] then {
fail "$message"
}
}
-re "\\((y or n|y or \\\[n\\\]|\\\[y\\\] or n)\\) " {
send_gdb "n\n" answer
- gdb_expect -re "$gdb_prompt $"
+ gdb_expect -re "$prompt_regexp"
fail "$message (got interactive prompt)"
set result -1
}
-re "\\\[0\\\] cancel\r\n\\\[1\\\] all.*\r\n> $" {
send_gdb "0\n"
- gdb_expect -re "$gdb_prompt $"
+ gdb_expect -re "$prompt_regexp"
fail "$message (got breakpoint menu)"
set result -1
}
}]
}
+# Return 1 if version MAJOR.MINOR is at least AT_LEAST_MAJOR.AT_LEAST_MINOR.
+proc version_at_least { major minor at_least_major at_least_minor} {
+ if { $major > $at_least_major } {
+ return 1
+ } elseif { $major == $at_least_major \
+ && $minor >= $at_least_minor } {
+ return 1
+ } else {
+ return 0
+ }
+}
+
+# Return 1 if tcl version used is at least MAJOR.MINOR
+proc tcl_version_at_least { major minor } {
+ global tcl_version
+ regexp {^([0-9]+)\.([0-9]+)$} $tcl_version \
+ dummy tcl_version_major tcl_version_minor
+ return [version_at_least $tcl_version_major $tcl_version_minor \
+ $major $minor]
+}
+
+if { [tcl_version_at_least 8 5] == 0 } {
+ # lrepeat was added in tcl 8.5. Only add if missing.
+ proc lrepeat { n element } {
+ if { [string is integer -strict $n] == 0 } {
+ error "expected integer but got \"$n\""
+ }
+ if { $n < 0 } {
+ error "bad count \"$n\": must be integer >= 0"
+ }
+ set res [list]
+ for {set i 0} {$i < $n} {incr i} {
+ lappend res $element
+ }
+ return $res
+ }
+}
+
# gdb_test_no_output COMMAND MESSAGE
# Send a command to GDB and verify that this command generated no output.
#
return 1
}
-re "$prompt_regexp" {}
- }
+ } "$prompt_regexp"
gdb_test_multiple "python print (sys.version_info\[0\])" "check if python 3" {
-re "3.*$prompt_regexp" {
-re ".*$prompt_regexp" {
set gdb_py_is_py3k 0
}
- }
+ } "$prompt_regexp"
return 0
}
upvar 1 $var myvar
foreach myvar $list {
with_test_prefix "$var=$myvar" {
- uplevel 1 $body
+ set code [catch {uplevel 1 $body} result]
+ }
+
+ if {$code == 1} {
+ global errorInfo errorCode
+ return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+ } elseif {$code == 3} {
+ break
+ } elseif {$code == 2} {
+ return -code $code $result
}
}
}
# Return 0 if we should skip tests that require the libstdc++ stap
# probes. This must be invoked while gdb is running, after shared
-# libraries have been loaded.
-
-proc skip_libstdcxx_probe_tests {} {
- global gdb_prompt
+# libraries have been loaded. PROMPT_REGEXP is the expected prompt.
+proc skip_libstdcxx_probe_tests_prompt { prompt_regexp } {
set ok 0
gdb_test_multiple "info probe" "check for stap probe in libstdc++" {
- -re ".*libstdcxx.*catch.*\r\n$gdb_prompt $" {
+ -re ".*libstdcxx.*catch.*\r\n$prompt_regexp" {
set ok 1
}
- -re "\r\n$gdb_prompt $" {
+ -re "\r\n$prompt_regexp" {
}
- }
+ } "$prompt_regexp"
return $ok
}
+# As skip_libstdcxx_probe_tests_prompt, with gdb_prompt.
+
+proc skip_libstdcxx_probe_tests {} {
+ global gdb_prompt
+ return [skip_libstdcxx_probe_tests_prompt "$gdb_prompt $"]
+}
+
# Return 1 if we should skip tests of the "compile" feature.
# This must be invoked after the inferior has been started.
-re "$prompt_regexp" {
pass $test
}
- }
+ } "$prompt_regexp"
return 0
}
regsub "\[\r\n\]*$" "$result" "" result
regsub "^\[\r\n\]*" "$result" "" result
+ if { $type == "executable" && $result == "" \
+ && ($nopie != -1 || $pie != -1) } {
+ set is_pie [exec_is_pie "$dest"]
+ if { $nopie != -1 && $is_pie == 1 } {
+ set result "nopie failed to prevent PIE executable"
+ } elseif { $pie != -1 && $is_pie == 0 } {
+ set result "pie failed to generate PIE executable"
+ }
+ }
+
if {[lsearch $options quiet] < 0} {
# We shall update this on a per language basis, to avoid
# changing the entire testsuite in one go.
return 0
}
+# Return list with major and minor version of readelf, or an empty list.
+gdb_caching_proc readelf_version {
+ set readelf_program [gdb_find_readelf]
+ set res [catch {exec $readelf_program --version} output]
+ if { $res != 0 } {
+ return [list]
+ }
+ set lines [split $output \n]
+ set line [lindex $lines 0]
+ set res [regexp {[ \t]+([0-9]+)[.]([0-9]+)[^ \t]*$} \
+ $line dummy major minor]
+ if { $res != 1 } {
+ return [list]
+ }
+ return [list $major $minor]
+}
+
+# Return 1 if readelf prints the PIE flag, 0 if is doesn't, and -1 if unknown.
+proc readelf_prints_pie { } {
+ set version [readelf_version]
+ if { [llength $version] == 0 } {
+ return -1
+ }
+ set major [lindex $version 0]
+ set minor [lindex $version 1]
+ # It would be better to construct a PIE executable and test if the PIE
+ # flag is printed by readelf, but we cannot reliably construct a PIE
+ # executable if the multilib_flags dictate otherwise
+ # (--target_board=unix/-no-pie/-fno-PIE).
+ return [version_at_least $major $minor 2 26]
+}
+
+# Return 1 if EXECUTABLE is a Position Independent Executable, 0 if it is not,
+# and -1 if unknown.
+
+proc exec_is_pie { executable } {
+ set res [readelf_prints_pie]
+ if { $res != 1 } {
+ return -1
+ }
+ set readelf_program [gdb_find_readelf]
+ set res [catch {exec $readelf_program -d $executable} output]
+ if { $res != 0 } {
+ return -1
+ }
+ set res [regexp -line {\(FLAGS_1\).*Flags:.* PIE($| )} $output]
+ if { $res == 1 } {
+ return 1
+ }
+ return 0
+}
+
# Return true if a test should be skipped due to lack of floating
# point support or GDB can't fetch the contents from floating point
# registers.
# Test the output of GDB_COMMAND matches the pattern obtained
# by concatenating all elements of EXPECTED_LINES. This makes
# it possible to split otherwise very long string into pieces.
-# If third argument is not empty, it's used as the name of the
+# If third argument TESTNAME is not empty, it's used as the name of the
# test to be printed on pass/fail.
-proc help_test_raw { gdb_command expected_lines args } {
- set message $gdb_command
- if [llength $args]>0 then {
- set message [lindex $args 0]
- }
+proc help_test_raw { gdb_command expected_lines {testname {}} } {
+ if {$testname == {}} {
+ set message $gdb_command
+ } else {
+ set message $testname
+ }
set expected_output [join $expected_lines ""]
gdb_test "${gdb_command}" "${expected_output}" $message
}
-# Test the output of "help COMMAND_CLASS". EXPECTED_INITIAL_LINES
+# A regexp that matches the end of help CLASS|PREFIX_COMMAND
+set help_list_trailer {
+ "Type \"apropos word\" to search for commands related to \"word\"\.[\r\n]+"
+ "Type \"apropos -v word\" for full documentation of commands related to \"word\"\.[\r\n]+"
+ "Command name abbreviations are allowed if unambiguous\."
+}
+
+# Test the output of "help COMMAND_CLASS". EXPECTED_INITIAL_LINES
# are regular expressions that should match the beginning of output,
-# before the list of commands in that class. The presence of
-# command list and standard epilogue will be tested automatically.
+# before the list of commands in that class.
+# LIST_OF_COMMANDS are regular expressions that should match the
+# list of commands in that class. If empty, the command list will be
+# matched automatically. The presence of standard epilogue will be tested
+# automatically.
+# If last argument TESTNAME is not empty, it's used as the name of the
+# test to be printed on pass/fail.
# Notice that the '[' and ']' characters don't need to be escaped for strings
# wrapped in {} braces.
-proc test_class_help { command_class expected_initial_lines args } {
+proc test_class_help { command_class expected_initial_lines {list_of_commands {}} {testname {}} } {
+ global help_list_trailer
+ if {[llength $list_of_commands]>0} {
+ set l_list_of_commands {"List of commands:[\r\n]+[\r\n]+"}
+ set l_list_of_commands [concat $l_list_of_commands $list_of_commands]
+ set l_list_of_commands [concat $l_list_of_commands {"[\r\n]+[\r\n]+"}]
+ } else {
+ set l_list_of_commands {"List of commands\:.*[\r\n]+"}
+ }
set l_stock_body {
- "List of commands\:.*[\r\n]+"
"Type \"help\" followed by command name for full documentation\.[\r\n]+"
- "Type \"apropos word\" to search for commands related to \"word\"\.[\r\n]+"
- "Command name abbreviations are allowed if unambiguous\."
}
- set l_entire_body [concat $expected_initial_lines $l_stock_body]
+ set l_entire_body [concat $expected_initial_lines $l_list_of_commands \
+ $l_stock_body $help_list_trailer]
+
+ help_test_raw "help ${command_class}" $l_entire_body $testname
+}
- eval [list help_test_raw "help ${command_class}" $l_entire_body] $args
+# Like test_class_help but specialised to test "help user-defined".
+proc test_user_defined_class_help { {list_of_commands {}} {testname {}} } {
+ test_class_help "user-defined" {
+ "User-defined commands\.[\r\n]+"
+ "The commands in this class are those defined by the user\.[\r\n]+"
+ "Use the \"define\" command to define a command\.[\r\n]+"
+ } $list_of_commands $testname
}
+
# COMMAND_LIST should have either one element -- command to test, or
# two elements -- abbreviated command to test, and full command the first
# element is abbreviation of.
# before the list of subcommands. The presence of
# subcommand list and standard epilogue will be tested automatically.
proc test_prefix_command_help { command_list expected_initial_lines args } {
+ global help_list_trailer
set command [lindex $command_list 0]
if {[llength $command_list]>1} {
set full_command [lindex $command_list 1]
# be expanded in this list.
set l_stock_body [list\
"List of $full_command subcommands\:.*\[\r\n\]+"\
- "Type \"help $full_command\" followed by $full_command subcommand name for full documentation\.\[\r\n\]+"\
- "Type \"apropos word\" to search for commands related to \"word\"\.\[\r\n\]+"\
- "Command name abbreviations are allowed if unambiguous\."]
- set l_entire_body [concat $expected_initial_lines $l_stock_body]
+ "Type \"help $full_command\" followed by $full_command subcommand name for full documentation\.\[\r\n\]+"]
+ set l_entire_body [concat $expected_initial_lines $l_stock_body $help_list_trailer]
if {[llength $args]>0} {
help_test_raw "help ${command}" $l_entire_body [lindex $args 0]
} else {