public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] gdb: replay diversion support
@ 2021-06-01 19:10 George Barrett
  2021-06-01 19:10 ` [RFC PATCH 1/7] gdb: add replay diversion interface to target_ops George Barrett
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: George Barrett

This patch series makes the GDB core aware of temporary diversions of
execution in a replay target and adds a remote protocol extension for
manipulating such diversions.

* Background

rr[1] is a deterministic process record and replay system for
Linux. Recording works by trapping on sources of non-deterministic
inputs (such as system calls, `rdtsc', signals, etc) during execution
and saving the inputs in a trace; replay executes the program,
intercepting these same sources and writing the previously-recorded
results to the process state. A GDB remote target is implemented for
interactive debugging of the replay. This enables space-efficient
whole-program record and replay with nifty features like reverse
debugging (if you've not already done so, definitely check it out!).

One of the cool features enabled by this approach is support for
inferior calls, since replay involves an actual live inferior
executing code; however, maintaining determinism means any state
changes must not impact replay and are necessarily limited in scope
and duration. rr solves this by attempting to detect when GDB is about
to start an inferior call and creating a 'diversion session' (a clone
of the process and rr state); this diversion session becomes the
inferior on which GDB operates until the next continue, at which point
the diversion is destroyed and the original replay session takes
over. This is usually transparent to both GDB and the user, but doing
this under GDB's nose has been a continuing source of bugs.

* Purpose

The goal of this series is to move the diversion session logic out of
rr and into GDB: rather than rr using heuristics and hacks to try and
guess what GDB wants and trying to manipulate state under it, GDB is
aware of diversions and is responsible for telling rr when to start
and end diversions. Obviously this work has been done with rr in mind,
but since the basic concept behind rr is fairly general I've tried to
design an interface that should be equally applicable to other rr-like
systems.

The proposed changes to rr can be found here.[2]

[1]: https://rr-project.org/
[2]: https://github.com/rr-debugger/rr/pull/2877

George Barrett (7):
  gdb: add replay diversion interface to target_ops
  gdb: handle early replay diversion exits
  gdb/remote: add vReplayDiversion packet
  gdb/inferior: add replay diversion state
  gdb/infcall: enter replay diversion before call
  gdb/infrun: solo thread resume in replay diversion
  gdb/infcmd: add replay diversion commands

 gdb/doc/gdb.texinfo     |  40 ++++++++++++++
 gdb/infcall.c           |   6 +++
 gdb/infcmd.c            |  59 +++++++++++++++++++-
 gdb/inferior.c          |  23 ++++++++
 gdb/inferior.h          |  21 ++++++++
 gdb/infrun.c            |  41 ++++++++++++--
 gdb/remote.c            | 116 ++++++++++++++++++++++++++++++++++++++--
 gdb/target-delegates.c  | 100 ++++++++++++++++++++++++++++++++++
 gdb/target.c            |  32 +++++++++++
 gdb/target.h            |  31 +++++++++++
 gdb/target/waitstatus.c |   2 +
 gdb/target/waitstatus.h |   4 ++
 12 files changed, 466 insertions(+), 9 deletions(-)

-- 
2.31.1

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

* [RFC PATCH 1/7] gdb: add replay diversion interface to target_ops
  2021-06-01 19:10 [RFC PATCH 0/7] gdb: replay diversion support George Barrett
@ 2021-06-01 19:10 ` George Barrett
  2021-06-01 19:10 ` [RFC PATCH 2/7] gdb: handle early replay diversion exits George Barrett
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: George Barrett

Some process replay targets do not support arbitrary manipulations of
their state, but instead require that things like memory or register
writes be done within a temporary 'replay diversion'. This commit adds
an interface through which such targets can announce their support of
such diversions and through which GDB can control the target's replay
diversion state.

gdb/ChangeLog:

2021-06-01  George Barrett  <bob@bob131.so>

	* target-delegates.c: Regenerate.
	* target.c (target_needs_replay_diversion)
	(target_in_replay_diversion, target_start_replay_diversion)
	(target_end_replay_diversion): Add definitions.
	* target.h (target_ops::needs_replay_diversion)
	(target_ops::in_replay_diversion)
	(target_ops::start_replay_diversion)
	(target_ops::end_replay_diversion): Add declarations.
	(target_needs_replay_diversion, target_in_replay_diversion)
	(target_start_replay_diversion, target_end_replay_diversion):
	Likewise.
---
 gdb/target-delegates.c | 100 +++++++++++++++++++++++++++++++++++++++++
 gdb/target.c           |  32 +++++++++++++
 gdb/target.h           |  31 +++++++++++++
 3 files changed, 163 insertions(+)

diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 3e759a2f80e..12ce70193c8 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -160,6 +160,10 @@ struct dummy_target : public target_ops
   bool record_is_replaying (ptid_t arg0) override;
   bool record_will_replay (ptid_t arg0, int arg1) override;
   void record_stop_replaying () override;
+  bool needs_replay_diversion () override;
+  bool in_replay_diversion () override;
+  void start_replay_diversion () override;
+  void end_replay_diversion () override;
   void goto_record_begin () override;
   void goto_record_end () override;
   void goto_record (ULONGEST arg0) override;
@@ -335,6 +339,10 @@ struct debug_target : public target_ops
   bool record_is_replaying (ptid_t arg0) override;
   bool record_will_replay (ptid_t arg0, int arg1) override;
   void record_stop_replaying () override;
+  bool needs_replay_diversion () override;
+  bool in_replay_diversion () override;
+  void start_replay_diversion () override;
+  void end_replay_diversion () override;
   void goto_record_begin () override;
   void goto_record_end () override;
   void goto_record (ULONGEST arg0) override;
@@ -4113,6 +4121,98 @@ debug_target::record_stop_replaying ()
   fputs_unfiltered (")\n", gdb_stdlog);
 }
 
