~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to tests/test-vmstate.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
static char temp_file[] = "/tmp/vmst.test.XXXXXX";
34
34
static int temp_fd;
35
35
 
36
 
/* Fake yield_until_fd_readable() implementation so we don't have to pull the
37
 
 * coroutine code as dependency.
38
 
 */
39
 
void yield_until_fd_readable(int fd)
40
 
{
41
 
    fd_set fds;
42
 
    FD_ZERO(&fds);
43
 
    FD_SET(fd, &fds);
44
 
    select(fd + 1, &fds, NULL, NULL, NULL);
45
 
}
46
 
 
47
36
 
48
37
/* Duplicate temp_fd and seek to the beginning of the file */
49
38
static QEMUFile *open_test_file(bool write)
90
79
    qemu_fclose(fsave);
91
80
}
92
81
 
93
 
static void compare_vmstate(uint8_t *wire, size_t size)
 
82
static void compare_vmstate(const uint8_t *wire, size_t size)
94
83
{
95
84
    QEMUFile *f = open_test_file(false);
96
85
    uint8_t result[size];
113
102
}
114
103
 
115
104
static int load_vmstate_one(const VMStateDescription *desc, void *obj,
116
 
                            int version, uint8_t *wire, size_t size)
 
105
                            int version, const uint8_t *wire, size_t size)
117
106
{
118
107
    QEMUFile *f;
119
108
    int ret;
137
126
static int load_vmstate(const VMStateDescription *desc,
138
127
                        void *obj, void *obj_clone,
139
128
                        void (*obj_copy)(void *, void*),
140
 
                        int version, uint8_t *wire, size_t size)
 
129
                        int version, const uint8_t *wire, size_t size)
141
130
{
142
131
    /* We test with zero size */
143
132
    obj_copy(obj_clone, obj);
289
278
    FIELD_EQUAL(i64_1);
290
279
    FIELD_EQUAL(i64_2);
291
280
}
292
 
#undef FIELD_EQUAL
293
281
 
294
282
typedef struct TestStruct {
295
283
    uint32_t a, b, c, e;
474
462
    qemu_fclose(loading);
475
463
}
476
464
 
477
 
 
478
465
typedef struct {
479
466
    int32_t i;
480
467
} TestStructTriv;
489
476
    }
490
477
};
491
478
 
 
479
/* test array migration */
 
480
 
492
481
#define AR_SIZE 4
493
482
 
494
483
typedef struct {
505
494
        VMSTATE_END_OF_LIST()
506
495
    }
507
496
};
 
497
 
 
498
static uint8_t wire_arr_ptr_no0[] = {
 
499
    0x00, 0x00, 0x00, 0x00,
 
500
    0x00, 0x00, 0x00, 0x01,
 
501
    0x00, 0x00, 0x00, 0x02,
 
502
    0x00, 0x00, 0x00, 0x03,
 
503
    QEMU_VM_EOF
 
504
};
 
505
 
508
506
static void test_arr_ptr_str_no0_save(void)
509
507
{
510
508
    TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
511
509
    TestArrayOfPtrToStuct sample = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
512
 
    uint8_t wire_sample[] = {
513
 
        0x00, 0x00, 0x00, 0x00,
514
 
        0x00, 0x00, 0x00, 0x01,
515
 
        0x00, 0x00, 0x00, 0x02,
516
 
        0x00, 0x00, 0x00, 0x03,
517
 
        QEMU_VM_EOF
518
 
    };
519
510
 
520
511
    save_vmstate(&vmsd_arps, &sample);
521
 
    compare_vmstate(wire_sample, sizeof(wire_sample));
 
512
    compare_vmstate(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
522
513
}
523
514
 
524
515
static void test_arr_ptr_str_no0_load(void)
527
518
    TestStructTriv ar[AR_SIZE] = {};
528
519
    TestArrayOfPtrToStuct obj = {.ar = {&ar[0], &ar[1], &ar[2], &ar[3]} };
529
520
    int idx;
530
 
    uint8_t wire_sample[] = {
531
 
        0x00, 0x00, 0x00, 0x00,
532
 
        0x00, 0x00, 0x00, 0x01,
533
 
        0x00, 0x00, 0x00, 0x02,
534
 
        0x00, 0x00, 0x00, 0x03,
535
 
        QEMU_VM_EOF
536
 
    };
537
 
 
538
 
    save_buffer(wire_sample, sizeof(wire_sample));
539
 
    SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
540
 
                          wire_sample, sizeof(wire_sample)));
