xref: /openbmc/qemu/replay/replay-debugging.c (revision a6caeee8)
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_free(replay_break_timer);
82         replay_break_timer = NULL;
83     }
84     replay_break_icount = -1ULL;
85 }
86 
87 static void replay_stop_vm(void *opaque)
88 {
89     vm_stop(RUN_STATE_PAUSED);
90     replay_delete_break();
91 }
92 
93 void qmp_replay_break(int64_t icount, Error **errp)
94 {
95     if (replay_mode == REPLAY_MODE_PLAY) {
96         if (icount >= replay_get_current_icount()) {
97             replay_break(icount, replay_stop_vm, NULL);
98         } else {
99             error_setg(errp,
100                 "cannot set breakpoint at the instruction in the past");
101         }
102     } else {
103         error_setg(errp, "setting the breakpoint is allowed only in play mode");
104     }
105 }
106 
107 void hmp_replay_break(Monitor *mon, const QDict *qdict)
108 {
109     int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
110     Error *err = NULL;
111 
112     qmp_replay_break(icount, &err);
113     if (err) {
114         error_report_err(err);
115         return;
116     }
117 }
118 
119 void qmp_replay_delete_break(Error **errp)
120 {
121     if (replay_mode == REPLAY_MODE_PLAY) {
122         replay_delete_break();
123     } else {
124         error_setg(errp, "replay breakpoints are allowed only in play mode");
125     }
126 }
127 
128 void hmp_replay_delete_break(Monitor *mon, const QDict *qdict)
129 {
130     Error *err = NULL;
131 
132     qmp_replay_delete_break(&err);
133     if (err) {
134         error_report_err(err);
135         return;
136     }
137 }
138 
139 static char *replay_find_nearest_snapshot(int64_t icount,
140                                           int64_t *snapshot_icount)
141 {
142     BlockDriverState *bs;
143     QEMUSnapshotInfo *sn_tab;
144     QEMUSnapshotInfo *nearest = NULL;
145     char *ret = NULL;
146     int rv;
147     int nb_sns, i;
148     AioContext *aio_context;
149 
150     *snapshot_icount = -1;
151 
152     bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, NULL);
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         rv = bdrv_all_has_snapshot(sn_tab[i].name, false, NULL, NULL);
164         if (rv < 0)
165             goto fail;
166         if (rv == 1) {
167             if (sn_tab[i].icount != -1ULL
168                 && sn_tab[i].icount <= icount
169                 && (!nearest || nearest->icount < sn_tab[i].icount)) {
170                 nearest = &sn_tab[i];
171             }
172         }
173     }
174     if (nearest) {
175         ret = g_strdup(nearest->name);
176         *snapshot_icount = nearest->icount;
177     }
178     g_free(sn_tab);
179 
180 fail:
181     return ret;
182 }
183 
184 static void replay_seek(int64_t icount, QEMUTimerCB callback, Error **errp)
185 {
186     char *snapshot = NULL;
187     int64_t snapshot_icount;
188 
189     if (replay_mode != REPLAY_MODE_PLAY) {
190         error_setg(errp, "replay must be enabled to seek");
191         return;
192     }
193 
194     snapshot = replay_find_nearest_snapshot(icount, &snapshot_icount);
195     if (snapshot) {
196         if (icount < replay_get_current_icount()
197             || replay_get_current_icount() < snapshot_icount) {
198             vm_stop(RUN_STATE_RESTORE_VM);
199             load_snapshot(snapshot, NULL, false, NULL, errp);
200         }
201         g_free(snapshot);
202     }
203     if (replay_get_current_icount() <= icount) {
204         replay_break(icount, callback, NULL);
205         vm_start();
206     } else {
207         error_setg(errp, "cannot seek to the specified instruction count");
208     }
209 }
210 
211 void qmp_replay_seek(int64_t icount, Error **errp)
212 {
213     replay_seek(icount, replay_stop_vm, errp);
214 }
215 
216 void hmp_replay_seek(Monitor *mon, const QDict *qdict)
217 {
218     int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
219     Error *err = NULL;
220 
221     qmp_replay_seek(icount, &err);
222     if (err) {
223         error_report_err(err);
224         return;
225     }
226 }
227 
228 static void replay_stop_vm_debug(void *opaque)
229 {
230     replay_is_debugging = false;
231     vm_stop(RUN_STATE_DEBUG);
232     replay_delete_break();
233 }
234 
235 bool replay_reverse_step(void)
236 {
237     Error *err = NULL;
238 
239     assert(replay_mode == REPLAY_MODE_PLAY);
240 
241     if (replay_get_current_icount() != 0) {
242         replay_seek(replay_get_current_icount() - 1,
243                     replay_stop_vm_debug, &err);
244         if (err) {
245             error_free(err);
246             return false;
247         }
248         replay_is_debugging = true;
249         return true;
250     }
251 
252     return false;
253 }
254 
255 static void replay_continue_end(void)
256 {
257     replay_is_debugging = false;
258     vm_stop(RUN_STATE_DEBUG);
259     replay_delete_break();
260 }
261 
262 static void replay_continue_stop(void *opaque)
263 {
264     Error *err = NULL;
265     if (replay_last_breakpoint != -1LL) {
266         replay_seek(replay_last_breakpoint, replay_stop_vm_debug, &err);
267         if (err) {
268             error_free(err);
269             replay_continue_end();
270         }
271         return;
272     }
273     /*
274      * No breakpoints since the last snapshot.
275      * Find previous snapshot and try again.
276      */
277     if (replay_last_snapshot != 0) {
278         replay_seek(replay_last_snapshot - 1, replay_continue_stop, &err);
279         if (err) {
280             error_free(err);
281             replay_continue_end();
282         }
283         replay_last_snapshot = replay_get_current_icount();
284     } else {
285         /* Seek to the very first step */
286         replay_seek(0, replay_stop_vm_debug, &err);
287         if (err) {
288             error_free(err);
289             replay_continue_end();
290         }
291     }
292 }
293 
294 bool replay_reverse_continue(void)
295 {
296     Error *err = NULL;
297 
298     assert(replay_mode == REPLAY_MODE_PLAY);
299 
300     if (replay_get_current_icount() != 0) {
301         replay_seek(replay_get_current_icount() - 1,
302                     replay_continue_stop, &err);
303         if (err) {
304             error_free(err);
305             return false;
306         }
307         replay_last_breakpoint = -1LL;
308         replay_is_debugging = true;
309         replay_last_snapshot = replay_get_current_icount();
310         return true;
311     }
312 
313     return false;
314 }
315 
316 void replay_breakpoint(void)
317 {
318     assert(replay_mode == REPLAY_MODE_PLAY);
319     replay_last_breakpoint = replay_get_current_icount();
320 }
321 
322 void replay_gdb_attached(void)
323 {
324     /*
325      * Create VM snapshot on temporary overlay to allow reverse
326      * debugging even if snapshots were not enabled.
327      */
328     if (replay_mode == REPLAY_MODE_PLAY
329         && !replay_snapshot) {
330         if (!save_snapshot("start_debugging", true, NULL, false, NULL, NULL)) {
331             /* Can't create the snapshot. Continue conventional debugging. */
332         }
333     }
334 }
335