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 "qemu-common.h" 15 #include "sysemu/replay.h" 16 #include "replay-internal.h" 17 #include "qemu/timer.h" 18 #include "qemu/main-loop.h" 19 #include "sysemu/sysemu.h" 20 #include "qemu/error-report.h" 21 22 /* Current version of the replay mechanism. 23 Increase it when file format changes. */ 24 #define REPLAY_VERSION 0xe02004 25 /* Size of replay log header */ 26 #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) 27 28 ReplayMode replay_mode = REPLAY_MODE_NONE; 29 30 /* Name of replay file */ 31 static char *replay_filename; 32 ReplayState replay_state; 33 static GSList *replay_blockers; 34 35 bool replay_next_event_is(int event) 36 { 37 bool res = false; 38 39 /* nothing to skip - not all instructions used */ 40 if (replay_state.instructions_count != 0) { 41 assert(replay_data_kind == EVENT_INSTRUCTION); 42 return event == EVENT_INSTRUCTION; 43 } 44 45 while (true) { 46 if (event == replay_data_kind) { 47 res = true; 48 } 49 switch (replay_data_kind) { 50 case EVENT_SHUTDOWN: 51 replay_finish_event(); 52 qemu_system_shutdown_request(); 53 break; 54 default: 55 /* clock, time_t, checkpoint and other events */ 56 return res; 57 } 58 } 59 return res; 60 } 61 62 uint64_t replay_get_current_step(void) 63 { 64 return cpu_get_icount_raw(); 65 } 66 67 int replay_get_instructions(void) 68 { 69 int res = 0; 70 replay_mutex_lock(); 71 if (replay_next_event_is(EVENT_INSTRUCTION)) { 72 res = replay_state.instructions_count; 73 } 74 replay_mutex_unlock(); 75 return res; 76 } 77 78 void replay_account_executed_instructions(void) 79 { 80 if (replay_mode == REPLAY_MODE_PLAY) { 81 replay_mutex_lock(); 82 if (replay_state.instructions_count > 0) { 83 int count = (int)(replay_get_current_step() 84 - replay_state.current_step); 85 replay_state.instructions_count -= count; 86 replay_state.current_step += count; 87 if (replay_state.instructions_count == 0) { 88 assert(replay_data_kind == EVENT_INSTRUCTION); 89 replay_finish_event(); 90 /* Wake up iothread. This is required because 91 timers will not expire until clock counters 92 will be read from the log. */ 93 qemu_notify_event(); 94 } 95 } 96 replay_mutex_unlock(); 97 } 98 } 99 100 bool replay_exception(void) 101 { 102 if (replay_mode == REPLAY_MODE_RECORD) { 103 replay_save_instructions(); 104 replay_mutex_lock(); 105 replay_put_event(EVENT_EXCEPTION); 106 replay_mutex_unlock(); 107 return true; 108 } else if (replay_mode == REPLAY_MODE_PLAY) { 109 bool res = replay_has_exception(); 110 if (res) { 111 replay_mutex_lock(); 112 replay_finish_event(); 113 replay_mutex_unlock(); 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 replay_account_executed_instructions(); 126 replay_mutex_lock(); 127 res = replay_next_event_is(EVENT_EXCEPTION); 128 replay_mutex_unlock(); 129 } 130 131 return res; 132 } 133 134 bool replay_interrupt(void) 135 { 136 if (replay_mode == REPLAY_MODE_RECORD) { 137 replay_save_instructions(); 138 replay_mutex_lock(); 139 replay_put_event(EVENT_INTERRUPT); 140 replay_mutex_unlock(); 141 return true; 142 } else if (replay_mode == REPLAY_MODE_PLAY) { 143 bool res = replay_has_interrupt(); 144 if (res) { 145 replay_mutex_lock(); 146 replay_finish_event(); 147 replay_mutex_unlock(); 148 } 149 return res; 150 } 151 152 return true; 153 } 154 155 bool replay_has_interrupt(void) 156 { 157 bool res = false; 158 if (replay_mode == REPLAY_MODE_PLAY) { 159 replay_account_executed_instructions(); 160 replay_mutex_lock(); 161 res = replay_next_event_is(EVENT_INTERRUPT); 162 replay_mutex_unlock(); 163 } 164 return res; 165 } 166 167 void replay_shutdown_request(void) 168 { 169 if (replay_mode == REPLAY_MODE_RECORD) { 170 replay_mutex_lock(); 171 replay_put_event(EVENT_SHUTDOWN); 172 replay_mutex_unlock(); 173 } 174 } 175 176 bool replay_checkpoint(ReplayCheckpoint checkpoint) 177 { 178 bool res = false; 179 assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); 180 replay_save_instructions(); 181 182 if (!replay_file) { 183 return true; 184 } 185 186 replay_mutex_lock(); 187 188 if (replay_mode == REPLAY_MODE_PLAY) { 189 if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { 190 replay_finish_event(); 191 } else if (replay_data_kind != EVENT_ASYNC) { 192 res = false; 193 goto out; 194 } 195 replay_read_events(checkpoint); 196 /* replay_read_events may leave some unread events. 197 Return false if not all of the events associated with 198 checkpoint were processed */ 199 res = replay_data_kind != EVENT_ASYNC; 200 } else if (replay_mode == REPLAY_MODE_RECORD) { 201 replay_put_event(EVENT_CHECKPOINT + checkpoint); 202 replay_save_events(checkpoint); 203 res = true; 204 } 205 out: 206 replay_mutex_unlock(); 207 return res; 208 } 209 210 static void replay_enable(const char *fname, int mode) 211 { 212 const char *fmode = NULL; 213 assert(!replay_file); 214 215 switch (mode) { 216 case REPLAY_MODE_RECORD: 217 fmode = "wb"; 218 break; 219 case REPLAY_MODE_PLAY: 220 fmode = "rb"; 221 break; 222 default: 223 fprintf(stderr, "Replay: internal error: invalid replay mode\n"); 224 exit(1); 225 } 226 227 atexit(replay_finish); 228 229 replay_mutex_init(); 230 231 replay_file = fopen(fname, fmode); 232 if (replay_file == NULL) { 233 fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno)); 234 exit(1); 235 } 236 237 replay_filename = g_strdup(fname); 238 239 replay_mode = mode; 240 replay_data_kind = -1; 241 replay_state.instructions_count = 0; 242 replay_state.current_step = 0; 243 244 /* skip file header for RECORD and check it for PLAY */ 245 if (replay_mode == REPLAY_MODE_RECORD) { 246 fseek(replay_file, HEADER_SIZE, SEEK_SET); 247 } else if (replay_mode == REPLAY_MODE_PLAY) { 248 unsigned int version = replay_get_dword(); 249 if (version != REPLAY_VERSION) { 250 fprintf(stderr, "Replay: invalid input log file version\n"); 251 exit(1); 252 } 253 /* go to the beginning */ 254 fseek(replay_file, HEADER_SIZE, SEEK_SET); 255 replay_fetch_data_kind(); 256 } 257 258 replay_init_events(); 259 } 260 261 void replay_configure(QemuOpts *opts) 262 { 263 const char *fname; 264 const char *rr; 265 ReplayMode mode = REPLAY_MODE_NONE; 266 Location loc; 267 268 if (!opts) { 269 return; 270 } 271 272 loc_push_none(&loc); 273 qemu_opts_loc_restore(opts); 274 275 rr = qemu_opt_get(opts, "rr"); 276 if (!rr) { 277 /* Just enabling icount */ 278 goto out; 279 } else if (!strcmp(rr, "record")) { 280 mode = REPLAY_MODE_RECORD; 281 } else if (!strcmp(rr, "replay")) { 282 mode = REPLAY_MODE_PLAY; 283 } else { 284 error_report("Invalid icount rr option: %s", rr); 285 exit(1); 286 } 287 288 fname = qemu_opt_get(opts, "rrfile"); 289 if (!fname) { 290 error_report("File name not specified for replay"); 291 exit(1); 292 } 293 294 replay_enable(fname, mode); 295 296 out: 297 loc_pop(&loc); 298 } 299 300 void replay_start(void) 301 { 302 if (replay_mode == REPLAY_MODE_NONE) { 303 return; 304 } 305 306 if (replay_blockers) { 307 error_reportf_err(replay_blockers->data, "Record/replay: "); 308 exit(1); 309 } 310 if (!use_icount) { 311 error_report("Please enable icount to use record/replay"); 312 exit(1); 313 } 314 315 /* Timer for snapshotting will be set up here. */ 316 317 replay_enable_events(); 318 } 319 320 void replay_finish(void) 321 { 322 if (replay_mode == REPLAY_MODE_NONE) { 323 return; 324 } 325 326 replay_save_instructions(); 327 328 /* finalize the file */ 329 if (replay_file) { 330 if (replay_mode == REPLAY_MODE_RECORD) { 331 /* write end event */ 332 replay_put_event(EVENT_END); 333 334 /* write header */ 335 fseek(replay_file, 0, SEEK_SET); 336 replay_put_dword(REPLAY_VERSION); 337 } 338 339 fclose(replay_file); 340 replay_file = NULL; 341 } 342 if (replay_filename) { 343 g_free(replay_filename); 344 replay_filename = NULL; 345 } 346 347 replay_finish_events(); 348 replay_mutex_destroy(); 349 } 350 351 void replay_add_blocker(Error *reason) 352 { 353 replay_blockers = g_slist_prepend(replay_blockers, reason); 354 } 355