public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 08/17] btrace: lock-step
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 05/17] btrace: split record_btrace_step_thread Markus Metzger
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Record btrace's to_wait method picks a single thread to step.  When passed
minus_one_ptid, it picks the current thread.  All other threads remain where
they are.

Change this to step all resumed threads together, one step at a time, until
the first thread reports an event.

We do delay reporting NO_HISTORY events until there are no other events to
report to prevent threads at the end of their execution history from starving
other threads.

We keep threads at the end of their execution history moving and replaying
until we announce their stop in to_wait.  This shouldn't really be user-visible
but its a detail worth mentioning.

Since record btrace's to_resume method also picks only a single thread to
resume, there shouldn't be a difference with the current all-stop.

With non-stop or all-stop on top of non-stop, we will see differences.  The
behaviour should be more natural as we're moving all threads.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c: Include vec.h.
	(record_btrace_find_thread_to_move): Removed.
	(btrace_step_no_resumed, btrace_step_again)
	(record_btrace_stop_replaying_at_end): New.
	(record_btrace_cancel_resume): Call record_btrace_stop_replaying_at_end.
	(record_btrace_single_step_forward): Remove calls to
	record_btrace_stop_replaying.
	(record_btrace_step_thread): Do only one step for BTHR_CONT and
	BTHR_RCONT.  Keep threads at the end of their history moving.
	(record_btrace_wait): Call record_btrace_step_thread for all threads
	until one reports an event.  Call record_btrace_stop_replaying_at_end
	for the eventing thread.
---
 gdb/record-btrace.c | 252 ++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 175 insertions(+), 77 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index fcd4351..bda9b7c 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -37,6 +37,7 @@
 #include "infrun.h"
 #include "event-loop.h"
 #include "inf-loop.h"
+#include "vec.h"
 
 /* The target_ops of record-btrace.  */
 static struct target_ops record_btrace_ops;
@@ -1838,6 +1839,26 @@ record_btrace_stop_replaying (struct thread_info *tp)
   registers_changed_ptid (tp->ptid);
 }
 
+/* Stop replaying TP if it is at the end of its execution history.  */
+
+static void
+record_btrace_stop_replaying_at_end (struct thread_info *tp)
+{
+  struct btrace_insn_iterator *replay, end;
+  struct btrace_thread_info *btinfo;
+
+  btinfo = &tp->btrace;
+  replay = btinfo->replay;
+
+  if (replay == NULL)
+    return;
+
+  btrace_insn_end (&end, btinfo);
+
+  if (btrace_insn_cmp (replay, &end) == 0)
+    record_btrace_stop_replaying (tp);
+}
+
 /* The to_resume method of target record-btrace.  */
 
 static void
@@ -1910,26 +1931,7 @@ record_btrace_cancel_resume (struct thread_info *tp)
 	 btrace_thread_flag_to_str (flags));
 
   tp->btrace.flags &= ~(BTHR_MOVE | BTHR_STOP);
-}
-
-/* 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 | BTHR_STOP)) != 0)
-    return tp;
-
-  /* Otherwise, find one other thread that has been resumed.  */
-  ALL_NON_EXITED_THREADS (tp)
-    if ((tp->btrace.flags & (BTHR_MOVE | BTHR_STOP)) != 0)
-      return tp;
-
-  return NULL;
+  record_btrace_stop_replaying_at_end (tp);
 }
 
 /* Return a target_waitstatus indicating that we ran out of history.  */
@@ -1983,6 +1985,30 @@ btrace_step_spurious (void)
   return status;
 }
 
+/* Return a target_waitstatus indicating that the thread was not resumed.  */
+
+static struct target_waitstatus
+btrace_step_no_resumed (void)
+{
+  struct target_waitstatus status;
+
+  status.kind = TARGET_WAITKIND_NO_RESUMED;
+
+  return status;
+}
+
+/* Return a target_waitstatus indicating that we should wait again.  */
+
+static struct target_waitstatus
+btrace_step_again (void)
+{
+  struct target_waitstatus status;
+
+  status.kind = TARGET_WAITKIND_IGNORE;
+
+  return status;
+}
+
 /* Clear the record histories.  */
 
 static void
@@ -2047,24 +2073,22 @@ record_btrace_single_step_forward (struct thread_info *tp)
     {
       unsigned int steps;
 
+      /* We will bail out here if we continue stepping after reaching the end
+	 of the execution history.  */
       steps = btrace_insn_next (replay, 1);
       if (steps == 0)
-	{
-	  record_btrace_stop_replaying (tp);
-	  return btrace_step_no_history ();
-	}
+	return btrace_step_no_history ();
     }
   while (btrace_insn_get (replay) == NULL);
 
   /* Determine the end of the instruction trace.  */
   btrace_insn_end (&end, btinfo);
 
-  /* We stop replaying if we reached the end of the trace.  */
+  /* The execution trace contains (and ends with) the current instruction.
+     This instruction has not been executed, yet, so the trace really ends
+     one instruction earlier.  */
   if (btrace_insn_cmp (replay, &end) == 0)
-    {
-      record_btrace_stop_replaying (tp);
-      return btrace_step_no_history ();
-    }
+    return btrace_step_no_history ();
 
   return btrace_step_spurious ();
 }
@@ -2144,65 +2168,56 @@ record_btrace_step_thread (struct thread_info *tp)
     case BTHR_STEP:
       status = record_btrace_single_step_forward (tp);
       if (status.kind != TARGET_WAITKIND_SPURIOUS)
-	return status;
+	break;
 
       return btrace_step_stopped ();
 
     case BTHR_RSTEP:
       status = record_btrace_single_step_backward (tp);
       if (status.kind != TARGET_WAITKIND_SPURIOUS)
-	return status;
+	break;
 
       return btrace_step_stopped ();
 
     case BTHR_CONT:
-      for (;;)
-	{
-	  status = record_btrace_single_step_forward (tp);
-	  if (status.kind != TARGET_WAITKIND_SPURIOUS)
-	    return status;
-
-	  if (btinfo->replay != NULL)
-	    {
-	      const struct btrace_insn *insn;
-
-	      insn = btrace_insn_get (btinfo->replay);
-	      gdb_assert (insn != NULL);
+      status = record_btrace_single_step_forward (tp);
+      if (status.kind != TARGET_WAITKIND_SPURIOUS)
+	break;
 
-	      DEBUG ("stepping %d (%s) ... %s", tp->num,
-		     target_pid_to_str (tp->ptid),
-		     core_addr_to_string_nz (insn->pc));
-	    }
-	}
+      btinfo->flags |= flags;
+      return btrace_step_again ();
 
     case BTHR_RCONT:
-      for (;;)
-	{
-	  const struct btrace_insn *insn;
-
-	  status = record_btrace_single_step_backward (tp);
-	  if (status.kind != TARGET_WAITKIND_SPURIOUS)
-	    return status;
+      status = record_btrace_single_step_backward (tp);
+      if (status.kind != TARGET_WAITKIND_SPURIOUS)
+	break;
 
-	  gdb_assert (btinfo->replay != NULL);
+      btinfo->flags |= flags;
+      return btrace_step_again ();
+    }
 
-	  insn = btrace_insn_get (btinfo->replay);
-	  gdb_assert (insn != NULL);
+  /* We keep threads moving at the end of their execution history.  The to_wait
+     method will stop the thread for whom the event is reported.  */
+  if (status.kind == TARGET_WAITKIND_NO_HISTORY)
+    btinfo->flags |= flags;
 
-	  DEBUG ("reverse-stepping %d (%s) ... %s", tp->num,
-		 target_pid_to_str (tp->ptid),
-		 core_addr_to_string_nz (insn->pc));
-	}
-    }
+  return status;
 }
 
+/* A vector of threads.  */
+
+typedef struct thread_info * tp_t;
+DEF_VEC_P (tp_t);
+
 /* The to_wait method of target record-btrace.  */
 
 static ptid_t
 record_btrace_wait (struct target_ops *ops, ptid_t ptid,
 		    struct target_waitstatus *status, int options)
 {
-  struct thread_info *tp, *other;
+  VEC (tp_t) *moving, *no_history;
+  struct thread_info *tp, *eventing;
+  struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
 
   DEBUG ("wait %s (0x%x)", target_pid_to_str (ptid), options);
 
@@ -2213,31 +2228,114 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
       return ops->to_wait (ops, ptid, status, options);
     }
 
-  /* Let's find a thread to move.  */
-  tp = record_btrace_find_thread_to_move (ptid);
-  if (tp == NULL)
+  moving = NULL;
+  no_history = NULL;
+
+  make_cleanup (VEC_cleanup (tp_t), &moving);
+  make_cleanup (VEC_cleanup (tp_t), &no_history);
+
+  /* Keep a work list of moving threads.  */
+  ALL_NON_EXITED_THREADS (tp)
+    if (ptid_match (tp->ptid, ptid)
+	&& ((tp->btrace.flags & (BTHR_MOVE | BTHR_STOP)) != 0))
+      VEC_safe_push (tp_t, moving, tp);
+
+  if (VEC_empty (tp_t, moving))
+    {
+      *status = btrace_step_no_resumed ();
+
+      DEBUG ("wait ended by %s: %s", target_pid_to_str (null_ptid),
+	     target_waitstatus_to_string (status));
+
+      do_cleanups (cleanups);
+      return null_ptid;
+    }
+
+  /* Step moving threads one by one, one step each, until either one thread
+     reports an event or we run out of threads to step.
+
+     When stepping more than one thread, chances are that some threads reach
+     the end of their execution history earlier than others.  If we reported
+     this immediately, all-stop on top of non-stop would stop all threads and
+     resume the same threads next time.  And we would report the same thread
+     having reached the end of its execution history again.
+
+     In the worst case, this would starve the other threads.  But even if other
+     threads would be allowed to make progress, this would result in far too
+     many intermediate stops.
+
+     We therefore delay the reporting of "no execution history" until we have
+     nothing else to report.  By this time, all threads should have moved to
+     either the beginning or the end of their execution history.  There will
+     be a single user-visible stop.  */
+  eventing = NULL;
+  while ((eventing == NULL) && !VEC_empty (tp_t, moving))
+    {
+      unsigned int ix;
+
+      ix = 0;
+      while ((eventing == NULL) && VEC_iterate (tp_t, moving, ix, tp))
+	{
+	  *status = record_btrace_step_thread (tp);
+
+	  switch (status->kind)
+	    {
+	    case TARGET_WAITKIND_IGNORE:
+	      ix++;
+	      break;
+
+	    case TARGET_WAITKIND_NO_HISTORY:
+	      VEC_safe_push (tp_t, no_history,
+			     VEC_ordered_remove (tp_t, moving, ix));
+	      break;
+
+	    default:
+	      eventing = VEC_unordered_remove (tp_t, moving, ix);
+	      break;
+	    }
+	}
+    }
+
+  if (eventing == NULL)
     {
-      DEBUG ("wait %s: no thread", target_pid_to_str (ptid));
+      /* We started with at least one moving thread.  This thread must have
+	 either stopped or reached the end of its execution history.
 
-      status->kind = TARGET_WAITKIND_IGNORE;
-      return minus_one_ptid;
+	 In the former case, EVENTING must not be NULL.
+	 In the latter case, NO_HISTORY must not be empty.  */
+      gdb_assert (!VEC_empty (tp_t, no_history));
+
+      /* We kept threads moving at the end of their execution history.  Stop
+	 EVENTING now that we are going to report its stop.  */
+      eventing = VEC_unordered_remove (tp_t, no_history, 0);
+      eventing->btrace.flags &= ~BTHR_MOVE;
+
+      *status = btrace_step_no_history ();
     }
 
-  /* We only move a single thread.  We're not able to correlate threads.  */
-  *status = record_btrace_step_thread (tp);
+  gdb_assert (eventing != NULL);
+
+  /* We kept threads replaying at the end of their execution history.  Stop
+     replaying EVENTING now that we are going to report its stop.  */
+  record_btrace_stop_replaying_at_end (eventing);
 
   /* Stop all other threads. */
   if (!target_is_non_stop_p ())
-    ALL_NON_EXITED_THREADS (other)
-      record_btrace_cancel_resume (other);
+    ALL_NON_EXITED_THREADS (tp)
+      record_btrace_cancel_resume (tp);
 
   /* Start record histories anew from the current position.  */
-  record_btrace_clear_histories (&tp->btrace);
+  record_btrace_clear_histories (&eventing->btrace);
 
   /* We moved the replay position but did not update registers.  */
-  registers_changed_ptid (tp->ptid);
+  registers_changed_ptid (eventing->ptid);
+
+  DEBUG ("wait ended by thread %d (%s): %s", eventing->num,
+	 target_pid_to_str (eventing->ptid),
+	 target_waitstatus_to_string (status));
 
-  return tp->ptid;
+  do_cleanups (cleanups);
+  return eventing->ptid;
 }
 
 /* The to_stop method of target record-btrace.  */
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 05/17] btrace: split record_btrace_step_thread
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 08/17] btrace: lock-step Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 01/17] btrace: fix non-stop check in to_wait Markus Metzger
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

The code for BTHR_STEP and BTHR_CONT is fairly similar.  Extract the common
parts into a new function record_btrace_single_step_forward.  The function
returns TARGET_WAITKIND_SPURIOUS to indicate that the single-step completed
without triggering a trap.

Same for BTHR_RSTEP and BTHR_RCONT.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (btrace_step_spurious)
	(record_btrace_single_step_forward)
	(record_btrace_single_step_backward): New.
	(record_btrace_step_thread): Call record_btrace_single_step_forward
	and record_btrace_single_step_backward.
---
 gdb/record-btrace.c | 187 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 105 insertions(+), 82 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 77494ba..fdf7afb 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1971,6 +1971,18 @@ btrace_step_stopped_on_request (void)
   return status;
 }
 
+/* Return a target_waitstatus indicating a spurious stop.  */
+
+static struct target_waitstatus
+btrace_step_spurious (void)
+{
+  struct target_waitstatus status;
+
+  status.kind = TARGET_WAITKIND_SPURIOUS;
+
+  return status;
+}
+
 /* Clear the record histories.  */
 
 static void
