]> git.proxmox.com Git - mirror_qemu.git/blame - replay/replay-debugging.c
replay: introduce breakpoint at the specified step
[mirror_qemu.git] / replay / replay-debugging.c
CommitLineData
e3b09ad2
PD
1/*
2 * replay-debugging.c
3 *
4 * Copyright (c) 2010-2020 Institute for System Programming
5 * of the Russian Academy of Sciences.
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
9 *
10 */
11
12#include "qemu/osdep.h"
13#include "qapi/error.h"
14#include "sysemu/replay.h"
e7510671 15#include "sysemu/runstate.h"
e3b09ad2
PD
16#include "replay-internal.h"
17#include "monitor/hmp.h"
18#include "monitor/monitor.h"
19#include "qapi/qapi-commands-replay.h"
e7510671
PD
20#include "qapi/qmp/qdict.h"
21#include "qemu/timer.h"
e3b09ad2
PD
22
23void hmp_info_replay(Monitor *mon, const QDict *qdict)
24{
25 if (replay_mode == REPLAY_MODE_NONE) {
26 monitor_printf(mon, "Record/replay is not active\n");
27 } else {
28 monitor_printf(mon,
29 "%s execution '%s': instruction count = %"PRId64"\n",
30 replay_mode == REPLAY_MODE_RECORD ? "Recording" : "Replaying",
31 replay_get_filename(), replay_get_current_icount());
32 }
33}
34
35ReplayInfo *qmp_query_replay(Error **errp)
36{
37 ReplayInfo *retval = g_new0(ReplayInfo, 1);
38
39 retval->mode = replay_mode;
40 if (replay_get_filename()) {
41 retval->filename = g_strdup(replay_get_filename());
42 retval->has_filename = true;
43 }
44 retval->icount = replay_get_current_icount();
45 return retval;
46}
e7510671
PD
47
48static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque)
49{
50 assert(replay_mode == REPLAY_MODE_PLAY);
51 assert(replay_mutex_locked());
52 assert(replay_break_icount >= replay_get_current_icount());
53 assert(callback);
54
55 replay_break_icount = icount;
56
57 if (replay_break_timer) {
58 timer_del(replay_break_timer);
59 }
60 replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
61 callback, opaque);
62}
63
64static void replay_delete_break(void)
65{
66 assert(replay_mode == REPLAY_MODE_PLAY);
67 assert(replay_mutex_locked());
68
69 if (replay_break_timer) {
70 timer_del(replay_break_timer);
71 timer_free(replay_break_timer);
72 replay_break_timer = NULL;
73 }
74 replay_break_icount = -1ULL;
75}
76
77static void replay_stop_vm(void *opaque)
78{
79 vm_stop(RUN_STATE_PAUSED);
80 replay_delete_break();
81}
82
83void qmp_replay_break(int64_t icount, Error **errp)
84{
85 if (replay_mode == REPLAY_MODE_PLAY) {
86 if (icount >= replay_get_current_icount()) {
87 replay_break(icount, replay_stop_vm, NULL);
88 } else {
89 error_setg(errp,
90 "cannot set breakpoint at the instruction in the past");
91 }
92 } else {
93 error_setg(errp, "setting the breakpoint is allowed only in play mode");
94 }
95}
96
97void hmp_replay_break(Monitor *mon, const QDict *qdict)
98{
99 int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
100 Error *err = NULL;
101
102 qmp_replay_break(icount, &err);
103 if (err) {
104 error_report_err(err);
105 return;
106 }
107}
108
109void qmp_replay_delete_break(Error **errp)
110{
111 if (replay_mode == REPLAY_MODE_PLAY) {
112 replay_delete_break();
113 } else {
114 error_setg(errp, "replay breakpoints are allowed only in play mode");
115 }
116}
117
118void hmp_replay_delete_break(Monitor *mon, const QDict *qdict)
119{
120 Error *err = NULL;
121
122 qmp_replay_delete_break(&err);
123 if (err) {
124 error_report_err(err);
125 return;
126 }
127}