]> git.proxmox.com Git - mirror_qemu.git/blame - replay/replay.c
Merge remote-tracking branch 'remotes/marcandre/tags/for-6.0-pull-request' into staging
[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"
740b1759 14#include "sysemu/cpu-timers.h"
d73abd6d 15#include "sysemu/replay.h"
54d31236 16#include "sysemu/runstate.h"
26bc60ac 17#include "replay-internal.h"
8b427044 18#include "qemu/main-loop.h"
922a01a0 19#include "qemu/option.h"
d2528bdc 20#include "sysemu/cpus.h"
7615936e
PD
21#include "qemu/error-report.h"
22
23/* Current version of the replay mechanism.
24 Increase it when file format changes. */
677a3bab 25#define REPLAY_VERSION 0xe0200a
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 36
e7510671
PD
37/* Replay breakpoints */
38uint64_t replay_break_icount = -1ULL;
39QEMUTimer *replay_break_timer;
40
26bc60ac
PD
41bool replay_next_event_is(int event)
42{
43 bool res = false;
44
45 /* nothing to skip - not all instructions used */
13f26713 46 if (replay_state.instruction_count != 0) {
f186d64d 47 assert(replay_state.data_kind == EVENT_INSTRUCTION);
26bc60ac
PD
48 return event == EVENT_INSTRUCTION;
49 }
50
51 while (true) {
e957ad8a
PD
52 unsigned int data_kind = replay_state.data_kind;
53 if (event == data_kind) {
26bc60ac
PD
54 res = true;
55 }
e957ad8a 56 switch (data_kind) {
802f045a 57 case EVENT_SHUTDOWN ... EVENT_SHUTDOWN_LAST:
b60c48a7 58 replay_finish_event();
e957ad8a 59 qemu_system_shutdown_request(data_kind - EVENT_SHUTDOWN);
b60c48a7 60 break;
26bc60ac
PD
61 default:
62 /* clock, time_t, checkpoint and other events */
63 return res;
64 }
65 }
66 return res;
67}
68
13f26713 69uint64_t replay_get_current_icount(void)
26bc60ac 70{
8191d368 71 return icount_get_raw();
26bc60ac 72}
8b427044
PD
73
74int replay_get_instructions(void)
75{
76 int res = 0;
77 replay_mutex_lock();
78 if (replay_next_event_is(EVENT_INSTRUCTION)) {
13f26713 79 res = replay_state.instruction_count;
e7510671
PD
80 if (replay_break_icount != -1LL) {
81 uint64_t current = replay_get_current_icount();
82 assert(replay_break_icount >= current);
83 if (current + res > replay_break_icount) {
84 res = replay_break_icount - current;
85 }
86 }
8b427044
PD
87 }
88 replay_mutex_unlock();
89 return res;
90}
91
92void replay_account_executed_instructions(void)
93{
94 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 95 g_assert(replay_mutex_locked());
13f26713 96 if (replay_state.instruction_count > 0) {
366a85e4 97 replay_advance_current_icount(replay_get_current_icount());
8b427044 98 }
8b427044
PD
99 }
100}
6f060969
PD
101
102bool replay_exception(void)
103{
d759c951 104
6f060969 105 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 106 g_assert(replay_mutex_locked());
6f060969 107 replay_save_instructions();
6f060969 108 replay_put_event(EVENT_EXCEPTION);
6f060969
PD
109 return true;
110 } else if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 111 g_assert(replay_mutex_locked());
6f060969
PD
112 bool res = replay_has_exception();
113 if (res) {
6f060969 114 replay_finish_event();
6f060969
PD
115 }
116 return res;
117 }
118
119 return true;
120}
121
122bool replay_has_exception(void)
123{
124 bool res = false;
125 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 126 g_assert(replay_mutex_locked());
6f060969 127 replay_account_executed_instructions();
6f060969 128 res = replay_next_event_is(EVENT_EXCEPTION);
6f060969
PD
129 }
130
131 return res;
132}
133
134bool replay_interrupt(void)
135{
136 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 137 g_assert(replay_mutex_locked());
6f060969 138 replay_save_instructions();
6f060969 139 replay_put_event(EVENT_INTERRUPT);
6f060969
PD
140 return true;
141 } else if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 142 g_assert(replay_mutex_locked());
6f060969
PD
143 bool res = replay_has_interrupt();
144 if (res) {
6f060969 145 replay_finish_event();
6f060969
PD
146 }
147 return res;
148 }
149
150 return true;
151}
152
153bool replay_has_interrupt(void)
154{
155 bool res = false;
156 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 157 g_assert(replay_mutex_locked());
6f060969 158 replay_account_executed_instructions();
6f060969 159 res = replay_next_event_is(EVENT_INTERRUPT);
6f060969
PD
160 }
161 return res;
162}
b60c48a7 163
802f045a 164void replay_shutdown_request(ShutdownCause cause)
b60c48a7
PD
165{
166 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 167 g_assert(replay_mutex_locked());
802f045a 168 replay_put_event(EVENT_SHUTDOWN + cause);
b60c48a7
PD
169 }
170}
8bd7f71d
PD
171
172bool replay_checkpoint(ReplayCheckpoint checkpoint)
173{
174 bool res = false;
66eb7825 175 static bool in_checkpoint;
8bd7f71d 176 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
8bd7f71d
PD
177
178 if (!replay_file) {
179 return true;
180 }
181
66eb7825 182 if (in_checkpoint) {
7cebff0d 183 /*
66eb7825 184 Recursion occurs when HW event modifies timers.
7cebff0d
PD
185 Prevent performing icount warp in this case and
186 wait for another invocation of the checkpoint.
187 */
188 g_assert(replay_mode == REPLAY_MODE_PLAY);
189 return false;
66eb7825
PD
190 }
191 in_checkpoint = true;
192
193 replay_save_instructions();
8bd7f71d
PD
194
195 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 196 g_assert(replay_mutex_locked());
8bd7f71d
PD
197 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
198 replay_finish_event();
f186d64d 199 } else if (replay_state.data_kind != EVENT_ASYNC) {
8bd7f71d
PD
200 res = false;
201 goto out;
202 }
203 replay_read_events(checkpoint);
204 /* replay_read_events may leave some unread events.
205 Return false if not all of the events associated with
206 checkpoint were processed */
f186d64d 207 res = replay_state.data_kind != EVENT_ASYNC;
8bd7f71d 208 } else if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 209 g_assert(replay_mutex_locked());
8bd7f71d 210 replay_put_event(EVENT_CHECKPOINT + checkpoint);
89e46eb4
PD
211 /* This checkpoint belongs to several threads.
212 Processing events from different threads is
213 non-deterministic */
ca9759c2
PD
214 if (checkpoint != CHECKPOINT_CLOCK_WARP_START
215 /* FIXME: this is temporary fix, other checkpoints
216 may also be invoked from the different threads someday.
217 Asynchronous event processing should be refactored
218 to create additional replay event kind which is
219 nailed to the one of the threads and which processes
220 the event queue. */
221 && checkpoint != CHECKPOINT_CLOCK_VIRTUAL) {
89e46eb4
PD
222 replay_save_events(checkpoint);
223 }
8bd7f71d
PD
224 res = true;
225 }
226out:
66eb7825 227 in_checkpoint = false;
8bd7f71d
PD
228 return res;
229}
7615936e 230
0c08185f
PD
231bool replay_has_checkpoint(void)
232{
233 bool res = false;
234 if (replay_mode == REPLAY_MODE_PLAY) {
235 g_assert(replay_mutex_locked());
236 replay_account_executed_instructions();
237 res = EVENT_CHECKPOINT <= replay_state.data_kind
238 && replay_state.data_kind <= EVENT_CHECKPOINT_LAST;
239 }
240 return res;
241}
242
7615936e
PD
243static void replay_enable(const char *fname, int mode)
244{
245 const char *fmode = NULL;
246 assert(!replay_file);
247
248 switch (mode) {
249 case REPLAY_MODE_RECORD:
250 fmode = "wb";
251 break;
252 case REPLAY_MODE_PLAY:
253 fmode = "rb";
254 break;
255 default:
256 fprintf(stderr, "Replay: internal error: invalid replay mode\n");
257 exit(1);
258 }
259
260 atexit(replay_finish);
261
7615936e
PD
262 replay_file = fopen(fname, fmode);
263 if (replay_file == NULL) {
264 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
265 exit(1);
266 }
267
268 replay_filename = g_strdup(fname);
7615936e 269 replay_mode = mode;
d759c951
AB
270 replay_mutex_init();
271
f186d64d 272 replay_state.data_kind = -1;
13f26713
PD
273 replay_state.instruction_count = 0;
274 replay_state.current_icount = 0;
f186d64d 275 replay_state.has_unread_data = 0;
7615936e
PD
276
277 /* skip file header for RECORD and check it for PLAY */
278 if (replay_mode == REPLAY_MODE_RECORD) {
279 fseek(replay_file, HEADER_SIZE, SEEK_SET);
280 } else if (replay_mode == REPLAY_MODE_PLAY) {
281 unsigned int version = replay_get_dword();
282 if (version != REPLAY_VERSION) {
283 fprintf(stderr, "Replay: invalid input log file version\n");
284 exit(1);
285 }
286 /* go to the beginning */
287 fseek(replay_file, HEADER_SIZE, SEEK_SET);
288 replay_fetch_data_kind();
289 }
290
291 replay_init_events();
292}
293
294void replay_configure(QemuOpts *opts)
295{
296 const char *fname;
297 const char *rr;
298 ReplayMode mode = REPLAY_MODE_NONE;
890ad550
EH
299 Location loc;
300
301 if (!opts) {
302 return;
303 }
304
305 loc_push_none(&loc);
306 qemu_opts_loc_restore(opts);
7615936e
PD
307
308 rr = qemu_opt_get(opts, "rr");
309 if (!rr) {
310 /* Just enabling icount */
d9d3aaea 311 goto out;
7615936e
PD
312 } else if (!strcmp(rr, "record")) {
313 mode = REPLAY_MODE_RECORD;
314 } else if (!strcmp(rr, "replay")) {
315 mode = REPLAY_MODE_PLAY;
316 } else {
317 error_report("Invalid icount rr option: %s", rr);
318 exit(1);
319 }
320
321 fname = qemu_opt_get(opts, "rrfile");
322 if (!fname) {
323 error_report("File name not specified for replay");
324 exit(1);
325 }
326
9c2037d0 327 replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
306e196f 328 replay_vmstate_register();
7615936e 329 replay_enable(fname, mode);
890ad550 330
d9d3aaea 331out:
890ad550 332 loc_pop(&loc);
7615936e
PD
333}
334
335void replay_start(void)
336{
337 if (replay_mode == REPLAY_MODE_NONE) {
338 return;
339 }
340
0194749a 341 if (replay_blockers) {
c29b77f9 342 error_reportf_err(replay_blockers->data, "Record/replay: ");
0194749a
PD
343 exit(1);
344 }
740b1759 345 if (!icount_enabled()) {
4c27b859
PD
346 error_report("Please enable icount to use record/replay");
347 exit(1);
348 }
0194749a 349
7615936e
PD
350 /* Timer for snapshotting will be set up here. */
351
352 replay_enable_events();
353}
354
355void replay_finish(void)
356{
357 if (replay_mode == REPLAY_MODE_NONE) {
358 return;
359 }
360
361 replay_save_instructions();
362
363 /* finalize the file */
364 if (replay_file) {
365 if (replay_mode == REPLAY_MODE_RECORD) {
ed5d7ff3
PD
366 /*
367 * Can't do it in the signal handler, therefore
368 * add shutdown event here for the case of Ctrl-C.
369 */
370 replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL);
7615936e
PD
371 /* write end event */
372 replay_put_event(EVENT_END);
373
374 /* write header */
375 fseek(replay_file, 0, SEEK_SET);
376 replay_put_dword(REPLAY_VERSION);
377 }
378
379 fclose(replay_file);
380 replay_file = NULL;
381 }
382 if (replay_filename) {
383 g_free(replay_filename);
384 replay_filename = NULL;
385 }
386
9c2037d0
PD
387 g_free(replay_snapshot);
388 replay_snapshot = NULL;
389
ae25dccb
PD
390 replay_mode = REPLAY_MODE_NONE;
391
7615936e 392 replay_finish_events();
7615936e 393}
0194749a
PD
394
395void replay_add_blocker(Error *reason)
396{
397 replay_blockers = g_slist_prepend(replay_blockers, reason);
398}
56db1198
PD
399
400const char *replay_get_filename(void)
401{
402 return replay_filename;
403}