@@ -2011,20 +2023,86 @@ record_btrace_replay_at_breakpoint (struct thread_info *tp)
 					     &btinfo->stop_reason);
 }
 
-/* Step a single thread.  */
+/* Step one instruction in forward direction.  */
 
 static struct target_waitstatus
-record_btrace_step_thread (struct thread_info *tp)
+record_btrace_single_step_forward (struct thread_info *tp)
 {
   struct btrace_insn_iterator *replay, end;
   struct btrace_thread_info *btinfo;
-  enum btrace_thread_flag flags;
-  unsigned int steps;
 
+  btinfo = &tp->btrace;
+  replay = btinfo->replay;
+
+  /* We're done if we're not replaying.  */
+  if (replay == NULL)
+    return btrace_step_no_history ();
+
+  /* Skip gaps during replay.  */
+  do
+    {
+      unsigned int steps;
+
+      steps = btrace_insn_next (replay, 1);
+      if (steps == 0)
+	{
+	  record_btrace_stop_replaying (tp);
+	  return btrace_step_no_history ();
+	}
+    }
+  while (btrace_insn_get (replay) == NULL);
+
+  /* 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_spurious ();
+}
+
+/* Step one instruction in backward direction.  */
+
+static struct target_waitstatus
+record_btrace_single_step_backward (struct thread_info *tp)
+{
+  struct btrace_insn_iterator *replay;
+  struct btrace_thread_info *btinfo;
 
   btinfo = &tp->btrace;
   replay = btinfo->replay;
 
+  /* 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.
+     Skip gaps during replay.  */
+  do
+    {
+      unsigned int steps;
+
+      steps = btrace_insn_prev (replay, 1);
+      if (steps == 0)
+	return btrace_step_no_history ();
+    }
+  while (btrace_insn_get (replay) == NULL);
+
+  return btrace_step_spurious ();
+}
+
+/* Step a single thread.  */
+
+static struct target_waitstatus
+record_btrace_step_thread (struct thread_info *tp)
+{
+  struct btrace_thread_info *btinfo;
+  struct target_waitstatus status;
+  enum btrace_thread_flag flags;
+
+  btinfo = &tp->btrace;
+
   flags = btinfo->flags & (BTHR_MOVE | BTHR_STOP);
   btinfo->flags &= ~(BTHR_MOVE | BTHR_STOP);
 
@@ -2045,110 +2123,55 @@ record_btrace_step_thread (struct thread_info *tp)
       return btrace_step_stopped_on_request ();
 
     case BTHR_STEP:
-      /* We're done if we're not replaying.  */
-      if (replay == NULL)
-	return btrace_step_no_history ();
-
-      /* Skip gaps during replay.  */
-      do
-	{
-	  steps = btrace_insn_next (replay, 1);
-	  if (steps == 0)
-	    {
-	      record_btrace_stop_replaying (tp);
-	      return btrace_step_no_history ();
-	    }
-	}
-      while (btrace_insn_get (replay) == NULL);
-
-      /* 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);
+      status = record_btrace_single_step_forward (tp);
+      if (status.kind != TARGET_WAITKIND_SPURIOUS)
+	return status;
 
       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.
-	 Skip gaps during replay.  */
-      do
-	{
-	  steps = btrace_insn_prev (replay, 1);
-	  if (steps == 0)
-	    return btrace_step_no_history ();
-
-	}
-      while (btrace_insn_get (replay) == NULL);
+      status = record_btrace_single_step_backward (tp);
+      if (status.kind != TARGET_WAITKIND_SPURIOUS)
+	return status;
 
       return btrace_step_stopped ();
 
     case BTHR_CONT:
-      /* We're done if we're not replaying.  */
-      if (replay == NULL)
-	return btrace_step_no_history ();
-
-      /* Determine the end of the instruction trace.  */
-      btrace_insn_end (&end, btinfo);
-
       for (;;)
 	{
-	  const struct btrace_insn *insn;
+	  status = record_btrace_single_step_forward (tp);
+	  if (status.kind != TARGET_WAITKIND_SPURIOUS)
+	    return status;
 
-	  /* Skip gaps during replay.  */
-	  do
+	  if (btinfo->replay != NULL)
 	    {
-	      steps = btrace_insn_next (replay, 1);
-	      if (steps == 0)
-		{
-		  record_btrace_stop_replaying (tp);
-		  return btrace_step_no_history ();
-		}
+	      const struct btrace_insn *insn;
 
-	      insn = btrace_insn_get (replay);
-	    }
-	  while (insn == NULL);
+	      insn = btrace_insn_get (btinfo->replay);
+	      gdb_assert (insn != NULL);
 
-	  /* 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 ();
+	      DEBUG ("stepping %d (%s) ... %s", tp->num,
+		     target_pid_to_str (tp->ptid),
+		     core_addr_to_string_nz (insn->pc));
 	    }
 
-	  DEBUG ("stepping %d (%s) ... %s", tp->num,
-		 target_pid_to_str (tp->ptid),
-		 core_addr_to_string_nz (insn->pc));
-
 	  if (record_btrace_replay_at_breakpoint (tp))
 	    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);
-
       for (;;)
 	{
 	  const struct btrace_insn *insn;
 
-	  /* If we can't step any further, we reached the end of the history.
-	     Skip gaps during replay.  */
-	  do
-	    {
-	      steps = btrace_insn_prev (replay, 1);
-	      if (steps == 0)
-		return btrace_step_no_history ();
+	  status = record_btrace_single_step_backward (tp);
+	  if (status.kind != TARGET_WAITKIND_SPURIOUS)
+	    return status;
 
-	      insn = btrace_insn_get (replay);
-	    }
-	  while (insn == NULL);
+	  gdb_assert (btinfo->replay != NULL);
+
+	  insn = btrace_insn_get (btinfo->replay);
+	  gdb_assert (insn != NULL);
 
 	  DEBUG ("reverse-stepping %d (%s) ... %s", tp->num,
 		 target_pid_to_str (tp->ptid),
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 04/17] btrace: extract the breakpoint check from record_btrace_step_thread
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (3 preceding siblings ...)
  2015-09-11  6:51 ` [PATCH v2 12/17] infrun: switch to NO_HISTORY thread Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 03/17] btrace: improve stepping debugging Markus Metzger
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

There are two places where record_btrace_step_thread checks for a breakpoint
at the current replay position.  Move this code into its own function.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_replay_at_breakpoint): New.
	(record_btrace_step_thread): Call record_btrace_replay_at_breakpoint.
---
 gdb/record-btrace.c | 42 ++++++++++++++++++++++++++++++------------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 7ee681c..77494ba 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1983,6 +1983,34 @@ record_btrace_clear_histories (struct btrace_thread_info *btinfo)
   btinfo->call_history = NULL;
 }
 
+/* Check whether TP's current replay position is at a breakpoint.  */
+
+static int
+record_btrace_replay_at_breakpoint (struct thread_info *tp)
+{
+  struct btrace_insn_iterator *replay;
+  struct btrace_thread_info *btinfo;
+  const struct btrace_insn *insn;
+  struct inferior *inf;
+
+  btinfo = &tp->btrace;
+  replay = btinfo->replay;
+
+  if (replay == NULL)
+    return 0;
+
+  insn = btrace_insn_get (replay);
+  if (insn == NULL)
+    return 0;
+
+  inf = find_inferior_ptid (tp->ptid);
+  if (inf == NULL)
+    return 0;
+
+  return record_check_stopped_by_breakpoint (inf->aspace, insn->pc,
+					     &btinfo->stop_reason);
+}
+
 /* Step a single thread.  */
 
 static struct target_waitstatus
@@ -1990,8 +2018,6 @@ 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;
 
@@ -2067,9 +2093,6 @@ record_btrace_step_thread (struct thread_info *tp)
       if (replay == NULL)
 	return btrace_step_no_history ();
 
-      inf = find_inferior_ptid (tp->ptid);
-      aspace = inf->aspace;
-
       /* Determine the end of the instruction trace.  */
       btrace_insn_end (&end, btinfo);
 
@@ -2102,8 +2125,7 @@ record_btrace_step_thread (struct thread_info *tp)
 		 target_pid_to_str (tp->ptid),
 		 core_addr_to_string_nz (insn->pc));
 
-	  if (record_check_stopped_by_breakpoint (aspace, insn->pc,
-						  &btinfo->stop_reason))
+	  if (record_btrace_replay_at_breakpoint (tp))
 	    return btrace_step_stopped ();
 	}
 
@@ -2112,9 +2134,6 @@ record_btrace_step_thread (struct thread_info *tp)
       if (replay == NULL)
 	replay = record_btrace_start_replaying (tp);
 
-      inf = find_inferior_ptid (tp->ptid);
-      aspace = inf->aspace;
-
       for (;;)
 	{
 	  const struct btrace_insn *insn;
@@ -2135,8 +2154,7 @@ record_btrace_step_thread (struct thread_info *tp)
 		 target_pid_to_str (tp->ptid),
 		 core_addr_to_string_nz (insn->pc));
 
-	  if (record_check_stopped_by_breakpoint (aspace, insn->pc,
-						  &btinfo->stop_reason))
+	  if (record_btrace_replay_at_breakpoint (tp))
 	    return btrace_step_stopped ();
 	}
     }
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 11/17] btrace: async
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (7 preceding siblings ...)
  2015-09-11  6:51 ` [PATCH v2 06/17] btrace: move breakpoint checking into stepping functions Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:52 ` [PATCH v2 15/17] btrace: allow full memory and register access for non-replaying threads Markus Metzger
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

The record btrace target runs synchronous with GDB.  That is, GDB steps
resumed threads in record btrace's to_wait method.  Without GDB calling
to_wait, nothing happens 'on the target'.

Check for further expected events in to_wait before reporting the current
event and mark record btrace's async event handler in async mode.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_maybe_mark_async_event): New.
	(record_btrace_wait): Call record_btrace_maybe_mark_async_event.
---
 gdb/record-btrace.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 0514471..764b349 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -2240,6 +2240,29 @@ record_btrace_step_thread (struct thread_info *tp)
 typedef struct thread_info * tp_t;
 DEF_VEC_P (tp_t);
 
+/* Announce further events if necessary.  */
+
+static void
+record_btrace_maybe_mark_async_event (const VEC (tp_t) *moving,
+				      const VEC (tp_t) *no_history)
+{
+  int more_moving, more_no_history;
+
+  more_moving = !VEC_empty (tp_t, moving);
+  more_no_history = !VEC_empty (tp_t, no_history);
+
+  if (!more_moving && !more_no_history)
+    return;
+
+  if (more_moving)
+    DEBUG ("movers pending");
+
+  if (more_no_history)
+    DEBUG ("no-history pending");
+
+  mark_async_event_handler (record_btrace_async_inferior_event_handler);
+}
+
 /* The to_wait method of target record-btrace.  */
 
 static ptid_t
@@ -2355,6 +2378,10 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
     ALL_NON_EXITED_THREADS (tp)
       record_btrace_cancel_resume (tp);
 
+  /* In async mode, we need to announce further events.  */
+  if (target_is_async_p ())
+    record_btrace_maybe_mark_async_event (moving, no_history);
+
   /* Start record histories anew from the current position.  */
   record_btrace_clear_histories (&eventing->btrace);
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 03/17] btrace: improve stepping debugging
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (4 preceding siblings ...)
  2015-09-11  6:51 ` [PATCH v2 04/17] btrace: extract the breakpoint check from record_btrace_step_thread Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 07/17] btrace: add missing NO_HISTORY Markus Metzger
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (btrace_thread_flag_to_str)
	(record_btrace_cancel_resume): New.
	(record_btrace_step_thread): Call btrace_thread_flag_to_str.
	(record_btrace_resume): Print execution direction.
	(record_btrace_resume_thread): Call btrace_thread_flag_to_str.
	(record_btrace_wait): Call record_btrace_cancel_resume.
---
 gdb/record-btrace.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 53 insertions(+), 4 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index a9ed4b7..7ee681c 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1659,6 +1659,32 @@ record_btrace_to_get_tailcall_unwinder (struct target_ops *self)
   return &record_btrace_tailcall_frame_unwind;
 }
 
+/* Return a human-readable string for FLAG.  */
+
+static const char *
+btrace_thread_flag_to_str (enum btrace_thread_flag flag)
+{
+  switch (flag)
+    {
+    case BTHR_STEP:
+      return "step";
+
+    case BTHR_RSTEP:
+      return "reverse-step";
+
+    case BTHR_CONT:
+      return "cont";
+
+    case BTHR_RCONT:
+      return "reverse-cont";
+
+    case BTHR_STOP:
+      return "stop";
+    }
+
+  return "<invalid>";
+}
+
 /* Indicate that TP should be resumed according to FLAG.  */
 
 static void
@@ -1667,7 +1693,8 @@ record_btrace_resume_thread (struct thread_info *tp,
 {
   struct btrace_thread_info *btinfo;
 
-  DEBUG ("resuming %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flag);
+  DEBUG ("resuming thread %d (%s): %x (%s)", tp->num,
+	 target_pid_to_str (tp->ptid), flag, btrace_thread_flag_to_str (flag));
 
   btinfo = &tp->btrace;
 
@@ -1820,7 +1847,9 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
   struct thread_info *tp, *other;
   enum btrace_thread_flag flag;
 
-  DEBUG ("resume %s: %s", target_pid_to_str (ptid), step ? "step" : "cont");
+  DEBUG ("resume %s: %s%s", target_pid_to_str (ptid),
+	 execution_direction == EXEC_REVERSE ? "reverse-" : "",
+	 step ? "step" : "cont");
 
   /* Store the execution direction of the last resume.  */
   record_btrace_resume_exec_dir = execution_direction;
@@ -1865,6 +1894,24 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
     }
 }
 
+/* Cancel resuming TP.  */
+
+static void
+record_btrace_cancel_resume (struct thread_info *tp)
+{
+  enum btrace_thread_flag flags;
+
+  flags = tp->btrace.flags & (BTHR_MOVE | BTHR_STOP);
+  if (flags == 0)
+    return;
+
+  DEBUG ("cancel resume thread %d (%s): %x (%s)", tp->num,
+	 target_pid_to_str (tp->ptid), flags,
+	 btrace_thread_flag_to_str (flags));
+
+  tp->btrace.flags &= ~(BTHR_MOVE | BTHR_STOP);
+}
+
 /* Find a thread to move.  */
 
 static struct thread_info *
@@ -1955,7 +2002,9 @@ record_btrace_step_thread (struct thread_info *tp)
   flags = btinfo->flags & (BTHR_MOVE | BTHR_STOP);
   btinfo->flags &= ~(BTHR_MOVE | BTHR_STOP);
 
-  DEBUG ("stepping %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flags);
+  DEBUG ("stepping thread %d (%s): %x (%s)", tp->num,
+	 target_pid_to_str (tp->ptid), flags,
+	 btrace_thread_flag_to_str (flags));
 
   /* We can't step without an execution history.  */
   if ((flags & BTHR_MOVE) != 0 && btrace_is_empty (tp))
@@ -2126,7 +2175,7 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
   /* Stop all other threads. */
   if (!target_is_non_stop_p ())
     ALL_NON_EXITED_THREADS (other)
-      other->btrace.flags &= ~(BTHR_MOVE | BTHR_STOP);
+      record_btrace_cancel_resume (other);
 
   /* Start record histories anew from the current position.  */
   record_btrace_clear_histories (&tp->btrace);
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 12/17] infrun: switch to NO_HISTORY thread
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (2 preceding siblings ...)
  2015-09-11  6:51 ` [PATCH v2 01/17] btrace: fix non-stop check in to_wait Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 04/17] btrace: extract the breakpoint check from record_btrace_step_thread Markus Metzger
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

A thread that runs out of its execution history is stopped.  We already set
stop_pc and call stop_waiting.  But we do not switch to the stopped thread.

In normal_stop, we call finish_thread_state_cleanup to set a thread's running
state.  In all-stop mode, we call it with minus_one_ptid; in non-stop mode, we
only call it for inferior_ptid.

If in non-stop mode normal_stop is called on behalf of a thread that is not
inferior_ptid, that other thread will still be reported as running.  If it is
actually stopped it can't be resumed again.

Record targets traditionally don't support non-stop and only resume
inferior_ptid.  So this has not been a problem, so far.

Switch to the eventing thread for NO_HISTORY events as preparation to support
non-stop for the record btrace target.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* infrun.c (handle_inferior_event_1): Switch to the eventing thread
	in the TARKET_WAITKIND_NO_HISTORY case.
---
 gdb/infrun.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index e89e02a..c4a99d8 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5095,8 +5095,14 @@ Cannot fill $_exitsignal with the correct signal number.\n"));
         fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_NO_HISTORY\n");
       /* Reverse execution: target ran out of history info.  */
 
+      /* Switch to the stopped thread.  */
+      if (!ptid_equal (ecs->ptid, inferior_ptid))
+	context_switch (ecs->ptid);
+      if (debug_infrun)
+	fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
+
       delete_just_stopped_threads_single_step_breakpoints ();
-      stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
+      stop_pc = regcache_read_pc (get_thread_regcache (inferior_ptid));
       observer_notify_no_history ();
       stop_waiting (ecs);
       return;
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 01/17] btrace: fix non-stop check in to_wait
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 08/17] btrace: lock-step Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 05/17] btrace: split record_btrace_step_thread Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 12/17] infrun: switch to NO_HISTORY thread Markus Metzger
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

The record btrace target stops other threads in non-stop mode after stepping
the to-be-resumed thread.

The check is done on the non_stop variable.  It should rather be done on
target_is_non_stop_p ().  With all-stop on top of non-stop, infrun will
take care of stopping other threads.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_wait): Replace non_stop check with
	target_is_non_stop_p ().
---
 gdb/record-btrace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 9e16ab4..2d8b20b 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -2104,7 +2104,7 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
   *status = record_btrace_step_thread (tp);
 
   /* Stop all other threads. */
-  if (!non_stop)
+  if (!target_is_non_stop_p ())
     ALL_NON_EXITED_THREADS (other)
       other->btrace.flags &= ~BTHR_MOVE;
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 06/17] btrace: move breakpoint checking into stepping functions
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (6 preceding siblings ...)
  2015-09-11  6:51 ` [PATCH v2 07/17] btrace: add missing NO_HISTORY Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 11/17] btrace: async Markus Metzger
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Breakpoints are only checked for BTHR_CONT and BTHR_RCONT stepping requests.
A BTHR_STEP and BTHR_RSTEP request will always report stopped without reason.
Since breakpoints are reported correctly, I assume infrun is handling this.

Move the breakpoint check into the btrace single stepping functions.  This
will cause us to report breakpoint hits now also for single-step requests.

One thing to notice is that

  - when executing forwards, the breakpoint is checked before 'executing'
    the instruction, i.e. before moving the PC to the next instruction.

  - when executing backwards,  the breakpoint is checked after 'executing'
    the instruction, i.e. after moving the PC to the preceding instruction
    in the recorded execution.

There is code in infrun (see, for example proceed and adjust_pc_after_break)
that handles this and also depends on this behaviour.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_step_thread): Move breakpoint check
	to ...
	(record_btrace_single_step_forward): ... here and
	(record_btrace_single_step_backward): ... here.
