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