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