1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2019, Joyent, Inc.
  14  */
  15 
  16 /*
  17  * 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 const char *
 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         return (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                 printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
 722                     name, off / NBBY, off);
 723         } else {
 724                 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         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] = "unknown_t";
 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                 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                 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                 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                 printf("};\n\n");
 809                 break;
 810         case CTF_K_TYPEDEF:
 811                 /*
 812                  * If this fails, it's probably because the referent type is in
 813                  * a parent container that was not supplied via -p.
 814                  */
 815                 if (ctfsrc_refname(id, refname, sizeof (refname)) == NULL) {
 816                         printf("typedef %s %s;\n\n", refname, name);
 817                         break;
 818                 }
 819 
 820                 if (!is_anon_refname(refname)) {
 821                         (void) ctf_type_cname(g_fp,
 822                             ctf_type_reference(g_fp, id), refname,
 823                             sizeof (refname), name);
 824 
 825                         printf("typedef %s;\n\n", refname);
 826                         break;
 827                 }
 828 
 829                 ref = ctf_type_reference(g_fp, id);
 830 
 831                 if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) {
 832                         printf("typedef enum {\n");
 833 
 834                         if (ctf_enum_iter(g_fp, ref,
 835                             ctfsrc_enum_cb, NULL) != 0) {
 836                                 ctfdump_fatal("failed to iterate enumerators "
 837                                     "of %s: %s\n", refname,
 838                                     ctf_errmsg(ctf_errno(g_fp)));
 839                         }
 840 
 841                         printf("} %s;\n\n", name);
 842                 } else {
 843                         if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) {
 844                                 ctfdump_fatal("failed to get size of %s: %s\n",
 845                                     refname, ctf_errmsg(ctf_errno(g_fp)));
 846                         }
 847 
 848                         printf("typedef %s{ /* 0x%zx bytes */\n",
 849                             refname, size);
 850 
 851                         if (ctf_member_iter(g_fp, ref,
 852                             ctfsrc_member_cb, NULL) != 0) {
 853                                 ctfdump_fatal("failed to iterate members "
 854                                     "of %s: %s\n", refname,
 855                                     ctf_errmsg(ctf_errno(g_fp)));
 856                         }
 857 
 858                         printf("} %s;\n\n", name);
 859                 }
 860 
 861                 break;
 862         case CTF_K_FORWARD:
 863                 printf("%s;\n\n", name);
 864                 break;
 865         case CTF_K_UNKNOWN:
 866         case CTF_K_INTEGER:
 867         case CTF_K_FLOAT:
 868         case CTF_K_POINTER:
 869         case CTF_K_ARRAY:
 870         case CTF_K_FUNCTION:
 871         case CTF_K_VOLATILE:
 872         case CTF_K_CONST:
 873         case CTF_K_RESTRICT:
 874                 break;
 875         default:
 876                 ctfdump_fatal("encountered unknown kind for type %s: %d\n",
 877                     name, kind);
 878                 break;
 879         }
 880 }
 881 
 882 static int
 883 ctfsrc_collect_objects_cb(const char *name, ctf_id_t id,
 884     ulong_t symidx, void *arg)
 885 {
 886         size_t *count = arg;
 887 
 888         /* local static vars can have an unknown ID */
 889         if (id == 0)
 890                 return (0);
 891 
 892         (void) strlcpy(idnames[*count].ci_name, name,
 893             sizeof (idnames[*count].ci_name));
 894         idnames[*count].ci_id = id;
 895         idnames[*count].ci_symidx = symidx;
 896         *count = *count + 1;
 897         return (0);
 898 }
 899 
 900 static void
 901 ctfsrc_object(ctf_id_t id, const char *name)
 902 {
 903         char tname[MAX_NAMELEN];
 904 
 905         if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) {
 906                 if (ctf_errno(g_fp) != ECTF_NOPARENT) {
 907                         ctfdump_fatal("type %ld missing name: %s\n", id,
 908                             ctf_errmsg(ctf_errno(g_fp)));
 909                 }
 910                 (void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
 911         }
 912 
 913         printf("extern %s;\n", tname);
 914 }
 915 
 916 static int
 917 ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
 918     ctf_funcinfo_t *ctc, void *arg)
 919 {
 920         size_t *count = arg;
 921 
 922         (void) strlcpy(idnames[*count].ci_name, name,
 923             sizeof (idnames[*count].ci_name));
 924         bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc));
 925         idnames[*count].ci_id = 0;
 926         idnames[*count].ci_symidx = symidx;
 927         *count = *count + 1;
 928         return (0);
 929 }
 930 
 931 static void
 932 ctfsrc_function(ctf_idname_t *idn)
 933 {
 934         ctf_funcinfo_t *cfi = &idn->ci_funcinfo;
 935         char name[MAX_NAMELEN] = "unknown_t";
 936 
 937         (void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name));
 938 
 939         printf("extern %s %s(", name, idn->ci_name);
 940 
 941         if (cfi->ctc_argc != 0) {
 942                 ctfdump_fargs_grow(cfi->ctc_argc);
 943                 if (ctf_func_args(g_fp, idn->ci_symidx,
 944                     g_nfargc, g_fargc) == CTF_ERR) {
 945                         ctfdump_fatal("failed to get arguments for function "
 946                             "%s: %s\n", idn->ci_name,
 947                             ctf_errmsg(ctf_errno(g_fp)));
 948                 }
 949 
 950                 for (size_t i = 0; i < cfi->ctc_argc; i++) {
 951                         ctf_id_t aid = g_fargc[i];
 952 
 953                         (void) strlcpy(name, "unknown_t", sizeof (name));
 954 
 955                         (void) ctf_type_name(g_fp, aid, name, sizeof (name));
 956 
 957                         printf("%s%s", name,
 958                             i + 1 == cfi->ctc_argc ? "" : ", ");
 959                 }
 960         } else {
 961                 if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
 962                         printf("void");
 963         }
 964 
 965         if (cfi->ctc_flags & CTF_FUNC_VARARG)
 966                 printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
 967 
 968         printf(");\n");
 969 }
 970 
 971 static int
 972 idname_compare(const void *lhs, const void *rhs)
 973 {
 974         return (strcmp(((ctf_idname_t *)lhs)->ci_name,
 975             ((ctf_idname_t *)rhs)->ci_name));
 976 }
 977 
 978 static void
 979 ctfdump_source(void)
 980 {
 981         ulong_t nr_syms = ctf_nr_syms(g_fp);
 982         ctf_id_t max_id = ctf_max_id(g_fp);
 983         size_t count = 0;
 984 
 985         printf("/* Types */\n\n");
 986 
 987         if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) {
 988                 ctfdump_fatal("failed to alloc idnames: %s\n",
 989                     strerror(errno));
 990         }
 991 
 992         /*
 993          * Prep for any unknown types (most likely, they exist in the parent,
 994          * but we weren't given the -p option).
 995          */
 996         for (size_t i = 0; i <= max_id; i++) {
 997                 (void) strlcpy(idnames[i].ci_name, "unknown_t",
 998                     sizeof (idnames[i].ci_name));
 999         }
