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 2020 Joyent, Inc. 14 * Copyright 2025 Oxide Computer Company 15 */ 16 17 /* 18 * Collection of common utilities for CTF testing. 19 */ 20 21 #include <strings.h> 22 #include <libctf.h> 23 #include "check-common.h" 24 25 typedef struct ctftests_lookup_cb { 26 ctf_file_t *clc_fp; 27 ctf_id_t clc_id; 28 const char *clc_name; 29 } ctftests_lookup_cb_t; 30 31 typedef struct ctftest_member_cb { 32 ctf_file_t *cmc_fp; 33 const check_member_t *cmc_members; 34 const char *cmc_name; 35 } ctftest_member_cb_t; 36 37 static int 38 ctftest_lookup_type_cb(ctf_id_t id, boolean_t root, void *arg) 39 { 40 char buf[2048]; 41 ctftests_lookup_cb_t *clc = arg; 42 43 if (ctf_type_name(clc->clc_fp, id, buf, sizeof (buf)) == NULL) 44 return (0); 45 46 if (strcmp(buf, clc->clc_name) != 0) 47 return (0); 48 49 clc->clc_id = id; 50 return (1); 51 } 52 53 /* 54 * This is a variant on the classic ctf_lookup_by_name(). ctf_lookup_by_name() 55 * skips qualifiers, which makes sense given what the consumers of it are trying 56 * to do. However, that's not what we want here. So instead we basically have to 57 * walk the type table. 58 */ 59 static ctf_id_t 60 ctftest_lookup_type(ctf_file_t *fp, const char *name) 61 { 62 ctftests_lookup_cb_t clc; 63 64 clc.clc_fp = fp; 65 clc.clc_id = CTF_ERR; 66 clc.clc_name = name; 67 68 (void) ctf_type_iter(fp, B_TRUE, ctftest_lookup_type_cb, &clc); 69 return (clc.clc_id); 70 } 71 72 static int 73 ctftest_lookup_object_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg) 74 { 75 ctftests_lookup_cb_t *clc = arg; 76 77 if (strcmp(obj, clc->clc_name) == 0) { 78 clc->clc_id = type; 79 return (1); 80 } 81 82 return (0); 83 } 84 85 static ctf_id_t 86 ctftest_lookup_symbol(ctf_file_t *fp, const char *name) 87 { 88 ctftests_lookup_cb_t clc; 89 90 clc.clc_fp = fp; 91 clc.clc_id = CTF_ERR; 92 clc.clc_name = name; 93 94 (void) ctf_object_iter(fp, ctftest_lookup_object_cb, &clc); 95 return (clc.clc_id); 96 } 97 98 typedef struct ctf_function_cb { 99 const char *cfc_name; 100 ulong_t *cfc_symp; 101 ctf_funcinfo_t *cfc_fip; 102 } ctf_function_cb_t; 103 104 static int 105 ctftest_lookup_function_cb(const char *name, ulong_t symidx, 106 ctf_funcinfo_t *fip, void *arg) 107 { 108 ctf_function_cb_t *cfc = arg; 109 if (strcmp(name, cfc->cfc_name) != 0) 110 return (0); 111 112 *cfc->cfc_symp = symidx; 113 *cfc->cfc_fip = *fip; 114 115 return (1); 116 } 117 118 /* 119 * Note, this function finds the first one with a matching name. This must not 120 * be used when performing searches where a given name may occur more than once. 121 */ 122 static boolean_t 123 ctftest_lookup_function(ctf_file_t *fp, const char *name, ulong_t *symp, 124 ctf_funcinfo_t *fip) 125 { 126 ctf_function_cb_t cfc; 127 128 *symp = 0; 129 cfc.cfc_name = name; 130 cfc.cfc_symp = symp; 131 cfc.cfc_fip = fip; 132 (void) ctf_function_iter(fp, ctftest_lookup_function_cb, &cfc); 133 return (*symp == 0 ? B_FALSE : B_TRUE); 134 } 135 136 boolean_t 137 ctftest_check_numbers(ctf_file_t *fp, const check_number_t *tests) 138 { 139 uint_t i; 140 boolean_t ret = B_TRUE; 141 142 for (i = 0; tests[i].cn_tname != NULL; i++) { 143 ctf_id_t id; 144 ctf_encoding_t enc; 145 146 if (ctftest_skip(tests[i].cn_skips)) { 147 warnx("skipping check numbers test %s due to known " 148 "compiler issue", tests[i].cn_tname); 149 continue; 150 } 151 152 id = ctftest_lookup_type(fp, tests[i].cn_tname); 153 if (id == CTF_ERR) { 154 warnx("failed to look up %s", tests[i].cn_tname); 155 ret = B_FALSE; 156 continue; 157 } 158 159 if (ctf_type_kind(fp, id) != tests[i].cn_kind) { 160 warnx("type kind mismatch for %s: got %u, expected %u", 161 tests[i].cn_tname, ctf_type_kind(fp, id), 162 tests[i].cn_kind); 163 ret = B_FALSE; 164 continue; 165 } 166 167 if (ctf_type_encoding(fp, id, &enc) == CTF_ERR) { 168 warnx("failed to get type encoding for %s: %s", 169 tests[i].cn_tname, ctf_errmsg(ctf_errno(fp))); 170 ret = B_FALSE; 171 continue; 172 } 173 174 if (enc.cte_format != tests[i].cn_flags) { 175 warnx("encoding flags mismatch for %s: got 0x%x, " 176 "expected 0x%x", tests[i].cn_tname, enc.cte_format, 177 tests[i].cn_flags); 178 ret = B_FALSE; 179 continue; 180 } 181 182 if (enc.cte_offset != tests[i].cn_offset) { 183 warnx("encoding offset mismatch for %s: got 0x%x, " 184 "expected 0x%x", tests[i].cn_tname, enc.cte_offset, 185 tests[i].cn_offset); 186 ret = B_FALSE; 187 continue; 188 } 189 190 if (enc.cte_bits != tests[i].cn_size) { 191 warnx("encoding size mismatch for %s: got 0x%x, " 192 "expected 0x%x", tests[i].cn_tname, enc.cte_bits, 193 tests[i].cn_size); 194 ret = B_FALSE; 195 continue; 196 } 197 } 198 199 return (ret); 200 } 201 202 typedef struct ctftests_symbol_cb { 203 ctf_file_t *csc_fp; 204 boolean_t csc_ret; 205 const check_symbol_t *csc_tests; 206 } ctftest_symbol_cb_t; 207 208 static int 209 ctftest_check_symbol_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg) 210 { 211 ctftest_symbol_cb_t *cb = arg; 212 const check_symbol_t *tests = cb->csc_tests; 213 ctf_file_t *fp = cb->csc_fp; 214 uint_t i; 215 216 for (i = 0; tests[i].cs_symbol != NULL; i++) { 217 ctf_id_t id; 218 219 if (strcmp(obj, tests[i].cs_symbol) != 0) 220 continue; 221 222 id = ctftest_lookup_type(fp, tests[i].cs_type); 223 if (id == CTF_ERR) { 224 warnx("failed to lookup type %s for symbol %s", 225 tests[i].cs_type, tests[i].cs_symbol); 226 cb->csc_ret = B_FALSE; 227 return (0); 228 } 229 230 if (id != type) { 231 warnx("type mismatch for symbol %s, has type id %ld" 232 ", but specified type %s has id %ld", 233 tests[i].cs_symbol, type, tests[i].cs_type, id); 234 cb->csc_ret = B_FALSE; 235 return (0); 236 } 237 } 238 239 return (0); 240 } 241 242 boolean_t 243 ctftest_check_symbols(ctf_file_t *fp, const check_symbol_t *tests) 244 { 245 ctftest_symbol_cb_t cb; 246 247 cb.csc_fp = fp; 248 cb.csc_ret = B_TRUE; 249 cb.csc_tests = tests; 250 if (ctf_object_iter(fp, ctftest_check_symbol_cb, &cb) != 0) 251 return (B_FALSE); 252 return (cb.csc_ret); 253 } 254 255 256 boolean_t 257 ctftest_check_descent(const char *symbol, ctf_file_t *fp, 258 const check_descent_t *tests, boolean_t quiet) 259 { 260 ctf_id_t base; 261 uint_t layer = 0; 262 263 /* 264 * First, find the initial type of the symbol. 265 */ 266 base = ctftest_lookup_symbol(fp, symbol); 267 if (base == CTF_ERR) { 268 warnx("failed to lookup type for symbol %s", symbol); 269 return (B_FALSE); 270 } 271 272 while (tests->cd_tname != NULL) { 273 ctf_id_t tid; 274 int kind; 275 ctf_arinfo_t ari; 276 277 if (base == CTF_ERR) { 278 if (!quiet) { 279 warnx("encountered non-reference type at layer " 280 "%u while still expecting type %s for " 281 "symbol %s", layer, 282 tests->cd_tname, symbol); 283 } 284 return (B_FALSE); 285 } 286 287 tid = ctftest_lookup_type(fp, tests->cd_tname); 288 if (tid == CTF_ERR) { 289 if (!quiet) { 290 warnx("failed to lookup type %s", 291 tests->cd_tname); 292 } 293 return (B_FALSE); 294 } 295 296 if (tid != base) { 297 if (!quiet) { 298 warnx("type mismatch at layer %u: found " 299 "id %ld, but expecting type id %ld for " 300 "type %s, symbol %s", layer, base, tid, 301 tests->cd_tname, symbol); 302 } 303 return (B_FALSE); 304 } 305 306 kind = ctf_type_kind(fp, base); 307 if (kind != tests->cd_kind) { 308 if (!quiet) { 309 warnx("type kind mismatch at layer %u: found " 310 "kind %u, but expected kind %u for %s, " 311 "symbol %s", layer, kind, tests->cd_kind, 312 tests->cd_tname, symbol); 313 } 314 return (B_FALSE); 315 } 316 317 switch (kind) { 318 case CTF_K_ARRAY: 319 if (ctf_array_info(fp, base, &ari) == CTF_ERR) { 320 if (!quiet) { 321 warnx("failed to lookup array info at " 322 "layer %ld for type %s, " 323 "symbol %s: %s", base, 324 tests->cd_tname, symbol, 325 ctf_errmsg(ctf_errno(fp))); 326 } 327 return (B_FALSE); 328 } 329 330 if (tests->cd_nents != ari.ctr_nelems) { 331 if (!quiet) { 332 warnx("array element mismatch at layer " 333 "%u for type %s, symbol %s: found " 334 "%u, expected %u", layer, 335 tests->cd_tname, symbol, 336 ari.ctr_nelems, tests->cd_nents); 337 } 338 return (B_FALSE); 339 } 340 341 tid = ctftest_lookup_type(fp, tests->cd_contents); 342 if (tid == CTF_ERR) { 343 if (!quiet) { 344 warnx("failed to look up type %s", 345 tests->cd_contents); 346 } 347 return (B_FALSE); 348 } 349 350 if (ari.ctr_contents != tid) { 351 if (!quiet) { 352 warnx("array contents mismatch at " 353 "layer %u for type %s, symbol %s: " 354 "found %ld, expected %s/%ld", 355 layer, tests->cd_tname, 356 symbol, ari.ctr_contents, 357 tests->cd_contents, tid); 358 } 359 return (B_FALSE); 360 } 361 base = ari.ctr_contents; 362 break; 363 default: 364 base = ctf_type_reference(fp, base); 365 break; 366 } 367 368 tests++; 369 layer++; 370 } 371 372 if (base != CTF_ERR) { 373 if (!quiet) { 374 warnx("found additional type %ld in chain, " 375 "but expected no more", base); 376 } 377 return (B_FALSE); 378 } 379 380 return (B_TRUE); 381 } 382 383 int 384 ctftest_check_enum_count(const char *name, int value, void *arg) 385 { 386 uint_t *u = arg; 387 *u = *u + 1; 388 return (0); 389 } 390 391 int 392 ctftest_check_enum_value(const char *name, int value, void *arg) 393 { 394 uint_t i; 395 const check_enum_t *enums = arg; 396 397 for (i = 0; enums[i].ce_name != NULL; i++) { 398 if (strcmp(enums[i].ce_name, name) != 0) 399 continue; 400 if (enums[i].ce_value == (int64_t)value) 401 return (0); 402 warnx("enum %s value mismatch: found %d, expected %" PRId64, 403 name, value, enums[i].ce_value); 404 return (1); 405 } 406 407 warnx("found no matching entry for enum member %s", name); 408 return (1); 409 } 410 411 boolean_t 412 ctftest_check_enum(const char *type, ctf_file_t *fp, const check_enum_t *enums) 413 { 414 int ret; 415 uint_t tcount, ecount; 416 ctf_id_t base; 417 418 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 419 warnx("Failed to look up type %s", type); 420 return (B_FALSE); 421 } 422 423 if (ctf_type_kind(fp, base) != CTF_K_ENUM) { 424 warnx("%s is not an enum", type); 425 return (B_FALSE); 426 } 427 428 /* 429 * First count how many entries we have. 430 */ 431 tcount = 0; 432 while (enums[tcount].ce_name != NULL) { 433 tcount++; 434 } 435 436 ecount = 0; 437 if (ctf_enum_iter(fp, base, ctftest_check_enum_count, &ecount) != 0) { 438 warnx("failed to walk enum %s: %s", type, 439 ctf_errmsg(ctf_errno(fp))); 440 return (B_FALSE); 441 } 442 443 if (tcount != ecount) { 444 warnx("enum value mismatch: expected %u values, but found %u", 445 tcount, ecount); 446 return (B_FALSE); 447 } 448 449 if ((ret = ctf_enum_iter(fp, base, ctftest_check_enum_value, 450 (void *)enums)) != 0) { 451 if (ret == -1) { 452 warnx("failed to walk enum %s: %s", type, 453 ctf_errmsg(ctf_errno(fp))); 454 } 455 return (B_FALSE); 456 } 457 458 return (B_TRUE); 459 } 460 461 int 462 ctftest_check_member_count(const char *mname, ctf_id_t mtype, ulong_t bitoff, 463 void *arg) 464 { 465 uint_t *countp = arg; 466 *countp = *countp + 1; 467 return (0); 468 } 469 470 int 471 ctftest_check_members_cb(const char *mname, ctf_id_t mtype, ulong_t bitoff, 472 void *arg) 473 { 474 uint_t i; 475 const ctftest_member_cb_t *cmc = arg; 476 const check_member_t *members = cmc->cmc_members; 477 ctf_file_t *fp = cmc->cmc_fp; 478 479 for (i = 0; members[i].cm_name != NULL; i++) { 480 boolean_t bad = B_FALSE; 481 char buf[2048]; 482 483 if (strcmp(mname, members[i].cm_name) != 0) 484 continue; 485 486 if (bitoff != members[i].cm_offset) { 487 warnx("member %s of type %s has mismatched bit offset: " 488 "found %lu, expected %lu", mname, cmc->cmc_name, 489 bitoff, members[i].cm_offset); 490 bad = B_TRUE; 491 } 492 493 if (ctf_type_name(fp, mtype, buf, sizeof (buf)) == NULL) { 494 warnx("failed to obtain type name for member %s: %s", 495 mname, ctf_errmsg(ctf_errno(fp))); 496 bad = B_TRUE; 497 } else if (strcmp(buf, members[i].cm_type) != 0) { 498 warnx("member %s has bad type, found %s, expected %s", 499 mname, buf, members[i].cm_type); 500 bad = B_TRUE; 501 } 502 503 return (bad ? 1 : 0); 504 } 505 506 warnx("found no matching entry for member %s of type %s", mname, 507 cmc->cmc_name); 508 return (1); 509 } 510 511 boolean_t 512 ctftest_check_members(const char *type, ctf_file_t *fp, int kind, 513 size_t size, const check_member_t *members) 514 { 515 int ret; 516 uint_t tcount, mcount; 517 ctf_id_t base; 518 ctftest_member_cb_t cmc; 519 520 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 521 warnx("failed to look up type %s", type); 522 return (B_FALSE); 523 } 524 525 if (ctf_type_kind(fp, base) != kind) { 526 warnx("%s has kind %s, expected %s", type, 527 ctf_kind_name(fp, ctf_type_kind(fp, base)), 528 ctf_kind_name(fp, kind)); 529 return (B_FALSE); 530 } 531 532 if (size != ctf_type_size(fp, base)) { 533 warnx("%s has bad size, expected %zu, found %zd", 534 type, size, ctf_type_size(fp, base)); 535 return (B_FALSE); 536 } 537 538 /* 539 * First count how many entries we have. 540 */ 541 tcount = 0; 542 while (members[tcount].cm_name != NULL) { 543 tcount++; 544 } 545 546 mcount = 0; 547 if (ctf_member_iter(fp, base, ctftest_check_member_count, &mcount) != 548 0) { 549 warnx("failed to walk members of %s: %s", type, 550 ctf_errmsg(ctf_errno(fp))); 551 return (B_FALSE); 552 } 553 554 if (tcount != mcount) { 555 warnx("type member mismatch: expected %u values, but found %u", 556 tcount, mcount); 557 return (B_FALSE); 558 } 559 560 cmc.cmc_fp = fp; 561 cmc.cmc_members = members; 562 cmc.cmc_name = type; 563 if ((ret = ctf_member_iter(fp, base, ctftest_check_members_cb, 564 &cmc)) != 0) { 565 if (ret == -1) { 566 warnx("failed to walk type %s: %s", type, 567 ctf_errmsg(ctf_errno(fp))); 568 } 569 return (B_FALSE); 570 } 571 572 return (B_TRUE); 573 } 574 575 boolean_t 576 ctftest_check_member_info(const char *type, ctf_file_t *fp, int kind, 577 size_t size, const check_member_t *members) 578 { 579 boolean_t ret = B_TRUE; 580 ctf_id_t base; 581 582 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 583 warnx("failed to look up type %s", type); 584 return (B_FALSE); 585 } 586 587 if (ctf_type_kind(fp, base) != kind) { 588 warnx("%s has kind %s, expected %s", type, 589 ctf_kind_name(fp, ctf_type_kind(fp, base)), 590 ctf_kind_name(fp, kind)); 591 return (B_FALSE); 592 } 593 594 if (size != ctf_type_size(fp, base)) { 595 warnx("%s has bad size, expected %zu, found %zd", 596 type, size, ctf_type_size(fp, base)); 597 ret = B_FALSE; 598 } 599 600 for (size_t i = 0; members[i].cm_name != NULL; i++) { 601 ctf_membinfo_t mi; 602 char buf[2048]; 603 604 if (ctf_member_info(fp, base, members[i].cm_name, &mi) == 605 CTF_ERR) { 606 warnx("failed to look up member %s in %s: %s", 607 members[i].cm_name, type, 608 ctf_errmsg(ctf_errno(fp))); 609 } 610 611 if (mi.ctm_offset != members[i].cm_offset) { 612 warnx("member %s of type %s has mismatched bit offset: " 613 "found %lu, expected %lu", members[i].cm_name, type, 614 mi.ctm_offset, members[i].cm_offset); 615 ret = B_FALSE; 616 } 617 618 if (ctf_type_name(fp, mi.ctm_type, buf, sizeof (buf)) == NULL) { 619 warnx("failed to obtain type name for member %s in %s: " 620 "%s", members[i].cm_name, type, 621 ctf_errmsg(ctf_errno(fp))); 622 ret = B_FALSE; 623 } else if (strcmp(buf, members[i].cm_type) != 0) { 624 warnx("member %s in %s has bad type, found %s, " 625 "expected %s", members[i].cm_name, type, buf, 626 members[i].cm_type); 627 ret = B_FALSE; 628 } 629 630 } 631 632 return (ret); 633 } 634 635 boolean_t 636 ctftest_check_function(const char *symbol, ctf_file_t *fp, const char *rtype, 637 uint_t nargs, uint_t flags, const char **argv) 638 { 639 ulong_t sym; 640 ctf_funcinfo_t fi; 641 uint_t i; 642 boolean_t ret = B_TRUE; 643 ctf_id_t *args; 644 char buf[2048]; 645 646 647 if (!ctftest_lookup_function(fp, symbol, &sym, &fi)) { 648 warnx("failed to look up function %s", symbol); 649 return (B_FALSE); 650 } 651 652 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) { 653 warnx("failed to lookup return type name for function %s", 654 symbol); 655 ret = B_FALSE; 656 } else if (strcmp(rtype, buf) != 0) { 657 warnx("return type has wrong type: found %s, expected %s", 658 buf, rtype); 659 ret = B_FALSE; 660 } 661 662 if (nargs != fi.ctc_argc) { 663 warnx("function argument mismatch: found %u, expected %u", 664 fi.ctc_argc, nargs); 665 ret = B_FALSE; 666 } 667 668 if (flags != fi.ctc_flags) { 669 warnx("function flags mismatch, found 0x%x, expected 0x%x", 670 fi.ctc_flags, flags); 671 ret = B_FALSE; 672 } 673 674 if (!ret || fi.ctc_argc == 0) { 675 return (ret); 676 } 677 678 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) { 679 warnx("failed to allocate memory for function arguments"); 680 return (B_FALSE); 681 } 682 683 if (ctf_func_args(fp, sym, fi.ctc_argc, args) != 0) { 684 warnx("failed to get function information: %s", 685 ctf_errmsg(ctf_errno(fp))); 686 free(args); 687 return (B_FALSE); 688 } 689 690 for (i = 0; i < fi.ctc_argc; i++) { 691 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) { 692 warnx("failed to obtain type name for argument %u: %s", 693 i, ctf_errmsg(ctf_errno(fp))); 694 ret = B_FALSE; 695 break; 696 } 697 698 if (strcmp(buf, argv[i]) != 0) { 699 warnx("argument %u has wrong type: found %s, " 700 "expected %s", i, buf, argv[i]); 701 ret = B_FALSE; 702 break; 703 } 704 } 705 706 free(args); 707 return (ret); 708 } 709 710 boolean_t 711 ctftest_check_fptr(const char *type, ctf_file_t *fp, const char *rtype, 712 uint_t nargs, uint_t flags, const char **argv) 713 { 714 ctf_id_t tid; 715 ctf_funcinfo_t fi; 716 uint_t i; 717 boolean_t ret = B_TRUE; 718 ctf_id_t *args; 719 char buf[2048]; 720 721 722 if ((tid = ctf_lookup_by_name(fp, type)) == CTF_ERR) { 723 warnx("failed to look up type %s: %s", type, 724 ctf_errmsg(ctf_errno(fp))); 725 return (B_FALSE); 726 } 727 728 /* 729 * Perform two CTF type resolves, one for the function pointer and one 730 * for the typedef that gets passed in. 731 */ 732 if ((tid = ctf_type_resolve(fp, tid)) == CTF_ERR) { 733 warnx("failed to convert type %s to base type: %s", type, 734 ctf_errmsg(ctf_errno(fp))); 735 return (B_FALSE); 736 } 737 738 if (ctf_type_kind(fp, tid) == CTF_K_POINTER && 739 (tid = ctf_type_reference(fp, tid)) == CTF_ERR) { 740 warnx("failed to convert type %s to base type: %s", type, 741 ctf_errmsg(ctf_errno(fp))); 742 return (B_FALSE); 743 } 744 745 if (ctf_func_info_by_id(fp, tid, &fi) != 0) { 746 warnx("failed to get function information for type %s: %s", 747 type, ctf_errmsg(ctf_errno(fp))); 748 return (B_FALSE); 749 } 750 751 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) { 752 warnx("failed to lookup return type name for function %s", 753 type); 754 ret = B_FALSE; 755 } else if (strcmp(rtype, buf) != 0) { 756 warnx("return type has wrong type: found %s, expected %s", 757 buf, rtype); 758 ret = B_FALSE; 759 } 760 761 if (nargs != fi.ctc_argc) { 762 warnx("function argument mismatch: found %u, expected %u", 763 fi.ctc_argc, nargs); 764 ret = B_FALSE; 765 } 766 767 if (flags != fi.ctc_flags) { 768 warnx("function flags mismatch, found 0x%x, expected 0x%x", 769 fi.ctc_flags, flags); 770 ret = B_FALSE; 771 } 772 773 if (!ret || fi.ctc_argc == 0) { 774 return (ret); 775 } 776 777 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) { 778 warnx("failed to allocate memory for function arguments"); 779 return (B_FALSE); 780 } 781 782 if (ctf_func_args_by_id(fp, tid, fi.ctc_argc, args) != 0) { 783 warnx("failed to get function information: %s", 784 ctf_errmsg(ctf_errno(fp))); 785 free(args); 786 return (B_FALSE); 787 } 788 789 for (i = 0; i < fi.ctc_argc; i++) { 790 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) { 791 warnx("failed to obtain type name for argument %u: %s", 792 i, ctf_errmsg(ctf_errno(fp))); 793 ret = B_FALSE; 794 break; 795 } 796 797 if (strcmp(buf, argv[i]) != 0) { 798 warnx("argument %u has wrong type: found %s, " 799 "expected %s", i, buf, argv[i]); 800 ret = B_FALSE; 801 break; 802 } 803 } 804 805 free(args); 806 return (ret); 807 } 808 809 boolean_t 810 ctftest_check_size(const char *type, ctf_file_t *fp, size_t size) 811 { 812 ctf_id_t base; 813 814 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 815 warnx("Failed to look up type %s", type); 816 return (B_FALSE); 817 } 818 819 if (size != ctf_type_size(fp, base)) { 820 warnx("%s has bad size, expected %zu, found %zd", 821 type, size, ctf_type_size(fp, base)); 822 return (B_FALSE); 823 } 824 825 return (B_TRUE); 826 } 827 828 typedef struct ctftest_duplicates { 829 ctf_file_t *ctd_fp; 830 char **ctd_names; 831 size_t ctd_len; 832 size_t ctd_curent; 833 boolean_t ctd_ret; 834 } ctftest_duplicates_t; 835 836 static int 837 ctftest_duplicates_cb(ctf_id_t id, boolean_t root, void *arg) 838 { 839 char buf[2048]; 840 ctftest_duplicates_t *dup = arg; 841 size_t i; 842 843 if (ctf_type_name(dup->ctd_fp, id, buf, sizeof (buf)) == NULL) { 844 warnx("failed to lookup name for id %ld", id); 845 dup->ctd_ret = B_FALSE; 846 return (1); 847 } 848 849 for (i = 0; i < dup->ctd_curent; i++) { 850 if (strcmp(buf, dup->ctd_names[i]) == 0) { 851 warnx("encountered duplicate type '%s'", buf); 852 dup->ctd_ret = B_FALSE; 853 /* 854 * Don't break out of the loop and keep going in case we 855 * find another duplicate. 856 */ 857 return (0); 858 } 859 } 860 861 if (dup->ctd_curent == dup->ctd_len) { 862 char **n; 863 size_t newlen = dup->ctd_len * 2; 864 865 n = recallocarray(dup->ctd_names, dup->ctd_len, newlen, 866 sizeof (char *)); 867 if (n == NULL) { 868 warnx("failed to resize type name array"); 869 dup->ctd_ret = B_FALSE; 870 return (1); 871 } 872 873 dup->ctd_names = n; 874 dup->ctd_len = newlen; 875 } 876 877 dup->ctd_names[dup->ctd_curent] = strdup(buf); 878 if (dup->ctd_names[dup->ctd_curent] == NULL) { 879 warn("failed to duplicate type name"); 880 dup->ctd_ret = B_FALSE; 881 return (1); 882 } 883 dup->ctd_curent++; 884 885 return (0); 886 } 887 888 boolean_t 889 ctftest_duplicates(ctf_file_t *fp) 890 { 891 size_t i; 892 ctftest_duplicates_t d; 893 894 bzero(&d, sizeof (d)); 895 d.ctd_fp = fp; 896 d.ctd_len = 4; 897 d.ctd_ret = B_TRUE; 898 d.ctd_names = recallocarray(NULL, 0, d.ctd_len, sizeof (char *)); 899 if (d.ctd_names == NULL) { 900 warnx("failed to allocate duplicate name storage"); 901 return (B_FALSE); 902 } 903 904 (void) ctf_type_iter(fp, B_TRUE, ctftest_duplicates_cb, &d); 905 906 for (i = 0; i < d.ctd_curent; i++) { 907 free(d.ctd_names[i]); 908 } 909 free(d.ctd_names); 910 911 return (d.ctd_ret); 912 } 913 914 boolean_t 915 ctftest_skip(check_skip_t skip) 916 { 917 const char *compiler; 918 919 if (skip == 0) { 920 return (B_FALSE); 921 } 922 923 compiler = getenv("ctf_cc_type"); 924 if (compiler == NULL) { 925 return (B_FALSE); 926 } 927 928 if ((skip & SKIP_CLANG) != 0 && strcmp(compiler, "clang") == 0) 929 return (B_TRUE); 930 931 return (B_FALSE); 932 } 933