xref: /qemu/replay/replay.c (revision 9277d81f)
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/replay.h"
15 #include "replay-internal.h"
16 #include "qemu/timer.h"
17 #include "qemu/main-loop.h"
18 #include "qemu/option.h"
19 #include "sysemu/cpus.h"
20 #include "sysemu/sysemu.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              0xe02007
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 bool 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) {
43         assert(replay_state.data_kind == EVENT_INSTRUCTION);
44         return event == EVENT_INSTRUCTION;
45     }
46 
47     while (true) {
48         if (event == replay_state.data_kind) {
49             res = true;
50         }
51         switch (replay_state.data_kind) {
52         case EVENT_SHUTDOWN ... EVENT_SHUTDOWN_LAST:
53             replay_finish_event();
54             qemu_system_shutdown_request(replay_state.data_kind -
55                                          EVENT_SHUTDOWN);
56             break;
57         default:
58             /* clock, time_t, checkpoint and other events */
59             return res;
60         }
61     }
62     return res;
63 }
64 
65 uint64_t replay_get_current_step(void)
66 {
67     return cpu_get_icount_raw();
68 }
69 
70 int 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 
81 void replay_account_executed_instructions(void)
82 {
83     if (replay_mode == REPLAY_MODE_PLAY) {
84         g_assert(replay_mutex_locked());
85         if (replay_state.instructions_count > 0) {
86             int count = (int)(replay_get_current_step()
87                               - replay_state.current_step);
88 
89             /* Time can only go forward */
90             assert(count >= 0);
91 
92             replay_state.instructions_count -= count;
93             replay_state.current_step += count;
94             if (replay_state.instructions_count == 0) {
95                 assert(replay_state.data_kind == EVENT_INSTRUCTION);
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         }
103     }
104 }
105 
106 bool replay_exception(void)
107 {
108 
109     if (replay_mode == REPLAY_MODE_RECORD) {
110         g_assert(replay_mutex_locked());
111         replay_save_instructions();
112         replay_put_event(EVENT_EXCEPTION);
113         return true;
114     } else if (replay_mode == REPLAY_MODE_PLAY) {
115         g_assert(replay_mutex_locked());
116         bool res = replay_has_exception();
117         if (res) {
118             replay_finish_event();
119         }
120         return res;
121     }
122 
123     return true;
124 }
125 
126 bool replay_has_exception(void)
127 {
128     bool res = false;
129     if (replay_mode == REPLAY_MODE_PLAY) {
130         g_assert(replay_mutex_locked());
131         replay_account_executed_instructions();
132         res = replay_next_event_is(EVENT_EXCEPTION);
133     }
134 
135     return res;
136 }
137 
138 bool replay_interrupt(void)
139 {
140     if (replay_mode == REPLAY_MODE_RECORD) {
141         g_assert(replay_mutex_locked());
142         replay_save_instructions();
143         replay_put_event(EVENT_INTERRUPT);
144         return true;
145     } else if (replay_mode == REPLAY_MODE_PLAY) {
146         g_assert(replay_mutex_locked());
147         bool res = replay_has_interrupt();
148         if (res) {
149             replay_finish_event();
150         }
151         return res;
152     }
153 
154     return true;
155 }
156 
157 bool replay_has_interrupt(void)
158 {
159     bool res = false;
160     if (replay_mode == REPLAY_MODE_PLAY) {
161         g_assert(replay_mutex_locked());
162         replay_account_executed_instructions();
163         res = replay_next_event_is(EVENT_INTERRUPT);
164     }
165     return res;
166 }
167 
168 void replay_shutdown_request(ShutdownCause cause)
169 {
170     if (replay_mode == REPLAY_MODE_RECORD) {
171         g_assert(replay_mutex_locked());
172         replay_put_event(EVENT_SHUTDOWN + cause);
173     }
174 }
175 
176 bool replay_checkpoint(ReplayCheckpoint checkpoint)
177 {
178     bool res = false;
179     static bool in_checkpoint;
180     assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
181 
182     if (!replay_file) {
183         return true;
184     }
185 
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();
197 
198     if (replay_mode == REPLAY_MODE_PLAY) {
199         g_assert(replay_mutex_locked());
200         if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
201             replay_finish_event();
202         } else if (replay_state.data_kind != EVENT_ASYNC) {
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 */
210         res = replay_state.data_kind != EVENT_ASYNC;
211     } else if (replay_mode == REPLAY_MODE_RECORD) {
212         g_assert(replay_mutex_locked());
213         replay_put_event(EVENT_CHECKPOINT + checkpoint);
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         }
220         res = true;
221     }
222 out:
223     in_checkpoint = false;
224     return res;
225 }
226 
227 static 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 
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);
253     replay_mode = mode;
254     replay_mutex_init();
255 
256     replay_state.data_kind = -1;
257     replay_state.instructions_count = 0;
258     replay_state.current_step = 0;
259     replay_state.has_unread_data = 0;
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 
278 void replay_configure(QemuOpts *opts)
279 {
280     const char *fname;
281     const char *rr;
282     ReplayMode mode = REPLAY_MODE_NONE;
283     Location loc;
284 
285     if (!opts) {
286         return;
287     }
288 
289     loc_push_none(&loc);
290     qemu_opts_loc_restore(opts);
291 
292     rr = qemu_opt_get(opts, "rr");
293     if (!rr) {
294         /* Just enabling icount */
295         goto out;
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 
311     replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
312     replay_vmstate_register();
313     replay_enable(fname, mode);
314 
315 out:
316     loc_pop(&loc);
317 }
318 
319 void replay_start(void)
320 {
321     if (replay_mode == REPLAY_MODE_NONE) {
322         return;
323     }
324 
325     if (replay_blockers) {
326         error_reportf_err(replay_blockers->data, "Record/replay: ");
327         exit(1);
328     }
329     if (!use_icount) {
330         error_report("Please enable icount to use record/replay");
331         exit(1);
332     }
333 
334     /* Timer for snapshotting will be set up here. */
335 
336     replay_enable_events();
337 }
338 
339 void 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 
366     g_free(replay_snapshot);
367     replay_snapshot = NULL;
368 
369     replay_finish_events();
370 }
371 
372 void replay_add_blocker(Error *reason)
373 {
374     replay_blockers = g_slist_prepend(replay_blockers, reason);
375 }
376