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 2019, Joyent, Inc. 14 * Copyright 2025 Oxide Computer Company 15 */ 16 17 /* 18 * Check that we properly handle structures and unions. 19 */ 20 21 #include "check-common.h" 22 23 static check_number_t check_bitfields[] = { 24 #ifdef TARGET_LP64 25 { "unsigned long:1", CTF_K_INTEGER, 0, 0, 1 }, 26 { "unsigned long:2", CTF_K_INTEGER, 0, 0, 2 }, 27 { "unsigned long:4", CTF_K_INTEGER, 0, 0, 4 }, 28 { "unsigned long:5", CTF_K_INTEGER, 0, 0, 5 }, 29 { "unsigned long:8", CTF_K_INTEGER, 0, 0, 8 }, 30 { "unsigned long:16", CTF_K_INTEGER, 0, 0, 16 }, 31 { "unsigned long:19", CTF_K_INTEGER, 0, 0, 19 }, 32 { "unsigned long:32", CTF_K_INTEGER, 0, 0, 32 }, 33 #else 34 { "unsigned long long:1", CTF_K_INTEGER, 0, 0, 1 }, 35 { "unsigned long long:2", CTF_K_INTEGER, 0, 0, 2 }, 36 { "unsigned long long:4", CTF_K_INTEGER, 0, 0, 4 }, 37 { "unsigned long long:5", CTF_K_INTEGER, 0, 0, 5 }, 38 { "unsigned long long:8", CTF_K_INTEGER, 0, 0, 8 }, 39 { "unsigned long long:16", CTF_K_INTEGER, 0, 0, 16 }, 40 { "unsigned long long:19", CTF_K_INTEGER, 0, 0, 19 }, 41 { "unsigned long long:32", CTF_K_INTEGER, 0, 0, 32 }, 42 #endif 43 { "unsigned short:1", CTF_K_INTEGER, 0, 0, 1 }, 44 { "unsigned int:7", CTF_K_INTEGER, 0, 0, 7 }, 45 /* 46 * Skipped on clang as it doesn't process csts correctly. See 47 * check_members_csts. 48 */ 49 { "unsigned int:32", CTF_K_INTEGER, 0, 0, 32, SKIP_CLANG }, 50 { "int:3", CTF_K_INTEGER, CTF_INT_SIGNED, 0, 3 }, 51 { NULL } 52 }; 53 54 static check_symbol_t check_syms[] = { 55 { "foo", "struct foo" }, 56 { "head", "nlist_t" }, 57 { "forward", "const forward_t" }, 58 { "oot", "struct round_up" }, 59 { "botw", "struct fixed_up" }, 60 { "sophie", "struct mysterious_barrel" }, 61 { "ayesha", "struct dusk_barrel" }, 62 { "stats", "struct stats" }, 63 { "ring", "struct fellowship" }, 64 { "rings", "struct rings" }, 65 { "nvme", "struct csts" }, 66 { "games", "union jrpg" }, 67 { "nier", "union nier" }, 68 { "kh", "union kh" }, 69 { "ct", "struct trigger" }, 70 { "regress", "const union regress [9]" }, 71 { NULL } 72 }; 73 74 static check_member_t check_member_foo[] = { 75 { "a", "int", 0 }, 76 { "b", "float", 4 * NBBY }, 77 { "c", "const char *", 8 * NBBY }, 78 { NULL } 79 }; 80 81 static check_member_t check_member_node[] = { 82 { "prev", "struct node *", 0 }, 83 #ifdef TARGET_LP64 84 { "next", "struct node *", 8 * NBBY }, 85 #else 86 { "next", "struct node *", 4 * NBBY }, 87 #endif 88 { NULL } 89 }; 90 91 static check_member_t check_member_nlist[] = { 92 { "size", "size_t", 0 }, 93 #ifdef TARGET_LP64 94 { "off", "size_t", 8 * NBBY }, 95 { "head", "struct node", 16 * NBBY }, 96 #else 97 { "off", "size_t", 4 * NBBY }, 98 { "head", "struct node", 8 * NBBY }, 99 #endif 100 { NULL } 101 }; 102 103 static check_member_t check_member_forward[] = { 104 { "past", "void *", 0 }, 105 #ifdef TARGET_LP64 106 { "present", "void *", 8 * NBBY }, 107 { "future", "void *", 16 * NBBY }, 108 #else 109 { "present", "void *", 4 * NBBY }, 110 { "future", "void *", 8 * NBBY }, 111 #endif 112 { NULL } 113 }; 114 115 static check_member_t check_member_round_up[] = { 116 { "triforce", "uint8_t", 0 }, 117 { "link", "uint32_t", 4 * NBBY }, 118 { "zelda", "uint8_t", 8 * NBBY }, 119 { "ganon", "uint8_t", 9 * NBBY }, 120 { NULL } 121 }; 122 123 static check_member_t check_member_fixed_up[] = { 124 { "triforce", "uint8_t", 0 }, 125 { "link", "uint32_t", 1 * NBBY }, 126 { "zelda", "uint8_t", 5 * NBBY }, 127 { "ganon", "uint8_t", 6 * NBBY }, 128 { NULL } 129 }; 130 131 #ifdef TARGET_LP64 132 static check_member_t check_member_component[] = { 133 { "m", "enum material", 0 }, 134 { "grade", "uint64_t", 8 * NBBY }, 135 { "count", "uint64_t", 16 * NBBY }, 136 { "locations", "const char *[4]", 24 * NBBY }, 137 { NULL } 138 }; 139 140 static check_member_t check_member_mysterious[] = { 141 { "name", "const char *", 0 }, 142 { "capacity", "size_t", 8 * NBBY }, 143 { "optional", "struct component [0]", 16 * NBBY }, 144 { NULL } 145 }; 146 147 static check_member_t check_member_dusk[] = { 148 { "name", "const char *", 0 }, 149 { "opacity", "size_t", 8 * NBBY }, 150 { "optional", "struct component [0]", 16 * NBBY }, 151 { NULL } 152 }; 153 154 155 static check_member_t check_member_stats[] = { 156 { "hp", "unsigned long:16", 0 }, 157 { "mp", "unsigned long:16", 16 }, 158 { "str", "unsigned long:8", 32 }, 159 { "dex", "unsigned long:4", 40 }, 160 { "con", "unsigned long:1", 44 }, 161 { "inte", "unsigned long:2", 45 }, 162 { "wis", "unsigned long:1", 47 }, 163 { "cha", "unsigned long:4", 48 }, 164 { "sanity", "unsigned long:1", 52 }, 165 { "attack", "unsigned long:2", 53 }, 166 { "mattack", "unsigned long:1", 55 }, 167 { "defense", "unsigned long:8", 56 }, 168 { "mdefense", "unsigned long:32", 64 }, 169 { "evasion", "unsigned long:8", 96 }, 170 { "crit", "unsigned long:5", 104 }, 171 { "luck", "unsigned long:19", 109 }, 172 { NULL } 173 }; 174 #else 175 static check_member_t check_member_component[] = { 176 { "m", "enum material", 0 }, 177 { "grade", "uint64_t", 4 * NBBY }, 178 { "count", "uint64_t", 12 * NBBY }, 179 { "locations", "const char *[4]", 20 * NBBY }, 180 { NULL } 181 }; 182 183 static check_member_t check_member_mysterious[] = { 184 { "name", "const char *", 0 }, 185 { "capacity", "size_t", 4 * NBBY }, 186 { "optional", "struct component [0]", 8 * NBBY }, 187 { NULL } 188 }; 189 190 static check_member_t check_member_dusk[] = { 191 { "name", "const char *", 0 }, 192 { "opacity", "size_t", 4 * NBBY }, 193 { "optional", "struct component [0]", 8 * NBBY }, 194 { NULL } 195 }; 196 197 198 static check_member_t check_member_stats[] = { 199 { "hp", "unsigned long long:16", 0 }, 200 { "mp", "unsigned long long:16", 16 }, 201 { "str", "unsigned long long:8", 32 }, 202 { "dex", "unsigned long long:4", 40 }, 203 { "con", "unsigned long long:1", 44 }, 204 { "inte", "unsigned long long:2", 45 }, 205 { "wis", "unsigned long long:1", 47 }, 206 { "cha", "unsigned long long:4", 48 }, 207 { "sanity", "unsigned long long:1", 52 }, 208 { "attack", "unsigned long long:2", 53 }, 209 { "mattack", "unsigned long long:1", 55 }, 210 { "defense", "unsigned long long:8", 56 }, 211 { "mdefense", "unsigned long long:32", 64 }, 212 { "evasion", "unsigned long long:8", 96 }, 213 { "crit", "unsigned long long:5", 104 }, 214 { "luck", "unsigned long long:19", 109 }, 215 { NULL } 216 }; 217 #endif 218 219 static check_member_t check_member_fellowship[] = { 220 { "frodo", "unsigned short:1", 0 }, 221 { "sam", "unsigned short:1", 1 }, 222 { "merry", "unsigned short:1", 2 }, 223 { "pippin", "unsigned short:1", 3 }, 224 { "aragorn", "unsigned short:1", 4 }, 225 { "boromir", "unsigned short:1", 5 }, 226 { "legolas", "unsigned short:1", 6 }, 227 { "gimli", "unsigned short:1", 7 }, 228 { "gandalf", "unsigned short:1", 8 }, 229 { NULL } 230 }; 231 232 static check_member_t check_member_rings[] = { 233 { "elves", "unsigned int:3", 0 }, 234 { "dwarves", "unsigned int:7", 3 }, 235 { "men", "unsigned int:9", 10 }, 236 { "one", "uint8_t", 3 * NBBY }, 237 { "silmarils", "uint8_t [3]", 4 * NBBY }, 238 { NULL } 239 }; 240 241 /* 242 * Unfortunately this test case fails with clang in at least versions 8-10. See 243 * https://bugs.llvm.org/show_bug.cgi?id=44601 for more information on the bug. 244 */ 245 static check_member_t check_member_csts[] = { 246 { "rdy", "unsigned int:7", 0 }, 247 { "csts", "unsigned int:32", 7 }, 248 { NULL } 249 }; 250 251 static check_member_t check_member_jrpg[] = { 252 { "ff", "int", 0 }, 253 { "atelier", "double [4]", 0 }, 254 { "tales", "const char *", 0 }, 255 { "chrono", "int (*)()", 0 }, 256 { "xeno", "struct rings", 0 }, 257 { NULL } 258 }; 259 260 static check_member_t check_member_android[] = { 261 { "_2b", "unsigned int:16", 0 }, 262 { "_9s", "unsigned int:16", 16 }, 263 { NULL } 264 }; 265 266 static check_member_t check_member_nier[] = { 267 { "automata", "uint32_t", 0 }, 268 { "android", "struct android", 0 }, 269 { NULL } 270 }; 271 272 static check_member_t check_member_kh[] = { 273 { "sora", "int:3", 0 }, 274 { "riku", "char:7", 0 }, 275 { "kairi", "double", 0 }, 276 { "namine", "complex double", 0 }, 277 { NULL } 278 }; 279 280 static check_member_t check_member_trigger[] = { 281 { "chrono", "uint8_t", 0 }, 282 { "cross", "uint8_t", 8 }, 283 /* 284 * This test has an anonymous union. Unfortunately, there's not a great 285 * way to distinguish between various anonymous unions in this form. 286 */ 287 #ifdef TARGET_LP64 288 { "", "union ", 64 }, 289 #else 290 { "", "union ", 32 }, 291 #endif 292 { NULL } 293 }; 294 295 static check_member_t check_member_regress[] = { 296 { "i", "unsigned int [3]", 0 }, 297 { "e", "long double", 0 }, 298 { NULL } 299 }; 300 301 static check_member_test_t members[] = { 302 #ifdef TARGET_LP64 303 { "struct foo", CTF_K_STRUCT, 16, check_member_foo }, 304 { "struct node", CTF_K_STRUCT, 16, check_member_node }, 305 { "struct nlist", CTF_K_STRUCT, 32, check_member_nlist }, 306 { "struct forward", CTF_K_STRUCT, 24, check_member_forward }, 307 #else 308 { "struct foo", CTF_K_STRUCT, 12, check_member_foo }, 309 { "struct node", CTF_K_STRUCT, 8, check_member_node }, 310 { "struct nlist", CTF_K_STRUCT, 16, check_member_nlist }, 311 { "struct forward", CTF_K_STRUCT, 12, check_member_forward }, 312 #endif 313 { "struct round_up", CTF_K_STRUCT, 12, check_member_round_up }, 314 { "struct fixed_up", CTF_K_STRUCT, 7, check_member_fixed_up }, 315 #ifdef TARGET_LP64 316 { "struct component", CTF_K_STRUCT, 56, check_member_component }, 317 { "struct mysterious_barrel", CTF_K_STRUCT, 16, 318 check_member_mysterious }, 319 { "struct dusk_barrel", CTF_K_STRUCT, 16, check_member_dusk }, 320 #else 321 { "struct component", CTF_K_STRUCT, 36, check_member_component }, 322 { "struct mysterious_barrel", CTF_K_STRUCT, 8, 323 check_member_mysterious }, 324 { "struct dusk_barrel", CTF_K_STRUCT, 8, check_member_dusk }, 325 #endif 326 { "struct stats", CTF_K_STRUCT, 16, check_member_stats }, 327 { "struct fellowship", CTF_K_STRUCT, 2, check_member_fellowship }, 328 { "struct rings", CTF_K_STRUCT, 8, check_member_rings }, 329 { "struct csts", CTF_K_STRUCT, 5, check_member_csts, SKIP_CLANG }, 330 { "union jrpg", CTF_K_UNION, 32, check_member_jrpg }, 331 { "struct android", CTF_K_STRUCT, 4, check_member_android }, 332 { "union nier", CTF_K_UNION, 4, check_member_nier }, 333 { "union kh", CTF_K_UNION, 16, check_member_kh }, 334 #ifdef TARGET_LP64 335 { "struct trigger", CTF_K_STRUCT, 32, check_member_trigger }, 336 { "union regress", CTF_K_UNION, 16, check_member_regress }, 337 #else 338 { "struct trigger", CTF_K_STRUCT, 28, check_member_trigger }, 339 { "union regress", CTF_K_UNION, 12, check_member_regress }, 340 #endif 341 { NULL } 342 }; 343 344 #ifdef TARGET_LP64 345 static check_member_t check_member_anon_basic[] = { 346 { "a", "int", 0 }, 347 { "b", "int", 8 * NBBY }, 348 { "c", "double", 8 * NBBY }, 349 { "d", "const char *", 8 * NBBY }, 350 { "e", "int", 16 * NBBY }, 351 { "f", "const char *", 24 * NBBY }, 352 { "g", "unsigned int [10]", 32 * NBBY }, 353 { NULL } 354 }; 355 #else /* !TARGET_LP64 */ 356 static check_member_t check_member_anon_basic[] = { 357 { "a", "int", 0 }, 358 { "b", "int", 4 * NBBY }, 359 { "c", "double", 4 * NBBY }, 360 { "d", "const char *", 4 * NBBY }, 361 { "e", "int", 12 * NBBY }, 362 { "f", "const char *", 16 * NBBY }, 363 { "g", "unsigned int [10]", 20 * NBBY }, 364 { NULL } 365 }; 366 #endif /* TARGET_LP64 */ 367 368 static check_member_t check_member_nested[] = { 369 { "a", "int", 0 }, 370 { "b", "int", 4 * NBBY }, 371 { "c", "int", 4 * NBBY }, 372 { "d", "int", 8 * NBBY }, 373 { "e", "int", 12 * NBBY }, 374 { "g", "int", 16 * NBBY }, 375 { "h", "int", 16 * NBBY }, 376 { "i", "int", 20 * NBBY }, 377 { "j", "int", 24 * NBBY }, 378 { "k", "int", 28 * NBBY }, 379 { "l", "int", 28 * NBBY }, 380 { "m", "int", 32 * NBBY }, 381 { "n", "int", 28 * NBBY }, 382 { "o", "int", 28 * NBBY }, 383 { "p", "int", 32 * NBBY }, 384 { NULL } 385 }; 386 387 /* 388 * This contains members tests that involve anonyous unions and structures and 389 * therefore only are for the ctftest_check_member_info() version. 390 */ 391 static check_member_test_t anon_members[] = { 392 #ifdef TARGET_LP64 393 { "struct anon_basic", CTF_K_STRUCT, 72, check_member_anon_basic }, 394 #else 395 { "struct anon_basic", CTF_K_STRUCT, 60, check_member_anon_basic }, 396 #endif 397 { "struct nested", CTF_K_STRUCT, 36, check_member_nested}, 398 { NULL } 399 }; 400 401 static check_descent_t check_descent_head[] = { 402 { "nlist_t", CTF_K_TYPEDEF }, 403 { "struct nlist", CTF_K_STRUCT }, 404 { NULL } 405 }; 406 407 static check_descent_t check_descent_forward[] = { 408 { "const forward_t", CTF_K_CONST }, 409 { "forward_t", CTF_K_TYPEDEF }, 410 { "struct forward", CTF_K_STRUCT }, 411 { NULL } 412 }; 413 414 static check_descent_test_t descents[] = { 415 { "head", check_descent_head }, 416 { "forward", check_descent_forward }, 417 { NULL } 418 }; 419 420 static check_descent_t check_descent_regress_gcc4[] = { 421 { "const union regress [9]", CTF_K_CONST }, 422 { "union regress [9]", CTF_K_ARRAY, "union regress", 9 }, 423 { "union regress", CTF_K_UNION }, 424 { NULL } 425 }; 426 427 static check_descent_t check_descent_regress_gcc7[] = { 428 { "const union regress [9]", CTF_K_ARRAY, "const union regress", 9 }, 429 { "const union regress", CTF_K_CONST }, 430 { "union regress", CTF_K_UNION }, 431 { NULL } 432 }; 433 434 /* 435 * See needed_array_qualifier(): applying this fix means the qualifier order is 436 * different between GCC versions. Accept either form. 437 */ 438 static check_descent_test_t alt_descents[] = { 439 { "regress", check_descent_regress_gcc4 }, 440 { "regress", check_descent_regress_gcc7 }, 441 { NULL } 442 }; 443 444 int 445 main(int argc, char *argv[]) 446 { 447 int ret = 0; 448 449 if (argc < 2) { 450 errx(EXIT_FAILURE, "missing test files"); 451 } 452 453 for (int i = 1; i < argc; i++) { 454 ctf_file_t *fp; 455 int alt_ok = 0; 456 457 if ((fp = ctf_open(argv[i], &ret)) == NULL) { 458 warnx("failed to open %s: %s", argv[i], 459 ctf_errmsg(ret)); 460 ret = EXIT_FAILURE; 461 continue; 462 } 463 464 if (!ctftest_check_numbers(fp, check_bitfields)) 465 ret = EXIT_FAILURE; 466 if (!ctftest_check_symbols(fp, check_syms)) 467 ret = EXIT_FAILURE; 468 for (size_t j = 0; descents[j].cdt_sym != NULL; j++) { 469 if (!ctftest_check_descent(descents[j].cdt_sym, fp, 470 descents[j].cdt_tests, B_FALSE)) { 471 ret = EXIT_FAILURE; 472 } 473 } 474 475 for (size_t j = 0; alt_descents[j].cdt_sym != NULL; j++) { 476 if (ctftest_check_descent(alt_descents[j].cdt_sym, fp, 477 alt_descents[j].cdt_tests, B_TRUE)) { 478 alt_ok = 1; 479 break; 480 } 481 } 482 483 if (!alt_ok) { 484 warnx("all descents failed for %s", 485 alt_descents[0].cdt_sym); 486 ret = EXIT_FAILURE; 487 } 488 489 for (size_t j = 0; members[j].cmt_type != NULL; j++) { 490 if (ctftest_skip(members[j].cmt_skips)) { 491 warnx("skipping members test %s due to " 492 "known compiler issue", 493 members[j].cmt_type); 494 continue; 495 } 496 497 if (!ctftest_check_members(members[j].cmt_type, fp, 498 members[j].cmt_kind, members[j].cmt_size, 499 members[j].cmt_members)) { 500 ret = EXIT_FAILURE; 501 } 502 503 if (!ctftest_check_member_info(members[j].cmt_type, fp, 504 members[j].cmt_kind, members[j].cmt_size, 505 members[j].cmt_members)) { 506 ret = EXIT_FAILURE; 507 } 508 } 509 510 for (size_t j = 0; anon_members[j].cmt_type != NULL; j++) { 511 if (!ctftest_check_member_info(anon_members[j].cmt_type, 512 fp, anon_members[j].cmt_kind, 513 anon_members[j].cmt_size, 514 anon_members[j].cmt_members)) { 515 ret = EXIT_FAILURE; 516 } 517 } 518 519 ctf_close(fp); 520 } 521 522 return (ret); 523 } 524