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 0xe0200c 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 g_assert(replay_mutex_locked()); 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 return res; 89 } 90 91 void replay_account_executed_instructions(void) 92 { 93 if (replay_mode == REPLAY_MODE_PLAY) { 94 g_assert(replay_mutex_locked()); 95 if (replay_state.instruction_count > 0) { 96 replay_advance_current_icount(replay_get_current_icount()); 97 } 98 } 99 } 100 101 bool replay_exception(void) 102 { 103 104 if (replay_mode == REPLAY_MODE_RECORD) { 105 g_assert(replay_mutex_locked()); 106 replay_save_instructions(); 107 replay_put_event(EVENT_EXCEPTION); 108 return true; 109 } else if (replay_mode == REPLAY_MODE_PLAY) { 110 g_assert(replay_mutex_locked()); 111 bool res = replay_has_exception(); 112 if (res) { 113 replay_finish_event(); 114 } 115 return res; 116 } 117 118 return true; 119 } 120 121 bool replay_has_exception(void) 122 { 123 bool res = false; 124 if (replay_mode == REPLAY_MODE_PLAY) { 125 g_assert(replay_mutex_locked()); 126 replay_account_executed_instructions(); 127 res = replay_next_event_is(EVENT_EXCEPTION); 128 } 129 130 return res; 131 } 132 133 bool replay_interrupt(void) 134 { 135 if (replay_mode == REPLAY_MODE_RECORD) { 136 g_assert(replay_mutex_locked()); 137 replay_save_instructions(); 138 replay_put_event(EVENT_INTERRUPT); 139 return true; 140 } else if (replay_mode == REPLAY_MODE_PLAY) { 141 g_assert(replay_mutex_locked()); 142 bool res = replay_has_interrupt(); 143 if (res) { 144 replay_finish_event(); 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 g_assert(replay_mutex_locked()); 157 replay_account_executed_instructions(); 158 res = replay_next_event_is(EVENT_INTERRUPT); 159 } 160 return res; 161 } 162 163 void replay_shutdown_request(ShutdownCause cause) 164 { 165 if (replay_mode == REPLAY_MODE_RECORD) { 166 g_assert(replay_mutex_locked()); 167 replay_put_event(EVENT_SHUTDOWN + cause); 168 } 169 } 170 171 bool replay_checkpoint(ReplayCheckpoint checkpoint) 172 { 173 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); 174 175 replay_save_instructions(); 176 177 if (replay_mode == REPLAY_MODE_PLAY) { 178 g_assert(replay_mutex_locked()); 179 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { 180 replay_finish_event(); 181 } else { 182 return false; 183 } 184 } else if (replay_mode == REPLAY_MODE_RECORD) { 185 g_assert(replay_mutex_locked()); 186 replay_put_event(EVENT_CHECKPOINT + checkpoint); 187 } 188 return true; 189 } 190 191 void replay_async_events(void) 192 { 193 static bool processing = false; 194 /* 195 * If we are already processing the events, recursion may occur 196 * in case of incorrect implementation when HW event modifies timers. 197 * Timer modification may invoke the icount warp, event processing, 198 * and cause the recursion. 199 */ 200 g_assert(!processing); 201 processing = true; 202 203 replay_save_instructions(); 204 205 if (replay_mode == REPLAY_MODE_PLAY) { 206 g_assert(replay_mutex_locked()); 207 replay_read_events(); 208 } else if (replay_mode == REPLAY_MODE_RECORD) { 209 g_assert(replay_mutex_locked()); 210 replay_save_events(); 211 } 212 processing = false; 213 } 214 215 bool replay_has_event(void) 216 { 217 bool res = false; 218 if (replay_mode == REPLAY_MODE_PLAY) { 219 g_assert(replay_mutex_locked()); 220 replay_account_executed_instructions(); 221 res = EVENT_CHECKPOINT <= replay_state.data_kind 222 && replay_state.data_kind <= EVENT_CHECKPOINT_LAST; 223 res = res || (EVENT_ASYNC <= replay_state.data_kind 224 && replay_state.data_kind <= EVENT_ASYNC_LAST); 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 g_free(replay_filename); 369 replay_filename = NULL; 370 371 g_free(replay_snapshot); 372 replay_snapshot = NULL; 373 374 replay_finish_events(); 375 replay_mode = REPLAY_MODE_NONE; 376 } 377 378 void replay_add_blocker(const char *feature) 379 { 380 Error *reason = NULL; 381 382 error_setg(&reason, "Record/replay feature is not supported for '%s'", 383 feature); 384 replay_blockers = g_slist_prepend(replay_blockers, reason); 385 } 386 387 const char *replay_get_filename(void) 388 { 389 return replay_filename; 390 } 391