xref: /illumos-gate/usr/src/cmd/ctfdump/ctfdump.c (revision db9597bf)
1bc1f688bSRobert Mustacchi /*
2bc1f688bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3bc1f688bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4bc1f688bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5bc1f688bSRobert Mustacchi  * 1.0 of the CDDL.
6bc1f688bSRobert Mustacchi  *
7bc1f688bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8bc1f688bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9bc1f688bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10bc1f688bSRobert Mustacchi  */
11bc1f688bSRobert Mustacchi 
12bc1f688bSRobert Mustacchi /*
13fe2dc8bdSJohn Levon  * Copyright 2020 Joyent, Inc.
14*db9597bfSRobert Mustacchi  * Copyright 2022 Oxide Computer Company
15bc1f688bSRobert Mustacchi  */
16bc1f688bSRobert Mustacchi 
17bc1f688bSRobert Mustacchi /*
18bc1f688bSRobert Mustacchi  * Dump information about CTF containers.
19bc1f688bSRobert Mustacchi  */
20bc1f688bSRobert Mustacchi 
21bc1f688bSRobert Mustacchi #include <stdio.h>
22bc1f688bSRobert Mustacchi #include <unistd.h>
23bc1f688bSRobert Mustacchi #include <libctf.h>
24bc1f688bSRobert Mustacchi #include <libgen.h>
25bc1f688bSRobert Mustacchi #include <stdarg.h>
26bc1f688bSRobert Mustacchi #include <stdlib.h>
27bc1f688bSRobert Mustacchi #include <stddef.h>
28bc1f688bSRobert Mustacchi #include <sys/sysmacros.h>
29bc1f688bSRobert Mustacchi #include <sys/types.h>
30bc1f688bSRobert Mustacchi #include <sys/stat.h>
31bc1f688bSRobert Mustacchi #include <sys/note.h>
32bc1f688bSRobert Mustacchi #include <fcntl.h>
33bc1f688bSRobert Mustacchi #include <errno.h>
34bc1f688bSRobert Mustacchi #include <string.h>
35bc1f688bSRobert Mustacchi #include <strings.h>
36bc1f688bSRobert Mustacchi #include <err.h>
37bc1f688bSRobert Mustacchi 
38bc1f688bSRobert Mustacchi #define	MAX_NAMELEN (512)
39bc1f688bSRobert Mustacchi 
40bc1f688bSRobert Mustacchi typedef enum ctfdump_arg {
41bc1f688bSRobert Mustacchi 	CTFDUMP_OBJECTS =	0x001,
42bc1f688bSRobert Mustacchi 	CTFDUMP_FUNCTIONS =	0x002,
43bc1f688bSRobert Mustacchi 	CTFDUMP_HEADER =	0x004,
44bc1f688bSRobert Mustacchi 	CTFDUMP_LABELS =	0x008,
45bc1f688bSRobert Mustacchi 	CTFDUMP_STRINGS =	0x010,
46bc1f688bSRobert Mustacchi 	CTFDUMP_STATS =		0x020,
47bc1f688bSRobert Mustacchi 	CTFDUMP_TYPES =		0x040,
48bc1f688bSRobert Mustacchi 	CTFDUMP_DEFAULT =	0x07f,
49bc1f688bSRobert Mustacchi 	CTFDUMP_OUTPUT =	0x080,
50bc1f688bSRobert Mustacchi 	CTFDUMP_SOURCE =	0x100,
51bc1f688bSRobert Mustacchi } ctfdump_arg_t;
52bc1f688bSRobert Mustacchi 
53bc1f688bSRobert Mustacchi typedef struct ctfdump_stat {
54bc1f688bSRobert Mustacchi 	ulong_t		cs_ndata;		/* number of data objects */
55bc1f688bSRobert Mustacchi 	ulong_t		cs_nfuncs;		/* number of functions */
56bc1f688bSRobert Mustacchi 	ulong_t		cs_nfuncargs;		/* number of function args */
57bc1f688bSRobert Mustacchi 	ulong_t		cs_nfuncmax;		/* largest number of args */
58bc1f688bSRobert Mustacchi 	ulong_t		cs_ntypes[CTF_K_MAX];	/* number of types */
59bc1f688bSRobert Mustacchi 	ulong_t		cs_nsmembs;		/* number of struct members */
60bc1f688bSRobert Mustacchi 	ulong_t		cs_nsmax;		/* largest number of members */
61bc1f688bSRobert Mustacchi 	ulong_t		cs_structsz;		/* sum of structures sizes */
62bc1f688bSRobert Mustacchi 	ulong_t		cs_sszmax;		/* largest structure */
63bc1f688bSRobert Mustacchi 	ulong_t		cs_numembs;		/* number of union members */
64bc1f688bSRobert Mustacchi 	ulong_t		cs_numax;		/* largest number of members */
65bc1f688bSRobert Mustacchi 	ulong_t		cs_unionsz;		/* sum of unions sizes */
66bc1f688bSRobert Mustacchi 	ulong_t		cs_uszmax;		/* largest union */
67bc1f688bSRobert Mustacchi 	ulong_t		cs_nemembs;		/* number of enum members */
68bc1f688bSRobert Mustacchi 	ulong_t		cs_nemax;		/* largest number of members */
69bc1f688bSRobert Mustacchi 	ulong_t		cs_nstrings;		/* number of strings */
70bc1f688bSRobert Mustacchi 	ulong_t		cs_strsz;		/* string size */
71bc1f688bSRobert Mustacchi 	ulong_t		cs_strmax;		/* longest string */
72bc1f688bSRobert Mustacchi } ctfdump_stat_t;
73bc1f688bSRobert Mustacchi 
74bc1f688bSRobert Mustacchi typedef struct {
75bc1f688bSRobert Mustacchi 	char ci_name[MAX_NAMELEN];
76bc1f688bSRobert Mustacchi 	ctf_id_t ci_id;
77bc1f688bSRobert Mustacchi 	ulong_t ci_symidx;
78bc1f688bSRobert Mustacchi 	ctf_funcinfo_t ci_funcinfo;
79bc1f688bSRobert Mustacchi } ctf_idname_t;
80bc1f688bSRobert Mustacchi 
81bc1f688bSRobert Mustacchi static ctf_idname_t *idnames;
82bc1f688bSRobert Mustacchi static const char *g_progname;
83bc1f688bSRobert Mustacchi static ctfdump_arg_t g_dump;
84bc1f688bSRobert Mustacchi static ctf_file_t *g_fp;
85bc1f688bSRobert Mustacchi static ctfdump_stat_t g_stats;
86bc1f688bSRobert Mustacchi static ctf_id_t *g_fargc;
87bc1f688bSRobert Mustacchi static int g_nfargc;
88bc1f688bSRobert Mustacchi 
89bc1f688bSRobert Mustacchi static int g_exit = 0;
90bc1f688bSRobert Mustacchi 
91bc1f688bSRobert Mustacchi static const char *ctfdump_fpenc[] = {
92bc1f688bSRobert Mustacchi 	NULL,
93bc1f688bSRobert Mustacchi 	"SINGLE",
94bc1f688bSRobert Mustacchi 	"DOUBLE",
95bc1f688bSRobert Mustacchi 	"COMPLEX",
96bc1f688bSRobert Mustacchi 	"DCOMPLEX",
97bc1f688bSRobert Mustacchi 	"LDCOMPLEX",
98bc1f688bSRobert Mustacchi 	"LDOUBLE",
99bc1f688bSRobert Mustacchi 	"INTERVAL",
100bc1f688bSRobert Mustacchi 	"DINTERVAL",
101bc1f688bSRobert Mustacchi 	"LDINTERVAL",
102bc1f688bSRobert Mustacchi 	"IMAGINARY",
103bc1f688bSRobert Mustacchi 	"DIMAGINARY",
104bc1f688bSRobert Mustacchi 	"LDIMAGINARY"
105bc1f688bSRobert Mustacchi };
106bc1f688bSRobert Mustacchi 
107bc1f688bSRobert Mustacchi /*
108bc1f688bSRobert Mustacchi  * When stats are requested, we have to go through everything. To make our lives
109bc1f688bSRobert Mustacchi  * easier, we'll just always allow the code to print everything out, but only
110bc1f688bSRobert Mustacchi  * output it if we have actually enabled that section.
111bc1f688bSRobert Mustacchi  */
112bc1f688bSRobert Mustacchi static void
ctfdump_printf(ctfdump_arg_t arg,const char * fmt,...)113bc1f688bSRobert Mustacchi ctfdump_printf(ctfdump_arg_t arg, const char *fmt, ...)
114bc1f688bSRobert Mustacchi {
115bc1f688bSRobert Mustacchi 	va_list ap;
116bc1f688bSRobert Mustacchi 
117bc1f688bSRobert Mustacchi 	if ((arg & g_dump) == 0)
118bc1f688bSRobert Mustacchi 		return;
119bc1f688bSRobert Mustacchi 
120bc1f688bSRobert Mustacchi 	va_start(ap, fmt);
121bc1f688bSRobert Mustacchi 	(void) vfprintf(stdout, fmt, ap);
122bc1f688bSRobert Mustacchi 	va_end(ap);
123bc1f688bSRobert Mustacchi }
124bc1f688bSRobert Mustacchi 
12588e8a81bSRichard Lowe static void __NORETURN
ctfdump_fatal(const char * fmt,...)126bc1f688bSRobert Mustacchi ctfdump_fatal(const char *fmt, ...)
127bc1f688bSRobert Mustacchi {
128bc1f688bSRobert Mustacchi 	va_list ap;
129bc1f688bSRobert Mustacchi 
130bc1f688bSRobert Mustacchi 	(void) fprintf(stderr, "%s: ", g_progname);
131bc1f688bSRobert Mustacchi 	va_start(ap, fmt);
132bc1f688bSRobert Mustacchi 	(void) vfprintf(stderr, fmt, ap);
133bc1f688bSRobert Mustacchi 	va_end(ap);
134bc1f688bSRobert Mustacchi 
135bc1f688bSRobert Mustacchi 	exit(1);
136bc1f688bSRobert Mustacchi }
137bc1f688bSRobert Mustacchi 
138bc1f688bSRobert Mustacchi static void
ctfdump_usage(const char * fmt,...)139bc1f688bSRobert Mustacchi ctfdump_usage(const char *fmt, ...)
140bc1f688bSRobert Mustacchi {
141bc1f688bSRobert Mustacchi 	if (fmt != NULL) {
142bc1f688bSRobert Mustacchi 		va_list ap;
143bc1f688bSRobert Mustacchi 		(void) fprintf(stderr, "%s: ", g_progname);
144bc1f688bSRobert Mustacchi 		va_start(ap, fmt);
145bc1f688bSRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
146bc1f688bSRobert Mustacchi 		va_end(ap);
147bc1f688bSRobert Mustacchi 	}
148bc1f688bSRobert Mustacchi 
149bc1f688bSRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s [-cdfhlsSt] [-p parent] [-u outfile] "
150bc1f688bSRobert Mustacchi 	    "file\n"
151bc1f688bSRobert Mustacchi 	    "\n"
152bc1f688bSRobert Mustacchi 	    "\t-c  dump C-style output\n"
153bc1f688bSRobert Mustacchi 	    "\t-d  dump object data\n"
154bc1f688bSRobert Mustacchi 	    "\t-f  dump function data\n"
155bc1f688bSRobert Mustacchi 	    "\t-h  dump the CTF header\n"
156bc1f688bSRobert Mustacchi 	    "\t-l  dump the label table\n"
157bc1f688bSRobert Mustacchi 	    "\t-p  use parent to supply additional information\n"
158bc1f688bSRobert Mustacchi 	    "\t-s  dump the string table\n"
159bc1f688bSRobert Mustacchi 	    "\t-S  dump statistics about the CTF container\n"
160bc1f688bSRobert Mustacchi 	    "\t-t  dump type information\n"
161bc1f688bSRobert Mustacchi 	    "\t-u  dump uncompressed CTF data to outfile\n",
162bc1f688bSRobert Mustacchi 	    g_progname);
163bc1f688bSRobert Mustacchi }
164bc1f688bSRobert Mustacchi 
165bc1f688bSRobert Mustacchi static void
ctfdump_title(ctfdump_arg_t arg,const char * header)166bc1f688bSRobert Mustacchi ctfdump_title(ctfdump_arg_t arg, const char *header)
167bc1f688bSRobert Mustacchi {
168bc1f688bSRobert Mustacchi 	static const char line[] = "----------------------------------------"
169bc1f688bSRobert Mustacchi 	    "----------------------------------------";
170bc1f688bSRobert Mustacchi 	ctfdump_printf(arg, "\n- %s %.*s\n\n", header, (int)78 - strlen(header),
171bc1f688bSRobert Mustacchi 	    line);
172bc1f688bSRobert Mustacchi }
173bc1f688bSRobert Mustacchi 
174bc1f688bSRobert Mustacchi static int
ctfdump_objects_cb(const char * name,ctf_id_t id,ulong_t symidx,void * arg)175bc1f688bSRobert Mustacchi ctfdump_objects_cb(const char *name, ctf_id_t id, ulong_t symidx, void *arg)
176bc1f688bSRobert Mustacchi {
177bc1f688bSRobert Mustacchi 	_NOTE(ARGUNUSED(arg));
178bc1f688bSRobert Mustacchi 
179bc1f688bSRobert Mustacchi 	int len;
180bc1f688bSRobert Mustacchi 
181bc1f688bSRobert Mustacchi 	len = snprintf(NULL, 0, "  [%lu] %ld", g_stats.cs_ndata, id);
182bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_OBJECTS, "  [%lu] %ld %*s%s (%lu)\n",
183bc1f688bSRobert Mustacchi 	    g_stats.cs_ndata, id, MAX(15 - len, 0), "", name, symidx);
184bc1f688bSRobert Mustacchi 	g_stats.cs_ndata++;
185bc1f688bSRobert Mustacchi 	return (0);
186bc1f688bSRobert Mustacchi }
187bc1f688bSRobert Mustacchi 
188bc1f688bSRobert Mustacchi static void
ctfdump_objects(void)189bc1f688bSRobert Mustacchi ctfdump_objects(void)
190bc1f688bSRobert Mustacchi {
191bc1f688bSRobert Mustacchi 	ctfdump_title(CTFDUMP_OBJECTS, "Data Objects");
192bc1f688bSRobert Mustacchi 	if (ctf_object_iter(g_fp, ctfdump_objects_cb, NULL) == CTF_ERR) {
193bc1f688bSRobert Mustacchi 		warnx("failed to dump objects: %s",
194bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(g_fp)));
195bc1f688bSRobert Mustacchi 		g_exit = 1;
196bc1f688bSRobert Mustacchi 	}
197bc1f688bSRobert Mustacchi }
198bc1f688bSRobert Mustacchi 
199bc1f688bSRobert Mustacchi static void
ctfdump_fargs_grow(int nargs)200bc1f688bSRobert Mustacchi ctfdump_fargs_grow(int nargs)
201bc1f688bSRobert Mustacchi {
202bc1f688bSRobert Mustacchi 	if (g_nfargc < nargs) {
203bc1f688bSRobert Mustacchi 		g_fargc = realloc(g_fargc, sizeof (ctf_id_t) * nargs);
204bc1f688bSRobert Mustacchi 		if (g_fargc == NULL)
205bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get memory for %d "
206bc1f688bSRobert Mustacchi 			    "ctf_id_t's\n", nargs);
207bc1f688bSRobert Mustacchi 		g_nfargc = nargs;
208bc1f688bSRobert Mustacchi 	}
209bc1f688bSRobert Mustacchi }
210bc1f688bSRobert Mustacchi 
211bc1f688bSRobert Mustacchi static int
ctfdump_functions_cb(const char * name,ulong_t symidx,ctf_funcinfo_t * ctc,void * arg)212bc1f688bSRobert Mustacchi ctfdump_functions_cb(const char *name, ulong_t symidx, ctf_funcinfo_t *ctc,
213bc1f688bSRobert Mustacchi     void *arg)
214bc1f688bSRobert Mustacchi {
215bc1f688bSRobert Mustacchi 	_NOTE(ARGUNUSED(arg));
216bc1f688bSRobert Mustacchi 	int i;
217bc1f688bSRobert Mustacchi 
218bc1f688bSRobert Mustacchi 	if (ctc->ctc_argc != 0) {
219bc1f688bSRobert Mustacchi 		ctfdump_fargs_grow(ctc->ctc_argc);
220bc1f688bSRobert Mustacchi 		if (ctf_func_args(g_fp, symidx, g_nfargc, g_fargc) == CTF_ERR)
221bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get arguments for function "
222bc1f688bSRobert Mustacchi 			    "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
223bc1f688bSRobert Mustacchi 	}
224bc1f688bSRobert Mustacchi 
225bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_FUNCTIONS,
226bc1f688bSRobert Mustacchi 	    "  [%lu] %s (%lu) returns: %ld args: (", g_stats.cs_nfuncs, name,
227bc1f688bSRobert Mustacchi 	    symidx, ctc->ctc_return);
228bc1f688bSRobert Mustacchi 	for (i = 0; i < ctc->ctc_argc; i++)
229bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_FUNCTIONS, "%ld%s", g_fargc[i],
230bc1f688bSRobert Mustacchi 		    i + 1 == ctc->ctc_argc ? "" : ", ");
231bc1f688bSRobert Mustacchi 	if (ctc->ctc_flags & CTF_FUNC_VARARG)
232bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_FUNCTIONS, "%s...",
233bc1f688bSRobert Mustacchi 		    ctc->ctc_argc == 0 ? "" : ", ");
234bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_FUNCTIONS, ")\n");
235bc1f688bSRobert Mustacchi 
236bc1f688bSRobert Mustacchi 	g_stats.cs_nfuncs++;
237bc1f688bSRobert Mustacchi 	g_stats.cs_nfuncargs += ctc->ctc_argc;
238bc1f688bSRobert Mustacchi 	g_stats.cs_nfuncmax = MAX(ctc->ctc_argc, g_stats.cs_nfuncmax);
239bc1f688bSRobert Mustacchi 
240bc1f688bSRobert Mustacchi 	return (0);
241bc1f688bSRobert Mustacchi }
242bc1f688bSRobert Mustacchi 
243bc1f688bSRobert Mustacchi static void
ctfdump_functions(void)244bc1f688bSRobert Mustacchi ctfdump_functions(void)
245bc1f688bSRobert Mustacchi {
246bc1f688bSRobert Mustacchi 	ctfdump_title(CTFDUMP_FUNCTIONS, "Functions");
247bc1f688bSRobert Mustacchi 
248bc1f688bSRobert Mustacchi 	if (ctf_function_iter(g_fp, ctfdump_functions_cb, NULL) == CTF_ERR) {
249bc1f688bSRobert Mustacchi 		warnx("failed to dump functions: %s",
250bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(g_fp)));
251bc1f688bSRobert Mustacchi 		g_exit = 1;
252bc1f688bSRobert Mustacchi 	}
253bc1f688bSRobert Mustacchi }
254bc1f688bSRobert Mustacchi 
255bc1f688bSRobert Mustacchi static void
ctfdump_header(void)256bc1f688bSRobert Mustacchi ctfdump_header(void)
257bc1f688bSRobert Mustacchi {
258bc1f688bSRobert Mustacchi 	const ctf_header_t *hp;
259bc1f688bSRobert Mustacchi 	const char *parname, *parlabel;
260bc1f688bSRobert Mustacchi 
261bc1f688bSRobert Mustacchi 	ctfdump_title(CTFDUMP_HEADER, "CTF Header");
262bc1f688bSRobert Mustacchi 	ctf_dataptr(g_fp, (const void **)&hp, NULL);
263bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_magic    = 0x%04x\n",
264bc1f688bSRobert Mustacchi 	    hp->cth_magic);
265bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_version  = %u\n",
266bc1f688bSRobert Mustacchi 	    hp->cth_version);
267bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_flags    = 0x%02x\n",
268bc1f688bSRobert Mustacchi 	    ctf_flags(g_fp));
269bc1f688bSRobert Mustacchi 	parname = ctf_parent_name(g_fp);
270bc1f688bSRobert Mustacchi 	parlabel = ctf_parent_label(g_fp);
271bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_parlabel = %s\n",
272bc1f688bSRobert Mustacchi 	    parlabel == NULL ? "(anon)" : parlabel);
273bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_parname  = %s\n",
274bc1f688bSRobert Mustacchi 	    parname == NULL ? "(anon)" : parname);
275bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_lbloff   = %u\n",
276bc1f688bSRobert Mustacchi 	    hp->cth_lbloff);
277bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_objtoff  = %u\n",
278bc1f688bSRobert Mustacchi 	    hp->cth_objtoff);
279bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_funcoff  = %u\n",
280bc1f688bSRobert Mustacchi 	    hp->cth_funcoff);
281bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_typeoff  = %u\n",
282bc1f688bSRobert Mustacchi 	    hp->cth_typeoff);
283bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_stroff   = %u\n",
284bc1f688bSRobert Mustacchi 	    hp->cth_stroff);
285bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_HEADER, "  cth_strlen   = %u\n",
286bc1f688bSRobert Mustacchi 	    hp->cth_strlen);
287bc1f688bSRobert Mustacchi }
288bc1f688bSRobert Mustacchi 
289bc1f688bSRobert Mustacchi static int
ctfdump_labels_cb(const char * name,const ctf_lblinfo_t * li,void * arg)290bc1f688bSRobert Mustacchi ctfdump_labels_cb(const char *name, const ctf_lblinfo_t *li, void *arg)
291bc1f688bSRobert Mustacchi {
292bc1f688bSRobert Mustacchi 	_NOTE(ARGUNUSED(arg));
293bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_LABELS, "  %5ld %s\n", li->ctb_typeidx, name);
294bc1f688bSRobert Mustacchi 	return (0);
295bc1f688bSRobert Mustacchi }
296bc1f688bSRobert Mustacchi 
297bc1f688bSRobert Mustacchi static void
ctfdump_labels(void)298bc1f688bSRobert Mustacchi ctfdump_labels(void)
299bc1f688bSRobert Mustacchi {
300bc1f688bSRobert Mustacchi 	ctfdump_title(CTFDUMP_LABELS, "Label Table");
301bc1f688bSRobert Mustacchi 	if (ctf_label_iter(g_fp, ctfdump_labels_cb, NULL) == CTF_ERR) {
302bc1f688bSRobert Mustacchi 		warnx("failed to dump labels: %s",
303bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(g_fp)));
304bc1f688bSRobert Mustacchi 		g_exit = 1;
305bc1f688bSRobert Mustacchi 	}
306bc1f688bSRobert Mustacchi }
307bc1f688bSRobert Mustacchi 
308bc1f688bSRobert Mustacchi static int
ctfdump_strings_cb(const char * s,void * arg)309bc1f688bSRobert Mustacchi ctfdump_strings_cb(const char *s, void *arg)
310bc1f688bSRobert Mustacchi {
311bc1f688bSRobert Mustacchi 	size_t len = strlen(s) + 1;
312bc1f688bSRobert Mustacchi 	ulong_t *stroff = arg;
313bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STRINGS, "  [%lu] %s\n", *stroff,
314bc1f688bSRobert Mustacchi 	    *s == '\0' ? "\\0" : s);
315bc1f688bSRobert Mustacchi 	*stroff = *stroff + len;
316bc1f688bSRobert Mustacchi 	g_stats.cs_nstrings++;
317bc1f688bSRobert Mustacchi 	g_stats.cs_strsz += len;
318bc1f688bSRobert Mustacchi 	g_stats.cs_strmax = MAX(g_stats.cs_strmax, len);
319bc1f688bSRobert Mustacchi 	return (0);
320bc1f688bSRobert Mustacchi }
321bc1f688bSRobert Mustacchi 
322bc1f688bSRobert Mustacchi static void
ctfdump_strings(void)323bc1f688bSRobert Mustacchi ctfdump_strings(void)
324bc1f688bSRobert Mustacchi {
325bc1f688bSRobert Mustacchi 	ulong_t stroff = 0;
326bc1f688bSRobert Mustacchi 
327bc1f688bSRobert Mustacchi 	ctfdump_title(CTFDUMP_STRINGS, "String Table");
328bc1f688bSRobert Mustacchi 	if (ctf_string_iter(g_fp, ctfdump_strings_cb, &stroff) == CTF_ERR) {
329bc1f688bSRobert Mustacchi 		warnx("failed to dump strings: %s",
330bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(g_fp)));
331bc1f688bSRobert Mustacchi 		g_exit = 1;
332bc1f688bSRobert Mustacchi 	}
333bc1f688bSRobert Mustacchi }
334bc1f688bSRobert Mustacchi 
335bc1f688bSRobert Mustacchi static void
ctfdump_stat_int(const char * name,ulong_t value)336bc1f688bSRobert Mustacchi ctfdump_stat_int(const char *name, ulong_t value)
337bc1f688bSRobert Mustacchi {
338bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "  %-36s= %lu\n", name, value);
339bc1f688bSRobert Mustacchi }
340bc1f688bSRobert Mustacchi 
341bc1f688bSRobert Mustacchi static void
ctfdump_stat_fp(const char * name,float value)342bc1f688bSRobert Mustacchi ctfdump_stat_fp(const char *name, float value)
343bc1f688bSRobert Mustacchi {
344bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "  %-36s= %.2f\n", name, value);
345bc1f688bSRobert Mustacchi }
346bc1f688bSRobert Mustacchi 
347bc1f688bSRobert Mustacchi static void
ctfdump_stats(void)348bc1f688bSRobert Mustacchi ctfdump_stats(void)
349bc1f688bSRobert Mustacchi {
350bc1f688bSRobert Mustacchi 	int i;
351bc1f688bSRobert Mustacchi 	ulong_t sum;
352bc1f688bSRobert Mustacchi 
353bc1f688bSRobert Mustacchi 	ctfdump_title(CTFDUMP_STATS, "CTF Statistics");
354bc1f688bSRobert Mustacchi 
355bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of data objects", g_stats.cs_ndata);
356bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "\n");
357bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of functions", g_stats.cs_nfuncs);
358bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of function arguments",
359bc1f688bSRobert Mustacchi 	    g_stats.cs_nfuncargs);
360bc1f688bSRobert Mustacchi 	ctfdump_stat_int("maximum argument list length", g_stats.cs_nfuncmax);
361bc1f688bSRobert Mustacchi 	if (g_stats.cs_nfuncs != 0)
362bc1f688bSRobert Mustacchi 		ctfdump_stat_fp("average argument list length",
363bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_nfuncargs / (float)g_stats.cs_nfuncs);
364bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "\n");
365bc1f688bSRobert Mustacchi 
366bc1f688bSRobert Mustacchi 	sum = 0;
367bc1f688bSRobert Mustacchi 	for (i = 0; i < CTF_K_MAX; i++)
368bc1f688bSRobert Mustacchi 		sum += g_stats.cs_ntypes[i];
369bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of types", sum);
370bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of integers",
371bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_INTEGER]);
372bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of floats",
373bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_FLOAT]);
374bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of pointers",
375bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_POINTER]);
376bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of arrays",
377bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_ARRAY]);
378bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of func types",
379bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_FUNCTION]);
380bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of structs",
381bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_STRUCT]);
382bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of unions",
383bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_UNION]);
384bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of enums",
385bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_ENUM]);
386bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of forward tags",
387bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_FORWARD]);
388bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of typedefs",
389bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_TYPEDEF]);
390bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of volatile types",
391bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_VOLATILE]);
392bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of const types",
393bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_CONST]);
394bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of restrict types",
395bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_RESTRICT]);
396bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of unknowns (holes)",
397bc1f688bSRobert Mustacchi 	    g_stats.cs_ntypes[CTF_K_UNKNOWN]);
398bc1f688bSRobert Mustacchi 
399bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "\n");
400bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of struct members", g_stats.cs_nsmembs);
401bc1f688bSRobert Mustacchi 	ctfdump_stat_int("maximum number of struct members", g_stats.cs_nsmax);
402bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total size of all structs", g_stats.cs_structsz);
403bc1f688bSRobert Mustacchi 	ctfdump_stat_int("maximum size of a struct", g_stats.cs_sszmax);
404bc1f688bSRobert Mustacchi 	if (g_stats.cs_ntypes[CTF_K_STRUCT] != 0) {
405bc1f688bSRobert Mustacchi 		ctfdump_stat_fp("average number of struct members",
406bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_nsmembs /
407bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_ntypes[CTF_K_STRUCT]);
408bc1f688bSRobert Mustacchi 		ctfdump_stat_fp("average size of a struct",
409bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_structsz /
410bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_ntypes[CTF_K_STRUCT]);
411bc1f688bSRobert Mustacchi 	}
412bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "\n");
413bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of union members", g_stats.cs_numembs);
414bc1f688bSRobert Mustacchi 	ctfdump_stat_int("maximum number of union members", g_stats.cs_numax);
415bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total size of all unions", g_stats.cs_unionsz);
416bc1f688bSRobert Mustacchi 	ctfdump_stat_int("maximum size of a union", g_stats.cs_uszmax);
417bc1f688bSRobert Mustacchi 	if (g_stats.cs_ntypes[CTF_K_UNION] != 0) {
418bc1f688bSRobert Mustacchi 		ctfdump_stat_fp("average number of union members",
419bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_numembs /
420bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_ntypes[CTF_K_UNION]);
421bc1f688bSRobert Mustacchi 		ctfdump_stat_fp("average size of a union",
422bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_unionsz /
423bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_ntypes[CTF_K_UNION]);
424bc1f688bSRobert Mustacchi 	}
425bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "\n");
426bc1f688bSRobert Mustacchi 
427bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of enum members", g_stats.cs_nemembs);
428bc1f688bSRobert Mustacchi 	ctfdump_stat_int("maximum number of enum members", g_stats.cs_nemax);
429bc1f688bSRobert Mustacchi 	if (g_stats.cs_ntypes[CTF_K_ENUM] != 0) {
430bc1f688bSRobert Mustacchi 		ctfdump_stat_fp("average number of enum members",
431bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_nemembs /
432bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_ntypes[CTF_K_ENUM]);
433bc1f688bSRobert Mustacchi 	}
434bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "\n");
435bc1f688bSRobert Mustacchi 
436bc1f688bSRobert Mustacchi 	ctfdump_stat_int("total number of strings", g_stats.cs_nstrings);
437bc1f688bSRobert Mustacchi 	ctfdump_stat_int("bytes of string data", g_stats.cs_strsz);
438bc1f688bSRobert Mustacchi 	ctfdump_stat_int("maximum string length", g_stats.cs_strmax);
439bc1f688bSRobert Mustacchi 	if (g_stats.cs_nstrings != 0)
440bc1f688bSRobert Mustacchi 		ctfdump_stat_fp("average string length",
441bc1f688bSRobert Mustacchi 		    (float)g_stats.cs_strsz / (float)g_stats.cs_nstrings);
442bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_STATS, "\n");
443bc1f688bSRobert Mustacchi }
444bc1f688bSRobert Mustacchi 
445bc1f688bSRobert Mustacchi static void
ctfdump_intenc_name(ctf_encoding_t * cte,char * buf,int len)446bc1f688bSRobert Mustacchi ctfdump_intenc_name(ctf_encoding_t *cte, char *buf, int len)
447bc1f688bSRobert Mustacchi {
448bc1f688bSRobert Mustacchi 	int off = 0;
449bc1f688bSRobert Mustacchi 	boolean_t space = B_FALSE;
450bc1f688bSRobert Mustacchi 
451bc1f688bSRobert Mustacchi 	if (cte->cte_format == 0 || (cte->cte_format &
452bc1f688bSRobert Mustacchi 	    ~(CTF_INT_SIGNED | CTF_INT_CHAR | CTF_INT_BOOL |
453bc1f688bSRobert Mustacchi 	    CTF_INT_VARARGS)) != 0) {
454bc1f688bSRobert Mustacchi 		(void) snprintf(buf, len, "0x%x", cte->cte_format);
455bc1f688bSRobert Mustacchi 		return;
456bc1f688bSRobert Mustacchi 	}
457bc1f688bSRobert Mustacchi 
458bc1f688bSRobert Mustacchi 	if (cte->cte_format & CTF_INT_SIGNED) {
459bc1f688bSRobert Mustacchi 		off += snprintf(buf + off, MAX(len - off, 0), "%sSIGNED",
460bc1f688bSRobert Mustacchi 		    space == B_TRUE ? " " : "");
461bc1f688bSRobert Mustacchi 		space = B_TRUE;
462bc1f688bSRobert Mustacchi 	}
463bc1f688bSRobert Mustacchi 
464bc1f688bSRobert Mustacchi 	if (cte->cte_format & CTF_INT_CHAR) {
465bc1f688bSRobert Mustacchi 		off += snprintf(buf + off, MAX(len - off, 0), "%sCHAR",
466bc1f688bSRobert Mustacchi 		    space == B_TRUE ? " " : "");
467bc1f688bSRobert Mustacchi 		space = B_TRUE;
468bc1f688bSRobert Mustacchi 	}
469bc1f688bSRobert Mustacchi 
470bc1f688bSRobert Mustacchi 	if (cte->cte_format & CTF_INT_BOOL) {
471bc1f688bSRobert Mustacchi 		off += snprintf(buf + off, MAX(len - off, 0), "%sBOOL",
472bc1f688bSRobert Mustacchi 		    space == B_TRUE ? " " : "");
473bc1f688bSRobert Mustacchi 		space = B_TRUE;
474bc1f688bSRobert Mustacchi 	}
475bc1f688bSRobert Mustacchi 
476bc1f688bSRobert Mustacchi 	if (cte->cte_format & CTF_INT_VARARGS) {
477bc1f688bSRobert Mustacchi 		off += snprintf(buf + off, MAX(len - off, 0), "%sVARARGS",
478bc1f688bSRobert Mustacchi 		    space == B_TRUE ? " " : "");
479bc1f688bSRobert Mustacchi 		space = B_TRUE;
480bc1f688bSRobert Mustacchi 	}
481bc1f688bSRobert Mustacchi }
482bc1f688bSRobert Mustacchi 
483bc1f688bSRobert Mustacchi static int
ctfdump_member_cb(const char * member,ctf_id_t type,ulong_t off,void * arg)484bc1f688bSRobert Mustacchi ctfdump_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
485bc1f688bSRobert Mustacchi {
486bc1f688bSRobert Mustacchi 	int *count = arg;
487*db9597bfSRobert Mustacchi 	ctfdump_printf(CTFDUMP_TYPES, "\t%s type=%ld off=%lu bits (%lu.%lu "
488*db9597bfSRobert Mustacchi 	    "bytes)\n", member, type, off, off / 8, off % 8);
489bc1f688bSRobert Mustacchi 	*count = *count + 1;
490bc1f688bSRobert Mustacchi 	return (0);
491bc1f688bSRobert Mustacchi }
492bc1f688bSRobert Mustacchi 
493bc1f688bSRobert Mustacchi static int
ctfdump_enum_cb(const char * name,int value,void * arg)494bc1f688bSRobert Mustacchi ctfdump_enum_cb(const char *name, int value, void *arg)
495bc1f688bSRobert Mustacchi {
496bc1f688bSRobert Mustacchi 	int *count = arg;
497bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_TYPES, "\t%s = %d\n", name, value);
498bc1f688bSRobert Mustacchi 	*count = *count + 1;
499bc1f688bSRobert Mustacchi 	return (0);
500bc1f688bSRobert Mustacchi }
501bc1f688bSRobert Mustacchi 
502bc1f688bSRobert Mustacchi static int
ctfdump_types_cb(ctf_id_t id,boolean_t root,void * arg)503bc1f688bSRobert Mustacchi ctfdump_types_cb(ctf_id_t id, boolean_t root, void *arg)
504bc1f688bSRobert Mustacchi {
505bc1f688bSRobert Mustacchi 	_NOTE(ARGUNUSED(arg));
506bc1f688bSRobert Mustacchi 	int kind, i, count;
507bc1f688bSRobert Mustacchi 	ctf_id_t ref;
508bc1f688bSRobert Mustacchi 	char name[MAX_NAMELEN], ienc[128];
509bc1f688bSRobert Mustacchi 	const char *encn;
510bc1f688bSRobert Mustacchi 	ctf_funcinfo_t ctc;
511bc1f688bSRobert Mustacchi 	ctf_arinfo_t ar;
512bc1f688bSRobert Mustacchi 	ctf_encoding_t cte;
513bc1f688bSRobert Mustacchi 	ssize_t size;
514bc1f688bSRobert Mustacchi 
515bc1f688bSRobert Mustacchi 	if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR)
516bc1f688bSRobert Mustacchi 		ctfdump_fatal("encountered malformed ctf, type %s does not "
517bc1f688bSRobert Mustacchi 		    "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
518bc1f688bSRobert Mustacchi 
519bc1f688bSRobert Mustacchi 	if (ctf_type_name(g_fp, id, name, sizeof (name)) == NULL) {
520bc1f688bSRobert Mustacchi 		if (ctf_errno(g_fp) != ECTF_NOPARENT)
521bc1f688bSRobert Mustacchi 			ctfdump_fatal("type %ld missing name: %s\n", id,
522bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(g_fp)));
523bc1f688bSRobert Mustacchi 		(void) snprintf(name, sizeof (name), "(unknown %s)",
524bc1f688bSRobert Mustacchi 		    ctf_kind_name(g_fp, kind));
525bc1f688bSRobert Mustacchi 	}
526bc1f688bSRobert Mustacchi 
527bc1f688bSRobert Mustacchi 	g_stats.cs_ntypes[kind]++;
528bc1f688bSRobert Mustacchi 	if (root == B_TRUE)
529bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "  <%ld> ", id);
530bc1f688bSRobert Mustacchi 	else
531bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "  [%ld] ", id);
532bc1f688bSRobert Mustacchi 
533bc1f688bSRobert Mustacchi 	switch (kind) {
534bc1f688bSRobert Mustacchi 	case CTF_K_UNKNOWN:
535bc1f688bSRobert Mustacchi 		break;
536bc1f688bSRobert Mustacchi 	case CTF_K_INTEGER:
537bc1f688bSRobert Mustacchi 		if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR)
538bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get encoding information "
539bc1f688bSRobert Mustacchi 			    "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
540bc1f688bSRobert Mustacchi 		ctfdump_intenc_name(&cte, ienc, sizeof (ienc));
541bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES,
542bc1f688bSRobert Mustacchi 		    "%s encoding=%s offset=%u bits=%u",
543bc1f688bSRobert Mustacchi 		    name, ienc, cte.cte_offset, cte.cte_bits);
544bc1f688bSRobert Mustacchi 		break;
545bc1f688bSRobert Mustacchi 	case CTF_K_FLOAT:
546bc1f688bSRobert Mustacchi 		if (ctf_type_encoding(g_fp, id, &cte) == CTF_ERR)
547bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get encoding information "
548bc1f688bSRobert Mustacchi 			    "for %s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
549bc1f688bSRobert Mustacchi 		if (cte.cte_format < 1 || cte.cte_format > 12)
550bc1f688bSRobert Mustacchi 			encn = "unknown";
551bc1f688bSRobert Mustacchi 		else
552bc1f688bSRobert Mustacchi 			encn = ctfdump_fpenc[cte.cte_format];
553bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "%s encoding=%s offset=%u "
554bc1f688bSRobert Mustacchi 		    "bits=%u", name, encn, cte.cte_offset, cte.cte_bits);
555bc1f688bSRobert Mustacchi 		break;
556bc1f688bSRobert Mustacchi 	case CTF_K_POINTER:
557bc1f688bSRobert Mustacchi 		if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
558bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get reference type for %s: "
559bc1f688bSRobert Mustacchi 			    "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
560bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
561bc1f688bSRobert Mustacchi 		    ref);
562bc1f688bSRobert Mustacchi 		break;
563bc1f688bSRobert Mustacchi 	case CTF_K_ARRAY:
564bc1f688bSRobert Mustacchi 		if (ctf_array_info(g_fp, id, &ar) == CTF_ERR)
565bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get array information for "
566bc1f688bSRobert Mustacchi 			    "%s: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
567bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "%s contents: %ld, index: %ld",
568bc1f688bSRobert Mustacchi 		    name, ar.ctr_contents, ar.ctr_index);
569bc1f688bSRobert Mustacchi 		break;
570bc1f688bSRobert Mustacchi 	case CTF_K_FUNCTION:
571bc1f688bSRobert Mustacchi 		if (ctf_func_info_by_id(g_fp, id, &ctc) == CTF_ERR)
572bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get function info for %s: "
573bc1f688bSRobert Mustacchi 			    "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
574bc1f688bSRobert Mustacchi 		if (ctc.ctc_argc > 0) {
575bc1f688bSRobert Mustacchi 			ctfdump_fargs_grow(ctc.ctc_argc);
576bc1f688bSRobert Mustacchi 			if (ctf_func_args_by_id(g_fp, id, g_nfargc, g_fargc) ==
577bc1f688bSRobert Mustacchi 			    CTF_ERR)
578bc1f688bSRobert Mustacchi 				ctfdump_fatal("failed to get function "
579bc1f688bSRobert Mustacchi 				    "arguments for %s: %s\n", name,
580bc1f688bSRobert Mustacchi 				    ctf_errmsg(ctf_errno(g_fp)));
581bc1f688bSRobert Mustacchi 		}
582bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES,
583bc1f688bSRobert Mustacchi 		    "%s returns: %ld args: (", name, ctc.ctc_return);
584bc1f688bSRobert Mustacchi 		for (i = 0; i < ctc.ctc_argc; i++) {
585bc1f688bSRobert Mustacchi 			ctfdump_printf(CTFDUMP_TYPES, "%ld%s", g_fargc[i],
586bc1f688bSRobert Mustacchi 			    i + 1 == ctc.ctc_argc ? "" : ", ");
587bc1f688bSRobert Mustacchi 		}
588bc1f688bSRobert Mustacchi 		if (ctc.ctc_flags & CTF_FUNC_VARARG)
589bc1f688bSRobert Mustacchi 			ctfdump_printf(CTFDUMP_TYPES, "%s...",
590bc1f688bSRobert Mustacchi 			    ctc.ctc_argc == 0 ? "" : ", ");
591bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, ")");
592bc1f688bSRobert Mustacchi 		break;
593bc1f688bSRobert Mustacchi 	case CTF_K_STRUCT:
594bc1f688bSRobert Mustacchi 	case CTF_K_UNION:
595bc1f688bSRobert Mustacchi 		size = ctf_type_size(g_fp, id);
596bc1f688bSRobert Mustacchi 		if (size == CTF_ERR)
597bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get size of %s: %s\n", name,
598bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(g_fp)));
599bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "%s (%zd bytes)\n", name, size);
600bc1f688bSRobert Mustacchi 		count = 0;
601bc1f688bSRobert Mustacchi 		if (ctf_member_iter(g_fp, id, ctfdump_member_cb, &count) != 0)
602bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to iterate members of %s: %s\n",
603bc1f688bSRobert Mustacchi 			    name, ctf_errmsg(ctf_errno(g_fp)));
604bc1f688bSRobert Mustacchi 		if (kind == CTF_K_STRUCT) {
605bc1f688bSRobert Mustacchi 			g_stats.cs_nsmembs += count;
606bc1f688bSRobert Mustacchi 			g_stats.cs_nsmax = MAX(count, g_stats.cs_nsmax);
607bc1f688bSRobert Mustacchi 			g_stats.cs_structsz += size;
608bc1f688bSRobert Mustacchi 			g_stats.cs_sszmax = MAX(size, g_stats.cs_sszmax);
609bc1f688bSRobert Mustacchi 		} else {
610bc1f688bSRobert Mustacchi 			g_stats.cs_numembs += count;
611bc1f688bSRobert Mustacchi 			g_stats.cs_numax = MAX(count, g_stats.cs_numax);
612bc1f688bSRobert Mustacchi 			g_stats.cs_unionsz += size;
613bc1f688bSRobert Mustacchi 			g_stats.cs_uszmax = MAX(count, g_stats.cs_uszmax);
614bc1f688bSRobert Mustacchi 		}
615bc1f688bSRobert Mustacchi 		break;
616bc1f688bSRobert Mustacchi 	case CTF_K_ENUM:
617fe2dc8bdSJohn Levon 		size = ctf_type_size(g_fp, id);
618fe2dc8bdSJohn Levon 
619fe2dc8bdSJohn Levon 		/* Only the oddest enums are worth reporting on size. */
620fe2dc8bdSJohn Levon 		if (size != CTF_ERR && size != sizeof (int)) {
621fe2dc8bdSJohn Levon 			ctfdump_printf(CTFDUMP_TYPES, "%s (%zd bytes)\n",
622fe2dc8bdSJohn Levon 			    name, size);
623fe2dc8bdSJohn Levon 		} else {
624fe2dc8bdSJohn Levon 			ctfdump_printf(CTFDUMP_TYPES, "%s\n", name);
625fe2dc8bdSJohn Levon 		}
626fe2dc8bdSJohn Levon 
627bc1f688bSRobert Mustacchi 		count = 0;
628bc1f688bSRobert Mustacchi 		if (ctf_enum_iter(g_fp, id, ctfdump_enum_cb, &count) != 0)
629bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to iterate enumerators of %s: "
630bc1f688bSRobert Mustacchi 			    "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
631bc1f688bSRobert Mustacchi 		g_stats.cs_nemembs += count;
632bc1f688bSRobert Mustacchi 		g_stats.cs_nemax = MAX(g_stats.cs_nemax, count);
633bc1f688bSRobert Mustacchi 		break;
634bc1f688bSRobert Mustacchi 	case CTF_K_FORWARD:
635bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "forward %s\n", name);
636bc1f688bSRobert Mustacchi 		break;
637bc1f688bSRobert Mustacchi 	case CTF_K_TYPEDEF:
638bc1f688bSRobert Mustacchi 		if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
639bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get reference type for %s: "
640bc1f688bSRobert Mustacchi 			    "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
641bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "typedef %s refers to %ld", name,
642bc1f688bSRobert Mustacchi 		    ref);
643bc1f688bSRobert Mustacchi 		break;
644bc1f688bSRobert Mustacchi 	case CTF_K_VOLATILE:
645bc1f688bSRobert Mustacchi 		if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
646bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get reference type for %s: "
647bc1f688bSRobert Mustacchi 			    "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
648bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
649bc1f688bSRobert Mustacchi 		    ref);
650bc1f688bSRobert Mustacchi 		break;
651bc1f688bSRobert Mustacchi 	case CTF_K_CONST:
652bc1f688bSRobert Mustacchi 		if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
653bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get reference type for %s: "
654bc1f688bSRobert Mustacchi 			    "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
655bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
656bc1f688bSRobert Mustacchi 		    ref);
657bc1f688bSRobert Mustacchi 		break;
658bc1f688bSRobert Mustacchi 	case CTF_K_RESTRICT:
659bc1f688bSRobert Mustacchi 		if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR)
660bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get reference type for %s: "
661bc1f688bSRobert Mustacchi 			    "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
662bc1f688bSRobert Mustacchi 		ctfdump_printf(CTFDUMP_TYPES, "%s refers to %ld", name,
663bc1f688bSRobert Mustacchi 		    ref);
664bc1f688bSRobert Mustacchi 		break;
665bc1f688bSRobert Mustacchi 	default:
666bc1f688bSRobert Mustacchi 		ctfdump_fatal("encountered unknown kind for type %s: %d\n",
667bc1f688bSRobert Mustacchi 		    name, kind);
668bc1f688bSRobert Mustacchi 	}
669bc1f688bSRobert Mustacchi 
670bc1f688bSRobert Mustacchi 	ctfdump_printf(CTFDUMP_TYPES, "\n");
671bc1f688bSRobert Mustacchi 
672bc1f688bSRobert Mustacchi 	return (0);
673bc1f688bSRobert Mustacchi }
674bc1f688bSRobert Mustacchi 
675bc1f688bSRobert Mustacchi static void
ctfdump_types(void)676bc1f688bSRobert Mustacchi ctfdump_types(void)
677bc1f688bSRobert Mustacchi {
678bc1f688bSRobert Mustacchi 	ctfdump_title(CTFDUMP_TYPES, "Types");
679bc1f688bSRobert Mustacchi 
680bc1f688bSRobert Mustacchi 	if (ctf_type_iter(g_fp, B_TRUE, ctfdump_types_cb, NULL) == CTF_ERR) {
681bc1f688bSRobert Mustacchi 		warnx("failed to dump types: %s",
682bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(g_fp)));
683bc1f688bSRobert Mustacchi 		g_exit = 1;
684bc1f688bSRobert Mustacchi 	}
685bc1f688bSRobert Mustacchi }
686bc1f688bSRobert Mustacchi 
687bc1f688bSRobert Mustacchi /*
688bc1f688bSRobert Mustacchi  * C-style output. This is designed mainly for comparison purposes, and doesn't
689bc1f688bSRobert Mustacchi  * produce directly valid C:
690bc1f688bSRobert Mustacchi  *
691bc1f688bSRobert Mustacchi  * - the declarations are sorted alphabetically not semantically
692bc1f688bSRobert Mustacchi  * - anonymous enums without other users are elided (e.g. IDCS_PROBE_SENT)
693bc1f688bSRobert Mustacchi  * - doubly-pointed-to functions are wrong (e.g. in kiconv_ops_t)
694bc1f688bSRobert Mustacchi  * - anon unions declared within SOUs aren't expanded
695bc1f688bSRobert Mustacchi  * - function arguments aren't expanded recursively
696bc1f688bSRobert Mustacchi  */
697bc1f688bSRobert Mustacchi 
6986ef284f1SJohn Levon static const char *
ctfsrc_refname(ctf_id_t id,char * buf,size_t bufsize)699bc1f688bSRobert Mustacchi ctfsrc_refname(ctf_id_t id, char *buf, size_t bufsize)
700bc1f688bSRobert Mustacchi {
701bc1f688bSRobert Mustacchi 	ctf_id_t ref;
702bc1f688bSRobert Mustacchi 
703bc1f688bSRobert Mustacchi 	if ((ref = ctf_type_reference(g_fp, id)) == CTF_ERR) {
704bc1f688bSRobert Mustacchi 		ctfdump_fatal("failed to get reference type for %ld: "
705bc1f688bSRobert Mustacchi 		    "%s\n", id, ctf_errmsg(ctf_errno(g_fp)));
706bc1f688bSRobert Mustacchi 	}
707bc1f688bSRobert Mustacchi 
7086ef284f1SJohn Levon 	return (ctf_type_name(g_fp, ref, buf, bufsize));
709bc1f688bSRobert Mustacchi }
710bc1f688bSRobert Mustacchi 
711bc1f688bSRobert Mustacchi static int
ctfsrc_member_cb(const char * member,ctf_id_t type,ulong_t off,void * arg)712bc1f688bSRobert Mustacchi ctfsrc_member_cb(const char *member, ctf_id_t type, ulong_t off, void *arg)
713bc1f688bSRobert Mustacchi {
714bc1f688bSRobert Mustacchi 	_NOTE(ARGUNUSED(arg));
715bc1f688bSRobert Mustacchi 	char name[MAX_NAMELEN];
716bc1f688bSRobert Mustacchi 
717bc1f688bSRobert Mustacchi 	if (ctf_type_cname(g_fp, type, name, sizeof (name), member) == NULL) {
718bc1f688bSRobert Mustacchi 		if (ctf_errno(g_fp) != ECTF_NOPARENT) {
719bc1f688bSRobert Mustacchi 			ctfdump_fatal("type %ld missing name: %s\n", type,
720bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(g_fp)));
721bc1f688bSRobert Mustacchi 		}
722bc1f688bSRobert Mustacchi 
723bc1f688bSRobert Mustacchi 		(void) snprintf(name, sizeof (name), "unknown_t %s", member);
724bc1f688bSRobert Mustacchi 	}
725bc1f688bSRobert Mustacchi 
726bc1f688bSRobert Mustacchi 	/*
727bc1f688bSRobert Mustacchi 	 * A byte offset is friendlier, but we'll print bits too if it's not
728bc1f688bSRobert Mustacchi 	 * aligned (i.e. a bitfield).
729bc1f688bSRobert Mustacchi 	 */
730bc1f688bSRobert Mustacchi 	if (off % NBBY != 0) {
7316ef284f1SJohn Levon 		printf("\t%s; /* offset: %lu bytes (%lu bits) */\n",
732bc1f688bSRobert Mustacchi 		    name, off / NBBY, off);
733bc1f688bSRobert Mustacchi 	} else {
7346ef284f1SJohn Levon 		printf("\t%s; /* offset: %lu bytes */\n",
735bc1f688bSRobert Mustacchi 		    name, off / NBBY);
736bc1f688bSRobert Mustacchi 	}
737bc1f688bSRobert Mustacchi 	return (0);
738bc1f688bSRobert Mustacchi }
739bc1f688bSRobert Mustacchi 
740bc1f688bSRobert Mustacchi static int
ctfsrc_enum_cb(const char * name,int value,void * arg)741bc1f688bSRobert Mustacchi ctfsrc_enum_cb(const char *name, int value, void *arg)
742bc1f688bSRobert Mustacchi {
743bc1f688bSRobert Mustacchi 	_NOTE(ARGUNUSED(arg));
7446ef284f1SJohn Levon 	printf("\t%s = %d,\n", name, value);
745bc1f688bSRobert Mustacchi 	return (0);
746bc1f688bSRobert Mustacchi }
747bc1f688bSRobert Mustacchi 
748bc1f688bSRobert Mustacchi static int
is_anon_refname(const char * refname)749bc1f688bSRobert Mustacchi is_anon_refname(const char *refname)
750bc1f688bSRobert Mustacchi {
751bc1f688bSRobert Mustacchi 	return ((strcmp(refname, "struct ") == 0 ||
752bc1f688bSRobert Mustacchi 	    strcmp(refname, "union ") == 0 ||
753bc1f688bSRobert Mustacchi 	    strcmp(refname, "enum ") == 0));
754bc1f688bSRobert Mustacchi }
755bc1f688bSRobert Mustacchi 
756bc1f688bSRobert Mustacchi static int
ctfsrc_collect_types_cb(ctf_id_t id,boolean_t root,void * arg)757bc1f688bSRobert Mustacchi ctfsrc_collect_types_cb(ctf_id_t id, boolean_t root, void *arg)
758bc1f688bSRobert Mustacchi {
759bc1f688bSRobert Mustacchi 	_NOTE(ARGUNUSED(root, arg));
760bc1f688bSRobert Mustacchi 	(void) ctf_type_name(g_fp, id, idnames[id].ci_name,
761bc1f688bSRobert Mustacchi 	    sizeof (idnames[id].ci_name));
762bc1f688bSRobert Mustacchi 	idnames[id].ci_id = id;
763bc1f688bSRobert Mustacchi 	return (0);
764bc1f688bSRobert Mustacchi }
765bc1f688bSRobert Mustacchi 
766bc1f688bSRobert Mustacchi static void
ctfsrc_type(ctf_id_t id,const char * name)767bc1f688bSRobert Mustacchi ctfsrc_type(ctf_id_t id, const char *name)
768bc1f688bSRobert Mustacchi {
7696ef284f1SJohn Levon 	char refname[MAX_NAMELEN] = "unknown_t";
770bc1f688bSRobert Mustacchi 	ctf_id_t ref;
771bc1f688bSRobert Mustacchi 	ssize_t size;
772bc1f688bSRobert Mustacchi 	int kind;
773bc1f688bSRobert Mustacchi 
774bc1f688bSRobert Mustacchi 	if ((kind = ctf_type_kind(g_fp, id)) == CTF_ERR) {
775bc1f688bSRobert Mustacchi 		ctfdump_fatal("encountered malformed ctf, type %s does not "
776bc1f688bSRobert Mustacchi 		    "have a kind: %s\n", name, ctf_errmsg(ctf_errno(g_fp)));
777bc1f688bSRobert Mustacchi 	}
778bc1f688bSRobert Mustacchi 
779bc1f688bSRobert Mustacchi 	switch (kind) {
780bc1f688bSRobert Mustacchi 	case CTF_K_STRUCT:
781bc1f688bSRobert Mustacchi 	case CTF_K_UNION:
782bc1f688bSRobert Mustacchi 		/*
783bc1f688bSRobert Mustacchi 		 * Delay printing anonymous SOUs; a later typedef will usually
784bc1f688bSRobert Mustacchi 		 * pick them up.
785bc1f688bSRobert Mustacchi 		 */
786bc1f688bSRobert Mustacchi 		if (is_anon_refname(name))
787bc1f688bSRobert Mustacchi 			break;
788bc1f688bSRobert Mustacchi 
789bc1f688bSRobert Mustacchi 		if ((size = ctf_type_size(g_fp, id)) == CTF_ERR) {
790bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get size of %s: %s\n", name,
791bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(g_fp)));
792bc1f688bSRobert Mustacchi 		}
793bc1f688bSRobert Mustacchi 
7946ef284f1SJohn Levon 		printf("%s { /* 0x%x bytes */\n", name, size);
795bc1f688bSRobert Mustacchi 
796bc1f688bSRobert Mustacchi 		if (ctf_member_iter(g_fp, id, ctfsrc_member_cb, NULL) != 0) {
797bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to iterate members of %s: %s\n",
798bc1f688bSRobert Mustacchi 			    name, ctf_errmsg(ctf_errno(g_fp)));
799bc1f688bSRobert Mustacchi 		}
800bc1f688bSRobert Mustacchi 
8016ef284f1SJohn Levon 		printf("};\n\n");
802bc1f688bSRobert Mustacchi 		break;
803bc1f688bSRobert Mustacchi 	case CTF_K_ENUM:
804bc1f688bSRobert Mustacchi 		/*
805bc1f688bSRobert Mustacchi 		 * This will throw away any anon enum that isn't followed by a
806bc1f688bSRobert Mustacchi 		 * typedef...
807bc1f688bSRobert Mustacchi 		 */
808bc1f688bSRobert Mustacchi 		if (is_anon_refname(name))
809bc1f688bSRobert Mustacchi 			break;
810bc1f688bSRobert Mustacchi 
8116ef284f1SJohn Levon 		printf("%s {\n", name);
812bc1f688bSRobert Mustacchi 
813bc1f688bSRobert Mustacchi 		if (ctf_enum_iter(g_fp, id, ctfsrc_enum_cb, NULL) != 0) {
814bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to iterate enumerators of %s: "
815bc1f688bSRobert Mustacchi 			    "%s\n", name, ctf_errmsg(ctf_errno(g_fp)));
816bc1f688bSRobert Mustacchi 		}
817bc1f688bSRobert Mustacchi 
818fe2dc8bdSJohn Levon 		size = ctf_type_size(g_fp, id);
819fe2dc8bdSJohn Levon 
820fe2dc8bdSJohn Levon 		/* Only the oddest enums are worth reporting on size. */
821fe2dc8bdSJohn Levon 		if (size != CTF_ERR && size != sizeof (int)) {
822fe2dc8bdSJohn Levon 			printf("} /* 0x%x bytes */;\n\n", size);
823fe2dc8bdSJohn Levon 		} else {
824fe2dc8bdSJohn Levon 			printf("};\n\n");
825fe2dc8bdSJohn Levon 		}
826bc1f688bSRobert Mustacchi 		break;
827bc1f688bSRobert Mustacchi 	case CTF_K_TYPEDEF:
8286ef284f1SJohn Levon 		/*
8296ef284f1SJohn Levon 		 * If this fails, it's probably because the referent type is in
8306ef284f1SJohn Levon 		 * a parent container that was not supplied via -p.
8316ef284f1SJohn Levon 		 */
8326ef284f1SJohn Levon 		if (ctfsrc_refname(id, refname, sizeof (refname)) == NULL) {
8336ef284f1SJohn Levon 			printf("typedef %s %s;\n\n", refname, name);
8346ef284f1SJohn Levon 			break;
8356ef284f1SJohn Levon 		}
836bc1f688bSRobert Mustacchi 
837bc1f688bSRobert Mustacchi 		if (!is_anon_refname(refname)) {
838bc1f688bSRobert Mustacchi 			(void) ctf_type_cname(g_fp,
839bc1f688bSRobert Mustacchi 			    ctf_type_reference(g_fp, id), refname,
840bc1f688bSRobert Mustacchi 			    sizeof (refname), name);
841bc1f688bSRobert Mustacchi 
8426ef284f1SJohn Levon 			printf("typedef %s;\n\n", refname);
843bc1f688bSRobert Mustacchi 			break;
844bc1f688bSRobert Mustacchi 		}
845bc1f688bSRobert Mustacchi 
846bc1f688bSRobert Mustacchi 		ref = ctf_type_reference(g_fp, id);
847bc1f688bSRobert Mustacchi 
848bc1f688bSRobert Mustacchi 		if (ctf_type_kind(g_fp, ref) == CTF_K_ENUM) {
8496ef284f1SJohn Levon 			printf("typedef enum {\n");
850bc1f688bSRobert Mustacchi 
851bc1f688bSRobert Mustacchi 			if (ctf_enum_iter(g_fp, ref,
852bc1f688bSRobert Mustacchi 			    ctfsrc_enum_cb, NULL) != 0) {
853bc1f688bSRobert Mustacchi 				ctfdump_fatal("failed to iterate enumerators "
854bc1f688bSRobert Mustacchi 				    "of %s: %s\n", refname,
855bc1f688bSRobert Mustacchi 				    ctf_errmsg(ctf_errno(g_fp)));
856bc1f688bSRobert Mustacchi 			}
857bc1f688bSRobert Mustacchi 
8586ef284f1SJohn Levon 			printf("} %s;\n\n", name);
859bc1f688bSRobert Mustacchi 		} else {
860bc1f688bSRobert Mustacchi 			if ((size = ctf_type_size(g_fp, ref)) == CTF_ERR) {
861bc1f688bSRobert Mustacchi 				ctfdump_fatal("failed to get size of %s: %s\n",
862bc1f688bSRobert Mustacchi 				    refname, ctf_errmsg(ctf_errno(g_fp)));
863bc1f688bSRobert Mustacchi 			}
864bc1f688bSRobert Mustacchi 
8656ef284f1SJohn Levon 			printf("typedef %s{ /* 0x%zx bytes */\n",
866bc1f688bSRobert Mustacchi 			    refname, size);
867bc1f688bSRobert Mustacchi 
868bc1f688bSRobert Mustacchi 			if (ctf_member_iter(g_fp, ref,
869bc1f688bSRobert Mustacchi 			    ctfsrc_member_cb, NULL) != 0) {
870bc1f688bSRobert Mustacchi 				ctfdump_fatal("failed to iterate members "
871bc1f688bSRobert Mustacchi 				    "of %s: %s\n", refname,
872bc1f688bSRobert Mustacchi 				    ctf_errmsg(ctf_errno(g_fp)));
873bc1f688bSRobert Mustacchi 			}
874bc1f688bSRobert Mustacchi 
8756ef284f1SJohn Levon 			printf("} %s;\n\n", name);
876bc1f688bSRobert Mustacchi 		}
877bc1f688bSRobert Mustacchi 
878bc1f688bSRobert Mustacchi 		break;
879bc1f688bSRobert Mustacchi 	case CTF_K_FORWARD:
8806ef284f1SJohn Levon 		printf("%s;\n\n", name);
881bc1f688bSRobert Mustacchi 		break;
882bc1f688bSRobert Mustacchi 	case CTF_K_UNKNOWN:
883bc1f688bSRobert Mustacchi 	case CTF_K_INTEGER:
884bc1f688bSRobert Mustacchi 	case CTF_K_FLOAT:
885bc1f688bSRobert Mustacchi 	case CTF_K_POINTER:
886bc1f688bSRobert Mustacchi 	case CTF_K_ARRAY:
887bc1f688bSRobert Mustacchi 	case CTF_K_FUNCTION:
888bc1f688bSRobert Mustacchi 	case CTF_K_VOLATILE:
889bc1f688bSRobert Mustacchi 	case CTF_K_CONST:
890bc1f688bSRobert Mustacchi 	case CTF_K_RESTRICT:
891bc1f688bSRobert Mustacchi 		break;
892bc1f688bSRobert Mustacchi 	default:
893bc1f688bSRobert Mustacchi 		ctfdump_fatal("encountered unknown kind for type %s: %d\n",
894bc1f688bSRobert Mustacchi 		    name, kind);
895bc1f688bSRobert Mustacchi 		break;
896bc1f688bSRobert Mustacchi 	}
897bc1f688bSRobert Mustacchi }
898bc1f688bSRobert Mustacchi 
899bc1f688bSRobert Mustacchi static int
ctfsrc_collect_objects_cb(const char * name,ctf_id_t id,ulong_t symidx,void * arg)900bc1f688bSRobert Mustacchi ctfsrc_collect_objects_cb(const char *name, ctf_id_t id,
901bc1f688bSRobert Mustacchi     ulong_t symidx, void *arg)
902bc1f688bSRobert Mustacchi {
903bc1f688bSRobert Mustacchi 	size_t *count = arg;
904bc1f688bSRobert Mustacchi 
905bc1f688bSRobert Mustacchi 	/* local static vars can have an unknown ID */
906bc1f688bSRobert Mustacchi 	if (id == 0)
907bc1f688bSRobert Mustacchi 		return (0);
908bc1f688bSRobert Mustacchi 
909bc1f688bSRobert Mustacchi 	(void) strlcpy(idnames[*count].ci_name, name,
910bc1f688bSRobert Mustacchi 	    sizeof (idnames[*count].ci_name));
911bc1f688bSRobert Mustacchi 	idnames[*count].ci_id = id;
912bc1f688bSRobert Mustacchi 	idnames[*count].ci_symidx = symidx;
913bc1f688bSRobert Mustacchi 	*count = *count + 1;
914bc1f688bSRobert Mustacchi 	return (0);
915bc1f688bSRobert Mustacchi }
916bc1f688bSRobert Mustacchi 
917bc1f688bSRobert Mustacchi static void
ctfsrc_object(ctf_id_t id,const char * name)918bc1f688bSRobert Mustacchi ctfsrc_object(ctf_id_t id, const char *name)
919bc1f688bSRobert Mustacchi {
920bc1f688bSRobert Mustacchi 	char tname[MAX_NAMELEN];
921bc1f688bSRobert Mustacchi 
922bc1f688bSRobert Mustacchi 	if (ctf_type_cname(g_fp, id, tname, sizeof (tname), name) == NULL) {
923bc1f688bSRobert Mustacchi 		if (ctf_errno(g_fp) != ECTF_NOPARENT) {
924bc1f688bSRobert Mustacchi 			ctfdump_fatal("type %ld missing name: %s\n", id,
925bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(g_fp)));
926bc1f688bSRobert Mustacchi 		}
927bc1f688bSRobert Mustacchi 		(void) snprintf(tname, sizeof (tname), "unknown_t %s", name);
928bc1f688bSRobert Mustacchi 	}
929bc1f688bSRobert Mustacchi 
9306ef284f1SJohn Levon 	printf("extern %s;\n", tname);
931bc1f688bSRobert Mustacchi }
932bc1f688bSRobert Mustacchi 
933bc1f688bSRobert Mustacchi static int
ctfsrc_collect_functions_cb(const char * name,ulong_t symidx,ctf_funcinfo_t * ctc,void * arg)934bc1f688bSRobert Mustacchi ctfsrc_collect_functions_cb(const char *name, ulong_t symidx,
935bc1f688bSRobert Mustacchi     ctf_funcinfo_t *ctc, void *arg)
936bc1f688bSRobert Mustacchi {
937bc1f688bSRobert Mustacchi 	size_t *count = arg;
938bc1f688bSRobert Mustacchi 
939bc1f688bSRobert Mustacchi 	(void) strlcpy(idnames[*count].ci_name, name,
940bc1f688bSRobert Mustacchi 	    sizeof (idnames[*count].ci_name));
941bc1f688bSRobert Mustacchi 	bcopy(ctc, &idnames[*count].ci_funcinfo, sizeof (*ctc));
942bc1f688bSRobert Mustacchi 	idnames[*count].ci_id = 0;
943bc1f688bSRobert Mustacchi 	idnames[*count].ci_symidx = symidx;
944bc1f688bSRobert Mustacchi 	*count = *count + 1;
945bc1f688bSRobert Mustacchi 	return (0);
946bc1f688bSRobert Mustacchi }
947bc1f688bSRobert Mustacchi 
948bc1f688bSRobert Mustacchi static void
ctfsrc_function(ctf_idname_t * idn)949bc1f688bSRobert Mustacchi ctfsrc_function(ctf_idname_t *idn)
950bc1f688bSRobert Mustacchi {
951bc1f688bSRobert Mustacchi 	ctf_funcinfo_t *cfi = &idn->ci_funcinfo;
952bc1f688bSRobert Mustacchi 	char name[MAX_NAMELEN] = "unknown_t";
953bc1f688bSRobert Mustacchi 
954bc1f688bSRobert Mustacchi 	(void) ctf_type_name(g_fp, cfi->ctc_return, name, sizeof (name));
955bc1f688bSRobert Mustacchi 
9566ef284f1SJohn Levon 	printf("extern %s %s(", name, idn->ci_name);
957bc1f688bSRobert Mustacchi 
958bc1f688bSRobert Mustacchi 	if (cfi->ctc_argc != 0) {
959bc1f688bSRobert Mustacchi 		ctfdump_fargs_grow(cfi->ctc_argc);
960bc1f688bSRobert Mustacchi 		if (ctf_func_args(g_fp, idn->ci_symidx,
961bc1f688bSRobert Mustacchi 		    g_nfargc, g_fargc) == CTF_ERR) {
962bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to get arguments for function "
963bc1f688bSRobert Mustacchi 			    "%s: %s\n", idn->ci_name,
964bc1f688bSRobert Mustacchi 			    ctf_errmsg(ctf_errno(g_fp)));
965bc1f688bSRobert Mustacchi 		}
966bc1f688bSRobert Mustacchi 
967bc1f688bSRobert Mustacchi 		for (size_t i = 0; i < cfi->ctc_argc; i++) {
968bc1f688bSRobert Mustacchi 			ctf_id_t aid = g_fargc[i];
969bc1f688bSRobert Mustacchi 
9706ef284f1SJohn Levon 			(void) strlcpy(name, "unknown_t", sizeof (name));
971bc1f688bSRobert Mustacchi 
972bc1f688bSRobert Mustacchi 			(void) ctf_type_name(g_fp, aid, name, sizeof (name));
973bc1f688bSRobert Mustacchi 
9746ef284f1SJohn Levon 			printf("%s%s", name,
975bc1f688bSRobert Mustacchi 			    i + 1 == cfi->ctc_argc ? "" : ", ");
976bc1f688bSRobert Mustacchi 		}
977bc1f688bSRobert Mustacchi 	} else {
978bc1f688bSRobert Mustacchi 		if (!(cfi->ctc_flags & CTF_FUNC_VARARG))
9796ef284f1SJohn Levon 			printf("void");
980bc1f688bSRobert Mustacchi 	}
981bc1f688bSRobert Mustacchi 
982bc1f688bSRobert Mustacchi 	if (cfi->ctc_flags & CTF_FUNC_VARARG)
9836ef284f1SJohn Levon 		printf("%s...", cfi->ctc_argc == 0 ? "" : ", ");
984bc1f688bSRobert Mustacchi 
9856ef284f1SJohn Levon 	printf(");\n");
986bc1f688bSRobert Mustacchi }
987bc1f688bSRobert Mustacchi 
988bc1f688bSRobert Mustacchi static int
idname_compare(const void * lhs,const void * rhs)989bc1f688bSRobert Mustacchi idname_compare(const void *lhs, const void *rhs)
990bc1f688bSRobert Mustacchi {
99188e8a81bSRichard Lowe 	int ret;
99288e8a81bSRichard Lowe 	char lname[MAX_NAMELEN] = {0};
99388e8a81bSRichard Lowe 	char rname[MAX_NAMELEN] = {0};
99488e8a81bSRichard Lowe 	const ctf_idname_t *l = lhs;
99588e8a81bSRichard Lowe 	const ctf_idname_t *r = rhs;
99688e8a81bSRichard Lowe 	uint_t arity = 0;
99788e8a81bSRichard Lowe 
99888e8a81bSRichard Lowe 	if ((ret = strcmp(l->ci_name, r->ci_name)) != 0)
99988e8a81bSRichard Lowe 		return (ret);
100088e8a81bSRichard Lowe 
100188e8a81bSRichard Lowe 	/* If the names match, try arity */
100288e8a81bSRichard Lowe 	if (l->ci_funcinfo.ctc_argc < r->ci_funcinfo.ctc_argc)
100388e8a81bSRichard Lowe 		return (-1);
100488e8a81bSRichard Lowe 	else if (l->ci_funcinfo.ctc_argc > r->ci_funcinfo.ctc_argc)
100588e8a81bSRichard Lowe 		return (1);
100688e8a81bSRichard Lowe 	else
100788e8a81bSRichard Lowe 		arity = l->ci_funcinfo.ctc_argc;
100888e8a81bSRichard Lowe 
100988e8a81bSRichard Lowe 	/* If arity doesn't help, try return type */
101088e8a81bSRichard Lowe 	(void) strlcpy(lname, "unknown_t", sizeof (lname));
101188e8a81bSRichard Lowe 	(void) strlcpy(rname, "unknown_t", sizeof (rname));
101288e8a81bSRichard Lowe 	(void) ctf_type_name(g_fp, l->ci_funcinfo.ctc_return, lname,
101388e8a81bSRichard Lowe 	    sizeof (lname));
101488e8a81bSRichard Lowe 	(void) ctf_type_name(g_fp, r->ci_funcinfo.ctc_return, rname,
101588e8a81bSRichard Lowe 	    sizeof (rname));
101688e8a81bSRichard Lowe 
101788e8a81bSRichard Lowe 	if ((ret = strcmp(lname, rname)) != 0)
101888e8a81bSRichard Lowe 		return (ret);
101988e8a81bSRichard Lowe 
102088e8a81bSRichard Lowe 	/* if return type doesn't help, try parameter types */
102188e8a81bSRichard Lowe 	if (arity == 0)
102288e8a81bSRichard Lowe 		return (0);
102388e8a81bSRichard Lowe 
102488e8a81bSRichard Lowe 	ctf_id_t *largs = calloc(arity, sizeof (ctf_id_t));
102588e8a81bSRichard Lowe 	ctf_id_t *rargs = calloc(arity, sizeof (ctf_id_t));
102688e8a81bSRichard Lowe 
102788e8a81bSRichard Lowe 	if ((largs == NULL) || (rargs == NULL)) {
102888e8a81bSRichard Lowe 		free(rargs);
102988e8a81bSRichard Lowe 		free(largs);
103088e8a81bSRichard Lowe 		ctfdump_fatal("failed to alloc argument ids for sorting: "
103188e8a81bSRichard Lowe 		    " %s\n", strerror(errno));
103288e8a81bSRichard Lowe 	}
103388e8a81bSRichard Lowe 
103488e8a81bSRichard Lowe 	if (ctf_func_args(g_fp, l->ci_symidx, arity, largs) == CTF_ERR) {
103588e8a81bSRichard Lowe 		free(rargs);
103688e8a81bSRichard Lowe 		free(largs);
103788e8a81bSRichard Lowe 		ctfdump_fatal("failed to get arguments for function "
103888e8a81bSRichard Lowe 		    "%s: %s\n", l->ci_name,
103988e8a81bSRichard Lowe 		    ctf_errmsg(ctf_errno(g_fp)));
104088e8a81bSRichard Lowe 	}
104188e8a81bSRichard Lowe 
104288e8a81bSRichard Lowe 	if (ctf_func_args(g_fp, r->ci_symidx, arity, rargs) == CTF_ERR) {
104388e8a81bSRichard Lowe 		free(rargs);
104488e8a81bSRichard Lowe 		free(largs);
104588e8a81bSRichard Lowe 		ctfdump_fatal("failed to get arguments for function "
104688e8a81bSRichard Lowe 		    "%s: %s\n", r->ci_name,
104788e8a81bSRichard Lowe 		    ctf_errmsg(ctf_errno(g_fp)));
104888e8a81bSRichard Lowe 	}
104988e8a81bSRichard Lowe 
105088e8a81bSRichard Lowe 	for (uint_t i = 0; i < arity; i++) {
105188e8a81bSRichard Lowe 		(void) strlcpy(lname, "unknown_t", sizeof (lname));
105288e8a81bSRichard Lowe 		(void) ctf_type_name(g_fp, largs[i], lname, sizeof (lname));
105388e8a81bSRichard Lowe 
105488e8a81bSRichard Lowe 		(void) strlcpy(rname, "unknown_t", sizeof (rname));
105588e8a81bSRichard Lowe 		(void) ctf_type_name(g_fp, rargs[i], rname, sizeof (rname));
105688e8a81bSRichard Lowe 
105788e8a81bSRichard Lowe 		if ((ret = strcmp(lname, rname)) != 0) {
105888e8a81bSRichard Lowe 			free(rargs);
105988e8a81bSRichard Lowe 			free(largs);
106088e8a81bSRichard Lowe 			return (ret);
106188e8a81bSRichard Lowe 		}
106288e8a81bSRichard Lowe 	}
106388e8a81bSRichard Lowe 
106488e8a81bSRichard Lowe 	free(rargs);
106588e8a81bSRichard Lowe 	free(largs);
106688e8a81bSRichard Lowe 	return (0);
1067bc1f688bSRobert Mustacchi }
1068bc1f688bSRobert Mustacchi 
1069bc1f688bSRobert Mustacchi static void
ctfdump_source(void)1070bc1f688bSRobert Mustacchi ctfdump_source(void)
1071bc1f688bSRobert Mustacchi {
1072bc1f688bSRobert Mustacchi 	ulong_t nr_syms = ctf_nr_syms(g_fp);
1073bc1f688bSRobert Mustacchi 	ctf_id_t max_id = ctf_max_id(g_fp);
1074bc1f688bSRobert Mustacchi 	size_t count = 0;
1075bc1f688bSRobert Mustacchi 
10766ef284f1SJohn Levon 	printf("/* Types */\n\n");
1077bc1f688bSRobert Mustacchi 
1078bc1f688bSRobert Mustacchi 	if ((idnames = calloc(max_id + 1, sizeof (idnames[0]))) == NULL) {
1079bc1f688bSRobert Mustacchi 		ctfdump_fatal("failed to alloc idnames: %s\n",
1080bc1f688bSRobert Mustacchi 		    strerror(errno));
1081bc1f688bSRobert Mustacchi 	}
1082bc1f688bSRobert Mustacchi 
10836ef284f1SJohn Levon 	/*
10846ef284f1SJohn Levon 	 * Prep for any unknown types (most likely, they exist in the parent,
10856ef284f1SJohn Levon 	 * but we weren't given the -p option).
10866ef284f1SJohn Levon 	 */
10876ef284f1SJohn Levon 	for (size_t i = 0; i <= max_id; i++) {
10886ef284f1SJohn Levon 		(void) strlcpy(idnames[i].ci_name, "unknown_t",
10896ef284f1SJohn Levon 		    sizeof (idnames[i].ci_name));
10906ef284f1SJohn Levon 	}
10916ef284f1SJohn Levon 
109259d77acbSJohn Levon 	if (ctf_type_iter(g_fp, B_TRUE, ctfsrc_collect_types_cb,
1093bc1f688bSRobert Mustacchi 	    idnames) == CTF_ERR) {
1094bc1f688bSRobert Mustacchi 		warnx("failed to collect types: %s",
1095bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(g_fp)));
1096bc1f688bSRobert Mustacchi 		g_exit = 1;
1097bc1f688bSRobert Mustacchi 	}
1098bc1f688bSRobert Mustacchi 
1099bc1f688bSRobert Mustacchi 	qsort(idnames, max_id, sizeof (ctf_idname_t), idname_compare);
1100bc1f688bSRobert Mustacchi 
11016ef284f1SJohn Levon 	for (size_t i = 0; i <= max_id; i++) {
1102bc1f688bSRobert Mustacchi 		if (idnames[i].ci_id != 0)
1103bc1f688bSRobert Mustacchi 			ctfsrc_type(idnames[i].ci_id, idnames[i].ci_name);
1104bc1f688bSRobert Mustacchi 	}
1105bc1f688bSRobert Mustacchi 
1106bc1f688bSRobert Mustacchi 	free(idnames);
1107bc1f688bSRobert Mustacchi 
11086ef284f1SJohn Levon 	printf("\n\n/* Data Objects */\n\n");
1109bc1f688bSRobert Mustacchi 
1110bc1f688bSRobert Mustacchi 	if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1111bc1f688bSRobert Mustacchi 		ctfdump_fatal("failed to alloc idnames: %s\n",
1112bc1f688bSRobert Mustacchi 		    strerror(errno));
1113bc1f688bSRobert Mustacchi 	}
1114bc1f688bSRobert Mustacchi 
1115bc1f688bSRobert Mustacchi 	if (ctf_object_iter(g_fp, ctfsrc_collect_objects_cb,
1116bc1f688bSRobert Mustacchi 	    &count) == CTF_ERR) {
1117bc1f688bSRobert Mustacchi 		warnx("failed to collect objects: %s",
1118bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(g_fp)));
1119bc1f688bSRobert Mustacchi 		g_exit = 1;
1120bc1f688bSRobert Mustacchi 	}
1121bc1f688bSRobert Mustacchi 
1122bc1f688bSRobert Mustacchi 	qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1123bc1f688bSRobert Mustacchi 
1124bc1f688bSRobert Mustacchi 	for (size_t i = 0; i < count; i++)
1125bc1f688bSRobert Mustacchi 		ctfsrc_object(idnames[i].ci_id, idnames[i].ci_name);
1126bc1f688bSRobert Mustacchi 
1127bc1f688bSRobert Mustacchi 	free(idnames);
1128bc1f688bSRobert Mustacchi 
11296ef284f1SJohn Levon 	printf("\n\n/* Functions */\n\n");
1130bc1f688bSRobert Mustacchi 
1131bc1f688bSRobert Mustacchi 	if ((idnames = calloc(nr_syms, sizeof (idnames[0]))) == NULL) {
1132bc1f688bSRobert Mustacchi 		ctfdump_fatal("failed to alloc idnames: %s\n",
1133bc1f688bSRobert Mustacchi 		    strerror(errno));
1134bc1f688bSRobert Mustacchi 	}
1135bc1f688bSRobert Mustacchi 
1136bc1f688bSRobert Mustacchi 	count = 0;
1137bc1f688bSRobert Mustacchi 
1138bc1f688bSRobert Mustacchi 	if (ctf_function_iter(g_fp, ctfsrc_collect_functions_cb,
1139bc1f688bSRobert Mustacchi 	    &count) == CTF_ERR) {
1140bc1f688bSRobert Mustacchi 		warnx("failed to collect functions: %s",
1141bc1f688bSRobert Mustacchi 		    ctf_errmsg(ctf_errno(g_fp)));
1142bc1f688bSRobert Mustacchi 		g_exit = 1;
1143bc1f688bSRobert Mustacchi 	}
1144bc1f688bSRobert Mustacchi 
1145bc1f688bSRobert Mustacchi 	qsort(idnames, count, sizeof (ctf_idname_t), idname_compare);
1146bc1f688bSRobert Mustacchi 
1147bc1f688bSRobert Mustacchi 	for (size_t i = 0; i < count; i++)
1148bc1f688bSRobert Mustacchi 		ctfsrc_function(&idnames[i]);
1149bc1f688bSRobert Mustacchi 
1150bc1f688bSRobert Mustacchi 	free(idnames);
1151bc1f688bSRobert Mustacchi }
1152bc1f688bSRobert Mustacchi 
1153bc1f688bSRobert Mustacchi static void
ctfdump_output(const char * out)1154bc1f688bSRobert Mustacchi ctfdump_output(const char *out)
1155bc1f688bSRobert Mustacchi {
1156bc1f688bSRobert Mustacchi 	int fd, ret;
1157bc1f688bSRobert Mustacchi 	const void *data;
1158bc1f688bSRobert Mustacchi 	size_t len;
1159bc1f688bSRobert Mustacchi 
1160bc1f688bSRobert Mustacchi 	ctf_dataptr(g_fp, &data, &len);
1161bc1f688bSRobert Mustacchi 	if ((fd = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
1162bc1f688bSRobert Mustacchi 		ctfdump_fatal("failed to open output file %s: %s\n", out,
1163bc1f688bSRobert Mustacchi 		    strerror(errno));
1164bc1f688bSRobert Mustacchi 
1165bc1f688bSRobert Mustacchi 	while (len > 0) {
1166bc1f688bSRobert Mustacchi 		ret = write(fd, data, len);
1167bc1f688bSRobert Mustacchi 		if (ret == -1 && errno == EINTR)
1168bc1f688bSRobert Mustacchi 			continue;
1169bc1f688bSRobert Mustacchi 		else if (ret == -1 && (errno == EFAULT || errno == EBADF))
1170bc1f688bSRobert Mustacchi 			abort();
1171bc1f688bSRobert Mustacchi 		else if (ret == -1)
1172bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to write to %s: %s\n", out,
1173bc1f688bSRobert Mustacchi 			    strerror(errno));
1174bc1f688bSRobert Mustacchi 		data = ((char *)data) + ret;
1175bc1f688bSRobert Mustacchi 		len -= ret;
1176bc1f688bSRobert Mustacchi 	}
1177bc1f688bSRobert Mustacchi 
1178bc1f688bSRobert Mustacchi 	do {
1179bc1f688bSRobert Mustacchi 		ret = close(fd);
1180bc1f688bSRobert Mustacchi 	} while (ret == -1 && errno == EINTR);
1181bc1f688bSRobert Mustacchi 	if (ret != 0 && errno == EBADF)
1182bc1f688bSRobert Mustacchi 		abort();
1183bc1f688bSRobert Mustacchi 	if (ret != 0)
1184bc1f688bSRobert Mustacchi 		ctfdump_fatal("failed to close %s: %s\n", out, strerror(errno));
1185bc1f688bSRobert Mustacchi }
1186bc1f688bSRobert Mustacchi 
1187bc1f688bSRobert Mustacchi int
main(int argc,char * argv[])1188bc1f688bSRobert Mustacchi main(int argc, char *argv[])
1189bc1f688bSRobert Mustacchi {
1190bc1f688bSRobert Mustacchi 	int c, fd, err;
1191bc1f688bSRobert Mustacchi 	const char *ufile = NULL, *parent = NULL;
1192bc1f688bSRobert Mustacchi 
1193bc1f688bSRobert Mustacchi 	g_progname = basename(argv[0]);
1194bc1f688bSRobert Mustacchi 	while ((c = getopt(argc, argv, ":cdfhlp:sStu:")) != -1) {
1195bc1f688bSRobert Mustacchi 		switch (c) {
1196bc1f688bSRobert Mustacchi 		case 'c':
1197bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_SOURCE;
1198bc1f688bSRobert Mustacchi 			break;
1199bc1f688bSRobert Mustacchi 		case 'd':
1200bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_OBJECTS;
1201bc1f688bSRobert Mustacchi 			break;
1202bc1f688bSRobert Mustacchi 		case 'f':
1203bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_FUNCTIONS;
1204bc1f688bSRobert Mustacchi 			break;
1205bc1f688bSRobert Mustacchi 		case 'h':
1206bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_HEADER;
1207bc1f688bSRobert Mustacchi 			break;
1208bc1f688bSRobert Mustacchi 		case 'l':
1209bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_LABELS;
1210bc1f688bSRobert Mustacchi 			break;
1211bc1f688bSRobert Mustacchi 		case 'p':
1212bc1f688bSRobert Mustacchi 			parent = optarg;
1213bc1f688bSRobert Mustacchi 			break;
1214bc1f688bSRobert Mustacchi 		case 's':
1215bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_STRINGS;
1216bc1f688bSRobert Mustacchi 			break;
1217bc1f688bSRobert Mustacchi 		case 'S':
1218bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_STATS;
1219bc1f688bSRobert Mustacchi 			break;
1220bc1f688bSRobert Mustacchi 		case 't':
1221bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_TYPES;
1222bc1f688bSRobert Mustacchi 			break;
1223bc1f688bSRobert Mustacchi 		case 'u':
1224bc1f688bSRobert Mustacchi 			g_dump |= CTFDUMP_OUTPUT;
1225bc1f688bSRobert Mustacchi 			ufile = optarg;
1226bc1f688bSRobert Mustacchi 			break;
1227bc1f688bSRobert Mustacchi 		case '?':
1228bc1f688bSRobert Mustacchi 			ctfdump_usage("Unknown option: -%c\n", optopt);
1229bc1f688bSRobert Mustacchi 			return (2);
1230bc1f688bSRobert Mustacchi 		case ':':
1231bc1f688bSRobert Mustacchi 			ctfdump_usage("Option -%c requires an operand\n",
1232bc1f688bSRobert Mustacchi 			    optopt);
1233bc1f688bSRobert Mustacchi 			return (2);
1234bc1f688bSRobert Mustacchi 		}
1235bc1f688bSRobert Mustacchi 	}
1236bc1f688bSRobert Mustacchi 
1237bc1f688bSRobert Mustacchi 	argc -= optind;
1238bc1f688bSRobert Mustacchi 	argv += optind;
1239bc1f688bSRobert Mustacchi 
1240bc1f688bSRobert Mustacchi 	if ((g_dump & CTFDUMP_SOURCE) && !!(g_dump & ~CTFDUMP_SOURCE)) {
1241bc1f688bSRobert Mustacchi 		ctfdump_usage("-c must be specified on its own\n");
1242bc1f688bSRobert Mustacchi 		return (2);
1243bc1f688bSRobert Mustacchi 	}
1244bc1f688bSRobert Mustacchi 
1245bc1f688bSRobert Mustacchi 	/*
1246bc1f688bSRobert Mustacchi 	 * Dump all information except C source by default.
1247bc1f688bSRobert Mustacchi 	 */
1248bc1f688bSRobert Mustacchi 	if (g_dump == 0)
1249bc1f688bSRobert Mustacchi 		g_dump = CTFDUMP_DEFAULT;
1250bc1f688bSRobert Mustacchi 
1251bc1f688bSRobert Mustacchi 	if (argc != 1) {
1252bc1f688bSRobert Mustacchi 		ctfdump_usage("no file to dump\n");
1253bc1f688bSRobert Mustacchi 		return (2);
1254bc1f688bSRobert Mustacchi 	}
1255bc1f688bSRobert Mustacchi 
1256bc1f688bSRobert Mustacchi 	if ((fd = open(argv[0], O_RDONLY)) < 0)
1257bc1f688bSRobert Mustacchi 		ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1258bc1f688bSRobert Mustacchi 		    strerror(errno));
1259bc1f688bSRobert Mustacchi 
1260bc1f688bSRobert Mustacchi 	g_fp = ctf_fdopen(fd, &err);
1261bc1f688bSRobert Mustacchi 	if (g_fp == NULL)
1262bc1f688bSRobert Mustacchi 		ctfdump_fatal("failed to open file %s: %s\n", argv[0],
1263bc1f688bSRobert Mustacchi 		    ctf_errmsg(err));
1264bc1f688bSRobert Mustacchi 
1265bc1f688bSRobert Mustacchi 	/*
1266bc1f688bSRobert Mustacchi 	 * Check to see if this file needs a parent. If it does not and we were
1267bc1f688bSRobert Mustacchi 	 * given one, that should be an error. If it does need one and the
1268bc1f688bSRobert Mustacchi 	 * parent is not specified, that is fine, we just won't know how to
1269bc1f688bSRobert Mustacchi 	 * find child types. If we are given a parent, check at least that the
1270bc1f688bSRobert Mustacchi 	 * labels match.
1271bc1f688bSRobert Mustacchi 	 */
1272bc1f688bSRobert Mustacchi 	if (ctf_parent_name(g_fp) == NULL) {
1273bc1f688bSRobert Mustacchi 		if (parent != NULL)
1274bc1f688bSRobert Mustacchi 			ctfdump_fatal("cannot use %s as a parent file, %s is "
1275bc1f688bSRobert Mustacchi 			    "not a child\n", parent, argv[0]);
1276bc1f688bSRobert Mustacchi 	} else if (parent != NULL) {
1277bc1f688bSRobert Mustacchi 		const char *explabel, *label;
1278bc1f688bSRobert Mustacchi 		ctf_file_t *pfp = ctf_open(parent, &err);
1279bc1f688bSRobert Mustacchi 
1280bc1f688bSRobert Mustacchi 		if (pfp == NULL)
1281bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to open parent file %s: %s\n",
1282bc1f688bSRobert Mustacchi 			    parent, ctf_errmsg(err));
1283bc1f688bSRobert Mustacchi 
1284bc1f688bSRobert Mustacchi 		/*
1285bc1f688bSRobert Mustacchi 		 * Before we import the parent into the child, check that the
1286bc1f688bSRobert Mustacchi 		 * labels match. While there is also the notion of the parent
1287bc1f688bSRobert Mustacchi 		 * name, it's less straightforward to match that. Require that
1288bc1f688bSRobert Mustacchi 		 * labels match.
1289bc1f688bSRobert Mustacchi 		 */
1290bc1f688bSRobert Mustacchi 		explabel = ctf_parent_label(g_fp);
1291bc1f688bSRobert Mustacchi 		label = ctf_label_topmost(pfp);
1292bc1f688bSRobert Mustacchi 		if (explabel == NULL || label == NULL ||
1293bc1f688bSRobert Mustacchi 		    strcmp(explabel, label) != 0) {
1294bc1f688bSRobert Mustacchi 			if (label == NULL)
1295bc1f688bSRobert Mustacchi 				label = "<missing>";
1296bc1f688bSRobert Mustacchi 			if (explabel == NULL)
1297bc1f688bSRobert Mustacchi 				explabel = "<missing>";
1298bc1f688bSRobert Mustacchi 			ctfdump_fatal("label mismatch between parent %s and "
1299bc1f688bSRobert Mustacchi 			    "child %s, parent has %s, child expects %s\n",
1300bc1f688bSRobert Mustacchi 			    parent, argv[0], label, explabel);
1301bc1f688bSRobert Mustacchi 		}
1302bc1f688bSRobert Mustacchi 
1303bc1f688bSRobert Mustacchi 		if (ctf_import(g_fp, pfp) != 0)
1304bc1f688bSRobert Mustacchi 			ctfdump_fatal("failed to import parent %s: %s\n",
1305bc1f688bSRobert Mustacchi 			    parent, ctf_errmsg(ctf_errno(g_fp)));
13066ef284f1SJohn Levon 	} else {
13076ef284f1SJohn Levon 		if (g_dump & CTFDUMP_SOURCE) {
13086ef284f1SJohn Levon 			printf("/* Warning: parent \"%s\" not supplied: many "
13096ef284f1SJohn Levon 			    "types will be unknown. */\n\n",
13106ef284f1SJohn Levon 			    ctf_parent_name(g_fp));
13116ef284f1SJohn Levon 		} else {
13126ef284f1SJohn Levon 			fprintf(stderr, "warning: parent \"%s\" not supplied: "
13136ef284f1SJohn Levon 			    "many types will be unknown\n\n",
13146ef284f1SJohn Levon 			    ctf_parent_name(g_fp));
13156ef284f1SJohn Levon 		}
1316bc1f688bSRobert Mustacchi 	}
1317bc1f688bSRobert Mustacchi 
1318bc1f688bSRobert Mustacchi 	if (g_dump & CTFDUMP_SOURCE) {
1319bc1f688bSRobert Mustacchi 		ctfdump_source();
1320bc1f688bSRobert Mustacchi 		return (0);
1321bc1f688bSRobert Mustacchi 	}
1322bc1f688bSRobert Mustacchi 
1323bc1f688bSRobert Mustacchi 	/*
1324bc1f688bSRobert Mustacchi 	 * If stats is set, we must run through everything exect CTFDUMP_OUTPUT.
1325bc1f688bSRobert Mustacchi 	 * We also do CTFDUMP_STATS last as a result.
1326bc1f688bSRobert Mustacchi 	 */
1327bc1f688bSRobert Mustacchi 	if (g_dump & CTFDUMP_HEADER)
1328bc1f688bSRobert Mustacchi 		ctfdump_header();
1329bc1f688bSRobert Mustacchi 
1330bc1f688bSRobert Mustacchi 	if (g_dump & (CTFDUMP_LABELS | CTFDUMP_STATS))
1331bc1f688bSRobert Mustacchi 		ctfdump_labels();
1332bc1f688bSRobert Mustacchi 
1333bc1f688bSRobert Mustacchi 	if (g_dump & (CTFDUMP_OBJECTS | CTFDUMP_STATS))
1334bc1f688bSRobert Mustacchi 		ctfdump_objects();
1335bc1f688bSRobert Mustacchi 
1336bc1f688bSRobert Mustacchi 	if (g_dump & (CTFDUMP_FUNCTIONS | CTFDUMP_STATS))
1337bc1f688bSRobert Mustacchi 		ctfdump_functions();
1338bc1f688bSRobert Mustacchi 
1339bc1f688bSRobert Mustacchi 	if (g_dump & (CTFDUMP_TYPES | CTFDUMP_STATS))
1340bc1f688bSRobert Mustacchi 		ctfdump_types();
1341bc1f688bSRobert Mustacchi 
1342bc1f688bSRobert Mustacchi 	if (g_dump & (CTFDUMP_STRINGS | CTFDUMP_STATS))
1343bc1f688bSRobert Mustacchi 		ctfdump_strings();
1344bc1f688bSRobert Mustacchi 
1345bc1f688bSRobert Mustacchi 	if (g_dump & CTFDUMP_STATS)
1346bc1f688bSRobert Mustacchi 		ctfdump_stats();
1347bc1f688bSRobert Mustacchi 
1348bc1f688bSRobert Mustacchi 	if (g_dump & CTFDUMP_OUTPUT)
1349bc1f688bSRobert Mustacchi 		ctfdump_output(ufile);
1350bc1f688bSRobert Mustacchi 
1351bc1f688bSRobert Mustacchi 	return (g_exit);
1352bc1f688bSRobert Mustacchi }
1353