xref: /openbmc/qemu/replay/replay.c (revision 3f53bc61)
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 "qemu-common.h"
15 #include "sysemu/replay.h"
16 #include "replay-internal.h"
17 #include "qemu/timer.h"
18 #include "qemu/main-loop.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              0xe02005
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:
53             replay_finish_event();
54             qemu_system_shutdown_request();
55             break;
56         default:
57             /* clock, time_t, checkpoint and other events */
58             return res;
59         }
60     }
61     return res;
62 }
63 
64 uint64_t replay_get_current_step(void)
65 {
66     return cpu_get_icount_raw();
67 }
68 
69 int replay_get_instructions(void)
70 {
71     int res = 0;
72     replay_mutex_lock();
73     if (replay_next_event_is(EVENT_INSTRUCTION)) {
74         res = replay_state.instructions_count;
75     }
76     replay_mutex_unlock();
77     return res;
78 }
79 
80 void replay_account_executed_instructions(void)
81 {
82     if (replay_mode == REPLAY_MODE_PLAY) {
83         replay_mutex_lock();
84         if (replay_state.instructions_count > 0) {
85             int count = (int)(replay_get_current_step()
86                               - replay_state.current_step);
87             replay_state.instructions_count -= count;
88             replay_state.current_step += count;
89             if (replay_state.instructions_count == 0) {
90                 assert(replay_state.data_kind == EVENT_INSTRUCTION);
91                 replay_finish_event();
92                 /* Wake up iothread. This is required because
93                    timers will not expire until clock counters
94                    will be read from the log. */
95                 qemu_notify_event();
96             }
97         }
98         replay_mutex_unlock();
99     }
100 }
101 
102 bool replay_exception(void)
103 {
104     if (replay_mode == REPLAY_MODE_RECORD) {
105         replay_save_instructions();
106         replay_mutex_lock();
107         replay_put_event(EVENT_EXCEPTION);
108         replay_mutex_unlock();
109         return true;
110     } else if (replay_mode == REPLAY_MODE_PLAY) {
111         bool res = replay_has_exception();
112         if (res) {
113             replay_mutex_lock();
114             replay_finish_event();
115             replay_mutex_unlock();
116         }
117         return res;
118     }
119 
120     return true;
121 }
122 
123 bool replay_has_exception(void)
124 {
125     bool res = false;
126     if (replay_mode == REPLAY_MODE_PLAY) {
127         replay_account_executed_instructions();
128         replay_mutex_lock();
129         res = replay_next_event_is(EVENT_EXCEPTION);
130         replay_mutex_unlock();
131     }
132 
133     return res;
134 }
135 
136 bool replay_interrupt(void)
137 {
138     if (replay_mode == REPLAY_MODE_RECORD) {
139         replay_save_instructions();
140         replay_mutex_lock();
141         replay_put_event(EVENT_INTERRUPT);
142         replay_mutex_unlock();
143         return true;
144     } else if (replay_mode == REPLAY_MODE_PLAY) {
145         bool res = replay_has_interrupt();
146         if (res) {
147             replay_mutex_lock();
148             replay_finish_event();
149             replay_mutex_unlock();
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         replay_account_executed_instructions();
162         replay_mutex_lock();
163         res = replay_next_event_is(EVENT_INTERRUPT);
164         replay_mutex_unlock();
165     }
166     return res;
167 }
168 
169 void replay_shutdown_request(void)
170 {
171     if (replay_mode == REPLAY_MODE_RECORD) {
172         replay_mutex_lock();
173         replay_put_event(EVENT_SHUTDOWN);
174         replay_mutex_unlock();
175     }
176 }
177 
178 bool replay_checkpoint(ReplayCheckpoint checkpoint)
179 {
180     bool res = false;
181     assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
182     replay_save_instructions();
183 
184     if (!replay_file) {
185         return true;
186     }
187 
188     replay_mutex_lock();
189 
190     if (replay_mode == REPLAY_MODE_PLAY) {
191         if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
192             replay_finish_event();
193         } else if (replay_state.data_kind != EVENT_ASYNC) {
194             res = false;
195             goto out;
196         }
197         replay_read_events(checkpoint);
198         /* replay_read_events may leave some unread events.
199            Return false if not all of the events associated with
200            checkpoint were processed */
201         res = replay_state.data_kind != EVENT_ASYNC;
202     } else if (replay_mode == REPLAY_MODE_RECORD) {
203         replay_put_event(EVENT_CHECKPOINT + checkpoint);
204         replay_save_events(checkpoint);
205         res = true;
206     }
207 out:
208     replay_mutex_unlock();
209     return res;
210 }
211 
212 static void replay_enable(const char *fname, int mode)
213 {
214     const char *fmode = NULL;
215     assert(!replay_file);
216 
217     switch (mode) {
218     case REPLAY_MODE_RECORD:
219         fmode = "wb";
220         break;
221     case REPLAY_MODE_PLAY:
222         fmode = "rb";
223         break;
224     default:
225         fprintf(stderr, "Replay: internal error: invalid replay mode\n");
226         exit(1);
227     }
228 
229     atexit(replay_finish);
230 
231     replay_mutex_init();
232 
233     replay_file = fopen(fname, fmode);
234     if (replay_file == NULL) {
235         fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
236         exit(1);
237     }
238 
239     replay_filename = g_strdup(fname);
240 
241     replay_mode = mode;
242     replay_state.data_kind = -1;
243     replay_state.instructions_count = 0;
244     replay_state.current_step = 0;
245     replay_state.has_unread_data = 0;
246 
247     /* skip file header for RECORD and check it for PLAY */
248     if (replay_mode == REPLAY_MODE_RECORD) {
249         fseek(replay_file, HEADER_SIZE, SEEK_SET);
250     } else if (replay_mode == REPLAY_MODE_PLAY) {
251         unsigned int version = replay_get_dword();
252         if (version != REPLAY_VERSION) {
253             fprintf(stderr, "Replay: invalid input log file version\n");
254             exit(1);
255         }
256         /* go to the beginning */
257         fseek(replay_file, HEADER_SIZE, SEEK_SET);
258         replay_fetch_data_kind();
259     }
260 
261     replay_init_events();
262 }
263 
264 void replay_configure(QemuOpts *opts)
265 {
266     const char *fname;
267     const char *rr;
268     ReplayMode mode = REPLAY_MODE_NONE;
269     Location loc;
270 
271     if (!opts) {
272         return;
273     }
274 
275     loc_push_none(&loc);
276     qemu_opts_loc_restore(opts);
277 
278     rr = qemu_opt_get(opts, "rr");
279     if (!rr) {
280         /* Just enabling icount */
281         goto out;
282     } else if (!strcmp(rr, "record")) {
283         mode = REPLAY_MODE_RECORD;
284     } else if (!strcmp(rr, "replay")) {
285         mode = REPLAY_MODE_PLAY;
286     } else {
287         error_report("Invalid icount rr option: %s", rr);
288         exit(1);
289     }
290 
291     fname = qemu_opt_get(opts, "rrfile");
292     if (!fname) {
293         error_report("File name not specified for replay");
294         exit(1);
295     }
296 
297     replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
298     replay_vmstate_register();
299     replay_enable(fname, mode);
300 
301 out:
302     loc_pop(&loc);
303 }
304 
305 void replay_start(void)
306 {
307     if (replay_mode == REPLAY_MODE_NONE) {
308         return;
309     }
310 
311     if (replay_blockers) {
312         error_reportf_err(replay_blockers->data, "Record/replay: ");
313         exit(1);
314     }
315     if (!use_icount) {
316         error_report("Please enable icount to use record/replay");
317         exit(1);
318     }
319 
320     /* Timer for snapshotting will be set up here. */
321 
322     replay_enable_events();
323 }
324 
325 void replay_finish(void)
326 {
327     if (replay_mode == REPLAY_MODE_NONE) {
328         return;
329     }
330 
331     replay_save_instructions();
332 
333     /* finalize the file */
334     if (replay_file) {
335         if (replay_mode == REPLAY_MODE_RECORD) {
336             /* write end event */
337             replay_put_event(EVENT_END);
338 
339             /* write header */
340             fseek(replay_file, 0, SEEK_SET);
341             replay_put_dword(REPLAY_VERSION);
342         }
343 
344         fclose(replay_file);
345         replay_file = NULL;
346     }
347     if (replay_filename) {
348         g_free(replay_filename);
349         replay_filename = NULL;
350     }
351 
352     g_free(replay_snapshot);
353     replay_snapshot = NULL;
354 
355     replay_finish_events();
356     replay_mutex_destroy();
357 }
358 
359 void replay_add_blocker(Error *reason)
360 {
361     replay_blockers = g_slist_prepend(replay_blockers, reason);
362 }
363