]> git.proxmox.com Git - mirror_qemu.git/blame - replay/replay.c
target/hppa: Update to SeaBIOS-hppa version 9
[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. */
3e21408b 25#define REPLAY_VERSION 0xe0200c
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;
83ecdb18 77 g_assert(replay_mutex_locked());
8b427044 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 87 }
8b427044
PD
88 return res;
89}
90
91void replay_account_executed_instructions(void)
92{
93 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 94 g_assert(replay_mutex_locked());
13f26713 95 if (replay_state.instruction_count > 0) {
366a85e4 96 replay_advance_current_icount(replay_get_current_icount());
8b427044 97 }
8b427044
PD
98 }
99}
6f060969
PD
100
101bool replay_exception(void)
102{
d759c951 103
6f060969 104 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 105 g_assert(replay_mutex_locked());
6f060969 106 replay_save_instructions();
6f060969 107 replay_put_event(EVENT_EXCEPTION);
6f060969
PD
108 return true;
109 } else if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 110 g_assert(replay_mutex_locked());
6f060969
PD
111 bool res = replay_has_exception();
112 if (res) {
6f060969 113 replay_finish_event();
6f060969
PD
114 }
115 return res;
116 }
117
118 return true;
119}
120
121bool replay_has_exception(void)
122{
123 bool res = false;
124 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 125 g_assert(replay_mutex_locked());
6f060969 126 replay_account_executed_instructions();
6f060969 127 res = replay_next_event_is(EVENT_EXCEPTION);
6f060969
PD
128 }
129
130 return res;
131}
132
133bool replay_interrupt(void)
134{
135 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 136 g_assert(replay_mutex_locked());
6f060969 137 replay_save_instructions();
6f060969 138 replay_put_event(EVENT_INTERRUPT);
6f060969
PD
139 return true;
140 } else if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 141 g_assert(replay_mutex_locked());
6f060969
PD
142 bool res = replay_has_interrupt();
143 if (res) {
6f060969 144 replay_finish_event();
6f060969
PD
145 }
146 return res;
147 }
148
149 return true;
150}
151
152bool replay_has_interrupt(void)
153{
154 bool res = false;
155 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 156 g_assert(replay_mutex_locked());
6f060969 157 replay_account_executed_instructions();
6f060969 158 res = replay_next_event_is(EVENT_INTERRUPT);
6f060969
PD
159 }
160 return res;
161}
b60c48a7 162
802f045a 163void replay_shutdown_request(ShutdownCause cause)
b60c48a7
PD
164{
165 if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 166 g_assert(replay_mutex_locked());
802f045a 167 replay_put_event(EVENT_SHUTDOWN + cause);
b60c48a7
PD
168 }
169}
8bd7f71d
PD
170
171bool replay_checkpoint(ReplayCheckpoint checkpoint)
172{
8bd7f71d 173 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
8bd7f71d 174
66eb7825 175 replay_save_instructions();
8bd7f71d
PD
176
177 if (replay_mode == REPLAY_MODE_PLAY) {
d759c951 178 g_assert(replay_mutex_locked());
8bd7f71d
PD
179 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
180 replay_finish_event();
60618e2d
PD
181 } else {
182 return false;
8bd7f71d 183 }
8bd7f71d 184 } else if (replay_mode == REPLAY_MODE_RECORD) {
d759c951 185 g_assert(replay_mutex_locked());
8bd7f71d 186 replay_put_event(EVENT_CHECKPOINT + checkpoint);
8bd7f71d 187 }
60618e2d
PD
188 return true;
189}
190
191void replay_async_events(void)
192{
193 static bool processing = false;
194 /*
195 * If we are already processing the events, recursion may occur
196 * in case of incorrect implementation when HW event modifies timers.
197 * Timer modification may invoke the icount warp, event processing,
198 * and cause the recursion.
199 */
200 g_assert(!processing);
201 processing = true;
202
203 replay_save_instructions();
204
205 if (replay_mode == REPLAY_MODE_PLAY) {
206 g_assert(replay_mutex_locked());
207 replay_read_events();
208 } else if (replay_mode == REPLAY_MODE_RECORD) {
209 g_assert(replay_mutex_locked());
210 replay_save_events();
211 }
212 processing = false;
8bd7f71d 213}
7615936e 214
60618e2d 215bool replay_has_event(void)
0c08185f
PD
216{
217 bool res = false;
218 if (replay_mode == REPLAY_MODE_PLAY) {
219 g_assert(replay_mutex_locked());
220 replay_account_executed_instructions();
221 res = EVENT_CHECKPOINT <= replay_state.data_kind
222 && replay_state.data_kind <= EVENT_CHECKPOINT_LAST;
3e21408b
PD
223 res = res || (EVENT_ASYNC <= replay_state.data_kind
224 && replay_state.data_kind <= EVENT_ASYNC_LAST);
0c08185f
PD
225 }
226 return res;
227}
228
7615936e
PD
229static void replay_enable(const char *fname, int mode)
230{
231 const char *fmode = NULL;
232 assert(!replay_file);
233
234 switch (mode) {
235 case REPLAY_MODE_RECORD:
236 fmode = "wb";
237 break;
238 case REPLAY_MODE_PLAY:
239 fmode = "rb";
240 break;
241 default:
242 fprintf(stderr, "Replay: internal error: invalid replay mode\n");
243 exit(1);
244 }
245
246 atexit(replay_finish);
247
7615936e
PD
248 replay_file = fopen(fname, fmode);
249 if (replay_file == NULL) {
250 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
251 exit(1);
252 }
253
254 replay_filename = g_strdup(fname);
7615936e 255 replay_mode = mode;
d759c951
AB
256 replay_mutex_init();
257
f186d64d 258 replay_state.data_kind = -1;
13f26713
PD
259 replay_state.instruction_count = 0;
260 replay_state.current_icount = 0;
f186d64d 261 replay_state.has_unread_data = 0;
7615936e
PD
262
263 /* skip file header for RECORD and check it for PLAY */
264 if (replay_mode == REPLAY_MODE_RECORD) {
265 fseek(replay_file, HEADER_SIZE, SEEK_SET);
266 } else if (replay_mode == REPLAY_MODE_PLAY) {
267 unsigned int version = replay_get_dword();
268 if (version != REPLAY_VERSION) {
269 fprintf(stderr, "Replay: invalid input log file version\n");
270 exit(1);
271 }
272 /* go to the beginning */
273 fseek(replay_file, HEADER_SIZE, SEEK_SET);
274 replay_fetch_data_kind();
275 }
276
277 replay_init_events();
278}
279
280void replay_configure(QemuOpts *opts)
281{
282 const char *fname;
283 const char *rr;
284 ReplayMode mode = REPLAY_MODE_NONE;
890ad550
EH
285 Location loc;
286
287 if (!opts) {
288 return;
289 }
290
291 loc_push_none(&loc);
292 qemu_opts_loc_restore(opts);
7615936e
PD
293
294 rr = qemu_opt_get(opts, "rr");
295 if (!rr) {
296 /* Just enabling icount */
d9d3aaea 297 goto out;
7615936e
PD
298 } else if (!strcmp(rr, "record")) {
299 mode = REPLAY_MODE_RECORD;
300 } else if (!strcmp(rr, "replay")) {
301 mode = REPLAY_MODE_PLAY;
302 } else {
303 error_report("Invalid icount rr option: %s", rr);
304 exit(1);
305 }
306
307 fname = qemu_opt_get(opts, "rrfile");
308 if (!fname) {
309 error_report("File name not specified for replay");
310 exit(1);
311 }
312
9c2037d0 313 replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
306e196f 314 replay_vmstate_register();
7615936e 315 replay_enable(fname, mode);
890ad550 316
d9d3aaea 317out:
890ad550 318 loc_pop(&loc);
7615936e
PD
319}
320
321void replay_start(void)
322{
323 if (replay_mode == REPLAY_MODE_NONE) {
324 return;
325 }
326
0194749a 327 if (replay_blockers) {
c29b77f9 328 error_reportf_err(replay_blockers->data, "Record/replay: ");
0194749a
PD
329 exit(1);
330 }
740b1759 331 if (!icount_enabled()) {
4c27b859
PD
332 error_report("Please enable icount to use record/replay");
333 exit(1);
334 }
0194749a 335
7615936e
PD
336 /* Timer for snapshotting will be set up here. */
337
338 replay_enable_events();
339}
340
341void replay_finish(void)
342{
343 if (replay_mode == REPLAY_MODE_NONE) {
344 return;
345 }
346
347 replay_save_instructions();
348
349 /* finalize the file */
350 if (replay_file) {
351 if (replay_mode == REPLAY_MODE_RECORD) {
ed5d7ff3
PD
352 /*
353 * Can't do it in the signal handler, therefore
354 * add shutdown event here for the case of Ctrl-C.
355 */
356 replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL);
7615936e
PD
357 /* write end event */
358 replay_put_event(EVENT_END);
359
360 /* write header */
361 fseek(replay_file, 0, SEEK_SET);
362 replay_put_dword(REPLAY_VERSION);
363 }
364
365 fclose(replay_file);
366 replay_file = NULL;
367 }
76eb88b1
MA
368 g_free(replay_filename);
369 replay_filename = NULL;
7615936e 370
9c2037d0
PD
371 g_free(replay_snapshot);
372 replay_snapshot = NULL;
373
7615936e 374 replay_finish_events();
c4b8ffcb 375 replay_mode = REPLAY_MODE_NONE;
7615936e 376}
0194749a 377
0ec8384f 378void replay_add_blocker(const char *feature)
0194749a 379{
0ec8384f
MA
380 Error *reason = NULL;
381
382 error_setg(&reason, "Record/replay feature is not supported for '%s'",
383 feature);
0194749a
PD
384 replay_blockers = g_slist_prepend(replay_blockers, reason);
385}
56db1198
PD
386
387const char *replay_get_filename(void)
388{
389 return replay_filename;
390}