All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 00/14] Reverse debugging
@ 2020-09-29 11:01 Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 01/14] replay: don't record interrupt poll Pavel Dovgalyuk
                   ` (15 more replies)
  0 siblings, 16 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

GDB remote protocol supports reverse debugging of the targets.
It includes 'reverse step' and 'reverse continue' operations.
The first one finds the previous step of the execution,
and the second one is intended to stop at the last breakpoint that
would happen when the program is executed normally.

Reverse debugging is possible in the replay mode, when at least
one snapshot was created at the record or replay phase.
QEMU can use these snapshots for travelling back in time with GDB.

Running the execution in replay mode allows using GDB reverse debugging
commands:
 - reverse-stepi (or rsi): Steps one instruction to the past.
   QEMU loads on of the prior snapshots and proceeds to the desired
   instruction forward. When that step is reaches, execution stops.
 - reverse-continue (or rc): Runs execution "backwards".
   QEMU tries to find breakpoint or watchpoint by loaded prior snapshot
   and replaying the execution. Then QEMU loads snapshots again and
   replays to the latest breakpoint. When there are no breakpoints in
   the examined section of the execution, QEMU finds one more snapshot
   and tries again. After the first snapshot is processed, execution
   stops at this snapshot.

The set of patches include the following modifications:
 - gdbstub update for reverse debugging support
 - functions that automatically perform reverse step and reverse
   continue operations
 - hmp/qmp commands for manipulating the replay process
 - improvement of the snapshotting for saving the execution step
   in the snapshot parameters
 - avocado-based acceptance tests for reverse debugging

The patches are available in the repository:
https://github.com/ispras/qemu/tree/rr-200901

v6 changes:
 - removed passing err variable without checking it's value after
v5 changes:
 - disabled reverse debugging tests for gitlab-based testing
   due to the unidentified timeout problem
v4 changes:
 - added VM snapshot creation on gdb connect (suggested by Alex Bennée)
 - removed useless calls to error_free
 - updated poll interrupt processing
 - minor changes
v3 changes:
 - rebased to support the new build system
 - bumped avocado framework version for using fixed remote gdb client
v2 changes:
 - rebased to the latest upstream version
 - fixed replaying of the POLL interrupts after the latest debug changes

---

Pavel Dovgaluk (11):
      replay: provide an accessor for rr filename
      qcow2: introduce icount field for snapshots
      qapi: introduce replay.json for record/replay-related stuff
      replay: introduce info hmp/qmp command
      replay: introduce breakpoint at the specified step
      replay: implement replay-seek command
      replay: flush rr queue before loading the vmstate
      gdbstub: add reverse step support in replay mode
      gdbstub: add reverse continue support in replay mode
      replay: describe reverse debugging in docs/replay.txt
      tests/acceptance: add reverse debugging test

Pavel Dovgalyuk (3):
      replay: don't record interrupt poll
      migration: introduce icount field for snapshots
      replay: create temporary snapshot at debugger connection


 MAINTAINERS                           |    2 
 accel/tcg/cpu-exec.c                  |   21 ++
 accel/tcg/translator.c                |    1 
 block/qapi.c                          |   18 +-
 block/qcow2-snapshot.c                |    9 +
 block/qcow2.h                         |    3 
 blockdev.c                            |   10 +
 docs/interop/qcow2.txt                |    5 
 docs/replay.txt                       |   46 +++++
 exec.c                                |    8 +
 gdbstub.c                             |   64 ++++++
 hmp-commands-info.hx                  |   11 +
 hmp-commands.hx                       |   50 +++++
 include/block/snapshot.h              |    1 
 include/monitor/hmp.h                 |    4 
 include/sysemu/replay.h               |   26 +++
 migration/savevm.c                    |   17 +-
 qapi/block-core.json                  |   11 +
 qapi/meson.build                      |    1 
 qapi/misc.json                        |   18 --
 qapi/qapi-schema.json                 |    1 
 qapi/replay.json                      |  121 ++++++++++++
 replay/meson.build                    |    1 
 replay/replay-debugging.c             |  332 +++++++++++++++++++++++++++++++++
 replay/replay-events.c                |    4 
 replay/replay-internal.h              |    6 -
 replay/replay.c                       |   22 ++
 softmmu/cpus.c                        |   19 ++
 stubs/replay.c                        |   15 +
 tests/acceptance/reverse_debugging.py |  208 +++++++++++++++++++++
 tests/qemu-iotests/267.out            |   48 ++---
 31 files changed, 1039 insertions(+), 64 deletions(-)
 create mode 100644 qapi/replay.json
 create mode 100644 replay/replay-debugging.c
 create mode 100644 tests/acceptance/reverse_debugging.py

--
Pavel Dovgalyuk


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

* [PATCH v6 01/14] replay: don't record interrupt poll
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 02/14] replay: provide an accessor for rr filename Pavel Dovgalyuk
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

Interrupt poll is not a real interrupt event. It is needed only for
thread safety. This interrupt is used for i386 and converted
to hardware interrupt by cpu_handle_interrupt function.
Therefore it is not needed to be recorded, because hardware
interrupt will be recorded after converting.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

--

v4 changes:
 - Condition check refactoring (suggested by Alex Bennée)
---
 accel/tcg/cpu-exec.c |   21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index e10b46283c..a2b913c72f 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -430,8 +430,7 @@ static inline bool cpu_handle_halt(CPUState *cpu)
 {
     if (cpu->halted) {
 #if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
-        if ((cpu->interrupt_request & CPU_INTERRUPT_POLL)
-            && replay_interrupt()) {
+        if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
             X86CPU *x86_cpu = X86_CPU(cpu);
             qemu_mutex_lock_iothread();
             apic_poll_irq(x86_cpu->apic_state);
@@ -527,6 +526,20 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
     return false;
 }
 
+/*
+ * CPU_INTERRUPT_POLL is a virtual event which gets converted into a
+ * "real" interrupt event later. It does not need to be recorded for
+ * replay purposes.
+ */
+static inline bool need_replay_interrupt(int interrupt_request)
+{
+#if defined(TARGET_I386)
+    return !(interrupt_request & CPU_INTERRUPT_POLL);
+#else
+    return true;
+#endif
+}
+
 static inline bool cpu_handle_interrupt(CPUState *cpu,
                                         TranslationBlock **last_tb)
 {
@@ -588,7 +601,9 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
            and via longjmp via cpu_loop_exit.  */
         else {
             if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
-                replay_interrupt();
+                if (need_replay_interrupt(interrupt_request)) {
+                    replay_interrupt();
+                }
                 /*
                  * After processing the interrupt, ensure an EXCP_DEBUG is
                  * raised when single-stepping so that GDB doesn't miss the



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

* [PATCH v6 02/14] replay: provide an accessor for rr filename
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 01/14] replay: don't record interrupt poll Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 03/14] qcow2: introduce icount field for snapshots Pavel Dovgalyuk
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds an accessor function for the name of the record/replay
log file. Adding an accessor instead of making variable global,
prevents accidental modification of this variable by other modules.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 include/sysemu/replay.h |    2 ++
 replay/replay.c         |    5 +++++
 2 files changed, 7 insertions(+)

diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 5471bb514d..c9c896ae8d 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -72,6 +72,8 @@ void replay_start(void);
 void replay_finish(void);
 /*! Adds replay blocker with the specified error description */
 void replay_add_blocker(Error *reason);
+/* Returns name of the replay log file */
+const char *replay_get_filename(void);
 
 /* Processing the instructions */
 
diff --git a/replay/replay.c b/replay/replay.c
index 83ed9e0e24..42e82f7bc7 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -399,3 +399,8 @@ void replay_add_blocker(Error *reason)
 {
     replay_blockers = g_slist_prepend(replay_blockers, reason);
 }
+
+const char *replay_get_filename(void)
+{
+    return replay_filename;
+}



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

* [PATCH v6 03/14] qcow2: introduce icount field for snapshots
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 01/14] replay: don't record interrupt poll Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 02/14] replay: provide an accessor for rr filename Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-10-01 12:53   ` Alex Bennée
  2020-09-29 11:01 ` [PATCH v6 04/14] migration: " Pavel Dovgalyuk
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch introduces the icount field for saving within the snapshot.
It is required for navigation between the snapshots in record/replay mode.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Acked-by: Kevin Wolf <kwolf@redhat.com>
---
 block/qcow2-snapshot.c |    7 +++++++
 block/qcow2.h          |    3 +++
 docs/interop/qcow2.txt |    5 +++++
 3 files changed, 15 insertions(+)

diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 9b68690f56..d68b25e0c5 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -164,6 +164,12 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
             sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
         }
 
+        if (sn->extra_data_size >= endof(QCowSnapshotExtraData, icount)) {
+            sn->icount = be64_to_cpu(extra.icount);
+        } else {
+            sn->icount = -1ULL;
+        }
+
         if (sn->extra_data_size > sizeof(extra)) {
             uint64_t extra_data_end;
             size_t unknown_extra_data_size;
@@ -333,6 +339,7 @@ int qcow2_write_snapshots(BlockDriverState *bs)
         memset(&extra, 0, sizeof(extra));
         extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
         extra.disk_size = cpu_to_be64(sn->disk_size);
+        extra.icount = cpu_to_be64(sn->icount);
 
         id_str_size = strlen(sn->id_str);
         name_size = strlen(sn->name);
diff --git a/block/qcow2.h b/block/qcow2.h
index b71e444fca..125ea9679b 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -206,6 +206,7 @@ typedef struct QEMU_PACKED QCowSnapshotHeader {
 typedef struct QEMU_PACKED QCowSnapshotExtraData {
     uint64_t vm_state_size_large;
     uint64_t disk_size;
+    uint64_t icount;
 } QCowSnapshotExtraData;
 
 
@@ -219,6 +220,8 @@ typedef struct QCowSnapshot {
     uint32_t date_sec;
     uint32_t date_nsec;
     uint64_t vm_clock_nsec;
+    /* icount value for the moment when snapshot was taken */
+    uint64_t icount;
     /* Size of all extra data, including QCowSnapshotExtraData if available */
     uint32_t extra_data_size;
     /* Data beyond QCowSnapshotExtraData, if any */
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
index 7da0d81df8..0463f761ef 100644
--- a/docs/interop/qcow2.txt
+++ b/docs/interop/qcow2.txt
@@ -707,6 +707,11 @@ Snapshot table entry:
 
                     Byte 48 - 55:   Virtual disk size of the snapshot in bytes
 
+                    Byte 56 - 63:   icount value which corresponds to
+                                    the record/replay instruction count
+                                    when the snapshot was taken. Set to -1
+                                    if icount was disabled
+
                     Version 3 images must include extra data at least up to
                     byte 55.
 



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

* [PATCH v6 04/14] migration: introduce icount field for snapshots
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (2 preceding siblings ...)
  2020-09-29 11:01 ` [PATCH v6 03/14] qcow2: introduce icount field for snapshots Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 05/14] qapi: introduce replay.json for record/replay-related stuff Pavel Dovgalyuk
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

Saving icount as a parameters of the snapshot allows navigation between
them in the execution replay scenario.
This information can be used for finding a specific snapshot for proceeding
the recorded execution to the specific moment of the time.
E.g., 'reverse step' action (introduced in one of the following patches)
needs to load the nearest snapshot which is prior to the current moment
of time.
This patch also updates snapshot test which verifies qemu monitor output.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Acked-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Kevin Wolf <kwolf@redhat.com>

--

v4 changes:
 - squashed format update with test output update
---
 block/qapi.c               |   18 +++++++++++++----
 block/qcow2-snapshot.c     |    2 ++
 blockdev.c                 |   10 +++++++++
 include/block/snapshot.h   |    1 +
 migration/savevm.c         |    5 +++++
 qapi/block-core.json       |   10 +++++++--
 stubs/replay.c             |    5 +++++
 tests/qemu-iotests/267.out |   48 ++++++++++++++++++++++----------------------
 8 files changed, 69 insertions(+), 30 deletions(-)

diff --git a/block/qapi.c b/block/qapi.c
index f423ece98c..1086ee0c76 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -230,6 +230,8 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
         info->date_nsec     = sn_tab[i].date_nsec;
         info->vm_clock_sec  = sn_tab[i].vm_clock_nsec / 1000000000;
         info->vm_clock_nsec = sn_tab[i].vm_clock_nsec % 1000000000;
+        info->icount        = sn_tab[i].icount;
+        info->has_icount    = sn_tab[i].icount != -1ULL;
 
         info_list = g_new0(SnapshotInfoList, 1);
         info_list->value = info;
@@ -694,14 +696,15 @@ BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
 void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
 {
     char date_buf[128], clock_buf[128];
+    char icount_buf[128] = {0};
     struct tm tm;
     time_t ti;
     int64_t secs;
     char *sizing = NULL;
 
     if (!sn) {
-        qemu_printf("%-10s%-20s%11s%20s%15s",
-                    "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
+        qemu_printf("%-10s%-18s%7s%20s%13s%11s",
+                    "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK", "ICOUNT");
     } else {
         ti = sn->date_sec;
         localtime_r(&ti, &tm);
@@ -715,11 +718,16 @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn)
                  (int)(secs % 60),
                  (int)((sn->vm_clock_nsec / 1000000) % 1000));
         sizing = size_to_str(sn->vm_state_size);
-        qemu_printf("%-10s%-20s%11s%20s%15s",
+        if (sn->icount != -1ULL) {
+            snprintf(icount_buf, sizeof(icount_buf),
+                "%"PRId64, sn->icount);
+        }
+        qemu_printf("%-10s%-18s%7s%20s%13s%11s",
                     sn->id_str, sn->name,
                     sizing,
                     date_buf,
-                    clock_buf);
+                    clock_buf,
+                    icount_buf);
     }
     g_free(sizing);
 }
@@ -881,6 +889,8 @@ void bdrv_image_info_dump(ImageInfo *info)
                 .date_nsec = elem->value->date_nsec,
                 .vm_clock_nsec = elem->value->vm_clock_sec * 1000000000ULL +
                                  elem->value->vm_clock_nsec,
+                .icount = elem->value->has_icount ?
+                          elem->value->icount : -1ULL,
             };
 
             pstrcpy(sn.id_str, sizeof(sn.id_str), elem->value->id);
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index d68b25e0c5..2e98c7f4b6 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -663,6 +663,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
     sn->date_sec = sn_info->date_sec;
     sn->date_nsec = sn_info->date_nsec;
     sn->vm_clock_nsec = sn_info->vm_clock_nsec;
+    sn->icount = sn_info->icount;
     sn->extra_data_size = sizeof(QCowSnapshotExtraData);
 
     /* Allocate the L1 table of the snapshot and copy the current one there. */
@@ -1007,6 +1008,7 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
         sn_info->date_sec = sn->date_sec;
         sn_info->date_nsec = sn->date_nsec;
         sn_info->vm_clock_nsec = sn->vm_clock_nsec;
+        sn_info->icount = sn->icount;
     }
     *psn_tab = sn_tab;
     return s->nb_snapshots;
diff --git a/blockdev.c b/blockdev.c
index bebd3ba1c3..a6ae475dac 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -59,6 +59,7 @@
 #include "sysemu/arch_init.h"
 #include "sysemu/qtest.h"
 #include "sysemu/runstate.h"
+#include "sysemu/replay.h"
 #include "qemu/cutils.h"
 #include "qemu/help_option.h"
 #include "qemu/main-loop.h"
@@ -1190,6 +1191,10 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
     info->vm_state_size = sn.vm_state_size;
     info->vm_clock_nsec = sn.vm_clock_nsec % 1000000000;
     info->vm_clock_sec = sn.vm_clock_nsec / 1000000000;