+bool
+target_ops::needs_replay_diversion ()
+{
+  return this->beneath ()->needs_replay_diversion ();
+}
+
+bool
+dummy_target::needs_replay_diversion ()
+{
+  return false;
+}
+
+bool
+debug_target::needs_replay_diversion ()
+{
+  bool result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->needs_replay_diversion (...)\n", this->beneath ()->shortname ());
+  result = this->beneath ()->needs_replay_diversion ();
+  fprintf_unfiltered (gdb_stdlog, "<- %s->needs_replay_diversion (", this->beneath ()->shortname ());
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_bool (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
+bool
+target_ops::in_replay_diversion ()
+{
+  return this->beneath ()->in_replay_diversion ();
+}
+
+bool
+dummy_target::in_replay_diversion ()
+{
+  return false;
+}
+
+bool
+debug_target::in_replay_diversion ()
+{
+  bool result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->in_replay_diversion (...)\n", this->beneath ()->shortname ());
+  result = this->beneath ()->in_replay_diversion ();
+  fprintf_unfiltered (gdb_stdlog, "<- %s->in_replay_diversion (", this->beneath ()->shortname ());
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_bool (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
+void
+target_ops::start_replay_diversion ()
+{
+  this->beneath ()->start_replay_diversion ();
+}
+
+void
+dummy_target::start_replay_diversion ()
+{
+  tcomplain ();
+}
+
+void
+debug_target::start_replay_diversion ()
+{
+  fprintf_unfiltered (gdb_stdlog, "-> %s->start_replay_diversion (...)\n", this->beneath ()->shortname ());
+  this->beneath ()->start_replay_diversion ();
+  fprintf_unfiltered (gdb_stdlog, "<- %s->start_replay_diversion (", this->beneath ()->shortname ());
+  fputs_unfiltered (")\n", gdb_stdlog);
+}
+
+void
+target_ops::end_replay_diversion ()
+{
+  this->beneath ()->end_replay_diversion ();
+}
+
+void
+dummy_target::end_replay_diversion ()
+{
+  tcomplain ();
+}
+
+void
+debug_target::end_replay_diversion ()
+{
+  fprintf_unfiltered (gdb_stdlog, "-> %s->end_replay_diversion (...)\n", this->beneath ()->shortname ());
+  this->beneath ()->end_replay_diversion ();
+  fprintf_unfiltered (gdb_stdlog, "<- %s->end_replay_diversion (", this->beneath ()->shortname ());
+  fputs_unfiltered (")\n", gdb_stdlog);
+}
+
 void
 target_ops::goto_record_begin ()
 {
diff --git a/gdb/target.c b/gdb/target.c
index 6babfc56256..7fbc6a1cd8d 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -4134,6 +4134,38 @@ target_record_stop_replaying (void)
 
 /* See target.h.  */
 
+bool
+target_needs_replay_diversion (void)
+{
+  return current_inferior ()->top_target ()->needs_replay_diversion ();
+}
+
+/* See target.h.  */
+
+bool
+target_in_replay_diversion (void)
+{
+  return current_inferior ()->top_target ()->in_replay_diversion ();
+}
+
+/* See target.h.  */
+
+void
+target_start_replay_diversion (void)
+{
+  current_inferior ()->top_target ()->start_replay_diversion ();
+}
+
+/* See target.h.  */
+
+void
+target_end_replay_diversion (void)
+{
+  current_inferior ()->top_target ()->end_replay_diversion ();
+}
+
+/* See target.h.  */
+
 void
 target_goto_record_begin (void)
 {
diff --git a/gdb/target.h b/gdb/target.h
index e22f9038197..4b0ddb40fa8 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1218,6 +1218,25 @@ struct target_ops
     virtual void record_stop_replaying ()
       TARGET_DEFAULT_IGNORE ();
 
+    /* Return TRUE if THIS is a deterministic replay target that
+       requires a special environment (a 'replay diversion') to be set
+       up before memory or register writes are possible.  */
+    virtual bool needs_replay_diversion ()
+      TARGET_DEFAULT_RETURN (false);
+
+    /* Return TRUE if the target is currently in a replay
+       diversion.  */
+    virtual bool in_replay_diversion ()
+      TARGET_DEFAULT_RETURN (false);
+
+    /* Begin a replay diversion.  */
+    virtual void start_replay_diversion ()
+      TARGET_DEFAULT_NORETURN (tcomplain ());
+
+    /* End the current replay diversion.  */
+    virtual void end_replay_diversion ()
+      TARGET_DEFAULT_NORETURN (tcomplain ());
+
     /* Go to the begin of the execution trace.  */
     virtual void goto_record_begin ()
       TARGET_DEFAULT_NORETURN (tcomplain ());
@@ -2537,6 +2556,18 @@ extern int target_record_will_replay (ptid_t ptid, int dir);
 /* See to_record_stop_replaying in struct target_ops.  */
 extern void target_record_stop_replaying (void);
 
+/* See needs_replay_diversion in struct target_ops.  */
+extern bool target_needs_replay_diversion (void);
+
+/* See in_replay_diversion in struct target_ops.  */
+extern bool target_in_replay_diversion (void);
+
+/* See start_replay_diversion in struct target_ops.  */
+extern void target_start_replay_diversion (void);
+
+/* See end_replay_diversion in struct target_ops.  */
+extern void target_end_replay_diversion (void);
+
 /* See to_goto_record_begin in struct target_ops.  */
 extern void target_goto_record_begin (void);
 
-- 
2.31.1

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

* [RFC PATCH 2/7] gdb: handle early replay diversion exits
  2021-06-01 19:10 [RFC PATCH 0/7] gdb: replay diversion support George Barrett
  2021-06-01 19:10 ` [RFC PATCH 1/7] gdb: add replay diversion interface to target_ops George Barrett
@ 2021-06-01 19:10 ` George Barrett
  2021-06-01 19:10 ` [RFC PATCH 3/7] gdb/remote: add vReplayDiversion packet George Barrett
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: George Barrett

Diversions of deterministic replay targets may exit early (if, for
example, a diversion was started for an inferior call to
`exit()'). This commit allows targets to notify of an early diversion
exit from `target_wait()' and has the GDB core handle it as an exit
without mourning the inferior.

gdb/ChangeLog:

2021-06-01  George Barrett  <bob@bob131.so>

	* infrun.c (handle_inferior_event): Don't check for a thread
	for TARGET_WAITKIND_REPLAY_DIVERSION_ENDED since it's
	inferior-wide.
	Handle TARGET_WAITKIND_REPLAY_DIVERSION_ENDED like an exit or
	a fatal signal, but don't mourn the inferior.
	(normal_stop): Don't assume the current thread will still be
	alive after a replay diversion has exited.
	Don't print "[Switching to x]" message for replay diversion
	exits.  Instead, print "[Replay diversion ended]".
	* target/waitstatus.c (target_waitstatus_to_string): Handle
	TARGET_WAITKIND_REPLAY_DIVERSION_ENDED.
	* target/waitstatus.h
	(target_waitkind::TARGET_WAITKIND_REPLAY_DIVERSION_ENDED): Add
	definition.
---
 gdb/infrun.c            | 25 ++++++++++++++++++++-----
 gdb/target/waitstatus.c |  2 ++
 gdb/target/waitstatus.h |  4 ++++
 3 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index e9624d2a9b6..166f1e513c4 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5269,7 +5269,8 @@ handle_inferior_event (struct execution_control_state *ecs)
     }
 
   if (ecs->ws.kind != TARGET_WAITKIND_EXITED
-      && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED)
+      && ecs->ws.kind != TARGET_WAITKIND_SIGNALLED
+      && ecs->ws.kind != TARGET_WAITKIND_REPLAY_DIVERSION_ENDED)
     {
       ecs->event_thread = find_thread_ptid (ecs->target, ecs->ptid);
       /* If it's a new thread, add it to the thread database.  */
@@ -5414,6 +5415,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 
     case TARGET_WAITKIND_EXITED:
     case TARGET_WAITKIND_SIGNALLED:
+    case TARGET_WAITKIND_REPLAY_DIVERSION_ENDED:
       {
 	/* Depending on the system, ecs->ptid may point to a thread or
 	   to a process.  On some targets, target_mourn_inferior may
@@ -5451,7 +5453,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 
 	  gdb::observers::exited.notify (ecs->ws.value.integer);
 	}
-      else
+      else if (ecs->ws.kind == TARGET_WAITKIND_SIGNALLED)
 	{
 	  struct gdbarch *gdbarch = current_inferior ()->gdbarch;
 
@@ -5480,7 +5482,9 @@ handle_inferior_event (struct execution_control_state *ecs)
 	}
 
       gdb_flush (gdb_stdout);
-      target_mourn_inferior (inferior_ptid);
+      if (ecs->ws.kind == TARGET_WAITKIND_EXITED
+	  || ecs->ws.kind == TARGET_WAITKIND_SIGNALLED)
+	target_mourn_inferior (inferior_ptid);
       stop_print_frame = false;
       stop_waiting (ecs);
       return;
@@ -8493,7 +8497,8 @@ normal_stop (void)
   if (!non_stop)
     finish_ptid = minus_one_ptid;
   else if (last.kind == TARGET_WAITKIND_SIGNALLED
-	   || last.kind == TARGET_WAITKIND_EXITED)
+	   || last.kind == TARGET_WAITKIND_EXITED
+	   || last.kind == TARGET_WAITKIND_REPLAY_DIVERSION_ENDED)
     {
       /* On some targets, we may still have live threads in the
 	 inferior when we get a process exit event.  E.g., for
@@ -8547,7 +8552,8 @@ normal_stop (void)
       && target_has_execution ()
       && last.kind != TARGET_WAITKIND_SIGNALLED
       && last.kind != TARGET_WAITKIND_EXITED
-      && last.kind != TARGET_WAITKIND_NO_RESUMED)
+      && last.kind != TARGET_WAITKIND_NO_RESUMED
+      && last.kind != TARGET_WAITKIND_REPLAY_DIVERSION_ENDED)
     {
       SWITCH_THRU_ALL_UIS ()
 	{
@@ -8569,6 +8575,15 @@ normal_stop (void)
 	  }
     }
 
+  if (last.kind == TARGET_WAITKIND_REPLAY_DIVERSION_ENDED)
+    {
+      SWITCH_THRU_ALL_UIS ()
+	{
+	  target_terminal::ours_for_output ();
+	  printf_filtered (_("[Replay diversion ended]\n"));
+	}
+    }
+
   /* Note: this depends on the update_thread_list call above.  */
   maybe_remove_breakpoints ();
 
diff --git a/gdb/target/waitstatus.c b/gdb/target/waitstatus.c
index c4fb061b293..3ea88c2a81a 100644
--- a/gdb/target/waitstatus.c
+++ b/gdb/target/waitstatus.c
@@ -67,6 +67,8 @@ target_waitstatus_to_string (const struct target_waitstatus *ws)
     case TARGET_WAITKIND_THREAD_EXITED:
       return string_printf ("%sthread exited, status = %d",
 			    kind_str, ws->value.integer);
+    case TARGET_WAITKIND_REPLAY_DIVERSION_ENDED:
+      return string_printf ("%sreplay diversion ended", kind_str);
     default:
       return string_printf ("%sunknown???", kind_str);
     }
diff --git a/gdb/target/waitstatus.h b/gdb/target/waitstatus.h
index 4123f42af5f..69c47040b25 100644
--- a/gdb/target/waitstatus.h
+++ b/gdb/target/waitstatus.h
@@ -99,6 +99,10 @@ enum target_waitkind
 
   /* The thread has exited.  The exit status is in value.integer.  */
   TARGET_WAITKIND_THREAD_EXITED,
+
+  /* An unexpected process exit occured during a diversion of
+     execution from a deterministic replay target.  */
+  TARGET_WAITKIND_REPLAY_DIVERSION_ENDED,
 };
 
 struct target_waitstatus
-- 
2.31.1

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

* [RFC PATCH 3/7] gdb/remote: add vReplayDiversion packet
  2021-06-01 19:10 [RFC PATCH 0/7] gdb: replay diversion support George Barrett
  2021-06-01 19:10 ` [RFC PATCH 1/7] gdb: add replay diversion interface to target_ops George Barrett
  2021-06-01 19:10 ` [RFC PATCH 2/7] gdb: handle early replay diversion exits George Barrett
@ 2021-06-01 19:10 ` George Barrett
  2021-06-01 19:18   ` Eli Zaretskii
  2021-06-01 19:10 ` [RFC PATCH 4/7] gdb/inferior: add replay diversion state George Barrett
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: George Barrett

This commit implements the replay diversion target interface for the
remote target and adds a remote protocol extension enabling the
control of remote deterministic replay targets.

gdb/ChangeLog:

2021-06-01  George Barrett  <bob@bob131.so>

	* remote.c (remote_state::in_replay_diversion): Define
	variable.
	(remote_state::needs_replay_diversion)
	(remote_state::in_replay_diversion)
	(remote_state::start_replay_diversion)
	(remote_state::end_replay_diversion): Declare overrides and
	add implementation.
	(PACKET_vReplayDiversion): Add declaration.
	(remote_protocol_features): Add PACKET_vReplayDiversion.
	(remote_target::remote_query_supported): Announce support for
	vReplayDiversion packet.
	(remote_target::process_stop_reply): If a remote signalled an
	exit during a replay diversion, change the wait status kind to
	TARGET_WAITKIND_REPLAY_DIVERSION_ENDED and prepare for a stop.
	(_initialize_remote): Add packet configuration command for
	vReplayDiversion.

gdb/doc/ChangeLog:

2021-06-01  George Barrett  <bob@bob131.so>

	* gdb.texinfo (Packets): Document vReplayDiversion packet.
	(General Query Packets): Document vReplayDiversion GDB and
	stub feature for qSupported.
---
 gdb/doc/gdb.texinfo |  40 +++++++++++++++
 gdb/remote.c        | 116 ++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 153 insertions(+), 3 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 90d827a50e7..e98530069f9 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -40412,6 +40412,31 @@ If this packet is handled differently to other unknown @samp{v}
 packets then it is possible that @value{GDBN} may run into problems in
 other areas, specifically around use of @samp{vFile:setfs:}.
 
+@item vReplayDiversion:@var{want-diversion}
+@cindex @samp{vReplayDiversion} packet
+Remotes designed to deterministically replay a recorded program trace
+may require a debugger to create temporary diversions before performing
+arbitrary writes to memory or registers of the inferior.  Sending the
+packet with @samp{1} for @var{want-diversion} sets up such a diversion;
+with @samp{0}, destroys the diversion and reverts the inferior state to
+that prior to the diversion setup.
+
+Diverted inferiors may exit unexpectedly (for example, due to an
+inferior call to @code{exit()}).  The remote should send an exit stop
+packet and end the diversion as though it had received
+@samp{vReplayDiversion:0}.
+
+This packet should only be used if both @value{GDBN} and the remote stub
+announce support for it.  @xref{qSupported}.
+
+Reply:
+@table @samp
+@item E.@var{error-reason}
+for an error
+@item OK
+for success
+@end table
+
 @item vRun;@var{filename}@r{[};@var{argument}@r{]}@dots{}
 @cindex @samp{vRun} packet
 Run the program @var{filename}, passing it each @var{argument} on its
@@ -41745,6 +41770,10 @@ including @samp{exec-events+} in its @samp{qSupported} reply.
 @item vContSupported
 This feature indicates whether @value{GDBN} wants to know the
 supported actions in the reply to @samp{vCont?} packet.
+
+@item vReplayDiversion
+This feature indicates whether @value{GDBN} supports replay targets
+needing temporary diversions of execution prior to inferior calls.
 @end table
 
 Stubs should ignore any unknown values for
@@ -42023,6 +42052,11 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab No
 
+@item @samp{vReplayDiversion}
+@tab No
+@tab @samp{-}
+@tab No
+
 @end multitable
 
 These are the currently defined stub features, in more detail:
@@ -42247,6 +42281,12 @@ For AArch64 GNU/Linux systems, this feature also requires access to the
 @file{/proc/@var{pid}/smaps} file so memory mapping page flags can be inspected.
 This is done via the @samp{vFile} requests.
 
+@item vReplayDiversion
+The remote stub is deterministically replaying a program recording and
+supports temporary diversions from the replay in order to execute
+arbitrary code.  Such targets must receive @code{vReplayDiversion:1}
+before any memory writes or register changes may occur.
+
 @end table
 
 @item qSymbol::
diff --git a/gdb/remote.c b/gdb/remote.c
index 9b465d77343..f38772da525 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -390,6 +390,10 @@ class remote_state
      this can go away.  */
   int wait_forever_enabled_p = 1;
 
+  /* Track whether the remote is currently executing in a replay
+     diversion.  */
+  bool in_replay_diversion = false;
+
 private:
   /* Mapping of remote protocol data for each gdbarch.  Usually there
      is only one entry here, though we may see more with stubs that
@@ -681,6 +685,12 @@ class remote_target : public process_stratum_target
 				 enum btrace_read_type type) override;
 
   const struct btrace_config *btrace_conf (const struct btrace_target_info *) override;
+
+  bool needs_replay_diversion () override;
+  bool in_replay_diversion () override;
+  void start_replay_diversion () override;
+  void end_replay_diversion () override;
+
   bool augmented_libraries_svr4_read () override;
   void follow_fork (bool, bool) override;
   void follow_exec (inferior *, ptid_t, const char *) override;
@@ -2184,6 +2194,9 @@ enum {
      packets and the tag violation stop replies.  */
   PACKET_memory_tagging_feature,
 
+  /* Support for replay diversions.  */
+  PACKET_vReplayDiversion,
+
   PACKET_MAX
 };
 
@@ -5333,6 +5346,8 @@ static const struct protocol_feature remote_protocol_features[] = {
   { "no-resumed", PACKET_DISABLE, remote_supported_packet, PACKET_no_resumed },
   { "memory-tagging", PACKET_DISABLE, remote_supported_packet,
     PACKET_memory_tagging_feature },
+  { "vReplayDiversion", PACKET_DISABLE, remote_supported_packet,
+    PACKET_vReplayDiversion },
 };
 
 static char *remote_support_xml;
@@ -5431,6 +5446,10 @@ remote_target::remote_query_supported ()
 	  != AUTO_BOOLEAN_FALSE)
 	remote_query_supported_append (&q, "memory-tagging+");
 
+      if (packet_set_cmd_state (PACKET_vReplayDiversion)
+	  != AUTO_BOOLEAN_FALSE)
+	remote_query_supported_append (&q, "vReplayDiversion+");
+
       /* Keep this one last to work around a gdbserver <= 7.10 bug in
 	 the qSupported:xmlRegisters=i386 handling.  */
       if (remote_support_xml != NULL
@@ -8017,9 +8036,19 @@ remote_target::process_stop_reply (struct stop_reply *stop_reply,
     ptid = select_thread_for_ambiguous_stop_reply (status);
   gdb_assert (ptid != null_ptid);
 
-  if (status->kind != TARGET_WAITKIND_EXITED
-      && status->kind != TARGET_WAITKIND_SIGNALLED
-      && status->kind != TARGET_WAITKIND_NO_RESUMED)
+  if (status->kind == TARGET_WAITKIND_EXITED
+      || status->kind == TARGET_WAITKIND_SIGNALLED)
+    {
+      remote_state *rs = get_remote_state ();
+      if (rs->in_replay_diversion)
+	{
+	  status->kind = TARGET_WAITKIND_REPLAY_DIVERSION_ENDED;
+	  rs->in_replay_diversion = false;
+	  for (thread_info *tp : all_non_exited_threads (this))
+	    get_remote_thread_info (tp)->set_not_resumed ();
+	}
+    }
+  else if (status->kind != TARGET_WAITKIND_NO_RESUMED)
     {
       /* Expedited registers.  */
       if (!stop_reply->regcache.empty ())
@@ -14247,6 +14276,84 @@ remote_target::btrace_conf (const struct btrace_target_info *tinfo)
   return &tinfo->conf;
 }
 
+bool
+remote_target::needs_replay_diversion ()
+{
+  return packet_support (PACKET_vReplayDiversion) == PACKET_ENABLE;
+}
+
+bool
+remote_target::in_replay_diversion ()
+{
+  return get_remote_state ()->in_replay_diversion;
+}
+
+void
+remote_target::start_replay_diversion ()
+{
+  REMOTE_SCOPED_DEBUG_ENTER_EXIT;
+
+  if (!needs_replay_diversion ())
+    return;
+
+  remote_state *rs = get_remote_state ();
+  if (rs->in_replay_diversion)
+    error ("Already in diversion");
+
+  remote_debug_printf ("Starting diversion");
+
+  xsnprintf (rs->buf.data (), get_remote_packet_size (), "vReplayDiversion:1");
+  putpkt (rs->buf);
+  getpkt (&rs->buf, 0);
+
+  switch (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vReplayDiversion]))
+    {
+    case PACKET_OK:
+      rs->in_replay_diversion = true;
+      return;
+    case PACKET_ERROR:
+      warning (_("Remote failure reply: %s"), rs->buf.data ());
+      break;
+    case PACKET_UNKNOWN:
+      break;
+    }
+
+  error ("Failed to start diversion");
+}
+
+void
+remote_target::end_replay_diversion ()
+{
+  REMOTE_SCOPED_DEBUG_ENTER_EXIT;
+
+  if (!needs_replay_diversion ())
+    return;
+
+  remote_state *rs = get_remote_state ();
+  if (!rs->in_replay_diversion)
+    error ("Not in diversion");
+
+  remote_debug_printf ("Ending diversion");
+
+  xsnprintf (rs->buf.data (), get_remote_packet_size (), "vReplayDiversion:0");
+  putpkt (rs->buf);
+  getpkt (&rs->buf, 0);
+
+  switch (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vReplayDiversion]))
+    {
+    case PACKET_OK:
+      rs->in_replay_diversion = false;
+      return;
+    case PACKET_ERROR:
+      warning (_("Remote failure reply: %s"), rs->buf.data ());
+      break;
+    case PACKET_UNKNOWN:
+      break;
+    }
+
+  error ("Failed to end diversion");
+}
+
 bool
 remote_target::augmented_libraries_svr4_read ()
 {
@@ -15222,6 +15329,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_memory_tagging_feature],
 			 "memory-tagging-feature", "memory-tagging-feature", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vReplayDiversion],
+			 "vReplayDiversion", "replay-diversion", 0);
+
   /* Assert that we've registered "set remote foo-packet" commands
      for all packet configs.  */
   {
-- 
2.31.1

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

* [RFC PATCH 4/7] gdb/inferior: add replay diversion state
  2021-06-01 19:10 [RFC PATCH 0/7] gdb: replay diversion support George Barrett
                   ` (2 preceding siblings ...)
  2021-06-01 19:10 ` [RFC PATCH 3/7] gdb/remote: add vReplayDiversion packet George Barrett
@ 2021-06-01 19:10 ` George Barrett
  2021-06-22 21:50   ` Lancelot SIX
  2021-06-01 19:11 ` [RFC PATCH 5/7] gdb/infcall: enter replay diversion before call George Barrett
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: George Barrett

Adds API to `struct inferior' for managing replay diversions of the
underlying target.

gdb/ChangeLog:

2021-06-01  George Barrett  <bob@bob131.so>

	* inferior.c (inferior::want_replay_diversion)
	(inferior::finish_replay_diversion): Add definitions.
	* inferior.h (inferior::want_replay_diversion)
	(inferior::finish_replay_diversion): Add declarations.
	(inferior::wants_replay_diversion_p)
	(inferior::m_wants_replay_diversion): Add definitions.
	* infrun.c (clear_proceed_status): Make sure to end any
	lingering replay diversion before proceeding.
---
 gdb/inferior.c | 23 +++++++++++++++++++++++
 gdb/inferior.h | 21 +++++++++++++++++++++
 gdb/infrun.c   |  6 ++++++
 3 files changed, 50 insertions(+)

diff --git a/gdb/inferior.c b/gdb/inferior.c
index 059839ec962..4c8de42cf6d 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -121,6 +121,29 @@ inferior::do_all_continuations ()
     }
 }
 
