From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, peter.maydell@linaro.org, war2jordan@live.com,
crosthwaite.peter@gmail.com, boost.lists@gmail.com,
artem.k.pisarenko@gmail.com, quintela@redhat.com,
ciro.santilli@gmail.com, jasowang@redhat.com, mst@redhat.com,
armbru@redhat.com, mreitz@redhat.com,
maria.klimushenkova@ispras.ru, dovgaluk@ispras.ru,
kraxel@redhat.com, pavel.dovgaluk@ispras.ru,
thomas.dullien@googlemail.com, pbonzini@redhat.com,
alex.bennee@linaro.org, dgilbert@redhat.com, rth@twiddle.net
Subject: [Qemu-devel] [PATCH v10 12/24] replay: introduce breakpoint at the specified step
Date: Thu, 17 Jan 2019 10:37:59 +0300 [thread overview]
Message-ID: <20190117073758.5399.16268.stgit@pasha-VirtualBox> (raw)
In-Reply-To: <20190117073649.5399.97670.stgit@pasha-VirtualBox>
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.Dovgaluk@ispras.ru>
--
v2:
- renamed replay_break qmp command into replay-break
(suggested by Eric Blake)
v7:
- introduces replay_delete_break command
v9:
- changed 'step' parameter name to 'icount'
- moved json stuff to replay.json and updated the description
(suggested by Markus Armbruster)
v10:
- updated descriptions (suggested by Markus Armbruster)
---
hmp-commands.hx | 34 ++++++++++++++++++
hmp.h | 2 +
qapi/replay.json | 36 +++++++++++++++++++
replay/replay-debugging.c | 86 +++++++++++++++++++++++++++++++++++++++++++++
replay/replay-internal.h | 4 ++
replay/replay.c | 17 +++++++++
6 files changed, 179 insertions(+)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index ba71558..d529f24 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1890,6 +1890,40 @@ Set QOM property @var{property} of object at location @var{path} to value @var{v
ETEXI
{
+ .name = "replay_break",
+ .args_type = "icount:i",
+ .params = "icount",
+ .help = "set breakpoint at the specified instruction count",
+ .cmd = hmp_replay_break,
+ },
+
+STEXI
+@item replay_break @var{icount}
+@findex replay_break
+Set replay breakpoint at instruction count @var{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'.
+ETEXI
+
+ {
+ .name = "replay_delete_break",
+ .args_type = "",
+ .params = "",
+ .help = "removes replay breakpoint",
+ .cmd = hmp_replay_delete_break,
+ },
+
+STEXI
+@item replay_delete_break
+@findex replay_delete_break
+Removes replay breakpoint which was previously set with replay_break.
+The command is ignored when there are no replay breakpoints.
+ETEXI
+
+ {
.name = "info",
.args_type = "item:s?",
.params = "[subcommand]",
diff --git a/hmp.h b/hmp.h
index d792149..c9b9b4f 100644
--- a/hmp.h
+++ b/hmp.h
@@ -149,5 +149,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 ef2fb4b..cb94991 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: 4.0
+#
+# Example:
+#
+# -> { "execute": "replay-break", "data": { "icount": 220414 } }
+#
+##
+{ 'command': 'replay-break', 'data': { 'icount': 'int' } }
+
+##
+# @replay-delete-break:
+#
+# Removes replay breakpoint which was set with @replay-break.
+# The command is ignored when there are no replay breakpoints.
+#
+# Since: 4.0
+#
+# Example:
+#
+# -> { "execute": "replay-delete-break" }
+#
+##
+{ 'command': 'replay-delete-break' }
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index 51f1c4d..a94685e 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -16,6 +16,8 @@
#include "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 +43,87 @@ ReplayInfo *qmp_query_replay(Error **errp)
retval->icount = replay_get_current_step();
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_step());
+ assert(callback);
+
+ replay_break_icount = icount;
+
+ if (replay_break_timer) {
+ timer_del(replay_break_timer);
+ } else {
+ 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_step()) {
+ 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);
+ error_free(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);
+ error_free(err);
+ return;
+ }
+}
diff --git a/replay/replay-internal.h b/replay/replay-internal.h
index af6f4d5..8c15a41 100644
--- a/replay/replay-internal.h
+++ b/replay/replay-internal.h
@@ -91,6 +91,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 aa53411..1be34aa 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.instructions_count;
+ if (replay_break_icount != -1LL) {
+ uint64_t current = replay_get_current_step();
+ 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_step) {
+ /* Cannot make callback directly from the vCPU thread */
+ timer_mod_ns(replay_break_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
+ }
}
}
}
next prev parent reply other threads:[~2019-01-17 7:37 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-01-17 7:36 [Qemu-devel] [PATCH v10 00/24] Fixing record/replay and adding reverse debugging Pavel Dovgalyuk
2019-01-17 7:36 ` [Qemu-devel] [PATCH v10 01/24] replay: add missing fix for internal function Pavel Dovgalyuk
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 02/24] block: implement bdrv_snapshot_goto for blkreplay Pavel Dovgalyuk
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 03/24] replay: disable default snapshot for record/replay Pavel Dovgalyuk
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 04/24] replay: update docs for record/replay with block devices Pavel Dovgalyuk
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 05/24] replay: don't drain/flush bdrv queue while RR is working Pavel Dovgalyuk
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 06/24] replay: finish record/replay before closing the disks Pavel Dovgalyuk
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 07/24] qcow2: introduce icount field for snapshots Pavel Dovgalyuk
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 08/24] migration: " Pavel Dovgalyuk
2019-01-17 12:45 ` Markus Armbruster
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 09/24] replay: provide an accessor for rr filename Pavel Dovgalyuk
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 10/24] qapi: introduce replay.json for record/replay-related stuff Pavel Dovgalyuk
2019-01-17 12:48 ` Markus Armbruster
2019-01-17 7:37 ` [Qemu-devel] [PATCH v10 11/24] replay: introduce info hmp/qmp command Pavel Dovgalyuk
2019-01-17 13:20 ` Markus Armbruster
2019-01-17 7:37 ` Pavel Dovgalyuk [this message]
2019-01-17 13:24 ` [Qemu-devel] [PATCH v10 12/24] replay: introduce breakpoint at the specified step Markus Armbruster
2019-01-18 5:34 ` Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 13/24] replay: implement replay-seek command Pavel Dovgalyuk
2019-01-17 13:30 ` Markus Armbruster
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 14/24] replay: refine replay-time module Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 15/24] replay: flush rr queue before loading the vmstate Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 16/24] gdbstub: add reverse step support in replay mode Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 17/24] gdbstub: add reverse continue " Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 18/24] replay: describe reverse debugging in docs/replay.txt Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 19/24] replay: add BH oneshot event for block layer Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 20/24] replay: init rtc after enabling the replay Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 21/24] replay: document development rules Pavel Dovgalyuk
2019-01-17 7:38 ` [Qemu-devel] [PATCH v10 22/24] util/qemu-timer: refactor deadline calculation for external timers Pavel Dovgalyuk
2019-01-17 7:39 ` [Qemu-devel] [PATCH v10 23/24] replay: fix replay shutdown Pavel Dovgalyuk
2019-01-17 7:39 ` [Qemu-devel] [PATCH v10 24/24] replay: rename step-related variables and functions Pavel Dovgalyuk
2019-01-31 18:15 ` [Qemu-devel] [PATCH v10 00/24] Fixing record/replay and adding reverse debugging no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190117073758.5399.16268.stgit@pasha-VirtualBox \
--to=pavel.dovgaluk@ispras.ru \
--cc=alex.bennee@linaro.org \
--cc=armbru@redhat.com \
--cc=artem.k.pisarenko@gmail.com \
--cc=boost.lists@gmail.com \
--cc=ciro.santilli@gmail.com \
--cc=crosthwaite.peter@gmail.com \
--cc=dgilbert@redhat.com \
--cc=dovgaluk@ispras.ru \
--cc=jasowang@redhat.com \
--cc=kraxel@redhat.com \
--cc=kwolf@redhat.com \
--cc=maria.klimushenkova@ispras.ru \
--cc=mreitz@redhat.com \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
--cc=rth@twiddle.net \
--cc=thomas.dullien@googlemail.com \
--cc=war2jordan@live.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.