+    if (sn.icount != -1ULL) {
+        info->icount = sn.icount;
+        info->has_icount = true;
+    }
 
     return info;
 
@@ -1350,6 +1355,11 @@ static void internal_snapshot_prepare(BlkActionState *common,
     sn->date_sec = tv.tv_sec;
     sn->date_nsec = tv.tv_usec * 1000;
     sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    if (replay_mode != REPLAY_MODE_NONE) {
+        sn->icount = replay_get_current_icount();
+    } else {
+        sn->icount = -1ULL;
+    }
 
     ret1 = bdrv_snapshot_create(bs, sn);
     if (ret1 < 0) {
diff --git a/include/block/snapshot.h b/include/block/snapshot.h
index 2bfcd57578..b0fe42993d 100644
--- a/include/block/snapshot.h
+++ b/include/block/snapshot.h
@@ -42,6 +42,7 @@ typedef struct QEMUSnapshotInfo {
     uint32_t date_sec; /* UTC date of the snapshot */
     uint32_t date_nsec;
     uint64_t vm_clock_nsec; /* VM clock relative to boot */
+    uint64_t icount; /* record/replay step */
 } QEMUSnapshotInfo;
 
 int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
diff --git a/migration/savevm.c b/migration/savevm.c
index 34e4b71052..0e8dc78684 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2723,6 +2723,11 @@ int save_snapshot(const char *name, Error **errp)
     sn->date_sec = tv.tv_sec;
     sn->date_nsec = tv.tv_usec * 1000;
     sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+    if (replay_mode != REPLAY_MODE_NONE) {
+        sn->icount = replay_get_current_icount();
+    } else {
+        sn->icount = -1ULL;
+    }
 
     if (name) {
         ret = bdrv_snapshot_find(bs, old_sn, name);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 3c16f1e11d..2135a61432 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -27,13 +27,18 @@
 #
 # @vm-clock-nsec: fractional part in nano seconds to be used with vm-clock-sec
 #
+# @icount: Current instruction count. Appears when execution record/replay
+#          is enabled. Used for "time-traveling" to match the moment
+#          in the recorded execution with the snapshots. (since 5.2)
+#
 # Since: 1.3
 #
 ##
 { 'struct': 'SnapshotInfo',
   'data': { 'id': 'str', 'name': 'str', 'vm-state-size': 'int',
             'date-sec': 'int', 'date-nsec': 'int',
-            'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } }
+            'vm-clock-sec': 'int', 'vm-clock-nsec': 'int',
+            '*icount': 'int' } }
 
 ##
 # @ImageInfoSpecificQCow2EncryptionBase:
@@ -5527,7 +5532,8 @@
 #                    "date-sec": 1000012,
 #                    "date-nsec": 10,
 #                    "vm-clock-sec": 100,
-#                    "vm-clock-nsec": 20
+#                    "vm-clock-nsec": 20,
+#                    "icount": 220414
 #      }
 #    }
 #
diff --git a/stubs/replay.c b/stubs/replay.c
index 5974ec1f50..eacb366aa8 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -88,3 +88,8 @@ int replay_read_random(void *buf, size_t len)
 {
     return 0;
 }
+
+uint64_t replay_get_current_icount(void)
+{
+    return 0;
+}
diff --git a/tests/qemu-iotests/267.out b/tests/qemu-iotests/267.out
index 215902b3ad..27471ffae8 100644
--- a/tests/qemu-iotests/267.out
+++ b/tests/qemu-iotests/267.out
@@ -33,8 +33,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
@@ -44,8 +44,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
@@ -69,8 +69,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
@@ -94,8 +94,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
@@ -105,8 +105,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
@@ -119,8 +119,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
@@ -134,8 +134,8 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
@@ -145,15 +145,15 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
 Internal snapshots on overlay:
 Snapshot list:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
-1         snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+1         snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 Internal snapshots on backing file:
 
 === -blockdev with NBD server on the backing file ===
@@ -166,17 +166,17 @@ QEMU X.Y.Z monitor - type 'help' for more information
 (qemu) savevm snap0
 (qemu) info snapshots
 List of snapshots present on all disks:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
---        snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 (qemu) loadvm snap0
 (qemu) quit
 
 Internal snapshots on overlay:
 Snapshot list:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
-1         snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+1         snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 Internal snapshots on backing file:
 Snapshot list:
-ID        TAG                 VM SIZE                DATE       VM CLOCK
-1         snap0                  SIZE yyyy-mm-dd hh:mm:ss   00:00:00.000
+ID        TAG               VM SIZE                DATE     VM CLOCK     ICOUNT
+1         snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           
 *** done



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

* [PATCH v6 05/14] qapi: introduce replay.json for record/replay-related stuff
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (3 preceding siblings ...)
  2020-09-29 11:01 ` [PATCH v6 04/14] migration: " Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-10-01 11:00   ` Alex Bennée
  2020-09-29 11:01 ` [PATCH v6 06/14] replay: introduce info hmp/qmp command Pavel Dovgalyuk
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds replay.json file. It will be
used for adding record/replay-related data structures and commands.

Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
---
 MAINTAINERS             |    1 +
 include/sysemu/replay.h |    1 +
 qapi/meson.build        |    1 +
 qapi/misc.json          |   18 ------------------
 qapi/qapi-schema.json   |    1 +
 qapi/replay.json        |   26 ++++++++++++++++++++++++++
 6 files changed, 30 insertions(+), 18 deletions(-)
 create mode 100644 qapi/replay.json

diff --git a/MAINTAINERS b/MAINTAINERS
index 5eed1e692b..7dcecb8653 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2672,6 +2672,7 @@ F: include/sysemu/replay.h
 F: docs/replay.txt
 F: stubs/replay.c
 F: tests/acceptance/replay_kernel.py
+F: qapi/replay.json
 
 IOVA Tree
 M: Peter Xu <peterx@redhat.com>
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index c9c896ae8d..e00ed2f4a5 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -14,6 +14,7 @@
 
 #include "qapi/qapi-types-misc.h"
 #include "qapi/qapi-types-run-state.h"
+#include "qapi/qapi-types-replay.h"
 #include "qapi/qapi-types-ui.h"
 #include "block/aio.h"
 
diff --git a/qapi/meson.build b/qapi/meson.build
index 2b2872a41d..f4fd514379 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -36,6 +36,7 @@ qapi_all_modules = [
   'qdev',
   'qom',
   'rdma',
+  'replay',
   'rocker',
   'run-state',
   'sockets',
diff --git a/qapi/misc.json b/qapi/misc.json
index 8cf6ebe67c..b194ec4a30 100644
--- a/qapi/misc.json
+++ b/qapi/misc.json
@@ -1556,24 +1556,6 @@
 { 'event': 'ACPI_DEVICE_OST',
      'data': { 'info': 'ACPIOSTInfo' } }
 
-##
-# @ReplayMode:
-#
-# Mode of the replay subsystem.
-#
-# @none: normal execution mode. Replay or record are not enabled.
-#
-# @record: record mode. All non-deterministic data is written into the
-#          replay log.
-#
-# @play: replay mode. Non-deterministic data required for system execution
-#        is read from the log.
-#
-# Since: 2.5
-##
-{ 'enum': 'ReplayMode',
-  'data': [ 'none', 'record', 'play' ] }
-
 ##
 # @xen-load-devices-state:
 #
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index f03ff91ceb..2604fcf6ec 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -82,6 +82,7 @@
 { 'include': 'qdev.json' }
 { 'include': 'machine.json' }
 { 'include': 'machine-target.json' }
+{ 'include': 'replay.json' }
 { 'include': 'misc.json' }
 { 'include': 'misc-target.json' }
 { 'include': 'audio.json' }
diff --git a/qapi/replay.json b/qapi/replay.json
new file mode 100644
index 0000000000..9e13551d20
--- /dev/null
+++ b/qapi/replay.json
@@ -0,0 +1,26 @@
+# -*- Mode: Python -*-
+#
+
+##
+# = Record/replay
+##
+
+{ 'include': 'common.json' }
+
+##
+# @ReplayMode:
+#
+# Mode of the replay subsystem.
+#
+# @none: normal execution mode. Replay or record are not enabled.
+#
+# @record: record mode. All non-deterministic data is written into the
+#          replay log.
+#
+# @play: replay mode. Non-deterministic data required for system execution
+#        is read from the log.
+#
+# Since: 2.5
+##
+{ 'enum': 'ReplayMode',
+  'data': [ 'none', 'record', 'play' ] }



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

* [PATCH v6 06/14] replay: introduce info hmp/qmp command
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (4 preceding siblings ...)
  2020-09-29 11:01 ` [PATCH v6 05/14] qapi: introduce replay.json for record/replay-related stuff Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 07/14] replay: introduce breakpoint at the specified step Pavel Dovgalyuk
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch introduces 'info replay' monitor command and
corresponding qmp request.
These commands request the current record/replay mode, replay log file
name, and the instruction count (number of recorded/replayed
instructions).  The instruction count can be used with the
replay_seek/replay_break commands added in the next two patches.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
---
 hmp-commands-info.hx      |   11 +++++++++++
 include/monitor/hmp.h     |    1 +
 qapi/block-core.json      |    3 ++-
 qapi/replay.json          |   39 +++++++++++++++++++++++++++++++++++++++
 replay/meson.build        |    1 +
 replay/replay-debugging.c |   43 +++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 replay/replay-debugging.c

diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 30209e3903..117ba25f91 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -881,4 +881,15 @@ SRST
     Show SEV information.
 ERST
 
+    {
+        .name       = "replay",
+        .args_type  = "",
+        .params     = "",
+        .help       = "show record/replay information",
+        .cmd        = hmp_info_replay,
+    },
 
+SRST
+  ``info replay``
+    Display the record/replay information: mode and the current icount.
+ERST
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index c986cfd28b..a790589b9e 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -130,5 +130,6 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict);
 void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
 void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
 void hmp_info_sev(Monitor *mon, const QDict *qdict);
+void hmp_info_replay(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 2135a61432..a0d12caf76 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -29,7 +29,8 @@
 #
 # @icount: Current instruction count. Appears when execution record/replay
 #          is enabled. Used for "time-traveling" to match the moment
-#          in the recorded execution with the snapshots. (since 5.2)
+#          in the recorded execution with the snapshots. This counter may
+#          be obtained through @query-replay command (since 5.2)
 #
 # Since: 1.3
 #
diff --git a/qapi/replay.json b/qapi/replay.json
index 9e13551d20..e6b3f6001d 100644
--- a/qapi/replay.json
+++ b/qapi/replay.json
@@ -24,3 +24,42 @@
 ##
 { 'enum': 'ReplayMode',
   'data': [ 'none', 'record', 'play' ] }
+
+##
+# @ReplayInfo:
+#
+# Record/replay information.
+#
+# @mode: current mode.
+#
+# @filename: name of the record/replay log file.
+#            It is present only in record or replay modes, when the log
+#            is recorded or replayed.
+#
+# @icount: current number of executed instructions.
+#
+# Since: 5.2
+#
+##
+{ 'struct': 'ReplayInfo',
+  'data': { 'mode': 'ReplayMode', '*filename': 'str', 'icount': 'int' } }
+
+##
+# @query-replay:
+#
+# Retrieve the record/replay information.
+# It includes current instruction count which may be used for
+# @replay-break and @replay-seek commands.
+#
+# Returns: record/replay information.
+#
+# Since: 5.2
+#
+# Example:
+#
+# -> { "execute": "query-replay" }
+# <- { "return": { "mode": "play", "filename": "log.rr", "icount": 220414 } }
+#
+##
+{ 'command': 'query-replay',
+  'returns': 'ReplayInfo' }
diff --git a/replay/meson.build b/replay/meson.build
index 8783aea7c8..f91163fb1e 100644
--- a/replay/meson.build
+++ b/replay/meson.build
@@ -9,4 +9,5 @@ softmmu_ss.add(files(
   'replay-net.c',
   'replay-audio.c',
   'replay-random.c',
+  'replay-debugging.c',
 ))
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
new file mode 100644
index 0000000000..51a6de4e81
--- /dev/null
+++ b/replay/replay-debugging.c
@@ -0,0 +1,43 @@
+/*
+ * replay-debugging.c
+ *
+ * Copyright (c) 2010-2020 Institute for System Programming
+ *                         of the Russian Academy of Sciences.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "sysemu/replay.h"
+#include "replay-internal.h"
+#include "monitor/hmp.h"
+#include "monitor/monitor.h"
+#include "qapi/qapi-commands-replay.h"
+
+void hmp_info_replay(Monitor *mon, const QDict *qdict)
+{
+    if (replay_mode == REPLAY_MODE_NONE) {
+        monitor_printf(mon, "Record/replay is not active\n");
+    } else {
+        monitor_printf(mon,
+            "%s execution '%s': instruction count = %"PRId64"\n",
+            replay_mode == REPLAY_MODE_RECORD ? "Recording" : "Replaying",
+            replay_get_filename(), replay_get_current_icount());
+    }
+}
+
+ReplayInfo *qmp_query_replay(Error **errp)
+{
+    ReplayInfo *retval = g_new0(ReplayInfo, 1);
+
+    retval->mode = replay_mode;
+    if (replay_get_filename()) {
+        retval->filename = g_strdup(replay_get_filename());
+        retval->has_filename = true;
+    }
+    retval->icount = replay_get_current_icount();
+    return retval;
+}



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

* [PATCH v6 07/14] replay: introduce breakpoint at the specified step
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (5 preceding siblings ...)
  2020-09-29 11:01 ` [PATCH v6 06/14] replay: introduce info hmp/qmp command Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 08/14] replay: implement replay-seek command Pavel Dovgalyuk
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch introduces replay_break, replay_delete_break
qmp and hmp commands.
These commands allow stopping at the specified instruction.
It may be useful for debugging when there are some known
events that should be investigated.
replay_break command has one argument - number of instructions
executed since the start of the replay.
replay_delete_break removes previously set breakpoint.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Acked-by: Markus Armbruster <armbru@redhat.com>

--

v4 changes:
 - removed useless error_free call
---
 hmp-commands.hx           |   32 +++++++++++++++++
 include/monitor/hmp.h     |    2 +
 qapi/replay.json          |   36 +++++++++++++++++++
 replay/replay-debugging.c |   84 +++++++++++++++++++++++++++++++++++++++++++++
 replay/replay-internal.h  |    4 ++
 replay/replay.c           |   17 +++++++++
 6 files changed, 175 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 27c4bbe0f2..ced47e49d5 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1819,6 +1819,38 @@ SRST
   Set QOM property *property* of object at location *path* to value *value*
 ERST
 
+    {
+        .name       = "replay_break",
+        .args_type  = "icount:i",
+        .params     = "icount",
+        .help       = "set breakpoint at the specified instruction count",
+        .cmd        = hmp_replay_break,
+    },
+
+SRST
+``replay_break`` *icount*
+  Set replay breakpoint at instruction count *icount*.
+  Execution stops when the specified instruction is reached.
+  There can be at most one breakpoint. When breakpoint is set, any prior
+  one is removed.  The breakpoint may be set only in replay mode and only
+  "in the future", i.e. at instruction counts greater than the current one.
+  The current instruction count can be observed with ``info replay``.
+ERST
+
+    {
+        .name       = "replay_delete_break",
+        .args_type  = "",
+        .params     = "",
+        .help       = "remove replay breakpoint",
+        .cmd        = hmp_replay_delete_break,
+    },
+
+SRST
+``replay_delete_break``
+  Remove replay breakpoint which was previously set with ``replay_break``.
+  The command is ignored when there are no replay breakpoints.
+ERST
+
     {
         .name       = "info",
         .args_type  = "item:s?",
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index a790589b9e..21849bdda5 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -131,5 +131,7 @@ void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict);
 void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict);
 void hmp_info_sev(Monitor *mon, const QDict *qdict);
 void hmp_info_replay(Monitor *mon, const QDict *qdict);
+void hmp_replay_break(Monitor *mon, const QDict *qdict);
+void hmp_replay_delete_break(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi/replay.json b/qapi/replay.json
index e6b3f6001d..173ba76107 100644
--- a/qapi/replay.json
+++ b/qapi/replay.json
@@ -63,3 +63,39 @@
 ##
 { 'command': 'query-replay',
   'returns': 'ReplayInfo' }
+
+##
+# @replay-break:
+#
+# Set replay breakpoint at instruction count @icount.
+# Execution stops when the specified instruction is reached.
+# There can be at most one breakpoint. When breakpoint is set, any prior
+# one is removed.  The breakpoint may be set only in replay mode and only
+# "in the future", i.e. at instruction counts greater than the current one.
+# The current instruction count can be observed with @query-replay.
+#
+# @icount: instruction count to stop at
+#
+# Since: 5.2
+#
+# Example:
+#
+# -> { "execute": "replay-break", "data": { "icount": 220414 } }
+#
+##
+{ 'command': 'replay-break', 'data': { 'icount': 'int' } }
+
+##
+# @replay-delete-break:
+#
+# Remove replay breakpoint which was set with @replay-break.
+# The command is ignored when there are no replay breakpoints.
+#
+# Since: 5.2
+#
+# Example:
+#
+# -> { "execute": "replay-delete-break" }
+#
+##
+{ 'command': 'replay-delete-break' }
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index 51a6de4e81..3dc23b84fc 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -12,10 +12,13 @@
 #include "qemu/osdep.h"
 #include "qapi/error.h"
 #include "sysemu/replay.h"
+#include "sysemu/runstate.h"
 #include "replay-internal.h"
 #include "monitor/hmp.h"
 #include "monitor/monitor.h"
 #include "qapi/qapi-commands-replay.h"
+#include "qapi/qmp/qdict.h"
+#include "qemu/timer.h"
 
 void hmp_info_replay(Monitor *mon, const QDict *qdict)
 {
@@ -41,3 +44,84 @@ ReplayInfo *qmp_query_replay(Error **errp)
     retval->icount = replay_get_current_icount();
     return retval;
 }
+
+static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque)
+{
+    assert(replay_mode == REPLAY_MODE_PLAY);
+    assert(replay_mutex_locked());
+    assert(replay_break_icount >= replay_get_current_icount());
+    assert(callback);
+
+    replay_break_icount = icount;
+
+    if (replay_break_timer) {
+        timer_del(replay_break_timer);
+    }
+    replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
+                                      callback, opaque);
+}
+
+static void replay_delete_break(void)
+{
+    assert(replay_mode == REPLAY_MODE_PLAY);
+    assert(replay_mutex_locked());
+
+    if (replay_break_timer) {
+        timer_del(replay_break_timer);
+        timer_free(replay_break_timer);
+        replay_break_timer = NULL;
+    }
+    replay_break_icount = -1ULL;
+}
+
+static void replay_stop_vm(void *opaque)
+{
+    vm_stop(RUN_STATE_PAUSED);
+    replay_delete_break();
+}
+
+void qmp_replay_break(int64_t icount, Error **errp)
+{
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        if (icount >= replay_get_current_icount()) {
+            replay_break(icount, replay_stop_vm, NULL);
+        } else {
+            error_setg(errp,
+                "cannot set breakpoint at the instruction in the past");
+        }
+    } else {
+        error_setg(errp, "setting the breakpoint is allowed only in play mode");
+    }
+}
+
+void hmp_replay_break(Monitor *mon, const QDict *qdict)
+{
+    int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
+    Error *err = NULL;
+
+    qmp_replay_break(icount, &err);
+    if (err) {
+        error_report_err(err);
+        return;
+    }
+}
+
+void qmp_replay_delete_break(Error **errp)
+{
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        replay_delete_break();
+    } else {
+        error_setg(errp, "replay breakpoints are allowed only in play mode");
+    }
+}
+
+void hmp_replay_delete_break(Monitor *mon, const QDict *qdict)
+{
+    Error *err = NULL;
+
+    qmp_replay_delete_break(&err);
+    if (err) {
+        error_report_err(err);
+        return;
+    }
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 33ac551e78..2f6145ec7c 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -94,6 +94,10 @@ extern ReplayState replay_state;
 
 /* File for replay writing */
 extern FILE *replay_file;
+/* Instruction count of the replay breakpoint */
+extern uint64_t replay_break_icount;
+/* Timer for the replay breakpoint callback */
+extern QEMUTimer *replay_break_timer;
 
 void replay_put_byte(uint8_t byte);
 void replay_put_event(uint8_t event);
diff --git a/replay/replay.c b/replay/replay.c
index 42e82f7bc7..220886e32e 100644
--- a/replay/replay.c
+++ b/replay/replay.c
@@ -34,6 +34,10 @@ static char *replay_filename;
 ReplayState replay_state;
 static GSList *replay_blockers;
 
+/* Replay breakpoints */
+uint64_t replay_break_icount = -1ULL;
+QEMUTimer *replay_break_timer;
+
 bool replay_next_event_is(int event)
 {
     bool res = false;
@@ -73,6 +77,13 @@ int replay_get_instructions(void)
     replay_mutex_lock();
     if (replay_next_event_is(EVENT_INSTRUCTION)) {
         res = replay_state.instruction_count;
+        if (replay_break_icount != -1LL) {
+            uint64_t current = replay_get_current_icount();
+            assert(replay_break_icount >= current);
+            if (current + res > replay_break_icount) {
+                res = replay_break_icount - current;
+            }
+        }
     }
     replay_mutex_unlock();
     return res;
@@ -99,6 +110,12 @@ void replay_account_executed_instructions(void)
                    will be read from the log. */
                 qemu_notify_event();
             }
+            /* Execution reached the break step */
+            if (replay_break_icount == replay_state.current_icount) {
+                /* Cannot make callback directly from the vCPU thread */
+                timer_mod_ns(replay_break_timer,
+                    qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
+            }
         }
     }
 }



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

