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