---
 gdb/record-btrace.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index fdf7afb..5e8c1d4 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -2038,6 +2038,10 @@ record_btrace_single_step_forward (struct thread_info *tp)
   if (replay == NULL)
     return btrace_step_no_history ();
 
+  /* Check if we're stepping a breakpoint.  */
+  if (record_btrace_replay_at_breakpoint (tp))
+    return btrace_step_stopped ();
+
   /* Skip gaps during replay.  */
   do
     {
@@ -2089,6 +2093,18 @@ record_btrace_single_step_backward (struct thread_info *tp)
     }
   while (btrace_insn_get (replay) == NULL);
 
+  /* Check if we're stepping a breakpoint.
+
+     For reverse-stepping, this check is after the step.  There is logic in
+     infrun.c that handles reverse-stepping separately.  See, for example,
+     proceed and adjust_pc_after_break.
+
+     This code assumes that for reverse-stepping, PC points to the last
+     de-executed instruction, whereas for forward-stepping PC points to the
+     next to-be-executed instruction.  */
+  if (record_btrace_replay_at_breakpoint (tp))
+    return btrace_step_stopped ();
+
   return btrace_step_spurious ();
 }
 
@@ -2154,9 +2170,6 @@ record_btrace_step_thread (struct thread_info *tp)
 		     target_pid_to_str (tp->ptid),
 		     core_addr_to_string_nz (insn->pc));
 	    }
-
-	  if (record_btrace_replay_at_breakpoint (tp))
-	    return btrace_step_stopped ();
 	}
 
     case BTHR_RCONT:
@@ -2176,9 +2189,6 @@ record_btrace_step_thread (struct thread_info *tp)
 	  DEBUG ("reverse-stepping %d (%s) ... %s", tp->num,
 		 target_pid_to_str (tp->ptid),
 		 core_addr_to_string_nz (insn->pc));
-
-	  if (record_btrace_replay_at_breakpoint (tp))
-	    return btrace_step_stopped ();
 	}
     }
 }
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 07/17] btrace: add missing NO_HISTORY
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (5 preceding siblings ...)
  2015-09-11  6:51 ` [PATCH v2 03/17] btrace: improve stepping debugging Markus Metzger
@ 2015-09-11  6:51 ` Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 06/17] btrace: move breakpoint checking into stepping functions Markus Metzger
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:51 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

If a single-step ended right at the end of the execution history, we forgot
to announce that.  Fix it.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_single_step_forward): Return
	NO_HISTORY if a step brings us to the end of the execution history.
---
 gdb/record-btrace.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 5e8c1d4..fcd4351 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -2061,7 +2061,10 @@ record_btrace_single_step_forward (struct thread_info *tp)
 
   /* We stop replaying if we reached the end of the trace.  */
   if (btrace_insn_cmp (replay, &end) == 0)
-    record_btrace_stop_replaying (tp);
+    {
+      record_btrace_stop_replaying (tp);
+      return btrace_step_no_history ();
+    }
 
   return btrace_step_spurious ();
 }
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 16/17] target: add to_record_stop_replaying target method
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (10 preceding siblings ...)
  2015-09-11  6:52 ` [PATCH v2 14/17] target, record: add PTID argument to to_record_is_replaying Markus Metzger
@ 2015-09-11  6:52 ` Markus Metzger
  2015-09-11  6:52 ` [PATCH v2 02/17] btrace: support to_stop Markus Metzger
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Add a new target method to_record_stop_replaying to stop replaying.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_resume): Call
	target_record_stop_replaying.
	(record_btrace_stop_replaying_all): New.
	(init_record_btrace_ops): Initialize to_record_stop_replaying.
	* record-full.c (record_full_stop_replaying): New.
	(init_record_full_ops ): Initialize to_record_stop_replaying.
	* target-delegates.c: Regenerated.
	* target.c (target_record_stop_replaying): New.
	* target.h (struct target_ops) <to_record_stop_replaying>: New.
	(target_record_stop_replaying): New.
---
 gdb/record-btrace.c    | 15 +++++++++++++--
 gdb/record-full.c      |  9 +++++++++
 gdb/target-delegates.c | 26 ++++++++++++++++++++++++++
 gdb/target.c           |  8 ++++++++
 gdb/target.h           |  7 +++++++
 5 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index b4e4560..e0b79a8 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1910,8 +1910,7 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
       /* ...and we stop replaying other threads if the thread to resume is not
 	 replaying.  */
       if (!btrace_is_replaying (tp) && execution_direction != EXEC_REVERSE)
-	ALL_NON_EXITED_THREADS (tp)
-	  record_btrace_stop_replaying (tp);
+	target_record_stop_replaying ();
     }
 
   /* As long as we're not replaying, just forward the request.
@@ -2596,6 +2595,17 @@ record_btrace_goto (struct target_ops *self, ULONGEST insn)
   record_btrace_set_replay (tp, &it);
 }
 
+/* The to_record_stop_replaying method of target record-btrace.  */
+
+static void
+record_btrace_stop_replaying_all (struct target_ops *self)
+{
+  struct thread_info *tp;
+
+  ALL_NON_EXITED_THREADS (tp)
+    record_btrace_stop_replaying (tp);
+}
+
 /* The to_execution_direction target method.  */
 
 static enum exec_direction_kind
@@ -2647,6 +2657,7 @@ init_record_btrace_ops (void)
   ops->to_call_history_from = record_btrace_call_history_from;
   ops->to_call_history_range = record_btrace_call_history_range;
   ops->to_record_is_replaying = record_btrace_is_replaying;
+  ops->to_record_stop_replaying = record_btrace_stop_replaying_all;
   ops->to_xfer_partial = record_btrace_xfer_partial;
   ops->to_remove_breakpoint = record_btrace_remove_breakpoint;
   ops->to_insert_breakpoint = record_btrace_insert_breakpoint;
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 03dc22d..35b3841 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1917,6 +1917,14 @@ record_full_goto (struct target_ops *self, ULONGEST target_insn)
   record_full_goto_entry (p);
 }
 
+/* The "to_record_stop_replaying" target method.  */
+
+static void
+record_full_stop_replaying (struct target_ops *self)
+{
+  record_full_goto_end (self);
+}
+
 static void
 init_record_full_ops (void)
 {
@@ -1957,6 +1965,7 @@ init_record_full_ops (void)
   record_full_ops.to_save_record = record_full_save;
   record_full_ops.to_delete_record = record_full_delete;
   record_full_ops.to_record_is_replaying = record_full_is_replaying;
+  record_full_ops.to_record_stop_replaying = record_full_stop_replaying;
   record_full_ops.to_goto_record_begin = record_full_goto_begin;
   record_full_ops.to_goto_record_end = record_full_goto_end;
   record_full_ops.to_goto_record = record_full_goto;
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index dda817f..f570be1 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -3578,6 +3578,28 @@ debug_record_is_replaying (struct target_ops *self, ptid_t arg1)
 }
 
 static void
+delegate_record_stop_replaying (struct target_ops *self)
+{
+  self = self->beneath;
+  self->to_record_stop_replaying (self);
+}
+
+static void
+tdefault_record_stop_replaying (struct target_ops *self)
+{
+}
+
+static void
+debug_record_stop_replaying (struct target_ops *self)
+{
+  fprintf_unfiltered (gdb_stdlog, "-> %s->to_record_stop_replaying (...)\n", debug_target.to_shortname);
+  debug_target.to_record_stop_replaying (&debug_target);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->to_record_stop_replaying (", debug_target.to_shortname);
+  target_debug_print_struct_target_ops_p (&debug_target);
+  fputs_unfiltered (")\n", gdb_stdlog);
+}
+
+static void
 delegate_goto_record_begin (struct target_ops *self)
 {
   self = self->beneath;
@@ -4210,6 +4232,8 @@ install_delegators (struct target_ops *ops)
     ops->to_delete_record = delegate_delete_record;
   if (ops->to_record_is_replaying == NULL)
     ops->to_record_is_replaying = delegate_record_is_replaying;
+  if (ops->to_record_stop_replaying == NULL)
+    ops->to_record_stop_replaying = delegate_record_stop_replaying;
   if (ops->to_goto_record_begin == NULL)
     ops->to_goto_record_begin = delegate_goto_record_begin;
   if (ops->to_goto_record_end == NULL)
@@ -4375,6 +4399,7 @@ install_dummy_methods (struct target_ops *ops)
   ops->to_save_record = tdefault_save_record;
   ops->to_delete_record = tdefault_delete_record;
   ops->to_record_is_replaying = tdefault_record_is_replaying;
+  ops->to_record_stop_replaying = tdefault_record_stop_replaying;
   ops->to_goto_record_begin = tdefault_goto_record_begin;
   ops->to_goto_record_end = tdefault_goto_record_end;
   ops->to_goto_record = tdefault_goto_record;
@@ -4526,6 +4551,7 @@ init_debug_target (struct target_ops *ops)
   ops->to_save_record = debug_save_record;
   ops->to_delete_record = debug_delete_record;
   ops->to_record_is_replaying = debug_record_is_replaying;
+  ops->to_record_stop_replaying = debug_record_stop_replaying;
   ops->to_goto_record_begin = debug_goto_record_begin;
   ops->to_goto_record_end = debug_goto_record_end;
   ops->to_goto_record = debug_goto_record;
diff --git a/gdb/target.c b/gdb/target.c
index 4b19602..0a393b3 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3656,6 +3656,14 @@ target_record_is_replaying (ptid_t ptid)
 /* See target.h.  */
 
 void
+target_record_stop_replaying (void)
+{
+  current_target.to_record_stop_replaying (&current_target);
+}
+
+/* See target.h.  */
+
+void
 target_goto_record_begin (void)
 {
   current_target.to_goto_record_begin (&current_target);
diff --git a/gdb/target.h b/gdb/target.h
index 1ba1941..926ee15 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1149,6 +1149,10 @@ struct target_ops
     int (*to_record_is_replaying) (struct target_ops *, ptid_t ptid)
       TARGET_DEFAULT_RETURN (0);
 
+    /* Stop replaying.  */
+    void (*to_record_stop_replaying) (struct target_ops *)
+      TARGET_DEFAULT_IGNORE ();
+
     /* Go to the begin of the execution trace.  */
     void (*to_goto_record_begin) (struct target_ops *)
       TARGET_DEFAULT_NORETURN (tcomplain ());
@@ -2426,6 +2430,9 @@ extern void target_delete_record (void);
 /* See to_record_is_replaying in struct target_ops.  */
 extern int target_record_is_replaying (ptid_t ptid);
 
+/* See to_record_stop_replaying in struct target_ops.  */
+extern void target_record_stop_replaying (void);
+
 /* See to_goto_record_begin in struct target_ops.  */
 extern void target_goto_record_begin (void);
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 14/17] target, record: add PTID argument to to_record_is_replaying
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (9 preceding siblings ...)
  2015-09-11  6:52 ` [PATCH v2 15/17] btrace: allow full memory and register access for non-replaying threads Markus Metzger
