1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2019, Joyent, Inc.
  14  */
  15 
  16 /*
  17  * Check that we properly handle structures and unions.
  18  */
  19 
  20 #include "check-common.h"
  21 
  22 static check_number_t check_bitfields[] = {
  23 #ifdef  TARGET_LP64
  24         { "unsigned long:1", CTF_K_INTEGER, 0, 0, 1 },
  25         { "unsigned long:2", CTF_K_INTEGER,  0, 0, 2 },
  26         { "unsigned long:4", CTF_K_INTEGER,  0, 0, 4 },
  27         { "unsigned long:5", CTF_K_INTEGER,  0, 0, 5 },
  28         { "unsigned long:8", CTF_K_INTEGER,  0, 0, 8 },
  29         { "unsigned long:16", CTF_K_INTEGER,  0, 0, 16 },
  30         { "unsigned long:19", CTF_K_INTEGER,  0, 0, 19 },
  31         { "unsigned long:32", CTF_K_INTEGER,  0, 0, 32 },
  32 #else
  33         { "unsigned long long:1", CTF_K_INTEGER, 0, 0, 1 },
  34         { "unsigned long long:2", CTF_K_INTEGER,  0, 0, 2 },
  35         { "unsigned long long:4", CTF_K_INTEGER,  0, 0, 4 },
  36         { "unsigned long long:5", CTF_K_INTEGER,  0, 0, 5 },
  37         { "unsigned long long:8", CTF_K_INTEGER,  0, 0, 8 },
  38         { "unsigned long long:16", CTF_K_INTEGER,  0, 0, 16 },
  39         { "unsigned long long:19", CTF_K_INTEGER,  0, 0, 19 },
  40         { "unsigned long long:32", CTF_K_INTEGER,  0, 0, 32 },
  41 #endif
  42         { "unsigned short:1", CTF_K_INTEGER, 0, 0, 1 },
  43         { "unsigned int:7", CTF_K_INTEGER, 0, 0, 7 },
  44         { "unsigned int:32", CTF_K_INTEGER, 0, 0, 32 },
  45         { "int:3", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 3 },
  46         { NULL }
  47 };
  48 
  49 static check_symbol_t check_syms[] = {
  50         { "foo", "struct foo" },
  51         { "head", "nlist_t" },
  52         { "forward", "const forward_t" },
  53         { "oot", "struct round_up" },
  54         { "botw", "struct fixed_up" },
  55         { "sophie", "struct mysterious_barrel" },
  56         { "ayesha", "struct dusk_barrel" },
  57         { "stats", "struct stats" },
  58         { "ring", "struct fellowship" },
  59         { "rings", "struct rings" },
  60         { "nvme", "struct csts" },
  61         { "games", "union jrpg" },
  62         { "nier", "union nier" },
  63         { "kh", "union kh" },
  64         { "ct", "struct trigger" },
  65         { "regress", "const union regress [9]" },
  66         { NULL }
  67 };
  68 
  69 static check_member_t check_member_foo[] = {
  70         { "a", "int", 0 },
  71         { "b", "float", 4 * NBBY },
  72         { "c", "const char *", 8 * NBBY },
  73         { NULL }
  74 };
  75 
  76 static check_member_t check_member_node[] = {
  77         { "prev", "struct node *", 0 },
  78 #ifdef  TARGET_LP64
  79         { "next", "struct node *", 8 * NBBY },
  80 #else
  81         { "next", "struct node *", 4 * NBBY },
  82 #endif
  83         { NULL }
  84 };
  85 
  86 static check_member_t check_member_nlist[] = {
  87         { "size", "size_t", 0 },
  88 #ifdef  TARGET_LP64
  89         { "off", "size_t", 8 * NBBY },
  90         { "head", "struct node", 16 * NBBY },
  91 #else
  92         { "off", "size_t", 4 * NBBY },
  93         { "head", "struct node", 8 * NBBY },
  94 #endif
  95         { NULL }
  96 };
  97 
  98 static check_member_t check_member_forward[] = {
  99         { "past", "void *", 0 },
 100 #ifdef  TARGET_LP64
 101         { "present", "void *", 8 * NBBY },
 102         { "future", "void *", 16 * NBBY },
 103 #else
 104         { "present", "void *", 4 * NBBY },
 105         { "future", "void *", 8 * NBBY },
 106 #endif
 107         { NULL }
 108 };
 109 
 110 static check_member_t check_member_round_up[] = {
 111         { "triforce", "uint8_t", 0 },
 112         { "link", "uint32_t", 4 * NBBY },
 113         { "zelda", "uint8_t", 8 * NBBY },
 114         { "ganon", "uint8_t", 9 * NBBY },
 115         { NULL }
 116 };
 117 
 118 static check_member_t check_member_fixed_up[] = {
 119         { "triforce", "uint8_t", 0 },
 120         { "link", "uint32_t", 1 * NBBY },
 121         { "zelda", "uint8_t", 5 * NBBY },
 122         { "ganon", "uint8_t", 6 * NBBY },
 123         { NULL }
 124 };
 125 
 126 #ifdef  TARGET_LP64
 127 static check_member_t check_member_component[] = {
 128         { "m", "enum material", 0 },
 129         { "grade", "uint64_t", 8 * NBBY },
 130         { "count", "uint64_t", 16 * NBBY },
 131         { "locations", "const char *[4]", 24 * NBBY },
 132         { NULL }
 133 };
 134 
 135 static check_member_t check_member_mysterious[] = {
 136         { "name", "const char *", 0 },
 137         { "capacity", "size_t", 8 * NBBY },
 138         { "optional", "struct component [0]", 16 * NBBY },
 139         { NULL }
 140 };
 141 
 142 static check_member_t check_member_dusk[] = {
 143         { "name", "const char *", 0 },
 144         { "opacity", "size_t", 8 * NBBY },
 145         { "optional", "struct component [0]", 16 * NBBY },
 146         { NULL }
 147 };
 148 
 149 
 150 static check_member_t check_member_stats[] = {
 151         { "hp", "unsigned long:16", 0 },
 152         { "mp", "unsigned long:16", 16 },
 153         { "str", "unsigned long:8", 32 },
 154         { "dex", "unsigned long:4", 40 },
 155         { "con", "unsigned long:1", 44 },
 156         { "inte", "unsigned long:2", 45 },
 157         { "wis", "unsigned long:1", 47 },
 158         { "cha", "unsigned long:4", 48 },
 159         { "sanity", "unsigned long:1", 52 },
 160         { "attack", "unsigned long:2", 53 },
 161         { "mattack", "unsigned long:1", 55 },
 162         { "defense", "unsigned long:8", 56 },
 163         { "mdefense", "unsigned long:32", 64 },
 164         { "evasion", "unsigned long:8", 96 },
 165         { "crit", "unsigned long:5", 104 },
 166         { "luck", "unsigned long:19", 109 },
 167         { NULL }
 168 };
 169 #else
 170 static check_member_t check_member_component[] = {
 171         { "m", "enum material", 0 },
 172         { "grade", "uint64_t", 4 * NBBY },
 173         { "count", "uint64_t", 12 * NBBY },
 174         { "locations", "const char *[4]", 20 * NBBY },
 175         { NULL }
 176 };
 177 
 178 static check_member_t check_member_mysterious[] = {
 179         { "name", "const char *", 0 },
 180         { "capacity", "size_t", 4 * NBBY },
 181         { "optional", "struct component [0]", 8 * NBBY },
 182         { NULL }
 183 };
 184 
 185 static check_member_t check_member_dusk[] = {
 186         { "name", "const char *", 0 },
 187         { "opacity", "size_t", 4 * NBBY },
 188         { "optional", "struct component [0]", 8 * NBBY },
 189         { NULL }
 190 };
 191 
 192 
 193 static check_member_t check_member_stats[] = {
 194         { "hp", "unsigned long long:16", 0 },
 195         { "mp", "unsigned long long:16", 16 },
 196         { "str", "unsigned long long:8", 32 },
 197         { "dex", "unsigned long long:4", 40 },
 198         { "con", "unsigned long long:1", 44 },
 199         { "inte", "unsigned long long:2", 45 },
 200         { "wis", "unsigned long long:1", 47 },
 201         { "cha", "unsigned long long:4", 48 },
 202         { "sanity", "unsigned long long:1", 52 },
 203         { "attack", "unsigned long long:2", 53 },
 204         { "mattack", "unsigned long long:1", 55 },
 205         { "defense", "unsigned long long:8", 56 },
 206         { "mdefense", "unsigned long long:32", 64 },
 207         { "evasion", "unsigned long long:8", 96 },
 208         { "crit", "unsigned long long:5", 104 },
 209         { "luck", "unsigned long long:19", 109 },
 210         { NULL }
 211 };
 212 #endif
 213 
 214 static check_member_t check_member_fellowship[] = {
 215         { "frodo", "unsigned short:1", 0 },
 216         { "sam", "unsigned short:1", 1 },
 217         { "merry", "unsigned short:1", 2 },
 218         { "pippin", "unsigned short:1", 3 },
 219         { "aragorn", "unsigned short:1", 4 },
 220         { "boromir", "unsigned short:1", 5 },
 221         { "legolas", "unsigned short:1", 6 },
 222         { "gimli", "unsigned short:1", 7 },
 223         { "gandalf", "unsigned short:1", 8 },
 224         { NULL }
 225 };
 226 
 227 static check_member_t check_member_rings[] = {
 228         { "elves", "unsigned int:3", 0 },
 229         { "dwarves", "unsigned int:7", 3 },
 230         { "men", "unsigned int:9", 10 },
 231         { "one", "uint8_t", 3 * NBBY },
 232         { "silmarils", "uint8_t [3]", 4 * NBBY },
 233         { NULL }
 234 };
 235 
 236 static check_member_t check_member_csts[] = {
 237         { "rdy", "unsigned int:7", 0 },
 238         { "csts", "unsigned int:32", 7 },
 239         { NULL }
 240 };
 241 
 242 static check_member_t check_member_jrpg[] = {
 243         { "ff", "int", 0 },
 244         { "atelier", "double [4]", 0 },
 245         { "tales", "const char *", 0 },
 246         { "chrono", "int (*)()", 0 },
 247         { "xeno", "struct rings", 0 },
 248         { NULL }
 249 };
 250 
 251 static check_member_t check_member_android[] = {
 252         { "_2b", "unsigned int:16", 0 },
 253         { "_9s", "unsigned int:16", 16 },
 254         { NULL }
 255 };
 256 
 257 static check_member_t check_member_nier[] = {
 258         { "automata", "uint32_t", 0 },
 259         { "android", "struct android", 0 },
 260         { NULL }
 261 };
 262 
 263 static check_member_t check_member_kh[] = {
 264         { "sora", "int:3", 0 },
 265         { "riku", "char:7", 0 },
 266         { "kairi", "double", 0 },
 267         { "namine", "complex double", 0 },
 268         { NULL }
 269 };
 270 
 271 static check_member_t check_member_trigger[] = {
 272         { "chrono", "uint8_t", 0 },
 273         { "cross", "uint8_t", 8 },
 274         /*
 275          * This test has an anonymous union. Unfortunately, there's not a great
 276          * way to distinguish between various anonymous unions in this form.
 277          */
 278 #ifdef  TARGET_LP64
 279         { "", "union ", 64 },
 280 #else
 281         { "", "union ", 32 },
 282 #endif
 283         { NULL }
 284 };
 285 
 286 static check_member_t check_member_regress[] = {
 287         { "i", "unsigned int [3]", 0 },
 288         { "e", "long double", 0 },
 289         { NULL }
 290 };
 291 
 292 static check_member_test_t members[] = {
 293 #ifdef  TARGET_LP64
 294         { "struct foo", CTF_K_STRUCT, 16, check_member_foo },
 295         { "struct node", CTF_K_STRUCT, 16, check_member_node },
 296         { "struct nlist", CTF_K_STRUCT, 32, check_member_nlist },
 297         { "struct forward", CTF_K_STRUCT, 24, check_member_forward },
 298 #else
 299         { "struct foo", CTF_K_STRUCT, 12, check_member_foo },
 300         { "struct node", CTF_K_STRUCT, 8, check_member_node },
 301         { "struct nlist", CTF_K_STRUCT, 16, check_member_nlist },
 302         { "struct forward", CTF_K_STRUCT, 12, check_member_forward },
 303 #endif
 304         { "struct round_up", CTF_K_STRUCT, 12, check_member_round_up },
 305         { "struct fixed_up", CTF_K_STRUCT, 7, check_member_fixed_up },
 306 #ifdef  TARGET_LP64
 307         { "struct component", CTF_K_STRUCT, 56, check_member_component },
 308         { "struct mysterious_barrel", CTF_K_STRUCT, 16,
 309             check_member_mysterious },
 310         { "struct dusk_barrel", CTF_K_STRUCT, 16, check_member_dusk },
 311 #else
 312         { "struct component", CTF_K_STRUCT, 36, check_member_component },
 313         { "struct mysterious_barrel", CTF_K_STRUCT, 8,
 314             check_member_mysterious },
 315         { "struct dusk_barrel", CTF_K_STRUCT, 8, check_member_dusk },
 316 #endif
 317         { "struct stats", CTF_K_STRUCT, 16, check_member_stats },
 318         { "struct fellowship", CTF_K_STRUCT, 2, check_member_fellowship },
 319         { "struct rings", CTF_K_STRUCT, 8, check_member_rings },
 320         { "struct csts", CTF_K_STRUCT, 5, check_member_csts },
 321         { "union jrpg", CTF_K_UNION, 32, check_member_jrpg },
 322         { "struct android", CTF_K_STRUCT, 4, check_member_android },
 323         { "union nier", CTF_K_UNION, 4, check_member_nier },
 324         { "union kh", CTF_K_UNION, 16, check_member_kh },
 325 #ifdef  TARGET_LP64
 326         { "struct trigger", CTF_K_STRUCT, 32, check_member_trigger },
 327         { "union regress", CTF_K_UNION, 16, check_member_regress },
 328 #else
 329         { "struct trigger", CTF_K_STRUCT, 28, check_member_trigger },
 330         { "union regress", CTF_K_UNION, 12, check_member_regress },
 331 #endif
 332         { NULL }
 333 };
 334 
 335 static check_descent_t check_descent_head[] = {
 336         { "nlist_t", CTF_K_TYPEDEF },
 337         { "struct nlist", CTF_K_STRUCT },
 338         { NULL }
 339 };
 340 
 341 static check_descent_t check_descent_forward[] = {
 342         { "const forward_t", CTF_K_CONST },
 343         { "forward_t", CTF_K_TYPEDEF },
 344         { "struct forward", CTF_K_STRUCT },
 345         { NULL }
 346 };
 347 
 348 static check_descent_t check_descent_regress[] = {
 349         { "const union regress [9]", CTF_K_CONST },
 350         { "union regress [9]", CTF_K_ARRAY, "union regress", 9 },
 351         { "union regress", CTF_K_UNION },
 352         { NULL }
 353 };
 354 
 355 static check_descent_test_t descents[] = {
 356         { "head", check_descent_head },
 357         { "forward", check_descent_forward },
 358         { "regress", check_descent_regress },
 359         { NULL }
 360 };
 361 
 362 int
 363 main(int argc, char *argv[])
 364 {
 365         int i, ret = 0;
 366 
 367         if (argc < 2) {
 368                 errx(EXIT_FAILURE, "missing test files");
 369         }
 370 
 371         for (i = 1; i < argc; i++) {
 372                 ctf_file_t *fp;
 373                 uint_t j;
 374 
 375                 if ((fp = ctf_open(argv[i], &ret)) == NULL) {
 376                         warnx("failed to open %s: %s", argv[i],
 377                             ctf_errmsg(ret));
 378                         ret = EXIT_FAILURE;
 379                         continue;
 380                 }
 381 
 382                 if (!ctftest_check_numbers(fp, check_bitfields))
 383                         ret = EXIT_FAILURE;
 384                 if (!ctftest_check_symbols(fp, check_syms))
 385                         ret = EXIT_FAILURE;
 386                 for (j = 0; descents[j].cdt_sym != NULL; j++) {
 387                         if (!ctftest_check_descent(descents[j].cdt_sym, fp,
 388                             descents[j].cdt_tests)) {
 389                                 ret = EXIT_FAILURE;
 390                         }
 391                 }
 392 
 393                 for (j = 0; members[j].cmt_type != NULL; j++) {
 394                         if (!ctftest_check_members(members[j].cmt_type, fp,
 395                             members[j].cmt_kind, members[j].cmt_size,
 396                             members[j].cmt_members)) {
 397                                 ret = EXIT_FAILURE;
 398                         }
 399                 }
 400 
 401                 ctf_close(fp);
 402         }
 403 
 404         return (ret);
 405 }