541
 
    for (idx = 0; idx < AR_SIZE; ++idx) {
542
 
        /* compare the target array ar with the ground truth array ar_gt */
543
 
        g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
544
 
    }
 
521
 
 
522
    save_buffer(wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0));
 
523
    SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
 
524
                          wire_arr_ptr_no0, sizeof(wire_arr_ptr_no0)));
 
525
    for (idx = 0; idx < AR_SIZE; ++idx) {
 
526
        /* compare the target array ar with the ground truth array ar_gt */
 
527
        g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
 
528
    }
 
529
}
 
530
 
 
531
static uint8_t wire_arr_ptr_0[] = {
 
532
    0x00, 0x00, 0x00, 0x00,
 
533
    VMS_NULLPTR_MARKER,
 
534
    0x00, 0x00, 0x00, 0x02,
 
535
    0x00, 0x00, 0x00, 0x03,
 
536
    QEMU_VM_EOF
 
537
};
 
538
 
 
539
static void test_arr_ptr_str_0_save(void)
 
540
{
 
541
    TestStructTriv ar[AR_SIZE] = {{.i = 0}, {.i = 1}, {.i = 2}, {.i = 3} };
 
542
    TestArrayOfPtrToStuct sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
 
543
 
 
544
    save_vmstate(&vmsd_arps, &sample);
 
545
    compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
 
546
}
 
547
 
 
548
static void test_arr_ptr_str_0_load(void)
 
