]> git.proxmox.com Git - mirror_qemu.git/blame - replay/replay.c
tools/virtiofsd/buffer.c: check whether buf is NULL in fuse_bufvec_advance func
[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
PD
96 if (replay_state.instruction_count > 0) {
97 int count = (int)(replay_get_current_icount()
98 - replay_state.current_icount);
982263ce
AB
99
100 /* Time can only go forward */
101 assert(count >= 0);
102
13f26713
PD
103 replay_state.instruction_count -= count;
104 replay_state.current_icount += count;
105 if (replay_state.instruction_count == 0) {
f186d64d 106 assert(replay_state.data_kind == EVENT_INSTRUCTION);
8b427044
PD
107 replay_finish_event();
108 /* Wake up iothread. This is required because
109 timers will not expire until clock counters
110 will be read from the log. */
111 qemu_notify_event();
112 }
e7510671
PD
113 /* Execution reached the break step */
114 if (replay_break_icount == replay_state.current_icount) {
115 /* Cannot make callback directly from the vCPU thread */
116 timer_mod_ns(replay_break_timer,
117 qemu_clock_get_ns(QEMU_CLOCK_REALTIME));
118 }
8b427044 119 }
8b427044
PD
120 }
121}
6f060969
PD
122
123bool replay_exception(void)
124{
d759c951 125
6f060969 126 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 127 g_assert(replay_mutex_locked());
6f060969 128 replay_save_instructions();
6f060969 129 replay_put_event(EVENT_EXCEPTION);
6f060969
PD
130 return true;
131 } else if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 132 g_assert(replay_mutex_locked());
6f060969
PD
133 bool res = replay_has_exception();
134 if (res) {
6f060969 135 replay_finish_event();
6f060969
PD
136 }
137 return res;
138 }
139
140 return true;
141}
142
143bool replay_has_exception(void)
144{
145 bool res = false;
146 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 147 g_assert(replay_mutex_locked());
6f060969 148 replay_account_executed_instructions();
6f060969 149 res = replay_next_event_is(EVENT_EXCEPTION);
6f060969
PD
150 }
151
152 return res;
153}
154
155bool replay_interrupt(void)
156{
157 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 158 g_assert(replay_mutex_locked());
6f060969 159 replay_save_instructions();
6f060969 160 replay_put_event(EVENT_INTERRUPT);
6f060969
PD
161 return true;
162 } else if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 163 g_assert(replay_mutex_locked());
6f060969
PD
164 bool res = replay_has_interrupt();
165 if (res) {
6f060969 166 replay_finish_event();
6f060969
PD
167 }
168 return res;
169 }
170
171 return true;
172}
173
174bool replay_has_interrupt(void)
175{
176 bool res = false;
177 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 178 g_assert(replay_mutex_locked());
6f060969 179 replay_account_executed_instructions();
6f060969 180 res = replay_next_event_is(EVENT_INTERRUPT);
6f060969
PD
181 }
182 return res;
183}
b60c48a7 184
802f045a 185void replay_shutdown_request(ShutdownCause cause)
b60c48a7
PD
186{
187 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 188 g_assert(replay_mutex_locked());
802f045a 189 replay_put_event(EVENT_SHUTDOWN + cause);
b60c48a7
PD
190 }
191}
8bd7f71d
PD
192
193bool replay_checkpoint(ReplayCheckpoint checkpoint)
194{
195 bool res = false;
66eb7825 196 static bool in_checkpoint;
8bd7f71d 197 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
8bd7f71d
PD
198
199 if (!replay_file) {
200 return true;
201 }
202
66eb7825
PD
203 if (in_checkpoint) {
204 /* If we are already in checkpoint, then there is no need
205 for additional synchronization.
206 Recursion occurs when HW event modifies timers.
207 Timer modification may invoke the checkpoint and
208 proceed to recursion. */
209 return true;
210 }
211 in_checkpoint = true;
212
213 replay_save_instructions();
8bd7f71d
PD
214
215 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 216 g_assert(replay_mutex_locked());
8bd7f71d
PD
217 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
218 replay_finish_event();
f186d64d 219 } else if (replay_state.data_kind != EVENT_ASYNC) {
8bd7f71d
PD
220 res = false;
221 goto out;
222 }
223 replay_read_events(checkpoint);
224 /* replay_read_events may leave some unread events.
225 Return false if not all of the events associated with
226 checkpoint were processed */
f186d64d 227 res = replay_state.data_kind != EVENT_ASYNC;
8bd7f71d 228 } else if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 229 g_assert(replay_mutex_locked());
8bd7f71d 230 replay_put_event(EVENT_CHECKPOINT + checkpoint);
89e46eb4
PD
231 /* This checkpoint belongs to several threads.
232 Processing events from different threads is
233 non-deterministic */
ca9759c2
PD
234 if (checkpoint != CHECKPOINT_CLOCK_WARP_START
235 /* FIXME: this is temporary fix, other checkpoints
236 may also be invoked from the different threads someday.
237 Asynchronous event processing should be refactored
238 to create additional replay event kind which is
239 nailed to the one of the threads and which processes
240 the event queue. */
241 && checkpoint != CHECKPOINT_CLOCK_VIRTUAL) {
89e46eb4
PD
242 replay_save_events(checkpoint);
243 }
8bd7f71d
PD
244 res = true;
245 }
246out:
66eb7825 247 in_checkpoint = false;
8bd7f71d
PD
248 return res;
249}
7615936e 250
0c08185f
PD
251bool replay_has_checkpoint(void)
252{
253 bool res = false;
254 if (replay_mode == REPLAY_MODE_PLAY) {
255 g_assert(replay_mutex_locked());
256 replay_account_executed_instructions();
257 res = EVENT_CHECKPOINT <= replay_state.data_kind
258 && replay_state.data_kind <= EVENT_CHECKPOINT_LAST;
259 }
260 return res;
261}
262
7615936e
PD
263static void replay_enable(const char *fname, int mode)
264{
265 const char *fmode = NULL;
266 assert(!replay_file);
267
268 switch (mode) {
269 case REPLAY_MODE_RECORD:
270 fmode = "wb";
271 break;
272 case REPLAY_MODE_PLAY:
273 fmode = "rb";
274 break;
275 default:
276 fprintf(stderr, "Replay: internal error: invalid replay mode\n");
277 exit(1);
278 }
279
280 atexit(replay_finish);
281
7615936e
PD
282 replay_file = fopen(fname, fmode);
283 if (replay_file == NULL) {
284 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
285 exit(1);
286 }
287
288 replay_filename = g_strdup(fname);
7615936e 289 replay_mode = mode;
d759c951
AB
290 replay_mutex_init();
291
f186d64d 292 replay_state.data_kind = -1;
13f26713
PD
293 replay_state.instruction_count = 0;
294 replay_state.current_icount = 0;
f186d64d 295 replay_state.has_unread_data = 0;
7615936e
PD
296
297 /* skip file header for RECORD and check it for PLAY */
298 if (replay_mode == REPLAY_MODE_RECORD) {
299 fseek(replay_file, HEADER_SIZE, SEEK_SET);
300 } else if (replay_mode == REPLAY_MODE_PLAY) {
301 unsigned int version = replay_get_dword();
302 if (version != REPLAY_VERSION) {
303 fprintf(stderr, "Replay: invalid input log file version\n");
304 exit(1);
305 }
306 /* go to the beginning */
307 fseek(replay_file, HEADER_SIZE, SEEK_SET);
308 replay_fetch_data_kind();
309 }
310
311 replay_init_events();
312}
313
314void replay_configure(QemuOpts *opts)
315{
316 const char *fname;
317 const char *rr;
318 ReplayMode mode = REPLAY_MODE_NONE;
890ad550
EH
319 Location loc;
320
321 if (!opts) {
322 return;
323 }
324
325 loc_push_none(&loc);
326 qemu_opts_loc_restore(opts);
7615936e
PD
327
328 rr = qemu_opt_get(opts, "rr");
329 if (!rr) {
330 /* Just enabling icount */
d9d3aaea 331 goto out;
7615936e
PD
332 } else if (!strcmp(rr, "record")) {
333 mode = REPLAY_MODE_RECORD;
334 } else if (!strcmp(rr, "replay")) {
335 mode = REPLAY_MODE_PLAY;
336 } else {
337 error_report("Invalid icount rr option: %s", rr);
338 exit(1);
339 }
340
341 fname = qemu_opt_get(opts, "rrfile");
342 if (!fname) {
343 error_report("File name not specified for replay");
344 exit(1);
345 }
346
9c2037d0 347 replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
306e196f 348 replay_vmstate_register();
7615936e 349 replay_enable(fname, mode);
890ad550 350
d9d3aaea 351out:
890ad550 352 loc_pop(&loc);
7615936e
PD
353}
354
355void replay_start(void)
356{
357 if (replay_mode == REPLAY_MODE_NONE) {
358 return;
359 }
360
0194749a 361 if (replay_blockers) {
c29b77f9 362 error_reportf_err(replay_blockers->data, "Record/replay: ");
0194749a
PD
363 exit(1);
364 }
740b1759 365 if (!icount_enabled()) {
4c27b859
PD
366 error_report("Please enable icount to use record/replay");
367 exit(1);
368 }
0194749a 369
7615936e
PD
370 /* Timer for snapshotting will be set up here. */
371
372 replay_enable_events();
373}
374
375void replay_finish(void)
376{
377 if (replay_mode == REPLAY_MODE_NONE) {
378 return;
379 }
380
381 replay_save_instructions();
382
383 /* finalize the file */
384 if (replay_file) {
385 if (replay_mode == REPLAY_MODE_RECORD) {
ed5d7ff3
PD
386 /*
387 * Can't do it in the signal handler, therefore
388 * add shutdown event here for the case of Ctrl-C.
389 */
390 replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL);
7615936e
PD
391 /* write end event */
392 replay_put_event(EVENT_END);
393
394 /* write header */
395 fseek(replay_file, 0, SEEK_SET);
396 replay_put_dword(REPLAY_VERSION);
397 }
398
399 fclose(replay_file);
400 replay_file = NULL;
401 }
402 if (replay_filename) {
403 g_free(replay_filename);
404 replay_filename = NULL;
405 }
406
9c2037d0
PD
407 g_free(replay_snapshot);
408 replay_snapshot = NULL;
409
ae25dccb
PD
410 replay_mode = REPLAY_MODE_NONE;
411
7615936e 412 replay_finish_events();
7615936e 413}
0194749a
PD
414
415void replay_add_blocker(Error *reason)
416{
417 replay_blockers = g_slist_prepend(replay_blockers, reason);
418}
56db1198
PD
419
420const char *replay_get_filename(void)
421{
422 return replay_filename;
423}