* [PATCH v6 08/14] replay: implement replay-seek command
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (6 preceding siblings ...)
  2020-09-29 11:01 ` [PATCH v6 07/14] replay: introduce breakpoint at the specified step Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-09-29 11:01 ` [PATCH v6 09/14] replay: flush rr queue before loading the vmstate Pavel Dovgalyuk
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds hmp/qmp commands replay_seek/replay-seek that proceed
the execution to the specified instruction count.
The command automatically loads nearest snapshot and replays the execution
to find the desired instruction count.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Acked-by: Markus Armbruster <armbru@redhat.com>

--

v4 changes:
 - fixed HMP command description indent
 - removed useless error_free call
---
 hmp-commands.hx           |   18 +++++++++
 include/monitor/hmp.h     |    1 +
 qapi/replay.json          |   20 ++++++++++
 replay/replay-debugging.c |   87 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 126 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index ced47e49d5..1981bf0511 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1851,6 +1851,24 @@ SRST
   The command is ignored when there are no replay breakpoints.
 ERST
 
+    {
+        .name       = "replay_seek",
+        .args_type  = "icount:i",
+        .params     = "icount",
+        .help       = "replay execution to the specified instruction count",
+        .cmd        = hmp_replay_seek,
+    },
+
+SRST
+``replay_seek`` *icount*
+  Automatically proceed to the instruction count *icount*, when
+  replaying the execution. The command automatically loads nearest
+  snapshot and replays the execution to find the desired instruction.
+  When there is no preceding snapshot or the execution is not replayed,
+  then the command fails.
+  *icount* for the reference may be observed with ``info replay`` command.
+ERST
+
     {
         .name       = "info",
         .args_type  = "item:s?",
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index 21849bdda5..655eb81a4c 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -133,5 +133,6 @@ void hmp_info_sev(Monitor *mon, const QDict *qdict);
 void hmp_info_replay(Monitor *mon, const QDict *qdict);
 void hmp_replay_break(Monitor *mon, const QDict *qdict);
 void hmp_replay_delete_break(Monitor *mon, const QDict *qdict);
+void hmp_replay_seek(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/qapi/replay.json b/qapi/replay.json
index 173ba76107..bfd83d7591 100644
--- a/qapi/replay.json
+++ b/qapi/replay.json
@@ -99,3 +99,23 @@
 #
 ##
 { 'command': 'replay-delete-break' }
+
+##
+# @replay-seek:
+#
+# Automatically proceed to the instruction count @icount, when
+# replaying the execution. The command automatically loads nearest
+# snapshot and replays the execution to find the desired instruction.
+# When there is no preceding snapshot or the execution is not replayed,
+# then the command fails.
+# icount for the reference may be obtained with @query-replay command.
+#
+# @icount: target instruction count
+#
+# Since: 5.2
+#
+# Example:
+#
+# -> { "execute": "replay-seek", "data": { "icount": 220414 } }
+##
+{ 'command': 'replay-seek', 'data': { 'icount': 'int' } }
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index 3dc23b84fc..e1fe6b8661 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -19,6 +19,8 @@
 #include "qapi/qapi-commands-replay.h"
 #include "qapi/qmp/qdict.h"
 #include "qemu/timer.h"
+#include "block/snapshot.h"
+#include "migration/snapshot.h"
 
 void hmp_info_replay(Monitor *mon, const QDict *qdict)
 {
@@ -125,3 +127,88 @@ void hmp_replay_delete_break(Monitor *mon, const QDict *qdict)
         return;
     }
 }
+
+static char *replay_find_nearest_snapshot(int64_t icount,
+                                          int64_t *snapshot_icount)
+{
+    BlockDriverState *bs;
+    QEMUSnapshotInfo *sn_tab;
+    QEMUSnapshotInfo *nearest = NULL;
+    char *ret = NULL;
+    int nb_sns, i;
+    AioContext *aio_context;
+
+    *snapshot_icount = -1;
+
+    bs = bdrv_all_find_vmstate_bs();
+    if (!bs) {
+        goto fail;
+    }
+    aio_context = bdrv_get_aio_context(bs);
+
+    aio_context_acquire(aio_context);
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    aio_context_release(aio_context);
+
+    for (i = 0; i < nb_sns; i++) {
+        if (bdrv_all_find_snapshot(sn_tab[i].name, &bs) == 0) {
+            if (sn_tab[i].icount != -1ULL
+                && sn_tab[i].icount <= icount
+                && (!nearest || nearest->icount < sn_tab[i].icount)) {
+                nearest = &sn_tab[i];
+            }
+        }
+    }
+    if (nearest) {
+        ret = g_strdup(nearest->name);
+        *snapshot_icount = nearest->icount;
+    }
+    g_free(sn_tab);
+
+fail:
+    return ret;
+}
+
+static void replay_seek(int64_t icount, QEMUTimerCB callback, Error **errp)
+{
+    char *snapshot = NULL;
+    int64_t snapshot_icount;
+
+    if (replay_mode != REPLAY_MODE_PLAY) {
+        error_setg(errp, "replay must be enabled to seek");
+        return;
+    }
+
+    snapshot = replay_find_nearest_snapshot(icount, &snapshot_icount);
+    if (snapshot) {
+        if (icount < replay_get_current_icount()
+            || replay_get_current_icount() < snapshot_icount) {
+            vm_stop(RUN_STATE_RESTORE_VM);
+            load_snapshot(snapshot, errp);
+        }
+        g_free(snapshot);
+    }
+    if (replay_get_current_icount() <= icount) {
+        replay_break(icount, callback, NULL);
+        vm_start();
+    } else {
+        error_setg(errp, "cannot seek to the specified instruction count");
+    }
+}
+
+void qmp_replay_seek(int64_t icount, Error **errp)
+{
+    replay_seek(icount, replay_stop_vm, errp);
+}
+
+void hmp_replay_seek(Monitor *mon, const QDict *qdict)
+{
+    int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
+    Error *err = NULL;
+
+    qmp_replay_seek(icount, &err);
+    if (err) {
+        error_report_err(err);
+        return;
+    }
+}



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

* [PATCH v6 09/14] replay: flush rr queue before loading the vmstate
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (7 preceding siblings ...)
  2020-09-29 11:01 ` [PATCH v6 08/14] replay: implement replay-seek command Pavel Dovgalyuk
@ 2020-09-29 11:01 ` Pavel Dovgalyuk
  2020-09-29 11:02 ` [PATCH v6 10/14] gdbstub: add reverse step support in replay mode Pavel Dovgalyuk
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

Non-empty record/replay queue prevents saving and loading the VM state,
because it includes pending bottom halves and block coroutines.
But when the new VM state is loaded, we don't have to preserve the consistency
of the current state anymore. Therefore this patch just flushes the queue
allowing the coroutines to finish and removes checking for empty rr queue
for load_snapshot function.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/sysemu/replay.h  |    2 ++
 migration/savevm.c       |   12 ++++++------
 replay/replay-events.c   |    4 ++++
 replay/replay-internal.h |    2 --
 4 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index e00ed2f4a5..239c01e7df 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -149,6 +149,8 @@ void replay_disable_events(void);
 void replay_enable_events(void);
 /*! Returns true when saving events is enabled */
 bool replay_events_enabled(void);
+/* Flushes events queue */
+void replay_flush_events(void);
 /*! Adds bottom half event to the queue */
 void replay_bh_schedule_event(QEMUBH *bh);
 /* Adds oneshot bottom half event to the queue */
diff --git a/migration/savevm.c b/migration/savevm.c
index 0e8dc78684..d2e141f7b1 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2881,12 +2881,6 @@ int load_snapshot(const char *name, Error **errp)
     AioContext *aio_context;
     MigrationIncomingState *mis = migration_incoming_get_current();
 
-    if (!replay_can_snapshot()) {
-        error_setg(errp, "Record/replay does not allow loading snapshot "
-                   "right now. Try once more later.");
-        return -EINVAL;
-    }
-
     if (!bdrv_all_can_snapshot(&bs)) {
         error_setg(errp,
                    "Device '%s' is writable but does not support snapshots",
@@ -2920,6 +2914,12 @@ int load_snapshot(const char *name, Error **errp)
         return -EINVAL;
     }
 
+    /*
+     * Flush the record/replay queue. Now the VM state is going
+     * to change. Therefore we don't need to preserve its consistency
+     */
+    replay_flush_events();
+
     /* Flush all IO requests so they don't interfere with the new state.  */
     bdrv_drain_all_begin();
 
diff --git a/replay/replay-events.c b/replay/replay-events.c
index 302b84043a..a1c6bb934e 100644
--- a/replay/replay-events.c
+++ b/replay/replay-events.c
@@ -77,6 +77,10 @@ bool replay_has_events(void)
 
 void replay_flush_events(void)
 {
+    if (replay_mode == REPLAY_MODE_NONE) {
+        return;
+    }
+
     g_assert(replay_mutex_locked());
 
     while (!QTAILQ_EMPTY(&events_list)) {
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index 2f6145ec7c..97649ed8d7 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -149,8 +149,6 @@ void replay_read_next_clock(unsigned int kind);
 void replay_init_events(void);
 /*! Clears internal data structures for events handling */
 void replay_finish_events(void);
-/*! Flushes events queue */
-void replay_flush_events(void);
 /*! Returns true if there are any unsaved events in the queue */
 bool replay_has_events(void);
 /*! Saves events from queue into the file */



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

* [PATCH v6 10/14] gdbstub: add reverse step support in replay mode
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (8 preceding siblings ...)
  2020-09-29 11:01 ` [PATCH v6 09/14] replay: flush rr queue before loading the vmstate Pavel Dovgalyuk
@ 2020-09-29 11:02 ` Pavel Dovgalyuk
  2020-09-29 11:02 ` [PATCH v6 11/14] gdbstub: add reverse continue " Pavel Dovgalyuk
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

GDB remote protocol supports two reverse debugging commands:
reverse step and reverse continue.
This patch adds support of the first one to the gdbstub.
Reverse step is intended to step one instruction in the backwards
direction. This is not possible in regular execution.
But replayed execution is deterministic, therefore we can load one of
the prior snapshots and proceed to the desired step. It is equivalent
to stepping one instruction back.
There should be at least one snapshot preceding the debugged part of
the replay log.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

--

v4 changes:
 - inverted condition in cpu_handle_guest_debug (suggested by Alex Bennée)
---
 accel/tcg/translator.c    |    1 +
 exec.c                    |    7 ++++++
 gdbstub.c                 |   55 +++++++++++++++++++++++++++++++++++++++++++--
 include/sysemu/replay.h   |   11 +++++++++
 replay/replay-debugging.c |   33 +++++++++++++++++++++++++++
 softmmu/cpus.c            |   14 +++++++++--
 stubs/replay.c            |    5 ++++
 7 files changed, 121 insertions(+), 5 deletions(-)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 603d17ff83..fb1e19c585 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -17,6 +17,7 @@
 #include "exec/log.h"
 #include "exec/translator.h"
 #include "exec/plugin-gen.h"
+#include "sysemu/replay.h"
 
 /* Pairs with tcg_clear_temp_count.
    To be called by #TranslatorOps.{translate_insn,tb_stop} if
diff --git a/exec.c b/exec.c
index 3f5deb35ff..10267f7ed0 100644
--- a/exec.c
+++ b/exec.c
@@ -2752,6 +2752,13 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
     QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
         if (watchpoint_address_matches(wp, addr, len)
             && (wp->flags & flags)) {
+            if (replay_running_debug()) {
+                /*
+                 * Don't process the watchpoints when we are
+                 * in a reverse debugging operation.
+                 */
+                return;
+            }
             if (flags == BP_MEM_READ) {
                 wp->flags |= BP_WATCHPOINT_HIT_READ;
             } else {
diff --git a/gdbstub.c b/gdbstub.c
index 9dfb6e4142..79e8ccc050 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -51,6 +51,7 @@
 #include "sysemu/runstate.h"
 #include "hw/semihosting/semihost.h"
 #include "exec/exec-all.h"
+#include "sysemu/replay.h"
 
 #ifdef CONFIG_USER_ONLY
 #define GDB_ATTACHED "0"
@@ -375,6 +376,20 @@ typedef struct GDBState {
  */
 static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
 
+/* Retrieves flags for single step mode. */
+static int get_sstep_flags(void)
+{
+    /*
+     * In replay mode all events written into the log should be replayed.
+     * That is why NOIRQ flag is removed in this mode.
+     */
+    if (replay_mode != REPLAY_MODE_NONE) {
+        return SSTEP_ENABLE;
+    } else {
+        return sstep_flags;
+    }
+}
+
 static GDBState gdbserver_state;
 
 static void init_gdbserver_state(void)
@@ -501,7 +516,7 @@ static int gdb_continue_partial(char *newstates)
                 break; /* nothing to do here */
             case 's':
                 trace_gdbstub_op_stepping(cpu->cpu_index);
-                cpu_single_step(cpu, sstep_flags);
+                cpu_single_step(cpu, get_sstep_flags());
                 cpu_resume(cpu);
                 flag = 1;
                 break;
@@ -1874,10 +1889,31 @@ static void handle_step(GdbCmdContext *gdb_ctx, void *user_ctx)
         gdb_set_cpu_pc((target_ulong)gdb_ctx->params[0].val_ull);
     }
 
-    cpu_single_step(gdbserver_state.c_cpu, sstep_flags);
+    cpu_single_step(gdbserver_state.c_cpu, get_sstep_flags());
     gdb_continue();
 }
 
