gdb/testsuite: Add gdb_test_name variable
[deliverable/binutils-gdb.git] / gdb / testsuite / lib / gdb.exp
index 49ec8b2a55084bdfca4c1b4fc99225338c8a30ad..50db45d1b1456bbc146a51e49e77e99734ecede0 100644 (file)
@@ -695,7 +695,7 @@ proc gdb_internal_error_resync {} {
 }
 
 
-# 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
@@ -707,6 +707,8 @@ proc gdb_internal_error_resync {} {
 #   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
@@ -717,10 +719,24 @@ proc gdb_internal_error_resync {} {
 #
 # gdb_test_multiple "print foo" "test foo" {
 #    -re "expected output 1" {
-#        pass "print foo"
+#        pass "test foo"
 #    }
 #    -re "expected output 2" {
-#        fail "print foo"
+#        fail "test foo"
+#    }
+# }
+#
+# Within action elements you can also make use of the variable
+# gdb_test_name.  This variable is setup automatically by
+# gdb_test_multiple, and contains the value of MESSAGE.  You can then
+# write this, which is equivalent to the above:
+#
+# gdb_test_multiple "print foo" "test foo" {
+#    -re "expected output 1" {
+#        pass $gdb_test_name
+#    }
+#    -re "expected output 2" {
+#        fail $gdb_test_name
 #    }
 # }
 #
@@ -744,7 +760,7 @@ proc gdb_internal_error_resync {} {
 # 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
@@ -754,6 +770,10 @@ proc gdb_test_multiple { command message user_code } {
     upvar expect_out expect_out
     global any_spawn_id
 
+    if { "$prompt_regexp" == "" } {
+       set prompt_regexp "$gdb_prompt $"
+    }
+
     if { $message == "" } {
        set message $command
     }
@@ -913,7 +933,7 @@ proc gdb_test_multiple { command message user_code } {
     }
 
     append code {
-       -re "Ending remote debugging.*$gdb_prompt $" {
+       -re "Ending remote debugging.*$prompt_regexp" {
            if ![isnative] then {
                warning "Can`t communicate to remote target."
            }
@@ -921,17 +941,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:.*$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 {
@@ -940,7 +960,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.*$prompt_regexp" {
            if ![string match "" $message] then {
                set errmsg "$message (the program exited)"
            } else {
@@ -949,7 +969,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.*$prompt_regexp" {
            if ![string match "" $message] then {
                set errmsg "$message (the program is no longer running)"
            } else {
@@ -958,7 +978,7 @@ proc gdb_test_multiple { command message user_code } {
            fail "$errmsg"
            set result -1
        }
-       -re "\r\n$gdb_prompt $" {
+       -re "\r\n$prompt_regexp" {
            if ![string match "" $message] then {
                fail "$message"
            }
@@ -972,13 +992,13 @@ proc gdb_test_multiple { command message user_code } {
        }
        -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
        }
@@ -1032,8 +1052,28 @@ proc gdb_test_multiple { command message user_code } {
        }
     }
 
+    # Create gdb_test_name in the parent scope.  If this variable
+    # already exists, which it might if we have nested calls to
+    # gdb_test_multiple, then preserve the old value, otherwise,
+    # create a new variable in the parent scope.
+    upvar gdb_test_name gdb_test_name
+    if { [info exists gdb_test_name] } {
+       set gdb_test_name_old "$gdb_test_name"
+    }
+    set gdb_test_name "$message"
+
     set result 0
     set code [catch {gdb_expect $code} string]
+
+    # Clean up the gdb_test_name variable.  If we had a
+    # previous value then restore it, otherwise, delete the variable
+    # from the parent scope.
+    if { [info exists gdb_test_name_old] } {
+       set gdb_test_name "$gdb_test_name_old"
+    } else {
+       unset gdb_test_name
+    }
+
     if {$code == 1} {
        global errorInfo errorCode
        return -code error -errorinfo $errorInfo -errorcode $errorCode $string
@@ -1077,24 +1117,66 @@ proc gdb_test { args } {
     set command [lindex $args 0]
     set pattern [lindex $args 1]
 
-    if [llength $args]==5 {
-       set question_string [lindex $args 3]
-       set response_string [lindex $args 4]
-    } else {
-       set question_string "^FOOBAR$"
-    }
-
-    return [gdb_test_multiple $command $message {
+    set user_code {}
+    lappend user_code {
        -re "\[\r\n\]*(?:$pattern)\[\r\n\]+$gdb_prompt $" {
            if ![string match "" $message] then {
                pass "$message"
             }
         }
-       -re "(${question_string})$" {
-           send_gdb "$response_string\n"
-           exp_continue
+    }
+
+    if { [llength $args] == 5 } {
+       set question_string [lindex $args 3]
+       set response_string [lindex $args 4]
+       lappend user_code {
+           -re "(${question_string})$" {
+               send_gdb "$response_string\n"
+               exp_continue
+           }
        }
-     }]
+     }
+
+    set user_code [join $user_code]
+    return [gdb_test_multiple $command $message $user_code]
+}
+
+# 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
@@ -1869,7 +1951,7 @@ proc skip_python_tests_prompt { prompt_regexp } {
            return 1
        }
        -re "$prompt_regexp" {}
-    }
+    } "$prompt_regexp"
 
     gdb_test_multiple "python print (sys.version_info\[0\])" "check if python 3" {
        -re "3.*$prompt_regexp" {
@@ -1878,7 +1960,7 @@ proc skip_python_tests_prompt { prompt_regexp } {
        -re ".*$prompt_regexp" {
             set gdb_py_is_py3k 0
         }
-    }
+    } "$prompt_regexp"
 
     return 0
 }
@@ -2320,6 +2402,18 @@ proc with_timeout_factor { factor body } {
     }
 }
 
+# Run BODY with timeout factor FACTOR if check-read1 is used.
+
+proc with_read1_timeout_factor { factor body } {
+    if { [info exists ::env(READ1)] == 1 && $::env(READ1) == 1 } {
+       # Use timeout factor
+    } else {
+       # Reset timeout factor
+       set factor 1
+    }
+    return [uplevel [list with_timeout_factor $factor $body]]
+}
+
 # Return 1 if _Complex types are supported, otherwise, return 0.
 
 gdb_caching_proc support_complex_tests {
@@ -3102,22 +3196,28 @@ proc skip_unwinder_tests {} {
     return $ok
 }
 
-# Return 0 if we should skip tests that require the libstdc++ stap
+# Return 1 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.
 
-    set ok 0
+proc skip_libstdcxx_probe_tests_prompt { prompt_regexp } {
+    set supported 0
     gdb_test_multiple "info probe" "check for stap probe in libstdc++" {
-       -re ".*libstdcxx.*catch.*\r\n$gdb_prompt $" {
-           set ok 1
+       -re ".*libstdcxx.*catch.*\r\n$prompt_regexp" {
+           set supported 1
        }
-       -re "\r\n$gdb_prompt $" {
+       -re "\r\n$prompt_regexp" {
        }
-    }
-    return $ok
+    } "$prompt_regexp"
+    set skip [expr !$supported]
+    return $skip
+}
+
+# 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.
@@ -3156,7 +3256,7 @@ proc gdb_is_target_1 { target_name target_stack_regexp prompt_regexp } {
        -re "$prompt_regexp" {
            pass $test
        }
-    }
+    } "$prompt_regexp"
     return 0
 }
 
@@ -3760,6 +3860,16 @@ proc gdb_compile {source dest type options} {
     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.
@@ -4653,6 +4763,10 @@ proc standard_output_file {basename} {
 
     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 [regsub {^/([a-z])/} $dir {\1:/}]
+    }
     return [file join $dir $basename]
 }
 
@@ -5160,6 +5274,58 @@ proc exec_has_index_section { executable } {
     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.
@@ -6540,5 +6706,32 @@ proc gdb_write_cmd_file { cmdline } {
     catch "close $cmd_file"
 }
 
+# Compare contents of FILE to string STR.  Pass with MSG if equal, otherwise
+# fail with MSG.
+
+proc cmp_file_string { file str msg } {
+    if { ![file exists $file]} {
+       fail "$msg"
+       return
+    }
+
+    set caught_error [catch {
+       set fp [open "$file" r]
+       set file_contents [read $fp]
+       close $fp
+    } error_message]
+    if { $caught_error } then {
+       error "$error_message"
+       fail "$msg"
+       return
+    }
+
+    if { $file_contents == $str } {
+       pass "$msg"
+    } else {
+       fail "$msg"
+    }
+}
+
 # Always load compatibility stuff.
 load_lib future.exp
This page took 0.030363 seconds and 4 git commands to generate.