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