4 * Copyright (c) 2010-2015 Institute for System Programming
5 * of the Russian Academy of Sciences.
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.
12 #include "qemu/osdep.h"
13 #include "sysemu/replay.h"
14 #include "replay-internal.h"
15 #include "qemu/error-report.h"
16 #include "sysemu/sysemu.h"
18 /* Mutex to protect reading and writing events to the log.
19 data_kind and has_unread_data are also protected
21 It also protects replay events queue which stores events to be
22 written or read to the log. */
23 static QemuMutex lock
;
25 /* File for replay writing */
26 static bool write_error
;
29 static void replay_write_error(void)
32 error_report("replay write error");
37 static void replay_read_error(void)
39 error_report("error reading the replay data");
43 void replay_put_byte(uint8_t byte
)
46 if (putc(byte
, replay_file
) == EOF
) {
52 void replay_put_event(uint8_t event
)
54 assert(event
< EVENT_COUNT
);
55 replay_put_byte(event
);
59 void replay_put_word(uint16_t word
)
61 replay_put_byte(word
>> 8);
62 replay_put_byte(word
);
65 void replay_put_dword(uint32_t dword
)
67 replay_put_word(dword
>> 16);
68 replay_put_word(dword
);
71 void replay_put_qword(int64_t qword
)
73 replay_put_dword(qword
>> 32);
74 replay_put_dword(qword
);
77 void replay_put_array(const uint8_t *buf
, size_t size
)
80 replay_put_dword(size
);
81 if (fwrite(buf
, 1, size
, replay_file
) != size
) {
87 uint8_t replay_get_byte(void)
91 int r
= getc(replay_file
);
100 uint16_t replay_get_word(void)
104 word
= replay_get_byte();
105 word
= (word
<< 8) + replay_get_byte();
111 uint32_t replay_get_dword(void)
115 dword
= replay_get_word();
116 dword
= (dword
<< 16) + replay_get_word();
122 int64_t replay_get_qword(void)
126 qword
= replay_get_dword();
127 qword
= (qword
<< 32) + replay_get_dword();
133 void replay_get_array(uint8_t *buf
, size_t *size
)
136 *size
= replay_get_dword();
137 if (fread(buf
, 1, *size
, replay_file
) != *size
) {
143 void replay_get_array_alloc(uint8_t **buf
, size_t *size
)
146 *size
= replay_get_dword();
147 *buf
= g_malloc(*size
);
148 if (fread(*buf
, 1, *size
, replay_file
) != *size
) {
154 void replay_check_error(void)
157 if (feof(replay_file
)) {
158 error_report("replay file is over");
159 qemu_system_vmstop_request_prepare();
160 qemu_system_vmstop_request(RUN_STATE_PAUSED
);
161 } else if (ferror(replay_file
)) {
162 error_report("replay file is over or something goes wrong");
163 qemu_system_vmstop_request_prepare();
164 qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR
);
169 void replay_fetch_data_kind(void)
172 if (!replay_state
.has_unread_data
) {
173 replay_state
.data_kind
= replay_get_byte();
174 if (replay_state
.data_kind
== EVENT_INSTRUCTION
) {
175 replay_state
.instructions_count
= replay_get_dword();
177 replay_check_error();
178 replay_state
.has_unread_data
= 1;
179 if (replay_state
.data_kind
>= EVENT_COUNT
) {
180 error_report("Replay: unknown event kind %d",
181 replay_state
.data_kind
);
188 void replay_finish_event(void)
190 replay_state
.has_unread_data
= 0;
191 replay_fetch_data_kind();
194 static __thread
bool replay_locked
;
196 void replay_mutex_init(void)
198 qemu_mutex_init(&lock
);
199 /* Hold the mutex while we start-up */
200 qemu_mutex_lock(&lock
);
201 replay_locked
= true;
204 bool replay_mutex_locked(void)
206 return replay_locked
;
209 /* Ordering constraints, replay_lock must be taken before BQL */
210 void replay_mutex_lock(void)
212 if (replay_mode
!= REPLAY_MODE_NONE
) {
213 g_assert(!qemu_mutex_iothread_locked());
214 g_assert(!replay_mutex_locked());
215 qemu_mutex_lock(&lock
);
216 replay_locked
= true;
220 void replay_mutex_unlock(void)
222 if (replay_mode
!= REPLAY_MODE_NONE
) {
223 g_assert(replay_mutex_locked());
224 replay_locked
= false;
225 qemu_mutex_unlock(&lock
);
229 void replay_advance_current_step(uint64_t current_step
)
231 int diff
= (int)(replay_get_current_step() - replay_state
.current_step
);
233 /* Time can only go forward */
237 replay_put_event(EVENT_INSTRUCTION
);
238 replay_put_dword(diff
);
239 replay_state
.current_step
+= diff
;
243 /*! Saves cached instructions. */
244 void replay_save_instructions(void)
246 if (replay_file
&& replay_mode
== REPLAY_MODE_RECORD
) {
247 g_assert(replay_mutex_locked());
248 replay_advance_current_step(replay_get_current_step());