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