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"
14740b1759SClaudio Fontana #include "sysemu/cpu-timers.h"
15d73abd6dSPavel Dovgalyuk #include "sysemu/replay.h"
1654d31236SMarkus Armbruster #include "sysemu/runstate.h"
1726bc60acSPavel Dovgalyuk #include "replay-internal.h"
188b427044SPavel Dovgalyuk #include "qemu/main-loop.h"
19922a01a0SMarkus Armbruster #include "qemu/option.h"
20d2528bdcSPaolo Bonzini #include "sysemu/cpus.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. */
253e21408bSPavel Dovgalyuk #define REPLAY_VERSION 0xe0200c
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
37e7510671SPavel Dovgalyuk /* Replay breakpoints */
38e7510671SPavel Dovgalyuk uint64_t replay_break_icount = -1ULL;
39e7510671SPavel Dovgalyuk QEMUTimer *replay_break_timer;
40e7510671SPavel Dovgalyuk
41dcda7321SAlex Bennée /* Pretty print event names */
42dcda7321SAlex Bennée
replay_async_event_name(ReplayAsyncEventKind event)43dcda7321SAlex Bennée static const char *replay_async_event_name(ReplayAsyncEventKind event)
44dcda7321SAlex Bennée {
45dcda7321SAlex Bennée switch (event) {
46dcda7321SAlex Bennée #define ASYNC_EVENT(_x) case REPLAY_ASYNC_EVENT_ ## _x: return "ASYNC_EVENT_"#_x
47dcda7321SAlex Bennée ASYNC_EVENT(BH);
48dcda7321SAlex Bennée ASYNC_EVENT(BH_ONESHOT);
49dcda7321SAlex Bennée ASYNC_EVENT(INPUT);
50dcda7321SAlex Bennée ASYNC_EVENT(INPUT_SYNC);
51dcda7321SAlex Bennée ASYNC_EVENT(CHAR_READ);
52dcda7321SAlex Bennée ASYNC_EVENT(BLOCK);
53dcda7321SAlex Bennée ASYNC_EVENT(NET);
54dcda7321SAlex Bennée #undef ASYNC_EVENT
55dcda7321SAlex Bennée default:
56dcda7321SAlex Bennée g_assert_not_reached();
57dcda7321SAlex Bennée }
58dcda7321SAlex Bennée }
59dcda7321SAlex Bennée
replay_clock_event_name(ReplayClockKind clock)60dcda7321SAlex Bennée static const char *replay_clock_event_name(ReplayClockKind clock)
61dcda7321SAlex Bennée {
62dcda7321SAlex Bennée switch (clock) {
63dcda7321SAlex Bennée #define CLOCK_EVENT(_x) case REPLAY_CLOCK_ ## _x: return "CLOCK_" #_x
64dcda7321SAlex Bennée CLOCK_EVENT(HOST);
65dcda7321SAlex Bennée CLOCK_EVENT(VIRTUAL_RT);
66dcda7321SAlex Bennée #undef CLOCK_EVENT
67dcda7321SAlex Bennée default:
68dcda7321SAlex Bennée g_assert_not_reached();
69dcda7321SAlex Bennée }
70dcda7321SAlex Bennée }
71dcda7321SAlex Bennée
72dcda7321SAlex Bennée /* Pretty print shutdown event names */
replay_shutdown_event_name(ShutdownCause cause)73dcda7321SAlex Bennée static const char *replay_shutdown_event_name(ShutdownCause cause)
74dcda7321SAlex Bennée {
75dcda7321SAlex Bennée switch (cause) {
76dcda7321SAlex Bennée #define SHUTDOWN_EVENT(_x) case SHUTDOWN_CAUSE_ ## _x: return "SHUTDOWN_CAUSE_" #_x
77dcda7321SAlex Bennée SHUTDOWN_EVENT(NONE);
78dcda7321SAlex Bennée SHUTDOWN_EVENT(HOST_ERROR);
79dcda7321SAlex Bennée SHUTDOWN_EVENT(HOST_QMP_QUIT);
80dcda7321SAlex Bennée SHUTDOWN_EVENT(HOST_QMP_SYSTEM_RESET);
81dcda7321SAlex Bennée SHUTDOWN_EVENT(HOST_SIGNAL);
82dcda7321SAlex Bennée SHUTDOWN_EVENT(HOST_UI);
83dcda7321SAlex Bennée SHUTDOWN_EVENT(GUEST_SHUTDOWN);
84dcda7321SAlex Bennée SHUTDOWN_EVENT(GUEST_RESET);
85dcda7321SAlex Bennée SHUTDOWN_EVENT(GUEST_PANIC);
86dcda7321SAlex Bennée SHUTDOWN_EVENT(SUBSYSTEM_RESET);
87dcda7321SAlex Bennée SHUTDOWN_EVENT(SNAPSHOT_LOAD);
88dcda7321SAlex Bennée #undef SHUTDOWN_EVENT
89dcda7321SAlex Bennée default:
90dcda7321SAlex Bennée g_assert_not_reached();
91dcda7321SAlex Bennée }
92dcda7321SAlex Bennée }
93dcda7321SAlex Bennée
replay_checkpoint_event_name(enum ReplayCheckpoint checkpoint)94dcda7321SAlex Bennée static const char *replay_checkpoint_event_name(enum ReplayCheckpoint checkpoint)
95dcda7321SAlex Bennée {
96dcda7321SAlex Bennée switch (checkpoint) {
97dcda7321SAlex Bennée #define CHECKPOINT_EVENT(_x) case CHECKPOINT_ ## _x: return "CHECKPOINT_" #_x
98dcda7321SAlex Bennée CHECKPOINT_EVENT(CLOCK_WARP_START);
99dcda7321SAlex Bennée CHECKPOINT_EVENT(CLOCK_WARP_ACCOUNT);
100dcda7321SAlex Bennée CHECKPOINT_EVENT(RESET_REQUESTED);
101dcda7321SAlex Bennée CHECKPOINT_EVENT(SUSPEND_REQUESTED);
102dcda7321SAlex Bennée CHECKPOINT_EVENT(CLOCK_VIRTUAL);
103dcda7321SAlex Bennée CHECKPOINT_EVENT(CLOCK_HOST);
104dcda7321SAlex Bennée CHECKPOINT_EVENT(CLOCK_VIRTUAL_RT);
105dcda7321SAlex Bennée CHECKPOINT_EVENT(INIT);
106dcda7321SAlex Bennée CHECKPOINT_EVENT(RESET);
107dcda7321SAlex Bennée #undef CHECKPOINT_EVENT
108dcda7321SAlex Bennée default:
109dcda7321SAlex Bennée g_assert_not_reached();
110dcda7321SAlex Bennée }
111dcda7321SAlex Bennée }
112dcda7321SAlex Bennée
replay_event_name(enum ReplayEvents event)113dcda7321SAlex Bennée static const char *replay_event_name(enum ReplayEvents event)
114dcda7321SAlex Bennée {
115dcda7321SAlex Bennée /* First deal with the simple ones */
116dcda7321SAlex Bennée switch (event) {
117dcda7321SAlex Bennée #define EVENT(_x) case EVENT_ ## _x: return "EVENT_"#_x
118dcda7321SAlex Bennée EVENT(INSTRUCTION);
119dcda7321SAlex Bennée EVENT(INTERRUPT);
120dcda7321SAlex Bennée EVENT(EXCEPTION);
121dcda7321SAlex Bennée EVENT(CHAR_WRITE);
122dcda7321SAlex Bennée EVENT(CHAR_READ_ALL);
123dcda7321SAlex Bennée EVENT(AUDIO_OUT);
124dcda7321SAlex Bennée EVENT(AUDIO_IN);
125dcda7321SAlex Bennée EVENT(RANDOM);
126dcda7321SAlex Bennée #undef EVENT
127dcda7321SAlex Bennée default:
128dcda7321SAlex Bennée if (event >= EVENT_ASYNC && event <= EVENT_ASYNC_LAST) {
129dcda7321SAlex Bennée return replay_async_event_name(event - EVENT_ASYNC);
130dcda7321SAlex Bennée } else if (event >= EVENT_SHUTDOWN && event <= EVENT_SHUTDOWN_LAST) {
131dcda7321SAlex Bennée return replay_shutdown_event_name(event - EVENT_SHUTDOWN);
132dcda7321SAlex Bennée } else if (event >= EVENT_CLOCK && event <= EVENT_CLOCK_LAST) {
133dcda7321SAlex Bennée return replay_clock_event_name(event - EVENT_CLOCK);
134dcda7321SAlex Bennée } else if (event >= EVENT_CHECKPOINT && event <= EVENT_CHECKPOINT_LAST) {
135dcda7321SAlex Bennée return replay_checkpoint_event_name(event - EVENT_CHECKPOINT);
136dcda7321SAlex Bennée }
137dcda7321SAlex Bennée }
138dcda7321SAlex Bennée
139dcda7321SAlex Bennée g_assert_not_reached();
140dcda7321SAlex Bennée }
141dcda7321SAlex Bennée
replay_next_event_is(int event)14226bc60acSPavel Dovgalyuk bool replay_next_event_is(int event)
14326bc60acSPavel Dovgalyuk {
14426bc60acSPavel Dovgalyuk bool res = false;
14526bc60acSPavel Dovgalyuk
14626bc60acSPavel Dovgalyuk /* nothing to skip - not all instructions used */
14713f26713SPavel Dovgalyuk if (replay_state.instruction_count != 0) {
148f186d64dSPavel Dovgalyuk assert(replay_state.data_kind == EVENT_INSTRUCTION);
14926bc60acSPavel Dovgalyuk return event == EVENT_INSTRUCTION;
15026bc60acSPavel Dovgalyuk }
15126bc60acSPavel Dovgalyuk
15226bc60acSPavel Dovgalyuk while (true) {
153e957ad8aSPavel Dovgalyuk unsigned int data_kind = replay_state.data_kind;
154e957ad8aSPavel Dovgalyuk if (event == data_kind) {
15526bc60acSPavel Dovgalyuk res = true;
15626bc60acSPavel Dovgalyuk }
157e957ad8aSPavel Dovgalyuk switch (data_kind) {
158802f045aSEric Blake case EVENT_SHUTDOWN ... EVENT_SHUTDOWN_LAST:
159b60c48a7SPavel Dovgalyuk replay_finish_event();
160e957ad8aSPavel Dovgalyuk qemu_system_shutdown_request(data_kind - EVENT_SHUTDOWN);
161b60c48a7SPavel Dovgalyuk break;
16226bc60acSPavel Dovgalyuk default:
16326bc60acSPavel Dovgalyuk /* clock, time_t, checkpoint and other events */
16426bc60acSPavel Dovgalyuk return res;
16526bc60acSPavel Dovgalyuk }
16626bc60acSPavel Dovgalyuk }
16726bc60acSPavel Dovgalyuk return res;
16826bc60acSPavel Dovgalyuk }
16926bc60acSPavel Dovgalyuk
replay_get_current_icount(void)17013f26713SPavel Dovgalyuk uint64_t replay_get_current_icount(void)
17126bc60acSPavel Dovgalyuk {
1728191d368SClaudio Fontana return icount_get_raw();
17326bc60acSPavel Dovgalyuk }
1748b427044SPavel Dovgalyuk
replay_get_instructions(void)1758b427044SPavel Dovgalyuk int replay_get_instructions(void)
1768b427044SPavel Dovgalyuk {
1778b427044SPavel Dovgalyuk int res = 0;
17883ecdb18SJamie Iles g_assert(replay_mutex_locked());
1798b427044SPavel Dovgalyuk if (replay_next_event_is(EVENT_INSTRUCTION)) {
18013f26713SPavel Dovgalyuk res = replay_state.instruction_count;
181e7510671SPavel Dovgalyuk if (replay_break_icount != -1LL) {
182e7510671SPavel Dovgalyuk uint64_t current = replay_get_current_icount();
183e7510671SPavel Dovgalyuk assert(replay_break_icount >= current);
184e7510671SPavel Dovgalyuk if (current + res > replay_break_icount) {
185e7510671SPavel Dovgalyuk res = replay_break_icount - current;
186e7510671SPavel Dovgalyuk }
187e7510671SPavel Dovgalyuk }
1888b427044SPavel Dovgalyuk }
1898b427044SPavel Dovgalyuk return res;
1908b427044SPavel Dovgalyuk }
1918b427044SPavel Dovgalyuk
replay_account_executed_instructions(void)1928b427044SPavel Dovgalyuk void replay_account_executed_instructions(void)
1938b427044SPavel Dovgalyuk {
1948b427044SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) {
195d759c951SAlex Bennée g_assert(replay_mutex_locked());
19613f26713SPavel Dovgalyuk if (replay_state.instruction_count > 0) {
197366a85e4SPavel Dovgalyuk replay_advance_current_icount(replay_get_current_icount());
1988b427044SPavel Dovgalyuk }
1998b427044SPavel Dovgalyuk }
2008b427044SPavel Dovgalyuk }
2016f060969SPavel Dovgalyuk
replay_exception(void)2026f060969SPavel Dovgalyuk bool replay_exception(void)
2036f060969SPavel Dovgalyuk {
204d759c951SAlex Bennée
2056f060969SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) {
206d759c951SAlex Bennée g_assert(replay_mutex_locked());
2076f060969SPavel Dovgalyuk replay_save_instructions();
2086f060969SPavel Dovgalyuk replay_put_event(EVENT_EXCEPTION);
2096f060969SPavel Dovgalyuk return true;
2106f060969SPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_PLAY) {
211d759c951SAlex Bennée g_assert(replay_mutex_locked());
2126f060969SPavel Dovgalyuk bool res = replay_has_exception();
2136f060969SPavel Dovgalyuk if (res) {
2146f060969SPavel Dovgalyuk replay_finish_event();
2156f060969SPavel Dovgalyuk }
2166f060969SPavel Dovgalyuk return res;
2176f060969SPavel Dovgalyuk }
2186f060969SPavel Dovgalyuk
2196f060969SPavel Dovgalyuk return true;
2206f060969SPavel Dovgalyuk }
2216f060969SPavel Dovgalyuk
replay_has_exception(void)2226f060969SPavel Dovgalyuk bool replay_has_exception(void)
2236f060969SPavel Dovgalyuk {
2246f060969SPavel Dovgalyuk bool res = false;
2256f060969SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) {
226d759c951SAlex Bennée g_assert(replay_mutex_locked());
2276f060969SPavel Dovgalyuk replay_account_executed_instructions();
2286f060969SPavel Dovgalyuk res = replay_next_event_is(EVENT_EXCEPTION);
2296f060969SPavel Dovgalyuk }
2306f060969SPavel Dovgalyuk
2316f060969SPavel Dovgalyuk return res;
2326f060969SPavel Dovgalyuk }
2336f060969SPavel Dovgalyuk
replay_interrupt(void)2346f060969SPavel Dovgalyuk bool replay_interrupt(void)
2356f060969SPavel Dovgalyuk {
2366f060969SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) {
237d759c951SAlex Bennée g_assert(replay_mutex_locked());
2386f060969SPavel Dovgalyuk replay_save_instructions();
2396f060969SPavel Dovgalyuk replay_put_event(EVENT_INTERRUPT);
2406f060969SPavel Dovgalyuk return true;
2416f060969SPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_PLAY) {
242d759c951SAlex Bennée g_assert(replay_mutex_locked());
2436f060969SPavel Dovgalyuk bool res = replay_has_interrupt();
2446f060969SPavel Dovgalyuk if (res) {
2456f060969SPavel Dovgalyuk replay_finish_event();
2466f060969SPavel Dovgalyuk }
2476f060969SPavel Dovgalyuk return res;
2486f060969SPavel Dovgalyuk }
2496f060969SPavel Dovgalyuk
2506f060969SPavel Dovgalyuk return true;
2516f060969SPavel Dovgalyuk }
2526f060969SPavel Dovgalyuk
replay_has_interrupt(void)2536f060969SPavel Dovgalyuk bool replay_has_interrupt(void)
2546f060969SPavel Dovgalyuk {
2556f060969SPavel Dovgalyuk bool res = false;
2566f060969SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) {
257d759c951SAlex Bennée g_assert(replay_mutex_locked());
2586f060969SPavel Dovgalyuk replay_account_executed_instructions();
2596f060969SPavel Dovgalyuk res = replay_next_event_is(EVENT_INTERRUPT);
2606f060969SPavel Dovgalyuk }
2616f060969SPavel Dovgalyuk return res;
2626f060969SPavel Dovgalyuk }
263b60c48a7SPavel Dovgalyuk
replay_shutdown_request(ShutdownCause cause)264802f045aSEric Blake void replay_shutdown_request(ShutdownCause cause)
265b60c48a7SPavel Dovgalyuk {
266b60c48a7SPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) {
267d759c951SAlex Bennée g_assert(replay_mutex_locked());
268802f045aSEric Blake replay_put_event(EVENT_SHUTDOWN + cause);
269b60c48a7SPavel Dovgalyuk }
270b60c48a7SPavel Dovgalyuk }
2718bd7f71dSPavel Dovgalyuk
replay_checkpoint(ReplayCheckpoint checkpoint)2728bd7f71dSPavel Dovgalyuk bool replay_checkpoint(ReplayCheckpoint checkpoint)
2738bd7f71dSPavel Dovgalyuk {
2748bd7f71dSPavel Dovgalyuk assert(EVENT_CHECKPOINT + checkpoint <= EVENT_CHECKPOINT_LAST);
2758bd7f71dSPavel Dovgalyuk
27666eb7825SPavel Dovgalyuk replay_save_instructions();
2778bd7f71dSPavel Dovgalyuk
2788bd7f71dSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) {
279d759c951SAlex Bennée g_assert(replay_mutex_locked());
2808bd7f71dSPavel Dovgalyuk if (replay_next_event_is(EVENT_CHECKPOINT + checkpoint)) {
2818bd7f71dSPavel Dovgalyuk replay_finish_event();
28260618e2dSPavel Dovgalyuk } else {
28360618e2dSPavel Dovgalyuk return false;
2848bd7f71dSPavel Dovgalyuk }
2858bd7f71dSPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_RECORD) {
286d759c951SAlex Bennée g_assert(replay_mutex_locked());
2878bd7f71dSPavel Dovgalyuk replay_put_event(EVENT_CHECKPOINT + checkpoint);
28889e46eb4SPavel Dovgalyuk }
28960618e2dSPavel Dovgalyuk return true;
2908bd7f71dSPavel Dovgalyuk }
2917615936eSPavel Dovgalyuk
replay_async_events(void)29260618e2dSPavel Dovgalyuk void replay_async_events(void)
29360618e2dSPavel Dovgalyuk {
29460618e2dSPavel Dovgalyuk static bool processing = false;
29560618e2dSPavel Dovgalyuk /*
29660618e2dSPavel Dovgalyuk * If we are already processing the events, recursion may occur
29760618e2dSPavel Dovgalyuk * in case of incorrect implementation when HW event modifies timers.
29860618e2dSPavel Dovgalyuk * Timer modification may invoke the icount warp, event processing,
29960618e2dSPavel Dovgalyuk * and cause the recursion.
30060618e2dSPavel Dovgalyuk */
30160618e2dSPavel Dovgalyuk g_assert(!processing);
30260618e2dSPavel Dovgalyuk processing = true;
30360618e2dSPavel Dovgalyuk
30460618e2dSPavel Dovgalyuk replay_save_instructions();
30560618e2dSPavel Dovgalyuk
30660618e2dSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) {
30760618e2dSPavel Dovgalyuk g_assert(replay_mutex_locked());
30860618e2dSPavel Dovgalyuk replay_read_events();
30960618e2dSPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_RECORD) {
31060618e2dSPavel Dovgalyuk g_assert(replay_mutex_locked());
31160618e2dSPavel Dovgalyuk replay_save_events();
31260618e2dSPavel Dovgalyuk }
31360618e2dSPavel Dovgalyuk processing = false;
31460618e2dSPavel Dovgalyuk }
31560618e2dSPavel Dovgalyuk
replay_has_event(void)31660618e2dSPavel Dovgalyuk bool replay_has_event(void)
3170c08185fSPavel Dovgalyuk {
3180c08185fSPavel Dovgalyuk bool res = false;
3190c08185fSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_PLAY) {
3200c08185fSPavel Dovgalyuk g_assert(replay_mutex_locked());
3210c08185fSPavel Dovgalyuk replay_account_executed_instructions();
3220c08185fSPavel Dovgalyuk res = EVENT_CHECKPOINT <= replay_state.data_kind
3230c08185fSPavel Dovgalyuk && replay_state.data_kind <= EVENT_CHECKPOINT_LAST;
3243e21408bSPavel Dovgalyuk res = res || (EVENT_ASYNC <= replay_state.data_kind
3253e21408bSPavel Dovgalyuk && replay_state.data_kind <= EVENT_ASYNC_LAST);
3260c08185fSPavel Dovgalyuk }
3270c08185fSPavel Dovgalyuk return res;
3280c08185fSPavel Dovgalyuk }
3290c08185fSPavel Dovgalyuk
replay_sync_error(const char * error)330dcda7321SAlex Bennée G_NORETURN void replay_sync_error(const char *error)
331dcda7321SAlex Bennée {
332dcda7321SAlex Bennée error_report("%s (insn total %"PRId64"/%d left, event %d is %s)", error,
333dcda7321SAlex Bennée replay_state.current_icount, replay_state.instruction_count,
334dcda7321SAlex Bennée replay_state.current_event,
335dcda7321SAlex Bennée replay_event_name(replay_state.data_kind));
336dcda7321SAlex Bennée abort();
337dcda7321SAlex Bennée }
338dcda7321SAlex Bennée
replay_enable(const char * fname,int mode)3397615936eSPavel Dovgalyuk static void replay_enable(const char *fname, int mode)
3407615936eSPavel Dovgalyuk {
3417615936eSPavel Dovgalyuk const char *fmode = NULL;
3427615936eSPavel Dovgalyuk assert(!replay_file);
3437615936eSPavel Dovgalyuk
3447615936eSPavel Dovgalyuk switch (mode) {
3457615936eSPavel Dovgalyuk case REPLAY_MODE_RECORD:
3467615936eSPavel Dovgalyuk fmode = "wb";
3477615936eSPavel Dovgalyuk break;
3487615936eSPavel Dovgalyuk case REPLAY_MODE_PLAY:
3497615936eSPavel Dovgalyuk fmode = "rb";
3507615936eSPavel Dovgalyuk break;
3517615936eSPavel Dovgalyuk default:
3527615936eSPavel Dovgalyuk fprintf(stderr, "Replay: internal error: invalid replay mode\n");
3537615936eSPavel Dovgalyuk exit(1);
3547615936eSPavel Dovgalyuk }
3557615936eSPavel Dovgalyuk
3567615936eSPavel Dovgalyuk atexit(replay_finish);
3577615936eSPavel Dovgalyuk
3587615936eSPavel Dovgalyuk replay_file = fopen(fname, fmode);
3597615936eSPavel Dovgalyuk if (replay_file == NULL) {
3607615936eSPavel Dovgalyuk fprintf(stderr, "Replay: open %s: %s\n", fname, strerror(errno));
3617615936eSPavel Dovgalyuk exit(1);
3627615936eSPavel Dovgalyuk }
3637615936eSPavel Dovgalyuk
3647615936eSPavel Dovgalyuk replay_filename = g_strdup(fname);
3657615936eSPavel Dovgalyuk replay_mode = mode;
366d759c951SAlex Bennée replay_mutex_init();
367d759c951SAlex Bennée
368f186d64dSPavel Dovgalyuk replay_state.data_kind = -1;
36913f26713SPavel Dovgalyuk replay_state.instruction_count = 0;
37013f26713SPavel Dovgalyuk replay_state.current_icount = 0;
371dcda7321SAlex Bennée replay_state.current_event = 0;
372f186d64dSPavel Dovgalyuk replay_state.has_unread_data = 0;
3737615936eSPavel Dovgalyuk
3747615936eSPavel Dovgalyuk /* skip file header for RECORD and check it for PLAY */
3757615936eSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) {
3767615936eSPavel Dovgalyuk fseek(replay_file, HEADER_SIZE, SEEK_SET);
3777615936eSPavel Dovgalyuk } else if (replay_mode == REPLAY_MODE_PLAY) {
3787615936eSPavel Dovgalyuk unsigned int version = replay_get_dword();
3797615936eSPavel Dovgalyuk if (version != REPLAY_VERSION) {
3807615936eSPavel Dovgalyuk fprintf(stderr, "Replay: invalid input log file version\n");
3817615936eSPavel Dovgalyuk exit(1);
3827615936eSPavel Dovgalyuk }
3837615936eSPavel Dovgalyuk /* go to the beginning */
3847615936eSPavel Dovgalyuk fseek(replay_file, HEADER_SIZE, SEEK_SET);
3857615936eSPavel Dovgalyuk replay_fetch_data_kind();
3867615936eSPavel Dovgalyuk }
3877615936eSPavel Dovgalyuk
388*9dbab31dSNicholas Piggin runstate_replay_enable();
389*9dbab31dSNicholas Piggin
3907615936eSPavel Dovgalyuk replay_init_events();
3917615936eSPavel Dovgalyuk }
3927615936eSPavel Dovgalyuk
replay_configure(QemuOpts * opts)3937615936eSPavel Dovgalyuk void replay_configure(QemuOpts *opts)
3947615936eSPavel Dovgalyuk {
3957615936eSPavel Dovgalyuk const char *fname;
3967615936eSPavel Dovgalyuk const char *rr;
3977615936eSPavel Dovgalyuk ReplayMode mode = REPLAY_MODE_NONE;
398890ad550SEduardo Habkost Location loc;
399890ad550SEduardo Habkost
400890ad550SEduardo Habkost if (!opts) {
401890ad550SEduardo Habkost return;
402890ad550SEduardo Habkost }
403890ad550SEduardo Habkost
404890ad550SEduardo Habkost loc_push_none(&loc);
405890ad550SEduardo Habkost qemu_opts_loc_restore(opts);
4067615936eSPavel Dovgalyuk
4077615936eSPavel Dovgalyuk rr = qemu_opt_get(opts, "rr");
4087615936eSPavel Dovgalyuk if (!rr) {
4097615936eSPavel Dovgalyuk /* Just enabling icount */
410d9d3aaeaSMarkus Armbruster goto out;
4117615936eSPavel Dovgalyuk } else if (!strcmp(rr, "record")) {
4127615936eSPavel Dovgalyuk mode = REPLAY_MODE_RECORD;
4137615936eSPavel Dovgalyuk } else if (!strcmp(rr, "replay")) {
4147615936eSPavel Dovgalyuk mode = REPLAY_MODE_PLAY;
4157615936eSPavel Dovgalyuk } else {
4167615936eSPavel Dovgalyuk error_report("Invalid icount rr option: %s", rr);
4177615936eSPavel Dovgalyuk exit(1);
4187615936eSPavel Dovgalyuk }
4197615936eSPavel Dovgalyuk
4207615936eSPavel Dovgalyuk fname = qemu_opt_get(opts, "rrfile");
4217615936eSPavel Dovgalyuk if (!fname) {
4227615936eSPavel Dovgalyuk error_report("File name not specified for replay");
4237615936eSPavel Dovgalyuk exit(1);
4247615936eSPavel Dovgalyuk }
4257615936eSPavel Dovgalyuk
4269c2037d0SPavel Dovgalyuk replay_snapshot = g_strdup(qemu_opt_get(opts, "rrsnapshot"));
427306e196fSPavel Dovgalyuk replay_vmstate_register();
4287615936eSPavel Dovgalyuk replay_enable(fname, mode);
429890ad550SEduardo Habkost
430d9d3aaeaSMarkus Armbruster out:
431890ad550SEduardo Habkost loc_pop(&loc);
4327615936eSPavel Dovgalyuk }
4337615936eSPavel Dovgalyuk
replay_start(void)4347615936eSPavel Dovgalyuk void replay_start(void)
4357615936eSPavel Dovgalyuk {
4367615936eSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_NONE) {
4377615936eSPavel Dovgalyuk return;
4387615936eSPavel Dovgalyuk }
4397615936eSPavel Dovgalyuk
4400194749aSPavel Dovgalyuk if (replay_blockers) {
441c29b77f9SMarkus Armbruster error_reportf_err(replay_blockers->data, "Record/replay: ");
4420194749aSPavel Dovgalyuk exit(1);
4430194749aSPavel Dovgalyuk }
444740b1759SClaudio Fontana if (!icount_enabled()) {
4454c27b859SPavel Dovgalyuk error_report("Please enable icount to use record/replay");
4464c27b859SPavel Dovgalyuk exit(1);
4474c27b859SPavel Dovgalyuk }
4480194749aSPavel Dovgalyuk
4497615936eSPavel Dovgalyuk /* Timer for snapshotting will be set up here. */
4507615936eSPavel Dovgalyuk
4517615936eSPavel Dovgalyuk replay_enable_events();
4527615936eSPavel Dovgalyuk }
4537615936eSPavel Dovgalyuk
replay_finish(void)4547615936eSPavel Dovgalyuk void replay_finish(void)
4557615936eSPavel Dovgalyuk {
4567615936eSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_NONE) {
4577615936eSPavel Dovgalyuk return;
4587615936eSPavel Dovgalyuk }
4597615936eSPavel Dovgalyuk
4607615936eSPavel Dovgalyuk replay_save_instructions();
4617615936eSPavel Dovgalyuk
4627615936eSPavel Dovgalyuk /* finalize the file */
4637615936eSPavel Dovgalyuk if (replay_file) {
4647615936eSPavel Dovgalyuk if (replay_mode == REPLAY_MODE_RECORD) {
465ed5d7ff3SPavel Dovgalyuk /*
466ed5d7ff3SPavel Dovgalyuk * Can't do it in the signal handler, therefore
467ed5d7ff3SPavel Dovgalyuk * add shutdown event here for the case of Ctrl-C.
468ed5d7ff3SPavel Dovgalyuk */
469ed5d7ff3SPavel Dovgalyuk replay_shutdown_request(SHUTDOWN_CAUSE_HOST_SIGNAL);
4707615936eSPavel Dovgalyuk /* write end event */
4717615936eSPavel Dovgalyuk replay_put_event(EVENT_END);
4727615936eSPavel Dovgalyuk
4737615936eSPavel Dovgalyuk /* write header */
4747615936eSPavel Dovgalyuk fseek(replay_file, 0, SEEK_SET);
4757615936eSPavel Dovgalyuk replay_put_dword(REPLAY_VERSION);
4767615936eSPavel Dovgalyuk }
4777615936eSPavel Dovgalyuk
4787615936eSPavel Dovgalyuk fclose(replay_file);
4797615936eSPavel Dovgalyuk replay_file = NULL;
4807615936eSPavel Dovgalyuk }
4817615936eSPavel Dovgalyuk g_free(replay_filename);
4827615936eSPavel Dovgalyuk replay_filename = NULL;
4837615936eSPavel Dovgalyuk
4849c2037d0SPavel Dovgalyuk g_free(replay_snapshot);
4859c2037d0SPavel Dovgalyuk replay_snapshot = NULL;
4869c2037d0SPavel Dovgalyuk
4877615936eSPavel Dovgalyuk replay_finish_events();
488c4b8ffcbSPavel Dovgalyuk replay_mode = REPLAY_MODE_NONE;
4897615936eSPavel Dovgalyuk }
4900194749aSPavel Dovgalyuk
replay_add_blocker(const char * feature)4910ec8384fSMarkus Armbruster void replay_add_blocker(const char *feature)
4920194749aSPavel Dovgalyuk {
4930ec8384fSMarkus Armbruster Error *reason = NULL;
4940ec8384fSMarkus Armbruster
4957653b1eaSMarkus Armbruster error_setg(&reason, "Record/replay is not supported with %s",
4960ec8384fSMarkus Armbruster feature);
4970194749aSPavel Dovgalyuk replay_blockers = g_slist_prepend(replay_blockers, reason);
4980194749aSPavel Dovgalyuk }
49956db1198SPavel Dovgalyuk
replay_get_filename(void)50056db1198SPavel Dovgalyuk const char *replay_get_filename(void)
50156db1198SPavel Dovgalyuk {
50256db1198SPavel Dovgalyuk return replay_filename;
50356db1198SPavel Dovgalyuk }
504