xref: /qemu/replay/replay-internal.c (revision db725815985654007ade0fd53590d613fd657208)
1c92079f4SPavel Dovgalyuk /*
2c92079f4SPavel Dovgalyuk  * replay-internal.c
3c92079f4SPavel Dovgalyuk  *
4c92079f4SPavel Dovgalyuk  * Copyright (c) 2010-2015 Institute for System Programming
5c92079f4SPavel Dovgalyuk  *                         of the Russian Academy of Sciences.
6c92079f4SPavel Dovgalyuk  *
7c92079f4SPavel Dovgalyuk  * This work is licensed under the terms of the GNU GPL, version 2 or later.
8c92079f4SPavel Dovgalyuk  * See the COPYING file in the top-level directory.
9c92079f4SPavel Dovgalyuk  *
10c92079f4SPavel Dovgalyuk  */
11c92079f4SPavel Dovgalyuk 
12d38ea87aSPeter Maydell #include "qemu/osdep.h"
1326bc60acSPavel Dovgalyuk #include "sysemu/replay.h"
14c92079f4SPavel Dovgalyuk #include "replay-internal.h"
15c92079f4SPavel Dovgalyuk #include "qemu/error-report.h"
16*db725815SMarkus Armbruster #include "qemu/main-loop.h"
17c92079f4SPavel Dovgalyuk #include "sysemu/sysemu.h"
18c92079f4SPavel Dovgalyuk 
19c16861efSPavel Dovgalyuk /* Mutex to protect reading and writing events to the log.
20f186d64dSPavel Dovgalyuk    data_kind and has_unread_data are also protected
21c16861efSPavel Dovgalyuk    by this mutex.
22c16861efSPavel Dovgalyuk    It also protects replay events queue which stores events to be
23c16861efSPavel Dovgalyuk    written or read to the log. */
24c16861efSPavel Dovgalyuk static QemuMutex lock;
25c16861efSPavel Dovgalyuk 
26c92079f4SPavel Dovgalyuk /* File for replay writing */
276dc0f529SPavel Dovgalyuk static bool write_error;
28c92079f4SPavel Dovgalyuk FILE *replay_file;
29c92079f4SPavel Dovgalyuk 
306dc0f529SPavel Dovgalyuk static void replay_write_error(void)
316dc0f529SPavel Dovgalyuk {
326dc0f529SPavel Dovgalyuk     if (!write_error) {
336dc0f529SPavel Dovgalyuk         error_report("replay write error");
346dc0f529SPavel Dovgalyuk         write_error = true;
356dc0f529SPavel Dovgalyuk     }
366dc0f529SPavel Dovgalyuk }
376dc0f529SPavel Dovgalyuk 
380b570077SPeter Maydell static void replay_read_error(void)
390b570077SPeter Maydell {
400b570077SPeter Maydell     error_report("error reading the replay data");
410b570077SPeter Maydell     exit(1);
420b570077SPeter Maydell }
430b570077SPeter Maydell 
44c92079f4SPavel Dovgalyuk void replay_put_byte(uint8_t byte)
45c92079f4SPavel Dovgalyuk {
46c92079f4SPavel Dovgalyuk     if (replay_file) {
476dc0f529SPavel Dovgalyuk         if (putc(byte, replay_file) == EOF) {
486dc0f529SPavel Dovgalyuk             replay_write_error();
496dc0f529SPavel Dovgalyuk         }
50c92079f4SPavel Dovgalyuk     }
51c92079f4SPavel Dovgalyuk }
52c92079f4SPavel Dovgalyuk 
53c92079f4SPavel Dovgalyuk void replay_put_event(uint8_t event)
54c92079f4SPavel Dovgalyuk {
5526bc60acSPavel Dovgalyuk     assert(event < EVENT_COUNT);
56c92079f4SPavel Dovgalyuk     replay_put_byte(event);
57c92079f4SPavel Dovgalyuk }
58c92079f4SPavel Dovgalyuk 
59c92079f4SPavel Dovgalyuk 
60c92079f4SPavel Dovgalyuk void replay_put_word(uint16_t word)
61c92079f4SPavel Dovgalyuk {
62c92079f4SPavel Dovgalyuk     replay_put_byte(word >> 8);
63c92079f4SPavel Dovgalyuk     replay_put_byte(word);
64c92079f4SPavel Dovgalyuk }
65c92079f4SPavel Dovgalyuk 
66c92079f4SPavel Dovgalyuk void replay_put_dword(uint32_t dword)
67c92079f4SPavel Dovgalyuk {
68c92079f4SPavel Dovgalyuk     replay_put_word(dword >> 16);
69c92079f4SPavel Dovgalyuk     replay_put_word(dword);
70c92079f4SPavel Dovgalyuk }
71c92079f4SPavel Dovgalyuk 
72c92079f4SPavel Dovgalyuk void replay_put_qword(int64_t qword)
73c92079f4SPavel Dovgalyuk {
74c92079f4SPavel Dovgalyuk     replay_put_dword(qword >> 32);
75c92079f4SPavel Dovgalyuk     replay_put_dword(qword);
76c92079f4SPavel Dovgalyuk }
77c92079f4SPavel Dovgalyuk 
78c92079f4SPavel Dovgalyuk void replay_put_array(const uint8_t *buf, size_t size)
79c92079f4SPavel Dovgalyuk {
80c92079f4SPavel Dovgalyuk     if (replay_file) {
81c92079f4SPavel Dovgalyuk         replay_put_dword(size);
826dc0f529SPavel Dovgalyuk         if (fwrite(buf, 1, size, replay_file) != size) {
836dc0f529SPavel Dovgalyuk             replay_write_error();
846dc0f529SPavel Dovgalyuk         }
85c92079f4SPavel Dovgalyuk     }
86c92079f4SPavel Dovgalyuk }
87c92079f4SPavel Dovgalyuk 
88c92079f4SPavel Dovgalyuk uint8_t replay_get_byte(void)
89c92079f4SPavel Dovgalyuk {
90c92079f4SPavel Dovgalyuk     uint8_t byte = 0;
91c92079f4SPavel Dovgalyuk     if (replay_file) {
920b570077SPeter Maydell         int r = getc(replay_file);
930b570077SPeter Maydell         if (r == EOF) {
940b570077SPeter Maydell             replay_read_error();
950b570077SPeter Maydell         }
960b570077SPeter Maydell         byte = r;
97c92079f4SPavel Dovgalyuk     }
98c92079f4SPavel Dovgalyuk     return byte;
99c92079f4SPavel Dovgalyuk }
100c92079f4SPavel Dovgalyuk 
101c92079f4SPavel Dovgalyuk uint16_t replay_get_word(void)
102c92079f4SPavel Dovgalyuk {
103c92079f4SPavel Dovgalyuk     uint16_t word = 0;
104c92079f4SPavel Dovgalyuk     if (replay_file) {
105c92079f4SPavel Dovgalyuk         word = replay_get_byte();
106c92079f4SPavel Dovgalyuk         word = (word << 8) + replay_get_byte();
107c92079f4SPavel Dovgalyuk     }
108c92079f4SPavel Dovgalyuk 
109c92079f4SPavel Dovgalyuk     return word;
110c92079f4SPavel Dovgalyuk }
111c92079f4SPavel Dovgalyuk 
112c92079f4SPavel Dovgalyuk uint32_t replay_get_dword(void)
113c92079f4SPavel Dovgalyuk {
114c92079f4SPavel Dovgalyuk     uint32_t dword = 0;
115c92079f4SPavel Dovgalyuk     if (replay_file) {
116c92079f4SPavel Dovgalyuk         dword = replay_get_word();
117c92079f4SPavel Dovgalyuk         dword = (dword << 16) + replay_get_word();
118c92079f4SPavel Dovgalyuk     }
119c92079f4SPavel Dovgalyuk 
120c92079f4SPavel Dovgalyuk     return dword;
121c92079f4SPavel Dovgalyuk }
122c92079f4SPavel Dovgalyuk 
123c92079f4SPavel Dovgalyuk int64_t replay_get_qword(void)
124c92079f4SPavel Dovgalyuk {
125c92079f4SPavel Dovgalyuk     int64_t qword = 0;
126c92079f4SPavel Dovgalyuk     if (replay_file) {
127c92079f4SPavel Dovgalyuk         qword = replay_get_dword();
128c92079f4SPavel Dovgalyuk         qword = (qword << 32) + replay_get_dword();
129c92079f4SPavel Dovgalyuk     }
130c92079f4SPavel Dovgalyuk 
131c92079f4SPavel Dovgalyuk     return qword;
132c92079f4SPavel Dovgalyuk }
133c92079f4SPavel Dovgalyuk 
134c92079f4SPavel Dovgalyuk void replay_get_array(uint8_t *buf, size_t *size)
135c92079f4SPavel Dovgalyuk {
136c92079f4SPavel Dovgalyuk     if (replay_file) {
137c92079f4SPavel Dovgalyuk         *size = replay_get_dword();
138c92079f4SPavel Dovgalyuk         if (fread(buf, 1, *size, replay_file) != *size) {
1390b570077SPeter Maydell             replay_read_error();
140c92079f4SPavel Dovgalyuk         }
141c92079f4SPavel Dovgalyuk     }
142c92079f4SPavel Dovgalyuk }
143c92079f4SPavel Dovgalyuk 
144c92079f4SPavel Dovgalyuk void replay_get_array_alloc(uint8_t **buf, size_t *size)
145c92079f4SPavel Dovgalyuk {
146c92079f4SPavel Dovgalyuk     if (replay_file) {
147c92079f4SPavel Dovgalyuk         *size = replay_get_dword();
148c92079f4SPavel Dovgalyuk         *buf = g_malloc(*size);
149c92079f4SPavel Dovgalyuk         if (fread(*buf, 1, *size, replay_file) != *size) {
1500b570077SPeter Maydell             replay_read_error();
151c92079f4SPavel Dovgalyuk         }
152c92079f4SPavel Dovgalyuk     }
153c92079f4SPavel Dovgalyuk }
154c92079f4SPavel Dovgalyuk 
155c92079f4SPavel Dovgalyuk void replay_check_error(void)
156c92079f4SPavel Dovgalyuk {
157c92079f4SPavel Dovgalyuk     if (replay_file) {
158c92079f4SPavel Dovgalyuk         if (feof(replay_file)) {
159c92079f4SPavel Dovgalyuk             error_report("replay file is over");
160c92079f4SPavel Dovgalyuk             qemu_system_vmstop_request_prepare();
161c92079f4SPavel Dovgalyuk             qemu_system_vmstop_request(RUN_STATE_PAUSED);
162c92079f4SPavel Dovgalyuk         } else if (ferror(replay_file)) {
163c92079f4SPavel Dovgalyuk             error_report("replay file is over or something goes wrong");
164c92079f4SPavel Dovgalyuk             qemu_system_vmstop_request_prepare();
165c92079f4SPavel Dovgalyuk             qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
166c92079f4SPavel Dovgalyuk         }
167c92079f4SPavel Dovgalyuk     }
168c92079f4SPavel Dovgalyuk }
169c92079f4SPavel Dovgalyuk 
170c92079f4SPavel Dovgalyuk void replay_fetch_data_kind(void)
171c92079f4SPavel Dovgalyuk {
172c92079f4SPavel Dovgalyuk     if (replay_file) {
173f186d64dSPavel Dovgalyuk         if (!replay_state.has_unread_data) {
174f186d64dSPavel Dovgalyuk             replay_state.data_kind = replay_get_byte();
175f186d64dSPavel Dovgalyuk             if (replay_state.data_kind == EVENT_INSTRUCTION) {
17626bc60acSPavel Dovgalyuk                 replay_state.instructions_count = replay_get_dword();
17726bc60acSPavel Dovgalyuk             }
178c92079f4SPavel Dovgalyuk             replay_check_error();
179f186d64dSPavel Dovgalyuk             replay_state.has_unread_data = 1;
180f186d64dSPavel Dovgalyuk             if (replay_state.data_kind >= EVENT_COUNT) {
181f186d64dSPavel Dovgalyuk                 error_report("Replay: unknown event kind %d",
182f186d64dSPavel Dovgalyuk                              replay_state.data_kind);
18326bc60acSPavel Dovgalyuk                 exit(1);
18426bc60acSPavel Dovgalyuk             }
185c92079f4SPavel Dovgalyuk         }
186c92079f4SPavel Dovgalyuk     }
187c92079f4SPavel Dovgalyuk }
188c92079f4SPavel Dovgalyuk 
189c92079f4SPavel Dovgalyuk void replay_finish_event(void)
190c92079f4SPavel Dovgalyuk {
191f186d64dSPavel Dovgalyuk     replay_state.has_unread_data = 0;
192c92079f4SPavel Dovgalyuk     replay_fetch_data_kind();
193c92079f4SPavel Dovgalyuk }
194c16861efSPavel Dovgalyuk 
195180d30beSAlex Bennée static __thread bool replay_locked;
196180d30beSAlex Bennée 
197c16861efSPavel Dovgalyuk void replay_mutex_init(void)
198c16861efSPavel Dovgalyuk {
199c16861efSPavel Dovgalyuk     qemu_mutex_init(&lock);
200d759c951SAlex Bennée     /* Hold the mutex while we start-up */
201d759c951SAlex Bennée     qemu_mutex_lock(&lock);
202d759c951SAlex Bennée     replay_locked = true;
203c16861efSPavel Dovgalyuk }
204c16861efSPavel Dovgalyuk 
205a36544d3SAlex Bennée bool replay_mutex_locked(void)
206180d30beSAlex Bennée {
207180d30beSAlex Bennée     return replay_locked;
208180d30beSAlex Bennée }
209180d30beSAlex Bennée 
210d759c951SAlex Bennée /* Ordering constraints, replay_lock must be taken before BQL */
211c16861efSPavel Dovgalyuk void replay_mutex_lock(void)
212c16861efSPavel Dovgalyuk {
213d759c951SAlex Bennée     if (replay_mode != REPLAY_MODE_NONE) {
214d759c951SAlex Bennée         g_assert(!qemu_mutex_iothread_locked());
215180d30beSAlex Bennée         g_assert(!replay_mutex_locked());
216c16861efSPavel Dovgalyuk         qemu_mutex_lock(&lock);
217180d30beSAlex Bennée         replay_locked = true;
218c16861efSPavel Dovgalyuk     }
219d759c951SAlex Bennée }
220c16861efSPavel Dovgalyuk 
221c16861efSPavel Dovgalyuk void replay_mutex_unlock(void)
222c16861efSPavel Dovgalyuk {
223d759c951SAlex Bennée     if (replay_mode != REPLAY_MODE_NONE) {
224180d30beSAlex Bennée         g_assert(replay_mutex_locked());
225180d30beSAlex Bennée         replay_locked = false;
226c16861efSPavel Dovgalyuk         qemu_mutex_unlock(&lock);
227c16861efSPavel Dovgalyuk     }
228d759c951SAlex Bennée }
22926bc60acSPavel Dovgalyuk 
23074c0b816SPaolo Bonzini void replay_advance_current_step(uint64_t current_step)
23126bc60acSPavel Dovgalyuk {
23226bc60acSPavel Dovgalyuk     int diff = (int)(replay_get_current_step() - replay_state.current_step);
233982263ceSAlex Bennée 
234982263ceSAlex Bennée     /* Time can only go forward */
235982263ceSAlex Bennée     assert(diff >= 0);
236982263ceSAlex Bennée 
23726bc60acSPavel Dovgalyuk     if (diff > 0) {
23826bc60acSPavel Dovgalyuk         replay_put_event(EVENT_INSTRUCTION);
23926bc60acSPavel Dovgalyuk         replay_put_dword(diff);
24026bc60acSPavel Dovgalyuk         replay_state.current_step += diff;
24126bc60acSPavel Dovgalyuk     }
24226bc60acSPavel Dovgalyuk }
24374c0b816SPaolo Bonzini 
24474c0b816SPaolo Bonzini /*! Saves cached instructions. */
24574c0b816SPaolo Bonzini void replay_save_instructions(void)
24674c0b816SPaolo Bonzini {
24774c0b816SPaolo Bonzini     if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
24874c0b816SPaolo Bonzini         g_assert(replay_mutex_locked());
24974c0b816SPaolo Bonzini         replay_advance_current_step(replay_get_current_step());
25074c0b816SPaolo Bonzini     }
25126bc60acSPavel Dovgalyuk }
252