Index: gdb/testsuite/lib/gdb.exp |
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp |
index b06e723fc6df86899a1c824e28179bbb10f0223e..df2d81839e2ef092f272c03b13ea8efc220c8de8 100644 |
--- a/gdb/testsuite/lib/gdb.exp |
+++ b/gdb/testsuite/lib/gdb.exp |
@@ -52,10 +52,13 @@ if ![info exists GDBFLAGS] { |
} |
verbose "using GDBFLAGS = $GDBFLAGS" 2 |
+# Make the build data directory available to tests. |
+set BUILD_DATA_DIRECTORY "[pwd]/../data-directory" |
+ |
# INTERNAL_GDBFLAGS contains flags that the testsuite requires. |
global INTERNAL_GDBFLAGS |
if ![info exists INTERNAL_GDBFLAGS] { |
- set INTERNAL_GDBFLAGS "-nw -nx -data-directory [pwd]/../data-directory" |
+ set INTERNAL_GDBFLAGS "-nw -nx -data-directory $BUILD_DATA_DIRECTORY" |
} |
# The variable gdb_prompt is a regexp which matches the gdb prompt. |
@@ -266,13 +269,6 @@ proc gdb_run_cmd {args} { |
} |
} |
} |
- if [target_info exists gdb_stub] { |
- gdb_expect 60 { |
- -re "$gdb_prompt $" { |
- send_gdb "continue\n" |
- } |
- } |
- } |
return |
} |
@@ -312,7 +308,7 @@ proc gdb_start_cmd {args} { |
-re "$gdb_prompt $" { } |
default { |
perror "gdb_init_command for target failed"; |
- return; |
+ return -1; |
} |
} |
} |
@@ -338,29 +334,44 @@ proc gdb_start_cmd {args} { |
# Set a breakpoint at FUNCTION. If there is an additional argument it is |
# a list of options; the supported options are allow-pending, temporary, |
-# and no-message. |
+# message, no-message, and passfail. |
+# The result is 1 for success, 0 for failure. |
+# |
+# Note: The handling of message vs no-message is messed up, but it's based |
+# on historical usage. By default this function does not print passes, |
+# only fails. |
+# no-message: turns off printing of fails (and passes, but they're already off) |
+# message: turns on printing of passes (and fails, but they're already on) |
proc gdb_breakpoint { function args } { |
global gdb_prompt |
global decimal |
set pending_response n |
- if {[lsearch -exact [lindex $args 0] allow-pending] != -1} { |
+ if {[lsearch -exact $args allow-pending] != -1} { |
set pending_response y |
} |
set break_command "break" |
set break_message "Breakpoint" |
- if {[lsearch -exact [lindex $args 0] temporary] != -1} { |
+ if {[lsearch -exact $args temporary] != -1} { |
set break_command "tbreak" |
set break_message "Temporary breakpoint" |
} |
- set no_message 0 |
- if {[lsearch -exact [lindex $args 0] no-message] != -1} { |
- set no_message 1 |
+ set print_pass 0 |
+ set print_fail 1 |
+ set no_message_loc [lsearch -exact $args no-message] |
+ set message_loc [lsearch -exact $args message] |
+ # The last one to appear in args wins. |
+ if { $no_message_loc > $message_loc } { |
+ set print_fail 0 |
+ } elseif { $message_loc > $no_message_loc } { |
+ set print_pass 1 |
} |
+ set test_name "setting breakpoint at $function" |
+ |
send_gdb "$break_command $function\n" |
# The first two regexps are what we get with -g, the third is without -g. |
gdb_expect 30 { |
@@ -369,8 +380,8 @@ proc gdb_breakpoint { function args } { |
-re "$break_message \[0-9\]* at .*$gdb_prompt $" {} |
-re "$break_message \[0-9\]* \\(.*\\) pending.*$gdb_prompt $" { |
if {$pending_response == "n"} { |
- if { $no_message == 0 } { |
- fail "setting breakpoint at $function" |
+ if { $print_fail } { |
+ fail $test_name |
} |
return 0 |
} |
@@ -380,23 +391,34 @@ proc gdb_breakpoint { function args } { |
exp_continue |
} |
-re "A problem internal to GDB has been detected" { |
- fail "setting breakpoint at $function in runto (GDB internal error)" |
+ if { $print_fail } { |
+ fail "$test_name (GDB internal error)" |
+ } |
gdb_internal_error_resync |
return 0 |
} |
-re "$gdb_prompt $" { |
- if { $no_message == 0 } { |
- fail "setting breakpoint at $function" |
+ if { $print_fail } { |
+ fail $test_name |
+ } |
+ return 0 |
+ } |
+ eof { |
+ if { $print_fail } { |
+ fail "$test_name (eof)" |
} |
return 0 |
} |
timeout { |
- if { $no_message == 0 } { |
- fail "setting breakpoint at $function (timeout)" |
+ if { $print_fail } { |
+ fail "$test_name (timeout)" |
} |
return 0 |
} |
} |
+ if { $print_pass } { |
+ pass $test_name |
+ } |
return 1; |
} |
@@ -404,8 +426,15 @@ proc gdb_breakpoint { function args } { |
# Since this is the only breakpoint that will be set, if it stops |
# at a breakpoint, we will assume it is the one we want. We can't |
# just compare to "function" because it might be a fully qualified, |
-# single quoted C++ function specifier. If there's an additional argument, |
-# pass it to gdb_breakpoint. |
+# single quoted C++ function specifier. |
+# |
+# If there are additional arguments, pass them to gdb_breakpoint. |
+# We recognize no-message/message ourselves. |
+# The default is no-message. |
+# no-message is messed up here, like gdb_breakpoint: to preserve |
+# historical usage fails are always printed by default. |
+# no-message: turns off printing of fails (and passes, but they're already off) |
+# message: turns on printing of passes (and fails, but they're already on) |
proc runto { function args } { |
global gdb_prompt |
@@ -413,7 +442,28 @@ proc runto { function args } { |
delete_breakpoints |
- if ![gdb_breakpoint $function [lindex $args 0]] { |
+ # Default to "no-message". |
+ set args "no-message $args" |
+ |
+ set print_pass 0 |
+ set print_fail 1 |
+ set no_message_loc [lsearch -exact $args no-message] |
+ set message_loc [lsearch -exact $args message] |
+ # The last one to appear in args wins. |
+ if { $no_message_loc > $message_loc } { |
+ set print_fail 0 |
+ } elseif { $message_loc > $no_message_loc } { |
+ set print_pass 1 |
+ } |
+ |
+ set test_name "running to $function in runto" |
+ |
+ # We need to use eval here to pass our varargs args to gdb_breakpoint |
+ # which is also a varargs function. |
+ # But we also have to be careful because $function may have multiple |
+ # elements, and we don't want Tcl to move the remaining elements after |
+ # the first to $args. That is why $function is wrapped in {}. |
+ if ![eval gdb_breakpoint {$function} $args] { |
return 0; |
} |
@@ -423,30 +473,46 @@ proc runto { function args } { |
# the "in func" output we get without -g. |
gdb_expect 30 { |
-re "Break.* at .*:$decimal.*$gdb_prompt $" { |
+ if { $print_pass } { |
+ pass $test_name |
+ } |
return 1 |
} |
-re "Breakpoint \[0-9\]*, \[0-9xa-f\]* in .*$gdb_prompt $" { |
+ if { $print_pass } { |
+ pass $test_name |
+ } |
return 1 |
} |
-re "The target does not support running in non-stop mode.\r\n$gdb_prompt $" { |
- unsupported "Non-stop mode not supported" |
+ if { $print_fail } { |
+ unsupported "Non-stop mode not supported" |
+ } |
return 0 |
} |
-re ".*A problem internal to GDB has been detected" { |
- fail "running to $function in runto (GDB internal error)" |
+ if { $print_fail } { |
+ fail "$test_name (GDB internal error)" |
+ } |
gdb_internal_error_resync |
return 0 |
} |
-re "$gdb_prompt $" { |
- fail "running to $function in runto" |
+ if { $print_fail } { |
+ fail $test_name |
+ } |
return 0 |
} |
eof { |
- fail "running to $function in runto (end of file)" |
+ if { $print_fail } { |
+ fail "$test_name (eof)" |
+ } |
return 0 |
} |
timeout { |
- fail "running to $function in runto (timeout)" |
+ if { $print_fail } { |
+ fail "$test_name (timeout)" |
+ } |
return 0 |
} |
} |
@@ -454,26 +520,12 @@ proc runto { function args } { |
} |
# Ask gdb to run until we hit a breakpoint at main. |
-# The case where the target uses stubs has to be handled |
-# specially--if it uses stubs, assuming we hit |
-# breakpoint() and just step out of the function. |
# |
# N.B. This function deletes all existing breakpoints. |
# If you don't want that, use gdb_start_cmd. |
proc runto_main { } { |
- global gdb_prompt |
- global decimal |
- |
- if ![target_info exists gdb_stub] { |
- return [runto main] |
- } |
- |
- delete_breakpoints |
- |
- gdb_step_for_stub; |
- |
- return 1 |
+ return [runto main no-message] |
} |
### Continue, and expect to hit a breakpoint. |
@@ -487,7 +539,7 @@ proc gdb_continue_to_breakpoint {name {location_pattern .*}} { |
send_gdb "continue\n" |
gdb_expect { |
- -re "Breakpoint .* (at|in) $location_pattern\r\n$gdb_prompt $" { |
+ -re "(?:Breakpoint|Temporary breakpoint) .* (at|in) $location_pattern\r\n$gdb_prompt $" { |
pass $full_name |
} |
-re ".*$gdb_prompt $" { |
@@ -526,6 +578,8 @@ proc gdb_continue_to_breakpoint {name {location_pattern .*}} { |
proc gdb_internal_error_resync {} { |
global gdb_prompt |
+ verbose -log "Resyncing due to internal error." |
+ |
set count 0 |
while {$count < 10} { |
gdb_expect { |
@@ -605,7 +659,7 @@ proc gdb_test_multiple { command message user_code } { |
} |
if {$use_gdb_stub |
- && [regexp -nocase {^\s*(r|run|star|start|at|att|atta|attac|attach)\M} \ |
+ && [regexp -nocase {^\s*(r|run|star|start|at|att|atta|attac|attach)\M} \ |
$command]} { |
error "gdbserver does not support $command without extended-remote" |
} |
@@ -745,21 +799,21 @@ proc gdb_test_multiple { command message user_code } { |
} |
set code { |
- -re ".*A problem internal to GDB has been detected" { |
- fail "$message (GDB internal error)" |
- gdb_internal_error_resync |
- } |
- -re "\\*\\*\\* DOSEXIT code.*" { |
- if { $message != "" } { |
- fail "$message"; |
- } |
- gdb_suppress_entire_file "GDB died"; |
- set result -1; |
- } |
+ -re ".*A problem internal to GDB has been detected" { |
+ fail "$message (GDB internal error)" |
+ gdb_internal_error_resync |
+ } |
+ -re "\\*\\*\\* DOSEXIT code.*" { |
+ if { $message != "" } { |
+ fail "$message"; |
+ } |
+ gdb_suppress_entire_file "GDB died"; |
+ set result -1; |
+ } |
} |
append code $processed_code |
append code { |
- -re "Ending remote debugging.*$gdb_prompt $" { |
+ -re "Ending remote debugging.*$gdb_prompt $" { |
if ![isnative] then { |
warning "Can`t communicate to remote target." |
} |
@@ -767,17 +821,17 @@ proc gdb_test_multiple { command message user_code } { |
gdb_start |
set result -1 |
} |
- -re "Undefined\[a-z\]* command:.*$gdb_prompt $" { |
+ -re "Undefined\[a-z\]* command:.*$gdb_prompt $" { |
perror "Undefined command \"$command\"." |
- fail "$message" |
+ fail "$message" |
set result 1 |
} |
- -re "Ambiguous command.*$gdb_prompt $" { |
+ -re "Ambiguous command.*$gdb_prompt $" { |
perror "\"$command\" is not a unique command name." |
- fail "$message" |
+ fail "$message" |
set result 1 |
} |
- -re "$inferior_exited_re with code \[0-9\]+.*$gdb_prompt $" { |
+ -re "$inferior_exited_re with code \[0-9\]+.*$gdb_prompt $" { |
if ![string match "" $message] then { |
set errmsg "$message (the program exited)" |
} else { |
@@ -786,7 +840,7 @@ proc gdb_test_multiple { command message user_code } { |
fail "$errmsg" |
set result -1 |
} |
- -re "$inferior_exited_re normally.*$gdb_prompt $" { |
+ -re "$inferior_exited_re normally.*$gdb_prompt $" { |
if ![string match "" $message] then { |
set errmsg "$message (the program exited)" |
} else { |
@@ -795,7 +849,7 @@ proc gdb_test_multiple { command message user_code } { |
fail "$errmsg" |
set result -1 |
} |
- -re "The program is not being run.*$gdb_prompt $" { |
+ -re "The program is not being run.*$gdb_prompt $" { |
if ![string match "" $message] then { |
set errmsg "$message (the program is no longer running)" |
} else { |
@@ -804,16 +858,16 @@ proc gdb_test_multiple { command message user_code } { |
fail "$errmsg" |
set result -1 |
} |
- -re "\r\n$gdb_prompt $" { |
+ -re "\r\n$gdb_prompt $" { |
if ![string match "" $message] then { |
fail "$message" |
} |
set result 1 |
} |
- "<return>" { |
+ "<return>" { |
send_gdb "\n" |
perror "Window too small." |
- fail "$message" |
+ fail "$message" |
set result -1 |
} |
-re "\\((y or n|y or \\\[n\\\]|\\\[y\\\] or n)\\) " { |
@@ -828,16 +882,16 @@ proc gdb_test_multiple { command message user_code } { |
fail "$message (got breakpoint menu)" |
set result -1 |
} |
- eof { |
- perror "Process no longer exists" |
- if { $message != "" } { |
- fail "$message" |
- } |
- return -1 |
+ eof { |
+ perror "Process no longer exists" |
+ if { $message != "" } { |
+ fail "$message" |
+ } |
+ return -1 |
} |
- full_buffer { |
+ full_buffer { |
perror "internal buffer is full." |
- fail "$message" |
+ fail "$message" |
set result -1 |
} |
timeout { |
@@ -1458,6 +1512,12 @@ proc skip_ada_tests {} { |
return 0 |
} |
+# Return a 1 if I don't even want to try to test GO. |
+ |
+proc skip_go_tests {} { |
+ return 0 |
+} |
+ |
# Return a 1 if I don't even want to try to test java. |
proc skip_java_tests {} { |
@@ -1502,6 +1562,93 @@ proc skip_shlib_tests {} { |
return 1 |
} |
+# Test files shall make sure all the test result lines in gdb.sum are |
+# unique in a test run, so that comparing the gdb.sum files of two |
+# test runs gives correct results. Test files that exercise |
+# variations of the same tests more than once, shall prefix the |
+# different test invocations with different identifying strings in |
+# order to make them unique. |
+# |
+# About test prefixes: |
+# |
+# $pf_prefix is the string that dejagnu prints after the result (FAIL, |
+# PASS, etc.), and before the test message/name in gdb.sum. E.g., the |
+# underlined substring in |
+# |
+# PASS: gdb.base/mytest.exp: some test |
+# ^^^^^^^^^^^^^^^^^^^^ |
+# |
+# is $pf_prefix. |
+# |
+# The easiest way to adjust the test prefix is to append a test |
+# variation prefix to the $pf_prefix, using the with_test_prefix |
+# procedure. E.g., |
+# |
+# proc do_tests {} { |
+# gdb_test ... ... "test foo" |
+# gdb_test ... ... "test bar" |
+# |
+# with_test_prefix "subvariation a" { |
+# gdb_test ... ... "test x" |
+# } |
+# |
+# with_test_prefix "subvariation b" { |
+# gdb_test ... ... "test x" |
+# } |
+# } |
+# |
+# with_test_prefix "variation1" { |
+# ...do setup for variation 1... |
+# do_tests |
+# } |
+# |
+# with_test_prefix "variation2" { |
+# ...do setup for variation 2... |
+# do_tests |
+# } |
+# |
+# Results in: |
+# |
+# PASS: gdb.base/mytest.exp: variation1: test foo |
+# PASS: gdb.base/mytest.exp: variation1: test bar |
+# PASS: gdb.base/mytest.exp: variation1: subvariation a: test x |
+# PASS: gdb.base/mytest.exp: variation1: subvariation b: test x |
+# PASS: gdb.base/mytest.exp: variation2: test foo |
+# PASS: gdb.base/mytest.exp: variation2: test bar |
+# PASS: gdb.base/mytest.exp: variation2: subvariation a: test x |
+# PASS: gdb.base/mytest.exp: variation2: subvariation b: test x |
+# |
+# If for some reason more flexibility is necessary, one can also |
+# manipulate the pf_prefix global directly, treating it as a string. |
+# E.g., |
+# |
+# global pf_prefix |
+# set saved_pf_prefix |
+# append pf_prefix "${foo}: bar" |
+# ... actual tests ... |
+# set pf_prefix $saved_pf_prefix |
+# |
+ |
+# Run BODY in the context of the caller, with the current test prefix |
+# (pf_prefix) appended with one space, then PREFIX, and then a colon. |
+# Returns the result of BODY. |
+# |
+proc with_test_prefix { prefix body } { |
+ global pf_prefix |
+ |
+ set saved $pf_prefix |
+ append pf_prefix " " $prefix ":" |
+ set code [catch {uplevel 1 $body} result] |
+ set pf_prefix $saved |
+ |
+ if {$code == 1} { |
+ global errorInfo errorCode |
+ return -code $code -errorinfo $errorInfo -errorcode $errorCode $result |
+ } else { |
+ return -code $code $result |
+ } |
+} |
+ |
# Return 1 if _Complex types are supported, otherwise, return 0. |
proc support_complex_tests {} { |
@@ -1752,7 +1899,7 @@ proc skip_altivec_tests {} { |
# Make sure we have a compiler that understands altivec. |
set compile_flags {debug nowarnings} |
- if [get_compiler_info not-used] { |
+ if [get_compiler_info] { |
warning "Could not get compiler info" |
return 1 |
} |
@@ -1841,7 +1988,7 @@ proc skip_vsx_tests {} { |
# Make sure we have a compiler that understands altivec. |
set compile_flags {debug nowarnings quiet} |
- if [get_compiler_info not-used] { |
+ if [get_compiler_info] { |
warning "Could not get compiler info" |
return 1 |
} |
@@ -2025,10 +2172,7 @@ set hp_aCC_compiler 0 |
# Figure out what compiler I am using. |
# |
-# BINFILE is a "compiler information" output file. This implementation |
-# does not use BINFILE. |
-# |
-# ARGS can be empty or "C++". If empty, "C" is assumed. |
+# ARG can be empty or "C++". If empty, "C" is assumed. |
# |
# There are several ways to do this, with various problems. |
# |
@@ -2077,7 +2221,7 @@ set hp_aCC_compiler 0 |
# |
# -- chastain 2004-01-06 |
-proc get_compiler_info {binfile args} { |
+proc get_compiler_info {{arg ""}} { |
# For compiler.c and compiler.cc |
global srcdir |
@@ -2095,7 +2239,7 @@ proc get_compiler_info {binfile args} { |
# Choose which file to preprocess. |
set ifile "${srcdir}/lib/compiler.c" |
- if { [llength $args] > 0 && [lindex $args 0] == "c++" } { |
+ if { $arg == "c++" } { |
set ifile "${srcdir}/lib/compiler.cc" |
} |
@@ -2106,12 +2250,12 @@ proc get_compiler_info {binfile args} { |
# We have to use -E and -o together, despite the comments |
# above, because of how DejaGnu handles remote host testing. |
set ppout "$outdir/compiler.i" |
- gdb_compile "${ifile}" "$ppout" preprocess [list "$args" quiet] |
+ gdb_compile "${ifile}" "$ppout" preprocess [list "$arg" quiet] |
set file [open $ppout r] |
set cppout [read $file] |
close $file |
} else { |
- set cppout [ gdb_compile "${ifile}" "" preprocess [list "$args" quiet] ] |
+ set cppout [ gdb_compile "${ifile}" "" preprocess [list "$arg" quiet] ] |
} |
log_file -a "$outdir/$tool.log" |
@@ -2292,14 +2436,8 @@ proc gdb_compile {source dest type options} { |
} |
set options $new_options |
- if [target_info exists gdb_stub] { |
- set options2 { "additional_flags=-Dusestubs" } |
- lappend options "libs=[target_info gdb_stub]"; |
- set options [concat $options2 $options] |
- } |
if [target_info exists is_vxworks] { |
set options2 { "additional_flags=-Dvxworks" } |
- lappend options "libs=[target_info gdb_stub]"; |
set options [concat $options2 $options] |
} |
if [info exists GDB_TESTCASE_OPTIONS] { |
@@ -2958,12 +3096,15 @@ proc gdb_continue { function } { |
proc default_gdb_init { args } { |
global gdb_wrapper_initialized |
global gdb_wrapper_target |
+ global gdb_test_file_name |
global cleanfiles |
set cleanfiles {} |
gdb_clear_suppressed; |
+ set gdb_test_file_name [file rootname [file tail [lindex $args 0]]] |
+ |
# Make sure that the wrapper is rebuilt |
# with the appropriate multilib option. |
if { $gdb_wrapper_target != [current_target_name] } { |
@@ -2997,6 +3138,84 @@ proc default_gdb_init { 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. |
+ |
+proc standard_output_file {basename} { |
+ global objdir subdir |
+ |
+ return [file join $objdir $subdir $basename] |
+} |
+ |
+# Set 'testfile', 'srcfile', and 'binfile'. |
+# |
+# ARGS is a list of source file specifications. |
+# Without any arguments, the .exp file's base name is used to |
+# compute the source file name. The ".c" extension is added in this case. |
+# If ARGS is not empty, each entry is a source file specification. |
+# If the specification starts with a ".", it is treated as a suffix |
+# to append to the .exp file's base name. |
+# If the specification is the empty string, it is treated as if it |
+# were ".c". |
+# Otherwise it is a file name. |
+# The first file in the list is used to set the 'srcfile' global. |
+# Each subsequent name is used to set 'srcfile2', 'srcfile3', etc. |
+# |
+# Most tests should call this without arguments. |
+# |
+# If a completely different binary file name is needed, then it |
+# should be handled in the .exp file with a suitable comment. |
+ |
+proc standard_testfile {args} { |
+ global gdb_test_file_name |
+ global subdir |
+ global gdb_test_file_last_vars |
+ |
+ # Outputs. |
+ global testfile binfile |
+ |
+ set testfile $gdb_test_file_name |
+ set binfile [standard_output_file ${testfile}] |
+ |
+ if {[llength $args] == 0} { |
+ set args .c |
+ } |
+ |
+ # Unset our previous output variables. |
+ # This can help catch hidden bugs. |
+ if {[info exists gdb_test_file_last_vars]} { |
+ foreach varname $gdb_test_file_last_vars { |
+ global $varname |
+ catch {unset $varname} |
+ } |
+ } |
+ # 'executable' is often set by tests. |
+ set gdb_test_file_last_vars {executable} |
+ |
+ set suffix "" |
+ foreach arg $args { |
+ set varname srcfile$suffix |
+ global $varname |
+ |
+ # Handle an extension. |
+ if {$arg == ""} { |
+ set arg $testfile.c |
+ } elseif {[string range $arg 0 0] == "."} { |
+ set arg $testfile$arg |
+ } |
+ |
+ set $varname $arg |
+ lappend gdb_test_file_last_vars $varname |
+ |
+ if {$suffix == ""} { |
+ set suffix 2 |
+ } else { |
+ incr suffix |
+ } |
+ } |
+} |
+ |
# The default timeout used when testing GDB commands. We want to use |
# the same timeout as the default dejagnu timeout, unless the user has |
# already provided a specific value (probably through a site.exp file). |
@@ -3010,14 +3229,19 @@ if ![info exists gdb_test_timeout] { |
# an error when that happens. |
set banned_variables { bug_id prms_id } |
+# A list of procedures that GDB testcases should not use. |
+# We try to prevent their use by monitoring invocations and raising |
+# an error when that happens. |
+set banned_procedures { strace } |
+ |
# gdb_init is called by runtest at start, but also by several |
# tests directly; gdb_finish is only called from within runtest after |
# each test source execution. |
# Placing several traces by repetitive calls to gdb_init leads |
# to problems, as only one trace is removed in gdb_finish. |
# To overcome this possible problem, we add a variable that records |
-# if the banned variables are traced. |
-set banned_variables_traced 0 |
+# if the banned variables and procedures are already traced. |
+set banned_traced 0 |
proc gdb_init { args } { |
# Reset the timeout value to the default. This way, any testcase |
@@ -3027,15 +3251,21 @@ proc gdb_init { args } { |
global timeout |
set timeout $gdb_test_timeout |
- # Block writes to all banned variables... |
+ # Block writes to all banned variables, and invocation of all |
+ # banned procedures... |
global banned_variables |
- global banned_variables_traced |
- if (!$banned_variables_traced) { |
+ global banned_procedures |
+ global banned_traced |
+ if (!$banned_traced) { |
foreach banned_var $banned_variables { |
global "$banned_var" |
trace add variable "$banned_var" write error |
} |
- set banned_variables_traced 1 |
+ foreach banned_proc $banned_procedures { |
+ global "$banned_proc" |
+ trace add execution "$banned_proc" enter error |
+ } |
+ set banned_traced 1 |
} |
# We set LC_ALL, LC_CTYPE, and LANG to C so that we get the same |
@@ -3084,13 +3314,18 @@ proc gdb_finish { } { |
# Unblock write access to the banned variables. Dejagnu typically |
# resets some of them between testcases. |
global banned_variables |
- global banned_variables_traced |
- if ($banned_variables_traced) { |
+ global banned_procedures |
+ global banned_traced |
+ if ($banned_traced) { |
foreach banned_var $banned_variables { |
global "$banned_var" |
trace remove variable "$banned_var" write error |
} |
- set banned_variables_traced 0 |
+ foreach banned_proc $banned_procedures { |
+ global "$banned_proc" |
+ trace remove execution "$banned_proc" enter error |
+ } |
+ set banned_traced 0 |
} |
} |
@@ -3164,95 +3399,10 @@ proc setup_kfail_for_target { PR target } { |
} |
} |
-# Test programs for embedded (often "bare board") systems sometimes use a |
-# "stub" either embedded in the test program itself or in the boot rom. |
-# The job of the stub is to implement the remote protocol to communicate |
-# with gdb and control the inferior. To initiate the remote protocol |
-# session with gdb the stub needs to be given control by the inferior. |
-# They do this by calling a function that typically triggers a trap |
-# from main that transfers control to the stub. |
-# The purpose of this function, gdb_step_for_stub, is to step out of |
-# that function ("breakpoint" in the example below) and back into main. |
-# |
-# Example: |
-# |
-# int |
-# main () |
-# { |
-# #ifdef usestubs |
-# set_debug_traps (); /* install trap handlers for stub */ |
-# breakpoint (); /* trigger a trap to give the stub control */ |
-# #endif |
-# /* test program begins here */ |
-# } |
-# |
-# Note that one consequence of this design is that a breakpoint on "main" |
-# does not Just Work (because if the target could stop there you still have |
-# to step past the calls to set_debug_traps,breakpoint). |
- |
-proc gdb_step_for_stub { } { |
- global gdb_prompt; |
- |
- if ![target_info exists gdb,use_breakpoint_for_stub] { |
- if [target_info exists gdb_stub_step_command] { |
- set command [target_info gdb_stub_step_command]; |
- } else { |
- set command "step"; |
- } |
- send_gdb "${command}\n"; |
- set tries 0; |
- gdb_expect 60 { |
- -re "(main.* at |.*in .*start).*$gdb_prompt" { |
- return; |
- } |
- -re ".*$gdb_prompt" { |
- incr tries; |
- if { $tries == 5 } { |
- fail "stepping out of breakpoint function"; |
- return; |
- } |
- send_gdb "${command}\n"; |
- exp_continue; |
- } |
- default { |
- fail "stepping out of breakpoint function"; |
- return; |
- } |
- } |
- } |
- send_gdb "where\n"; |
- gdb_expect { |
- -re "main\[^\r\n\]*at \(\[^:]+\):\(\[0-9\]+\)" { |
- set file $expect_out(1,string); |
- set linenum [expr $expect_out(2,string) + 1]; |
- set breakplace "${file}:${linenum}"; |
- } |
- default {} |
- } |
- send_gdb "break ${breakplace}\n"; |
- gdb_expect 60 { |
- -re "Breakpoint (\[0-9\]+) at.*$gdb_prompt" { |
- set breakpoint $expect_out(1,string); |
- } |
- -re "Breakpoint (\[0-9\]+): file.*$gdb_prompt" { |
- set breakpoint $expect_out(1,string); |
- } |
- default {} |
- } |
- send_gdb "continue\n"; |
- gdb_expect 60 { |
- -re "Breakpoint ${breakpoint},.*$gdb_prompt" { |
- gdb_test "delete $breakpoint" ".*" ""; |
- return; |
- } |
- default {} |
- } |
-} |
- |
# gdb_get_line_number TEXT [FILE] |
# |
# Search the source file FILE, and return the line number of the |
-# first line containing TEXT. If no match is found, return -1. |
+# first line containing TEXT. If no match is found, an error is thrown. |
# |
# TEXT is a string literal, not a regular expression. |
# |
@@ -3325,15 +3475,13 @@ proc gdb_get_line_number { text { file "" } } { |
} |
if { [ catch { set fd [open "$file"] } message ] } then { |
- perror "$message" |
- return -1 |
+ error "$message" |
} |
set found -1 |
for { set line 1 } { 1 } { incr line } { |
if { [ catch { set nchar [gets "$fd" body] } message ] } then { |
- perror "$message" |
- return -1 |
+ error "$message" |
} |
if { $nchar < 0 } then { |
break |
@@ -3345,8 +3493,11 @@ proc gdb_get_line_number { text { file "" } } { |
} |
if { [ catch { close "$fd" } message ] } then { |
- perror "$message" |
- return -1 |
+ error "$message" |
+ } |
+ |
+ if {$found == -1} { |
+ error "undefined tag \"$text\"" |
} |
return $found |
@@ -3655,29 +3806,31 @@ proc test_prefix_command_help { command_list expected_initial_lines args } { |
} |
} |
-# Build executable named EXECUTABLE, from SOURCES. If SOURCES are not |
-# provided, uses $EXECUTABLE.c. The TESTNAME paramer is the name of test |
-# to pass to untested, if something is wrong. OPTIONS are passed |
-# to gdb_compile directly. |
-proc build_executable { testname executable {sources ""} {options {debug}} } { |
- |
- global objdir |
+# Build executable named EXECUTABLE from specifications that allow |
+# different options to be passed to different sub-compilations. |
+# TESTNAME is the name of the test; this is passed to 'untested' if |
+# something fails. |
+# OPTIONS is passed to the final link, using gdb_compile. |
+# ARGS is a flat list of source specifications, of the form: |
+# { SOURCE1 OPTIONS1 [ SOURCE2 OPTIONS2 ]... } |
+# Each SOURCE is compiled to an object file using its OPTIONS, |
+# using gdb_compile. |
+# Returns 0 on success, -1 on failure. |
+proc build_executable_from_specs {testname executable options args} { |
global subdir |
global srcdir |
- if {[llength $sources]==0} { |
- set sources ${executable}.c |
- } |
- set binfile ${objdir}/${subdir}/${executable} |
+ set binfile [standard_output_file $executable] |
set objects {} |
- for {set i 0} "\$i<[llength $sources]" {incr i} { |
- set s [lindex $sources $i] |
- if { [gdb_compile "${srcdir}/${subdir}/${s}" "${binfile}${i}.o" object $options] != "" } { |
+ set i 0 |
+ foreach {s local_options} $args { |
+ if { [gdb_compile "${srcdir}/${subdir}/${s}" "${binfile}${i}.o" object $local_options] != "" } { |
untested $testname |
return -1 |
} |
lappend objects "${binfile}${i}.o" |
+ incr i |
} |
if { [gdb_compile $objects "${binfile}" executable $options] != "" } { |
@@ -3689,28 +3842,59 @@ proc build_executable { testname executable {sources ""} {options {debug}} } { |
if { [lsearch -exact $options "c++"] >= 0 } { |
set info_options "c++" |
} |
- if [get_compiler_info ${binfile} ${info_options}] { |
+ if [get_compiler_info ${info_options}] { |
return -1 |
} |
return 0 |
} |
+# Build executable named EXECUTABLE, from SOURCES. If SOURCES are not |
+# provided, uses $EXECUTABLE.c. The TESTNAME paramer is the name of test |
+# to pass to untested, if something is wrong. OPTIONS are passed |
+# to gdb_compile directly. |
+proc build_executable { testname executable {sources ""} {options {debug}} } { |
+ if {[llength $sources]==0} { |
+ set sources ${executable}.c |
+ } |
+ |
+ set arglist [list $testname $executable $options] |
+ foreach source $sources { |
+ lappend arglist $source $options |
+ } |
+ |
+ return [eval build_executable_from_specs $arglist] |
+} |
+ |
# Starts fresh GDB binary and loads EXECUTABLE into GDB. EXECUTABLE is |
-# the name of binary in ${objdir}/${subdir}. |
+# the basename of the binary. |
proc clean_restart { executable } { |
global srcdir |
- global objdir |
global subdir |
- set binfile ${objdir}/${subdir}/${executable} |
+ set binfile [standard_output_file ${executable}] |
gdb_exit |
gdb_start |
gdb_reinitialize_dir $srcdir/$subdir |
gdb_load ${binfile} |
+} |
- if [target_info exists gdb_stub] { |
- gdb_step_for_stub; |
- } |
+# Prepares for testing by calling build_executable_full, then |
+# clean_restart. |
+# TESTNAME is the name of the test. |
+# Each element in ARGS is a list of the form |
+# { EXECUTABLE OPTIONS SOURCE_SPEC... } |
+# These are passed to build_executable_from_specs, which see. |
+# The last EXECUTABLE is passed to clean_restart. |
+# Returns 0 on success, non-zero on failure. |
+proc prepare_for_testing_full {testname args} { |
+ foreach spec $args { |
+ if {[eval build_executable_from_specs [list $testname] $spec] == -1} { |
+ return -1 |
+ } |
+ set executable [lindex $spec 0] |
+ } |
+ clean_restart $executable |
+ return 0 |
} |
# Prepares for testing, by calling build_executable, and then clean_restart. |
@@ -3874,7 +4058,7 @@ proc core_find {binfile {deletefiles {}} {arg ""}} { |
# could have many core files lying around, and it may be difficult to |
# tell which one is ours, so let's run the program in a subdirectory. |
set found 0 |
- set coredir "${objdir}/${subdir}/coredir.[getpid]" |
+ set coredir [standard_output_file coredir.[getpid]] |
file mkdir $coredir |
catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile} ${arg}; true) >/dev/null 2>&1\"" |
# remote_exec host "${binfile}" |