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 "sysemu/cpu-timers.h" 15 #include "sysemu/replay.h" 16 #include "sysemu/runstate.h" 17 #include "replay-internal.h" 18 #include "qemu/main-loop.h" 19 #include "qemu/option.h" 20 #include "sysemu/cpus.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 0xe0200a 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 /* Replay breakpoints */ 38 uint64_t replay_break_icount = -1ULL; 39 QEMUTimer *replay_break_timer; 40 41 bool replay_next_event_is(int event) 42 { 43 bool res = false; 44 45 /* nothing to skip - not all instructions used */ 46 if (replay_state.instruction_count != 0) { 47 assert(replay_state.data_kind == EVENT_INSTRUCTION); 48 return event == EVENT_INSTRUCTION; 49 } 50 51 while (true) { 52 unsigned int data_kind = replay_state.data_kind; 53 if (event == data_kind) { 54 res = true; 55 } 56 switch (data_kind) { 57 case EVENT_SHUTDOWN ... EVENT_SHUTDOWN_LAST: 58 replay_finish_event(); 59 qemu_system_shutdown_request(data_kind - EVENT_SHUTDOWN); 60 break; 61 default: 62 /* clock, time_t, checkpoint and other events */ 63 return res; 64 } 65 } 66 return res; 67 } 68 69 uint64_t replay_get_current_icount(void) 70 { 71 return icount_get_raw(); 72 } 73 74 int replay_get_instructions(void) 75 { 76 int res = 0; 77 replay_mutex_lock(); 78 if (replay_next_event_is(EVENT_INSTRUCTION)) { 79 res = replay_state.instruction_count; 80 if (replay_break_icount != -1LL) { 81 uint64_t current = replay_get_current_icount(); 82 assert(replay_break_icount >= current); 83 if (current + res > replay_break_icount) { 84 res = replay_break_icount - current; 85 } 86 } 87 } 88 replay_mutex_unlock(); 89 return res; 90 } 91 92 void replay_account_executed_instructions(void) 93 { 94 if (replay_mode == REPLAY_MODE_PLAY) { 95 g_assert(replay_mutex_locked()); 96 if (replay_state.instruction_count > 0) { 97 replay_advance_current_icount(replay_get_current_icount()); 98 } 99 } 100 } 101 102 bool replay_exception(void) 103 { 104 105 if (replay_mode == REPLAY_MODE_RECORD) { 106 g_assert(replay_mutex_locked()); 107 replay_save_instructions(); 108 replay_put_event(EVENT_EXCEPTION); 109 return true; 110 } else if (replay_mode == REPLAY_MODE_PLAY) { 111 g_assert(replay_mutex_locked()); 112 bool res = replay_has_exception(); 113 if (res) { 114 replay_finish_event(); 115 } 116 return res; 117 } 118 119 return true; 120 } 121 122 bool replay_has_exception(void) 123 { 124 bool res = false; 125 if (replay_mode == REPLAY_MODE_PLAY) { 126 g_assert(replay_mutex_locked()); 127 replay_account_executed_instructions(); 128 res = replay_next_event_is(EVENT_EXCEPTION); 129 } 130 131 return res; 132 } 133 134 bool replay_interrupt(void) 135 { 136 if (replay_mode == REPLAY_MODE_RECORD) { 137 g_assert(replay_mutex_locked()); 138 replay_save_instructions(); 139 replay_put_event(EVENT_INTERRUPT); 140 return true; 141 } else if (replay_mode == REPLAY_MODE_PLAY) { 142 g_assert(replay_mutex_locked()); 143 bool res = replay_has_interrupt(); 144 if (res) { 145 replay_finish_event(); 146 } 147 return res; 148 } 149 150 return true; 151 } 152 153 bool replay_has_interrupt(void) 154 { 155 bool res = false; 156 if (replay_mode == REPLAY_MODE_PLAY) { 157 g_assert(replay_mutex_locked()); 158 replay_account_executed_instructions(); 159 res = replay_next_event_is(EVENT_INTERRUPT); 160 } 161 return res; 162 } 163 164 void replay_shutdown_request(ShutdownCause cause) 165 { 166 if (replay_mode == REPLAY_MODE_RECORD) { 167 g_assert(replay_mutex_locked()); 168 replay_put_event(EVENT_SHUTDOWN + cause); 169 } 170 } 171 172 bool replay_checkpoint(ReplayCheckpoint checkpoint) 173 { 174 bool res = false; 175 static bool in_checkpoint; 176 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); 177 178 if (!replay_file) { 179 return true; 180 } 181 182 if (in_checkpoint) { 183 /* If we are already in checkpoint, then there is no need 184 for additional synchronization. 185 Recursion occurs when HW event modifies timers. 186 Timer modification may invoke the checkpoint and 187 proceed to recursion. */ 188 return true; 189 } 190 in_checkpoint = true; 191 192 replay_save_instructions(); 193 194 if (replay_mode == REPLAY_MODE_PLAY) { 195 g_assert(replay_mutex_locked()); 196 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { 197 replay_finish_event(); 198 } else if (replay_state.data_kind != EVENT_ASYNC) { 199 res = false; 200 goto out; 201 } 202 replay_read_events(checkpoint); 203 /* replay_read_events may leave some unread events. 204 Return false if not all of the events associated with 205 checkpoint were processed */ 206 res = replay_state.data_kind != EVENT_ASYNC; 207 } else if (replay_mode == REPLAY_MODE_RECORD) { 208 g_assert(replay_mutex_locked()); 209 replay_put_event(EVENT_CHECKPOINT + checkpoint); 210 /* This checkpoint belongs to several threads. 211 Processing events from different threads is 212 non-deterministic */ 213 if (checkpoint != CHECKPOINT_CLOCK_WARP_START 214 /* FIXME: this is temporary fix, other checkpoints 215 may also be invoked from the different threads someday. 216 Asynchronous event processing should be refactored 217 to create additional replay event kind which is 218 nailed to the one of the threads and which processes 219 the event queue. */ 220 && checkpoint != CHECKPOINT_CLOCK_VIRTUAL) { 221 replay_save_events(checkpoint); 222 } 223 res = true; 224 } 225 out: 226 in_checkpoint = false; 227 return res; 228 } 229 230 bool replay_has_checkpoint(void) 231 { 232 bool res = false; 233 if (replay_mode == REPLAY_MODE_PLAY) { 234 g_assert(replay_mutex_locked()); 235 replay_account_executed_instructions(); 236 res = EVENT_CHECKPOINT <= replay_state.data_kind 237 && replay_state.data_kind <= EVENT_CHECKPOINT_LAST; 238 } 239 return res; 240 } 241 242 static void replay_enable(const char *fname, int mode) 243 { 244 const char *fmode = NULL; 245 assert(!replay_file); 246 247 switch (mode) { 248 case REPLAY_MODE_RECORD: 249 fmode = "wb"; 250 break; 251 case REPLAY_MODE_PLAY: 252 fmode = "rb"; 253 break; 254 default: 255 fprintf(stderr, "Replay: internal error: invalid replay mode\n"); 256 exit(1); 257 } 258 259 atexit(replay_finish); 260 261 replay_file = fopen(fname, fmode); 262 if (replay_file == NULL) { 263 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno)); 264 exit(1); 265 } 266 267 replay_filename = g_strdup(fname); 268 replay_mode = mode; 269 replay_mutex_init(); 270 271 replay_state.data_kind = -1; 272 replay_state.instruction_count = 0; 273 replay_state.current_icount = 0; 274 replay_state.has_unread_data = 0; 275 276 /* skip file header for RECORD and check it for PLAY */ 277 if (replay_mode == REPLAY_MODE_RECORD) { 278 fseek(replay_file, HEADER_SIZE, SEEK_SET); 279 } else if (replay_mode == REPLAY_MODE_PLAY) { 280 unsigned int version = replay_get_dword(); 281 if (version != REPLAY_VERSION) { 282 fprintf(stderr, "Replay: invalid input log file version\n"); 283 exit(1); 284 } 285 /* go to the beginning */ 286 fseek(replay_file, HEADER_SIZE, SEEK_SET); 287 replay_fetch_data_kind(); 288 } 289 290 replay_init_events(); 291 } 292 293 void replay_configure(QemuOpts *opts) 294 { 295 const char *fname; 296 const char *rr; 297 ReplayMode mode = REPLAY_MODE_NONE; 298 Location loc; 299 300 if (!opts) { 301 return; 302 } 303 304 loc_push_none(&loc); 305 qemu_opts_loc_restore(opts); 306 307 rr = qemu_opt_get(opts, "rr"); 308 if (!rr) { 309 /* Just enabling icount */ 310 goto out; 311 } else if (!strcmp(rr, "record")) { 312 mode = REPLAY_MODE_RECORD; 313 } else if (!strcmp(rr, "replay")) { 314 mode = REPLAY_MODE_PLAY; 315 } else { 316 error_report("Invalid icount rr option: %s", rr); 317 exit(1); 318 } 319 320 fname = qemu_opt_get(opts, "rrfile"); 321 if (!fname) { 322 error_report("File name not specified for replay"); 323 exit(1); 324 } 325 326 replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot")); 327 replay_vmstate_register(); 328 replay_enable(fname, mode); 329 330 out: 331 loc_pop(&loc); 332 } 333 334 void replay_start(void) 335 { 336 if (replay_mode == REPLAY_MODE_NONE) { 337 return; 338 } 339 340 if (replay_blockers) { 341 error_reportf_err(replay_blockers->data, "Record/replay: "); 342 exit(1); 343 } 344 if (!icount_enabled()) { 345 error_report("Please enable icount to use record/replay"); 346 exit(1); 347 } 348 349 /* Timer for snapshotting will be set up here. */ 350 351 replay_enable_events(); 352 } 353 354 void replay_finish(void) 355 { 356 if (replay_mode == REPLAY_MODE_NONE) { 357 return; 358 } 359 360 replay_save_instructions(); 361 362 /* finalize the file */ 363 if (replay_file) { 364 if (replay_mode == REPLAY_MODE_RECORD) { 365 /* 366 * Can't do it in the signal handler, therefore 367 * add shutdown event here for the case of Ctrl-C. 368 */ 369 replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL); 370 /* write end event */ 371 replay_put_event(EVENT_END); 372 373 /* write header */ 374 fseek(replay_file, 0, SEEK_SET); 375 replay_put_dword(REPLAY_VERSION); 376 } 377 378 fclose(replay_file); 379 replay_file = NULL; 380 } 381 if (replay_filename) { 382 g_free(replay_filename); 383 replay_filename = NULL; 384 } 385 386 g_free(replay_snapshot); 387 replay_snapshot = NULL; 388 389 replay_mode = REPLAY_MODE_NONE; 390 391 replay_finish_events(); 392 } 393 394 void replay_add_blocker(Error *reason) 395 { 396 replay_blockers = g_slist_prepend(replay_blockers, reason); 397 } 398 399 const char *replay_get_filename(void) 400 { 401 return replay_filename; 402 } 403