diff --git a/gdb/testsuite/gdb.base/annota1.exp b/gdb/testsuite/gdb.base/annota1.exp
index 2d4737f533f..086b8f6a2f6 100644
--- a/gdb/testsuite/gdb.base/annota1.exp
+++ b/gdb/testsuite/gdb.base/annota1.exp
@@ -15,7 +15,6 @@
 
 # This file was written by Elena Zannoni (ezannoni@cygnus.com)
 
-
 # This testcase cannot use runto_main because of the different prompt
 # we get when using annotation level 2.
 #
@@ -97,11 +96,11 @@ gdb_expect {
 #
 gdb_test_multiple "info break" "breakpoint info" {
     -re "\r\n\032\032post-prompt\r\n\r\n\032\032breakpoints-headers\r\n\r\n\032\032field 0\r\nNum     \r\n\032\032field 1\r\nType           \r\n\032\032field 2\r\nDisp \r\n\032\032field 3\r\nEnb \r\n\032\032field 4\r\nAddress    +\r\n\032\032field 5\r\nWhat\r\n\r\n\032\032breakpoints-table\r\n\r\n\032\032record\r\n\r\n\032\032field 0\r\n1       \r\n\032\032field 1\r\nbreakpoint     \r\n\032\032field 2\r\nkeep \r\n\032\032field 3\r\ny   \r\n\032\032field 4\r\n$hex +\r\n\032\032field 5\r\nin main at ${escapedsrcfile}:$main_line\r\n\r\n\032\032breakpoints-table-end\r\n$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
     -re "\r\n\032\032post-prompt\r\n\r\n\032\032breakpoints-headers\r\n\r\n\032\032field 0\r\nNum     \r\n\032\032field 1\r\nType           \r\n\032\032field 2\r\nDisp \r\n\032\032field 3\r\nEnb \r\n\032\032field 4\r\nAddress    +\r\n\032\032field 5\r\nWhat\r\n\r\n\032\032breakpoints-table\r\n\r\n\032\032record\r\n\r\n\032\032field 0\r\n1       \r\n\032\032field 1\r\nbreakpoint     \r\n\032\032field 2\r\nkeep \r\n\032\032field 3\r\ny   \r\n\032\032field 4\r\n$hex +\r\n\032\032field 5\r\nin main at .*${srcfile}:$main_line\r\n\r\n\032\032breakpoints-table-end\r\n$gdb_prompt$" {
 	setup_xfail "*-*-*" 1270
-	fail $gdb_test_name
+	fail [gdb_test_name]
     }
 }
 
@@ -147,7 +146,7 @@ gdb_test_multiple "run" "run until main breakpoint" {
 		    "\032\032source.*$srcfile:$main_line:.*:beg:$hex\r\n\r\n" \
 		    "\032\032frame-end\r\n\r\n" \
 		    "\032\032stopped.*$gdb_prompt$" } ] {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 #exp_internal 0
@@ -160,7 +159,7 @@ gdb_test_multiple "run" "run until main breakpoint" {
 #
 gdb_test_multiple "next" "go after array init line" {
     -re "source .*annota1.c.*$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
@@ -179,7 +178,7 @@ gdb_test_multiple "next" "go after array init line" {
 #
 gdb_test_multiple "print my_array" "print array" {
     -re "\r\n\032\032post-prompt\r\n\r\n\032\032value-history-begin 1 -\r\n.*= \r\n\032\032value-history-value\r\n.\r\n\032\032array-section-begin 0 -\r\n1\r\n\032\032elt\r\n, 2\r\n\032\032elt\r\n, 3\r\n\032\032elt\r\n\r\n\032\032array-section-end\r\n.\r\n\r\n\032\032value-history-end\r\n$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
@@ -193,7 +192,7 @@ gdb_test_multiple "print my_array" "print array" {
 #exp_internal 1
 gdb_test_multiple "print non_existent_value" "print non_existent_value" {
     -re "\r\n\032\032post-prompt\r\n\r\n\032\032error-begin\r\nNo symbol \"non_existent_value\" in current context.\r\n\r\n\032\032error\r\n$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
@@ -204,7 +203,7 @@ gdb_test_multiple "print non_existent_value" "print non_existent_value" {
 #
 gdb_test_multiple "break handle_USR1" "break handle_USR1" {
     -re  "\r\n\032\032post-prompt\r\nBreakpoint.*at $hex: file.*$srcfile, line.*\r\n\032\032breakpoints-invalid\r\n.*$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
@@ -213,10 +212,10 @@ gdb_test_multiple "break handle_USR1" "break handle_USR1" {
 #
 gdb_test_multiple "break printf" "break printf" {
     -re  "\r\n\032\032post-prompt\r\nBreakpoint.*at $hex.*\032\032breakpoints-invalid\r\n.*$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
     -re  "\r\n\032\032post-prompt\r\nwarning: Breakpoint address adjusted from $hex to $hex.\r\n\r\n\032\032breakpoints-invalid\r\nBreakpoint.*at $hex.*$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
@@ -229,9 +228,9 @@ set pat_end "\r\n\032\032breakpoint 3\r\n\r\nBreakpoint 3, \r\n\032\032frame-beg
 
 gdb_test_multiple "continue" "continue to printf" {
     -re "${pat_begin}($pat_adjust)?$pat_end" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
-    -re ".*$gdb_prompt$"     { fail $gdb_test_name }
+    -re ".*$gdb_prompt$"     { fail [gdb_test_name] }
 }
 
 #
@@ -246,11 +245,11 @@ set pat_end "\r\n\032\032frame-source-file-end\r\n:\r\n\032\032frame-source-line
 
 gdb_test_multiple "backtrace" "backtrace from shlibrary" {
     -re "$pat_begin$escapedsrcfile$pat_end" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
     -re "$pat_begin.*$srcfile$pat_end" {
 	setup_xfail "*-*-*" 1270
-	fail $gdb_test_name
+	fail [gdb_test_name]
     }
 }
 
@@ -269,11 +268,11 @@ if [target_info exists gdb,nosignals] {
 } else {
     gdb_test_multiple "signal SIGUSR1" "send SIGUSR1" {
 	-re "\r\n\032\032post-prompt\r\nContinuing with signal SIGUSR1.\r\n\r\n\032\032starting\(\(\r\n\r\n\032\032frames-invalid\)|\(\r\n\r\n\032\032breakpoints-invalid\)\)+\r\n\r\n\032\032breakpoint 2\r\n\r\nBreakpoint 2, \r\n\032\032frame-begin 0 $hex\r\n\r\n\032\032frame-function-name\r\nhandle_USR1\r\n\032\032frame-args\r\n \\(\r\n\032\032arg-begin\r\nsig\r\n\032\032arg-name-end\r\n=\r\n\032\032arg-value -\r\n$decimal\r\n\032\032arg-end\r\n\\)\r\n\032\032frame-source-begin\r\n at \r\n\032\032frame-source-file\r\n${escapedsrcfile}\r\n\032\032frame-source-file-end\r\n:\r\n\032\032frame-source-line\r\n.*\r\n\032\032frame-source-end\r\n\r\n\r\n\032\032source.*annota1.c:.*:.*:beg:$hex\r\n$decimal\[^\r\n\]+\r\n\r\n\032\032frame-end\r\n\r\n\032\032stopped\r\n$gdb_prompt$" {
-	    pass $gdb_test_name
+	    pass [gdb_test_name]
 	}
 	-re "\r\n\032\032post-prompt\r\nContinuing with signal SIGUSR1.\r\n\r\n\032\032starting\(\(\r\n\r\n\032\032frames-invalid\)|\(\r\n\r\n\032\032breakpoints-invalid\)\)+\r\n\r\n\032\032breakpoint 2\r\n\r\nBreakpoint 2, \r\n\032\032frame-begin 0 $hex\r\n\r\n\032\032frame-function-name\r\nhandle_USR1\r\n\032\032frame-args\r\n \\(\r\n\032\032arg-begin\r\nsig\r\n\032\032arg-name-end\r\n=\r\n\032\032arg-value -\r\n$decimal\r\n\032\032arg-end\r\n\\)\r\n\032\032frame-source-begin\r\n at \r\n\032\032frame-source-file\r\n.*${srcfile}\r\n\032\032frame-source-file-end\r\n:\r\n\032\032frame-source-line\r\n.*\r\n\032\032frame-source-end\r\n\r\n\r\n\032\032source.*annota1.c:.*:.*:beg:$hex\r\n$decimal\[^\r\n\]+\r\n\r\n\032\032frame-end\r\n\r\n\032\032stopped\r\n$gdb_prompt$" {
 	    setup_xfail "*-*-*" 1270
-	    fail $gdb_test_name
+	    fail [gdb_test_name]
 	}
     }
 
@@ -283,7 +282,7 @@ if [target_info exists gdb,nosignals] {
     #
     gdb_test_multiple "backtrace" "backtrace @ signal handler" {
 	-re "frame-begin 0 $hex\r\n#0.*frame-end.*frame-begin 1 $hex\r\n#1.*(\032\032signal-handler-caller\r\n.signal handler called.\r\n\r\n)+\032\032frame-end\r\n\r\n\032\032frame-begin 2 $hex\r\n#2.*(frame-begin 3 $hex\r\n#3.*)*frame-end.*$gdb_prompt$" {
-	    pass $gdb_test_name
+	    pass [gdb_test_name]
 	}
     }
 }
@@ -293,19 +292,19 @@ if [target_info exists gdb,nosignals] {
 #
 gdb_test_multiple "delete 1" "delete bp 1" {
     -re "\r\n\032\032post-prompt\r\n${breakpoints_invalid}$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
 gdb_test_multiple "delete 2" "delete bp 2" {
     -re "\r\n\032\032post-prompt\r\n${breakpoints_invalid}$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
 gdb_test_multiple "delete 3" "delete bp 3" {
     -re "\r\n\032\032post-prompt\r\n${breakpoints_invalid}$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
@@ -315,11 +314,11 @@ gdb_test_multiple "delete 3" "delete bp 3" {
 #
 gdb_test_multiple "break ${srcfile}:${main_line}" "break in main" {
     -re "post-prompt.*Breakpoint 4 at $hex: file ${escapedsrcfile}, line $main_line.*\032\032breakpoints-invalid.*$gdb_prompt$" {
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
     -re "post-prompt.*Breakpoint 4 at $hex: file .*${srcfile}, line $main_line.*\032\032breakpoints-invalid.*$gdb_prompt$" {
 	setup_xfail "*-*-*" 1270
-	fail $gdb_test_name
+	fail [gdb_test_name]
     }
 }
 
@@ -408,7 +407,7 @@ set pid -1
 gdb_test_multiple "info inferior 1" "get inferior pid" {
     -re "process (\[0-9\]*).*$gdb_prompt$" {
 	set pid $expect_out(1,string)
-	pass $gdb_test_name
+	pass [gdb_test_name]
     }
 }
 
@@ -427,7 +426,7 @@ if [target_info exists gdb,nosignals] {
 } else {
     gdb_test_multiple "signal SIGTRAP" "signal sent" {
 	-re ".*\032\032post-prompt\r\nContinuing with signal SIGTRAP.\r\n\r\n\032\032starting\(\r\n\r\n\032\032frames-invalid\)+\r\n\r\n\032\032signalled\r\n\r\nProgram terminated with signal \r\n\032\032signal-name\r\nSIGTRAP\r\n\032\032signal-name-end\r\n, \r\n\032\032signal-string\r\nTrace.breakpoint trap\r\n\032\032signal-string-end\r\n.\r\nThe program no longer exists.\r\n\r\n\032\032thread-exited,id=\"${decimal}\",group-id=\"i${decimal}\"\r\n\r\n\032\032stopped\r\n$gdb_prompt$" {
-	    pass $gdb_test_name
+	    pass [gdb_test_name]
 	}
     }
 }
@@ -480,13 +479,13 @@ proc thread_test {} {
 
 	gdb_test_multiple "continue" "new thread" {
 	    -re "\032\032new-thread.*\r\n$gdb_prompt$" {
-		pass $gdb_test_name
+		pass [gdb_test_name]
 	    }
 	}
 
     gdb_test_multiple "continue" "thread exit" {
 	    -re "\032\032thread-exited,id=\"${decimal}\",group-id=\"i${decimal}\".*\r\n$gdb_prompt$" {
-		pass $gdb_test_name
+		pass [gdb_test_name]
 	    }
     }
     }
@@ -495,7 +494,7 @@ proc thread_test {} {
 proc thread_switch {} {
     gdb_test_multiple "thread 1" "thread switch" {
 	-re ".*\032\032thread-changed" {
-	    pass $gdb_test_name
+	    pass [gdb_test_name]
 	}
     }
 }
diff --git a/gdb/testsuite/lib/data-structures.exp b/gdb/testsuite/lib/data-structures.exp
index 5c136d329c5..fac9195320a 100644
--- a/gdb/testsuite/lib/data-structures.exp
+++ b/gdb/testsuite/lib/data-structures.exp
@@ -103,8 +103,24 @@ namespace eval ::Stack {
 	}
     }
 
+    proc at {oid idx} {
+	variable data_
+
+	error_if $oid
+	if {[llength $data_($oid)] < $idx} {
+	    ::error "stack index out of range"
+	}
+
+	verbose -log "Got: $data_($oid)"
+
+	# We need to index from the far end of the array, as that is
+	# where the most recent elements are.
+	set idx [expr [llength $data_($oid)] - $idx - 1]
+	return [lindex $data_($oid) $idx]
+    }
+
     # Export procs to be used.
-    namespace export empty push pop new delete length error_if
+    namespace export empty push pop new delete length error_if at
 
     # Create an ensemble command to use instead of requiring users
     # to type namespace proc names.
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index a35c3d75516..3471007c1ee 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -29,6 +29,7 @@ load_lib libgloss.exp
 load_lib cache.exp
 load_lib gdb-utils.exp
 load_lib memory.exp
+load_lib data-structures.exp
 
 global GDB
 
@@ -694,6 +695,41 @@ proc gdb_internal_error_resync {} {
     return 0
 }
 
+# Global stack used to track current nested calls to gdb_test_multiple.
+set gdb_test_name_stack [::Stack::new]
+
+# Returns the MESSAGE that was passed to gdb_test_multiple.  By
+# default (with no arguments) this returns the MESSAGE from the last
+# call to gdb_test_multiple.  Positive integer arguments index into
+# previously nested calls.  For example, this is the most common use case:
+#
+# gdb_test_multiple "command" "message" {
+#   -re "pattern" {
+#     pass [gdb_test_name]
+#   }
+# }
+#
+# In this case you would expect to see 'PASS: script.exp: message".
+#
+# The INDEX argument can be used like this:
+#
+# gdb_test_multiple "command" "message" {
+#   -re "pattern" {
+#     gdb_test_multiple "another_command" "" {
+#       -re "another_pattern" {
+#         pass [gdb_test_name 1]
+#       }
+#     }
+#   }
+# }
+#
+# In this case you would expect to see "PASS: script.exp: message",
+# even though the pass is actually coming from the nested call to
+# gdb_test_multiple.
+proc gdb_test_name {{index 0}} {
+    global gdb_test_name_stack
+    return [stack at $gdb_test_name_stack $index]
+}
 
 # gdb_test_multiple COMMAND MESSAGE EXPECT_ARGUMENTS PROMPT_REGEXP
 # Send a command to gdb; test the result.
@@ -726,17 +762,17 @@ proc gdb_internal_error_resync {} {
 #    }
 # }
 #
-# Within action elements you can also make use of the variable
-# gdb_test_name, this variable is setup automatically by
-# gdb_test_multiple, and contains the value of MESSAGE.  You can then
-# write this, which is equivalent to the above:
+# Within action elements you can also make use of the procedure
+# gdb_test_name, this returns the MESSAGE that was passed to the last
+# call to gdb_test_multiple.  You can then write this, which is
+# equivalent to the above:
 #
 # gdb_test_multiple "print foo" "test foo" {
 #    -re "expected output 1" {
-#        pass $gdb_test_name
+#        pass [gdb_test_name]
 #    }
 #    -re "expected output 2" {
-#        fail $gdb_test_name
+#        fail [gdb_test_name]
 #    }
 # }
 #
@@ -769,6 +805,7 @@ proc gdb_test_multiple { command message user_code { prompt_regexp "" } } {
     upvar timeout timeout
     upvar expect_out expect_out
     global any_spawn_id
+    global gdb_test_name_stack
 
     if { "$prompt_regexp" == "" } {
 	set prompt_regexp "$gdb_prompt $"
@@ -1052,27 +1089,14 @@ proc gdb_test_multiple { command message user_code { prompt_regexp "" } } {
 	}
     }
 
-    # Create gdb_test_name in the parent scope.  If this variable
-    # already exists, which is might if we have nested calls to
-    # gdb_test_multiple, then preserve the old value, otherwise,
-    # create a new variable in the parent scope.
-    upvar gdb_test_name gdb_test_name
-    if { [info exists gdb_test_name] } {
-	set gdb_test_name_old "$gdb_test_name"
-    }
-    set gdb_test_name "$message"
+    # Add the latest test name to the test name stack.
+    stack push $gdb_test_name_stack "$message"
 
     set result 0
     set code [catch {gdb_expect $code} string]
 
-    # Clean up the gdb_test_name variable.  If we had a
-    # previous value then restore it, otherwise, delete the variable
-    # from the parent scope.
-    if { [info exists gdb_test_name_old] } {
-	set gdb_test_name "$gdb_test_name_old"
-    } else {
-	unset gdb_test_name
-    }
+    # Clean up the test name stack.
+    stack pop $gdb_test_name_stack
 
     if {$code == 1} {
 	global errorInfo errorCode
