diff mbox

[RFC,08/22] Monitor commands

Message ID 007c01cf951e$ea84e850$bf8eb8f0$@Dovgaluk@ispras.ru
State New
Headers show

Commit Message

Pavel Dovgalyuk July 1, 2014, 11:23 a.m. UTC
This patch adds commands to control replay from the monitor.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@gmail.com>
---

     monitor_printf(mon, "'");
@@ -2596,6 +2734,7 @@ int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error **errp)
     return fd;
 }
 
+
 /* Please update hmp-commands.hx when adding or changing commands */
 static mon_cmd_t info_cmds[] = {
     {

Comments

Eric Blake July 1, 2014, 5:33 p.m. UTC | #1
On 07/01/2014 05:23 AM, Pavel Dovgaluk wrote:
> This patch adds commands to control replay from the monitor.
> 
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@gmail.com>
> ---

What are the counterpart QMP commands?  It is seldom right to add an HMP
command unless the same thing can be done via QMP.


> @@ -2596,6 +2734,7 @@ int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error **errp)
>      return fd;
>  }
>  
> +
>  /* Please update hmp-commands.hx when adding or changing commands */
>  static mon_cmd_t info_cmds[] = {

Spurious newline addition?
Pavel Dovgalyuk July 2, 2014, 10:43 a.m. UTC | #2
> -----Original Message-----
> From: Eric Blake [mailto:eblake@redhat.com]
> Sent: Tuesday, July 01, 2014 9:33 PM
> To: Pavel Dovgaluk; 'QEMU Developers'
> Subject: Re: [Qemu-devel] [RFC PATCH 08/22] Monitor commands
> 
> On 07/01/2014 05:23 AM, Pavel Dovgaluk wrote:
> > This patch adds commands to control replay from the monitor.
> >
> > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@gmail.com>
> > ---
> 
> What are the counterpart QMP commands?  It is seldom right to add an HMP
> command unless the same thing can be done via QMP.

We haven't controlled qemu through QMP yet, thus haven't implemented QMP support
for replay commands.

Today I started adding this support and noticed, that QMP in current master branch is
broken - it does not reply anything except information at start.

> > @@ -2596,6 +2734,7 @@ int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error
> **errp)
> >      return fd;
> >  }
> >
> > +
> >  /* Please update hmp-commands.hx when adding or changing commands */
> >  static mon_cmd_t info_cmds[] = {
> 
> Spurious newline addition?

Thanks, forgot to undo this.

Pavel Dovgaluk
Kirill Batuzov July 2, 2014, 10:54 a.m. UTC | #3
On Wed, 2 Jul 2014, Pavel Dovgaluk wrote:

> > -----Original Message-----
> > From: Eric Blake [mailto:eblake@redhat.com]
> > Sent: Tuesday, July 01, 2014 9:33 PM
> > To: Pavel Dovgaluk; 'QEMU Developers'
> > Subject: Re: [Qemu-devel] [RFC PATCH 08/22] Monitor commands
> > 
> > On 07/01/2014 05:23 AM, Pavel Dovgaluk wrote:
> > > This patch adds commands to control replay from the monitor.
> > >
> > > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@gmail.com>
> > > ---
> > 
> > What are the counterpart QMP commands?  It is seldom right to add an HMP
> > command unless the same thing can be done via QMP.
> 
> We haven't controlled qemu through QMP yet, thus haven't implemented QMP support
> for replay commands.
> 
> Today I started adding this support and noticed, that QMP in current master branch is
> broken - it does not reply anything except information at start.
>

On Windows hosts only. I've sent a fix for this problem yesterday:
https://lists.gnu.org/archive/html/qemu-devel/2014-07/msg00169.html

> > > @@ -2596,6 +2734,7 @@ int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error
> > **errp)
> > >      return fd;
> > >  }
> > >
> > > +
> > >  /* Please update hmp-commands.hx when adding or changing commands */
> > >  static mon_cmd_t info_cmds[] = {
> > 
> > Spurious newline addition?
> 
> Thanks, forgot to undo this.
> 
> Pavel Dovgaluk
> 
> 
>
diff mbox

Patch

diff --git a/hmp-commands.hx b/hmp-commands.hx
index d0943b1..01d3203
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1629,6 +1629,107 @@  passed since 1970, i.e. unix epoch.
 ETEXI
 
     {
+        .name       = "replay_info",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show replay info",
+        .mhandler.cmd = do_replay_info,
+    },
+
+STEXI
+@item replay_info
+Shows information about replay process.
+
+ETEXI
+
+    {
+        .name       = "replay_break",
+        .args_type  = "step:l",
+        .params     = "step",
+        .help       = "stop replaying at the specified replay step",
+        .mhandler.cmd = do_replay_break,
+    },
+
+STEXI
+@item replay_break @var{step}
+Stops replaying at the specified @var{step}.
+
+ETEXI
+
+    {
+        .name       = "replay_seek",
+        .args_type  = "step:l",
+        .params     = "step",
+        .help       = "seeks the replay log to the specified step",
+        .mhandler.cmd = do_replay_seek,
+    },
+
+STEXI
+@item replay_seek @var{step}
+Seeks the replay log to the specified @var{step}.
+
+ETEXI
+
+    {
+        .name       = "replay_events",
+        .args_type  = "",
+        .params     = "",
+        .help       = "shows events information from the replay log",
+        .mhandler.cmd = do_replay_events,
+    },
+
+STEXI
+@item replay_events
+Shows events information from the replay log.
+
+ETEXI
+
+    {
+        .name       = "replay_get_packet",
+        .args_type  = "id:l",
+        .params     = "id",
+        .help       = "retrieves network packet with the specified id",
+        .mhandler.cmd = do_replay_get_packet,
+    },
+
+STEXI
+@item replay_get_packet @var{id}
+Retrieves network packet with the specified @var{id}.
+
+ETEXI
+
+    {
+        .name       = "replay_set_packet",
+        .args_type  = "id:l,bytes:s?",
+        .params     = "id [bytes]",
+        .help       = "sets network packet with the specified id",
+        .mhandler.cmd = do_replay_set_packet,
+    },
+
+STEXI
+@item replay_set_packet @var{id} @var{bytes}
+Sets network packet with the specified @var{id}. While replaying,
+packet with this @var{id} will be replaced with the specified @var{bytes}.
+If @var{bytes} parameter is not specified, removes packet from storage of 
+modified packets.
+
+ETEXI
+
+    {
+        .name       = "replay_change",
+        .args_type  = "",
+        .params     = "",
+        .help       = "start execution of VM from the current replay step",
+        .mhandler.cmd = do_replay_change,
+    },
+
+STEXI
+@item replay_change
+Start execution of VM from the current replay step.
+
+ETEXI
+
+    {
         .name       = "chardev-add",
         .args_type  = "args:s",
         .params     = "args",

diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 3d6929d..d569a83
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -40,6 +40,7 @@  int monitor_handle_fd_param2(Monitor *mon, const char *fdname, Error **errp);
 void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
     GCC_FMT_ATTR(2, 0);
 void monitor_printf(Monitor *mon, const char *fmt, ...) GCC_FMT_ATTR(2, 3);
+void monitor_print_bytes(Monitor *mon, const uint8_t *bytes, uint64_t length);
 void monitor_flush(Monitor *mon);
 int monitor_set_cpu(int cpu_index);
 int monitor_get_cpu_index(void);

diff --git a/monitor.c b/monitor.c
index 799131b..7bd4770
--- a/monitor.c
+++ b/monitor.c
@@ -73,6 +73,8 @@ 
 #include "block/qapi.h"
 #include "qapi/qmp-event.h"
 #include "qapi-event.h"
+#include "replay/replay.h"
+#include "block/block_int.h"
 
 /* for pic/irq_info */
 #if defined(TARGET_SPARC)
@@ -379,6 +381,13 @@  void monitor_printf(Monitor *mon, const char *fmt, ...)
     va_end(ap);
 }
 
+void monitor_print_bytes(Monitor *mon, const uint8_t *bytes, uint64_t length)
+{
+    while (length--) {
+        monitor_printf(mon, "%02x", *bytes++);
+    }
+}
+
 static int GCC_FMT_ATTR(2, 3) monitor_fprintf(FILE *stream,
                                               const char *fmt, ...)
 {
@@ -1173,6 +1182,135 @@  static void do_watchdog_action(Monitor *mon, const QDict *qdict)
     }
 }
 
