2009-06-27 Michael Snyder <msnyder@vmware.com>
authorMichael Snyder <msnyder@vmware.com>
Sat, 27 Jun 2009 18:49:20 +0000 (18:49 +0000)
committerMichael Snyder <msnyder@vmware.com>
Sat, 27 Jun 2009 18:49:20 +0000 (18:49 +0000)
* 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/ms1.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/ur1.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.

23 files changed:
gdb/testsuite/ChangeLog
gdb/testsuite/configure
gdb/testsuite/configure.ac
gdb/testsuite/gdb.reverse/Makefile.in [new file with mode: 0644]
gdb/testsuite/gdb.reverse/break-reverse.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/break-reverse.exp [new file with mode: 0644]
gdb/testsuite/gdb.reverse/consecutive-reverse.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/consecutive-reverse.exp [new file with mode: 0644]
gdb/testsuite/gdb.reverse/finish-reverse.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/finish-reverse.exp [new file with mode: 0644]
gdb/testsuite/gdb.reverse/machinestate.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/machinestate.exp [new file with mode: 0644]
gdb/testsuite/gdb.reverse/ms1.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/shr2.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/solib-reverse.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/solib-reverse.exp [new file with mode: 0644]
gdb/testsuite/gdb.reverse/step-reverse.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/step-reverse.exp [new file with mode: 0644]
gdb/testsuite/gdb.reverse/until-reverse.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/until-reverse.exp [new file with mode: 0644]
gdb/testsuite/gdb.reverse/ur1.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/watch-reverse.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/watch-reverse.exp [new file with mode: 0644]

index 2f88eeb14fdb7a8af0f5d20bfd5970c109dd9447..e5bd21bbffef393bc1543161a9cfddce9936fb55 100644 (file)
@@ -1,3 +1,29 @@
+2009-06-27  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/ms1.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/ur1.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.
+
 2009-06-26  Doug Evans  <dje@google.com>
 
        * gdb.base/psymtab.exp: Turn off pending breakpoints.