+scoped_want_replay_diversion
+inferior::want_replay_diversion ()
+{
+  if (!process_target ()->needs_replay_diversion ())
+    return {};
+  if (!process_target ()->in_replay_diversion ())
+    {
+      process_target ()->start_replay_diversion ();
+      printf_unfiltered ("[New replay diversion]\n");
+    }
+  return make_scoped_restore (&m_wants_replay_diversion, true);
+}
+
+void
+inferior::finish_replay_diversion ()
+{
+  if (process_target ()->in_replay_diversion () && !m_wants_replay_diversion)
+    {
+      process_target ()->end_replay_diversion ();
+      printf_unfiltered ("[Replay diversion ended]\n");
+    }
+}
+
 struct inferior *
 add_inferior_silent (int pid)
 {
diff --git a/gdb/inferior.h b/gdb/inferior.h
index f4b8b025e35..9cc939a60af 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -317,6 +317,9 @@ extern void set_current_inferior (inferior *);
    selected.  */
 extern void switch_to_inferior_no_thread (inferior *inf);
 
+using scoped_want_replay_diversion
+  = gdb::optional<scoped_restore_tmpl<bool>>;
+
 /* GDB represents the state of each program execution with an object
    called an inferior.  An inferior typically corresponds to a process
    but is more general and applies also to targets that do not have a
@@ -438,6 +441,21 @@ class inferior : public refcounted_object
   void set_tty (const char *terminal_name);
   const char *tty ();
 
+  /* Begin a replay diversion (if the target supports it and if not
+     already started) and prevent finish_replay_diversion() from
+     having any effect for the lifetime of the returned scoped
+     restore.  */
+  scoped_want_replay_diversion want_replay_diversion ();
+
+  /* Return TRUE if some code still wants a replay diversion to
+     persist.  */
+  inline bool wants_replay_diversion_p () { return m_wants_replay_diversion; }
+
+  /* If the target is currently in a replay diversion and no scoped
+     restores from want_replay_diversion() are still alive, end the
+     diversion.  */
+  void finish_replay_diversion ();
+
   /* Convenient handle (GDB inferior id).  Unique across all
      inferiors.  */
   int num = 0;
@@ -566,6 +584,9 @@ class inferior : public refcounted_object
 
   /* The list of continuations.  */
   std::list<std::function<void ()>> m_continuations;
+
+  /* TRUE if calls to finish_replay_diversion() should be ignored.  */
+  bool m_wants_replay_diversion = false;
 };
 
 /* Keep a registry of per-inferior data-pointers required by other GDB
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 166f1e513c4..58ed3e92161 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2677,6 +2677,12 @@ clear_proceed_status (int step)
 				     execution_direction))
     target_record_stop_replaying ();
 
+  /* If we're preparing to proceed and no-one needs the replay
+     diversion anymore, end it.  It doesn't make sense to continue
+     replay within a diversion session.  */
+  if (inferior_ptid != null_ptid)
+    current_inferior ()->finish_replay_diversion ();
+
   if (!non_stop && inferior_ptid != null_ptid)
     {
       ptid_t resume_ptid = user_visible_resume_ptid (step);
-- 
2.31.1

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

* [RFC PATCH 5/7] gdb/infcall: enter replay diversion before call
  2021-06-01 19:10 [RFC PATCH 0/7] gdb: replay diversion support George Barrett
                   ` (3 preceding siblings ...)
  2021-06-01 19:10 ` [RFC PATCH 4/7] gdb/inferior: add replay diversion state George Barrett
@ 2021-06-01 19:11 ` George Barrett
  2021-06-01 19:11 ` [RFC PATCH 6/7] gdb/infrun: solo thread resume in replay diversion George Barrett
  2021-06-01 19:11 ` [RFC PATCH 7/7] gdb/infcmd: add replay diversion commands George Barrett
  6 siblings, 0 replies; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:11 UTC (permalink / raw)
  To: gdb-patches; +Cc: George Barrett

Ensures a replay diversion is set up before making an inferior call.

gdb/ChangeLog:

2021-06-01  George Barrett  <bob@bob131.so>

	* infcall.c (call_function_by_hand_dummy): Ensure a replay is
	set up before making an inferior call.
---
 gdb/infcall.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/gdb/infcall.c b/gdb/infcall.c
index ca3347fbb9d..f8660f2ecd2 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -840,6 +840,12 @@ call_function_by_hand_dummy (struct value *function,
      is released once the regcache has been pushed).  */
   infcall_suspend_state_up caller_state (save_infcall_suspend_state ());
 
+  /* If the target supports replay diversions, make sure the inferior
+     is in one before proceeding.  This is mandatory for such targets
+     and a no-op for others.  */
+  scoped_want_replay_diversion save_want_diversion
+    = call_thread->inf->want_replay_diversion ();
+
   /* Ensure that the initial SP is correctly aligned.  */
   {
     CORE_ADDR old_sp = get_frame_sp (frame);
-- 
2.31.1

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

* [RFC PATCH 6/7] gdb/infrun: solo thread resume in replay diversion
  2021-06-01 19:10 [RFC PATCH 0/7] gdb: replay diversion support George Barrett
                   ` (4 preceding siblings ...)
  2021-06-01 19:11 ` [RFC PATCH 5/7] gdb/infcall: enter replay diversion before call George Barrett
@ 2021-06-01 19:11 ` George Barrett
  2021-06-01 19:11 ` [RFC PATCH 7/7] gdb/infcmd: add replay diversion commands George Barrett
  6 siblings, 0 replies; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:11 UTC (permalink / raw)
  To: gdb-patches; +Cc: George Barrett

Treat 'scheduler-locking = replay' similarly to 'scheduler-locking =
on' when in a replay diversion.

gdb/ChangeLog:

2021-06-01  George Barrett  <bob@bob131.so>

	* infrun.c (user_visible_resume_ptid): Do solo thread
	resumption if the scheduler mode is 'replay' and the target is
	in a replay diversion.
---
 gdb/infrun.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index 58ed3e92161..b9e0236f52a 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -2088,6 +2088,16 @@ user_visible_resume_ptid (int step)
 	 mode.  */
       resume_ptid = inferior_ptid;
     }
+  else if ((scheduler_mode == schedlock_replay)
+	   && target_in_replay_diversion ())
+    {
+      /* User-settable 'scheduler' mode requires solo thread resume in
+	 replay mode during a replay diversion.  This prevents GDB
+	 from unintentionally asking the target to resume replay of
+	 another thread when performing an inferior call in the
+	 current thread, for example.  */
+      resume_ptid = inferior_ptid;
+    }
   else if (!sched_multi && target_supports_multi_process ())
     {
       /* Resume all threads of the current process (and none of other
-- 
2.31.1

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

* [RFC PATCH 7/7] gdb/infcmd: add replay diversion commands
  2021-06-01 19:10 [RFC PATCH 0/7] gdb: replay diversion support George Barrett
                   ` (5 preceding siblings ...)
  2021-06-01 19:11 ` [RFC PATCH 6/7] gdb/infrun: solo thread resume in replay diversion George Barrett
@ 2021-06-01 19:11 ` George Barrett
  2021-06-22 21:57   ` Lancelot SIX
  6 siblings, 1 reply; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:11 UTC (permalink / raw)
  To: gdb-patches; +Cc: George Barrett

Adds commands 'replay-diversion start', 'replay-diversion end' and
'show replay-diversion' to make diversion state of the target
inspectable/manipulable by the user.

gdb/ChangeLog:

2021-06-01  George Barrett  <bob@bob131.so>

	* infcmd.c (replay_diversion_start_command)
	(replay_diversion_end_command, show_replay_diversion_command):
	Implement commands.
	(_initialize_infcmd): Add commands: 'replay-diversion start',
	'replay-diversion end' and 'show replay-diversion'.
---
 gdb/infcmd.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 38947ca265e..92aa164a992 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -3001,6 +3001,45 @@ show_print_finish (struct ui_file *file, int from_tty,
 Printing of return value after `finish' is %s.\n"),
 		    value);
 }