1000 
1001         if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb,
1002             idnames) == CTF_ERR) {
1003                 warnx("failed to collect types: %s",
1004                     ctf_errmsg(ctf_errno(g_fp)));
1005                 g_exit = 1;
1006         }
1007 
1008         qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare);
1009 
1010         for (size_t i = 0; i <= max_id; i++) {
1011                 if (idnames[i].ci_id != 0)
1012                         ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name);
1013         }
1014 
1015         free(idnames);
1016 
1017         printf("\n\n/* Data Objects */\n\n");
1018 
1019         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1020                 ctfdump_fatal("failed to alloc idnames: %s\n",
1021                     strerror(errno));
1022         }
1023 
1024         if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb,
1025             &count) == CTF_ERR) {
1026                 warnx("failed to collect objects: %s",
1027                     ctf_errmsg(ctf_errno(g_fp)));
1028                 g_exit = 1;
1029         }
1030 
1031         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1032 
1033         for (size_t i = 0; i < count; i++)
1034                 ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name);
1035 
1036         free(idnames);
1037 
1038         printf("\n\n/* Functions */\n\n");
1039 
1040         if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1041                 ctfdump_fatal("failed to alloc idnames: %s\n",
1042                     strerror(errno));
1043         }
1044 
1045         count = 0;
1046 
1047         if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb,
1048             &count) == CTF_ERR) {
1049                 warnx("failed to collect functions: %s",
1050                     ctf_errmsg(ctf_errno(g_fp)));
1051                 g_exit = 1;
1052         }
1053 
1054         qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1055 
1056         for (size_t i = 0; i < count; i++)
1057                 ctfsrc_function(&idnames[i]);
1058 
1059         free(idnames);
1060 }
1061 
1062 static void
1063 ctfdump_output(const char *out)
1064 {
1065         int fd, ret;
1066         const void *data;
1067         size_t len;
1068 
1069         ctf_dataptr(g_fp, &data, &len);
1070         if ((fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
1071                 ctfdump_fatal("failed to open output file %s: %s\n", out,
1072                     strerror(errno));
1073 
1074         while (len > 0) {
1075                 ret = write(fd, data, len);
1076                 if (ret == -1 && errno == EINTR)
1077                         continue;
1078                 else if (ret == -1 && (errno == EFAULT || errno == EBADF))
1079                         abort();
1080                 else if (ret == -1)
1081                         ctfdump_fatal("failed to write to %s: %s\n", out,
1082                             strerror(errno));
1083                 data = ((char *)data) + ret;
1084                 len -= ret;
1085         }
1086 
1087         do {
1088                 ret = close(fd);
1089         } while (ret == -1 && errno == EINTR);
1090         if (ret != 0 && errno == EBADF)
1091                 abort();
1092         if (ret != 0)
1093                 ctfdump_fatal("failed to close %s: %s\n", out, strerror(errno));
1094 }
1095 
1096 int
1097 main(int argc, char *argv[])
1098 {
1099         int c, fd, err;
1100         const char *ufile = NULL, *parent = NULL;
1101 
1102         g_progname = basename(argv[0]);
1103         while ((c = getopt(argc, argv, ":cdfhlp:sStu:")) != -1) {
1104                 switch (c) {
1105                 case 'c':
1106                         g_dump |= CTFDUMP_SOURCE;
1107                         break;
1108                 case 'd':
1109                         g_dump |= CTFDUMP_OBJECTS;
1110                         break;
1111                 case 'f':
1112                         g_dump |= CTFDUMP_FUNCTIONS;
1113                         break;
1114                 case 'h':
1115                         g_dump |= CTFDUMP_HEADER;
1116                         break;
1117                 case 'l':
1118                         g_dump |= CTFDUMP_LABELS;
1119                         break;
1120                 case 'p':
1121                         parent = optarg;
1122                         break;
1123                 case 's':
1124                         g_dump |= CTFDUMP_STRINGS;
1125                         break;
1126                 case 'S':
1127                         g_dump |= CTFDUMP_STATS;
1128                         break;
1129                 case 't':
1130                         g_dump |= CTFDUMP_TYPES;
1131                         break;
1132                 case 'u':
1133                         g_dump |= CTFDUMP_OUTPUT;
1134                         ufile = optarg;
1135                         break;
1136                 case '?':
1137                         ctfdump_usage("Unknown option: -%c\n", optopt);
1138                         return (2);
1139                 case ':':
1140                         ctfdump_usage("Option -%c requires an operand\n",
1141                             optopt);
1142                         return (2);
1143                 }
1144         }
1145 
1146         argc -= optind;
1147         argv += optind;
1148 
1149         if ((g_dump & CTFDUMP_SOURCE) && !!(g_dump & ~CTFDUMP_SOURCE)) {
1150                 ctfdump_usage("-c must be specified on its own\n");
1151                 return (2);
1152         }
1153 
1154         /*
1155          * Dump all information except C source by default.
1156          */
1157         if (g_dump == 0)
1158                 g_dump = CTFDUMP_DEFAULT;
1159 
1160         if (argc != 1) {
1161                 ctfdump_usage("no file to dump\n");
1162                 return (2);
1163         }
1164 
1165         if ((fd = open(argv[0], O_RDONLY)) < 0)
1166                 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1167                     strerror(errno));
1168 
1169         g_fp = ctf_fdopen(fd, &err);
1170         if (g_fp == NULL)
1171                 ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1172                     ctf_errmsg(err));
1173 
1174         /*
1175          * Check to see if this file needs a parent. If it does not and we were
1176          * given one, that should be an error. If it does need one and the
1177          * parent is not specified, that is fine, we just won't know how to
1178          * find child types. If we are given a parent, check at least that the
1179          * labels match.
1180          */
1181         if (ctf_parent_name(g_fp) == NULL) {
1182                 if (parent != NULL)
1183                         ctfdump_fatal("cannot use %s as a parent file, %s is "
1184                             "not a child\n", parent, argv[0]);
1185         } else if (parent != NULL) {
1186                 const char *explabel, *label;
1187                 ctf_file_t *pfp = ctf_open(parent, &err);
1188 
1189                 if (pfp == NULL)
1190                         ctfdump_fatal("failed to open parent file %s: %s\n",
1191                             parent, ctf_errmsg(err));
1192 
1193                 /*
1194                  * Before we import the parent into the child, check that the
1195                  * labels match. While there is also the notion of the parent
1196                  * name, it's less straightforward to match that. Require that
1197                  * labels match.
1198                  */
1199                 explabel = ctf_parent_label(g_fp);
1200                 label = ctf_label_topmost(pfp);
1201                 if (explabel == NULL || label == NULL ||
1202                     strcmp(explabel, label) != 0) {
1203                         if (label == NULL)
1204                                 label = "<missing>";
1205                         if (explabel == NULL)
1206                                 explabel = "<missing>";
1207                         ctfdump_fatal("label mismatch between parent %s and "
1208                             "child %s, parent has %s, child expects %s\n",
1209                             parent, argv[0], label, explabel);
1210                 }
1211 
1212                 if (ctf_import(g_fp, pfp) != 0)
1213                         ctfdump_fatal("failed to import parent %s: %s\n",
1214                             parent, ctf_errmsg(ctf_errno(g_fp)));
1215         } else {
1216                 if (g_dump & CTFDUMP_SOURCE) {
1217                         printf("/* Warning: parent \"%s\" not supplied: many "
1218                             "types will be unknown. */\n\n",
1219                             ctf_parent_name(g_fp));
1220                 } else {
1221                         fprintf(stderr, "warning: parent \"%s\" not supplied: "
1222                             "many types will be unknown\n\n",
1223                             ctf_parent_name(g_fp));
1224                 }
1225         }
1226 
1227         if (g_dump & CTFDUMP_SOURCE) {
1228                 ctfdump_source();
1229                 return (0);
1230         }
1231 
1232         /*
1233          * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
1234          * We also do CTFDUMP_STATS last as a result.
1235          */
1236         if (g_dump & CTFDUMP_HEADER)
1237                 ctfdump_header();
1238 
1239         if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS))
1240                 ctfdump_labels();
1241 
1242         if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS))
1243                 ctfdump_objects();
1244 
1245         if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS))
1246                 ctfdump_functions();
1247 
1248         if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS))
1249                 ctfdump_types();
1250 
1251         if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS))
1252                 ctfdump_strings();
1253 
1254         if (g_dump & CTFDUMP_STATS)
1255                 ctfdump_stats();
1256 
1257         if (g_dump & CTFDUMP_OUTPUT)
1258                 ctfdump_output(ufile);
1259 
1260         return (g_exit);
1261 }