xref: /openbmc/qemu/replay/replay-debugging.c (revision e7cff9c6)
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 #include "block/snapshot.h"
23 #include "migration/snapshot.h"
24 
25 static bool replay_is_debugging;
26 static int64_t replay_last_breakpoint;
27 static int64_t replay_last_snapshot;
28 
29 bool replay_running_debug(void)
30 {
31     return replay_is_debugging;
32 }
33 
34 void hmp_info_replay(Monitor *mon, const QDict *qdict)
35 {
36     if (replay_mode == REPLAY_MODE_NONE) {
37         monitor_printf(mon, "Record/replay is not active\n");
38     } else {
39         monitor_printf(mon,
40             "%s execution '%s': instruction count = %"PRId64"\n",
41             replay_mode == REPLAY_MODE_RECORD ? "Recording" : "Replaying",
42             replay_get_filename(), replay_get_current_icount());
43     }
44 }
45 
46 ReplayInfo *qmp_query_replay(Error **errp)
47 {
48     ReplayInfo *retval = g_new0(ReplayInfo, 1);
49 
50     retval->mode = replay_mode;
51     if (replay_get_filename()) {
52         retval->filename = g_strdup(replay_get_filename());
53         retval->has_filename = true;
54     }
55     retval->icount = replay_get_current_icount();
56     return retval;
57 }
58 
59 static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque)
60 {
61     assert(replay_mode == REPLAY_MODE_PLAY);
62     assert(replay_mutex_locked());
63     assert(replay_break_icount >= replay_get_current_icount());
64     assert(callback);
65 
66     replay_break_icount = icount;
67 
68     if (replay_break_timer) {
69         timer_del(replay_break_timer);
70     }
71     replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
72                                       callback, opaque);
73 }
74 
75 static void replay_delete_break(void)
76 {
77     assert(replay_mode == REPLAY_MODE_PLAY);
78     assert(replay_mutex_locked());
79 
80     if (replay_break_timer) {
81         timer_del(replay_break_timer);
82         timer_free(replay_break_timer);
83         replay_break_timer = NULL;
84     }
85     replay_break_icount = -1ULL;
86 }
87 
88 static void replay_stop_vm(void *opaque)
89 {
90     vm_stop(RUN_STATE_PAUSED);
91     replay_delete_break();
92 }
93 
94 void qmp_replay_break(int64_t icount, Error **errp)
95 {
96     if (replay_mode == REPLAY_MODE_PLAY) {
97         if (icount >= replay_get_current_icount()) {
98             replay_break(icount, replay_stop_vm, NULL);
99         } else {
100             error_setg(errp,
101                 "cannot set breakpoint at the instruction in the past");
102         }
103     } else {
104         error_setg(errp, "setting the breakpoint is allowed only in play mode");
105     }
106 }
107 
108 void hmp_replay_break(Monitor *mon, const QDict *qdict)
109 {
110     int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
111     Error *err = NULL;
112 
113     qmp_replay_break(icount, &err);
114     if (err) {
115         error_report_err(err);
116         return;
117     }
118 }
119 
120 void qmp_replay_delete_break(Error **errp)
121 {
122     if (replay_mode == REPLAY_MODE_PLAY) {
123         replay_delete_break();
124     } else {
125         error_setg(errp, "replay breakpoints are allowed only in play mode");
126     }
127 }
128 
129 void hmp_replay_delete_break(Monitor *mon, const QDict *qdict)
130 {
131     Error *err = NULL;
132 
133     qmp_replay_delete_break(&err);
134     if (err) {
135         error_report_err(err);
136         return;
137     }
138 }
139 
140 static char *replay_find_nearest_snapshot(int64_t icount,
141                                           int64_t *snapshot_icount)
142 {
143     BlockDriverState *bs;
144     QEMUSnapshotInfo *sn_tab;
145     QEMUSnapshotInfo *nearest = NULL;
146     char *ret = NULL;
147     int nb_sns, i;
148     AioContext *aio_context;
149 
150     *snapshot_icount = -1;
151 
152     bs = bdrv_all_find_vmstate_bs();
153     if (!bs) {
154         goto fail;
155     }
156     aio_context = bdrv_get_aio_context(bs);
157 
158     aio_context_acquire(aio_context);
159     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
160     aio_context_release(aio_context);
161 
162     for (i = 0; i < nb_sns; i++) {
163         if (bdrv_all_find_snapshot(sn_tab[i].name, &bs) == 0) {
164             if (sn_tab[i].icount != -1ULL
165                 && sn_tab[i].icount <= icount
166                 && (!nearest || nearest->icount < sn_tab[i].icount)) {
167                 nearest = &sn_tab[i];
168             }
169         }
170     }
171     if (nearest) {
172         ret = g_strdup(nearest->name);
173         *snapshot_icount = nearest->icount;
174     }
175     g_free(sn_tab);
176 
177 fail:
178     return ret;
179 }
180 
181 static void replay_seek(int64_t icount, QEMUTimerCB callback, Error **errp)
182 {
183     char *snapshot = NULL;
184     int64_t snapshot_icount;
185 
186     if (replay_mode != REPLAY_MODE_PLAY) {
187         error_setg(errp, "replay must be enabled to seek");
188         return;
189     }
190 
191     snapshot = replay_find_nearest_snapshot(icount, &snapshot_icount);
192     if (snapshot) {
193         if (icount < replay_get_current_icount()
194             || replay_get_current_icount() < snapshot_icount) {
195             vm_stop(RUN_STATE_RESTORE_VM);
196             load_snapshot(snapshot, errp);
197         }
198         g_free(snapshot);
199     }
200     if (replay_get_current_icount() <= icount) {
201         replay_break(icount, callback, NULL);
202         vm_start();
203     } else {
204         error_setg(errp, "cannot seek to the specified instruction count");
205     }
206 }
207 
208 void qmp_replay_seek(int64_t icount, Error **errp)
209 {
210     replay_seek(icount, replay_stop_vm, errp);
211 }
212 
213 void hmp_replay_seek(Monitor *mon, const QDict *qdict)
214 {
215     int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
216     Error *err = NULL;
217 
218     qmp_replay_seek(icount, &err);
219     if (err) {
220         error_report_err(err);
221         return;
222     }
223 }
224 
225 static void replay_stop_vm_debug(void *opaque)
226 {
227     replay_is_debugging = false;
228     vm_stop(RUN_STATE_DEBUG);
229     replay_delete_break();
230 }
231 
232 bool replay_reverse_step(void)
233 {
234     Error *err = NULL;
235 
236     assert(replay_mode == REPLAY_MODE_PLAY);
237 
238     if (replay_get_current_icount() != 0) {
239         replay_seek(replay_get_current_icount() - 1,
240                     replay_stop_vm_debug, &err);
241         if (err) {
242             error_free(err);
243             return false;
244         }
245         replay_is_debugging = true;
246         return true;
247     }
248 
249     return false;
250 }
251 
252 static void replay_continue_end(void)
253 {
254     replay_is_debugging = false;
255     vm_stop(RUN_STATE_DEBUG);
256     replay_delete_break();
257 }
258 
259 static void replay_continue_stop(void *opaque)
260 {
261     Error *err = NULL;
262     if (replay_last_breakpoint != -1LL) {
263         replay_seek(replay_last_breakpoint, replay_stop_vm_debug, &err);
264         if (err) {
265             error_free(err);
266             replay_continue_end();
267         }
268         return;
269     }
270     /*
271      * No breakpoints since the last snapshot.
272      * Find previous snapshot and try again.
273      */
274     if (replay_last_snapshot != 0) {
275         replay_seek(replay_last_snapshot - 1, replay_continue_stop, &err);
276         if (err) {
277             error_free(err);
278             replay_continue_end();
279         }
280         replay_last_snapshot = replay_get_current_icount();
281     } else {
282         /* Seek to the very first step */
283         replay_seek(0, replay_stop_vm_debug, &err);
284         if (err) {
285             error_free(err);
286             replay_continue_end();
287         }
288     }
289 }
290 
291 bool replay_reverse_continue(void)
292 {
293     Error *err = NULL;
294 
295     assert(replay_mode == REPLAY_MODE_PLAY);
296 
297     if (replay_get_current_icount() != 0) {
298         replay_seek(replay_get_current_icount() - 1,
299                     replay_continue_stop, &err);
300         if (err) {
301             error_free(err);
302             return false;
303         }
304         replay_last_breakpoint = -1LL;
305         replay_is_debugging = true;
306         replay_last_snapshot = replay_get_current_icount();
307         return true;
308     }
309 
310     return false;
311 }
312 
313 void replay_breakpoint(void)
314 {
315     assert(replay_mode == REPLAY_MODE_PLAY);
316     replay_last_breakpoint = replay_get_current_icount();
317 }
318 
319 void replay_gdb_attached(void)
320 {
321     /*
322      * Create VM snapshot on temporary overlay to allow reverse
323      * debugging even if snapshots were not enabled.
324      */
325     if (replay_mode == REPLAY_MODE_PLAY
326         && !replay_snapshot) {
327         if (save_snapshot("start_debugging", NULL) != 0) {
328             /* Can't create the snapshot. Continue conventional debugging. */
329         }
330     }
331 }
332