This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] New testsuite directory gdb.reverse, and tests


Here are some new tests to test reverse debugging.
I've moved the test solib-reverse (submitted earlier) into this directory.

Since most targets don't (yet) implement reverse debugging,
these tests all return with no results unless you add the
following to your board description file:

set_board_info gdb,can_reverse 1

In addition, since Process Record requires some special
commands that will not be used by remote debug targets
such as SID and Simics (eg. to start and stop recording),
you'll also want to define the following for process record:

set_board_info gdb,use_precord 1

I hope that the Virtutech folk will try out these tests
using Simics and let me know if any changes are required.

OK, to commit?

2009-06-24  Michael Snyder  <msnyder@vmware.com>

	* gdb.reverse: New directory.
	* gdb.reverse/break-reverse.c: New test.
	* gdb.reverse/break-reverse.exp: New test.
	* gdb.reverse/consecutive-reverse.c: New test.
	* gdb.reverse/consecutive-reverse.exp: New test.
	* gdb.reverse/finish-reverse.c: New test.
	* gdb.reverse/finish-reverse.exp: New test.
	* gdb.reverse/machinestate.c: New test.
	* gdb.reverse/machinestate1.c: New test.
	* gdb.reverse/machinestate.exp: New test.
	* gdb.reverse/Makefile.in: New file.
	* gdb.reverse/shr2.c: New test.
	* gdb.reverse/solib-reverse.c: New test.
	* gdb.reverse/solib-reverse.exp: New test.
	* gdb.reverse/step-reverse.c: New test.
	* gdb.reverse/step-reverse.exp: New test.
	* gdb.reverse/until-reverse.c: New test.
	* gdb.reverse/until-reverse1.c: New test.
	* gdb.reverse/until-reverse.exp: New test.
	* gdb.reverse/watch-reverse.c: New test.
	* gdb.reverse/watch-reverse.exp: New test.
	* configure.ac (AC_OUTPUT): Add gdb.reverse/Makefile.
	* configure: Regenerate.

Index: configure
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/configure,v
retrieving revision 1.29
diff -u -p -r1.29 configure
--- configure	19 Oct 2008 19:59:31 -0000	1.29
+++ configure	24 Jun 2009 20:38:54 -0000
@@ -3131,7 +3131,7 @@ done
 
 
 
-                                                                                                                                                                                                        ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+                                                                                                                                                                                                                  ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -3699,6 +3699,7 @@ do
   "gdb.opt/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.opt/Makefile" ;;
   "gdb.pascal/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.pascal/Makefile" ;;
   "gdb.python/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.python/Makefile" ;;
+  "gdb.reverse/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.reverse/Makefile" ;;
   "gdb.threads/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.threads/Makefile" ;;
   "gdb.trace/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.trace/Makefile" ;;
   "gdb.xml/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.xml/Makefile" ;;
Index: configure.ac
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/configure.ac,v
retrieving revision 1.12
diff -u -p -r1.12 configure.ac
--- configure.ac	19 Oct 2008 19:59:31 -0000	1.12
+++ configure.ac	24 Jun 2009 20:38:54 -0000
@@ -117,5 +117,5 @@ AC_OUTPUT([Makefile \
   gdb.fortran/Makefile gdb.server/Makefile \
   gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile \
   gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile \
-  gdb.python/Makefile \
+  gdb.python/Makefile gdb.reverse/Makefile \
   gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile])
