diff options
Diffstat (limited to 'qemu/replay')
-rw-r--r-- | qemu/replay/Makefile.objs | 6 | ||||
-rwxr-xr-x | qemu/replay/replay-char.c | 168 | ||||
-rw-r--r-- | qemu/replay/replay-events.c | 311 | ||||
-rw-r--r-- | qemu/replay/replay-input.c | 169 | ||||
-rw-r--r-- | qemu/replay/replay-internal.c | 207 | ||||
-rw-r--r-- | qemu/replay/replay-internal.h | 158 | ||||
-rw-r--r-- | qemu/replay/replay-time.c | 65 | ||||
-rw-r--r-- | qemu/replay/replay.c | 354 |
8 files changed, 0 insertions, 1438 deletions
diff --git a/qemu/replay/Makefile.objs b/qemu/replay/Makefile.objs deleted file mode 100644 index fcb3f74d6..000000000 --- a/qemu/replay/Makefile.objs +++ /dev/null @@ -1,6 +0,0 @@ -common-obj-y += replay.o -common-obj-y += replay-internal.o -common-obj-y += replay-events.o -common-obj-y += replay-time.o -common-obj-y += replay-input.o -common-obj-y += replay-char.o diff --git a/qemu/replay/replay-char.c b/qemu/replay/replay-char.c deleted file mode 100755 index 23b692297..000000000 --- a/qemu/replay/replay-char.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * replay-char.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 <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "qemu/osdep.h" -#include "qemu/error-report.h" -#include "sysemu/replay.h" -#include "replay-internal.h" -#include "sysemu/sysemu.h" -#include "sysemu/char.h" - -/* Char drivers that generate qemu_chr_be_write events - that should be saved into the log. */ -static CharDriverState **char_drivers; -static int drivers_count; - -/* Char event attributes. */ -typedef struct CharEvent { - int id; - uint8_t *buf; - size_t len; -} CharEvent; - -static int find_char_driver(CharDriverState *chr) -{ - int i = 0; - for ( ; i < drivers_count ; ++i) { - if (char_drivers[i] == chr) { - return i; - } - } - return -1; -} - -void replay_register_char_driver(CharDriverState *chr) -{ - if (replay_mode == REPLAY_MODE_NONE) { - return; - } - char_drivers = g_realloc(char_drivers, - sizeof(*char_drivers) * (drivers_count + 1)); - char_drivers[drivers_count++] = chr; -} - -void replay_chr_be_write(CharDriverState *s, uint8_t *buf, int len) -{ - CharEvent *event = g_malloc0(sizeof(CharEvent)); - - event->id = find_char_driver(s); - if (event->id < 0) { - fprintf(stderr, "Replay: cannot find char driver\n"); - exit(1); - } - event->buf = g_malloc(len); - memcpy(event->buf, buf, len); - event->len = len; - - replay_add_event(REPLAY_ASYNC_EVENT_CHAR_READ, event, NULL, 0); -} - -void replay_event_char_read_run(void *opaque) -{ - CharEvent *event = (CharEvent *)opaque; - - qemu_chr_be_write_impl(char_drivers[event->id], event->buf, - (int)event->len); - - g_free(event->buf); - g_free(event); -} - -void replay_event_char_read_save(void *opaque) -{ - CharEvent *event = (CharEvent *)opaque; - - replay_put_byte(event->id); - replay_put_array(event->buf, event->len); -} - -void *replay_event_char_read_load(void) -{ - CharEvent *event = g_malloc0(sizeof(CharEvent)); - - event->id = replay_get_byte(); - replay_get_array_alloc(&event->buf, &event->len); - - return event; -} - -void replay_char_write_event_save(int res, int offset) -{ - replay_save_instructions(); - replay_mutex_lock(); - replay_put_event(EVENT_CHAR_WRITE); - replay_put_dword(res); - replay_put_dword(offset); - replay_mutex_unlock(); -} - -void replay_char_write_event_load(int *res, int *offset) -{ - replay_account_executed_instructions(); - replay_mutex_lock(); - if (replay_next_event_is(EVENT_CHAR_WRITE)) { - *res = replay_get_dword(); - *offset = replay_get_dword(); - replay_finish_event(); - replay_mutex_unlock(); - } else { - replay_mutex_unlock(); - error_report("Missing character write event in the replay log"); - exit(1); - } -} - -int replay_char_read_all_load(uint8_t *buf) -{ - replay_mutex_lock(); - if (replay_next_event_is(EVENT_CHAR_READ_ALL)) { - size_t size; - int res; - replay_get_array(buf, &size); - replay_finish_event(); - replay_mutex_unlock(); - res = (int)size; - assert(res >= 0); - return res; - } else if (replay_next_event_is(EVENT_CHAR_READ_ALL_ERROR)) { - int res = replay_get_dword(); - replay_finish_event(); - replay_mutex_unlock(); - return res; - } else { - replay_mutex_unlock(); - error_report("Missing character read all event in the replay log"); - exit(1); - } -} - -void replay_char_read_all_save_error(int res) -{ - assert(res < 0); - replay_save_instructions(); - replay_mutex_lock(); - replay_put_event(EVENT_CHAR_READ_ALL_ERROR); - replay_put_dword(res); - replay_mutex_unlock(); -} - -void replay_char_read_all_save_buf(uint8_t *buf, int offset) -{ - replay_save_instructions(); - replay_mutex_lock(); - replay_put_event(EVENT_CHAR_READ_ALL); - replay_put_array(buf, offset); - replay_mutex_unlock(); -} diff --git a/qemu/replay/replay-events.c b/qemu/replay/replay-events.c deleted file mode 100644 index 3807245ae..000000000 --- a/qemu/replay/replay-events.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * replay-events.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 "qemu-common.h" -#include "qemu/error-report.h" -#include "sysemu/replay.h" -#include "replay-internal.h" -#include "block/aio.h" -#include "ui/input.h" - -typedef struct Event { - ReplayAsyncEventKind event_kind; - void *opaque; - void *opaque2; - uint64_t id; - - QTAILQ_ENTRY(Event) events; -} Event; - -static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list); -static unsigned int read_event_kind = -1; -static uint64_t read_id = -1; -static int read_checkpoint = -1; - -static bool events_enabled; - -/* Functions */ - -static void replay_run_event(Event *event) -{ - switch (event->event_kind) { - case REPLAY_ASYNC_EVENT_BH: - aio_bh_call(event->opaque); - break; - case REPLAY_ASYNC_EVENT_INPUT: - qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque); - qapi_free_InputEvent((InputEvent *)event->opaque); - break; - case REPLAY_ASYNC_EVENT_INPUT_SYNC: - qemu_input_event_sync_impl(); - break; - case REPLAY_ASYNC_EVENT_CHAR_READ: - replay_event_char_read_run(event->opaque); - break; - case REPLAY_ASYNC_EVENT_BLOCK: - aio_bh_call(event->opaque); - break; - default: - error_report("Replay: invalid async event ID (%d) in the queue", - event->event_kind); - exit(1); - break; - } -} - -void replay_enable_events(void) -{ - events_enabled = true; -} - -bool replay_has_events(void) -{ - return !QTAILQ_EMPTY(&events_list); -} - -void replay_flush_events(void) -{ - replay_mutex_lock(); - while (!QTAILQ_EMPTY(&events_list)) { - Event *event = QTAILQ_FIRST(&events_list); - replay_mutex_unlock(); - replay_run_event(event); - replay_mutex_lock(); - QTAILQ_REMOVE(&events_list, event, events); - g_free(event); - } - replay_mutex_unlock(); -} - -void replay_disable_events(void) -{ - if (replay_mode != REPLAY_MODE_NONE) { - events_enabled = false; - /* Flush events queue before waiting of completion */ - replay_flush_events(); - } -} - -void replay_clear_events(void) -{ - replay_mutex_lock(); - while (!QTAILQ_EMPTY(&events_list)) { - Event *event = QTAILQ_FIRST(&events_list); - QTAILQ_REMOVE(&events_list, event, events); - - g_free(event); - } - replay_mutex_unlock(); -} - -/*! Adds specified async event to the queue */ -void replay_add_event(ReplayAsyncEventKind event_kind, - void *opaque, - void *opaque2, uint64_t id) -{ - assert(event_kind < REPLAY_ASYNC_COUNT); - - if (!replay_file || replay_mode == REPLAY_MODE_NONE - || !events_enabled) { - Event e; - e.event_kind = event_kind; - e.opaque = opaque; - e.opaque2 = opaque2; - e.id = id; - replay_run_event(&e); - return; - } - - Event *event = g_malloc0(sizeof(Event)); - event->event_kind = event_kind; - event->opaque = opaque; - event->opaque2 = opaque2; - event->id = id; - - replay_mutex_lock(); - QTAILQ_INSERT_TAIL(&events_list, event, events); - replay_mutex_unlock(); -} - -void replay_bh_schedule_event(QEMUBH *bh) -{ - if (replay_mode != REPLAY_MODE_NONE && events_enabled) { - uint64_t id = replay_get_current_step(); - replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); - } else { - qemu_bh_schedule(bh); - } -} - -void replay_add_input_event(struct InputEvent *event) -{ - replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0); -} - -void replay_add_input_sync_event(void) -{ - replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0); -} - -void replay_block_event(QEMUBH *bh, uint64_t id) -{ - if (replay_mode != REPLAY_MODE_NONE && events_enabled) { - replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id); - } else { - qemu_bh_schedule(bh); - } -} - -static void replay_save_event(Event *event, int checkpoint) -{ - if (replay_mode != REPLAY_MODE_PLAY) { - /* put the event into the file */ - replay_put_event(EVENT_ASYNC); - replay_put_byte(checkpoint); - replay_put_byte(event->event_kind); - - /* save event-specific data */ - switch (event->event_kind) { - case REPLAY_ASYNC_EVENT_BH: - replay_put_qword(event->id); - break; - case REPLAY_ASYNC_EVENT_INPUT: - replay_save_input_event(event->opaque); - break; - case REPLAY_ASYNC_EVENT_INPUT_SYNC: - break; - case REPLAY_ASYNC_EVENT_CHAR_READ: - replay_event_char_read_save(event->opaque); - break; - case REPLAY_ASYNC_EVENT_BLOCK: - replay_put_qword(event->id); - break; - default: - error_report("Unknown ID %" PRId64 " of replay event", event->id); - exit(1); - } - } -} - -/* Called with replay mutex locked */ -void replay_save_events(int checkpoint) -{ - while (!QTAILQ_EMPTY(&events_list)) { - Event *event = QTAILQ_FIRST(&events_list); - replay_save_event(event, checkpoint); - - replay_mutex_unlock(); - replay_run_event(event); - replay_mutex_lock(); - QTAILQ_REMOVE(&events_list, event, events); - g_free(event); - } -} - -static Event *replay_read_event(int checkpoint) -{ - Event *event; - if (read_event_kind == -1) { - read_checkpoint = replay_get_byte(); - read_event_kind = replay_get_byte(); - read_id = -1; - replay_check_error(); - } - - if (checkpoint != read_checkpoint) { - return NULL; - } - - /* Events that has not to be in the queue */ - switch (read_event_kind) { - case REPLAY_ASYNC_EVENT_BH: - if (read_id == -1) { - read_id = replay_get_qword(); - } - break; - case REPLAY_ASYNC_EVENT_INPUT: - event = g_malloc0(sizeof(Event)); - event->event_kind = read_event_kind; - event->opaque = replay_read_input_event(); - return event; - case REPLAY_ASYNC_EVENT_INPUT_SYNC: - event = g_malloc0(sizeof(Event)); - event->event_kind = read_event_kind; - event->opaque = 0; - return event; - case REPLAY_ASYNC_EVENT_CHAR_READ: - event = g_malloc0(sizeof(Event)); - event->event_kind = read_event_kind; - event->opaque = replay_event_char_read_load(); - return event; - case REPLAY_ASYNC_EVENT_BLOCK: - if (read_id == -1) { - read_id = replay_get_qword(); - } - break; - default: - error_report("Unknown ID %d of replay event", read_event_kind); - exit(1); - break; - } - - QTAILQ_FOREACH(event, &events_list, events) { - if (event->event_kind == read_event_kind - && (read_id == -1 || read_id == event->id)) { - break; - } - } - - if (event) { - QTAILQ_REMOVE(&events_list, event, events); - } else { - return NULL; - } - - /* Read event-specific data */ - - return event; -} - -/* Called with replay mutex locked */ -void replay_read_events(int checkpoint) -{ - while (replay_data_kind == EVENT_ASYNC) { - Event *event = replay_read_event(checkpoint); - if (!event) { - break; - } - replay_mutex_unlock(); - replay_run_event(event); - replay_mutex_lock(); - - g_free(event); - replay_finish_event(); - read_event_kind = -1; - } -} - -void replay_init_events(void) -{ - read_event_kind = -1; -} - -void replay_finish_events(void) -{ - events_enabled = false; - replay_clear_events(); -} - -bool replay_events_enabled(void) -{ - return events_enabled; -} diff --git a/qemu/replay/replay-input.c b/qemu/replay/replay-input.c deleted file mode 100644 index 06babe0ec..000000000 --- a/qemu/replay/replay-input.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * replay-input.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/notify.h" -#include "ui/input.h" -#include "qapi/qmp-output-visitor.h" -#include "qapi/qmp-input-visitor.h" -#include "qapi-visit.h" - -static InputEvent *qapi_clone_InputEvent(InputEvent *src) -{ - QmpOutputVisitor *qov; - QmpInputVisitor *qiv; - Visitor *ov, *iv; - QObject *obj; - InputEvent *dst = NULL; - - qov = qmp_output_visitor_new(); - ov = qmp_output_get_visitor(qov); - visit_type_InputEvent(ov, NULL, &src, &error_abort); - obj = qmp_output_get_qobject(qov); - qmp_output_visitor_cleanup(qov); - if (!obj) { - return NULL; - } - - qiv = qmp_input_visitor_new(obj); - iv = qmp_input_get_visitor(qiv); - visit_type_InputEvent(iv, NULL, &dst, &error_abort); - qmp_input_visitor_cleanup(qiv); - qobject_decref(obj); - - return dst; -} - -void replay_save_input_event(InputEvent *evt) -{ - InputKeyEvent *key; - InputBtnEvent *btn; - InputMoveEvent *move; - replay_put_dword(evt->type); - - switch (evt->type) { - case INPUT_EVENT_KIND_KEY: - key = evt->u.key.data; - replay_put_dword(key->key->type); - - switch (key->key->type) { - case KEY_VALUE_KIND_NUMBER: - replay_put_qword(key->key->u.number.data); - replay_put_byte(key->down); - break; - case KEY_VALUE_KIND_QCODE: - replay_put_dword(key->key->u.qcode.data); - replay_put_byte(key->down); - break; - case KEY_VALUE_KIND__MAX: - /* keep gcc happy */ - break; - } - break; - case INPUT_EVENT_KIND_BTN: - btn = evt->u.btn.data; - replay_put_dword(btn->button); - replay_put_byte(btn->down); - break; - case INPUT_EVENT_KIND_REL: - move = evt->u.rel.data; - replay_put_dword(move->axis); - replay_put_qword(move->value); - break; - case INPUT_EVENT_KIND_ABS: - move = evt->u.abs.data; - replay_put_dword(move->axis); - replay_put_qword(move->value); - break; - case INPUT_EVENT_KIND__MAX: - /* keep gcc happy */ - break; - } -} - -InputEvent *replay_read_input_event(void) -{ - InputEvent evt; - KeyValue keyValue; - InputKeyEvent key; - key.key = &keyValue; - InputBtnEvent btn; - InputMoveEvent rel; - InputMoveEvent abs; - - evt.type = replay_get_dword(); - switch (evt.type) { - case INPUT_EVENT_KIND_KEY: - evt.u.key.data = &key; - evt.u.key.data->key->type = replay_get_dword(); - - switch (evt.u.key.data->key->type) { - case KEY_VALUE_KIND_NUMBER: - evt.u.key.data->key->u.number.data = replay_get_qword(); - evt.u.key.data->down = replay_get_byte(); - break; - case KEY_VALUE_KIND_QCODE: - evt.u.key.data->key->u.qcode.data = (QKeyCode)replay_get_dword(); - evt.u.key.data->down = replay_get_byte(); - break; - case KEY_VALUE_KIND__MAX: - /* keep gcc happy */ - break; - } - break; - case INPUT_EVENT_KIND_BTN: - evt.u.btn.data = &btn; - evt.u.btn.data->button = (InputButton)replay_get_dword(); - evt.u.btn.data->down = replay_get_byte(); - break; - case INPUT_EVENT_KIND_REL: - evt.u.rel.data = &rel; - evt.u.rel.data->axis = (InputAxis)replay_get_dword(); - evt.u.rel.data->value = replay_get_qword(); - break; - case INPUT_EVENT_KIND_ABS: - evt.u.abs.data = &abs; - evt.u.abs.data->axis = (InputAxis)replay_get_dword(); - evt.u.abs.data->value = replay_get_qword(); - break; - case INPUT_EVENT_KIND__MAX: - /* keep gcc happy */ - break; - } - - return qapi_clone_InputEvent(&evt); -} - -void replay_input_event(QemuConsole *src, InputEvent *evt) -{ - if (replay_mode == REPLAY_MODE_PLAY) { - /* Nothing */ - } else if (replay_mode == REPLAY_MODE_RECORD) { - replay_add_input_event(qapi_clone_InputEvent(evt)); - } else { - qemu_input_event_send_impl(src, evt); - } -} - -void replay_input_sync_event(void) -{ - if (replay_mode == REPLAY_MODE_PLAY) { - /* Nothing */ - } else if (replay_mode == REPLAY_MODE_RECORD) { - replay_add_input_sync_event(); - } else { - qemu_input_event_sync_impl(); - } -} diff --git a/qemu/replay/replay-internal.c b/qemu/replay/replay-internal.c deleted file mode 100644 index 5835e8def..000000000 --- a/qemu/replay/replay-internal.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * replay-internal.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 "qemu-common.h" -#include "sysemu/replay.h" -#include "replay-internal.h" -#include "qemu/error-report.h" -#include "sysemu/sysemu.h" - -unsigned int replay_data_kind = -1; -static unsigned int replay_has_unread_data; - -/* Mutex to protect reading and writing events to the log. - replay_data_kind and replay_has_unread_data are also protected - by this mutex. - It also protects replay events queue which stores events to be - written or read to the log. */ -static QemuMutex lock; - -/* File for replay writing */ -FILE *replay_file; - -void replay_put_byte(uint8_t byte) -{ - if (replay_file) { - putc(byte, replay_file); - } -} - -void replay_put_event(uint8_t event) -{ - assert(event < EVENT_COUNT); - replay_put_byte(event); -} - - -void replay_put_word(uint16_t word) -{ - replay_put_byte(word >> 8); - replay_put_byte(word); -} - -void replay_put_dword(uint32_t dword) -{ - replay_put_word(dword >> 16); - replay_put_word(dword); -} - -void replay_put_qword(int64_t qword) -{ - replay_put_dword(qword >> 32); - replay_put_dword(qword); -} - -void replay_put_array(const uint8_t *buf, size_t size) -{ - if (replay_file) { - replay_put_dword(size); - fwrite(buf, 1, size, replay_file); - } -} - -uint8_t replay_get_byte(void) -{ - uint8_t byte = 0; - if (replay_file) { - byte = getc(replay_file); - } - return byte; -} - -uint16_t replay_get_word(void) -{ - uint16_t word = 0; - if (replay_file) { - word = replay_get_byte(); - word = (word << 8) + replay_get_byte(); - } - - return word; -} - -uint32_t replay_get_dword(void) -{ - uint32_t dword = 0; - if (replay_file) { - dword = replay_get_word(); - dword = (dword << 16) + replay_get_word(); - } - - return dword; -} - -int64_t replay_get_qword(void) -{ - int64_t qword = 0; - if (replay_file) { - qword = replay_get_dword(); - qword = (qword << 32) + replay_get_dword(); - } - - return qword; -} - -void replay_get_array(uint8_t *buf, size_t *size) -{ - if (replay_file) { - *size = replay_get_dword(); - if (fread(buf, 1, *size, replay_file) != *size) { - error_report("replay read error"); - } - } -} - -void replay_get_array_alloc(uint8_t **buf, size_t *size) -{ - if (replay_file) { - *size = replay_get_dword(); - *buf = g_malloc(*size); - if (fread(*buf, 1, *size, replay_file) != *size) { - error_report("replay read error"); - } - } -} - -void replay_check_error(void) -{ - if (replay_file) { - if (feof(replay_file)) { - error_report("replay file is over"); - qemu_system_vmstop_request_prepare(); - qemu_system_vmstop_request(RUN_STATE_PAUSED); - } else if (ferror(replay_file)) { - error_report("replay file is over or something goes wrong"); - qemu_system_vmstop_request_prepare(); - qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR); - } - } -} - -void replay_fetch_data_kind(void) -{ - if (replay_file) { - if (!replay_has_unread_data) { - replay_data_kind = replay_get_byte(); - if (replay_data_kind == EVENT_INSTRUCTION) { - replay_state.instructions_count = replay_get_dword(); - } - replay_check_error(); - replay_has_unread_data = 1; - if (replay_data_kind >= EVENT_COUNT) { - error_report("Replay: unknown event kind %d", replay_data_kind); - exit(1); - } - } - } -} - -void replay_finish_event(void) -{ - replay_has_unread_data = 0; - replay_fetch_data_kind(); -} - -void replay_mutex_init(void) -{ - qemu_mutex_init(&lock); -} - -void replay_mutex_destroy(void) -{ - qemu_mutex_destroy(&lock); -} - -void replay_mutex_lock(void) -{ - qemu_mutex_lock(&lock); -} - -void replay_mutex_unlock(void) -{ - qemu_mutex_unlock(&lock); -} - -/*! Saves cached instructions. */ -void replay_save_instructions(void) -{ - if (replay_file && replay_mode == REPLAY_MODE_RECORD) { - replay_mutex_lock(); - int diff = (int)(replay_get_current_step() - replay_state.current_step); - if (diff > 0) { - replay_put_event(EVENT_INSTRUCTION); - replay_put_dword(diff); - replay_state.current_step += diff; - } - replay_mutex_unlock(); - } -} diff --git a/qemu/replay/replay-internal.h b/qemu/replay/replay-internal.h deleted file mode 100644 index efbf14c8a..000000000 --- a/qemu/replay/replay-internal.h +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef REPLAY_INTERNAL_H -#define REPLAY_INTERNAL_H - -/* - * replay-internal.h - * - * 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. - * - */ - - -enum ReplayEvents { - /* for instruction event */ - EVENT_INSTRUCTION, - /* for software interrupt */ - EVENT_INTERRUPT, - /* for emulated exceptions */ - EVENT_EXCEPTION, - /* for async events */ - EVENT_ASYNC, - /* for shutdown request */ - EVENT_SHUTDOWN, - /* for character device write event */ - EVENT_CHAR_WRITE, - /* for character device read all event */ - EVENT_CHAR_READ_ALL, - EVENT_CHAR_READ_ALL_ERROR, - /* for clock read/writes */ - /* some of greater codes are reserved for clocks */ - EVENT_CLOCK, - EVENT_CLOCK_LAST = EVENT_CLOCK + REPLAY_CLOCK_COUNT - 1, - /* for checkpoint event */ - /* some of greater codes are reserved for checkpoints */ - EVENT_CHECKPOINT, - EVENT_CHECKPOINT_LAST = EVENT_CHECKPOINT + CHECKPOINT_COUNT - 1, - /* end of log event */ - EVENT_END, - EVENT_COUNT -}; - -/* Asynchronous events IDs */ - -enum ReplayAsyncEventKind { - REPLAY_ASYNC_EVENT_BH, - REPLAY_ASYNC_EVENT_INPUT, - REPLAY_ASYNC_EVENT_INPUT_SYNC, - REPLAY_ASYNC_EVENT_CHAR_READ, - REPLAY_ASYNC_EVENT_BLOCK, - REPLAY_ASYNC_COUNT -}; - -typedef enum ReplayAsyncEventKind ReplayAsyncEventKind; - -typedef struct ReplayState { - /*! Cached clock values. */ - int64_t cached_clock[REPLAY_CLOCK_COUNT]; - /*! Current step - number of processed instructions and timer events. */ - uint64_t current_step; - /*! Number of instructions to be executed before other events happen. */ - int instructions_count; -} ReplayState; -extern ReplayState replay_state; - -extern unsigned int replay_data_kind; - -/* File for replay writing */ -extern FILE *replay_file; - -void replay_put_byte(uint8_t byte); -void replay_put_event(uint8_t event); -void replay_put_word(uint16_t word); -void replay_put_dword(uint32_t dword); -void replay_put_qword(int64_t qword); -void replay_put_array(const uint8_t *buf, size_t size); - -uint8_t replay_get_byte(void); -uint16_t replay_get_word(void); -uint32_t replay_get_dword(void); -int64_t replay_get_qword(void); -void replay_get_array(uint8_t *buf, size_t *size); -void replay_get_array_alloc(uint8_t **buf, size_t *size); - -/* Mutex functions for protecting replay log file */ - -void replay_mutex_init(void); -void replay_mutex_destroy(void); -void replay_mutex_lock(void); -void replay_mutex_unlock(void); - -/*! Checks error status of the file. */ -void replay_check_error(void); - -/*! Finishes processing of the replayed event and fetches - the next event from the log. */ -void replay_finish_event(void); -/*! Reads data type from the file and stores it in the - replay_data_kind variable. */ -void replay_fetch_data_kind(void); - -/*! Saves queued events (like instructions and sound). */ -void replay_save_instructions(void); - -/*! Skips async events until some sync event will be found. - \return true, if event was found */ -bool replay_next_event_is(int event); - -/*! Reads next clock value from the file. - If clock kind read from the file is different from the parameter, - the value is not used. */ -void replay_read_next_clock(unsigned int kind); - -/* Asynchronous events queue */ - -/*! Initializes events' processing internals */ -void replay_init_events(void); -/*! Clears internal data structures for events handling */ -void replay_finish_events(void); -/*! Enables storing events in the queue */ -void replay_enable_events(void); -/*! Flushes events queue */ -void replay_flush_events(void); -/*! Clears events list before loading new VM state */ -void replay_clear_events(void); -/*! Returns true if there are any unsaved events in the queue */ -bool replay_has_events(void); -/*! Saves events from queue into the file */ -void replay_save_events(int checkpoint); -/*! Read events from the file into the input queue */ -void replay_read_events(int checkpoint); -/*! Adds specified async event to the queue */ -void replay_add_event(ReplayAsyncEventKind event_kind, void *opaque, - void *opaque2, uint64_t id); - -/* Input events */ - -/*! Saves input event to the log */ -void replay_save_input_event(InputEvent *evt); -/*! Reads input event from the log */ -InputEvent *replay_read_input_event(void); -/*! Adds input event to the queue */ -void replay_add_input_event(struct InputEvent *event); -/*! Adds input sync event to the queue */ -void replay_add_input_sync_event(void); - -/* Character devices */ - -/*! Called to run char device read event. */ -void replay_event_char_read_run(void *opaque); -/*! Writes char read event to the file. */ -void replay_event_char_read_save(void *opaque); -/*! Reads char event read from the file. */ -void *replay_event_char_read_load(void); - -#endif diff --git a/qemu/replay/replay-time.c b/qemu/replay/replay-time.c deleted file mode 100644 index fffe072c5..000000000 --- a/qemu/replay/replay-time.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * replay-time.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 "qemu-common.h" -#include "sysemu/replay.h" -#include "replay-internal.h" -#include "qemu/error-report.h" - -int64_t replay_save_clock(ReplayClockKind kind, int64_t clock) -{ - replay_save_instructions(); - - if (replay_file) { - replay_mutex_lock(); - replay_put_event(EVENT_CLOCK + kind); - replay_put_qword(clock); - replay_mutex_unlock(); - } - - return clock; -} - -void replay_read_next_clock(ReplayClockKind kind) -{ - unsigned int read_kind = replay_data_kind - EVENT_CLOCK; - - assert(read_kind == kind); - - int64_t clock = replay_get_qword(); - - replay_check_error(); - replay_finish_event(); - - replay_state.cached_clock[read_kind] = clock; -} - -/*! Reads next clock event from the input. */ -int64_t replay_read_clock(ReplayClockKind kind) -{ - replay_account_executed_instructions(); - - if (replay_file) { - int64_t ret; - replay_mutex_lock(); - if (replay_next_event_is(EVENT_CLOCK + kind)) { - replay_read_next_clock(kind); - } - ret = replay_state.cached_clock[kind]; - replay_mutex_unlock(); - - return ret; - } - - error_report("REPLAY INTERNAL ERROR %d", __LINE__); - exit(1); -} 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); -} |