This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch v3 22/23] record-btrace: add (reverse-)stepping support
- From: Markus Metzger <markus dot t dot metzger at intel dot com>
- To: jan dot kratochvil at redhat dot com
- Cc: gdb-patches at sourceware dot org, Eli Zaretskii <eliz at gnu dot org>
- Date: Mon, 10 Jun 2013 10:04:55 +0200
- Subject: [patch v3 22/23] record-btrace: add (reverse-)stepping support
- References: <1370851496-32313-1-git-send-email-markus dot t dot metzger at intel dot com>
There's an open regarding frame unwinding. When I start stepping, the frame
cache will still be based on normal unwinding as will the frame cached in the
thread's stepping context. This will prevent me from detecting that i stepped
into a subroutine.
To overcome that, I'm resetting the frame cache and setting the thread's
stepping cache based on the current frame - which is now computed using branch
tracing unwind. I had to split get_current_frame to avoid checks that would
prevent me from doing this.
I also need to call registers_changed when I return from to_wait. Otherwise,
the PC is not updated and the current location is shown incorrectly. Not sure
whether this is intended or whether I'm unintentionally working around
something, here.
It looks like I don't need any special support for breakpoints. Is there a
scenario where normal breakpoints won't work?
Regarding testing, I added new tests for record-btrace stepping. At least some
of the gdb.reverse tests would be applicable to record-btrace, as well. Yet, I
don't see how I could run them once with record-full and once with
record-btrace.
CC: Eli Zaretskii <eliz@gnu.org>
2013-06-10 Markus Metzger <markus.t.metzger@intel.com>
* btrace.h (btrace_thread_flag): New.
(struct btrace_thread_info)<flags>: New.
* frame.c (get_current_frame_nocheck): New.
(get_current_frame): Call get_current_frame_nocheck.
* frame.h (get_current_frame_nocheck): New.
* record-btrace.c (record_btrace_resume_thread,
record_btrace_find_thread_to_move, btrace_step_no_history,
btrace_step_stopped, record_btrace_start_replaying,
record_btrace_step_thread): New.
(record_btrace_resume, record_btrace_wait): Extend.
(record_btrace_can_execute_reverse): New.
(record_btrace_set_replay): Split into this, ...
(record_btrace_stop_replaying): ... this, ...
(record_btrace_clear_histories): ... and this.
(init_record_btrace_ops): Init to_can_execute_reverse.
* NEWS: Announce it.
testsuite/
* gdb.btrace/delta.exp: Check reverse stepi.
* gdb.btrace/finish.exp: New.
* gdb.btrace/next.exp: New.
* gdb.btrace/nexti.exp: New.
* gdb.btrace/record_goto.c: Add comments.
* gdb.btrace/step.exp: New.
* gdb.btrace/stepi.exp: New.
doc/
* gdb.texinfo: Document limited reverse/replay support
for target record-btrace.
---
gdb/NEWS | 4 +
gdb/btrace.h | 22 ++
gdb/doc/gdb.texinfo | 4 +-
gdb/frame.c | 38 +++--
gdb/frame.h | 4 +
gdb/record-btrace.c | 335 ++++++++++++++++++++++++++++++--
gdb/testsuite/gdb.btrace/delta.exp | 13 ++
gdb/testsuite/gdb.btrace/finish.exp | 70 +++++++
gdb/testsuite/gdb.btrace/next.exp | 89 +++++++++
gdb/testsuite/gdb.btrace/nexti.exp | 89 +++++++++
gdb/testsuite/gdb.btrace/record_goto.c | 36 ++--
gdb/testsuite/gdb.btrace/step.exp | 113 +++++++++++
gdb/testsuite/gdb.btrace/stepi.exp | 114 +++++++++++
13 files changed, 879 insertions(+), 52 deletions(-)
create mode 100644 gdb/testsuite/gdb.btrace/finish.exp
create mode 100644 gdb/testsuite/gdb.btrace/next.exp
create mode 100644 gdb/testsuite/gdb.btrace/nexti.exp
create mode 100644 gdb/testsuite/gdb.btrace/step.exp
create mode 100644 gdb/testsuite/gdb.btrace/stepi.exp
diff --git a/gdb/NEWS b/gdb/NEWS
index cbec17b..857b493 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -12,6 +12,10 @@
Nios II ELF nios2*-*-elf
Nios II GNU/Linux nios2*-*-linux
+* The btrace record target supports limited replay and reverse
+ execution. The target does not record data and does therefore
+ not allow reading memory or registers.
+
* The btrace record target supports the 'record goto' command.
For locations inside the execution trace, the back trace is computed
based on the information stored in the execution trace.
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 04466d3..22fabb5 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -149,6 +149,25 @@ struct btrace_call_history
struct btrace_call_iterator end;
};
+/* Branch trace thread flags. */
+enum btrace_thread_flag
+ {
+ /* The thread is to be stepped forwards. */
+ BTHR_STEP = (1 << 0),
+
+ /* The thread is to be stepped backwards. */
+ BTHR_RSTEP = (1 << 1),
+
+ /* The thread is to be continued forwards. */
+ BTHR_CONT = (1 << 2),
+
+ /* The thread is to be continued backwards. */
+ BTHR_RCONT = (1 << 3),
+
+ /* The thread is to be moved. */
+ BTHR_MOVE = (BTHR_STEP | BTHR_RSTEP | BTHR_CONT | BTHR_RCONT)
+ };
+
/* Branch trace information per thread.
This represents the branch trace configuration as well as the entry point
@@ -176,6 +195,9 @@ struct btrace_thread_info
becomes zero. */
int level;
+ /* A bit-vector of btrace_thread_flag. */
+ unsigned int flags;
+
/* The instruction history iterator. */
struct btrace_insn_history *insn_history;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5884ca4..602897f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6192,8 +6192,8 @@ replay implementation. This method allows replaying and reverse
execution.
@item btrace
-Hardware-supported instruction recording. This method does not allow
-replaying and reverse execution.
+Hardware-supported instruction recording. This method does not record
+data. It allows limited replay and reverse execution.
This recording method may not be available on all processors.
@end table
diff --git a/gdb/frame.c b/gdb/frame.c
index 5c080eb..f2dbdb4 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1367,6 +1367,29 @@ unwind_to_current_frame (struct ui_out *ui_out, void *args)
return 0;
}
+/* See frame.h. */
+
+struct frame_info *get_current_frame_nocheck (void)
+{
+ if (current_frame == NULL)
+ {
+ struct frame_info *sentinel_frame =
+ create_sentinel_frame (current_program_space, get_current_regcache ());
+
+ if (catch_exceptions (current_uiout, unwind_to_current_frame,
+ sentinel_frame, RETURN_MASK_ERROR) != 0)
+ {
+ /* Oops! Fake a current frame? Is this useful? It has a PC
+ of zero, for instance. */
+ current_frame = sentinel_frame;
+ }
+ }
+
+ return current_frame;
+}
+
+/* See frame.h. */
+
struct frame_info *
get_current_frame (void)
{
@@ -1381,6 +1404,7 @@ get_current_frame (void)
error (_("No stack."));
if (!target_has_memory)
error (_("No memory."));
+
/* Traceframes are effectively a substitute for the live inferior. */
if (get_traceframe_number () < 0)
{
@@ -1392,19 +1416,7 @@ get_current_frame (void)
error (_("Target is executing."));
}
- if (current_frame == NULL)
- {
- struct frame_info *sentinel_frame =
- create_sentinel_frame (current_program_space, get_current_regcache ());
- if (catch_exceptions (current_uiout, unwind_to_current_frame,
- sentinel_frame, RETURN_MASK_ERROR) != 0)
- {
- /* Oops! Fake a current frame? Is this useful? It has a PC
- of zero, for instance. */
- current_frame = sentinel_frame;
- }
- }
- return current_frame;
+ return get_current_frame_nocheck ();
}
/* The "selected" stack frame is used by default for local and arg
diff --git a/gdb/frame.h b/gdb/frame.h
index db4cc52..e3f004b 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -240,6 +240,10 @@ enum frame_type
error. */
extern struct frame_info *get_current_frame (void);
+/* Similar to get_current_frame except that we omit all checks. May
+ return NULL if unwinding fails. */
+extern struct frame_info *get_current_frame_nocheck (void);
+
/* Does the current target interface have enough state to be able to
query the current inferior for frame info, and is the inferior in a
state where that is possible? */
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 994f9d5..14791da 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1186,14 +1186,40 @@ static const struct frame_unwind record_btrace_frame_unwind =
record_btrace_frame_dealloc_cache
};
+/* Indicate that TP should be resumed according to FLAG. */
+
+static void
+record_btrace_resume_thread (struct thread_info *tp,
+ enum btrace_thread_flag flag)
+{
+ struct btrace_thread_info *btinfo;
+
+ DEBUG ("resuming %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flag);
+
+ btinfo = &tp->btrace;
+
+ if ((btinfo->flags & BTHR_MOVE) != 0)
+ error (_("Thread already moving."));
+
+ /* Fetch the latest branch trace. */
+ btrace_fetch (tp);
+
+ btinfo->flags |= flag;
+}
+
/* The to_resume method of target record-btrace. */
static void
record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
enum gdb_signal signal)
{
+ struct thread_info *tp;
+ enum btrace_thread_flag flag;
+
+ DEBUG ("resume %s: %s", target_pid_to_str (ptid), step ? "step" : "cont");
+
/* As long as we're not replaying, just forward the request. */
- if (!record_btrace_is_replaying ())
+ if (!record_btrace_is_replaying () && execution_direction != EXEC_REVERSE)
{
for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
if (ops->to_resume != NULL)
@@ -1202,7 +1228,256 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
error (_("Cannot find target for stepping."));
}
- error (_("You can't do this from here. Do 'record goto end', first."));
+ /* We can't pass signals when replaying. */
+ if (signal != GDB_SIGNAL_0)
+ error (_("You can't resume with signal from here."));
+
+ /* Compute the btrace thread flag for the requested move. */
+ if (step == 0)
+ flag = execution_direction == EXEC_REVERSE ? BTHR_RCONT : BTHR_CONT;
+ else
+ flag = execution_direction == EXEC_REVERSE ? BTHR_RSTEP : BTHR_STEP;
+
+ /* Find the thread to move. */
+ if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid))
+ {
+ ALL_THREADS (tp)
+ record_btrace_resume_thread (tp, flag);
+ }
+ else
+ {
+ tp = find_thread_ptid (ptid);
+ if (tp == NULL)
+ error (_("Cannot find thread to resume."));
+
+ record_btrace_resume_thread (tp, flag);
+ }
+
+ /* We just indicate the resume intent here. The actual stepping happens in
+ record_btrace_wait below. */
+}
+
+/* Find a thread to move. */
+
+static struct thread_info *
+record_btrace_find_thread_to_move (ptid_t ptid)
+{
+ struct thread_info *tp;
+
+ /* First check the parameter thread. */
+ tp = find_thread_ptid (ptid);
+ if (tp != NULL && (tp->btrace.flags & BTHR_MOVE) != 0)
+ return tp;
+
+ /* Otherwise, find one other thread that has been resumed. */
+ ALL_THREADS (tp)
+ if ((tp->btrace.flags & BTHR_MOVE) != 0)
+ return tp;
+
+ return NULL;
+}
+
+/* Return a targetwait status indicating that we ran out of history. */
+
+static struct target_waitstatus
+btrace_step_no_history (void)
+{
+ struct target_waitstatus status;
+
+ status.kind = TARGET_WAITKIND_NO_HISTORY;
+
+ return status;
+}
+
+/* Return a targetwait status indicating that we stopped. */
+
+static struct target_waitstatus
+btrace_step_stopped (void)
+{
+ struct target_waitstatus status;
+
+ status.kind = TARGET_WAITKIND_STOPPED;
+ status.value.sig = GDB_SIGNAL_TRAP;
+
+ return status;
+}
+
+/* Clear the record histories. */
+
+static void
+record_btrace_clear_histories (struct btrace_thread_info *btinfo)
+{
+ xfree (btinfo->insn_history);
+ xfree (btinfo->call_history);
+
+ btinfo->insn_history = NULL;
+ btinfo->call_history = NULL;
+}
+
+/* Stop replaying a thread. */
+
+static struct btrace_insn_iterator *
+record_btrace_start_replaying (struct btrace_thread_info *btinfo)
+{
+ struct btrace_insn_iterator *replay;
+ const struct btrace_insn *insn;
+ struct symtab_and_line sal;
+ struct frame_info *frame;
+
+ /* We can't start replaying without trace. */
+ if (btinfo->begin == NULL)
+ return NULL;
+
+ /* We start replaying at the end of the branch trace. This corresponds to the
+ current instruction. */
+ replay = xzalloc (sizeof (*replay));
+ btrace_insn_end (replay, btinfo);
+
+ /* We're not replaying, yet. */
+ gdb_assert (btinfo->replay == NULL);
+ btinfo->replay = replay;
+
+ /* Make sure we're not using any stale registers or frames. */
+ registers_changed ();
+ reinit_frame_cache ();
+
+ /* We just started replaying. The frame id cached for stepping is based
+ on unwinding, not on branch tracing. Recompute it. */
+ frame = get_current_frame_nocheck ();
+ insn = btrace_insn_get (replay);
+ sal = find_pc_line (insn->pc, 0);
+ set_step_info (frame, sal);
+
+ return replay;
+}
+
+/* Stop replaying a thread. */
+
+static void
+record_btrace_stop_replaying (struct btrace_thread_info *btinfo)
+{
+ xfree (btinfo->replay);
+ btinfo->replay = NULL;
+}
+
+/* Step a single thread. */
+
+static struct target_waitstatus
+record_btrace_step_thread (struct thread_info *tp)
+{
+ struct btrace_insn_iterator *replay, end;
+ struct btrace_thread_info *btinfo;
+ struct address_space *aspace;
+ unsigned int steps, flag;
+
+ btinfo = &tp->btrace;
+ replay = btinfo->replay;
+
+ flag = btinfo->flags & BTHR_MOVE;
+ btinfo->flags &= ~BTHR_MOVE;
+
+ DEBUG ("wait %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flag);
+
+ switch (flag)
+ {
+ default:
+ internal_error (__FILE__, __LINE__, _("invalid stepping type."));
+
+ case BTHR_STEP:
+ /* We're done if we're not replaying. */
+ if (replay == NULL)
+ return btrace_step_no_history ();
+
+ /* We are always able to step at least once. */
+ steps = btrace_insn_next (replay, 1);
+ gdb_assert (steps == 1);
+
+ /* Determine the end of the instruction trace. */
+ btrace_insn_end (&end, btinfo);
+
+ /* We stop replaying if we reached the end of the trace. */
+ if (btrace_insn_cmp (replay, &end) == 0)
+ record_btrace_stop_replaying (btinfo);
+
+ return btrace_step_stopped ();
+
+ case BTHR_RSTEP:
+ /* Start replaying if we're not already doing so. */
+ if (replay == NULL)
+ replay = record_btrace_start_replaying (btinfo);
+
+ /* If we can't step any further, we reached the end of the history. */
+ steps = btrace_insn_prev (replay, 1);
+ if (steps == 0)
+ return btrace_step_no_history ();
+
+ return btrace_step_stopped ();
+
+ case BTHR_CONT:
+ /* We're done if we're not replaying. */
+ if (replay == NULL)
+ return btrace_step_no_history ();
+
+ /* I'd much rather go from TP to its inferior, but how? */
+ aspace = current_inferior ()->aspace;
+
+ /* Determine the end of the instruction trace. */
+ btrace_insn_end (&end, btinfo);
+
+ for (;;)
+ {
+ const struct btrace_insn *insn;
+
+ /* We are always able to step at least once. */
+ steps = btrace_insn_next (replay, 1);
+ gdb_assert (steps == 1);
+
+ /* We stop replaying if we reached the end of the trace. */
+ if (btrace_insn_cmp (replay, &end) == 0)
+ {
+ record_btrace_stop_replaying (btinfo);
+ return btrace_step_no_history ();
+ }
+
+ insn = btrace_insn_get (replay);
+ gdb_assert (insn);
+
+ DEBUG ("wait %d (%s): stepping ... %s", tp->num,
+ target_pid_to_str (tp->ptid),
+ core_addr_to_string_nz (insn->pc));
+
+ if (breakpoint_here_p (aspace, insn->pc))
+ return btrace_step_stopped ();
+ }
+
+ case BTHR_RCONT:
+ /* Start replaying if we're not already doing so. */
+ if (replay == NULL)
+ replay = record_btrace_start_replaying (btinfo);
+
+ /* I'd much rather go from TP to its inferior, but how? */
+ aspace = current_inferior ()->aspace;
+
+ for (;;)
+ {
+ const struct btrace_insn *insn;
+
+ /* If we can't step any further, we're done. */
+ steps = btrace_insn_prev (replay, 1);
+ if (steps == 0)
+ return btrace_step_no_history ();
+
+ insn = btrace_insn_get (replay);
+ gdb_assert (insn);
+
+ DEBUG ("wait %d (%s): reverse-stepping ... %s", tp->num,
+ target_pid_to_str (tp->ptid),
+ core_addr_to_string_nz (insn->pc));
+
+ if (breakpoint_here_p (aspace, insn->pc))
+ return btrace_step_stopped ();
+ }
+ }
}
/* The to_wait method of target record-btrace. */
@@ -1211,8 +1486,12 @@ static ptid_t
record_btrace_wait (struct target_ops *ops, ptid_t ptid,
struct target_waitstatus *status, int options)
{
+ struct thread_info *tp;
+
+ DEBUG ("wait %s (0x%x)", target_pid_to_str (ptid), options);
+
/* As long as we're not replaying, just forward the request. */
- if (!record_btrace_is_replaying ())
+ if (!record_btrace_is_replaying () && execution_direction != EXEC_REVERSE)
{
for (ops = ops->beneath; ops != NULL; ops = ops->beneath)
if (ops->to_wait != NULL)
@@ -1221,7 +1500,35 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
error (_("Cannot find target for stepping."));
}
- error (_("You can't do this from here. Do 'record goto end', first."));
+ /* Let's find a thread to move. */
+ tp = record_btrace_find_thread_to_move (ptid);
+ if (tp == NULL)
+ {
+ DEBUG ("wait %s: no thread", target_pid_to_str (ptid));
+
+ status->kind = TARGET_WAITKIND_IGNORE;
+ return minus_one_ptid;
+ }
+
+ /* We only move a single thread. We're not able to correlate threads. */
+ *status = record_btrace_step_thread (tp);
+
+ /* Start record histories anew from the current position. */
+ record_btrace_clear_histories (&tp->btrace);
+
+ /* GDB seems to need this. Without, a stale PC seems to be used resulting in
+ the current location to be displayed incorrectly. */
+ registers_changed ();
+
+ return tp->ptid;
+}
+
+/* The to_can_execute_reverse method of target record-btrace. */
+
+static int
+record_btrace_can_execute_reverse (void)
+{
+ return 1;
}
/* The to_find_new_threads method of target record-btrace. */
@@ -1249,30 +1556,19 @@ record_btrace_set_replay (struct btrace_thread_info *btinfo,
const struct btrace_insn_iterator *it)
{
if (it == NULL || it->function == NULL)
- {
- if (btinfo->replay == NULL)
- return;
-
- xfree (btinfo->replay);
- btinfo->replay = NULL;
- }
+ record_btrace_stop_replaying (btinfo);
else
{
if (btinfo->replay == NULL)
- btinfo->replay = xzalloc (sizeof (*btinfo->replay));
+ record_btrace_start_replaying (btinfo);
else if (btrace_insn_cmp (btinfo->replay, it) == 0)
return;
*btinfo->replay = *it;
}
- /* Clear the function call and instruction histories so we start anew
- from the new replay position. */
- xfree (btinfo->insn_history);
- xfree (btinfo->call_history);
-
- btinfo->insn_history = NULL;
- btinfo->call_history = NULL;
+ /* Start anew from the new replay position. */
+ record_btrace_clear_histories (btinfo);
registers_changed ();
reinit_frame_cache ();
@@ -1368,6 +1664,7 @@ init_record_btrace_ops (void)
ops->to_goto_record_begin = record_btrace_goto_begin;
ops->to_goto_record_end = record_btrace_goto_end;
ops->to_goto_record = record_btrace_goto;
+ ops->to_can_execute_reverse = record_btrace_can_execute_reverse;
ops->to_stratum = record_stratum;
ops->to_magic = OPS_MAGIC;
}
diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp
index 9ee2629..49d151e 100644
--- a/gdb/testsuite/gdb.btrace/delta.exp
+++ b/gdb/testsuite/gdb.btrace/delta.exp
@@ -61,3 +61,16 @@ gdb_test "record instruction-history /f 1" "
1\t 0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tmov *\\\$0x0,%eax\r" "delta, 4.2"
gdb_test "record function-call-history /c 1" "
1\tmain\r" "delta, 4.3"
+
+# check that we can reverse-stepi that instruction
+gdb_test "reverse-stepi"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 1 instructions in 1 functions for .*\r
+Replay in progress\. At instruction 1\." "delta, 5.1"
+
+# and back
+gdb_test "stepi"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 1 instructions in 1 functions for .*" "delta, 5.2"
diff --git a/gdb/testsuite/gdb.btrace/finish.exp b/gdb/testsuite/gdb.btrace/finish.exp
new file mode 100644
index 0000000..87ebfe1
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/finish.exp
@@ -0,0 +1,70 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <markus.t.metzger@intel.com>
+#
+# 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/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# start inferior
+standard_testfile x86-record_goto.S
+if [prepare_for_testing finish.exp $testfile $srcfile] {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+# trace the call to the test function
+gdb_test_no_output "record btrace"
+gdb_test "next"
+
+# let's go somewhere where we can finish
+gdb_test "record goto 32" ".*fun1\.1.*" "finish, 1.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 32\." "finish, 1.2"
+
+# let's finish into fun2
+gdb_test "finish" ".*fun2\.3.*" "finish, 2.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 35\." "finish, 2.2"
+
+# now let's reverse-finish into fun3
+gdb_test "reverse-finish" ".*fun3\.3.*" "finish, 3.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 27\." "finish, 3.2"
+
+# finish again - into fun4
+gdb_test "finish" ".*fun4\.5.*" "finish, 4.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 39\." "finish, 4.2"
+
+# and reverse-finish again - into main
+gdb_test "reverse-finish" ".*main\.2.*" "finish, 5.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 1\." "finish, 5.2"
diff --git a/gdb/testsuite/gdb.btrace/next.exp b/gdb/testsuite/gdb.btrace/next.exp
new file mode 100644
index 0000000..12a5e8e
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/next.exp
@@ -0,0 +1,89 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <markus.t.metzger@intel.com>
+#
+# 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/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# start inferior
+standard_testfile x86-record_goto.S
+if [prepare_for_testing next.exp $testfile $srcfile] {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+# trace the call to the test function
+gdb_test_no_output "record btrace"
+gdb_test "next"
+
+# we start with stepping to make sure that the trace is fetched automatically
+# the call is outside of our trace
+gdb_test "reverse-next" ".*main\.2.*" "next, 1.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 1\." "next, 1.2"
+
+# we can't reverse-step any further
+gdb_test "reverse-next" "No more reverse-execution history\.\r
+.*main\.2.*" "next, 1.3"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 1\." "next, 1.4"
+
+# but we can step back again
+gdb_test "next" ".*main\.3.*" "next, 1.5"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r" "next, 1.6"
+
+# let's go somewhere where we can step some more
+gdb_test "record goto 22" ".*fun3\.2.*" "next, 2.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 22\." "next, 2.2"
+
+gdb_test "next" ".*fun3\.3.*" "next, 2.3"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 27\." "next, 2.4"
+
+gdb_test "next" ".*fun3\.4.*" "next, 2.5"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 37\." "next, 2.6"
+
+# and back again
+gdb_test "reverse-next" ".*fun3\.3.*" "next, 3.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 27\." "next, 3.2"
+
+gdb_test "reverse-next" ".*fun3\.2.*" "next, 3.3"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 22\." "next, 3.4"
diff --git a/gdb/testsuite/gdb.btrace/nexti.exp b/gdb/testsuite/gdb.btrace/nexti.exp
new file mode 100644
index 0000000..559a9b7
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/nexti.exp
@@ -0,0 +1,89 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <markus.t.metzger@intel.com>
+#
+# 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/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# start inferior
+standard_testfile x86-record_goto.S
+if [prepare_for_testing nexti.exp $testfile $srcfile] {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+# trace the call to the test function
+gdb_test_no_output "record btrace"
+gdb_test "next"
+
+# we start with stepping to make sure that the trace is fetched automatically
+# the call is outside of our trace
+gdb_test "reverse-nexti" ".*main\.2.*" "nexti, 1.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 1\." "nexti, 1.2"
+
+# we can't reverse-step any further
+gdb_test "reverse-nexti" "No more reverse-execution history\.\r
+.*main\.2.*" "nexti, 1.3"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 1\." "nexti, 1.4"
+
+# but we can step back again
+gdb_test "nexti" ".*main\.3.*" "next, 1.5"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r" "next, 1.6"
+
+# let's go somewhere where we can step some more
+gdb_test "record goto 22" ".*fun3\.2.*" "nexti, 2.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 22\." "nexti, 2.2"
+
+gdb_test "nexti" ".*fun3\.3.*" "nexti, 2.3"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 27\." "nexti, 2.4"
+
+gdb_test "nexti" ".*fun3\.4.*" "nexti, 2.5"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 37\." "nexti, 2.6"
+
+# and back again
+gdb_test "reverse-nexti" ".*fun3\.3.*" "nexti, 3.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 27\." "nexti, 3.2"
+
+gdb_test "reverse-nexti" ".*fun3\.2.*" "nexti, 3.3"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 22\." "nexti, 3.4"
diff --git a/gdb/testsuite/gdb.btrace/record_goto.c b/gdb/testsuite/gdb.btrace/record_goto.c
index 1250708..90537f9 100644
--- a/gdb/testsuite/gdb.btrace/record_goto.c
+++ b/gdb/testsuite/gdb.btrace/record_goto.c
@@ -19,33 +19,33 @@
void
fun1 (void)
-{
-}
+{ /* fun1.1 */
+} /* fun1.2 */
void
fun2 (void)
-{
- fun1 ();
-}
+{ /* fun2.1 */
+ fun1 (); /* fun2.2 */
+} /* fun2.3 */
void
fun3 (void)
-{
- fun1 ();
- fun2 ();
-}
+{ /* fun3.1 */
+ fun1 (); /* fun3.2 */
+ fun2 (); /* fun3.3 */
+} /* fun3.4 */
void
fun4 (void)
-{
- fun1 ();
- fun2 ();
- fun3 ();
-}
+{ /* fun4.1 */
+ fun1 (); /* fun4.2 */
+ fun2 (); /* fun4.3 */
+ fun3 (); /* fun4.4 */
+} /* fun4.5 */
int
main (void)
-{
- fun4 ();
- return 0;
-}
+{ /* main.1 */
+ fun4 (); /* main.2 */
+ return 0; /* main.3 */
+} /* main.4 */
diff --git a/gdb/testsuite/gdb.btrace/step.exp b/gdb/testsuite/gdb.btrace/step.exp
new file mode 100644
index 0000000..bb8942e
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/step.exp
@@ -0,0 +1,113 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <markus.t.metzger@intel.com>
+#
+# 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/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# start inferior
+standard_testfile x86-record_goto.S
+if [prepare_for_testing step.exp $testfile $srcfile] {
+ return -1
+}
+
+if ![runto_main] {
+ return -1
+}
+
+# trace the call to the test function
+gdb_test_no_output "record btrace"
+gdb_test "next"
+
+# let's start by stepping back into the function we just returned from
+gdb_test "reverse-step" ".*fun4\.5.*" "step, 1.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 39\." "step, 1.2"
+
+# again
+gdb_test "reverse-step" ".*fun3\.4.*" "step, 2.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 37\." "step, 2.2"
+
+# and again
+gdb_test "reverse-step" ".*fun2\.3.*" "step, 3.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 35\." "step, 3.2"
+
+# once more
+gdb_test "reverse-step" ".*fun1\.2.*" "step, 4.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 33\." "step, 4.2"
+
+# and out again the other side
+gdb_test "reverse-step" ".*fun2\.2.*" "step, 5.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 30\." "step, 5.2"
+
+# once again
+gdb_test "reverse-step" ".*fun3\.3.*" "step, 6.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 27\." "step, 6.2"
+
+# and back the way we came
+gdb_test "step" ".*fun2\.2.*" "step, 7.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 30\." "step, 7.2"
+
+gdb_test "step" ".*fun1\.2.*" "step, 8.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 33\." "step, 8.2"
+
+gdb_test "step" ".*fun2\.3.*" "step, 9.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 35\." "step, 9.2"
+
+gdb_test "step" ".*fun3\.4.*" "step, 10.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 37\." "step, 10.2"
+
+gdb_test "step" ".*fun4\.5.*" "step, 11.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 39\." "step, 11.2"
+
+gdb_test "step" ".*main\.3.*" "step, 12.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r" "step, 12.2"
diff --git a/gdb/testsuite/gdb.btrace/stepi.exp b/gdb/testsuite/gdb.btrace/stepi.exp
new file mode 100644
index 0000000..22f1574
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/stepi.exp
@@ -0,0 +1,114 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <markus.t.metzger@intel.com>
+#
+# 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/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# start inferior
+standard_testfile x86-record_goto.S
+if [prepare_for_testing stepi.exp $testfile $srcfile] {
+ return -1
+}
+
+global gdb_prompt
+
+if ![runto_main] {
+ return -1
+}
+
+# trace the call to the test function
+gdb_test_no_output "record btrace"
+gdb_test "next"
+
+# we start with stepping to make sure that the trace is fetched automatically
+gdb_test "reverse-stepi" ".*fun4\.5.*" "stepi, 1.1"
+gdb_test "reverse-stepi" ".*fun4\.5.*" "stepi, 1.2"
+
+# let's check where we are in the trace
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 39\." "stepi, 1.3"
+
+# let's step forward and check again
+gdb_test "stepi" ".*fun4\.5.*" "stepi, 2.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 40\." "stepi, 2.2"
+
+# with the next step, we stop replaying
+gdb_test "stepi" ".*main\.3.*" "stepi, 2.3"
+gdb_test_multiple "info record" "stepi, 2.4" {
+ -re "Replay in progress.*$gdb_prompt $" { fail "stepi, 2.4" }
+ -re ".*$gdb_prompt $" { pass "stepi, 2.4" }
+}
+
+# let's step from a goto position somewhere in the middle
+gdb_test "record goto 22" ".*fun3\.2.*" "stepi, 3.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 22\." "stepi, 3.2"
+gdb_test "stepi" ".*fun1\.1.*" "stepi, 3.3"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 23\." "stepi, 3.4"
+
+# and back again
+gdb_test "reverse-stepi" ".*fun3\.2.*" "stepi, 4.1"
+gdb_test "reverse-stepi" ".*fun3\.1.*" "stepi, 4.2"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 21\." "stepi, 4.3"
+
+# let's try to step off the left end
+gdb_test "record goto begin" ".*main\.2.*" "stepi, 5.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 1\." "stepi, 5.2"
+gdb_test "reverse-stepi" "No more reverse-execution history\.\r
+.*main\.2.*" "stepi, 5.3"
+gdb_test "reverse-stepi" "No more reverse-execution history\.\r
+.*main\.2.*" "stepi, 5.4"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 1\." "stepi, 5.5"
+
+# we can step forward, though
+gdb_test "stepi" ".*fun4\.1.*" "stepi, 6.1"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 2\." "stepi, 6.2"
+
+# let's try to step off the left end again
+gdb_test "reverse-stepi" ".*main\.2.*" "stepi, 7.1"
+gdb_test "reverse-stepi" "No more reverse-execution history\.\r
+.*main\.2.*" "stepi, 7.2"
+gdb_test "reverse-stepi" "No more reverse-execution history\.\r
+.*main\.2.*" "stepi, 7.3"
+gdb_test "info record" "
+Active record target: record-btrace\r
+Recorded 40 instructions in 16 functions for .*\r
+Replay in progress\. At instruction 1\." "stepi, 7.4"
--
1.7.1