btrace: reword error messages
[deliverable/binutils-gdb.git] / gdb / testsuite / lib / gdb.exp
index 7287ed3257add3f0a411035758bb25ccb4e32de2..e90c4614032ecaf20af2cfeb770f3e0ec84bf5f6 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 1992-2005, 2007-2012 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
@@ -26,17 +26,28 @@ if {$tool == ""} {
 }
 
 load_lib libgloss.exp
+load_lib cache.exp
+load_lib gdb-utils.exp
+load_lib memory.exp
 
 global GDB
 
+# The spawn ID used for I/O interaction with the inferior.  For native
+# targets, or remote targets that can do I/O through GDB
+# (semi-hosting) this will be the same as the host/GDB's spawn ID.
+# Otherwise, the board may set this to some other spawn ID.  E.g.,
+# when debugging with GDBserver, this is set to GDBserver's spawn ID,
+# so input/output is done on gdbserver's tty.
+global inferior_spawn_id
+
 if [info exists TOOL_EXECUTABLE] {
-    set GDB $TOOL_EXECUTABLE;
+    set GDB $TOOL_EXECUTABLE
 }
 if ![info exists GDB] {
     if ![is_remote host] {
        set GDB [findfile $base_dir/../../gdb/gdb "$base_dir/../../gdb/gdb" [transform gdb]]
     } else {
-       set GDB [transform gdb];
+       set GDB [transform gdb]
     }
 }
 verbose "using GDB = $GDB" 2
@@ -52,19 +63,27 @@ 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.
-# Set it if it is not already set.
+# Set it if it is not already set.  This is also set by default_gdb_init
+# but it's not clear what removing one of them will break.
+# See with_gdb_prompt for more details on prompt handling.
 global gdb_prompt
 if ![info exists gdb_prompt] then {
-    set gdb_prompt "\[(\]gdb\[)\]"
+    set gdb_prompt "\\(gdb\\)"
 }
 
+# A regexp that matches the pagination prompt.
+set pagination_prompt [string_to_regexp "---Type <return> to continue, or q <return> to quit---"]
+
 # The variable fullname_syntax_POSIX is a regexp which matches a POSIX 
 # absolute path ie. /foo/ 
 set fullname_syntax_POSIX {/[^\n]*/}
@@ -99,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.
 
 #
