[patch v7 24/24] record-btrace: add (reverse-)stepping support

Markus Metzger
2013-11-29T14:42:08Z

Non-stop mode is not working. Do not allow record-btrace in non-stop mode.

CC: Eli Zaretskii <eliz@gnu.org>
2013-11-29 Markus Metzger <markus.t.metzger@intel.com>

* btrace.h (btrace_thread_flag): New.
(struct btrace_thread_info)<flags>: 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,
record_btrace_find_resume_thread): New.
(record_btrace_resume, record_btrace_wait): Extend.
(record_btrace_can_execute_reverse): New.
(record_btrace_open): Fail in non-stop mode.
(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/tailcall.exp: Update. Add stepping tests.
* 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.
* gdb.btrace/multi-thread-step.c: New.
* gdb.btrace/multi-thread-step.exp: New.
* gdb.btrace/rn-dl-bind.c: New.
* gdb.btrace/rn-dl-bind.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 | 6 +-
gdb/record-btrace.c | 407 +++++++++++++++++++++++--
gdb/testsuite/gdb.btrace/delta.exp | 13 +
gdb/testsuite/gdb.btrace/finish.exp | 70 +++++
gdb/testsuite/gdb.btrace/multi-thread-step.c | 53 ++++
gdb/testsuite/gdb.btrace/multi-thread-step.exp | 99 ++++++
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/rn-dl-bind.c | 37 +++
gdb/testsuite/gdb.btrace/rn-dl-bind.exp | 48 +++
gdb/testsuite/gdb.btrace/step.exp | 113 +++++++
gdb/testsuite/gdb.btrace/stepi.exp | 114 +++++++
gdb/testsuite/gdb.btrace/tailcall.exp | 24 ++
16 files changed, 1183 insertions(+), 41 deletions(-)
create mode 100644 gdb/testsuite/gdb.btrace/finish.exp
create mode 100644 gdb/testsuite/gdb.btrace/multi-thread-step.c
create mode 100644 gdb/testsuite/gdb.btrace/multi-thread-step.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/rn-dl-bind.c
create mode 100644 gdb/testsuite/gdb.btrace/rn-dl-bind.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 2513d4a..1575554 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -92,6 +92,10 @@ info exceptions REGEXP
For locations inside the execution trace, the back trace is computed
based on the information stored in the execution trace.

+* The btrace record target supports limited reverse execution and replay.
+ The target does not record data and does therefore not allow reading
+ memory or registers.
+
* New options

set debug symfile off|on
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 548ebba..5b52ec6 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -153,6 +153,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
@@ -182,6 +201,9 @@ struct btrace_thread_info
becomes zero. */
int level;

+ /* A bit-vector of btrace_thread_flag. */
+ enum btrace_thread_flag flags;
+
/* The instruction history iterator. */
struct btrace_insn_history *insn_history;

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 543f2f2..32363a8 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6240,8 +6240,10 @@ 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. Further, the data is collected in a ring buffer so old data will
+be overwritten when the buffer is full. It allows limited replay and
+reverse execution.

This recording method may not be available on all processors.
@end table
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 1e8cfc1..bc23f2d 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -167,6 +167,10 @@ record_btrace_open (char *args, int from_tty)
if (!target_supports_btrace ())
error (_("Target does not support branch tracing."));

+ if (non_stop)
+ error (_("Record btrace can't debug inferior in non-stop mode "
+ "(non-stop)."));
+
gdb_assert (record_btrace_thread_observer == NULL);

disable_chain = make_cleanup (null_cleanup, NULL);
@@ -1233,14 +1237,147 @@ const struct frame_unwind record_btrace_tailcall_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;
+}
+
+/* Find the thread to resume given a PTID. */
+
+static struct thread_info *
+record_btrace_find_resume_thread (ptid_t ptid)
+{
+ struct thread_info *tp;
+
+ /* When asked to resume everything, we pick the current thread. */
+ if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid))
+ ptid = inferior_ptid;
+
+ return find_thread_ptid (ptid);
+}
+
+/* Stop replaying a thread. */
+
+static struct btrace_insn_iterator *
+record_btrace_start_replaying (struct thread_info *tp)
+{
+ volatile struct gdb_exception except;
+ struct btrace_insn_iterator *replay;
+ struct btrace_thread_info *btinfo;
+ int executing;
+
+ btinfo = &tp->btrace;
+ replay = NULL;
+
+ /* We can't start replaying without trace. */
+ if (btinfo->begin == NULL)
+ return NULL;
+
+ /* Clear the executing flag to allow changes to the current frame. */
+ executing = is_executing (tp->ptid);
+ set_executing (tp->ptid, 0);
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ struct frame_info *frame;
+ struct frame_id frame_id;
+ int upd_step_frame_id, upd_step_stack_frame_id;
+
+ /* The current frame without replaying - computed via normal unwind. */
+ frame = get_current_frame ();
+ frame_id = get_frame_id (frame);
+
+ /* Check if we need to update any stepping-related frame id's. */
+ upd_step_frame_id = frame_id_eq (frame_id,
+ tp->control.step_frame_id);
+ upd_step_stack_frame_id = frame_id_eq (frame_id,
+ tp->control.step_stack_frame_id);
+
+ /* We start replaying at the end of the branch trace. This corresponds
+ to the current instruction. */
+ replay = xmalloc (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. */
+ registers_changed_ptid (tp->ptid);
+
+ /* The current frame with replaying - computed via btrace unwind. */
+ frame = get_current_frame ();
+ frame_id = get_frame_id (frame);
+
+ /* Replace stepping related frames where necessary. */
+ if (upd_step_frame_id)
+ tp->control.step_frame_id = frame_id;
+ if (upd_step_stack_frame_id)
+ tp->control.step_stack_frame_id = frame_id;
+ }
+
+ /* Restore the previous execution state. */
+ set_executing (tp->ptid, executing);
+
+ if (except.reason < 0)
+ throw_exception (except);
+
+ return replay;
+}
+
+/* Stop replaying a thread. */
+
+static void
+record_btrace_stop_replaying (struct thread_info *tp)
+{
+ struct btrace_thread_info *btinfo;
+
+ btinfo = &tp->btrace;
+
+ xfree (btinfo->replay);
+ btinfo->replay = NULL;
+
+ /* Make sure we're not leaving any stale registers. */
+ registers_changed_ptid (tp->ptid);
+}
+
/* 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, *other;
+ enum btrace_thread_flag flag;
+
+ DEBUG ("resume %s: %s", target_pid_to_str (ptid), step ? "step" : "cont");
+
+ tp = record_btrace_find_resume_thread (ptid);
+
+ /* Stop replaying other threads if the thread to resume is not replaying. */
+ if (tp != NULL && !btrace_is_replaying (tp)
+ && execution_direction != EXEC_REVERSE)
+ ALL_THREADS (other)
+ record_btrace_stop_replaying (other);
+
/* 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)
@@ -1249,7 +1386,209 @@ 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."));
+ /* 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 if (tp == NULL)
+ error (_("Cannot find thread to resume."));
+ else
+ 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;
+
+ /* Next check the current thread. */
+ tp = find_thread_ptid (inferior_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;
+}
+
+/* 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;
+ struct inferior *inf;
+ enum btrace_thread_flag flags;
+ unsigned int steps;
+
+ btinfo = &tp->btrace;
+ replay = btinfo->replay;
+
+ flags = btinfo->flags & BTHR_MOVE;
+ btinfo->flags &= ~BTHR_MOVE;
+
+ DEBUG ("stepping %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flags);
+
+ switch (flags)
+ {
+ 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 (tp);
+
+ return btrace_step_stopped ();
+
+ case BTHR_RSTEP:
+ /* Start replaying if we're not already doing so. */
+ if (replay == NULL)
+ replay = record_btrace_start_replaying (tp);
+
+ /* 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 ();
+
+ inf = find_inferior_pid (ptid_get_pid (tp->ptid));
+ aspace = inf->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 (tp);
+ return btrace_step_no_history ();
+ }
+
+ insn = btrace_insn_get (replay);
+ gdb_assert (insn);
+
+ DEBUG ("stepping %d (%s) ... %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 (tp);
+
+ inf = find_inferior_pid (ptid_get_pid (tp->ptid));
+ aspace = inf->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 ("stepping %d (%s): reverse~ ... %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. */
@@ -1258,8 +1597,12 @@ static ptid_t
record_btrace_wait (struct target_ops *ops, ptid_t ptid,
struct target_waitstatus *status, int options)
{
+ struct thread_info *tp, *other;
+
+ 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)
@@ -1268,7 +1611,40 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
error (_("Cannot find target for waiting."));
}

