1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2020 Joyent, Inc.
  14  */
  15 
  16 /*
  17  * 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                 size = ctf_type_size(g_fp, id);
 617 
 618                 /* Only the oddest enums are worth reporting on size. */
 619                 if (size != CTF_ERR && size != sizeof (int)) {
 620                         ctfdump_printf(CTFDUMP_TYPES, "%s (%zd bytes)\n",
 621                             name, size);
 622                 } else {
 623                         ctfdump_printf(CTFDUMP_TYPES, "%s\n", name);
 624                 }
 625 
 626                 count = 0;
 627                 if (ctf_enum_iter(g_fp, id, ctfdump_enum_cb, &count) != 0)
 628                         ctfdump_fatal("failed to iterate enumerators of %s: "
 629                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 630                 g_stats.cs_nemembs += count;
 631                 g_stats.cs_nemax = MAX(g_stats.cs_nemax, count);
 632                 break;
 633         case CTF_K_FORWARD:
 634                 ctfdump_printf(CTFDUMP_TYPES, "forward %s\n", name);
 635                 break;
 636         case CTF_K_TYPEDEF:
 637                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 638                         ctfdump_fatal("failed to get reference type for %s: "
 639                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 640                 ctfdump_printf(CTFDUMP_TYPES, "typedef %s refers to %ld", name,
 641                     ref);
 642                 break;
 643         case CTF_K_VOLATILE:
 644                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 645                         ctfdump_fatal("failed to get reference type for %s: "
 646                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 647                 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
 648                     ref);
 649                 break;
 650         case CTF_K_CONST:
 651                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 652                         ctfdump_fatal("failed to get reference type for %s: "
 653                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 654                 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
 655                     ref);
 656                 break;
 657         case CTF_K_RESTRICT:
 658                 if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
 659                         ctfdump_fatal("failed to get reference type for %s: "
 660                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 661                 ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
 662                     ref);
 663                 break;
 664         default:
 665                 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
 666                     name, kind);
 667         }
 668 
 669         ctfdump_printf(CTFDUMP_TYPES, "\n");
 670 
 671         return (0);
 672 }
 673 
 674 static void
 675 ctfdump_types(void)
 676 {
 677         ctfdump_title(CTFDUMP_TYPES, "Types");
 678 
 679         if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) {
 680                 warnx("failed to dump types: %s",
 681                     ctf_errmsg(ctf_errno(g_fp)));
 682                 g_exit = 1;
 683         }
 684 }
 685 
 686 /*
 687  * C-style output. This is designed mainly for comparison purposes, and doesn't
 688  * produce directly valid C:
 689  *
 690  * - the declarations are sorted alphabetically not semantically
 691  * - anonymous enums without other users are elided (e.g. IDCS_PROBE_SENT)
 692  * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t)
 693  * - anon unions declared within SOUs aren't expanded
 694  * - function arguments aren't expanded recursively
 695  */
 696 
 697 static const char *
 698 ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize)
 699 {
 700         ctf_id_t ref;
 701 
 702         if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) {
 703                 ctfdump_fatal("failed to get reference type for %ld: "
 704                     "%s\n", id, ctf_errmsg(ctf_errno(g_fp)));
 705         }
 706 
 707         return (ctf_type_name(g_fp, ref, buf, bufsize));
 708 }
 709 
 710 static int
 711 ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
 712 {
 713         _NOTE(ARGUNUSED(arg));
 714         char name[MAX_NAMELEN];
 715 
 716         if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) {
 717                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 718                         ctfdump_fatal("type %ld missing name: %s\n", type,
 719                             ctf_errmsg(ctf_errno(g_fp)));
 720                 }
 721 
 722                 (void) snprintf(name, sizeof (name), "unknown_t %s", member);
 723         }
 724 
 725         /*
 726          * A byte offset is friendlier, but we'll print bits too if it's not
 727          * aligned (i.e. a bitfield).
 728          */
 729         if (off % NBBY != 0) {
 730                 printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
 731                     name, off / NBBY, off);
 732         } else {
 733                 printf("\t%s; /* offset: %lu bytes */\n",
 734                     name, off / NBBY);
 735         }
 736         return (0);
 737 }
 738 
 739 static int
 740 ctfsrc_enum_cb(const char *name, int value, void *arg)
 741 {
 742         _NOTE(ARGUNUSED(arg));
 743         printf("\t%s = %d,\n", name, value);
 744         return (0);
 745 }
 746 
 747 static int
 748 is_anon_refname(const char *refname)
 749 {
 750         return ((strcmp(refname, "struct ") == 0 ||
 751             strcmp(refname, "union ") == 0 ||
 752             strcmp(refname, "enum ") == 0));
 753 }
 754 
 755 static int
 756 ctfsrc_collect_types_cb(ctf_id_t id, boolean_t root, void *arg)
 757 {
 758         _NOTE(ARGUNUSED(root, arg));
 759         (void) ctf_type_name(g_fp, id, idnames[id].ci_name,
 760             sizeof (idnames[id].ci_name));
 761         idnames[id].ci_id = id;
 762         return (0);
 763 }
 764 
 765 static void
 766 ctfsrc_type(ctf_id_t id, const char *name)
 767 {
 768         char refname[MAX_NAMELEN] = "unknown_t";
 769         ctf_id_t ref;
 770         ssize_t size;
 771         int kind;
 772 
 773         if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) {
 774                 ctfdump_fatal("encountered malformed ctf, type %s does not "
 775                     "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 776         }
 777 
 778         switch (kind) {
 779         case CTF_K_STRUCT:
 780         case CTF_K_UNION:
 781                 /*
 782                  * Delay printing anonymous SOUs; a later typedef will usually
 783                  * pick them up.
 784                  */
 785                 if (is_anon_refname(name))
 786                         break;
 787 
 788                 if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) {
 789                         ctfdump_fatal("failed to get size of %s: %s\n", name,
 790                             ctf_errmsg(ctf_errno(g_fp)));
 791                 }
 792 
 793                 printf("%s { /* 0x%x bytes */\n", name, size);
 794 
 795                 if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) {
 796                         ctfdump_fatal("failed to iterate members of %s: %s\n",
 797                             name, ctf_errmsg(ctf_errno(g_fp)));
 798                 }
 799 
 800                 printf("};\n\n");
 801                 break;
 802         case CTF_K_ENUM:
 803                 /*
 804                  * This will throw away any anon enum that isn't followed by a
 805                  * typedef...
 806                  */
 807                 if (is_anon_refname(name))
 808                         break;
 809 
 810                 printf("%s {\n", name);
 811 
 812                 if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) {
 813                         ctfdump_fatal("failed to iterate enumerators of %s: "
 814                             "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
 815                 }
 816 
 817                 size = ctf_type_size(g_fp, id);
 818 
 819                 /* Only the oddest enums are worth reporting on size. */
 820                 if (size != CTF_ERR && size != sizeof (int)) {
 821                         printf("} /* 0x%x bytes */;\n\n", size);
 822                 } else {
 823                         printf("};\n\n");
 824                 }
 825                 break;
 826         case CTF_K_TYPEDEF:
 827                 /*
 828                  * If this fails, it's probably because the referent type is in
 829                  * a parent container that was not supplied via -p.
 830                  */
 831                 if (ctfsrc_refname(id, refname, sizeof (refname)) == NULL) {
 832                         printf("typedef %s %s;\n\n", refname, name);
 833                         break;
 834                 }
 835 
 836                 if (!is_anon_refname(refname)) {
 837                         (void) ctf_type_cname(g_fp,
 838                             ctf_type_reference(g_fp, id), refname,
 839                             sizeof (refname), name);
 840 
 841                         printf("typedef %s;\n\n", refname);
 842                         break;
 843                 }
 844 
 845                 ref = ctf_type_reference(g_fp, id);
 846 
 847                 if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) {
 848                         printf("typedef enum {\n");
 849 
 850                         if (ctf_enum_iter(g_fp, ref,
 851                             ctfsrc_enum_cb, NULL) != 0) {
 852                                 ctfdump_fatal("failed to iterate enumerators "
 853                                     "of %s: %s\n", refname,
 854                                     ctf_errmsg(ctf_errno(g_fp)));
 855                         }
 856 
 857                         printf("} %s;\n\n", name);
 858                 } else {
 859                         if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) {
 860                                 ctfdump_fatal("failed to get size of %s: %s\n",
 861                                     refname, ctf_errmsg(ctf_errno(g_fp)));
 862                         }
 863 
 864                         printf("typedef %s{ /* 0x%zx bytes */\n",
 865                             refname, size);
 866 
 867                         if (ctf_member_iter(g_fp, ref,
 868                             ctfsrc_member_cb, NULL) != 0) {
 869                                 ctfdump_fatal("failed to iterate members "
 870                                     "of %s: %s\n", refname,
 871                                     ctf_errmsg(ctf_errno(g_fp)));
 872                         }
 873 
 874                         printf("} %s;\n\n", name);
 875                 }
 876 
 877                 break;
 878         case CTF_K_FORWARD:
 879                 printf("%s;\n\n", name);
 880                 break;
 881         case CTF_K_UNKNOWN:
 882         case CTF_K_INTEGER:
 883         case CTF_K_FLOAT:
 884         case CTF_K_POINTER:
 885         case CTF_K_ARRAY:
 886         case CTF_K_FUNCTION:
 887         case CTF_K_VOLATILE:
 888         case CTF_K_CONST:
 889         case CTF_K_RESTRICT:
 890                 break;
 891         default:
 892                 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
 893                     name, kind);
 894                 break;
 895         }
 896 }
 897 
 898 static int
 899 ctfsrc_collect_objects_cb(const char *name, ctf_id_t id,
 900     ulong_t symidx, void *arg)
 901 {
 902         size_t *count = arg;
 903 
 904         /* local static vars can have an unknown ID */
 905         if (id == 0)
 906                 return (0);
 907 
 908         (void) strlcpy(idnames[*count].ci_name, name,
 909             sizeof (idnames[*count].ci_name));
 910         idnames[*count].ci_id = id;
 911         idnames[*count].ci_symidx = symidx;
 912         *count = *count + 1;
 913         return (0);
 914 }
 915 
 916 static void
 917 ctfsrc_object(ctf_id_t id, const char *name)
 918 {
 919         char tname[MAX_NAMELEN];
 920 
 921         if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) {
 922                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 923                         ctfdump_fatal("type %ld missing name: %s\n", id,
 924                             ctf_errmsg(ctf_errno(g_fp)));
 925                 }
 926                 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
 927         }
 928 
 929         printf("extern %s;\n", tname);
 930 }
 931 
 932 static int
 933 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
 934     ctf_funcinfo_t *ctc, void *arg)
 935 {
 936         size_t *count = arg;
 937 
 938         (void) strlcpy(idnames[*count].ci_name, name,
 939             sizeof (idnames[*count].ci_name));
 940         bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc));
 941         idnames[*count].ci_id = 0;
 942         idnames[*count].ci_symidx = symidx;
 943         *count = *count + 1;
 944         return (0);
 945 }
 946 
 947 static void
 948 ctfsrc_function(ctf_idname_t *idn)
 949 {
 950         ctf_funcinfo_t *cfi = &idn->ci_funcinfo;
 951         char name[MAX_NAMELEN] = "unknown_t";
 952 
 953         (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name));
 954 
 955         printf("extern %s %s(", name, idn->ci_name);
 956 
 957         if (cfi->ctc_argc != 0) {
 958                 ctfdump_fargs_grow(cfi->ctc_argc);
 959                 if (ctf_func_args(g_fp, idn->ci_symidx,
 960                     g_nfargc, g_fargc) == CTF_ERR) {
 961                         ctfdump_fatal("failed to get arguments for function "
 962                             "%s: %s\n", idn->ci_name,
 963                             ctf_errmsg(ctf_errno(g_fp)));
 964                 }
 965 
 966                 for (size_t i = 0; i < cfi->ctc_argc; i++) {
 967                         ctf_id_t aid = g_fargc[i];
 968 
 969                         (void) strlcpy(name, "unknown_t", sizeof (name));
 970 
 971                         (void) ctf_type_name(g_fp, aid, name, sizeof (name));
 972 
 973                         printf("%s%s", name,
 974                             i + 1 == cfi->ctc_argc ? "" : ", ");
 975                 }
 976         } else {
 977                 if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
 978                         printf("void");
 979         }
 980 
 981         if (cfi->ctc_flags & CTF_FUNC_VARARG)
 982                 printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
 983 
 984         printf(");\n");
 985 }
 986 
 987 static int
 988 idname_compare(const void *lhs, const void *rhs)
 989 {
 990         return (strcmp(((ctf_idname_t *)lhs)->ci_name,
 991             ((ctf_idname_t *)rhs)->ci_name));
 992 }
 993 
 994 static void
 995 ctfdump_source(void)
 996 {
 997         ulong_t nr_syms = ctf_nr_syms(g_fp);
 998         ctf_id_t max_id = ctf_max_id(g_fp);
 999         size_t count = 0;
1000 
1001         printf("/* Types */\n\n");
1002 
1003         if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) {
1004                 ctfdump_fatal("failed to alloc idnames: %s\n",
1005                     strerror(errno));
1006         }
1007 
1008         /*
1009          * Prep for any unknown types (most likely, they exist in the parent,
1010          * but we weren't given the -p option).
1011          */
1012         for (size_t i = 0; i <= max_id; i++) {
1013                 (void) strlcpy(idnames[i].ci_name, "unknown_t",
1014                     sizeof (idnames[i].ci_name));
1015         }
1016 
1017         if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb,
1018             idnames) == CTF_ERR) {
1019                 warnx("failed to collect types: %s",
1020                     ctf_errmsg(ctf_errno(g_fp)));
1021                 g_exit = 1;
1022         }
1023 
1024         qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare);
1025 
1026         for (size_t i = 0; i <= max_id; i++) {
1027                 if (idnames[i].ci_id != 0)
1028                         ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name);
1029         }
1030 
1031         free(idnames);
1032 
1033         printf("\n\n/* Data Objects */\n\n");
1034 
1035         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1036                 ctfdump_fatal("failed to alloc idnames: %s\n",
1037                     strerror(errno));
1038         }
1039 
1040         if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb,
1041             &count) == CTF_ERR) {
1042                 warnx("failed to collect objects: %s",
1043                     ctf_errmsg(ctf_errno(g_fp)));
1044                 g_exit = 1;
1045         }
1046 
1047         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1048 
1049         for (size_t i = 0; i < count; i++)
1050                 ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name);
1051 
1052         free(idnames);
1053 
1054         printf("\n\n/* Functions */\n\n");
1055 
1056         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1057                 ctfdump_fatal("failed to alloc idnames: %s\n",
1058                     strerror(errno));
1059         }
1060 
1061         count = 0;
1062 
1063         if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb,
1064             &count) == CTF_ERR) {
1065                 warnx("failed to collect functions: %s",
1066                     ctf_errmsg(ctf_errno(g_fp)));
1067                 g_exit = 1;
1068         }
1069 
1070         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1071 
1072         for (size_t i = 0; i < count; i++)
1073                 ctfsrc_function(&idnames[i]);
1074 
1075         free(idnames);
1076 }
1077 
1078 static void
1079 ctfdump_output(const char *out)
1080 {
1081         int fd, ret;
1082         const void *data;
1083         size_t len;
1084 
1085         ctf_dataptr(g_fp, &data, &len);
1086         if ((fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
1087                 ctfdump_fatal("failed to open output file %s: %s\n", out,
1088                     strerror(errno));
1089 
1090         while (len > 0) {
1091                 ret = write(fd, data, len);
1092                 if (ret == -1 && errno == EINTR)
1093                         continue;
1094                 else if (ret == -1 && (errno == EFAULT || errno == EBADF))
1095                         abort();
1096                 else if (ret == -1)
1097                         ctfdump_fatal("failed to write to %s: %s\n", out,
1098                             strerror(errno));
1099                 data = ((char *)data) + ret;
1100                 len -= ret;
1101         }
1102 
1103         do {
1104                 ret = close(fd);
1105         } while (ret == -1 && errno == EINTR);
1106         if (ret != 0 && errno == EBADF)
1107                 abort();
1108         if (ret != 0)
1109                 ctfdump_fatal("failed to close %s: %s\n", out, strerror(errno));
1110 }
1111 
1112 int
1113 main(int argc, char *argv[])
1114 {
1115         int c, fd, err;
1116         const char *ufile = NULL, *parent = NULL;
1117 
1118         g_progname = basename(argv[0]);
1119         while ((c = getopt(argc, argv, ":cdfhlp:sStu:")) != -1) {
1120                 switch (c) {
1121                 case 'c':
1122                         g_dump |= CTFDUMP_SOURCE;
1123                         break;
1124                 case 'd':
1125                         g_dump |= CTFDUMP_OBJECTS;
1126                         break;
1127                 case 'f':
1128                         g_dump |= CTFDUMP_FUNCTIONS;
1129                         break;
1130                 case 'h':
1131                         g_dump |= CTFDUMP_HEADER;
1132                         break;
1133                 case 'l':
1134                         g_dump |= CTFDUMP_LABELS;
1135                         break;
1136                 case 'p':
1137                         parent = optarg;
1138                         break;
1139                 case 's':
1140                         g_dump |= CTFDUMP_STRINGS;
1141                         break;
1142                 case 'S':
1143                         g_dump |= CTFDUMP_STATS;
1144                         break;
1145                 case 't':
1146                         g_dump |= CTFDUMP_TYPES;
1147                         break;
1148                 case 'u':
1149                         g_dump |= CTFDUMP_OUTPUT;
1150                         ufile = optarg;
1151                         break;
1152                 case '?':
1153                         ctfdump_usage("Unknown option: -%c\n", optopt);
1154                         return (2);
1155                 case ':':
1156                         ctfdump_usage("Option -%c requires an operand\n",
1157                             optopt);
1158                         return (2);
1159                 }
1160         }
1161 
1162         argc -= optind;
1163         argv += optind;
1164 
1165         if ((g_dump & CTFDUMP_SOURCE) && !!(g_dump & ~CTFDUMP_SOURCE)) {
1166                 ctfdump_usage("-c must be specified on its own\n");
1167                 return (2);
1168         }
1169 
1170         /*
1171          * Dump all information except C source by default.
1172          */
1173         if (g_dump == 0)
1174                 g_dump = CTFDUMP_DEFAULT;
1175 
1176         if (argc != 1) {
1177                 ctfdump_usage("no file to dump\n");
1178                 return (2);
1179         }
1180 
1181         if ((fd = open(argv[0], O_RDONLY)) < 0)
1182                 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1183                     strerror(errno));
1184 
1185         g_fp = ctf_fdopen(fd, &err);
1186         if (g_fp == NULL)
1187                 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1188                     ctf_errmsg(err));
1189 
1190         /*
1191          * Check to see if this file needs a parent. If it does not and we were
1192          * given one, that should be an error. If it does need one and the
1193          * parent is not specified, that is fine, we just won't know how to
1194          * find child types. If we are given a parent, check at least that the
1195          * labels match.
1196          */
1197         if (ctf_parent_name(g_fp) == NULL) {
1198                 if (parent != NULL)
1199                         ctfdump_fatal("cannot use %s as a parent file, %s is "
1200                             "not a child\n", parent, argv[0]);
1201         } else if (parent != NULL) {
1202                 const char *explabel, *label;
1203                 ctf_file_t *pfp = ctf_open(parent, &err);
1204 
1205                 if (pfp == NULL)
1206                         ctfdump_fatal("failed to open parent file %s: %s\n",
1207                             parent, ctf_errmsg(err));
1208 
1209                 /*
1210                  * Before we import the parent into the child, check that the
1211                  * labels match. While there is also the notion of the parent
1212                  * name, it's less straightforward to match that. Require that
1213                  * labels match.
1214                  */
1215                 explabel = ctf_parent_label(g_fp);
1216                 label = ctf_label_topmost(pfp);
1217                 if (explabel == NULL || label == NULL ||
1218                     strcmp(explabel, label) != 0) {
1219                         if (label == NULL)
1220                                 label = "<missing>";
1221                         if (explabel == NULL)
1222                                 explabel = "<missing>";
1223                         ctfdump_fatal("label mismatch between parent %s and "
1224                             "child %s, parent has %s, child expects %s\n",
1225                             parent, argv[0], label, explabel);
1226                 }
1227 
1228                 if (ctf_import(g_fp, pfp) != 0)
1229                         ctfdump_fatal("failed to import parent %s: %s\n",
1230                             parent, ctf_errmsg(ctf_errno(g_fp)));
1231         } else {
1232                 if (g_dump & CTFDUMP_SOURCE) {
1233                         printf("/* Warning: parent \"%s\" not supplied: many "
1234                             "types will be unknown. */\n\n",
1235                             ctf_parent_name(g_fp));
1236                 } else {
1237                         fprintf(stderr, "warning: parent \"%s\" not supplied: "
1238                             "many types will be unknown\n\n",
1239                             ctf_parent_name(g_fp));
1240                 }
1241         }
1242 
1243         if (g_dump & CTFDUMP_SOURCE) {
1244                 ctfdump_source();
1245                 return (0);
1246         }
1247 
1248         /*
1249          * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
1250          * We also do CTFDUMP_STATS last as a result.
1251          */
1252         if (g_dump & CTFDUMP_HEADER)
1253                 ctfdump_header();
1254 
1255         if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS))
1256                 ctfdump_labels();
1257 
1258         if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS))
1259                 ctfdump_objects();
1260 
1261         if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS))
1262                 ctfdump_functions();
1263 
1264         if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS))
1265                 ctfdump_types();
1266 
1267         if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS))
1268                 ctfdump_strings();
1269 
1270         if (g_dump & CTFDUMP_STATS)
1271                 ctfdump_stats();
1272 
1273         if (g_dump & CTFDUMP_OUTPUT)
1274                 ctfdump_output(ufile);
1275 
1276         return (g_exit);
1277 }