Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/vmstate.c
2 views
1
/* SPDX-License-Identifier: BSD-3-Clause */
2
/*
3
* VMState interpreter
4
*
5
* Copyright (c) 2009-2018 Red Hat Inc
6
*
7
* Authors:
8
* Juan Quintela <[email protected]>
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
*
14
* 1. Redistributions of source code must retain the above
15
* copyright notice, this list of conditions and the following
16
* disclaimer.
17
*
18
* 2. Redistributions in binary form must reproduce the above
19
* copyright notice, this list of conditions and the following
20
* disclaimer in the documentation and/or other materials provided
21
* with the distribution.
22
*
23
* 3. Neither the name of the copyright holder nor the names of its
24
* contributors may be used to endorse or promote products derived
25
* from this software without specific prior written permission.
26
*
27
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38
* OF THE POSSIBILITY OF SUCH DAMAGE.
39
*/
40
#include <assert.h>
41
#include <errno.h>
42
#include <string.h>
43
#include <glib.h>
44
45
#include "stream.h"
46
#include "vmstate.h"
47
48
static int get_nullptr(SlirpIStream *f, void *pv, size_t size,
49
const VMStateField *field)
50
{
51
if (slirp_istream_read_u8(f) == VMS_NULLPTR_MARKER) {
52
return 0;
53
}
54
g_warning("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
55
return -EINVAL;
56
}
57
58
static int put_nullptr(SlirpOStream *f, void *pv, size_t size,
59
const VMStateField *field)
60
61
{
62
if (pv == NULL) {
63
slirp_ostream_write_u8(f, VMS_NULLPTR_MARKER);
64
return 0;
65
}
66
g_warning("vmstate: put_nullptr must be called with pv == NULL");
67
return -EINVAL;
68
}
69
70
const VMStateInfo slirp_vmstate_info_nullptr = {
71
.name = "uint64",
72
.get = get_nullptr,
73
.put = put_nullptr,
74
};
75
76
/* 8 bit unsigned int */
77
78
static int get_uint8(SlirpIStream *f, void *pv, size_t size,
79
const VMStateField *field)
80
{
81
uint8_t *v = pv;
82
*v = slirp_istream_read_u8(f);
83
return 0;
84
}
85
86
static int put_uint8(SlirpOStream *f, void *pv, size_t size,
87
const VMStateField *field)
88
{
89
uint8_t *v = pv;
90
slirp_ostream_write_u8(f, *v);
91
return 0;
92
}
93
94
const VMStateInfo slirp_vmstate_info_uint8 = {
95
.name = "uint8",
96
.get = get_uint8,
97
.put = put_uint8,
98
};
99
100
/* 16 bit unsigned int */
101
102
static int get_uint16(SlirpIStream *f, void *pv, size_t size,
103
const VMStateField *field)
104
{
105
uint16_t *v = pv;
106
*v = slirp_istream_read_u16(f);
107
return 0;
108
}
109
110
static int put_uint16(SlirpOStream *f, void *pv, size_t size,
111
const VMStateField *field)
112
{
113
uint16_t *v = pv;
114
slirp_ostream_write_u16(f, *v);
115
return 0;
116
}
117
118
const VMStateInfo slirp_vmstate_info_uint16 = {
119
.name = "uint16",
120
.get = get_uint16,
121
.put = put_uint16,
122
};
123
124
/* 32 bit unsigned int */
125
126
static int get_uint32(SlirpIStream *f, void *pv, size_t size,
127
const VMStateField *field)
128
{
129
uint32_t *v = pv;
130
*v = slirp_istream_read_u32(f);
131
return 0;
132
}
133
134
static int put_uint32(SlirpOStream *f, void *pv, size_t size,
135
const VMStateField *field)
136
{
137
uint32_t *v = pv;
138
slirp_ostream_write_u32(f, *v);
139
return 0;
140
}
141
142
const VMStateInfo slirp_vmstate_info_uint32 = {
143
.name = "uint32",
144
.get = get_uint32,
145
.put = put_uint32,
146
};
147
148
/* 16 bit int */
149
150
static int get_int16(SlirpIStream *f, void *pv, size_t size,
151
const VMStateField *field)
152
{
153
int16_t *v = pv;
154
*v = slirp_istream_read_i16(f);
155
return 0;
156
}
157
158
static int put_int16(SlirpOStream *f, void *pv, size_t size,
159
const VMStateField *field)
160
{
161
int16_t *v = pv;
162
slirp_ostream_write_i16(f, *v);
163
return 0;
164
}
165
166
const VMStateInfo slirp_vmstate_info_int16 = {
167
.name = "int16",
168
.get = get_int16,
169
.put = put_int16,
170
};
171
172
/* 32 bit int */
173
174
static int get_int32(SlirpIStream *f, void *pv, size_t size,
175
const VMStateField *field)
176
{
177
int32_t *v = pv;
178
*v = slirp_istream_read_i32(f);
179
return 0;
180
}
181
182
static int put_int32(SlirpOStream *f, void *pv, size_t size,
183
const VMStateField *field)
184
{
185
int32_t *v = pv;
186
slirp_ostream_write_i32(f, *v);
187
return 0;
188
}
189
190
const VMStateInfo slirp_vmstate_info_int32 = {
191
.name = "int32",
192
.get = get_int32,
193
.put = put_int32,
194
};
195
196
/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
197
* a temporary buffer and the pre_load/pre_save methods in the child vmsd
198
* copy stuff from the parent into the child and do calculations to fill
199
* in fields that don't really exist in the parent but need to be in the
200
* stream.
201
*/
202
static int get_tmp(SlirpIStream *f, void *pv, size_t size,
203
const VMStateField *field)
204
{
205
int ret;
206
const VMStateDescription *vmsd = field->vmsd;
207
int version_id = field->version_id;
208
void *tmp = g_malloc(size);
209
210
/* Writes the parent field which is at the start of the tmp */
211
*(void **)tmp = pv;
212
ret = slirp_vmstate_load_state(f, vmsd, tmp, version_id);
213
g_free(tmp);
214
return ret;
215
}
216
217
static int put_tmp(SlirpOStream *f, void *pv, size_t size,
218
const VMStateField *field)
219
{
220
const VMStateDescription *vmsd = field->vmsd;
221
void *tmp = g_malloc(size);
222
int ret;
223
224
/* Writes the parent field which is at the start of the tmp */
225
*(void **)tmp = pv;
226
ret = slirp_vmstate_save_state(f, vmsd, tmp);
227
g_free(tmp);
228
229
return ret;
230
}
231
232
const VMStateInfo slirp_vmstate_info_tmp = {
233
.name = "tmp",
234
.get = get_tmp,
235
.put = put_tmp,
236
};
237
238
/* uint8_t buffers */
239
240
static int get_buffer(SlirpIStream *f, void *pv, size_t size,
241
const VMStateField *field)
242
{
243
slirp_istream_read(f, pv, size);
244
return 0;
245
}
246
247
static int put_buffer(SlirpOStream *f, void *pv, size_t size,
248
const VMStateField *field)
249
{
250
slirp_ostream_write(f, pv, size);
251
return 0;
252
}
253
254
const VMStateInfo slirp_vmstate_info_buffer = {
255
.name = "buffer",
256
.get = get_buffer,
257
.put = put_buffer,
258
};
259
260
static int vmstate_n_elems(char *opaque, const VMStateField *field)
261
{
262
int n_elems = 1;
263
264
if (field->flags & VMS_ARRAY) {
265
n_elems = field->num;
266
} else if (field->flags & VMS_VARRAY_INT32) {
267
n_elems = *(int32_t *)(opaque + field->num_offset);
268
} else if (field->flags & VMS_VARRAY_UINT32) {
269
n_elems = *(uint32_t *)(opaque + field->num_offset);
270
} else if (field->flags & VMS_VARRAY_UINT16) {
271
n_elems = *(uint16_t *)(opaque + field->num_offset);
272
} else if (field->flags & VMS_VARRAY_UINT8) {
273
n_elems = *(uint8_t *)(opaque + field->num_offset);
274
}
275
276
if (field->flags & VMS_MULTIPLY_ELEMENTS) {
277
n_elems *= field->num;
278
}
279
280
return n_elems;
281
}
282
283
static int vmstate_size(char *opaque, const VMStateField *field)
284
{
285
int size = field->size;
286
287
if (field->flags & VMS_VBUFFER) {
288
size = *(int32_t *)(opaque + field->size_offset);
289
if (field->flags & VMS_MULTIPLY) {
290
size *= field->size;
291
}
292
}
293
294
return size;
295
}
296
297
static int vmstate_save_state_v(SlirpOStream *f, const VMStateDescription *vmsd,
298
char *opaque, int version_id)
299
{
300
int ret = 0;
301
const VMStateField *field = vmsd->fields;
302
303
if (vmsd->pre_save) {
304
ret = vmsd->pre_save(opaque);
305
if (ret) {
306
g_warning("pre-save failed: %s", vmsd->name);
307
return ret;
308
}
309
}
310
311
while (field->name) {
312
if ((field->field_exists && field->field_exists(opaque, version_id)) ||
313
(!field->field_exists && field->version_id <= version_id)) {
314
char *first_elem = opaque + field->offset;
315
int i, n_elems = vmstate_n_elems(opaque, field);
316
int size = vmstate_size(opaque, field);
317
318
if (field->flags & VMS_POINTER) {
319
first_elem = *(void **)first_elem;
320
assert(first_elem || !n_elems || !size);
321
}
322
for (i = 0; i < n_elems; i++) {
323
void *curr_elem = first_elem + size * i;
324
325
if (field->flags & VMS_ARRAY_OF_POINTER) {
326
assert(curr_elem);
327
curr_elem = *(void **)curr_elem;
328
}
329
if (!curr_elem && size) {
330
/* if null pointer write placeholder and do not follow */
331
assert(field->flags & VMS_ARRAY_OF_POINTER);
332
ret = slirp_vmstate_info_nullptr.put(f, curr_elem, size,
333
NULL);
334
} else if (field->flags & VMS_STRUCT) {
335
ret = slirp_vmstate_save_state(f, field->vmsd, curr_elem);
336
} else if (field->flags & VMS_VSTRUCT) {
337
ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
338
field->struct_version_id);
339
} else {
340
ret = field->info->put(f, curr_elem, size, field);
341
}
342
if (ret) {
343
g_warning("Save of field %s/%s failed", vmsd->name,
344
field->name);
345
return ret;
346
}
347
}
348
} else {
349
if (field->flags & VMS_MUST_EXIST) {
350
g_warning("Output state validation failed: %s/%s", vmsd->name,
351
field->name);
352
assert(!(field->flags & VMS_MUST_EXIST));
353
}
354
}
355
field++;
356
}
357
358
return 0;
359
}
360
361
int slirp_vmstate_save_state(SlirpOStream *f, const VMStateDescription *vmsd,
362
void *opaque)
363
{
364
return vmstate_save_state_v(f, vmsd, opaque, vmsd->version_id);
365
}
366
367
static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
368
{
369
if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
370
size_t size = vmstate_size(opaque, field);
371
size *= vmstate_n_elems(opaque, field);
372
if (size) {
373
*(void **)ptr = g_malloc(size);
374
}
375
}
376
}
377
378
int slirp_vmstate_load_state(SlirpIStream *f, const VMStateDescription *vmsd,
379
void *opaque_, int version_id)
380
{
381
VMStateField *field = vmsd->fields;
382
int ret = 0;
383
char *opaque = opaque_;
384
385
if (version_id > vmsd->version_id) {
386
g_warning("%s: incoming version_id %d is too new "
387
"for local version_id %d",
388
vmsd->name, version_id, vmsd->version_id);
389
return -EINVAL;
390
}
391
if (vmsd->pre_load) {
392
int ret = vmsd->pre_load(opaque);
393
if (ret) {
394
return ret;
395
}
396
}
397
while (field->name) {
398
if ((field->field_exists && field->field_exists(opaque, version_id)) ||
399
(!field->field_exists && field->version_id <= version_id)) {
400
char *first_elem = opaque + field->offset;
401
int i, n_elems = vmstate_n_elems(opaque, field);
402
int size = vmstate_size(opaque, field);
403
404
vmstate_handle_alloc(first_elem, field, opaque);
405
if (field->flags & VMS_POINTER) {
406
first_elem = *(void **)first_elem;
407
assert(first_elem || !n_elems || !size);
408
}
409
for (i = 0; i < n_elems; i++) {
410
void *curr_elem = first_elem + size * i;
411
412
if (field->flags & VMS_ARRAY_OF_POINTER) {
413
curr_elem = *(void **)curr_elem;
414
}
415
if (!curr_elem && size) {
416
/* if null pointer check placeholder and do not follow */
417
assert(field->flags & VMS_ARRAY_OF_POINTER);
418
ret = slirp_vmstate_info_nullptr.get(f, curr_elem, size,
419
NULL);
420
} else if (field->flags & VMS_STRUCT) {
421
ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
422
field->vmsd->version_id);
423
} else if (field->flags & VMS_VSTRUCT) {
424
ret = slirp_vmstate_load_state(f, field->vmsd, curr_elem,
425
field->struct_version_id);
426
} else {
427
ret = field->info->get(f, curr_elem, size, field);
428
}
429
if (ret < 0) {
430
g_warning("Failed to load %s:%s", vmsd->name, field->name);
431
return ret;
432
}
433
}
434
} else if (field->flags & VMS_MUST_EXIST) {
435
g_warning("Input validation failed: %s/%s", vmsd->name,
436
field->name);
437
return -1;
438
}
439
field++;
440
}
441
if (vmsd->post_load) {
442
ret = vmsd->post_load(opaque, version_id);
443
}
444
return ret;
445
}
446
447