aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog18
-rw-r--r--gdb/NEWS4
-rw-r--r--gdb/btrace.h22
-rw-r--r--gdb/doc/ChangeLog5
-rw-r--r--gdb/doc/gdb.texinfo6
-rw-r--r--gdb/record-btrace.c430
-rw-r--r--gdb/testsuite/ChangeLog18
-rw-r--r--gdb/testsuite/gdb.btrace/Makefile.in3
-rw-r--r--gdb/testsuite/gdb.btrace/data.c36
-rw-r--r--gdb/testsuite/gdb.btrace/data.exp45
-rw-r--r--gdb/testsuite/gdb.btrace/delta.exp15
-rw-r--r--gdb/testsuite/gdb.btrace/finish.exp59
-rw-r--r--gdb/testsuite/gdb.btrace/multi-thread-step.c53
-rw-r--r--gdb/testsuite/gdb.btrace/multi-thread-step.exp135
-rw-r--r--gdb/testsuite/gdb.btrace/next.exp76
-rw-r--r--gdb/testsuite/gdb.btrace/nexti.exp76
-rw-r--r--gdb/testsuite/gdb.btrace/record_goto.c36
-rw-r--r--gdb/testsuite/gdb.btrace/rn-dl-bind.c37
-rw-r--r--gdb/testsuite/gdb.btrace/rn-dl-bind.exp52
-rw-r--r--gdb/testsuite/gdb.btrace/step.exp89
-rw-r--r--gdb/testsuite/gdb.btrace/stepi.exp93
-rw-r--r--gdb/testsuite/gdb.btrace/tailcall.exp13
22 files changed, 1279 insertions, 42 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index ad768a1..3e7f149 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,23 @@
2014-01-16 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_decr_pc_after_break)
+ (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.
+
+2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
+
* target.h (struct target_ops) <to_decr_pc_after_break>: New.
(forward_target_decr_pc_after_break)
(target_decr_pc_after_break): New.
diff --git a/gdb/NEWS b/gdb/NEWS
index 840d139..44189d5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -22,6 +22,10 @@
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 therefore does not allow reading
+ memory or registers.
+
* New remote packets
qXfer:btrace:read's annex
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 193f916..f83a80f 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/ChangeLog b/gdb/doc/ChangeLog
index b873f51..74a2763 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
+ * gdb.texinfo: Document limited reverse/replay support
+ for target record-btrace.
+
+2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
+
* gdb.texinfo (Process Record and Replay): Update documentation.
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 57071d1..e77ca2a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6263,8 +6263,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 8c8620c..3a93fdb 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -169,6 +169,9 @@ 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."));
+
gdb_assert (record_btrace_thread_observer == NULL);
disable_chain = make_cleanup (null_cleanup, NULL);
@@ -1290,14 +1293,166 @@ 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);
+}
+
+/* Start 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.
+ We are not actually running, yet. We just started a reverse execution
+ command or a record goto command.
+ For the latter, EXECUTING is false and this has no effect.
+ For the former, EXECUTING is true and we're in to_wait, about to
+ move the thread. Since we need to recompute the stack, we temporarily
+ set EXECUTING to flase. */
+ executing = is_executing (tp->ptid);
+ set_executing (tp->ptid, 0);
+
+ /* GDB stores the current frame_id when stepping in order to detects steps
+ into subroutines.
+ Since frames are computed differently when we're replaying, we need to
+ recompute those stored frames and fix them up so we can still detect
+ subroutines after we started replaying. */
+ 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)
+ {
+ xfree (btinfo->replay);
+ btinfo->replay = NULL;
+
+ registers_changed_ptid (tp->ptid);
+
+ 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);
+ if (tp == NULL)
+ error (_("Cannot find thread to resume."));
+
+ /* Stop replaying other threads if the thread to resume is not replaying. */
+ if (!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)
@@ -1306,7 +1461,200 @@ 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;
+
+ /* At the moment, we only move a single thread. We could also move
+ all threads in parallel by single-stepping each resumed thread
+ until the first runs into an event.
+ When we do that, we would want to continue all other threads.
+ For now, just resume one thread to not confuse to_wait. */
+ 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 target_waitstatus 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 target_waitstatus indicating that a step finished. */
+
+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 ("reverse-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 ();
+ }
+ }
}
/* The to_wait method of target record-btrace. */
@@ -1315,8 +1663,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)
@@ -1325,7 +1677,53 @@ 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);
+
+ /* We moved the replay position but did not update registers. */
+ 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_decr_pc_after_break method of target record-btrace. */
+
+static CORE_ADDR
+record_btrace_decr_pc_after_break (struct target_ops *ops,
+ struct gdbarch *gdbarch)
+{
+ /* When replaying, we do not actually execute the breakpoint instruction
+ so there is no need to adjust the PC after hitting a breakpoint. */
+ if (record_btrace_is_replaying ())
+ return 0;
+
+ return forward_target_decr_pc_after_break (ops->beneath, gdbarch);
}
/* The to_find_new_threads method of target record-btrace. */
@@ -1375,32 +1773,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. */
@@ -1502,6 +1888,8 @@ 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_decr_pc_after_break = record_btrace_decr_pc_after_break;
ops->to_stratum = record_stratum;
ops->to_magic = OPS_MAGIC;
}
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9637566..6a9d8c0 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,23 @@
2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
+ * 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.
+ * gdb.btrace/data.c: New.
+ * gdb.btrace/data.exp: New.
+ * gdb.btrace/Makefile.in (EXECUTABLES): Add new.
+
+2014-01-16 Markus Metzger <markus.t.metzger@intel.com>
+
* gdb.btrace/Makefile.in (EXECUTABLES): Add delta.
* gdb.btrace/exception.exp: Update.
* gdb.btrace/instruction_history.exp: Update.
diff --git a/gdb/testsuite/gdb.btrace/Makefile.in b/gdb/testsuite/gdb.btrace/Makefile.in
index 2ae673a..ec00b59 100644
--- a/gdb/testsuite/gdb.btrace/Makefile.in
+++ b/gdb/testsuite/gdb.btrace/Makefile.in
@@ -2,7 +2,8 @@ VPATH = @srcdir@
srcdir = @srcdir@
EXECUTABLES = enable function_call_history instruction_history tailcall \
- exception unknown_functions record_goto delta
+ exception unknown_functions record_goto delta finish next nexti step \
+ stepi multi-thread-step rn-dl-bind data
MISCELLANEOUS =
diff --git a/gdb/testsuite/gdb.btrace/data.c b/gdb/testsuite/gdb.btrace/data.c
new file mode 100644
index 0000000..7368394
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/data.c
@@ -0,0 +1,36 @@
+/* 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/>. */
+
+volatile static int glob;
+
+void
+test (void)
+{ /* test.1 */
+ volatile static int loc;
+
+ loc += 1; /* test.2 */
+ glob += loc; /* test.3 */
+} /* test.4 */
+
+int
+main (void)
+{ /* main.1 */
+ test (); /* main.2 */
+ return 0; /* main.3 */
+} /* main.4 */
diff --git a/gdb/testsuite/gdb.btrace/data.exp b/gdb/testsuite/gdb.btrace/data.exp
new file mode 100644
index 0000000..d6bc854
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/data.exp
@@ -0,0 +1,45 @@
+# 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] {
+ return -1
+}
+if ![runto_main] {
+ return -1
+}
+
+# trace the test code
+gdb_test_no_output "record btrace"
+gdb_test "next" ".*main\.3.*"
+
+# reverse step into test
+gdb_test "reverse-step" ".*test\.4.*"
+
+# we can't read memory while we're replaying
+gdb_test "print glob" "Memory at .* unavailable\."
+gdb_test "print loc" "Memory at .* unavailable\."
+
+# stop replaying and try again
+gdb_test "record goto end"
+gdb_test "print glob" "1"
diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp
index e606751..5c3505c 100644
--- a/gdb/testsuite/gdb.btrace/delta.exp
+++ b/gdb/testsuite/gdb.btrace/delta.exp
@@ -66,3 +66,18 @@ with_test_prefix "once" {
with_test_prefix "twice" {
check_trace
}
+
+# check that we can reverse-stepi that instruction
+gdb_test "reverse-stepi"
+gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 1 instructions in 1 functions for .*" \
+ "Replay in progress\. At instruction 1\." \
+ ] "\r\n"] "reverse-stepi"
+
+# and back
+gdb_test "stepi"
+gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 1 instructions in 1 functions for .*" \
+ ] "\r\n"] "and back"
diff --git a/gdb/testsuite/gdb.btrace/finish.exp b/gdb/testsuite/gdb.btrace/finish.exp
new file mode 100644
index 0000000..a27082e
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/finish.exp
@@ -0,0 +1,59 @@
+# 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"
+
+proc check_replay_at { insn } {
+ gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for .*" \
+ "Replay in progress\. At instruction $insn\." \
+ ] "\r\n"]
+}
+
+# let's go somewhere where we can finish
+gdb_test "record goto 32" ".*fun1\.1.*"
+with_test_prefix "at 32" { check_replay_at 32 }
+
+gdb_test "finish" ".*fun2\.3.*"
+with_test_prefix "finish into fun2" { check_replay_at 35 }
+
+gdb_test "reverse-finish" ".*fun3\.3.*"
+with_test_prefix "reverse-finish into fun3" { check_replay_at 27 }
+
+gdb_test "finish" ".*fun4\.5.*"
+with_test_prefix "finish into fun4" { check_replay_at 39 }
+
+gdb_test "reverse-finish" ".*main\.2.*"
+with_test_prefix "reverse-finish into main" { check_replay_at 1 }
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..2c108b2
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/multi-thread-step.exp
@@ -0,0 +1,135 @@
+# 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 } {
+ gdb_breakpoint $line
+ gdb_continue_to_breakpoint "cont to $line" ".*$line\r\n.*"
+ delete_breakpoints
+}
+
+# trace the code between the two breakpoints
+delete_breakpoints
+gdb_cont_to_line $srcfile:$bp_1
+# make sure GDB knows about the new thread
+gdb_test "info threads" ".*"
+gdb_test_no_output "record btrace"
+gdb_cont_to_line $srcfile:$bp_2
+
+# navigate in the trace history for both threads
+with_test_prefix "navigate" {
+ gdb_test "thread 1" ".*"
+ with_test_prefix "thread 1" {
+ gdb_test "record goto begin" ".*"
+ gdb_test "info record" ".*Replay in progress\. At instruction 1\."
+ }
+ gdb_test "thread 2" ".*"
+ with_test_prefix "thread 2" {
+ gdb_test "record goto begin" ".*"
+ gdb_test "info record" ".*Replay in progress\. At instruction 1\."
+ }
+}
+
+# step both threads
+with_test_prefix "step" {
+ gdb_test "thread 1" ".*"
+ with_test_prefix "thread 1" {
+ gdb_test "info record" ".*Replay in progress\. At instruction 1\."
+ gdb_test "stepi" ".*"
+ gdb_test "info record" ".*Replay in progress\. At instruction 2\."
+ }
+ gdb_test "thread 2" ".*"
+ with_test_prefix "thread 2" {
+ gdb_test "info record" ".*Replay in progress\. At instruction 1\."
+ gdb_test "stepi" ".*"
+ gdb_test "info record" ".*Replay in progress\. At instruction 2\."
+ }
+}
+
+# run to the end of the history for both threads
+with_test_prefix "cont" {
+ gdb_test "thread 1" ".*"
+ with_test_prefix "thread 1" {
+ gdb_test "info record" ".*Replay in progress\. At instruction 2\."
+ gdb_test "continue" "No more reverse-execution history.*"
+ }
+ gdb_test "thread 2" ".*"
+ with_test_prefix "thread 2" {
+ gdb_test "info record" ".*Replay in progress\. At instruction 2\."
+ gdb_test "continue" "No more reverse-execution history.*"
+ }
+}
+
+# reverse-step both threads
+with_test_prefix "reverse-step" {
+ gdb_test "thread 1" ".*"
+ with_test_prefix "thread 1" {
+ gdb_test "reverse-stepi" ".*"
+ gdb_test "info record" ".*Replay in progress\..*"
+ }
+ gdb_test "thread 2" ".*"
+ with_test_prefix "thread 2" {
+ gdb_test "reverse-stepi" ".*"
+ gdb_test "info record" ".*Replay in progress\..*"
+ }
+}
+
+# both threads are still replaying
+with_test_prefix "check" {
+ gdb_test "thread 1" ".*"
+ with_test_prefix "thread 1" {
+ gdb_test "info record" ".*Replay in progress\..*"
+ }
+ gdb_test "thread 2" ".*"
+ with_test_prefix "thread 2" {
+ gdb_test "info record" ".*Replay in progress\..*"
+ }
+}
+
+# navigate back into the history for thread 1 and continue thread 2
+with_test_prefix "cont" {
+ gdb_test "thread 1" ".*"
+ with_test_prefix "thread 1" {
+ gdb_test "record goto begin" ".*"
+ gdb_test "info record" ".*Replay in progress\. At instruction 1\."
+ }
+ gdb_test "thread 2" ".*"
+ with_test_prefix "thread 2" {
+ gdb_test "record goto end" ".*"
+ gdb_cont_to_line $srcfile:$bp_3
+ }
+}
diff --git a/gdb/testsuite/gdb.btrace/next.exp b/gdb/testsuite/gdb.btrace/next.exp
new file mode 100644
index 0000000..b39eb79
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/next.exp
@@ -0,0 +1,76 @@
+# 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"
+
+proc check_replay_at { insn } {
+ gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for .*" \
+ "Replay in progress\. At instruction $insn\." \
+ ] "\r\n"]
+}
+
+# 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.*"
+with_test_prefix "reverse-next - 1" { check_replay_at 1 }
+
+# we can't reverse-step any further
+gdb_test "reverse-next" "No more reverse-execution history\.\r\n.*main\.2.*"
+with_test_prefix "reverse-next - 2" { check_replay_at 1 }
+
+# but we can step back again
+gdb_test "next" ".*main\.3.*"
+gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
+ ] "\r\n"] "next back"
+
+# let's go somewhere where we can step some more
+gdb_test "record goto 22" ".*fun3\.2.*"
+with_test_prefix "goto 22" { check_replay_at 22 }
+
+gdb_test "next" ".*fun3\.3.*"
+with_test_prefix "next to 27" { check_replay_at 27 }
+
+gdb_test "next" ".*fun3\.4.*"
+with_test_prefix "next to 37" { check_replay_at 37 }
+
+# and back again
+gdb_test "reverse-next" ".*fun3\.3.*"
+with_test_prefix "reverse-next to 27" { check_replay_at 27 }
+
+gdb_test "reverse-next" ".*fun3\.2.*"
+with_test_prefix "reverse-next to 22" { check_replay_at 22 }
diff --git a/gdb/testsuite/gdb.btrace/nexti.exp b/gdb/testsuite/gdb.btrace/nexti.exp
new file mode 100644
index 0000000..fd94df6
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/nexti.exp
@@ -0,0 +1,76 @@
+# 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"
+
+proc check_replay_at { insn } {
+ gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for .*" \
+ "Replay in progress\. At instruction $insn\." \
+ ] "\r\n"]
+}
+
+# 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.*"
+with_test_prefix "reverse-nexti - 1" { check_replay_at 1 }
+
+# we can't reverse-step any further
+gdb_test "reverse-nexti" "No more reverse-execution history\.\r\n.*main\.2.*"
+with_test_prefix "reverse-nexti - 1" { check_replay_at 1 }
+
+# but we can step back again
+gdb_test "nexti" ".*main\.3.*" "next, 1.5"
+gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
+ ] "\r\n"] "nexti back"
+
+# let's go somewhere where we can step some more
+gdb_test "record goto 22" ".*fun3\.2.*"
+with_test_prefix "goto 22" { check_replay_at 22 }
+
+gdb_test "nexti" ".*fun3\.3.*"
+with_test_prefix "nexti to 27" { check_replay_at 27 }
+
+gdb_test "nexti" ".*fun3\.4.*"
+with_test_prefix "nexti to 37" { check_replay_at 37 }
+
+# and back again
+gdb_test "reverse-nexti" ".*fun3\.3.*"
+with_test_prefix "reverse-nexti to 27" { check_replay_at 27 }
+
+gdb_test "reverse-nexti" ".*fun3\.2.*"
+with_test_prefix "reverse-nexti to 22" { check_replay_at 22 }
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..2f2250a
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/rn-dl-bind.exp
@@ -0,0 +1,52 @@
+# 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/>.
+#
+#
+# Test that we can reverse-next over the dynamic linker's symbol
+# lookup code.
+
+# 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"
+gdb_test "next" ".*main\.2.*"
+
+# just dump the function-call-history to help debugging
+gdb_test_no_output "set record function-call-history-size 0"
+gdb_test "record function-call-history /cli 1" ".*"
+
+# check that we can reverse-next and next
+gdb_test "reverse-next" ".*main\.1.*"
+gdb_test "next" ".*main\.2.*"
+
+# now go into test and try to reverse-next and next over the library call
+gdb_test "reverse-step" ".*test\.3.*"
+gdb_test "reverse-step" ".*test\.2.*"
+gdb_test "reverse-next" ".*test\.1.*"
+gdb_test "next" ".*test\.2.*"
diff --git a/gdb/testsuite/gdb.btrace/step.exp b/gdb/testsuite/gdb.btrace/step.exp
new file mode 100644
index 0000000..7c34d25
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/step.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 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"
+
+proc check_replay_at { insn } {
+ gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for .*" \
+ "Replay in progress\. At instruction $insn\." \
+ ] "\r\n"]
+}
+
+# let's start by stepping back into the function we just returned from
+gdb_test "reverse-step" ".*fun4\.5.*"
+with_test_prefix "reverse-step to 39" { check_replay_at 39 }
+
+# again
+gdb_test "reverse-step" ".*fun3\.4.*"
+with_test_prefix "reverse-step to 37" { check_replay_at 37 }
+
+# and again
+gdb_test "reverse-step" ".*fun2\.3.*"
+with_test_prefix "reverse-step to 35" { check_replay_at 35 }
+
+# once more
+gdb_test "reverse-step" ".*fun1\.2.*"
+with_test_prefix "reverse-step to 33" { check_replay_at 33 }
+
+# and out again the other side
+gdb_test "reverse-step" ".*fun2\.2.*"
+with_test_prefix "reverse-step to 30" { check_replay_at 30 }
+
+# once again
+gdb_test "reverse-step" ".*fun3\.3.*"
+with_test_prefix "reverse-step to 27" { check_replay_at 27 }
+
+# and back the way we came
+gdb_test "step" ".*fun2\.2.*"
+with_test_prefix "step to 30" { check_replay_at 30 }
+
+gdb_test "step" ".*fun1\.2.*"
+with_test_prefix "step to 33" { check_replay_at 33 }
+
+gdb_test "step" ".*fun2\.3.*"
+with_test_prefix "step to 35" { check_replay_at 35 }
+
+gdb_test "step" ".*fun3\.4.*"
+with_test_prefix "step to 37" { check_replay_at 37 }
+
+gdb_test "step" ".*fun4\.5.*"
+with_test_prefix "step to 39" { check_replay_at 39 }
+
+gdb_test "step" ".*main\.3.*"
+gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
+ ] "\r\n"] "step to live"
diff --git a/gdb/testsuite/gdb.btrace/stepi.exp b/gdb/testsuite/gdb.btrace/stepi.exp
new file mode 100644
index 0000000..fb12e28
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/stepi.exp
@@ -0,0 +1,93 @@
+# 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
+}
+
+proc check_replay_at { insn } {
+ gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for .*" \
+ "Replay in progress\. At instruction $insn\." \
+ ] "\r\n"]
+}
+
+# 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.*"
+gdb_test "reverse-stepi" ".*fun4\.5.*"
+
+# let's check where we are in the trace
+with_test_prefix "reverse-stepi to 39" { check_replay_at 39 }
+
+# let's step forward and check again
+gdb_test "stepi" ".*fun4\.5.*"
+with_test_prefix "stepi to 40" { check_replay_at 40 }
+
+# with the next step, we stop replaying
+gdb_test "stepi" ".*main\.3.*"
+gdb_test "info record" [join [list \
+ "Active record target: record-btrace" \
+ "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
+ ] "\r\n"] "stepi to live"
+
+# let's step from a goto position somewhere in the middle
+gdb_test "record goto 22" ".*fun3\.2.*"
+with_test_prefix "goto 22" { check_replay_at 22 }
+
+gdb_test "stepi" ".*fun1\.1.*"
+with_test_prefix "stepi to 23" { check_replay_at 23 }
+
+# and back again
+gdb_test "reverse-stepi" ".*fun3\.2.*"
+gdb_test "reverse-stepi" ".*fun3\.1.*"
+with_test_prefix "reverse-stepi to 21" { check_replay_at 21 }
+
+# let's try to step off the left end
+gdb_test "record goto begin" ".*main\.2.*"
+with_test_prefix "goto begin" { check_replay_at 1 }
+
+gdb_test "reverse-stepi" "No more reverse-execution history\.\r\n.*main\.2.*"
+gdb_test "reverse-stepi" "No more reverse-execution history\.\r\n.*main\.2.*"
+with_test_prefix "reverse-stepi at begin" { check_replay_at 1 }
+
+# we can step forward, though
+gdb_test "stepi" ".*fun4\.1.*"
+with_test_prefix "stepi to 2" { check_replay_at 2 }
+
+# let's try to step off the left end again
+gdb_test "reverse-stepi" ".*main\.2.*"
+gdb_test "reverse-stepi" "No more reverse-execution history\.\r\n.*main\.2.*"
+gdb_test "reverse-stepi" "No more reverse-execution history\.\r\n.*main\.2.*"
+with_test_prefix "reverse-stepi at begin" { check_replay_at 1 }
diff --git a/gdb/testsuite/gdb.btrace/tailcall.exp b/gdb/testsuite/gdb.btrace/tailcall.exp
index 23988f2..ce1f053 100644
--- a/gdb/testsuite/gdb.btrace/tailcall.exp
+++ b/gdb/testsuite/gdb.btrace/tailcall.exp
@@ -77,3 +77,16 @@ gdb_test "backtrace" [join [list \
# walk the backtrace
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.*"
+gdb_test "reverse-step" "\[^\r\n\]*bar \\(\\) at x86-tailcall.c:24\r\n.*"
+gdb_test "reverse-finish" "\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*"
+gdb_test "reverse-step" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*"
+gdb_test "next" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:39\r\n.*"
+gdb_test "reverse-next" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*"
+gdb_test "step" "\[^\r\n\]*foo \\(\\) at x86-tailcall.c:29\r\n.*"
+gdb_test "finish" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*"
+gdb_test "reverse-step" "\[^\r\n\]*bar \\(\\) at x86-tailcall.c:24\r\n.*"
+gdb_test "finish" "\[^\r\n\]*main \\(\\) at x86-tailcall.c:37\r\n.*"