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  * Dump information about CTF containers.
  18  */
  19 
  20 #include <stdio.h>
  21 #include <unistd.h>
  22 #include <libctf.h>
  23 #include <libgen.h>
  24 #include <stdarg.h>
  25 #include <stdlib.h>
  26 #include <stddef.h>
  27 #include <sys/sysmacros.h>
  28 #include <sys/types.h>
  29 #include <sys/stat.h>
  30 #include <sys/note.h>
  31 #include <fcntl.h>
  32 #include <errno.h>
  33 #include <string.h>
  34 #include <strings.h>
  35 #include <err.h>
  36 
  37 #define MAX_NAMELEN (512)
  38 
  39 typedef enum ctfdump_arg {
  40         CTFDUMP_OBJECTS =       0x001,
  41         CTFDUMP_FUNCTIONS =     0x002,
  42         CTFDUMP_HEADER =        0x004,
  43         CTFDUMP_LABELS =        0x008,
  44         CTFDUMP_STRINGS =       0x010,
  45         CTFDUMP_STATS =         0x020,
  46         CTFDUMP_TYPES =         0x040,
  47         CTFDUMP_DEFAULT =       0x07f,
  48         CTFDUMP_OUTPUT =        0x080,
  49         CTFDUMP_SOURCE =        0x100,
  50 } ctfdump_arg_t;
  51 
  52 typedef struct ctfdump_stat {
  53         ulong_t         cs_ndata;               /* number of data objects */
  54         ulong_t         cs_nfuncs;              /* number of functions */
  55         ulong_t         cs_nfuncargs;           /* number of function args */
  56         ulong_t         cs_nfuncmax;            /* largest number of args */
  57         ulong_t         cs_ntypes[CTF_K_MAX];   /* number of types */
  58         ulong_t         cs_nsmembs;             /* number of struct members */
  59         ulong_t         cs_nsmax;               /* largest number of members */
  60         ulong_t         cs_structsz;            /* sum of structures sizes */
  61         ulong_t         cs_sszmax;              /* largest structure */
  62         ulong_t         cs_numembs;             /* number of union members */
  63         ulong_t         cs_numax;               /* largest number of members */
  64         ulong_t         cs_unionsz;             /* sum of unions sizes */
  65         ulong_t         cs_uszmax;              /* largest union */
  66         ulong_t         cs_nemembs;             /* number of enum members */
  67         ulong_t         cs_nemax;               /* largest number of members */
  68         ulong_t         cs_nstrings;            /* number of strings */
  69         ulong_t         cs_strsz;               /* string size */
  70         ulong_t         cs_strmax;              /* longest string */
  71 } ctfdump_stat_t;
  72 
  73 typedef struct {
  74         char ci_name[MAX_NAMELEN];
  75         ctf_id_t ci_id;
  76         ulong_t ci_symidx;
  77         ctf_funcinfo_t ci_funcinfo;
  78 } ctf_idname_t;
  79 
  80 static ctf_idname_t *idnames;
  81 static const char *g_progname;
  82 static ctfdump_arg_t g_dump;
  83 static ctf_file_t *g_fp;
  84 static ctfdump_stat_t g_stats;
  85 static ctf_id_t *g_fargc;
  86 static int g_nfargc;
  87 
  88 static int g_exit = 0;
  89 
  90 static const char *ctfdump_fpenc[] = {
  91         NULL,
  92         "SINGLE",
  93         "DOUBLE",
  94         "COMPLEX",
  95         "DCOMPLEX",
  96         "LDCOMPLEX",
  97         "LDOUBLE",
  98         "INTERVAL",
  99         "DINTERVAL",
 100         "LDINTERVAL",
 101         "IMAGINARY",
 102         "DIMAGINARY",
 103         "LDIMAGINARY"
 104 };
 105 
 106 /*
 107  * When stats are requested, we have to go through everything. To make our lives
 108  * easier, we'll just always allow the code to print everything out, but only
 109  * output it if we have actually enabled that section.
 110  */
 111 static void
 112 ctfdump_printf(ctfdump_arg_t arg, const char *fmt, ...)
 113 {
 114         va_list ap;
 115 
 116         if ((arg & g_dump) == 0)
 117                 return;
 118 
 119         va_start(ap, fmt);
 120         (void) vfprintf(stdout, fmt, ap);
 121         va_end(ap);
 122 }
 123 
 124 static void
 125 ctfdump_fatal(const char *fmt, ...)
 126 {
 127         va_list ap;
 128 
 129         (void) fprintf(stderr, "%s: ", g_progname);
 130         va_start(ap, fmt);
 131         (void) vfprintf(stderr, fmt, ap);
 132         va_end(ap);
 133 
 134         exit(1);
 135 }
 136 
 137 static void
 138 ctfdump_usage(const char *fmt, ...)
 139 {
 140         if (fmt != NULL) {
 141                 va_list ap;
 142                 (void) fprintf(stderr, "%s: ", g_progname);
 143                 va_start(ap, fmt);
 144                 (void) vfprintf(stderr, fmt, ap);
 145                 va_end(ap);
 146         }
 147 
 148         (void) fprintf(stderr, "Usage: %s [-cdfhlsSt] [-p parent] [-u outfile] "
 149             "file\n"
 150             "\n"
 151             "\t-c  dump C-style output\n"
 152             "\t-d  dump object data\n"
 153             "\t-f  dump function data\n"
 154             "\t-h  dump the CTF header\n"
 155             "\t-l  dump the label table\n"
 156             "\t-p  use parent to supply additional information\n"
 157             "\t-s  dump the string table\n"
 158             "\t-S  dump statistics about the CTF container\n"
 159             "\t-t  dump type information\n"
 160             "\t-u  dump uncompressed CTF data to outfile\n",
 161             g_progname);
 162 }
 163 
 164 static void
 165 ctfdump_title(ctfdump_arg_t arg, const char *header)
 166 {
 167         static const char line[] = "----------------------------------------"
 168             "----------------------------------------";
 169         ctfdump_printf(arg, "\n- %s %.*s\n\n", header, (int)78 - strlen(header),
 170             line);
 171 }
 172 
 173 static int
 174 ctfdump_objects_cb(const char *name, ctf_id_t id, ulong_t symidx, void *arg)
 175 {
 176         _NOTE(ARGUNUSED(arg));
 177 
 178         int len;
 179 
 180         len = snprintf(NULL, 0, "  [%lu] %ld", g_stats.cs_ndata, id);
 181         ctfdump_printf(CTFDUMP_OBJECTS, "  [%lu] %ld %*s%s (%lu)\n",
 182             g_stats.cs_ndata, id, MAX(15 - len, 0), "", name, symidx);
 183         g_stats.cs_ndata++;
 184         return (0);
 185 }
 186 
 187 static void
 188 ctfdump_objects(void)
 189 {
 190         ctfdump_title(CTFDUMP_OBJECTS, "Data Objects");
 191         if (ctf_object_iter(g_fp, ctfdump_objects_cb, NULL) == CTF_ERR) {
 192                 warnx("failed to dump objects: %s",
 193                     ctf_errmsg(ctf_errno(g_fp)));
 194                 g_exit = 1;
 195         }
 196 }
 197 
 198 static void
 199 ctfdump_fargs_grow(int nargs)
 200 {
 201         if (g_nfargc < nargs) {
 202                 g_fargc = realloc(g_fargc, sizeof (ctf_id_t) * nargs);
 203                 if (g_fargc == NULL)
 204                         ctfdump_fatal("failed to get memory for %d "
 205                             "ctf_id_t's\n", nargs);
 206                 g_nfargc = nargs;
 207         }
 208 }
 209 
 210 static int
 211 ctfdump_functions_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *ctc,
 212     void *arg)
 213 {
 214         _NOTE(ARGUNUSED(arg));
 215         int i;
 216 
 217         if (ctc->ctc_argc != 0) {
 218                 ctfdump_fargs_grow(ctc->ctc_argc);
 219                 if (ctf_func_args(g_fp, symidx, g_nfargc, g_fargc) == CTF_ERR)
 220                         ctfdump_fatal("failed to get arguments for function "
 221                             "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 222         }
 223 
 224         ctfdump_printf(CTFDUMP_FUNCTIONS,
 225             "  [%lu] %s (%lu) returns: %ld args: (", g_stats.cs_nfuncs, name,
 226             symidx, ctc->ctc_return);
 227         for (i = 0; i < ctc->ctc_argc; i++)
 228                 ctfdump_printf(CTFDUMP_FUNCTIONS, "%ld%s", g_fargc[i],
 229                     i + 1 == ctc->ctc_argc ? "" : ", ");
 230         if (ctc->ctc_flags & CTF_FUNC_VARARG)
 231                 ctfdump_printf(CTFDUMP_FUNCTIONS, "%s...",
 232                     ctc->ctc_argc == 0 ? "" : ", ");
 233         ctfdump_printf(CTFDUMP_FUNCTIONS, ")\n");
 234 
 235         g_stats.cs_nfuncs++;
 236         g_stats.cs_nfuncargs += ctc->ctc_argc;
 237         g_stats.cs_nfuncmax = MAX(ctc->ctc_argc, g_stats.cs_nfuncmax);
 238 
 239         return (0);
 240 }
 241 
 242 static void
 243 ctfdump_functions(void)
 244 {
 245         ctfdump_title(CTFDUMP_FUNCTIONS, "Functions");
 246 
 247         if (ctf_function_iter(g_fp, ctfdump_functions_cb, NULL) == CTF_ERR) {
 248                 warnx("failed to dump functions: %s",
 249                     ctf_errmsg(ctf_errno(g_fp)));
 250                 g_exit = 1;
 251         }
 252 }
 253 
 254 static void
 255 ctfdump_header(void)
 256 {
 257         const ctf_header_t *hp;
 258         const char *parname, *parlabel;
 259 
 260         ctfdump_title(CTFDUMP_HEADER, "CTF Header");
 261         ctf_dataptr(g_fp, (const void **)&hp, NULL);
 262         ctfdump_printf(CTFDUMP_HEADER, "  cth_magic    = 0x%04x\n",
 263             hp->cth_magic);
 264         ctfdump_printf(CTFDUMP_HEADER, "  cth_version  = %u\n",
 265             hp->cth_version);
 266         ctfdump_printf(CTFDUMP_HEADER, "  cth_flags    = 0x%02x\n",
 267             ctf_flags(g_fp));
 268         parname = ctf_parent_name(g_fp);
 269         parlabel = ctf_parent_label(g_fp);
 270         ctfdump_printf(CTFDUMP_HEADER, "  cth_parlabel = %s\n",
 271             parlabel == NULL ? "(anon)" : parlabel);
 272         ctfdump_printf(CTFDUMP_HEADER, "  cth_parname  = %s\n",
 273             parname == NULL ? "(anon)" : parname);
 274         ctfdump_printf(CTFDUMP_HEADER, "  cth_lbloff   = %u\n",
 275             hp->cth_lbloff);
 276         ctfdump_printf(CTFDUMP_HEADER, "  cth_objtoff  = %u\n",
 277             hp->cth_objtoff);
 278         ctfdump_printf(CTFDUMP_HEADER, "  cth_funcoff  = %u\n",
 279             hp->cth_funcoff);
 280         ctfdump_printf(CTFDUMP_HEADER, "  cth_typeoff  = %u\n",
 281             hp->cth_typeoff);
 282         ctfdump_printf(CTFDUMP_HEADER, "  cth_stroff   = %u\n",
 283             hp->cth_stroff);
 284         ctfdump_printf(CTFDUMP_HEADER, "  cth_strlen   = %u\n",
 285             hp->cth_strlen);
 286 }
 287 
 288 static int
 289 ctfdump_labels_cb(const char *name, const ctf_lblinfo_t *li, void *arg)
 290 {
 291         _NOTE(ARGUNUSED(arg));
 292         ctfdump_printf(CTFDUMP_LABELS, "  %5ld %s\n", li->ctb_typeidx, name);
 293         return (0);
 294 }
 295 
 296 static void
 297 ctfdump_labels(void)
 298 {
 299         ctfdump_title(CTFDUMP_LABELS, "Label Table");
 300         if (ctf_label_iter(g_fp, ctfdump_labels_cb, NULL) == CTF_ERR) {
 301                 warnx("failed to dump labels: %s",
 302                     ctf_errmsg(ctf_errno(g_fp)));
 303                 g_exit = 1;
 304         }
 305 }
 306 
 307 static int
 308 ctfdump_strings_cb(const char *s, void *arg)
 309 {
 310         size_t len = strlen(s) + 1;
 311         ulong_t *stroff = arg;
 312         ctfdump_printf(CTFDUMP_STRINGS, "  [%lu] %s\n", *stroff,
 313             *s == '\0' ? "\\0" : s);
 314         *stroff = *stroff + len;
 315         g_stats.cs_nstrings++;
 316         g_stats.cs_strsz += len;
 317         g_stats.cs_strmax = MAX(g_stats.cs_strmax, len);
 318         return (0);
 319 }
 320 
 321 static void
 322 ctfdump_strings(void)
 323 {
 324         ulong_t stroff = 0;
 325 
 326         ctfdump_title(CTFDUMP_STRINGS, "String Table");
 327         if (ctf_string_iter(g_fp, ctfdump_strings_cb, &stroff) == CTF_ERR) {
 328                 warnx("failed to dump strings: %s",
 329                     ctf_errmsg(ctf_errno(g_fp)));
 330                 g_exit = 1;
 331         }
 332 }
 333 
 334 static void
 335 ctfdump_stat_int(const char *name, ulong_t value)
 336 {
 337         ctfdump_printf(CTFDUMP_STATS, "  %-36s= %lu\n", name, value);
 338 }
 339 
 340 static void
 341 ctfdump_stat_fp(const char *name, float value)
 342 {
 343         ctfdump_printf(CTFDUMP_STATS, "  %-36s= %.2f\n", name, value);
 344 }
 345 
 346 static void
 347 ctfdump_stats(void)
 348 {
 349         int i;
 350         ulong_t sum;
 351 
 352         ctfdump_title(CTFDUMP_STATS, "CTF Statistics");
 353 
 354         ctfdump_stat_int("total number of data objects", g_stats.cs_ndata);
 355         ctfdump_printf(CTFDUMP_STATS, "\n");
 356         ctfdump_stat_int("total number of functions", g_stats.cs_nfuncs);
 357         ctfdump_stat_int("total number of function arguments",
 358             g_stats.cs_nfuncargs);
 359         ctfdump_stat_int("maximum argument list length", g_stats.cs_nfuncmax);
 360         if (g_stats.cs_nfuncs != 0)
 361                 ctfdump_stat_fp("average argument list length",
 362                     (float)g_stats.cs_nfuncargs / (float)g_stats.cs_nfuncs);
 363         ctfdump_printf(CTFDUMP_STATS, "\n");
 364 
 365         sum = 0;
 366         for (i = 0; i < CTF_K_MAX; i++)
 367                 sum += g_stats.cs_ntypes[i];
 368         ctfdump_stat_int("total number of types", sum);
 369         ctfdump_stat_int("total number of integers",
 370             g_stats.cs_ntypes[CTF_K_INTEGER]);
 371         ctfdump_stat_int("total number of floats",
 372             g_stats.cs_ntypes[CTF_K_FLOAT]);
 373         ctfdump_stat_int("total number of pointers",
 374             g_stats.cs_ntypes[CTF_K_POINTER]);
 375         ctfdump_stat_int("total number of arrays",
 376             g_stats.cs_ntypes[CTF_K_ARRAY]);
 377         ctfdump_stat_int("total number of func types",
 378             g_stats.cs_ntypes[CTF_K_FUNCTION]);
 379         ctfdump_stat_int("total number of structs",
 380             g_stats.cs_ntypes[CTF_K_STRUCT]);
 381         ctfdump_stat_int("total number of unions",
 382             g_stats.cs_ntypes[CTF_K_UNION]);
 383         ctfdump_stat_int("total number of enums",
 384             g_stats.cs_ntypes[CTF_K_ENUM]);
 385         ctfdump_stat_int("total number of forward tags",
 386             g_stats.cs_ntypes[CTF_K_FORWARD]);
 387         ctfdump_stat_int("total number of typedefs",
 388             g_stats.cs_ntypes[CTF_K_TYPEDEF]);
 389         ctfdump_stat_int("total number of volatile types",
 390             g_stats.cs_ntypes[CTF_K_VOLATILE]);
 391         ctfdump_stat_int("total number of const types",
 392             g_stats.cs_ntypes[CTF_K_CONST]);
 393         ctfdump_stat_int("total number of restrict types",
 394             g_stats.cs_ntypes[CTF_K_RESTRICT]);
 395         ctfdump_stat_int("total number of unknowns (holes)",
 396             g_stats.cs_ntypes[CTF_K_UNKNOWN]);
 397 
 398         ctfdump_printf(CTFDUMP_STATS, "\n");
 399         ctfdump_stat_int("total number of struct members", g_stats.cs_nsmembs);
 400         ctfdump_stat_int("maximum number of struct members", g_stats.cs_nsmax);
 401         ctfdump_stat_int("total size of all structs", g_stats.cs_structsz);
 402         ctfdump_stat_int("maximum size of a struct", g_stats.cs_sszmax);
 403         if (g_stats.cs_ntypes[CTF_K_STRUCT] != 0) {
 404                 ctfdump_stat_fp("average number of struct members",
 405                     (float)g_stats.cs_nsmembs /
 406                     (float)g_stats.cs_ntypes[CTF_K_STRUCT]);
 407                 ctfdump_stat_fp("average size of a struct",
 408                     (float)g_stats.cs_structsz /
 409                     (float)g_stats.cs_ntypes[CTF_K_STRUCT]);
 410         }
 411         ctfdump_printf(CTFDUMP_STATS, "\n");
 412         ctfdump_stat_int("total number of union members", g_stats.cs_numembs);
 413         ctfdump_stat_int("maximum number of union members", g_stats.cs_numax);
 414         ctfdump_stat_int("total size of all unions", g_stats.cs_unionsz);
 415         ctfdump_stat_int("maximum size of a union", g_stats.cs_uszmax);
 416         if (g_stats.cs_ntypes[CTF_K_UNION] != 0) {
 417                 ctfdump_stat_fp("average number of union members",
 418                     (float)g_stats.cs_numembs /
 419                     (float)g_stats.cs_ntypes[CTF_K_UNION]);
 420                 ctfdump_stat_fp("average size of a union",
 421                     (float)g_stats.cs_unionsz /
 422                     (float)g_stats.cs_ntypes[CTF_K_UNION]);
 423         }
 424         ctfdump_printf(CTFDUMP_STATS, "\n");
 425 
 426         ctfdump_stat_int("total number of enum members", g_stats.cs_nemembs);
 427         ctfdump_stat_int("maximum number of enum members", g_stats.cs_nemax);
 428         if (g_stats.cs_ntypes[CTF_K_ENUM] != 0) {
 429                 ctfdump_stat_fp("average number of enum members",
 430                     (float)g_stats.cs_nemembs /
 431                     (float)g_stats.cs_ntypes[CTF_K_ENUM]);
 432         }
 433         ctfdump_printf(CTFDUMP_STATS, "\n");
 434 
 435         ctfdump_stat_int("total number of strings", g_stats.cs_nstrings);
 436         ctfdump_stat_int("bytes of string data", g_stats.cs_strsz);
 437         ctfdump_stat_int("maximum string length", g_stats.cs_strmax);
 438         if (g_stats.cs_nstrings != 0)
 439                 ctfdump_stat_fp("average string length",
 440                     (float)g_stats.cs_strsz / (float)g_stats.cs_nstrings);
 441         ctfdump_printf(CTFDUMP_STATS, "\n");
 442 }
 443 
 444 static void
 445 ctfdump_intenc_name(ctf_encoding_t *cte, char *buf, int len)
 446 {
 447         int off = 0;
 448         boolean_t space = B_FALSE;
 449 
 450         if (cte->cte_format == 0 || (cte->cte_format &
 451             ~(CTF_INT_SIGNED | CTF_INT_CHAR | CTF_INT_BOOL |
 452             CTF_INT_VARARGS)) != 0) {
 453                 (void) snprintf(buf, len, "0x%x", cte->cte_format);
 454                 return;
 455         }
 456 
 457         if (cte->cte_format & CTF_INT_SIGNED) {
 458                 off += snprintf(buf + off, MAX(len - off, 0), "%sSIGNED",
 459                     space == B_TRUE ? " " : "");
 460                 space = B_TRUE;
 461         }
 462 
 463         if (cte->cte_format & CTF_INT_CHAR) {
 464                 off += snprintf(buf + off, MAX(len - off, 0), "%sCHAR",
 465                     space == B_TRUE ? " " : "");
 466                 space = B_TRUE;
 467         }
 468 
 469         if (cte->cte_format & CTF_INT_BOOL) {
 470                 off += snprintf(buf + off, MAX(len - off, 0), "%sBOOL",
 471                     space == B_TRUE ? " " : "");
 472                 space = B_TRUE;
 473         }
 474 
 475         if (cte->cte_format & CTF_INT_VARARGS) {
 476                 off += snprintf(buf + off, MAX(len - off, 0), "%sVARARGS",
 477                     space == B_TRUE ? " " : "");
 478                 space = B_TRUE;
 479         }
 480 }
 481 
 482 static int
 483 ctfdump_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
 484 {
 485         int *count = arg;
 486         ctfdump_printf(CTFDUMP_TYPES, "\t%s type=%ld off=%lu\n", member, type,
 487             off);
 488         *count = *count + 1;
 489         return (0);
 490 }
 491 
 492 static int
 493 ctfdump_enum_cb(const char *name, int value, void *arg)
 494 {
 495         int *count = arg;
 496         ctfdump_printf(CTFDUMP_TYPES, "\t%s = %d\n", name, value);
 497         *count = *count + 1;
 498         return (0);
 499 }
 500 
 501 static int
 502 ctfdump_types_cb(ctf_id_t id, boolean_t root, void *arg)
 503 {
 504         _NOTE(ARGUNUSED(arg));
 505         int kind, i, count;
 506         ctf_id_t ref;
 507         char name[MAX_NAMELEN], ienc[128];
 508         const char *encn;
 509         ctf_funcinfo_t ctc;
 510         ctf_arinfo_t ar;
 511         ctf_encoding_t cte;
 512         ssize_t size;
 513 
 514         if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR)
 515                 ctfdump_fatal("encountered malformed ctf, type %s does not "
 516                     "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 517 
 518         if (ctf_type_name(g_fp, id, name, sizeof (name)) == NULL) {
 519                 if (ctf_errno(g_fp) != ECTF_NOPARENT)
 520                         ctfdump_fatal("type %ld missing name: %s\n", id,
 521                             ctf_errmsg(ctf_errno(g_fp)));
 522                 (void) snprintf(name, sizeof (name), "(unknown %s)",
 523                     ctf_kind_name(g_fp, kind));
 524         }
 525 
 526         g_stats.cs_ntypes[kind]++;
 527         if (root == B_TRUE)
 528                 ctfdump_printf(CTFDUMP_TYPES, "  <%ld> ", id);
 529         else
 530                 ctfdump_printf(CTFDUMP_TYPES, "  [%ld] ", id);
 531 
 532         switch (kind) {
 533         case CTF_K_UNKNOWN:
 534                 break;
 535         case CTF_K_INTEGER:
 536                 if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR)
 537                         ctfdump_fatal("failed to get encoding information "
 538                             "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 539                 ctfdump_intenc_name(&cte, ienc, sizeof (ienc));
 540                 ctfdump_printf(CTFDUMP_TYPES,
 541                     "%s encoding=%s offset=%u bits=%u",
 542                     name, ienc, cte.cte_offset, cte.cte_bits);
 543                 break;
 544         case CTF_K_FLOAT:
 545                 if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR)
 546                         ctfdump_fatal("failed to get encoding information "
 547                             "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 548                 if (cte.cte_format < 1 || cte.cte_format > 12)
 549                         encn = "unknown";
 550                 else
 551                         encn = ctfdump_fpenc[cte.cte_format];
 552                 ctfdump_printf(CTFDUMP_TYPES, "%s encoding=%s offset=%u "
 553                     "bits=%u", name, encn, cte.cte_offset, cte.cte_bits);
 554                 break;
 555         case CTF_K_POINTER:
 556                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 557                         ctfdump_fatal("failed to get reference type for %s: "
 558                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 559                 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
 560                     ref);
 561                 break;
 562         case CTF_K_ARRAY:
 563                 if (ctf_array_info(g_fp, id, &ar) == CTF_ERR)
 564                         ctfdump_fatal("failed to get array information for "
 565                             "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 566                 ctfdump_printf(CTFDUMP_TYPES, "%s contents: %ld, index: %ld",
 567                     name, ar.ctr_contents, ar.ctr_index);
 568                 break;
 569         case CTF_K_FUNCTION:
 570                 if (ctf_func_info_by_id(g_fp, id, &ctc) == CTF_ERR)
 571                         ctfdump_fatal("failed to get function info for %s: "
 572                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 573                 if (ctc.ctc_argc > 0) {
 574                         ctfdump_fargs_grow(ctc.ctc_argc);
 575                         if (ctf_func_args_by_id(g_fp, id, g_nfargc, g_fargc) ==
 576                             CTF_ERR)
 577                                 ctfdump_fatal("failed to get function "
 578                                     "arguments for %s: %s\n", name,
 579                                     ctf_errmsg(ctf_errno(g_fp)));
 580                 }
 581                 ctfdump_printf(CTFDUMP_TYPES,
 582                     "%s returns: %ld args: (", name, ctc.ctc_return);
 583                 for (i = 0; i < ctc.ctc_argc; i++) {
 584                         ctfdump_printf(CTFDUMP_TYPES, "%ld%s", g_fargc[i],
 585                             i + 1 == ctc.ctc_argc ? "" : ", ");
 586                 }
 587                 if (ctc.ctc_flags & CTF_FUNC_VARARG)
 588                         ctfdump_printf(CTFDUMP_TYPES, "%s...",
 589                             ctc.ctc_argc == 0 ? "" : ", ");
 590                 ctfdump_printf(CTFDUMP_TYPES, ")");
 591                 break;
 592         case CTF_K_STRUCT:
 593         case CTF_K_UNION:
 594                 size = ctf_type_size(g_fp, id);
 595                 if (size == CTF_ERR)
 596                         ctfdump_fatal("failed to get size of %s: %s\n", name,
 597                             ctf_errmsg(ctf_errno(g_fp)));
 598                 ctfdump_printf(CTFDUMP_TYPES, "%s (%zd bytes)\n", name, size);
 599                 count = 0;
 600                 if (ctf_member_iter(g_fp, id, ctfdump_member_cb, &count) != 0)
 601                         ctfdump_fatal("failed to iterate members of %s: %s\n",
 602                             name, ctf_errmsg(ctf_errno(g_fp)));
 603                 if (kind == CTF_K_STRUCT) {
 604                         g_stats.cs_nsmembs += count;
 605                         g_stats.cs_nsmax = MAX(count, g_stats.cs_nsmax);
 606                         g_stats.cs_structsz += size;
 607                         g_stats.cs_sszmax = MAX(size, g_stats.cs_sszmax);
 608                 } else {
 609                         g_stats.cs_numembs += count;
 610                         g_stats.cs_numax = MAX(count, g_stats.cs_numax);
 611                         g_stats.cs_unionsz += size;
 612                         g_stats.cs_uszmax = MAX(count, g_stats.cs_uszmax);
 613                 }
 614                 break;
 615         case CTF_K_ENUM:
 616                 ctfdump_printf(CTFDUMP_TYPES, "%s\n", name);
 617                 count = 0;
 618                 if (ctf_enum_iter(g_fp, id, ctfdump_enum_cb, &count) != 0)
 619                         ctfdump_fatal("failed to iterate enumerators of %s: "
 620                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 621                 g_stats.cs_nemembs += count;
 622                 g_stats.cs_nemax = MAX(g_stats.cs_nemax, count);
 623                 break;
 624         case CTF_K_FORWARD:
 625                 ctfdump_printf(CTFDUMP_TYPES, "forward %s\n", name);
 626                 break;
 627         case CTF_K_TYPEDEF:
 628                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 629                         ctfdump_fatal("failed to get reference type for %s: "
 630                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 631                 ctfdump_printf(CTFDUMP_TYPES, "typedef %s refers to %ld", name,
 632                     ref);
 633                 break;
 634         case CTF_K_VOLATILE:
 635                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 636                         ctfdump_fatal("failed to get reference type for %s: "
 637                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 638                 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
 639                     ref);
 640                 break;
 641         case CTF_K_CONST:
 642                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 643                         ctfdump_fatal("failed to get reference type for %s: "
 644                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 645                 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
 646                     ref);
 647                 break;
 648         case CTF_K_RESTRICT:
 649                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 650                         ctfdump_fatal("failed to get reference type for %s: "
 651                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 652                 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
 653                     ref);
 654                 break;
 655         default:
 656                 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
 657                     name, kind);
 658         }
 659 
 660         ctfdump_printf(CTFDUMP_TYPES, "\n");
 661 
 662         return (0);
 663 }
 664 
 665 static void
 666 ctfdump_types(void)
 667 {
 668         ctfdump_title(CTFDUMP_TYPES, "Types");
 669 
 670         if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) {
 671                 warnx("failed to dump types: %s",
 672                     ctf_errmsg(ctf_errno(g_fp)));
 673                 g_exit = 1;
 674         }
 675 }
 676 
 677 /*
 678  * C-style output. This is designed mainly for comparison purposes, and doesn't
 679  * produce directly valid C:
 680  *
 681  * - the declarations are sorted alphabetically not semantically
 682  * - anonymous enums without other users are elided (e.g. IDCS_PROBE_SENT)
 683  * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t)
 684  * - anon unions declared within SOUs aren't expanded
 685  * - function arguments aren't expanded recursively
 686  */
 687 
 688 static void
 689 ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize)
 690 {
 691         ctf_id_t ref;
 692 
 693         if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) {
 694                 ctfdump_fatal("failed to get reference type for %ld: "
 695                     "%s\n", id, ctf_errmsg(ctf_errno(g_fp)));
 696         }
 697 
 698         (void) ctf_type_name(g_fp, ref, buf, bufsize);
 699 }
 700 
 701 static int
 702 ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
 703 {
 704         _NOTE(ARGUNUSED(arg));
 705         char name[MAX_NAMELEN];
 706 
 707         if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) {
 708                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 709                         ctfdump_fatal("type %ld missing name: %s\n", type,
 710                             ctf_errmsg(ctf_errno(g_fp)));
 711                 }
 712 
 713                 (void) snprintf(name, sizeof (name), "unknown_t %s", member);
 714         }
 715 
 716         /*
 717          * A byte offset is friendlier, but we'll print bits too if it's not
 718          * aligned (i.e. a bitfield).
 719          */
 720         if (off % NBBY != 0) {
 721                 (void) printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
 722                     name, off / NBBY, off);
 723         } else {
 724                 (void) printf("\t%s; /* offset: %lu bytes */\n",
 725                     name, off / NBBY);
 726         }
 727         return (0);
 728 }
 729 
 730 static int
 731 ctfsrc_enum_cb(const char *name, int value, void *arg)
 732 {
 733         _NOTE(ARGUNUSED(arg));
 734         (void) printf("\t%s = %d,\n", name, value);
 735         return (0);
 736 }
 737 
 738 static int
 739 is_anon_refname(const char *refname)
 740 {
 741         return ((strcmp(refname, "struct ") == 0 ||
 742             strcmp(refname, "union ") == 0 ||
 743             strcmp(refname, "enum ") == 0));
 744 }
 745 
 746 static int
 747 ctfsrc_collect_types_cb(ctf_id_t id, boolean_t root, void *arg)
 748 {
 749         _NOTE(ARGUNUSED(root, arg));
 750         (void) ctf_type_name(g_fp, id, idnames[id].ci_name,
 751             sizeof (idnames[id].ci_name));
 752         idnames[id].ci_id = id;
 753         return (0);
 754 }
 755 
 756 static void
 757 ctfsrc_type(ctf_id_t id, const char *name)
 758 {
 759         char refname[MAX_NAMELEN];
 760         ctf_id_t ref;
 761         ssize_t size;
 762         int kind;
 763 
 764         if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) {
 765                 ctfdump_fatal("encountered malformed ctf, type %s does not "
 766                     "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 767         }
 768 
 769         switch (kind) {
 770         case CTF_K_STRUCT:
 771         case CTF_K_UNION:
 772                 /*
 773                  * Delay printing anonymous SOUs; a later typedef will usually
 774                  * pick them up.
 775                  */
 776                 if (is_anon_refname(name))
 777                         break;
 778 
 779                 if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) {
 780                         ctfdump_fatal("failed to get size of %s: %s\n", name,
 781                             ctf_errmsg(ctf_errno(g_fp)));
 782                 }
 783 
 784                 (void) printf("%s { /* 0x%x bytes */\n", name, size);
 785 
 786                 if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) {
 787                         ctfdump_fatal("failed to iterate members of %s: %s\n",
 788                             name, ctf_errmsg(ctf_errno(g_fp)));
 789                 }
 790 
 791                 (void) printf("};\n\n");
 792                 break;
 793         case CTF_K_ENUM:
 794                 /*
 795                  * This will throw away any anon enum that isn't followed by a
 796                  * typedef...
 797                  */
 798                 if (is_anon_refname(name))
 799                         break;
 800 
 801                 (void) printf("%s {\n", name);
 802 
 803                 if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) {
 804                         ctfdump_fatal("failed to iterate enumerators of %s: "
 805                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 806                 }
 807 
 808                 (void) printf("};\n\n");
 809                 break;
 810         case CTF_K_TYPEDEF:
 811                 ctfsrc_refname(id, refname, sizeof (refname));
 812 
 813                 if (!is_anon_refname(refname)) {
 814                         (void) ctf_type_cname(g_fp,
 815                             ctf_type_reference(g_fp, id), refname,
 816                             sizeof (refname), name);
 817 
 818                         (void) printf("typedef %s;\n\n", refname);
 819                         break;
 820                 }
 821 
 822                 ref = ctf_type_reference(g_fp, id);
 823 
 824                 if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) {
 825                         (void) printf("typedef enum {\n");
 826 
 827                         if (ctf_enum_iter(g_fp, ref,
 828                             ctfsrc_enum_cb, NULL) != 0) {
 829                                 ctfdump_fatal("failed to iterate enumerators "
 830                                     "of %s: %s\n", refname,
 831                                     ctf_errmsg(ctf_errno(g_fp)));
 832                         }
 833 
 834                         (void) printf("} %s;\n\n", name);
 835                 } else {
 836                         if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) {
 837                                 ctfdump_fatal("failed to get size of %s: %s\n",
 838                                     refname, ctf_errmsg(ctf_errno(g_fp)));
 839                         }
 840 
 841                         (void) printf("typedef %s{ /* 0x%zx bytes */\n",
 842                             refname, size);
 843 
 844                         if (ctf_member_iter(g_fp, ref,
 845                             ctfsrc_member_cb, NULL) != 0) {
 846                                 ctfdump_fatal("failed to iterate members "
 847                                     "of %s: %s\n", refname,
 848                                     ctf_errmsg(ctf_errno(g_fp)));
 849                         }
 850 
 851                         (void) printf("} %s;\n\n", name);
 852                 }
 853 
 854                 break;
 855         case CTF_K_FORWARD:
 856                 (void) printf("%s;\n\n", name);
 857                 break;
 858         case CTF_K_UNKNOWN:
 859         case CTF_K_INTEGER:
 860         case CTF_K_FLOAT:
 861         case CTF_K_POINTER:
 862         case CTF_K_ARRAY:
 863         case CTF_K_FUNCTION:
 864         case CTF_K_VOLATILE:
 865         case CTF_K_CONST:
 866         case CTF_K_RESTRICT:
 867                 break;
 868         default:
 869                 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
 870                     name, kind);
 871                 break;
 872         }
 873 }
 874 
 875 static int
 876 ctfsrc_collect_objects_cb(const char *name, ctf_id_t id,
 877     ulong_t symidx, void *arg)
 878 {
 879         size_t *count = arg;
 880 
 881         /* local static vars can have an unknown ID */
 882         if (id == 0)
 883                 return (0);
 884 
 885         (void) strlcpy(idnames[*count].ci_name, name,
 886             sizeof (idnames[*count].ci_name));
 887         idnames[*count].ci_id = id;
 888         idnames[*count].ci_symidx = symidx;
 889         *count = *count + 1;
 890         return (0);
 891 }
 892 
 893 static void
 894 ctfsrc_object(ctf_id_t id, const char *name)
 895 {
 896         char tname[MAX_NAMELEN];
 897 
 898         if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) {
 899                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 900                         ctfdump_fatal("type %ld missing name: %s\n", id,
 901                             ctf_errmsg(ctf_errno(g_fp)));
 902                 }
 903                 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
 904         }
 905 
 906         (void) printf("extern %s;\n", tname);
 907 }
 908 
 909 static int
 910 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
 911     ctf_funcinfo_t *ctc, void *arg)
 912 {
 913         size_t *count = arg;
 914 
 915         (void) strlcpy(idnames[*count].ci_name, name,
 916             sizeof (idnames[*count].ci_name));
 917         bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc));
 918         idnames[*count].ci_id = 0;
 919         idnames[*count].ci_symidx = symidx;
 920         *count = *count + 1;
 921         return (0);
 922 }
 923 
 924 static void
 925 ctfsrc_function(ctf_idname_t *idn)
 926 {
 927         ctf_funcinfo_t *cfi = &idn->ci_funcinfo;
 928         char name[MAX_NAMELEN] = "unknown_t";
 929 
 930         (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name));
 931 
 932         (void) printf("extern %s %s(", name, idn->ci_name);
 933 
 934         if (cfi->ctc_argc != 0) {
 935                 ctfdump_fargs_grow(cfi->ctc_argc);
 936                 if (ctf_func_args(g_fp, idn->ci_symidx,
 937                     g_nfargc, g_fargc) == CTF_ERR) {
 938                         ctfdump_fatal("failed to get arguments for function "
 939                             "%s: %s\n", idn->ci_name,
 940                             ctf_errmsg(ctf_errno(g_fp)));
 941                 }
 942 
 943                 for (size_t i = 0; i < cfi->ctc_argc; i++) {
 944                         ctf_id_t aid = g_fargc[i];
 945 
 946                         name[0] = '\0';
 947 
 948                         (void) ctf_type_name(g_fp, aid, name, sizeof (name));
 949 
 950                         (void) printf("%s%s", name,
 951                             i + 1 == cfi->ctc_argc ? "" : ", ");
 952                 }
 953         } else {
 954                 if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
 955                         (void) printf("void");
 956         }
 957 
 958         if (cfi->ctc_flags & CTF_FUNC_VARARG)
 959                 (void) printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
 960 
 961         (void) printf(");\n");
 962 }
 963 
 964 static int
 965 idname_compare(const void *lhs, const void *rhs)
 966 {
 967         return (strcmp(((ctf_idname_t *)lhs)->ci_name,
 968             ((ctf_idname_t *)rhs)->ci_name));
 969 }
 970 
 971 static void
 972 ctfdump_source(void)
 973 {
 974         ulong_t nr_syms = ctf_nr_syms(g_fp);
 975         ctf_id_t max_id = ctf_max_id(g_fp);
 976         size_t count = 0;
 977 
 978         (void) printf("/* Types */\n\n");
 979 
 980         if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) {
 981                 ctfdump_fatal("failed to alloc idnames: %s\n",
 982                     strerror(errno));
 983         }
 984 
 985         if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb,
 986             idnames) == CTF_ERR) {
 987                 warnx("failed to collect types: %s",
 988                     ctf_errmsg(ctf_errno(g_fp)));
 989                 g_exit = 1;
 990         }
 991 
 992         qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare);
 993 
 994         for (size_t i = 0; i < max_id; i++) {
 995                 if (idnames[i].ci_id != 0)
 996                         ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name);
 997         }
 998 
 999         free(idnames);
