blob: 8f87e9b957e12c1fe82de93df2919ab09c709c88 [file] [log] [blame]
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +03001/*
2 * replay-internal.c
3 *
4 * Copyright (c) 2010-2015 Institute for System Programming
5 * of the Russian Academy of Sciences.
6 *
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.
9 *
10 */
11
Peter Maydelld38ea872016-01-29 17:50:05 +000012#include "qemu/osdep.h"
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030013#include "qemu-common.h"
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +030014#include "sysemu/replay.h"
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030015#include "replay-internal.h"
16#include "qemu/error-report.h"
17#include "sysemu/sysemu.h"
18
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +030019/* Mutex to protect reading and writing events to the log.
Pavel Dovgalyukf186d642016-09-26 11:08:04 +030020 data_kind and has_unread_data are also protected
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +030021 by this mutex.
22 It also protects replay events queue which stores events to be
23 written or read to the log. */
24static QemuMutex lock;
25
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030026/* File for replay writing */
Pavel Dovgalyuk6dc0f522018-02-27 12:52:59 +030027static bool write_error;
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030028FILE *replay_file;
29
Pavel Dovgalyuk6dc0f522018-02-27 12:52:59 +030030static void replay_write_error(void)
31{
32 if (!write_error) {
33 error_report("replay write error");
34 write_error = true;
35 }
36}
37
Peter Maydell0b570072018-11-06 15:33:30 +000038static void replay_read_error(void)
39{
40 error_report("error reading the replay data");
41 exit(1);
42}
43
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030044void replay_put_byte(uint8_t byte)
45{
46 if (replay_file) {
Pavel Dovgalyuk6dc0f522018-02-27 12:52:59 +030047 if (putc(byte, replay_file) == EOF) {
48 replay_write_error();
49 }
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030050 }
51}
52
53void replay_put_event(uint8_t event)
54{
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +030055 assert(event < EVENT_COUNT);
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030056 replay_put_byte(event);
57}
58
59
60void replay_put_word(uint16_t word)
61{
62 replay_put_byte(word >> 8);
63 replay_put_byte(word);
64}
65
66void replay_put_dword(uint32_t dword)
67{
68 replay_put_word(dword >> 16);
69 replay_put_word(dword);
70}
71
72void replay_put_qword(int64_t qword)
73{
74 replay_put_dword(qword >> 32);
75 replay_put_dword(qword);
76}
77
78void replay_put_array(const uint8_t *buf, size_t size)
79{
80 if (replay_file) {
81 replay_put_dword(size);
Pavel Dovgalyuk6dc0f522018-02-27 12:52:59 +030082 if (fwrite(buf, 1, size, replay_file) != size) {
83 replay_write_error();
84 }
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030085 }
86}
87
88uint8_t replay_get_byte(void)
89{
90 uint8_t byte = 0;
91 if (replay_file) {
Peter Maydell0b570072018-11-06 15:33:30 +000092 int r = getc(replay_file);
93 if (r == EOF) {
94 replay_read_error();
95 }
96 byte = r;
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +030097 }
98 return byte;
99}
100
101uint16_t replay_get_word(void)
102{
103 uint16_t word = 0;
104 if (replay_file) {
105 word = replay_get_byte();
106 word = (word << 8) + replay_get_byte();
107 }
108
109 return word;
110}
111
112uint32_t replay_get_dword(void)
113{
114 uint32_t dword = 0;
115 if (replay_file) {
116 dword = replay_get_word();
117 dword = (dword << 16) + replay_get_word();
118 }
119
120 return dword;
121}
122
123int64_t replay_get_qword(void)
124{
125 int64_t qword = 0;
126 if (replay_file) {
127 qword = replay_get_dword();
128 qword = (qword << 32) + replay_get_dword();
129 }
130
131 return qword;
132}
133
134void replay_get_array(uint8_t *buf, size_t *size)
135{
136 if (replay_file) {
137 *size = replay_get_dword();
138 if (fread(buf, 1, *size, replay_file) != *size) {
Peter Maydell0b570072018-11-06 15:33:30 +0000139 replay_read_error();
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300140 }
141 }
142}
143
144void replay_get_array_alloc(uint8_t **buf, size_t *size)
145{
146 if (replay_file) {
147 *size = replay_get_dword();
148 *buf = g_malloc(*size);
149 if (fread(*buf, 1, *size, replay_file) != *size) {
Peter Maydell0b570072018-11-06 15:33:30 +0000150 replay_read_error();
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300151 }
152 }
153}
154
155void replay_check_error(void)
156{
157 if (replay_file) {
158 if (feof(replay_file)) {
159 error_report("replay file is over");
160 qemu_system_vmstop_request_prepare();
161 qemu_system_vmstop_request(RUN_STATE_PAUSED);
162 } else if (ferror(replay_file)) {
163 error_report("replay file is over or something goes wrong");
164 qemu_system_vmstop_request_prepare();
165 qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
166 }
167 }
168}
169
170void replay_fetch_data_kind(void)
171{
172 if (replay_file) {
Pavel Dovgalyukf186d642016-09-26 11:08:04 +0300173 if (!replay_state.has_unread_data) {
174 replay_state.data_kind = replay_get_byte();
175 if (replay_state.data_kind == EVENT_INSTRUCTION) {
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300176 replay_state.instructions_count = replay_get_dword();
177 }
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300178 replay_check_error();
Pavel Dovgalyukf186d642016-09-26 11:08:04 +0300179 replay_state.has_unread_data = 1;
180 if (replay_state.data_kind >= EVENT_COUNT) {
181 error_report("Replay: unknown event kind %d",
182 replay_state.data_kind);
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300183 exit(1);
184 }
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300185 }
186 }
187}
188
189void replay_finish_event(void)
190{
Pavel Dovgalyukf186d642016-09-26 11:08:04 +0300191 replay_state.has_unread_data = 0;
Pavel Dovgalyukc92079f2015-09-17 19:23:43 +0300192 replay_fetch_data_kind();
193}
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300194
Alex Bennée180d30b2018-02-27 12:52:37 +0300195static __thread bool replay_locked;
196
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300197void replay_mutex_init(void)
198{
199 qemu_mutex_init(&lock);
Alex Bennéed759c952018-02-27 12:52:48 +0300200 /* Hold the mutex while we start-up */
201 qemu_mutex_lock(&lock);
202 replay_locked = true;
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300203}
204
Alex Bennéea36544d2018-02-27 12:52:42 +0300205bool replay_mutex_locked(void)
Alex Bennée180d30b2018-02-27 12:52:37 +0300206{
207 return replay_locked;
208}
209
Alex Bennéed759c952018-02-27 12:52:48 +0300210/* Ordering constraints, replay_lock must be taken before BQL */
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300211void replay_mutex_lock(void)
212{
Alex Bennéed759c952018-02-27 12:52:48 +0300213 if (replay_mode != REPLAY_MODE_NONE) {
214 g_assert(!qemu_mutex_iothread_locked());
215 g_assert(!replay_mutex_locked());
216 qemu_mutex_lock(&lock);
217 replay_locked = true;
218 }
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300219}
220
221void replay_mutex_unlock(void)
222{
Alex Bennéed759c952018-02-27 12:52:48 +0300223 if (replay_mode != REPLAY_MODE_NONE) {
224 g_assert(replay_mutex_locked());
225 replay_locked = false;
226 qemu_mutex_unlock(&lock);
227 }
Pavel Dovgalyukc16861e2015-09-17 19:23:48 +0300228}
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300229
Paolo Bonzini74c0b812018-10-08 13:24:14 +0200230void replay_advance_current_step(uint64_t current_step)
231{
232 int diff = (int)(replay_get_current_step() - replay_state.current_step);
233
234 /* Time can only go forward */
235 assert(diff >= 0);
236
237 if (diff > 0) {
238 replay_put_event(EVENT_INSTRUCTION);
239 replay_put_dword(diff);
240 replay_state.current_step += diff;
241 }
242}
243
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300244/*! Saves cached instructions. */
245void replay_save_instructions(void)
246{
247 if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
Alex Bennéed759c952018-02-27 12:52:48 +0300248 g_assert(replay_mutex_locked());
Paolo Bonzini74c0b812018-10-08 13:24:14 +0200249 replay_advance_current_step(replay_get_current_step());
Pavel Dovgalyuk26bc60a2015-09-17 19:23:54 +0300250 }
251}