hw/block/nvme: support multiple namespaces
[qemu.git] / replay / replay.c
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
12 #include "qemu/osdep.h"
13 #include "qapi/error.h"
14 #include "sysemu/cpu-timers.h"
15 #include "sysemu/replay.h"
16 #include "sysemu/runstate.h"
17 #include "replay-internal.h"
18 #include "qemu/main-loop.h"
19 #include "qemu/option.h"
20 #include "sysemu/cpus.h"
21 #include "qemu/error-report.h"
22
23 /* Current version of the replay mechanism.
24    Increase it when file format changes. */
25 #define REPLAY_VERSION              0xe0200a
26 /* Size of replay log header */
27 #define HEADER_SIZE                 (sizeof(uint32_t) + sizeof(uint64_t))
28
29 ReplayMode replay_mode = REPLAY_MODE_NONE;
30 char *replay_snapshot;
31
32 /* Name of replay file  */
33 static char *replay_filename;
34 ReplayState replay_state;
35 static GSList *replay_blockers;
36
37 /* Replay breakpoints */
38 uint64_t replay_break_icount = -1ULL;
39 QEMUTimer *replay_break_timer;
40
41 bool replay_next_event_is(int event)
42 {
43     bool res = false;
44
45     /* nothing to skip - not all instructions used */
46     if (replay_state.instruction_count != 0) {
47         assert(replay_state.data_kind == EVENT_INSTRUCTION);
48         return event == EVENT_INSTRUCTION;
49     }
50
51     while (true) {
52         unsigned int data_kind = replay_state.data_kind;
53         if (event == data_kind) {
54             res = true;
55         }
56         switch (data_kind) {
57         case EVENT_SHUTDOWN ... EVENT_SHUTDOWN_LAST:
58             replay_finish_event();
59             qemu_system_shutdown_request(data_kind - EVENT_SHUTDOWN);
60             break;
61         default:
62             /* clock, time_t, checkpoint and other events */
63             return res;
64         }
65     }
66     return res;
67 }
68
69 uint64_t replay_get_current_icount(void)
70 {
71     return icount_get_raw();
72 }
73
74 int replay_get_instructions(void)
75 {
76     int res = 0;
77     replay_mutex_lock();
78     if (replay_next_event_is(EVENT_INSTRUCTION)) {
79         res = replay_state.instruction_count;
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         }
87     }
88     replay_mutex_unlock();
89     return res;
90 }
91
92 void replay_account_executed_instructions(void)
93 {
94     if (replay_mode == REPLAY_MODE_PLAY) {
95         g_assert(replay_mutex_locked());
96         if (replay_state.instruction_count > 0) {
97             int count = (int)(replay_get_current_icount()
98                               - replay_state.current_icount);
99
100             /* Time can only go forward */
101             assert(count >= 0);
102
103             replay_state.instruction_count -= count;
104             replay_state.current_icount += count;
105             if (replay_state.instruction_count == 0) {
106                 assert(replay_state.data_kind == EVENT_INSTRUCTION);
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             }
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             }
119         }
120     }
121 }
122
123 bool replay_exception(void)
124 {
125
126     if (replay_mode == REPLAY_MODE_RECORD) {
127         g_assert(replay_mutex_locked());
128         replay_save_instructions();
129         replay_put_event(EVENT_EXCEPTION);
130         return true;
131     } else if (replay_mode == REPLAY_MODE_PLAY) {
132         g_assert(replay_mutex_locked());
133         bool res = replay_has_exception();
134         if (res) {
135             replay_finish_event();
136         }
137         return res;
138     }
139
140     return true;
141 }
142
143 bool replay_has_exception(void)
144 {
145     bool res = false;
146     if (replay_mode == REPLAY_MODE_PLAY) {
147         g_assert(replay_mutex_locked());
148         replay_account_executed_instructions();
149         res = replay_next_event_is(EVENT_EXCEPTION);
150     }
151
152     return res;
153 }
154
155 bool replay_interrupt(void)
156 {
157     if (replay_mode == REPLAY_MODE_RECORD) {
158         g_assert(replay_mutex_locked());
159         replay_save_instructions();
160         replay_put_event(EVENT_INTERRUPT);
161         return true;
162     } else if (replay_mode == REPLAY_MODE_PLAY) {
163         g_assert(replay_mutex_locked());
164         bool res = replay_has_interrupt();
165         if (res) {
166             replay_finish_event();
167         }
168         return res;
169     }
170
171     return true;
172 }
173
174 bool replay_has_interrupt(void)
175 {
176     bool res = false;
177     if (replay_mode == REPLAY_MODE_PLAY) {
178         g_assert(replay_mutex_locked());
179         replay_account_executed_instructions();
180         res = replay_next_event_is(EVENT_INTERRUPT);
181     }
182     return res;
183 }
184
185 void replay_shutdown_request(ShutdownCause cause)
186 {
187     if (replay_mode == REPLAY_MODE_RECORD) {
188         g_assert(replay_mutex_locked());
189         replay_put_event(EVENT_SHUTDOWN + cause);
190     }
191 }
192
193 bool replay_checkpoint(ReplayCheckpoint checkpoint)
194 {
195     bool res = false;
196     static bool in_checkpoint;
197     assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
198
199     if (!replay_file) {
200         return true;
201     }
202
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();
214
215     if (replay_mode == REPLAY_MODE_PLAY) {
216         g_assert(replay_mutex_locked());
217         if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
218             replay_finish_event();
219         } else if (replay_state.data_kind != EVENT_ASYNC) {
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 */
227         res = replay_state.data_kind != EVENT_ASYNC;
228     } else if (replay_mode == REPLAY_MODE_RECORD) {
229         g_assert(replay_mutex_locked());
230         replay_put_event(EVENT_CHECKPOINT + checkpoint);
231         /* This checkpoint belongs to several threads.
232            Processing events from different threads is
233            non-deterministic */
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) {
242             replay_save_events(checkpoint);
243         }
244         res = true;
245     }
246 out:
247     in_checkpoint = false;
248     return res;
249 }
250
251 bool 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
263 static 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
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);
289     replay_mode = mode;
290     replay_mutex_init();
291
292     replay_state.data_kind = -1;
293     replay_state.instruction_count = 0;
294     replay_state.current_icount = 0;
295     replay_state.has_unread_data = 0;
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
314 void replay_configure(QemuOpts *opts)
315 {
316     const char *fname;
317     const char *rr;
318     ReplayMode mode = REPLAY_MODE_NONE;
319     Location loc;
320
321     if (!opts) {
322         return;
323     }
324
325     loc_push_none(&loc);
326     qemu_opts_loc_restore(opts);
327
328     rr = qemu_opt_get(opts, "rr");
329     if (!rr) {
330         /* Just enabling icount */
331         goto out;
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
347     replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
348     replay_vmstate_register();
349     replay_enable(fname, mode);
350
351 out:
352     loc_pop(&loc);
353 }
354
355 void replay_start(void)
356 {
357     if (replay_mode == REPLAY_MODE_NONE) {
358         return;
359     }
360
361     if (replay_blockers) {
362         error_reportf_err(replay_blockers->data, "Record/replay: ");
363         exit(1);
364     }
365     if (!icount_enabled()) {
366         error_report("Please enable icount to use record/replay");
367         exit(1);
368     }
369
370     /* Timer for snapshotting will be set up here. */
371
372     replay_enable_events();
373 }
374
375 void 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) {
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);
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
407     g_free(replay_snapshot);
408     replay_snapshot = NULL;
409
410     replay_mode = REPLAY_MODE_NONE;
411
412     replay_finish_events();
413 }
414
415 void replay_add_blocker(Error *reason)
416 {
417     replay_blockers = g_slist_prepend(replay_blockers, reason);
418 }
419
420 const char *replay_get_filename(void)
421 {
422     return replay_filename;
423 }
This page took 0.048686 seconds and 4 git commands to generate.