Index: gdb.reverse/break-reverse.c
===================================================================
RCS file: gdb.reverse/break-reverse.c
diff -N gdb.reverse/break-reverse.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/break-reverse.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,37 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2008, 2009 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int xyz;
+
+int bar ()
+{
+  xyz = 2; /* break in bar */
+  return 1;
+}
+
+int foo ()
+{
+  xyz = 1; /* break in foo */
+  return bar ();
+}
+
+int main ()
+{
+  xyz = 0;	/* break in main */
+  foo ();
+  return (xyz == 2 ? 0 : 1);
+}		/* end of main */
Index: gdb.reverse/break-reverse.exp
===================================================================
RCS file: gdb.reverse/break-reverse.exp
diff -N gdb.reverse/break-reverse.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/break-reverse.exp	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,89 @@
+#   Copyright 2008, 2009 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Michael Snyder (msnyder@vmware.com).
+
+#
+# Test reverse debugging with breakpoints.
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "break-reverse"
+set srcfile  ${testfile}.c
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile] } {
+    return -1
+}
+
+set foo_location  [gdb_get_line_number "break in foo" ]
+set bar_location  [gdb_get_line_number "break in bar" ]
+set main_location [gdb_get_line_number "break in main"]
+set end_location  [gdb_get_line_number "end of main"  ]
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+gdb_test "break foo" \
+    "Breakpoint $decimal at .* line $foo_location\." \
+    "set breakpoint on foo"
+
+gdb_test "break bar" \
+    "Breakpoint $decimal at .* line $bar_location\." \
+    "set breakpoint on bar"
+
+gdb_test "break $end_location" \
+    "Breakpoint $decimal at .* line $end_location\." \
+    set breakpoint at end of main"
+
+gdb_continue_to_breakpoint "foo" ".*/$srcfile:$foo_location.*"
+gdb_continue_to_breakpoint "bar" ".*/$srcfile:$bar_location.*"
+gdb_continue_to_breakpoint "end" ".*/$srcfile:$end_location.*"
+
+# FIXME 'set exec-dir' command should give some output so we can test.
+gdb_test "set exec-direction reverse" "" "set reverse"
+
+gdb_continue_to_breakpoint "bar backward"  ".*/$srcfile:$bar_location.*"
+gdb_continue_to_breakpoint "foo backward"  ".*/$srcfile:$foo_location.*"
+
+gdb_test_multiple "continue" "main backward" {
+    -re ".*Breakpoint $decimal,.*/$srcfile:$main_location.*$gdb_prompt $" {
+	pass "main backward"
+    }
+    -re "No more reverse-execution history.* break in main .*$gdb_prompt $" {
+	pass "main backward"
+    }
+}
+
+gdb_test "set exec-direction forward" "" "set forward"
+
+gdb_continue_to_breakpoint "foo" ".*/$srcfile:$foo_location.*"
+gdb_continue_to_breakpoint "bar" ".*/$srcfile:$bar_location.*"
+
+gdb_test_multiple "continue" "end of record log" {
+    -re ".*Breakpoint $decimal,.*/$srcfile:$end_location.*$gdb_prompt $" {
+	pass "end of record log"
+    }
+    -re "No more reverse-execution history.* end of main .*$gdb_prompt $" {
+	pass "end of record log"
+    }
+}
Index: gdb.reverse/consecutive-reverse.c
===================================================================
RCS file: gdb.reverse/consecutive-reverse.c
diff -N gdb.reverse/consecutive-reverse.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/consecutive-reverse.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,37 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2008, 2009 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* 
+   Purpose of this test:  to test breakpoints on consecutive instructions.
+*/
+
+int a[7] = {1, 2, 3, 4, 5, 6, 7};
+
+/* assert: first line of foo has more than one instruction. */
+int foo ()
+{
+  return a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6];
+}
+
+main()
+{
+#ifdef usestubs
+    set_debug_traps ();
+    breakpoint ();
+#endif
+  foo ();
+}
Index: gdb.reverse/consecutive-reverse.exp
===================================================================
RCS file: gdb.reverse/consecutive-reverse.exp
diff -N gdb.reverse/consecutive-reverse.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/consecutive-reverse.exp	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,131 @@
+#   Copyright 2008, 2009 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+# Based on a file written by Michael Snyder. (msnyder@redhat.com)
+
+#
+# Test reverse debugging breakpoints at consecutive instruction addresses.
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "consecutive-reverse"
+set srcfile ${testfile}.c
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile] } {
+    return -1
+}
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+gdb_breakpoint foo
+gdb_test "continue" "Breakpoint $decimal, foo .*" \
+	"continue to breakpoint in foo"
+
+set foo1_addr 0
+set foo2_addr 0
+set stop_addr 0
+
+send_gdb "x /2i \$pc\n"
+gdb_expect {
+    global hex
+    global foo1_addr
+    global foo2_addr
+    global gdb_prompt
+
+    -re "($hex).*\[\r\n\]+($hex).*$gdb_prompt $" {
+	set foo1_addr $expect_out(1,string)
+	set foo2_addr $expect_out(2,string)
+	pass "get breakpoint address for foo"
+    }
+    -re ".*$gdb_prompt $" {
+	fail "get breakpoint address for foo"
+	return 0;
+    }
+    timeout {
+	fail "get breakpoint address for foo (timeout)"
+	return 0;
+    }
+}
+
+gdb_test "break \*$foo2_addr" "Breakpoint $decimal at $foo2_addr: file .*" \
+	"set bp, 2nd instr"
+
+send_gdb "step\n"
+gdb_expect {
+    -re "Breakpoint $decimal, ($hex) in foo.*$gdb_prompt $" {
+	set stop_addr $expect_out(1,string)
+	if [eval expr "$foo2_addr == $stop_addr"] then {
+	    pass "stopped at bp, 2nd instr"
+	} else {
+	    fail "stopped at bp, 2nd instr (wrong address)"
+	}
+    }
+    -re ".*$gdb_prompt $" {
+	fail "stopped at bp, 2nd instr"
+    }
+    timeout {
+	fail "stopped at bp, 2nd instr (timeout)"
+
+    }
+}
+
+###
+###
+###
+
+# Set reverse execution direction
+# FIXME: command needs to acknowledge, so we can test if it succeeded.
+
+gdb_test "set exec-dir reverse" "" "set reverse execution"
+
+# Now step backward and hope to hit the first breakpoint.
+
+set test_msg "stopped at bp in reverse, 1st instr"
+gdb_test_multiple "step" "$test_msg" {
+    -re "Breakpoint $decimal, ($hex) in foo.*$gdb_prompt $" {
+	set stop_addr $expect_out(1,string)
+	if [eval expr "$foo1_addr == $stop_addr"] then {
+	    pass "$test_msg"
+	} else {
+	    fail "$test_msg (wrong address)"
+	}
+    }
+    -re "Breakpoint $decimal, foo.*$gdb_prompt $" {
+	send_gdb "print \$pc == $foo1_addr\n"
+	gdb_expect {
+	    -re "$decimal = 1\[\r\n\]+$gdb_prompt $" {
+		pass "$test_msg"
+	    }
+	    -re "$decimal = 0\[\r\n\]+$gdb_prompt $" {
+		fail "$test_msg (wrong address)"
+	    }
+	}
+    }
+    -re ".*$gdb_prompt $" {
+	fail "$test_msg"
+    }
+}
Index: gdb.reverse/finish-reverse.c
===================================================================
RCS file: gdb.reverse/finish-reverse.c
diff -N gdb.reverse/finish-reverse.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/finish-reverse.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,127 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2008, 2009 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Test gdb's "return" command in reverse.  */
+
+int void_test = 0;
+int main_test = 0;
+
+char      char_returnval      = '1';
+short     short_returnval     = 1;
+int       int_returnval       = 1;
+long      long_returnval      = 1;
+long long long_long_returnval = 1;
+float     float_returnval     = 1;
+double    double_returnval    = 1;
+
+union {
+  char      char_testval;
+  short     short_testval;
+  int       int_testval;
+  long      long_testval;
+  long long long_long_testval;
+  float     float_testval;
+  double    double_testval;
+  char      ffff[80];
+} testval;
+
+void void_func ()
+{
+  void_test = 1;		/* VOID FUNC */
+}
+
+char char_func ()
+{
+  return char_returnval;	/* CHAR FUNC */
+}
+
+short short_func ()
+{
+  return short_returnval;	/* SHORT FUNC */
+}
+
+int int_func ()
+{
+  return int_returnval;		/* INT FUNC */
+}
+
+long long_func ()
+{
+  return long_returnval;	/* LONG FUNC */
+}
+
+long long long_long_func ()
+{
+  return long_long_returnval;	/* LONG LONG FUNC */
+}
+
+float float_func ()
+{
+  return float_returnval;	/* FLOAT FUNC */
+}
+
+double double_func ()
+{
+  return double_returnval;	/* DOUBLE FUNC */
+}
+
+int main (int argc, char **argv)
+{
+  char char_resultval;
+  short short_resultval;
+  int int_resultval;
+  long long_resultval;
+  long long long_long_resultval;
+  float float_resultval;
+  double double_resultval;
+  int i;
+
+  /* A "test load" that will insure that the function really returns 
+     a ${type} (as opposed to just a truncated or part of a ${type}).  */
+  for (i = 0; i < sizeof (testval.ffff); i++)
+    testval.ffff[i] = 0xff;
+
+  void_func (); 				/* call to void_func */
+  char_resultval      = char_func ();		/* void_checkpoint */
+  short_resultval     = short_func ();		/* char_checkpoint */
+  int_resultval       = int_func ();		/* short_checkpoint */
+  long_resultval      = long_func ();		/* int_checkpoint */
+  long_long_resultval = long_long_func ();	/* long_checkpoint */
+
+  /* On machines using IEEE floating point, the test pattern of all
+     1-bits established above turns out to be a floating-point NaN
+     ("Not a Number").  According to the IEEE rules, NaN's aren't even
+     equal to themselves.  This can lead to stupid conversations with
+     GDB like:
+
+       (gdb) p testval.float_testval == testval.float_testval
+       $7 = 0
+       (gdb)
+
+     This is the correct answer, but it's not the sort of thing
+     return2.exp wants to see.  So to make things work the way they
+     ought, we'll set aside the `union' cleverness and initialize the
+     test values explicitly here.  These values have interesting bits
+     throughout the value, so we'll still detect truncated values.  */
+
+  testval.float_testval = 2.7182818284590452354;/* long_long_checkpoint */
+  float_resultval     = float_func ();		
+  testval.double_testval = 3.14159265358979323846; /* float_checkpoint */
+  double_resultval    = double_func ();		
+  main_test = 1;				/* double_checkpoint */
+  return 0;
+}
Index: gdb.reverse/finish-reverse.exp
===================================================================
RCS file: gdb.reverse/finish-reverse.exp
diff -N gdb.reverse/finish-reverse.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/finish-reverse.exp	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,264 @@
+# Copyright 2008, 2009 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+#
+# Test "reverse-finish" command
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "finish-reverse"
+set srcfile ${testfile}.c
+
+if { [prepare_for_testing $testfile.exp "$testfile" $srcfile] } {
+    return -1
+}
+
+proc test_start_of_line { line_text test_msg } {
+    global gdb_prompt
+    global decimal
+    global hex
+
+    send_gdb "info line\n"
+    gdb_expect {
+	-re "Line $decimal of .* starts at address ($hex) .*$gdb_prompt $" {
+	    set line_begin $expect_out(1,string)
+	}
+	default {
+	    fail "Get line address in test_start_of_line"
+	}
+    }
+    send_gdb "info reg pc\n"
+    gdb_expect {
+	-re ".*: ($hex)\r\n*$gdb_prompt $" {
+	    set stop_pc $expect_out(1,string)
+	}
+	default {
+	    fail"Get stop pc in test_start_of_line"
+	}
+    }
+    gdb_test "print $line_begin == $stop_pc" \
+	" = 1\[\r\n\]*" \
+	"test_start_of_line, $test_msg"
+}
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+# Test finish from void func
+
+set breakloc [gdb_get_line_number "VOID FUNC" "$srcfile"]
+gdb_test "break void_func" \
+    "Breakpoint $decimal at .*/$srcfile, line $breakloc\." \
+    "set breakpoint on void_func"
+gdb_continue_to_breakpoint "void_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "finish from void_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re " call to void_func .*$gdb_prompt $" {
+	send_gdb "step\n"
+	exp_continue
+    }
+    -re " void_checkpoint .*$gdb_prompt $" {
+	pass "$test_msg"
+    }
+}
+
+# Test finish from char func
+
+set breakloc [gdb_get_line_number "CHAR FUNC" "$srcfile"]
+gdb_test "break char_func" \
+    "Breakpoint $decimal at .*/$srcfile, line $breakloc\." \
+    "set breakpoint on char_func"
+gdb_continue_to_breakpoint "char_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "finish from char_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re " void_checkpoint .*$gdb_prompt $" {
+	send_gdb "step\n"
+	exp_continue
+    }
+    -re " char_checkpoint .*$gdb_prompt $" {
+	pass "$test_msg"
+    }
+}
+
+# Test finish from short func
+
+set breakloc [gdb_get_line_number "SHORT FUNC" "$srcfile"]
+gdb_test "break short_func" \
+    "Breakpoint $decimal at .* line $breakloc\." \
+    "set breakpoint on short_func"
+gdb_continue_to_breakpoint "short_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "finish from short_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re " char_checkpoint .*$gdb_prompt $" {
+	send_gdb "step\n"
+	exp_continue
+    }
+    -re " short_checkpoint .*$gdb_prompt $" {
+	pass "$test_msg"
+    }
+}
+
+# Test finish from int func
+
+set breakloc [gdb_get_line_number "INT FUNC" "$srcfile"]
+gdb_test "break int_func" \
+    "Breakpoint $decimal at .* line $breakloc\." \
+    "set breakpoint on int_func"
+gdb_continue_to_breakpoint "int_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "finish from int_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re " short_checkpoint .*$gdb_prompt $" {
+	send_gdb "step\n"
+	exp_continue
+    }
+    -re " int_checkpoint .*$gdb_prompt $" {
+	pass "$test_msg"
+    }
+}
+
+# Test finish from long func
+
+set breakloc [gdb_get_line_number "LONG FUNC" "$srcfile"]
+gdb_test "break long_func" \
+    "Breakpoint $decimal at .* line $breakloc\." \
+    "set breakpoint on long_func"
+gdb_continue_to_breakpoint "long_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "finish from long_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re " int_checkpoint .*$gdb_prompt $" {
+	send_gdb "step\n"
+	exp_continue
+    }
+    -re " long_checkpoint .*$gdb_prompt $" {
+	pass "$test_msg"
+    }
+}
+
+# Test finish from long long func
+
+set breakloc [gdb_get_line_number "LONG LONG FUNC" "$srcfile"]
+gdb_test "break long_long_func" \
+    "Breakpoint $decimal at .* line $breakloc\." \
+    "set breakpoint on long_long_func"
+gdb_continue_to_breakpoint "long_long_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "finish from long_long_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re " long_checkpoint .*$gdb_prompt $" {
+	send_gdb "step\n"
+	exp_continue
+    }
+    -re " long_long_checkpoint .*$gdb_prompt $" {
+	pass "$test_msg"
+    }
+}
+
+
+###
+###
+###
+
+# Now switch to reverse
+gdb_test "set exec-dir reverse" "" "set reverse execution"
+
+# Test reverse finish from long long func
+
+set breakloc [gdb_get_line_number "LONG LONG FUNC" "$srcfile"]
+gdb_continue_to_breakpoint "long_long_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "reverse finish from long_long_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re ".* long_checkpoint.*$gdb_prompt $" {
+	test_start_of_line "long_checkpoint" "$test_msg"
+    }
+}
+
+# Test reverse finish from long func
+
+set breakloc [gdb_get_line_number "LONG FUNC" "$srcfile"]
+gdb_continue_to_breakpoint "long_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "reverse finish from long_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re ".* int_checkpoint.*$gdb_prompt $" {
+	test_start_of_line "int_checkpoint" "$test_msg"
+    }
+}
+
+# Test reverse finish from int func
+
+set breakloc [gdb_get_line_number "INT FUNC" "$srcfile"]
+gdb_continue_to_breakpoint "int_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "reverse finish from int_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re ".* short_checkpoint.*$gdb_prompt $" {
+	test_start_of_line "short_checkpoint" "$test_msg"
+    }
+}
+
+# Test reverse finish from short func
+
+set breakloc [gdb_get_line_number "SHORT FUNC" "$srcfile"]
+gdb_continue_to_breakpoint "short_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "reverse finish from short_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re ".* char_checkpoint.*$gdb_prompt $" {
+	test_start_of_line "char_checkpoint" "$test_msg"
+    }
+}
+
+# Test reverse finish from char func
+
+set breakloc [gdb_get_line_number "CHAR FUNC" "$srcfile"]
+gdb_continue_to_breakpoint "char_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "reverse finish from char_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re ".* void_checkpoint.*$gdb_prompt $" {
+	test_start_of_line "void_checkpoint" "$test_msg"
+    }
+}
+
+# Test reverse finish from void func
+
+set breakloc [gdb_get_line_number "VOID FUNC" "$srcfile"]
+gdb_continue_to_breakpoint "void_func" ".*/$srcfile:$breakloc.*"
+
+set test_msg "reverse finish from void_func"
+gdb_test_multiple "finish" "$test_msg" {
+    -re ".* call to void_func.*$gdb_prompt $" {
+	test_start_of_line "call to void_func" "$test_msg"
+    }
+}
+
+return 0
Index: gdb.reverse/machinestate.c
===================================================================
RCS file: gdb.reverse/machinestate.c
diff -N gdb.reverse/machinestate.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/machinestate.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,101 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2008, 2009 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/*
+ * Test restoration of machine state
+ */
+
+extern void hide (int);
+
+/* Test register variable
+   Requires -- compiler honors 'register'.  */
+
+void 
+register_state (void)
+{
+  register int a = 0;
+
+  hide (a);	/* External function to defeat optimization.  */
+  a++;		/* register_state: set breakpoint here */
+  hide (a);	/* register post-change */
+}
+
+/* Test auto variable (whatever that means).  */
+
+void
+auto_state (void)
+{
+  auto int a = 0;
+
+  hide (a);	/* External function to defeat optimization.  */
+  a++;		/* auto_state: set breakpoint here */
+  hide (a);	/* auto post-change */
+}
+
+/* Test function-static variable.  */
+
+void
+function_static_state (void)
+{
+  static int a = 0;
+
+  hide (a);	/* External function to defeat optimization.  */
+  a++;		/* function_static_state: set breakpoint here */
+  hide (a);	/* function static post-change */
+}
+
+/* Test module-static variable.  */
+
+static int astatic;
+
+void
+module_static_state (void)
+{
+  astatic = 0;
+
+  hide (astatic);	/* External function to defeat optimization.  */
+  astatic++;		/* module_static_state: set breakpoint here */
+  hide (astatic);	/* module static post-change */
+}
+
+/* Test module-global variable.  */
+
+int aglobal;
+
+void
+module_global_state (void)
+{
+  aglobal = 0;
+
+  hide (aglobal);	/* External function to defeat optimization.  */
+  aglobal++;		/* module_global_state: set breakpoint here */
+  hide (aglobal);	/* module global post-change */
+}
+
+/* main test driver */
+
+int 
+main (int argc, char **argv)
+{
+  register_state ();	/* begin main */
+  auto_state ();
+  function_static_state ();
+  module_static_state ();
+  module_global_state ();
+  
+  return 0;		/* end main */
+}
Index: gdb.reverse/machinestate.exp
===================================================================
RCS file: gdb.reverse/machinestate.exp
diff -N gdb.reverse/machinestate.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/machinestate.exp	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,233 @@
+# Copyright 2008, 2009 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+#
+# This test tests the restoration of various kinds of machine state
+# to their original values by reverse execution.  We will execute
+# the program forward while it changes various types of data, and
+# then execute it backward to see if their values get restored.
+#
+# The types of machine state (data) that are tested are:
+#   register variable
+#   auto variable
+#   function static variable
+#   module static variable
+#   module global variable
+#
+# TODO:
+# various, possibly including...
+#   .bss variable, .data variable, ...
+#   shared library variable
+#   heap variable (pointer)...
+#   overlay variables...
+#   Test forward replay
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "machinestate"
+set srcfile  ${testfile}.c
+set srcfile1 ${testfile}1.c
+
+if { [prepare_for_testing $testfile.exp $testfile {machinestate.c machinestate1.c} ] } {
+    return -1
+}
+
+set newline "\[\r\n\]+"
+
+set beginmain [gdb_get_line_number " begin main " $srcfile]
+set endmain   [gdb_get_line_number " end main "   $srcfile]
+
+# Test begins
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+# Proceed to end of main
+
+gdb_test "break $endmain" \
+    "Breakpoint.* file .*/$srcfile, line $endmain.*" ""
+gdb_continue_to_breakpoint "end of main" ".*/$srcfile:$endmain.*"
+
+###
+###
+###
+
+# Now run backward to each of several points where data is changed.
+#
+
+# Module global variable, reverse
+
+set breakloc [gdb_get_line_number \
+		  "module_global_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "reverse-continue" ".*/$srcfile:$breakloc.*" "reverse to $breakloc"
+
+gdb_test "print aglobal" ".* = 0$newline"  "module global reverse-breakpoint"
+gdb_test "step"          ".* module global post-change .*" ""
+gdb_test "print aglobal" ".* = 1$newline"  "module global forward past bp"
+gdb_test "reverse-step"  ".*$newline$breakloc.*" ""
+gdb_test "print aglobal" ".* = 0$newline"  "module global reverse-step to bp"
+
+
+# Module static variable, reverse
+
+set breakloc [gdb_get_line_number \
+		  "module_static_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "reverse-continue" ".*/$srcfile:$breakloc.*" "reverse to $breakloc"
+
+gdb_test "print astatic" ".* = 0$newline"  "module static reverse-breakpoint"
+gdb_test "step"          ".* module static post-change .*" ""
+gdb_test "print astatic" ".* = 1$newline"  "module static forward"
+gdb_test "reverse-step"  ".*$newline$breakloc.*" ""
+gdb_test "print astatic" ".* = 0$newline"  "module static reverse-step"
+
+# Function static variable, reverse
+
+set breakloc [gdb_get_line_number \
+		  "function_static_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "reverse-continue" ".*/$srcfile:$breakloc.*" "reverse to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "function static reverse-breakpoint"
+gdb_test "step"         ".* function static post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "function static forward"
+gdb_test "reverse-step" ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "function static reverse-step"
+
+# Auto variable, reverse
+
+set breakloc [gdb_get_line_number \
+		  "auto_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "reverse-continue" ".*/$srcfile:$breakloc.*" "reverse to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "auto var reverse-breakpoint"
+gdb_test "step"         ".* auto post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "auto var forward"
+gdb_test "reverse-step" ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "auto var reverse-step"
+
+# Register variable, reverse
+
+set breakloc [gdb_get_line_number \
+		  "register_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "reverse-continue" ".*/$srcfile:$breakloc.*" "reverse to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "register var reverse-breakpoint"
+gdb_test "step"         ".* register post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "register var step post-change"
+gdb_test "reverse-step" ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "register var reverse step-to"
+
+# Proceed to beginning of main
+
+gdb_test "tbreak $beginmain" ".*/$srcfile, line $beginmain.*" ""
+gdb_test "reverse-continue"  ".*/$srcfile:$beginmain.*" "reverse to main"
+
+# Now repeat tests while replaying forward.
+
+# Register variable, forward
+
+set breakloc [gdb_get_line_number \
+		  "register_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "register var forward-breakpoint"
+gdb_test "reverse-step" ".*hide.*" ""
+gdb_test "step"         ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "register var forward step-to"
+gdb_test "step"         ".* register post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "register var step post-change"
+
+# Auto variable, forward
+
+set breakloc [gdb_get_line_number \
+		  "auto_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "auto var forward-breakpoint"
+gdb_test "reverse-step" ".*hide.*" ""
+gdb_test "step"         ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "auto var forward step-to"
+gdb_test "step"         ".* auto post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "auto var step post-change"
+
+# Function static variable, forward
+
+set breakloc [gdb_get_line_number \
+		  "function_static_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "function static forward-breakpoint"
+gdb_test "reverse-step" ".*hide.*" ""
+gdb_test "step"         ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "function static forward step-to"
+gdb_test "step"         ".* function static post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "function static step post-change"
+
+# Module static variable, forward
+
+set breakloc [gdb_get_line_number \
+		  "module_static_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print astatic" ".* = 0$newline"  "module static forward-breakpoint"
+gdb_test "reverse-step"  ".*hide.*" ""
+gdb_test "step"          ".*$newline$breakloc.*" ""
+gdb_test "print astatic" ".* = 0$newline"  "module static forward step-to"
+gdb_test "step"          ".* module static post-change .*" ""
+gdb_test "print astatic" ".* = 1$newline"  "module static step post-change"
+
+# Module global variable, forward
+
+set breakloc [gdb_get_line_number \
+		  "module_global_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print aglobal" ".* = 0$newline"  "module global forward-breakpoint"
+gdb_test "reverse-step"  ".*hide.*" ""
+gdb_test "step"          ".*$newline$breakloc.*" ""
+gdb_test "print aglobal" ".* = 0$newline"  "module global forward step-to"
+gdb_test "step"          ".* module global post-change .*" ""
+gdb_test "print aglobal" ".* = 1$newline"  "module global step post-change"
+
Index: gdb.reverse/machinestate1.c
===================================================================
RCS file: gdb.reverse/machinestate1.c
diff -N gdb.reverse/machinestate1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/machinestate1.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2008 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/*
+ * Aux function for machine state test.
+ */
+
+void 
+hide (int x)
+{
+}
Index: gdb.reverse/shr2.c
===================================================================
RCS file: gdb.reverse/shr2.c
diff -N gdb.reverse/shr2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/shr2.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,34 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2009 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef PROTOTYPES
+int shr2(int x)
+#else
+int shr2(x) int x;
+#endif
+{
+  return 2*x;
+}
+
+#ifdef PROTOTYPES
+int shr2_local(int x)
+#else
+int shr2_local(x) int x;
+#endif
+{
+  return 2*x;
+}
Index: gdb.reverse/solib-reverse.c
===================================================================
RCS file: gdb.reverse/solib-reverse.c
diff -N gdb.reverse/solib-reverse.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/solib-reverse.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,43 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2009 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Test reverse debugging of shared libraries.  */
+
+#include <stdio.h>
+
+/* Shared library function */
+extern int shr2(int);
+
+int main ()
+{
+  char* cptr = "String 1";
+  int b[2] = {5,8};
+
+  b[0] = shr2(12);		/* begin part two */
+  b[1] = shr2(17);		/* middle part two */
+
+  b[0] = 6;   b[1] = 9;		/* generic statement, end part two */
+  printf ("message 1\n");	/* printf one */
+  printf ("message 2\n");	/* printf two */
+  printf ("message 3\n");	/* printf three */
+  sleep (0);			/* sleep one */
+  sleep (0);			/* sleep two */
+  sleep (0);			/* sleep three */
+
+  return 0;			/* end part one */
+}
+
Index: gdb.reverse/solib-reverse.exp
===================================================================
RCS file: gdb.reverse/solib-reverse.exp
diff -N gdb.reverse/solib-reverse.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/solib-reverse.exp	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,127 @@
+# Copyright 2009
+# 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file was written by Michael Snyder (msnyder@vmware.com).
+
+#
+# Test reverse debugging with shared libraries.
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "solib-reverse"
+set srcfile  ${testfile}.c
+set libfile  "shr2"
+set libsrc   ${libfile}.c
+set library  ${objdir}/${subdir}/${libfile}.sl
+set binfile  ${objdir}/${subdir}/${testfile}
+
+if [get_compiler_info ${binfile}] {
+    return -1
+}
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/${libsrc} ${library} "debug"] != "" } {
+    untested "Could not compile shared library."
+    return -1
+}
+
+set exec_opts [list debug shlib=${library}]
+
+if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile} executable $exec_opts] != "" } {
+    untested "Could not compile $binfile."
+    return -1
+}
+     
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+#
+# Test reverse-step over undebuggable solib functions.
+#
+
+# Run forward past some solib function calls.
+
+set end_part_one [gdb_get_line_number " end part one" "$srcfile"]
+set end_part_two [gdb_get_line_number " end part two" "$srcfile"]
+gdb_test "until $end_part_one" " end part one.*" "run until end part one"
+
+gdb_test "reverse-step" " sleep three .*" "reverse-step third sleep"
+gdb_test "reverse-step" " sleep two .*"   "reverse-step second sleep"
+gdb_test "reverse-step" " sleep one .*"   \
+		    "reverse-step first sleep, dynsym resolve"
+
+gdb_test "reverse-step" " printf three .*" "reverse-step third printf"
+gdb_test "reverse-step" " printf two .*"   "reverse-step second printf"
+gdb_test "reverse-step" " printf one .*"   \
+		    "reverse-step first printf, dynsym resolve"
+gdb_test "reverse-step" " generic statement.*" "reverse-step generic"
+
+
+#
+# Test reverse-next over undebuggable solib functions.
+#
+
+# Run forward again...
+
+gdb_test "until $end_part_one" " end part one.*" "forward to end part one"
+
+gdb_test "reverse-next" " sleep three .*" "reverse-next third sleep"
+gdb_test "reverse-next" " sleep two .*"   "reverse-next second sleep"
+gdb_test "reverse-next" " sleep one .*"   \
+		    "reverse-next first sleep, dynsym resolve"
+
+gdb_test "reverse-next" " printf three .*" "reverse-next third printf"
+gdb_test "reverse-next" " printf two .*"   "reverse-next second printf"
+gdb_test "reverse-next" " printf one .*"   \
+		    "reverse-next first printf, dynsym resolve"
+gdb_test "reverse-next" " generic statement.*" "reverse-next generic"
+
+
+#
+# Test reverse-step into debuggable solib function
+#
+
+gdb_test "reverse-step" "${libsrc}.*" "reverse-step into solib function one"
+gdb_test "reverse-step" "return 2.x.*" "reverse-step within solib function one"
+gdb_test "reverse-step" " middle part two.*" "reverse-step back to main one"
+
+gdb_test "reverse-step" "${libsrc}.*" "reverse-step into solib function two"
+gdb_test "reverse-step" "return 2.x.*" "reverse-step within solib function two"
+gdb_test "reverse-step" " begin part two.*" "reverse-step back to main two"
+
+#
+# Test reverse-next over debuggable solib function
+#
+
+gdb_test "until $end_part_two" " end part two.*" "run until end part two"
+
+gdb_test "reverse-next" " middle part two.*" "reverse-next over solib function one"
+gdb_test "reverse-next" " begin part two.*" "reverse-next over solib function two"
Index: gdb.reverse/step-reverse.c
===================================================================
RCS file: gdb.reverse/step-reverse.c
diff -N gdb.reverse/step-reverse.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/step-reverse.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,78 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2008, 2009 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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+
+/* Test various kinds of stepping.
+*/
+int myglob = 0;
+
+int callee() {		/* ENTER CALLEE */
+  myglob++; return 0;	/* ARRIVED IN CALLEE */
+}			/* RETURN FROM CALLEE */
+
+/* A structure which, we hope, will need to be passed using memcpy.  */
+struct rhomboidal {
+  int rather_large[100];
+};
+
+void
+large_struct_by_value (struct rhomboidal r)
+{
+  myglob += r.rather_large[42]; /* step-test.exp: arrive here 1 */
+}
+
+int main () {
+   int w,x,y,z;
+   int a[10], b[10];
+
+   /* Test "next" and "step" */
+   w = 0;	/* BREAK AT MAIN */
+   x = 1;	/* NEXT TEST 1 */
+   y = 2;	/* STEP TEST 1 */
+   z = 3;	/* REVERSE NEXT TEST 1 */
+   w = w + 2;	/* NEXT TEST 2 */
+   x = x + 3;	/* REVERSE STEP TEST 1 */
+   y = y + 4;
+   z = z + 5;	/* STEP TEST 2 */
+
+   /* Test that "next" goes over a call */
+   callee();	/* NEXT OVER THIS CALL */
+
+   /* Test that "step" doesn't */
+   callee();	/* STEP INTO THIS CALL */
+
+   /* Test "stepi" */
+   a[5] = a[3] - a[4]; /* FINISH TEST */
+   callee();	/* STEPI TEST */
+   
+   /* Test "nexti" */
+   callee();	/* NEXTI TEST */
+
+   y = w + z;
+
+   {
+     struct rhomboidal r;
+     memset (r.rather_large, 0, sizeof (r.rather_large));
+     r.rather_large[42] = 10;
+     large_struct_by_value (r);  /* step-test.exp: large struct by value */
+   }
+
+   exit (0);
+}
+
Index: gdb.reverse/step-reverse.exp
===================================================================
RCS file: gdb.reverse/step-reverse.exp
diff -N gdb.reverse/step-reverse.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/step-reverse.exp	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,250 @@
+# Copyright 2008, 2009 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+# step-reverse.exp -- Expect script to test reverse stepping in gdb.
+# Lots of code borrowed from "step-test.exp".
+
+#
+# Test step and next in reverse
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "step-reverse"
+set srcfile  ${testfile}.c
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile] } {
+    return -1
+}
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+# plain vanilla step/next (no count)
+
+gdb_test "next" ".*NEXT TEST 1.*" "next test 1"
+gdb_test "step" ".*STEP TEST 1.*" "step test 1"
+
+# step/next with count
+
+gdb_test "next 2" ".*NEXT TEST 2.*" "next test 2"
+gdb_test "step 3" ".*STEP TEST 2.*" "step test 2"
+
+# step over call
+
+gdb_test "step" ".*NEXT OVER THIS CALL.*" "step up to call"
+gdb_test "next" ".*STEP INTO THIS CALL.*" "next over call"
+
+# step into call
+
+gdb_test "step" ".*ARRIVED IN CALLEE.*" "step into call"
+
+# finish out of call
+
+set test_message "finish out of fn call"
+gdb_test_multiple "finish" "$test_message" {
+    -re "FINISH TEST.*$gdb_prompt $" {
+	pass "$test_message"
+    }
+    -re "STEP INTO THIS CALL.*$gdb_prompt $" {
+	send_gdb "step\n"
+	exp_continue
+    }
+}
+
+# stepi over flat code (no calls)
+
+set test_message "simple stepi"
+gdb_test_multiple "stepi" "$test_message" {
+    -re "STEPI TEST.*$gdb_prompt $" {
+	pass "$test_message"
+    }
+    -re "FINISH TEST.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+    -re "NEXTI TEST.*$gdb_prompt $" {
+	fail "$test_message (too far)"
+    }
+}
+
+# stepi into a function call
+
+set test_message "stepi into function call"
+gdb_test_multiple "stepi" "$test_message" {
+    -re "ARRIVED IN CALLEE.*$gdb_prompt $" {
+	pass "$test_message"
+    }
+    -re "NEXTI TEST.*$gdb_prompt $" {
+	fail "$test_message (too far)"
+    }
+    -re "RETURN FROM CALLEE.*$gdb_prompt $" {
+	fail "$test_message (too far)"
+    }
+    -re "ENTER CALLEE.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+}
+
+# stepi thru return of a function call
+
+set test_message "stepi back from function call"
+gdb_test_multiple "stepi" "$test_message" {
+    -re "NEXTI TEST.*$gdb_prompt $" {
+	pass "$test_message"
+    }
+    -re "ARRIVED IN CALLEE.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+    -re "RETURN FROM CALLEE.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+    -re "STEPI TEST.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+    -re "ENTER CALLEE.*$gdb_prompt $" {
+	fail "$test_message (too far)"
+    }
+}
+
+###
+###
+###
+
+# Set reverse execution direction
+# FIXME: command needs to acknowledge, so we can test if it succeeded.
+
+gdb_test "set exec-dir reverse" "" "set reverse execution"
+
+# stepi backward thru return and into a function
+
+set stepi_location  [gdb_get_line_number "ARRIVED IN CALLEE" "$srcfile"]
+set test_message "reverse stepi thru function return"
+gdb_test_multiple "stepi" "$test_message" {
+    -re "NEXTI TEST.*$gdb_prompt $" {
+	fail "$test_message (start statement)"
+    }
+    -re "RETURN FROM CALLEE.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+    -re "$hex\[ \t\]*$stepi_location.*ARRIVED IN CALLEE.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+    -re "ARRIVED IN CALLEE.*$gdb_prompt $" {
+	pass "$test_message"
+    }
+    -re "ENTER CALLEE.*$gdb_prompt $" {
+	fail "$test_message (too far)"
+    }
+    -re "STEPI TEST.*$gdb_prompt $" {
+	fail "$test_message (too far)"
+    }
+}
+
+# stepi backward out of a function call
+
+set stepi_location  [gdb_get_line_number "FINISH TEST" "$srcfile"]
+set test_message "reverse stepi from a function call"
+gdb_test_multiple "stepi" "$test_message" {
+    -re "ARRIVED IN CALLEE.*$gdb_prompt $" {
+	fail "$test_message (start statement)"
+    }
+    -re "ENTER CALLEE.*$gdb_prompt $" {
+	send_gdb "stepi\n" 
+	exp_continue
+    }
+    -re "${hex}\[ \t\]*$stepi_location.*STEPI TEST.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+    -re "STEPI TEST.*$gdb_prompt $" {
+	pass "$test_message"
+    }
+    -re "STEP INTO THIS CALL.*$gdb_prompt $" {
+	fail "$test_message (too far)"
+    }
+}
+
+# stepi backward over flat code (no calls)
+
+set stepi_location  [gdb_get_line_number "FINISH TEST" "$srcfile"]
+set test_message "simple reverse stepi"
+gdb_test_multiple "stepi" "$test_message" {
+    -re "STEPI TEST.*$gdb_prompt $" {
+	fail "$test_message (start statement)"
+    }
+    -re "$hex\[ \t\]*$stepi_location.* FINISH TEST.*$gdb_prompt $" {
+	send_gdb "stepi\n"
+	exp_continue
+    }
+    -re "$stepi_location.* FINISH TEST.*$gdb_prompt $" {
+	pass "$test_message"
+    }
+    -re "STEP INTO THIS CALL.*$gdb_prompt $" {
+	fail "$test_message (too far)"
+    }
+}
+
+# step backward into function (thru return)
+
+set test_message "reverse step into fn call"
+gdb_test_multiple "step" "$test_message" {
+    -re "RETURN FROM CALLEE.*$gdb_prompt $" {
+	send_gdb "step\n"
+	exp_continue
+    }
+    -re "ARRIVED IN CALLEE.*$gdb_prompt $" {
+	pass "$test_message"
+    }
+}
+
+# step backward out of called function (thru call)
+
+gdb_test "step" ".*STEP INTO THIS CALL.*" "reverse step out of called fn"
+
+# next backward over call
+
+gdb_test "next" ".*NEXT OVER THIS CALL.*" "reverse next over call"
+
+# step/next backward with count
+
+gdb_test "step 3" ".*REVERSE STEP TEST 1.*" "reverse step test 1"
+gdb_test "next 2" ".*REVERSE NEXT TEST 1.*" "reverse next test 1"
+
+# step/next backward without count
+
+gdb_test "step" ".*STEP TEST 1.*" "reverse step test 2"
+gdb_test "next" ".*NEXT TEST 1.*" "reverse next test 2"
+
+
+
+# Finish test by running forward to the end.
+# FIXME return to this later...
+# gdb_test "set exec-dir forward" "" "set forward execution"
+# gdb_continue_to_end "step-reverse.exp"
+
+return 0
Index: gdb.reverse/until-reverse.c
===================================================================
RCS file: gdb.reverse/until-reverse.c
diff -N gdb.reverse/until-reverse.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/until-reverse.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,149 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2008, 2009
+   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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+   Please email any bugs, comments, and/or additions to this file to:
+   bug-gdb@prep.ai.mit.edu  */
+
+#ifdef vxworks
+
+#  include <stdio.h>
+
+/* VxWorks does not supply atoi.  */
+static int
+atoi (z)
+     char *z;
+{
+  int i = 0;
+
+  while (*z >= '0' && *z <= '9')
+    i = i * 10 + (*z++ - '0');
+  return i;
+}
+
+/* I don't know of any way to pass an array to VxWorks.  This function
+   can be called directly from gdb.  */
+
+vxmain (arg)
+char *arg;
+{
+  char *argv[2];
+
+  argv[0] = "";
+  argv[1] = arg;
+  main (2, argv, (char **) 0);
+}
+
+#else /* ! vxworks */
+#  include <stdio.h>
+#  include <stdlib.h>
+#endif /* ! vxworks */
+
+#ifdef PROTOTYPES
+extern int marker1 (void);
+extern int marker2 (int a);
+extern void marker3 (char *a, char *b);
+extern void marker4 (long d);
+#else
+extern int marker1 ();
+extern int marker2 ();
+extern void marker3 ();
+extern void marker4 ();
+#endif
+
+/*
+ *	This simple classical example of recursion is useful for
+ *	testing stack backtraces and such.
+ */
+
+#ifdef PROTOTYPES
+int factorial(int);
+
+int
+main (int argc, char **argv, char **envp)
+#else
+int
+main (argc, argv, envp)
+int argc;
+char *argv[], **envp;
+#endif
+{
+#ifdef usestubs
+    set_debug_traps();  /* set breakpoint 5 here */
+    breakpoint();
+#endif
+    if (argc == 12345) {  /* an unlikely value < 2^16, in case uninited */ /* set breakpoint 6 here */
+	fprintf (stderr, "usage:  factorial <number>\n");
+	return 1;
+    }
+    printf ("%d\n", factorial (atoi ("6")));  /* set breakpoint 1 here */
+    /* set breakpoint 12 here */
+    marker1 ();  /* set breakpoint 11 here */
+    marker2 (43); /* set breakpoint 20 here */
+    marker3 ("stack", "trace"); /* set breakpoint 21 here */
+    marker4 (177601976L);
+    /* We're used by a test that requires malloc, so make sure it is
+       in the executable.  */
+    (void)malloc (1);
+
+    argc = (argc == 12345); /* This is silly, but we can step off of it */ /* set breakpoint 2 here */
+    return argc;  /* set breakpoint 10 here */
+} /* set breakpoint 10a here */
+
+#ifdef PROTOTYPES
+int factorial (int value)
+#else
+int factorial (value)
+int value;
+#endif
+{
+  if (value > 1) {  /* set breakpoint 7 here */
+	value *= factorial (value - 1);
+    }
+    return (value); /* set breakpoint 19 here */
+}
+
+#ifdef PROTOTYPES
+int multi_line_if_conditional (int a, int b, int c)
+#else
+int multi_line_if_conditional (a, b, c)
+  int a, b, c;
+#endif
+{
+  if (a    /* set breakpoint 3 here */
+      && b
+      && c)
+    return 0;
+  else
+    return 1;
+}
+
+#ifdef PROTOTYPES
+int multi_line_while_conditional (int a, int b, int c)
+#else
+int multi_line_while_conditional (a, b, c)
+  int a, b, c;
+#endif
+{
+  while (a /* set breakpoint 4 here */
+      && b
+      && c)
+    {
+      a--, b--, c--;
+    }
+  return 0;
+}
Index: gdb.reverse/until-reverse.exp
===================================================================
RCS file: gdb.reverse/until-reverse.exp
diff -N gdb.reverse/until-reverse.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/until-reverse.exp	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,133 @@
+# Copyright 2008, 2009 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+#
+# Test 'until' and 'advance' in reverse.
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "until-reverse"
+set srcfile ${testfile}.c
+set srcfile1 ${testfile}1.c
+
+if { [prepare_for_testing $testfile.exp $testfile {until-reverse.c until-reverse1.c} ] } {
+    return -1
+}
+
+set bp_location1  [gdb_get_line_number "set breakpoint 1 here"]
+set bp_location7  [gdb_get_line_number "set breakpoint 7 here"]
+set bp_location9  [gdb_get_line_number "set breakpoint 9 here" "$srcfile1"]
+set bp_location19 [gdb_get_line_number "set breakpoint 19 here"]
+set bp_location20 [gdb_get_line_number "set breakpoint 20 here"]
+set bp_location21 [gdb_get_line_number "set breakpoint 21 here"]
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+# Verify that plain vanilla "until <location>" works.
+#
+gdb_test "until $bp_location1" \
+    "main .* at .*:$bp_location1.*" \
+    "until line number"
+
+# Advance up to factorial, outer invocation
+#
+gdb_test "advance factorial" \
+    "factorial .value=6..*$srcfile:$bp_location7.*" \
+    "advance to factorial"
+
+# At this point, 'until' should continue the inferior up to when all the
+# inner invocations of factorial() are completed and we are back at this
+# frame.
+#
+gdb_test "until $bp_location19" \
+    "factorial .value=720.*${srcfile}:$bp_location19.*" \
+    "until factorial, recursive function"
+
+# Finish out to main scope
+#
+gdb_test "finish" \
+    " in main .*$srcfile:$bp_location1.*" \
+    "finish to main"
+
+# Advance to a function called by main (marker2)
+#
+gdb_test "advance marker2" \
+    "marker2 .a=43.*$srcfile1:$bp_location9.*" \
+    "advance to marker2"
+
+# Now issue an until with another function, not called by the current
+# frame, as argument. This should not work, i.e. the program should
+# stop at main, the caller, where we put the 'guard' breakpoint.
+#
+set test_msg "until func, not called by current frame"
+gdb_test_multiple "until marker3" "$test_msg" {
+    -re "main .*at .*${srcfile}:$bp_location20.*$gdb_prompt $" {
+	pass "$test_msg"
+    }
+    -re "main .*at .*${srcfile}:$bp_location21.*$gdb_prompt $" {
+	pass "$test_msg"
+    }
+}
+
+###
+###
+###
+
+# Set reverse execution direction
+# FIXME: command needs to acknowledge, so we can test if it succeeded.
+
+gdb_test "set exec-dir reverse" "" "set reverse execution"
+
+#
+# We should now be at main, after the return from marker2.
+# "Advance" backward into marker2.
+#
+
+gdb_test "advance marker2" \
+    "marker2 .a=43.*$srcfile1:$bp_location9.*" \
+    "reverse-advance to marker2"
+
+# Finish out to main scope (backward)
+
+gdb_test "finish" \
+    " in main .*$srcfile:$bp_location20.*" \
+    "reverse-finish from marker2"
+
+# Advance backward to last line of factorial (outer invocation)
+
+gdb_test "advance $bp_location19" \
+    "factorial .value=720.*${srcfile}:$bp_location19.*" \
+    "reverse-advance to final return of factorial"
+
+# Now do "until" across the recursive calls, 
+# ending up in the same frame where we are now.
+
+gdb_test "until $bp_location7" \
+    "factorial .value=6..*$srcfile:$bp_location7.*" \
+    "reverse-until to entry of factorial"
+
+
Index: gdb.reverse/until-reverse1.c
===================================================================
RCS file: gdb.reverse/until-reverse1.c
diff -N gdb.reverse/until-reverse1.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/until-reverse1.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,52 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 1992, 1993, 1994, 1995, 1999, 2002, 2003, 2007, 2008
+   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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+   Please email any bugs, comments, and/or additions to this file to:
+   bug-gdb@prep.ai.mit.edu  */
+
+/* The code for this file was extracted from the gdb testsuite
+   testcase "break.c". */
+
+/* The following functions do nothing useful.  They are included
+   simply as places to try setting breakpoints at.  They are
+   explicitly "one-line functions" to verify that this case works
+   (some versions of gcc have or have had problems with this).
+  
+   These functions are in a separate source file to prevent an
+   optimizing compiler from inlining them and optimizing them away. */
+
+#ifdef PROTOTYPES
+int marker1 (void) { return (0); }	/* set breakpoint 15 here */
+int marker2 (int a) { return (1); }	/* set breakpoint 8 here */
+void marker3 (char *a, char *b) {}	/* set breakpoint 17 here */
+void marker4 (long d) {}		/* set breakpoint 14 here */
+#else
+int marker1 () { return (0); }		/* set breakpoint 16 here */
+int marker2 (a) int a; { return (1); }	/* set breakpoint 9 here */
+void marker3 (a, b) char *a, *b; {}	/* set breakpoint 18 here */
+void marker4 (d) long d; {}		/* set breakpoint 13 here */
+#endif
+
+/* A structure we use for field name completion tests.  */
+struct some_struct
+{
+  int a_field;
+  int b_field;
+};
+
+struct some_struct values[50];
Index: gdb.reverse/watch-reverse.c
===================================================================
RCS file: gdb.reverse/watch-reverse.c
diff -N gdb.reverse/watch-reverse.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/watch-reverse.c	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,222 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2008, 2009
+   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
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+   Please email any bugs, comments, and/or additions to this file to:
+   bug-gdb@prep.ai.mit.edu  */
+
+#include <stdio.h>
+#include <unistd.h>
+/*
+ *	Since using watchpoints can be very slow, we have to take some pains to
+ *	ensure that we don't run too long with them enabled or we run the risk
+ *	of having the test timeout.  To help avoid this, we insert some marker
+ *	functions in the execution stream so we can set breakpoints at known
+ *	locations, without worrying about invalidating line numbers by changing
+ *	this file.  We use null bodied functions are markers since gdb does
+ *	not support breakpoints at labeled text points at this time.
+ *
+ *	One place we need is a marker for when we start executing our tests
+ *	instructions rather than any process startup code, so we insert one
+ *	right after entering main().  Another is right before we finish, before
+ *	we start executing any process termination code.
+ *
+ *	Another problem we have to guard against, at least for the test
+ *	suite, is that we need to ensure that the line that causes the
+ *	watchpoint to be hit is still the current line when gdb notices
+ *	the hit.  Depending upon the specific code generated by the compiler,
+ *	the instruction after the one that triggers the hit may be part of
+ *	the same line or part of the next line.  Thus we ensure that there
+ *	are always some instructions to execute on the same line after the
+ *	code that should trigger the hit.
+ */
+
+int count = -1;
+int ival1 = -1;
+int ival2 = -1;
+int ival3 = -1;
+int ival4 = -1;
+int ival5 = -1;
+char buf[10];
+struct foo
+{
+  int val;
+};
+struct foo struct1, struct2, *ptr1, *ptr2;
+
+int doread = 0;
+
+char *global_ptr;
+
+void marker1 ()
+{
+}
+
+void marker2 ()
+{
+}
+
+void marker4 ()
+{
+}
+
+void marker5 ()
+{
+}
+
+void marker6 ()
+{
+}
+
+#ifdef PROTOTYPES
+void recurser (int  x)
+#else
+void recurser (x) int  x;
+#endif
+{
+  int  local_x;
+
+  if (x > 0)
+    recurser (x-1);
+  local_x = x;
+}
+
+void
+func2 ()
+{
+  int  local_a;
+  static int  static_b;
+
+  ival5++;
+  local_a = ival5;
+  static_b = local_a;
+}
+
+void
+func3 ()
+{
+  int x;
+  int y;
+
+  x = 0;
+  x = 1;				/* second x assignment */
+  y = 1;
+  y = 2;
+}
+
+int
+func1 ()
+{
+  /* The point of this is that we will set a breakpoint at this call.
+
+     Then, if DECR_PC_AFTER_BREAK equals the size of a function call
+     instruction (true on a sun3 if this is gcc-compiled--FIXME we
+     should use asm() to make it work for any compiler, present or
+     future), then we will end up branching to the location just after
+     the breakpoint.  And we better not confuse that with hitting the
+     breakpoint.  */
+  func2 ();
+  return 73;
+}
+
+void
+func4 ()
+{
+  buf[0] = 3;
+  global_ptr = buf;
+  buf[0] = 7;
+}
+
+int main ()
+{
+#ifdef usestubs
+  set_debug_traps();
+  breakpoint();
+#endif
+  struct1.val = 1;
+  struct2.val = 2;
+  ptr1 = &struct1;
+  ptr2 = &struct2;
+  marker1 ();
+  func1 ();
+  for (count = 0; count < 4; count++) {
+    ival1 = count;
+    ival3 = count; ival4 = count;
+  }
+  ival1 = count; /* Outside loop */
+  ival2 = count;
+  ival3 = count; ival4 = count;
+  marker2 ();
+  if (doread)
+    {
+      static char msg[] = "type stuff for buf now:";
+      write (1, msg, sizeof (msg) - 1);
+      read (0, &buf[0], 5);
+    }
+  marker4 ();
+
+  /* We have a watchpoint on ptr1->val.  It should be triggered if
+     ptr1's value changes.  */
+  ptr1 = ptr2;
+
+  /* This should not trigger the watchpoint.  If it does, then we
+     used the wrong value chain to re-insert the watchpoints or we
+     are not evaluating the watchpoint expression correctly.  */
+  struct1.val = 5;
+  marker5 ();
+
+  /* We have a watchpoint on ptr1->val.  It should be triggered if
+     ptr1's value changes.  */
+  ptr1 = ptr2;
+
+  /* This should not trigger the watchpoint.  If it does, then we
+     used the wrong value chain to re-insert the watchpoints or we
+     are not evaluating the watchpoint expression correctly.  */
+  struct1.val = 5;
+  marker5 ();
+
+  /* We're going to watch locals of func2, to see that out-of-scope
+     watchpoints are detected and properly deleted.
+     */
+  marker6 ();
+
+  /* This invocation is used for watches of a single
+     local variable. */
+  func2 ();
+
+  /* This invocation is used for watches of an expression
+     involving a local variable. */
+  func2 ();
+
+  /* This invocation is used for watches of a static
+     (non-stack-based) local variable. */
+  func2 ();
+
+  /* This invocation is used for watches of a local variable
+     when recursion happens.
+     */
+  marker6 ();
+  recurser (2);
+
+  marker6 ();
+
+  func3 ();
+
+  func4 ();
+
+  return 0;
+}
Index: gdb.reverse/watch-reverse.exp
===================================================================
RCS file: gdb.reverse/watch-reverse.exp
diff -N gdb.reverse/watch-reverse.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gdb.reverse/watch-reverse.exp	24 Jun 2009 20:38:54 -0000
@@ -0,0 +1,131 @@
+# Copyright 2008, 2009 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
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+# Based on a file written by Fred Fish. (fnf@cygnus.com)
+
+#
+# Test reverse debugging with watchpoints
+#
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "watch-reverse"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile] } {
+    return -1
+}
+
+runto main
+
+if [target_info exists gdb,use_precord] {
+    # Activate process record/replay
+    gdb_test "record" "" "Turn on process record"
+    # FIXME: command ought to acknowledge, so we can test if it succeeded.
+}
+
+# Only software watchpoints can be used in reverse
+gdb_test "set can-use-hw-watchpoints 0" "" ""
+
+gdb_test "break marker1" \
+    "Breakpoint $decimal at $hex: file .*$srcfile, line $decimal.*" \
+    "set breakpoint at marker1"
+
+gdb_test "break marker2" \
+    "Breakpoint $decimal at $hex: file .*$srcfile, line $decimal.*" \
+    "set breakpoint at marker2"
+
+gdb_continue_to_breakpoint "marker1" ".*/$srcfile:.*"
+
+gdb_test "watch ival3" \
+    ".*\[Ww\]atchpoint $decimal: ival3.*" \
+    "set watchpoint on ival3"
+
+# Continue until first change, from -1 to 0
+
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = -1.*New value = 0.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit, first time"
+
+# Continue until the next change, from 0 to 1.
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 0.*New value = 1.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit, second time"
+
+# Continue until the next change, from 1 to 2.
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 1.*New value = 2.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit, third time"
+
+# Continue until the next change, from 2 to 3.
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 2.*New value = 3.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit, fourth time"
+
+# Continue until the next change, from 3 to 4.
+# Note that this one is outside the loop.
+
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 3.*New value = 4.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit, fifth time"
+
+# Continue until we hit the finishing marker function.
+# Make sure we hit no more watchpoints.
+
+gdb_continue_to_breakpoint "marker2" ".*/$srcfile:.*"
+
+###
+###
+###
+
+# FIXME 'set exec-dir' command should give some output so we can test.
+gdb_test "set exec-direction reverse" "" "set reverse"
+
+# Reverse until the previous change, from 4 to 3
+# Note that this one is outside the loop
+
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 4.*New value = 3.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit in reverse, first time"
+
+# Reverse until the previous change, from 3 to 2.
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 3.*New value = 2.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit in reverse, second time"
+
+# Reverse until the previous change, from 2 to 1.
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 2.*New value = 1.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit in reverse, third time"
+
+# Reverse until the previous change, from 1 to 0.
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 1.*New value = 0.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit in reverse, fourth time"
+
+# Reverse until first change, from 0 to -1
+
+gdb_test "continue" \
+    ".*\[Ww\]atchpoint.*ival3.*Old value = 0.*New value = -1.*ival3 = count; ival4 = count;.*" \
+    "watchpoint hit in reverse, fifth time"
+
+
+return 0

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]