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 %ld" 231 ", but specified type %s has id %ld", 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 " 298 "id %ld, but expecting type id %ld for " 299 "type %s, 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 %ld for type %s, " 322 "symbol %s: %s", base, 323 tests->cd_tname, symbol, 324 ctf_errmsg(ctf_errno(fp))); 325 } 326 return (B_FALSE); 327 } 328 329 if (tests->cd_nents != ari.ctr_nelems) { 330 if (!quiet) { 331 warnx("array element mismatch at layer " 332 "%u for type %s, symbol %s: found " 333 "%u, expected %u", layer, 334 tests->cd_tname, symbol, 335 ari.ctr_nelems, tests->cd_nents); 336 } 337 return (B_FALSE); 338 } 339 340 tid = ctftest_lookup_type(fp, tests->cd_contents); 341 if (tid == CTF_ERR) { 342 if (!quiet) { 343 warnx("failed to look up type %s", 344 tests->cd_contents); 345 } 346 return (B_FALSE); 347 } 348 349 if (ari.ctr_contents != tid) { 350 if (!quiet) { 351 warnx("array contents mismatch at " 352 "layer %u for type %s, symbol %s: " 353 "found %ld, expected %s/%ld", 354 layer, tests->cd_tname, 355 symbol, ari.ctr_contents, 356 tests->cd_contents, tid); 357 } 358 return (B_FALSE); 359 } 360 base = ari.ctr_contents; 361 break; 362 default: 363 base = ctf_type_reference(fp, base); 364 break; 365 } 366 367 tests++; 368 layer++; 369 } 370 371 if (base != CTF_ERR) { 372 if (!quiet) { 373 warnx("found additional type %ld in chain, " 374 "but expected no more", base); 375 } 376 return (B_FALSE); 377 } 378 379 return (B_TRUE); 380 } 381 382 int 383 ctftest_check_enum_count(const char *name, int value, void *arg) 384 { 385 uint_t *u = arg; 386 *u = *u + 1; 387 return (0); 388 } 389 390 int 391 ctftest_check_enum_value(const char *name, int value, void *arg) 392 { 393 uint_t i; 394 const check_enum_t *enums = arg; 395 396 for (i = 0; enums[i].ce_name != NULL; i++) { 397 if (strcmp(enums[i].ce_name, name) != 0) 398 continue; 399 if (enums[i].ce_value == (int64_t)value) 400 return (0); 401 warnx("enum %s value mismatch: found %d, expected %" PRId64, 402 name, value, enums[i].ce_value); 403 return (1); 404 } 405 406 warnx("found no matching entry for enum member %s", name); 407 return (1); 408 } 409 410 boolean_t 411 ctftest_check_enum(const char *type, ctf_file_t *fp, const check_enum_t *enums) 412 { 413 int ret; 414 uint_t tcount, ecount; 415 ctf_id_t base; 416 417 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 418 warnx("Failed to look up type %s", type); 419 return (B_FALSE); 420 } 421 422 if (ctf_type_kind(fp, base) != CTF_K_ENUM) { 423 warnx("%s is not an enum", type); 424 return (B_FALSE); 425 } 426 427 /* 428 * First count how many entries we have. 429 */ 430 tcount = 0; 431 while (enums[tcount].ce_name != NULL) { 432 tcount++; 433 } 434 435 ecount = 0; 436 if (ctf_enum_iter(fp, base, ctftest_check_enum_count, &ecount) != 0) { 437 warnx("failed to walk enum %s: %s", type, 438 ctf_errmsg(ctf_errno(fp))); 439 return (B_FALSE); 440 } 441 442 if (tcount != ecount) { 443 warnx("enum value mismatch: expected %u values, but found %u", 444 tcount, ecount); 445 return (B_FALSE); 446 } 447 448 if ((ret = ctf_enum_iter(fp, base, ctftest_check_enum_value, 449 (void *)enums)) != 0) { 450 if (ret == -1) { 451 warnx("failed to walk enum %s: %s", type, 452 ctf_errmsg(ctf_errno(fp))); 453 } 454 return (B_FALSE); 455 } 456 457 return (B_TRUE); 458 } 459 460 int 461 ctftest_check_member_count(const char *mname, ctf_id_t mtype, ulong_t bitoff, 462 void *arg) 463 { 464 uint_t *countp = arg; 465 *countp = *countp + 1; 466 return (0); 467 } 468 469 int 470 ctftest_check_members_cb(const char *mname, ctf_id_t mtype, ulong_t bitoff, 471 void *arg) 472 { 473 uint_t i; 474 const ctftest_member_cb_t *cmc = arg; 475 const check_member_t *members = cmc->cmc_members; 476 ctf_file_t *fp = cmc->cmc_fp; 477 478 for (i = 0; members[i].cm_name != NULL; i++) { 479 boolean_t bad = B_FALSE; 480 char buf[2048]; 481 482 if (strcmp(mname, members[i].cm_name) != 0) 483 continue; 484 485 if (bitoff != members[i].cm_offset) { 486 warnx("member %s of type %s has mismatched bit offset: " 487 "found %lu, expected %lu", mname, cmc->cmc_name, 488 bitoff, members[i].cm_offset); 489 bad = B_TRUE; 490 } 491 492 if (ctf_type_name(fp, mtype, buf, sizeof (buf)) == NULL) { 493 warnx("failed to obtain type name for member %s: %s", 494 mname, ctf_errmsg(ctf_errno(fp))); 495 bad = B_TRUE; 496 } else if (strcmp(buf, members[i].cm_type) != 0) { 497 warnx("member %s has bad type, found %s, expected %s", 498 mname, buf, members[i].cm_type); 499 bad = B_TRUE; 500 } 501 502 return (bad ? 1 : 0); 503 } 504 505 warnx("found no matching entry for member %s of type %s", mname, 506 cmc->cmc_name); 507 return (1); 508 } 509 510 boolean_t 511 ctftest_check_members(const char *type, ctf_file_t *fp, int kind, 512 size_t size, const check_member_t *members) 513 { 514 int ret; 515 uint_t tcount, mcount; 516 ctf_id_t base; 517 ctftest_member_cb_t cmc; 518 519 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 520 warnx("failed to look up type %s", type); 521 return (B_FALSE); 522 } 523 524 if (ctf_type_kind(fp, base) != kind) { 525 warnx("%s has kind %s, expected %s", type, 526 ctf_kind_name(fp, ctf_type_kind(fp, base)), 527 ctf_kind_name(fp, kind)); 528 return (B_FALSE); 529 } 530 531 if (size != ctf_type_size(fp, base)) { 532 warnx("%s has bad size, expected %zu, found %zd", 533 type, size, ctf_type_size(fp, base)); 534 return (B_FALSE); 535 } 536 537 /* 538 * First count how many entries we have. 539 */ 540 tcount = 0; 541 while (members[tcount].cm_name != NULL) { 542 tcount++; 543 } 544 545 mcount = 0; 546 if (ctf_member_iter(fp, base, ctftest_check_member_count, &mcount) != 547 0) { 548 warnx("failed to walk members of %s: %s", type, 549 ctf_errmsg(ctf_errno(fp))); 550 return (B_FALSE); 551 } 552 553 if (tcount != mcount) { 554 warnx("type member mismatch: expected %u values, but found %u", 555 tcount, mcount); 556 return (B_FALSE); 557 } 558 559 cmc.cmc_fp = fp; 560 cmc.cmc_members = members; 561 cmc.cmc_name = type; 562 if ((ret = ctf_member_iter(fp, base, ctftest_check_members_cb, 563 &cmc)) != 0) { 564 if (ret == -1) { 565 warnx("failed to walk type %s: %s", type, 566 ctf_errmsg(ctf_errno(fp))); 567 } 568 return (B_FALSE); 569 } 570 571 return (B_TRUE); 572 } 573 574 boolean_t 575 ctftest_check_function(const char *symbol, ctf_file_t *fp, const char *rtype, 576 uint_t nargs, uint_t flags, const char **argv) 577 { 578 ulong_t sym; 579 ctf_funcinfo_t fi; 580 uint_t i; 581 boolean_t ret = B_TRUE; 582 ctf_id_t *args; 583 char buf[2048]; 584 585 586 if (!ctftest_lookup_function(fp, symbol, &sym, &fi)) { 587 warnx("failed to look up function %s", symbol); 588 return (B_FALSE); 589 } 590 591 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) { 592 warnx("failed to lookup return type name for function %s", 593 symbol); 594 ret = B_FALSE; 595 } else if (strcmp(rtype, buf) != 0) { 596 warnx("return type has wrong type: found %s, expected %s", 597 buf, rtype); 598 ret = B_FALSE; 599 } 600 601 if (nargs != fi.ctc_argc) { 602 warnx("function argument mismatch: found %u, expected %u", 603 fi.ctc_argc, nargs); 604 ret = B_FALSE; 605 } 606 607 if (flags != fi.ctc_flags) { 608 warnx("function flags mismatch, found 0x%x, expected 0x%x", 609 fi.ctc_flags, flags); 610 ret = B_FALSE; 611 } 612 613 if (!ret || fi.ctc_argc == 0) { 614 return (ret); 615 } 616 617 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) { 618 warnx("failed to allocate memory for function arguments"); 619 return (B_FALSE); 620 } 621 622 if (ctf_func_args(fp, sym, fi.ctc_argc, args) != 0) { 623 warnx("failed to get function information: %s", 624 ctf_errmsg(ctf_errno(fp))); 625 free(args); 626 return (B_FALSE); 627 } 628 629 for (i = 0; i < fi.ctc_argc; i++) { 630 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) { 631 warnx("failed to obtain type name for argument %u: %s", 632 i, ctf_errmsg(ctf_errno(fp))); 633 ret = B_FALSE; 634 break; 635 } 636 637 if (strcmp(buf, argv[i]) != 0) { 638 warnx("argument %u has wrong type: found %s, " 639 "expected %s", i, buf, argv[i]); 640 ret = B_FALSE; 641 break; 642 } 643 } 644 645 free(args); 646 return (ret); 647 } 648 649 boolean_t 650 ctftest_check_fptr(const char *type, ctf_file_t *fp, const char *rtype, 651 uint_t nargs, uint_t flags, const char **argv) 652 { 653 ctf_id_t tid; 654 ctf_funcinfo_t fi; 655 uint_t i; 656 boolean_t ret = B_TRUE; 657 ctf_id_t *args; 658 char buf[2048]; 659 660 661 if ((tid = ctf_lookup_by_name(fp, type)) == CTF_ERR) { 662 warnx("failed to look up type %s: %s", type, 663 ctf_errmsg(ctf_errno(fp))); 664 return (B_FALSE); 665 } 666 667 /* 668 * Perform two CTF type resolves, one for the function pointer and one 669 * for the typedef that gets passed in. 670 */ 671 if ((tid = ctf_type_resolve(fp, tid)) == CTF_ERR) { 672 warnx("failed to convert type %s to base type: %s", type, 673 ctf_errmsg(ctf_errno(fp))); 674 return (B_FALSE); 675 } 676 677 if (ctf_type_kind(fp, tid) == CTF_K_POINTER && 678 (tid = ctf_type_reference(fp, tid)) == CTF_ERR) { 679 warnx("failed to convert type %s to base type: %s", type, 680 ctf_errmsg(ctf_errno(fp))); 681 return (B_FALSE); 682 } 683 684 if (ctf_func_info_by_id(fp, tid, &fi) != 0) { 685 warnx("failed to get function information for type %s: %s", 686 type, ctf_errmsg(ctf_errno(fp))); 687 return (B_FALSE); 688 } 689 690 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) { 691 warnx("failed to lookup return type name for function %s", 692 type); 693 ret = B_FALSE; 694 } else if (strcmp(rtype, buf) != 0) { 695 warnx("return type has wrong type: found %s, expected %s", 696 buf, rtype); 697 ret = B_FALSE; 698 } 699 700 if (nargs != fi.ctc_argc) { 701 warnx("function argument mismatch: found %u, expected %u", 702 fi.ctc_argc, nargs); 703 ret = B_FALSE; 704 } 705 706 if (flags != fi.ctc_flags) { 707 warnx("function flags mismatch, found 0x%x, expected 0x%x", 708 fi.ctc_flags, flags); 709 ret = B_FALSE; 710 } 711 712 if (!ret || fi.ctc_argc == 0) { 713 return (ret); 714 } 715 716 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) { 717 warnx("failed to allocate memory for function arguments"); 718 return (B_FALSE); 719 } 720 721 if (ctf_func_args_by_id(fp, tid, fi.ctc_argc, args) != 0) { 722 warnx("failed to get function information: %s", 723 ctf_errmsg(ctf_errno(fp))); 724 free(args); 725 return (B_FALSE); 726 } 727 728 for (i = 0; i < fi.ctc_argc; i++) { 729 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) { 730 warnx("failed to obtain type name for argument %u: %s", 731 i, ctf_errmsg(ctf_errno(fp))); 732 ret = B_FALSE; 733 break; 734 } 735 736 if (strcmp(buf, argv[i]) != 0) { 737 warnx("argument %u has wrong type: found %s, " 738 "expected %s", i, buf, argv[i]); 739 ret = B_FALSE; 740 break; 741 } 742 } 743 744 free(args); 745 return (ret); 746 } 747 748 boolean_t 749 ctftest_check_size(const char *type, ctf_file_t *fp, size_t size) 750 { 751 ctf_id_t base; 752 753 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 754 warnx("Failed to look up type %s", type); 755 return (B_FALSE); 756 } 757 758 if (size != ctf_type_size(fp, base)) { 759 warnx("%s has bad size, expected %zu, found %zd", 760 type, size, ctf_type_size(fp, base)); 761 return (B_FALSE); 762 } 763 764 return (B_TRUE); 765 } 766 767 typedef struct ctftest_duplicates { 768 ctf_file_t *ctd_fp; 769 char **ctd_names; 770 size_t ctd_len; 771 size_t ctd_curent; 772 boolean_t ctd_ret; 773 } ctftest_duplicates_t; 774 775 static int 776 ctftest_duplicates_cb(ctf_id_t id, boolean_t root, void *arg) 777 { 778 char buf[2048]; 779 ctftest_duplicates_t *dup = arg; 780 size_t i; 781 782 if (ctf_type_name(dup->ctd_fp, id, buf, sizeof (buf)) == NULL) { 783 warnx("failed to lookup name for id %ld", id); 784 dup->ctd_ret = B_FALSE; 785 return (1); 786 } 787 788 for (i = 0; i < dup->ctd_curent; i++) { 789 if (strcmp(buf, dup->ctd_names[i]) == 0) { 790 warnx("encountered duplicate type '%s'", buf); 791 dup->ctd_ret = B_FALSE; 792 /* 793 * Don't break out of the loop and keep going in case we 794 * find another duplicate. 795 */ 796 return (0); 797 } 798 } 799 800 if (dup->ctd_curent == dup->ctd_len) { 801 char **n; 802 size_t newlen = dup->ctd_len * 2; 803 804 n = recallocarray(dup->ctd_names, dup->ctd_len, newlen, 805 sizeof (char *)); 806 if (n == NULL) { 807 warnx("failed to resize type name array"); 808 dup->ctd_ret = B_FALSE; 809 return (1); 810 } 811 812 dup->ctd_names = n; 813 dup->ctd_len = newlen; 814 } 815 816 dup->ctd_names[dup->ctd_curent] = strdup(buf); 817 if (dup->ctd_names[dup->ctd_curent] == NULL) { 818 warn("failed to duplicate type name"); 819 dup->ctd_ret = B_FALSE; 820 return (1); 821 } 822 dup->ctd_curent++; 823 824 return (0); 825 } 826 827 boolean_t 828 ctftest_duplicates(ctf_file_t *fp) 829 { 830 size_t i; 831 ctftest_duplicates_t d; 832 833 bzero(&d, sizeof (d)); 834 d.ctd_fp = fp; 835 d.ctd_len = 4; 836 d.ctd_ret = B_TRUE; 837 d.ctd_names = recallocarray(NULL, 0, d.ctd_len, sizeof (char *)); 838 if (d.ctd_names == NULL) { 839 warnx("failed to allocate duplicate name storage"); 840 return (B_FALSE); 841 } 842 843 (void) ctf_type_iter(fp, B_TRUE, ctftest_duplicates_cb, &d); 844 845 for (i = 0; i < d.ctd_curent; i++) { 846 free(d.ctd_names[i]); 847 } 848 free(d.ctd_names); 849 850 return (d.ctd_ret); 851 } 852 853 boolean_t 854 ctftest_skip(check_skip_t skip) 855 { 856 const char *compiler; 857 858 if (skip == 0) { 859 return (B_FALSE); 860 } 861 862 compiler = getenv("ctf_cc_type"); 863 if (compiler == NULL) { 864 return (B_FALSE); 865 } 866 867 if ((skip & SKIP_CLANG) != 0 && strcmp(compiler, "clang") == 0) 868 return (B_TRUE); 869 870 return (B_FALSE); 871 } 872