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 "qemu-common.h"
14 #include "sysemu/replay.h"
15 #include "replay-internal.h"
16 #include "qemu/error-report.h"
17 #include "sysemu/sysemu.h"
19 /* Mutex to protect reading and writing events to the log.
20 data_kind and has_unread_data are also protected
22 It also protects replay events queue which stores events to be
23 written or read to the log. */
24 static QemuMutex lock
;
26 /* File for replay writing */
27 static bool write_error
;
30 static void replay_write_error(void)
33 error_report("replay write error");
38 void replay_put_byte(uint8_t byte
)
41 if (putc(byte
, replay_file
) == EOF
) {
47 void replay_put_event(uint8_t event
)
49 assert(event
< EVENT_COUNT
);
50 replay_put_byte(event
);
54 void replay_put_word(uint16_t word
)
56 replay_put_byte(word
>> 8);
57 replay_put_byte(word
);
60 void replay_put_dword(uint32_t dword
)
62 replay_put_word(dword
>> 16);
63 replay_put_word(dword
);
66 void replay_put_qword(int64_t qword
)
68 replay_put_dword(qword
>> 32);
69 replay_put_dword(qword
);
72 void replay_put_array(const uint8_t *buf
, size_t size
)
75 replay_put_dword(size
);
76 if (fwrite(buf
, 1, size
, replay_file
) != size
) {
82 uint8_t replay_get_byte(void)
86 byte
= getc(replay_file
);
91 uint16_t replay_get_word(void)
95 word
= replay_get_byte();
96 word
= (word
<< 8) + replay_get_byte();
102 uint32_t replay_get_dword(void)
106 dword
= replay_get_word();
107 dword
= (dword
<< 16) + replay_get_word();
113 int64_t replay_get_qword(void)
117 qword
= replay_get_dword();
118 qword
= (qword
<< 32) + replay_get_dword();
124 void replay_get_array(uint8_t *buf
, size_t *size
)
127 *size
= replay_get_dword();
128 if (fread(buf
, 1, *size
, replay_file
) != *size
) {
129 error_report("replay read error");
134 void replay_get_array_alloc(uint8_t **buf
, size_t *size
)
137 *size
= replay_get_dword();
138 *buf
= g_malloc(*size
);
139 if (fread(*buf
, 1, *size
, replay_file
) != *size
) {
140 error_report("replay read error");
145 void replay_check_error(void)
148 if (feof(replay_file
)) {
149 error_report("replay file is over");
150 qemu_system_vmstop_request_prepare();
151 qemu_system_vmstop_request(RUN_STATE_PAUSED
);
152 } else if (ferror(replay_file
)) {
153 error_report("replay file is over or something goes wrong");
154 qemu_system_vmstop_request_prepare();
155 qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR
);
160 void replay_fetch_data_kind(void)
163 if (!replay_state
.has_unread_data
) {
164 replay_state
.data_kind
= replay_get_byte();
165 if (replay_state
.data_kind
== EVENT_INSTRUCTION
) {
166 replay_state
.instructions_count
= replay_get_dword();
168 replay_check_error();
169 replay_state
.has_unread_data
= 1;
170 if (replay_state
.data_kind
>= EVENT_COUNT
) {
171 error_report("Replay: unknown event kind %d",
172 replay_state
.data_kind
);
179 void replay_finish_event(void)
181 replay_state
.has_unread_data
= 0;
182 replay_fetch_data_kind();
185 static __thread
bool replay_locked
;
187 void replay_mutex_init(void)
189 qemu_mutex_init(&lock
);
190 /* Hold the mutex while we start-up */
191 qemu_mutex_lock(&lock
);
192 replay_locked
= true;
195 bool replay_mutex_locked(void)
197 return replay_locked
;
200 /* Ordering constraints, replay_lock must be taken before BQL */
201 void replay_mutex_lock(void)
203 if (replay_mode
!= REPLAY_MODE_NONE
) {
204 g_assert(!qemu_mutex_iothread_locked());
205 g_assert(!replay_mutex_locked());
206 qemu_mutex_lock(&lock
);
207 replay_locked
= true;
211 void replay_mutex_unlock(void)
213 if (replay_mode
!= REPLAY_MODE_NONE
) {
214 g_assert(replay_mutex_locked());
215 replay_locked
= false;
216 qemu_mutex_unlock(&lock
);
220 /*! Saves cached instructions. */
221 void replay_save_instructions(void)
223 if (replay_file
&& replay_mode
== REPLAY_MODE_RECORD
) {
224 g_assert(replay_mutex_locked());
225 int diff
= (int)(replay_get_current_step() - replay_state
.current_step
);
227 /* Time can only go forward */
231 replay_put_event(EVENT_INSTRUCTION
);
232 replay_put_dword(diff
);
233 replay_state
.current_step
+= diff
;