summaryrefslogtreecommitdiffstats
path: root/qemu/replay/replay.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/replay/replay.c')
-rw-r--r--qemu/replay/replay.c354
1 files changed, 0 insertions, 354 deletions
diff --git a/qemu/replay/replay.c b/qemu/replay/replay.c
deleted file mode 100644
index 167fd2942..000000000
--- a/qemu/replay/replay.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * replay.c
- *
- * Copyright (c) 2010-2015 Institute for System Programming
- * of the Russian Academy of Sciences.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "sysemu/replay.h"
-#include "replay-internal.h"
-#include "qemu/timer.h"
-#include "qemu/main-loop.h"
-#include "sysemu/sysemu.h"
-#include "qemu/error-report.h"
-
-/* Current version of the replay mechanism.
- Increase it when file format changes. */
-#define REPLAY_VERSION 0xe02004
-/* Size of replay log header */
-#define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
-
-ReplayMode replay_mode = REPLAY_MODE_NONE;
-
-/* Name of replay file */
-static char *replay_filename;
-ReplayState replay_state;
-static GSList *replay_blockers;
-
-bool replay_next_event_is(int event)
-{
- bool res = false;
-
- /* nothing to skip - not all instructions used */
- if (replay_state.instructions_count != 0) {
- assert(replay_data_kind == EVENT_INSTRUCTION);
- return event == EVENT_INSTRUCTION;
- }
-
- while (true) {
- if (event == replay_data_kind) {
- res = true;
- }
- switch (replay_data_kind) {
- case EVENT_SHUTDOWN:
- replay_finish_event();
- qemu_system_shutdown_request();
- break;
- default:
- /* clock, time_t, checkpoint and other events */
- return res;
- }
- }
- return res;
-}
-
-uint64_t replay_get_current_step(void)
-{
- return cpu_get_icount_raw();
-}
-
-int replay_get_instructions(void)
-{
- int res = 0;
- replay_mutex_lock();
- if (replay_next_event_is(EVENT_INSTRUCTION)) {
- res = replay_state.instructions_count;
- }
- replay_mutex_unlock();
- return res;
-}
-
-void replay_account_executed_instructions(void)
-{
- if (replay_mode == REPLAY_MODE_PLAY) {
- replay_mutex_lock();
- if (replay_state.instructions_count > 0) {
- int count = (int)(replay_get_current_step()
- - replay_state.current_step);
- replay_state.instructions_count -= count;
- replay_state.current_step += count;
- if (replay_state.instructions_count == 0) {
- assert(replay_data_kind == EVENT_INSTRUCTION);
- replay_finish_event();
- /* Wake up iothread. This is required because
- timers will not expire until clock counters
- will be read from the log. */
- qemu_notify_event();
- }
- }
- replay_mutex_unlock();
- }
-}
-
-bool replay_exception(void)
-{
- if (replay_mode == REPLAY_MODE_RECORD) {
- replay_save_instructions();
- replay_mutex_lock();
- replay_put_event(EVENT_EXCEPTION);
- replay_mutex_unlock();
- return true;
- } else if (replay_mode == REPLAY_MODE_PLAY) {
- bool res = replay_has_exception();
- if (res) {
- replay_mutex_lock();
- replay_finish_event();
- replay_mutex_unlock();
- }
- return res;
- }
-
- return true;
-}
-
-bool replay_has_exception(void)
-{
- bool res = false;
- if (replay_mode == REPLAY_MODE_PLAY) {
- replay_account_executed_instructions();
- replay_mutex_lock();
- res = replay_next_event_is(EVENT_EXCEPTION);
- replay_mutex_unlock();
- }
-
- return res;
-}
-
-bool replay_interrupt(void)
-{
- if (replay_mode == REPLAY_MODE_RECORD) {
- replay_save_instructions();
- replay_mutex_lock();
- replay_put_event(EVENT_INTERRUPT);
- replay_mutex_unlock();
- return true;
- } else if (replay_mode == REPLAY_MODE_PLAY) {
- bool res = replay_has_interrupt();
- if (res) {
- replay_mutex_lock();
- replay_finish_event();
- replay_mutex_unlock();
- }
- return res;
- }
-
- return true;
-}
-
-bool replay_has_interrupt(void)
-{
- bool res = false;
- if (replay_mode == REPLAY_MODE_PLAY) {
- replay_account_executed_instructions();
- replay_mutex_lock();
- res = replay_next_event_is(EVENT_INTERRUPT);
- replay_mutex_unlock();
- }
- return res;
-}
-
-void replay_shutdown_request(void)
-{
- if (replay_mode == REPLAY_MODE_RECORD) {
- replay_mutex_lock();
- replay_put_event(EVENT_SHUTDOWN);
- replay_mutex_unlock();
- }
-}
-
-bool replay_checkpoint(ReplayCheckpoint checkpoint)
-{
- bool res = false;
- assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
- replay_save_instructions();
-
- if (!replay_file) {
- return true;
- }
-
- replay_mutex_lock();
-
- if (replay_mode == REPLAY_MODE_PLAY) {
- if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
- replay_finish_event();
- } else if (replay_data_kind != EVENT_ASYNC) {
- res = false;
- goto out;
- }
- replay_read_events(checkpoint);
- /* replay_read_events may leave some unread events.
- Return false if not all of the events associated with
- checkpoint were processed */
- res = replay_data_kind != EVENT_ASYNC;
- } else if (replay_mode == REPLAY_MODE_RECORD) {
- replay_put_event(EVENT_CHECKPOINT + checkpoint);
- replay_save_events(checkpoint);
- res = true;
- }
-out:
- replay_mutex_unlock();
- return res;
-}
-
-static void replay_enable(const char *fname, int mode)
-{
- const char *fmode = NULL;
- assert(!replay_file);
-
- switch (mode) {
- case REPLAY_MODE_RECORD:
- fmode = "wb";
- break;
- case REPLAY_MODE_PLAY:
- fmode = "rb";
- break;
- default:
- fprintf(stderr, "Replay: internal error: invalid replay mode\n");
- exit(1);
- }
-
- atexit(replay_finish);
-
- replay_mutex_init();
-
- replay_file = fopen(fname, fmode);
- if (replay_file == NULL) {
- fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
- exit(1);
- }
-
- replay_filename = g_strdup(fname);
-
- replay_mode = mode;
- replay_data_kind = -1;
- replay_state.instructions_count = 0;
- replay_state.current_step = 0;
-
- /* skip file header for RECORD and check it for PLAY */
- if (replay_mode == REPLAY_MODE_RECORD) {
- fseek(replay_file, HEADER_SIZE, SEEK_SET);
- } else if (replay_mode == REPLAY_MODE_PLAY) {
- unsigned int version = replay_get_dword();
- if (version != REPLAY_VERSION) {
- fprintf(stderr, "Replay: invalid input log file version\n");
- exit(1);
- }
- /* go to the beginning */
- fseek(replay_file, HEADER_SIZE, SEEK_SET);
- replay_fetch_data_kind();
- }
-
- replay_init_events();
-}
-
-void replay_configure(QemuOpts *opts)
-{
- const char *fname;
- const char *rr;
- ReplayMode mode = REPLAY_MODE_NONE;
- Location loc;
-
- if (!opts) {
- return;
- }
-
- loc_push_none(&loc);
- qemu_opts_loc_restore(opts);
-
- rr = qemu_opt_get(opts, "rr");
- if (!rr) {
- /* Just enabling icount */
- goto out;
- } else if (!strcmp(rr, "record")) {
- mode = REPLAY_MODE_RECORD;
- } else if (!strcmp(rr, "replay")) {
- mode = REPLAY_MODE_PLAY;
- } else {
- error_report("Invalid icount rr option: %s", rr);
- exit(1);
- }
-
- fname = qemu_opt_get(opts, "rrfile");
- if (!fname) {
- error_report("File name not specified for replay");
- exit(1);
- }
-
- replay_enable(fname, mode);
-
-out:
- loc_pop(&loc);
-}
-
-void replay_start(void)
-{
- if (replay_mode == REPLAY_MODE_NONE) {
- return;
- }
-
- if (replay_blockers) {
- error_reportf_err(replay_blockers->data, "Record/replay: ");
- exit(1);
- }
- if (!use_icount) {
- error_report("Please enable icount to use record/replay");
- exit(1);
- }
-
- /* Timer for snapshotting will be set up here. */
-
- replay_enable_events();
-}
-
-void replay_finish(void)
-{
- if (replay_mode == REPLAY_MODE_NONE) {
- return;
- }
-
- replay_save_instructions();
-
- /* finalize the file */
- if (replay_file) {
- if (replay_mode == REPLAY_MODE_RECORD) {
- /* write end event */
- replay_put_event(EVENT_END);
-
- /* write header */
- fseek(replay_file, 0, SEEK_SET);
- replay_put_dword(REPLAY_VERSION);
- }
-
- fclose(replay_file);
- replay_file = NULL;
- }
- if (replay_filename) {
- g_free(replay_filename);
- replay_filename = NULL;
- }
-
- replay_finish_events();
- replay_mutex_destroy();
-}
-
-void replay_add_blocker(Error *reason)
-{
- replay_blockers = g_slist_prepend(replay_blockers, reason);
-}