@ 2015-09-11  6:52 ` Markus Metzger
  2015-09-11  6:52 ` [PATCH v2 16/17] target: add to_record_stop_replaying target method Markus Metzger
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

The to_record_is_replaying target method is used to query record targets if
they are replaying.  This is currently interpreted as "is any thread being
replayed".

Add a PTID argument and change the interpretation to "is any thread matching
PTID being replayed".

Change all users to pass minus_one_ptid to preserve the old meaning.

The record full target does not really support multi-threading and ignores
the PTID argument.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_is_replaying): Add ptid argument.
	Update users to pass minus_one_ptid.
	* record-full.c (record_full_is_replaying): Add ptid argument (ignored).
	* record.c (cmd_record_delete): Pass inferior_ptid to
	target_record_is_replaying.
	* target-delegates.c: Regenerated.
	* target.c (target_record_is_replaying): Add ptid argument.
	* target.h (struct target_ops) <to_record_is_replaying>: Add ptid
	argument.
	(target_record_is_replaying): Add ptid argument.
---
 gdb/record-btrace.c    | 33 +++++++++++++++++++--------------
 gdb/record-full.c      |  2 +-
 gdb/record.c           |  2 +-
 gdb/target-delegates.c | 12 +++++++-----
 gdb/target.c           |  4 ++--
 gdb/target.h           |  6 +++---
 6 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 8eefae2..481d22d 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1136,12 +1136,12 @@ record_btrace_call_history_from (struct target_ops *self,
 /* The to_record_is_replaying method of target record-btrace.  */
 
 static int
-record_btrace_is_replaying (struct target_ops *self)
+record_btrace_is_replaying (struct target_ops *self, ptid_t ptid)
 {
   struct thread_info *tp;
 
   ALL_NON_EXITED_THREADS (tp)
-    if (btrace_is_replaying (tp))
+    if (ptid_match (tp->ptid, ptid) && btrace_is_replaying (tp))
       return 1;
 
   return 0;
@@ -1160,7 +1160,7 @@ record_btrace_xfer_partial (struct target_ops *ops, enum target_object object,
   /* Filter out requests that don't make sense during replay.  */
   if (replay_memory_access == replay_memory_access_read_only
       && !record_btrace_generating_corefile
-      && record_btrace_is_replaying (ops))
+      && record_btrace_is_replaying (ops, minus_one_ptid))
     {
       switch (object)
 	{
@@ -1313,7 +1313,8 @@ record_btrace_store_registers (struct target_ops *ops,
 {
   struct target_ops *t;
 
-  if (!record_btrace_generating_corefile && record_btrace_is_replaying (ops))
+  if (!record_btrace_generating_corefile
+      && record_btrace_is_replaying (ops, minus_one_ptid))
     error (_("This record target does not allow writing registers."));
 
   gdb_assert (may_write_registers != 0);
@@ -1330,7 +1331,8 @@ record_btrace_prepare_to_store (struct target_ops *ops,
 {
   struct target_ops *t;
 
-  if (!record_btrace_generating_corefile && record_btrace_is_replaying (ops))
+  if (!record_btrace_generating_corefile
+      && record_btrace_is_replaying (ops, minus_one_ptid))
     return;
 
   t = ops->beneath;
@@ -1917,7 +1919,8 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
      For non-stop targets this means that no thread is replaying.  In order to
      make progress, we may need to explicitly move replaying threads to the end
      of their execution history.  */
-  if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
+  if ((execution_direction != EXEC_REVERSE)
+      && !record_btrace_is_replaying (ops, minus_one_ptid))
     {
       ops = ops->beneath;
       return ops->to_resume (ops, orig_ptid, step, signal);
@@ -2273,7 +2276,8 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
   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 (ops) && execution_direction != EXEC_REVERSE)
+  if ((execution_direction != EXEC_REVERSE)
+      && !record_btrace_is_replaying (ops, minus_one_ptid))
     {
       ops = ops->beneath;
       return ops->to_wait (ops, ptid, status, options);
@@ -2401,7 +2405,8 @@ record_btrace_stop (struct target_ops *ops, ptid_t ptid)
   DEBUG ("stop %s", target_pid_to_str (ptid));
 
   /* As long as we're not replaying, just forward the request.  */
-  if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
+  if ((execution_direction != EXEC_REVERSE)
+      && !record_btrace_is_replaying (ops, minus_one_ptid))
     {
       ops = ops->beneath;
       ops->to_stop (ops, ptid);
@@ -2432,7 +2437,7 @@ record_btrace_can_execute_reverse (struct target_ops *self)
 static int
 record_btrace_stopped_by_sw_breakpoint (struct target_ops *ops)
 {
-  if (record_btrace_is_replaying (ops))
+  if (record_btrace_is_replaying (ops, minus_one_ptid))
     {
       struct thread_info *tp = inferior_thread ();
 
@@ -2448,7 +2453,7 @@ record_btrace_stopped_by_sw_breakpoint (struct target_ops *ops)
 static int
 record_btrace_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
 {
-  if (record_btrace_is_replaying (ops))
+  if (record_btrace_is_replaying (ops, minus_one_ptid))
     return 1;
 
   return ops->beneath->to_supports_stopped_by_sw_breakpoint (ops->beneath);
@@ -2459,7 +2464,7 @@ record_btrace_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
 static int
 record_btrace_stopped_by_hw_breakpoint (struct target_ops *ops)
 {
-  if (record_btrace_is_replaying (ops))
+  if (record_btrace_is_replaying (ops, minus_one_ptid))
     {
       struct thread_info *tp = inferior_thread ();
 
@@ -2475,7 +2480,7 @@ record_btrace_stopped_by_hw_breakpoint (struct target_ops *ops)
 static int
 record_btrace_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
 {
-  if (record_btrace_is_replaying (ops))
+  if (record_btrace_is_replaying (ops, minus_one_ptid))
     return 1;
 
   return ops->beneath->to_supports_stopped_by_hw_breakpoint (ops->beneath);
@@ -2487,7 +2492,7 @@ static void
 record_btrace_update_thread_list (struct target_ops *ops)
 {
   /* We don't add or remove threads during replay.  */
-  if (record_btrace_is_replaying (ops))
+  if (record_btrace_is_replaying (ops, minus_one_ptid))
     return;
 
   /* Forward the request.  */
@@ -2501,7 +2506,7 @@ static int
 record_btrace_thread_alive (struct target_ops *ops, ptid_t ptid)
 {
   /* We don't add or remove threads during replay.  */
-  if (record_btrace_is_replaying (ops))
+  if (record_btrace_is_replaying (ops, minus_one_ptid))
     return find_thread_ptid (ptid) != NULL;
 
   /* Forward the request.  */
diff --git a/gdb/record-full.c b/gdb/record-full.c
index 06bfdb8..03dc22d 100644
--- a/gdb/record-full.c
+++ b/gdb/record-full.c
@@ -1840,7 +1840,7 @@ record_full_delete (struct target_ops *self)
 /* The "to_record_is_replaying" target method.  */
 
 static int
-record_full_is_replaying (struct target_ops *self)
+record_full_is_replaying (struct target_ops *self, ptid_t ptid)
 {
   return RECORD_FULL_IS_REPLAY;
 }
diff --git a/gdb/record.c b/gdb/record.c
index ad83a29..71ef973 100644
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -234,7 +234,7 @@ cmd_record_delete (char *args, int from_tty)
 {
   require_record_target ();
 
-  if (!target_record_is_replaying ())
+  if (!target_record_is_replaying (inferior_ptid))
     {
       printf_unfiltered (_("Already at end of record list.\n"));
       return;
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 8d51b6c..dda817f 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -3549,26 +3549,28 @@ debug_delete_record (struct target_ops *self)
 }
 
 static int
-delegate_record_is_replaying (struct target_ops *self)
+delegate_record_is_replaying (struct target_ops *self, ptid_t arg1)
 {
   self = self->beneath;
-  return self->to_record_is_replaying (self);
+  return self->to_record_is_replaying (self, arg1);
 }
 
 static int
-tdefault_record_is_replaying (struct target_ops *self)
+tdefault_record_is_replaying (struct target_ops *self, ptid_t arg1)
 {
   return 0;
 }
 
 static int
-debug_record_is_replaying (struct target_ops *self)
+debug_record_is_replaying (struct target_ops *self, ptid_t arg1)
 {
   int result;
   fprintf_unfiltered (gdb_stdlog, "-> %s->to_record_is_replaying (...)\n", debug_target.to_shortname);
-  result = debug_target.to_record_is_replaying (&debug_target);
+  result = debug_target.to_record_is_replaying (&debug_target, arg1);
   fprintf_unfiltered (gdb_stdlog, "<- %s->to_record_is_replaying (", debug_target.to_shortname);
   target_debug_print_struct_target_ops_p (&debug_target);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_ptid_t (arg1);
   fputs_unfiltered (") = ", gdb_stdlog);
   target_debug_print_int (result);
   fputs_unfiltered ("\n", gdb_stdlog);
diff --git a/gdb/target.c b/gdb/target.c
index 3da984e..4b19602 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3648,9 +3648,9 @@ target_delete_record (void)
 /* See target.h.  */
 
 int
-target_record_is_replaying (void)
+target_record_is_replaying (ptid_t ptid)
 {
-  return current_target.to_record_is_replaying (&current_target);
+  return current_target.to_record_is_replaying (&current_target, ptid);
 }
 
 /* See target.h.  */
diff --git a/gdb/target.h b/gdb/target.h
index da18f99..1ba1941 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1145,8 +1145,8 @@ struct target_ops
     void (*to_delete_record) (struct target_ops *)
       TARGET_DEFAULT_NORETURN (tcomplain ());
 
-    /* Query if the record target is currently replaying.  */
-    int (*to_record_is_replaying) (struct target_ops *)
+    /* Query if the record target is currently replaying PTID.  */
+    int (*to_record_is_replaying) (struct target_ops *, ptid_t ptid)
       TARGET_DEFAULT_RETURN (0);
 
     /* Go to the begin of the execution trace.  */
@@ -2424,7 +2424,7 @@ extern int target_supports_delete_record (void);
 extern void target_delete_record (void);
 
 /* See to_record_is_replaying in struct target_ops.  */
-extern int target_record_is_replaying (void);
+extern int target_record_is_replaying (ptid_t ptid);
 
 /* See to_goto_record_begin in struct target_ops.  */
 extern void target_goto_record_begin (void);
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 13/17] btrace: non-stop
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (12 preceding siblings ...)
  2015-09-11  6:52 ` [PATCH v2 02/17] btrace: support to_stop Markus Metzger
@ 2015-09-11  6:52 ` Markus Metzger
  2015-09-11  6:58   ` Eli Zaretskii
  2015-09-11  6:52 ` [PATCH v2 10/17] btrace: temporarily set inferior_ptid in record_btrace_start_replaying Markus Metzger
                   ` (3 subsequent siblings)
  17 siblings, 1 reply; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Eli Zaretskii

Support non-stop mode in record btrace.

CC: Eli Zaretskii <eliz@gnu.org>

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_open): Remove non_stop check.
	* NEWS: Announce that record btrace supports non-stop mode.

testsuite/
	* gdb.btrace/non-stop.c: New.
	* gdb.btrace/non-stop.exp: New.
---
 gdb/NEWS                              |   2 +
 gdb/record-btrace.c                   |   3 -
 gdb/testsuite/gdb.btrace/non-stop.c   |  45 +++++++
 gdb/testsuite/gdb.btrace/non-stop.exp | 245 ++++++++++++++++++++++++++++++++++
 4 files changed, 292 insertions(+), 3 deletions(-)
 create mode 100644 gdb/testsuite/gdb.btrace/non-stop.c
 create mode 100644 gdb/testsuite/gdb.btrace/non-stop.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 0cf51e1..1fa1862 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,8 @@
 
 *** Changes since GDB 7.10
 
+* Record btrace now supports non-stop mode.
+
 * Support for tracepoints on aarch64-linux was added in GDBserver.
 
 * The 'record instruction-history' command now indicates speculative execution
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 764b349..8eefae2 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -216,9 +216,6 @@ record_btrace_open (const char *args, int from_tty)
   if (!target_has_execution)
     error (_("The program is not being run."));
 
-  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);
diff --git a/gdb/testsuite/gdb.btrace/non-stop.c b/gdb/testsuite/gdb.btrace/non-stop.c
new file mode 100644
index 0000000..2fc8dfb
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/non-stop.c
@@ -0,0 +1,45 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2015 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+
+static int global;
+
+static void *
+test (void *arg)
+{
+  unsigned int i;
+
+  i = 0; /* bp.1 */
+  for (; i < 10; ++i) global += i; /* loop */
+
+  return arg; /* bp.2 */
+}
+
+int
+main (void)
+{
+  pthread_t th;
+
+  pthread_create (&th, NULL, test, NULL);
+
+  test (NULL);
+
+  pthread_join (th, NULL);
+
+  return 0; /* bp.3 */
+}
diff --git a/gdb/testsuite/gdb.btrace/non-stop.exp b/gdb/testsuite/gdb.btrace/non-stop.exp
new file mode 100644
index 0000000..bc4ffb1
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/non-stop.exp
@@ -0,0 +1,245 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2015 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# 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
+
+gdb_test_no_output "set non-stop on"
+
+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]
+
+gdb_breakpoint $bp_1
+gdb_breakpoint $bp_2
+
+# get the line number containing most of the trace
+set loop [gdb_get_line_number "loop" $srcfile]
+
+# a stop on the above line as reported by GDB
+set loop_line "$loop\[^\\\r\\\n\]*/\\\* loop \\\*/"
+
+# make sure $line matches the full expected output per thread.
+# and let's hope that GDB never mixes the output from different threads.
+proc gdb_cont_to { threads cmd line nthreads } {
+    global gdb_prompt
+    set full_cmd "thread apply $threads $cmd"
+
+    # consume the prompt.  since we started the command in the background,
+    # the prompt precedes any further output except some errors.
+    gdb_test_multiple "$full_cmd &" "$full_cmd: prompt" {
+        -re "$gdb_prompt " {
+            pass "$full_cmd: prompt"
+        }
+    }
+
+    # now check for the expected line - one per thread.
+    for {set i 0} {$i < $nthreads} {incr i} {
+        set test "$full_cmd: thread $i"
+
+        gdb_test_multiple "" $test {
+            -re "$line\[^\\\r\\\n\]*\r\n" {
+                pass $test
+            }
+        }
+    }
+}
+
+proc gdb_cont_to_bp_line { line threads nthreads } {
+    gdb_cont_to $threads "continue" \
+        [multi_line \
+             "Breakpoint\[^\\\r\\\n\]*$line" \
+             "\[^\\\r\\\n\]*" \
+            ] \
+        $nthreads
+}
+
+proc gdb_cont_to_no_history { threads cmd nthreads } {
+    gdb_cont_to $threads $cmd \
+        [multi_line \
+             "No more reverse-execution history\." \
+             "\[^\\\r\\\n\]*" \
+             "\[^\\\r\\\n\]*" \
+            ] \
+        $nthreads
+}
+
+# trace the code between the two breakpoints
+gdb_cont_to_bp_line "$srcfile:$bp_1" all 2
+gdb_test_no_output "record btrace"
+gdb_cont_to_bp_line "$srcfile:$bp_2" all 2
+
+# we don't need those breakpoints any longer.
+# they will only disturb our stepping.
+delete_breakpoints
+
+# show the threads - this is useful for debugging fails
+gdb_test "thread apply all info rec" ".*"
+gdb_test "info threads" ".*"
+
+with_test_prefix "navigate" {
+    gdb_test "thread apply 1 record goto 2" "$loop_line"
+    gdb_test "thread apply 2 record goto 4" "$loop_line"
+    gdb_test "thread apply 1 info record" \
+        ".*Replay in progress\.  At instruction 2\."
+    gdb_test "thread apply 2 info record" \
+        ".*Replay in progress\.  At instruction 4\."
+
+    gdb_test "thread apply all record goto 5" "$loop_line"
+    gdb_test "thread apply 1 info record" \
+        ".*Replay in progress\.  At instruction 5\."
+    gdb_test "thread apply 2 info record" \
+        ".*Replay in progress\.  At instruction 5\."
+}
+
+with_test_prefix "step" {
+    with_test_prefix "thread 1" {
+        gdb_test "thread apply 1 stepi 2" "$loop_line"
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 7\."
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 5\."
+    }
+
+    with_test_prefix "thread 2" {
+        gdb_test "thread apply 2 stepi 3" "$loop_line"
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 7\."
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 8\."
+    }
+
+    with_test_prefix "all" {
+        gdb_cont_to all "stepi 4" "$loop_line" 2
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 11\."
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 12\."
+    }
+}
+
+with_test_prefix "reverse-step" {
+    with_test_prefix "thread 1" {
+        gdb_test "thread apply 1 reverse-stepi 2" "$loop_line"
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 9\."
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 12\."
+    }
+
+    with_test_prefix "thread 2" {
+        gdb_test "thread apply 2 reverse-stepi 3" "$loop_line"
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 9\."
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 9\."
+    }
+
+    with_test_prefix "all" {
+        gdb_cont_to all "reverse-stepi 4" "$loop_line" 2
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 5\."
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 5\."
+    }
+}
+
+with_test_prefix "continue" {
+    with_test_prefix "thread 1" {
+        gdb_cont_to_no_history 1 "continue" 1
+        gdb_test "thread apply 1 info record" \
+            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 5\."
+
+        gdb_cont_to_no_history 1 "reverse-continue" 1
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 1\."
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 5\."
+    }
+
+    with_test_prefix "thread 2" {
+        gdb_cont_to_no_history 2 "continue" 1
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 1\."
+        gdb_test "thread apply 2 info record" \
+            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
+
+        gdb_cont_to_no_history 2 "reverse-continue" 1
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 1\."
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 1\."
+    }
+}
+
+# a thread may only resume if no thread is still replaying
+with_test_prefix "no progress" {
+    with_test_prefix "thread 1" {
+        gdb_test "thread apply 1 record goto end" ".*"
+        gdb_test "thread apply 2 record goto begin" ".*"
+
+        gdb_cont_to_no_history 1 "continue" 1
+        gdb_cont_to_no_history 1 "step" 1
+        gdb_test "thread apply 1 info record" \
+            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
+        gdb_test "thread apply 2 info record" \
+            ".*Replay in progress\.  At instruction 1\."
+    }
+
+    with_test_prefix "thread 2" {
+        gdb_test "thread apply 1 record goto begin" ".*"
+        gdb_test "thread apply 2 record goto end" ".*"
+
+        gdb_cont_to_no_history 2 "continue" 1
+        gdb_cont_to_no_history 2 "step" 1
+        gdb_test "thread apply 1 info record" \
+            ".*Replay in progress\.  At instruction 1\."
+        gdb_test "thread apply 2 info record" \
+            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
+    }
+
+    with_test_prefix "all" {
+        gdb_test "thread apply all record goto begin" ".*"
+
+        gdb_cont_to_no_history all "continue" 2
+        gdb_test "thread apply 1 info record" \
+            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
+        gdb_test "thread apply 2 info record" \
+            ".*Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*"
+    }
+}
+
+# now that both threads stopped replaying we may resume recording
+with_test_prefix "cont to end" {
+    gdb_breakpoint $bp_3
+    gdb_cont_to_bp_line "$srcfile:$bp_3" all 1
+}
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 00/17] record btrace: non-stop and ASNS
@ 2015-09-11  6:52 Markus Metzger
  2015-09-11  6:51 ` [PATCH v2 08/17] btrace: lock-step Markus Metzger
                   ` (17 more replies)
  0 siblings, 18 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Changes to v1:
  - reworked non-stop test
  - changed the error string when trying to store registers while replaying
  - fixed all-stop/non-stop confusion in comments

This patch series adds support for non-stop mode to the record btrace target
and prepares for all-stop on top of non-stop (ASNS).

It adds a new scheduler-locking mode "reverse" for the current record btrace
behaviour of scheduler-locking during reverse/replay execution.

I tested this with the current all-stop and with Pedro's ASNS (by reverting
his disable patch).

The patch series can also be found on branch users/mmetzger/btrace-non-stop.

Markus Metzger (17):
  btrace: fix non-stop check in to_wait
  btrace: support to_stop
  btrace: improve stepping debugging
  btrace: extract the breakpoint check from record_btrace_step_thread
  btrace: split record_btrace_step_thread
  btrace: move breakpoint checking into stepping functions
  btrace: add missing NO_HISTORY
  btrace: lock-step
  btrace: resume all requested threads
  btrace: temporarily set inferior_ptid in record_btrace_start_replaying
  btrace: async
  infrun: switch to NO_HISTORY thread
  btrace: non-stop
  target, record: add PTID argument to to_record_is_replaying
  btrace: allow full memory and register access for non-replaying
    threads
  target: add to_record_stop_replaying target method
  infrun: scheduler-locking reverse

 gdb/NEWS                              |   6 +
 gdb/btrace.h                          |   5 +-
 gdb/doc/gdb.texinfo                   |   4 +-
 gdb/infrun.c                          |  43 +-
 gdb/record-btrace.c                   | 723 ++++++++++++++++++++++++----------
 gdb/record-full.c                     |  11 +-
 gdb/record.c                          |   2 +-
 gdb/target-delegates.c                |  38 +-
 gdb/target.c                          |  12 +-
 gdb/target.h                          |  13 +-
 gdb/testsuite/gdb.btrace/non-stop.c   |  45 +++
 gdb/testsuite/gdb.btrace/non-stop.exp | 245 ++++++++++++
 12 files changed, 922 insertions(+), 225 deletions(-)
 create mode 100644 gdb/testsuite/gdb.btrace/non-stop.c
 create mode 100644 gdb/testsuite/gdb.btrace/non-stop.exp

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 09/17] btrace: resume all requested threads
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (15 preceding siblings ...)
  2015-09-11  6:52 ` [PATCH v2 17/17] infrun: scheduler-locking reverse Markus Metzger
@ 2015-09-11  6:52 ` Markus Metzger
  2015-09-11  7:56 ` [PATCH v2 00/17] record btrace: non-stop and ASNS Pedro Alves
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

The record targets are implicitly schedlocked.  They only step the current
thread and keep other threads where they are.

Change record btrace to step all requested threads in to_resume.

For maintenance and debugging, we keep the old behaviour when the target below
is not non-stop.  Enable with "maint set target-non-stop on".

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_resume_thread): A move request
	overwrites a previous move request.
	(record_btrace_find_resume_thread): Removed.
	(record_btrace_resume): Resume all requested threads.
---
 gdb/record-btrace.c | 73 ++++++++++++++++++++++++++---------------------------
 1 file changed, 36 insertions(+), 37 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index bda9b7c..c25b8f4 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1699,31 +1699,14 @@ record_btrace_resume_thread (struct thread_info *tp,
 
   btinfo = &tp->btrace;
 
-  if ((btinfo->flags & BTHR_MOVE) != 0)
-    error (_("Thread already moving."));
-
   /* Fetch the latest branch trace.  */
   btrace_fetch (tp);
 
-  /* A resume request overwrites a preceding stop request.  */
-  btinfo->flags &= ~BTHR_STOP;
+  /* A resume request overwrites a preceding resume or stop request.  */
+  btinfo->flags &= ~(BTHR_MOVE | BTHR_STOP);
   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 *
@@ -1865,30 +1848,50 @@ static void
 record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
 		      enum gdb_signal signal)
 {
-  struct thread_info *tp, *other;
+  struct thread_info *tp;
   enum btrace_thread_flag flag;
+  ptid_t orig_ptid;
 
   DEBUG ("resume %s: %s%s", target_pid_to_str (ptid),
 	 execution_direction == EXEC_REVERSE ? "reverse-" : "",
 	 step ? "step" : "cont");
 
-  /* Store the execution direction of the last resume.  */
+  orig_ptid = ptid;
+
+  /* Store the execution direction of the last resume.
+
+     If there is more than one to_resume call, we have to rely on infrun
+     to not change the execution direction in-between.  */
   record_btrace_resume_exec_dir = execution_direction;
 
-  tp = record_btrace_find_resume_thread (ptid);
-  if (tp == NULL)
-    error (_("Cannot find thread to resume."));
+  /* For all-stop targets...  */
+  if (!target_is_non_stop_p ())
+    {
+      /* ...we pick the current thread when asked to resume an entire process
+	 or everything.  */
+      if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid))
+	ptid = inferior_ptid;
+
+      tp = find_thread_ptid (ptid);
+      if (tp == NULL)
+	error (_("Cannot find thread to resume."));
+
+      /* ...and we stop replaying other threads if the thread to resume is not
+	 replaying.  */
+      if (!btrace_is_replaying (tp) && execution_direction != EXEC_REVERSE)
+	ALL_NON_EXITED_THREADS (tp)
+	  record_btrace_stop_replaying (tp);
+    }
 
-  /* Stop replaying other threads if the thread to resume is not replaying.  */
-  if (!btrace_is_replaying (tp) && execution_direction != EXEC_REVERSE)
-    ALL_NON_EXITED_THREADS (other)
-      record_btrace_stop_replaying (other);
+  /* As long as we're not replaying, just forward the request.
 
-  /* As long as we're not replaying, just forward the request.  */
+     For non-stop targets this means that no thread is replaying.  In order to
+     make progress, we may need to explicitly move replaying threads to the end
+     of their execution history.  */
   if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
     {
       ops = ops->beneath;
-      return ops->to_resume (ops, ptid, step, signal);
+      return ops->to_resume (ops, orig_ptid, step, signal);
     }
 
   /* Compute the btrace thread flag for the requested move.  */
@@ -1897,15 +1900,11 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
   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.  */
+  ALL_NON_EXITED_THREADS (tp)
+    if (ptid_match (tp->ptid, ptid))
+      record_btrace_resume_thread (tp, flag);
 
   /* Async support.  */
   if (target_can_async_p ())
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (14 preceding siblings ...)
  2015-09-11  6:52 ` [PATCH v2 10/17] btrace: temporarily set inferior_ptid in record_btrace_start_replaying Markus Metzger
@ 2015-09-11  6:52 ` Markus Metzger
  2015-09-11  7:01   ` Eli Zaretskii
  2015-09-11  6:52 ` [PATCH v2 09/17] btrace: resume all requested threads Markus Metzger
  2015-09-11  7:56 ` [PATCH v2 00/17] record btrace: non-stop and ASNS Pedro Alves
  17 siblings, 1 reply; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Eli Zaretskii

Record targets behave as if scheduler-locking were on during replay/reverse
execution.  Add a new scheduler-locking option "reverse" to make this implicit
behaviour explicit.  It behaves like "on" during reverse/replay execution and
like "off" during normal execution.

By making the current behaviour a scheduler-locking option, we allow the user
to change it.  Since it is the current behaviour, this new option is also
the new default.

One caveat is that when resuming a thread that is at the end of its execution
history, record btrace implicitly stops replaying other threads and resumes
the entire process.  This is a convenience feature to not require the user
to explicitly move all other threads to the end of their execution histories
before being able to resume the process.

We mimick this behaviour with scheduler-locking reverse and move it from
record-btrace into infrun.  With all-stop on top of non-stop, we can't do
this in record-btrace anymore.

Record full does not really support multi-threading and is therefore not
impacted.  If it were extended to support multi-threading, it would 'benefit'
from this change.  The good thing is that all record targets will behave the
same with respect to scheduler-locking.

I put the code for this into clear_proceed_status.  It also sends the
about_to_proceed notification.

CC: Eli Zaretskii <eliz@gnu.org>

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* NEWS: Announce new scheduler-locking mode.
	* infrun.c (schedlock_reverse): New.
	(scheduler_enums): Add schedlock_reverse.
	(scheduler_mode): Change default to schedlock_reverse.
	(user_visible_resume_ptid): Handle schedlock_reverse.
	(clear_proceed_status_thread): Stop replaying if resumed thread is
	not replaying.
	(schedlock_applies): Handle schedlock_reverse.
	(_initialize_infrun): Document new scheduler-locking mode.
	* record-btrace.c (record_btrace_resume): Remove code to stop other
	threads when not replaying the resumed thread.

doc/
	* gdb.texinfo (All-Stop Mode): Describe new scheduler-locking mode.
---
 gdb/NEWS            |  4 ++++
 gdb/doc/gdb.texinfo |  4 +++-
 gdb/infrun.c        | 35 ++++++++++++++++++++++++++++++-----
 gdb/record-btrace.c | 10 ++--------
 4 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 1fa1862..896cdeb 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -45,6 +45,10 @@ show remote multiprocess-extensions-packet
   The "/m" option is now considered deprecated: its "source-centric"
   output hasn't proved useful in practice.
 
+* The "set scheduler-locking" command supports a new mode "reverse".
+  It behaves like "off" during normal execution and like "on" during
+  reverse or replay execution.
+
 * Support for various ROM monitors has been removed:
 
   target dbug		dBUG ROM monitor for Motorola ColdFire
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index cd0abad..36a6777 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -5846,7 +5846,9 @@ Other threads never get a chance to run when you step, and they are
 completely free to run when you use commands
 like @samp{continue}, @samp{until}, or @samp{finish}.  However, unless another
 thread hits a breakpoint during its timeslice, @value{GDBN} does not change
-the current thread away from the thread that you are debugging.
+the current thread away from the thread that you are debugging.  The
+@code{reverse} mode behaves like @code{off} during normal execution
+and like @code{on} during reverse or replay execution.
 
 @item show scheduler-locking
 Display the current scheduler locking mode.
diff --git a/gdb/infrun.c b/gdb/infrun.c
index c4a99d8..403dfcf 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2167,13 +2167,15 @@ resume_cleanups (void *ignore)
 static const char schedlock_off[] = "off";
 static const char schedlock_on[] = "on";
 static const char schedlock_step[] = "step";
+static const char schedlock_reverse[] = "reverse";
 static const char *const scheduler_enums[] = {
   schedlock_off,
   schedlock_on,
   schedlock_step,
+  schedlock_reverse,
   NULL
 };
-static const char *scheduler_mode = schedlock_off;
+static const char *scheduler_mode = schedlock_reverse;
 static void
 show_scheduler_mode (struct ui_file *file, int from_tty,
 		     struct cmd_list_element *c, const char *value)
@@ -2239,6 +2241,14 @@ user_visible_resume_ptid (int step)
 	 resume.  */
       resume_ptid = inferior_ptid;
     }
+  else if ((scheduler_mode == schedlock_reverse)
+	   && ((execution_direction == EXEC_REVERSE)
+	       || target_record_is_replaying (minus_one_ptid)))
+    {
+      /* User-settable 'scheduler' mode requires solo thread resume during
+	 reverse/replay stepping.  */
+      resume_ptid = inferior_ptid;
+    }
   else if (!sched_multi && target_supports_multi_process ())
     {
       /* Resume all threads of the current process (and none of other
@@ -2777,6 +2787,18 @@ clear_proceed_status_thread (struct thread_info *tp)
 void
 clear_proceed_status (int step)
 {
+  /* With scheduler-locking reverse, stop replaying other threads if we're
+     not replaying the user-visible resume ptid.
+
+     This is a convenience feature to not require the user to explicitly
+     stop replaying the other threads.  We're assuming that the user's
+     intent is to resume tracing the recorded process.  */
+  if (!non_stop && (scheduler_mode == schedlock_reverse)
+      && (execution_direction != EXEC_REVERSE)
+      && target_record_is_replaying (minus_one_ptid)
+      && !target_record_is_replaying (user_visible_resume_ptid (step)))
+    target_record_stop_replaying ();
+
   if (!non_stop)
     {
       struct thread_info *tp;
@@ -2864,7 +2886,9 @@ schedlock_applies (struct thread_info *tp)
 {
   return (scheduler_mode == schedlock_on
 	  || (scheduler_mode == schedlock_step
-	      && tp->control.stepping_command));
+	      && tp->control.stepping_command)
+	  || (scheduler_mode == schedlock_reverse
+	      && target_record_is_replaying (minus_one_ptid)));
 }
 
 /* Basic routine for continuing the program in various fashions.
@@ -9066,9 +9090,10 @@ By default, the debugger will use the same inferior."),
 			scheduler_enums, &scheduler_mode, _("\
 Set mode for locking scheduler during execution."), _("\
 Show mode for locking scheduler during execution."), _("\
-off  == no locking (threads may preempt at any time)\n\
-on   == full locking (no thread except the current thread may run)\n\
-step == scheduler locked during stepping commands (step, next, stepi, nexti).\n\
+off     == no locking (threads may preempt at any time)\n\
+on      == full locking (no thread except the current thread may run)\n\
+step    == scheduler locked during stepping commands (step, next, stepi, nexti).\n\
+reverse == scheduler locked during reverse/replay execution.\n\
 	In this mode, other threads may run during other commands."),
 			set_schedlock_func,	/* traps on target vector */
 			show_scheduler_mode,
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index e0b79a8..b8e6466 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1895,22 +1895,16 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
      to not change the execution direction in-between.  */
   record_btrace_resume_exec_dir = execution_direction;
 
-  /* For all-stop targets...  */
+  /* For all-stop targets we pick the current thread when asked to resume an
+     entire process or everything.  */
   if (!target_is_non_stop_p ())
     {
-      /* ...we pick the current thread when asked to resume an entire process
-	 or everything.  */
       if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid))
 	ptid = inferior_ptid;
 
       tp = find_thread_ptid (ptid);
       if (tp == NULL)
 	error (_("Cannot find thread to resume."));
-
-      /* ...and we stop replaying other threads if the thread to resume is not
-	 replaying.  */
-      if (!btrace_is_replaying (tp) && execution_direction != EXEC_REVERSE)
-	target_record_stop_replaying ();
     }
 
   /* As long as we're not replaying, just forward the request.
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 15/17] btrace: allow full memory and register access for non-replaying threads
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (8 preceding siblings ...)
  2015-09-11  6:51 ` [PATCH v2 11/17] btrace: async Markus Metzger
@ 2015-09-11  6:52 ` Markus Metzger
  2015-09-11  6:52 ` [PATCH v2 14/17] target, record: add PTID argument to to_record_is_replaying Markus Metzger
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

The record btrace target does not allow accessing memory and storing registers
while replaying.  For multi-threaded applications, this prevents those
accesses also for threads that are at the end of their execution history as
long as at least one thread is replaying.

Change this to only check if the selected thread is replaying.  This allows
threads that are at the end of their execution history to read and write
memory and to store registers.

Also change the error message to reflect this change.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (record_btrace_xfer_partial)
	(record_btrace_store_registers, record_btrace_prepare_to_store):
	Call record_btrace_is_replaying with inferior_ptid instead of
	minus_one_ptid.
	(record_btrace_store_registers): Change error message.
---
 gdb/record-btrace.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 481d22d..b4e4560 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1160,7 +1160,7 @@ record_btrace_xfer_partial (struct target_ops *ops, enum target_object object,
   /* Filter out requests that don't make sense during replay.  */
   if (replay_memory_access == replay_memory_access_read_only
       && !record_btrace_generating_corefile
-      && record_btrace_is_replaying (ops, minus_one_ptid))
+      && record_btrace_is_replaying (ops, inferior_ptid))
     {
       switch (object)
 	{
@@ -1314,8 +1314,8 @@ record_btrace_store_registers (struct target_ops *ops,
   struct target_ops *t;
 
   if (!record_btrace_generating_corefile
-      && record_btrace_is_replaying (ops, minus_one_ptid))
-    error (_("This record target does not allow writing registers."));
+      && record_btrace_is_replaying (ops, inferior_ptid))
+    error (_("Cannot write registers while replaying."));
 
   gdb_assert (may_write_registers != 0);
 
@@ -1332,7 +1332,7 @@ record_btrace_prepare_to_store (struct target_ops *ops,
   struct target_ops *t;
 
   if (!record_btrace_generating_corefile
-      && record_btrace_is_replaying (ops, minus_one_ptid))
+      && record_btrace_is_replaying (ops, inferior_ptid))
     return;
 
   t = ops->beneath;
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 10/17] btrace: temporarily set inferior_ptid in record_btrace_start_replaying
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (13 preceding siblings ...)
  2015-09-11  6:52 ` [PATCH v2 13/17] btrace: non-stop Markus Metzger
@ 2015-09-11  6:52 ` Markus Metzger
  2015-09-11  6:52 ` [PATCH v2 17/17] infrun: scheduler-locking reverse Markus Metzger
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Get_current_frame uses inferior_ptid.  In record_btrace_start_replaying,
we need to get the current frame of the argument thread.  So far, this
has always been inferior_ptid.  With non-stop, this is not guaranteed.

Temporarily set inferior_ptid to the ptid of the argument thread.

We already temporarily set the argument thread's executing flag to false.

Move both into a new function get_thread_current_frame that does the temporary
adjustments, calls get_current_frame, and restores the previous values.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* record-btrace.c (get_thread_current_frame): New.
	(record_btrace_start_replaying): Call get_thread_current_frame.
---
 gdb/record-btrace.c | 70 ++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 51 insertions(+), 19 deletions(-)

diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index c25b8f4..0514471 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1707,6 +1707,55 @@ record_btrace_resume_thread (struct thread_info *tp,
   btinfo->flags |= flag;
 }
 
+/* Get the current frame for TP.  */
+
+static struct frame_info *
+get_thread_current_frame (struct thread_info *tp)
+{
+  struct frame_info *frame;
+  ptid_t old_inferior_ptid;
+  int executing;
+
+  /* Set INFERIOR_PTID, which is implicitly used by get_current_frame.  */
+  old_inferior_ptid = inferior_ptid;
+  inferior_ptid = tp->ptid;
+
+  /* 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 (inferior_ptid);
+  set_executing (inferior_ptid, 0);
+
+  frame = NULL;
+  TRY
+    {
+      frame = get_current_frame ();
+    }
+  CATCH (except, RETURN_MASK_ALL)
+    {
+      /* Restore the previous execution state.  */
+      set_executing (inferior_ptid, executing);
+
+      /* Restore the previous inferior_ptid.  */
+      inferior_ptid = old_inferior_ptid;
+
+      throw_exception (except);
+    }
+  END_CATCH
+
+  /* Restore the previous execution state.  */
+  set_executing (inferior_ptid, executing);
+
+  /* Restore the previous inferior_ptid.  */
+  inferior_ptid = old_inferior_ptid;
+
+  return frame;
+}
+
 /* Start replaying a thread.  */
 
 static struct btrace_insn_iterator *
@@ -1714,7 +1763,6 @@ record_btrace_start_replaying (struct thread_info *tp)
 {
   struct btrace_insn_iterator *replay;
   struct btrace_thread_info *btinfo;
-  int executing;
 
   btinfo = &tp->btrace;
   replay = NULL;
@@ -1723,16 +1771,6 @@ record_btrace_start_replaying (struct thread_info *tp)
   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
@@ -1745,7 +1783,7 @@ record_btrace_start_replaying (struct thread_info *tp)
       int upd_step_frame_id, upd_step_stack_frame_id;
 
       /* The current frame without replaying - computed via normal unwind.  */
-      frame = get_current_frame ();
+      frame = get_thread_current_frame (tp);
       frame_id = get_frame_id (frame);
 
       /* Check if we need to update any stepping-related frame id's.  */
@@ -1777,7 +1815,7 @@ record_btrace_start_replaying (struct thread_info *tp)
       registers_changed_ptid (tp->ptid);
 
       /* The current frame with replaying - computed via btrace unwind.  */
-      frame = get_current_frame ();
+      frame = get_thread_current_frame (tp);
       frame_id = get_frame_id (frame);
 
       /* Replace stepping related frames where necessary.  */
@@ -1788,9 +1826,6 @@ record_btrace_start_replaying (struct thread_info *tp)
     }
   CATCH (except, RETURN_MASK_ALL)
     {
-      /* Restore the previous execution state.  */
-      set_executing (tp->ptid, executing);
-
       xfree (btinfo->replay);
       btinfo->replay = NULL;
 
@@ -1800,9 +1835,6 @@ record_btrace_start_replaying (struct thread_info *tp)
     }
   END_CATCH
 
-  /* Restore the previous execution state.  */
-  set_executing (tp->ptid, executing);
-
   return replay;
 }
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 02/17] btrace: support to_stop
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (11 preceding siblings ...)
  2015-09-11  6:52 ` [PATCH v2 16/17] target: add to_record_stop_replaying target method Markus Metzger
@ 2015-09-11  6:52 ` Markus Metzger
  2015-09-11  6:52 ` [PATCH v2 13/17] btrace: non-stop Markus Metzger
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 29+ messages in thread
From: Markus Metzger @ 2015-09-11  6:52 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Add support for the to_stop target method to the btrace record target.

2015-09-11  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* btrace.h (enum btrace_thread_flag) <BTHR_STOP>: New.
	* record-btrace (record_btrace_resume_thread): Clear BTHR_STOP.
	(record_btrace_find_thread_to_move): Also accept threads that have
	BTHR_STOP set.
	(btrace_step_stopped_on_request, record_btrace_stop): New.
	(record_btrace_step_thread): Support BTHR_STOP.
	(record_btrace_wait): Also clear BTHR_STOP when stopping other threads.
	(init_record_btrace_ops): Initialize to_stop.
---
 gdb/btrace.h        |  5 ++++-
 gdb/record-btrace.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 59 insertions(+), 9 deletions(-)

diff --git a/gdb/btrace.h b/gdb/btrace.h
index 756a778..f844df8 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -240,7 +240,10 @@ enum btrace_thread_flag
   BTHR_RCONT = (1 << 3),
 
   /* The thread is to be moved.  */
-  BTHR_MOVE = (BTHR_STEP | BTHR_RSTEP | BTHR_CONT | BTHR_RCONT)
+  BTHR_MOVE = (BTHR_STEP | BTHR_RSTEP | BTHR_CONT | BTHR_RCONT),
+
+  /* The thread is to be stopped.  */
+  BTHR_STOP = (1 << 4)
 };
 
 #if defined (HAVE_LIBIPT)
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 2d8b20b..a9ed4b7 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -1677,6 +1677,8 @@ record_btrace_resume_thread (struct thread_info *tp,
   /* Fetch the latest branch trace.  */
   btrace_fetch (tp);
 
+  /* A resume request overwrites a preceding stop request.  */
+  btinfo->flags &= ~BTHR_STOP;
   btinfo->flags |= flag;
 }
 
@@ -1872,12 +1874,12 @@ record_btrace_find_thread_to_move (ptid_t ptid)
 
   /* First check the parameter thread.  */
   tp = find_thread_ptid (ptid);
-  if (tp != NULL && (tp->btrace.flags & BTHR_MOVE) != 0)
+  if (tp != NULL && (tp->btrace.flags & (BTHR_MOVE | BTHR_STOP)) != 0)
     return tp;
 
   /* Otherwise, find one other thread that has been resumed.  */
   ALL_NON_EXITED_THREADS (tp)
-    if ((tp->btrace.flags & BTHR_MOVE) != 0)
+    if ((tp->btrace.flags & (BTHR_MOVE | BTHR_STOP)) != 0)
       return tp;
 
   return NULL;
@@ -1908,6 +1910,20 @@ btrace_step_stopped (void)
   return status;
 }
 
+/* Return a target_waitstatus indicating that a thread was stopped as
+   requested.  */
+
+static struct target_waitstatus
+btrace_step_stopped_on_request (void)
+{
+  struct target_waitstatus status;
+
+  status.kind = TARGET_WAITKIND_STOPPED;
+  status.value.sig = GDB_SIGNAL_0;
+
+  return status;
+}
+
 /* Clear the record histories.  */
 
 static void
@@ -1932,23 +1948,27 @@ record_btrace_step_thread (struct thread_info *tp)
   enum btrace_thread_flag flags;
   unsigned int steps;
 
-  /* We can't step without an execution history.  */
-  if (btrace_is_empty (tp))
-    return btrace_step_no_history ();
 
   btinfo = &tp->btrace;
   replay = btinfo->replay;
 
-  flags = btinfo->flags & BTHR_MOVE;
-  btinfo->flags &= ~BTHR_MOVE;
+  flags = btinfo->flags & (BTHR_MOVE | BTHR_STOP);
+  btinfo->flags &= ~(BTHR_MOVE | BTHR_STOP);
 
   DEBUG ("stepping %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flags);
 
+  /* We can't step without an execution history.  */
+  if ((flags & BTHR_MOVE) != 0 && btrace_is_empty (tp))
+    return btrace_step_no_history ();
+
   switch (flags)
     {
     default:
       internal_error (__FILE__, __LINE__, _("invalid stepping type."));
 
+    case BTHR_STOP:
+      return btrace_step_stopped_on_request ();
+
     case BTHR_STEP:
       /* We're done if we're not replaying.  */
       if (replay == NULL)
@@ -2106,7 +2126,7 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
   /* Stop all other threads. */
   if (!target_is_non_stop_p ())
     ALL_NON_EXITED_THREADS (other)
-      other->btrace.flags &= ~BTHR_MOVE;
+      other->btrace.flags &= ~(BTHR_MOVE | BTHR_STOP);
 
   /* Start record histories anew from the current position.  */
   record_btrace_clear_histories (&tp->btrace);
@@ -2117,6 +2137,32 @@ record_btrace_wait (struct target_ops *ops, ptid_t ptid,
   return tp->ptid;
 }
 
+/* The to_stop method of target record-btrace.  */
+
+static void
+record_btrace_stop (struct target_ops *ops, ptid_t ptid)
+{
+  DEBUG ("stop %s", target_pid_to_str (ptid));
+
+  /* As long as we're not replaying, just forward the request.  */
+  if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
+    {
+      ops = ops->beneath;
+      ops->to_stop (ops, ptid);
+    }
+  else
+    {
+      struct thread_info *tp;
+
+      ALL_NON_EXITED_THREADS (tp)
+       if (ptid_match (tp->ptid, ptid))
+         {
+           tp->btrace.flags &= ~BTHR_MOVE;
+           tp->btrace.flags |= BTHR_STOP;
+         }
+    }
+ }
+
 /* The to_can_execute_reverse method of target record-btrace.  */
 
 static int
@@ -2350,6 +2396,7 @@ init_record_btrace_ops (void)
   ops->to_get_tailcall_unwinder = &record_btrace_to_get_tailcall_unwinder;
   ops->to_resume = record_btrace_resume;
   ops->to_wait = record_btrace_wait;
+  ops->to_stop = record_btrace_stop;
   ops->to_update_thread_list = record_btrace_update_thread_list;
   ops->to_thread_alive = record_btrace_thread_alive;
   ops->to_goto_record_begin = record_btrace_goto_begin;
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 13/17] btrace: non-stop
  2015-09-11  6:52 ` [PATCH v2 13/17] btrace: non-stop Markus Metzger
@ 2015-09-11  6:58   ` Eli Zaretskii
  0 siblings, 0 replies; 29+ messages in thread
From: Eli Zaretskii @ 2015-09-11  6:58 UTC (permalink / raw)
  To: Markus Metzger; +Cc: palves, gdb-patches

> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, Eli Zaretskii <eliz@gnu.org>
> Date: Fri, 11 Sep 2015 08:51:34 +0200
> 
> Support non-stop mode in record btrace.
> 
> CC: Eli Zaretskii <eliz@gnu.org>
> 
> 2015-09-11  Markus Metzger <markus.t.metzger@intel.com>
> 
> gdb/
> 	* record-btrace.c (record_btrace_open): Remove non_stop check.
> 	* NEWS: Announce that record btrace supports non-stop mode.
> 
> testsuite/
> 	* gdb.btrace/non-stop.c: New.
> 	* gdb.btrace/non-stop.exp: New.

OK for the NEWS part.

Thanks.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-11  6:52 ` [PATCH v2 17/17] infrun: scheduler-locking reverse Markus Metzger
@ 2015-09-11  7:01   ` Eli Zaretskii
  2015-09-11  8:55     ` Pedro Alves
  0 siblings, 1 reply; 29+ messages in thread
From: Eli Zaretskii @ 2015-09-11  7:01 UTC (permalink / raw)
  To: Markus Metzger; +Cc: palves, gdb-patches

> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, Eli Zaretskii <eliz@gnu.org>
> Date: Fri, 11 Sep 2015 08:51:38 +0200
> 
> Record targets behave as if scheduler-locking were on during replay/reverse
> execution.  Add a new scheduler-locking option "reverse" to make this implicit
> behaviour explicit.  It behaves like "on" during reverse/replay execution and
> like "off" during normal execution.

I suggest to call this value "replay" instead.  "Reverse" has other
meanings that can interfere with its mnemonic value.

> 2015-09-11  Markus Metzger <markus.t.metzger@intel.com>
> 
> gdb/
> 	* NEWS: Announce new scheduler-locking mode.
> 	* infrun.c (schedlock_reverse): New.
> 	(scheduler_enums): Add schedlock_reverse.
> 	(scheduler_mode): Change default to schedlock_reverse.
> 	(user_visible_resume_ptid): Handle schedlock_reverse.
> 	(clear_proceed_status_thread): Stop replaying if resumed thread is
> 	not replaying.
> 	(schedlock_applies): Handle schedlock_reverse.
> 	(_initialize_infrun): Document new scheduler-locking mode.
> 	* record-btrace.c (record_btrace_resume): Remove code to stop other
> 	threads when not replaying the resumed thread.
> 
> doc/
> 	* gdb.texinfo (All-Stop Mode): Describe new scheduler-locking mode.

OK for the documentation parts.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 00/17] record btrace: non-stop and ASNS
  2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
                   ` (16 preceding siblings ...)
  2015-09-11  6:52 ` [PATCH v2 09/17] btrace: resume all requested threads Markus Metzger
@ 2015-09-11  7:56 ` Pedro Alves
  2015-09-11  8:02   ` Metzger, Markus T
  17 siblings, 1 reply; 29+ messages in thread
From: Pedro Alves @ 2015-09-11  7:56 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

On 09/11/2015 07:51 AM, Markus Metzger wrote:
> Changes to v1:
>   - reworked non-stop test
>   - changed the error string when trying to store registers while replaying
>   - fixed all-stop/non-stop confusion in comments
> 
> This patch series adds support for non-stop mode to the record btrace target
> and prepares for all-stop on top of non-stop (ASNS).
> 
> It adds a new scheduler-locking mode "reverse" for the current record btrace
> behaviour of scheduler-locking during reverse/replay execution.
> 
> I tested this with the current all-stop and with Pedro's ASNS (by reverting
> his disable patch).
> 
> The patch series can also be found on branch users/mmetzger/btrace-non-stop.

Thanks Markus.  The core changes are OK.  The btrace changes all LGTM too.

Excellent work.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH v2 00/17] record btrace: non-stop and ASNS
  2015-09-11  7:56 ` [PATCH v2 00/17] record btrace: non-stop and ASNS Pedro Alves
@ 2015-09-11  8:02   ` Metzger, Markus T
  0 siblings, 0 replies; 29+ messages in thread
From: Metzger, Markus T @ 2015-09-11  8:02 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> -----Original Message-----
> From: gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] On Behalf Of Pedro Alves
> Sent: Friday, September 11, 2015 9:57 AM
> To: Metzger, Markus T
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH v2 00/17] record btrace: non-stop and ASNS
> 
> On 09/11/2015 07:51 AM, Markus Metzger wrote:
> > Changes to v1:
> >   - reworked non-stop test
> >   - changed the error string when trying to store registers while replaying
> >   - fixed all-stop/non-stop confusion in comments
> >
> > This patch series adds support for non-stop mode to the record btrace
> target
> > and prepares for all-stop on top of non-stop (ASNS).
> >
> > It adds a new scheduler-locking mode "reverse" for the current record
> btrace
> > behaviour of scheduler-locking during reverse/replay execution.
> >
> > I tested this with the current all-stop and with Pedro's ASNS (by reverting
> > his disable patch).
> >
> > The patch series can also be found on branch users/mmetzger/btrace-non-
> stop.
> 
> Thanks Markus.  The core changes are OK.  The btrace changes all LGTM too.
> 
> Excellent work.

Thanks.

Eli suggested a different wording for the new scheduler-locking mode.  I'm
waiting a bit for further comments on this patch or for reactions on Eli's
suggestion.

Regards,
Markus.
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Prof. Dr. Hermann Eul
Chairperson of the Supervisory Board: Tiffany Doon Silva
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-11  7:01   ` Eli Zaretskii
@ 2015-09-11  8:55     ` Pedro Alves
  2015-09-11  9:02       ` Eli Zaretskii
  0 siblings, 1 reply; 29+ messages in thread
From: Pedro Alves @ 2015-09-11  8:55 UTC (permalink / raw)
  To: Eli Zaretskii, Markus Metzger; +Cc: gdb-patches

On 09/11/2015 08:00 AM, Eli Zaretskii wrote:
>> From: Markus Metzger <markus.t.metzger@intel.com>
>> Cc: gdb-patches@sourceware.org, Eli Zaretskii <eliz@gnu.org>
>> Date: Fri, 11 Sep 2015 08:51:38 +0200
>>
>> Record targets behave as if scheduler-locking were on during replay/reverse
>> execution.  Add a new scheduler-locking option "reverse" to make this implicit
>> behaviour explicit.  It behaves like "on" during reverse/replay execution and
>> like "off" during normal execution.
> 
> I suggest to call this value "replay" instead.  "Reverse" has other
> meanings that can interfere with its mnemonic value.

I'll admit that when reviewing this, I also noticed that the setting
applies both when stepping backwards, and when replaying forward,
and wondered whether that would be confusing.

Do we call reverse execution "replay" too?  The docs are a bit confusing
on this, sometimes it looks like we do, sometimes not.  E.g., [1]

  When debugging in the reverse direction, gdb will work in replay mode as
  long as the execution log includes the record for the previous instruction;
  otherwise, it will work in record mode, if the platform supports reverse
  execution, or stop if not.

[1] - https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-Replay.html#Process-Record-and-Replay

I think the "If the platform supports reverse execution" part is talking
about when the remote target supports reverse debugging directly,
like e.g., Qemu / Simics / VMWare(?).

But then it seems confusing to call reverse stepping "record mode",
as in "if it's rewinding time, what it is recording??".

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-11  8:55     ` Pedro Alves
@ 2015-09-11  9:02       ` Eli Zaretskii
  2015-09-16 12:28         ` Metzger, Markus T
  0 siblings, 1 reply; 29+ messages in thread
From: Eli Zaretskii @ 2015-09-11  9:02 UTC (permalink / raw)
  To: Pedro Alves; +Cc: markus.t.metzger, gdb-patches

> Date: Fri, 11 Sep 2015 09:55:41 +0100
> From: Pedro Alves <palves@redhat.com>
> CC: gdb-patches@sourceware.org
> 
> I'll admit that when reviewing this, I also noticed that the setting
> applies both when stepping backwards, and when replaying forward,
> and wondered whether that would be confusing.
> 
> Do we call reverse execution "replay" too?  The docs are a bit confusing
> on this, sometimes it looks like we do, sometimes not.  E.g., [1]
> 
>   When debugging in the reverse direction, gdb will work in replay mode as
>   long as the execution log includes the record for the previous instruction;
>   otherwise, it will work in record mode, if the platform supports reverse
>   execution, or stop if not.
> 
> [1] - https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-Replay.html#Process-Record-and-Replay
> 
> I think the "If the platform supports reverse execution" part is talking
> about when the remote target supports reverse debugging directly,
> like e.g., Qemu / Simics / VMWare(?).
> 
> But then it seems confusing to call reverse stepping "record mode",
> as in "if it's rewinding time, what it is recording??".

I'm okay with calling the value "reverse-execution".  But "reverse"
alone caused my brow to raise, since that value doesn't reverse
anything.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-11  9:02       ` Eli Zaretskii
@ 2015-09-16 12:28         ` Metzger, Markus T
  2015-09-16 12:54           ` Pedro Alves
  0 siblings, 1 reply; 29+ messages in thread
From: Metzger, Markus T @ 2015-09-16 12:28 UTC (permalink / raw)
  To: Eli Zaretskii, Pedro Alves; +Cc: gdb-patches

> -----Original Message-----
> From: Eli Zaretskii [mailto:eliz@gnu.org]
> Sent: Friday, September 11, 2015 11:02 AM
> To: Pedro Alves
> Cc: Metzger, Markus T; gdb-patches@sourceware.org
> Subject: Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
> 
> > Date: Fri, 11 Sep 2015 09:55:41 +0100
> > From: Pedro Alves <palves@redhat.com>
> > CC: gdb-patches@sourceware.org

The second paragraph of [1] says "When this [record] target is in use, if the
execution log includes the record for the next instruction, gdb will debug in
replay mode.".

Following this definition of "replay mode", I agree with Eli's first suggestion
to call the new scheduler-locking mode "replay".

I'm avoiding the term "replay" since esp. record btrace does not replay in the
sense of "re-execute the program".  All it does is move the PC around.  Record
full does a bit more but it is still not re-executing the program.


> > I'll admit that when reviewing this, I also noticed that the setting
> > applies both when stepping backwards, and when replaying forward,
> > and wondered whether that would be confusing.
> >
> > Do we call reverse execution "replay" too?  The docs are a bit confusing
> > on this, sometimes it looks like we do, sometimes not.  E.g., [1]
> >
> >   When debugging in the reverse direction, gdb will work in replay mode as
> >   long as the execution log includes the record for the previous instruction;
> >   otherwise, it will work in record mode, if the platform supports reverse
> >   execution, or stop if not.
> >
> > [1] - https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-
> Replay.html#Process-Record-and-Replay
> >
> > I think the "If the platform supports reverse execution" part is talking
> > about when the remote target supports reverse debugging directly,
> > like e.g., Qemu / Simics / VMWare(?).
> >
> > But then it seems confusing to call reverse stepping "record mode",
> > as in "if it's rewinding time, what it is recording??".

It looks like "replay" mode means that GDB is executing from its (own)
execution log; "record" mode means that GDB is extending its execution
log.

Traditionally, GDB records when stepping forward from the end of the
execution log.  On targets that support native reverse-stepping, however,
GDB is able to extend its execution log also when stepping backward from
the beginning of GDB's execution log.

This doesn't work with record btrace.

Regards,
Markus.

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Prof. Dr. Hermann Eul
Chairperson of the Supervisory Board: Tiffany Doon Silva
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-16 12:28         ` Metzger, Markus T
@ 2015-09-16 12:54           ` Pedro Alves
  2015-09-16 13:32             ` Pedro Alves
  0 siblings, 1 reply; 29+ messages in thread
From: Pedro Alves @ 2015-09-16 12:54 UTC (permalink / raw)
  To: Metzger, Markus T, Eli Zaretskii; +Cc: gdb-patches

On 09/16/2015 01:27 PM, Metzger, Markus T wrote:
>> -----Original Message-----
>> From: Eli Zaretskii [mailto:eliz@gnu.org]
>> Sent: Friday, September 11, 2015 11:02 AM
>> To: Pedro Alves
>> Cc: Metzger, Markus T; gdb-patches@sourceware.org
>> Subject: Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
>>
>>> Date: Fri, 11 Sep 2015 09:55:41 +0100
>>> From: Pedro Alves <palves@redhat.com>
>>> CC: gdb-patches@sourceware.org
> 
> The second paragraph of [1] says "When this [record] target is in use, if the
> execution log includes the record for the next instruction, gdb will debug in
> replay mode.".
> 
> Following this definition of "replay mode", I agree with Eli's first suggestion
> to call the new scheduler-locking mode "replay".

Me too.

> It looks like "replay" mode means that GDB is executing from its (own)
> execution log; "record" mode means that GDB is extending its execution
> log.

That makes sense.

> 
> Traditionally, GDB records when stepping forward from the end of the
> execution log.  On targets that support native reverse-stepping, however,
> GDB is able to extend its execution log also when stepping backward from
> the beginning of GDB's execution log.

Sounds like wishful thinking on the part of the author though then.
I don't think that gdb actually implements that, or ever did.

> This doesn't work with record btrace.

AFAICS, it doesn't work with record-full either.

When you reach the end of the execution log going backwards, and then issue
another back-step, record_full_wait_1 does not try to step backwards any
further, but just immediately returns TARGET_WAITKIND_NO_HISTORY again.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-16 12:54           ` Pedro Alves
@ 2015-09-16 13:32             ` Pedro Alves
  2015-09-16 13:56               ` Metzger, Markus T
  0 siblings, 1 reply; 29+ messages in thread
From: Pedro Alves @ 2015-09-16 13:32 UTC (permalink / raw)
  To: Metzger, Markus T, Eli Zaretskii; +Cc: gdb-patches

On 09/16/2015 01:54 PM, Pedro Alves wrote:
> On 09/16/2015 01:27 PM, Metzger, Markus T wrote:
>>> -----Original Message-----
>>> From: Eli Zaretskii [mailto:eliz@gnu.org]
>>> Sent: Friday, September 11, 2015 11:02 AM
>>> To: Pedro Alves
>>> Cc: Metzger, Markus T; gdb-patches@sourceware.org
>>> Subject: Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
>>>
>>>> Date: Fri, 11 Sep 2015 09:55:41 +0100
>>>> From: Pedro Alves <palves@redhat.com>
>>>> CC: gdb-patches@sourceware.org
>>
>> The second paragraph of [1] says "When this [record] target is in use, if the
>> execution log includes the record for the next instruction, gdb will debug in
>> replay mode.".
>>
>> Following this definition of "replay mode", I agree with Eli's first suggestion
>> to call the new scheduler-locking mode "replay".
> 
> Me too.

Actually, there's still one detail, that goes back to what I first asked;
whether we call reverse execution "replay" too.  So it now
sounds clearer to me that when we're reverse debugging with a target
that does native reverse-stepping, where the user is not using
a record/replay target and has not typed "record", etc., we don't
call reverse debugging "replay".  However, the patch had this:

+  else if ((scheduler_mode == schedlock_reverse)
+	   && ((execution_direction == EXEC_REVERSE)
+	       || target_record_is_replaying (minus_one_ptid)))
+    {

That means that the setting is in effect also when reverse debugging
_without_ a record/replay target, e.g., with qemu/simics/etc.
Do we want the setting to take effect with these too, or do we not?
It doesn't a difference in practice today because the RSP packets for
reverse debugging assuming a single threaded target, but once we
support connecting to multiple remote targets at the same time, for
instance, it would come into effect.

Just bringing this up so we make an informed decision.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 29+ messages in thread

* RE: [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-16 13:32             ` Pedro Alves
@ 2015-09-16 13:56               ` Metzger, Markus T
  2015-09-16 14:25                 ` Pedro Alves
  0 siblings, 1 reply; 29+ messages in thread
From: Metzger, Markus T @ 2015-09-16 13:56 UTC (permalink / raw)
  To: Pedro Alves, Eli Zaretskii; +Cc: gdb-patches

> -----Original Message-----
> From: Pedro Alves [mailto:palves@redhat.com]
> Sent: Wednesday, September 16, 2015 3:33 PM
> To: Metzger, Markus T; Eli Zaretskii
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH v2 17/17] infrun: scheduler-locking reverse


> Actually, there's still one detail, that goes back to what I first asked;
> whether we call reverse execution "replay" too.  So it now
> sounds clearer to me that when we're reverse debugging with a target
> that does native reverse-stepping, where the user is not using
> a record/replay target and has not typed "record", etc., we don't
> call reverse debugging "replay".  However, the patch had this:
> 
> +  else if ((scheduler_mode == schedlock_reverse)
> +	   && ((execution_direction == EXEC_REVERSE)
> +	       || target_record_is_replaying (minus_one_ptid)))
> +    {

The target_record_is_replaying (minus_one_ptid) call checks whether
	a) there is a record target and
	b) whether at least one thread is in replay mode.

We might have a record target but none of the threads are currently
replaying.  For record btrace this means that all threads are at the end
of their execution history (including an empty history).

That's why we need to check the execution direction, as well.


> That means that the setting is in effect also when reverse debugging
> _without_ a record/replay target, e.g., with qemu/simics/etc.
> Do we want the setting to take effect with these too, or do we not?
> It doesn't a difference in practice today because the RSP packets for
> reverse debugging assuming a single threaded target, but once we
> support connecting to multiple remote targets at the same time, for
> instance, it would come into effect.

What if we added an execution_direction parameter to
to_record_is_replaying?

I wouldn't use the global variable since it isn't obvious that the execution
mode plays any role here.  It might further change between the check
and the actual resume.

Record btrace would return true if at least one thread is replaying or
if the execution direction is reverse.

Record full would return true if either
a) the execution direction is reverse and at least one thread is not
at the beginning of its execution history.
b) the execution direction is forward and at least one thread is not
at the end of its execution history.

That is, it will, once it actually supports this.

The default would be false.


If you're OK with this, I can add it as a separate patch and use it in the
schedlock patch.

Regards,
Markus.

Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Prof. Dr. Hermann Eul
Chairperson of the Supervisory Board: Tiffany Doon Silva
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 17/17] infrun: scheduler-locking reverse
  2015-09-16 13:56               ` Metzger, Markus T
@ 2015-09-16 14:25                 ` Pedro Alves
  0 siblings, 0 replies; 29+ messages in thread
From: Pedro Alves @ 2015-09-16 14:25 UTC (permalink / raw)
  To: Metzger, Markus T, Eli Zaretskii; +Cc: gdb-patches

On 09/16/2015 02:56 PM, Metzger, Markus T wrote:

> If you're OK with this, I can add it as a separate patch and use it in the
> schedlock patch.

Sounds good to me.

Thanks,
Pedro Alves

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2015-09-16 14:25 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-11  6:52 [PATCH v2 00/17] record btrace: non-stop and ASNS Markus Metzger
2015-09-11  6:51 ` [PATCH v2 08/17] btrace: lock-step Markus Metzger
2015-09-11  6:51 ` [PATCH v2 05/17] btrace: split record_btrace_step_thread Markus Metzger
2015-09-11  6:51 ` [PATCH v2 01/17] btrace: fix non-stop check in to_wait Markus Metzger
2015-09-11  6:51 ` [PATCH v2 12/17] infrun: switch to NO_HISTORY thread Markus Metzger
2015-09-11  6:51 ` [PATCH v2 04/17] btrace: extract the breakpoint check from record_btrace_step_thread Markus Metzger
2015-09-11  6:51 ` [PATCH v2 03/17] btrace: improve stepping debugging Markus Metzger
2015-09-11  6:51 ` [PATCH v2 07/17] btrace: add missing NO_HISTORY Markus Metzger
2015-09-11  6:51 ` [PATCH v2 06/17] btrace: move breakpoint checking into stepping functions Markus Metzger
2015-09-11  6:51 ` [PATCH v2 11/17] btrace: async Markus Metzger
2015-09-11  6:52 ` [PATCH v2 15/17] btrace: allow full memory and register access for non-replaying threads Markus Metzger
2015-09-11  6:52 ` [PATCH v2 14/17] target, record: add PTID argument to to_record_is_replaying Markus Metzger
2015-09-11  6:52 ` [PATCH v2 16/17] target: add to_record_stop_replaying target method Markus Metzger
2015-09-11  6:52 ` [PATCH v2 02/17] btrace: support to_stop Markus Metzger
2015-09-11  6:52 ` [PATCH v2 13/17] btrace: non-stop Markus Metzger
2015-09-11  6:58   ` Eli Zaretskii
2015-09-11  6:52 ` [PATCH v2 10/17] btrace: temporarily set inferior_ptid in record_btrace_start_replaying Markus Metzger
2015-09-11  6:52 ` [PATCH v2 17/17] infrun: scheduler-locking reverse Markus Metzger
2015-09-11  7:01   ` Eli Zaretskii
2015-09-11  8:55     ` Pedro Alves
2015-09-11  9:02       ` Eli Zaretskii
2015-09-16 12:28         ` Metzger, Markus T
2015-09-16 12:54           ` Pedro Alves
2015-09-16 13:32             ` Pedro Alves
2015-09-16 13:56               ` Metzger, Markus T
2015-09-16 14:25                 ` Pedro Alves
2015-09-11  6:52 ` [PATCH v2 09/17] btrace: resume all requested threads Markus Metzger
2015-09-11  7:56 ` [PATCH v2 00/17] record btrace: non-stop and ASNS Pedro Alves
2015-09-11  8:02   ` Metzger, Markus T

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).