+\f
+/* Implement `replay-diversion start'.  */
+
+static void
+replay_diversion_start_command (const char *args, int from_tty)
+{
+  if (inferior_ptid == null_ptid)
+    error (_("The program is not being run."));
+  if (target_in_replay_diversion ())
+    error (_("Already in a replay diversion."));
+  target_start_replay_diversion ();
+}
+
+/* Implement `replay-diversion end'.  */
+
+static void
+replay_diversion_end_command (const char *args, int from_tty)
+{
+  if (inferior_ptid == null_ptid)
+    error (_("The program is not being run."));
+  if (!target_in_replay_diversion ())
+    error (_("Not in a replay diversion."));
+  if (current_inferior ()->wants_replay_diversion_p ())
+    error (_("Attempt to end a replay diversion in use."));
+  target_end_replay_diversion ();
+}
+
+/* Implement `show replay-diversion'.  */
+
+static void
+show_replay_diversion_command (const char *args, int from_tty)
+{
+  if (target_in_replay_diversion ())
+    puts_filtered ("Inferior in replay diversion.\n");
+  else if (target_needs_replay_diversion ())
+    puts_filtered ("Inferior in deterministic replay.\n");
+  else
+    puts_filtered ("Inferior doesn't support replay diversion.\n");
+}
 
 
 /* This help string is used for the run, start, and starti commands.
@@ -3023,7 +3062,8 @@ void _initialize_infcmd ();
 void
 _initialize_infcmd ()
 {
-  static struct cmd_list_element *info_proc_cmdlist;
+  static struct cmd_list_element *info_proc_cmdlist,
+                                 *replay_diversion_cmdlist;
   struct cmd_list_element *c = NULL;
   const char *cmd_name;
 
@@ -3347,4 +3387,21 @@ Show whether `finish' prints the return value."), NULL,
 			   NULL,
 			   show_print_finish,
 			   &setprintlist, &showprintlist);
+
+  add_basic_prefix_cmd ("replay-diversion", class_obscure, _("\
+Enter and exit diversions of trace replay."),
+			&replay_diversion_cmdlist,
+			0 /* allow-unknown */, &cmdlist);
+
+  add_cmd ("start", class_obscure, replay_diversion_start_command,
+	   _("Start a replay diversion."),
+	   &replay_diversion_cmdlist);
+
+  add_cmd ("end", class_obscure, replay_diversion_end_command,
+	   _("End a replay diversion."),
+	   &replay_diversion_cmdlist);
+
+  add_cmd ("replay-diversion", no_class, show_replay_diversion_command,
+	   _("Show whether the inferior is currently in a replay diversion."),
+	   &showlist);
 }