@@ -108,8 +131,14 @@ proc default_gdb_version {} {
     global GDB
     global INTERNAL_GDBFLAGS GDBFLAGS
     global gdb_prompt
+    global inotify_pid
+
+    if {[info exists inotify_pid]} {
+       eval exec kill $inotify_pid
+    }
+
     set output [remote_exec host "$GDB $INTERNAL_GDBFLAGS --version"]
-    set tmp [lindex $output 1];
+    set tmp [lindex $output 1]
     set version ""
     regexp " \[0-9\]\[^ \t\n\r\]+" "$tmp" version
     if ![is_remote host] {
@@ -120,11 +149,12 @@ proc default_gdb_version {} {
 }
 
 proc gdb_version { } {
-    return [default_gdb_version];
+    return [default_gdb_version]
 }
 
 #
 # gdb_unload -- unload a file if one is loaded
+# Return 0 on success, -1 on error.
 #
 
 proc gdb_unload {} {
@@ -145,10 +175,11 @@ proc gdb_unload {} {
        }
        -re "$gdb_prompt $" {}
        timeout {
-           perror "couldn't unload file in $GDB (timeout)."
+           perror "couldn't unload file in $GDB (timeout)."
            return -1
        }
     }
+    return 0
 }
 
 # Many of the tests depend on setting breakpoints at various places and
@@ -163,26 +194,49 @@ proc delete_breakpoints {} {
     # we need a larger timeout value here or this thing just confuses
     # itself.  May need a better implementation if possible. - guo
     #
-    send_gdb "delete breakpoints\n"
-    gdb_expect 100 {
-        -re "Delete all breakpoints.*y or n.*$" {
-           send_gdb "y\n";
+    set timeout 100
+
+    set msg "delete all breakpoints in delete_breakpoints"
+    set deleted 0
+    gdb_test_multiple "delete breakpoints" "$msg" {
+       -re "Delete all breakpoints.*y or n.*$" {
+           send_gdb "y\n"
            exp_continue
        }
-        -re "$gdb_prompt $" { # This happens if there were no breakpoints
-           }
-        timeout { perror "Delete all breakpoints in delete_breakpoints (timeout)" ; return }
+       -re "$gdb_prompt $" {
+           set deleted 1
+       }
     }
-    send_gdb "info breakpoints\n"
-    gdb_expect 100 {
-        -re "No breakpoints or watchpoints..*$gdb_prompt $" {}
-        -re "$gdb_prompt $" { perror "breakpoints not deleted" ; return }
-        -re "Delete all breakpoints.*or n.*$" {
-           send_gdb "y\n";
-           exp_continue
+
+    if {$deleted} {
+       # Confirm with "info breakpoints".
+       set deleted 0
+       set msg "info breakpoints"
+       gdb_test_multiple $msg $msg {
+           -re "No breakpoints or watchpoints..*$gdb_prompt $" {
+               set deleted 1
+           }
+           -re "$gdb_prompt $" {
+           }
        }
-        timeout { perror "info breakpoints (timeout)" ; return }
     }
+
+    if {!$deleted} {
+       perror "breakpoints not deleted"
+    }
+}
+
+# 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.
@@ -197,13 +251,13 @@ proc delete_breakpoints {} {
 proc gdb_run_cmd {args} {
     global gdb_prompt use_gdb_stub
 
-    if [target_info exists gdb_init_command] {
-       send_gdb "[target_info gdb_init_command]\n";
+    foreach command [gdb_init_commands] {
+       send_gdb "$command\n"
        gdb_expect 30 {
            -re "$gdb_prompt $" { }
            default {
-               perror "gdb_init_command for target failed";
-               return;
+               perror "gdb_init_command for target failed"
+               return
            }
        }
     }
@@ -211,57 +265,57 @@ proc gdb_run_cmd {args} {
     if $use_gdb_stub {
        if [target_info exists gdb,do_reload_on_run] {
            if { [gdb_reload] != 0 } {
-               return;
+               return
            }
-           send_gdb "continue\n";
+           send_gdb "continue\n"
            gdb_expect 60 {
                -re "Continu\[^\r\n\]*\[\r\n\]" {}
                default {}
            }
-           return;
+           return
        }
 
        if [target_info exists gdb,start_symbol] {
-           set start [target_info gdb,start_symbol];
+           set start [target_info gdb,start_symbol]
        } else {
-           set start "start";
+           set start "start"
        }
        send_gdb  "jump *$start\n"
-       set start_attempt 1;
+       set start_attempt 1
        while { $start_attempt } {
            # Cap (re)start attempts at three to ensure that this loop
            # always eventually fails.  Don't worry about trying to be
            # clever and not send a command when it has failed.
            if [expr $start_attempt > 3] {
-               perror "Jump to start() failed (retry count exceeded)";
-               return;
+               perror "Jump to start() failed (retry count exceeded)"
+               return
            }
-           set start_attempt [expr $start_attempt + 1];
+           set start_attempt [expr $start_attempt + 1]
            gdb_expect 30 {
                -re "Continuing at \[^\r\n\]*\[\r\n\]" {
-                   set start_attempt 0;
+                   set start_attempt 0
                }
                -re "No symbol \"_start\" in current.*$gdb_prompt $" {
-                   perror "Can't find start symbol to run in gdb_run";
-                   return;
+                   perror "Can't find start symbol to run in gdb_run"
+                   return
                }
                -re "No symbol \"start\" in current.*$gdb_prompt $" {
-                   send_gdb "jump *_start\n";
+                   send_gdb "jump *_start\n"
                }
                -re "No symbol.*context.*$gdb_prompt $" {
-                   set start_attempt 0;
+                   set start_attempt 0
                }
                -re "Line.* Jump anyway.*y or n. $" {
                    send_gdb "y\n"
                }
                -re "The program is not being run.*$gdb_prompt $" {
                    if { [gdb_reload] != 0 } {
-                       return;
+                       return
                    }
-                   send_gdb "jump *$start\n";
+                   send_gdb "jump *$start\n"
                }
                timeout {
-                   perror "Jump to start() failed (timeout)"
+                   perror "Jump to start() failed (timeout)"
                    return
                }
            }
@@ -271,7 +325,7 @@ proc gdb_run_cmd {args} {
 
     if [target_info exists gdb,do_reload_on_run] {
        if { [gdb_reload] != 0 } {
-           return;
+           return
        }
     }
     send_gdb "run $args\n"
@@ -299,13 +353,13 @@ proc gdb_run_cmd {args} {
 proc gdb_start_cmd {args} {
     global gdb_prompt use_gdb_stub
 
-    if [target_info exists gdb_init_command] {
-       send_gdb "[target_info gdb_init_command]\n";
+    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;
+               perror "gdb_init_command for target failed"
+               return -1
            }
        }
     }
@@ -329,31 +383,87 @@ 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,
-# and no-message.
+# 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
+# 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
+    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]
+    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 {
@@ -362,8 +472,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
                }
@@ -373,32 +483,50 @@ 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
        }
     }
-    return 1;
+    if { $print_pass } {
+       pass $test_name
+    }
+    return 1
 }    
 
 # Set breakpoint at function and run gdb until it breaks there.
 # 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
@@ -406,8 +534,29 @@ proc runto { function args } {
 
     delete_breakpoints
 
-    if ![gdb_breakpoint $function [lindex $args 0]] {
-       return 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
     }
 
     gdb_run_cmd
@@ -416,33 +565,52 @@ 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
        }
     }
+    if { $print_pass } {
+       pass $test_name
+    }
     return 1
 }
 
@@ -452,7 +620,7 @@ proc runto { function args } {
 # If you don't want that, use gdb_start_cmd.
 
 proc runto_main { } {
-    return [runto main]
+    return [runto main no-message]
 }
 
 ### Continue, and expect to hit a breakpoint.
@@ -464,17 +632,10 @@ proc gdb_continue_to_breakpoint {name {location_pattern .*}} {
     global gdb_prompt
     set full_name "continue to breakpoint: $name"
 
-    send_gdb "continue\n"
-    gdb_expect {
-       -re "Breakpoint .* (at|in) $location_pattern\r\n$gdb_prompt $" {
+    gdb_test_multiple "continue" $full_name {
+       -re "(?:Breakpoint|Temporary breakpoint) .* (at|in) $location_pattern\r\n$gdb_prompt $" {
            pass $full_name
        }
-       -re ".*$gdb_prompt $" {
-           fail $full_name
-       }
-       timeout { 
-           fail "$full_name (timeout)"
-       }
     }
 }
 
@@ -505,6 +666,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 {
@@ -560,16 +723,35 @@ proc gdb_internal_error_resync {} {
 #    }
 # }
 #
+# Like with "expect", you can also specify the spawn id to match with
+# -i "$id".  Interesting spawn ids are $inferior_spawn_id and
+# $gdb_spawn_id.  The former matches inferior I/O, while the latter
+# matches GDB I/O.  E.g.:
+#
+# send_inferior "hello\n"
+# gdb_test_multiple "continue" "test echo" {
+#    -i "$inferior_spawn_id" -re "^hello\r\nhello\r\n$" {
+#        pass "got echo"
+#    }
+#    -i "$gdb_spawn_id" -re "Breakpoint.*$gdb_prompt $" {
+#        fail "hit breakpoint"
+#    }
+# }
+#
 # The standard patterns, such as "Inferior exited..." and "A problem
-# ...", all being implicitly appended to that list.
+# ...", all being implicitly appended to that list.  These are always
+# 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 } {
     global verbose use_gdb_stub
-    global gdb_prompt
+    global gdb_prompt pagination_prompt
     global GDB
+    global gdb_spawn_id
     global inferior_exited_re
     upvar timeout timeout
     upvar expect_out expect_out
+    global any_spawn_id
 
     if { $message == "" } {
        set message $command
@@ -584,7 +766,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"
     }
@@ -627,14 +809,14 @@ proc gdb_test_multiple { command message user_code } {
            lappend processed_code $item
            continue
        }
-       if { $item == "-timeout" } {
+       if { $item == "-timeout" || $item == "-i" } {
            set expecting_arg 1
            lappend processed_code $item
            continue
        }
        if { $expecting_arg } {
            set expecting_arg 0
-           lappend processed_code $item
+           lappend processed_code $subst_item
            continue
        }
        if { $expecting_action } {
@@ -663,22 +845,22 @@ proc gdb_test_multiple { command message user_code } {
     }
 
     set result -1
-    set string "${command}\n";
+    set string "${command}\n"
     if { $command != "" } {
        set multi_line_re "\[\r\n\] *>"
        while { "$string" != "" } {
-           set foo [string first "\n" "$string"];
-           set len [string length "$string"];
+           set foo [string first "\n" "$string"]
+           set len [string length "$string"]
            if { $foo < [expr $len - 1] } {
-               set str [string range "$string" 0 $foo];
+               set str [string range "$string" 0 $foo]
                if { [send_gdb "$str"] != "" } {
-                   global suppress_flag;
+                   global suppress_flag
 
                    if { ! $suppress_flag } {
-                       perror "Couldn't send $command to GDB.";
+                       perror "Couldn't send $command to GDB."
                    }
-                   fail "$message";
-                   return $result;
+                   fail "$message"
+                   return $result
                }
                # since we're checking if each line of the multi-line
                # command are 'accepted' by GDB here,
@@ -689,56 +871,45 @@ proc gdb_test_multiple { command message user_code } {
                    -notransfer -re "$multi_line_re$" { verbose "partial: match" 3 }
                    timeout { verbose "partial: timeout" 3 }
                }
-               set string [string range "$string" [expr $foo + 1] end];
+               set string [string range "$string" [expr $foo + 1] end]
                set multi_line_re "$multi_line_re.*\[\r\n\] *>"
            } else {
-               break;
+               break
            }
        }
        if { "$string" != "" } {
            if { [send_gdb "$string"] != "" } {
-               global suppress_flag;
+               global suppress_flag
 
                if { ! $suppress_flag } {
-                   perror "Couldn't send $command to GDB.";
+                   perror "Couldn't send $command to GDB."
                }
-               fail "$message";
-               return $result;
+               fail "$message"
+               return $result
            }
        }
     }
 
-    if [target_info exists gdb,timeout] {
-       set tmt [target_info gdb,timeout];
-    } else {
-       if [info exists timeout] {
-           set tmt $timeout;
-       } else {
-           global timeout;
-           if [info exists timeout] {
-               set tmt $timeout;
-           } else {
-               set tmt 60;
+    set code {
+       -re ".*A problem internal to GDB has been detected" {
+           fail "$message (GDB internal error)"
+           gdb_internal_error_resync
+           set result -1
+       }
+       -re "\\*\\*\\* DOSEXIT code.*" {
+           if { $message != "" } {
+               fail "$message"
            }
+           gdb_suppress_entire_file "GDB died"
+           set result -1
        }
     }
-
-    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;
-        }
-    }
     append code $processed_code
     append code {
-        -re "Ending remote debugging.*$gdb_prompt $" {
+       # Reset the spawn id, in case the processed code used -i.
+       -i "$gdb_spawn_id"
+
+       -re "Ending remote debugging.*$gdb_prompt $" {
            if ![isnative] then {
                warning "Can`t communicate to remote target."
            }
@@ -746,17 +917,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 {
@@ -765,7 +936,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 {
@@ -774,7 +945,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 {
@@ -783,16 +954,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>" {
+       -re "$pagination_prompt" {
            send_gdb "\n"
            perror "Window too small."
-            fail "$message"
+           fail "$message"
            set result -1
        }
        -re "\\((y or n|y or \\\[n\\\]|\\\[y\\\] or n)\\) " {
@@ -807,16 +978,19 @@ 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
+
+       # Patterns below apply to any spawn id specified.
+       -i $any_spawn_id
+       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 {
@@ -828,9 +1002,9 @@ proc gdb_test_multiple { command message user_code } {
     }
 
     set result 0
-    set code [catch {gdb_expect $tmt $code} string]
+    set code [catch {gdb_expect $code} string]
     if {$code == 1} {
-       global errorInfo errorCode;
+       global errorInfo errorCode
        return -code error -errorinfo $errorInfo -errorcode $errorCode $string
     } elseif {$code > 1} {
        return -code $code $string
@@ -844,7 +1018,9 @@ proc gdb_test_multiple { command message user_code } {
 # COMMAND is the command to execute, send to GDB with send_gdb.  If
 #   this is the null string no command is sent.
 # PATTERN is the pattern to match for a PASS, and must NOT include
-#   the \r\n sequence immediately before the gdb prompt.
+#   the \r\n sequence immediately before the gdb prompt.  This argument
+#   may be omitted to just match the prompt, ignoring whatever output 
+#   precedes it.
 # MESSAGE is an optional message to be printed.  If this is
 #   omitted, then the pass/fail messages use the command string as the
 #   message.  (If this is the empty string, then sometimes we don't
@@ -859,9 +1035,7 @@ proc gdb_test_multiple { command message user_code } {
 #   -1 if there was an internal error.
 #  
 proc gdb_test { args } {
-    global verbose
     global gdb_prompt
-    global GDB
     upvar timeout timeout
 
     if [llength $args]>2 then {
@@ -873,21 +1047,21 @@ proc gdb_test { args } {
     set pattern [lindex $args 1]
 
     if [llength $args]==5 {
-       set question_string [lindex $args 3];
-       set response_string [lindex $args 4];
+       set question_string [lindex $args 3]
+       set response_string [lindex $args 4]
     } else {
        set question_string "^FOOBAR$"
     }
 
     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"
             }
         }
        -re "(${question_string})$" {
-           send_gdb "$response_string\n";
-           exp_continue;
+           send_gdb "$response_string\n"
+           exp_continue
        }
      }]
 }
@@ -923,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.
@@ -946,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]
 }
 
@@ -1025,14 +1202,6 @@ proc test_print_reject { args } {
     }
 }
 \f
-# Given an input string, adds backslashes as needed to create a
-# regexp that will match the string.
-
-proc string_to_regexp {str} {
-    set result $str
-    regsub -all {[]*+.|()^$\[\\]} $str {\\&} result
-    return $result
-}
 
 # Same as gdb_test, but the second parameter is not a regexp,
 # but a string that must match exactly.
@@ -1123,12 +1292,100 @@ proc gdb_test_list_exact { cmd name elm_find_regexp elm_extract_regexp result_ma
        }
     }
 }
+
+# gdb_test_stdio COMMAND INFERIOR_PATTERN GDB_PATTERN MESSAGE
+# Send a command to gdb; expect inferior and gdb output.
+#
+# See gdb_test_multiple for a description of the COMMAND and MESSAGE
+# parameters.
+#
+# INFERIOR_PATTERN is the pattern to match against inferior output.
+#
+# GDB_PATTERN is the pattern to match against gdb output, and must NOT
+# include the \r\n sequence immediately before the gdb prompt, nor the
+# prompt.  The default is empty.
+#
+# Both inferior and gdb patterns must match for a PASS.
+#
+# If MESSAGE is ommitted, then COMMAND will be used as the message.
+#
+# Returns:
+#    1 if the test failed,
+#    0 if the test passes,
+#   -1 if there was an internal error.
+#
+
+proc gdb_test_stdio {command inferior_pattern {gdb_pattern ""} {message ""}} {
+    global inferior_spawn_id gdb_spawn_id
+    global gdb_prompt
+
+    if {$message == ""} {
+       set message $command
+    }
+
+    set inferior_matched 0
+    set gdb_matched 0
+
+    # Use an indirect spawn id list, and remove the inferior spawn id
+    # from the expected output as soon as it matches, in case
+    # $inferior_pattern happens to be a prefix of the resulting full
+    # gdb pattern below (e.g., "\r\n").
+    global gdb_test_stdio_spawn_id_list
+    set gdb_test_stdio_spawn_id_list "$inferior_spawn_id"
+
+    # Note that if $inferior_spawn_id and $gdb_spawn_id are different,
+    # then we may see gdb's output arriving before the inferior's
+    # output.
+    set res [gdb_test_multiple $command $message {
+       -i gdb_test_stdio_spawn_id_list -re "$inferior_pattern" {
+           set inferior_matched 1
+           if {!$gdb_matched} {
+               set gdb_test_stdio_spawn_id_list ""
+               exp_continue
+           }
+       }
+       -i $gdb_spawn_id -re "$gdb_pattern\r\n$gdb_prompt $" {
+           set gdb_matched 1
+           if {!$inferior_matched} {
+               exp_continue
+           }
+       }
+    }]
+    if {$res == 0} {
+       pass $message
+    } else {
+       verbose -log "inferior_matched=$inferior_matched, gdb_matched=$gdb_matched"
+    }
+    return $res
+}
+
 \f
+
+# Issue a PASS and return true if evaluating CONDITION in the caller's
+# frame returns true, and issue a FAIL and return false otherwise.
+# MESSAGE is the pass/fail message to be printed.  If MESSAGE is
+# omitted or is empty, then the pass/fail messages use the condition
+# string as the message.
+
+proc gdb_assert { condition {message ""} } {
+    if { $message == ""} {
+       set message $condition
+    }
+
+    set res [uplevel 1 expr $condition]
+    if {!$res} {
+       fail $message
+    } else {
+       pass $message
+    }
+    return $res
+}
+
 proc gdb_reinitialize_dir { subdir } {
     global gdb_prompt
 
     if [is_remote host] {
-       return "";
+       return ""
     }
     send_gdb "dir\n"
     gdb_expect 60 {
@@ -1164,22 +1421,37 @@ 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;
+    gdb_stop_suppressing_tests
 
     if ![info exists gdb_spawn_id] {
-       return;
+       return
     }
 
     verbose "Quitting $GDB $INTERNAL_GDBFLAGS $GDBFLAGS"
 
+    if {[info exists inotify_log_file] && [file exists $inotify_log_file]} {
+       set fd [open $inotify_log_file]
+       set data [read -nonewline $fd]
+       close $fd
+
+       if {[string compare $data ""] != 0} {
+           warning "parallel-unsafe file creations noticed"
+
+           # Clear the log.
+           set fd [open $inotify_log_file w]
+           close $fd
+       }
+    }
+
     if { [is_remote host] && [board_info host exists fileid] } {
-       send_gdb "quit\n";
+       send_gdb "quit\n"
        gdb_expect 10 {
            -re "y or n" {
-               send_gdb "y\n";
-               exp_continue;
+               send_gdb "y\n"
+               exp_continue
            }
            -re "DOSEXIT code" { }
            default { }
@@ -1187,9 +1459,10 @@ proc default_gdb_exit {} {
     }
 
     if ![is_remote host] {
-       remote_close host;
+       remote_close host
     }
     unset gdb_spawn_id
+    unset inferior_spawn_id
 }
 
 # Load a file into the debugger.
@@ -1200,6 +1473,8 @@ proc default_gdb_exit {} {
 #
 #   debug    file was loaded successfully and has debug information
 #   nodebug  file was loaded successfully and has no debug information
+#   lzma     file was loaded, .gnu_debugdata found, but no LZMA support
+#            compiled in
 #   fail     file was not loaded
 #
 # I tried returning this information as part of the return value,
@@ -1215,6 +1490,7 @@ proc gdb_file_cmd { arg } {
     global GDB
     global last_loaded_file
 
+    # Save this for the benefit of gdbserver-support.exp.
     set last_loaded_file $arg
 
     # Set whether debug info was found.
@@ -1246,13 +1522,18 @@ proc gdb_file_cmd { arg } {
 
     send_gdb "file $arg\n"
     gdb_expect 120 {
+       -re "Reading symbols from.*LZMA support was disabled.*done.*$gdb_prompt $" {
+           verbose "\t\tLoaded $arg into $GDB; .gnu_debugdata found but no LZMA available"
+           set gdb_file_cmd_debug_info "lzma"
+           return 0
+       }
        -re "Reading symbols from.*no debugging symbols found.*done.*$gdb_prompt $" {
-           verbose "\t\tLoaded $arg into the $GDB with no debugging symbols"
+           verbose "\t\tLoaded $arg into $GDB with no debugging symbols"
            set gdb_file_cmd_debug_info "nodebug"
            return 0
        }
         -re "Reading symbols from.*done.*$gdb_prompt $" {
-            verbose "\t\tLoaded $arg into the $GDB"
+            verbose "\t\tLoaded $arg into $GDB"
            set gdb_file_cmd_debug_info "debug"
            return 0
         }
@@ -1265,49 +1546,51 @@ proc gdb_file_cmd { arg } {
                    return 0
                 }
                 timeout {
-                    perror "(timeout) Couldn't load $arg, other program already loaded."
+                    perror "Couldn't load $arg, other program already loaded (timeout)."
                    return -1
                 }
+               eof {
+                   perror "Couldn't load $arg, other program already loaded (eof)."
+                   return -1
+               }
             }
        }
         -re "No such file or directory.*$gdb_prompt $" {
             perror "($arg) No such file or directory"
            return -1
         }
+       -re "A problem internal to GDB has been detected" {
+           fail "($arg) (GDB internal error)"
+           gdb_internal_error_resync
+           return -1
+       }
         -re "$gdb_prompt $" {
-            perror "couldn't load $arg into $GDB."
+            perror "Couldn't load $arg into $GDB."
            return -1
             }
         timeout {
-            perror "couldn't load $arg into $GDB (timed out)."
+            perror "Couldn't load $arg into $GDB (timeout)."
            return -1
         }
         eof {
             # This is an attempt to detect a core dump, but seems not to
             # work.  Perhaps we need to match .* followed by eof, in which
             # gdb_expect does not seem to have a way to do that.
-            perror "couldn't load $arg into $GDB (end of file)."
+            perror "Couldn't load $arg into $GDB (eof)."
            return -1
         }
     }
 }
 
-#
-# start gdb -- start gdb running, default procedure
-#
-# When running over NFS, particularly if running many simultaneous
-# tests on different hosts all using the same server, things can
-# get really slow.  Give gdb at least 3 minutes to start up.
-#
-proc default_gdb_start { } {
-    global verbose use_gdb_stub
+# Default gdb_spawn procedure.
+
+proc default_gdb_spawn { } {
+    global use_gdb_stub
     global GDB
     global INTERNAL_GDBFLAGS GDBFLAGS
-    global gdb_prompt
-    global timeout
-    global gdb_spawn_id;
+    global gdb_spawn_id
 
-    gdb_stop_suppressing_tests;
+    gdb_stop_suppressing_tests
 
     # Set the default value, it may be overriden later by specific testfile.
     #
@@ -1321,7 +1604,7 @@ proc default_gdb_start { } {
     verbose "Spawning $GDB $INTERNAL_GDBFLAGS $GDBFLAGS"
 
     if [info exists gdb_spawn_id] {
-       return 0;
+       return 0
     }
 
     if ![is_remote host] {
@@ -1330,26 +1613,66 @@ proc default_gdb_start { } {
            exit 1
        }
     }
-    set res [remote_spawn host "$GDB $INTERNAL_GDBFLAGS $GDBFLAGS [host_info gdb_opts]"];
+    set res [remote_spawn host "$GDB $INTERNAL_GDBFLAGS $GDBFLAGS [host_info gdb_opts]"]
     if { $res < 0 || $res == "" } {
        perror "Spawning $GDB failed."
-       return 1;
+       return 1
     }
-    gdb_expect 360 {
-       -re "\[\r\n\]$gdb_prompt $" {
-           verbose "GDB initialized."
-       }
-       -re "$gdb_prompt $"     {
-           perror "GDB never initialized."
-           return -1
-       }
-       timeout {
-           perror "(timeout) GDB never initialized after 10 seconds."
-           remote_close host;
-           return -1
+
+    set gdb_spawn_id $res
+    return 0
+}
+
+# Default gdb_start procedure.
+
+proc default_gdb_start { } {
+    global gdb_prompt pagination_prompt
+    global gdb_spawn_id
+    global inferior_spawn_id
+
+    if [info exists gdb_spawn_id] {
+       return 0
+    }
+
+    set res [gdb_spawn]
+    if { $res != 0} {
+       return $res
+    }
+
+    # Default to assuming inferior I/O is done on GDB's terminal.
+    if {![info exists inferior_spawn_id]} {
+       set inferior_spawn_id $gdb_spawn_id
+    }
+
+    # When running over NFS, particularly if running many simultaneous
+    # tests on different hosts all using the same server, things can
+    # get really slow.  Give gdb at least 3 minutes to start up.
+    set loop_again 1
+    while { $loop_again } {
+       set loop_again 0
+       gdb_expect 360 {
+           -re "$pagination_prompt" {
+               verbose "Hit pagination during startup. Pressing enter to continue."
+               send_gdb "\n"
+               set loop_again 1
+           }
+           -re "\[\r\n\]$gdb_prompt $" {
+               verbose "GDB initialized."
+           }
+           -re "$gdb_prompt $" {
+               perror "GDB never initialized."
+               unset gdb_spawn_id
+               return -1
+           }
+           timeout     {
+               perror "(timeout) GDB never initialized after 10 seconds."
+               remote_close host
+               unset gdb_spawn_id
+               return -1
+           }
        }
     }
-    set gdb_spawn_id -1;
+
     # force the height to "unlimited", so no pagers get used
 
     send_gdb "set height 0\n"
@@ -1371,7 +1694,25 @@ proc default_gdb_start { } {
            warning "Couldn't set the width to 0."
        }
     }
-    return 0;
+    return 0
+}
+
+# Utility procedure to give user control of the gdb prompt in a script. It is
+# meant to be used for debugging test cases, and should not be left in the
+# test cases code.
+
+proc gdb_interact { } {
+    global gdb_spawn_id
+    set spawn_id $gdb_spawn_id
+
+    send_user "+------------------------------------------+\n"
+    send_user "| Script interrupted, you can now interact |\n"
+    send_user "| with by gdb. Type >>> to continue.       |\n"
+    send_user "+------------------------------------------+\n"
+
+    interact {
+       ">>>" return
+    }
 }
 
 # Examine the output of compilation to determine whether compilation
@@ -1437,27 +1778,70 @@ proc skip_ada_tests {} {
     return 0
 }
 
-# Return a 1 if I don't even want to try to test java.
+# 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 D.
 
-proc skip_java_tests {} {
+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.
 
-proc skip_python_tests {} {
-    global gdb_prompt
-    gdb_test_multiple "python print 'test'" "verify python support" {
-       -re "not supported.*$gdb_prompt $"      {
+proc skip_python_tests_prompt { prompt_regexp } {
+    global gdb_py_is_py3k
+    global gdb_py_is_py24
+
+    gdb_test_multiple "python print ('test')" "verify python support" {
+       -re "not supported.*$prompt_regexp" {
            unsupported "Python support is disabled."
            return 1
        }
-       -re "$gdb_prompt $"     {}
+       -re "$prompt_regexp" {}
+    }
+
+    set gdb_py_is_py24 0
+    gdb_test_multiple "python print (sys.version_info\[0\])" "check if python 3" {
+       -re "3.*$prompt_regexp" {
+            set gdb_py_is_py3k 1
+        }
+       -re ".*$prompt_regexp" {
+            set gdb_py_is_py3k 0
+        }
+    }
+    if { $gdb_py_is_py3k == 0 } {
+        gdb_test_multiple "python print (sys.version_info\[1\])" "check if python 2.4" {
+           -re "\[45\].*$prompt_regexp" {
+                set gdb_py_is_py24 1
+            }
+           -re ".*$prompt_regexp" {
+                set gdb_py_is_py24 0
+            }
+        }
     }
 
     return 0
 }
 
+# Return a 1 for configurations that do not support Python scripting.
+# Note: This also sets various globals that specify which version of Python
+# is in use.  See skip_python_tests_prompt.
+
+proc skip_python_tests {} {
+    global gdb_prompt
+    return [skip_python_tests_prompt "$gdb_prompt $"]
+}
+
 # Return a 1 if we should skip shared library tests.
 
 proc skip_shlib_tests {} {
@@ -1481,6 +1865,22 @@ proc skip_shlib_tests {} {
     return 1
 }
 
+# Return 1 if we should skip tui related tests.
+
+proc skip_tui_tests {} {
+    global gdb_prompt
+
+    gdb_test_multiple "help layout" "verify tui support" {
+       -re "Undefined command: \"layout\".*$gdb_prompt $" {
+           return 1
+       }
+       -re "$gdb_prompt $" {
+       }
+    }
+
+    return 0
+}
+
 # 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
@@ -1568,30 +1968,299 @@ proc with_test_prefix { prefix body } {
   }
 }
 
+# Wrapper for foreach that calls with_test_prefix on each iteration,
+# including the iterator's name and current value in the prefix.
+
+proc foreach_with_prefix {var list body} {
+    upvar 1 $var myvar
+    foreach myvar $list {
+       with_test_prefix "$var=$myvar" {
+           uplevel 1 $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.
+#
+# This is useful for providing a scope in which it is safe to temporarily
+# modify global variables, e.g.
+#
+#   global INTERNAL_GDBFLAGS
+#   global env
+#
+#   set foo GDBHISTSIZE
+#
+#   save_vars { INTERNAL_GDBFLAGS env($foo) env(HOME) } {
+#       append INTERNAL_GDBFLAGS " -nx"
+#       unset -nocomplain env(GDBHISTSIZE)
+#       gdb_start
+#       gdb_test ...
+#   }
+#
+# Here, although INTERNAL_GDBFLAGS, env(GDBHISTSIZE) and env(HOME) may be
+# modified inside BODY, this proc guarantees that the modifications will be
+# undone after BODY finishes executing.
+
+proc save_vars { vars body } {
+    array set saved_scalars { }
+    array set saved_arrays { }
+    set unset_vars { }
+
+    foreach var $vars {
+       # First evaluate VAR in the context of the caller in case the variable
+       # name may be a not-yet-interpolated string like env($foo)
+       set var [uplevel 1 list $var]
+
+       if [uplevel 1 [list info exists $var]] {
+           if [uplevel 1 [list array exists $var]] {
+               set saved_arrays($var) [uplevel 1 [list array get $var]]
+           } else {
+               set saved_scalars($var) [uplevel 1 [list set $var]]
+           }
+       } else {
+           lappend unset_vars $var
+       }
+    }
+
+    set code [catch {uplevel 1 $body} result]
+
+    foreach {var value} [array get saved_scalars] {
+       uplevel 1 [list set $var $value]
+    }
+
+    foreach {var value} [array get saved_arrays] {
+       uplevel 1 [list unset $var]
+       uplevel 1 [list array set $var $value]
+    }
+
+    foreach var $unset_vars {
+       uplevel 1 [list unset -nocomplain $var]
+    }
+
+    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
+# $gdb_prompt.
+# Returns the result of BODY.
+#
+# Notes:
+#
+# 1) If you want to use, for example, "(foo)" as the prompt you must pass it
+# as "(foo)", and not the regexp form "\(foo\)" (expressed as "\\(foo\\)" in
+# TCL).  PROMPT is internally converted to a suitable regexp for matching.
+# We do the conversion from "(foo)" to "\(foo\)" here for a few reasons:
+#   a) It's more intuitive for callers to pass the plain text form.
+#   b) We need two forms of the prompt:
+#      - a regexp to use in output matching,
+#      - a value to pass to the "set prompt" command.
+#   c) It's easier to convert the plain text form to its regexp form.
+#
+# 2) Don't add a trailing space, we do that here.
+
+proc with_gdb_prompt { prompt body } {
+    global gdb_prompt
+
+    # Convert "(foo)" to "\(foo\)".
+    # We don't use string_to_regexp because while it works today it's not
+    # clear it will work tomorrow: the value we need must work as both a
+    # regexp *and* as the argument to the "set prompt" command, at least until
+    # we start recording both forms separately instead of just $gdb_prompt.
+    # The testsuite is pretty-much hardwired to interpret $gdb_prompt as the
+    # regexp form.
+    regsub -all {[]*+.|()^$\[\\]} $prompt {\\&} prompt
+
+    set saved $gdb_prompt
+
+    verbose -log "Setting gdb prompt to \"$prompt \"."
+    set gdb_prompt $prompt
+    gdb_test_no_output "set prompt $prompt " ""
+
+    set code [catch {uplevel 1 $body} result]
+
+    verbose -log "Restoring gdb prompt to \"$saved \"."
+    set gdb_prompt $saved
+    gdb_test_no_output "set prompt $saved " ""
+
+    if {$code == 1} {
+       global errorInfo errorCode
+       return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+    } else {
+       return -code $code $result
+    }
+}
+
+# Run tests in BODY with target-charset setting to TARGET_CHARSET.  When
+# BODY is finished, restore target-charset.
+
+proc with_target_charset { target_charset body } {
+    global gdb_prompt
+
+    set saved ""
+    gdb_test_multiple "show target-charset" "" {
+       -re "The target character set is \".*; currently (.*)\"\..*$gdb_prompt " {
+           set saved $expect_out(1,string)
+       }
+       -re "The target character set is \"(.*)\".*$gdb_prompt " {
+           set saved $expect_out(1,string)
+       }
+       -re ".*$gdb_prompt " {
+           fail "get target-charset"
+       }
+    }
+
+    gdb_test_no_output "set target-charset $target_charset" ""
+
+    set code [catch {uplevel 1 $body} result]
+
+    gdb_test_no_output "set target-charset $saved" ""
+
+    if {$code == 1} {
+       global errorInfo errorCode
+       return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+    } else {
+       return -code $code $result
+    }
+}
+
+# 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,
+# - the board variable "gdb,timeout".
+
+proc get_largest_timeout {} {
+    upvar #0 timeout gtimeout
+    upvar 2 timeout timeout
+
+    set tmt 0
+    if [info exists timeout] {
+      set tmt $timeout
+    }
+    if { [info exists gtimeout] && $gtimeout > $tmt } {
+       set tmt $gtimeout
+    }
+    if { [target_info exists gdb,timeout]
+        && [target_info gdb,timeout] > $tmt } {
+       set tmt [target_info gdb,timeout]
+    }
+    if { $tmt == 0 } {
+       # Eeeeew.
+       set tmt 60
+    }
+
+    return $tmt
+}
+
+# Run tests in BODY with timeout increased by factor of FACTOR.  When
+# BODY is finished, restore timeout.
+
+proc with_timeout_factor { factor body } {
+    global timeout
+
+    set savedtimeout $timeout
+
+    set timeout [expr [get_largest_timeout] * $factor]
+    set code [catch {uplevel 1 $body} result]
+
+    set timeout $savedtimeout
+    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 {} {
-    global support_complex_tests_saved
+gdb_caching_proc support_complex_tests {
 
-    # Use the cached value, if it exists.
-    if [info exists support_complex_tests_saved] {
-        verbose "returning saved $support_complex_tests_saved" 2
-        return $support_complex_tests_saved
+    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.
-    set src complex[pid].c
-    set exe complex[pid].x
-
-    set f [open $src "w"]
-    puts $f "int main() {"
-    puts $f "_Complex float cf;"
-    puts $f "_Complex double cd;"
-    puts $f "_Complex long double cld;"
-    puts $f "  return 0; }"
-    close $f
+    set src [standard_temp_file complex[pid].c]
+    set exe [standard_temp_file complex[pid].x]
+
+    gdb_produce_source $src {
+       int main() {
+           _Complex float cf;
+           _Complex double cd;
+           _Complex long double cld;
+           return 0;
+       }
+    }
 
     verbose "compiling testfile $src" 2
     set compile_flags {debug nowarnings quiet}
@@ -1601,29 +2270,47 @@ proc support_complex_tests {} {
 
     if ![string match "" $lines] then {
         verbose "testfile compilation failed, returning 0" 2
-        set support_complex_tests_saved 0
+        set result 0
+    } else {
+       set result 1
+    }
+
+    return $result
+}
+
+# Return 1 if GDB can get a type for siginfo from the target, otherwise
+# return 0.
+
+proc supports_get_siginfo_type {} {
+    if { [istarget "*-*-linux*"] } {
+       return 1
     } else {
-       set support_complex_tests_saved 1
+       return 0
+    }
+}
+
+# Return 1 if the target supports hardware single stepping.
+
+proc can_hardware_single_step {} {
+
+    if { [istarget "arm*-*-*"] || [istarget "mips*-*-*"]
+        || [istarget "tic6x-*-*"] || [istarget "sparc*-*-linux*"]
+        || [istarget "nios2-*-*"] } {
+       return 0
     }
 
-    return $support_complex_tests_saved
+    return 1
 }
 
 # Return 1 if target hardware or OS supports single stepping to signal
 # handler, otherwise, return 0.
 
 proc can_single_step_to_signal_handler {} {
-
     # Targets don't have hardware single step.  On these targets, when
     # a signal is delivered during software single step, gdb is unable
     # to determine the next instruction addresses, because start of signal
     # handler is one of them.
-    if { [istarget "arm*-*-*"] || [istarget "mips*-*-*"]
-        || [istarget "tic6x-*-*"] || [istarget "sparc*-*-linux*"] } {
-       return 0
-    }
-
-    return 1
+    return [can_hardware_single_step]
 }
 
 # Return 1 if target supports process record, otherwise return 0.
@@ -1634,7 +2321,11 @@ proc supports_process_record {} {
        return [target_info gdb,use_precord]
     }
 
-    if { [istarget "x86_64-*-linux*"] || [istarget "i\[34567\]86-*-linux*"] } {
+    if { [istarget "arm*-*-linux*"] || [istarget "x86_64-*-linux*"]
+         || [istarget "i\[34567\]86-*-linux*"]
+         || [istarget "aarch64*-*-linux*"]
+         || [istarget "powerpc*-*-linux*"]
+         || [istarget "s390*-*-linux*"] } {
        return 1
     }
 
@@ -1649,37 +2340,113 @@ proc supports_reverse {} {
        return [target_info gdb,can_reverse]
     }
 
-    if { [istarget "x86_64-*-linux*"] || [istarget "i\[34567\]86-*-linux*"] } {
+    if { [istarget "arm*-*-linux*"] || [istarget "x86_64-*-linux*"]
+         || [istarget "i\[34567\]86-*-linux*"]
+         || [istarget "aarch64*-*-linux*"]
+         || [istarget "powerpc*-*-linux*"]
+         || [istarget "s390*-*-linux*"] } {
        return 1
     }
 
     return 0
 }
 
-# Return 1 if target is ILP32.
-# This cannot be decided simply from looking at the target string,
-# as it might depend on externally passed compiler options like -m64.
-proc is_ilp32_target {} {
-    global is_ilp32_target_saved
+# Return 1 if readline library is used.
 
-    # Use the cached value, if it exists.  Cache value per "board" to handle
-    # runs with multiple options (e.g. unix/{-m32,-64}) correctly.
-    set me "is_ilp32_target"
-    set board [target_info name]
-    if [info exists is_ilp32_target_saved($board)] {
-        verbose "$me:  returning saved $is_ilp32_target_saved($board)" 2
-        return $is_ilp32_target_saved($board)
+proc readline_is_used { } {
+    global gdb_prompt
+
+    gdb_test_multiple "show editing" "" {
+       -re ".*Editing of command lines as they are typed is on\..*$gdb_prompt $" {
+           return 1
+       }
+       -re ".*$gdb_prompt $" {
+           return 0
+       }
+    }
+}
+
+# Return 1 if target is ELF.
+gdb_caching_proc is_elf_target {
+    set me "is_elf_target"
+
+    set src [standard_temp_file is_elf_target[pid].c]
+    set obj [standard_temp_file is_elf_target[pid].o]
+
+    gdb_produce_source $src {
+       int foo () {return 0;}
+    }
+
+    verbose "$me:  compiling testfile $src" 2
+    set lines [gdb_compile $src $obj object {quiet}]
+
+    file delete $src
+
+    if ![string match "" $lines] then {
+       verbose "$me:  testfile compilation failed, returning 0" 2
+       return 0
+    }
+
+    set fp_obj [open $obj "r"]
+    fconfigure $fp_obj -translation binary
+    set data [read $fp_obj]
+    close $fp_obj
+
+    file delete $obj
+
+    set ELFMAG "\u007FELF"
+
+    if {[string compare -length 4 $data $ELFMAG] != 0} {
+       verbose "$me:  returning 0" 2
+       return 0
     }
 
+    verbose "$me:  returning 1" 2
+    return 1
+}
+
+# Return 1 if the memory at address zero is readable.
+
+gdb_caching_proc is_address_zero_readable {
+    global gdb_prompt
+
+    set ret 0
+    gdb_test_multiple "x 0" "" {
+       -re "Cannot access memory at address 0x0.*$gdb_prompt $" {
+           set ret 0
+       }
+       -re ".*$gdb_prompt $" {
+           set ret 1
+       }
+    }
+
+    return $ret
+}
+
+# Produce source file NAME and write SOURCES into it.
 
-    set src ilp32[pid].c
-    set obj ilp32[pid].o
+proc gdb_produce_source { name sources } {
+    set index 0
+    set f [open $name "w"]
 
-    set f [open $src "w"]
-    puts $f "int dummy\[sizeof (int) == 4"
-    puts $f "           && sizeof (void *) == 4"
-    puts $f "           && sizeof (long) == 4 ? 1 : -1\];"
+    puts $f $sources
     close $f
+}
+
+# Return 1 if target is ILP32.
+# This cannot be decided simply from looking at the target string,
+# as it might depend on externally passed compiler options like -m64.
+gdb_caching_proc is_ilp32_target {
+    set me "is_ilp32_target"
+
+    set src [standard_temp_file ilp32[pid].c]
+    set obj [standard_temp_file ilp32[pid].o]
+
+    gdb_produce_source $src {
+       int dummy[sizeof (int) == 4
+                 && sizeof (void *) == 4
+                 && sizeof (long) == 4 ? 1 : -1];
+    }
 
     verbose "$me:  compiling testfile $src" 2
     set lines [gdb_compile $src $obj object {quiet}]
@@ -1688,36 +2455,55 @@ proc is_ilp32_target {} {
 
     if ![string match "" $lines] then {
         verbose "$me:  testfile compilation failed, returning 0" 2
-        return [set is_ilp32_target_saved($board) 0]
+        return 0
     }
 
     verbose "$me:  returning 1" 2
-    return [set is_ilp32_target_saved($board) 1]
+    return 1
 }
 
 # Return 1 if target is LP64.
 # This cannot be decided simply from looking at the target string,
 # as it might depend on externally passed compiler options like -m64.
-proc is_lp64_target {} {
-    global is_lp64_target_saved
-
-    # Use the cached value, if it exists.  Cache value per "board" to handle
-    # runs with multiple options (e.g. unix/{-m32,-64}) correctly.
+gdb_caching_proc is_lp64_target {
     set me "is_lp64_target"
-    set board [target_info name]
-    if [info exists is_lp64_target_saved($board)] {
-        verbose "$me:  returning saved $is_lp64_target_saved($board)" 2
-        return $is_lp64_target_saved($board)
+
+    set src [standard_temp_file lp64[pid].c]
+    set obj [standard_temp_file lp64[pid].o]
+
+    gdb_produce_source $src {
+       int dummy[sizeof (int) == 4
+                 && sizeof (void *) == 8
+                 && sizeof (long) == 8 ? 1 : -1];
     }
 
-    set src lp64[pid].c
-    set obj lp64[pid].o
+    verbose "$me:  compiling testfile $src" 2
+    set lines [gdb_compile $src $obj object {quiet}]
+    file delete $src
+    file delete $obj
 
-    set f [open $src "w"]
-    puts $f "int dummy\[sizeof (int) == 4"
-    puts $f "           && sizeof (void *) == 8"
-    puts $f "           && sizeof (long) == 8 ? 1 : -1\];"
-    close $f
+    if ![string match "" $lines] then {
+        verbose "$me:  testfile compilation failed, returning 0" 2
+        return 0
+    }
+
+    verbose "$me:  returning 1" 2
+    return 1
+}
+
+# Return 1 if target has 64 bit addresses.
+# This cannot be decided simply from looking at the target string,
+# as it might depend on externally passed compiler options like -m64.
+gdb_caching_proc is_64_target {
+    set me "is_64_target"
+
+    set src [standard_temp_file is64[pid].c]
+    set obj [standard_temp_file is64[pid].o]
+
+    gdb_produce_source $src {
+       int function(void) { return 3; }
+       int dummy[sizeof (&function) == 8 ? 1 : -1];
+    }
 
     verbose "$me:  compiling testfile $src" 2
     set lines [gdb_compile $src $obj object {quiet}]
@@ -1726,41 +2512,32 @@ proc is_lp64_target {} {
 
     if ![string match "" $lines] then {
         verbose "$me:  testfile compilation failed, returning 0" 2
-        return [set is_lp64_target_saved($board) 0]
+        return 0
     }
 
     verbose "$me:  returning 1" 2
-    return [set is_lp64_target_saved($board) 1]
+    return 1
 }
 
 # Return 1 if target has x86_64 registers - either amd64 or x32.
 # x32 target identifies as x86_64-*-linux*, therefore it cannot be determined
 # just from the target string.
-proc is_amd64_regs_target {} {
-    global is_amd64_regs_target_saved
-
+gdb_caching_proc is_amd64_regs_target {
     if {![istarget "x86_64-*-*"] && ![istarget "i?86-*"]} {
        return 0
     }
 
-    # Use the cached value, if it exists.  Cache value per "board" to handle
-    # runs with multiple options (e.g. unix/{-m32,-64}) correctly.
     set me "is_amd64_regs_target"
-    set board [target_info name]
-    if [info exists is_amd64_regs_target_saved($board)] {
-        verbose "$me:  returning saved $is_amd64_regs_target_saved($board)" 2
-        return $is_amd64_regs_target_saved($board)
-    }
 
-    set src reg64[pid].s
-    set obj reg64[pid].o
+    set src [standard_temp_file reg64[pid].s]
+    set obj [standard_temp_file reg64[pid].o]
 
-    set f [open $src "w"]
+    set list {}
     foreach reg \
-            {rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15} {
-       puts $f "\tincq %$reg"
-    }
-    close $f
+       {rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15} {
+           lappend list "\tincq %$reg"
+       }
+    gdb_produce_source $src [join $list \n]
 
     verbose "$me:  compiling testfile $src" 2
     set lines [gdb_compile $src $obj object {quiet}]
@@ -1769,11 +2546,11 @@ proc is_amd64_regs_target {} {
 
     if ![string match "" $lines] then {
         verbose "$me:  testfile compilation failed, returning 0" 2
-        return [set is_amd64_regs_target_saved($board) 0]
+        return 0
     }
 
     verbose "$me:  returning 1" 2
-    return [set is_amd64_regs_target_saved($board) 1]
+    return 1
 }
 
 # Return 1 if this target is an x86 or x86-64 with -m32.
@@ -1784,76 +2561,258 @@ proc is_x86_like_target {} {
     return [expr [is_ilp32_target] && ![is_amd64_regs_target]]
 }
 
+# Return 1 if this target is an arm or aarch32 on aarch64.
+
+gdb_caching_proc is_aarch32_target {
+    if { [istarget "arm*-*-*"] } {
+       return 1
+    }
+
+    if { ![istarget "aarch64*-*-*"] } {
+       return 0
+    }
+
+    set me "is_aarch32_target"
+
+    set src [standard_temp_file aarch32[pid].s]
+    set obj [standard_temp_file aarch32[pid].o]
+
+    set list {}
+    foreach reg \
+       {r0 r1 r2 r3} {
+           lappend list "\tmov $reg, $reg"
+       }
+    gdb_produce_source $src [join $list \n]
+
+    verbose "$me:  compiling testfile $src" 2
+    set lines [gdb_compile $src $obj object {quiet}]
+    file delete $src
+    file delete $obj
+
+    if ![string match "" $lines] then {
+       verbose "$me:  testfile compilation failed, returning 0" 2
+       return 0
+    }
+
+    verbose "$me:  returning 1" 2
+    return 1
+}
+
+# Return 1 if this target is an aarch64, either lp64 or ilp32.
+
+proc is_aarch64_target {} {
+    if { ![istarget "aarch64*-*-*"] } {
+       return 0
+    }
+
+    return [expr ![is_aarch32_target]]
+}
+
 # Return 1 if displaced stepping is supported on target, otherwise, return 0.
 proc support_displaced_stepping {} {
 
     if { [istarget "x86_64-*-linux*"] || [istarget "i\[34567\]86-*-linux*"]
         || [istarget "arm*-*-linux*"] || [istarget "powerpc-*-linux*"]
-        || [istarget "powerpc64-*-linux*"] || [istarget "s390*-*-*"] } {
+        || [istarget "powerpc64-*-linux*"] || [istarget "s390*-*-*"]
+        || [istarget "aarch64*-*-linux*"] } {
        return 1
     }
 
-    return 0
+    return 0
+}
+
+# Run a test on the target to see if it supports vmx hardware.  Return 0 if so, 
+# 1 if it does not.  Based on 'check_vmx_hw_available' from the GCC testsuite.
+
+gdb_caching_proc skip_altivec_tests {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "skip_altivec_tests"
+
+    # Some simulators are known to not support VMX instructions.
+    if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] } {
+        verbose "$me:  target known to not support VMX, returning 1" 2
+        return 1
+    }
+
+    # Make sure we have a compiler that understands altivec.
+    set compile_flags {debug nowarnings}
+    if [get_compiler_info] {
+       warning "Could not get compiler info"
+       return 1
+    }
+    if [test_compiler_info gcc*] {
+        set compile_flags "$compile_flags additional_flags=-maltivec"
+    } elseif [test_compiler_info xlc*] {
+        set compile_flags "$compile_flags additional_flags=-qaltivec"
+    } else {
+        verbose "Could not compile with altivec support, returning 1" 2
+        return 1
+    }
+
+    # Set up, compile, and execute a test program containing VMX instructions.
+    # Include the current process ID in the file names to prevent conflicts
+    # with invocations for multiple testsuites.
+    set src [standard_temp_file vmx[pid].c]
+    set exe [standard_temp_file vmx[pid].x]
+
+    gdb_produce_source $src {
+       int main() {
+           #ifdef __MACH__
+           asm volatile ("vor v0,v0,v0");
+           #else
+           asm volatile ("vor 0,0,0");
+           #endif
+           return 0;
+       }
+    }
+
+    verbose "$me:  compiling testfile $src" 2
+    set lines [gdb_compile $src $exe executable $compile_flags]
+    file delete $src
+
+    if ![string match "" $lines] then {
+        verbose "$me:  testfile compilation failed, returning 1" 2
+        return 1
+    }
+
+    # No error message, compilation succeeded so now run it via gdb.
+
+    gdb_exit
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load "$exe"
+    gdb_run_cmd
+    gdb_expect {
+        -re ".*Illegal instruction.*${gdb_prompt} $" {
+            verbose -log "\n$me altivec hardware not detected" 
+            set skip_vmx_tests 1
+        }
+        -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+            verbose -log "\n$me: altivec hardware detected" 
+            set skip_vmx_tests 0
+        }
+        default {
+          warning "\n$me: default case taken"
+            set skip_vmx_tests 1
+        }
+    }
+    gdb_exit
+    remote_file build delete $exe
+
+    verbose "$me:  returning $skip_vmx_tests" 2
+    return $skip_vmx_tests
+}
+
+# Run a test on the target to see if it supports vmx hardware.  Return 0 if so,
+# 1 if it does not.  Based on 'check_vmx_hw_available' from the GCC testsuite.
+
+gdb_caching_proc skip_vsx_tests {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "skip_vsx_tests"
+
+    # Some simulators are known to not support Altivec instructions, so
+    # they won't support VSX instructions as well.
+    if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] } {
+        verbose "$me:  target known to not support VSX, returning 1" 2
+        return 1
+    }
+
+    # Make sure we have a compiler that understands altivec.
+    set compile_flags {debug nowarnings quiet}
+    if [get_compiler_info] {
+       warning "Could not get compiler info"
+       return 1
+    }
+    if [test_compiler_info gcc*] {
+        set compile_flags "$compile_flags additional_flags=-mvsx"
+    } elseif [test_compiler_info xlc*] {
+        set compile_flags "$compile_flags additional_flags=-qasm=gcc"
+    } else {
+        verbose "Could not compile with vsx support, returning 1" 2
+        return 1
+    }
+
+    set src [standard_temp_file vsx[pid].c]
+    set exe [standard_temp_file vsx[pid].x]
+
+    gdb_produce_source $src {
+       int main() {
+           double a[2] = { 1.0, 2.0 };
+           #ifdef __MACH__
+           asm volatile ("lxvd2x v0,v0,%[addr]" : : [addr] "r" (a));
+           #else
+           asm volatile ("lxvd2x 0,0,%[addr]" : : [addr] "r" (a));
+           #endif
+           return 0;
+       }
+    }
+
+    verbose "$me:  compiling testfile $src" 2
+    set lines [gdb_compile $src $exe executable $compile_flags]
+    file delete $src
+
+    if ![string match "" $lines] then {
+        verbose "$me:  testfile compilation failed, returning 1" 2
+        return 1
+    }
+
+    # No error message, compilation succeeded so now run it via gdb.
+
+    gdb_exit
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load "$exe"
+    gdb_run_cmd
+    gdb_expect {
+        -re ".*Illegal instruction.*${gdb_prompt} $" {
+            verbose -log "\n$me VSX hardware not detected"
+            set skip_vsx_tests 1
+        }
+        -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+            verbose -log "\n$me: VSX hardware detected"
+            set skip_vsx_tests 0
+        }
+        default {
+          warning "\n$me: default case taken"
+            set skip_vsx_tests 1
+        }
+    }
+    gdb_exit
+    remote_file build delete $exe
+
+    verbose "$me:  returning $skip_vsx_tests" 2
+    return $skip_vsx_tests
 }
 
-# Run a test on the target to see if it supports vmx hardware.  Return 0 if so, 
+# Run a test on the target to see if it supports TSX hardware.  Return 0 if so,
 # 1 if it does not.  Based on 'check_vmx_hw_available' from the GCC testsuite.
 
-proc skip_altivec_tests {} {
-    global skip_vmx_tests_saved
+gdb_caching_proc skip_tsx_tests {
     global srcdir subdir gdb_prompt inferior_exited_re
 
-    # Use the cached value, if it exists.
-    set me "skip_altivec_tests"
-    if [info exists skip_vmx_tests_saved] {
-        verbose "$me:  returning saved $skip_vmx_tests_saved" 2
-        return $skip_vmx_tests_saved
-    }
+    set me "skip_tsx_tests"
 
-    # Some simulators are known to not support VMX instructions.
-    if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] } {
-        verbose "$me:  target known to not support VMX, returning 1" 2
-        return [set skip_vmx_tests_saved 1]
-    }
+    set src [standard_temp_file tsx[pid].c]
+    set exe [standard_temp_file tsx[pid].x]
 
-    # Make sure we have a compiler that understands altivec.
-    set compile_flags {debug nowarnings}
-    if [get_compiler_info not-used] {
-       warning "Could not get compiler info"
-       return 1
+    gdb_produce_source $src {
+    int main() {
+        asm volatile ("xbegin .L0");
+        asm volatile ("xend");
+        asm volatile (".L0: nop");
+        return 0;
     }
-    if [test_compiler_info gcc*] {
-        set compile_flags "$compile_flags additional_flags=-maltivec"
-    } elseif [test_compiler_info xlc*] {
-        set compile_flags "$compile_flags additional_flags=-qaltivec"
-    } else {
-        verbose "Could not compile with altivec support, returning 1" 2
-        return 1
     }
 
-    # Set up, compile, and execute a test program containing VMX instructions.
-    # Include the current process ID in the file names to prevent conflicts
-    # with invocations for multiple testsuites.
-    set src vmx[pid].c
-    set exe vmx[pid].x
-
-    set f [open $src "w"]
-    puts $f "int main() {"
-    puts $f "#ifdef __MACH__"
-    puts $f "  asm volatile (\"vor v0,v0,v0\");"
-    puts $f "#else"
-    puts $f "  asm volatile (\"vor 0,0,0\");"
-    puts $f "#endif"
-    puts $f "  return 0; }"
-    close $f
-
     verbose "$me:  compiling testfile $src" 2
-    set lines [gdb_compile $src $exe executable $compile_flags]
+    set lines [gdb_compile $src $exe executable {nowarnings quiet}]
     file delete $src
 
     if ![string match "" $lines] then {
-        verbose "$me:  testfile compilation failed, returning 1" 2
-        return [set skip_vmx_tests_saved 1]
+        verbose "$me:  testfile compilation failed." 2
+        return 1
     }
 
     # No error message, compilation succeeded so now run it via gdb.
@@ -1865,82 +2824,122 @@ proc skip_altivec_tests {} {
     gdb_run_cmd
     gdb_expect {
         -re ".*Illegal instruction.*${gdb_prompt} $" {
-            verbose -log "\n$me altivec hardware not detected" 
-            set skip_vmx_tests_saved 1
+            verbose -log "$me:  TSX hardware not detected."
+            set skip_tsx_tests 1
         }
         -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
-            verbose -log "\n$me: altivec hardware detected" 
-            set skip_vmx_tests_saved 0
+            verbose -log "$me:  TSX hardware detected."
+            set skip_tsx_tests 0
         }
         default {
-          warning "\n$me: default case taken"
-            set skip_vmx_tests_saved 1
+            warning "\n$me:  default case taken."
+            set skip_tsx_tests 1
         }
     }
     gdb_exit
     remote_file build delete $exe
 
-    verbose "$me:  returning $skip_vmx_tests_saved" 2
-    return $skip_vmx_tests_saved
+    verbose "$me:  returning $skip_tsx_tests" 2
+    return $skip_tsx_tests
 }
 
-# Run a test on the target to see if it supports vmx hardware.  Return 0 if so,
+# Run a test on the target to see if it supports btrace hardware.  Return 0 if so,
 # 1 if it does not.  Based on 'check_vmx_hw_available' from the GCC testsuite.
 
-proc skip_vsx_tests {} {
-    global skip_vsx_tests_saved
+gdb_caching_proc skip_btrace_tests {
     global srcdir subdir gdb_prompt inferior_exited_re
 
-    # Use the cached value, if it exists.
-    set me "skip_vsx_tests"
-    if [info exists skip_vsx_tests_saved] {
-        verbose "$me:  returning saved $skip_vsx_tests_saved" 2
-        return $skip_vsx_tests_saved
+    set me "skip_btrace_tests"
+    if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } {
+        verbose "$me:  target does not support btrace, returning 1" 2
+        return 1
     }
 
-    # Some simulators are known to not support Altivec instructions, so
-    # they won't support VSX instructions as well.
-    if { [istarget powerpc-*-eabi] || [istarget powerpc*-*-eabispe] } {
-        verbose "$me:  target known to not support VSX, returning 1" 2
-        return [set skip_vsx_tests_saved 1]
+    # Set up, compile, and execute a test program.
+    # Include the current process ID in the file names to prevent conflicts
+    # with invocations for multiple testsuites.
+    set src [standard_temp_file btrace[pid].c]
+    set exe [standard_temp_file btrace[pid].x]
+
+    gdb_produce_source $src {
+       int main(void) { return 0; }
     }
 
-    # Make sure we have a compiler that understands altivec.
+    verbose "$me:  compiling testfile $src" 2
     set compile_flags {debug nowarnings quiet}
-    if [get_compiler_info not-used] {
-       warning "Could not get compiler info"
-       return 1
+    set lines [gdb_compile $src $exe executable $compile_flags]
+
+    if ![string match "" $lines] then {
+        verbose "$me:  testfile compilation failed, returning 1" 2
+       file delete $src
+        return 1
     }
-    if [test_compiler_info gcc*] {
-        set compile_flags "$compile_flags additional_flags=-mvsx"
-    } elseif [test_compiler_info xlc*] {
-        set compile_flags "$compile_flags additional_flags=-qasm=gcc"
-    } else {
-        verbose "Could not compile with vsx support, returning 1" 2
+
+    # No error message, compilation succeeded so now run it via gdb.
+
+    gdb_exit
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load $exe
+    if ![runto_main] {
+       file delete $src
+        return 1
+    }
+    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" "check btrace support" {
+        -re "You can't do that when your target is.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "Target does not support branch tracing.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "Could not enable branch tracing.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "^record btrace\r\n$gdb_prompt $" {
+            set skip_btrace_tests 0
+        }
+    }
+    gdb_exit
+    remote_file build delete $exe
+
+    verbose "$me:  returning $skip_btrace_tests" 2
+    return $skip_btrace_tests
+}
+
+# Run a test on the target to see if it supports btrace pt hardware.
+# Return 0 if so, 1 if it does not.  Based on 'check_vmx_hw_available'
+# from the GCC testsuite.
+
+gdb_caching_proc skip_btrace_pt_tests {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "skip_btrace_tests"
+    if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } {
+        verbose "$me:  target does not support btrace, returning 1" 2
         return 1
     }
 
-    set src vsx[pid].c
-    set exe vsx[pid].x
+    # Set up, compile, and execute a test program.
+    # Include the current process ID in the file names to prevent conflicts
+    # with invocations for multiple testsuites.
+    set src [standard_temp_file btrace[pid].c]
+    set exe [standard_temp_file btrace[pid].x]
 
-    set f [open $src "w"]
-    puts $f "int main() {"
-    puts $f "  double a\[2\] = { 1.0, 2.0 };"
-    puts $f "#ifdef __MACH__"
-    puts $f "  asm volatile (\"lxvd2x v0,v0,%\[addr\]\" : : \[addr\] \"r\" (a));"
-    puts $f "#else"
-    puts $f "  asm volatile (\"lxvd2x 0,0,%\[addr\]\" : : \[addr\] \"r\" (a));"
-    puts $f "#endif"
-    puts $f "  return 0; }"
-    close $f
+    gdb_produce_source $src {
+       int main(void) { return 0; }
+    }
 
     verbose "$me:  compiling testfile $src" 2
+    set compile_flags {debug nowarnings quiet}
     set lines [gdb_compile $src $exe executable $compile_flags]
-    file delete $src
 
     if ![string match "" $lines] then {
         verbose "$me:  testfile compilation failed, returning 1" 2
-        return [set skip_vsx_tests_saved 1]
+       file delete $src
+        return 1
     }
 
     # No error message, compilation succeeded so now run it via gdb.
@@ -1948,36 +2947,36 @@ proc skip_vsx_tests {} {
     gdb_exit
     gdb_start
     gdb_reinitialize_dir $srcdir/$subdir
-    gdb_load "$exe"
-    gdb_run_cmd
-    gdb_expect {
-        -re ".*Illegal instruction.*${gdb_prompt} $" {
-            verbose -log "\n$me VSX hardware not detected"
-            set skip_vsx_tests_saved 1
+    gdb_load $exe
+    if ![runto_main] {
+       file delete $src
+        return 1
+    }
+    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 pt support" {
+        -re "You can't do that when your target is.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
         }
-        -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
-            verbose -log "\n$me: VSX hardware detected"
-            set skip_vsx_tests_saved 0
+        -re "Target does not support branch tracing.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
         }
-        default {
-          warning "\n$me: default case taken"
-            set skip_vsx_tests_saved 1
+        -re "Could not enable branch tracing.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "support was disabled at compile time.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "^record btrace pt\r\n$gdb_prompt $" {
+            set skip_btrace_tests 0
         }
     }
     gdb_exit
     remote_file build delete $exe
 
-    verbose "$me:  returning $skip_vsx_tests_saved" 2
-    return $skip_vsx_tests_saved
-}
-
-# Skip all the tests in the file if you are not on an hppa running
-# hpux target.
-
-proc skip_hp_tests {} {
-    eval set skip_hp [ expr ![isnative] || ![istarget "hppa*-*-hpux*"] ]
-    verbose "Skip hp tests is $skip_hp"
-    return $skip_hp
+    verbose "$me:  returning $skip_btrace_tests" 2
+    return $skip_btrace_tests
 }
 
 # Return whether we should skip tests for showing inlined functions in
@@ -2024,7 +3023,9 @@ proc skip_hw_breakpoint_tests {} {
     if { [istarget "i?86-*-*"] 
         || [istarget "x86_64-*-*"]
         || [istarget "ia64-*-*"] 
-        || [istarget "arm*-*-*"]} {
+        || [istarget "arm*-*-*"]
+        || [istarget "aarch64*-*-*"]
+        || [istarget "s390*-*-*"] } {
        return 0
     }
 
@@ -2044,6 +3045,7 @@ proc skip_hw_watchpoint_tests {} {
         || [istarget "x86_64-*-*"]
         || [istarget "ia64-*-*"] 
         || [istarget "arm*-*-*"]
+        || [istarget "aarch64*-*-*"]
         || [istarget "powerpc*-*-linux*"]
         || [istarget "s390*-*-*"] } {
        return 0
@@ -2084,17 +3086,160 @@ proc skip_hw_watchpoint_access_tests {} {
     return 0
 }
 
-set compiler_info              "unknown"
+# Return 1 if we should skip tests that require the runtime unwinder
+# hook.  This must be invoked while gdb is running, after shared
+# libraries have been loaded.  This is needed because otherwise a
+# shared libgcc won't be visible.
+
+proc skip_unwinder_tests {} {
+    global gdb_prompt
+
+    set ok 0
+    gdb_test_multiple "print _Unwind_DebugHook" "check for unwinder hook" {
+       -re "= .*no debug info.*_Unwind_DebugHook.*\r\n$gdb_prompt $" {
+       }
+       -re "= .*_Unwind_DebugHook.*\r\n$gdb_prompt $" {
+           set ok 1
+       }
+       -re "No symbol .* in current context.\r\n$gdb_prompt $" {
+       }
+    }
+    if {!$ok} {
+       gdb_test_multiple "info probe" "check for stap probe in unwinder" {
+           -re ".*libgcc.*unwind.*\r\n$gdb_prompt $" {
+               set ok 1
+           }
+           -re "\r\n$gdb_prompt $" {
+           }
+       }
+    }
+    return $ok
+}
+
+# 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
+
+    set ok 0
+    gdb_test_multiple "info probe" "check for stap probe in libstdc++" {
+       -re ".*libstdcxx.*catch.*\r\n$gdb_prompt $" {
+           set ok 1
+       }
+       -re "\r\n$gdb_prompt $" {
+       }
+    }
+    return $ok
+}
+
+# Return 1 if we should skip tests of the "compile" feature.
+# This must be invoked after the inferior has been started.
+
+proc skip_compile_feature_tests {} {
+    global gdb_prompt
+
+    set result 0
+    gdb_test_multiple "compile code -- ;" "check for working compile command" {
+       "Could not load libcc1.*\r\n$gdb_prompt $" {
+           set result 1
+       }
+       -re "Command not supported on this host\\..*\r\n$gdb_prompt $" {
+           set result 1
+       }
+       -re "\r\n$gdb_prompt $" {
+       }
+    }
+    return $result
+}
+
+# Helper for gdb_is_target_remote.  PROMPT_REGEXP is the expected
+# prompt.
+
+proc gdb_is_target_remote_prompt { prompt_regexp } {
+
+    set test "probe for target remote"
+    gdb_test_multiple "maint print target-stack" $test {
+       -re ".*emote serial target in gdb-specific protocol.*$prompt_regexp" {
+           pass $test
+           return 1
+       }
+       -re "$prompt_regexp" {
+           pass $test
+       }
+    }
+    return 0
+}
+
+# Check whether we're testing with the remote or extended-remote
+# targets.
+
+proc gdb_is_target_remote {} {
+    global gdb_prompt
+
+    return [gdb_is_target_remote_prompt "$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.
+
+gdb_caching_proc target_is_gdbserver {
+    global gdb_prompt
+
+    set is_gdbserver -1
+    set test "probing for GDBserver"
+
+    gdb_test_multiple "monitor help" $test {
+       -re "The following monitor commands are supported.*Quit GDBserver.*$gdb_prompt $" {
+           set is_gdbserver 1
+       }
+       -re "$gdb_prompt $" {
+           set is_gdbserver 0
+       }
+    }
+
+    if { $is_gdbserver == -1 } {
+       verbose -log "Unable to tell whether we are using GDBserver or not."
+    }
+
+    return $is_gdbserver
+}
+
+# N.B. compiler_info is intended to be local to this file.
+# Call test_compiler_info with no arguments to fetch its value.
+# Yes, this is counterintuitive when there's get_compiler_info,
+# but that's the current API.
+if [info exists compiler_info] {
+    unset compiler_info
+}
+
 set gcc_compiled               0
-set hp_cc_compiler             0
-set hp_aCC_compiler            0
 
 # Figure out what compiler I am using.
+# The result is cached so only the first invocation runs the compiler.
 #
-# 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.
 #
@@ -2113,8 +3258,8 @@ set hp_aCC_compiler               0
 #   if the build machine is the same as the host machine, which is
 #   usually true of the targets which are not gcc.  But this code does
 #   not figure which compiler to call, and it always ends up using the C
-#   compiler.  Not good for setting hp_aCC_compiler.  Targets
-#   hppa*-*-hpux* and mips*-*-irix* used to do this.
+#   compiler.  Not good for setting hp_aCC_compiler.  Target
+#   hppa*-*-hpux* used to do this.
 #
 # [ gdb_compile -E $ifile > $binfile.ci ]
 # source $binfile.ci
@@ -2143,7 +3288,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
 
@@ -2156,30 +3301,34 @@ proc get_compiler_info {binfile args} {
 
     # Legacy global data symbols.
     global gcc_compiled
-    global hp_cc_compiler
-    global hp_aCC_compiler
+
+    if [info exists compiler_info] {
+       # Already computed.
+       return 0
+    }
 
     # 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"
     }
 
     # Run $ifile through the right preprocessor.
     # Toggle gdb.log to keep the compiler output out of the log.
+    set saved_log [log_file -info]
     log_file
     if [is_remote host] {
        # 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" 
+    eval log_file $saved_log
 
     # Eval the output.
     set unknown 0
@@ -2199,22 +3348,20 @@ proc get_compiler_info {binfile args} {
        }
     }
 
-    # Reset to unknown compiler if any diagnostics happened.
+    # Set to unknown if for some reason compiler_info didn't get defined.
+    if ![info exists compiler_info] {
+       verbose -log "get_compiler_info: compiler_info not provided"
+       set compiler_info "unknown"
+    }
+    # Also set to unknown compiler if any diagnostics happened.
     if { $unknown } {
+       verbose -log "get_compiler_info: got unexpected diagnostics"
        set compiler_info "unknown"
     }
 
     # Set the legacy symbols.
-    set gcc_compiled     0
-    set hp_cc_compiler   0
-    set hp_aCC_compiler  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 }
-    if { [regexp "^hpcc-"  "$compiler_info" ] } { set hp_cc_compiler 1 }
-    if { [regexp "^hpacc-" "$compiler_info" ] } { set hp_aCC_compiler 1 }
+    set gcc_compiled 0
+    regexp "^gcc-(\[0-9\]+)-" "$compiler_info" matchall gcc_compiled
 
     # Log what happened.
     verbose -log "get_compiler_info: $compiler_info"
@@ -2224,28 +3371,21 @@ proc get_compiler_info {binfile args} {
     uplevel \#0 { set true 1 }
     uplevel \#0 { set false 0 }
 
-    # Use of aCC results in boolean results being displayed as
-    # "true" or "false"
-    if { $hp_aCC_compiler } {
-      uplevel \#0 { set true true }
-      uplevel \#0 { set false false }
-    }
-
-    return 0;
+    return 0
 }
 
+# Return the compiler_info string if no arg is provided.
+# Otherwise the argument is a glob-style expression to match against
+# compiler_info.
+
 proc test_compiler_info { {compiler ""} } {
     global compiler_info
+    get_compiler_info
 
-     # if no arg, return the compiler_info string
-
-     if [string match "" $compiler] {
-         if [info exists compiler_info] {
-             return $compiler_info
-         } else {
-             perror "No compiler info found."
-         }
-     }
+    # If no arg, return the compiler_info string.
+    if [string match "" $compiler] {
+       return $compiler_info
+    }
 
     return [string match $compiler $compiler_info]
 }
@@ -2264,19 +3404,19 @@ set gdb_wrapper_initialized 0
 set gdb_wrapper_target ""
 
 proc gdb_wrapper_init { args } {
-    global gdb_wrapper_initialized;
-    global gdb_wrapper_file;
-    global gdb_wrapper_flags;
+    global gdb_wrapper_initialized
+    global gdb_wrapper_file
+    global gdb_wrapper_flags
     global gdb_wrapper_target
 
     if { $gdb_wrapper_initialized == 1 } { return; }
 
     if {[target_info exists needs_status_wrapper] && \
            [target_info needs_status_wrapper] != "0"} {
-       set result [build_wrapper "testglue.o"];
+       set result [build_wrapper "testglue.o"]
        if { $result != "" } {
-           set gdb_wrapper_file [lindex $result 0];
-           set gdb_wrapper_flags [lindex $result 1];
+           set gdb_wrapper_file [lindex $result 0]
+           set gdb_wrapper_flags [lindex $result 1]
        } else {
            warning "Status wrapper failed to build."
        }
@@ -2285,15 +3425,77 @@ 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 ""
 
+# Compile source files specified by SOURCE into a binary of type TYPE at path
+# DEST.  gdb_compile is implemented using DejaGnu's target_compile, so the type
+# parameter and most options are passed directly to it.
+#
+# The type can be one of the following:
+#
+#   - object: Compile into an object file.
+#   - executable: Compile and link into an executable.
+#   - preprocess: Preprocess the source files.
+#   - assembly: Generate assembly listing.
+#
+# The following options are understood and processed by gdb_compile:
+#
+#   - shlib=so_path: Add SO_PATH to the sources, and enable some target-specific
+#     quirks to be able to use shared libraries.
+#   - shlib_load: Link with appropriate libraries to allow the test to
+#     dynamically load libraries at runtime.  For example, on Linux, this adds
+#     -ldl so that the test can use dlopen.
+#   - nowarnings:  Inhibit all compiler warnings.
+#
+# And here are some of the not too obscure options understood by DejaGnu that
+# influence the compilation:
+#
+#   - additional_flags=flag: Add FLAG to the compiler flags.
+#   - libs=library: Add LIBRARY to the libraries passed to the linker.  The
+#     argument can be a file, in which case it's added to the sources, or a
+#     linker flag.
+#   - ldflags=flag: Add FLAG to the linker flags.
+#   - incdir=path: Add PATH to the searched include directories.
+#   - libdir=path: Add PATH to the linker searched directories.
+#   - ada, c++, f77: Compile the file as Ada, C++ or Fortran.
+#   - debug: Build with debug information.
+#   - optimize: Build with optimization.
+
 proc gdb_compile {source dest type options} {
-    global GDB_TESTCASE_OPTIONS;
-    global gdb_wrapper_file;
-    global gdb_wrapper_flags;
-    global gdb_wrapper_initialized;
+    global GDB_TESTCASE_OPTIONS
+    global gdb_wrapper_file
+    global gdb_wrapper_flags
+    global gdb_wrapper_initialized
     global srcdir
     global objdir
     global gdb_saved_set_unbuffered_mode_obj
@@ -2302,11 +3504,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
@@ -2324,24 +3532,28 @@ proc gdb_compile {source dest type options} {
                      || [istarget *-*-cygwin*]) } {
                    lappend new_options "additional_flags=-Wl,--enable-auto-import"
                }
+               if { [test_compiler_info "gcc-*"] || [test_compiler_info "clang-*"] } {
+                   # Undo debian's change in the default.
+                   # Put it at the front to not override any user-provided
+                   # value, and to make sure it appears in front of all the
+                   # shlibs!
+                   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*]
-             || [istarget hppa*-*-hpux*])} {
+             || [istarget *-*-pe*]) } {
            # Do not need anything.
        } elseif { [istarget *-*-freebsd*] || [istarget *-*-openbsd*] } {
            lappend new_options "ldflags=-Wl,-rpath,${outdir}"
@@ -2358,12 +3570,8 @@ proc gdb_compile {source dest type options} {
     }
     set options $new_options
 
-    if [target_info exists is_vxworks] {
-       set options2 { "additional_flags=-Dvxworks" }
-       set options [concat $options2 $options]
-    }
     if [info exists GDB_TESTCASE_OPTIONS] {
-       lappend options "additional_flags=$GDB_TESTCASE_OPTIONS";
+       lappend options "additional_flags=$GDB_TESTCASE_OPTIONS"
     }
     verbose "options are $options"
     verbose "source is $source $dest $type $options"
@@ -2411,11 +3619,14 @@ proc gdb_compile {source dest type options} {
                if { $result != "" } {
                    return $result
                }
-
-               set gdb_saved_set_unbuffered_mode_obj ${objdir}/set_unbuffered_mode_saved.o
+               if {[is_remote host]} {
+                   set gdb_saved_set_unbuffered_mode_obj set_unbuffered_mode_saved.o
+               } else {
+                   set gdb_saved_set_unbuffered_mode_obj ${objdir}/set_unbuffered_mode_saved.o
+               }
                # Link a copy of the output object, because the
                # original may be automatically deleted.
-               remote_exec host "cp -f $unbuf_obj $gdb_saved_set_unbuffered_mode_obj"
+               remote_download host $unbuf_obj $gdb_saved_set_unbuffered_mode_obj
            } else {
                verbose "gdb_saved_set_unbuffered_obj already compiled"
            }
@@ -2432,13 +3643,13 @@ proc gdb_compile {source dest type options} {
        }
     }
 
-    set result [target_compile $source $dest $type $options];
+    set result [target_compile $source $dest $type $options]
 
     # Prune uninteresting compiler (and linker) output.
     regsub "Creating library file: \[^\r\n\]*\[\r\n\]+" $result "" result
 
-    regsub "\[\r\n\]*$" "$result" "" result;
-    regsub "^\[\r\n\]*" "$result" "" result;
+    regsub "\[\r\n\]*$" "$result" "" result
+    regsub "^\[\r\n\]*" "$result" "" result
     
     if {[lsearch $options quiet] < 0} {
        # We shall update this on a per language basis, to avoid
@@ -2449,7 +3660,7 @@ proc gdb_compile {source dest type options} {
            clone_output "gdb compile failed, $result"
        }
     }
-    return $result;
+    return $result
 }
 
 
@@ -2483,21 +3694,34 @@ proc gdb_compile_pthreads {source dest type options} {
         }
     }
     if {!$built_binfile} {
-        unsupported "Couldn't compile $source: ${why_msg}"
+       unsupported "couldn't compile [file tail $source]: ${why_msg}"
         return -1
     }
 }
 
-# Build a shared library from SOURCES.  You must use get_compiler_info
-# first.
+# Build a shared library from SOURCES.
 
 proc gdb_compile_shlib {sources dest options} {
     set obj_options $options
 
+    set info_options ""
+    if { [lsearch -exact $options "c++"] >= 0 } {
+       set info_options "c++"
+    }
+    if [get_compiler_info ${info_options}] {
+       return -1
+    }
+
     switch -glob [test_compiler_info] {
         "xlc-*" {
             lappend obj_options "additional_flags=-qpic"
         }
+       "clang-*" {
+           if { !([istarget "*-*-cygwin*"]
+                  || [istarget "*-*-mingw*"]) } {
+               lappend obj_options "additional_flags=-fpic"
+           }
+       }
         "gcc-*" {
             if { !([istarget "powerpc*-*-aix*"]
                    || [istarget "rs6000*-*-aix*"]
@@ -2507,19 +3731,11 @@ proc gdb_compile_shlib {sources dest options} {
                 lappend obj_options "additional_flags=-fpic"
             }
         }
+        "icc-*" {
+                lappend obj_options "additional_flags=-fpic"
+        }
         default {
-            switch -glob [istarget] {
-                "hppa*-hp-hpux*" {
-                    lappend obj_options "additional_flags=+z"
-                }
-                "mips-sgi-irix*" {
-                    # Disable SGI compiler's implicit -Dsgi
-                    lappend obj_options "additional_flags=-Usgi"
-                } 
-                default {
-                    # don't know what the compiler is...
-                }
-            }
+           # don't know what the compiler is...
         }
     }
 
@@ -2533,35 +3749,48 @@ proc gdb_compile_shlib {sources dest options} {
        lappend objects ${outdir}/${sourcebase}.o
     }
 
-    if [istarget "hppa*-*-hpux*"] {
-       remote_exec build "ld -b ${objects} -o ${dest}"
+    set link_options $options
+    if [test_compiler_info "xlc-*"] {
+       lappend link_options "additional_flags=-qmkshrobj"
     } else {
-       set link_options $options
-       if [test_compiler_info "xlc-*"] {
-          lappend link_options "additional_flags=-qmkshrobj"
-       } else {
-          lappend link_options "additional_flags=-shared"
-
-          if { ([istarget "*-*-mingw*"]
-                || [istarget *-*-cygwin*]
-                || [istarget *-*-pe*])} {
-              lappend link_options "additional_flags=-Wl,--out-implib,${dest}.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).
-             set destbase [file tail $dest]
-             lappend link_options "additional_flags=-Wl,-soname,$destbase"
-           }
-       }
-       if {[gdb_compile "${objects}" "${dest}" executable $link_options] != ""} {
-           return -1
-       }
+       lappend link_options "additional_flags=-shared"
+
+       if { ([istarget "*-*-mingw*"]
+             || [istarget *-*-cygwin*]
+             || [istarget *-*-pe*]) } {
+           if { [is_remote host] } {
+               set name [file tail ${dest}]
+           } else {
+               set name ${dest}
+           }
+           lappend link_options "additional_flags=-Wl,--out-implib,${name}.a"
+       } 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"
+       }
+    }
+    if {[gdb_compile "${objects}" "${dest}" executable $link_options] != ""} {
+       return -1
+    }
+    if { [is_remote host]
+        && ([istarget "*-*-mingw*"]
+            || [istarget *-*-cygwin*]
+            || [istarget *-*-pe*]) } {
+       set dest_tail_name [file tail ${dest}]
+       remote_upload host $dest_tail_name.a ${dest}.a
+       remote_file host delete $dest_tail_name.a
     }
+
+    return ""
 }
 
 # This is just like gdb_compile_shlib, above, except that it tries compiling
@@ -2594,7 +3823,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
     }
 }
@@ -2634,84 +3863,72 @@ proc gdb_compile_objc {source dest type options} {
         }
     }
     if {!$built_binfile} {
-        unsupported "Couldn't compile $source: ${why_msg}"
+        unsupported "couldn't compile [file tail $source]: ${why_msg}"
         return -1
     }
 }
 
 proc send_gdb { string } {
-    global suppress_flag;
+    global suppress_flag
     if { $suppress_flag } {
-       return "suppressed";
+       return "suppressed"
     }
-    return [remote_send host "$string"];
+    return [remote_send host "$string"]
 }
 
-#
-#
+# Send STRING to the inferior's terminal.
 
-proc gdb_expect { args } {
-    if { [llength $args] == 2  && [lindex $args 0] != "-re" } {
-       set atimeout [lindex $args 0];
-       set expcode [list [lindex $args 1]];
+proc send_inferior { string } {
+    global inferior_spawn_id
+
+    if {[catch "send -i $inferior_spawn_id -- \$string" errorInfo]} {
+       return "$errorInfo"
     } else {
-       set expcode $args;
+       return ""
     }
+}
 
-    upvar timeout timeout;
-
-    if [target_info exists gdb,timeout] {
-       if [info exists timeout] {
-           if { $timeout < [target_info gdb,timeout] } {
-               set gtimeout [target_info gdb,timeout];
-           } else {
-               set gtimeout $timeout;
-           }
-       } else {
-           set gtimeout [target_info gdb,timeout];
-       }
-    }
+#
+#
 
-    if ![info exists gtimeout] {
-       global timeout;
-       if [info exists timeout] {
-           set gtimeout $timeout;
-       }
+proc gdb_expect { args } {
+    if { [llength $args] == 2  && [lindex $args 0] != "-re" } {
+       set atimeout [lindex $args 0]
+       set expcode [list [lindex $args 1]]
+    } else {
+       set expcode $args
     }
 
+    # A timeout argument takes precedence, otherwise of all the timeouts
+    # select the largest.
     if [info exists atimeout] {
-       if { ![info exists gtimeout] || $gtimeout < $atimeout } {
-           set gtimeout $atimeout;
-       }
+       set tmt $atimeout
     } else {
-       if ![info exists gtimeout] {
-           # Eeeeew.
-           set gtimeout 60;
-       }
+       set tmt [get_largest_timeout]
     }
 
-    global suppress_flag;
-    global remote_suppress_flag;
+    global suppress_flag
+    global remote_suppress_flag
     if [info exists remote_suppress_flag] {
-       set old_val $remote_suppress_flag;
+       set old_val $remote_suppress_flag
     }
     if [info exists suppress_flag] {
        if { $suppress_flag } {
-           set remote_suppress_flag 1;
+           set remote_suppress_flag 1
        }
     }
     set code [catch \
-       {uplevel remote_expect host $gtimeout $expcode} string];
+       {uplevel remote_expect host $tmt $expcode} string]
     if [info exists old_val] {
-       set remote_suppress_flag $old_val;
+       set remote_suppress_flag $old_val
     } else {
        if [info exists remote_suppress_flag] {
-           unset remote_suppress_flag;
+           unset remote_suppress_flag
        }
     }
 
     if {$code == 1} {
-        global errorInfo errorCode;
+        global errorInfo errorCode
 
        return -code error -errorinfo $errorInfo -errorcode $errorCode $string
     } else {
@@ -2804,10 +4021,10 @@ proc gdb_expect_list {test sentinel list} {
 #
 #
 proc gdb_suppress_entire_file { reason } {
-    global suppress_flag;
+    global suppress_flag
 
-    warning "$reason\n";
-    set suppress_flag -1;
+    warning "$reason\n"
+    set suppress_flag -1
 }
 
 #
@@ -2816,17 +4033,17 @@ proc gdb_suppress_entire_file { reason } {
 # gdb_stop_suppressing_tests).
 #
 proc gdb_suppress_tests { args } {
-    global suppress_flag;
+    global suppress_flag
 
     return;  # fnf - disable pending review of results where
              # testsuite ran better without this
-    incr suppress_flag;
+    incr suppress_flag
 
     if { $suppress_flag == 1 } {
        if { [llength $args] > 0 } {
-           warning "[lindex $args 0]\n";
+           warning "[lindex $args 0]\n"
        } else {
-           warning "Because of previous failure, all subsequent tests in this group will automatically fail.\n";
+           warning "Because of previous failure, all subsequent tests in this group will automatically fail.\n"
        }
     }
 }
@@ -2835,24 +4052,60 @@ proc gdb_suppress_tests { args } {
 # Clear suppress_flag.
 #
 proc gdb_stop_suppressing_tests { } {
-    global suppress_flag;
+    global suppress_flag
 
     if [info exists suppress_flag] {
        if { $suppress_flag > 0 } {
-           set suppress_flag 0;
-           clone_output "Tests restarted.\n";
+           set suppress_flag 0
+           clone_output "Tests restarted.\n"
        }
     } else {
-       set suppress_flag 0;
+       set suppress_flag 0
     }
 }
 
 proc gdb_clear_suppressed { } {
-    global suppress_flag;
+    global suppress_flag
+
+    set suppress_flag 0
+}
+
+# Spawn the gdb process.
+#
+# This doesn't expect any output or do any other initialization,
+# leaving those to the caller.
+#
+# Overridable function -- you can override this function in your
+# baseboard file.
+
+proc gdb_spawn { } {
+    default_gdb_spawn
+}
+
+# Spawn GDB with CMDLINE_FLAGS appended to the GDBFLAGS global.
+
+proc gdb_spawn_with_cmdline_opts { cmdline_flags } {
+    global GDBFLAGS
+
+    set saved_gdbflags $GDBFLAGS
+
+    if {$GDBFLAGS != ""} {
+       append GDBFLAGS " "
+    }
+    append GDBFLAGS $cmdline_flags
 
-    set suppress_flag 0;
+    set res [gdb_spawn]
+
+    set GDBFLAGS $saved_gdbflags
+
+    return $res
 }
 
+# Start gdb running, wait for prompt, and disable the pagers.
+
+# Overridable function -- you can override this function in your
+# baseboard file.
+
 proc gdb_start { } {
     default_gdb_start
 }
@@ -2861,6 +4114,92 @@ proc gdb_exit { } {
     catch default_gdb_exit
 }
 
+# Return true if we can spawn a program on the target and attach to
+# it.
+
+proc can_spawn_for_attach { } {
+    # We use exp_pid to get the inferior's pid, assuming that gives
+    # back the pid of the program.  On remote boards, that would give
+    # us instead the PID of e.g., the ssh client, etc.
+    if [is_remote target] then {
+       return 0
+    }
+
+    # The "attach" command doesn't make sense when the target is
+    # stub-like, where GDB finds the program already started on
+    # initial connection.
+    if {[target_info exists use_gdb_stub]} {
+       return 0
+    }
+
+    # Assume yes.
+    return 1
+}
+
+# Kill a progress previously started with spawn_wait_for_attach, and
+# reap its wait status.  PROC_SPAWN_ID is the spawn id associated with
+# the process.
+
+proc kill_wait_spawned_process { proc_spawn_id } {
+    set pid [exp_pid -i $proc_spawn_id]
+
+    verbose -log "killing ${pid}"
+    remote_exec build "kill -9 ${pid}"
+
+    verbose -log "closing ${proc_spawn_id}"
+    catch "close -i $proc_spawn_id"
+    verbose -log "waiting for ${proc_spawn_id}"
+
+    # If somehow GDB ends up still attached to the process here, a
+    # blocking wait hangs until gdb is killed (or until gdb / the
+    # ptracer reaps the exit status too, but that won't happen because
+    # something went wrong.)  Passing -nowait makes expect tell Tcl to
+    # wait for the PID in the background.  That's fine because we
+    # don't care about the exit status.  */
+    wait -nowait -i $proc_spawn_id
+}
+
+# Returns the process id corresponding to the given spawn id.
+
+proc spawn_id_get_pid { spawn_id } {
+    set testpid [exp_pid -i $spawn_id]
+
+    if { [istarget "*-*-cygwin*"] } {
+       # testpid is the Cygwin PID, GDB uses the Windows PID, which
+       # might be different due to the way fork/exec works.
+       set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ]
+    }
+
+    return $testpid
+}
+
+# Start a set of programs running and then wait for a bit, to be sure
+# that they can be attached to.  Return a list of processes spawn IDs,
+# one element for each process spawned.  It's a test error to call
+# this when [can_spawn_for_attach] is false.
+
+proc spawn_wait_for_attach { executable_list } {
+    set spawn_id_list {}
+
+    if ![can_spawn_for_attach] {
+       # The caller should have checked can_spawn_for_attach itself
+       # before getting here.
+       error "can't spawn for attach with this target/board"
+    }
+
+    foreach {executable} $executable_list {
+       # Note we use Expect's spawn, not Tcl's exec, because with
+       # spawn we control when to wait for/reap the process.  That
+       # allows killing the process by PID without being subject to
+       # pid-reuse races.
+       lappend spawn_id_list [remote_spawn target $executable]
+    }
+
+    sleep 2
+
+    return $spawn_id_list
+}
+
 #
 # gdb_load_cmd -- load a file into the debugger.
 #                ARGS - additional args to load command.
@@ -2905,6 +4244,73 @@ proc gdb_load_cmd { args } {
     return -1
 }
 
+# Invoke "gcore".  CORE is the name of the core file to write.  TEST
+# is the name of the test case.  This will return 1 if the core file
+# was created, 0 otherwise.  If this fails to make a core file because
+# this configuration of gdb does not support making core files, it
+# will call "unsupported", not "fail".  However, if this fails to make
+# a core file for some other reason, then it will call "fail".
+
+proc gdb_gcore_cmd {core test} {
+    global gdb_prompt
+
+    set result 0
+    gdb_test_multiple "gcore $core" $test {
+       -re "Saved corefile .*\[\r\n\]+$gdb_prompt $" {
+           pass $test
+           set result 1
+       }
+       -re "(?:Can't create a corefile|Target does not support core file generation\\.)\[\r\n\]+$gdb_prompt $" {
+           unsupported $test
+       }
+    }
+
+    return $result
+}
+
+# Load core file CORE.  TEST is the name of the test case.
+# This will record a pass/fail for loading the core file.
+# Returns:
+#  1 - core file is successfully loaded
+#  0 - core file loaded but has a non fatal error
+# -1 - core file failed to load
+
+proc gdb_core_cmd { core test } {
+    global gdb_prompt
+
+    gdb_test_multiple "core $core" "$test" {
+       -re "\\\[Thread debugging using \[^ \r\n\]* enabled\\\]\r\n" {
+           exp_continue
+       }
+       -re " is not a core dump:.*\r\n$gdb_prompt $" {
+           fail "$test (bad file format)"
+           return -1
+       }
+       -re ": No such file or directory.*\r\n$gdb_prompt $" {
+           fail "$test (file not found)"
+           return -1
+       }
+       -re "Couldn't find .* registers in core file.*\r\n$gdb_prompt $" {
+           fail "$test (incomplete note section)"
+           return 0
+       }
+       -re "Core was generated by .*\r\n$gdb_prompt $" {
+           pass "$test"
+           return 1
+       }
+       -re ".*$gdb_prompt $" {
+           fail "$test"
+           return -1
+       }
+       timeout {
+           fail "$test (timeout)"
+           return -1
+       }
+    }
+    fail "unsupported output from 'core' command"
+    return -1
+}
+
 # Return the filename to download to the target and load on the target
 # for this shared library.  Normally just LIBNAME, unless shared libraries
 # for this target have separate link and load images.
@@ -2958,43 +4364,80 @@ proc gdb_touch_execfile { binfile } {
     }
 }
 
-# gdb_download
+# Like remote_download but provides a gdb-specific behavior.
+#
+# If the destination board is remote, the local file FROMFILE is transferred as
+# usual with remote_download to TOFILE on the remote board.  The destination
+# filename is added to the CLEANFILES global, so it can be cleaned up at the
+# end of the test.
 #
-# Copy a file to the remote target and return its target filename.
-# Schedule the file to be deleted at the end of this test.
+# If the destination board is local, the destination path TOFILE is passed
+# through standard_output_file, and FROMFILE is copied there.
+#
+# In both cases, if TOFILE is omitted, it defaults to the [file tail] of
+# FROMFILE.
 
-proc gdb_download { filename } {
-    global cleanfiles
+proc gdb_remote_download {dest fromfile {tofile {}}} {
+    # If TOFILE is not given, default to the same filename as FROMFILE.
+    if {[string length $tofile] == 0} {
+       set tofile [file tail $fromfile]
+    }
+
+    if {[is_remote $dest]} {
+       # When the DEST is remote, we simply send the file to DEST.
+       global cleanfiles
+
+       set destname [remote_download $dest $fromfile $tofile]
+       lappend cleanfiles $destname
+
+       return $destname
+    } else {
+       # 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]
 
-    set destname [remote_download target $filename]
-    lappend cleanfiles $destname
-    return $destname
+       file copy -force $fromfile $tofile
+
+       return $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_download [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
 }
 
 #
-# gdb_load -- load a file into the debugger.
+# gdb_load -- load a file into the debugger.  Specifying no file
+# defaults to the executable currently being debugged.
+# The return value is 0 for success, -1 for failure.
 # Many files in config/*.exp override this procedure.
 #
 proc gdb_load { arg } {
-    return [gdb_file_cmd $arg]
+    if { $arg != "" } {
+       return [gdb_file_cmd $arg]
+    }
+    return 0
 }
 
 # gdb_reload -- load a file into the target.  Called before "running",
@@ -3012,17 +4455,21 @@ proc gdb_reload { } {
 proc gdb_continue { function } {
     global decimal
 
-    return [gdb_test "continue" ".*Breakpoint $decimal, $function .*" "continue to $function"];
+    return [gdb_test "continue" ".*Breakpoint $decimal, $function .*" "continue to $function"]
 }
 
-proc default_gdb_init { args } {
+proc default_gdb_init { test_file_name } {
     global gdb_wrapper_initialized
     global gdb_wrapper_target
+    global gdb_test_file_name
     global cleanfiles
+    global pf_prefix
     
     set cleanfiles {}
 
-    gdb_clear_suppressed;
+    gdb_clear_suppressed
+
+    set gdb_test_file_name [file rootname [file tail $test_file_name]]
 
     # Make sure that the wrapper is rebuilt
     # with the appropriate multilib option.
@@ -3032,22 +4479,18 @@ proc default_gdb_init { args } {
     
     # Unlike most tests, we have a small number of tests that generate
     # a very large amount of output.  We therefore increase the expect
-    # buffer size to be able to contain the entire test output.
-    match_max -d 30000
+    # buffer size to be able to contain the entire test output.  This
+    # is especially needed by gdb.base/info-macros.exp.
+    match_max -d 65536
     # Also set this value for the currently running GDB. 
     match_max [match_max -d]
 
     # We want to add the name of the TCL testcase to the PASS/FAIL messages.
-    if { [llength $args] > 0 } {
-       global pf_prefix
+    set pf_prefix "[file tail [file dirname $test_file_name]]/[file tail $test_file_name]:"
 
-       set file [lindex $args 0];
-
-       set pf_prefix "[file tail [file dirname $file]]/[file tail $file]:";
-    }
-    global gdb_prompt;
+    global gdb_prompt
     if [target_info exists gdb_prompt] {
-       set gdb_prompt [target_info gdb_prompt];
+       set gdb_prompt [target_info gdb_prompt]
     } else {
        set gdb_prompt "\\(gdb\\)"
     }
@@ -3057,6 +4500,117 @@ proc default_gdb_init { args } {
     }
 }
 
+# Return a path using GDB_PARALLEL.
+# ARGS is a list of path elements to append to "$objdir/$GDB_PARALLEL".
+# GDB_PARALLEL must be defined, the caller must check.
+#
+# The default value for GDB_PARALLEL is, canonically, ".".
+# The catch is that tests don't expect an additional "./" in file paths so
+# omit any directory for the default case.
+# GDB_PARALLEL is written as "yes" for the default case in Makefile.in to mark
+# its special handling.
+
+proc make_gdb_parallel_path { args } {
+    global GDB_PARALLEL objdir
+    set joiner [list "file" "join" $objdir]
+    if { [info exists GDB_PARALLEL] && $GDB_PARALLEL != "yes" } {
+       lappend joiner $GDB_PARALLEL
+    }
+    set joiner [concat $joiner $args]
+    return [eval $joiner]
+}
+
+# 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 gdb_test_file_name
+
+    set dir [make_gdb_parallel_path outputs $subdir $gdb_test_file_name]
+    file mkdir $dir
+    return [file join $dir $basename]
+}
+
+# Return the name of a file in our standard temporary directory.
+
+proc standard_temp_file {basename} {
+    # Since a particular runtest invocation is only executing a single test
+    # file at any given time, we can use the runtest pid to build the
+    # path of the temp directory.
+    set dir [make_gdb_parallel_path temp [pid]]
+    file mkdir $dir
+    return [file join $dir $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).
@@ -3084,7 +4638,7 @@ set banned_procedures { strace }
 # if the banned variables and procedures are already traced.
 set banned_traced 0
 
-proc gdb_init { args } {
+proc gdb_init { test_file_name } {
     # Reset the timeout value to the default.  This way, any testcase
     # that changes the timeout value without resetting it cannot affect
     # the timeout used in subsequent testcases.
@@ -3092,6 +4646,36 @@ proc gdb_init { args } {
     global timeout
     set timeout $gdb_test_timeout
 
+    if { [regexp ".*gdb\.reverse\/.*" $test_file_name]
+        && [target_info exists gdb_reverse_timeout] } {
+       set timeout [target_info gdb_reverse_timeout]
+    }
+
+    # If GDB_INOTIFY is given, check for writes to '.'.  This is a
+    # debugging tool to help confirm that the test suite is
+    # parallel-safe.  You need "inotifywait" from the
+    # inotify-tools package to use this.
+    global GDB_INOTIFY inotify_pid
+    if {[info exists GDB_INOTIFY] && ![info exists inotify_pid]} {
+       global outdir tool inotify_log_file
+
+       set exclusions {outputs temp gdb[.](log|sum) cache}
+       set exclusion_re ([join $exclusions |])
+
+       set inotify_log_file [standard_temp_file inotify.out]
+       set inotify_pid [exec inotifywait -r -m -e move,create,delete . \
+                            --exclude $exclusion_re \
+                            |& tee -a $outdir/$tool.log $inotify_log_file &]
+
+       # Wait for the watches; hopefully this is long enough.
+       sleep 2
+
+       # Clear the log so that we don't emit a warning the first time
+       # we check it.
+       set fd [open $inotify_log_file w]
+       close $fd
+    }
+
     # Block writes to all banned variables, and invocation of all
     # banned procedures...
     global banned_variables
@@ -3129,7 +4713,7 @@ proc gdb_init { args } {
     setenv TERM "vt100"
 
     # Some tests (for example gdb.base/maint.exp) shell out from gdb to use
-    # grep.  Clear GREP_OPTIONS to make the behavoiur predictable, 
+    # grep.  Clear GREP_OPTIONS to make the behavior predictable,
     # especially having color output turned on can cause tests to fail.
     setenv GREP_OPTIONS ""
 
@@ -3138,10 +4722,12 @@ proc gdb_init { args } {
     set gdbserver_reconnect_p 1
     unset gdbserver_reconnect_p
 
-    return [eval default_gdb_init $args];
+    return [default_gdb_init $test_file_name]
 }
 
 proc gdb_finish { } {
+    global gdbserver_reconnect_p
+    global gdb_prompt
     global cleanfiles
 
     # Exit first, so that the files are no longer in use.
@@ -3188,19 +4774,19 @@ proc get_debug_format { } {
        -re "Compiled with (.*) debugging format.\r\n.*$gdb_prompt $" {
            set debug_format $expect_out(1,string)
            verbose "debug format is $debug_format"
-           return 1;
+           return 1
        }
        -re "No current source file.\r\n$gdb_prompt $" {
            perror "get_debug_format used when no current source file"
-           return 0;
+           return 0
        }
        -re "$gdb_prompt $" {
            warning "couldn't check debug format (no valid response)."
-           return 1;
+           return 1
        }
        timeout {
-           warning "couldn't check debug format (timeout)."
-           return 1;
+           warning "couldn't check debug format (timeout)."
+           return 1
        }
     }
 }
@@ -3224,20 +4810,12 @@ proc test_debug_format {format} {
 # expected to fail, 0 otherwise (or if it is unknown).  Must have
 # previously called get_debug_format.
 proc setup_xfail_format { format } {
-    set ret [test_debug_format $format];
+    set ret [test_debug_format $format]
 
     if {$ret} then {
        setup_xfail "*-*-*"
     }
-    return $ret;
-}
-
-# Like setup_kfail, but only call setup_kfail conditionally if
-# istarget[TARGET] returns true.
-proc setup_kfail_for_target { PR target } {
-    if { [istarget $target] } {
-       setup_kfail $PR $target
-    }
+    return $ret
 }
 
 # gdb_get_line_number TEXT [FILE]
@@ -3344,11 +4922,8 @@ proc gdb_get_line_number { text { file "" } } {
     return $found
 }
 
-# gdb_continue_to_end:
-#      The case where the target uses stubs has to be handled specially. If a
-#       stub is used, we set a breakpoint at exit because we cannot rely on
-#       exit() behavior of a remote target.
-# 
+# Continue the program until it ends.
+#
 # MSSG is the error message that gets printed.  If not given, a
 #      default is used.
 # COMMAND is the command to invoke.  If not given, "continue" is
@@ -3371,7 +4946,19 @@ proc gdb_continue_to_end {{mssg ""} {command continue} {allow_extra 0}} {
   } else {
       set extra ""
   }
-  if $use_gdb_stub {
+
+  # By default, we don't rely on exit() behavior of remote stubs --
+  # it's common for exit() to be implemented as a simple infinite
+  # loop, or a forced crash/reset.  For native targets, by default, we
+  # assume process exit is reported as such.  If a non-reliable target
+  # is used, we set a breakpoint at exit, and continue to that.
+  if { [target_info exists exit_is_reliable] } {
+      set exit_is_reliable [target_info exit_is_reliable]
+  } else {
+      set exit_is_reliable [expr ! $use_gdb_stub]
+  }
+
+  if { ! $exit_is_reliable } {
     if {![gdb_breakpoint "exit"]} {
       return 0
     }
@@ -3415,55 +5002,262 @@ 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;
+       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;
+    return 0
 }
 
 # Print a message and return true if a test should be skipped
 # due to lack of stdio support.
 
-proc gdb_skip_stdio_test { msg } {
-    if [target_info exists gdb,noinferiorio] {
-       verbose "Skipping test '$msg': no inferior i/o.";
-       return 1;
+proc gdb_skip_stdio_test { msg } {
+    if [target_info exists gdb,noinferiorio] {
+       verbose "Skipping test '$msg': no inferior i/o."
+       return 1
+    }
+    return 0
+}
+
+proc gdb_skip_bogus_test { msg } {
+    return 0
+}
+
+# Return true if a test should be skipped due to lack of XML support
+# in the host GDB.
+# 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
+    set xml_missing 0
+    gdb_test_multiple "set tdesc filename $xml_file" "" {
+       -re ".*XML support was disabled at compile time.*$gdb_prompt $" {
+           set xml_missing 1
+       }
+       -re ".*$gdb_prompt $" { }
+    }
+    gdb_exit
+    return $xml_missing
+}
+
+# Return true if argv[0] is available.
+
+gdb_caching_proc gdb_has_argv0 {
+    set result 0
+
+    # Set up, compile, and execute a test program to check whether
+    # argv[0] is available.
+    set src [standard_temp_file has_argv0[pid].c]
+    set exe [standard_temp_file has_argv0[pid].x]
+
+    gdb_produce_source $src {
+       int main (int argc, char **argv) {
+           return 0;
+       }
+    }
+
+    gdb_compile $src $exe executable {debug}
+
+    # Helper proc.
+    proc gdb_has_argv0_1 { exe } {
+       global srcdir subdir
+       global gdb_prompt hex
+
+       gdb_exit
+       gdb_start
+       gdb_reinitialize_dir $srcdir/$subdir
+       gdb_load "$exe"
+
+       # Set breakpoint on main.
+       gdb_test_multiple "break main" "break main" {
+           -re "Breakpoint.*${gdb_prompt} $" {
+           }
+           -re "${gdb_prompt} $" {
+               return 0
+           }
+       }
+
+       # Run to main.
+       gdb_run_cmd
+       gdb_test_multiple "" "run to main" {
+           -re "Breakpoint.*${gdb_prompt} $" {
+           }
+           -re "${gdb_prompt} $" {
+               return 0
+           }
+       }
+
+       set old_elements "200"
+       set test "show print elements"
+       gdb_test_multiple $test $test {
+           -re "Limit on string chars or array elements to print is (\[^\r\n\]+)\\.\r\n$gdb_prompt $" {
+               set old_elements $expect_out(1,string)
+           }
+       }
+       set old_repeats "200"
+       set test "show print repeats"
+       gdb_test_multiple $test $test {
+           -re "Threshold for repeated print elements is (\[^\r\n\]+)\\.\r\n$gdb_prompt $" {
+               set old_repeats $expect_out(1,string)
+           }
+       }
+       gdb_test_no_output "set print elements unlimited" ""
+       gdb_test_no_output "set print repeats unlimited" ""
+
+       set retval 0
+       # Check whether argc is 1.
+       gdb_test_multiple "p argc" "p argc" {
+           -re " = 1\r\n${gdb_prompt} $" {
+
+               gdb_test_multiple "p argv\[0\]" "p argv\[0\]" {
+                   -re " = $hex \".*[file tail $exe]\"\r\n${gdb_prompt} $" {
+                       set retval 1
+                   }
+                   -re "${gdb_prompt} $" {
+                   }
+               }
+           }
+           -re "${gdb_prompt} $" {
+           }
+       }
+       
+       gdb_test_no_output "set print elements $old_elements" ""
+       gdb_test_no_output "set print repeats $old_repeats" ""
+
+       return $retval
     }
-    return 0;
-}
-
-proc gdb_skip_bogus_test { msg } {
-    return 0;
-}
 
-# Return true if a test should be skipped due to lack of XML support
-# in the host GDB.
-# NOTE: This must be called while gdb is *not* running.
+    set result [gdb_has_argv0_1 $exe]
 
-proc gdb_skip_xml_test { } {
-    global gdb_prompt
-    global srcdir
-    global xml_missing_cached
+    gdb_exit
+    file delete $src
+    file delete $exe
 
-    if {[info exists xml_missing_cached]} {
-       return $xml_missing_cached
+    if { !$result
+      && ([istarget *-*-linux*]
+         || [istarget *-*-freebsd*] || [istarget *-*-kfreebsd*]
+         || [istarget *-*-netbsd*] || [istarget *-*-knetbsd*]
+         || [istarget *-*-openbsd*]
+         || [istarget *-*-darwin*]
+         || [istarget *-*-solaris*]
+         || [istarget *-*-aix*]
+         || [istarget *-*-gnu*]
+         || [istarget *-*-cygwin*] || [istarget *-*-mingw32*]
+         || [istarget *-*-*djgpp*] || [istarget *-*-go32*]
+         || [istarget *-wince-pe] || [istarget *-*-mingw32ce*]
+         || [istarget *-*-symbianelf*]
+         || [istarget *-*-osf*]
+         || [istarget *-*-dicos*]
+         || [istarget *-*-nto*]
+         || [istarget *-*-*vms*]
+         || [istarget *-*-lynx*178]) } {
+       fail "argv\[0\] should be available on this target"
     }
 
-    gdb_start
-    set xml_missing_cached 0
-    gdb_test_multiple "set tdesc filename ${srcdir}/gdb.xml/trivial.xml" "" {
-       -re ".*XML support was disabled at compile time.*$gdb_prompt $" {
-           set xml_missing_cached 1
-       }
-       -re ".*$gdb_prompt $" { }
-    }
-    gdb_exit
-    return $xml_missing_cached
+    return $result
 }
 
 # Note: the procedure gdb_gnu_strip_debug will produce an executable called
@@ -3482,33 +5276,55 @@ proc gdb_skip_xml_test { } {
 # foo.debug --> foo's debug info
 # foo --> like foo, but with a new .gnu_debuglink section pointing to foo.debug.
 
+# Fetch the build id from the file.
+# Returns "" if there is none.
+
+proc get_build_id { filename } {
+    if { ([istarget "*-*-mingw*"]
+         || [istarget *-*-cygwin*]) } {
+       set objdump_program [gdb_find_objdump]
+       set result [catch {set data [exec $objdump_program -p $filename | grep signature | cut "-d " -f4]} output]
+       verbose "result is $result"
+       verbose "output is $output"
+       if {$result == 1} {
+           return ""
+       }
+       return $data
+    } else {
+       set tmp [standard_output_file "${filename}-tmp"]
+       set objcopy_program [gdb_find_objcopy]
+       set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $filename $tmp" output]
+       verbose "result is $result"
+       verbose "output is $output"
+       if {$result == 1} {
+           return ""
+       }
+       set fi [open $tmp]
+       fconfigure $fi -translation binary
+       # Skip the NOTE header.
+       read $fi 16
+       set data [read $fi]
+       close $fi
+       file delete $tmp
+       if ![string compare $data ""] then {
+           return ""
+       }
+       # Convert it to hex.
+       binary scan $data H* data
+       return $data
+    }
+}
+
 # Return the build-id hex string (usually 160 bits as 40 hex characters)
 # converted to the form: .build-id/ab/cdef1234...89.debug
 # Return "" if no build-id found.
-proc build_id_debug_filename_get { exec } {
-    set tmp "${exec}-tmp"
-    set objcopy_program [transform objcopy]
-
-    set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $exec $tmp" output]
-    verbose "result is $result"
-    verbose "output is $output"
-    if {$result == 1} {
+proc build_id_debug_filename_get { filename } {
+    set data [get_build_id $filename]
+    if { $data == "" } {
        return ""
     }
-    set fi [open $tmp]
-    fconfigure $fi -translation binary
-    # Skip the NOTE header.
-    read $fi 16
-    set data [read $fi]
-    close $fi
-    file delete $tmp
-    if ![string compare $data ""] then {
-       return ""
-    }
-    # Convert it to hex.
-    binary scan $data H* data
     regsub {^..} $data {\0/} data
-    return ".build-id/${data}.debug";
+    return ".build-id/${data}.debug"
 }
 
 # Create stripped files for DEST, replacing it.  If ARGS is passed, it is a
@@ -3525,7 +5341,7 @@ proc gdb_gnu_strip_debug { dest args } {
     set debug_file "${dest}.debug"
 
     set strip_to_file_program [transform strip]
-    set objcopy_program [transform objcopy]
+    set objcopy_program [gdb_find_objcopy]
 
     set debug_link [file tail $debug_file]
     set stripped_file "${dest}.stripped"
@@ -3606,11 +5422,13 @@ proc help_test_raw { gdb_command expected_lines args } {
 # 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.
+# 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 } {
     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\]+"
+        "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]
@@ -3647,58 +5465,141 @@ 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.  If OPTIONS
+# contains the option "pthreads", then gdb_compile_pthreads is used.
+# 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] != "" } {
-            untested $testname
-            return -1
-        }
-        lappend objects "${binfile}${i}.o"
+    set info_options ""
+    if { [lsearch -exact $options "c++"] >= 0 } {
+       set info_options "c++"
     }
-    
-    if  { [gdb_compile $objects "${binfile}" executable $options] != "" } {
-        untested $testname
+    if [get_compiler_info ${info_options}] {
         return -1
     }
 
-    set info_options ""
-    if { [lsearch -exact $options "c++"] >= 0 } {
-       set info_options "c++"
+    set func gdb_compile
+    set func_index [lsearch -regexp $options {^(pthreads|shlib|shlib_pthreads)$}]
+    if {$func_index != -1} {
+       set func "${func}_[lindex $options $func_index]"
+    }
+
+    # gdb_compile_shlib and gdb_compile_shlib_pthreads do not use the 3rd
+    # parameter.  They also requires $sources while gdb_compile and
+    # gdb_compile_pthreads require $objects.  Moreover they ignore any options.
+    if [string match gdb_compile_shlib* $func] {
+       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 [$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
+       foreach {s local_options} $args {
+           if { ! [regexp "^/" "$s"] } then {
+               set s "$srcdir/$subdir/$s"
+           }
+           if  { [gdb_compile "${s}" "${binfile}${i}.o" object $local_options] != "" } {
+               untested $testname
+               return -1
+           }
+           lappend objects "${binfile}${i}.o"
+           incr i
+       }
+       set ret [$func $objects "${binfile}" executable $options]
     }
-    if [get_compiler_info ${binfile} ${info_options}] {
+    if  { $ret != "" } {
+        untested $testname
         return -1
     }
+
     return 0
 }
 
-# Starts fresh GDB binary and loads EXECUTABLE into GDB. EXECUTABLE is
-# the name of binary in ${objdir}/${subdir}.
-proc clean_restart { executable } {
+# 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 an optional executable into GDB.
+# Usage: clean_restart [executable]
+# EXECUTABLE is the basename of the binary.
+
+proc clean_restart { args } {
     global srcdir
-    global objdir
     global subdir
-    set binfile ${objdir}/${subdir}/${executable}
+
+    if { [llength $args] > 1 } {
+       error "bad number of args: [llength $args]"
+    }
 
     gdb_exit
     gdb_start
     gdb_reinitialize_dir $srcdir/$subdir
-    gdb_load ${binfile}
+
+    if { [llength $args] >= 1 } {
+       set executable [lindex $args 0]
+       set binfile [standard_output_file ${executable}]
+       gdb_load ${binfile}
+    }
+}
+
+# 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.
@@ -3713,13 +5614,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)"
        }
@@ -3730,15 +5639,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)"
@@ -3747,25 +5664,75 @@ 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 { } {
+    global gdb_prompt
+
+    gdb_test_multiple "show target-charset" "" {
+       -re "The target character set is \"auto; currently (\[^\"\]*)\".*$gdb_prompt $" {
+           return $expect_out(1,string)
+       }
+       -re "The target character set is \"(\[^\"\]*)\".*$gdb_prompt $" {
+           return $expect_out(1,string)
+       }
+    }
+
+    # Pick a reasonable default.
+    warning "Unable to read 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 ""
 }
 
 # Get the current value for remotetimeout and return it.
@@ -3775,7 +5742,7 @@ proc get_remotetimeout { } {
 
     gdb_test_multiple "show remotetimeout" "" {
        -re "Timeout limit to wait for target to respond is ($decimal).*$gdb_prompt $" {
-           return $expect_out(1,string);
+           return $expect_out(1,string)
        }
     }
 
@@ -3795,6 +5762,38 @@ 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
+# will return "ls".
+
+proc relative_filename {root full} {
+    set root_split [file split $root]
+    set full_split [file split $full]
+
+    set len [llength $root_split]
+
+    if {[eval file join $root_split]
+       != [eval file join [lrange $full_split 0 [expr {$len - 1}]]]} {
+       error "$full not a subdir of $root"
+    }
+
+    return [eval file join [lrange $full_split $len end]]
+}
+
 # Log gdb command line and script if requested.
 if {[info exists TRANSCRIPT]} {
   rename send_gdb real_send_gdb
@@ -3842,6 +5841,18 @@ if {[info exists TRANSCRIPT]} {
   }
 }
 
+# If GDB_PARALLEL exists, then set up the parallel-mode directories.
+if {[info exists GDB_PARALLEL]} {
+    if {[is_remote host]} {
+       unset GDB_PARALLEL
+    } else {
+       file mkdir \
+           [make_gdb_parallel_path outputs] \
+           [make_gdb_parallel_path temp] \
+           [make_gdb_parallel_path cache]
+    }
+}
+
 proc core_find {binfile {deletefiles {}} {arg ""}} {
     global objdir subdir
 
@@ -3862,7 +5873,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}"
@@ -3909,18 +5920,276 @@ proc core_find {binfile {deletefiles {}} {arg ""}} {
     return $destcore
 }
 
-# gdb_target_symbol_prefix_flags returns a string that can be added
-# to gdb_compile options to define SYMBOL_PREFIX macro value
-# symbol_prefix_flags returns a string that can be added
-# for targets that use underscore as symbol prefix.
-# TODO: find out automatically if the target needs this.
+# gdb_target_symbol_prefix compiles a test program and then examines
+# the output from objdump to determine the prefix (such as underscore)
+# for linker symbol prefixes.
+
+gdb_caching_proc gdb_target_symbol_prefix {
+    # Set up and compile a simple test program...
+    set src [standard_temp_file main[pid].c]
+    set exe [standard_temp_file main[pid].x]
+
+    gdb_produce_source $src {
+       int main() {
+           return 0;
+       }
+    }
+
+    verbose "compiling testfile $src" 2
+    set compile_flags {debug nowarnings quiet}
+    set lines [gdb_compile $src $exe executable $compile_flags]
+
+    set prefix ""
+
+    if ![string match "" $lines] then {
+        verbose "gdb_target_symbol_prefix: testfile compilation failed, returning null prefix" 2
+    } else {
+       set objdump_program [gdb_find_objdump]
+       set result [catch "exec $objdump_program --syms $exe" output]
+
+       if { $result == 0 \
+            && ![regexp -lineanchor \
+                 { ([^ a-zA-Z0-9]*)main$} $output dummy prefix] } {
+           verbose "gdb_target_symbol_prefix: Could not find main in objdump output; returning null prefix" 2
+       }
+    }
+
+    file delete $src
+    file delete $exe
+
+    return $prefix
+}
+
+# gdb_target_symbol returns the provided symbol with the correct prefix
+# prepended.  (See gdb_target_symbol_prefix, above.)
+
+proc gdb_target_symbol { symbol } {
+  set prefix [gdb_target_symbol_prefix]
+  return "${prefix}${symbol}"
+}
+
+# gdb_target_symbol_prefix_flags_asm returns a string that can be
+# added to gdb_compile options to define the C-preprocessor macro
+# SYMBOL_PREFIX with a value that can be prepended to symbols
+# for targets which require a prefix, such as underscore.
+#
+# This version (_asm) defines the prefix without double quotes
+# surrounding the prefix.  It is used to define the macro
+# SYMBOL_PREFIX for assembly language files.  Another version, below,
+# is used for symbols in inline assembler in C/C++ files.
+# 
+# The lack of quotes in this version (_asm) makes it possible to
+# define supporting macros in the .S file.  (The version which
+# uses quotes for the prefix won't work for such files since it's
+# impossible to define a quote-stripping macro in C.)
+#
+# It's possible to use this version (_asm) for C/C++ source files too,
+# but a string is usually required in such files; providing a version
+# (no _asm) which encloses the prefix with double quotes makes it
+# somewhat easier to define the supporting macros in the test case.
+
+proc gdb_target_symbol_prefix_flags_asm {} {
+    set prefix [gdb_target_symbol_prefix]
+    if {$prefix ne ""} {
+       return "additional_flags=-DSYMBOL_PREFIX=$prefix"
+    } else {
+       return "";
+    }
+}
+
+# gdb_target_symbol_prefix_flags returns the same string as
+# gdb_target_symbol_prefix_flags_asm, above, but with the prefix
+# enclosed in double quotes if there is a prefix.
+#
+# See the comment for gdb_target_symbol_prefix_flags_asm for an
+# extended discussion.
 
 proc gdb_target_symbol_prefix_flags {} {
-    if { [istarget "*-*-cygwin*"] || [istarget "i?86-*-mingw*"]
-        || [istarget "*-*-msdosdjgpp*"] || [istarget "*-*-go32*"] } {
-       return "additional_flags=-DSYMBOL_PREFIX=\"_\""
+    set prefix [gdb_target_symbol_prefix]
+    if {$prefix ne ""} {
+       return "additional_flags=-DSYMBOL_PREFIX=\"$prefix\""
     } else {
-       return ""
+       return "";
+    }
+}
+
+# A wrapper for 'remote_exec host' that passes or fails a test.
+# Returns 0 if all went well, nonzero on failure.
+# TEST is the name of the test, other arguments are as for remote_exec.
+
+proc run_on_host { test program args } {
+    verbose -log "run_on_host: $program $args"
+    # remote_exec doesn't work properly if the output is set but the
+    # input is the empty string -- so replace an empty input with
+    # /dev/null.
+    if {[llength $args] > 1 && [lindex $args 1] == ""} {
+       set args [lreplace $args 1 1 "/dev/null"]
+    }
+    set result [eval remote_exec host [list $program] $args]
+    verbose "result is $result"
+    set status [lindex $result 0]
+    set output [lindex $result 1]
+    if {$status == 0} {
+       pass $test
+       return 0
+    } else {
+       verbose -log "run_on_host failed: $output"
+       fail $test
+       return -1
+    }
+}
+
+# Return non-zero if "board_info debug_flags" mentions Fission.
+# http://gcc.gnu.org/wiki/DebugFission
+# Fission doesn't support everything yet.
+# This supports working around bug 15954.
+
+proc using_fission { } {
+    set debug_flags [board_info [target_info name] debug_flags]
+    return [regexp -- "-gsplit-dwarf" $debug_flags]
+}
+
+# Search the caller's ARGS list and set variables according to the list of
+# valid options described by ARGSET.
+#
+# The first member of each one- or two-element list in ARGSET defines the
+# name of a variable that will be added to the caller's scope.
+#
+# If only one element is given to describe an option, it the value is
+# 0 if the option is not present in (the caller's) ARGS or 1 if
+# it is.
+#
+# If two elements are given, the second element is the default value of
+# the variable.  This is then overwritten if the option exists in ARGS.
+#
+# Any parse_args elements in (the caller's) ARGS will be removed, leaving
+# any optional components.
+
+# Example:
+# proc myproc {foo args} {
+#  parse_args {{bar} {baz "abc"} {qux}}
+#    # ...
+# }
+# myproc ABC -bar -baz DEF peanut butter
+# will define the following variables in myproc:
+# foo (=ABC), bar (=1), baz (=DEF), and qux (=0)
+# args will be the list {peanut butter}
+
+proc parse_args { argset } {
+    upvar args args
+
+    foreach argument $argset {
+        if {[llength $argument] == 1} {
+            # No default specified, so we assume that we should set
+            # the value to 1 if the arg is present and 0 if it's not.
+            # It is assumed that no value is given with the argument.
+            set result [lsearch -exact $args "-$argument"]
+            if {$result != -1} then {
+                uplevel 1 [list set $argument 1]
+                set args [lreplace $args $result $result]
+            } else {
+                uplevel 1 [list set $argument 0]
+            }
+        } elseif {[llength $argument] == 2} {
+            # There are two items in the argument.  The second is a
+            # default value to use if the item is not present.
+            # Otherwise, the variable is set to whatever is provided
+            # after the item in the args.
+            set arg [lindex $argument 0]
+            set result [lsearch -exact $args "-[lindex $arg 0]"]
+            if {$result != -1} then {
+                uplevel 1 [list set $arg [lindex $args [expr $result+1]]]
+                set args [lreplace $args $result [expr $result+1]]
+            } else {
+                uplevel 1 [list set $arg [lindex $argument 1]]
+            }
+        } else {
+            error "Badly formatted argument \"$argument\" in argument set"
+        }
+    }
+
+    # The remaining args should be checked to see that they match the
+    # number of items expected to be passed into the procedure...
+}
+
+# Capture the output of COMMAND in a string ignoring PREFIX (a regexp);
+# return that string.
+
+proc capture_command_output { command prefix } {
+    global gdb_prompt
+    global expect_out
+
+    set output_string ""
+    gdb_test_multiple "$command" "capture_command_output for $command" {
+       -re "[string_to_regexp ${command}]\[\r\n\]+${prefix}(.*)\[\r\n\]+$gdb_prompt $" {
+           set output_string $expect_out(1,string)
+       }
+    }
+    return $output_string
+}
+
+# A convenience function that joins all the arguments together, with a
+# regexp that matches exactly one end of line in between each argument.
+# This function is ideal to write the expected output of a GDB command
+# that generates more than a couple of lines, as this allows us to write
+# each line as a separate string, which is easier to read by a human
+# being.
+
+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 " {
+               }
+           }
+       }
     }
 }
 
This page took 0.080096 seconds and 4 git commands to generate.