/* * replay-snapshot.c * * Copyright (c) 2010-2016 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 "sysemu/replay.h" #include "replay-internal.h" #include "monitor/monitor.h" #include "qapi/qmp/qstring.h" #include "qemu/error-report.h" #include "migration/vmstate.h" #include "migration/snapshot.h" static int replay_pre_save(void *opaque) { ReplayState *state = opaque; state->file_offset = ftell(replay_file); state->host_clock_last = qemu_clock_get_last(QEMU_CLOCK_HOST); return 0; } static int replay_post_load(void *opaque, int version_id) { ReplayState *state = opaque; if (replay_mode == REPLAY_MODE_PLAY) { fseek(replay_file, state->file_offset, SEEK_SET); qemu_clock_set_last(QEMU_CLOCK_HOST, state->host_clock_last); /* If this was a vmstate, saved in recording mode, we need to initialize replay data fields. */ replay_fetch_data_kind(); } else if (replay_mode == REPLAY_MODE_RECORD) { /* This is only useful for loading the initial state. Therefore reset all the counters. */ state->instructions_count = 0; state->block_request_id = 0; } return 0; } static const VMStateDescription vmstate_replay = { .name = "replay", .version_id = 1, .minimum_version_id = 1, .pre_save = replay_pre_save, .post_load = replay_post_load, .fields = (VMStateField[]) { VMSTATE_INT64_ARRAY(cached_clock, ReplayState, REPLAY_CLOCK_COUNT), VMSTATE_UINT64(current_step, ReplayState), VMSTATE_INT32(instructions_count, ReplayState), VMSTATE_UINT32(data_kind, ReplayState), VMSTATE_UINT32(has_unread_data, ReplayState), VMSTATE_UINT64(file_offset, ReplayState), VMSTATE_UINT64(block_request_id, ReplayState), VMSTATE_UINT64(host_clock_last, ReplayState), VMSTATE_INT32(read_event_kind, ReplayState), VMSTATE_UINT64(read_event_id, ReplayState), VMSTATE_INT32(read_event_checkpoint, ReplayState), VMSTATE_END_OF_LIST() }, }; void replay_vmstate_register(void) { vmstate_register(NULL, 0, &vmstate_replay, &replay_state); } void replay_vmstate_init(void) { Error *err = NULL; if (replay_snapshot) { if (replay_mode == REPLAY_MODE_RECORD) { if (save_snapshot(replay_snapshot, &err) != 0) { error_report_err(err); error_report("Could not create snapshot for icount record"); exit(1); } } else if (replay_mode == REPLAY_MODE_PLAY) { if (load_snapshot(replay_snapshot, &err) != 0) { error_report_err(err); error_report("Could not load snapshot for icount replay"); exit(1); } } } } bool replay_can_snapshot(void) { return replay_mode == REPLAY_MODE_NONE || !replay_has_events(); }