549
{
 
550
    TestStructTriv ar_gt[AR_SIZE] = {{.i = 0}, {.i = 0}, {.i = 2}, {.i = 3} };
 
551
    TestStructTriv ar[AR_SIZE] = {};
 
552
    TestArrayOfPtrToStuct obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
 
553
    int idx;
 
554
 
 
555
    save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
 
556
    SUCCESS(load_vmstate_one(&vmsd_arps, &obj, 1,
 
557
                          wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
 
558
    for (idx = 0; idx < AR_SIZE; ++idx) {
 
559
        /* compare the target array ar with the ground truth array ar_gt */
 
560
        g_assert_cmpint(ar_gt[idx].i, ==, ar[idx].i);
 
561
    }
 
562
    for (idx = 0; idx < AR_SIZE; ++idx) {
 
563
        if (idx == 1) {
 
564
            g_assert_cmpint((uintptr_t)(obj.ar[idx]), ==, 0);
 
565
        } else {
 
566
            g_assert_cmpint((uintptr_t)(obj.ar[idx]), !=, 0);
 
567
        }
 
568
    }
 
569
}
 
570
 
 
571
typedef struct TestArrayOfPtrToInt {
 
572
    int32_t *ar[AR_SIZE];
 
573
} TestArrayOfPtrToInt;
 
574
 
 
575
const VMStateDescription vmsd_arpp = {
 
576
    .name = "test/arps",
 
577
    .version_id = 1,
 
578
    .minimum_version_id = 1,
 
579
    .fields = (VMStateField[]) {
 
580
        VMSTATE_ARRAY_OF_POINTER(ar, TestArrayOfPtrToInt,
 
581
                AR_SIZE, 0, vmstate_info_int32, int32_t*),
 
582
        VMSTATE_END_OF_LIST()
 
583
    }
 
584
};
 
585
 
 
586
static void test_arr_ptr_prim_0_save(void)
 
587
{
 
588
    int32_t ar[AR_SIZE] = {0 , 1, 2, 3};
 
589
    TestArrayOfPtrToInt  sample = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
 
590
 
 
591
    save_vmstate(&vmsd_arpp, &sample);
 
592
    compare_vmstate(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
 
593
}
 
594
 
 
595
static void test_arr_ptr_prim_0_load(void)
 
596
{
 
597
    int32_t ar_gt[AR_SIZE] = {0, 1, 2, 3};
 
598
    int32_t ar[AR_SIZE] = {3 , 42, 1, 0};
 
599
    TestArrayOfPtrToInt obj = {.ar = {&ar[0], NULL, &ar[2], &ar[3]} };
 
600
    int idx;
 
601
 
 
602
    save_buffer(wire_arr_ptr_0, sizeof(wire_arr_ptr_0));
 
603
    SUCCESS(load_vmstate_one(&vmsd_arpp, &obj, 1,
 
604
                          wire_arr_ptr_0, sizeof(wire_arr_ptr_0)));
 
605
    for (idx = 0; idx < AR_SIZE; ++idx) {
 
606
        /* compare the target array ar with the ground truth array ar_gt */
 
607
        if (idx == 1) {
 
608
            g_assert_cmpint(42, ==, ar[idx]);
 
609
        } else {
 
610
            g_assert_cmpint(ar_gt[idx], ==, ar[idx]);
 
611
        }
 
612
    }
 
613
}
 
614
 
 
615
/* test QTAILQ migration */
 
616
typedef struct TestQtailqElement TestQtailqElement;
 
617
 
 
618
struct TestQtailqElement {
 
619
    bool     b;
 
620
    uint8_t  u8;
 
621
    QTAILQ_ENTRY(TestQtailqElement) next;
 
622
};
 
623
 
 
624
typedef struct TestQtailq {
 
625
    int16_t  i16;
 
626
    QTAILQ_HEAD(TestQtailqHead, TestQtailqElement) q;
 
627
    int32_t  i32;
 
628
} TestQtailq;
 
629
 
 
630
static const VMStateDescription vmstate_q_element = {
 
631
    .name = "test/queue-element",
 
632
    .version_id = 1,
 
633
    .minimum_version_id = 1,
 
634
    .fields = (VMStateField[]) {
 
635
        VMSTATE_BOOL(b, TestQtailqElement),
 
636
        VMSTATE_UINT8(u8, TestQtailqElement),
 
637
        VMSTATE_END_OF_LIST()
 
638
    },
 
639
};
 
640
 
 
641
static const VMStateDescription vmstate_q = {
 
642
    .name = "test/queue",
 
643
    .version_id = 1,
 
644
    .minimum_version_id = 1,
 
645
    .fields = (VMStateField[]) {
 
646
        VMSTATE_INT16(i16, TestQtailq),
 
647
        VMSTATE_QTAILQ_V(q, TestQtailq, 1, vmstate_q_element, TestQtailqElement,
 
648
                         next),
 
649
        VMSTATE_INT32(i32, TestQtailq),
 
650
        VMSTATE_END_OF_LIST()
 
651
    }
 
652
};
 
653
 
 
654
uint8_t wire_q[] = {
 
655
    /* i16 */                     0xfe, 0x0,
 
656
    /* start of element 0 of q */ 0x01,
 
657
    /* .b  */                     0x01,
 
658
    /* .u8 */                     0x82,
 
659
    /* start of element 1 of q */ 0x01,
 
660
    /* b */                       0x00,
 
661
    /* u8 */                      0x41,
 
662
    /* end of q */                0x00,
 
663
    /* i32 */                     0x00, 0x01, 0x11, 0x70,
 
664
    QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
 
665
};
 
666
 
 
667
static void test_save_q(void)
 
668
{
 
669
    TestQtailq obj_q = {
 
670
        .i16 = -512,
 
671
        .i32 = 70000,
 
672
    };
 
673
 
 
674
    TestQtailqElement obj_qe1 = {
 
675
        .b = true,
 
676
        .u8 = 130,
 
677
    };
 
678
 
 
679
    TestQtailqElement obj_qe2 = {
 
680
        .b = false,
 
681
        .u8 = 65,
 
682
    };
 
683
 
 
684
    QTAILQ_INIT(&obj_q.q);
 
685
    QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next);
 
686
    QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next);
 
687
 
 
688
    save_vmstate(&vmstate_q, &obj_q);
 
689
    compare_vmstate(wire_q, sizeof(wire_q));
 
690
}
 
691
 
 
692
static void test_load_q(void)
 
693
{
 
694
    TestQtailq obj_q = {
 
695
        .i16 = -512,
 
696
        .i32 = 70000,
 
697
    };
 
698
 
 
699
    TestQtailqElement obj_qe1 = {
 
700
        .b = true,
 
701
        .u8 = 130,
 
702
    };
 
703
 
 
704
    TestQtailqElement obj_qe2 = {
 
705
        .b = false,
 
706
        .u8 = 65,
 
707
    };
 
708
 
 
709
    QTAILQ_INIT(&obj_q.q);
 
710
    QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe1, next);
 
711
    QTAILQ_INSERT_TAIL(&obj_q.q, &obj_qe2, next);
 
712
 
 
713
    QEMUFile *fsave = open_test_file(true);
 
714
 
 
715
    qemu_put_buffer(fsave, wire_q, sizeof(wire_q));
 
716
    g_assert(!qemu_file_get_error(fsave));
 
717
    qemu_fclose(fsave);
 
718
 
 
719
    QEMUFile *fload = open_test_file(false);
 
720
    TestQtailq tgt;
 
721
 
 
722
    QTAILQ_INIT(&tgt.q);
 
723
    vmstate_load_state(fload, &vmstate_q, &tgt, 1);
 
724
    char eof = qemu_get_byte(fload);
 
725
    g_assert(!qemu_file_get_error(fload));
 
726
    g_assert_cmpint(tgt.i16, ==, obj_q.i16);
 
727
    g_assert_cmpint(tgt.i32, ==, obj_q.i32);
 
728
    g_assert_cmpint(eof, ==, QEMU_VM_EOF);
 
729
 
 
730
    TestQtailqElement *qele_from = QTAILQ_FIRST(&obj_q.q);
 
731
    TestQtailqElement *qlast_from = QTAILQ_LAST(&obj_q.q, TestQtailqHead);
 
732
    TestQtailqElement *qele_to = QTAILQ_FIRST(&tgt.q);
 
733
    TestQtailqElement *qlast_to = QTAILQ_LAST(&tgt.q, TestQtailqHead);
 
734
 
 
735
    while (1) {
 
736
        g_assert_cmpint(qele_to->b, ==, qele_from->b);
 
737
        g_assert_cmpint(qele_to->u8, ==, qele_from->u8);
 
738
        if ((qele_from == qlast_from) || (qele_to == qlast_to)) {
 
739
            break;
 
740
        }
 
741
        qele_from = QTAILQ_NEXT(qele_from, next);
 
742
        qele_to = QTAILQ_NEXT(qele_to, next);
 
743
    }
 
744
 
 
745
    g_assert_cmpint((uintptr_t) qele_from, ==, (uintptr_t) qlast_from);
 
746
    g_assert_cmpint((uintptr_t) qele_to, ==, (uintptr_t) qlast_to);
 
747
 
 
748
    /* clean up */
 
749
    TestQtailqElement *qele;
 
750
    while (!QTAILQ_EMPTY(&tgt.q)) {
 
751
        qele = QTAILQ_LAST(&tgt.q, TestQtailqHead);
 
752
        QTAILQ_REMOVE(&tgt.q, qele, next);
 
753
        free(qele);
 
754
        qele = NULL;
 
755
    }
 
756
    qemu_fclose(fload);
 
757
}
 
