xref: /qemu/replay/replay-internal.c (revision 7a4e543d)
1 /*
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 
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"
18 
19 unsigned int replay_data_kind = -1;
20 static unsigned int replay_has_unread_data;
21 
22 /* Mutex to protect reading and writing events to the log.
23    replay_data_kind and replay_has_unread_data are also protected
24    by this mutex.
25    It also protects replay events queue which stores events to be
26    written or read to the log. */
27 static QemuMutex lock;
28 
29 /* File for replay writing */
30 FILE *replay_file;
31 
32 void replay_put_byte(uint8_t byte)
33 {
34     if (replay_file) {
35         putc(byte, replay_file);
36     }
37 }
38 
39 void replay_put_event(uint8_t event)
40 {
41     assert(event < EVENT_COUNT);
42     replay_put_byte(event);
43 }
44 
45 
46 void replay_put_word(uint16_t word)
47 {
48     replay_put_byte(word >> 8);
49     replay_put_byte(word);
50 }
51 
52 void replay_put_dword(uint32_t dword)
53 {
54     replay_put_word(dword >> 16);
55     replay_put_word(dword);
56 }
57 
58 void replay_put_qword(int64_t qword)
59 {
60     replay_put_dword(qword >> 32);
61     replay_put_dword(qword);
62 }
63 
64 void replay_put_array(const uint8_t *buf, size_t size)
65 {
66     if (replay_file) {
67         replay_put_dword(size);
68         fwrite(buf, 1, size, replay_file);
69     }
70 }
71 
72 uint8_t replay_get_byte(void)
73 {
74     uint8_t byte = 0;
75     if (replay_file) {
76         byte = getc(replay_file);
77     }
78     return byte;
79 }
80 
81 uint16_t replay_get_word(void)
82 {
83     uint16_t word = 0;
84     if (replay_file) {
85         word = replay_get_byte();
86         word = (word << 8) + replay_get_byte();
87     }
88 
89     return word;
90 }
91 
92 uint32_t replay_get_dword(void)
93 {
94     uint32_t dword = 0;
95     if (replay_file) {
96         dword = replay_get_word();
97         dword = (dword << 16) + replay_get_word();
98     }
99 
100     return dword;
101 }
102 
103 int64_t replay_get_qword(void)
104 {
105     int64_t qword = 0;
106     if (replay_file) {
107         qword = replay_get_dword();
108         qword = (qword << 32) + replay_get_dword();
109     }
110 
111     return qword;
112 }
113 
114 void replay_get_array(uint8_t *buf, size_t *size)
115 {
116     if (replay_file) {
117         *size = replay_get_dword();
118         if (fread(buf, 1, *size, replay_file) != *size) {
119             error_report("replay read error");
120         }
121     }
122 }
123 
124 void replay_get_array_alloc(uint8_t **buf, size_t *size)
125 {
126     if (replay_file) {
127         *size = replay_get_dword();
128         *buf = g_malloc(*size);
129         if (fread(*buf, 1, *size, replay_file) != *size) {
130             error_report("replay read error");
131         }
132     }
133 }
134 
135 void replay_check_error(void)
136 {
137     if (replay_file) {
138         if (feof(replay_file)) {
139             error_report("replay file is over");
140             qemu_system_vmstop_request_prepare();
141             qemu_system_vmstop_request(RUN_STATE_PAUSED);
142         } else if (ferror(replay_file)) {
143             error_report("replay file is over or something goes wrong");
144             qemu_system_vmstop_request_prepare();
145             qemu_system_vmstop_request(RUN_STATE_INTERNAL_ERROR);
146         }
147     }
148 }
149 
150 void replay_fetch_data_kind(void)
151 {
152     if (replay_file) {
153         if (!replay_has_unread_data) {
154             replay_data_kind = replay_get_byte();
155             if (replay_data_kind == EVENT_INSTRUCTION) {
156                 replay_state.instructions_count = replay_get_dword();
157             }
158             replay_check_error();
159             replay_has_unread_data = 1;
160             if (replay_data_kind >= EVENT_COUNT) {
161                 error_report("Replay: unknown event kind %d", replay_data_kind);
162                 exit(1);
163             }
164         }
165     }
166 }
167 
168 void replay_finish_event(void)
169 {
170     replay_has_unread_data = 0;
171     replay_fetch_data_kind();
172 }
173 
174 void replay_mutex_init(void)
175 {
176     qemu_mutex_init(&lock);
177 }
178 
179 void replay_mutex_destroy(void)
180 {
181     qemu_mutex_destroy(&lock);
182 }
183 
184 void replay_mutex_lock(void)
185 {
186     qemu_mutex_lock(&lock);
187 }
188 
189 void replay_mutex_unlock(void)
190 {
191     qemu_mutex_unlock(&lock);
192 }
193 
194 /*! Saves cached instructions. */
195 void replay_save_instructions(void)
196 {
197     if (replay_file && replay_mode == REPLAY_MODE_RECORD) {
198         replay_mutex_lock();
199         int diff = (int)(replay_get_current_step() - replay_state.current_step);
200         if (diff > 0) {
201             replay_put_event(EVENT_INSTRUCTION);
202             replay_put_dword(diff);
203             replay_state.current_step += diff;
204         }
205         replay_mutex_unlock();
206     }
207 }
208