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