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