+static void handle_backward(GdbCmdContext *gdb_ctx, void *user_ctx)
+{
+    if (replay_mode != REPLAY_MODE_PLAY) {
+        put_packet("E22");
+    }
+    if (gdb_ctx->num_params == 1) {
+        switch (gdb_ctx->params[0].opcode) {
+        case 's':
+            if (replay_reverse_step()) {
+                gdb_continue();
+            } else {
+                put_packet("E14");
+            }
+            return;
+        }
+    }
+
+    /* Default invalid command */
+    put_packet("");
+}
+
 static void handle_v_cont_query(GdbCmdContext *gdb_ctx, void *user_ctx)
 {
     put_packet("vCont;c;C;s;S");
@@ -2124,6 +2160,10 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
         g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+");
     }
 
+    if (replay_mode == REPLAY_MODE_PLAY) {
+        g_string_append(gdbserver_state.str_buf, ";ReverseStep+");
+    }
+
     if (gdb_ctx->num_params &&
         strstr(gdb_ctx->params[0].data, "multiprocess+")) {
         gdbserver_state.multiprocess = true;
@@ -2460,6 +2500,17 @@ static int gdb_handle_packet(const char *line_buf)
             cmd_parser = &step_cmd_desc;
         }
         break;
+    case 'b':
+        {
+            static const GdbCmdParseEntry backward_cmd_desc = {
+                .handler = handle_backward,
+                .cmd = "b",
+                .cmd_startswith = 1,
+                .schema = "o0"
+            };
+            cmd_parser = &backward_cmd_desc;
+        }
+        break;
     case 'F':
         {
             static const GdbCmdParseEntry file_io_cmd_desc = {
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 239c01e7df..13a8123b09 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -75,6 +75,17 @@ void replay_finish(void);
 void replay_add_blocker(Error *reason);
 /* Returns name of the replay log file */
 const char *replay_get_filename(void);
+/*
+ * Start making one step in backward direction.
+ * Used by gdbstub for backwards debugging.
+ * Returns true on success.
+ */
+bool replay_reverse_step(void);
+/*
+ * Returns true if replay module is processing
+ * reverse_continue or reverse_step request
+ */
+bool replay_running_debug(void);
 
 /* Processing the instructions */
 
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index e1fe6b8661..f7594a88cd 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -22,6 +22,13 @@
 #include "block/snapshot.h"
 #include "migration/snapshot.h"
 
+static bool replay_is_debugging;
+
+bool replay_running_debug(void)
+{
+    return replay_is_debugging;
+}
+
 void hmp_info_replay(Monitor *mon, const QDict *qdict)
 {
     if (replay_mode == REPLAY_MODE_NONE) {
@@ -212,3 +219,29 @@ void hmp_replay_seek(Monitor *mon, const QDict *qdict)
         return;
     }
 }
+
+static void replay_stop_vm_debug(void *opaque)
+{
+    replay_is_debugging = false;
+    vm_stop(RUN_STATE_DEBUG);
+    replay_delete_break();
+}
+
+bool replay_reverse_step(void)
+{
+    Error *err = NULL;
+
+    assert(replay_mode == REPLAY_MODE_PLAY);
+
+    if (replay_get_current_icount() != 0) {
+        replay_seek(replay_get_current_icount() - 1, replay_stop_vm_debug, &err);
+        if (err) {
+            error_free(err);
+            return false;
+        }
+        replay_is_debugging = true;
+        return true;
+    }
+
+    return false;
+}
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index ac8940d52e..1fa9c4c1de 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -1004,9 +1004,17 @@ static bool cpu_can_run(CPUState *cpu)
 
 static void cpu_handle_guest_debug(CPUState *cpu)
 {
-    gdb_set_stop_cpu(cpu);
-    qemu_system_debug_request();
-    cpu->stopped = true;
+    if (replay_running_debug()) {
+        if (!cpu->singlestep_enabled) {
+            cpu_single_step(cpu, SSTEP_ENABLE);
+        } else {
+            cpu_single_step(cpu, 0);
+        }
+    } else {
+        gdb_set_stop_cpu(cpu);
+        qemu_system_debug_request();
+        cpu->stopped = true;
+    }
 }
 
 #ifdef CONFIG_LINUX
diff --git a/stubs/replay.c b/stubs/replay.c
index eacb366aa8..d5b52302e9 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -93,3 +93,8 @@ uint64_t replay_get_current_icount(void)
 {
     return 0;
 }
+
+bool replay_reverse_step(void)
+{
+    return false;
+}



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

* [PATCH v6 11/14] gdbstub: add reverse continue support in replay mode
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (9 preceding siblings ...)
  2020-09-29 11:02 ` [PATCH v6 10/14] gdbstub: add reverse step support in replay mode Pavel Dovgalyuk
@ 2020-09-29 11:02 ` Pavel Dovgalyuk
  2020-09-29 11:02 ` [PATCH v6 12/14] replay: describe reverse debugging in docs/replay.txt Pavel Dovgalyuk
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch adds support of the reverse continue operation for gdbstub.
Reverse continue finds the last breakpoint that would happen in normal
execution from the beginning to the current moment.
Implementation of the reverse continue replays the execution twice:
to find the breakpoints that were hit and to seek to the last breakpoint.
Reverse continue loads the previous snapshot and tries to find the breakpoint
since that moment. If there are no such breakpoints, it proceeds to
the earlier snapshot, and so on. When no breakpoints or watchpoints were
hit at all, execution stops at the beginning of the replay log.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
---
 exec.c                    |    1 +
 gdbstub.c                 |   10 ++++++
 include/sysemu/replay.h   |    8 +++++
 replay/replay-debugging.c |   71 +++++++++++++++++++++++++++++++++++++++++++++
 softmmu/cpus.c            |    5 +++
 stubs/replay.c            |    5 +++
 6 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/exec.c b/exec.c
index 10267f7ed0..dfe1a6d75f 100644
--- a/exec.c
+++ b/exec.c
@@ -2757,6 +2757,7 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
                  * Don't process the watchpoints when we are
                  * in a reverse debugging operation.
                  */
+                replay_breakpoint();
                 return;
             }
             if (flags == BP_MEM_READ) {
diff --git a/gdbstub.c b/gdbstub.c
index 79e8ccc050..ac92273018 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1907,6 +1907,13 @@ static void handle_backward(GdbCmdContext *gdb_ctx, void *user_ctx)
                 put_packet("E14");
             }
             return;
+        case 'c':
+            if (replay_reverse_continue()) {
+                gdb_continue();
+            } else {
+                put_packet("E14");
+            }
+            return;
         }
     }
 
@@ -2161,7 +2168,8 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
     }
 
     if (replay_mode == REPLAY_MODE_PLAY) {
-        g_string_append(gdbserver_state.str_buf, ";ReverseStep+");
+        g_string_append(gdbserver_state.str_buf,
+            ";ReverseStep+;ReverseContinue+");
     }
 
     if (gdb_ctx->num_params &&
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 13a8123b09..b6cac175c4 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -81,11 +81,19 @@ const char *replay_get_filename(void);
  * Returns true on success.
  */
 bool replay_reverse_step(void);
+/*
+ * Start searching the last breakpoint/watchpoint.
+ * Used by gdbstub for backwards debugging.
+ * Returns true if the process successfully started.
+ */
+bool replay_reverse_continue(void);
 /*
  * Returns true if replay module is processing
  * reverse_continue or reverse_step request
  */
 bool replay_running_debug(void);
+/* Called in reverse debugging mode to collect breakpoint information */
+void replay_breakpoint(void);
 
 /* Processing the instructions */
 
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index f7594a88cd..d02d4e0766 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -23,6 +23,8 @@
 #include "migration/snapshot.h"
 
 static bool replay_is_debugging;
+static int64_t replay_last_breakpoint;
+static int64_t replay_last_snapshot;
 
 bool replay_running_debug(void)
 {
@@ -245,3 +247,72 @@ bool replay_reverse_step(void)
 
     return false;
 }
+
+static void replay_continue_end(void)
+{
+    replay_is_debugging = false;
+    vm_stop(RUN_STATE_DEBUG);
+    replay_delete_break();
+}
+
+static void replay_continue_stop(void *opaque)
+{
+    Error *err = NULL;
+    if (replay_last_breakpoint != -1LL) {
+        replay_seek(replay_last_breakpoint, replay_stop_vm_debug, &err);
+        if (err) {
+            error_free(err);
+            replay_continue_end();
+        }
+        return;
+    }
+    /*
+     * No breakpoints since the last snapshot.
+     * Find previous snapshot and try again.
+     */
+    if (replay_last_snapshot != 0) {
+        replay_seek(replay_last_snapshot - 1, replay_continue_stop, &err);
+        if (err) {
+            error_free(err);
+            replay_continue_end();
+        }
+        replay_last_snapshot = replay_get_current_icount();
+        return;
+    } else {
+        /* Seek to the very first step */
+        replay_seek(0, replay_stop_vm_debug, &err);
+        if (err) {
+            error_free(err);
+            replay_continue_end();
+        }
+        return;
+    }
+    replay_continue_end();
+}
+
+bool replay_reverse_continue(void)
+{
+    Error *err = NULL;
+
+    assert(replay_mode == REPLAY_MODE_PLAY);
+
+    if (replay_get_current_icount() != 0) {
+        replay_seek(replay_get_current_icount() - 1, replay_continue_stop, &err);
+        if (err) {
+            error_free(err);
+            return false;
+        }
+        replay_last_breakpoint = -1LL;
+        replay_is_debugging = true;
+        replay_last_snapshot = replay_get_current_icount();
+        return true;
+    }
+
+    return false;
+}
+
+void replay_breakpoint(void)
+{
+    assert(replay_mode == REPLAY_MODE_PLAY);
+    replay_last_breakpoint = replay_get_current_icount();
+}
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index 1fa9c4c1de..8334dceab4 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -1006,6 +1006,11 @@ static void cpu_handle_guest_debug(CPUState *cpu)
 {
     if (replay_running_debug()) {
         if (!cpu->singlestep_enabled) {
+            /*
+             * Report about the breakpoint and
+             * make a single step to skip it
+             */
+            replay_breakpoint();
             cpu_single_step(cpu, SSTEP_ENABLE);
         } else {
             cpu_single_step(cpu, 0);
diff --git a/stubs/replay.c b/stubs/replay.c
index d5b52302e9..45ebe77fb9 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -98,3 +98,8 @@ bool replay_reverse_step(void)
 {
     return false;
 }
+
+bool replay_reverse_continue(void)
+{
+    return false;
+}



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

* [PATCH v6 12/14] replay: describe reverse debugging in docs/replay.txt
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (10 preceding siblings ...)
  2020-09-29 11:02 ` [PATCH v6 11/14] gdbstub: add reverse continue " Pavel Dovgalyuk
@ 2020-09-29 11:02 ` Pavel Dovgalyuk
  2020-09-29 11:02 ` [PATCH v6 13/14] replay: create temporary snapshot at debugger connection Pavel Dovgalyuk
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>

This patch updates the documentation and describes usage of the reverse
debugging in QEMU+GDB.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

--

v4 changes:
 - added an example of the command line for reverse debugging of
   the diskless machine
---
 docs/replay.txt |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/docs/replay.txt b/docs/replay.txt
index 70c27edb36..39fe5e9740 100644
--- a/docs/replay.txt
+++ b/docs/replay.txt
@@ -265,6 +265,16 @@ of the original disk image, use overlay files linked to the original images.
 Therefore all new snapshots (including the starting one) will be saved in
 overlays and the original image remains unchanged.
 
+When you need to use snapshots with diskless virtual machine,
+it must be started with 'orphan' qcow2 image. This image will be used
+for storing VM snapshots. Here is the example of the command line for this:
+
+  qemu-system-i386 -icount shift=3,rr=replay,rrfile=record.bin,rrsnapshot=init \
+    -net none -drive file=empty.qcow2,if=none,id=rr
+
+empty.qcow2 drive does not connected to any virtual block device and used
+for VM snapshots only.
+
 Network devices
 ---------------
 
@@ -294,6 +304,42 @@ for recording and replaying must contain identical number of ports in record
 and replay modes, but their backends may differ.
 E.g., '-serial stdio' in record mode, and '-serial null' in replay mode.
 
+Reverse debugging
+-----------------
+
+Reverse debugging allows "executing" the program in reverse direction.
+GDB remote protocol supports "reverse step" and "reverse continue"
+commands. The first one steps single instruction backwards in time,
+and the second one finds the last breakpoint in the past.
+
+Recorded executions may be used to enable reverse debugging. QEMU can't
+execute the code in backwards direction, but can load a snapshot and
+replay forward to find the desired position or breakpoint.
+
+The following GDB commands are supported:
+ - reverse-stepi (or rsi) - step one instruction backwards
+ - reverse-continue (or rc) - find last breakpoint in the past
+
+Reverse step loads the nearest snapshot and replays the execution until
+the required instruction is met.
+
+Reverse continue may include several passes of examining the execution
+between the snapshots. Each of the passes include the following steps:
+ 1. loading the snapshot
+ 2. replaying to examine the breakpoints
+ 3. if breakpoint or watchpoint was met
+    - loading the snaphot again
+    - replaying to the required breakpoint
+ 4. else
+    - proceeding to the p.1 with the earlier snapshot
+
+Therefore usage of the reverse debugging requires at least one snapshot
+created in advance. This can be done by omitting 'snapshot' option
+for the block drives and adding 'rrsnapshot' for both record and replay
+command lines.
+See the "Snapshotting" section to learn more about running record/replay
+and creating the snapshot in these modes.
+
 Replay log format
 -----------------
 



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

* [PATCH v6 13/14] replay: create temporary snapshot at debugger connection
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (11 preceding siblings ...)
  2020-09-29 11:02 ` [PATCH v6 12/14] replay: describe reverse debugging in docs/replay.txt Pavel Dovgalyuk
@ 2020-09-29 11:02 ` Pavel Dovgalyuk
  2020-09-29 11:02 ` [PATCH v6 14/14] tests/acceptance: add reverse debugging test Pavel Dovgalyuk
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

When record/replay does not uses overlays for storing the snapshots,
user is not capable of issuing reverse debugging commands.
This patch adds creation of the VM snapshot on the temporary
overlay image, when the debugger connects to QEMU.
Therefore the execution can be rewind to the moment
of the debugger connection while debugging the virtual machine.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>

--

v6:
 - dropped unused error processing (suggested by Philippe Mathieu-Daudé)
---
 gdbstub.c                 |    1 +
 include/sysemu/replay.h   |    2 ++
 replay/replay-debugging.c |   14 ++++++++++++++
 3 files changed, 17 insertions(+)

diff --git a/gdbstub.c b/gdbstub.c
index ac92273018..f19f98ab1a 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -3321,6 +3321,7 @@ static void gdb_chr_event(void *opaque, QEMUChrEvent event)
         s->g_cpu = s->c_cpu;
 
         vm_stop(RUN_STATE_PAUSED);
+        replay_gdb_attached();
         gdb_has_xml = false;
         break;
     default:
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index b6cac175c4..2aa34b8919 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -94,6 +94,8 @@ bool replay_reverse_continue(void);
 bool replay_running_debug(void);
 /* Called in reverse debugging mode to collect breakpoint information */
 void replay_breakpoint(void);
+/* Called when gdb is attached to gdbstub */
+void replay_gdb_attached(void);
 
 /* Processing the instructions */
 
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index d02d4e0766..a55715ba0a 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -316,3 +316,17 @@ void replay_breakpoint(void)
     assert(replay_mode == REPLAY_MODE_PLAY);
     replay_last_breakpoint = replay_get_current_icount();
 }
+
+void replay_gdb_attached(void)
+{
+    /*
+     * Create VM snapshot on temporary overlay to allow reverse
+     * debugging even if snapshots were not enabled.
+     */
+    if (replay_mode == REPLAY_MODE_PLAY
+        && !replay_snapshot) {
+        if (save_snapshot("start_debugging", NULL) != 0) {
+            /* Can't create the snapshot. Continue conventional debugging. */
+        }
+    }
+}



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

* [PATCH v6 14/14] tests/acceptance: add reverse debugging test
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (12 preceding siblings ...)
  2020-09-29 11:02 ` [PATCH v6 13/14] replay: create temporary snapshot at debugger connection Pavel Dovgalyuk
@ 2020-09-29 11:02 ` Pavel Dovgalyuk
  2020-09-29 22:15   ` Willian Rampazzo
  2020-09-29 15:51 ` [PATCH v6 00/14] Reverse debugging no-reply
  2020-10-02 15:39 ` Paolo Bonzini
  15 siblings, 1 reply; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-09-29 11:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, wrampazz, pavel.dovgalyuk, ehabkost, alex.bennee,
	mtosatti, armbru, mreitz, stefanha, crosa, pbonzini, philmd,
	zhiwei_liu, rth

From: Pavel Dovgalyuk <Pavel.Dovgaluk@gmail.com>

This is a test for GDB reverse debugging commands: reverse step and reverse continue.
Every test in this suite consists of two phases: record and replay.
Recording saves the execution of some instructions and makes an initial
VM snapshot to allow reverse execution.
Replay saves the order of the first instructions and then checks that they
are executed backwards in the correct order.
After that the execution is replayed to the end, and reverse continue
command is checked by setting several breakpoints, and asserting
that the execution is stopped at the last of them.

Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

--

v5:
 - disabled (as some other tests) when running on gitlab
   due to the unidentified timeout problem
---
 MAINTAINERS                           |    1 
 tests/acceptance/reverse_debugging.py |  208 +++++++++++++++++++++++++++++++++
 2 files changed, 209 insertions(+)
 create mode 100644 tests/acceptance/reverse_debugging.py

diff --git a/MAINTAINERS b/MAINTAINERS
index 7dcecb8653..b2cafc36ee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2672,6 +2672,7 @@ F: include/sysemu/replay.h
 F: docs/replay.txt
 F: stubs/replay.c
 F: tests/acceptance/replay_kernel.py
+F: tests/acceptance/reverse_debugging.py
 F: qapi/replay.json
 
 IOVA Tree
diff --git a/tests/acceptance/reverse_debugging.py b/tests/acceptance/reverse_debugging.py
new file mode 100644
index 0000000000..b72fdf6cdc
--- /dev/null
+++ b/tests/acceptance/reverse_debugging.py
@@ -0,0 +1,208 @@
+# Reverse debugging test
+#
+# Copyright (c) 2020 ISP RAS
+#
+# Author:
+#  Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later.  See the COPYING file in the top-level directory.
+import os
+import logging
+
+from avocado import skipIf
+from avocado_qemu import BUILD_DIR
+from avocado.utils import gdb
+from avocado.utils import process
+from avocado.utils.path import find_command
+from boot_linux_console import LinuxKernelTest
+
+class ReverseDebugging(LinuxKernelTest):
+    """
+    Test GDB reverse debugging commands: reverse step and reverse continue.
+    Recording saves the execution of some instructions and makes an initial
+    VM snapshot to allow reverse execution.
+    Replay saves the order of the first instructions and then checks that they
+    are executed backwards in the correct order.
+    After that the execution is replayed to the end, and reverse continue
+    command is checked by setting several breakpoints, and asserting
+    that the execution is stopped at the last of them.
+    """
+
+    timeout = 10
+    STEPS = 10
+    endian_is_le = True
+
+    def run_vm(self, record, shift, args, replay_path, image_path):
+        logger = logging.getLogger('replay')
+        vm = self.get_vm()
+        vm.set_console()
+        if record:
+            logger.info('recording the execution...')
+            mode = 'record'
+        else:
+            logger.info('replaying the execution...')
+            mode = 'replay'
+            vm.add_args('-s', '-S')
+        vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s,rrsnapshot=init' %
+                    (shift, mode, replay_path),
+                    '-net', 'none')
+        vm.add_args('-drive', 'file=%s,if=none' % image_path)
+        if args:
+            vm.add_args(*args)
+        vm.launch()
+        return vm
+
+    @staticmethod
+    def get_reg_le(g, reg):
+        res = g.cmd(b'p%x' % reg)
+        num = 0
+        for i in range(len(res))[-2::-2]:
+            num = 0x100 * num + int(res[i:i + 2], 16)
+        return num
+
+    @staticmethod
+    def get_reg_be(g, reg):
+        res = g.cmd(b'p%x' % reg)
+        return int(res, 16)
+
+    def get_reg(self, g, reg):
+        # value may be encoded in BE or LE order
+        if self.endian_is_le:
+            return self.get_reg_le(g, reg)
+        else:
+            return self.get_reg_be(g, reg)
+
+    def get_pc(self, g):
+        return self.get_reg(g, self.REG_PC)
+
+    def check_pc(self, g, addr):
+        pc = self.get_pc(g)
+        if pc != addr:
+            self.fail('Invalid PC (read %x instead of %x)' % (pc, addr))
+
+    @staticmethod
+    def gdb_step(g):
+        g.cmd(b's', b'T05thread:01;')
+
+    @staticmethod
+    def gdb_bstep(g):
+        g.cmd(b'bs', b'T05thread:01;')
+
+    @staticmethod
+    def vm_get_icount(vm):
+        return vm.qmp('query-replay')['return']['icount']
+
+    def reverse_debugging(self, shift=7, args=None):
+        logger = logging.getLogger('replay')
+
+        # create qcow2 for snapshots
+        logger.info('creating qcow2 image for VM snapshots')
+        image_path = os.path.join(self.workdir, 'disk.qcow2')
+        qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
+        if not os.path.exists(qemu_img):
+            qemu_img = find_command('qemu-img', False)
+        if qemu_img is False:
+            self.cancel('Could not find "qemu-img", which is required to '
+                        'create the temporary qcow2 image')
+        cmd = '%s create -f qcow2 %s 128M' % (qemu_img, image_path)
+        process.run(cmd)
+
+        replay_path = os.path.join(self.workdir, 'replay.bin')
+
+        # record the log
+        vm = self.run_vm(True, shift, args, replay_path, image_path)
+        while self.vm_get_icount(vm) <= self.STEPS:
+            pass
+        last_icount = self.vm_get_icount(vm)
+        vm.shutdown()
+
+        logger.info("recorded log with %s+ steps" % last_icount)
+
+        # replay and run debug commands
+        vm = self.run_vm(False, shift, args, replay_path, image_path)
+        logger.info('connecting to gdbstub')
+        g = gdb.GDBRemote('127.0.0.1', 1234, False, False)
+        g.connect()
+        r = g.cmd(b'qSupported')
+        if b'qXfer:features:read+' in r:
+            g.cmd(b'qXfer:features:read:target.xml:0,ffb')
+        if b'ReverseStep+' not in r:
+            self.fail('Reverse step is not supported by QEMU')
+        if b'ReverseContinue+' not in r:
+            self.fail('Reverse continue is not supported by QEMU')
+
+        logger.info('stepping forward')
+        steps = []
+        # record first instruction addresses
+        for _ in range(self.STEPS):
+            pc = self.get_pc(g)
+            logger.info('saving position %x' % pc)
+            steps.append(pc)
+            self.gdb_step(g)
+
+        # visit the recorded instruction in reverse order
+        logger.info('stepping backward')
+        for addr in steps[::-1]:
+            self.gdb_bstep(g)
+            self.check_pc(g, addr)
+            logger.info('found position %x' % addr)
+
+        logger.info('seeking to the end (icount %s)' % (last_icount - 1))
+        vm.qmp('replay-break', icount=last_icount - 1)
+        # continue - will return after pausing
+        g.cmd(b'c', b'T02thread:01;')
+
+        logger.info('setting breakpoints')
+        for addr in steps:
+            # hardware breakpoint at addr with len=1
+            g.cmd(b'Z1,%x,1' % addr, b'OK')
+
+        logger.info('running reverse continue to reach %x' % steps[-1])
+        # reverse continue - will return after stopping at the breakpoint
+        g.cmd(b'bc', b'T05thread:01;')
+
+        # assume that none of the first instructions is executed again
+        # breaking the order of the breakpoints
+        self.check_pc(g, steps[-1])
+        logger.info('successfully reached %x' % steps[-1])
+
+        logger.info('exitting gdb and qemu')
+        vm.shutdown()
+
+class ReverseDebugging_X86_64(ReverseDebugging):
+    REG_PC = 0x10
+    REG_CS = 0x12
+    def get_pc(self, g):
+        return self.get_reg_le(g, self.REG_PC) \
+            + self.get_reg_le(g, self.REG_CS) * 0x10
+
+    # unidentified gitlab timeout problem
+    @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
+    def test_x86_64_pc(self):
+        """
+        :avocado: tags=arch:x86_64
+        :avocado: tags=machine:pc
+        """
+        # start with BIOS only
+        self.reverse_debugging()
+
+class ReverseDebugging_AArch64(ReverseDebugging):
+    REG_PC = 32
+
+    # unidentified gitlab timeout problem
+    @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
+    def test_aarch64_virt(self):
+        """
+        :avocado: tags=arch:aarch64
+        :avocado: tags=machine:virt
+        :avocado: tags=cpu:cortex-a53
+        """
+        kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
+                      '/linux/releases/29/Everything/aarch64/os/images/pxeboot'
+                      '/vmlinuz')
+        kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493'
+        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
+
+        self.reverse_debugging(
+            args=('-kernel', kernel_path, '-cpu', 'cortex-a53'))



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

