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