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. */ 23 static QemuMutex lock; 24 25 /* File for replay writing */ 26 static bool write_error; 27 FILE *replay_file; 28 29 static void replay_write_error(void) 30 { 31 if (!write_error) { 32 error_report("replay write error"); 33 write_error = true; 34 } 35 } 36 37 static void replay_read_error(void) 38 { 39 error_report("error reading the replay data"); 40 exit(1); 41 } 42 43 void 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 52 void replay_put_event(uint8_t event) 53 { 54 assert(event < EVENT_COUNT); 55 replay_put_byte(event); 56 } 57 58 59 void replay_put_word(uint16_t word) 60 { 61 replay_put_byte(word >> 8); 62 replay_put_byte(word); 63 } 64 65 void replay_put_dword(uint32_t dword) 66 { 67 replay_put_word(dword >> 16); 68 replay_put_word(dword); 69 } 70 71 void replay_put_qword(int64_t qword) 72 { 73 replay_put_dword(qword >> 32); 74 replay_put_dword(qword); 75 } 76 77 void 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 87 uint8_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 100 uint16_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 111 uint32_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 122 int64_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 133 void 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 143 void 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 154 void 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 169 void 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 188 void replay_finish_event(void) 189 { 190 replay_state.has_unread_data = 0; 191 replay_fetch_data_kind(); 192 } 193 194 static __thread bool replay_locked; 195 196 void 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 204 bool replay_mutex_locked(void) 205 { 206 return replay_locked; 207 } 208 209 /* Ordering constraints, replay_lock must be taken before BQL */ 210 void 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 220 void 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 229 void 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. */ 244 void 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