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 }