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