]> git.proxmox.com Git - mirror_qemu.git/blame - replay/replay.c
hw/block/nvme: remove the req dependency in map functions
[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
PD
182 if (in_checkpoint) {
183 /* If we are already in checkpoint, then there is no need
184 for additional synchronization.
185 Recursion occurs when HW event modifies timers.
186 Timer modification may invoke the checkpoint and
187 proceed to recursion. */
188 return true;
189 }
190 in_checkpoint = true;
191
192 replay_save_instructions();
8bd7f71d
PD
193
194 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 195 g_assert(replay_mutex_locked());
8bd7f71d
PD
196 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
197 replay_finish_event();
f186d64d 198 } else if (replay_state.data_kind != EVENT_ASYNC) {
8bd7f71d
PD
199 res = false;
200 goto out;
201 }
202 replay_read_events(checkpoint);
203 /* replay_read_events may leave some unread events.
204 Return false if not all of the events associated with
205 checkpoint were processed */
f186d64d 206 res = replay_state.data_kind != EVENT_ASYNC;
8bd7f71d 207 } else if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 208 g_assert(replay_mutex_locked());
8bd7f71d 209 replay_put_event(EVENT_CHECKPOINT + checkpoint);
89e46eb4
PD
210 /* This checkpoint belongs to several threads.
211 Processing events from different threads is
212 non-deterministic */
ca9759c2
PD
213 if (checkpoint != CHECKPOINT_CLOCK_WARP_START
214 /* FIXME: this is temporary fix, other checkpoints
215 may also be invoked from the different threads someday.
216 Asynchronous event processing should be refactored
217 to create additional replay event kind which is
218 nailed to the one of the threads and which processes
219 the event queue. */
220 && checkpoint != CHECKPOINT_CLOCK_VIRTUAL) {
89e46eb4
PD
221 replay_save_events(checkpoint);
222 }
8bd7f71d
PD
223 res = true;
224 }
225out:
66eb7825 226 in_checkpoint = false;
8bd7f71d
PD
227 return res;
228}
7615936e 229
0c08185f
PD
230bool replay_has_checkpoint(void)
231{
232 bool res = false;
233 if (replay_mode == REPLAY_MODE_PLAY) {
234 g_assert(replay_mutex_locked());
235 replay_account_executed_instructions();
236 res = EVENT_CHECKPOINT <= replay_state.data_kind
237 && replay_state.data_kind <= EVENT_CHECKPOINT_LAST;
238 }
239 return res;
240}
241
7615936e
PD
242static void replay_enable(const char *fname, int mode)
243{
244 const char *fmode = NULL;
245 assert(!replay_file);
246
247 switch (mode) {
248 case REPLAY_MODE_RECORD:
249 fmode = "wb";
250 break;
251 case REPLAY_MODE_PLAY:
252 fmode = "rb";
253 break;
254 default:
255 fprintf(stderr, "Replay: internal error: invalid replay mode\n");
256 exit(1);
257 }
258
259 atexit(replay_finish);
260
7615936e
PD
261 replay_file = fopen(fname, fmode);
262 if (replay_file == NULL) {
263 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
264 exit(1);
265 }
266
267 replay_filename = g_strdup(fname);
7615936e 268 replay_mode = mode;
d759c951
AB
269 replay_mutex_init();
270
f186d64d 271 replay_state.data_kind = -1;
13f26713
PD
272 replay_state.instruction_count = 0;
273 replay_state.current_icount = 0;
f186d64d 274 replay_state.has_unread_data = 0;
7615936e
PD
275
276 /* skip file header for RECORD and check it for PLAY */
277 if (replay_mode == REPLAY_MODE_RECORD) {
278 fseek(replay_file, HEADER_SIZE, SEEK_SET);
279 } else if (replay_mode == REPLAY_MODE_PLAY) {
280 unsigned int version = replay_get_dword();
281 if (version != REPLAY_VERSION) {
282 fprintf(stderr, "Replay: invalid input log file version\n");
283 exit(1);
284 }
285 /* go to the beginning */
286 fseek(replay_file, HEADER_SIZE, SEEK_SET);
287 replay_fetch_data_kind();
288 }
289
290 replay_init_events();
291}
292
293void replay_configure(QemuOpts *opts)
294{
295 const char *fname;
296 const char *rr;
297 ReplayMode mode = REPLAY_MODE_NONE;
890ad550
EH
298 Location loc;
299
300 if (!opts) {
301 return;
302 }
303
304 loc_push_none(&loc);
305 qemu_opts_loc_restore(opts);
7615936e
PD
306
307 rr = qemu_opt_get(opts, "rr");
308 if (!rr) {
309 /* Just enabling icount */
d9d3aaea 310 goto out;
7615936e
PD
311 } else if (!strcmp(rr, "record")) {
312 mode = REPLAY_MODE_RECORD;
313 } else if (!strcmp(rr, "replay")) {
314 mode = REPLAY_MODE_PLAY;
315 } else {
316 error_report("Invalid icount rr option: %s", rr);
317 exit(1);
318 }
319
320 fname = qemu_opt_get(opts, "rrfile");
321 if (!fname) {
322 error_report("File name not specified for replay");
323 exit(1);
324 }
325
9c2037d0 326 replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
306e196f 327 replay_vmstate_register();
7615936e 328 replay_enable(fname, mode);
890ad550 329
d9d3aaea 330out:
890ad550 331 loc_pop(&loc);
7615936e
PD
332}
333
334void replay_start(void)
335{
336 if (replay_mode == REPLAY_MODE_NONE) {
337 return;
338 }
339
0194749a 340 if (replay_blockers) {
c29b77f9 341 error_reportf_err(replay_blockers->data, "Record/replay: ");
0194749a
PD
342 exit(1);
343 }
740b1759 344 if (!icount_enabled()) {
4c27b859
PD
345 error_report("Please enable icount to use record/replay");
346 exit(1);
347 }
0194749a 348
7615936e
PD
349 /* Timer for snapshotting will be set up here. */
350
351 replay_enable_events();
352}
353
354void replay_finish(void)
355{
356 if (replay_mode == REPLAY_MODE_NONE) {
357 return;
358 }
359
360 replay_save_instructions();
361
362 /* finalize the file */
363 if (replay_file) {
364 if (replay_mode == REPLAY_MODE_RECORD) {
ed5d7ff3
PD
365 /*
366 * Can't do it in the signal handler, therefore
367 * add shutdown event here for the case of Ctrl-C.
368 */
369 replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL);
7615936e
PD
370 /* write end event */
371 replay_put_event(EVENT_END);
372
373 /* write header */
374 fseek(replay_file, 0, SEEK_SET);
375 replay_put_dword(REPLAY_VERSION);
376 }
377
378 fclose(replay_file);
379 replay_file = NULL;
380 }
381 if (replay_filename) {
382 g_free(replay_filename);
383 replay_filename = NULL;
384 }
385
9c2037d0
PD
386 g_free(replay_snapshot);
387 replay_snapshot = NULL;
388
ae25dccb
PD
389 replay_mode = REPLAY_MODE_NONE;
390
7615936e 391 replay_finish_events();
7615936e 392}
0194749a
PD
393
394void replay_add_blocker(Error *reason)
395{
396 replay_blockers = g_slist_prepend(replay_blockers, reason);
397}
56db1198
PD
398
399const char *replay_get_filename(void)
400{
401 return replay_filename;
402}