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