-- 
2.31.1

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

* Re: [RFC PATCH 3/7] gdb/remote: add vReplayDiversion packet
  2021-06-01 19:10 ` [RFC PATCH 3/7] gdb/remote: add vReplayDiversion packet George Barrett
@ 2021-06-01 19:18   ` Eli Zaretskii
  2021-06-01 19:27     ` George Barrett
  0 siblings, 1 reply; 12+ messages in thread
From: Eli Zaretskii @ 2021-06-01 19:18 UTC (permalink / raw)
  To: George Barrett; +Cc: gdb-patches

> Date: Wed, 02 Jun 2021 05:10:39 +1000
> From: George Barrett via Gdb-patches <gdb-patches@sourceware.org>
> Cc: George Barrett <bob@bob131.so>
> 
> This commit implements the replay diversion target interface for the
> remote target and adds a remote protocol extension enabling the
> control of remote deterministic replay targets.
> 
> gdb/ChangeLog:
> 
> 2021-06-01  George Barrett  <bob@bob131.so>
> 
> 	* remote.c (remote_state::in_replay_diversion): Define
> 	variable.
> 	(remote_state::needs_replay_diversion)
> 	(remote_state::in_replay_diversion)
> 	(remote_state::start_replay_diversion)
> 	(remote_state::end_replay_diversion): Declare overrides and
> 	add implementation.
> 	(PACKET_vReplayDiversion): Add declaration.
> 	(remote_protocol_features): Add PACKET_vReplayDiversion.
> 	(remote_target::remote_query_supported): Announce support for
> 	vReplayDiversion packet.
> 	(remote_target::process_stop_reply): If a remote signalled an
> 	exit during a replay diversion, change the wait status kind to
> 	TARGET_WAITKIND_REPLAY_DIVERSION_ENDED and prepare for a stop.
> 	(_initialize_remote): Add packet configuration command for
> 	vReplayDiversion.
> 
> gdb/doc/ChangeLog:
> 
> 2021-06-01  George Barrett  <bob@bob131.so>
> 
> 	* gdb.texinfo (Packets): Document vReplayDiversion packet.
> 	(General Query Packets): Document vReplayDiversion GDB and
> 	stub feature for qSupported.

The gdb.texinfo part is OK, with one comment:

> +Diverted inferiors may exit unexpectedly (for example, due to an
> +inferior call to @code{exit()}).  The remote should send an exit stop
                    ^^^^^^^^^^^^^
Please use @code{exit}, without the parentheses.  The way you wrote
it, it looks like a call to 'exit' with no arguments, which is not
what you mean.

Thanks.

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

* Re: [RFC PATCH 3/7] gdb/remote: add vReplayDiversion packet
  2021-06-01 19:18   ` Eli Zaretskii
