OSDN Git Service

docker: debian-bootstrap.pre allow customising of variant/url
[qmiga/qemu.git] / tests / test-vmstate.c
1 /*
2  *  Test code for VMState
3  *
4  *  Copyright (c) 2013 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24
25 #include "qemu/osdep.h"
26
27 #include "qemu-common.h"
28 #include "../migration/migration.h"
29 #include "migration/vmstate.h"
30 #include "migration/qemu-file-types.h"
31 #include "../migration/qemu-file.h"
32 #include "../migration/qemu-file-channel.h"
33 #include "../migration/savevm.h"
34 #include "qemu/coroutine.h"
35 #include "io/channel-file.h"
36
37 static char temp_file[] = "/tmp/vmst.test.XXXXXX";
38 static int temp_fd;
39
40
41 /* Duplicate temp_fd and seek to the beginning of the file */
42 static QEMUFile *open_test_file(bool write)
43 {
44     int fd = dup(temp_fd);
45     QIOChannel *ioc;
46     QEMUFile *f;
47
48     lseek(fd, 0, SEEK_SET);
49     if (write) {
50         g_assert_cmpint(ftruncate(fd, 0), ==, 0);
51     }
52     ioc = QIO_CHANNEL(qio_channel_file_new_fd(fd));
53     if (write) {
54         f = qemu_fopen_channel_output(ioc);
55     } else {
56         f = qemu_fopen_channel_input(ioc);
57     }
58     object_unref(OBJECT(ioc));
59     return f;
60 }
61
62 #define SUCCESS(val) \
63     g_assert_cmpint((val), ==, 0)
64
65 #define FAILURE(val) \
66     g_assert_cmpint((val), !=, 0)
67
68 static void save_vmstate(const VMStateDescription *desc, void *obj)
69 {
70     QEMUFile *f = open_test_file(true);
71
72     /* Save file with vmstate */
73     int ret = vmstate_save_state(f, desc, obj, NULL);
74     g_assert(!ret);
75     qemu_put_byte(f, QEMU_VM_EOF);
76     g_assert(!qemu_file_get_error(f));
77     qemu_fclose(f);
78 }
79
80 static void save_buffer(const uint8_t *buf, size_t buf_size)
81 {
82     QEMUFile *fsave = open_test_file(true);
83     qemu_put_buffer(fsave, buf, buf_size);
84     qemu_fclose(fsave);
85 }
86
87 static void compare_vmstate(const uint8_t *wire, size_t size)
88 {
89     QEMUFile *f = open_test_file(false);
90     uint8_t result[size];
91
92     /* read back as binary */
93
94     g_assert_cmpint(qemu_get_buffer(f, result, sizeof(result)), ==,
95                     sizeof(result));
96     g_assert(!qemu_file_get_error(f));
97
98     /* Compare that what is on the file is the same that what we
99        expected to be there */
100     SUCCESS(memcmp(result, wire, sizeof(result)));
101
102     /* Must reach EOF */
103     qemu_get_byte(f);
104     g_assert_cmpint(qemu_file_get_error(f), ==, -EIO);
105
106     qemu_fclose(f);
107 }
108
109 static int load_vmstate_one(const VMStateDescription *desc, void *obj,
110                             int version, const uint8_t *wire, size_t size)
111 {
112     QEMUFile *f;
113     int ret;
114
115     f = open_test_file(true);
116     qemu_put_buffer(f, wire, size);
117     qemu_fclose(f);
118
119     f = open_test_file(false);
120     ret = vmstate_load_state(f, desc, obj, version);
121     if (ret) {
122         g_assert(qemu_file_get_error(f));
123     } else{
124         g_assert(!qemu_file_get_error(f));
125     }
126     qemu_fclose(f);
127     return ret;
128 }
129
130
131 static int load_vmstate(const VMStateDescription *desc,
132                         void *obj, void *obj_clone,
133                         void (*obj_copy)(void *, void*),
134                         int version, const uint8_t *wire, size_t size)
135 {
136     /* We test with zero size */
137     obj_copy(obj_clone, obj);
138     FAILURE(load_vmstate_one(desc, obj, version, wire, 0));
139
140     /* Stream ends with QEMU_EOF, so we need at least 3 bytes to be
141      * able to test in the middle */
142
143     if (size > 3) {
144
145         /* We test with size - 2. We can't test size - 1 due to EOF tricks */
146         obj_copy(obj, obj_clone);
147         FAILURE(load_vmstate_one(desc, obj, version, wire, size - 2));
148
149         /* Test with size/2, first half of real state */
150         obj_copy(obj, obj_clone);
151         FAILURE(load_vmstate_one(desc, obj, version, wire, size/2));
152
153         /* Test with size/2, second half of real state */
154         obj_copy(obj, obj_clone);
155         FAILURE(load_vmstate_one(desc, obj, version, wire + (size/2), size/2));
156
157     }
158     obj_copy(obj, obj_clone);
159     return load_vmstate_one(desc, obj, version, wire, size);
160 }
161
162 /* Test struct that we are going to use for our tests */
163
164 typedef struct TestSimple {
165     bool     b_1,   b_2;
166     uint8_t  u8_1;
167     uint16_t u16_1;
168     uint32_t u32_1;
169     uint64_t u64_1;
170     int8_t   i8_1,  i8_2;
171     int16_t  i16_1, i16_2;
172     int32_t  i32_1, i32_2;
173     int64_t  i64_1, i64_2;
174 } TestSimple;
175
176 /* Object instantiation, we are going to use it in more than one test */
177
178 TestSimple obj_simple = {
179     .b_1 = true,
180     .b_2 = false,
181     .u8_1 = 130,
182     .u16_1 = 512,
183     .u32_1 = 70000,
184     .u64_1 = 12121212,
185     .i8_1 = 65,
186     .i8_2 = -65,
187     .i16_1 = 512,
188     .i16_2 = -512,
189     .i32_1 = 70000,
190     .i32_2 = -70000,
191     .i64_1 = 12121212,
192     .i64_2 = -12121212,
193 };
194
195 /* Description of the values.  If you add a primitive type
196    you are expected to add a test here */
197
198 static const VMStateDescription vmstate_simple_primitive = {
199     .name = "simple/primitive",
200     .version_id = 1,
201     .minimum_version_id = 1,
202     .fields = (VMStateField[]) {
203         VMSTATE_BOOL(b_1, TestSimple),
204         VMSTATE_BOOL(b_2, TestSimple),
205         VMSTATE_UINT8(u8_1, TestSimple),
206         VMSTATE_UINT16(u16_1, TestSimple),
207         VMSTATE_UINT32(u32_1, TestSimple),
208         VMSTATE_UINT64(u64_1, TestSimple),
209         VMSTATE_INT8(i8_1, TestSimple),
210         VMSTATE_INT8(i8_2, TestSimple),
211         VMSTATE_INT16(i16_1, TestSimple),
212         VMSTATE_INT16(i16_2, TestSimple),
213         VMSTATE_INT32(i32_1, TestSimple),
214         VMSTATE_INT32(i32_2, TestSimple),
215         VMSTATE_INT64(i64_1, TestSimple),
216         VMSTATE_INT64(i64_2, TestSimple),
217         VMSTATE_END_OF_LIST()
218     }
219 };
220
221 /* It describes what goes through the wire.  Our tests are basically:
222
223    * save test
224      - save a struct a vmstate to a file
225      - read that file back (binary read, no vmstate)
226      - compare it with what we expect to be on the wire
227    * load test
228      - save to the file what we expect to be on the wire
229      - read struct back with vmstate in a different
230      - compare back with the original struct
231 */
232
233 uint8_t wire_simple_primitive[] = {
234     /* b_1 */   0x01,
235     /* b_2 */   0x00,
236     /* u8_1 */  0x82,
237     /* u16_1 */ 0x02, 0x00,
238     /* u32_1 */ 0x00, 0x01, 0x11, 0x70,
239     /* u64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
240     /* i8_1 */  0x41,
241     /* i8_2 */  0xbf,
242     /* i16_1 */ 0x02, 0x00,
243     /* i16_2 */ 0xfe, 0x0,
244     /* i32_1 */ 0x00, 0x01, 0x11, 0x70,
245     /* i32_2 */ 0xff, 0xfe, 0xee, 0x90,
246     /* i64_1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xf4, 0x7c,
247     /* i64_2 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x0b, 0x84,
248     QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
249 };
250
251 static void obj_simple_copy(void *target, void *source)
252 {
253     memcpy(target, source, sizeof(TestSimple));
254 }
255
256 static void test_simple_primitive(void)
257 {
258     TestSimple obj, obj_clone;
259
260     memset(&obj, 0, sizeof(obj));
261     save_vmstate(&vmstate_simple_primitive, &obj_simple);
262
263     compare_vmstate(wire_simple_primitive, sizeof(wire_simple_primitive));
264
265     SUCCESS(load_vmstate(&vmstate_simple_primitive, &obj, &obj_clone,
266                          obj_simple_copy, 1, wire_simple_primitive,
267                          sizeof(wire_simple_primitive)));
268
269 #define FIELD_EQUAL(name)   g_assert_cmpint(obj.name, ==, obj_simple.name)
270
271     FIELD_EQUAL(b_1);
272     FIELD_EQUAL(b_2);
273     FIELD_EQUAL(u8_1);
274     FIELD_EQUAL(u16_1);
275     FIELD_EQUAL(u32_1);
276     FIELD_EQUAL(u64_1);
277     FIELD_EQUAL(i8_1);
278     FIELD_EQUAL(i8_2);
279     FIELD_EQUAL(i16_1);
280     FIELD_EQUAL(i16_2);
281     FIELD_EQUAL(i32_1);
282     FIELD_EQUAL(i32_2);
283     FIELD_EQUAL(i64_1);
284     FIELD_EQUAL(i64_2);
285 }
286
287 typedef struct TestStruct {
288     uint32_t a, b, c, e;
289     uint64_t d, f;
290     bool skip_c_e;
291 } TestStruct;
292
293 static const VMStateDescription vmstate_versioned = {
294     .name = "test/versioned",
295     .version_id = 2,
296     .minimum_version_id = 1,
297     .fields = (VMStateField[]) {
298         VMSTATE_UINT32(a, TestStruct),
299         VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so
300                                              * we catch bugs more easily.
301                                              */
302         VMSTATE_UINT32(c, TestStruct),
303         VMSTATE_UINT64(d, TestStruct),
304         VMSTATE_UINT32_V(e, TestStruct, 2),
305         VMSTATE_UINT64_V(f, TestStruct, 2),
306         VMSTATE_END_OF_LIST()
307     }
308 };
309
310 static void test_load_v1(void)
311 {
312     uint8_t buf[] = {
313         0, 0, 0, 10,             /* a */
314         0, 0, 0, 30,             /* c */
315         0, 0, 0, 0, 0, 0, 0, 40, /* d */
316         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
317     };
318     save_buffer(buf, sizeof(buf));
319
320     QEMUFile *loading = open_test_file(false);
321     TestStruct obj = { .b = 200, .e = 500, .f = 600 };
322     vmstate_load_state(loading, &vmstate_versioned, &obj, 1);
323     g_assert(!qemu_file_get_error(loading));
324     g_assert_cmpint(obj.a, ==, 10);
325     g_assert_cmpint(obj.b, ==, 200);
326     g_assert_cmpint(obj.c, ==, 30);
327     g_assert_cmpint(obj.d, ==, 40);
328     g_assert_cmpint(obj.e, ==, 500);
329     g_assert_cmpint(obj.f, ==, 600);
330     qemu_fclose(loading);
331 }
332
333 static void test_load_v2(void)
334 {
335     uint8_t buf[] = {
336         0, 0, 0, 10,             /* a */
337         0, 0, 0, 20,             /* b */
338         0, 0, 0, 30,             /* c */
339         0, 0, 0, 0, 0, 0, 0, 40, /* d */
340         0, 0, 0, 50,             /* e */
341         0, 0, 0, 0, 0, 0, 0, 60, /* f */
342         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
343     };
344     save_buffer(buf, sizeof(buf));
345
346     QEMUFile *loading = open_test_file(false);
347     TestStruct obj;
348     vmstate_load_state(loading, &vmstate_versioned, &obj, 2);
349     g_assert_cmpint(obj.a, ==, 10);
350     g_assert_cmpint(obj.b, ==, 20);
351     g_assert_cmpint(obj.c, ==, 30);
352     g_assert_cmpint(obj.d, ==, 40);
353     g_assert_cmpint(obj.e, ==, 50);
354     g_assert_cmpint(obj.f, ==, 60);
355     qemu_fclose(loading);
356 }
357
358 static bool test_skip(void *opaque, int version_id)
359 {
360     TestStruct *t = (TestStruct *)opaque;
361     return !t->skip_c_e;
362 }
363
364 static const VMStateDescription vmstate_skipping = {
365     .name = "test/skip",
366     .version_id = 2,
367     .minimum_version_id = 1,
368     .fields = (VMStateField[]) {
369         VMSTATE_UINT32(a, TestStruct),
370         VMSTATE_UINT32(b, TestStruct),
371         VMSTATE_UINT32_TEST(c, TestStruct, test_skip),
372         VMSTATE_UINT64(d, TestStruct),
373         VMSTATE_UINT32_TEST(e, TestStruct, test_skip),
374         VMSTATE_UINT64_V(f, TestStruct, 2),
375         VMSTATE_END_OF_LIST()
376     }
377 };
378
379
380 static void test_save_noskip(void)
381 {
382     QEMUFile *fsave = open_test_file(true);
383     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
384                        .skip_c_e = false };
385     int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
386     g_assert(!ret);
387     g_assert(!qemu_file_get_error(fsave));
388
389     uint8_t expected[] = {
390         0, 0, 0, 1,             /* a */
391         0, 0, 0, 2,             /* b */
392         0, 0, 0, 3,             /* c */
393         0, 0, 0, 0, 0, 0, 0, 4, /* d */
394         0, 0, 0, 5,             /* e */
395         0, 0, 0, 0, 0, 0, 0, 6, /* f */
396     };
397
398     qemu_fclose(fsave);
399     compare_vmstate(expected, sizeof(expected));
400 }
401
402 static void test_save_skip(void)
403 {
404     QEMUFile *fsave = open_test_file(true);
405     TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6,
406                        .skip_c_e = true };
407     int ret = vmstate_save_state(fsave, &vmstate_skipping, &obj, NULL);
408     g_assert(!ret);
409     g_assert(!qemu_file_get_error(fsave));
410
411     uint8_t expected[] = {
412         0, 0, 0, 1,             /* a */
413         0, 0, 0, 2,             /* b */
414         0, 0, 0, 0, 0, 0, 0, 4, /* d */
415         0, 0, 0, 0, 0, 0, 0, 6, /* f */
416     };
417
418     qemu_fclose(fsave);
419     compare_vmstate(expected, sizeof(expected));
420 }
421
422 static void test_load_noskip(void)
423 {
424     uint8_t buf[] = {
425         0, 0, 0, 10,             /* a */
426         0, 0, 0, 20,             /* b */
427         0, 0, 0, 30,             /* c */
428         0, 0, 0, 0, 0, 0, 0, 40, /* d */
429         0, 0, 0, 50,             /* e */
430         0, 0, 0, 0, 0, 0, 0, 60, /* f */
431         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
432     };
433     save_buffer(buf, sizeof(buf));
434
435     QEMUFile *loading = open_test_file(false);
436     TestStruct obj = { .skip_c_e = false };
437     vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
438     g_assert(!qemu_file_get_error(loading));
439     g_assert_cmpint(obj.a, ==, 10);
440     g_assert_cmpint(obj.b, ==, 20);
441     g_assert_cmpint(obj.c, ==, 30);
442     g_assert_cmpint(obj.d, ==, 40);
443     g_assert_cmpint(obj.e, ==, 50);
444     g_assert_cmpint(obj.f, ==, 60);
445     qemu_fclose(loading);
446 }
447
448 static void test_load_skip(void)
449 {
450     uint8_t buf[] = {
451         0, 0, 0, 10,             /* a */
452         0, 0, 0, 20,             /* b */
453         0, 0, 0, 0, 0, 0, 0, 40, /* d */
454         0, 0, 0, 0, 0, 0, 0, 60, /* f */
455         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
456     };
457     save_buffer(buf, sizeof(buf));
458
459     QEMUFile *loading = open_test_file(false);
460     TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 };
461     vmstate_load_state(loading, &vmstate_skipping, &obj, 2);
462     g_assert(!qemu_file_get_error(loading));
463     g_assert_cmpint(obj.a, ==, 10);
464     g_assert_cmpint(obj.b, ==, 20);
465     g_assert_cmpint(obj.c, ==, 300);
466     g_assert_cmpint(obj.d, ==, 40);
467     g_assert_cmpint(obj.e, ==, 500);
468     g_assert_cmpint(obj.f, ==, 60);
469     qemu_fclose(loading);
470 }
471
472 typedef struct {
473     int32_t i;
474 } TestStructTriv;
475
476 const VMStateDescription vmsd_tst = {
477     .name = "test/tst",
478     .version_id = 1,
479     .minimum_version_id = 1,
480     .fields = (VMStateField[]) {
481         VMSTATE_INT32(i, TestStructTriv),
482         VMSTATE_END_OF_LIST()
483     }
484 };
485
486 /* test array migration */
487
488 #define AR_SIZE 4
489
490 typedef struct {
491     TestStructTriv *ar[AR_SIZE];
492 } TestArrayOfPtrToStuct;
493
494 const VMStateDescription vmsd_arps = {
495     .name = "test/arps",
496     .version_id = 1,
497     .minimum_version_id = 1,
498     .fields = (VMStateField[]) {
499         VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(ar, TestArrayOfPtrToStuct,
500                 AR_SIZE, 0, vmsd_tst, TestStructTriv),
501         VMSTATE_END_OF_LIST()
502     }
503 };
504
505 static uint8_t wire_arr_ptr_no0[] = {
506     0x00, 0x00, 0x00, 0x00,
507     0x00, 0x00, 0x00, 0x01,
508     0x00, 0x00, 0x00, 0x02,
509     0x00, 0x00, 0x00, 0x03,
510     QEMU_VM_EOF
511 };
512
513 static void test_arr_ptr_str_no0_save(void)
514 {
515     TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
516     TestArrayOfPtrToStuct sample = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
517
518     save_vmstate(&vmsd_arps, &sample);
519     compare_vmstate(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
520 }
521
522 static void test_arr_ptr_str_no0_load(void)
523 {
524     TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
525     TestStructTriv ar[AR_SIZE] = {};
526     TestArrayOfPtrToStuct obj = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
527     int idx;
528
529     save_buffer(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
530     SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
531                           wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)));
532     for (idx = 0; idx < AR_SIZE; ++idx) {
533         /* compare the target array ar with the ground truth array ar_gt */
534         g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
535     }
536 }
537
538 static uint8_t wire_arr_ptr_0[] = {
539     0x00, 0x00, 0x00, 0x00,
540     VMS_NULLPTR_MARKER,
541     0x00, 0x00, 0x00, 0x02,
542     0x00, 0x00, 0x00, 0x03,
543     QEMU_VM_EOF
544 };
545
546 static void test_arr_ptr_str_0_save(void)
547 {
548     TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
549     TestArrayOfPtrToStuct sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
550
551     save_vmstate(&vmsd_arps, &sample);
552     compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
553 }
554
555 static void test_arr_ptr_str_0_load(void)
556 {
557     TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 0}, {.i = 2}, {.i = 3} };
558     TestStructTriv ar[AR_SIZE] = {};
559     TestArrayOfPtrToStuct obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
560     int idx;
561
562     save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
563     SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
564                           wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
565     for (idx = 0; idx < AR_SIZE; ++idx) {
566         /* compare the target array ar with the ground truth array ar_gt */
567         g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
568     }
569     for (idx = 0; idx < AR_SIZE; ++idx) {
570         if (idx == 1) {
571             g_assert_cmpint((uintptr_t)(obj.ar[idx]), ==, 0);
572         } else {
573             g_assert_cmpint((uintptr_t)(obj.ar[idx]), !=, 0);
574         }
575     }
576 }
577
578 typedef struct TestArrayOfPtrToInt {
579     int32_t *ar[AR_SIZE];
580 } TestArrayOfPtrToInt;
581
582 const VMStateDescription vmsd_arpp = {
583     .name = "test/arps",
584     .version_id = 1,
585     .minimum_version_id = 1,
586     .fields = (VMStateField[]) {
587         VMSTATE_ARRAY_OF_POINTER(ar, TestArrayOfPtrToInt,
588                 AR_SIZE, 0, vmstate_info_int32, int32_t*),
589         VMSTATE_END_OF_LIST()
590     }
591 };
592
593 static void test_arr_ptr_prim_0_save(void)
594 {
595     int32_t ar[AR_SIZE] = {0 , 1, 2, 3};
596     TestArrayOfPtrToInt  sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
597
598     save_vmstate(&vmsd_arpp, &sample);
599     compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
600 }
601
602 static void test_arr_ptr_prim_0_load(void)
603 {
604     int32_t ar_gt[AR_SIZE] = {0, 1, 2, 3};
605     int32_t ar[AR_SIZE] = {3 , 42, 1, 0};
606     TestArrayOfPtrToInt obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
607     int idx;
608
609     save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
610     SUCCESS(load_vmstate_one(&vmsd_arpp, &obj, 1,
611                           wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
612     for (idx = 0; idx < AR_SIZE; ++idx) {
613         /* compare the target array ar with the ground truth array ar_gt */
614         if (idx == 1) {
615             g_assert_cmpint(42, ==, ar[idx]);
616         } else {
617             g_assert_cmpint(ar_gt[idx], ==, ar[idx]);
618         }
619     }
620 }
621
622 /* test QTAILQ migration */
623 typedef struct TestQtailqElement TestQtailqElement;
624
625 struct TestQtailqElement {
626     bool     b;
627     uint8_t  u8;
628     QTAILQ_ENTRY(TestQtailqElement) next;
629 };
630
631 typedef struct TestQtailq {
632     int16_t  i16;
633     QTAILQ_HEAD(TestQtailqHead, TestQtailqElement) q;
634     int32_t  i32;
635 } TestQtailq;
636
637 static const VMStateDescription vmstate_q_element = {
638     .name = "test/queue-element",
639     .version_id = 1,
640     .minimum_version_id = 1,
641     .fields = (VMStateField[]) {
642         VMSTATE_BOOL(b, TestQtailqElement),
643         VMSTATE_UINT8(u8, TestQtailqElement),
644         VMSTATE_END_OF_LIST()
645     },
646 };
647
648 static const VMStateDescription vmstate_q = {
649     .name = "test/queue",
650     .version_id = 1,
651     .minimum_version_id = 1,
652     .fields = (VMStateField[]) {
653         VMSTATE_INT16(i16, TestQtailq),
654         VMSTATE_QTAILQ_V(q, TestQtailq, 1, vmstate_q_element, TestQtailqElement,
655                          next),
656         VMSTATE_INT32(i32, TestQtailq),
657         VMSTATE_END_OF_LIST()
658     }
659 };
660
661 uint8_t wire_q[] = {
662     /* i16 */                     0xfe, 0x0,
663     /* start of element 0 of q */ 0x01,
664     /* .b  */                     0x01,
665     /* .u8 */                     0x82,
666     /* start of element 1 of q */ 0x01,
667     /* b */                       0x00,
668     /* u8 */                      0x41,
669     /* end of q */                0x00,
670     /* i32 */                     0x00, 0x01, 0x11, 0x70,
671     QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
672 };
673
674 static void test_save_q(void)
675 {
676     TestQtailq obj_q = {
677         .i16 = -512,
678         .i32 = 70000,
679     };
680
681     TestQtailqElement obj_qe1 = {
682         .b = true,
683         .u8 = 130,
684     };
685
686     TestQtailqElement obj_qe2 = {
687         .b = false,
688         .u8 = 65,
689     };
690
691     QTAILQ_INIT(&obj_q.q);
692     QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next);
693     QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next);
694
695     save_vmstate(&vmstate_q, &obj_q);
696     compare_vmstate(wire_q, sizeof(wire_q));
697 }
698
699 static void test_load_q(void)
700 {
701     TestQtailq obj_q = {
702         .i16 = -512,
703         .i32 = 70000,
704     };
705
706     TestQtailqElement obj_qe1 = {
707         .b = true,
708         .u8 = 130,
709     };
710
711     TestQtailqElement obj_qe2 = {
712         .b = false,
713         .u8 = 65,
714     };
715
716     QTAILQ_INIT(&obj_q.q);
717     QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next);
718     QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next);
719
720     QEMUFile *fsave = open_test_file(true);
721
722     qemu_put_buffer(fsave, wire_q, sizeof(wire_q));
723     g_assert(!qemu_file_get_error(fsave));
724     qemu_fclose(fsave);
725
726     QEMUFile *fload = open_test_file(false);
727     TestQtailq tgt;
728
729     QTAILQ_INIT(&tgt.q);
730     vmstate_load_state(fload, &vmstate_q, &tgt, 1);
731     char eof = qemu_get_byte(fload);
732     g_assert(!qemu_file_get_error(fload));
733     g_assert_cmpint(tgt.i16, ==, obj_q.i16);
734     g_assert_cmpint(tgt.i32, ==, obj_q.i32);
735     g_assert_cmpint(eof, ==, QEMU_VM_EOF);
736
737     TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q);
738     TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q, TestQtailqHead);
739     TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q);
740     TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q, TestQtailqHead);
741
742     while (1) {
743         g_assert_cmpint(qele_to->b, ==, qele_from->b);
744         g_assert_cmpint(qele_to->u8, ==, qele_from->u8);
745         if ((qele_from == qlast_from) || (qele_to == qlast_to)) {
746             break;
747         }
748         qele_from = QTAILQ_NEXT(qele_from, next);
749         qele_to = QTAILQ_NEXT(qele_to, next);
750     }
751
752     g_assert_cmpint((uintptr_t) qele_from, ==, (uintptr_t) qlast_from);
753     g_assert_cmpint((uintptr_t) qele_to, ==, (uintptr_t) qlast_to);
754
755     /* clean up */
756     TestQtailqElement *qele;
757     while (!QTAILQ_EMPTY(&tgt.q)) {
758         qele = QTAILQ_LAST(&tgt.q, TestQtailqHead);
759         QTAILQ_REMOVE(&tgt.q, qele, next);
760         free(qele);
761         qele = NULL;
762     }
763     qemu_fclose(fload);
764 }
765
766 typedef struct TmpTestStruct {
767     TestStruct *parent;
768     int64_t diff;
769 } TmpTestStruct;
770
771 static int tmp_child_pre_save(void *opaque)
772 {
773     struct TmpTestStruct *tts = opaque;
774
775     tts->diff = tts->parent->b - tts->parent->a;
776
777     return 0;
778 }
779
780 static int tmp_child_post_load(void *opaque, int version_id)
781 {
782     struct TmpTestStruct *tts = opaque;
783
784     tts->parent->b = tts->parent->a + tts->diff;
785
786     return 0;
787 }
788
789 static const VMStateDescription vmstate_tmp_back_to_parent = {
790     .name = "test/tmp_child_parent",
791     .fields = (VMStateField[]) {
792         VMSTATE_UINT64(f, TestStruct),
793         VMSTATE_END_OF_LIST()
794     }
795 };
796
797 static const VMStateDescription vmstate_tmp_child = {
798     .name = "test/tmp_child",
799     .pre_save = tmp_child_pre_save,
800     .post_load = tmp_child_post_load,
801     .fields = (VMStateField[]) {
802         VMSTATE_INT64(diff, TmpTestStruct),
803         VMSTATE_STRUCT_POINTER(parent, TmpTestStruct,
804                                vmstate_tmp_back_to_parent, TestStruct),
805         VMSTATE_END_OF_LIST()
806     }
807 };
808
809 static const VMStateDescription vmstate_with_tmp = {
810     .name = "test/with_tmp",
811     .version_id = 1,
812     .fields = (VMStateField[]) {
813         VMSTATE_UINT32(a, TestStruct),
814         VMSTATE_UINT64(d, TestStruct),
815         VMSTATE_WITH_TMP(TestStruct, TmpTestStruct, vmstate_tmp_child),
816         VMSTATE_END_OF_LIST()
817     }
818 };
819
820 static void obj_tmp_copy(void *target, void *source)
821 {
822     memcpy(target, source, sizeof(TestStruct));
823 }
824
825 static void test_tmp_struct(void)
826 {
827     TestStruct obj, obj_clone;
828
829     uint8_t const wire_with_tmp[] = {
830         /* u32 a */ 0x00, 0x00, 0x00, 0x02,
831         /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
832         /* diff  */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
833         /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
834         QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
835     };
836
837     memset(&obj, 0, sizeof(obj));
838     obj.a = 2;
839     obj.b = 4;
840     obj.d = 1;
841     obj.f = 8;
842     save_vmstate(&vmstate_with_tmp, &obj);
843
844     compare_vmstate(wire_with_tmp, sizeof(wire_with_tmp));
845
846     memset(&obj, 0, sizeof(obj));
847     SUCCESS(load_vmstate(&vmstate_with_tmp, &obj, &obj_clone,
848                          obj_tmp_copy, 1, wire_with_tmp,
849                          sizeof(wire_with_tmp)));
850     g_assert_cmpint(obj.a, ==, 2); /* From top level vmsd */
851     g_assert_cmpint(obj.b, ==, 4); /* from the post_load */
852     g_assert_cmpint(obj.d, ==, 1); /* From top level vmsd */
853     g_assert_cmpint(obj.f, ==, 8); /* From the child->parent */
854 }
855
856 int main(int argc, char **argv)
857 {
858     temp_fd = mkstemp(temp_file);
859
860     module_call_init(MODULE_INIT_QOM);
861
862     g_test_init(&argc, &argv, NULL);
863     g_test_add_func("/vmstate/simple/primitive", test_simple_primitive);
864     g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
865     g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
866     g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);
867     g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip);
868     g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip);
869     g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip);
870     g_test_add_func("/vmstate/array/ptr/str/no0/save",
871                     test_arr_ptr_str_no0_save);
872     g_test_add_func("/vmstate/array/ptr/str/no0/load",
873                     test_arr_ptr_str_no0_load);
874     g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save);
875     g_test_add_func("/vmstate/array/ptr/str/0/load",
876                     test_arr_ptr_str_0_load);
877     g_test_add_func("/vmstate/array/ptr/prim/0/save",
878                     test_arr_ptr_prim_0_save);
879     g_test_add_func("/vmstate/array/ptr/prim/0/load",
880                     test_arr_ptr_prim_0_load);
881     g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q);
882     g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q);
883     g_test_add_func("/vmstate/tmp_struct", test_tmp_struct);
884     g_test_run();
885
886     close(temp_fd);
887     unlink(temp_file);
888
889     return 0;
890 }