xref: /openbmc/qemu/replay/replay-debugging.c (revision e7510671)
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"
15 #include "sysemu/runstate.h"
16 #include "replay-internal.h"
17 #include "monitor/hmp.h"
18 #include "monitor/monitor.h"
19 #include "qapi/qapi-commands-replay.h"
20 #include "qapi/qmp/qdict.h"
21 #include "qemu/timer.h"
22 
23 void 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 
35 ReplayInfo *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 }
47 
48 static 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 
64 static 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 
77 static void replay_stop_vm(void *opaque)
78 {
79     vm_stop(RUN_STATE_PAUSED);
80     replay_delete_break();
81 }
82 
83 void 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 
97 void 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 
109 void 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 
118 void 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 }
128