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


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

[patch v6 21/21] record-btrace: add (reverse-)stepping support


There's an open regarding frame unwinding.  When I start stepping, the frame
cache will still be based on normal unwinding as will the frame cached in the
thread's stepping context.  This will prevent me from detecting that i stepped
into a subroutine.

To overcome that, I'm resetting the frame cache and setting the thread's
stepping cache based on the current frame - which is now computed using branch
tracing unwind.  I had to split get_current_frame to avoid checks that would
prevent me from doing this.

I also need to call registers_changed when I return from to_wait.  Otherwise,
the PC is not updated and the current location is shown incorrectly.  Not sure
whether this is intended or whether I'm unintentionally working around
something, here.

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

Reviewed-by: Eli Zaretskii  <eliz@gnu.org>
2013-09-20  Markus Metzger  <markus.t.metzger@intel.com>

	* btrace.h (btrace_thread_flag): New.
	(struct btrace_thread_info)<flags>: New.
	* frame.c (get_current_frame_nocheck): New.
	(get_current_frame): Call get_current_frame_nocheck.
	* frame.h (get_current_frame_nocheck): New.
	* record-btrace.c (record_btrace_resume_thread,
	record_btrace_find_thread_to_move, btrace_step_no_history,
	btrace_step_stopped, record_btrace_start_replaying,
	record_btrace_step_thread,
	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                            |    4 +-
 gdb/frame.c                                    |   37 ++-
 gdb/frame.h                                    |    4 +
 gdb/record-btrace.c                            |  381 ++++++++++++++++++++++--
 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 ++
 18 files changed, 1183 insertions(+), 54 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 6005b89..acac3ab 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -25,6 +25,10 @@ Nios II ELF 			nios2*-*-elf
 Nios II GNU/Linux		nios2*-*-linux
 Texas Instruments MSP430	msp430*-*-elf
 
+* The btrace record target supports limited replay and reverse
+  execution.  The target does not record data and does therefore
+  not allow reading memory or registers.
+
 * The btrace record target supports the 'record goto' command.
   For locations inside the execution trace, the back trace is computed
   based on the information stored in the execution trace.
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 36e12cb..34476b0 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 1098b60..50e7206 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6192,8 +6192,8 @@ replay implementation.  This method allows replaying and reverse
 execution.
 
 @item btrace
-Hardware-supported instruction recording.  This method does not allow
-replaying and reverse execution.
+Hardware-supported instruction recording.  This method does not record
+data.  It allows limited replay and reverse execution.
 
 This recording method may not be available on all processors.
 @end table
diff --git a/gdb/frame.c b/gdb/frame.c
index 0fd98ff..5a6f107 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1367,6 +1367,29 @@ unwind_to_current_frame (struct ui_out *ui_out, void *args)
   return 0;
 }
 
+/* See frame.h.  */
+
+struct frame_info *get_current_frame_nocheck (void)
+{
+  if (current_frame == NULL)
+    {
+      struct frame_info *sentinel_frame =
+	create_sentinel_frame (current_program_space, get_current_regcache ());
+
+      if (catch_exceptions (current_uiout, unwind_to_current_frame,
+			    sentinel_frame, RETURN_MASK_ERROR) != 0)
+	{
+	  /* Oops! Fake a current frame?  Is this useful?  It has a PC
+             of zero, for instance.  */
+	  current_frame = sentinel_frame;
+	}
+    }
+
+  return current_frame;
+}
+
+/* See frame.h.  */
+
 struct frame_info *
 get_current_frame (void)
 {
@@ -1392,19 +1415,7 @@ get_current_frame (void)
 	error (_("Target is executing."));
     }
 
-  if (current_frame == NULL)
-    {
-      struct frame_info *sentinel_frame =
-	create_sentinel_frame (current_program_space, get_current_regcache ());
-      if (catch_exceptions (current_uiout, unwind_to_current_frame,
-			    sentinel_frame, RETURN_MASK_ERROR) != 0)
-	{
-	  /* Oops! Fake a current frame?  Is this useful?  It has a PC
-             of zero, for instance.  */
-	  current_frame = sentinel_frame;
-	}
-    }
-  return current_frame;
+  return get_current_frame_nocheck ();
 }
 
 /* The "selected" stack frame is used by default for local and arg
diff --git a/gdb/frame.h b/gdb/frame.h
index f0da19e..cd2033d 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -242,6 +242,10 @@ enum frame_type
    error.  */
 extern struct frame_info *get_current_frame (void);
 
+/* Similar to get_current_frame except that we omit all checks.  May
+   return NULL if unwinding fails.  */
+extern struct frame_info *get_current_frame_nocheck (void);
+
 /* Does the current target interface have enough state to be able to
    query the current inferior for frame info, and is the inferior in a
    state where that is possible?  */
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 1620700..d634712 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);
@@ -1235,14 +1239,117 @@ static 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)
+{
+  struct btrace_thread_info *btinfo;
+  struct btrace_insn_iterator *replay;
+  const struct btrace_insn *insn;
+  struct symtab_and_line sal;
+  struct frame_info *frame;
+
+  btinfo = &tp->btrace;
+
+  /* We can't start replaying without trace.  */
+  if (btinfo->begin == NULL)
+    return NULL;
+
+  /* We start replaying at the end of the branch trace.  This corresponds to the
+     current instruction.  */
+  replay = 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);
+
+  /* We just started replaying.  The frame id cached for stepping is based
+     on unwinding, not on branch tracing.  Recompute it.  */
+  frame = get_current_frame_nocheck ();
+  insn = btrace_insn_get (replay);
+  sal = find_pc_line (insn->pc, 0);
+  set_step_info (frame, sal);
+
+  return replay;
+}
+
+/* Stop replaying a thread.  */
+
+static void
+record_btrace_stop_replaying (struct 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)
@@ -1251,7 +1358,213 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
       error (_("Cannot find target for stepping."));
     }
 
-  error (_("You can't do this from here.  Do 'record goto end', first."));
+  /* We can't pass signals when replaying.  */
+  if (signal != GDB_SIGNAL_0)
+    error (_("You can't resume with signal from here."));
+
+  /* Compute the btrace thread flag for the requested move.  */
+  if (step == 0)
+    flag = execution_direction == EXEC_REVERSE ? BTHR_RCONT : BTHR_CONT;
+  else
+    flag = execution_direction == EXEC_REVERSE ? BTHR_RSTEP : BTHR_STEP;
+
+  /* Find the thread to move.  */
+  if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid))
+    {
+      ALL_THREADS (tp)
+	record_btrace_resume_thread (tp, flag);
+    }
+  else 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.  */
@@ -1260,8 +1573,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)
@@ -1270,7 +1587,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.  */
@@ -1303,32 +1653,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.  */
@@ -1427,6 +1765,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.7.1


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