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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).