xref: /openbmc/qemu/replay/replay.c (revision 2eefd4fcec4b8fe41ceee2a8f00cdec1fe81b75c)
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