qemu/replay/replay-internal.c
<<
>>
Prefs
   1/*
   2 * replay-internal.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
  12#include "qemu/osdep.h"
  13#include "sysemu/replay.h"
  14#include "replay-internal.h"
  15#include "qemu/error-report.h"
  16#include "sysemu/sysemu.h"
  17
  18/* Mutex to protect reading and writing events to the log.
  19   data_kind and has_unread_data are also protected
  20   by this mutex.
  21   It also protects replay events queue which stores events to be
  22   written or read to the log. */
  23static QemuMutex lock;
  24
  25/* File for replay writing */
  26static bool write_error;
  27FILE *replay_file;
  28
  29static void replay_write_error(void)
  30{
  31    if (!write_error) {
  32        error_report("replay write error");
  33        write_error = true;
  34    }
  35}
  36
  37static void replay_read_error(void)
  38{
  39    error_report("error reading the replay data");
  40    exit(1);
  41}
  42
  43void replay_put_byte(uint8_t byte)
  44{
  45    if (replay_file) {
  46        if (putc(byte, replay_file) == EOF) {
  47            replay_write_error();
  48        }
  49    }
  50}
  51
  52void replay_put_event(uint8_t event)
  53{
  54    assert(event < EVENT_COUNT);
  55    replay_put_byte(event);
  56}
  57
  58
  59void replay_put_word(uint16_t word)
  60{
  61    replay_put_byte(word >> 8);
  62    replay_put_byte(word);
  63}
  64
  65void replay_put_dword(uint32_t dword)
  66{
  67    replay_put_word(dword >> 16);
  68    replay_put_word(dword);
  69}
  70
  71void replay_put_qword(int64_t qword)
  72{
  73    replay_put_dword(qword >> 32);
  74    replay_put_dword(qword);
  75}
  76
  77void replay_put_array(const uint8_t *buf, size_t size)
  78{
  79    if (replay_file) {
  80        replay_put_dword(size);
  81        if (fwrite(buf, 1, size, replay_file) != size) {
  82            replay_write_error();
  83        }
  84    }
  85}
  86
  87uint8_t replay_get_byte(void)
  88{
  89    uint8_t byte = 0;
  90    if (replay_file) {
  91        int r = getc(replay_file);
  92        if (r == EOF) {
  93            replay_read_error();
  94        }
  95        byte = r;
  96    }
  97    return byte;
  98}
  99
 100uint16_t replay_get_word(void)
 101{
 102    uint16_t word = 0;
 103    if (replay_file) {
 104        word = replay_get_byte();
 105        word = (word << 8) + replay_get_byte();
 106    }
 107
 108    return word;
 109}
 110
 111uint32_t replay_get_dword(void)
 112{
 113    uint32_t dword = 0;
 114    if (replay_file) {
 115        dword = replay_get_word();
 116        dword = (dword << 16) + replay_get_word();
 117    }
 118
 119    return dword;
 120}
 121
 122int64_t replay_get_qword(void)
 123{
 124    int64_t qword = 0;
 125    if (replay_file) {
 126        qword = replay_get_dword();
 127        qword = (qword << 32) + replay_get_dword();
 128    }
 129
 130    return qword;
 131}
 132
 133void replay_get_array(uint8_t *buf, size_t *size)
 134{
 135    if (replay_file) {
 136        *size = replay_get_dword();
 137        if (fread(buf, 1, *size, replay_file) != *size) {
 138            replay_read_error();
 139        }
 140    }
 141}
 142
 143void replay_get_array_alloc(uint8_t **buf, size_t *size)
 144{
 145    if (replay_file) {
 146        *size = replay_get_dword();
 147        *buf = g_malloc(*size);
 148        if (fread(*buf, 1, *size, replay_file) != *size) {
 149            replay_read_error();
 150        }
 151    }
 152}
 153
 154void replay_check_error(void)
 155{
 156    if (replay_file) {
 157        if (feof(replay_file)) {
 158            error_report("replay file is over");
 159            qemu_system_vmstop_request_prepare();
 160            qemu_system_vmstop_request(RUN_STATE_PAUSED);
 161        } else if (ferror(replay_file)) {
 162            error_report("replay file is over or something goes wrong");
 163            qemu_system_vmstop_request_prepare();
 164            qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
 165        }
 166    }
 167}
 168
 169void replay_fetch_data_kind(void)
 170{
 171    if (replay_file) {
 172        if (!replay_state.has_unread_data) {
 173            replay_state.data_kind = replay_get_byte();
 174            if (replay_state.data_kind == EVENT_INSTRUCTION) {
 175                replay_state.instructions_count = replay_get_dword();
 176            }
 177            replay_check_error();
 178            replay_state.has_unread_data = 1;
 179            if (replay_state.data_kind >= EVENT_COUNT) {
 180                error_report("Replay: unknown event kind %d",
 181                             replay_state.data_kind);
 182                exit(1);
 183            }
 184        }
 185    }
 186}
 187
 188void replay_finish_event(void)
 189{
 190    replay_state.has_unread_data = 0;
 191    replay_fetch_data_kind();
 192}
 193
 194static __thread bool replay_locked;
 195
 196void replay_mutex_init(void)
 197{
 198    qemu_mutex_init(&lock);
 199    /* Hold the mutex while we start-up */
 200    qemu_mutex_lock(&lock);
 201    replay_locked = true;
 202}
 203
 204bool replay_mutex_locked(void)
 205{
 206    return replay_locked;
 207}
 208
 209/* Ordering constraints, replay_lock must be taken before BQL */
 210void replay_mutex_lock(void)
 211{
 212    if (replay_mode != REPLAY_MODE_NONE) {
 213        g_assert(!qemu_mutex_iothread_locked());
 214        g_assert(!replay_mutex_locked());
 215        qemu_mutex_lock(&lock);
 216        replay_locked = true;
 217    }
 218}
 219
 220void replay_mutex_unlock(void)
 221{
 222    if (replay_mode != REPLAY_MODE_NONE) {
 223        g_assert(replay_mutex_locked());
 224        replay_locked = false;
 225        qemu_mutex_unlock(&lock);
 226    }
 227}
 228
 229void replay_advance_current_step(uint64_t current_step)
 230{
 231    int diff = (int)(replay_get_current_step() - replay_state.current_step);
 232
 233    /* Time can only go forward */
 234    assert(diff >= 0);
 235
 236    if (diff > 0) {
 237        replay_put_event(EVENT_INSTRUCTION);
 238        replay_put_dword(diff);
 239        replay_state.current_step += diff;
 240    }
 241}
 242
 243/*! Saves cached instructions. */
 244void replay_save_instructions(void)
 245{
 246    if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
 247        g_assert(replay_mutex_locked());
 248        replay_advance_current_step(replay_get_current_step());
 249    }
 250}
 251