index ef35b13865731449ad74d8bd285f4ed41125ee17..3973a2a34b1f30ad6185d143439faf3780b0bc97 100755 (executable)
@@ -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 3d8fae4a616897ac6157eccbba4ce55e46571511..bb98e6f79f62eac951d9bcb39ae0688a8bfe7bad 100644 (file)
@@ -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])
diff --git a/gdb/testsuite/gdb.reverse/Makefile.in b/gdb/testsuite/gdb.reverse/Makefile.in
new file mode 100644 (file)
index 0000000..43b2f58
--- /dev/null
@@ -0,0 +1,19 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES   = break-reverse consecutive-reverse finish-reverse \
+       machinestate solib-reverse step-reverse until-reverse \
+       watch-reverse 
+
+MISCELLANEOUS = 
+
+all info install-info dvi install uninstall installcheck check:
+       @echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+       rm -f *~ *.o *.x *.ci *.sl a.out core
+       rm -f $(EXECUTABLES) $(MISCELLANEOUS)
+
+distclean maintainer-clean realclean: clean
+       rm -f Makefile config.status config.log site.*
+
diff --git a/gdb/testsuite/gdb.reverse/break-reverse.c b/gdb/testsuite/gdb.reverse/break-reverse.c
new file mode 100644 (file)
index 0000000..f35e32b
--- /dev/null
@@ -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 */
diff --git a/gdb/testsuite/gdb.reverse/break-reverse.exp b/gdb/testsuite/gdb.reverse/break-reverse.exp
new file mode 100644 (file)
index 0000000..db8f351
--- /dev/null
@@ -0,0 +1,86 @@
+#   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 is part of the GDB testsuite.  It tests 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"
+    }
+}
diff --git a/gdb/testsuite/gdb.reverse/consecutive-reverse.c b/gdb/testsuite/gdb.reverse/consecutive-reverse.c
new file mode 100644 (file)
index 0000000..8452141
--- /dev/null
@@ -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 ();
+}
diff --git a/gdb/testsuite/gdb.reverse/consecutive-reverse.exp b/gdb/testsuite/gdb.reverse/consecutive-reverse.exp
new file mode 100644 (file)
index 0000000..e2ba83a
--- /dev/null
@@ -0,0 +1,125 @@
+#   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 is part of the GDB testsuite.  It tests stepping over
+# consecutive instructions in reverse.
+
+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"
+    }
+}
diff --git a/gdb/testsuite/gdb.reverse/finish-reverse.c b/gdb/testsuite/gdb.reverse/finish-reverse.c
new file mode 100644 (file)
index 0000000..aeea295
--- /dev/null
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.reverse/finish-reverse.exp b/gdb/testsuite/gdb.reverse/finish-reverse.exp
new file mode 100644 (file)
index 0000000..69d5df2
--- /dev/null
@@ -0,0 +1,260 @@
+# 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 is part of the GDB testsuite.  It tests 'finish' with
+# reverse debugging.
+
+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
diff --git a/gdb/testsuite/gdb.reverse/machinestate.c b/gdb/testsuite/gdb.reverse/machinestate.c
new file mode 100644 (file)
index 0000000..8eb4595
--- /dev/null
@@ -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 */
+}
diff --git a/gdb/testsuite/gdb.reverse/machinestate.exp b/gdb/testsuite/gdb.reverse/machinestate.exp
new file mode 100644 (file)
index 0000000..97faf2a
--- /dev/null
@@ -0,0 +1,230 @@
+# 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 is part of the GDB testsuite.  
+# 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 ms1.c
+
+if { [prepare_for_testing $testfile.exp $testfile {machinestate.c ms1.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"
+
diff --git a/gdb/testsuite/gdb.reverse/ms1.c b/gdb/testsuite/gdb.reverse/ms1.c
new file mode 100644 (file)
index 0000000..435ff12
--- /dev/null
@@ -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)
+{
+}
diff --git a/gdb/testsuite/gdb.reverse/shr2.c b/gdb/testsuite/gdb.reverse/shr2.c
new file mode 100644 (file)
index 0000000..1aa3ff3
--- /dev/null
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.reverse/solib-reverse.c b/gdb/testsuite/gdb.reverse/solib-reverse.c
new file mode 100644 (file)
index 0000000..cf96ee9
--- /dev/null
@@ -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 */
+}
+
diff --git a/gdb/testsuite/gdb.reverse/solib-reverse.exp b/gdb/testsuite/gdb.reverse/solib-reverse.exp
new file mode 100644 (file)
index 0000000..8ad2be8
--- /dev/null
@@ -0,0 +1,124 @@
+# 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 is part of the GDB testsuite.  It tests 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"
diff --git a/gdb/testsuite/gdb.reverse/step-reverse.c b/gdb/testsuite/gdb.reverse/step-reverse.c
new file mode 100644 (file)
index 0000000..1584bd2
--- /dev/null
@@ -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);
+}
+
diff --git a/gdb/testsuite/gdb.reverse/step-reverse.exp b/gdb/testsuite/gdb.reverse/step-reverse.exp
new file mode 100644 (file)
index 0000000..050b750
--- /dev/null
@@ -0,0 +1,251 @@
+# 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 is part of the GDB testsuite.  It tests reverse stepping.
+# 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
diff --git a/gdb/testsuite/gdb.reverse/until-reverse.c b/gdb/testsuite/gdb.reverse/until-reverse.c
new file mode 100644 (file)
index 0000000..b1d1d3b
--- /dev/null
@@ -0,0 +1,146 @@
+/* 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/>.  */
+
+#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;
+}
diff --git a/gdb/testsuite/gdb.reverse/until-reverse.exp b/gdb/testsuite/gdb.reverse/until-reverse.exp
new file mode 100644 (file)
index 0000000..6667fa2
--- /dev/null
@@ -0,0 +1,129 @@
+# 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 is part of the GDB testsuite.  It tests 'until' and 
+# 'advance' in reverse debugging.
+
+if ![target_info exists gdb,can_reverse] {
+    return
+}
+
+set testfile "until-reverse"
+set srcfile ${testfile}.c
+set srcfile1 ur1.c
+
+if { [prepare_for_testing $testfile.exp $testfile {until-reverse.c ur1.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"
+
+
diff --git a/gdb/testsuite/gdb.reverse/ur1.c b/gdb/testsuite/gdb.reverse/ur1.c
new file mode 100644 (file)
index 0000000..dc8bef4
--- /dev/null
@@ -0,0 +1,49 @@
+/* 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/>.  */
+
+/* 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];
diff --git a/gdb/testsuite/gdb.reverse/watch-reverse.c b/gdb/testsuite/gdb.reverse/watch-reverse.c
new file mode 100644 (file)
index 0000000..e487f2c
--- /dev/null
@@ -0,0 +1,219 @@
+/* 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 <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;
+}
diff --git a/gdb/testsuite/gdb.reverse/watch-reverse.exp b/gdb/testsuite/gdb.reverse/watch-reverse.exp
new file mode 100644 (file)
index 0000000..ab9efa8
--- /dev/null
@@ -0,0 +1,127 @@
+# 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/>.
+
+# Based on a file written by Fred Fish. (fnf@cygnus.com)
+# This file is part of the GDB testsuite.  It tests 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