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 */ 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 id = ctftest_lookup_type(fp, tests[i].cn_tname); 146 if (id == CTF_ERR) { 147 warnx("failed to look up %s", tests[i].cn_tname); 148 ret = B_FALSE; 149 continue; 150 } 151 152 if (ctf_type_kind(fp, id) != tests[i].cn_kind) { 153 warnx("type kind mismatch for %s: got %u, expected %u", 154 tests[i].cn_tname, ctf_type_kind(fp, id), 155 tests[i].cn_kind); 156 ret = B_FALSE; 157 continue; 158 } 159 160 if (ctf_type_encoding(fp, id, &enc) == CTF_ERR) { 161 warnx("failed to get type encoding for %s: %s", 162 tests[i].cn_tname, ctf_errmsg(ctf_errno(fp))); 163 ret = B_FALSE; 164 continue; 165 } 166 167 if (enc.cte_format != tests[i].cn_flags) { 168 warnx("encoding flags mismatch for %s: got 0x%x, " 169 "expected 0x%x", tests[i].cn_tname, enc.cte_format, 170 tests[i].cn_flags); 171 ret = B_FALSE; 172 continue; 173 } 174 175 if (enc.cte_offset != tests[i].cn_offset) { 176 warnx("encoding offset mismatch for %s: got 0x%x, " 177 "expected 0x%x", tests[i].cn_tname, enc.cte_offset, 178 tests[i].cn_offset); 179 ret = B_FALSE; 180 continue; 181 } 182 183 if (enc.cte_bits != tests[i].cn_size) { 184 warnx("encoding size mismatch for %s: got 0x%x, " 185 "expected 0x%x", tests[i].cn_tname, enc.cte_bits, 186 tests[i].cn_size); 187 ret = B_FALSE; 188 continue; 189 } 190 } 191 192 return (ret); 193 } 194 195 typedef struct ctftests_symbol_cb { 196 ctf_file_t *csc_fp; 197 boolean_t csc_ret; 198 const check_symbol_t *csc_tests; 199 } ctftest_symbol_cb_t; 200 201 static int 202 ctftest_check_symbol_cb(const char *obj, ctf_id_t type, ulong_t idx, void *arg) 203 { 204 ctftest_symbol_cb_t *cb = arg; 205 const check_symbol_t *tests = cb->csc_tests; 206 ctf_file_t *fp = cb->csc_fp; 207 uint_t i; 208 209 for (i = 0; tests[i].cs_symbol != NULL; i++) { 210 ctf_id_t id; 211 212 if (strcmp(obj, tests[i].cs_symbol) != 0) 213 continue; 214 215 id = ctftest_lookup_type(fp, tests[i].cs_type); 216 if (id == CTF_ERR) { 217 warnx("failed to lookup type %s for symbol %s", 218 tests[i].cs_type, tests[i].cs_symbol); 219 cb->csc_ret = B_FALSE; 220 return (0); 221 } 222 223 if (id != type) { 224 warnx("type mismatch for symbol %s, has type id %u, " 225 "but specified type %s has id %u", 226 tests[i].cs_symbol, type, tests[i].cs_type, id); 227 cb->csc_ret = B_FALSE; 228 return (0); 229 } 230 } 231 232 return (0); 233 } 234 235 boolean_t 236 ctftest_check_symbols(ctf_file_t *fp, const check_symbol_t *tests) 237 { 238 ctftest_symbol_cb_t cb; 239 240 cb.csc_fp = fp; 241 cb.csc_ret = B_TRUE; 242 cb.csc_tests = tests; 243 if (ctf_object_iter(fp, ctftest_check_symbol_cb, &cb) != 0) 244 return (B_FALSE); 245 return (cb.csc_ret); 246 } 247 248 249 boolean_t 250 ctftest_check_descent(const char *symbol, ctf_file_t *fp, 251 const check_descent_t *tests, boolean_t quiet) 252 { 253 ctf_id_t base; 254 uint_t layer = 0; 255 256 /* 257 * First, find the initial type of the symbol. 258 */ 259 base = ctftest_lookup_symbol(fp, symbol); 260 if (base == CTF_ERR) { 261 warnx("failed to lookup type for symbol %s", symbol); 262 return (B_FALSE); 263 } 264 265 while (tests->cd_tname != NULL) { 266 ctf_id_t tid; 267 int kind; 268 ctf_arinfo_t ari; 269 270 if (base == CTF_ERR) { 271 if (!quiet) { 272 warnx("encountered non-reference type at layer " 273 "%u while still expecting type %s for " 274 "symbol %s", layer, 275 tests->cd_tname, symbol); 276 } 277 return (B_FALSE); 278 } 279 280 tid = ctftest_lookup_type(fp, tests->cd_tname); 281 if (tid == CTF_ERR) { 282 if (!quiet) { 283 warnx("failed to lookup type %s", 284 tests->cd_tname); 285 } 286 return (B_FALSE); 287 } 288 289 if (tid != base) { 290 if (!quiet) { 291 warnx("type mismatch at layer %u: found id %u, " 292 "but expecting type id %u for type %s, " 293 "symbol %s", layer, base, tid, 294 tests->cd_tname, symbol); 295 } 296 return (B_FALSE); 297 } 298 299 kind = ctf_type_kind(fp, base); 300 if (kind != tests->cd_kind) { 301 if (!quiet) { 302 warnx("type kind mismatch at layer %u: found " 303 "kind %u, but expected kind %u for %s, " 304 "symbol %s", layer, kind, tests->cd_kind, 305 tests->cd_tname, symbol); 306 } 307 return (B_FALSE); 308 } 309 310 switch (kind) { 311 case CTF_K_ARRAY: 312 if (ctf_array_info(fp, base, &ari) == CTF_ERR) { 313 if (!quiet) { 314 warnx("failed to lookup array info at " 315 "layer %u for type %s, symbol " 316 "%s: %s", base, tests->cd_tname, 317 symbol, ctf_errmsg(ctf_errno(fp))); 318 } 319 return (B_FALSE); 320 } 321 322 if (tests->cd_nents != ari.ctr_nelems) { 323 if (!quiet) { 324 warnx("array element mismatch at layer " 325 "%u for type %s, symbol %s: found " 326 "%u, expected %u", layer, 327 tests->cd_tname, symbol, 328 ari.ctr_nelems, tests->cd_nents); 329 } 330 return (B_FALSE); 331 } 332 333 tid = ctftest_lookup_type(fp, tests->cd_contents); 334 if (tid == CTF_ERR) { 335 if (!quiet) { 336 warnx("failed to look up type %s", 337 tests->cd_contents); 338 } 339 return (B_FALSE); 340 } 341 342 if (ari.ctr_contents != tid) { 343 if (!quiet) { 344 warnx("array contents mismatch at " 345 "layer %u for type %s, symbol %s: " 346 "found %u, expected %s/%u", layer, 347 tests->cd_tname, symbol, 348 ari.ctr_contents, 349 tests->cd_contents, tid); 350 } 351 return (B_FALSE); 352 } 353 base = ari.ctr_contents; 354 break; 355 default: 356 base = ctf_type_reference(fp, base); 357 break; 358 } 359 360 tests++; 361 layer++; 362 } 363 364 if (base != CTF_ERR) { 365 if (!quiet) { 366 warnx("found additional type %u in chain, " 367 "but expected no more", base); 368 } 369 return (B_FALSE); 370 } 371 372 return (B_TRUE); 373 } 374 375 int 376 ctftest_check_enum_count(const char *name, int value, void *arg) 377 { 378 uint_t *u = arg; 379 *u = *u + 1; 380 return (0); 381 } 382 383 int 384 ctftest_check_enum_value(const char *name, int value, void *arg) 385 { 386 uint_t i; 387 const check_enum_t *enums = arg; 388 389 for (i = 0; enums[i].ce_name != NULL; i++) { 390 if (strcmp(enums[i].ce_name, name) != 0) 391 continue; 392 if (enums[i].ce_value == (int64_t)value) 393 return (0); 394 warnx("enum %s value mismatch: found %d, expected %" PRId64, 395 name, value, enums[i].ce_value); 396 return (1); 397 } 398 399 warnx("found no matching entry for enum member %s", name); 400 return (1); 401 } 402 403 boolean_t 404 ctftest_check_enum(const char *type, ctf_file_t *fp, const check_enum_t *enums) 405 { 406 int ret; 407 uint_t tcount, ecount; 408 ctf_id_t base; 409 410 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 411 warnx("Failed to look up type %s", type); 412 return (B_FALSE); 413 } 414 415 if (ctf_type_kind(fp, base) != CTF_K_ENUM) { 416 warnx("%s is not an enum", type); 417 return (B_FALSE); 418 } 419 420 /* 421 * First count how many entries we have. 422 */ 423 tcount = 0; 424 while (enums[tcount].ce_name != NULL) { 425 tcount++; 426 } 427 428 ecount = 0; 429 if (ctf_enum_iter(fp, base, ctftest_check_enum_count, &ecount) != 0) { 430 warnx("failed to walk enum %s: %s", type, 431 ctf_errmsg(ctf_errno(fp))); 432 return (B_FALSE); 433 } 434 435 if (tcount != ecount) { 436 warnx("enum value mismatch: expected %u values, but found %u", 437 tcount, ecount); 438 return (B_FALSE); 439 } 440 441 if ((ret = ctf_enum_iter(fp, base, ctftest_check_enum_value, 442 (void *)enums)) != 0) { 443 if (ret == -1) { 444 warnx("failed to walk enum %s: %s", type, 445 ctf_errmsg(ctf_errno(fp))); 446 } 447 return (B_FALSE); 448 } 449 450 return (B_TRUE); 451 } 452 453 int 454 ctftest_check_member_count(const char *mname, ctf_id_t mtype, ulong_t bitoff, 455 void *arg) 456 { 457 uint_t *countp = arg; 458 *countp = *countp + 1; 459 return (0); 460 } 461 462 int 463 ctftest_check_members_cb(const char *mname, ctf_id_t mtype, ulong_t bitoff, 464 void *arg) 465 { 466 uint_t i; 467 const ctftest_member_cb_t *cmc = arg; 468 const check_member_t *members = cmc->cmc_members; 469 ctf_file_t *fp = cmc->cmc_fp; 470 471 for (i = 0; members[i].cm_name != NULL; i++) { 472 boolean_t bad = B_FALSE; 473 char buf[2048]; 474 475 if (strcmp(mname, members[i].cm_name) != 0) 476 continue; 477 478 if (bitoff != members[i].cm_offset) { 479 warnx("member %s of type %s has mismatched bit offset: " 480 "found %lu, expected %lu", mname, cmc->cmc_name, 481 bitoff, members[i].cm_offset); 482 bad = B_TRUE; 483 } 484 485 if (ctf_type_name(fp, mtype, buf, sizeof (buf)) == NULL) { 486 warnx("failed to obtain type name for member %s", 487 mname, ctf_errmsg(ctf_errno(fp))); 488 bad = B_TRUE; 489 } else if (strcmp(buf, members[i].cm_type) != 0) { 490 warnx("member %s has bad type, found %s, expected %s", 491 mname, buf, members[i].cm_type); 492 bad = B_TRUE; 493 } 494 495 return (bad ? 1 : 0); 496 } 497 498 warnx("found no matching entry for member %s of type %s", mname, 499 cmc->cmc_name); 500 return (1); 501 } 502 503 boolean_t 504 ctftest_check_members(const char *type, ctf_file_t *fp, int kind, 505 size_t size, const check_member_t *members) 506 { 507 int ret; 508 uint_t tcount, mcount; 509 ctf_id_t base; 510 ctftest_member_cb_t cmc; 511 512 if ((base = ctftest_lookup_type(fp, type)) == CTF_ERR) { 513 warnx("failed to look up type %s", type); 514 return (B_FALSE); 515 } 516 517 if (ctf_type_kind(fp, base) != kind) { 518 warnx("%s has kind %s, expected %s", type, 519 ctf_kind_name(fp, ctf_type_kind(fp, base)), 520 ctf_kind_name(fp, kind)); 521 return (B_FALSE); 522 } 523 524 if (size != ctf_type_size(fp, base)) { 525 warnx("%s has bad size, expected %lu, found %lu", 526 type, size, ctf_type_size(fp, base)); 527 return (B_FALSE); 528 } 529 530 /* 531 * First count how many entries we have. 532 */ 533 tcount = 0; 534 while (members[tcount].cm_name != NULL) { 535 tcount++; 536 } 537 538 mcount = 0; 539 if (ctf_member_iter(fp, base, ctftest_check_member_count, &mcount) != 540 0) { 541 warnx("failed to walk members of %s: %s", type, 542 ctf_errmsg(ctf_errno(fp))); 543 return (B_FALSE); 544 } 545 546 if (tcount != mcount) { 547 warnx("type member mismatch: expected %u values, but found %u", 548 tcount, mcount); 549 return (B_FALSE); 550 } 551 552 cmc.cmc_fp = fp; 553 cmc.cmc_members = members; 554 cmc.cmc_name = type; 555 if ((ret = ctf_member_iter(fp, base, ctftest_check_members_cb, 556 &cmc)) != 0) { 557 if (ret == -1) { 558 warnx("failed to walk type %s: %s", type, 559 ctf_errmsg(ctf_errno(fp))); 560 } 561 return (B_FALSE); 562 } 563 564 return (B_TRUE); 565 } 566 567 boolean_t 568 ctftest_check_function(const char *symbol, ctf_file_t *fp, const char *rtype, 569 uint_t nargs, uint_t flags, const char **argv) 570 { 571 ulong_t sym; 572 ctf_funcinfo_t fi; 573 uint_t i; 574 boolean_t ret = B_TRUE; 575 ctf_id_t *args; 576 char buf[2048]; 577 578 579 if (!ctftest_lookup_function(fp, symbol, &sym, &fi)) { 580 warnx("failed to look up function %s", symbol); 581 return (B_FALSE); 582 } 583 584 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) { 585 warnx("failed to lookup return type name for function %s", 586 symbol); 587 ret = B_FALSE; 588 } else if (strcmp(rtype, buf) != 0) { 589 warnx("return type has wrong type: found %s, expected %s", 590 buf, rtype); 591 ret = B_FALSE; 592 } 593 594 if (nargs != fi.ctc_argc) { 595 warnx("function argument mismatch: found %u, expected %u", 596 fi.ctc_argc, nargs); 597 ret = B_FALSE; 598 } 599 600 if (flags != fi.ctc_flags) { 601 warnx("function flags mismatch, found 0x%x, expected 0x%x", 602 fi.ctc_flags, flags); 603 ret = B_FALSE; 604 } 605 606 if (!ret || fi.ctc_argc == 0) { 607 return (ret); 608 } 609 610 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) { 611 warnx("failed to allocate memory for function arguments"); 612 return (B_FALSE); 613 } 614 615 if (ctf_func_args(fp, sym, fi.ctc_argc, args) != 0) { 616 warnx("failed to get function information: %s", 617 ctf_errmsg(ctf_errno(fp))); 618 free(args); 619 return (B_FALSE); 620 } 621 622 for (i = 0; i < fi.ctc_argc; i++) { 623 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) { 624 warnx("failed to obtain type name for argument %u", 625 i, ctf_errmsg(ctf_errno(fp))); 626 ret = B_FALSE; 627 break; 628 } 629 630 if (strcmp(buf, argv[i]) != 0) { 631 warnx("argument %u has wrong type: found %s, " 632 "expected %s", i, buf, argv[i]); 633 ret = B_FALSE; 634 break; 635 } 636 } 637 638 free(args); 639 return (ret); 640 } 641 642 boolean_t 643 ctftest_check_fptr(const char *type, ctf_file_t *fp, const char *rtype, 644 uint_t nargs, uint_t flags, const char **argv) 645 { 646 ctf_id_t tid; 647 ctf_funcinfo_t fi; 648 uint_t i; 649 boolean_t ret = B_TRUE; 650 ctf_id_t *args; 651 char buf[2048]; 652 653 654 if ((tid = ctf_lookup_by_name(fp, type)) == CTF_ERR) { 655 warnx("failed to look up type %s: %s", type, 656 ctf_errmsg(ctf_errno(fp))); 657 return (B_FALSE); 658 } 659 660 /* 661 * Perform two CTF type resolves, one for the function pointer and one 662 * for the typedef that gets passed in. 663 */ 664 if ((tid = ctf_type_resolve(fp, tid)) == CTF_ERR) { 665 warnx("failed to convert type %s to base type: %s", type, 666 ctf_errmsg(ctf_errno(fp))); 667 return (B_FALSE); 668 } 669 670 if (ctf_type_kind(fp, tid) == CTF_K_POINTER && 671 (tid = ctf_type_reference(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_func_info_by_id(fp, tid, &fi) != 0) { 678 warnx("failed to get function information for type %s: %s", 679 type, ctf_errmsg(ctf_errno(fp))); 680 return (B_FALSE); 681 } 682 683 if (ctf_type_name(fp, fi.ctc_return, buf, sizeof (buf)) == NULL) { 684 warnx("failed to lookup return type name for function %s", 685 type); 686 ret = B_FALSE; 687 } else if (strcmp(rtype, buf) != 0) { 688 warnx("return type has wrong type: found %s, expected %s", 689 buf, rtype); 690 ret = B_FALSE; 691 } 692 693 if (nargs != fi.ctc_argc) { 694 warnx("function argument mismatch: found %u, expected %u", 695 fi.ctc_argc, nargs); 696 ret = B_FALSE; 697 } 698 699 if (flags != fi.ctc_flags) { 700 warnx("function flags mismatch, found 0x%x, expected 0x%x", 701 fi.ctc_flags, flags); 702 ret = B_FALSE; 703 } 704 705 if (!ret || fi.ctc_argc == 0) { 706 return (ret); 707 } 708 709 if ((args = calloc(fi.ctc_argc, sizeof (ctf_id_t))) == NULL) { 710 warnx("failed to allocate memory for function arguments"); 711 return (B_FALSE); 712 } 713 714 if (ctf_func_args_by_id(fp, tid, fi.ctc_argc, args) != 0) { 715 warnx("failed to get function information: %s", 716 ctf_errmsg(ctf_errno(fp))); 717 free(args); 718 return (B_FALSE); 719 } 720 721 for (i = 0; i < fi.ctc_argc; i++) { 722 if (ctf_type_name(fp, args[i], buf, sizeof (buf)) == NULL) { 723 warnx("failed to obtain type name for argument %u", 724 i, ctf_errmsg(ctf_errno(fp))); 725 ret = B_FALSE; 726 break; 727 } 728 729 if (strcmp(buf, argv[i]) != 0) { 730 warnx("argument %u has wrong type: found %s, " 731 "expected %s", i, buf, argv[i]); 732 ret = B_FALSE; 733 break; 734 } 735 } 736 737 free(args); 738 return (ret); 739 } 740 741 typedef struct ctftest_duplicates { 742 ctf_file_t *ctd_fp; 743 char **ctd_names; 744 size_t ctd_len; 745 size_t ctd_curent; 746 boolean_t ctd_ret; 747 } ctftest_duplicates_t; 748 749 static int 750 ctftest_duplicates_cb(ctf_id_t id, boolean_t root, void *arg) 751 { 752 char buf[2048]; 753 ctftest_duplicates_t *dup = arg; 754 size_t i; 755 756 if (ctf_type_name(dup->ctd_fp, id, buf, sizeof (buf)) == NULL) { 757 warnx("failed to lookup name for id %ld", id); 758 dup->ctd_ret = B_FALSE; 759 return (1); 760 } 761 762 for (i = 0; i < dup->ctd_curent; i++) { 763 if (strcmp(buf, dup->ctd_names[i]) == 0) { 764 warnx("encountered duplicate type '%s'", buf); 765 dup->ctd_ret = B_FALSE; 766 /* 767 * Don't break out of the loop and keep going in case we 768 * find another duplicate. 769 */ 770 return (0); 771 } 772 } 773 774 if (dup->ctd_curent == dup->ctd_len) { 775 char **n; 776 size_t newlen = dup->ctd_len * 2; 777 778 n = recallocarray(dup->ctd_names, dup->ctd_len, newlen, 779 sizeof (char *)); 780 if (n == NULL) { 781 warnx("failed to resize type name array"); 782 dup->ctd_ret = B_FALSE; 783 return (1); 784 } 785 786 dup->ctd_names = n; 787 dup->ctd_len = newlen; 788 } 789 790 dup->ctd_names[dup->ctd_curent] = strdup(buf); 791 if (dup->ctd_names[dup->ctd_curent] == NULL) { 792 warn("failed to duplicate type name"); 793 dup->ctd_ret = B_FALSE; 794 return (1); 795 } 796 dup->ctd_curent++; 797 798 return (0); 799 } 800 801 boolean_t 802 ctftest_duplicates(ctf_file_t *fp) 803 { 804 size_t i; 805 ctftest_duplicates_t d; 806 807 bzero(&d, sizeof (d)); 808 d.ctd_fp = fp; 809 d.ctd_len = 4; 810 d.ctd_ret = B_TRUE; 811 d.ctd_names = recallocarray(NULL, 0, d.ctd_len, sizeof (char *)); 812 if (d.ctd_names == NULL) { 813 warnx("failed to allocate duplicate name storage"); 814 return (B_FALSE); 815 } 816 817 (void) ctf_type_iter(fp, B_TRUE, ctftest_duplicates_cb, &d); 818 819 for (i = 0; i < d.ctd_curent; i++) { 820 free(d.ctd_names[i]); 821 } 822 free(d.ctd_names); 823 824 return (d.ctd_ret); 825 }