1d73abd6dSPavel Dovgalyuk /* 2d73abd6dSPavel Dovgalyuk * replay.c 3d73abd6dSPavel Dovgalyuk * 4d73abd6dSPavel Dovgalyuk * Copyright (c) 2010-2015 Institute for System Programming 5d73abd6dSPavel Dovgalyuk * of the Russian Academy of Sciences. 6d73abd6dSPavel Dovgalyuk * 7d73abd6dSPavel Dovgalyuk * This work is licensed under the terms of the GNU GPL, version 2 or later. 8d73abd6dSPavel Dovgalyuk * See the COPYING file in the top-level directory. 9d73abd6dSPavel Dovgalyuk * 10d73abd6dSPavel Dovgalyuk */ 11d73abd6dSPavel Dovgalyuk 12d38ea87aSPeter Maydell #include "qemu/osdep.h" 13da34e65cSMarkus Armbruster #include "qapi/error.h" 1426bc60acSPavel Dovgalyuk #include "qemu-common.h" 15d73abd6dSPavel Dovgalyuk #include "sysemu/replay.h" 1626bc60acSPavel Dovgalyuk #include "replay-internal.h" 1726bc60acSPavel Dovgalyuk #include "qemu/timer.h" 188b427044SPavel Dovgalyuk #include "qemu/main-loop.h" 19d2528bdcSPaolo Bonzini #include "sysemu/cpus.h" 20b60c48a7SPavel Dovgalyuk #include "sysemu/sysemu.h" 217615936eSPavel Dovgalyuk #include "qemu/error-report.h" 227615936eSPavel Dovgalyuk 237615936eSPavel Dovgalyuk /* Current version of the replay mechanism. 247615936eSPavel Dovgalyuk Increase it when file format changes. */ 255b12c163SAlex Bennée #define REPLAY_VERSION 0xe02006 267615936eSPavel Dovgalyuk /* Size of replay log header */ 277615936eSPavel Dovgalyuk #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) 28d73abd6dSPavel Dovgalyuk 29d73abd6dSPavel Dovgalyuk ReplayMode replay_mode = REPLAY_MODE_NONE; 309c2037d0SPavel Dovgalyuk char *replay_snapshot; 3126bc60acSPavel Dovgalyuk 327615936eSPavel Dovgalyuk /* Name of replay file */ 337615936eSPavel Dovgalyuk static char *replay_filename; 3426bc60acSPavel Dovgalyuk ReplayState replay_state; 350194749aSPavel Dovgalyuk static GSList *replay_blockers; 3626bc60acSPavel Dovgalyuk 3726bc60acSPavel Dovgalyuk bool replay_next_event_is(int event) 3826bc60acSPavel Dovgalyuk { 3926bc60acSPavel Dovgalyuk bool res = false; 4026bc60acSPavel Dovgalyuk 4126bc60acSPavel Dovgalyuk /* nothing to skip - not all instructions used */ 4226bc60acSPavel Dovgalyuk if (replay_state.instructions_count != 0) { 43f186d64dSPavel Dovgalyuk assert(replay_state.data_kind == EVENT_INSTRUCTION); 4426bc60acSPavel Dovgalyuk return event == EVENT_INSTRUCTION; 4526bc60acSPavel Dovgalyuk } 4626bc60acSPavel Dovgalyuk 4726bc60acSPavel Dovgalyuk while (true) { 48f186d64dSPavel Dovgalyuk if (event == replay_state.data_kind) { 4926bc60acSPavel Dovgalyuk res = true; 5026bc60acSPavel Dovgalyuk } 51f186d64dSPavel Dovgalyuk switch (replay_state.data_kind) { 52802f045aSEric Blake case EVENT_SHUTDOWN ... EVENT_SHUTDOWN_LAST: 53b60c48a7SPavel Dovgalyuk replay_finish_event(); 54*cf83f140SEric Blake qemu_system_shutdown_request(replay_state.data_kind - 55*cf83f140SEric Blake EVENT_SHUTDOWN); 56b60c48a7SPavel Dovgalyuk break; 5726bc60acSPavel Dovgalyuk default: 5826bc60acSPavel Dovgalyuk /* clock, time_t, checkpoint and other events */ 5926bc60acSPavel Dovgalyuk return res; 6026bc60acSPavel Dovgalyuk } 6126bc60acSPavel Dovgalyuk } 6226bc60acSPavel Dovgalyuk return res; 6326bc60acSPavel Dovgalyuk } 6426bc60acSPavel Dovgalyuk 6526bc60acSPavel Dovgalyuk uint64_t replay_get_current_step(void) 6626bc60acSPavel Dovgalyuk { 6726bc60acSPavel Dovgalyuk return cpu_get_icount_raw(); 6826bc60acSPavel Dovgalyuk } 698b427044SPavel Dovgalyuk 708b427044SPavel Dovgalyuk int replay_get_instructions(void) 718b427044SPavel Dovgalyuk { 728b427044SPavel Dovgalyuk int res = 0; 738b427044SPavel Dovgalyuk replay_mutex_lock(); 748b427044SPavel Dovgalyuk if (replay_next_event_is(EVENT_INSTRUCTION)) { 758b427044SPavel Dovgalyuk res = replay_state.instructions_count; 768b427044SPavel Dovgalyuk } 778b427044SPavel Dovgalyuk replay_mutex_unlock(); 788b427044SPavel Dovgalyuk return res; 798b427044SPavel Dovgalyuk } 808b427044SPavel Dovgalyuk 818b427044SPavel Dovgalyuk void replay_account_executed_instructions(void) 828b427044SPavel Dovgalyuk { 838b427044SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) { 848b427044SPavel Dovgalyuk replay_mutex_lock(); 858b427044SPavel Dovgalyuk if (replay_state.instructions_count > 0) { 868b427044SPavel Dovgalyuk int count = (int)(replay_get_current_step() 878b427044SPavel Dovgalyuk - replay_state.current_step); 88982263ceSAlex Bennée 89982263ceSAlex Bennée /* Time can only go forward */ 90982263ceSAlex Bennée assert(count >= 0); 91982263ceSAlex Bennée 928b427044SPavel Dovgalyuk replay_state.instructions_count -= count; 938b427044SPavel Dovgalyuk replay_state.current_step += count; 948b427044SPavel Dovgalyuk if (replay_state.instructions_count == 0) { 95f186d64dSPavel Dovgalyuk assert(replay_state.data_kind == EVENT_INSTRUCTION); 968b427044SPavel Dovgalyuk replay_finish_event(); 978b427044SPavel Dovgalyuk /* Wake up iothread. This is required because 988b427044SPavel Dovgalyuk timers will not expire until clock counters 998b427044SPavel Dovgalyuk will be read from the log. */ 1008b427044SPavel Dovgalyuk qemu_notify_event(); 1018b427044SPavel Dovgalyuk } 1028b427044SPavel Dovgalyuk } 1038b427044SPavel Dovgalyuk replay_mutex_unlock(); 1048b427044SPavel Dovgalyuk } 1058b427044SPavel Dovgalyuk } 1066f060969SPavel Dovgalyuk 1076f060969SPavel Dovgalyuk bool replay_exception(void) 1086f060969SPavel Dovgalyuk { 1096f060969SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) { 1106f060969SPavel Dovgalyuk replay_save_instructions(); 1116f060969SPavel Dovgalyuk replay_mutex_lock(); 1126f060969SPavel Dovgalyuk replay_put_event(EVENT_EXCEPTION); 1136f060969SPavel Dovgalyuk replay_mutex_unlock(); 1146f060969SPavel Dovgalyuk return true; 1156f060969SPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_PLAY) { 1166f060969SPavel Dovgalyuk bool res = replay_has_exception(); 1176f060969SPavel Dovgalyuk if (res) { 1186f060969SPavel Dovgalyuk replay_mutex_lock(); 1196f060969SPavel Dovgalyuk replay_finish_event(); 1206f060969SPavel Dovgalyuk replay_mutex_unlock(); 1216f060969SPavel Dovgalyuk } 1226f060969SPavel Dovgalyuk return res; 1236f060969SPavel Dovgalyuk } 1246f060969SPavel Dovgalyuk 1256f060969SPavel Dovgalyuk return true; 1266f060969SPavel Dovgalyuk } 1276f060969SPavel Dovgalyuk 1286f060969SPavel Dovgalyuk bool replay_has_exception(void) 1296f060969SPavel Dovgalyuk { 1306f060969SPavel Dovgalyuk bool res = false; 1316f060969SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) { 1326f060969SPavel Dovgalyuk replay_account_executed_instructions(); 1336f060969SPavel Dovgalyuk replay_mutex_lock(); 1346f060969SPavel Dovgalyuk res = replay_next_event_is(EVENT_EXCEPTION); 1356f060969SPavel Dovgalyuk replay_mutex_unlock(); 1366f060969SPavel Dovgalyuk } 1376f060969SPavel Dovgalyuk 1386f060969SPavel Dovgalyuk return res; 1396f060969SPavel Dovgalyuk } 1406f060969SPavel Dovgalyuk 1416f060969SPavel Dovgalyuk bool replay_interrupt(void) 1426f060969SPavel Dovgalyuk { 1436f060969SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) { 1446f060969SPavel Dovgalyuk replay_save_instructions(); 1456f060969SPavel Dovgalyuk replay_mutex_lock(); 1466f060969SPavel Dovgalyuk replay_put_event(EVENT_INTERRUPT); 1476f060969SPavel Dovgalyuk replay_mutex_unlock(); 1486f060969SPavel Dovgalyuk return true; 1496f060969SPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_PLAY) { 1506f060969SPavel Dovgalyuk bool res = replay_has_interrupt(); 1516f060969SPavel Dovgalyuk if (res) { 1526f060969SPavel Dovgalyuk replay_mutex_lock(); 1536f060969SPavel Dovgalyuk replay_finish_event(); 1546f060969SPavel Dovgalyuk replay_mutex_unlock(); 1556f060969SPavel Dovgalyuk } 1566f060969SPavel Dovgalyuk return res; 1576f060969SPavel Dovgalyuk } 1586f060969SPavel Dovgalyuk 1596f060969SPavel Dovgalyuk return true; 1606f060969SPavel Dovgalyuk } 1616f060969SPavel Dovgalyuk 1626f060969SPavel Dovgalyuk bool replay_has_interrupt(void) 1636f060969SPavel Dovgalyuk { 1646f060969SPavel Dovgalyuk bool res = false; 1656f060969SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) { 1666f060969SPavel Dovgalyuk replay_account_executed_instructions(); 1676f060969SPavel Dovgalyuk replay_mutex_lock(); 1686f060969SPavel Dovgalyuk res = replay_next_event_is(EVENT_INTERRUPT); 1696f060969SPavel Dovgalyuk replay_mutex_unlock(); 1706f060969SPavel Dovgalyuk } 1716f060969SPavel Dovgalyuk return res; 1726f060969SPavel Dovgalyuk } 173b60c48a7SPavel Dovgalyuk 174802f045aSEric Blake void replay_shutdown_request(ShutdownCause cause) 175b60c48a7SPavel Dovgalyuk { 176b60c48a7SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) { 177b60c48a7SPavel Dovgalyuk replay_mutex_lock(); 178802f045aSEric Blake replay_put_event(EVENT_SHUTDOWN + cause); 179b60c48a7SPavel Dovgalyuk replay_mutex_unlock(); 180b60c48a7SPavel Dovgalyuk } 181b60c48a7SPavel Dovgalyuk } 1828bd7f71dSPavel Dovgalyuk 1838bd7f71dSPavel Dovgalyuk bool replay_checkpoint(ReplayCheckpoint checkpoint) 1848bd7f71dSPavel Dovgalyuk { 1858bd7f71dSPavel Dovgalyuk bool res = false; 1868bd7f71dSPavel Dovgalyuk assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST); 1878bd7f71dSPavel Dovgalyuk replay_save_instructions(); 1888bd7f71dSPavel Dovgalyuk 1898bd7f71dSPavel Dovgalyuk if (!replay_file) { 1908bd7f71dSPavel Dovgalyuk return true; 1918bd7f71dSPavel Dovgalyuk } 1928bd7f71dSPavel Dovgalyuk 1938bd7f71dSPavel Dovgalyuk replay_mutex_lock(); 1948bd7f71dSPavel Dovgalyuk 1958bd7f71dSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) { 1968bd7f71dSPavel Dovgalyuk if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) { 1978bd7f71dSPavel Dovgalyuk replay_finish_event(); 198f186d64dSPavel Dovgalyuk } else if (replay_state.data_kind != EVENT_ASYNC) { 1998bd7f71dSPavel Dovgalyuk res = false; 2008bd7f71dSPavel Dovgalyuk goto out; 2018bd7f71dSPavel Dovgalyuk } 2028bd7f71dSPavel Dovgalyuk replay_read_events(checkpoint); 2038bd7f71dSPavel Dovgalyuk /* replay_read_events may leave some unread events. 2048bd7f71dSPavel Dovgalyuk Return false if not all of the events associated with 2058bd7f71dSPavel Dovgalyuk checkpoint were processed */ 206f186d64dSPavel Dovgalyuk res = replay_state.data_kind != EVENT_ASYNC; 2078bd7f71dSPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_RECORD) { 2088bd7f71dSPavel Dovgalyuk replay_put_event(EVENT_CHECKPOINT + checkpoint); 2098bd7f71dSPavel Dovgalyuk replay_save_events(checkpoint); 2108bd7f71dSPavel Dovgalyuk res = true; 2118bd7f71dSPavel Dovgalyuk } 2128bd7f71dSPavel Dovgalyuk out: 2138bd7f71dSPavel Dovgalyuk replay_mutex_unlock(); 2148bd7f71dSPavel Dovgalyuk return res; 2158bd7f71dSPavel Dovgalyuk } 2167615936eSPavel Dovgalyuk 2177615936eSPavel Dovgalyuk static void replay_enable(const char *fname, int mode) 2187615936eSPavel Dovgalyuk { 2197615936eSPavel Dovgalyuk const char *fmode = NULL; 2207615936eSPavel Dovgalyuk assert(!replay_file); 2217615936eSPavel Dovgalyuk 2227615936eSPavel Dovgalyuk switch (mode) { 2237615936eSPavel Dovgalyuk case REPLAY_MODE_RECORD: 2247615936eSPavel Dovgalyuk fmode = "wb"; 2257615936eSPavel Dovgalyuk break; 2267615936eSPavel Dovgalyuk case REPLAY_MODE_PLAY: 2277615936eSPavel Dovgalyuk fmode = "rb"; 2287615936eSPavel Dovgalyuk break; 2297615936eSPavel Dovgalyuk default: 2307615936eSPavel Dovgalyuk fprintf(stderr, "Replay: internal error: invalid replay mode\n"); 2317615936eSPavel Dovgalyuk exit(1); 2327615936eSPavel Dovgalyuk } 2337615936eSPavel Dovgalyuk 2347615936eSPavel Dovgalyuk atexit(replay_finish); 2357615936eSPavel Dovgalyuk 2367615936eSPavel Dovgalyuk replay_mutex_init(); 2377615936eSPavel Dovgalyuk 2387615936eSPavel Dovgalyuk replay_file = fopen(fname, fmode); 2397615936eSPavel Dovgalyuk if (replay_file == NULL) { 2407615936eSPavel Dovgalyuk fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno)); 2417615936eSPavel Dovgalyuk exit(1); 2427615936eSPavel Dovgalyuk } 2437615936eSPavel Dovgalyuk 2447615936eSPavel Dovgalyuk replay_filename = g_strdup(fname); 2457615936eSPavel Dovgalyuk 2467615936eSPavel Dovgalyuk replay_mode = mode; 247f186d64dSPavel Dovgalyuk replay_state.data_kind = -1; 2487615936eSPavel Dovgalyuk replay_state.instructions_count = 0; 2497615936eSPavel Dovgalyuk replay_state.current_step = 0; 250f186d64dSPavel Dovgalyuk replay_state.has_unread_data = 0; 2517615936eSPavel Dovgalyuk 2527615936eSPavel Dovgalyuk /* skip file header for RECORD and check it for PLAY */ 2537615936eSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) { 2547615936eSPavel Dovgalyuk fseek(replay_file, HEADER_SIZE, SEEK_SET); 2557615936eSPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_PLAY) { 2567615936eSPavel Dovgalyuk unsigned int version = replay_get_dword(); 2577615936eSPavel Dovgalyuk if (version != REPLAY_VERSION) { 2587615936eSPavel Dovgalyuk fprintf(stderr, "Replay: invalid input log file version\n"); 2597615936eSPavel Dovgalyuk exit(1); 2607615936eSPavel Dovgalyuk } 2617615936eSPavel Dovgalyuk /* go to the beginning */ 2627615936eSPavel Dovgalyuk fseek(replay_file, HEADER_SIZE, SEEK_SET); 2637615936eSPavel Dovgalyuk replay_fetch_data_kind(); 2647615936eSPavel Dovgalyuk } 2657615936eSPavel Dovgalyuk 2667615936eSPavel Dovgalyuk replay_init_events(); 2677615936eSPavel Dovgalyuk } 2687615936eSPavel Dovgalyuk 2697615936eSPavel Dovgalyuk void replay_configure(QemuOpts *opts) 2707615936eSPavel Dovgalyuk { 2717615936eSPavel Dovgalyuk const char *fname; 2727615936eSPavel Dovgalyuk const char *rr; 2737615936eSPavel Dovgalyuk ReplayMode mode = REPLAY_MODE_NONE; 274890ad550SEduardo Habkost Location loc; 275890ad550SEduardo Habkost 276890ad550SEduardo Habkost if (!opts) { 277890ad550SEduardo Habkost return; 278890ad550SEduardo Habkost } 279890ad550SEduardo Habkost 280890ad550SEduardo Habkost loc_push_none(&loc); 281890ad550SEduardo Habkost qemu_opts_loc_restore(opts); 2827615936eSPavel Dovgalyuk 2837615936eSPavel Dovgalyuk rr = qemu_opt_get(opts, "rr"); 2847615936eSPavel Dovgalyuk if (!rr) { 2857615936eSPavel Dovgalyuk /* Just enabling icount */ 286d9d3aaeaSMarkus Armbruster goto out; 2877615936eSPavel Dovgalyuk } else if (!strcmp(rr, "record")) { 2887615936eSPavel Dovgalyuk mode = REPLAY_MODE_RECORD; 2897615936eSPavel Dovgalyuk } else if (!strcmp(rr, "replay")) { 2907615936eSPavel Dovgalyuk mode = REPLAY_MODE_PLAY; 2917615936eSPavel Dovgalyuk } else { 2927615936eSPavel Dovgalyuk error_report("Invalid icount rr option: %s", rr); 2937615936eSPavel Dovgalyuk exit(1); 2947615936eSPavel Dovgalyuk } 2957615936eSPavel Dovgalyuk 2967615936eSPavel Dovgalyuk fname = qemu_opt_get(opts, "rrfile"); 2977615936eSPavel Dovgalyuk if (!fname) { 2987615936eSPavel Dovgalyuk error_report("File name not specified for replay"); 2997615936eSPavel Dovgalyuk exit(1); 3007615936eSPavel Dovgalyuk } 3017615936eSPavel Dovgalyuk 3029c2037d0SPavel Dovgalyuk replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot")); 303306e196fSPavel Dovgalyuk replay_vmstate_register(); 3047615936eSPavel Dovgalyuk replay_enable(fname, mode); 305890ad550SEduardo Habkost 306d9d3aaeaSMarkus Armbruster out: 307890ad550SEduardo Habkost loc_pop(&loc); 3087615936eSPavel Dovgalyuk } 3097615936eSPavel Dovgalyuk 3107615936eSPavel Dovgalyuk void replay_start(void) 3117615936eSPavel Dovgalyuk { 3127615936eSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_NONE) { 3137615936eSPavel Dovgalyuk return; 3147615936eSPavel Dovgalyuk } 3157615936eSPavel Dovgalyuk 3160194749aSPavel Dovgalyuk if (replay_blockers) { 317c29b77f9SMarkus Armbruster error_reportf_err(replay_blockers->data, "Record/replay: "); 3180194749aSPavel Dovgalyuk exit(1); 3190194749aSPavel Dovgalyuk } 3204c27b859SPavel Dovgalyuk if (!use_icount) { 3214c27b859SPavel Dovgalyuk error_report("Please enable icount to use record/replay"); 3224c27b859SPavel Dovgalyuk exit(1); 3234c27b859SPavel Dovgalyuk } 3240194749aSPavel Dovgalyuk 3257615936eSPavel Dovgalyuk /* Timer for snapshotting will be set up here. */ 3267615936eSPavel Dovgalyuk 3277615936eSPavel Dovgalyuk replay_enable_events(); 3287615936eSPavel Dovgalyuk } 3297615936eSPavel Dovgalyuk 3307615936eSPavel Dovgalyuk void replay_finish(void) 3317615936eSPavel Dovgalyuk { 3327615936eSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_NONE) { 3337615936eSPavel Dovgalyuk return; 3347615936eSPavel Dovgalyuk } 3357615936eSPavel Dovgalyuk 3367615936eSPavel Dovgalyuk replay_save_instructions(); 3377615936eSPavel Dovgalyuk 3387615936eSPavel Dovgalyuk /* finalize the file */ 3397615936eSPavel Dovgalyuk if (replay_file) { 3407615936eSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) { 3417615936eSPavel Dovgalyuk /* write end event */ 3427615936eSPavel Dovgalyuk replay_put_event(EVENT_END); 3437615936eSPavel Dovgalyuk 3447615936eSPavel Dovgalyuk /* write header */ 3457615936eSPavel Dovgalyuk fseek(replay_file, 0, SEEK_SET); 3467615936eSPavel Dovgalyuk replay_put_dword(REPLAY_VERSION); 3477615936eSPavel Dovgalyuk } 3487615936eSPavel Dovgalyuk 3497615936eSPavel Dovgalyuk fclose(replay_file); 3507615936eSPavel Dovgalyuk replay_file = NULL; 3517615936eSPavel Dovgalyuk } 3527615936eSPavel Dovgalyuk if (replay_filename) { 3537615936eSPavel Dovgalyuk g_free(replay_filename); 3547615936eSPavel Dovgalyuk replay_filename = NULL; 3557615936eSPavel Dovgalyuk } 3567615936eSPavel Dovgalyuk 3579c2037d0SPavel Dovgalyuk g_free(replay_snapshot); 3589c2037d0SPavel Dovgalyuk replay_snapshot = NULL; 3599c2037d0SPavel Dovgalyuk 3607615936eSPavel Dovgalyuk replay_finish_events(); 3617615936eSPavel Dovgalyuk replay_mutex_destroy(); 3627615936eSPavel Dovgalyuk } 3630194749aSPavel Dovgalyuk 3640194749aSPavel Dovgalyuk void replay_add_blocker(Error *reason) 3650194749aSPavel Dovgalyuk { 3660194749aSPavel Dovgalyuk replay_blockers = g_slist_prepend(replay_blockers, reason); 3670194749aSPavel Dovgalyuk } 368