758
 
 
759
typedef struct TmpTestStruct {
 
760
    TestStruct *parent;
 
761
    int64_t diff;
 
762
} TmpTestStruct;
 
763
 
 
764
static void tmp_child_pre_save(void *opaque)
 
765
{
 
766
    struct TmpTestStruct *tts = opaque;
 
767
 
 
768
    tts->diff = tts->parent->b - tts->parent->a;
 
769
}
 
770
 
 
771
static int tmp_child_post_load(void *opaque, int version_id)
 
772
{
 
773
    struct TmpTestStruct *tts = opaque;
 
774
 
 
775
    tts->parent->b = tts->parent->a + tts->diff;
 
776
 
 
777
    return 0;
 
778
}
 
779
 
 
780
static const VMStateDescription vmstate_tmp_back_to_parent = {
 
781
    .name = "test/tmp_child_parent",
 
782
    .fields = (VMStateField[]) {
 
783
        VMSTATE_UINT64(f, TestStruct),
 
784
        VMSTATE_END_OF_LIST()
 
785
    }
 
786
};
 
787
 
 
788
static const VMStateDescription vmstate_tmp_child = {
 
789
    .name = "test/tmp_child",
 
790
    .pre_save = tmp_child_pre_save,
 
791
    .post_load = tmp_child_post_load,
 
792
    .fields = (VMStateField[]) {
 
793
        VMSTATE_INT64(diff, TmpTestStruct),
 
794
        VMSTATE_STRUCT_POINTER(parent, TmpTestStruct,
 
795
                               vmstate_tmp_back_to_parent, TestStruct),
 
796
        VMSTATE_END_OF_LIST()
 
797
    }
 
798
};
 
