xref: /onnv-gate/usr/src/tools/ctf/dump/dump.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/sysmacros.h>
31*0Sstevel@tonic-gate #include <sys/stat.h>
32*0Sstevel@tonic-gate #include <sys/mman.h>
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include <strings.h>
35*0Sstevel@tonic-gate #include <unistd.h>
36*0Sstevel@tonic-gate #include <stdlib.h>
37*0Sstevel@tonic-gate #include <stdio.h>
38*0Sstevel@tonic-gate #include <fcntl.h>
39*0Sstevel@tonic-gate #include <gelf.h>
40*0Sstevel@tonic-gate #include <zlib.h>
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #include "ctf_headers.h"
43*0Sstevel@tonic-gate #include "utils.h"
44*0Sstevel@tonic-gate #include "symbol.h"
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate #define	WARN(x)	{ warn(x); return (E_ERROR); }
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate /*
49*0Sstevel@tonic-gate  * Flags that indicate what data is to be displayed.  An explicit `all' value is
50*0Sstevel@tonic-gate  * provided to allow the code to distinguish between a request for everything
51*0Sstevel@tonic-gate  * (currently requested by invoking ctfdump without flags) and individual
52*0Sstevel@tonic-gate  * requests for all of the types of data (an invocation with all flags).  In the
53*0Sstevel@tonic-gate  * former case, we want to be able to implicitly adjust the definition of `all'
54*0Sstevel@tonic-gate  * based on the CTF version of the file being dumped.  For example, if a v2 file
55*0Sstevel@tonic-gate  * is being dumped, `all' includes F_LABEL - a request to dump the label
56*0Sstevel@tonic-gate  * section.  If a v1 file is being dumped, `all' does not include F_LABEL,
57*0Sstevel@tonic-gate  * because v1 CTF doesn't support labels.  We need to be able to distinguish
58*0Sstevel@tonic-gate  * between `ctfdump foo', which has an implicit request for labels if `foo'
59*0Sstevel@tonic-gate  * supports them, and `ctfdump -l foo', which has an explicity request.  In the
60*0Sstevel@tonic-gate  * latter case, we exit with an error if `foo' is a v1 CTF file.
61*0Sstevel@tonic-gate  */
62*0Sstevel@tonic-gate static enum {
63*0Sstevel@tonic-gate 	F_DATA	= 0x01,		/* show data object section */
64*0Sstevel@tonic-gate 	F_FUNC	= 0x02,		/* show function section */
65*0Sstevel@tonic-gate 	F_HDR	= 0x04,		/* show header */
66*0Sstevel@tonic-gate 	F_STR	= 0x08,		/* show string table */
67*0Sstevel@tonic-gate 	F_TYPES	= 0x10,		/* show type section */
68*0Sstevel@tonic-gate 	F_STATS = 0x20, 	/* show statistics */
69*0Sstevel@tonic-gate 	F_LABEL	= 0x40,		/* show label section */
70*0Sstevel@tonic-gate 	F_ALL	= 0x80,		/* explicit request for `all' */
71*0Sstevel@tonic-gate 	F_ALLMSK = 0xff		/* show all sections and statistics */
72*0Sstevel@tonic-gate } flags = 0;
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate static struct {
75*0Sstevel@tonic-gate 	ulong_t s_ndata;	/* total number of data objects */
76*0Sstevel@tonic-gate 	ulong_t s_nfunc;	/* total number of functions */
77*0Sstevel@tonic-gate 	ulong_t s_nargs;	/* total number of function arguments */
78*0Sstevel@tonic-gate 	ulong_t s_argmax;	/* longest argument list */
79*0Sstevel@tonic-gate 	ulong_t s_ntypes;	/* total number of types */
80*0Sstevel@tonic-gate 	ulong_t s_types[16];	/* number of types by kind */
81*0Sstevel@tonic-gate 	ulong_t s_nsmem;	/* total number of struct members */
82*0Sstevel@tonic-gate 	ulong_t s_nsbytes;	/* total size of all structs */
83*0Sstevel@tonic-gate 	ulong_t s_smmax;	/* largest struct in terms of members */
84*0Sstevel@tonic-gate 	ulong_t s_sbmax;	/* largest struct in terms of bytes */
85*0Sstevel@tonic-gate 	ulong_t s_numem;	/* total number of union members */
86*0Sstevel@tonic-gate 	ulong_t s_nubytes;	/* total size of all unions */
87*0Sstevel@tonic-gate 	ulong_t s_ummax;	/* largest union in terms of members */
88*0Sstevel@tonic-gate 	ulong_t s_ubmax;	/* largest union in terms of bytes */
89*0Sstevel@tonic-gate 	ulong_t s_nemem;	/* total number of enum members */
90*0Sstevel@tonic-gate 	ulong_t s_emmax;	/* largest enum in terms of members */
91*0Sstevel@tonic-gate 	ulong_t s_nstr;		/* total number of strings */
92*0Sstevel@tonic-gate 	size_t s_strlen;	/* total length of all strings */
93*0Sstevel@tonic-gate 	size_t s_strmax;	/* longest string length */
94*0Sstevel@tonic-gate } stats;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate typedef struct ctf_data {
97*0Sstevel@tonic-gate 	caddr_t cd_ctfdata;	/* Pointer to the CTF data */
98*0Sstevel@tonic-gate 	size_t cd_ctflen;	/* Length of CTF data */
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	/*
101*0Sstevel@tonic-gate 	 * cd_symdata will be non-NULL if the CTF data is being retrieved from
102*0Sstevel@tonic-gate 	 * an ELF file with a symbol table.  cd_strdata and cd_nsyms should be
103*0Sstevel@tonic-gate 	 * used only if cd_symdata is non-NULL.
104*0Sstevel@tonic-gate 	 */
105*0Sstevel@tonic-gate 	Elf_Data *cd_symdata;	/* Symbol table */
106*0Sstevel@tonic-gate 	Elf_Data *cd_strdata;	/* Symbol table strings */
107*0Sstevel@tonic-gate 	int cd_nsyms;		/* Number of symbol table entries */
108*0Sstevel@tonic-gate } ctf_data_t;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate static const char *
ref_to_str(uint_t name,const ctf_header_t * hp,const ctf_data_t * cd)111*0Sstevel@tonic-gate ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	size_t offset = CTF_NAME_OFFSET(name);
114*0Sstevel@tonic-gate 	const char *s = cd->cd_ctfdata + hp->cth_stroff + offset;
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	if (CTF_NAME_STID(name) != CTF_STRTAB_0)
117*0Sstevel@tonic-gate 		return ("<< ??? - name in external strtab >>");
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	if (offset >= hp->cth_strlen)
120*0Sstevel@tonic-gate 		return ("<< ??? - name exceeds strlab len >>");
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	if (hp->cth_stroff + offset >= cd->cd_ctflen)
123*0Sstevel@tonic-gate 		return ("<< ??? - file truncated >>");
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	if (s[0] == '\0')
126*0Sstevel@tonic-gate 		return ("(anon)");
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	return (s);
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate static const char *
int_encoding_to_str(uint_t encoding)132*0Sstevel@tonic-gate int_encoding_to_str(uint_t encoding)
133*0Sstevel@tonic-gate {
134*0Sstevel@tonic-gate 	static char buf[32];
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR |
137*0Sstevel@tonic-gate 	    CTF_INT_BOOL | CTF_INT_VARARGS)) != 0)
138*0Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), " 0x%x", encoding);
139*0Sstevel@tonic-gate 	else {
140*0Sstevel@tonic-gate 		buf[0] = '\0';
141*0Sstevel@tonic-gate 		if (encoding & CTF_INT_SIGNED)
142*0Sstevel@tonic-gate 			(void) strcat(buf, " SIGNED");
143*0Sstevel@tonic-gate 		if (encoding & CTF_INT_CHAR)
144*0Sstevel@tonic-gate 			(void) strcat(buf, " CHAR");
145*0Sstevel@tonic-gate 		if (encoding & CTF_INT_BOOL)
146*0Sstevel@tonic-gate 			(void) strcat(buf, " BOOL");
147*0Sstevel@tonic-gate 		if (encoding & CTF_INT_VARARGS)
148*0Sstevel@tonic-gate 			(void) strcat(buf, " VARARGS");
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	return (buf + 1);
152*0Sstevel@tonic-gate }
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate static const char *
fp_encoding_to_str(uint_t encoding)155*0Sstevel@tonic-gate fp_encoding_to_str(uint_t encoding)
156*0Sstevel@tonic-gate {
157*0Sstevel@tonic-gate 	static const char *const encs[] = {
158*0Sstevel@tonic-gate 		NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX",
159*0Sstevel@tonic-gate 		"LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",
160*0Sstevel@tonic-gate 		"DIMAGINARY", "LDIMAGINARY"
161*0Sstevel@tonic-gate 	};
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	static char buf[16];
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) {
166*0Sstevel@tonic-gate 		(void) snprintf(buf, sizeof (buf), "%u", encoding);
167*0Sstevel@tonic-gate 		return (buf);
168*0Sstevel@tonic-gate 	}
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 	return (encs[encoding]);
171*0Sstevel@tonic-gate }
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate static void
print_line(const char * s)174*0Sstevel@tonic-gate print_line(const char *s)
175*0Sstevel@tonic-gate {
176*0Sstevel@tonic-gate 	static const char line[] = "----------------------------------------"
177*0Sstevel@tonic-gate 	    "----------------------------------------";
178*0Sstevel@tonic-gate 	(void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line);
179*0Sstevel@tonic-gate }
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate static int
print_header(const ctf_header_t * hp,const ctf_data_t * cd)182*0Sstevel@tonic-gate print_header(const ctf_header_t *hp, const ctf_data_t *cd)
183*0Sstevel@tonic-gate {
184*0Sstevel@tonic-gate 	print_line("- CTF Header ");
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	(void) printf("  cth_magic    = 0x%04x\n", hp->cth_magic);
187*0Sstevel@tonic-gate 	(void) printf("  cth_version  = %u\n", hp->cth_version);
188*0Sstevel@tonic-gate 	(void) printf("  cth_flags    = 0x%02x\n", hp->cth_flags);
189*0Sstevel@tonic-gate 	(void) printf("  cth_parlabel = %s\n",
190*0Sstevel@tonic-gate 	    ref_to_str(hp->cth_parlabel, hp, cd));
191*0Sstevel@tonic-gate 	(void) printf("  cth_parname  = %s\n",
192*0Sstevel@tonic-gate 	    ref_to_str(hp->cth_parname, hp, cd));
193*0Sstevel@tonic-gate 	(void) printf("  cth_lbloff   = %u\n", hp->cth_lbloff);
194*0Sstevel@tonic-gate 	(void) printf("  cth_objtoff  = %u\n", hp->cth_objtoff);
195*0Sstevel@tonic-gate 	(void) printf("  cth_funcoff  = %u\n", hp->cth_funcoff);
196*0Sstevel@tonic-gate 	(void) printf("  cth_typeoff  = %u\n", hp->cth_typeoff);
197*0Sstevel@tonic-gate 	(void) printf("  cth_stroff   = %u\n", hp->cth_stroff);
198*0Sstevel@tonic-gate 	(void) printf("  cth_strlen   = %u\n", hp->cth_strlen);
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	return (E_SUCCESS);
201*0Sstevel@tonic-gate }
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate static int
print_labeltable(const ctf_header_t * hp,const ctf_data_t * cd)204*0Sstevel@tonic-gate print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd)
205*0Sstevel@tonic-gate {
206*0Sstevel@tonic-gate 	/* LINTED - pointer alignment */
207*0Sstevel@tonic-gate 	const ctf_lblent_t *ctl = (ctf_lblent_t *)(cd->cd_ctfdata +
208*0Sstevel@tonic-gate 	    hp->cth_lbloff);
209*0Sstevel@tonic-gate 	ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl);
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	print_line("- Label Table ");
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	if (hp->cth_lbloff & 3)
214*0Sstevel@tonic-gate 		WARN("cth_lbloff is not aligned properly\n");
215*0Sstevel@tonic-gate 	if (hp->cth_lbloff >= cd->cd_ctflen)
216*0Sstevel@tonic-gate 		WARN("file is truncated or cth_lbloff is corrupt\n");
217*0Sstevel@tonic-gate 	if (hp->cth_objtoff >= cd->cd_ctflen)
218*0Sstevel@tonic-gate 		WARN("file is truncated or cth_objtoff is corrupt\n");
219*0Sstevel@tonic-gate 	if (hp->cth_lbloff > hp->cth_objtoff)
220*0Sstevel@tonic-gate 		WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	for (i = 0; i < n; i++, ctl++) {
223*0Sstevel@tonic-gate 		(void) printf("  %5u %s\n", ctl->ctl_typeidx,
224*0Sstevel@tonic-gate 		    ref_to_str(ctl->ctl_label, hp, cd));
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	return (E_SUCCESS);
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate /*
231*0Sstevel@tonic-gate  * Given the current symbol index (-1 to start at the beginning of the symbol
232*0Sstevel@tonic-gate  * table) and the type of symbol to match, this function returns the index of
233*0Sstevel@tonic-gate  * the next matching symbol (if any), and places the name of that symbol in
234*0Sstevel@tonic-gate  * *namep.  If no symbol is found, -1 is returned.
235*0Sstevel@tonic-gate  */
236*0Sstevel@tonic-gate static int
next_sym(const ctf_data_t * cd,const int symidx,const uchar_t matchtype,char ** namep)237*0Sstevel@tonic-gate next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,
238*0Sstevel@tonic-gate     char **namep)
239*0Sstevel@tonic-gate {
240*0Sstevel@tonic-gate 	int i;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	for (i = symidx + 1; i < cd->cd_nsyms; i++) {
243*0Sstevel@tonic-gate 		GElf_Sym sym;
244*0Sstevel@tonic-gate 		char *name;
245*0Sstevel@tonic-gate 		int type;
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 		if (gelf_getsym(cd->cd_symdata, i, &sym) == 0)
248*0Sstevel@tonic-gate 			return (-1);
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 		name = (char *)cd->cd_strdata->d_buf + sym.st_name;
251*0Sstevel@tonic-gate 		type = GELF_ST_TYPE(sym.st_info);
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 		/*
254*0Sstevel@tonic-gate 		 * Skip various types of symbol table entries.
255*0Sstevel@tonic-gate 		 */
256*0Sstevel@tonic-gate 		if (type != matchtype || ignore_symbol(&sym, name))
257*0Sstevel@tonic-gate 			continue;
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 		/* Found one */
260*0Sstevel@tonic-gate 		*namep = name;
261*0Sstevel@tonic-gate 		return (i);
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	return (-1);
265*0Sstevel@tonic-gate }
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate static int
read_data(const ctf_header_t * hp,const ctf_data_t * cd)268*0Sstevel@tonic-gate read_data(const ctf_header_t *hp, const ctf_data_t *cd)
269*0Sstevel@tonic-gate {
270*0Sstevel@tonic-gate 	/* LINTED - pointer alignment */
271*0Sstevel@tonic-gate 	const ushort_t *idp = (ushort_t *)(cd->cd_ctfdata + hp->cth_objtoff);
272*0Sstevel@tonic-gate 	ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / sizeof (ushort_t);
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	if (flags != F_STATS)
275*0Sstevel@tonic-gate 		print_line("- Data Objects ");
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	if (hp->cth_objtoff & 1)
278*0Sstevel@tonic-gate 		WARN("cth_objtoff is not aligned properly\n");
279*0Sstevel@tonic-gate 	if (hp->cth_objtoff >= cd->cd_ctflen)
280*0Sstevel@tonic-gate 		WARN("file is truncated or cth_objtoff is corrupt\n");
281*0Sstevel@tonic-gate 	if (hp->cth_funcoff >= cd->cd_ctflen)
282*0Sstevel@tonic-gate 		WARN("file is truncated or cth_funcoff is corrupt\n");
283*0Sstevel@tonic-gate 	if (hp->cth_objtoff > hp->cth_funcoff)
284*0Sstevel@tonic-gate 		WARN("file is corrupt -- cth_objtoff > cth_funcoff\n");
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	if (flags != F_STATS) {
287*0Sstevel@tonic-gate 		int symidx, len, i;
288*0Sstevel@tonic-gate 		char *name = NULL;
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 		for (symidx = -1, i = 0; i < n; i++) {
291*0Sstevel@tonic-gate 			int nextsym;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 			if (cd->cd_symdata == NULL || (nextsym = next_sym(cd,
294*0Sstevel@tonic-gate 			    symidx, STT_OBJECT, &name)) < 0)
295*0Sstevel@tonic-gate 				name = NULL;
296*0Sstevel@tonic-gate 			else
297*0Sstevel@tonic-gate 				symidx = nextsym;
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 			len = printf("  [%u] %u", i, *idp++);
300*0Sstevel@tonic-gate 			if (name != NULL)
301*0Sstevel@tonic-gate 				(void) printf("%*s%s (%u)", (15 - len), "",
302*0Sstevel@tonic-gate 				    name, symidx);
303*0Sstevel@tonic-gate 			(void) putchar('\n');
304*0Sstevel@tonic-gate 		}
305*0Sstevel@tonic-gate 	}
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	stats.s_ndata = n;
308*0Sstevel@tonic-gate 	return (E_SUCCESS);
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate static int
read_funcs(const ctf_header_t * hp,const ctf_data_t * cd)312*0Sstevel@tonic-gate read_funcs(const ctf_header_t *hp, const ctf_data_t *cd)
313*0Sstevel@tonic-gate {
314*0Sstevel@tonic-gate 	/* LINTED - pointer alignment */
315*0Sstevel@tonic-gate 	const ushort_t *fp = (ushort_t *)(cd->cd_ctfdata + hp->cth_funcoff);
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	/* LINTED - pointer alignment */
318*0Sstevel@tonic-gate 	const ushort_t *end = (ushort_t *)(cd->cd_ctfdata + hp->cth_typeoff);
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	ulong_t id;
321*0Sstevel@tonic-gate 	int symidx;
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	if (flags != F_STATS)
324*0Sstevel@tonic-gate 		print_line("- Functions ");
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	if (hp->cth_funcoff & 1)
327*0Sstevel@tonic-gate 		WARN("cth_funcoff is not aligned properly\n");
328*0Sstevel@tonic-gate 	if (hp->cth_funcoff >= cd->cd_ctflen)
329*0Sstevel@tonic-gate 		WARN("file is truncated or cth_funcoff is corrupt\n");
330*0Sstevel@tonic-gate 	if (hp->cth_typeoff >= cd->cd_ctflen)
331*0Sstevel@tonic-gate 		WARN("file is truncated or cth_typeoff is corrupt\n");
332*0Sstevel@tonic-gate 	if (hp->cth_funcoff > hp->cth_typeoff)
333*0Sstevel@tonic-gate 		WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	for (symidx = -1, id = 0; fp < end; id++) {
336*0Sstevel@tonic-gate 		ushort_t info = *fp++;
337*0Sstevel@tonic-gate 		ushort_t kind = CTF_INFO_KIND(info);
338*0Sstevel@tonic-gate 		ushort_t n = CTF_INFO_VLEN(info);
339*0Sstevel@tonic-gate 		ushort_t i;
340*0Sstevel@tonic-gate 		int nextsym;
341*0Sstevel@tonic-gate 		char *name;
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 		if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx,
344*0Sstevel@tonic-gate 		    STT_FUNC, &name)) < 0)
345*0Sstevel@tonic-gate 			name = NULL;
346*0Sstevel@tonic-gate 		else
347*0Sstevel@tonic-gate 			symidx = nextsym;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 		if (kind == CTF_K_UNKNOWN && n == 0)
350*0Sstevel@tonic-gate 			continue; /* skip padding */
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 		if (kind != CTF_K_FUNCTION) {
353*0Sstevel@tonic-gate 			(void) printf("  [%lu] unexpected kind -- %u\n",
354*0Sstevel@tonic-gate 			    id, kind);
355*0Sstevel@tonic-gate 			return (E_ERROR);
356*0Sstevel@tonic-gate 		}
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 		if (fp + n > end) {
359*0Sstevel@tonic-gate 			(void) printf("  [%lu] vlen %u extends past section "
360*0Sstevel@tonic-gate 			    "boundary\n", id, n);
361*0Sstevel@tonic-gate 			return (E_ERROR);
362*0Sstevel@tonic-gate 		}
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 		if (flags != F_STATS) {
365*0Sstevel@tonic-gate 			(void) printf("  [%lu] FUNC ", id);
366*0Sstevel@tonic-gate 			if (name != NULL)
367*0Sstevel@tonic-gate 				(void) printf("(%s) ", name);
368*0Sstevel@tonic-gate 			(void) printf("returns: %u args: (", *fp++);
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 			if (n != 0) {
371*0Sstevel@tonic-gate 				(void) printf("%u", *fp++);
372*0Sstevel@tonic-gate 				for (i = 1; i < n; i++)
373*0Sstevel@tonic-gate 					(void) printf(", %u", *fp++);
374*0Sstevel@tonic-gate 			}
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 			(void) printf(")\n");
377*0Sstevel@tonic-gate 		} else
378*0Sstevel@tonic-gate 			fp += n + 1; /* skip to next function definition */
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 		stats.s_nfunc++;
381*0Sstevel@tonic-gate 		stats.s_nargs += n;
382*0Sstevel@tonic-gate 		stats.s_argmax = MAX(stats.s_argmax, n);
383*0Sstevel@tonic-gate 	}
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 	return (E_SUCCESS);
386*0Sstevel@tonic-gate }
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate static int
read_types(const ctf_header_t * hp,const ctf_data_t * cd)389*0Sstevel@tonic-gate read_types(const ctf_header_t *hp, const ctf_data_t *cd)
390*0Sstevel@tonic-gate {
391*0Sstevel@tonic-gate 	/* LINTED - pointer alignment */
392*0Sstevel@tonic-gate 	const ctf_type_t *tp = (ctf_type_t *)(cd->cd_ctfdata + hp->cth_typeoff);
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	/* LINTED - pointer alignment */
395*0Sstevel@tonic-gate 	const ctf_type_t *end = (ctf_type_t *)(cd->cd_ctfdata + hp->cth_stroff);
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	ulong_t id;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	if (flags != F_STATS)
400*0Sstevel@tonic-gate 		print_line("- Types ");
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	if (hp->cth_typeoff & 3)
403*0Sstevel@tonic-gate 		WARN("cth_typeoff is not aligned properly\n");
404*0Sstevel@tonic-gate 	if (hp->cth_typeoff >= cd->cd_ctflen)
405*0Sstevel@tonic-gate 		WARN("file is truncated or cth_typeoff is corrupt\n");
406*0Sstevel@tonic-gate 	if (hp->cth_stroff >= cd->cd_ctflen)
407*0Sstevel@tonic-gate 		WARN("file is truncated or cth_stroff is corrupt\n");
408*0Sstevel@tonic-gate 	if (hp->cth_typeoff > hp->cth_stroff)
409*0Sstevel@tonic-gate 		WARN("file is corrupt -- cth_typeoff > cth_stroff\n");
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	id = 1;
412*0Sstevel@tonic-gate 	if (hp->cth_parlabel || hp->cth_parname)
413*0Sstevel@tonic-gate 		id += 1 << CTF_PARENT_SHIFT;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	for (/* */; tp < end; id++) {
416*0Sstevel@tonic-gate 		ulong_t i, n = CTF_INFO_VLEN(tp->ctt_info);
417*0Sstevel@tonic-gate 		size_t size, increment, vlen = 0;
418*0Sstevel@tonic-gate 		int kind = CTF_INFO_KIND(tp->ctt_info);
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 		union {
421*0Sstevel@tonic-gate 			const void *ptr;
422*0Sstevel@tonic-gate 			const ctf_array_t *ap;
423*0Sstevel@tonic-gate 			const ctf_member_t *mp;
424*0Sstevel@tonic-gate 			const ctf_lmember_t *lmp;
425*0Sstevel@tonic-gate 			const ctf_enum_t *ep;
426*0Sstevel@tonic-gate 			const ushort_t *argp;
427*0Sstevel@tonic-gate 		} u;
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 		if (flags != F_STATS) {
430*0Sstevel@tonic-gate 			(void) printf("  %c%lu%c ",
431*0Sstevel@tonic-gate 			    "[<"[CTF_INFO_ISROOT(tp->ctt_info)], id,
432*0Sstevel@tonic-gate 			    "]>"[CTF_INFO_ISROOT(tp->ctt_info)]);
433*0Sstevel@tonic-gate 		}
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 		if (tp->ctt_size == CTF_LSIZE_SENT) {
436*0Sstevel@tonic-gate 			increment = sizeof (ctf_type_t);
437*0Sstevel@tonic-gate 			size = (size_t)CTF_TYPE_LSIZE(tp);
438*0Sstevel@tonic-gate 		} else {
439*0Sstevel@tonic-gate 			increment = sizeof (ctf_stype_t);
440*0Sstevel@tonic-gate 			size = tp->ctt_size;
441*0Sstevel@tonic-gate 		}
442*0Sstevel@tonic-gate 		u.ptr = (caddr_t)tp + increment;
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate 		switch (kind) {
445*0Sstevel@tonic-gate 		case CTF_K_INTEGER:
446*0Sstevel@tonic-gate 			if (flags != F_STATS) {
447*0Sstevel@tonic-gate 				uint_t encoding = *((const uint_t *)u.ptr);
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 				(void) printf("INTEGER %s encoding=%s offset=%u"
450*0Sstevel@tonic-gate 				    " bits=%u", ref_to_str(tp->ctt_name, hp,
451*0Sstevel@tonic-gate 				    cd), int_encoding_to_str(
452*0Sstevel@tonic-gate 				    CTF_INT_ENCODING(encoding)),
453*0Sstevel@tonic-gate 				    CTF_INT_OFFSET(encoding),
454*0Sstevel@tonic-gate 				    CTF_INT_BITS(encoding));
455*0Sstevel@tonic-gate 			}
456*0Sstevel@tonic-gate 			vlen = sizeof (uint_t);
457*0Sstevel@tonic-gate 			break;
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 		case CTF_K_FLOAT:
460*0Sstevel@tonic-gate 			if (flags != F_STATS) {
461*0Sstevel@tonic-gate 				uint_t encoding = *((const uint_t *)u.ptr);
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 				(void) printf("FLOAT %s encoding=%s offset=%u "
464*0Sstevel@tonic-gate 				    "bits=%u", ref_to_str(tp->ctt_name, hp,
465*0Sstevel@tonic-gate 				    cd), fp_encoding_to_str(
466*0Sstevel@tonic-gate 				    CTF_FP_ENCODING(encoding)),
467*0Sstevel@tonic-gate 				    CTF_FP_OFFSET(encoding),
468*0Sstevel@tonic-gate 				    CTF_FP_BITS(encoding));
469*0Sstevel@tonic-gate 			}
470*0Sstevel@tonic-gate 			vlen = sizeof (uint_t);
471*0Sstevel@tonic-gate 			break;
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 		case CTF_K_POINTER:
474*0Sstevel@tonic-gate 			if (flags != F_STATS) {
475*0Sstevel@tonic-gate 				(void) printf("POINTER %s refers to %u",
476*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd),
477*0Sstevel@tonic-gate 				    tp->ctt_type);
478*0Sstevel@tonic-gate 			}
479*0Sstevel@tonic-gate 			break;
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 		case CTF_K_ARRAY:
482*0Sstevel@tonic-gate 			if (flags != F_STATS) {
483*0Sstevel@tonic-gate 				(void) printf("ARRAY %s content: %u index: %u "
484*0Sstevel@tonic-gate 				    "nelems: %u\n", ref_to_str(tp->ctt_name,
485*0Sstevel@tonic-gate 				    hp, cd), u.ap->cta_contents,
486*0Sstevel@tonic-gate 				    u.ap->cta_index, u.ap->cta_nelems);
487*0Sstevel@tonic-gate 			}
488*0Sstevel@tonic-gate 			vlen = sizeof (ctf_array_t);
489*0Sstevel@tonic-gate 			break;
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 		case CTF_K_FUNCTION:
492*0Sstevel@tonic-gate 			if (flags != F_STATS) {
493*0Sstevel@tonic-gate 				(void) printf("FUNCTION %s returns: %u args: (",
494*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd),
495*0Sstevel@tonic-gate 				    tp->ctt_type);
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 				if (n != 0) {
498*0Sstevel@tonic-gate 					(void) printf("%u", *u.argp++);
499*0Sstevel@tonic-gate 					for (i = 1; i < n; i++, u.argp++)
500*0Sstevel@tonic-gate 						(void) printf(", %u", *u.argp);
501*0Sstevel@tonic-gate 				}
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 				(void) printf(")");
504*0Sstevel@tonic-gate 			}
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 			vlen = sizeof (ushort_t) * (n + (n & 1));
507*0Sstevel@tonic-gate 			break;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 		case CTF_K_STRUCT:
510*0Sstevel@tonic-gate 		case CTF_K_UNION:
511*0Sstevel@tonic-gate 			if (kind == CTF_K_STRUCT) {
512*0Sstevel@tonic-gate 				stats.s_nsmem += n;
513*0Sstevel@tonic-gate 				stats.s_smmax = MAX(stats.s_smmax, n);
514*0Sstevel@tonic-gate 				stats.s_nsbytes += size;
515*0Sstevel@tonic-gate 				stats.s_sbmax = MAX(stats.s_sbmax, size);
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 				if (flags != F_STATS)
518*0Sstevel@tonic-gate 					(void) printf("STRUCT");
519*0Sstevel@tonic-gate 			} else {
520*0Sstevel@tonic-gate 				stats.s_numem += n;
521*0Sstevel@tonic-gate 				stats.s_ummax = MAX(stats.s_ummax, n);
522*0Sstevel@tonic-gate 				stats.s_nubytes += size;
523*0Sstevel@tonic-gate 				stats.s_ubmax = MAX(stats.s_ubmax, size);
524*0Sstevel@tonic-gate 
525*0Sstevel@tonic-gate 				if (flags != F_STATS)
526*0Sstevel@tonic-gate 					(void) printf("UNION");
527*0Sstevel@tonic-gate 			}
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 			if (flags != F_STATS) {
530*0Sstevel@tonic-gate 				(void) printf(" %s (%d bytes)\n",
531*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd), size);
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 				if (size >= CTF_LSTRUCT_THRESH) {
534*0Sstevel@tonic-gate 					for (i = 0; i < n; i++, u.lmp++) {
535*0Sstevel@tonic-gate 						(void) printf(
536*0Sstevel@tonic-gate 						    "\t%s type=%u off=%llu\n",
537*0Sstevel@tonic-gate 						    ref_to_str(u.lmp->ctlm_name,
538*0Sstevel@tonic-gate 						    hp, cd), u.lmp->ctlm_type,
539*0Sstevel@tonic-gate 						    CTF_LMEM_OFFSET(u.lmp));
540*0Sstevel@tonic-gate 					}
541*0Sstevel@tonic-gate 				} else {
542*0Sstevel@tonic-gate 					for (i = 0; i < n; i++, u.mp++) {
543*0Sstevel@tonic-gate 						(void) printf(
544*0Sstevel@tonic-gate 						    "\t%s type=%u off=%u\n",
545*0Sstevel@tonic-gate 						    ref_to_str(u.mp->ctm_name,
546*0Sstevel@tonic-gate 						    hp, cd), u.mp->ctm_type,
547*0Sstevel@tonic-gate 						    u.mp->ctm_offset);
548*0Sstevel@tonic-gate 					}
549*0Sstevel@tonic-gate 				}
550*0Sstevel@tonic-gate 			}
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 			vlen = n * (size >= CTF_LSTRUCT_THRESH ?
553*0Sstevel@tonic-gate 			    sizeof (ctf_lmember_t) : sizeof (ctf_member_t));
554*0Sstevel@tonic-gate 			break;
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 		case CTF_K_ENUM:
557*0Sstevel@tonic-gate 			if (flags != F_STATS) {
558*0Sstevel@tonic-gate 				(void) printf("ENUM %s\n",
559*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd));
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 				for (i = 0; i < n; i++, u.ep++) {
562*0Sstevel@tonic-gate 					(void) printf("\t%s = %d\n",
563*0Sstevel@tonic-gate 					    ref_to_str(u.ep->cte_name, hp, cd),
564*0Sstevel@tonic-gate 					    u.ep->cte_value);
565*0Sstevel@tonic-gate 				}
566*0Sstevel@tonic-gate 			}
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 			stats.s_nemem += n;
569*0Sstevel@tonic-gate 			stats.s_emmax = MAX(stats.s_emmax, n);
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 			vlen = sizeof (ctf_enum_t) * n;
572*0Sstevel@tonic-gate 			break;
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 		case CTF_K_FORWARD:
575*0Sstevel@tonic-gate 			if (flags != F_STATS) {
576*0Sstevel@tonic-gate 				(void) printf("FORWARD %s",
577*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd));
578*0Sstevel@tonic-gate 			}
579*0Sstevel@tonic-gate 			break;
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 		case CTF_K_TYPEDEF:
582*0Sstevel@tonic-gate 			if (flags != F_STATS) {
583*0Sstevel@tonic-gate 				(void) printf("TYPEDEF %s refers to %u",
584*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd),
585*0Sstevel@tonic-gate 				    tp->ctt_type);
586*0Sstevel@tonic-gate 			}
587*0Sstevel@tonic-gate 			break;
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		case CTF_K_VOLATILE:
590*0Sstevel@tonic-gate 			if (flags != F_STATS) {
591*0Sstevel@tonic-gate 				(void) printf("VOLATILE %s refers to %u",
592*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd),
593*0Sstevel@tonic-gate 				    tp->ctt_type);
594*0Sstevel@tonic-gate 			}
595*0Sstevel@tonic-gate 			break;
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 		case CTF_K_CONST:
598*0Sstevel@tonic-gate 			if (flags != F_STATS) {
599*0Sstevel@tonic-gate 				(void) printf("CONST %s refers to %u",
600*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd),
601*0Sstevel@tonic-gate 				    tp->ctt_type);
602*0Sstevel@tonic-gate 			}
603*0Sstevel@tonic-gate 			break;
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 		case CTF_K_RESTRICT:
606*0Sstevel@tonic-gate 			if (flags != F_STATS) {
607*0Sstevel@tonic-gate 				(void) printf("RESTRICT %s refers to %u",
608*0Sstevel@tonic-gate 				    ref_to_str(tp->ctt_name, hp, cd),
609*0Sstevel@tonic-gate 				    tp->ctt_type);
610*0Sstevel@tonic-gate 			}
611*0Sstevel@tonic-gate 			break;
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 		case CTF_K_UNKNOWN:
614*0Sstevel@tonic-gate 			break; /* hole in type id space */
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 		default:
617*0Sstevel@tonic-gate 			(void) printf("unexpected kind %u\n", kind);
618*0Sstevel@tonic-gate 			return (E_ERROR);
619*0Sstevel@tonic-gate 		}
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 		if (flags != F_STATS)
622*0Sstevel@tonic-gate 			(void) printf("\n");
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 		stats.s_ntypes++;
625*0Sstevel@tonic-gate 		stats.s_types[kind]++;
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 		tp = (ctf_type_t *)((uintptr_t)tp + increment + vlen);
628*0Sstevel@tonic-gate 	}
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 	return (E_SUCCESS);
631*0Sstevel@tonic-gate }
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate static int
read_strtab(const ctf_header_t * hp,const ctf_data_t * cd)634*0Sstevel@tonic-gate read_strtab(const ctf_header_t *hp, const ctf_data_t *cd)
635*0Sstevel@tonic-gate {
636*0Sstevel@tonic-gate 	size_t n, off, len = hp->cth_strlen;
637*0Sstevel@tonic-gate 	const char *s = cd->cd_ctfdata + hp->cth_stroff;
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	if (flags != F_STATS)
640*0Sstevel@tonic-gate 		print_line("- String Table ");
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate 	if (hp->cth_stroff >= cd->cd_ctflen)
643*0Sstevel@tonic-gate 		WARN("file is truncated or cth_stroff is corrupt\n");
644*0Sstevel@tonic-gate 	if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen)
645*0Sstevel@tonic-gate 		WARN("file is truncated or cth_strlen is corrupt\n");
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	for (off = 0; len != 0; off += n) {
648*0Sstevel@tonic-gate 		if (flags != F_STATS) {
649*0Sstevel@tonic-gate 			(void) printf("  [%lu] %s\n", (ulong_t)off,
650*0Sstevel@tonic-gate 			    s[0] == '\0' ? "\\0" : s);
651*0Sstevel@tonic-gate 		}
652*0Sstevel@tonic-gate 		n = strlen(s) + 1;
653*0Sstevel@tonic-gate 		len -= n;
654*0Sstevel@tonic-gate 		s += n;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 		stats.s_nstr++;
657*0Sstevel@tonic-gate 		stats.s_strlen += n;
658*0Sstevel@tonic-gate 		stats.s_strmax = MAX(stats.s_strmax, n);
659*0Sstevel@tonic-gate 	}
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 	return (E_SUCCESS);
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate static void
long_stat(const char * name,ulong_t value)665*0Sstevel@tonic-gate long_stat(const char *name, ulong_t value)
666*0Sstevel@tonic-gate {
667*0Sstevel@tonic-gate 	(void) printf("  %-36s= %lu\n", name, value);
668*0Sstevel@tonic-gate }
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate static void
fp_stat(const char * name,float value)671*0Sstevel@tonic-gate fp_stat(const char *name, float value)
672*0Sstevel@tonic-gate {
673*0Sstevel@tonic-gate 	(void) printf("  %-36s= %.2f\n", name, value);
674*0Sstevel@tonic-gate }
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate static int
print_stats(void)677*0Sstevel@tonic-gate print_stats(void)
678*0Sstevel@tonic-gate {
679*0Sstevel@tonic-gate 	print_line("- CTF Statistics ");
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	long_stat("total number of data objects", stats.s_ndata);
682*0Sstevel@tonic-gate 	(void) printf("\n");
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 	long_stat("total number of functions", stats.s_nfunc);
685*0Sstevel@tonic-gate 	long_stat("total number of function arguments", stats.s_nargs);
686*0Sstevel@tonic-gate 	long_stat("maximum argument list length", stats.s_argmax);
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 	if (stats.s_nfunc != 0) {
689*0Sstevel@tonic-gate 		fp_stat("average argument list length",
690*0Sstevel@tonic-gate 		    (float)stats.s_nargs / (float)stats.s_nfunc);
691*0Sstevel@tonic-gate 	}
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	(void) printf("\n");
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	long_stat("total number of types", stats.s_ntypes);
696*0Sstevel@tonic-gate 	long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]);
697*0Sstevel@tonic-gate 	long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]);
698*0Sstevel@tonic-gate 	long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]);
699*0Sstevel@tonic-gate 	long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]);
700*0Sstevel@tonic-gate 	long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]);
701*0Sstevel@tonic-gate 	long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]);
702*0Sstevel@tonic-gate 	long_stat("total number of unions", stats.s_types[CTF_K_UNION]);
703*0Sstevel@tonic-gate 	long_stat("total number of enums", stats.s_types[CTF_K_ENUM]);
704*0Sstevel@tonic-gate 	long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]);
705*0Sstevel@tonic-gate 	long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]);
706*0Sstevel@tonic-gate 	long_stat("total number of volatile types",
707*0Sstevel@tonic-gate 	    stats.s_types[CTF_K_VOLATILE]);
708*0Sstevel@tonic-gate 	long_stat("total number of const types", stats.s_types[CTF_K_CONST]);
709*0Sstevel@tonic-gate 	long_stat("total number of restrict types",
710*0Sstevel@tonic-gate 	    stats.s_types[CTF_K_RESTRICT]);
711*0Sstevel@tonic-gate 	long_stat("total number of unknowns (holes)",
712*0Sstevel@tonic-gate 	    stats.s_types[CTF_K_UNKNOWN]);
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	(void) printf("\n");
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 	long_stat("total number of struct members", stats.s_nsmem);
717*0Sstevel@tonic-gate 	long_stat("maximum number of struct members", stats.s_smmax);
718*0Sstevel@tonic-gate 	long_stat("total size of all structs", stats.s_nsbytes);
719*0Sstevel@tonic-gate 	long_stat("maximum size of a struct", stats.s_sbmax);
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	if (stats.s_types[CTF_K_STRUCT] != 0) {
722*0Sstevel@tonic-gate 		fp_stat("average number of struct members",
723*0Sstevel@tonic-gate 		    (float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]);
724*0Sstevel@tonic-gate 		fp_stat("average size of a struct", (float)stats.s_nsbytes /
725*0Sstevel@tonic-gate 		    (float)stats.s_types[CTF_K_STRUCT]);
726*0Sstevel@tonic-gate 	}
727*0Sstevel@tonic-gate 
728*0Sstevel@tonic-gate 	(void) printf("\n");
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 	long_stat("total number of union members", stats.s_numem);
731*0Sstevel@tonic-gate 	long_stat("maximum number of union members", stats.s_ummax);
732*0Sstevel@tonic-gate 	long_stat("total size of all unions", stats.s_nubytes);
733*0Sstevel@tonic-gate 	long_stat("maximum size of a union", stats.s_ubmax);
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate 	if (stats.s_types[CTF_K_UNION] != 0) {
736*0Sstevel@tonic-gate 		fp_stat("average number of union members",
737*0Sstevel@tonic-gate 		    (float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]);
738*0Sstevel@tonic-gate 		fp_stat("average size of a union", (float)stats.s_nubytes /
739*0Sstevel@tonic-gate 		    (float)stats.s_types[CTF_K_UNION]);
740*0Sstevel@tonic-gate 	}
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate 	(void) printf("\n");
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	long_stat("total number of enum members", stats.s_nemem);
745*0Sstevel@tonic-gate 	long_stat("maximum number of enum members", stats.s_emmax);
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate 	if (stats.s_types[CTF_K_ENUM] != 0) {
748*0Sstevel@tonic-gate 		fp_stat("average number of enum members",
749*0Sstevel@tonic-gate 		    (float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]);
750*0Sstevel@tonic-gate 	}
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 	(void) printf("\n");
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	long_stat("total number of unique strings", stats.s_nstr);
755*0Sstevel@tonic-gate 	long_stat("bytes of string data", stats.s_strlen);
756*0Sstevel@tonic-gate 	long_stat("maximum string length", stats.s_strmax);
757*0Sstevel@tonic-gate 
758*0Sstevel@tonic-gate 	if (stats.s_nstr != 0) {
759*0Sstevel@tonic-gate 		fp_stat("average string length",
760*0Sstevel@tonic-gate 		    (float)stats.s_strlen / (float)stats.s_nstr);
761*0Sstevel@tonic-gate 	}
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate 	(void) printf("\n");
764*0Sstevel@tonic-gate 	return (E_SUCCESS);
765*0Sstevel@tonic-gate }
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate static int
print_usage(FILE * fp,int verbose)768*0Sstevel@tonic-gate print_usage(FILE *fp, int verbose)
769*0Sstevel@tonic-gate {
770*0Sstevel@tonic-gate 	(void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getpname());
771*0Sstevel@tonic-gate 
772*0Sstevel@tonic-gate 	if (verbose) {
773*0Sstevel@tonic-gate 		(void) fprintf(fp,
774*0Sstevel@tonic-gate 		    "\t-d  dump data object section\n"
775*0Sstevel@tonic-gate 		    "\t-f  dump function section\n"
776*0Sstevel@tonic-gate 		    "\t-h  dump file header\n"
777*0Sstevel@tonic-gate 		    "\t-l  dump label table\n"
778*0Sstevel@tonic-gate 		    "\t-s  dump string table\n"
779*0Sstevel@tonic-gate 		    "\t-S  dump statistics\n"
780*0Sstevel@tonic-gate 		    "\t-t  dump type section\n"
781*0Sstevel@tonic-gate 		    "\t-u  save uncompressed CTF to a file\n");
782*0Sstevel@tonic-gate 	}
783*0Sstevel@tonic-gate 
784*0Sstevel@tonic-gate 	return (E_USAGE);
785*0Sstevel@tonic-gate }
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate static Elf_Scn *
findelfscn(Elf * elf,GElf_Ehdr * ehdr,char * secname)788*0Sstevel@tonic-gate findelfscn(Elf *elf, GElf_Ehdr *ehdr, char *secname)
789*0Sstevel@tonic-gate {
790*0Sstevel@tonic-gate 	GElf_Shdr shdr;
791*0Sstevel@tonic-gate 	Elf_Scn *scn;
792*0Sstevel@tonic-gate 	char *name;
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 	for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) {
795*0Sstevel@tonic-gate 		if (gelf_getshdr(scn, &shdr) != NULL && (name =
796*0Sstevel@tonic-gate 		    elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL &&
797*0Sstevel@tonic-gate 		    strcmp(name, secname) == 0)
798*0Sstevel@tonic-gate 			return (scn);
799*0Sstevel@tonic-gate 	}
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 	return (NULL);
802*0Sstevel@tonic-gate }
803*0Sstevel@tonic-gate 
804*0Sstevel@tonic-gate int
main(int argc,char * argv[])805*0Sstevel@tonic-gate main(int argc, char *argv[])
806*0Sstevel@tonic-gate {
807*0Sstevel@tonic-gate 	const char *filename = NULL;
808*0Sstevel@tonic-gate 	const char *ufile = NULL;
809*0Sstevel@tonic-gate 	int error = 0;
810*0Sstevel@tonic-gate 	int c, fd, ufd;
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	ctf_data_t cd;
813*0Sstevel@tonic-gate 	const ctf_preamble_t *pp;
814*0Sstevel@tonic-gate 	ctf_header_t *hp;
815*0Sstevel@tonic-gate 	Elf *elf;
816*0Sstevel@tonic-gate 	GElf_Ehdr ehdr;
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 	(void) elf_version(EV_CURRENT);
819*0Sstevel@tonic-gate 
820*0Sstevel@tonic-gate 	for (opterr = 0; optind < argc; optind++) {
821*0Sstevel@tonic-gate 		while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) {
822*0Sstevel@tonic-gate 			switch (c) {
823*0Sstevel@tonic-gate 			case 'd':
824*0Sstevel@tonic-gate 				flags |= F_DATA;
825*0Sstevel@tonic-gate 				break;
826*0Sstevel@tonic-gate 			case 'f':
827*0Sstevel@tonic-gate 				flags |= F_FUNC;
828*0Sstevel@tonic-gate 				break;
829*0Sstevel@tonic-gate 			case 'h':
830*0Sstevel@tonic-gate 				flags |= F_HDR;
831*0Sstevel@tonic-gate 				break;
832*0Sstevel@tonic-gate 			case 'l':
833*0Sstevel@tonic-gate 				flags |= F_LABEL;
834*0Sstevel@tonic-gate 				break;
835*0Sstevel@tonic-gate 			case 's':
836*0Sstevel@tonic-gate 				flags |= F_STR;
837*0Sstevel@tonic-gate 				break;
838*0Sstevel@tonic-gate 			case 'S':
839*0Sstevel@tonic-gate 				flags |= F_STATS;
840*0Sstevel@tonic-gate 				break;
841*0Sstevel@tonic-gate 			case 't':
842*0Sstevel@tonic-gate 				flags |= F_TYPES;
843*0Sstevel@tonic-gate 				break;
844*0Sstevel@tonic-gate 			case 'u':
845*0Sstevel@tonic-gate 				ufile = optarg;
846*0Sstevel@tonic-gate 				break;
847*0Sstevel@tonic-gate 			default:
848*0Sstevel@tonic-gate 				if (optopt == '?')
849*0Sstevel@tonic-gate 					return (print_usage(stdout, 1));
850*0Sstevel@tonic-gate 				warn("illegal option -- %c\n", optopt);
851*0Sstevel@tonic-gate 				return (print_usage(stderr, 0));
852*0Sstevel@tonic-gate 			}
853*0Sstevel@tonic-gate 		}
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 		if (optind < argc) {
856*0Sstevel@tonic-gate 			if (filename != NULL)
857*0Sstevel@tonic-gate 				return (print_usage(stderr, 0));
858*0Sstevel@tonic-gate 			filename = argv[optind];
859*0Sstevel@tonic-gate 		}
860*0Sstevel@tonic-gate 	}
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 	if (filename == NULL)
863*0Sstevel@tonic-gate 		return (print_usage(stderr, 0));
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 	if (flags == 0 && ufile == NULL)
866*0Sstevel@tonic-gate 		flags = F_ALLMSK;
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY)) == -1)
869*0Sstevel@tonic-gate 		die("failed to open %s", filename);
870*0Sstevel@tonic-gate 
871*0Sstevel@tonic-gate 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL &&
872*0Sstevel@tonic-gate 	    gelf_getehdr(elf, &ehdr) != NULL) {
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 		Elf_Data *dp;
875*0Sstevel@tonic-gate 		Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf");
876*0Sstevel@tonic-gate 		Elf_Scn *symscn;
877*0Sstevel@tonic-gate 		GElf_Shdr ctfshdr;
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 		if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL)
880*0Sstevel@tonic-gate 			die("%s does not contain .SUNW_ctf data\n", filename);
881*0Sstevel@tonic-gate 
882*0Sstevel@tonic-gate 		cd.cd_ctfdata = dp->d_buf;
883*0Sstevel@tonic-gate 		cd.cd_ctflen = dp->d_size;
884*0Sstevel@tonic-gate 
885*0Sstevel@tonic-gate 		/*
886*0Sstevel@tonic-gate 		 * If the sh_link field of the CTF section header is non-zero
887*0Sstevel@tonic-gate 		 * it indicates which section contains the symbol table that
888*0Sstevel@tonic-gate 		 * should be used. We default to the .symtab section if sh_link
889*0Sstevel@tonic-gate 		 * is zero or if there's an error reading the section header.
890*0Sstevel@tonic-gate 		 */
891*0Sstevel@tonic-gate 		if (gelf_getshdr(ctfscn, &ctfshdr) != NULL &&
892*0Sstevel@tonic-gate 		    ctfshdr.sh_link != 0) {
893*0Sstevel@tonic-gate 			symscn = elf_getscn(elf, ctfshdr.sh_link);
894*0Sstevel@tonic-gate 		} else {
895*0Sstevel@tonic-gate 			symscn = findelfscn(elf, &ehdr, ".symtab");
896*0Sstevel@tonic-gate 		}
897*0Sstevel@tonic-gate 
898*0Sstevel@tonic-gate 		/* If we found a symbol table, find the corresponding strings */
899*0Sstevel@tonic-gate 		if (symscn != NULL) {
900*0Sstevel@tonic-gate 			GElf_Shdr shdr;
901*0Sstevel@tonic-gate 			Elf_Scn *symstrscn;
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 			if (gelf_getshdr(symscn, &shdr) != NULL) {
904*0Sstevel@tonic-gate 				symstrscn = elf_getscn(elf, shdr.sh_link);
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 				cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
907*0Sstevel@tonic-gate 				cd.cd_symdata = elf_getdata(symscn, NULL);
908*0Sstevel@tonic-gate 				cd.cd_strdata = elf_getdata(symstrscn, NULL);
909*0Sstevel@tonic-gate 			}
910*0Sstevel@tonic-gate 		}
911*0Sstevel@tonic-gate 	} else {
912*0Sstevel@tonic-gate 		struct stat st;
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate 		if (fstat(fd, &st) == -1)
915*0Sstevel@tonic-gate 			die("failed to fstat %s", filename);
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 		cd.cd_ctflen = st.st_size;
918*0Sstevel@tonic-gate 		cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ,
919*0Sstevel@tonic-gate 		    MAP_PRIVATE, fd, 0);
920*0Sstevel@tonic-gate 		if (cd.cd_ctfdata == MAP_FAILED)
921*0Sstevel@tonic-gate 			die("failed to mmap %s", filename);
922*0Sstevel@tonic-gate 	}
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	/*
925*0Sstevel@tonic-gate 	 * Get a pointer to the CTF data buffer and interpret the first portion
926*0Sstevel@tonic-gate 	 * as a ctf_header_t.  Validate the magic number and size.
927*0Sstevel@tonic-gate 	 */
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 	if (cd.cd_ctflen < sizeof (ctf_preamble_t))
930*0Sstevel@tonic-gate 		die("%s does not contain a CTF preamble\n", filename);
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	/* LINTED - pointer alignment */
933*0Sstevel@tonic-gate 	pp = (const ctf_preamble_t *)cd.cd_ctfdata;
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 	if (pp->ctp_magic != CTF_MAGIC)
936*0Sstevel@tonic-gate 		die("%s does not appear to contain CTF data\n", filename);
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate 	if (pp->ctp_version == CTF_VERSION) {
939*0Sstevel@tonic-gate 		/* LINTED - pointer alignment */
940*0Sstevel@tonic-gate 		hp = (ctf_header_t *)cd.cd_ctfdata;
941*0Sstevel@tonic-gate 		cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t);
942*0Sstevel@tonic-gate 
943*0Sstevel@tonic-gate 		if (cd.cd_ctflen < sizeof (ctf_header_t)) {
944*0Sstevel@tonic-gate 			die("%s does not contain a v%d CTF header\n", filename,
945*0Sstevel@tonic-gate 			    CTF_VERSION);
946*0Sstevel@tonic-gate 		}
947*0Sstevel@tonic-gate 
948*0Sstevel@tonic-gate 	} else {
949*0Sstevel@tonic-gate 		die("%s contains unsupported CTF version %d\n", filename,
950*0Sstevel@tonic-gate 		    pp->ctp_version);
951*0Sstevel@tonic-gate 	}
952*0Sstevel@tonic-gate 
953*0Sstevel@tonic-gate 	/*
954*0Sstevel@tonic-gate 	 * If the data buffer is compressed, then malloc a buffer large enough
955*0Sstevel@tonic-gate 	 * to hold the decompressed data, and use zlib to decompress it.
956*0Sstevel@tonic-gate 	 */
957*0Sstevel@tonic-gate 	if (hp->cth_flags & CTF_F_COMPRESS) {
958*0Sstevel@tonic-gate 		z_stream zstr;
959*0Sstevel@tonic-gate 		void *buf;
960*0Sstevel@tonic-gate 		int rc;
961*0Sstevel@tonic-gate 
962*0Sstevel@tonic-gate 		if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL)
963*0Sstevel@tonic-gate 			die("failed to allocate decompression buffer");
964*0Sstevel@tonic-gate 
965*0Sstevel@tonic-gate 		bzero(&zstr, sizeof (z_stream));
966*0Sstevel@tonic-gate 		zstr.next_in = (void *)cd.cd_ctfdata;
967*0Sstevel@tonic-gate 		zstr.avail_in = cd.cd_ctflen;
968*0Sstevel@tonic-gate 		zstr.next_out = buf;
969*0Sstevel@tonic-gate 		zstr.avail_out = hp->cth_stroff + hp->cth_strlen;
970*0Sstevel@tonic-gate 
971*0Sstevel@tonic-gate 		if ((rc = inflateInit(&zstr)) != Z_OK)
972*0Sstevel@tonic-gate 			die("failed to initialize zlib: %s\n", zError(rc));
973*0Sstevel@tonic-gate 
974*0Sstevel@tonic-gate 		if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END)
975*0Sstevel@tonic-gate 			die("failed to decompress CTF data: %s\n", zError(rc));
976*0Sstevel@tonic-gate 
977*0Sstevel@tonic-gate 		if ((rc = inflateEnd(&zstr)) != Z_OK)
978*0Sstevel@tonic-gate 			die("failed to finish decompression: %s\n", zError(rc));
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 		if (zstr.total_out != hp->cth_stroff + hp->cth_strlen)
981*0Sstevel@tonic-gate 			die("CTF data is corrupt -- short decompression\n");
982*0Sstevel@tonic-gate 
983*0Sstevel@tonic-gate 		cd.cd_ctfdata = buf;
984*0Sstevel@tonic-gate 		cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen;
985*0Sstevel@tonic-gate 	}
986*0Sstevel@tonic-gate 
987*0Sstevel@tonic-gate 	if (flags & F_HDR)
988*0Sstevel@tonic-gate 		error |= print_header(hp, &cd);
989*0Sstevel@tonic-gate 	if (flags & (F_LABEL))
990*0Sstevel@tonic-gate 		error |= print_labeltable(hp, &cd);
991*0Sstevel@tonic-gate 	if (flags & (F_DATA | F_STATS))
992*0Sstevel@tonic-gate 		error |= read_data(hp, &cd);
993*0Sstevel@tonic-gate 	if (flags & (F_FUNC | F_STATS))
994*0Sstevel@tonic-gate 		error |= read_funcs(hp, &cd);
995*0Sstevel@tonic-gate 	if (flags & (F_TYPES | F_STATS))
996*0Sstevel@tonic-gate 		error |= read_types(hp, &cd);
997*0Sstevel@tonic-gate 	if (flags & (F_STR | F_STATS))
998*0Sstevel@tonic-gate 		error |= read_strtab(hp, &cd);
999*0Sstevel@tonic-gate 	if (flags & F_STATS)
1000*0Sstevel@tonic-gate 		error |= print_stats();
1001*0Sstevel@tonic-gate 
1002*0Sstevel@tonic-gate 	/*
1003*0Sstevel@tonic-gate 	 * If the -u option is specified, write the uncompressed CTF data to a
1004*0Sstevel@tonic-gate 	 * raw CTF file.  CTF data can already be extracted compressed by
1005*0Sstevel@tonic-gate 	 * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.
1006*0Sstevel@tonic-gate 	 */
1007*0Sstevel@tonic-gate 	if (ufile != NULL) {
1008*0Sstevel@tonic-gate 		ctf_header_t h;
1009*0Sstevel@tonic-gate 
1010*0Sstevel@tonic-gate 		bcopy(hp, &h, sizeof (h));
1011*0Sstevel@tonic-gate 		h.cth_flags &= ~CTF_F_COMPRESS;
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate 		if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 ||
1014*0Sstevel@tonic-gate 		    write(ufd, &h, sizeof (h)) != sizeof (h) ||
1015*0Sstevel@tonic-gate 		    write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != cd.cd_ctflen) {
1016*0Sstevel@tonic-gate 			warn("failed to write CTF data to '%s'", ufile);
1017*0Sstevel@tonic-gate 			error |= E_ERROR;
1018*0Sstevel@tonic-gate 		}
1019*0Sstevel@tonic-gate 
1020*0Sstevel@tonic-gate 		(void) close(ufd);
1021*0Sstevel@tonic-gate 	}
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	if (elf != NULL)
1024*0Sstevel@tonic-gate 		(void) elf_end(elf);
1025*0Sstevel@tonic-gate 
1026*0Sstevel@tonic-gate 	(void) close(fd);
1027*0Sstevel@tonic-gate 	return (error);
1028*0Sstevel@tonic-gate }
1029