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