/* * 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 "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 Chardev **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(Chardev *chr) { int i = 0; for ( ; i < drivers_count ; ++i) { if (char_drivers[i] == chr) { return i; } } return -1; } void replay_register_char_driver(Chardev *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(Chardev *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(); }