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 0xe0200b 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 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); 175 176 replay_save_instructions(); 177 178 if (replay_mode == REPLAY_MODE_PLAY) { 179 g_assert(replay_mutex_locked()); 180 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { 181 replay_finish_event(); 182 } else { 183 return false; 184 } 185 } else if (replay_mode == REPLAY_MODE_RECORD) { 186 g_assert(replay_mutex_locked()); 187 replay_put_event(EVENT_CHECKPOINT + checkpoint); 188 } 189 return true; 190 } 191 192 void replay_async_events(void) 193 { 194 static bool processing = false; 195 /* 196 * If we are already processing the events, recursion may occur 197 * in case of incorrect implementation when HW event modifies timers. 198 * Timer modification may invoke the icount warp, event processing, 199 * and cause the recursion. 200 */ 201 g_assert(!processing); 202 processing = true; 203 204 replay_save_instructions(); 205 206 if (replay_mode == REPLAY_MODE_PLAY) { 207 g_assert(replay_mutex_locked()); 208 replay_read_events(); 209 } else if (replay_mode == REPLAY_MODE_RECORD) { 210 g_assert(replay_mutex_locked()); 211 replay_save_events(); 212 } 213 processing = false; 214 } 215 216 bool replay_has_event(void) 217 { 218 bool res = false; 219 if (replay_mode == REPLAY_MODE_PLAY) { 220 g_assert(replay_mutex_locked()); 221 replay_account_executed_instructions(); 222 res = EVENT_CHECKPOINT <= replay_state.data_kind 223 && replay_state.data_kind <= EVENT_CHECKPOINT_LAST; 224 res = res || replay_state.data_kind == EVENT_ASYNC; 225 } 226 return res; 227 } 228 229 static void replay_enable(const char *fname, int mode) 230 { 231 const char *fmode = NULL; 232 assert(!replay_file); 233 234 switch (mode) { 235 case REPLAY_MODE_RECORD: 236 fmode = "wb"; 237 break; 238 case REPLAY_MODE_PLAY: 239 fmode = "rb"; 240 break; 241 default: 242 fprintf(stderr, "Replay: internal error: invalid replay mode\n"); 243 exit(1); 244 } 245 246 atexit(replay_finish); 247 248 replay_file = fopen(fname, fmode); 249 if (replay_file == NULL) { 250 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno)); 251 exit(1); 252 } 253 254 replay_filename = g_strdup(fname); 255 replay_mode = mode; 256 replay_mutex_init(); 257 258 replay_state.data_kind = -1; 259 replay_state.instruction_count = 0; 260 replay_state.current_icount = 0; 261 replay_state.has_unread_data = 0; 262 263 /* skip file header for RECORD and check it for PLAY */ 264 if (replay_mode == REPLAY_MODE_RECORD) { 265 fseek(replay_file, HEADER_SIZE, SEEK_SET); 266 } else if (replay_mode == REPLAY_MODE_PLAY) { 267 unsigned int version = replay_get_dword(); 268 if (version != REPLAY_VERSION) { 269 fprintf(stderr, "Replay: invalid input log file version\n"); 270 exit(1); 271 } 272 /* go to the beginning */ 273 fseek(replay_file, HEADER_SIZE, SEEK_SET); 274 replay_fetch_data_kind(); 275 } 276 277 replay_init_events(); 278 } 279 280 void replay_configure(QemuOpts *opts) 281 { 282 const char *fname; 283 const char *rr; 284 ReplayMode mode = REPLAY_MODE_NONE; 285 Location loc; 286 287 if (!opts) { 288 return; 289 } 290 291 loc_push_none(&loc); 292 qemu_opts_loc_restore(opts); 293 294 rr = qemu_opt_get(opts, "rr"); 295 if (!rr) { 296 /* Just enabling icount */ 297 goto out; 298 } else if (!strcmp(rr, "record")) { 299 mode = REPLAY_MODE_RECORD; 300 } else if (!strcmp(rr, "replay")) { 301 mode = REPLAY_MODE_PLAY; 302 } else { 303 error_report("Invalid icount rr option: %s", rr); 304 exit(1); 305 } 306 307 fname = qemu_opt_get(opts, "rrfile"); 308 if (!fname) { 309 error_report("File name not specified for replay"); 310 exit(1); 311 } 312 313 replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot")); 314 replay_vmstate_register(); 315 replay_enable(fname, mode); 316 317 out: 318 loc_pop(&loc); 319 } 320 321 void replay_start(void) 322 { 323 if (replay_mode == REPLAY_MODE_NONE) { 324 return; 325 } 326 327 if (replay_blockers) { 328 error_reportf_err(replay_blockers->data, "Record/replay: "); 329 exit(1); 330 } 331 if (!icount_enabled()) { 332 error_report("Please enable icount to use record/replay"); 333 exit(1); 334 } 335 336 /* Timer for snapshotting will be set up here. */ 337 338 replay_enable_events(); 339 } 340 341 void replay_finish(void) 342 { 343 if (replay_mode == REPLAY_MODE_NONE) { 344 return; 345 } 346 347 replay_save_instructions(); 348 349 /* finalize the file */ 350 if (replay_file) { 351 if (replay_mode == REPLAY_MODE_RECORD) { 352 /* 353 * Can't do it in the signal handler, therefore 354 * add shutdown event here for the case of Ctrl-C. 355 */ 356 replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL); 357 /* write end event */ 358 replay_put_event(EVENT_END); 359 360 /* write header */ 361 fseek(replay_file, 0, SEEK_SET); 362 replay_put_dword(REPLAY_VERSION); 363 } 364 365 fclose(replay_file); 366 replay_file = NULL; 367 } 368 if (replay_filename) { 369 g_free(replay_filename); 370 replay_filename = NULL; 371 } 372 373 g_free(replay_snapshot); 374 replay_snapshot = NULL; 375 376 replay_finish_events(); 377 replay_mode = REPLAY_MODE_NONE; 378 } 379 380 void replay_add_blocker(Error *reason) 381 { 382 replay_blockers = g_slist_prepend(replay_blockers, reason); 383 } 384 385 const char *replay_get_filename(void) 386 { 387 return replay_filename; 388 } 389