1000 
1001         (void) printf("\n\n/* Data Objects */\n\n");
1002 
1003         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1004                 ctfdump_fatal("failed to alloc idnames: %s\n",
1005                     strerror(errno));
1006         }
1007 
1008         if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb,
1009             &count) == CTF_ERR) {
1010                 warnx("failed to collect objects: %s",
1011                     ctf_errmsg(ctf_errno(g_fp)));
1012                 g_exit = 1;
1013         }
1014 
1015         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1016 
1017         for (size_t i = 0; i < count; i++)
1018                 ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name);
1019 
1020         free(idnames);
1021 
1022         (void) printf("\n\n/* Functions */\n\n");
1023 
1024         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1025                 ctfdump_fatal("failed to alloc idnames: %s\n",
1026                     strerror(errno));
1027         }
1028 
1029         count = 0;
1030 
1031         if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb,
1032             &count) == CTF_ERR) {
1033                 warnx("failed to collect functions: %s",
1034                     ctf_errmsg(ctf_errno(g_fp)));
1035                 g_exit = 1;
1036         }
1037 
1038         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1039 
1040         for (size_t i = 0; i < count; i++)
1041                 ctfsrc_function(&idnames[i]);
1042 
1043         free(idnames);
1044 }
1045 
1046 static void
1047 ctfdump_output(const char *out)
1048 {
1049         int fd, ret;
1050         const void *data;
1051         size_t len;
1052 
1053         ctf_dataptr(g_fp, &data, &len);
1054         if ((fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
1055                 ctfdump_fatal("failed to open output file %s: %s\n", out,
1056                     strerror(errno));
1057 
1058         while (len > 0) {
1059                 ret = write(fd, data, len);
1060                 if (ret == -1 && errno == EINTR)
1061                         continue;
1062                 else if (ret == -1 && (errno == EFAULT || errno == EBADF))
1063                         abort();
1064                 else if (ret == -1)
1065                         ctfdump_fatal("failed to write to %s: %s\n", out,
1066                             strerror(errno));
1067                 data = ((char *)data) + ret;
1068                 len -= ret;
1069         }
1070 
1071         do {
1072                 ret = close(fd);
1073         } while (ret == -1 && errno == EINTR);
1074         if (ret != 0 && errno == EBADF)
1075                 abort();
1076         if (ret != 0)
1077                 ctfdump_fatal("failed to close %s: %s\n", out, strerror(errno));
1078 }
1079 
1080 int
1081 main(int argc, char *argv[])
1082 {
1083         int c, fd, err;
1084         const char *ufile = NULL, *parent = NULL;
1085 
1086         g_progname = basename(argv[0]);
1087         while ((c = getopt(argc, argv, ":cdfhlp:sStu:")) != -1) {
1088                 switch (c) {
1089                 case 'c':
1090                         g_dump |= CTFDUMP_SOURCE;
1091                         break;
1092                 case 'd':
1093                         g_dump |= CTFDUMP_OBJECTS;
1094                         break;
1095                 case 'f':
1096                         g_dump |= CTFDUMP_FUNCTIONS;
1097                         break;
1098                 case 'h':
1099                         g_dump |= CTFDUMP_HEADER;
1100                         break;
1101                 case 'l':
1102                         g_dump |= CTFDUMP_LABELS;
1103                         break;
1104                 case 'p':
1105                         parent = optarg;
1106                         break;
1107                 case 's':
1108                         g_dump |= CTFDUMP_STRINGS;
1109                         break;
1110                 case 'S':
1111                         g_dump |= CTFDUMP_STATS;
1112                         break;
1113                 case 't':
1114                         g_dump |= CTFDUMP_TYPES;
1115                         break;
1116                 case 'u':
1117                         g_dump |= CTFDUMP_OUTPUT;
1118                         ufile = optarg;
1119                         break;
1120                 case '?':
1121                         ctfdump_usage("Unknown option: -%c\n", optopt);
1122                         return (2);
1123                 case ':':
1124                         ctfdump_usage("Option -%c requires an operand\n",
1125                             optopt);
1126                         return (2);
1127                 }
1128         }
1129 
1130         argc -= optind;
1131         argv += optind;
1132 
1133         if ((g_dump & CTFDUMP_SOURCE) && !!(g_dump & ~CTFDUMP_SOURCE)) {
1134                 ctfdump_usage("-c must be specified on its own\n");
1135                 return (2);
1136         }
1137 
1138         /*
1139          * Dump all information except C source by default.
1140          */
1141         if (g_dump == 0)
1142                 g_dump = CTFDUMP_DEFAULT;
1143 
1144         if (argc != 1) {
1145                 ctfdump_usage("no file to dump\n");
1146                 return (2);
1147         }
1148 
1149         if ((fd = open(argv[0], O_RDONLY)) < 0)
1150                 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1151                     strerror(errno));
1152 
1153         g_fp = ctf_fdopen(fd, &err);
1154         if (g_fp == NULL)
1155                 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1156                     ctf_errmsg(err));
1157 
1158         /*
1159          * Check to see if this file needs a parent. If it does not and we were
1160          * given one, that should be an error. If it does need one and the
1161          * parent is not specified, that is fine, we just won't know how to
1162          * find child types. If we are given a parent, check at least that the
1163          * labels match.
1164          */
1165         if (ctf_parent_name(g_fp) == NULL) {
1166                 if (parent != NULL)
1167                         ctfdump_fatal("cannot use %s as a parent file, %s is "
1168                             "not a child\n", parent, argv[0]);
1169         } else if (parent != NULL) {
1170                 const char *explabel, *label;
1171                 ctf_file_t *pfp = ctf_open(parent, &err);
1172 
1173                 if (pfp == NULL)
1174                         ctfdump_fatal("failed to open parent file %s: %s\n",
1175                             parent, ctf_errmsg(err));
1176 
1177                 /*
1178                  * Before we import the parent into the child, check that the
1179                  * labels match. While there is also the notion of the parent
1180                  * name, it's less straightforward to match that. Require that
1181                  * labels match.
1182                  */
1183                 explabel = ctf_parent_label(g_fp);
1184                 label = ctf_label_topmost(pfp);
1185                 if (explabel == NULL || label == NULL ||
1186                     strcmp(explabel, label) != 0) {
1187                         if (label == NULL)
1188                                 label = "<missing>";
1189                         if (explabel == NULL)
1190                                 explabel = "<missing>";
1191                         ctfdump_fatal("label mismatch between parent %s and "
1192                             "child %s, parent has %s, child expects %s\n",
1193                             parent, argv[0], label, explabel);
1194                 }
1195 
1196                 if (ctf_import(g_fp, pfp) != 0)
1197                         ctfdump_fatal("failed to import parent %s: %s\n",
1198                             parent, ctf_errmsg(ctf_errno(g_fp)));
1199         }
1200 
1201         if (g_dump & CTFDUMP_SOURCE) {
1202                 ctfdump_source();
1203                 return (0);
1204         }
1205 
1206         /*
1207          * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
1208          * We also do CTFDUMP_STATS last as a result.
1209          */
1210         if (g_dump & CTFDUMP_HEADER)
1211                 ctfdump_header();
1212 
1213         if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS))
1214                 ctfdump_labels();
1215 
1216         if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS))
1217                 ctfdump_objects();
1218 
1219         if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS))
1220                 ctfdump_functions();
1221 
1222         if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS))
1223                 ctfdump_types();
1224 
1225         if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS))
1226                 ctfdump_strings();
1227 
1228         if (g_dump & CTFDUMP_STATS)
1229                 ctfdump_stats();
1230 
1231         if (g_dump & CTFDUMP_OUTPUT)
1232                 ctfdump_output(ufile);
1233 
1234         return (g_exit);
1235 }