aboutsummaryrefslogtreecommitdiff
path: root/replay/replay-debugging.c
diff options
context:
space:
mode:
Diffstat (limited to 'replay/replay-debugging.c')
-rw-r--r--replay/replay-debugging.c84
1 files changed, 84 insertions, 0 deletions
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;
+ }
+}