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