* Re: [PATCH v6 00/14] Reverse debugging
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (13 preceding siblings ...)
  2020-09-29 11:02 ` [PATCH v6 14/14] tests/acceptance: add reverse debugging test Pavel Dovgalyuk
@ 2020-09-29 15:51 ` no-reply
  2020-10-02 15:39 ` Paolo Bonzini
  15 siblings, 0 replies; 23+ messages in thread
From: no-reply @ 2020-09-29 15:51 UTC (permalink / raw)
  To: pavel.dovgalyuk
  Cc: kwolf, pavel.dovgalyuk, ehabkost, philmd, mtosatti, stefanha,
	qemu-devel, armbru, wrampazz, crosa, pbonzini, mreitz,
	alex.bennee, zhiwei_liu, rth

Patchew URL: https://patchew.org/QEMU/160137726426.31007.12061315974029139983.stgit@pasha-ThinkPad-X280/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 160137726426.31007.12061315974029139983.stgit@pasha-ThinkPad-X280
Subject: [PATCH v6 00/14] Reverse debugging

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Switched to a new branch 'test'
42ed9ff tests/acceptance: add reverse debugging test
9e6312b replay: create temporary snapshot at debugger connection
e5b95b0 replay: describe reverse debugging in docs/replay.txt
47c1dc5 gdbstub: add reverse continue support in replay mode
9f812ce gdbstub: add reverse step support in replay mode
47580b0 replay: flush rr queue before loading the vmstate
3a46821 replay: implement replay-seek command
333560c replay: introduce breakpoint at the specified step
912d979 replay: introduce info hmp/qmp command
f174f33 qapi: introduce replay.json for record/replay-related stuff
fa8bc32 migration: introduce icount field for snapshots
1785cc5 qcow2: introduce icount field for snapshots
5d53fea replay: provide an accessor for rr filename
84a429f replay: don't record interrupt poll

=== OUTPUT BEGIN ===
1/14 Checking commit 84a429fe86d2 (replay: don't record interrupt poll)
2/14 Checking commit 5d53feae3272 (replay: provide an accessor for rr filename)
3/14 Checking commit 1785cc5df6f7 (qcow2: introduce icount field for snapshots)
4/14 Checking commit fa8bc32691b4 (migration: introduce icount field for snapshots)
ERROR: trailing whitespace
#226: FILE: tests/qemu-iotests/267.out:37:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#237: FILE: tests/qemu-iotests/267.out:48:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#248: FILE: tests/qemu-iotests/267.out:73:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#259: FILE: tests/qemu-iotests/267.out:98:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#270: FILE: tests/qemu-iotests/267.out:109:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#281: FILE: tests/qemu-iotests/267.out:123:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#292: FILE: tests/qemu-iotests/267.out:138:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#303: FILE: tests/qemu-iotests/267.out:149:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#312: FILE: tests/qemu-iotests/267.out:156:
+1         snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#323: FILE: tests/qemu-iotests/267.out:170:
+--        snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#332: FILE: tests/qemu-iotests/267.out:177:
+1         snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

ERROR: trailing whitespace
#338: FILE: tests/qemu-iotests/267.out:181:
+1         snap0                SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000           $

total: 12 errors, 0 warnings, 259 lines checked

Patch 4/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

5/14 Checking commit f174f339f352 (qapi: introduce replay.json for record/replay-related stuff)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#93: 
new file mode 100644

total: 0 errors, 1 warnings, 78 lines checked

Patch 5/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
6/14 Checking commit 912d9793f5a5 (replay: introduce info hmp/qmp command)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#122: 
new file mode 100644

total: 0 errors, 1 warnings, 120 lines checked

Patch 6/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
7/14 Checking commit 333560c38d6a (replay: introduce breakpoint at the specified step)
8/14 Checking commit 3a46821e71ef (replay: implement replay-seek command)
9/14 Checking commit 47580b0a465e (replay: flush rr queue before loading the vmstate)
10/14 Checking commit 9f812ced7a0a (gdbstub: add reverse step support in replay mode)
WARNING: line over 80 characters
#220: FILE: replay/replay-debugging.c:237:
+        replay_seek(replay_get_current_icount() - 1, replay_stop_vm_debug, &err);

total: 0 errors, 1 warnings, 201 lines checked

Patch 10/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
11/14 Checking commit 47c1dc583443 (gdbstub: add reverse continue support in replay mode)
WARNING: line over 80 characters
#150: FILE: replay/replay-debugging.c:300:
+        replay_seek(replay_get_current_icount() - 1, replay_continue_stop, &err);

total: 0 errors, 1 warnings, 146 lines checked

Patch 11/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
12/14 Checking commit e5b95b028f0d (replay: describe reverse debugging in docs/replay.txt)
13/14 Checking commit 9e6312b2ec00 (replay: create temporary snapshot at debugger connection)
14/14 Checking commit 42ed9ffcae51 (tests/acceptance: add reverse debugging test)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#40: 
new file mode 100644

total: 0 errors, 1 warnings, 215 lines checked

Patch 14/14 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/160137726426.31007.12061315974029139983.stgit@pasha-ThinkPad-X280/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [PATCH v6 14/14] tests/acceptance: add reverse debugging test
  2020-09-29 11:02 ` [PATCH v6 14/14] tests/acceptance: add reverse debugging test Pavel Dovgalyuk
