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