gdb: Restore selected frame in print_frame_local_vars
[external/binutils.git] / gdb / testsuite / lib / gdb.exp
index 4e5c89b..ee66a38 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 1992-2016 Free Software Foundation, Inc.
+# Copyright 1992-2018 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@ if {$tool == ""} {
 load_lib libgloss.exp
 load_lib cache.exp
 load_lib gdb-utils.exp
+load_lib memory.exp
 
 global GDB
 
@@ -117,6 +118,10 @@ set octal "\[0-7\]+"
 
 set inferior_exited_re "(\\\[Inferior \[0-9\]+ \\(.*\\) exited)"
 
+# A regular expression that matches a value history number.
+# E.g., $1, $2, etc.
+set valnum_re "\\\$$decimal"
+
 ### Only procedures should come after this point.
 
 #
@@ -221,6 +226,19 @@ proc delete_breakpoints {} {
     }
 }
 
+# Returns true iff the target supports using the "run" command.
+
+proc target_can_use_run_cmd {} {
+    if [target_info exists use_gdb_stub] {
+       # In this case, when we connect, the inferior is already
+       # running.
+       return 0
+    }
+
+    # Assume yes.
+    return 1
+}
+
 # Generic run command.
 #
 # The second pattern below matches up to the first newline *only*.
@@ -365,9 +383,46 @@ proc gdb_start_cmd {args} {
     return -1
 }
 
+# Generic starti command.  Return 0 if we could start the program, -1
+# if we could not.
+#
+# N.B. This function does not wait for gdb to return to the prompt,
+# that is the caller's responsibility.
+
+proc gdb_starti_cmd {args} {
+    global gdb_prompt use_gdb_stub
+
+    foreach command [gdb_init_commands] {
+       send_gdb "$command\n"
+       gdb_expect 30 {
+           -re "$gdb_prompt $" { }
+           default {
+               perror "gdb_init_command for target failed"
+               return -1
+           }
+       }
+    }
+
+    if $use_gdb_stub {
+       return -1
+    }
+
+    send_gdb "starti $args\n"
+    gdb_expect 60 {
+       -re "The program .* has been started already.*y or n. $" {
+           send_gdb "y\n"
+           exp_continue
+       }
+       -re "Starting program: \[^\r\n\]*" {
+           return 0
+       }
+    }
+    return -1
+}
+
 # Set a breakpoint at FUNCTION.  If there is an additional argument it is
 # a list of options; the supported options are allow-pending, temporary,
-# message, no-message, and passfail.
+# message, no-message, passfail and qualified.
 # The result is 1 for success, 0 for failure.
 #
 # Note: The handling of message vs no-message is messed up, but it's based
@@ -392,6 +447,10 @@ proc gdb_breakpoint { function args } {
        set break_message "Temporary breakpoint"
     }
 
+    if {[lsearch -exact $args qualified] != -1} {
+       append break_command " -qualified"
+    }
+
     set print_pass 0
     set print_fail 1
     set no_message_loc [lsearch -exact $args no-message]
@@ -519,7 +578,7 @@ proc runto { function args } {
        }
        -re "The target does not support running in non-stop mode.\r\n$gdb_prompt $" {
            if { $print_fail } {
-               unsupported "Non-stop mode not supported"
+               unsupported "non-stop mode not supported"
            }
            return 0
        }
