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