/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2019, Joyent, Inc. */ /* * Check that we properly handle structures and unions. */ #include "check-common.h" static check_number_t check_bitfields[] = { #ifdef TARGET_LP64 { "unsigned long:1", CTF_K_INTEGER, 0, 0, 1 }, { "unsigned long:2", CTF_K_INTEGER, 0, 0, 2 }, { "unsigned long:4", CTF_K_INTEGER, 0, 0, 4 }, { "unsigned long:5", CTF_K_INTEGER, 0, 0, 5 }, { "unsigned long:8", CTF_K_INTEGER, 0, 0, 8 }, { "unsigned long:16", CTF_K_INTEGER, 0, 0, 16 }, { "unsigned long:19", CTF_K_INTEGER, 0, 0, 19 }, { "unsigned long:32", CTF_K_INTEGER, 0, 0, 32 }, #else { "unsigned long long:1", CTF_K_INTEGER, 0, 0, 1 }, { "unsigned long long:2", CTF_K_INTEGER, 0, 0, 2 }, { "unsigned long long:4", CTF_K_INTEGER, 0, 0, 4 }, { "unsigned long long:5", CTF_K_INTEGER, 0, 0, 5 }, { "unsigned long long:8", CTF_K_INTEGER, 0, 0, 8 }, { "unsigned long long:16", CTF_K_INTEGER, 0, 0, 16 }, { "unsigned long long:19", CTF_K_INTEGER, 0, 0, 19 }, { "unsigned long long:32", CTF_K_INTEGER, 0, 0, 32 }, #endif { "unsigned short:1", CTF_K_INTEGER, 0, 0, 1 }, { "unsigned int:7", CTF_K_INTEGER, 0, 0, 7 }, { "unsigned int:32", CTF_K_INTEGER, 0, 0, 32 }, { "int:3", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 3 }, { NULL } }; static check_symbol_t check_syms[] = { { "foo", "struct foo" }, { "head", "nlist_t" }, { "forward", "const forward_t" }, { "oot", "struct round_up" }, { "botw", "struct fixed_up" }, { "sophie", "struct mysterious_barrel" }, { "ayesha", "struct dusk_barrel" }, { "stats", "struct stats" }, { "ring", "struct fellowship" }, { "rings", "struct rings" }, { "nvme", "struct csts" }, { "games", "union jrpg" }, { "nier", "union nier" }, { "kh", "union kh" }, { "ct", "struct trigger" }, { "regress", "const union regress [9]" }, { NULL } }; static check_member_t check_member_foo[] = { { "a", "int", 0 }, { "b", "float", 4 * NBBY }, { "c", "const char *", 8 * NBBY }, { NULL } }; static check_member_t check_member_node[] = { { "prev", "struct node *", 0 }, #ifdef TARGET_LP64 { "next", "struct node *", 8 * NBBY }, #else { "next", "struct node *", 4 * NBBY }, #endif { NULL } }; static check_member_t check_member_nlist[] = { { "size", "size_t", 0 }, #ifdef TARGET_LP64 { "off", "size_t", 8 * NBBY }, { "head", "struct node", 16 * NBBY }, #else { "off", "size_t", 4 * NBBY }, { "head", "struct node", 8 * NBBY }, #endif { NULL } }; static check_member_t check_member_forward[] = { { "past", "void *", 0 }, #ifdef TARGET_LP64 { "present", "void *", 8 * NBBY }, { "future", "void *", 16 * NBBY }, #else { "present", "void *", 4 * NBBY }, { "future", "void *", 8 * NBBY }, #endif { NULL } }; static check_member_t check_member_round_up[] = { { "triforce", "uint8_t", 0 }, { "link", "uint32_t", 4 * NBBY }, { "zelda", "uint8_t", 8 * NBBY }, { "ganon", "uint8_t", 9 * NBBY }, { NULL } }; static check_member_t check_member_fixed_up[] = { { "triforce", "uint8_t", 0 }, { "link", "uint32_t", 1 * NBBY }, { "zelda", "uint8_t", 5 * NBBY }, { "ganon", "uint8_t", 6 * NBBY }, { NULL } }; #ifdef TARGET_LP64 static check_member_t check_member_component[] = { { "m", "enum material", 0 }, { "grade", "uint64_t", 8 * NBBY }, { "count", "uint64_t", 16 * NBBY }, { "locations", "const char *[4]", 24 * NBBY }, { NULL } }; static check_member_t check_member_mysterious[] = { { "name", "const char *", 0 }, { "capacity", "size_t", 8 * NBBY }, { "optional", "struct component [0]", 16 * NBBY }, { NULL } }; static check_member_t check_member_dusk[] = { { "name", "const char *", 0 }, { "opacity", "size_t", 8 * NBBY }, { "optional", "struct component [0]", 16 * NBBY }, { NULL } }; static check_member_t check_member_stats[] = { { "hp", "unsigned long:16", 0 }, { "mp", "unsigned long:16", 16 }, { "str", "unsigned long:8", 32 }, { "dex", "unsigned long:4", 40 }, { "con", "unsigned long:1", 44 }, { "inte", "unsigned long:2", 45 }, { "wis", "unsigned long:1", 47 }, { "cha", "unsigned long:4", 48 }, { "sanity", "unsigned long:1", 52 }, { "attack", "unsigned long:2", 53 }, { "mattack", "unsigned long:1", 55 }, { "defense", "unsigned long:8", 56 }, { "mdefense", "unsigned long:32", 64 }, { "evasion", "unsigned long:8", 96 }, { "crit", "unsigned long:5", 104 }, { "luck", "unsigned long:19", 109 }, { NULL } }; #else static check_member_t check_member_component[] = { { "m", "enum material", 0 }, { "grade", "uint64_t", 4 * NBBY }, { "count", "uint64_t", 12 * NBBY }, { "locations", "const char *[4]", 20 * NBBY }, { NULL } }; static check_member_t check_member_mysterious[] = { { "name", "const char *", 0 }, { "capacity", "size_t", 4 * NBBY }, { "optional", "struct component [0]", 8 * NBBY }, { NULL } }; static check_member_t check_member_dusk[] = { { "name", "const char *", 0 }, { "opacity", "size_t", 4 * NBBY }, { "optional", "struct component [0]", 8 * NBBY }, { NULL } }; static check_member_t check_member_stats[] = { { "hp", "unsigned long long:16", 0 }, { "mp", "unsigned long long:16", 16 }, { "str", "unsigned long long:8", 32 }, { "dex", "unsigned long long:4", 40 }, { "con", "unsigned long long:1", 44 }, { "inte", "unsigned long long:2", 45 }, { "wis", "unsigned long long:1", 47 }, { "cha", "unsigned long long:4", 48 }, { "sanity", "unsigned long long:1", 52 }, { "attack", "unsigned long long:2", 53 }, { "mattack", "unsigned long long:1", 55 }, { "defense", "unsigned long long:8", 56 }, { "mdefense", "unsigned long long:32", 64 }, { "evasion", "unsigned long long:8", 96 }, { "crit", "unsigned long long:5", 104 }, { "luck", "unsigned long long:19", 109 }, { NULL } }; #endif static check_member_t check_member_fellowship[] = { { "frodo", "unsigned short:1", 0 }, { "sam", "unsigned short:1", 1 }, { "merry", "unsigned short:1", 2 }, { "pippin", "unsigned short:1", 3 }, { "aragorn", "unsigned short:1", 4 }, { "boromir", "unsigned short:1", 5 }, { "legolas", "unsigned short:1", 6 }, { "gimli", "unsigned short:1", 7 }, { "gandalf", "unsigned short:1", 8 }, { NULL } }; static check_member_t check_member_rings[] = { { "elves", "unsigned int:3", 0 }, { "dwarves", "unsigned int:7", 3 }, { "men", "unsigned int:9", 10 }, { "one", "uint8_t", 3 * NBBY }, { "silmarils", "uint8_t [3]", 4 * NBBY }, { NULL } }; static check_member_t check_member_csts[] = { { "rdy", "unsigned int:7", 0 }, { "csts", "unsigned int:32", 7 }, { NULL } }; static check_member_t check_member_jrpg[] = { { "ff", "int", 0 }, { "atelier", "double [4]", 0 }, { "tales", "const char *", 0 }, { "chrono", "int (*)()", 0 }, { "xeno", "struct rings", 0 }, { NULL } }; static check_member_t check_member_android[] = { { "_2b", "unsigned int:16", 0 }, { "_9s", "unsigned int:16", 16 }, { NULL } }; static check_member_t check_member_nier[] = { { "automata", "uint32_t", 0 }, { "android", "struct android", 0 }, { NULL } }; static check_member_t check_member_kh[] = { { "sora", "int:3", 0 }, { "riku", "char:7", 0 }, { "kairi", "double", 0 }, { "namine", "complex double", 0 }, { NULL } }; static check_member_t check_member_trigger[] = { { "chrono", "uint8_t", 0 }, { "cross", "uint8_t", 8 }, /* * This test has an anonymous union. Unfortunately, there's not a great * way to distinguish between various anonymous unions in this form. */ #ifdef TARGET_LP64 { "", "union ", 64 }, #else { "", "union ", 32 }, #endif { NULL } }; static check_member_t check_member_regress[] = { { "i", "unsigned int [3]", 0 }, { "e", "long double", 0 }, { NULL } }; static check_member_test_t members[] = { #ifdef TARGET_LP64 { "struct foo", CTF_K_STRUCT, 16, check_member_foo }, { "struct node", CTF_K_STRUCT, 16, check_member_node }, { "struct nlist", CTF_K_STRUCT, 32, check_member_nlist }, { "struct forward", CTF_K_STRUCT, 24, check_member_forward }, #else { "struct foo", CTF_K_STRUCT, 12, check_member_foo }, { "struct node", CTF_K_STRUCT, 8, check_member_node }, { "struct nlist", CTF_K_STRUCT, 16, check_member_nlist }, { "struct forward", CTF_K_STRUCT, 12, check_member_forward }, #endif { "struct round_up", CTF_K_STRUCT, 12, check_member_round_up }, { "struct fixed_up", CTF_K_STRUCT, 7, check_member_fixed_up }, #ifdef TARGET_LP64 { "struct component", CTF_K_STRUCT, 56, check_member_component }, { "struct mysterious_barrel", CTF_K_STRUCT, 16, check_member_mysterious }, { "struct dusk_barrel", CTF_K_STRUCT, 16, check_member_dusk }, #else { "struct component", CTF_K_STRUCT, 36, check_member_component }, { "struct mysterious_barrel", CTF_K_STRUCT, 8, check_member_mysterious }, { "struct dusk_barrel", CTF_K_STRUCT, 8, check_member_dusk }, #endif { "struct stats", CTF_K_STRUCT, 16, check_member_stats }, { "struct fellowship", CTF_K_STRUCT, 2, check_member_fellowship }, { "struct rings", CTF_K_STRUCT, 8, check_member_rings }, { "struct csts", CTF_K_STRUCT, 5, check_member_csts }, { "union jrpg", CTF_K_UNION, 32, check_member_jrpg }, { "struct android", CTF_K_STRUCT, 4, check_member_android }, { "union nier", CTF_K_UNION, 4, check_member_nier }, { "union kh", CTF_K_UNION, 16, check_member_kh }, #ifdef TARGET_LP64 { "struct trigger", CTF_K_STRUCT, 32, check_member_trigger }, { "union regress", CTF_K_UNION, 16, check_member_regress }, #else { "struct trigger", CTF_K_STRUCT, 28, check_member_trigger }, { "union regress", CTF_K_UNION, 12, check_member_regress }, #endif { NULL } }; static check_descent_t check_descent_head[] = { { "nlist_t", CTF_K_TYPEDEF }, { "struct nlist", CTF_K_STRUCT }, { NULL } }; static check_descent_t check_descent_forward[] = { { "const forward_t", CTF_K_CONST }, { "forward_t", CTF_K_TYPEDEF }, { "struct forward", CTF_K_STRUCT }, { NULL } }; static check_descent_test_t descents[] = { { "head", check_descent_head }, { "forward", check_descent_forward }, { NULL } }; static check_descent_t check_descent_regress_gcc4[] = { { "const union regress [9]", CTF_K_CONST }, { "union regress [9]", CTF_K_ARRAY, "union regress", 9 }, { "union regress", CTF_K_UNION }, { NULL } }; static check_descent_t check_descent_regress_gcc7[] = { { "const union regress [9]", CTF_K_ARRAY, "const union regress", 9 }, { "const union regress", CTF_K_CONST }, { "union regress", CTF_K_UNION }, { NULL } }; /* * See needed_array_qualifier(): applying this fix means the qualifier order is * different between GCC versions. Accept either form. */ static check_descent_test_t alt_descents[] = { { "regress", check_descent_regress_gcc4 }, { "regress", check_descent_regress_gcc7 }, { NULL } }; int main(int argc, char *argv[]) { int i, ret = 0; if (argc < 2) { errx(EXIT_FAILURE, "missing test files"); } for (i = 1; i < argc; i++) { ctf_file_t *fp; int alt_ok = 0; uint_t j; if ((fp = ctf_open(argv[i], &ret)) == NULL) { warnx("failed to open %s: %s", argv[i], ctf_errmsg(ret)); ret = EXIT_FAILURE; continue; } if (!ctftest_check_numbers(fp, check_bitfields)) ret = EXIT_FAILURE; if (!ctftest_check_symbols(fp, check_syms)) ret = EXIT_FAILURE; for (j = 0; descents[j].cdt_sym != NULL; j++) { if (!ctftest_check_descent(descents[j].cdt_sym, fp, descents[j].cdt_tests, B_FALSE)) { ret = EXIT_FAILURE; } } for (j = 0; alt_descents[j].cdt_sym != NULL; j++) { if (ctftest_check_descent(alt_descents[j].cdt_sym, fp, alt_descents[j].cdt_tests, B_TRUE)) { alt_ok = 1; break; } } if (!alt_ok) { warnx("all descents failed for %s", alt_descents[0].cdt_sym); ret = EXIT_FAILURE; } for (j = 0; members[j].cmt_type != NULL; j++) { if (!ctftest_check_members(members[j].cmt_type, fp, members[j].cmt_kind, members[j].cmt_size, members[j].cmt_members)) { ret = EXIT_FAILURE; } } ctf_close(fp); } return (ret); }