@@ -995,7 +1054,7 @@ proc gdb_test { args } {
     }
 
     return [gdb_test_multiple $command $message {
-       -re "\[\r\n\]*($pattern)\[\r\n\]+$gdb_prompt $" {
+       -re "\[\r\n\]*(?:$pattern)\[\r\n\]+$gdb_prompt $" {
            if ![string match "" $message] then {
                pass "$message"
             }
@@ -1038,7 +1097,8 @@ proc gdb_test_no_output { args } {
 # This is useful when the sequence is long and contains ".*", a single
 # regexp to match the entire output can get a timeout much easier.
 #
-# COMMAND is the command to send.
+# COMMAND is the command to execute, send to GDB with send_gdb.  If
+#   this is the null string no command is sent.
 # TEST_NAME is passed to pass/fail.  COMMAND is used if TEST_NAME is "".
 # EXPECTED_OUTPUT_LIST is a list of regexps of expected output, which are
 # processed in order, and all must be present in the output.
@@ -1061,7 +1121,9 @@ proc gdb_test_sequence { command test_name expected_output_list } {
        set test_name $command
     }
     lappend expected_output_list ""; # implicit ".*" before gdb prompt
-    send_gdb "$command\n"
+    if { $command != "" } {
+       send_gdb "$command\n"
+    }
     return [gdb_expect_list $test_name "$gdb_prompt $" $expected_output_list]
 }
 
@@ -1359,7 +1421,7 @@ proc default_gdb_exit {} {
     global GDB
     global INTERNAL_GDBFLAGS GDBFLAGS
     global verbose
-    global gdb_spawn_id
+    global gdb_spawn_id inferior_spawn_id
     global inotify_log_file
 
     gdb_stop_suppressing_tests
@@ -1400,6 +1462,7 @@ proc default_gdb_exit {} {
        remote_close host
     }
     unset gdb_spawn_id
+    unset inferior_spawn_id
 }
 
 # Load a file into the debugger.
@@ -1721,18 +1784,17 @@ proc skip_go_tests {} {
     return 0
 }
 
-# Return a 1 if I don't even want to try to test java.
-
-proc skip_java_tests {} {
-    return 0
-}
-
 # Return a 1 if I don't even want to try to test D.
 
 proc skip_d_tests {} {
     return 0
 }
 
+# Return 1 to skip Rust tests, 0 to try them.
+proc skip_rust_tests {} {
+    return [expr {![isnative]}]
+}
+
 # Return a 1 for configurations that do not support Python scripting.
 # PROMPT_REGEXP is the expected prompt.
 
@@ -1918,6 +1980,14 @@ proc foreach_with_prefix {var list body} {
     }
 }
 
+# Like TCL's native proc, but defines a procedure that wraps its body
+# within 'with_test_prefix "$proc_name" { ... }'.
+proc proc_with_prefix {name arguments body} {
+    # Define the advertised proc.
+    proc $name $arguments [list with_test_prefix $name $body]
+}
+
+
 # Run BODY in the context of the caller.  After BODY is run, the variables
 # listed in VARS will be reset to the values they had before BODY was run.
 #
@@ -1984,6 +2054,30 @@ proc save_vars { vars body } {
     }
 }
 
+# Run tests in BODY with the current working directory (CWD) set to
+# DIR.  When BODY is finished, restore the original CWD.  Return the
+# result of BODY.
+#
+# This procedure doesn't check if DIR is a valid directory, so you
+# have to make sure of that.
+
+proc with_cwd { dir body } {
+    set saved_dir [pwd]
+    verbose -log "Switching to directory $dir (saved CWD: $saved_dir)."
+    cd $dir
+
+    set code [catch {uplevel 1 $body} result]
+
+    verbose -log "Switching back to $saved_dir."
+    cd $saved_dir
+
+    if {$code == 1} {
+       global errorInfo errorCode
+       return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+    } else {
+       return -code $code $result
+    }
+}
 
 # Run tests in BODY with GDB prompt and variable $gdb_prompt set to
 # PROMPT.  When BODY is finished, restore GDB prompt and variable
@@ -2069,6 +2163,56 @@ proc with_target_charset { target_charset body } {
     }
 }
 
+# Switch the default spawn id to SPAWN_ID, so that gdb_test,
+# mi_gdb_test etc. default to using it.
+
+proc switch_gdb_spawn_id {spawn_id} {
+    global gdb_spawn_id
+    global board board_info
+
+    set gdb_spawn_id $spawn_id
+    set board [host_info name]
+    set board_info($board,fileid) $spawn_id
+}
+
+# Clear the default spawn id.
+
+proc clear_gdb_spawn_id {} {
+    global gdb_spawn_id
+    global board board_info
+
+    unset -nocomplain gdb_spawn_id
+    set board [host_info name]
+    unset -nocomplain board_info($board,fileid)
+}
+
+# Run BODY with SPAWN_ID as current spawn id.
+
+proc with_spawn_id { spawn_id body } {
+    global gdb_spawn_id
+
+    if [info exists gdb_spawn_id] {
+       set saved_spawn_id $gdb_spawn_id
+    }
+
+    switch_gdb_spawn_id $spawn_id
+
+    set code [catch {uplevel 1 $body} result]
+
+    if [info exists saved_spawn_id] {
+       switch_gdb_spawn_id $saved_spawn_id
+    } else {
+       clear_gdb_spawn_id
+    }
+
+    if {$code == 1} {
+       global errorInfo errorCode
+       return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+    } else {
+       return -code $code $result
+    }
+}
+
 # Select the largest timeout from all the timeouts:
 # - the local "timeout" variable of the scope two levels above,
 # - the global "timeout" variable,
@@ -2120,6 +2264,13 @@ proc with_timeout_factor { factor body } {
 # Return 1 if _Complex types are supported, otherwise, return 0.
 
 gdb_caching_proc support_complex_tests {
+
+    if { [gdb_skip_float_test] } {
+       # If floating point is not supported, _Complex is not
+       # supported.
+       return 0
+    }
+
     # Set up, compile, and execute a test program containing _Complex types.
     # Include the current process ID in the file names to prevent conflicts
     # with invocations for multiple testsuites.
@@ -2828,7 +2979,7 @@ gdb_caching_proc skip_btrace_pt_tests {
     file delete $src
     # In case of an unexpected output, we return 2 as a fail value.
     set skip_btrace_tests 2
-    gdb_test_multiple "record btrace pt" "check btrace support" {
+    gdb_test_multiple "record btrace pt" "check btrace pt support" {
         -re "You can't do that when your target is.*\r\n$gdb_prompt $" {
             set skip_btrace_tests 1
         }
@@ -2838,7 +2989,7 @@ gdb_caching_proc skip_btrace_pt_tests {
         -re "Could not enable branch tracing.*\r\n$gdb_prompt $" {
             set skip_btrace_tests 1
         }
-        -re "GDB does not support.*\r\n$gdb_prompt $" {
+        -re "support was disabled at compile time.*\r\n$gdb_prompt $" {
             set skip_btrace_tests 1
         }
         -re "^record btrace pt\r\n$gdb_prompt $" {
@@ -2852,6 +3003,36 @@ gdb_caching_proc skip_btrace_pt_tests {
     return $skip_btrace_tests
 }
 
+# A helper that compiles a test case to see if __int128 is supported.
+proc gdb_int128_helper {lang} {
+    set src [standard_temp_file i128[pid].c]
+    set obj [standard_temp_file i128[pid].o]
+
+    verbose -log "checking $lang for __int128"
+    gdb_produce_source $src {
+       __int128 x;
+       int main() { return 0; }
+    }
+
+    set lines [gdb_compile $src $obj object [list nowarnings quiet $lang]]
+    file delete $src
+    file delete $obj
+
+    set result [expr {!![string match "" $lines]}]
+    verbose -log "__int128 for $lang result = $result"
+    return $result
+}
+
+# Return true if the C compiler understands the __int128 type.
+gdb_caching_proc has_int128_c {
+    return [gdb_int128_helper c]
+}
+
+# Return true if the C++ compiler understands the __int128 type.
+gdb_caching_proc has_int128_cxx {
+    return [gdb_int128_helper c++]
+}
+
 # Return whether we should skip tests for showing inlined functions in
 # backtraces.  Requires get_compiler_info and get_debug_format.
 
@@ -2897,7 +3078,8 @@ proc skip_hw_breakpoint_tests {} {
         || [istarget "x86_64-*-*"]
         || [istarget "ia64-*-*"] 
         || [istarget "arm*-*-*"]
-        || [istarget "aarch64*-*-*"]} {
+        || [istarget "aarch64*-*-*"]
+        || [istarget "s390*-*-*"] } {
        return 0
     }
 
@@ -3026,14 +3208,16 @@ proc skip_compile_feature_tests {} {
     return $result
 }
 
-# Helper for gdb_is_target_remote.  PROMPT_REGEXP is the expected
-# prompt.
-
-proc gdb_is_target_remote_prompt { prompt_regexp } {
+# Helper for gdb_is_target_* procs.  TARGET_NAME is the name of the target
+# we're looking for (used to build the test name).  TARGET_STACK_REGEXP
+# is a regexp that will match the output of "maint print target-stack" if
+# the target in question is currently pushed.  PROMPT_REGEXP is a regexp
+# matching the expected prompt after the command output.
 
-    set test "probe for target remote"
+proc gdb_is_target_1 { target_name target_stack_regexp prompt_regexp } {
+    set test "probe for target ${target_name}"
     gdb_test_multiple "maint print target-stack" $test {
-       -re ".*emote serial target in gdb-specific protocol.*$prompt_regexp" {
+       -re "${target_stack_regexp}${prompt_regexp}" {
            pass $test
            return 1
        }
@@ -3044,15 +3228,49 @@ proc gdb_is_target_remote_prompt { prompt_regexp } {
     return 0
 }
 
+# Helper for gdb_is_target_remote where the expected prompt is variable.
+
+proc gdb_is_target_remote_prompt { prompt_regexp } {
+    return [gdb_is_target_1 "remote" ".*emote serial target in gdb-specific protocol.*" $prompt_regexp]
+}
+
 # Check whether we're testing with the remote or extended-remote
 # targets.
 
-proc gdb_is_target_remote {} {
+proc gdb_is_target_remote { } {
     global gdb_prompt
 
     return [gdb_is_target_remote_prompt "$gdb_prompt $"]
 }
 
+# Check whether we're testing with the native target.
+
+proc gdb_is_target_native { } {
+    global gdb_prompt
+
+    return [gdb_is_target_1 "native" ".*native \\(Native process\\).*" "$gdb_prompt $"]
+}
+
+# Return the effective value of use_gdb_stub.
+#
+# If the use_gdb_stub global has been set (it is set when the gdb process is
+# spawned), return that.  Otherwise, return the value of the use_gdb_stub
+# property from the board file.
+#
+# This is the preferred way of checking use_gdb_stub, since it allows to check
+# the value before the gdb has been spawned and it will return the correct value
+# even when it was overriden by the test.
+
+proc use_gdb_stub {} {
+  global use_gdb_stub
+
+  if [info exists use_gdb_stub] {
+     return $use_gdb_stub
+  }
+
+  return [target_info exists use_gdb_stub]
+}
+
 # Return 1 if the current remote target is an instance of our GDBserver, 0
 # otherwise.  Return -1 if there was an error and we can't tell.
 
@@ -3060,7 +3278,7 @@ gdb_caching_proc target_is_gdbserver {
     global gdb_prompt
 
     set is_gdbserver -1
-    set test "Probing for GDBserver"
+    set test "probing for GDBserver"
 
     gdb_test_multiple "monitor help" $test {
        -re "The following monitor commands are supported.*Quit GDBserver.*$gdb_prompt $" {
@@ -3212,12 +3430,8 @@ proc get_compiler_info {{arg ""}} {
     }
 
     # Set the legacy symbols.
-    set gcc_compiled     0
-    if { [regexp "^gcc-1-" "$compiler_info" ] } { set gcc_compiled 1 }
-    if { [regexp "^gcc-2-" "$compiler_info" ] } { set gcc_compiled 2 }
-    if { [regexp "^gcc-3-" "$compiler_info" ] } { set gcc_compiled 3 }
-    if { [regexp "^gcc-4-" "$compiler_info" ] } { set gcc_compiled 4 }
-    if { [regexp "^gcc-5-" "$compiler_info" ] } { set gcc_compiled 5 }
+    set gcc_compiled 0
+    regexp "^gcc-(\[0-9\]+)-" "$compiler_info" matchall gcc_compiled
 
     # Log what happened.
     verbose -log "get_compiler_info: $compiler_info"
@@ -3281,6 +3495,34 @@ proc gdb_wrapper_init { args } {
     set gdb_wrapper_target [current_target_name]
 }
 
+# Determine options that we always want to pass to the compiler.
+gdb_caching_proc universal_compile_options {
+    set me "universal_compile_options"
+    set options {}
+
+    set src [standard_temp_file ccopts[pid].c]
+    set obj [standard_temp_file ccopts[pid].o]
+
+    gdb_produce_source $src {
+       int foo(void) { return 0; }
+    }
+
+    # Try an option for disabling colored diagnostics.  Some compilers
+    # yield colored diagnostics by default (when run from a tty) unless
+    # such an option is specified.
+    set opt "additional_flags=-fdiagnostics-color=never"
+    set lines [target_compile $src $obj object [list "quiet" $opt]]
+    if [string match "" $lines] then {
+       # Seems to have worked; use the option.
+       lappend options $opt
+    }
+    file delete $src
+    file delete $obj
+
+    verbose "$me:  returning $options" 2
+    return $options
+}
+
 # Some targets need to always link a special object in.  Save its path here.
 global gdb_saved_set_unbuffered_mode_obj
 set gdb_saved_set_unbuffered_mode_obj ""
@@ -3332,11 +3574,17 @@ proc gdb_compile {source dest type options} {
 
     # Add platform-specific options if a shared library was specified using
     # "shlib=librarypath" in OPTIONS.
-    set new_options ""
+    set new_options {}
+    if {[lsearch -exact $options rust] != -1} {
+       # -fdiagnostics-color is not a rustcc option.
+    } else {
+       set new_options [universal_compile_options]
+    }
     set shlib_found 0
     set shlib_load 0
     foreach opt $options {
-        if [regexp {^shlib=(.*)} $opt dummy_var shlib_name] {
+        if {[regexp {^shlib=(.*)} $opt dummy_var shlib_name]
+           && $type == "executable"} {
             if [test_compiler_info "xlc-*"] {
                # IBM xlc compiler doesn't accept shared library named other
                # than .so: use "-Wl," to bypass this
@@ -3362,19 +3610,17 @@ proc gdb_compile {source dest type options} {
                    lappend new_options "early_flags=-Wl,--no-as-needed"
                }
             }
-       } elseif { $opt == "shlib_load" } {
+       } elseif { $opt == "shlib_load" && $type == "executable" } {
            set shlib_load 1
         } else {
             lappend new_options $opt
         }
     }
 
-    # We typically link to shared libraries using an absolute path, and
-    # that's how they are found at runtime.  If we are going to
-    # dynamically load one by basename, we must specify rpath.  If we
-    # are using a remote host, DejaGNU will link to the shared library
-    # using a relative path, so again we must specify an rpath.
-    if { $shlib_load || ($shlib_found && [is_remote target]) } {
+    # Because we link with libraries using their basename, we may need
+    # (depending on the platform) to set a special rpath value, to allow
+    # the executable to find the libraries it depends on.
+    if { $shlib_load || $shlib_found } {
        if { ([istarget "*-*-mingw*"]
              || [istarget *-*-cygwin*]
              || [istarget *-*-pe*]) } {
@@ -3518,7 +3764,7 @@ proc gdb_compile_pthreads {source dest type options} {
         }
     }
     if {!$built_binfile} {
-       unsupported "Couldn't compile [file tail $source]: ${why_msg}"
+       unsupported "couldn't compile [file tail $source]: ${why_msg}"
         return -1
     }
 }
@@ -3555,6 +3801,9 @@ proc gdb_compile_shlib {sources dest options} {
                 lappend obj_options "additional_flags=-fpic"
             }
         }
+        "icc-*" {
+                lappend obj_options "additional_flags=-fpic"
+        }
         default {
            # don't know what the compiler is...
         }
@@ -3585,14 +3834,16 @@ proc gdb_compile_shlib {sources dest options} {
                set name ${dest}
            }
            lappend link_options "additional_flags=-Wl,--out-implib,${name}.a"
-       } elseif [is_remote target] {
-           # By default, we do not set the soname.  This causes the linker
-           # on ELF systems to create a DT_NEEDED entry in the executable
-           # refering to the full path name of the library.  This is a
-           # problem in remote testing if the library is in a different
-           # directory there.  To fix this, we set a soname of just the
-           # base filename for the library, and add an appropriate -rpath
-           # to the main executable (in gdb_compile).
+       } else {
+           # Set the soname of the library.  This causes the linker on ELF
+           # systems to create the DT_NEEDED entry in the executable referring
+           # to the soname of the library, and not its absolute path.  This
+           # (using the absolute path) would be problem when testing on a
+           # remote target.
+           #
+           # In conjunction with setting the soname, we add the special
+           # rpath=$ORIGIN value when building the executable, so that it's
+           # able to find the library in its own directory.
            set destbase [file tail $dest]
            lappend link_options "additional_flags=-Wl,-soname,$destbase"
        }
@@ -3642,7 +3893,7 @@ proc gdb_compile_shlib_pthreads {sources dest options} {
         }
     }
     if {!$built_binfile} {
-        unsupported "Couldn't compile $sources: ${why_msg}"
+        unsupported "couldn't compile $sources: ${why_msg}"
         return -1
     }
 }
@@ -3682,7 +3933,7 @@ proc gdb_compile_objc {source dest type options} {
         }
     }
     if {!$built_binfile} {
-        unsupported "Couldn't compile [file tail $source]: ${why_msg}"
+        unsupported "couldn't compile [file tail $source]: ${why_msg}"
         return -1
     }
 }
@@ -4211,8 +4462,13 @@ proc gdb_remote_download {dest fromfile {tofile {}}} {
 
        return $destname
     } else {
-       # When the DEST is local, we copy the file to the test directory
-       # (where the executable is), except if that's already where it is.
+       # When the DEST is local, we copy the file to the test directory (where
+       # the executable is).
+       #
+       # Note that we pass TOFILE through standard_output_file, regardless of
+       # whether it is absolute or relative, because we don't want the tests
+       # to be able to write outside their standard output directory.
+
        set tofile [standard_output_file $tofile]
 
        file copy -force $fromfile $tofile
@@ -4221,22 +4477,24 @@ proc gdb_remote_download {dest fromfile {tofile {}}} {
     }
 }
 
-# gdb_load_shlibs LIB...
+# gdb_load_shlib LIB...
 #
-# Copy the listed libraries to the target.
+# Copy the listed library to the target.
 
-proc gdb_load_shlibs { args } {
-    if {![is_remote target]} {
-       return
-    }
+proc gdb_load_shlib { file } {
+    set dest [gdb_remote_download target [shlib_target_file $file]]
 
-    foreach file $args {
-       gdb_remote_download target [shlib_target_file $file]
+    if {[is_remote target]} {
+       # If the target is remote, we need to tell gdb where to find the
+       # libraries.
+       #
+       # We could set this even when not testing remotely, but a user
+       # generally won't set it unless necessary.  In order to make the tests
+       # more like the real-life scenarios, we don't set it for local testing.
+       gdb_test "set solib-search-path [file dirname $file]" "" ""
     }
 
-    # Even if the target supplies full paths for shared libraries,
-    # they may not be paths for this system.
-    gdb_test "set solib-search-path [file dirname [lindex $args 0]]" "" ""
+    return $dest
 }
 
 #
@@ -4814,14 +5072,102 @@ proc rerun_to_main {} {
   }
 }
 
-# Print a message and return true if a test should be skipped
-# due to lack of floating point suport.
+# 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.
 
-proc gdb_skip_float_test { msg } {
+gdb_caching_proc gdb_skip_float_test {
     if [target_info exists gdb,skip_float_tests] {
-       verbose "Skipping test '$msg': no float tests."
        return 1
     }
+
+    # There is an ARM kernel ptrace bug that hardware VFP registers
+    # are not updated after GDB ptrace set VFP registers.  The bug
+    # was introduced by kernel commit 8130b9d7b9d858aa04ce67805e8951e3cb6e9b2f
+    # in 2012 and is fixed in e2dfb4b880146bfd4b6aa8e138c0205407cebbaf
+    # in May 2016.  In other words, kernels older than 4.6.3, 4.4.14,
+    # 4.1.27, 3.18.36, and 3.14.73 have this bug.
+    # This kernel bug is detected by check how does GDB change the
+    # program result by changing one VFP register.
+    if { [istarget "arm*-*-linux*"] } {
+
+       set compile_flags {debug nowarnings }
+
+       # Set up, compile, and execute a test program having VFP
+       # operations.
+       set src [standard_temp_file arm_vfp[pid].c]
+       set exe [standard_temp_file arm_vfp[pid].x]
+
+       gdb_produce_source $src {
+           int main() {
+               double d = 4.0;
+               int ret;
+
+               asm ("vldr d0, [%0]" : : "r" (&d));
+               asm ("vldr d1, [%0]" : : "r" (&d));
+               asm (".global break_here\n"
+                    "break_here:");
+               asm ("vcmp.f64 d0, d1\n"
+                    "vmrs APSR_nzcv, fpscr\n"
+                    "bne L_value_different\n"
+                    "movs %0, #0\n"
+                    "b L_end\n"
+                    "L_value_different:\n"
+                    "movs %0, #1\n"
+                    "L_end:\n" : "=r" (ret) :);
+
+               /* Return $d0 != $d1.  */
+               return ret;
+           }
+       }
+
+       verbose "compiling testfile $src" 2
+       set lines [gdb_compile $src $exe executable $compile_flags]
+       file delete $src
+
+       if ![string match "" $lines] then {
+           verbose "testfile compilation failed, returning 1" 2
+           return 0
+       }
+
+       # No error message, compilation succeeded so now run it via gdb.
+       # Run the test up to 5 times to detect whether ptrace can
+       # correctly update VFP registers or not.
+       set skip_vfp_test 0
+       for {set i 0} {$i < 5} {incr i} {
+           global gdb_prompt srcdir subdir
+
+           gdb_exit
+           gdb_start
+           gdb_reinitialize_dir $srcdir/$subdir
+           gdb_load "$exe"
+
+           runto_main
+           gdb_test "break *break_here"
+           gdb_continue_to_breakpoint "break_here"
+
+           # Modify $d0 to a different value, so the exit code should
+           # be 1.
+           gdb_test "set \$d0 = 5.0"
+
+           set test "continue to exit"
+           gdb_test_multiple "continue" "$test" {
+               -re "exited with code 01.*$gdb_prompt $" {
+               }
+               -re "exited normally.*$gdb_prompt $" {
+                   # However, the exit code is 0.  That means something
+                   # wrong in setting VFP registers.
+                   set skip_vfp_test 1
+                   break
+               }
+           }
+       }
+
+       gdb_exit
+       remote_file build delete $exe
+
+       return $skip_vfp_test
+    }
     return 0
 }
 
@@ -4845,9 +5191,14 @@ proc gdb_skip_bogus_test { msg } {
 # NOTE: This must be called while gdb is *not* running.
 
 gdb_caching_proc gdb_skip_xml_test {
+    global gdb_spawn_id
     global gdb_prompt
     global srcdir
 
+    if { [info exists gdb_spawn_id] } {
+        error "GDB must not be running in gdb_skip_xml_tests."
+    }
+
     set xml_file [gdb_remote_download host "${srcdir}/gdb.xml/trivial.xml"]
 
     gdb_start
@@ -5228,6 +5579,16 @@ proc build_executable_from_specs {testname executable options args} {
            }
        }
        set ret [$func $sources_path "${binfile}" $options]
+    } elseif {[lsearch -exact $options rust] != -1} {
+       set sources_path {}
+       foreach {s local_options} $args {
+           if { [regexp "^/" "$s"] } then {
+               lappend sources_path "$s"
+           } else {
+               lappend sources_path "$srcdir/$subdir/$s"
+           }
+       }
+       set ret [gdb_compile_rust $sources_path "${binfile}" $options]
     } else {
        set objects {}
        set i 0
@@ -5323,13 +5684,21 @@ proc prepare_for_testing { testname executable {sources ""} {options {debug}}} {
     return 0
 }
 
-proc get_valueof { fmt exp default } {
+# Retrieve the value of EXP in the inferior, represented in format
+# specified in FMT (using "printFMT").  DEFAULT is used as fallback if
+# print fails.  TEST is the test message to use.  It can be omitted,
+# in which case a test message is built from EXP.
+
+proc get_valueof { fmt exp default {test ""} } {
     global gdb_prompt
 
-    set test "get valueof \"${exp}\""
+    if {$test == "" } {
+       set test "get valueof \"${exp}\""
+    }
+
     set val ${default}
     gdb_test_multiple "print${fmt} ${exp}" "$test" {
-       -re "\\$\[0-9\]* = (.*)\[\r\n\]*$gdb_prompt $" {
+       -re "\\$\[0-9\]* = (\[^\r\n\]*)\[\r\n\]*$gdb_prompt $" {
            set val $expect_out(1,string)
            pass "$test ($val)"
        }
@@ -5340,15 +5709,23 @@ proc get_valueof { fmt exp default } {
     return ${val}
 }
 
-proc get_integer_valueof { exp default } {
+# Retrieve the value of EXP in the inferior, as a signed decimal value
+# (using "print /d").  DEFAULT is used as fallback if print fails.
+# TEST is the test message to use.  It can be omitted, in which case
+# a test message is built from EXP.
+
+proc get_integer_valueof { exp default {test ""} } {
     global gdb_prompt
 
-    set test "get integer valueof \"${exp}\""
+    if {$test == ""} {
+       set test "get integer valueof \"${exp}\""
+    }
+
     set val ${default}
     gdb_test_multiple "print /d ${exp}" "$test" {
        -re "\\$\[0-9\]* = (\[-\]*\[0-9\]*).*$gdb_prompt $" {
            set val $expect_out(1,string)
-           pass "$test ($val)"
+           pass "$test"
        }
        timeout {
            fail "$test (timeout)"
@@ -5357,25 +5734,34 @@ proc get_integer_valueof { exp default } {
     return ${val}
 }
 
-proc get_hexadecimal_valueof { exp default } {
+# Retrieve the value of EXP in the inferior, as an hexadecimal value
+# (using "print /x").  DEFAULT is used as fallback if print fails.
+# TEST is the test message to use.  It can be omitted, in which case
+# a test message is built from EXP.
+
+proc get_hexadecimal_valueof { exp default {test ""} } {
     global gdb_prompt
-    send_gdb "print /x ${exp}\n"
-    set test "get hexadecimal valueof \"${exp}\""
-    gdb_expect {
+
+    if {$test == ""} {
+       set test "get hexadecimal valueof \"${exp}\""
+    }
+
+    set val ${default}
+    gdb_test_multiple "print /x ${exp}" $test {
        -re "\\$\[0-9\]* = (0x\[0-9a-zA-Z\]+).*$gdb_prompt $" {
            set val $expect_out(1,string)
            pass "$test"
        }
-       timeout {
-           set val ${default}
-           fail "$test (timeout)"
-       }
     }
     return ${val}
 }
 
-proc get_sizeof { type default } {
-    return [get_integer_valueof "sizeof (${type})" $default]
+# Retrieve the size of TYPE in the inferior, as a decimal value.  DEFAULT
+# is used as fallback if print fails.  TEST is the test message to use.
+# It can be omitted, in which case a test message is 'sizeof (TYPE)'.
+
+proc get_sizeof { type default {test ""} } {
+    return [get_integer_valueof "sizeof (${type})" $default $test]
 }
 
 proc get_target_charset { } {
@@ -5395,6 +5781,46 @@ proc get_target_charset { } {
     return "UTF-8"
 }
 
+# Get the address of VAR.
+
+proc get_var_address { var } {
+    global gdb_prompt hex
+
+    # Match output like:
+    # $1 = (int *) 0x0
+    # $5 = (int (*)()) 0
+    # $6 = (int (*)()) 0x24 <function_bar>
+
+    gdb_test_multiple "print &${var}" "get address of ${var}" {
+       -re "\\\$\[0-9\]+ = \\(.*\\) (0|$hex)( <${var}>)?\[\r\n\]+${gdb_prompt} $"
+       {
+           pass "get address of ${var}"
+           if { $expect_out(1,string) == "0" } {
+               return "0x0"
+           } else {
+               return $expect_out(1,string)
+           }
+       }
+    }
+    return ""
+}
+
+# Return the frame number for the currently selected frame
+proc get_current_frame_number {{test_name ""}} {
+    global gdb_prompt
+
+    if { $test_name == "" } {
+       set test_name "get current frame number"
+    }
+    set frame_num -1
+    gdb_test_multiple "frame" $test_name {
+       -re "#(\[0-9\]+) .*$gdb_prompt $" {
+           set frame_num $expect_out(1,string)
+       }
+    }
+    return $frame_num
+}
+
 # Get the current value for remotetimeout and return it.
 proc get_remotetimeout { } {
     global gdb_prompt
@@ -5422,6 +5848,19 @@ proc set_remotetimeout { timeout } {
     }
 }
 
+# Get the target's current endianness and return it.
+proc get_endianness { } {
+    global gdb_prompt
+
+    gdb_test_multiple "show endian" "determine endianness" {
+       -re ".* (little|big) endian.*\r\n$gdb_prompt $" {
+           # Pass silently.
+           return $expect_out(1,string)
+       }
+    }
+    return "little"
+}
+
 # ROOT and FULL are file names.  Returns the relative path from ROOT
 # to FULL.  Note that FULL must be in a subdirectory of ROOT.
 # For example, given ROOT = /usr/bin and FULL = /usr/bin/ls, this
@@ -5786,5 +6225,59 @@ proc multi_line { args } {
     return [join $args "\r\n"]
 }
 
+# Similar to the above, but while multi_line is meant to be used to
+# match GDB output, this one is meant to be used to build strings to
+# send as GDB input.
+
+proc multi_line_input { args } {
+    return [join $args "\n"]
+}
+
+# Return the version of the DejaGnu framework.
+#
+# The return value is a list containing the major, minor and patch version
+# numbers.  If the version does not contain a minor or patch number, they will
+# be set to 0.  For example:
+#
+#   1.6   -> {1 6 0}
+#   1.6.1 -> {1 6 1}
+#   2     -> {2 0 0}
+
+proc dejagnu_version { } {
+    # The frame_version variable is defined by DejaGnu, in runtest.exp.
+    global frame_version
+
+    verbose -log "DejaGnu version: $frame_version"
+    verbose -log "Expect version: [exp_version]"
+    verbose -log "Tcl version: [info tclversion]"
+
+    set dg_ver [split $frame_version .]
+
+    while { [llength $dg_ver] < 3 } {
+       lappend dg_ver 0
+    }
+
+    return $dg_ver
+}
+
+# Define user-defined command COMMAND using the COMMAND_LIST as the
+# command's definition.  The terminating "end" is added automatically.
+
+proc gdb_define_cmd {command command_list} {
+    global gdb_prompt
+
+    set input [multi_line_input {*}$command_list "end"]
+    set test "define $command"
+
+    gdb_test_multiple "define $command" $test {
+       -re "End with"  {
+           gdb_test_multiple $input $test {
+               -re "\r\n$gdb_prompt " {
+               }
+           }
+       }
+    }
+}
+
 # Always load compatibility stuff.
 load_lib future.exp