1 /* 2 * replay.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-common.h" 13 #include "sysemu/replay.h" 14 #include "replay-internal.h" 15 #include "qemu/timer.h" 16 #include "qemu/main-loop.h" 17 #include "sysemu/sysemu.h" 18 #include "qemu/error-report.h" 19 20 /* Current version of the replay mechanism. 21 Increase it when file format changes. */ 22 #define REPLAY_VERSION 0xe02002 23 /* Size of replay log header */ 24 #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) 25 26 ReplayMode replay_mode = REPLAY_MODE_NONE; 27 28 /* Name of replay file */ 29 static char *replay_filename; 30 ReplayState replay_state; 31 32 bool replay_next_event_is(int event) 33 { 34 bool res = false; 35 36 /* nothing to skip - not all instructions used */ 37 if (replay_state.instructions_count != 0) { 38 assert(replay_data_kind == EVENT_INSTRUCTION); 39 return event == EVENT_INSTRUCTION; 40 } 41 42 while (true) { 43 if (event == replay_data_kind) { 44 res = true; 45 } 46 switch (replay_data_kind) { 47 case EVENT_SHUTDOWN: 48 replay_finish_event(); 49 qemu_system_shutdown_request(); 50 break; 51 default: 52 /* clock, time_t, checkpoint and other events */ 53 return res; 54 } 55 } 56 return res; 57 } 58 59 uint64_t replay_get_current_step(void) 60 { 61 return cpu_get_icount_raw(); 62 } 63 64 int replay_get_instructions(void) 65 { 66 int res = 0; 67 replay_mutex_lock(); 68 if (replay_next_event_is(EVENT_INSTRUCTION)) { 69 res = replay_state.instructions_count; 70 } 71 replay_mutex_unlock(); 72 return res; 73 } 74 75 void replay_account_executed_instructions(void) 76 { 77 if (replay_mode == REPLAY_MODE_PLAY) { 78 replay_mutex_lock(); 79 if (replay_state.instructions_count > 0) { 80 int count = (int)(replay_get_current_step() 81 - replay_state.current_step); 82 replay_state.instructions_count -= count; 83 replay_state.current_step += count; 84 if (replay_state.instructions_count == 0) { 85 assert(replay_data_kind == EVENT_INSTRUCTION); 86 replay_finish_event(); 87 /* Wake up iothread. This is required because 88 timers will not expire until clock counters 89 will be read from the log. */ 90 qemu_notify_event(); 91 } 92 } 93 replay_mutex_unlock(); 94 } 95 } 96 97 bool replay_exception(void) 98 { 99 if (replay_mode == REPLAY_MODE_RECORD) { 100 replay_save_instructions(); 101 replay_mutex_lock(); 102 replay_put_event(EVENT_EXCEPTION); 103 replay_mutex_unlock(); 104 return true; 105 } else if (replay_mode == REPLAY_MODE_PLAY) { 106 bool res = replay_has_exception(); 107 if (res) { 108 replay_mutex_lock(); 109 replay_finish_event(); 110 replay_mutex_unlock(); 111 } 112 return res; 113 } 114 115 return true; 116 } 117 118 bool replay_has_exception(void) 119 { 120 bool res = false; 121 if (replay_mode == REPLAY_MODE_PLAY) { 122 replay_account_executed_instructions(); 123 replay_mutex_lock(); 124 res = replay_next_event_is(EVENT_EXCEPTION); 125 replay_mutex_unlock(); 126 } 127 128 return res; 129 } 130 131 bool replay_interrupt(void) 132 { 133 if (replay_mode == REPLAY_MODE_RECORD) { 134 replay_save_instructions(); 135 replay_mutex_lock(); 136 replay_put_event(EVENT_INTERRUPT); 137 replay_mutex_unlock(); 138 return true; 139 } else if (replay_mode == REPLAY_MODE_PLAY) { 140 bool res = replay_has_interrupt(); 141 if (res) { 142 replay_mutex_lock(); 143 replay_finish_event(); 144 replay_mutex_unlock(); 145 } 146 return res; 147 } 148 149 return true; 150 } 151 152 bool replay_has_interrupt(void) 153 { 154 bool res = false; 155 if (replay_mode == REPLAY_MODE_PLAY) { 156 replay_account_executed_instructions(); 157 replay_mutex_lock(); 158 res = replay_next_event_is(EVENT_INTERRUPT); 159 replay_mutex_unlock(); 160 } 161 return res; 162 } 163 164 void replay_shutdown_request(void) 165 { 166 if (replay_mode == REPLAY_MODE_RECORD) { 167 replay_mutex_lock(); 168 replay_put_event(EVENT_SHUTDOWN); 169 replay_mutex_unlock(); 170 } 171 } 172 173 bool replay_checkpoint(ReplayCheckpoint checkpoint) 174 { 175 bool res = false; 176 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); 177 replay_save_instructions(); 178 179 if (!replay_file) { 180 return true; 181 } 182 183 replay_mutex_lock(); 184 185 if (replay_mode == REPLAY_MODE_PLAY) { 186 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { 187 replay_finish_event(); 188 } else if (replay_data_kind != EVENT_ASYNC) { 189 res = false; 190 goto out; 191 } 192 replay_read_events(checkpoint); 193 /* replay_read_events may leave some unread events. 194 Return false if not all of the events associated with 195 checkpoint were processed */ 196 res = replay_data_kind != EVENT_ASYNC; 197 } else if (replay_mode == REPLAY_MODE_RECORD) { 198 replay_put_event(EVENT_CHECKPOINT + checkpoint); 199 replay_save_events(checkpoint); 200 res = true; 201 } 202 out: 203 replay_mutex_unlock(); 204 return res; 205 } 206 207 static void replay_enable(const char *fname, int mode) 208 { 209 const char *fmode = NULL; 210 assert(!replay_file); 211 212 switch (mode) { 213 case REPLAY_MODE_RECORD: 214 fmode = "wb"; 215 break; 216 case REPLAY_MODE_PLAY: 217 fmode = "rb"; 218 break; 219 default: 220 fprintf(stderr, "Replay: internal error: invalid replay mode\n"); 221 exit(1); 222 } 223 224 atexit(replay_finish); 225 226 replay_mutex_init(); 227 228 replay_file = fopen(fname, fmode); 229 if (replay_file == NULL) { 230 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno)); 231 exit(1); 232 } 233 234 replay_filename = g_strdup(fname); 235 236 replay_mode = mode; 237 replay_data_kind = -1; 238 replay_state.instructions_count = 0; 239 replay_state.current_step = 0; 240 241 /* skip file header for RECORD and check it for PLAY */ 242 if (replay_mode == REPLAY_MODE_RECORD) { 243 fseek(replay_file, HEADER_SIZE, SEEK_SET); 244 } else if (replay_mode == REPLAY_MODE_PLAY) { 245 unsigned int version = replay_get_dword(); 246 if (version != REPLAY_VERSION) { 247 fprintf(stderr, "Replay: invalid input log file version\n"); 248 exit(1); 249 } 250 /* go to the beginning */ 251 fseek(replay_file, HEADER_SIZE, SEEK_SET); 252 replay_fetch_data_kind(); 253 } 254 255 replay_init_events(); 256 } 257 258 void replay_configure(QemuOpts *opts) 259 { 260 const char *fname; 261 const char *rr; 262 ReplayMode mode = REPLAY_MODE_NONE; 263 264 rr = qemu_opt_get(opts, "rr"); 265 if (!rr) { 266 /* Just enabling icount */ 267 return; 268 } else if (!strcmp(rr, "record")) { 269 mode = REPLAY_MODE_RECORD; 270 } else if (!strcmp(rr, "replay")) { 271 mode = REPLAY_MODE_PLAY; 272 } else { 273 error_report("Invalid icount rr option: %s", rr); 274 exit(1); 275 } 276 277 fname = qemu_opt_get(opts, "rrfile"); 278 if (!fname) { 279 error_report("File name not specified for replay"); 280 exit(1); 281 } 282 283 replay_enable(fname, mode); 284 } 285 286 void replay_start(void) 287 { 288 if (replay_mode == REPLAY_MODE_NONE) { 289 return; 290 } 291 292 /* Timer for snapshotting will be set up here. */ 293 294 replay_enable_events(); 295 } 296 297 void replay_finish(void) 298 { 299 if (replay_mode == REPLAY_MODE_NONE) { 300 return; 301 } 302 303 replay_save_instructions(); 304 305 /* finalize the file */ 306 if (replay_file) { 307 if (replay_mode == REPLAY_MODE_RECORD) { 308 /* write end event */ 309 replay_put_event(EVENT_END); 310 311 /* write header */ 312 fseek(replay_file, 0, SEEK_SET); 313 replay_put_dword(REPLAY_VERSION); 314 } 315 316 fclose(replay_file); 317 replay_file = NULL; 318 } 319 if (replay_filename) { 320 g_free(replay_filename); 321 replay_filename = NULL; 322 } 323 324 replay_finish_events(); 325 replay_mutex_destroy(); 326 } 327