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
39typedef 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
52typedef 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
73typedef 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
80static ctf_idname_t *idnames;
81static const char *g_progname;
82static ctfdump_arg_t g_dump;
83static ctf_file_t *g_fp;
84static ctfdump_stat_t g_stats;
85static ctf_id_t *g_fargc;
86static int g_nfargc;
87
88static int g_exit = 0;
89
90static 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 */
111static void
112ctfdump_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
124static void
125ctfdump_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
137static void
138ctfdump_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
164static void
165ctfdump_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
173static int
174ctfdump_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
187static void
188ctfdump_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
198static void
199ctfdump_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
210static int
211ctfdump_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
242static void
243ctfdump_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
254static void
255ctfdump_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
288static int
289ctfdump_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
296static void
297ctfdump_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
307static int
308ctfdump_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
321static void
322ctfdump_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
334static void
335ctfdump_stat_int(const char *name, ulong_t value)
336{
337	ctfdump_printf(CTFDUMP_STATS, "  %-36s= %lu\n", name, value);
338}
339
340static void
341ctfdump_stat_fp(const char *name, float value)
342{
343	ctfdump_printf(CTFDUMP_STATS, "  %-36s= %.2f\n", name, value);
344}
345
346static void
347ctfdump_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
444static void
445ctfdump_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
482static int
483ctfdump_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
492static int
493ctfdump_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
501static int
502ctfdump_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
674static void
675ctfdump_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
697static const char *
698ctfsrc_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
710static int
711ctfsrc_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
739static int
740ctfsrc_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
747static int
748is_anon_refname(const char *refname)
749{
750	return ((strcmp(refname, "struct ") == 0 ||
751	    strcmp(refname, "union ") == 0 ||
752	    strcmp(refname, "enum ") == 0));
753}
754
755static int
756ctfsrc_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
765static void
766ctfsrc_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
898static int
899ctfsrc_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
916static void
917ctfsrc_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
932static int
933ctfsrc_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
947static void
948ctfsrc_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
987static int
988idname_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
994static void
995ctfdump_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
1078static void
1079ctfdump_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
1112int
1113main(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}
1278