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