- 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);
+
+ /* Stop all other threads. */
+ if (!non_stop)
+ ALL_THREADS (other)
+ other->btrace.flags &= ~BTHR_MOVE;
+
+ /* 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_ptid (tp->ptid);
+
+ 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. */
@@ -1301,32 +1677,20 @@ record_btrace_set_replay (struct thread_info *tp,
btinfo = &tp->btrace;

if (it == NULL || it->function == NULL)
- {
- if (btinfo->replay == NULL)
- return;
-
- xfree (btinfo->replay);
- btinfo->replay = NULL;
- }
+ record_btrace_stop_replaying (tp);
else
{
if (btinfo->replay == NULL)
- btinfo->replay = xmalloc (sizeof (*btinfo->replay));
+ record_btrace_start_replaying (tp);
else if (btrace_insn_cmp (btinfo->replay, it) == 0)
return;

*btinfo->replay = *it;
+ registers_changed_ptid (tp->ptid);
}

- /* 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;
-
- registers_changed_ptid (tp->ptid);
+ /* Start anew from the new replay position. */
+ record_btrace_clear_histories (btinfo);
}

/* The to_goto_record_begin method of target record-btrace. */
@@ -1425,6 +1789,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/multi-thread-step.c b/gdb/testsuite/gdb.btrace/multi-thread-step.c
new file mode 100644
index 0000000..487565b
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/multi-thread-step.c
@@ -0,0 +1,53 @@
+/* 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/>. */
+
+#include <pthread.h>
+
+static pthread_barrier_t barrier;
+static int global;
+
+static void *
+test (void *arg)
+{
+ pthread_barrier_wait (&barrier);
+
+ global = 42; /* bp.1 */
+
+ pthread_barrier_wait (&barrier);
+
+ global = 42; /* bp.2 */
+
+ return arg;
+}
+
+int
+main (void)
+{
+ pthread_t th;
+
+ pthread_barrier_init (&barrier, NULL, 2);
+ pthread_create (&th, NULL, test, NULL);
+
+ test (NULL);
+
+ pthread_join (th, NULL);
+ pthread_barrier_destroy (&barrier);
+
+ return 0; /* bp.3 */
+}
diff --git a/gdb/testsuite/gdb.btrace/multi-thread-step.exp b/gdb/testsuite/gdb.btrace/multi-thread-step.exp
new file mode 100644
index 0000000..d247845
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/multi-thread-step.exp
@@ -0,0 +1,99 @@
+# 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
+if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" "$binfile" executable {debug}] != "" } {
+ return -1
+}
+clean_restart $testfile
+
+if ![runto_main] {
+ return -1
+}
+
+# set up breakpoints
+set bp_1 [gdb_get_line_number "bp.1" $srcfile]
+set bp_2 [gdb_get_line_number "bp.2" $srcfile]
+set bp_3 [gdb_get_line_number "bp.3" $srcfile]
+
+proc gdb_cont_to_line { line test } {
+ gdb_breakpoint $line
+ gdb_continue_to_breakpoint "$test" ".*$line\r\n.*"
+ delete_breakpoints
+}
+
+# trace the code between the two breakpoints
+delete_breakpoints
+gdb_cont_to_line $srcfile:$bp_1 "mts, 0.1"
+# make sure GDB knows about the new thread
+gdb_test "info threads" ".*" "mts, 0.2"
+gdb_test_no_output "record btrace" "mts, 0.3"
+gdb_cont_to_line $srcfile:$bp_2 "mts, 0.4"
+
+# navigate in the trace history for both threads
+gdb_test "thread 1" ".*" "mts, 1.1"
+gdb_test "record goto begin" ".*" "mts, 1.2"
+gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 1.3"
+gdb_test "thread 2" ".*" "mts, 1.4"
+gdb_test "record goto begin" ".*" "mts, 1.5"
+gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 1.6"
+
+# step both threads
+gdb_test "thread 1" ".*" "mts, 2.1"
+gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 2.2"
+gdb_test "stepi" ".*" "mts, 2.3"
+gdb_test "info record" ".*Replay in progress\. At instruction 2\." "mts, 2.4"
+gdb_test "thread 2" ".*" "mts, 2.5"
+gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 2.6"
+gdb_test "stepi" ".*" "mts, 2.7"
+gdb_test "info record" ".*Replay in progress\. At instruction 2\." "mts, 2.8"
+
+# run to the end of the history for both threads
+gdb_test "thread 1" ".*" "mts, 3.1"
+gdb_test "info record" ".*Replay in progress\. At instruction 2\." "mts, 3.2"
+gdb_test "continue" "No more reverse-execution history.*" "mts, 3.3"
+gdb_test "thread 2" ".*" "mts, 3.4"
+gdb_test "info record" ".*Replay in progress\. At instruction 2\." "mts, 3.5"
+gdb_test "continue" "No more reverse-execution history.*" "mts, 3.6"
+
+# reverse-step both threads
+gdb_test "thread 1" ".*" "mts, 4.1"
+gdb_test "reverse-stepi" ".*" "mts, 4.2"
+gdb_test "info record" ".*Replay in progress\..*" "mts, 4.3"
+gdb_test "thread 2" ".*" "mts, 4.4"
+gdb_test "reverse-stepi" ".*" "mts, 4.5"
+gdb_test "info record" ".*Replay in progress\..*" "mts, 4.6"
+
+# both threads are still replaying
+gdb_test "thread 1" ".*" "mts, 5.1"
+gdb_test "info record" ".*Replay in progress\..*" "mts, 5.2"
+gdb_test "thread 2" ".*" "mts, 5.3"
+gdb_test "info record" ".*Replay in progress\..*" "mts, 5.4"
+
+# navigate back into the history for thread 1 and continue thread 2
+gdb_test "thread 1" ".*" "mts, 6.1"
+gdb_test "record goto begin" ".*" "mts, 6.2"
+gdb_test "info record" ".*Replay in progress\. At instruction 1\." "mts, 6.3"
+gdb_test "thread 2" ".*" "mts, 6.4"
+gdb_test "record goto end" ".*" "mts, 6.5"
+gdb_cont_to_line $srcfile:$bp_3 "mts, 6.6"
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/rn-dl-bind.c b/gdb/testsuite/gdb.btrace/rn-dl-bind.c
new file mode 100644
index 0000000..4930297
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/rn-dl-bind.c
@@ -0,0 +1,37 @@
+/* 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/>. */
+
+#include <stdlib.h>
+
+int test (void)
+{
+ int ret;
+
+ ret = strtoul ("42", NULL, 10); /* test.1 */
+ return ret; /* test.2 */
+} /* test.3 */
+
+int
+main (void)
+{
+ int ret;
+
+ ret = test (); /* main.1 */
+ return ret; /* main.2 */
+} /* main.3 */
diff --git a/gdb/testsuite/gdb.btrace/rn-dl-bind.exp b/gdb/testsuite/gdb.btrace/rn-dl-bind.exp
new file mode 100644
index 0000000..4d803f9
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/rn-dl-bind.exp
@@ -0,0 +1,48 @@
+# 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
+if [prepare_for_testing $testfile.exp $testfile $srcfile {c++ debug}] {
+ return -1
+}
+if ![runto_main] {
+ return -1
+}
+
+# trace the code for the call to test
+gdb_test_no_output "record btrace" "rn-dl-bind, 0.1"
+gdb_test "next" ".*main\.2.*" "rn-dl-bind, 0.2"
+
+# just dump the function-call-history to help debugging
+gdb_test_no_output "set record function-call-history-size 0" "rn-dl-bind, 0.3"
+gdb_test "record function-call-history /cli 1" ".*" "rn-dl-bind, 0.4"
+
+# check that we can reverse-next and next
+gdb_test "reverse-next" ".*main\.1.*" "rn-dl-bind, 1.1"
+gdb_test "next" ".*main\.2.*" "rn-dl-bind, 1.2"
+
+# now go into test and try to reverse-next and next over the library call
+gdb_test "reverse-step" ".*test\.3.*" "rn-dl-bind, 2.1"
+gdb_test "reverse-step" ".*test\.2.*" "rn-dl-bind, 2.2"
+gdb_test "reverse-next" ".*test\.1.*" "rn-dl-bind, 2.3"
+gdb_test "next" ".*test\.2.*" "rn-dl-bind, 2.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"
diff --git a/gdb/testsuite/gdb.btrace/tailcall.exp b/gdb/testsuite/gdb.btrace/tailcall.exp
index b9520c4..bc1ff29 100644
--- a/gdb/testsuite/gdb.btrace/tailcall.exp
+++ b/gdb/testsuite/gdb.btrace/tailcall.exp
@@ -77,3 +77,27 @@ gdb_test "up" "
#1\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*" "up to foo"
gdb_test "up" "
#2\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" "up to main"
+gdb_test "down" "
+#1\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*" "down to foo"
+
+# test stepping into and out of tailcalls.
+gdb_test "finish" "
+\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" "step, 1.1"
+gdb_test "reverse-step" "
+\[^\r\n\]*bar \\(\\) at x86-tailcall.c:24\r\n.*" "step, 1.2"
+gdb_test "reverse-finish" "
+\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*" "step, 1.3"
+gdb_test "reverse-step" "
+\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" "step, 1.4"
+gdb_test "next" "
+\[^\r\n\]*main \\(\\) at x86-tailcall.c:39\r\n.*" "step, 1.5"
+gdb_test "reverse-next" "
+\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" "step, 1.6"
+gdb_test "step" "
+\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*" "step, 1.7"
+gdb_test "finish" "
+\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" "step, 1.8"
+gdb_test "reverse-step" "
+\[^\r\n\]*bar \\(\\) at x86-tailcall.c:24\r\n.*" "step, 1.9"
+gdb_test "finish" "
+\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*" "step, 1.10"
--
1.8.3.1