@ 2020-09-29 22:15   ` Willian Rampazzo
  0 siblings, 0 replies; 23+ messages in thread
From: Willian Rampazzo @ 2020-09-29 22:15 UTC (permalink / raw)
  To: Pavel Dovgalyuk
  Cc: Kevin Wolf, Eduardo Habkost, Alex Bennée, Marcelo Tosatti,
	qemu-devel, Markus Armbruster, Stefan Hajnoczi,
	Cleber Rosa Junior, Paolo Bonzini, Max Reitz,
	Philippe Mathieu Daude, zhiwei_liu, Richard Henderson

On Tue, Sep 29, 2020 at 8:02 AM Pavel Dovgalyuk
<pavel.dovgalyuk@ispras.ru> wrote:
>
> From: Pavel Dovgalyuk <Pavel.Dovgaluk@gmail.com>
>
> This is a test for GDB reverse debugging commands: reverse step and reverse continue.
> Every test in this suite consists of two phases: record and replay.
> Recording saves the execution of some instructions and makes an initial
> VM snapshot to allow reverse execution.
> Replay saves the order of the first instructions and then checks that they
> are executed backwards in the correct order.
> After that the execution is replayed to the end, and reverse continue
> command is checked by setting several breakpoints, and asserting
> that the execution is stopped at the last of them.
>
> Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>
> --
>
> v5:
>  - disabled (as some other tests) when running on gitlab
>    due to the unidentified timeout problem
> ---
>  MAINTAINERS                           |    1
>  tests/acceptance/reverse_debugging.py |  208 +++++++++++++++++++++++++++++++++
>  2 files changed, 209 insertions(+)
>  create mode 100644 tests/acceptance/reverse_debugging.py
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7dcecb8653..b2cafc36ee 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2672,6 +2672,7 @@ F: include/sysemu/replay.h
>  F: docs/replay.txt
>  F: stubs/replay.c
>  F: tests/acceptance/replay_kernel.py
> +F: tests/acceptance/reverse_debugging.py
>  F: qapi/replay.json
>
>  IOVA Tree
> diff --git a/tests/acceptance/reverse_debugging.py b/tests/acceptance/reverse_debugging.py
> new file mode 100644
> index 0000000000..b72fdf6cdc
> --- /dev/null
> +++ b/tests/acceptance/reverse_debugging.py
> @@ -0,0 +1,208 @@
> +# Reverse debugging test
> +#
> +# Copyright (c) 2020 ISP RAS
> +#
> +# Author:
> +#  Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
> +#
> +# This work is licensed under the terms of the GNU GPL, version 2 or
> +# later.  See the COPYING file in the top-level directory.
> +import os
> +import logging
> +
> +from avocado import skipIf
> +from avocado_qemu import BUILD_DIR
> +from avocado.utils import gdb
> +from avocado.utils import process
> +from avocado.utils.path import find_command
> +from boot_linux_console import LinuxKernelTest
> +
> +class ReverseDebugging(LinuxKernelTest):
> +    """
> +    Test GDB reverse debugging commands: reverse step and reverse continue.
> +    Recording saves the execution of some instructions and makes an initial
> +    VM snapshot to allow reverse execution.
> +    Replay saves the order of the first instructions and then checks that they
> +    are executed backwards in the correct order.
> +    After that the execution is replayed to the end, and reverse continue
> +    command is checked by setting several breakpoints, and asserting
> +    that the execution is stopped at the last of them.
> +    """
> +
> +    timeout = 10
> +    STEPS = 10
> +    endian_is_le = True
> +
> +    def run_vm(self, record, shift, args, replay_path, image_path):
> +        logger = logging.getLogger('replay')
> +        vm = self.get_vm()
> +        vm.set_console()
> +        if record:
> +            logger.info('recording the execution...')
> +            mode = 'record'
> +        else:
> +            logger.info('replaying the execution...')
> +            mode = 'replay'
> +            vm.add_args('-s', '-S')
> +        vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s,rrsnapshot=init' %
> +                    (shift, mode, replay_path),
> +                    '-net', 'none')
> +        vm.add_args('-drive', 'file=%s,if=none' % image_path)
> +        if args:
> +            vm.add_args(*args)
> +        vm.launch()
> +        return vm
> +
> +    @staticmethod
> +    def get_reg_le(g, reg):
> +        res = g.cmd(b'p%x' % reg)
> +        num = 0
> +        for i in range(len(res))[-2::-2]:
> +            num = 0x100 * num + int(res[i:i + 2], 16)
> +        return num
> +
> +    @staticmethod
> +    def get_reg_be(g, reg):
> +        res = g.cmd(b'p%x' % reg)
> +        return int(res, 16)
> +
> +    def get_reg(self, g, reg):
> +        # value may be encoded in BE or LE order
> +        if self.endian_is_le:
> +            return self.get_reg_le(g, reg)
> +        else:
> +            return self.get_reg_be(g, reg)
> +
> +    def get_pc(self, g):
> +        return self.get_reg(g, self.REG_PC)
> +
> +    def check_pc(self, g, addr):
> +        pc = self.get_pc(g)
> +        if pc != addr:
> +            self.fail('Invalid PC (read %x instead of %x)' % (pc, addr))
> +
> +    @staticmethod
> +    def gdb_step(g):
> +        g.cmd(b's', b'T05thread:01;')
> +
> +    @staticmethod
> +    def gdb_bstep(g):
> +        g.cmd(b'bs', b'T05thread:01;')
> +
> +    @staticmethod
> +    def vm_get_icount(vm):
> +        return vm.qmp('query-replay')['return']['icount']
> +
> +    def reverse_debugging(self, shift=7, args=None):
> +        logger = logging.getLogger('replay')
> +
> +        # create qcow2 for snapshots
> +        logger.info('creating qcow2 image for VM snapshots')
> +        image_path = os.path.join(self.workdir, 'disk.qcow2')
> +        qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
> +        if not os.path.exists(qemu_img):
> +            qemu_img = find_command('qemu-img', False)
> +        if qemu_img is False:
> +            self.cancel('Could not find "qemu-img", which is required to '
> +                        'create the temporary qcow2 image')
> +        cmd = '%s create -f qcow2 %s 128M' % (qemu_img, image_path)
> +        process.run(cmd)
> +
> +        replay_path = os.path.join(self.workdir, 'replay.bin')
> +
> +        # record the log
> +        vm = self.run_vm(True, shift, args, replay_path, image_path)
> +        while self.vm_get_icount(vm) <= self.STEPS:
> +            pass
> +        last_icount = self.vm_get_icount(vm)
> +        vm.shutdown()
> +
> +        logger.info("recorded log with %s+ steps" % last_icount)
> +
> +        # replay and run debug commands
> +        vm = self.run_vm(False, shift, args, replay_path, image_path)
> +        logger.info('connecting to gdbstub')
> +        g = gdb.GDBRemote('127.0.0.1', 1234, False, False)
> +        g.connect()
> +        r = g.cmd(b'qSupported')
> +        if b'qXfer:features:read+' in r:
> +            g.cmd(b'qXfer:features:read:target.xml:0,ffb')
> +        if b'ReverseStep+' not in r:
> +            self.fail('Reverse step is not supported by QEMU')
> +        if b'ReverseContinue+' not in r:
> +            self.fail('Reverse continue is not supported by QEMU')
> +
> +        logger.info('stepping forward')
> +        steps = []
> +        # record first instruction addresses
> +        for _ in range(self.STEPS):
> +            pc = self.get_pc(g)
> +            logger.info('saving position %x' % pc)
> +            steps.append(pc)
> +            self.gdb_step(g)
> +
> +        # visit the recorded instruction in reverse order
> +        logger.info('stepping backward')
> +        for addr in steps[::-1]:
> +            self.gdb_bstep(g)
> +            self.check_pc(g, addr)
> +            logger.info('found position %x' % addr)
> +
> +        logger.info('seeking to the end (icount %s)' % (last_icount - 1))
> +        vm.qmp('replay-break', icount=last_icount - 1)
> +        # continue - will return after pausing
> +        g.cmd(b'c', b'T02thread:01;')
> +
> +        logger.info('setting breakpoints')
> +        for addr in steps:
> +            # hardware breakpoint at addr with len=1
> +            g.cmd(b'Z1,%x,1' % addr, b'OK')
> +
> +        logger.info('running reverse continue to reach %x' % steps[-1])
> +        # reverse continue - will return after stopping at the breakpoint
> +        g.cmd(b'bc', b'T05thread:01;')
> +
> +        # assume that none of the first instructions is executed again
> +        # breaking the order of the breakpoints
> +        self.check_pc(g, steps[-1])
> +        logger.info('successfully reached %x' % steps[-1])
> +
> +        logger.info('exitting gdb and qemu')
> +        vm.shutdown()
> +
> +class ReverseDebugging_X86_64(ReverseDebugging):
> +    REG_PC = 0x10
> +    REG_CS = 0x12
> +    def get_pc(self, g):
> +        return self.get_reg_le(g, self.REG_PC) \
> +            + self.get_reg_le(g, self.REG_CS) * 0x10
> +
> +    # unidentified gitlab timeout problem
> +    @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
> +    def test_x86_64_pc(self):
> +        """
> +        :avocado: tags=arch:x86_64
> +        :avocado: tags=machine:pc
> +        """
> +        # start with BIOS only
> +        self.reverse_debugging()
> +
> +class ReverseDebugging_AArch64(ReverseDebugging):
> +    REG_PC = 32
> +
> +    # unidentified gitlab timeout problem
> +    @skipIf(os.getenv('GITLAB_CI'), 'Running on GitLab')
> +    def test_aarch64_virt(self):
> +        """
> +        :avocado: tags=arch:aarch64
> +        :avocado: tags=machine:virt
> +        :avocado: tags=cpu:cortex-a53
> +        """
> +        kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
> +                      '/linux/releases/29/Everything/aarch64/os/images/pxeboot'
> +                      '/vmlinuz')
> +        kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493'
> +        kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
> +
> +        self.reverse_debugging(
> +            args=('-kernel', kernel_path, '-cpu', 'cortex-a53'))
>

The code looks good to me!

Reviewed-by: Willian Rampazzo <willianr@redhat.com>



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

* Re: [PATCH v6 05/14] qapi: introduce replay.json for record/replay-related stuff
  2020-09-29 11:01 ` [PATCH v6 05/14] qapi: introduce replay.json for record/replay-related stuff Pavel Dovgalyuk
@ 2020-10-01 11:00   ` Alex Bennée
  0 siblings, 0 replies; 23+ messages in thread
From: Alex Bennée @ 2020-10-01 11:00 UTC (permalink / raw)
  To: Pavel Dovgalyuk
  Cc: kwolf, wrampazz, ehabkost, mtosatti, qemu-devel, armbru,
	stefanha, crosa, pbonzini, mreitz, philmd, zhiwei_liu, rth


Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru> writes:

> From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
>
> This patch adds replay.json file. It will be
> used for adding record/replay-related data structures and commands.
>
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
> Reviewed-by: Markus Armbruster <armbru@redhat.com>
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>

Just to note there are now some minor conflicts in qapi/misc.json and
meson.build which meant this didn't apply cleanly.

-- 
Alex Bennée


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

* Re: [PATCH v6 03/14] qcow2: introduce icount field for snapshots
  2020-09-29 11:01 ` [PATCH v6 03/14] qcow2: introduce icount field for snapshots Pavel Dovgalyuk
