xref: /qemu/replay/replay-debugging.c (revision b49f4755)
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 
replay_running_debug(void)29fda8458bSPavel Dovgalyuk bool replay_running_debug(void)
30fda8458bSPavel Dovgalyuk {
31fda8458bSPavel Dovgalyuk     return replay_is_debugging;
32fda8458bSPavel Dovgalyuk }
33fda8458bSPavel Dovgalyuk 
hmp_info_replay(Monitor * mon,const QDict * qdict)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 
qmp_query_replay(Error ** errp)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     }
54e3b09ad2SPavel Dovgalyuk     retval->icount = replay_get_current_icount();
55e3b09ad2SPavel Dovgalyuk     return retval;
56e3b09ad2SPavel Dovgalyuk }
57e7510671SPavel Dovgalyuk 
replay_break(uint64_t icount,QEMUTimerCB callback,void * opaque)58e7510671SPavel Dovgalyuk static void replay_break(uint64_t icount, QEMUTimerCB callback, void *opaque)
59e7510671SPavel Dovgalyuk {
60e7510671SPavel Dovgalyuk     assert(replay_mode == REPLAY_MODE_PLAY);
61e7510671SPavel Dovgalyuk     assert(replay_mutex_locked());
62e7510671SPavel Dovgalyuk     assert(replay_break_icount >= replay_get_current_icount());
63e7510671SPavel Dovgalyuk     assert(callback);
64e7510671SPavel Dovgalyuk 
65e7510671SPavel Dovgalyuk     replay_break_icount = icount;
66e7510671SPavel Dovgalyuk 
67e7510671SPavel Dovgalyuk     if (replay_break_timer) {
68e7510671SPavel Dovgalyuk         timer_del(replay_break_timer);
69e7510671SPavel Dovgalyuk     }
70e7510671SPavel Dovgalyuk     replay_break_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
71e7510671SPavel Dovgalyuk                                       callback, opaque);
72e7510671SPavel Dovgalyuk }
73e7510671SPavel Dovgalyuk 
replay_delete_break(void)74e7510671SPavel Dovgalyuk static void replay_delete_break(void)
75e7510671SPavel Dovgalyuk {
76e7510671SPavel Dovgalyuk     assert(replay_mode == REPLAY_MODE_PLAY);
77e7510671SPavel Dovgalyuk     assert(replay_mutex_locked());
78e7510671SPavel Dovgalyuk 
79e7510671SPavel Dovgalyuk     if (replay_break_timer) {
80e7510671SPavel Dovgalyuk         timer_free(replay_break_timer);
81e7510671SPavel Dovgalyuk         replay_break_timer = NULL;
82e7510671SPavel Dovgalyuk     }
83e7510671SPavel Dovgalyuk     replay_break_icount = -1ULL;
84e7510671SPavel Dovgalyuk }
85e7510671SPavel Dovgalyuk 
replay_stop_vm(void * opaque)86e7510671SPavel Dovgalyuk static void replay_stop_vm(void *opaque)
87e7510671SPavel Dovgalyuk {
88e7510671SPavel Dovgalyuk     vm_stop(RUN_STATE_PAUSED);
89e7510671SPavel Dovgalyuk     replay_delete_break();
90e7510671SPavel Dovgalyuk }
91e7510671SPavel Dovgalyuk 
qmp_replay_break(int64_t icount,Error ** errp)92e7510671SPavel Dovgalyuk void qmp_replay_break(int64_t icount, Error **errp)
93e7510671SPavel Dovgalyuk {
94e7510671SPavel Dovgalyuk     if (replay_mode == REPLAY_MODE_PLAY) {
95e7510671SPavel Dovgalyuk         if (icount >= replay_get_current_icount()) {
96e7510671SPavel Dovgalyuk             replay_break(icount, replay_stop_vm, NULL);
97e7510671SPavel Dovgalyuk         } else {
98e7510671SPavel Dovgalyuk             error_setg(errp,
99e7510671SPavel Dovgalyuk                 "cannot set breakpoint at the instruction in the past");
100e7510671SPavel Dovgalyuk         }
101e7510671SPavel Dovgalyuk     } else {
102e7510671SPavel Dovgalyuk         error_setg(errp, "setting the breakpoint is allowed only in play mode");
103e7510671SPavel Dovgalyuk     }
104e7510671SPavel Dovgalyuk }
105e7510671SPavel Dovgalyuk 
hmp_replay_break(Monitor * mon,const QDict * qdict)106e7510671SPavel Dovgalyuk void hmp_replay_break(Monitor *mon, const QDict *qdict)
107e7510671SPavel Dovgalyuk {
108e7510671SPavel Dovgalyuk     int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
109e7510671SPavel Dovgalyuk     Error *err = NULL;
110e7510671SPavel Dovgalyuk 
111e7510671SPavel Dovgalyuk     qmp_replay_break(icount, &err);
112e7510671SPavel Dovgalyuk     if (err) {
113e7510671SPavel Dovgalyuk         error_report_err(err);
114e7510671SPavel Dovgalyuk         return;
115e7510671SPavel Dovgalyuk     }
116e7510671SPavel Dovgalyuk }
117e7510671SPavel Dovgalyuk 
qmp_replay_delete_break(Error ** errp)118e7510671SPavel Dovgalyuk void qmp_replay_delete_break(Error **errp)
119e7510671SPavel Dovgalyuk {
120e7510671SPavel Dovgalyuk     if (replay_mode == REPLAY_MODE_PLAY) {
121e7510671SPavel Dovgalyuk         replay_delete_break();
122e7510671SPavel Dovgalyuk     } else {
123e7510671SPavel Dovgalyuk         error_setg(errp, "replay breakpoints are allowed only in play mode");
124e7510671SPavel Dovgalyuk     }
125e7510671SPavel Dovgalyuk }
126e7510671SPavel Dovgalyuk 
hmp_replay_delete_break(Monitor * mon,const QDict * qdict)127e7510671SPavel Dovgalyuk void hmp_replay_delete_break(Monitor *mon, const QDict *qdict)
128e7510671SPavel Dovgalyuk {
129e7510671SPavel Dovgalyuk     Error *err = NULL;
130e7510671SPavel Dovgalyuk 
131e7510671SPavel Dovgalyuk     qmp_replay_delete_break(&err);
132e7510671SPavel Dovgalyuk     if (err) {
133e7510671SPavel Dovgalyuk         error_report_err(err);
134e7510671SPavel Dovgalyuk         return;
135e7510671SPavel Dovgalyuk     }
136e7510671SPavel Dovgalyuk }
137f6baed3dSPavel Dovgalyuk 
replay_find_nearest_snapshot(int64_t icount,int64_t * snapshot_icount)138f6baed3dSPavel Dovgalyuk static char *replay_find_nearest_snapshot(int64_t icount,
139f6baed3dSPavel Dovgalyuk                                           int64_t *snapshot_icount)
140f6baed3dSPavel Dovgalyuk {
141f6baed3dSPavel Dovgalyuk     BlockDriverState *bs;
142f6baed3dSPavel Dovgalyuk     QEMUSnapshotInfo *sn_tab;
143f6baed3dSPavel Dovgalyuk     QEMUSnapshotInfo *nearest = NULL;
144f6baed3dSPavel Dovgalyuk     char *ret = NULL;
1453d3e9b1fSDaniel P. Berrangé     int rv;
146f6baed3dSPavel Dovgalyuk     int nb_sns, i;
147f6baed3dSPavel Dovgalyuk 
148f6baed3dSPavel Dovgalyuk     *snapshot_icount = -1;
149f6baed3dSPavel Dovgalyuk 
150c22d644cSDaniel P. Berrangé     bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, NULL);
151f6baed3dSPavel Dovgalyuk     if (!bs) {
152f6baed3dSPavel Dovgalyuk         goto fail;
153f6baed3dSPavel Dovgalyuk     }
154f6baed3dSPavel Dovgalyuk 
155f6baed3dSPavel Dovgalyuk     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
156f6baed3dSPavel Dovgalyuk 
157f6baed3dSPavel Dovgalyuk     for (i = 0; i < nb_sns; i++) {
1583d3e9b1fSDaniel P. Berrangé         rv = bdrv_all_has_snapshot(sn_tab[i].name, false, NULL, NULL);
1593d3e9b1fSDaniel P. Berrangé         if (rv < 0)
1603d3e9b1fSDaniel P. Berrangé             goto fail;
1613d3e9b1fSDaniel P. Berrangé         if (rv == 1) {
162f6baed3dSPavel Dovgalyuk             if (sn_tab[i].icount != -1ULL
163f6baed3dSPavel Dovgalyuk                 && sn_tab[i].icount <= icount
164f6baed3dSPavel Dovgalyuk                 && (!nearest || nearest->icount < sn_tab[i].icount)) {
165f6baed3dSPavel Dovgalyuk                 nearest = &sn_tab[i];
166f6baed3dSPavel Dovgalyuk             }
167f6baed3dSPavel Dovgalyuk         }
168f6baed3dSPavel Dovgalyuk     }
169f6baed3dSPavel Dovgalyuk     if (nearest) {
170f6baed3dSPavel Dovgalyuk         ret = g_strdup(nearest->name);
171f6baed3dSPavel Dovgalyuk         *snapshot_icount = nearest->icount;
172f6baed3dSPavel Dovgalyuk     }
173f6baed3dSPavel Dovgalyuk     g_free(sn_tab);
174f6baed3dSPavel Dovgalyuk 
175f6baed3dSPavel Dovgalyuk fail:
176f6baed3dSPavel Dovgalyuk     return ret;
177f6baed3dSPavel Dovgalyuk }
178f6baed3dSPavel Dovgalyuk 
replay_seek(int64_t icount,QEMUTimerCB callback,Error ** errp)179f6baed3dSPavel Dovgalyuk static void replay_seek(int64_t icount, QEMUTimerCB callback, Error **errp)
180f6baed3dSPavel Dovgalyuk {
181f6baed3dSPavel Dovgalyuk     char *snapshot = NULL;
182f6baed3dSPavel Dovgalyuk     int64_t snapshot_icount;
183f6baed3dSPavel Dovgalyuk 
184f6baed3dSPavel Dovgalyuk     if (replay_mode != REPLAY_MODE_PLAY) {
185f6baed3dSPavel Dovgalyuk         error_setg(errp, "replay must be enabled to seek");
186f6baed3dSPavel Dovgalyuk         return;
187f6baed3dSPavel Dovgalyuk     }
188f6baed3dSPavel Dovgalyuk 
189f6baed3dSPavel Dovgalyuk     snapshot = replay_find_nearest_snapshot(icount, &snapshot_icount);
190f6baed3dSPavel Dovgalyuk     if (snapshot) {
191f6baed3dSPavel Dovgalyuk         if (icount < replay_get_current_icount()
192f6baed3dSPavel Dovgalyuk             || replay_get_current_icount() < snapshot_icount) {
193f6baed3dSPavel Dovgalyuk             vm_stop(RUN_STATE_RESTORE_VM);
194*f1a9fcddSDaniel P. Berrangé             load_snapshot(snapshot, NULL, false, NULL, errp);
195f6baed3dSPavel Dovgalyuk         }
196f6baed3dSPavel Dovgalyuk         g_free(snapshot);
197f6baed3dSPavel Dovgalyuk     }
198f6baed3dSPavel Dovgalyuk     if (replay_get_current_icount() <= icount) {
199f6baed3dSPavel Dovgalyuk         replay_break(icount, callback, NULL);
200f6baed3dSPavel Dovgalyuk         vm_start();
201f6baed3dSPavel Dovgalyuk     } else {
202f6baed3dSPavel Dovgalyuk         error_setg(errp, "cannot seek to the specified instruction count");
203f6baed3dSPavel Dovgalyuk     }
204f6baed3dSPavel Dovgalyuk }
205f6baed3dSPavel Dovgalyuk 
qmp_replay_seek(int64_t icount,Error ** errp)206f6baed3dSPavel Dovgalyuk void qmp_replay_seek(int64_t icount, Error **errp)
207f6baed3dSPavel Dovgalyuk {
208f6baed3dSPavel Dovgalyuk     replay_seek(icount, replay_stop_vm, errp);
209f6baed3dSPavel Dovgalyuk }
210f6baed3dSPavel Dovgalyuk 
hmp_replay_seek(Monitor * mon,const QDict * qdict)211f6baed3dSPavel Dovgalyuk void hmp_replay_seek(Monitor *mon, const QDict *qdict)
212f6baed3dSPavel Dovgalyuk {
213f6baed3dSPavel Dovgalyuk     int64_t icount = qdict_get_try_int(qdict, "icount", -1LL);
214f6baed3dSPavel Dovgalyuk     Error *err = NULL;
215f6baed3dSPavel Dovgalyuk 
216f6baed3dSPavel Dovgalyuk     qmp_replay_seek(icount, &err);
217f6baed3dSPavel Dovgalyuk     if (err) {
218f6baed3dSPavel Dovgalyuk         error_report_err(err);
219f6baed3dSPavel Dovgalyuk         return;
220f6baed3dSPavel Dovgalyuk     }
221f6baed3dSPavel Dovgalyuk }
222fda8458bSPavel Dovgalyuk 
replay_stop_vm_debug(void * opaque)223fda8458bSPavel Dovgalyuk static void replay_stop_vm_debug(void *opaque)
224fda8458bSPavel Dovgalyuk {
225fda8458bSPavel Dovgalyuk     replay_is_debugging = false;
226fda8458bSPavel Dovgalyuk     vm_stop(RUN_STATE_DEBUG);
227fda8458bSPavel Dovgalyuk     replay_delete_break();
228fda8458bSPavel Dovgalyuk }
229fda8458bSPavel Dovgalyuk 
replay_reverse_step(void)230fda8458bSPavel Dovgalyuk bool replay_reverse_step(void)
231fda8458bSPavel Dovgalyuk {
232fda8458bSPavel Dovgalyuk     Error *err = NULL;
233fda8458bSPavel Dovgalyuk 
234fda8458bSPavel Dovgalyuk     assert(replay_mode == REPLAY_MODE_PLAY);
235fda8458bSPavel Dovgalyuk 
236fda8458bSPavel Dovgalyuk     if (replay_get_current_icount() != 0) {
237fda8458bSPavel Dovgalyuk         replay_seek(replay_get_current_icount() - 1,
238fda8458bSPavel Dovgalyuk                     replay_stop_vm_debug, &err);
239fda8458bSPavel Dovgalyuk         if (err) {
240fda8458bSPavel Dovgalyuk             error_free(err);
241fda8458bSPavel Dovgalyuk             return false;
242fda8458bSPavel Dovgalyuk         }
243fda8458bSPavel Dovgalyuk         replay_is_debugging = true;
244fda8458bSPavel Dovgalyuk         return true;
245fda8458bSPavel Dovgalyuk     }
246fda8458bSPavel Dovgalyuk 
247fda8458bSPavel Dovgalyuk     return false;
248fda8458bSPavel Dovgalyuk }
249cda38259SPavel Dovgalyuk 
replay_continue_end(void)250cda38259SPavel Dovgalyuk static void replay_continue_end(void)
251cda38259SPavel Dovgalyuk {
252cda38259SPavel Dovgalyuk     replay_is_debugging = false;
253cda38259SPavel Dovgalyuk     vm_stop(RUN_STATE_DEBUG);
254cda38259SPavel Dovgalyuk     replay_delete_break();
255cda38259SPavel Dovgalyuk }
256cda38259SPavel Dovgalyuk 
replay_continue_stop(void * opaque)257cda38259SPavel Dovgalyuk static void replay_continue_stop(void *opaque)
258cda38259SPavel Dovgalyuk {
259cda38259SPavel Dovgalyuk     Error *err = NULL;
260cda38259SPavel Dovgalyuk     if (replay_last_breakpoint != -1LL) {
261cda38259SPavel Dovgalyuk         replay_seek(replay_last_breakpoint, replay_stop_vm_debug, &err);
262cda38259SPavel Dovgalyuk         if (err) {
263cda38259SPavel Dovgalyuk             error_free(err);
264cda38259SPavel Dovgalyuk             replay_continue_end();
265cda38259SPavel Dovgalyuk         }
266cda38259SPavel Dovgalyuk         return;
267cda38259SPavel Dovgalyuk     }
268cda38259SPavel Dovgalyuk     /*
269cda38259SPavel Dovgalyuk      * No breakpoints since the last snapshot.
270cda38259SPavel Dovgalyuk      * Find previous snapshot and try again.
271cda38259SPavel Dovgalyuk      */
272cda38259SPavel Dovgalyuk     if (replay_last_snapshot != 0) {
273cda38259SPavel Dovgalyuk         replay_seek(replay_last_snapshot - 1, replay_continue_stop, &err);
274cda38259SPavel Dovgalyuk         if (err) {
275cda38259SPavel Dovgalyuk             error_free(err);
276cda38259SPavel Dovgalyuk             replay_continue_end();
277cda38259SPavel Dovgalyuk         }
278cda38259SPavel Dovgalyuk         replay_last_snapshot = replay_get_current_icount();
279cda38259SPavel Dovgalyuk     } else {
280cda38259SPavel Dovgalyuk         /* Seek to the very first step */
281cda38259SPavel Dovgalyuk         replay_seek(0, replay_stop_vm_debug, &err);
282cda38259SPavel Dovgalyuk         if (err) {
283cda38259SPavel Dovgalyuk             error_free(err);
284cda38259SPavel Dovgalyuk             replay_continue_end();
285cda38259SPavel Dovgalyuk         }
286cda38259SPavel Dovgalyuk     }
287cda38259SPavel Dovgalyuk }
288cda38259SPavel Dovgalyuk 
replay_reverse_continue(void)289cda38259SPavel Dovgalyuk bool replay_reverse_continue(void)
290cda38259SPavel Dovgalyuk {
291cda38259SPavel Dovgalyuk     Error *err = NULL;
292cda38259SPavel Dovgalyuk 
293cda38259SPavel Dovgalyuk     assert(replay_mode == REPLAY_MODE_PLAY);
294cda38259SPavel Dovgalyuk 
295cda38259SPavel Dovgalyuk     if (replay_get_current_icount() != 0) {
296cda38259SPavel Dovgalyuk         replay_seek(replay_get_current_icount() - 1,
297cda38259SPavel Dovgalyuk                     replay_continue_stop, &err);
298cda38259SPavel Dovgalyuk         if (err) {
299cda38259SPavel Dovgalyuk             error_free(err);
300cda38259SPavel Dovgalyuk             return false;
301cda38259SPavel Dovgalyuk         }
302cda38259SPavel Dovgalyuk         replay_last_breakpoint = -1LL;
303cda38259SPavel Dovgalyuk         replay_is_debugging = true;
304cda38259SPavel Dovgalyuk         replay_last_snapshot = replay_get_current_icount();
305cda38259SPavel Dovgalyuk         return true;
306cda38259SPavel Dovgalyuk     }
307cda38259SPavel Dovgalyuk 
308cda38259SPavel Dovgalyuk     return false;
309cda38259SPavel Dovgalyuk }
310cda38259SPavel Dovgalyuk 
replay_breakpoint(void)311cda38259SPavel Dovgalyuk void replay_breakpoint(void)
312cda38259SPavel Dovgalyuk {
313cda38259SPavel Dovgalyuk     assert(replay_mode == REPLAY_MODE_PLAY);
314cda38259SPavel Dovgalyuk     replay_last_breakpoint = replay_get_current_icount();
315cda38259SPavel Dovgalyuk }
31656357d80SPavel Dovgalyuk 
replay_gdb_attached(void)31756357d80SPavel Dovgalyuk void replay_gdb_attached(void)
31856357d80SPavel Dovgalyuk {
31956357d80SPavel Dovgalyuk     /*
32056357d80SPavel Dovgalyuk      * Create VM snapshot on temporary overlay to allow reverse
32156357d80SPavel Dovgalyuk      * debugging even if snapshots were not enabled.
32256357d80SPavel Dovgalyuk      */
32356357d80SPavel Dovgalyuk     if (replay_mode == REPLAY_MODE_PLAY
32456357d80SPavel Dovgalyuk         && !replay_snapshot) {
325*f1a9fcddSDaniel P. Berrangé         if (!save_snapshot("start_debugging", true, NULL, false, NULL, NULL)) {
32656357d80SPavel Dovgalyuk             /* Can't create the snapshot. Continue conventional debugging. */
32756357d80SPavel Dovgalyuk         }
32856357d80SPavel Dovgalyuk     }
32956357d80SPavel Dovgalyuk }
330