+static void do_replay_info(Monitor *mon, const QDict *qdict)
+{
+    switch (replay_mode) {
+    case REPLAY_NONE:
+        monitor_printf(mon, "Replay is not enabled.\n");
+        break;
+    case REPLAY_SAVE:
+        monitor_printf(mon, "Saving replay log.\n");
+        monitor_printf(mon, "\tcurrent step: %" PRId64 "\n", replay_get_current_step());
+        break;
+    case REPLAY_PLAY:
+        monitor_printf(mon, "Playing replay log ");
+        switch (replay_get_play_submode()) {
+        case REPLAY_PLAY_NORMAL:
+            monitor_printf(mon, "(normal mode)");
+            break;
+        case REPLAY_PLAY_REVERSE:
+            monitor_printf(mon, "(reverse debugging)");
+            break;
+        case REPLAY_PLAY_CHANGED:
+            monitor_printf(mon, "(changed mode)");
+            break;
+        case REPLAY_PLAY_GOTO:
+            monitor_printf(mon, "(preparing to trace)");
+            break;
+        case REPLAY_PLAY_UNKNOWN:
+        default:
+            monitor_printf(mon, "(unknown mode)");
+            break;
+        }
+        monitor_printf(mon, "\n");
+        monitor_printf(mon, "\tcurrent step: %" PRId64 "\n", replay_get_current_step());
+        break;
+    }
+}
+
+
+static void do_replay_break(Monitor *mon, const QDict *qdict)
+{
+    if (replay_mode == REPLAY_PLAY) {
+        if (replay_get_play_submode() == REPLAY_PLAY_CHANGED) {
+            monitor_printf(mon, "Cannot stop on the specified step in the changed mode.\n");
+            return;
+        }
+        uint64_t step = qdict_get_int(qdict, "step");
+        if (step >= replay_get_current_step()) {
+            monitor_printf(mon, "Setting break at step: %" PRId64 "\n", step);
+            replay_set_break(step);
+        } else {
+            monitor_printf(mon, "Cannot stop on the preceding step.\n");
+        }
+    } else {
+        monitor_printf(mon, "You can stop at the specific step only in PLAY mode.\n");
+    }
+}
+
+
+static void do_replay_seek(Monitor *mon, const QDict *qdict)
+{
+    if (replay_mode == REPLAY_PLAY) {
+        uint64_t step = qdict_get_int(qdict, "step");
+        if (replay_seek_step(step)) {
+            monitor_printf(mon, "Seeking for step: %" PRId64 "\n", step);
+            if (!runstate_is_running()) {
+                vm_start();
+            }
+        } else {
+            monitor_printf(mon, "Cannot seek to the specified step.\n");
+        }
+    } else {
+        monitor_printf(mon, "You can go to the specific step only in PLAY mode.\n");
+    }
+}
+
+
+static void do_replay_events(Monitor *mon, const QDict *qdict)
+{
+    if (replay_mode == REPLAY_PLAY) {
+        replay_events(mon);
+    } else {
+        monitor_printf(mon, "You can go to the specific step only in PLAY mode.\n");
+    }
+}
+
+
+static void do_replay_get_packet(Monitor *mon, const QDict *qdict)
+{
+    if (replay_mode == REPLAY_PLAY) {
+        if (!replay_get_packet(mon, qdict_get_int(qdict, "id"))) {
+            monitor_printf(mon, "Could not print specified network packet.\n");
+        }
+    } else {
+        monitor_printf(mon, "You can print packets only in replay PLAY mode.\n");
+    }
+}
+
+
+static void do_replay_set_packet(Monitor *mon, const QDict *qdict)
+{
+    if (replay_mode == REPLAY_PLAY) {
+        if (!replay_set_packet(mon, qdict_get_int(qdict, "id"), qdict_get_try_str(qdict, "bytes")))
{
+            monitor_printf(mon, "Could not set specified network packet.\n");
+        }
+    } else {
+        monitor_printf(mon, "You can set packets' contents only in replay PLAY mode.\n");
+    }
+}
+
+static void do_replay_change(Monitor *mon, const QDict *qdict)
+{
+    if (replay_mode != REPLAY_PLAY) {
+        monitor_printf(mon, "Cannot start execution from non-play mode.\n");
+        return;
+    }
+
+    if (!replay_icount) {
+        monitor_printf(mon, "Execution can only be started from icount mode.\n");
+        return;
+    }
+    
+    if (runstate_is_running()) {
+        monitor_printf(mon, "Stop the VM before executing of replay_change.\n");
+        return;
+    }
+    
+    replay_change(mon);
+}
+
+
 static void monitor_printc(Monitor *mon, int c)
 {