[gdb/testsuite] Fail in gdb_compile if pie results in non-PIE executable
[external/binutils.git] / gdb / testsuite / lib / gdb.exp
index 41f0ef5..529b6f6 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
@@ -744,7 +746,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 +756,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 +919,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 +927,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 +946,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 +955,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 +964,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 +978,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
        }
@@ -1097,6 +1103,44 @@ proc gdb_test { args } {
      }]
 }
 
+# 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.
 #
@@ -1869,7 +1913,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 +1922,7 @@ proc skip_python_tests_prompt { prompt_regexp } {
        -re ".*$prompt_regexp" {
             set gdb_py_is_py3k 0
         }
-    }
+    } "$prompt_regexp"
 
     return 0
 }
@@ -2031,7 +2075,9 @@ proc foreach_with_prefix {var list body} {
        if {$code == 1} {
            global errorInfo errorCode
            return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
-       } else {
+       } elseif {$code == 3} {
+           break
+       } elseif {$code == 2} {
            return -code $code $result
        }
     }
@@ -3102,22 +3148,27 @@ proc skip_unwinder_tests {} {
 
 # 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.
 
@@ -3154,7 +3205,7 @@ proc gdb_is_target_1 { target_name target_stack_regexp prompt_regexp } {
        -re "$prompt_regexp" {
            pass $test
        }
-    }
+    } "$prompt_regexp"
     return 0
 }
 
@@ -3758,6 +3809,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.
@@ -5158,6 +5219,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.