11673e404SJohn Birrell /*
21673e404SJohn Birrell  * CDDL HEADER START
31673e404SJohn Birrell  *
41673e404SJohn Birrell  * The contents of this file are subject to the terms of the
51673e404SJohn Birrell  * Common Development and Distribution License, Version 1.0 only
61673e404SJohn Birrell  * (the "License").  You may not use this file except in compliance
71673e404SJohn Birrell  * with the License.
81673e404SJohn Birrell  *
91673e404SJohn Birrell  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
101673e404SJohn Birrell  * or http://www.opensolaris.org/os/licensing.
111673e404SJohn Birrell  * See the License for the specific language governing permissions
121673e404SJohn Birrell  * and limitations under the License.
131673e404SJohn Birrell  *
141673e404SJohn Birrell  * When distributing Covered Code, include this CDDL HEADER in each
151673e404SJohn Birrell  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
161673e404SJohn Birrell  * If applicable, add the following below this CDDL HEADER, with the
171673e404SJohn Birrell  * fields enclosed by brackets "[]" replaced with your own identifying
181673e404SJohn Birrell  * information: Portions Copyright [yyyy] [name of copyright owner]
191673e404SJohn Birrell  *
201673e404SJohn Birrell  * CDDL HEADER END
211673e404SJohn Birrell  */
221673e404SJohn Birrell /*
231673e404SJohn Birrell  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
241673e404SJohn Birrell  * Use is subject to license terms.
251673e404SJohn Birrell  */
261673e404SJohn Birrell 
271673e404SJohn Birrell #include <sys/types.h>
281673e404SJohn Birrell #include <sys/sysmacros.h>
291673e404SJohn Birrell #include <sys/stat.h>
301673e404SJohn Birrell #include <sys/mman.h>
311673e404SJohn Birrell 
3245dd2eaaSMark Johnston #include <err.h>
331673e404SJohn Birrell #include <strings.h>
341673e404SJohn Birrell #include <unistd.h>
351673e404SJohn Birrell #include <stdlib.h>
361673e404SJohn Birrell #include <stdio.h>
371673e404SJohn Birrell #include <fcntl.h>
381673e404SJohn Birrell #include <gelf.h>
391673e404SJohn Birrell #include <zlib.h>
401673e404SJohn Birrell 
411673e404SJohn Birrell #include "ctf_headers.h"
421673e404SJohn Birrell #include "utils.h"
431673e404SJohn Birrell #include "symbol.h"
441673e404SJohn Birrell 
451673e404SJohn Birrell #define	WARN(x)	{ warn(x); return (E_ERROR); }
461673e404SJohn Birrell 
471673e404SJohn Birrell /*
481673e404SJohn Birrell  * Flags that indicate what data is to be displayed.  An explicit `all' value is
491673e404SJohn Birrell  * provided to allow the code to distinguish between a request for everything
501673e404SJohn Birrell  * (currently requested by invoking ctfdump without flags) and individual
511673e404SJohn Birrell  * requests for all of the types of data (an invocation with all flags).  In the
521673e404SJohn Birrell  * former case, we want to be able to implicitly adjust the definition of `all'
531673e404SJohn Birrell  * based on the CTF version of the file being dumped.  For example, if a v2 file
541673e404SJohn Birrell  * is being dumped, `all' includes F_LABEL - a request to dump the label
551673e404SJohn Birrell  * section.  If a v1 file is being dumped, `all' does not include F_LABEL,
561673e404SJohn Birrell  * because v1 CTF doesn't support labels.  We need to be able to distinguish
571673e404SJohn Birrell  * between `ctfdump foo', which has an implicit request for labels if `foo'
581673e404SJohn Birrell  * supports them, and `ctfdump -l foo', which has an explicity request.  In the
591673e404SJohn Birrell  * latter case, we exit with an error if `foo' is a v1 CTF file.
601673e404SJohn Birrell  */
611673e404SJohn Birrell static enum {
621673e404SJohn Birrell 	F_DATA	= 0x01,		/* show data object section */
631673e404SJohn Birrell 	F_FUNC	= 0x02,		/* show function section */
641673e404SJohn Birrell 	F_HDR	= 0x04,		/* show header */
651673e404SJohn Birrell 	F_STR	= 0x08,		/* show string table */
661673e404SJohn Birrell 	F_TYPES	= 0x10,		/* show type section */
671673e404SJohn Birrell 	F_STATS = 0x20, 	/* show statistics */
681673e404SJohn Birrell 	F_LABEL	= 0x40,		/* show label section */
691673e404SJohn Birrell 	F_ALL	= 0x80,		/* explicit request for `all' */
701673e404SJohn Birrell 	F_ALLMSK = 0xff		/* show all sections and statistics */
711673e404SJohn Birrell } flags = 0;
721673e404SJohn Birrell 
731673e404SJohn Birrell static struct {
741673e404SJohn Birrell 	ulong_t s_ndata;	/* total number of data objects */
751673e404SJohn Birrell 	ulong_t s_nfunc;	/* total number of functions */
761673e404SJohn Birrell 	ulong_t s_nargs;	/* total number of function arguments */
771673e404SJohn Birrell 	ulong_t s_argmax;	/* longest argument list */
781673e404SJohn Birrell 	ulong_t s_ntypes;	/* total number of types */
791673e404SJohn Birrell 	ulong_t s_types[16];	/* number of types by kind */
801673e404SJohn Birrell 	ulong_t s_nsmem;	/* total number of struct members */
811673e404SJohn Birrell 	ulong_t s_nsbytes;	/* total size of all structs */
821673e404SJohn Birrell 	ulong_t s_smmax;	/* largest struct in terms of members */
831673e404SJohn Birrell 	ulong_t s_sbmax;	/* largest struct in terms of bytes */
841673e404SJohn Birrell 	ulong_t s_numem;	/* total number of union members */
851673e404SJohn Birrell 	ulong_t s_nubytes;	/* total size of all unions */
861673e404SJohn Birrell 	ulong_t s_ummax;	/* largest union in terms of members */
871673e404SJohn Birrell 	ulong_t s_ubmax;	/* largest union in terms of bytes */
881673e404SJohn Birrell 	ulong_t s_nemem;	/* total number of enum members */
891673e404SJohn Birrell 	ulong_t s_emmax;	/* largest enum in terms of members */
901673e404SJohn Birrell 	ulong_t s_nstr;		/* total number of strings */
911673e404SJohn Birrell 	size_t s_strlen;	/* total length of all strings */
921673e404SJohn Birrell 	size_t s_strmax;	/* longest string length */
931673e404SJohn Birrell } stats;
941673e404SJohn Birrell 
951673e404SJohn Birrell typedef struct ctf_data {
961673e404SJohn Birrell 	caddr_t cd_ctfdata;	/* Pointer to the CTF data */
971673e404SJohn Birrell 	size_t cd_ctflen;	/* Length of CTF data */
981673e404SJohn Birrell 
99bdf290cdSMark Johnston 	size_t cd_idwidth;	/* Size of a type ID, in bytes */
100bdf290cdSMark Johnston 
1011673e404SJohn Birrell 	/*
1021673e404SJohn Birrell 	 * cd_symdata will be non-NULL if the CTF data is being retrieved from
1031673e404SJohn Birrell 	 * an ELF file with a symbol table.  cd_strdata and cd_nsyms should be
1041673e404SJohn Birrell 	 * used only if cd_symdata is non-NULL.
1051673e404SJohn Birrell 	 */
1061673e404SJohn Birrell 	Elf_Data *cd_symdata;	/* Symbol table */
1071673e404SJohn Birrell 	Elf_Data *cd_strdata;	/* Symbol table strings */
1081673e404SJohn Birrell 	int cd_nsyms;		/* Number of symbol table entries */
1091673e404SJohn Birrell } ctf_data_t;
1101673e404SJohn Birrell 
1111673e404SJohn Birrell static const char *
ref_to_str(uint_t name,const ctf_header_t * hp,const ctf_data_t * cd)1121673e404SJohn Birrell ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd)
1131673e404SJohn Birrell {
1141673e404SJohn Birrell 	size_t offset = CTF_NAME_OFFSET(name);
1151673e404SJohn Birrell 	const char *s = cd->cd_ctfdata + hp->cth_stroff + offset;
1161673e404SJohn Birrell 
1171673e404SJohn Birrell 	if (CTF_NAME_STID(name) != CTF_STRTAB_0)
1181673e404SJohn Birrell 		return ("<< ??? - name in external strtab >>");
1191673e404SJohn Birrell 
1201673e404SJohn Birrell 	if (offset >= hp->cth_strlen)
1211673e404SJohn Birrell 		return ("<< ??? - name exceeds strlab len >>");
1221673e404SJohn Birrell 
1231673e404SJohn Birrell 	if (hp->cth_stroff + offset >= cd->cd_ctflen)
1241673e404SJohn Birrell 		return ("<< ??? - file truncated >>");
1251673e404SJohn Birrell 
1261673e404SJohn Birrell 	if (s[0] == '\0')
1271673e404SJohn Birrell 		return ("(anon)");
1281673e404SJohn Birrell 
1291673e404SJohn Birrell 	return (s);
1301673e404SJohn Birrell }
1311673e404SJohn Birrell 
1321673e404SJohn Birrell static const char *
int_encoding_to_str(uint_t encoding)1331673e404SJohn Birrell int_encoding_to_str(uint_t encoding)
1341673e404SJohn Birrell {
1351673e404SJohn Birrell 	static char buf[32];
1361673e404SJohn Birrell 
1371673e404SJohn Birrell 	if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR |
1381673e404SJohn Birrell 	    CTF_INT_BOOL | CTF_INT_VARARGS)) != 0)
1391673e404SJohn Birrell 		(void) snprintf(buf, sizeof (buf), " 0x%x", encoding);
1401673e404SJohn Birrell 	else {
1411673e404SJohn Birrell 		buf[0] = '\0';
1421673e404SJohn Birrell 		if (encoding & CTF_INT_SIGNED)
1431673e404SJohn Birrell 			(void) strcat(buf, " SIGNED");
1441673e404SJohn Birrell 		if (encoding & CTF_INT_CHAR)
1451673e404SJohn Birrell 			(void) strcat(buf, " CHAR");
1461673e404SJohn Birrell 		if (encoding & CTF_INT_BOOL)
1471673e404SJohn Birrell 			(void) strcat(buf, " BOOL");
1481673e404SJohn Birrell 		if (encoding & CTF_INT_VARARGS)
1491673e404SJohn Birrell 			(void) strcat(buf, " VARARGS");
1501673e404SJohn Birrell 	}
1511673e404SJohn Birrell 
1521673e404SJohn Birrell 	return (buf + 1);
1531673e404SJohn Birrell }
1541673e404SJohn Birrell 
1551673e404SJohn Birrell static const char *
fp_encoding_to_str(uint_t encoding)1561673e404SJohn Birrell fp_encoding_to_str(uint_t encoding)
1571673e404SJohn Birrell {
1581673e404SJohn Birrell 	static const char *const encs[] = {
1591673e404SJohn Birrell 		NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX",
1601673e404SJohn Birrell 		"LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",
1611673e404SJohn Birrell 		"DIMAGINARY", "LDIMAGINARY"
1621673e404SJohn Birrell 	};
1631673e404SJohn Birrell 
1641673e404SJohn Birrell 	static char buf[16];
1651673e404SJohn Birrell 
1661673e404SJohn Birrell 	if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) {
1671673e404SJohn Birrell 		(void) snprintf(buf, sizeof (buf), "%u", encoding);
1681673e404SJohn Birrell 		return (buf);
1691673e404SJohn Birrell 	}
1701673e404SJohn Birrell 
1711673e404SJohn Birrell 	return (encs[encoding]);
1721673e404SJohn Birrell }
1731673e404SJohn Birrell 
1741673e404SJohn Birrell static void
print_line(const char * s)1751673e404SJohn Birrell print_line(const char *s)
1761673e404SJohn Birrell {
1771673e404SJohn Birrell 	static const char line[] = "----------------------------------------"
1781673e404SJohn Birrell 	    "----------------------------------------";
1791673e404SJohn Birrell 	(void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line);
1801673e404SJohn Birrell }
1811673e404SJohn Birrell 
1821673e404SJohn Birrell static int
print_header(const ctf_header_t * hp,const ctf_data_t * cd)1831673e404SJohn Birrell print_header(const ctf_header_t *hp, const ctf_data_t *cd)
1841673e404SJohn Birrell {
1851673e404SJohn Birrell 	print_line("- CTF Header ");
1861673e404SJohn Birrell 
1871673e404SJohn Birrell 	(void) printf("  cth_magic    = 0x%04x\n", hp->cth_magic);
1881673e404SJohn Birrell 	(void) printf("  cth_version  = %u\n", hp->cth_version);
1891673e404SJohn Birrell 	(void) printf("  cth_flags    = 0x%02x\n", hp->cth_flags);
1901673e404SJohn Birrell 	(void) printf("  cth_parlabel = %s\n",
1911673e404SJohn Birrell 	    ref_to_str(hp->cth_parlabel, hp, cd));
1921673e404SJohn Birrell 	(void) printf("  cth_parname  = %s\n",
1931673e404SJohn Birrell 	    ref_to_str(hp->cth_parname, hp, cd));
1941673e404SJohn Birrell 	(void) printf("  cth_lbloff   = %u\n", hp->cth_lbloff);
1951673e404SJohn Birrell 	(void) printf("  cth_objtoff  = %u\n", hp->cth_objtoff);
1961673e404SJohn Birrell 	(void) printf("  cth_funcoff  = %u\n", hp->cth_funcoff);
1971673e404SJohn Birrell 	(void) printf("  cth_typeoff  = %u\n", hp->cth_typeoff);
1981673e404SJohn Birrell 	(void) printf("  cth_stroff   = %u\n", hp->cth_stroff);
1991673e404SJohn Birrell 	(void) printf("  cth_strlen   = %u\n", hp->cth_strlen);
2001673e404SJohn Birrell 
2011673e404SJohn Birrell 	return (E_SUCCESS);
2021673e404SJohn Birrell }
2031673e404SJohn Birrell 
2041673e404SJohn Birrell static int
print_labeltable(const ctf_header_t * hp,const ctf_data_t * cd)2051673e404SJohn Birrell print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd)
2061673e404SJohn Birrell {
2079098da06SJohn Birrell 	void *v = (void *) (cd->cd_ctfdata + hp->cth_lbloff);
2089098da06SJohn Birrell 	const ctf_lblent_t *ctl = v;
2091673e404SJohn Birrell 	ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl);
2101673e404SJohn Birrell 
2111673e404SJohn Birrell 	print_line("- Label Table ");
2121673e404SJohn Birrell 
2131673e404SJohn Birrell 	if (hp->cth_lbloff & 3)
2141673e404SJohn Birrell 		WARN("cth_lbloff is not aligned properly\n");
2151673e404SJohn Birrell 	if (hp->cth_lbloff >= cd->cd_ctflen)
2161673e404SJohn Birrell 		WARN("file is truncated or cth_lbloff is corrupt\n");
2171673e404SJohn Birrell 	if (hp->cth_objtoff >= cd->cd_ctflen)
2181673e404SJohn Birrell 		WARN("file is truncated or cth_objtoff is corrupt\n");
2191673e404SJohn Birrell 	if (hp->cth_lbloff > hp->cth_objtoff)
2201673e404SJohn Birrell 		WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");
2211673e404SJohn Birrell 
2221673e404SJohn Birrell 	for (i = 0; i < n; i++, ctl++) {
2231673e404SJohn Birrell 		(void) printf("  %5u %s\n", ctl->ctl_typeidx,
2241673e404SJohn Birrell 		    ref_to_str(ctl->ctl_label, hp, cd));
2251673e404SJohn Birrell 	}
2261673e404SJohn Birrell 
2271673e404SJohn Birrell 	return (E_SUCCESS);
2281673e404SJohn Birrell }
2291673e404SJohn Birrell 
2301673e404SJohn Birrell /*
2311673e404SJohn Birrell  * Given the current symbol index (-1 to start at the beginning of the symbol
2321673e404SJohn Birrell  * table) and the type of symbol to match, this function returns the index of
2331673e404SJohn Birrell  * the next matching symbol (if any), and places the name of that symbol in
2341673e404SJohn Birrell  * *namep.  If no symbol is found, -1 is returned.
2351673e404SJohn Birrell  */
2361673e404SJohn Birrell static int
next_sym(const ctf_data_t * cd,const int symidx,const uchar_t matchtype,char ** namep)2371673e404SJohn Birrell next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,
2381673e404SJohn Birrell     char **namep)
2391673e404SJohn Birrell {
2401673e404SJohn Birrell 	int i;
2411673e404SJohn Birrell 
2421673e404SJohn Birrell 	for (i = symidx + 1; i < cd->cd_nsyms; i++) {
2431673e404SJohn Birrell 		GElf_Sym sym;
2441673e404SJohn Birrell 		char *name;
2451673e404SJohn Birrell 		int type;
2461673e404SJohn Birrell 
2471673e404SJohn Birrell 		if (gelf_getsym(cd->cd_symdata, i, &sym) == 0)
2481673e404SJohn Birrell 			return (-1);
2491673e404SJohn Birrell 
2501673e404SJohn Birrell 		name = (char *)cd->cd_strdata->d_buf + sym.st_name;
2511673e404SJohn Birrell 		type = GELF_ST_TYPE(sym.st_info);
2521673e404SJohn Birrell 
2531673e404SJohn Birrell 		/*
2541673e404SJohn Birrell 		 * Skip various types of symbol table entries.
2551673e404SJohn Birrell 		 */
2561673e404SJohn Birrell 		if (type != matchtype || ignore_symbol(&sym, name))
2571673e404SJohn Birrell 			continue;
2581673e404SJohn Birrell 
2591673e404SJohn Birrell 		/* Found one */
2601673e404SJohn Birrell 		*namep = name;
2611673e404SJohn Birrell 		return (i);
2621673e404SJohn Birrell 	}
2631673e404SJohn Birrell 
2641673e404SJohn Birrell 	return (-1);
2651673e404SJohn Birrell }
2661673e404SJohn Birrell 
2671673e404SJohn Birrell static int
read_data(const ctf_header_t * hp,const ctf_data_t * cd)2681673e404SJohn Birrell read_data(const ctf_header_t *hp, const ctf_data_t *cd)
2691673e404SJohn Birrell {
270bdf290cdSMark Johnston 	const char *v = (void *) (cd->cd_ctfdata + hp->cth_objtoff);
271bdf290cdSMark Johnston 	ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / cd->cd_idwidth;
2721673e404SJohn Birrell 
2731673e404SJohn Birrell 	if (flags != F_STATS)
2741673e404SJohn Birrell 		print_line("- Data Objects ");
2751673e404SJohn Birrell 
2761673e404SJohn Birrell 	if (hp->cth_objtoff & 1)
2771673e404SJohn Birrell 		WARN("cth_objtoff is not aligned properly\n");
2781673e404SJohn Birrell 	if (hp->cth_objtoff >= cd->cd_ctflen)
2791673e404SJohn Birrell 		WARN("file is truncated or cth_objtoff is corrupt\n");
2801673e404SJohn Birrell 	if (hp->cth_funcoff >= cd->cd_ctflen)
2811673e404SJohn Birrell 		WARN("file is truncated or cth_funcoff is corrupt\n");
2821673e404SJohn Birrell 	if (hp->cth_objtoff > hp->cth_funcoff)
2831673e404SJohn Birrell 		WARN("file is corrupt -- cth_objtoff > cth_funcoff\n");
2841673e404SJohn Birrell 
2851673e404SJohn Birrell 	if (flags != F_STATS) {
2861673e404SJohn Birrell 		int symidx, len, i;
2871673e404SJohn Birrell 		char *name = NULL;
2881673e404SJohn Birrell 
2899098da06SJohn Birrell 		for (symidx = -1, i = 0; i < (int) n; i++) {
290bdf290cdSMark Johnston 			uint32_t id = 0;
2911673e404SJohn Birrell 			int nextsym;
2921673e404SJohn Birrell 
2931673e404SJohn Birrell 			if (cd->cd_symdata == NULL || (nextsym = next_sym(cd,
2941673e404SJohn Birrell 			    symidx, STT_OBJECT, &name)) < 0)
2951673e404SJohn Birrell 				name = NULL;
2961673e404SJohn Birrell 			else
2971673e404SJohn Birrell 				symidx = nextsym;
2981673e404SJohn Birrell 
299bdf290cdSMark Johnston 			memcpy(&id, v, cd->cd_idwidth);
300bdf290cdSMark Johnston 			v += cd->cd_idwidth;
301bdf290cdSMark Johnston 			len = printf("  [%u] %u", i, id);
3021673e404SJohn Birrell 			if (name != NULL)
3031673e404SJohn Birrell 				(void) printf("%*s%s (%u)", (15 - len), "",
3041673e404SJohn Birrell 				    name, symidx);
3051673e404SJohn Birrell 			(void) putchar('\n');
3061673e404SJohn Birrell 		}
3071673e404SJohn Birrell 	}
3081673e404SJohn Birrell 
3091673e404SJohn Birrell 	stats.s_ndata = n;
3101673e404SJohn Birrell 	return (E_SUCCESS);
3111673e404SJohn Birrell }
3121673e404SJohn Birrell 
3131673e404SJohn Birrell static int
read_funcs(const ctf_header_t * hp,const ctf_data_t * cd)3141673e404SJohn Birrell read_funcs(const ctf_header_t *hp, const ctf_data_t *cd)
3151673e404SJohn Birrell {
316bdf290cdSMark Johnston 	const char *v = (void *) (cd->cd_ctfdata + hp->cth_funcoff);
317bdf290cdSMark Johnston 	uint_t f = 0, info;
3181673e404SJohn Birrell 
319bdf290cdSMark Johnston 	const char *end = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
3201673e404SJohn Birrell 
3211673e404SJohn Birrell 	ulong_t id;
3221673e404SJohn Birrell 	int symidx;
3231673e404SJohn Birrell 
3241673e404SJohn Birrell 	if (flags != F_STATS)
3251673e404SJohn Birrell 		print_line("- Functions ");
3261673e404SJohn Birrell 
3271673e404SJohn Birrell 	if (hp->cth_funcoff & 1)
3281673e404SJohn Birrell 		WARN("cth_funcoff is not aligned properly\n");
3291673e404SJohn Birrell 	if (hp->cth_funcoff >= cd->cd_ctflen)
3301673e404SJohn Birrell 		WARN("file is truncated or cth_funcoff is corrupt\n");
3311673e404SJohn Birrell 	if (hp->cth_typeoff >= cd->cd_ctflen)
3321673e404SJohn Birrell 		WARN("file is truncated or cth_typeoff is corrupt\n");
3331673e404SJohn Birrell 	if (hp->cth_funcoff > hp->cth_typeoff)
3341673e404SJohn Birrell 		WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");
3351673e404SJohn Birrell 
336bdf290cdSMark Johnston 	for (symidx = -1, id = 0; v < end; id++) {
337bdf290cdSMark Johnston 		info = 0;
338bdf290cdSMark Johnston 		memcpy(&info, v, cd->cd_idwidth);
339bdf290cdSMark Johnston 		v += cd->cd_idwidth;
340bdf290cdSMark Johnston 		ushort_t kind = hp->cth_version == CTF_VERSION_2 ?
341bdf290cdSMark Johnston 		    CTF_V2_INFO_KIND(info) : CTF_V3_INFO_KIND(info);
342bdf290cdSMark Johnston 		ushort_t n = hp->cth_version == CTF_VERSION_2 ?
343bdf290cdSMark Johnston 		    CTF_V2_INFO_VLEN(info) : CTF_V3_INFO_VLEN(info);
3441673e404SJohn Birrell 		ushort_t i;
3451673e404SJohn Birrell 		int nextsym;
3461673e404SJohn Birrell 		char *name;
3471673e404SJohn Birrell 
3481673e404SJohn Birrell 		if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx,
3491673e404SJohn Birrell 		    STT_FUNC, &name)) < 0)
3501673e404SJohn Birrell 			name = NULL;
3511673e404SJohn Birrell 		else
3521673e404SJohn Birrell 			symidx = nextsym;
3531673e404SJohn Birrell 
3541673e404SJohn Birrell 		if (kind == CTF_K_UNKNOWN && n == 0)
3551673e404SJohn Birrell 			continue; /* skip padding */
3561673e404SJohn Birrell 
3571673e404SJohn Birrell 		if (kind != CTF_K_FUNCTION) {
3581673e404SJohn Birrell 			(void) printf("  [%lu] unexpected kind -- %u\n",
3591673e404SJohn Birrell 			    id, kind);
3601673e404SJohn Birrell 			return (E_ERROR);
3611673e404SJohn Birrell 		}
3621673e404SJohn Birrell 
363bdf290cdSMark Johnston 		if (v + n * cd->cd_idwidth > end) {
3641673e404SJohn Birrell 			(void) printf("  [%lu] vlen %u extends past section "
3651673e404SJohn Birrell 			    "boundary\n", id, n);
3661673e404SJohn Birrell 			return (E_ERROR);
3671673e404SJohn Birrell 		}
3681673e404SJohn Birrell 
3691673e404SJohn Birrell 		if (flags != F_STATS) {
3701673e404SJohn Birrell 			(void) printf("  [%lu] FUNC ", id);
3711673e404SJohn Birrell 			if (name != NULL)
3721673e404SJohn Birrell 				(void) printf("(%s) ", name);
373bdf290cdSMark Johnston 			memcpy(&f, v, cd->cd_idwidth);
374bdf290cdSMark Johnston 			v += cd->cd_idwidth;
375bdf290cdSMark Johnston 			(void) printf("returns: %u args: (", f);
3761673e404SJohn Birrell 
3771673e404SJohn Birrell 			if (n != 0) {
378bdf290cdSMark Johnston 				memcpy(&f, v, cd->cd_idwidth);
379bdf290cdSMark Johnston 				v += cd->cd_idwidth;
380bdf290cdSMark Johnston 				(void) printf("%u", f);
381bdf290cdSMark Johnston 				for (i = 1; i < n; i++) {
382bdf290cdSMark Johnston 					memcpy(&f, v, cd->cd_idwidth);
383bdf290cdSMark Johnston 					v += cd->cd_idwidth;
384bdf290cdSMark Johnston 					(void) printf(", %u", f);
385bdf290cdSMark Johnston 				}
3861673e404SJohn Birrell 			}
3871673e404SJohn Birrell 
3881673e404SJohn Birrell 			(void) printf(")\n");
3891673e404SJohn Birrell 		} else
390bdf290cdSMark Johnston 			v += n * cd->cd_idwidth + 1; /* skip to next function definition */
3911673e404SJohn Birrell 
3921673e404SJohn Birrell 		stats.s_nfunc++;
3931673e404SJohn Birrell 		stats.s_nargs += n;
3941673e404SJohn Birrell 		stats.s_argmax = MAX(stats.s_argmax, n);
3951673e404SJohn Birrell 	}
3961673e404SJohn Birrell 
3971673e404SJohn Birrell 	return (E_SUCCESS);
3981673e404SJohn Birrell }
3991673e404SJohn Birrell 
4001673e404SJohn Birrell static int
read_types(const ctf_header_t * hp,const ctf_data_t * cd)4011673e404SJohn Birrell read_types(const ctf_header_t *hp, const ctf_data_t *cd)
4021673e404SJohn Birrell {
403bdf290cdSMark Johnston 	const char *v = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
404bdf290cdSMark Johnston 	const char *end = (void *) (cd->cd_ctfdata + hp->cth_stroff);
4051673e404SJohn Birrell 	ulong_t id;
406bdf290cdSMark Johnston 	uint_t version;
4071673e404SJohn Birrell 
4081673e404SJohn Birrell 	if (flags != F_STATS)
4091673e404SJohn Birrell 		print_line("- Types ");
4101673e404SJohn Birrell 
4111673e404SJohn Birrell 	if (hp->cth_typeoff & 3)
4121673e404SJohn Birrell 		WARN("cth_typeoff is not aligned properly\n");
4131673e404SJohn Birrell 	if (hp->cth_typeoff >= cd->cd_ctflen)
4141673e404SJohn Birrell 		WARN("file is truncated or cth_typeoff is corrupt\n");
4151673e404SJohn Birrell 	if (hp->cth_stroff >= cd->cd_ctflen)
4161673e404SJohn Birrell 		WARN("file is truncated or cth_stroff is corrupt\n");
4171673e404SJohn Birrell 	if (hp->cth_typeoff > hp->cth_stroff)
4181673e404SJohn Birrell 		WARN("file is corrupt -- cth_typeoff > cth_stroff\n");
4191673e404SJohn Birrell 
420bdf290cdSMark Johnston 	version = hp->cth_version;
421bdf290cdSMark Johnston 
4221673e404SJohn Birrell 	id = 1;
4231673e404SJohn Birrell 	if (hp->cth_parlabel || hp->cth_parname)
424bdf290cdSMark Johnston 		id += 1ul << (hp->cth_version == CTF_VERSION_2 ?
425bdf290cdSMark Johnston 		    CTF_V2_PARENT_SHIFT : CTF_V3_PARENT_SHIFT);
4261673e404SJohn Birrell 
427bdf290cdSMark Johnston 	for (/* */; v < end; id++) {
428bdf290cdSMark Johnston 		struct ctf_type_v2 t2;
429bdf290cdSMark Johnston 		struct ctf_type_v3 t3;
430bdf290cdSMark Johnston 		ulong_t i, n;
4311673e404SJohn Birrell 		size_t size, increment, vlen = 0;
432bdf290cdSMark Johnston 		uint_t isroot, name, type;
433bdf290cdSMark Johnston 		int kind;
434bdf290cdSMark Johnston 
435bdf290cdSMark Johnston 		if (version == CTF_VERSION_2) {
436bdf290cdSMark Johnston 			memcpy(&t2, v, sizeof(t2));
437bdf290cdSMark Johnston 			name = t2.ctt_name;
438bdf290cdSMark Johnston 			n = CTF_V2_INFO_VLEN(t2.ctt_info);
439bdf290cdSMark Johnston 			isroot = CTF_V2_INFO_ISROOT(t2.ctt_info);
440bdf290cdSMark Johnston 			kind = CTF_V2_INFO_KIND(t2.ctt_info);
441bdf290cdSMark Johnston 			type = t2.ctt_type;
442bdf290cdSMark Johnston 
443bdf290cdSMark Johnston 			if (t2.ctt_size == CTF_V2_LSIZE_SENT) {
444bdf290cdSMark Johnston 				increment = sizeof (struct ctf_type_v2);
445bdf290cdSMark Johnston 				size = (size_t)CTF_TYPE_LSIZE(&t2);
446bdf290cdSMark Johnston 			} else {
447bdf290cdSMark Johnston 				increment = sizeof (struct ctf_stype_v2);
448bdf290cdSMark Johnston 				size = t2.ctt_size;
449bdf290cdSMark Johnston 			}
450bdf290cdSMark Johnston 		} else {
451bdf290cdSMark Johnston 			memcpy(&t3, v, sizeof(t3));
452bdf290cdSMark Johnston 			name = t3.ctt_name;
453bdf290cdSMark Johnston 			n = CTF_V3_INFO_VLEN(t3.ctt_info);
454bdf290cdSMark Johnston 			isroot = CTF_V3_INFO_ISROOT(t3.ctt_info);
455bdf290cdSMark Johnston 			kind = CTF_V3_INFO_KIND(t3.ctt_info);
456bdf290cdSMark Johnston 			type = t3.ctt_type;
457bdf290cdSMark Johnston 
458bdf290cdSMark Johnston 			if (t3.ctt_size == CTF_V3_LSIZE_SENT) {
459bdf290cdSMark Johnston 				increment = sizeof (struct ctf_type_v3);
460bdf290cdSMark Johnston 				size = (size_t)CTF_TYPE_LSIZE(&t3);
461bdf290cdSMark Johnston 			} else {
462bdf290cdSMark Johnston 				increment = sizeof (struct ctf_stype_v3);
463bdf290cdSMark Johnston 				size = t3.ctt_size;
464bdf290cdSMark Johnston 			}
465bdf290cdSMark Johnston 		}
4661673e404SJohn Birrell 
4671673e404SJohn Birrell 		union {
468bdf290cdSMark Johnston 			const char *ptr;
469bdf290cdSMark Johnston 			struct ctf_array_v2 *ap2;
470bdf290cdSMark Johnston 			struct ctf_array_v3 *ap3;
471bdf290cdSMark Johnston 			const struct ctf_member_v2 *mp2;
472bdf290cdSMark Johnston 			const struct ctf_member_v3 *mp3;
473bdf290cdSMark Johnston 			const struct ctf_lmember_v2 *lmp2;
474bdf290cdSMark Johnston 			const struct ctf_lmember_v3 *lmp3;
4751673e404SJohn Birrell 			const ctf_enum_t *ep;
4761673e404SJohn Birrell 		} u;
4771673e404SJohn Birrell 
478bdf290cdSMark Johnston 		u.ptr = v + increment;
479bdf290cdSMark Johnston 
4801673e404SJohn Birrell 		if (flags != F_STATS) {
4811673e404SJohn Birrell 			(void) printf("  %c%lu%c ",
482bdf290cdSMark Johnston 			    "[<"[isroot], id, "]>"[isroot]);
4831673e404SJohn Birrell 		}
4841673e404SJohn Birrell 
4851673e404SJohn Birrell 		switch (kind) {
4861673e404SJohn Birrell 		case CTF_K_INTEGER:
4871673e404SJohn Birrell 			if (flags != F_STATS) {
488bdf290cdSMark Johnston 				uint_t encoding =
489bdf290cdSMark Johnston 				    *((const uint_t *)(const void *)u.ptr);
4901673e404SJohn Birrell 
4911673e404SJohn Birrell 				(void) printf("INTEGER %s encoding=%s offset=%u"
492bdf290cdSMark Johnston 				    " bits=%u", ref_to_str(name, hp, cd),
493bdf290cdSMark Johnston 				    int_encoding_to_str(
4941673e404SJohn Birrell 				    CTF_INT_ENCODING(encoding)),
4951673e404SJohn Birrell 				    CTF_INT_OFFSET(encoding),
4961673e404SJohn Birrell 				    CTF_INT_BITS(encoding));
4971673e404SJohn Birrell 			}
498bdf290cdSMark Johnston 			vlen = sizeof (uint32_t);
4991673e404SJohn Birrell 			break;
5001673e404SJohn Birrell 
5011673e404SJohn Birrell 		case CTF_K_FLOAT:
5021673e404SJohn Birrell 			if (flags != F_STATS) {
503bdf290cdSMark Johnston 				uint_t encoding =
504bdf290cdSMark Johnston 				    *((const uint_t *)(const void *)u.ptr);
5051673e404SJohn Birrell 
5061673e404SJohn Birrell 				(void) printf("FLOAT %s encoding=%s offset=%u "
507bdf290cdSMark Johnston 				    "bits=%u", ref_to_str(name, hp, cd),
508bdf290cdSMark Johnston 				    fp_encoding_to_str(
5091673e404SJohn Birrell 				    CTF_FP_ENCODING(encoding)),
5101673e404SJohn Birrell 				    CTF_FP_OFFSET(encoding),
5111673e404SJohn Birrell 				    CTF_FP_BITS(encoding));
5121673e404SJohn Birrell 			}
513bdf290cdSMark Johnston 			vlen = sizeof (uint32_t);
5141673e404SJohn Birrell 			break;
5151673e404SJohn Birrell 
5161673e404SJohn Birrell 		case CTF_K_POINTER:
5171673e404SJohn Birrell 			if (flags != F_STATS) {
5181673e404SJohn Birrell 				(void) printf("POINTER %s refers to %u",
519bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd), type);
5201673e404SJohn Birrell 			}
5211673e404SJohn Birrell 			break;
5221673e404SJohn Birrell 
523bdf290cdSMark Johnston 		case CTF_K_ARRAY: {
524bdf290cdSMark Johnston 			uint_t contents, index, nelems;
525bdf290cdSMark Johnston 
526bdf290cdSMark Johnston 			if (version == CTF_VERSION_2) {
527bdf290cdSMark Johnston 				contents = u.ap2->cta_contents;
528bdf290cdSMark Johnston 				index = u.ap2->cta_index;
529bdf290cdSMark Johnston 				nelems = u.ap2->cta_nelems;
530bdf290cdSMark Johnston 			} else {
531bdf290cdSMark Johnston 				contents = u.ap3->cta_contents;
532bdf290cdSMark Johnston 				index = u.ap3->cta_index;
533bdf290cdSMark Johnston 				nelems = u.ap3->cta_nelems;
534bdf290cdSMark Johnston 			}
5351673e404SJohn Birrell 			if (flags != F_STATS) {
5361673e404SJohn Birrell 				(void) printf("ARRAY %s content: %u index: %u "
537bdf290cdSMark Johnston 				    "nelems: %u\n", ref_to_str(name, hp, cd),
538bdf290cdSMark Johnston 				    contents, index, nelems);
5391673e404SJohn Birrell 			}
540bdf290cdSMark Johnston 			if (version == 2)
541bdf290cdSMark Johnston 				vlen = sizeof (struct ctf_array_v2);
542bdf290cdSMark Johnston 			else
543bdf290cdSMark Johnston 				vlen = sizeof (struct ctf_array_v3);
5441673e404SJohn Birrell 			break;
545bdf290cdSMark Johnston 		}
5461673e404SJohn Birrell 
547bdf290cdSMark Johnston 		case CTF_K_FUNCTION: {
548bdf290cdSMark Johnston 			uint_t arg = 0;
549bdf290cdSMark Johnston 
5501673e404SJohn Birrell 			if (flags != F_STATS) {
5511673e404SJohn Birrell 				(void) printf("FUNCTION %s returns: %u args: (",
552bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd), type);
5531673e404SJohn Birrell 
5541673e404SJohn Birrell 				if (n != 0) {
555bdf290cdSMark Johnston 					memcpy(&arg, u.ptr, cd->cd_idwidth);
556bdf290cdSMark Johnston 					u.ptr += cd->cd_idwidth;
557bdf290cdSMark Johnston 					(void) printf("%u", arg);
558bdf290cdSMark Johnston 					for (i = 1; i < n;
559bdf290cdSMark Johnston 					    i++, u.ptr += cd->cd_idwidth) {
560bdf290cdSMark Johnston 						memcpy(&arg, u.ptr,
561bdf290cdSMark Johnston 						    cd->cd_idwidth);
562bdf290cdSMark Johnston 						(void) printf(", %u", arg);
563bdf290cdSMark Johnston 					}
5641673e404SJohn Birrell 				}
5651673e404SJohn Birrell 
5661673e404SJohn Birrell 				(void) printf(")");
5671673e404SJohn Birrell 			}
5681673e404SJohn Birrell 
569bdf290cdSMark Johnston 			vlen = roundup2(cd->cd_idwidth * n, 4);
5701673e404SJohn Birrell 			break;
571bdf290cdSMark Johnston 		}
5721673e404SJohn Birrell 
5731673e404SJohn Birrell 		case CTF_K_STRUCT:
5741673e404SJohn Birrell 		case CTF_K_UNION:
5751673e404SJohn Birrell 			if (kind == CTF_K_STRUCT) {
5761673e404SJohn Birrell 				stats.s_nsmem += n;
5771673e404SJohn Birrell 				stats.s_smmax = MAX(stats.s_smmax, n);
5781673e404SJohn Birrell 				stats.s_nsbytes += size;
5791673e404SJohn Birrell 				stats.s_sbmax = MAX(stats.s_sbmax, size);
5801673e404SJohn Birrell 
5811673e404SJohn Birrell 				if (flags != F_STATS)
5821673e404SJohn Birrell 					(void) printf("STRUCT");
5831673e404SJohn Birrell 			} else {
5841673e404SJohn Birrell 				stats.s_numem += n;
5851673e404SJohn Birrell 				stats.s_ummax = MAX(stats.s_ummax, n);
5861673e404SJohn Birrell 				stats.s_nubytes += size;
5871673e404SJohn Birrell 				stats.s_ubmax = MAX(stats.s_ubmax, size);
5881673e404SJohn Birrell 
5891673e404SJohn Birrell 				if (flags != F_STATS)
5901673e404SJohn Birrell 					(void) printf("UNION");
5911673e404SJohn Birrell 			}
5921673e404SJohn Birrell 
5931673e404SJohn Birrell 			if (flags != F_STATS) {
5949098da06SJohn Birrell 				(void) printf(" %s (%zd bytes)\n",
595bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd), size);
5961673e404SJohn Birrell 
597bdf290cdSMark Johnston 				if (version == CTF_VERSION_2) {
598bdf290cdSMark Johnston 					if (size >= CTF_V2_LSTRUCT_THRESH) {
599bdf290cdSMark Johnston 						for (i = 0; i < n; i++, u.lmp2++) {
6001673e404SJohn Birrell 							(void) printf(
6011673e404SJohn Birrell 							    "\t%s type=%u off=%llu\n",
602bdf290cdSMark Johnston 							    ref_to_str(u.lmp2->ctlm_name,
603bdf290cdSMark Johnston 							    hp, cd), u.lmp2->ctlm_type,
6049098da06SJohn Birrell 							    (unsigned long long)
605bdf290cdSMark Johnston 							    CTF_LMEM_OFFSET(u.lmp2));
6061673e404SJohn Birrell 						}
6071673e404SJohn Birrell 					} else {
608bdf290cdSMark Johnston 						for (i = 0; i < n; i++, u.mp2++) {
6091673e404SJohn Birrell 							(void) printf(
6101673e404SJohn Birrell 							    "\t%s type=%u off=%u\n",
611bdf290cdSMark Johnston 							    ref_to_str(u.mp2->ctm_name,
612bdf290cdSMark Johnston 							    hp, cd), u.mp2->ctm_type,
613bdf290cdSMark Johnston 							    u.mp2->ctm_offset);
614bdf290cdSMark Johnston 						}
615bdf290cdSMark Johnston 					}
616bdf290cdSMark Johnston 				} else {
617bdf290cdSMark Johnston 					if (size >= CTF_V3_LSTRUCT_THRESH) {
618bdf290cdSMark Johnston 						for (i = 0; i < n; i++, u.lmp3++) {
619bdf290cdSMark Johnston 							(void) printf(
620bdf290cdSMark Johnston 							    "\t%s type=%u off=%llu\n",
621bdf290cdSMark Johnston 							    ref_to_str(u.lmp3->ctlm_name,
622bdf290cdSMark Johnston 							    hp, cd), u.lmp3->ctlm_type,
623bdf290cdSMark Johnston 							    (unsigned long long)
624bdf290cdSMark Johnston 							    CTF_LMEM_OFFSET(u.lmp3));
625bdf290cdSMark Johnston 						}
626bdf290cdSMark Johnston 					} else {
627bdf290cdSMark Johnston 						for (i = 0; i < n; i++, u.mp3++) {
628bdf290cdSMark Johnston 							(void) printf(
629bdf290cdSMark Johnston 							    "\t%s type=%u off=%u\n",
630bdf290cdSMark Johnston 							    ref_to_str(u.mp3->ctm_name,
631bdf290cdSMark Johnston 							    hp, cd), u.mp3->ctm_type,
632bdf290cdSMark Johnston 							    u.mp3->ctm_offset);
633bdf290cdSMark Johnston 						}
6341673e404SJohn Birrell 					}
6351673e404SJohn Birrell 				}
6361673e404SJohn Birrell 			}
6371673e404SJohn Birrell 
638bdf290cdSMark Johnston 			if (version == CTF_VERSION_2) {
639bdf290cdSMark Johnston 				vlen = n * (size >= CTF_V2_LSTRUCT_THRESH ?
640bdf290cdSMark Johnston 				    sizeof (struct ctf_lmember_v2) :
641bdf290cdSMark Johnston 				    sizeof (struct ctf_member_v2));
642bdf290cdSMark Johnston 			} else {
643bdf290cdSMark Johnston 				vlen = n * (size >= CTF_V3_LSTRUCT_THRESH ?
644bdf290cdSMark Johnston 				    sizeof (struct ctf_lmember_v3) :
645bdf290cdSMark Johnston 				    sizeof (struct ctf_member_v3));
646bdf290cdSMark Johnston 			}
6471673e404SJohn Birrell 			break;
6481673e404SJohn Birrell 
6491673e404SJohn Birrell 		case CTF_K_ENUM:
6501673e404SJohn Birrell 			if (flags != F_STATS) {
6511673e404SJohn Birrell 				(void) printf("ENUM %s\n",
652bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd));
6531673e404SJohn Birrell 
6541673e404SJohn Birrell 				for (i = 0; i < n; i++, u.ep++) {
6551673e404SJohn Birrell 					(void) printf("\t%s = %d\n",
6561673e404SJohn Birrell 					    ref_to_str(u.ep->cte_name, hp, cd),
6571673e404SJohn Birrell 					    u.ep->cte_value);
6581673e404SJohn Birrell 				}
6591673e404SJohn Birrell 			}
6601673e404SJohn Birrell 
6611673e404SJohn Birrell 			stats.s_nemem += n;
6621673e404SJohn Birrell 			stats.s_emmax = MAX(stats.s_emmax, n);
6631673e404SJohn Birrell 
6641673e404SJohn Birrell 			vlen = sizeof (ctf_enum_t) * n;
6651673e404SJohn Birrell 			break;
6661673e404SJohn Birrell 
6671673e404SJohn Birrell 		case CTF_K_FORWARD:
6681673e404SJohn Birrell 			if (flags != F_STATS) {
6691673e404SJohn Birrell 				(void) printf("FORWARD %s",
670bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd));
6711673e404SJohn Birrell 			}
6721673e404SJohn Birrell 			break;
6731673e404SJohn Birrell 
6741673e404SJohn Birrell 		case CTF_K_TYPEDEF:
6751673e404SJohn Birrell 			if (flags != F_STATS) {
6761673e404SJohn Birrell 				(void) printf("TYPEDEF %s refers to %u",
677bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd), type);
6781673e404SJohn Birrell 			}
6791673e404SJohn Birrell 			break;
6801673e404SJohn Birrell 
6811673e404SJohn Birrell 		case CTF_K_VOLATILE:
6821673e404SJohn Birrell 			if (flags != F_STATS) {
6831673e404SJohn Birrell 				(void) printf("VOLATILE %s refers to %u",
684bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd), type);
6851673e404SJohn Birrell 			}
6861673e404SJohn Birrell 			break;
6871673e404SJohn Birrell 
6881673e404SJohn Birrell 		case CTF_K_CONST:
6891673e404SJohn Birrell 			if (flags != F_STATS) {
6901673e404SJohn Birrell 				(void) printf("CONST %s refers to %u",
691bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd), type);
6921673e404SJohn Birrell 			}
6931673e404SJohn Birrell 			break;
6941673e404SJohn Birrell 
6951673e404SJohn Birrell 		case CTF_K_RESTRICT:
6961673e404SJohn Birrell 			if (flags != F_STATS) {
6971673e404SJohn Birrell 				(void) printf("RESTRICT %s refers to %u",
698bdf290cdSMark Johnston 				    ref_to_str(name, hp, cd), type);
6991673e404SJohn Birrell 			}
7001673e404SJohn Birrell 			break;
7011673e404SJohn Birrell 
7021673e404SJohn Birrell 		case CTF_K_UNKNOWN:
7031673e404SJohn Birrell 			break; /* hole in type id space */
7041673e404SJohn Birrell 
7051673e404SJohn Birrell 		default:
7061673e404SJohn Birrell 			(void) printf("unexpected kind %u\n", kind);
7071673e404SJohn Birrell 			return (E_ERROR);
7081673e404SJohn Birrell 		}
7091673e404SJohn Birrell 
7101673e404SJohn Birrell 		if (flags != F_STATS)
7111673e404SJohn Birrell 			(void) printf("\n");
7121673e404SJohn Birrell 
7131673e404SJohn Birrell 		stats.s_ntypes++;
7141673e404SJohn Birrell 		stats.s_types[kind]++;
7151673e404SJohn Birrell 
716bdf290cdSMark Johnston 		v += increment + vlen;
7171673e404SJohn Birrell 	}
7181673e404SJohn Birrell 
7191673e404SJohn Birrell 	return (E_SUCCESS);
7201673e404SJohn Birrell }
7211673e404SJohn Birrell 
7221673e404SJohn Birrell static int
read_strtab(const ctf_header_t * hp,const ctf_data_t * cd)7231673e404SJohn Birrell read_strtab(const ctf_header_t *hp, const ctf_data_t *cd)
7241673e404SJohn Birrell {
7251673e404SJohn Birrell 	size_t n, off, len = hp->cth_strlen;
7261673e404SJohn Birrell 	const char *s = cd->cd_ctfdata + hp->cth_stroff;
7271673e404SJohn Birrell 
7281673e404SJohn Birrell 	if (flags != F_STATS)
7291673e404SJohn Birrell 		print_line("- String Table ");
7301673e404SJohn Birrell 
7311673e404SJohn Birrell 	if (hp->cth_stroff >= cd->cd_ctflen)
7321673e404SJohn Birrell 		WARN("file is truncated or cth_stroff is corrupt\n");
7331673e404SJohn Birrell 	if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen)
7341673e404SJohn Birrell 		WARN("file is truncated or cth_strlen is corrupt\n");
7351673e404SJohn Birrell 
7361673e404SJohn Birrell 	for (off = 0; len != 0; off += n) {
7371673e404SJohn Birrell 		if (flags != F_STATS) {
7381673e404SJohn Birrell 			(void) printf("  [%lu] %s\n", (ulong_t)off,
7391673e404SJohn Birrell 			    s[0] == '\0' ? "\\0" : s);
7401673e404SJohn Birrell 		}
7411673e404SJohn Birrell 		n = strlen(s) + 1;
7421673e404SJohn Birrell 		len -= n;
7431673e404SJohn Birrell 		s += n;
7441673e404SJohn Birrell 
7451673e404SJohn Birrell 		stats.s_nstr++;
7461673e404SJohn Birrell 		stats.s_strlen += n;
7471673e404SJohn Birrell 		stats.s_strmax = MAX(stats.s_strmax, n);
7481673e404SJohn Birrell 	}
7491673e404SJohn Birrell 
7501673e404SJohn Birrell 	return (E_SUCCESS);
7511673e404SJohn Birrell }
7521673e404SJohn Birrell 
7531673e404SJohn Birrell static void
long_stat(const char * name,ulong_t value)7541673e404SJohn Birrell long_stat(const char *name, ulong_t value)
7551673e404SJohn Birrell {
7561673e404SJohn Birrell 	(void) printf("  %-36s= %lu\n", name, value);
7571673e404SJohn Birrell }
7581673e404SJohn Birrell 
7591673e404SJohn Birrell static void
fp_stat(const char * name,float value)7601673e404SJohn Birrell fp_stat(const char *name, float value)
7611673e404SJohn Birrell {
7621673e404SJohn Birrell 	(void) printf("  %-36s= %.2f\n", name, value);
7631673e404SJohn Birrell }
7641673e404SJohn Birrell 
7651673e404SJohn Birrell static int
print_stats(void)7661673e404SJohn Birrell print_stats(void)
7671673e404SJohn Birrell {
7681673e404SJohn Birrell 	print_line("- CTF Statistics ");
7691673e404SJohn Birrell 
7701673e404SJohn Birrell 	long_stat("total number of data objects", stats.s_ndata);
7711673e404SJohn Birrell 	(void) printf("\n");
7721673e404SJohn Birrell 
7731673e404SJohn Birrell 	long_stat("total number of functions", stats.s_nfunc);
7741673e404SJohn Birrell 	long_stat("total number of function arguments", stats.s_nargs);
7751673e404SJohn Birrell 	long_stat("maximum argument list length", stats.s_argmax);
7761673e404SJohn Birrell 
7771673e404SJohn Birrell 	if (stats.s_nfunc != 0) {
7781673e404SJohn Birrell 		fp_stat("average argument list length",
7791673e404SJohn Birrell 		    (float)stats.s_nargs / (float)stats.s_nfunc);
7801673e404SJohn Birrell 	}
7811673e404SJohn Birrell 
7821673e404SJohn Birrell 	(void) printf("\n");
7831673e404SJohn Birrell 
7841673e404SJohn Birrell 	long_stat("total number of types", stats.s_ntypes);
7851673e404SJohn Birrell 	long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]);
7861673e404SJohn Birrell 	long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]);
7871673e404SJohn Birrell 	long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]);
7881673e404SJohn Birrell 	long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]);
7891673e404SJohn Birrell 	long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]);
7901673e404SJohn Birrell 	long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]);
7911673e404SJohn Birrell 	long_stat("total number of unions", stats.s_types[CTF_K_UNION]);
7921673e404SJohn Birrell 	long_stat("total number of enums", stats.s_types[CTF_K_ENUM]);
7931673e404SJohn Birrell 	long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]);
7941673e404SJohn Birrell 	long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]);
7951673e404SJohn Birrell 	long_stat("total number of volatile types",
7961673e404SJohn Birrell 	    stats.s_types[CTF_K_VOLATILE]);
7971673e404SJohn Birrell 	long_stat("total number of const types", stats.s_types[CTF_K_CONST]);
7981673e404SJohn Birrell 	long_stat("total number of restrict types",
7991673e404SJohn Birrell 	    stats.s_types[CTF_K_RESTRICT]);
8001673e404SJohn Birrell 	long_stat("total number of unknowns (holes)",
8011673e404SJohn Birrell 	    stats.s_types[CTF_K_UNKNOWN]);
8021673e404SJohn Birrell 
8031673e404SJohn Birrell 	(void) printf("\n");
8041673e404SJohn Birrell 
8051673e404SJohn Birrell 	long_stat("total number of struct members", stats.s_nsmem);
8061673e404SJohn Birrell 	long_stat("maximum number of struct members", stats.s_smmax);
8071673e404SJohn Birrell 	long_stat("total size of all structs", stats.s_nsbytes);
8081673e404SJohn Birrell 	long_stat("maximum size of a struct", stats.s_sbmax);
8091673e404SJohn Birrell 
8101673e404SJohn Birrell 	if (stats.s_types[CTF_K_STRUCT] != 0) {
8111673e404SJohn Birrell 		fp_stat("average number of struct members",
8121673e404SJohn Birrell 		    (float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]);
8131673e404SJohn Birrell 		fp_stat("average size of a struct", (float)stats.s_nsbytes /
8141673e404SJohn Birrell 		    (float)stats.s_types[CTF_K_STRUCT]);
8151673e404SJohn Birrell 	}
8161673e404SJohn Birrell 
8171673e404SJohn Birrell 	(void) printf("\n");
8181673e404SJohn Birrell 
8191673e404SJohn Birrell 	long_stat("total number of union members", stats.s_numem);
8201673e404SJohn Birrell 	long_stat("maximum number of union members", stats.s_ummax);
8211673e404SJohn Birrell 	long_stat("total size of all unions", stats.s_nubytes);
8221673e404SJohn Birrell 	long_stat("maximum size of a union", stats.s_ubmax);
8231673e404SJohn Birrell 
8241673e404SJohn Birrell 	if (stats.s_types[CTF_K_UNION] != 0) {
8251673e404SJohn Birrell 		fp_stat("average number of union members",
8261673e404SJohn Birrell 		    (float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]);
8271673e404SJohn Birrell 		fp_stat("average size of a union", (float)stats.s_nubytes /
8281673e404SJohn Birrell 		    (float)stats.s_types[CTF_K_UNION]);
8291673e404SJohn Birrell 	}
8301673e404SJohn Birrell 
8311673e404SJohn Birrell 	(void) printf("\n");
8321673e404SJohn Birrell 
8331673e404SJohn Birrell 	long_stat("total number of enum members", stats.s_nemem);
8341673e404SJohn Birrell 	long_stat("maximum number of enum members", stats.s_emmax);
8351673e404SJohn Birrell 
8361673e404SJohn Birrell 	if (stats.s_types[CTF_K_ENUM] != 0) {
8371673e404SJohn Birrell 		fp_stat("average number of enum members",
8381673e404SJohn Birrell 		    (float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]);
8391673e404SJohn Birrell 	}
8401673e404SJohn Birrell 
8411673e404SJohn Birrell 	(void) printf("\n");
8421673e404SJohn Birrell 
8431673e404SJohn Birrell 	long_stat("total number of unique strings", stats.s_nstr);
8441673e404SJohn Birrell 	long_stat("bytes of string data", stats.s_strlen);
8451673e404SJohn Birrell 	long_stat("maximum string length", stats.s_strmax);
8461673e404SJohn Birrell 
8471673e404SJohn Birrell 	if (stats.s_nstr != 0) {
8481673e404SJohn Birrell 		fp_stat("average string length",
8491673e404SJohn Birrell 		    (float)stats.s_strlen / (float)stats.s_nstr);
8501673e404SJohn Birrell 	}
8511673e404SJohn Birrell 
8521673e404SJohn Birrell 	(void) printf("\n");
8531673e404SJohn Birrell 	return (E_SUCCESS);
8541673e404SJohn Birrell }
8551673e404SJohn Birrell 
8561673e404SJohn Birrell static int
print_usage(FILE * fp,int verbose)8571673e404SJohn Birrell print_usage(FILE *fp, int verbose)
8581673e404SJohn Birrell {
8593dd55242SZhenlei Huang 	(void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getprogname());
8601673e404SJohn Birrell 
8611673e404SJohn Birrell 	if (verbose) {
8621673e404SJohn Birrell 		(void) fprintf(fp,
8631673e404SJohn Birrell 		    "\t-d  dump data object section\n"
8641673e404SJohn Birrell 		    "\t-f  dump function section\n"
8651673e404SJohn Birrell 		    "\t-h  dump file header\n"
8661673e404SJohn Birrell 		    "\t-l  dump label table\n"
8671673e404SJohn Birrell 		    "\t-s  dump string table\n"
8681673e404SJohn Birrell 		    "\t-S  dump statistics\n"
8691673e404SJohn Birrell 		    "\t-t  dump type section\n"
8701673e404SJohn Birrell 		    "\t-u  save uncompressed CTF to a file\n");
8711673e404SJohn Birrell 	}
8721673e404SJohn Birrell 
8731673e404SJohn Birrell 	return (E_USAGE);
8741673e404SJohn Birrell }
8751673e404SJohn Birrell 
8761673e404SJohn Birrell static Elf_Scn *
findelfscn(Elf * elf,GElf_Ehdr * ehdr,const char * secname)8779098da06SJohn Birrell findelfscn(Elf *elf, GElf_Ehdr *ehdr, const char *secname)
8781673e404SJohn Birrell {
8791673e404SJohn Birrell 	GElf_Shdr shdr;
8801673e404SJohn Birrell 	Elf_Scn *scn;
8811673e404SJohn Birrell 	char *name;
8821673e404SJohn Birrell 
8831673e404SJohn Birrell 	for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) {
8841673e404SJohn Birrell 		if (gelf_getshdr(scn, &shdr) != NULL && (name =
8851673e404SJohn Birrell 		    elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL &&
8861673e404SJohn Birrell 		    strcmp(name, secname) == 0)
8871673e404SJohn Birrell 			return (scn);
8881673e404SJohn Birrell 	}
8891673e404SJohn Birrell 
8901673e404SJohn Birrell 	return (NULL);
8911673e404SJohn Birrell }
8921673e404SJohn Birrell 
8931673e404SJohn Birrell int
main(int argc,char * argv[])8941673e404SJohn Birrell main(int argc, char *argv[])
8951673e404SJohn Birrell {
8961673e404SJohn Birrell 	const char *filename = NULL;
8971673e404SJohn Birrell 	const char *ufile = NULL;
8981673e404SJohn Birrell 	int error = 0;
8991673e404SJohn Birrell 	int c, fd, ufd;
9001673e404SJohn Birrell 
9011673e404SJohn Birrell 	ctf_data_t cd;
9021673e404SJohn Birrell 	const ctf_preamble_t *pp;
9039098da06SJohn Birrell 	ctf_header_t *hp = NULL;
9041673e404SJohn Birrell 	Elf *elf;
9051673e404SJohn Birrell 	GElf_Ehdr ehdr;
9061673e404SJohn Birrell 
9071673e404SJohn Birrell 	(void) elf_version(EV_CURRENT);
9081673e404SJohn Birrell 
9091673e404SJohn Birrell 	for (opterr = 0; optind < argc; optind++) {
9101673e404SJohn Birrell 		while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) {
9111673e404SJohn Birrell 			switch (c) {
9121673e404SJohn Birrell 			case 'd':
9131673e404SJohn Birrell 				flags |= F_DATA;
9141673e404SJohn Birrell 				break;
9151673e404SJohn Birrell 			case 'f':
9161673e404SJohn Birrell 				flags |= F_FUNC;
9171673e404SJohn Birrell 				break;
9181673e404SJohn Birrell 			case 'h':
9191673e404SJohn Birrell 				flags |= F_HDR;
9201673e404SJohn Birrell 				break;
9211673e404SJohn Birrell 			case 'l':
9221673e404SJohn Birrell 				flags |= F_LABEL;
9231673e404SJohn Birrell 				break;
9241673e404SJohn Birrell 			case 's':
9251673e404SJohn Birrell 				flags |= F_STR;
9261673e404SJohn Birrell 				break;
9271673e404SJohn Birrell 			case 'S':
9281673e404SJohn Birrell 				flags |= F_STATS;
9291673e404SJohn Birrell 				break;
9301673e404SJohn Birrell 			case 't':
9311673e404SJohn Birrell 				flags |= F_TYPES;
9321673e404SJohn Birrell 				break;
9331673e404SJohn Birrell 			case 'u':
9341673e404SJohn Birrell 				ufile = optarg;
9351673e404SJohn Birrell 				break;
9361673e404SJohn Birrell 			default:
9371673e404SJohn Birrell 				if (optopt == '?')
9381673e404SJohn Birrell 					return (print_usage(stdout, 1));
9391673e404SJohn Birrell 				warn("illegal option -- %c\n", optopt);
9401673e404SJohn Birrell 				return (print_usage(stderr, 0));
9411673e404SJohn Birrell 			}
9421673e404SJohn Birrell 		}
9431673e404SJohn Birrell 
9441673e404SJohn Birrell 		if (optind < argc) {
9451673e404SJohn Birrell 			if (filename != NULL)
9461673e404SJohn Birrell 				return (print_usage(stderr, 0));
9471673e404SJohn Birrell 			filename = argv[optind];
9481673e404SJohn Birrell 		}
9491673e404SJohn Birrell 	}
9501673e404SJohn Birrell 
9511673e404SJohn Birrell 	if (filename == NULL)
9521673e404SJohn Birrell 		return (print_usage(stderr, 0));
9531673e404SJohn Birrell 
9541673e404SJohn Birrell 	if (flags == 0 && ufile == NULL)
9551673e404SJohn Birrell 		flags = F_ALLMSK;
9561673e404SJohn Birrell 
9571673e404SJohn Birrell 	if ((fd = open(filename, O_RDONLY)) == -1)
9581673e404SJohn Birrell 		die("failed to open %s", filename);
9591673e404SJohn Birrell 
9601673e404SJohn Birrell 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL &&
9611673e404SJohn Birrell 	    gelf_getehdr(elf, &ehdr) != NULL) {
9621673e404SJohn Birrell 
9639098da06SJohn Birrell 		Elf_Data *dp = NULL;
9641673e404SJohn Birrell 		Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf");
9651673e404SJohn Birrell 		Elf_Scn *symscn;
9661673e404SJohn Birrell 		GElf_Shdr ctfshdr;
9671673e404SJohn Birrell 
9681673e404SJohn Birrell 		if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL)
9691673e404SJohn Birrell 			die("%s does not contain .SUNW_ctf data\n", filename);
9701673e404SJohn Birrell 
9711673e404SJohn Birrell 		cd.cd_ctfdata = dp->d_buf;
9721673e404SJohn Birrell 		cd.cd_ctflen = dp->d_size;
9731673e404SJohn Birrell 
9741673e404SJohn Birrell 		/*
9751673e404SJohn Birrell 		 * If the sh_link field of the CTF section header is non-zero
9761673e404SJohn Birrell 		 * it indicates which section contains the symbol table that
9771673e404SJohn Birrell 		 * should be used. We default to the .symtab section if sh_link
9781673e404SJohn Birrell 		 * is zero or if there's an error reading the section header.
9791673e404SJohn Birrell 		 */
9801673e404SJohn Birrell 		if (gelf_getshdr(ctfscn, &ctfshdr) != NULL &&
9811673e404SJohn Birrell 		    ctfshdr.sh_link != 0) {
9821673e404SJohn Birrell 			symscn = elf_getscn(elf, ctfshdr.sh_link);
9831673e404SJohn Birrell 		} else {
9841673e404SJohn Birrell 			symscn = findelfscn(elf, &ehdr, ".symtab");
9851673e404SJohn Birrell 		}
9861673e404SJohn Birrell 
9871673e404SJohn Birrell 		/* If we found a symbol table, find the corresponding strings */
9881673e404SJohn Birrell 		if (symscn != NULL) {
9891673e404SJohn Birrell 			GElf_Shdr shdr;
9901673e404SJohn Birrell 			Elf_Scn *symstrscn;
9911673e404SJohn Birrell 
9921673e404SJohn Birrell 			if (gelf_getshdr(symscn, &shdr) != NULL) {
9931673e404SJohn Birrell 				symstrscn = elf_getscn(elf, shdr.sh_link);
9941673e404SJohn Birrell 
9951673e404SJohn Birrell 				cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
9961673e404SJohn Birrell 				cd.cd_symdata = elf_getdata(symscn, NULL);
9971673e404SJohn Birrell 				cd.cd_strdata = elf_getdata(symstrscn, NULL);
9981673e404SJohn Birrell 			}
9991673e404SJohn Birrell 		}
10001673e404SJohn Birrell 	} else {
10011673e404SJohn Birrell 		struct stat st;
10021673e404SJohn Birrell 
10031673e404SJohn Birrell 		if (fstat(fd, &st) == -1)
10041673e404SJohn Birrell 			die("failed to fstat %s", filename);
10051673e404SJohn Birrell 
10061673e404SJohn Birrell 		cd.cd_ctflen = st.st_size;
10071673e404SJohn Birrell 		cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ,
10081673e404SJohn Birrell 		    MAP_PRIVATE, fd, 0);
10091673e404SJohn Birrell 		if (cd.cd_ctfdata == MAP_FAILED)
10101673e404SJohn Birrell 			die("failed to mmap %s", filename);
10111673e404SJohn Birrell 	}
10121673e404SJohn Birrell 
10131673e404SJohn Birrell 	/*
10141673e404SJohn Birrell 	 * Get a pointer to the CTF data buffer and interpret the first portion
10151673e404SJohn Birrell 	 * as a ctf_header_t.  Validate the magic number and size.
10161673e404SJohn Birrell 	 */
10171673e404SJohn Birrell 
10181673e404SJohn Birrell 	if (cd.cd_ctflen < sizeof (ctf_preamble_t))
10191673e404SJohn Birrell 		die("%s does not contain a CTF preamble\n", filename);
10201673e404SJohn Birrell 
10219098da06SJohn Birrell 	void *v = (void *) cd.cd_ctfdata;
10229098da06SJohn Birrell 	pp = v;
10231673e404SJohn Birrell 
10241673e404SJohn Birrell 	if (pp->ctp_magic != CTF_MAGIC)
10251673e404SJohn Birrell 		die("%s does not appear to contain CTF data\n", filename);
10261673e404SJohn Birrell 
1027bdf290cdSMark Johnston 	if (pp->ctp_version >= CTF_VERSION_2) {
10289098da06SJohn Birrell 		v = (void *) cd.cd_ctfdata;
10299098da06SJohn Birrell 		hp = v;
10301673e404SJohn Birrell 		cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t);
10311673e404SJohn Birrell 
1032bdf290cdSMark Johnston 		cd.cd_idwidth = pp->ctp_version == CTF_VERSION_2 ? 2 : 4;
1033bdf290cdSMark Johnston 
10341673e404SJohn Birrell 		if (cd.cd_ctflen < sizeof (ctf_header_t)) {
10351673e404SJohn Birrell 			die("%s does not contain a v%d CTF header\n", filename,
1036bdf290cdSMark Johnston 			    pp->ctp_version);
10371673e404SJohn Birrell 		}
10381673e404SJohn Birrell 
10391673e404SJohn Birrell 	} else {
10401673e404SJohn Birrell 		die("%s contains unsupported CTF version %d\n", filename,
10411673e404SJohn Birrell 		    pp->ctp_version);
10421673e404SJohn Birrell 	}
10431673e404SJohn Birrell 
10441673e404SJohn Birrell 	/*
10451673e404SJohn Birrell 	 * If the data buffer is compressed, then malloc a buffer large enough
10461673e404SJohn Birrell 	 * to hold the decompressed data, and use zlib to decompress it.
10471673e404SJohn Birrell 	 */
10481673e404SJohn Birrell 	if (hp->cth_flags & CTF_F_COMPRESS) {
10491673e404SJohn Birrell 		z_stream zstr;
10501673e404SJohn Birrell 		void *buf;
10511673e404SJohn Birrell 		int rc;
10521673e404SJohn Birrell 
10531673e404SJohn Birrell 		if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL)
10541673e404SJohn Birrell 			die("failed to allocate decompression buffer");
10551673e404SJohn Birrell 
10561673e404SJohn Birrell 		bzero(&zstr, sizeof (z_stream));
10571673e404SJohn Birrell 		zstr.next_in = (void *)cd.cd_ctfdata;
10581673e404SJohn Birrell 		zstr.avail_in = cd.cd_ctflen;
10591673e404SJohn Birrell 		zstr.next_out = buf;
10601673e404SJohn Birrell 		zstr.avail_out = hp->cth_stroff + hp->cth_strlen;
10611673e404SJohn Birrell 
10621673e404SJohn Birrell 		if ((rc = inflateInit(&zstr)) != Z_OK)
10631673e404SJohn Birrell 			die("failed to initialize zlib: %s\n", zError(rc));
10641673e404SJohn Birrell 
10651673e404SJohn Birrell 		if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END)
10661673e404SJohn Birrell 			die("failed to decompress CTF data: %s\n", zError(rc));
10671673e404SJohn Birrell 
10681673e404SJohn Birrell 		if ((rc = inflateEnd(&zstr)) != Z_OK)
10691673e404SJohn Birrell 			die("failed to finish decompression: %s\n", zError(rc));
10701673e404SJohn Birrell 
10711673e404SJohn Birrell 		if (zstr.total_out != hp->cth_stroff + hp->cth_strlen)
10721673e404SJohn Birrell 			die("CTF data is corrupt -- short decompression\n");
10731673e404SJohn Birrell 
10741673e404SJohn Birrell 		cd.cd_ctfdata = buf;
10751673e404SJohn Birrell 		cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen;
10761673e404SJohn Birrell 	}
10771673e404SJohn Birrell 
10781673e404SJohn Birrell 	if (flags & F_HDR)
10791673e404SJohn Birrell 		error |= print_header(hp, &cd);
10801673e404SJohn Birrell 	if (flags & (F_LABEL))
10811673e404SJohn Birrell 		error |= print_labeltable(hp, &cd);
10821673e404SJohn Birrell 	if (flags & (F_DATA | F_STATS))
10831673e404SJohn Birrell 		error |= read_data(hp, &cd);
10841673e404SJohn Birrell 	if (flags & (F_FUNC | F_STATS))
10851673e404SJohn Birrell 		error |= read_funcs(hp, &cd);
10861673e404SJohn Birrell 	if (flags & (F_TYPES | F_STATS))
10871673e404SJohn Birrell 		error |= read_types(hp, &cd);
10881673e404SJohn Birrell 	if (flags & (F_STR | F_STATS))
10891673e404SJohn Birrell 		error |= read_strtab(hp, &cd);
10901673e404SJohn Birrell 	if (flags & F_STATS)
10911673e404SJohn Birrell 		error |= print_stats();
10921673e404SJohn Birrell 
10931673e404SJohn Birrell 	/*
10941673e404SJohn Birrell 	 * If the -u option is specified, write the uncompressed CTF data to a
10951673e404SJohn Birrell 	 * raw CTF file.  CTF data can already be extracted compressed by
10961673e404SJohn Birrell 	 * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.
10971673e404SJohn Birrell 	 */
10981673e404SJohn Birrell 	if (ufile != NULL) {
10991673e404SJohn Birrell 		ctf_header_t h;
11001673e404SJohn Birrell 
11011673e404SJohn Birrell 		bcopy(hp, &h, sizeof (h));
11021673e404SJohn Birrell 		h.cth_flags &= ~CTF_F_COMPRESS;
11031673e404SJohn Birrell 
11041673e404SJohn Birrell 		if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 ||
11051673e404SJohn Birrell 		    write(ufd, &h, sizeof (h)) != sizeof (h) ||
11069098da06SJohn Birrell 		    write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != (int) cd.cd_ctflen) {
11071673e404SJohn Birrell 			warn("failed to write CTF data to '%s'", ufile);
11081673e404SJohn Birrell 			error |= E_ERROR;
11091673e404SJohn Birrell 		}
11101673e404SJohn Birrell 
11111673e404SJohn Birrell 		(void) close(ufd);
11121673e404SJohn Birrell 	}
11131673e404SJohn Birrell 
11141673e404SJohn Birrell 	if (elf != NULL)
11151673e404SJohn Birrell 		(void) elf_end(elf);
11161673e404SJohn Birrell 
11171673e404SJohn Birrell 	(void) close(fd);
11181673e404SJohn Birrell 	return (error);
11191673e404SJohn Birrell }
1120