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