@ 2021-06-01 19:27     ` George Barrett
  0 siblings, 0 replies; 12+ messages in thread
From: George Barrett @ 2021-06-01 19:27 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Tue, Jun 01, 2021 at 10:18:43PM +0300, Eli Zaretskii wrote:
> Please use @code{exit}, without the parentheses.  The way you wrote
> it, it looks like a call to 'exit' with no arguments, which is not
> what you mean.

Ack.

Thanks for the fast review!

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

* Re: [RFC PATCH 4/7] gdb/inferior: add replay diversion state
  2021-06-01 19:10 ` [RFC PATCH 4/7] gdb/inferior: add replay diversion state George Barrett
@ 2021-06-22 21:50   ` Lancelot SIX
  0 siblings, 0 replies; 12+ messages in thread
From: Lancelot SIX @ 2021-06-22 21:50 UTC (permalink / raw)
  To: George Barrett; +Cc: gdb-patches

On Wed, Jun 02, 2021 at 05:10:52AM +1000, George Barrett via Gdb-patches wrote:
> Adds API to `struct inferior' for managing replay diversions of the
> underlying target.
> 
> gdb/ChangeLog:
> 
> 2021-06-01  George Barrett  <bob@bob131.so>
> 
> 	* inferior.c (inferior::want_replay_diversion)
> 	(inferior::finish_replay_diversion): Add definitions.
> 	* inferior.h (inferior::want_replay_diversion)
> 	(inferior::finish_replay_diversion): Add declarations.
> 	(inferior::wants_replay_diversion_p)
> 	(inferior::m_wants_replay_diversion): Add definitions.
> 	* infrun.c (clear_proceed_status): Make sure to end any
> 	lingering replay diversion before proceeding.
> ---
>  gdb/inferior.c | 23 +++++++++++++++++++++++
>  gdb/inferior.h | 21 +++++++++++++++++++++
>  gdb/infrun.c   |  6 ++++++
>  3 files changed, 50 insertions(+)
> 
> diff --git a/gdb/inferior.c b/gdb/inferior.c
> index 059839ec962..4c8de42cf6d 100644
> --- a/gdb/inferior.c
> +++ b/gdb/inferior.c
> @@ -121,6 +121,29 @@ inferior::do_all_continuations ()
>      }
>  }
>  
> +scoped_want_replay_diversion
> +inferior::want_replay_diversion ()
> +{
> +  if (!process_target ()->needs_replay_diversion ())
> +    return {};
> +  if (!process_target ()->in_replay_diversion ())
> +    {
> +      process_target ()->start_replay_diversion ();
> +      printf_unfiltered ("[New replay diversion]\n");

Hi,

I am wondering if this message should be translatable, i.e. using

      printf_unfiltered (_("[New replay diversion]\n"));

instead.

> +    }
> +  return make_scoped_restore (&m_wants_replay_diversion, true);
> +}
> +
> +void
> +inferior::finish_replay_diversion ()
> +{
> +  if (process_target ()->in_replay_diversion () && !m_wants_replay_diversion)
> +    {
> +      process_target ()->end_replay_diversion ();
> +      printf_unfiltered ("[Replay diversion ended]\n");

Same here, could probably use _().

Best,
Lancelot.

> +    }
> +}
> +
>  struct inferior *
>  add_inferior_silent (int pid)
>  {
> diff --git a/gdb/inferior.h b/gdb/inferior.h
> index f4b8b025e35..9cc939a60af 100644
> --- a/gdb/inferior.h
> +++ b/gdb/inferior.h
> @@ -317,6 +317,9 @@ extern void set_current_inferior (inferior *);
>     selected.  */
>  extern void switch_to_inferior_no_thread (inferior *inf);
>  
> +using scoped_want_replay_diversion
> +  = gdb::optional<scoped_restore_tmpl<bool>>;
> +
>  /* GDB represents the state of each program execution with an object
>     called an inferior.  An inferior typically corresponds to a process
>     but is more general and applies also to targets that do not have a
> @@ -438,6 +441,21 @@ class inferior : public refcounted_object
>    void set_tty (const char *terminal_name);
>    const char *tty ();
>  
> +  /* Begin a replay diversion (if the target supports it and if not
> +     already started) and prevent finish_replay_diversion() from
> +     having any effect for the lifetime of the returned scoped
> +     restore.  */
> +  scoped_want_replay_diversion want_replay_diversion ();
> +
> +  /* Return TRUE if some code still wants a replay diversion to
> +     persist.  */
> +  inline bool wants_replay_diversion_p () { return m_wants_replay_diversion; }
> +
> +  /* If the target is currently in a replay diversion and no scoped
> +     restores from want_replay_diversion() are still alive, end the
> +     diversion.  */
> +  void finish_replay_diversion ();
> +
>    /* Convenient handle (GDB inferior id).  Unique across all
>       inferiors.  */
>    int num = 0;
> @@ -566,6 +584,9 @@ class inferior : public refcounted_object
>  
>    /* The list of continuations.  */
>    std::list<std::function<void ()>> m_continuations;
> +
> +  /* TRUE if calls to finish_replay_diversion() should be ignored.  */
> +  bool m_wants_replay_diversion = false;
>  };
>  
>  /* Keep a registry of per-inferior data-pointers required by other GDB
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 166f1e513c4..58ed3e92161 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -2677,6 +2677,12 @@ clear_proceed_status (int step)
>  				     execution_direction))
>      target_record_stop_replaying ();
>  
> +  /* If we're preparing to proceed and no-one needs the replay
> +     diversion anymore, end it.  It doesn't make sense to continue
> +     replay within a diversion session.  */
> +  if (inferior_ptid != null_ptid)
> +    current_inferior ()->finish_replay_diversion ();
> +
>    if (!non_stop && inferior_ptid != null_ptid)
>      {
>        ptid_t resume_ptid = user_visible_resume_ptid (step);
> -- 
> 2.31.1

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

* Re: [RFC PATCH 7/7] gdb/infcmd: add replay diversion commands
  2021-06-01 19:11 ` [RFC PATCH 7/7] gdb/infcmd: add replay diversion commands George Barrett
@ 2021-06-22 21:57   ` Lancelot SIX
  0 siblings, 0 replies; 12+ messages in thread
From: Lancelot SIX @ 2021-06-22 21:57 UTC (permalink / raw)
  To: George Barrett; +Cc: gdb-patches

On Wed, Jun 02, 2021 at 05:11:25AM +1000, George Barrett via Gdb-patches wrote:
> Adds commands 'replay-diversion start', 'replay-diversion end' and
> 'show replay-diversion' to make diversion state of the target
> inspectable/manipulable by the user.
> 
> gdb/ChangeLog:
> 
> 2021-06-01  George Barrett  <bob@bob131.so>
> 
> 	* infcmd.c (replay_diversion_start_command)
> 	(replay_diversion_end_command, show_replay_diversion_command):
> 	Implement commands.
> 	(_initialize_infcmd): Add commands: 'replay-diversion start',
> 	'replay-diversion end' and 'show replay-diversion'.
> ---
>  gdb/infcmd.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 58 insertions(+), 1 deletion(-)
> 
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 38947ca265e..92aa164a992 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -3001,6 +3001,45 @@ show_print_finish (struct ui_file *file, int from_tty,
>  Printing of return value after `finish' is %s.\n"),
>  		    value);
>  }
> +\f
> +/* Implement `replay-diversion start'.  */
> +
> +static void
> +replay_diversion_start_command (const char *args, int from_tty)
> +{
> +  if (inferior_ptid == null_ptid)
> +    error (_("The program is not being run."));
> +  if (target_in_replay_diversion ())
> +    error (_("Already in a replay diversion."));
> +  target_start_replay_diversion ();
> +}
> +
> +/* Implement `replay-diversion end'.  */
> +
> +static void
> +replay_diversion_end_command (const char *args, int from_tty)
> +{
> +  if (inferior_ptid == null_ptid)
> +    error (_("The program is not being run."));
> +  if (!target_in_replay_diversion ())
> +    error (_("Not in a replay diversion."));
> +  if (current_inferior ()->wants_replay_diversion_p ())
> +    error (_("Attempt to end a replay diversion in use."));
> +  target_end_replay_diversion ();
> +}
> +
> +/* Implement `show replay-diversion'.  */
> +
> +static void
> +show_replay_diversion_command (const char *args, int from_tty)
> +{
> +  if (target_in_replay_diversion ())
> +    puts_filtered ("Inferior in replay diversion.\n");
> +  else if (target_needs_replay_diversion ())
> +    puts_filtered ("Inferior in deterministic replay.\n");
> +  else
> +    puts_filtered ("Inferior doesn't support replay diversion.\n");
> +}
> 

Hi,

You forgot to wrap the messages in '_()' in this function.

Best,
Lancelot.

>  
>  /* This help string is used for the run, start, and starti commands.
> @@ -3023,7 +3062,8 @@ void _initialize_infcmd ();
>  void
>  _initialize_infcmd ()
>  {
> -  static struct cmd_list_element *info_proc_cmdlist;
> +  static struct cmd_list_element *info_proc_cmdlist,
> +                                 *replay_diversion_cmdlist;
>    struct cmd_list_element *c = NULL;
>    const char *cmd_name;
>  
> @@ -3347,4 +3387,21 @@ Show whether `finish' prints the return value."), NULL,
>  			   NULL,
>  			   show_print_finish,
>  			   &setprintlist, &showprintlist);
> +
> +  add_basic_prefix_cmd ("replay-diversion", class_obscure, _("\
> +Enter and exit diversions of trace replay."),
> +			&replay_diversion_cmdlist,
> +			0 /* allow-unknown */, &cmdlist);
> +
> +  add_cmd ("start", class_obscure, replay_diversion_start_command,
> +	   _("Start a replay diversion."),
> +	   &replay_diversion_cmdlist);
> +
> +  add_cmd ("end", class_obscure, replay_diversion_end_command,
> +	   _("End a replay diversion."),
> +	   &replay_diversion_cmdlist);
> +
> +  add_cmd ("replay-diversion", no_class, show_replay_diversion_command,
> +	   _("Show whether the inferior is currently in a replay diversion."),
> +	   &showlist);
>  }
> -- 
> 2.31.1

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

end of thread, other threads:[~2021-06-22 21:57 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-01 19:10 [RFC PATCH 0/7] gdb: replay diversion support George Barrett
2021-06-01 19:10 ` [RFC PATCH 1/7] gdb: add replay diversion interface to target_ops George Barrett
2021-06-01 19:10 ` [RFC PATCH 2/7] gdb: handle early replay diversion exits George Barrett
2021-06-01 19:10 ` [RFC PATCH 3/7] gdb/remote: add vReplayDiversion packet George Barrett
2021-06-01 19:18   ` Eli Zaretskii
2021-06-01 19:27     ` George Barrett
2021-06-01 19:10 ` [RFC PATCH 4/7] gdb/inferior: add replay diversion state George Barrett
2021-06-22 21:50   ` Lancelot SIX
2021-06-01 19:11 ` [RFC PATCH 5/7] gdb/infcall: enter replay diversion before call George Barrett
2021-06-01 19:11 ` [RFC PATCH 6/7] gdb/infrun: solo thread resume in replay diversion George Barrett
2021-06-01 19:11 ` [RFC PATCH 7/7] gdb/infcmd: add replay diversion commands George Barrett
2021-06-22 21:57   ` Lancelot SIX

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).