@@ -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",
@@ -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);
@@ -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)
{
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[] = { {