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