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 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 || (EVENT_ASYNC <= replay_state.data_kind 225 && replay_state.data_kind <= EVENT_ASYNC_LAST); 226 } 227 return res; 228 } 229 230 static void replay_enable(const char *fname, int mode) 231 { 232 const char *fmode = NULL; 233 assert(!replay_file); 234 235 switch (mode) { 236 case REPLAY_MODE_RECORD: 237 fmode = "wb"; 238 break; 239 case REPLAY_MODE_PLAY: 240 fmode = "rb"; 241 break; 242 default: 243 fprintf(stderr, "Replay: internal error: invalid replay mode\n"); 244 exit(1); 245 } 246 247 atexit(replay_finish); 248 249 replay_file = fopen(fname, fmode); 250 if (replay_file == NULL) { 251 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno)); 252 exit(1); 253 } 254 255 replay_filename = g_strdup(fname); 256 replay_mode = mode; 257 replay_mutex_init(); 258 259 replay_state.data_kind = -1; 260 replay_state.instruction_count = 0; 261 replay_state.current_icount = 0; 262 replay_state.has_unread_data = 0; 263 264 /* skip file header for RECORD and check it for PLAY */ 265 if (replay_mode == REPLAY_MODE_RECORD) { 266 fseek(replay_file, HEADER_SIZE, SEEK_SET); 267 } else if (replay_mode == REPLAY_MODE_PLAY) { 268 unsigned int version = replay_get_dword(); 269 if (version != REPLAY_VERSION) { 270 fprintf(stderr, "Replay: invalid input log file version\n"); 271 exit(1); 272 } 273 /* go to the beginning */ 274 fseek(replay_file, HEADER_SIZE, SEEK_SET); 275 replay_fetch_data_kind(); 276 } 277 278 replay_init_events(); 279 } 280 281 void replay_configure(QemuOpts *opts) 282 { 283 const char *fname; 284 const char *rr; 285 ReplayMode mode = REPLAY_MODE_NONE; 286 Location loc; 287 288 if (!opts) { 289 return; 290 } 291 292 loc_push_none(&loc); 293 qemu_opts_loc_restore(opts); 294 295 rr = qemu_opt_get(opts, "rr"); 296 if (!rr) { 297 /* Just enabling icount */ 298 goto out; 299 } else if (!strcmp(rr, "record")) { 300 mode = REPLAY_MODE_RECORD; 301 } else if (!strcmp(rr, "replay")) { 302 mode = REPLAY_MODE_PLAY; 303 } else { 304 error_report("Invalid icount rr option: %s", rr); 305 exit(1); 306 } 307 308 fname = qemu_opt_get(opts, "rrfile"); 309 if (!fname) { 310 error_report("File name not specified for replay"); 311 exit(1); 312 } 313 314 replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot")); 315 replay_vmstate_register(); 316 replay_enable(fname, mode); 317 318 out: 319 loc_pop(&loc); 320 } 321 322 void replay_start(void) 323 { 324 if (replay_mode == REPLAY_MODE_NONE) { 325 return; 326 } 327 328 if (replay_blockers) { 329 error_reportf_err(replay_blockers->data, "Record/replay: "); 330 exit(1); 331 } 332 if (!icount_enabled()) { 333 error_report("Please enable icount to use record/replay"); 334 exit(1); 335 } 336 337 /* Timer for snapshotting will be set up here. */ 338 339 replay_enable_events(); 340 } 341 342 void replay_finish(void) 343 { 344 if (replay_mode == REPLAY_MODE_NONE) { 345 return; 346 } 347 348 replay_save_instructions(); 349 350 /* finalize the file */ 351 if (replay_file) { 352 if (replay_mode == REPLAY_MODE_RECORD) { 353 /* 354 * Can't do it in the signal handler, therefore 355 * add shutdown event here for the case of Ctrl-C. 356 */ 357 replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL); 358 /* write end event */ 359 replay_put_event(EVENT_END); 360 361 /* write header */ 362 fseek(replay_file, 0, SEEK_SET); 363 replay_put_dword(REPLAY_VERSION); 364 } 365 366 fclose(replay_file); 367 replay_file = NULL; 368 } 369 g_free(replay_filename); 370 replay_filename = NULL; 371 372 g_free(replay_snapshot); 373 replay_snapshot = NULL; 374 375 replay_finish_events(); 376 replay_mode = REPLAY_MODE_NONE; 377 } 378 379 void replay_add_blocker(Error *reason) 380 { 381 replay_blockers = g_slist_prepend(replay_blockers, reason); 382 } 383 384 const char *replay_get_filename(void) 385 { 386 return replay_filename; 387 } 388