@ 2020-10-01 12:53   ` Alex Bennée
  0 siblings, 0 replies; 23+ messages in thread
From: Alex Bennée @ 2020-10-01 12:53 UTC (permalink / raw)
  To: Pavel Dovgalyuk
  Cc: kwolf, wrampazz, ehabkost, mtosatti, qemu-devel, armbru,
	stefanha, crosa, pbonzini, mreitz, philmd, zhiwei_liu, rth


Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru> writes:

> From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
>
> This patch introduces the icount field for saving within the snapshot.
> It is required for navigation between the snapshots in record/replay mode.
>
> Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgalyuk@ispras.ru>
> Acked-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block/qcow2-snapshot.c |    7 +++++++
>  block/qcow2.h          |    3 +++
>  docs/interop/qcow2.txt |    5 +++++
>  3 files changed, 15 insertions(+)
>
> diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
> index 9b68690f56..d68b25e0c5 100644
> --- a/block/qcow2-snapshot.c
> +++ b/block/qcow2-snapshot.c
> @@ -164,6 +164,12 @@ static int qcow2_do_read_snapshots(BlockDriverState *bs, bool repair,
>              sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
>          }
>  
> +        if (sn->extra_data_size >= endof(QCowSnapshotExtraData, icount)) {
> +            sn->icount = be64_to_cpu(extra.icount);
> +        } else {
> +            sn->icount = -1ULL;
> +        }
> +
>          if (sn->extra_data_size > sizeof(extra)) {
>              uint64_t extra_data_end;
>              size_t unknown_extra_data_size;
> @@ -333,6 +339,7 @@ int qcow2_write_snapshots(BlockDriverState *bs)
>          memset(&extra, 0, sizeof(extra));
>          extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
>          extra.disk_size = cpu_to_be64(sn->disk_size);
> +        extra.icount = cpu_to_be64(sn->icount);
>  
>          id_str_size = strlen(sn->id_str);
>          name_size = strlen(sn->name);
> diff --git a/block/qcow2.h b/block/qcow2.h
> index b71e444fca..125ea9679b 100644
> --- a/block/qcow2.h
> +++ b/block/qcow2.h
> @@ -206,6 +206,7 @@ typedef struct QEMU_PACKED QCowSnapshotHeader {
>  typedef struct QEMU_PACKED QCowSnapshotExtraData {
>      uint64_t vm_state_size_large;
>      uint64_t disk_size;
> +    uint64_t icount;
>  } QCowSnapshotExtraData;
>  
>  
> @@ -219,6 +220,8 @@ typedef struct QCowSnapshot {
>      uint32_t date_sec;
>      uint32_t date_nsec;
>      uint64_t vm_clock_nsec;
> +    /* icount value for the moment when snapshot was taken */
> +    uint64_t icount;
>      /* Size of all extra data, including QCowSnapshotExtraData if available */
>      uint32_t extra_data_size;
>      /* Data beyond QCowSnapshotExtraData, if any */
> diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
> index 7da0d81df8..0463f761ef 100644
> --- a/docs/interop/qcow2.txt
> +++ b/docs/interop/qcow2.txt
> @@ -707,6 +707,11 @@ Snapshot table entry:
>  
>                      Byte 48 - 55:   Virtual disk size of the snapshot in bytes
>  
> +                    Byte 56 - 63:   icount value which corresponds to
> +                                    the record/replay instruction count
> +                                    when the snapshot was taken. Set to -1
> +                                    if icount was disabled
> +
>                      Version 3 images must include extra data at least up to
>                      byte 55.
>  

Hmm is this why I'm seeing some of the iotests fail on the CI:

261      fail       [11:34:17] [11:34:44]                    output mismatch (see 261.out.bad)
--- /builds/stsquad/qemu/tests/qemu-iotests/261.out	2020-10-01 11:16:22.000000000 +0000
+++ /builds/stsquad/qemu/build/tests/qemu-iotests/261.out.bad	2020-10-01 11:34:44.000000000 +0000
@@ -29,9 +29,10 @@
   [0]
     ID: 1
     Name: sn0
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
   [1]
     ID: 2
     Name: sn1
@@ -42,9 +43,10 @@
   [2]
     ID: 3
     Name: sn2
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
 
 === Repair botched v3 ===
 
@@ -61,9 +63,10 @@
   [0]
     ID: 1
     Name: sn0
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
   [1]
     ID: 2
     Name: sn1
@@ -74,9 +77,10 @@
   [2]
     ID: 3
     Name: sn2
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
 
 === Add new snapshot ===
 
@@ -85,9 +89,10 @@
   [0]
     ID: 1
     Name: sn0
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
   [1]
     ID: 2
     Name: sn1
@@ -98,15 +103,17 @@
   [2]
     ID: 3
     Name: sn2
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
   [3]
     ID: 4
     Name: sn3
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: 
 
 === Remove different snapshots ===
 
@@ -123,9 +130,10 @@
   [1]
     ID: 3
     Name: sn2
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
 
 --- sn1 ---
 No errors were found on the image.
@@ -133,15 +141,17 @@
   [0]
     ID: 1
     Name: sn0
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
   [1]
     ID: 3
     Name: sn2
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
 
 --- sn2 ---
 No errors were found on the image.
@@ -149,9 +159,10 @@
   [0]
     ID: 1
     Name: sn0
-    Extra data size: 16
+    Extra data size: 24
     VM state size: 0
     Disk size: 67108864
+    Unknown extra data: ��������
   [1]
     ID: 2
     Name: sn1
@@ -210,7 +221,7 @@
 No errors were found on the image.
 
 507 snapshots should remain:
-  qemu-img info reports 507 snapshots
+  qemu-img info reports 0 snapshots
   Image header reports 507 snapshots
 
 === Snapshot table too big with one entry with too much extra data ===
@@ -341,6 +352,6 @@
 No errors were found on the image.
 
 65536 snapshots should remain:
-  qemu-img info reports 65536 snapshots
+  qemu-img info reports 0 snapshots
   Image header reports 65536 snapshots
 *** done


-- 
Alex Bennée


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

* Re: [PATCH v6 00/14] Reverse debugging
  2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
                   ` (14 preceding siblings ...)
  2020-09-29 15:51 ` [PATCH v6 00/14] Reverse debugging no-reply
@ 2020-10-02 15:39 ` Paolo Bonzini
  2020-10-02 16:01   ` Pavel Dovgalyuk
                     ` (2 more replies)
  15 siblings, 3 replies; 23+ messages in thread
From: Paolo Bonzini @ 2020-10-02 15:39 UTC (permalink / raw)
  To: Pavel Dovgalyuk, qemu-devel
  Cc: kwolf, ehabkost, philmd, mtosatti, stefanha, armbru, mreitz,
	wrampazz, crosa, alex.bennee, zhiwei_liu, rth

On 29/09/20 13:01, Pavel Dovgalyuk wrote:
> GDB remote protocol supports reverse debugging of the targets.
> It includes 'reverse step' and 'reverse continue' operations.
> The first one finds the previous step of the execution,
> and the second one is intended to stop at the last breakpoint that
> would happen when the program is executed normally.
> 
> Reverse debugging is possible in the replay mode, when at least
> one snapshot was created at the record or replay phase.
> QEMU can use these snapshots for travelling back in time with GDB.
> 
> Running the execution in replay mode allows using GDB reverse debugging
> commands:
>  - reverse-stepi (or rsi): Steps one instruction to the past.
>    QEMU loads on of the prior snapshots and proceeds to the desired
>    instruction forward. When that step is reaches, execution stops.
>  - reverse-continue (or rc): Runs execution "backwards".
>    QEMU tries to find breakpoint or watchpoint by loaded prior snapshot
>    and replaying the execution. Then QEMU loads snapshots again and
>    replays to the latest breakpoint. When there are no breakpoints in
>    the examined section of the execution, QEMU finds one more snapshot
>    and tries again. After the first snapshot is processed, execution
>    stops at this snapshot.
> 
> The set of patches include the following modifications:
>  - gdbstub update for reverse debugging support
>  - functions that automatically perform reverse step and reverse
>    continue operations
>  - hmp/qmp commands for manipulating the replay process
>  - improvement of the snapshotting for saving the execution step
>    in the snapshot parameters
>  - avocado-based acceptance tests for reverse debugging
> 
> The patches are available in the repository:
> https://github.com/ispras/qemu/tree/rr-200901

Hi Pavel,

I'm still seeing failures in "make check-block":

https://gitlab.com/bonzini/qemu/-/jobs/769653852

Paolo

> v6 changes:
>  - removed passing err variable without checking it's value after
> v5 changes:
>  - disabled reverse debugging tests for gitlab-based testing
>    due to the unidentified timeout problem
> v4 changes:
>  - added VM snapshot creation on gdb connect (suggested by Alex Bennée)
>  - removed useless calls to error_free
>  - updated poll interrupt processing
>  - minor changes
> v3 changes:
>  - rebased to support the new build system
>  - bumped avocado framework version for using fixed remote gdb client
> v2 changes:
>  - rebased to the latest upstream version
>  - fixed replaying of the POLL interrupts after the latest debug changes
> 
> ---
> 
> Pavel Dovgaluk (11):
>       replay: provide an accessor for rr filename
>       qcow2: introduce icount field for snapshots
>       qapi: introduce replay.json for record/replay-related stuff
>       replay: introduce info hmp/qmp command
>       replay: introduce breakpoint at the specified step
>       replay: implement replay-seek command
>       replay: flush rr queue before loading the vmstate
>       gdbstub: add reverse step support in replay mode
>       gdbstub: add reverse continue support in replay mode
>       replay: describe reverse debugging in docs/replay.txt
>       tests/acceptance: add reverse debugging test
> 
> Pavel Dovgalyuk (3):
>       replay: don't record interrupt poll
>       migration: introduce icount field for snapshots
>       replay: create temporary snapshot at debugger connection
> 
> 
>  MAINTAINERS                           |    2 
>  accel/tcg/cpu-exec.c                  |   21 ++
>  accel/tcg/translator.c                |    1 
>  block/qapi.c                          |   18 +-
>  block/qcow2-snapshot.c                |    9 +
>  block/qcow2.h                         |    3 
>  blockdev.c                            |   10 +
>  docs/interop/qcow2.txt                |    5 
>  docs/replay.txt                       |   46 +++++
>  exec.c                                |    8 +
>  gdbstub.c                             |   64 ++++++
>  hmp-commands-info.hx                  |   11 +
>  hmp-commands.hx                       |   50 +++++
>  include/block/snapshot.h              |    1 
>  include/monitor/hmp.h                 |    4 
>  include/sysemu/replay.h               |   26 +++
>  migration/savevm.c                    |   17 +-
>  qapi/block-core.json                  |   11 +
>  qapi/meson.build                      |    1 
>  qapi/misc.json                        |   18 --
>  qapi/qapi-schema.json                 |    1 
>  qapi/replay.json                      |  121 ++++++++++++
>  replay/meson.build                    |    1 
>  replay/replay-debugging.c             |  332 +++++++++++++++++++++++++++++++++
>  replay/replay-events.c                |    4 
>  replay/replay-internal.h              |    6 -
>  replay/replay.c                       |   22 ++
>  softmmu/cpus.c                        |   19 ++
>  stubs/replay.c                        |   15 +
>  tests/acceptance/reverse_debugging.py |  208 +++++++++++++++++++++
>  tests/qemu-iotests/267.out            |   48 ++---
>  31 files changed, 1039 insertions(+), 64 deletions(-)
>  create mode 100644 qapi/replay.json
>  create mode 100644 replay/replay-debugging.c
>  create mode 100644 tests/acceptance/reverse_debugging.py
> 
> --
> Pavel Dovgalyuk
> 



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

* Re: [PATCH v6 00/14] Reverse debugging
  2020-10-02 15:39 ` Paolo Bonzini
@ 2020-10-02 16:01   ` Pavel Dovgalyuk
  2020-10-02 16:25   ` Pavel Dovgalyuk
  2020-10-03 17:19   ` Pavel Dovgalyuk
  2 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-10-02 16:01 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: kwolf, ehabkost, philmd, mtosatti, stefanha, armbru, mreitz,
	wrampazz, crosa, alex.bennee, zhiwei_liu, rth

On 02.10.2020 18:39, Paolo Bonzini wrote:
> On 29/09/20 13:01, Pavel Dovgalyuk wrote:
>> GDB remote protocol supports reverse debugging of the targets.
>> It includes 'reverse step' and 'reverse continue' operations.
>> The first one finds the previous step of the execution,
>> and the second one is intended to stop at the last breakpoint that
>> would happen when the program is executed normally.
>>
>> Reverse debugging is possible in the replay mode, when at least
>> one snapshot was created at the record or replay phase.
>> QEMU can use these snapshots for travelling back in time with GDB.
>>
>> Running the execution in replay mode allows using GDB reverse debugging
>> commands:
>>   - reverse-stepi (or rsi): Steps one instruction to the past.
>>     QEMU loads on of the prior snapshots and proceeds to the desired
>>     instruction forward. When that step is reaches, execution stops.
>>   - reverse-continue (or rc): Runs execution "backwards".
>>     QEMU tries to find breakpoint or watchpoint by loaded prior snapshot
>>     and replaying the execution. Then QEMU loads snapshots again and
>>     replays to the latest breakpoint. When there are no breakpoints in
>>     the examined section of the execution, QEMU finds one more snapshot
>>     and tries again. After the first snapshot is processed, execution
>>     stops at this snapshot.
>>
>> The set of patches include the following modifications:
>>   - gdbstub update for reverse debugging support
>>   - functions that automatically perform reverse step and reverse
>>     continue operations
>>   - hmp/qmp commands for manipulating the replay process
>>   - improvement of the snapshotting for saving the execution step
>>     in the snapshot parameters
>>   - avocado-based acceptance tests for reverse debugging
>>
>> The patches are available in the repository:
>> https://github.com/ispras/qemu/tree/rr-200901
> 
> Hi Pavel,
> 
> I'm still seeing failures in "make check-block":
> 
> https://gitlab.com/bonzini/qemu/-/jobs/769653852

I saw a message from Alex about it, but I don't see any errors when run 
'make check' myself. Could it be caused by new patches that also were 
added to your branch?

It seems, that some 'valid' test output should be updated, because 
patches changed the qcow2 snapshot extra data size.


> 
> Paolo
> 
>> v6 changes:
>>   - removed passing err variable without checking it's value after
>> v5 changes:
>>   - disabled reverse debugging tests for gitlab-based testing
>>     due to the unidentified timeout problem
>> v4 changes:
>>   - added VM snapshot creation on gdb connect (suggested by Alex Bennée)
>>   - removed useless calls to error_free
>>   - updated poll interrupt processing
>>   - minor changes
>> v3 changes:
>>   - rebased to support the new build system
>>   - bumped avocado framework version for using fixed remote gdb client
>> v2 changes:
>>   - rebased to the latest upstream version
>>   - fixed replaying of the POLL interrupts after the latest debug changes
>>
>> ---
>>
>> Pavel Dovgaluk (11):
>>        replay: provide an accessor for rr filename
>>        qcow2: introduce icount field for snapshots
>>        qapi: introduce replay.json for record/replay-related stuff
>>        replay: introduce info hmp/qmp command
>>        replay: introduce breakpoint at the specified step
>>        replay: implement replay-seek command
>>        replay: flush rr queue before loading the vmstate
>>        gdbstub: add reverse step support in replay mode
>>        gdbstub: add reverse continue support in replay mode
>>        replay: describe reverse debugging in docs/replay.txt
>>        tests/acceptance: add reverse debugging test
>>
>> Pavel Dovgalyuk (3):
>>        replay: don't record interrupt poll
>>        migration: introduce icount field for snapshots
>>        replay: create temporary snapshot at debugger connection
>>
>>
>>   MAINTAINERS                           |    2
>>   accel/tcg/cpu-exec.c                  |   21 ++
>>   accel/tcg/translator.c                |    1
>>   block/qapi.c                          |   18 +-
>>   block/qcow2-snapshot.c                |    9 +
>>   block/qcow2.h                         |    3
>>   blockdev.c                            |   10 +
>>   docs/interop/qcow2.txt                |    5
>>   docs/replay.txt                       |   46 +++++
>>   exec.c                                |    8 +
>>   gdbstub.c                             |   64 ++++++
>>   hmp-commands-info.hx                  |   11 +
>>   hmp-commands.hx                       |   50 +++++
>>   include/block/snapshot.h              |    1
>>   include/monitor/hmp.h                 |    4
>>   include/sysemu/replay.h               |   26 +++
>>   migration/savevm.c                    |   17 +-
>>   qapi/block-core.json                  |   11 +
>>   qapi/meson.build                      |    1
>>   qapi/misc.json                        |   18 --
>>   qapi/qapi-schema.json                 |    1
>>   qapi/replay.json                      |  121 ++++++++++++
>>   replay/meson.build                    |    1
>>   replay/replay-debugging.c             |  332 +++++++++++++++++++++++++++++++++
>>   replay/replay-events.c                |    4
>>   replay/replay-internal.h              |    6 -
>>   replay/replay.c                       |   22 ++
>>   softmmu/cpus.c                        |   19 ++
>>   stubs/replay.c                        |   15 +
>>   tests/acceptance/reverse_debugging.py |  208 +++++++++++++++++++++
>>   tests/qemu-iotests/267.out            |   48 ++---
>>   31 files changed, 1039 insertions(+), 64 deletions(-)
>>   create mode 100644 qapi/replay.json
>>   create mode 100644 replay/replay-debugging.c
>>   create mode 100644 tests/acceptance/reverse_debugging.py
>>
>> --
>> Pavel Dovgalyuk
>>
> 



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