799
 
 
800
static const VMStateDescription vmstate_with_tmp = {
 
801
    .name = "test/with_tmp",
 
802
    .version_id = 1,
 
803
    .fields = (VMStateField[]) {
 
804
        VMSTATE_UINT32(a, TestStruct),
 
805
        VMSTATE_UINT64(d, TestStruct),
 
806
        VMSTATE_WITH_TMP(TestStruct, TmpTestStruct, vmstate_tmp_child),
 
807
        VMSTATE_END_OF_LIST()
 
808
    }
 
809
};
 
810
 
 
811
static void obj_tmp_copy(void *target, void *source)
 
812
{
 
813
    memcpy(target, source, sizeof(TestStruct));
 
814
}
 
815
 
 
816
static void test_tmp_struct(void)
 
817
{
 
818
    TestStruct obj, obj_clone;
 
819
 
 
820
    uint8_t const wire_with_tmp[] = {
 
821
        /* u32 a */ 0x00, 0x00, 0x00, 0x02,
 
822
        /* u64 d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
 
823
        /* diff  */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
 
824
        /* u64 f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
 
825
        QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
 
826
    };
 
827
 
 
828
    memset(&obj, 0, sizeof(obj));
 
829
    obj.a = 2;
 
830
    obj.b = 4;
 
831
    obj.d = 1;
 
832
    obj.f = 8;
 
833
    save_vmstate(&vmstate_with_tmp, &obj);
 
834
 
 
835
    compare_vmstate(wire_with_tmp, sizeof(wire_with_tmp));
 
836
 
 
837
    memset(&obj, 0, sizeof(obj));
 
838
    SUCCESS(load_vmstate(&vmstate_with_tmp, &obj, &obj_clone,
 
839
                         obj_tmp_copy, 1, wire_with_tmp,
 
840
                         sizeof(wire_with_tmp)));
 
841
    g_assert_cmpint(obj.a, ==, 2); /* From top level vmsd */
 
842
    g_assert_cmpint(obj.b, ==, 4); /* from the post_load */
 
843
    g_assert_cmpint(obj.d, ==, 1); /* From top level vmsd */
 
844
    g_assert_cmpint(obj.f, ==, 8); /* From the child->parent */
545
845
}
546
846
 
547
847
int main(int argc, char **argv)
562
862
                    test_arr_ptr_str_no0_save);
563
863
    g_test_add_func("/vmstate/array/ptr/str/no0/load",
564
864
                    test_arr_ptr_str_no0_load);
 
865
    g_test_add_func("/vmstate/array/ptr/str/0/save", test_arr_ptr_str_0_save);
 
866
    g_test_add_func("/vmstate/array/ptr/str/0/load",
 
867
                    test_arr_ptr_str_0_load);
 
868
    g_test_add_func("/vmstate/array/ptr/prim/0/save",
 
869
                    test_arr_ptr_prim_0_save);
 
870
    g_test_add_func("/vmstate/array/ptr/prim/0/load",
 
871
                    test_arr_ptr_prim_0_load);
 
872
    g_test_add_func("/vmstate/qtailq/save/saveq", test_save_q);
 
873
    g_test_add_func("/vmstate/qtailq/load/loadq", test_load_q);
 
874
    g_test_add_func("/vmstate/tmp_struct", test_tmp_struct);
565
875
    g_test_run();
566
876
 
567
877
    close(temp_fd);