]> git.proxmox.com Git - mirror_qemu.git/blame - replay/replay.c
hw/intc/arm_gicv3_common: Move post_load hooks to top-level VMSD
[mirror_qemu.git] / replay / replay.c
CommitLineData
d73abd6d
PD
1/*
2 * replay.c
3 *
4 * Copyright (c) 2010-2015 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
d38ea87a 12#include "qemu/osdep.h"
da34e65c 13#include "qapi/error.h"
d73abd6d 14#include "sysemu/replay.h"
26bc60ac
PD
15#include "replay-internal.h"
16#include "qemu/timer.h"
8b427044 17#include "qemu/main-loop.h"
922a01a0 18#include "qemu/option.h"
d2528bdc 19#include "sysemu/cpus.h"
b60c48a7 20#include "sysemu/sysemu.h"
7615936e
PD
21#include "qemu/error-report.h"
22
23/* Current version of the replay mechanism.
24 Increase it when file format changes. */
80be169c 25#define REPLAY_VERSION 0xe02007
7615936e
PD
26/* Size of replay log header */
27#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
d73abd6d
PD
28
29ReplayMode replay_mode = REPLAY_MODE_NONE;
9c2037d0 30char *replay_snapshot;
26bc60ac 31
7615936e
PD
32/* Name of replay file */
33static char *replay_filename;
26bc60ac 34ReplayState replay_state;
0194749a 35static GSList *replay_blockers;
26bc60ac
PD
36
37bool replay_next_event_is(int event)
38{
39 bool res = false;
40
41 /* nothing to skip - not all instructions used */
42 if (replay_state.instructions_count != 0) {
f186d64d 43 assert(replay_state.data_kind == EVENT_INSTRUCTION);
26bc60ac
PD
44 return event == EVENT_INSTRUCTION;
45 }
46
47 while (true) {
f186d64d 48 if (event == replay_state.data_kind) {
26bc60ac
PD
49 res = true;
50 }
f186d64d 51 switch (replay_state.data_kind) {
802f045a 52 case EVENT_SHUTDOWN ... EVENT_SHUTDOWN_LAST:
b60c48a7 53 replay_finish_event();
cf83f140
EB
54 qemu_system_shutdown_request(replay_state.data_kind -
55 EVENT_SHUTDOWN);
b60c48a7 56 break;
26bc60ac
PD
57 default:
58 /* clock, time_t, checkpoint and other events */
59 return res;
60 }
61 }
62 return res;
63}
64
65uint64_t replay_get_current_step(void)
66{
67 return cpu_get_icount_raw();
68}
8b427044
PD
69
70int replay_get_instructions(void)
71{
72 int res = 0;
73 replay_mutex_lock();
74 if (replay_next_event_is(EVENT_INSTRUCTION)) {
75 res = replay_state.instructions_count;
76 }
77 replay_mutex_unlock();
78 return res;
79}
80
81void replay_account_executed_instructions(void)
82{
83 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 84 g_assert(replay_mutex_locked());
8b427044
PD
85 if (replay_state.instructions_count > 0) {
86 int count = (int)(replay_get_current_step()
87 - replay_state.current_step);
982263ce
AB
88
89 /* Time can only go forward */
90 assert(count >= 0);
91
8b427044
PD
92 replay_state.instructions_count -= count;
93 replay_state.current_step += count;
94 if (replay_state.instructions_count == 0) {
f186d64d 95 assert(replay_state.data_kind == EVENT_INSTRUCTION);
8b427044
PD
96 replay_finish_event();
97 /* Wake up iothread. This is required because
98 timers will not expire until clock counters
99 will be read from the log. */
100 qemu_notify_event();
101 }
102 }
8b427044
PD
103 }
104}
6f060969
PD
105
106bool replay_exception(void)
107{
d759c951 108
6f060969 109 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 110 g_assert(replay_mutex_locked());
6f060969 111 replay_save_instructions();
6f060969 112 replay_put_event(EVENT_EXCEPTION);
6f060969
PD
113 return true;
114 } else if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 115 g_assert(replay_mutex_locked());
6f060969
PD
116 bool res = replay_has_exception();
117 if (res) {
6f060969 118 replay_finish_event();
6f060969
PD
119 }
120 return res;
121 }
122
123 return true;
124}
125
126bool replay_has_exception(void)
127{
128 bool res = false;
129 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 130 g_assert(replay_mutex_locked());
6f060969 131 replay_account_executed_instructions();
6f060969 132 res = replay_next_event_is(EVENT_EXCEPTION);
6f060969
PD
133 }
134
135 return res;
136}
137
138bool replay_interrupt(void)
139{
140 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 141 g_assert(replay_mutex_locked());
6f060969 142 replay_save_instructions();
6f060969 143 replay_put_event(EVENT_INTERRUPT);
6f060969
PD
144 return true;
145 } else if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 146 g_assert(replay_mutex_locked());
6f060969
PD
147 bool res = replay_has_interrupt();
148 if (res) {
6f060969 149 replay_finish_event();
6f060969
PD
150 }
151 return res;
152 }
153
154 return true;
155}
156
157bool replay_has_interrupt(void)
158{
159 bool res = false;
160 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 161 g_assert(replay_mutex_locked());
6f060969 162 replay_account_executed_instructions();
6f060969 163 res = replay_next_event_is(EVENT_INTERRUPT);
6f060969
PD
164 }
165 return res;
166}
b60c48a7 167
802f045a 168void replay_shutdown_request(ShutdownCause cause)
b60c48a7
PD
169{
170 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 171 g_assert(replay_mutex_locked());
802f045a 172 replay_put_event(EVENT_SHUTDOWN + cause);
b60c48a7
PD
173 }
174}
8bd7f71d
PD
175
176bool replay_checkpoint(ReplayCheckpoint checkpoint)
177{
178 bool res = false;
66eb7825 179 static bool in_checkpoint;
8bd7f71d 180 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
8bd7f71d
PD
181
182 if (!replay_file) {
183 return true;
184 }
185
66eb7825
PD
186 if (in_checkpoint) {
187 /* If we are already in checkpoint, then there is no need
188 for additional synchronization.
189 Recursion occurs when HW event modifies timers.
190 Timer modification may invoke the checkpoint and
191 proceed to recursion. */
192 return true;
193 }
194 in_checkpoint = true;
195
196 replay_save_instructions();
8bd7f71d
PD
197
198 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 199 g_assert(replay_mutex_locked());
8bd7f71d
PD
200 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
201 replay_finish_event();
f186d64d 202 } else if (replay_state.data_kind != EVENT_ASYNC) {
8bd7f71d
PD
203 res = false;
204 goto out;
205 }
206 replay_read_events(checkpoint);
207 /* replay_read_events may leave some unread events.
208 Return false if not all of the events associated with
209 checkpoint were processed */
f186d64d 210 res = replay_state.data_kind != EVENT_ASYNC;
8bd7f71d 211 } else if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 212 g_assert(replay_mutex_locked());
8bd7f71d 213 replay_put_event(EVENT_CHECKPOINT + checkpoint);
89e46eb4
PD
214 /* This checkpoint belongs to several threads.
215 Processing events from different threads is
216 non-deterministic */
217 if (checkpoint != CHECKPOINT_CLOCK_WARP_START) {
218 replay_save_events(checkpoint);
219 }
8bd7f71d
PD
220 res = true;
221 }
222out:
66eb7825 223 in_checkpoint = false;
8bd7f71d
PD
224 return res;
225}
7615936e
PD
226
227static void replay_enable(const char *fname, int mode)
228{
229 const char *fmode = NULL;
230 assert(!replay_file);
231
232 switch (mode) {
233 case REPLAY_MODE_RECORD:
234 fmode = "wb";
235 break;
236 case REPLAY_MODE_PLAY:
237 fmode = "rb";
238 break;
239 default:
240 fprintf(stderr, "Replay: internal error: invalid replay mode\n");
241 exit(1);
242 }
243
244 atexit(replay_finish);
245
7615936e
PD
246 replay_file = fopen(fname, fmode);
247 if (replay_file == NULL) {
248 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
249 exit(1);
250 }
251
252 replay_filename = g_strdup(fname);
7615936e 253 replay_mode = mode;
d759c951
AB
254 replay_mutex_init();
255
f186d64d 256 replay_state.data_kind = -1;
7615936e
PD
257 replay_state.instructions_count = 0;
258 replay_state.current_step = 0;
f186d64d 259 replay_state.has_unread_data = 0;
7615936e
PD
260
261 /* skip file header for RECORD and check it for PLAY */
262 if (replay_mode == REPLAY_MODE_RECORD) {
263 fseek(replay_file, HEADER_SIZE, SEEK_SET);
264 } else if (replay_mode == REPLAY_MODE_PLAY) {
265 unsigned int version = replay_get_dword();
266 if (version != REPLAY_VERSION) {
267 fprintf(stderr, "Replay: invalid input log file version\n");
268 exit(1);
269 }
270 /* go to the beginning */
271 fseek(replay_file, HEADER_SIZE, SEEK_SET);
272 replay_fetch_data_kind();
273 }
274
275 replay_init_events();
276}
277
278void replay_configure(QemuOpts *opts)
279{
280 const char *fname;
281 const char *rr;
282 ReplayMode mode = REPLAY_MODE_NONE;
890ad550
EH
283 Location loc;
284
285 if (!opts) {
286 return;
287 }
288
289 loc_push_none(&loc);
290 qemu_opts_loc_restore(opts);
7615936e
PD
291
292 rr = qemu_opt_get(opts, "rr");
293 if (!rr) {
294 /* Just enabling icount */
d9d3aaea 295 goto out;
7615936e
PD
296 } else if (!strcmp(rr, "record")) {
297 mode = REPLAY_MODE_RECORD;
298 } else if (!strcmp(rr, "replay")) {
299 mode = REPLAY_MODE_PLAY;
300 } else {
301 error_report("Invalid icount rr option: %s", rr);
302 exit(1);
303 }
304
305 fname = qemu_opt_get(opts, "rrfile");
306 if (!fname) {
307 error_report("File name not specified for replay");
308 exit(1);
309 }
310
9c2037d0 311 replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
306e196f 312 replay_vmstate_register();
7615936e 313 replay_enable(fname, mode);
890ad550 314
d9d3aaea 315out:
890ad550 316 loc_pop(&loc);
7615936e
PD
317}
318
319void replay_start(void)
320{
321 if (replay_mode == REPLAY_MODE_NONE) {
322 return;
323 }
324
0194749a 325 if (replay_blockers) {
c29b77f9 326 error_reportf_err(replay_blockers->data, "Record/replay: ");
0194749a
PD
327 exit(1);
328 }
4c27b859
PD
329 if (!use_icount) {
330 error_report("Please enable icount to use record/replay");
331 exit(1);
332 }
0194749a 333
7615936e
PD
334 /* Timer for snapshotting will be set up here. */
335
336 replay_enable_events();
337}
338
339void replay_finish(void)
340{
341 if (replay_mode == REPLAY_MODE_NONE) {
342 return;
343 }
344
345 replay_save_instructions();
346
347 /* finalize the file */
348 if (replay_file) {
349 if (replay_mode == REPLAY_MODE_RECORD) {
350 /* write end event */
351 replay_put_event(EVENT_END);
352
353 /* write header */
354 fseek(replay_file, 0, SEEK_SET);
355 replay_put_dword(REPLAY_VERSION);
356 }
357
358 fclose(replay_file);
359 replay_file = NULL;
360 }
361 if (replay_filename) {
362 g_free(replay_filename);
363 replay_filename = NULL;
364 }
365
9c2037d0
PD
366 g_free(replay_snapshot);
367 replay_snapshot = NULL;
368
7615936e 369 replay_finish_events();
7615936e 370}
0194749a
PD
371
372void replay_add_blocker(Error *reason)
373{
374 replay_blockers = g_slist_prepend(replay_blockers, reason);
375}