* Re: [PATCH v6 00/14] Reverse debugging
  2020-10-02 15:39 ` Paolo Bonzini
  2020-10-02 16:01   ` Pavel Dovgalyuk
@ 2020-10-02 16:25   ` Pavel Dovgalyuk
  2020-10-03 17:19   ` Pavel Dovgalyuk
  2 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-10-02 16:25 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: kwolf, ehabkost, philmd, mtosatti, stefanha, armbru, mreitz,
	wrampazz, crosa, alex.bennee, zhiwei_liu, rth

On 02.10.2020 18:39, Paolo Bonzini wrote:
> On 29/09/20 13:01, Pavel Dovgalyuk wrote:
>> GDB remote protocol supports reverse debugging of the targets.
>> It includes 'reverse step' and 'reverse continue' operations.
>> The first one finds the previous step of the execution,
>> and the second one is intended to stop at the last breakpoint that
>> would happen when the program is executed normally.
>>
>> Reverse debugging is possible in the replay mode, when at least
>> one snapshot was created at the record or replay phase.
>> QEMU can use these snapshots for travelling back in time with GDB.
>>
>> Running the execution in replay mode allows using GDB reverse debugging
>> commands:
>>   - reverse-stepi (or rsi): Steps one instruction to the past.
>>     QEMU loads on of the prior snapshots and proceeds to the desired
>>     instruction forward. When that step is reaches, execution stops.
>>   - reverse-continue (or rc): Runs execution "backwards".
>>     QEMU tries to find breakpoint or watchpoint by loaded prior snapshot
>>     and replaying the execution. Then QEMU loads snapshots again and
>>     replays to the latest breakpoint. When there are no breakpoints in
>>     the examined section of the execution, QEMU finds one more snapshot
>>     and tries again. After the first snapshot is processed, execution
>>     stops at this snapshot.
>>
>> The set of patches include the following modifications:
>>   - gdbstub update for reverse debugging support
>>   - functions that automatically perform reverse step and reverse
>>     continue operations
>>   - hmp/qmp commands for manipulating the replay process
>>   - improvement of the snapshotting for saving the execution step
>>     in the snapshot parameters
>>   - avocado-based acceptance tests for reverse debugging
>>
>> The patches are available in the repository:
>> https://github.com/ispras/qemu/tree/rr-200901
> 
> Hi Pavel,
> 
> I'm still seeing failures in "make check-block":
> 
> https://gitlab.com/bonzini/qemu/-/jobs/769653852

Ok, now I can reproduce it with manually running 'check -qcow2 261'.
I'll send a patch soon.

> 
> Paolo
> 
>> v6 changes:
>>   - removed passing err variable without checking it's value after
>> v5 changes:
>>   - disabled reverse debugging tests for gitlab-based testing
>>     due to the unidentified timeout problem
>> v4 changes:
>>   - added VM snapshot creation on gdb connect (suggested by Alex Bennée)
>>   - removed useless calls to error_free
>>   - updated poll interrupt processing
>>   - minor changes
>> v3 changes:
>>   - rebased to support the new build system
>>   - bumped avocado framework version for using fixed remote gdb client
>> v2 changes:
>>   - rebased to the latest upstream version
>>   - fixed replaying of the POLL interrupts after the latest debug changes
>>
>> ---
>>
>> Pavel Dovgaluk (11):
>>        replay: provide an accessor for rr filename
>>        qcow2: introduce icount field for snapshots
>>        qapi: introduce replay.json for record/replay-related stuff
>>        replay: introduce info hmp/qmp command
>>        replay: introduce breakpoint at the specified step
>>        replay: implement replay-seek command
>>        replay: flush rr queue before loading the vmstate
>>        gdbstub: add reverse step support in replay mode
>>        gdbstub: add reverse continue support in replay mode
>>        replay: describe reverse debugging in docs/replay.txt
>>        tests/acceptance: add reverse debugging test
>>
>> Pavel Dovgalyuk (3):
>>        replay: don't record interrupt poll
>>        migration: introduce icount field for snapshots
>>        replay: create temporary snapshot at debugger connection
>>
>>
>>   MAINTAINERS                           |    2
>>   accel/tcg/cpu-exec.c                  |   21 ++
>>   accel/tcg/translator.c                |    1
>>   block/qapi.c                          |   18 +-
>>   block/qcow2-snapshot.c                |    9 +
>>   block/qcow2.h                         |    3
>>   blockdev.c                            |   10 +
>>   docs/interop/qcow2.txt                |    5
>>   docs/replay.txt                       |   46 +++++
>>   exec.c                                |    8 +
>>   gdbstub.c                             |   64 ++++++
>>   hmp-commands-info.hx                  |   11 +
>>   hmp-commands.hx                       |   50 +++++
>>   include/block/snapshot.h              |    1
>>   include/monitor/hmp.h                 |    4
>>   include/sysemu/replay.h               |   26 +++
>>   migration/savevm.c                    |   17 +-
>>   qapi/block-core.json                  |   11 +
>>   qapi/meson.build                      |    1
>>   qapi/misc.json                        |   18 --
>>   qapi/qapi-schema.json                 |    1
>>   qapi/replay.json                      |  121 ++++++++++++
>>   replay/meson.build                    |    1
>>   replay/replay-debugging.c             |  332 +++++++++++++++++++++++++++++++++
>>   replay/replay-events.c                |    4
>>   replay/replay-internal.h              |    6 -
>>   replay/replay.c                       |   22 ++
>>   softmmu/cpus.c                        |   19 ++
>>   stubs/replay.c                        |   15 +
>>   tests/acceptance/reverse_debugging.py |  208 +++++++++++++++++++++
>>   tests/qemu-iotests/267.out            |   48 ++---
>>   31 files changed, 1039 insertions(+), 64 deletions(-)
>>   create mode 100644 qapi/replay.json
>>   create mode 100644 replay/replay-debugging.c
>>   create mode 100644 tests/acceptance/reverse_debugging.py
>>
>> --
>> Pavel Dovgalyuk
>>
> 



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

* Re: [PATCH v6 00/14] Reverse debugging
  2020-10-02 15:39 ` Paolo Bonzini
  2020-10-02 16:01   ` Pavel Dovgalyuk
  2020-10-02 16:25   ` Pavel Dovgalyuk
@ 2020-10-03 17:19   ` Pavel Dovgalyuk
  2 siblings, 0 replies; 23+ messages in thread
From: Pavel Dovgalyuk @ 2020-10-03 17:19 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel
  Cc: kwolf, ehabkost, philmd, mtosatti, stefanha, armbru, mreitz,
	wrampazz, crosa, alex.bennee, zhiwei_liu, rth

On 02.10.2020 18:39, Paolo Bonzini wrote:
> On 29/09/20 13:01, Pavel Dovgalyuk wrote:
>> GDB remote protocol supports reverse debugging of the targets.
>> It includes 'reverse step' and 'reverse continue' operations.
>> The first one finds the previous step of the execution,
>> and the second one is intended to stop at the last breakpoint that
>> would happen when the program is executed normally.
>>
>> Reverse debugging is possible in the replay mode, when at least
>> one snapshot was created at the record or replay phase.
>> QEMU can use these snapshots for travelling back in time with GDB.
>>
>> Running the execution in replay mode allows using GDB reverse debugging
>> commands:
>>   - reverse-stepi (or rsi): Steps one instruction to the past.
>>     QEMU loads on of the prior snapshots and proceeds to the desired
>>     instruction forward. When that step is reaches, execution stops.
>>   - reverse-continue (or rc): Runs execution "backwards".
>>     QEMU tries to find breakpoint or watchpoint by loaded prior snapshot
>>     and replaying the execution. Then QEMU loads snapshots again and
>>     replays to the latest breakpoint. When there are no breakpoints in
>>     the examined section of the execution, QEMU finds one more snapshot
>>     and tries again. After the first snapshot is processed, execution
>>     stops at this snapshot.
>>
>> The set of patches include the following modifications:
>>   - gdbstub update for reverse debugging support
>>   - functions that automatically perform reverse step and reverse
>>     continue operations
>>   - hmp/qmp commands for manipulating the replay process
>>   - improvement of the snapshotting for saving the execution step
>>     in the snapshot parameters
>>   - avocado-based acceptance tests for reverse debugging
>>
>> The patches are available in the repository:
>> https://github.com/ispras/qemu/tree/rr-200901
> 
> Hi Pavel,
> 
> I'm still seeing failures in "make check-block":
> 
> https://gitlab.com/bonzini/qemu/-/jobs/769653852

Please, find the new version.
The patches 3 and 4 were updated.

However, is there any reason that not all the tests are executed?
I ran 'check -qcow2' without list of the tests, and encountered some 
problems with test 286 (that are fixed now).
But this test was not executed in your gitlab repository and with 'make 
check' on my local machine.

> 
> Paolo
> 
>> v6 changes:
>>   - removed passing err variable without checking it's value after
>> v5 changes:
>>   - disabled reverse debugging tests for gitlab-based testing
>>     due to the unidentified timeout problem
>> v4 changes:
>>   - added VM snapshot creation on gdb connect (suggested by Alex Bennée)
>>   - removed useless calls to error_free
>>   - updated poll interrupt processing
>>   - minor changes
>> v3 changes:
>>   - rebased to support the new build system
>>   - bumped avocado framework version for using fixed remote gdb client
>> v2 changes:
>>   - rebased to the latest upstream version
>>   - fixed replaying of the POLL interrupts after the latest debug changes
>>
>> ---
>>
>> Pavel Dovgaluk (11):
>>        replay: provide an accessor for rr filename
>>        qcow2: introduce icount field for snapshots
>>        qapi: introduce replay.json for record/replay-related stuff
>>        replay: introduce info hmp/qmp command
>>        replay: introduce breakpoint at the specified step
>>        replay: implement replay-seek command
>>        replay: flush rr queue before loading the vmstate
>>        gdbstub: add reverse step support in replay mode
>>        gdbstub: add reverse continue support in replay mode
>>        replay: describe reverse debugging in docs/replay.txt
>>        tests/acceptance: add reverse debugging test
>>
>> Pavel Dovgalyuk (3):
>>        replay: don't record interrupt poll
>>        migration: introduce icount field for snapshots
>>        replay: create temporary snapshot at debugger connection
>>
>>
>>   MAINTAINERS                           |    2
>>   accel/tcg/cpu-exec.c                  |   21 ++
>>   accel/tcg/translator.c                |    1
>>   block/qapi.c                          |   18 +-
>>   block/qcow2-snapshot.c                |    9 +
>>   block/qcow2.h                         |    3
>>   blockdev.c                            |   10 +
>>   docs/interop/qcow2.txt                |    5
>>   docs/replay.txt                       |   46 +++++
>>   exec.c                                |    8 +
>>   gdbstub.c                             |   64 ++++++
>>   hmp-commands-info.hx                  |   11 +
>>   hmp-commands.hx                       |   50 +++++
>>   include/block/snapshot.h              |    1
>>   include/monitor/hmp.h                 |    4
>>   include/sysemu/replay.h               |   26 +++
>>   migration/savevm.c                    |   17 +-
>>   qapi/block-core.json                  |   11 +
>>   qapi/meson.build                      |    1
>>   qapi/misc.json                        |   18 --
>>   qapi/qapi-schema.json                 |    1
>>   qapi/replay.json                      |  121 ++++++++++++
>>   replay/meson.build                    |    1
>>   replay/replay-debugging.c             |  332 +++++++++++++++++++++++++++++++++
>>   replay/replay-events.c                |    4
>>   replay/replay-internal.h              |    6 -
>>   replay/replay.c                       |   22 ++
>>   softmmu/cpus.c                        |   19 ++
>>   stubs/replay.c                        |   15 +
>>   tests/acceptance/reverse_debugging.py |  208 +++++++++++++++++++++
>>   tests/qemu-iotests/267.out            |   48 ++---
>>   31 files changed, 1039 insertions(+), 64 deletions(-)
>>   create mode 100644 qapi/replay.json
>>   create mode 100644 replay/replay-debugging.c
>>   create mode 100644 tests/acceptance/reverse_debugging.py
>>
>> --
>> Pavel Dovgalyuk
>>
> 



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

end of thread, other threads:[~2020-10-03 17:28 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-29 11:01 [PATCH v6 00/14] Reverse debugging Pavel Dovgalyuk
2020-09-29 11:01 ` [PATCH v6 01/14] replay: don't record interrupt poll Pavel Dovgalyuk
2020-09-29 11:01 ` [PATCH v6 02/14] replay: provide an accessor for rr filename Pavel Dovgalyuk
2020-09-29 11:01 ` [PATCH v6 03/14] qcow2: introduce icount field for snapshots Pavel Dovgalyuk
2020-10-01 12:53   ` Alex Bennée
2020-09-29 11:01 ` [PATCH v6 04/14] migration: " Pavel Dovgalyuk
2020-09-29 11:01 ` [PATCH v6 05/14] qapi: introduce replay.json for record/replay-related stuff Pavel Dovgalyuk
2020-10-01 11:00   ` Alex Bennée
2020-09-29 11:01 ` [PATCH v6 06/14] replay: introduce info hmp/qmp command Pavel Dovgalyuk
2020-09-29 11:01 ` [PATCH v6 07/14] replay: introduce breakpoint at the specified step Pavel Dovgalyuk
2020-09-29 11:01 ` [PATCH v6 08/14] replay: implement replay-seek command Pavel Dovgalyuk
2020-09-29 11:01 ` [PATCH v6 09/14] replay: flush rr queue before loading the vmstate Pavel Dovgalyuk
2020-09-29 11:02 ` [PATCH v6 10/14] gdbstub: add reverse step support in replay mode Pavel Dovgalyuk
2020-09-29 11:02 ` [PATCH v6 11/14] gdbstub: add reverse continue " Pavel Dovgalyuk
2020-09-29 11:02 ` [PATCH v6 12/14] replay: describe reverse debugging in docs/replay.txt Pavel Dovgalyuk
2020-09-29 11:02 ` [PATCH v6 13/14] replay: create temporary snapshot at debugger connection Pavel Dovgalyuk
2020-09-29 11:02 ` [PATCH v6 14/14] tests/acceptance: add reverse debugging test Pavel Dovgalyuk
2020-09-29 22:15   ` Willian Rampazzo
2020-09-29 15:51 ` [PATCH v6 00/14] Reverse debugging no-reply
2020-10-02 15:39 ` Paolo Bonzini
2020-10-02 16:01   ` Pavel Dovgalyuk
2020-10-02 16:25   ` Pavel Dovgalyuk
2020-10-03 17:19   ` Pavel Dovgalyuk

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.