1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"@(#)dump.c	1.12	05/06/08 SMI"
28
29#if !defined(__APPLE__)
30#include <sys/types.h>
31#include <sys/sysmacros.h>
32#include <sys/stat.h>
33#include <sys/mman.h>
34#else
35#include <sys/types.h>
36//#include <sys/sysmacros.h>
37#include <sys/stat.h>
38#include <sys/mman.h>
39
40#include "darwin_shim.h"
41#include <mach-o/loader.h>
42#include <mach-o/nlist.h>
43#include <mach-o/stab.h>
44
45int debug_level;
46const char *progname = "ctfdump";
47#endif /* __APPLE__ */
48
49#include <strings.h>
50#include <unistd.h>
51#include <stdlib.h>
52#include <stdio.h>
53#include <fcntl.h>
54#include <gelf.h>
55#include <zlib.h>
56
57#include "ctf_headers.h"
58#include "strtab.h"
59#include "ctftools.h"
60#include "utils.h"
61#include "symbol.h"
62
63#ifdef __APPLE__
64extern caddr_t write_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp);
65extern caddr_t write_compressed_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp);
66struct ctf_buf {
67	strtab_t ctb_strtab;	/* string table */
68	caddr_t ctb_base;	/* pointer to base of buffer */
69	caddr_t ctb_end;	/* pointer to end of buffer */
70	caddr_t ctb_ptr;	/* pointer to empty buffer space */
71	size_t ctb_size;	/* size of buffer */
72	int nptent;		/* number of processed types */
73	int ntholes;		/* number of type holes */
74};
75
76void write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname, caddr_t ctfdata, size_t ctfsize, int flags);
77
78#endif /* __APPLE__ */
79
80#define	WARN(x)	{ warn(x); return (E_ERROR); }
81
82/*
83 * Flags that indicate what data is to be displayed.  An explicit `all' value is
84 * provided to allow the code to distinguish between a request for everything
85 * (currently requested by invoking ctfdump without flags) and individual
86 * requests for all of the types of data (an invocation with all flags).  In the
87 * former case, we want to be able to implicitly adjust the definition of `all'
88 * based on the CTF version of the file being dumped.  For example, if a v2 file
89 * is being dumped, `all' includes F_LABEL - a request to dump the label
90 * section.  If a v1 file is being dumped, `all' does not include F_LABEL,
91 * because v1 CTF doesn't support labels.  We need to be able to distinguish
92 * between `ctfdump foo', which has an implicit request for labels if `foo'
93 * supports them, and `ctfdump -l foo', which has an explicity request.  In the
94 * latter case, we exit with an error if `foo' is a v1 CTF file.
95 */
96static enum {
97	F_DATA	= 0x01,		/* show data object section */
98	F_FUNC	= 0x02,		/* show function section */
99	F_HDR	= 0x04,		/* show header */
100	F_STR	= 0x08,		/* show string table */
101	F_TYPES	= 0x10,		/* show type section */
102	F_STATS = 0x20, 	/* show statistics */
103	F_LABEL	= 0x40,		/* show label section */
104	F_ALL	= 0x80,		/* explicit request for `all' */
105	F_ALLMSK = 0xff		/* show all sections and statistics */
106} flags = 0;
107
108static struct {
109	ulong_t s_ndata;	/* total number of data objects */
110	ulong_t s_nfunc;	/* total number of functions */
111	ulong_t s_nargs;	/* total number of function arguments */
112	ulong_t s_argmax;	/* longest argument list */
113	ulong_t s_ntypes;	/* total number of types */
114	ulong_t s_types[16];	/* number of types by kind */
115	ulong_t s_nsmem;	/* total number of struct members */
116	ulong_t s_nsbytes;	/* total size of all structs */
117	ulong_t s_smmax;	/* largest struct in terms of members */
118	ulong_t s_sbmax;	/* largest struct in terms of bytes */
119	ulong_t s_numem;	/* total number of union members */
120	ulong_t s_nubytes;	/* total size of all unions */
121	ulong_t s_ummax;	/* largest union in terms of members */
122	ulong_t s_ubmax;	/* largest union in terms of bytes */
123	ulong_t s_nemem;	/* total number of enum members */
124	ulong_t s_emmax;	/* largest enum in terms of members */
125	ulong_t s_nstr;		/* total number of strings */
126	size_t s_strlen;	/* total length of all strings */
127	size_t s_strmax;	/* longest string length */
128} stats;
129
130typedef struct ctf_data {
131	caddr_t cd_ctfdata;	/* Pointer to the CTF data */
132	size_t cd_ctflen;	/* Length of CTF data */
133
134	/*
135	 * cd_symdata will be non-NULL if the CTF data is being retrieved from
136	 * an ELF file with a symbol table.  cd_strdata and cd_nsyms should be
137	 * used only if cd_symdata is non-NULL.
138	 */
139	Elf_Data *cd_symdata;	/* Symbol table */
140	Elf_Data *cd_strdata;	/* Symbol table strings */
141	int cd_nsyms;		/* Number of symbol table entries */
142#if defined (__APPLE__)
143	Elf32_Word sh_link;
144#endif /* __APPLE__ */
145} ctf_data_t;
146
147static const char *
148ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd)
149{
150	size_t offset = CTF_NAME_OFFSET(name);
151	const char *s = cd->cd_ctfdata + hp->cth_stroff + offset;
152
153	if (CTF_NAME_STID(name) != CTF_STRTAB_0)
154		return ("<< ??? - name in external strtab >>");
155
156	if (offset >= hp->cth_strlen)
157		return ("<< ??? - name exceeds strlab len >>");
158
159	if (hp->cth_stroff + offset >= cd->cd_ctflen)
160		return ("<< ??? - file truncated >>");
161
162	if (s[0] == '\0')
163		return ("(anon)");
164
165	return (s);
166}
167
168static const char *
169int_encoding_to_str(uint_t encoding)
170{
171	static char buf[32];
172
173	if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR |
174	    CTF_INT_BOOL | CTF_INT_VARARGS)) != 0)
175		(void) snprintf(buf, sizeof (buf), " 0x%x", encoding);
176	else {
177		buf[0] = '\0';
178		if (encoding & CTF_INT_SIGNED)
179			(void) strcat(buf, " SIGNED");
180		if (encoding & CTF_INT_CHAR)
181			(void) strcat(buf, " CHAR");
182		if (encoding & CTF_INT_BOOL)
183			(void) strcat(buf, " BOOL");
184		if (encoding & CTF_INT_VARARGS)
185			(void) strcat(buf, " VARARGS");
186	}
187
188	return (buf + 1);
189}
190
191static const char *
192fp_encoding_to_str(uint_t encoding)
193{
194	static const char *const encs[] = {
195		NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX",
196		"LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",
197		"DIMAGINARY", "LDIMAGINARY"
198	};
199
200	static char buf[16];
201
202	if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) {
203		(void) snprintf(buf, sizeof (buf), "%u", encoding);
204		return (buf);
205	}
206
207	return (encs[encoding]);
208}
209
210static void
211print_line(const char *s)
212{
213	static const char line[] = "----------------------------------------"
214	    "----------------------------------------";
215	(void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line);
216}
217
218static int
219print_header(const ctf_header_t *hp, const ctf_data_t *cd)
220{
221	print_line("- CTF Header ");
222
223	(void) printf("  cth_magic    = 0x%04x\n", hp->cth_magic);
224	(void) printf("  cth_version  = %u\n", hp->cth_version);
225	(void) printf("  cth_flags    = 0x%02x\n", hp->cth_flags);
226	(void) printf("  cth_parlabel = %s\n",
227	    ref_to_str(hp->cth_parlabel, hp, cd));
228	(void) printf("  cth_parname  = %s\n",
229	    ref_to_str(hp->cth_parname, hp, cd));
230	(void) printf("  cth_lbloff   = %u\n", hp->cth_lbloff);
231	(void) printf("  cth_objtoff  = %u\n", hp->cth_objtoff);
232	(void) printf("  cth_funcoff  = %u\n", hp->cth_funcoff);
233	(void) printf("  cth_typeoff  = %u\n", hp->cth_typeoff);
234	(void) printf("  cth_stroff   = %u\n", hp->cth_stroff);
235	(void) printf("  cth_strlen   = %u\n", hp->cth_strlen);
236
237	return (E_SUCCESS);
238}
239
240static int
241print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd)
242{
243	/* LINTED - pointer alignment */
244	const ctf_lblent_t *ctl = (ctf_lblent_t *)(cd->cd_ctfdata +
245	    hp->cth_lbloff);
246	ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl);
247
248	print_line("- Label Table ");
249
250	if (hp->cth_lbloff & 3)
251		WARN("cth_lbloff is not aligned properly\n");
252	if (hp->cth_lbloff >= cd->cd_ctflen)
253		WARN("file is truncated or cth_lbloff is corrupt\n");
254	if (hp->cth_objtoff >= cd->cd_ctflen)
255		WARN("file is truncated or cth_objtoff is corrupt\n");
256	if (hp->cth_lbloff > hp->cth_objtoff)
257		WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");
258
259	for (i = 0; i < n; i++, ctl++) {
260		(void) printf("  %5u %s\n", ctl->ctl_typeidx,
261		    ref_to_str(ctl->ctl_label, hp, cd));
262	}
263
264	return (E_SUCCESS);
265}
266
267#if defined(__APPLE__)
268static GElf_Sym *
269gelf_getsym_macho(Elf_Data * data, int ndx, GElf_Sym * sym, const char *base)
270{
271	const struct nlist *nsym = (const struct nlist *)(data->d_buf);
272	const char *name;
273	char *tmp;
274
275	nsym += ndx;
276	name = base + nsym->n_un.n_strx;
277
278	if (0 == nsym->n_un.n_strx) // iff a null, "", name.
279		name = "null name"; // return NULL;
280
281	if ('_' == name[0])
282		name++; // Lop off omnipresent underscore to match DWARF convention
283
284	sym->st_name = (GElf_Sxword)(name - base);
285	sym->st_value = nsym->n_value;
286	sym->st_size = 0;
287	sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_NOTYPE));
288	sym->st_other = 0;
289	sym->st_shndx = SHN_MACHO; /* Mark underlying file as Mach-o */
290
291	if (nsym->n_type & N_STAB) { /* Detect C++ methods */
292
293		switch(nsym->n_type) {
294		case N_FUN:
295			sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
296			break;
297		case N_GSYM:
298			sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT));
299			break;
300		default:
301			break;
302		}
303
304	} else if ((N_ABS | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT)) ||
305		(N_SECT | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT))) {
306
307		sym->st_info = GELF_ST_INFO((STB_GLOBAL), (nsym->n_desc));
308	} else if ((N_UNDF | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT)) &&
309				nsym->n_sect == NO_SECT) {
310		sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT)); /* Common */
311	}
312
313	return sym;
314}
315
316static GElf_Sym *
317gelf_getsym_macho_64(Elf_Data * data, int ndx, GElf_Sym * sym, const char *base)
318{
319	const struct nlist_64 *nsym = (const struct nlist_64 *)(data->d_buf);
320	const char *name;
321	char *tmp;
322
323	nsym += ndx;
324	name = base + nsym->n_un.n_strx;
325
326	if (0 == nsym->n_un.n_strx) // iff a null, "", name.
327		name = "null name"; // return NULL;
328
329	if ('_' == name[0])
330		name++; // Lop off omnipresent underscore to match DWARF convention
331
332	sym->st_name = (GElf_Sxword)(name - base);
333	sym->st_value = nsym->n_value;
334	sym->st_size = 0;
335	sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_NOTYPE));
336	sym->st_other = 0;
337	sym->st_shndx = SHN_MACHO_64; /* Mark underlying file as Mach-o */
338
339	if (nsym->n_type & N_STAB) { /* Detect C++ methods */
340
341		switch(nsym->n_type) {
342		case N_FUN:
343			sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
344			break;
345		case N_GSYM:
346			sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT));
347			break;
348		default:
349			break;
350		}
351
352	} else if ((N_ABS | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT)) ||
353		(N_SECT | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT))) {
354
355		sym->st_info = GELF_ST_INFO((STB_GLOBAL), (nsym->n_desc));
356	} else if ((N_UNDF | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT)) &&
357				nsym->n_sect == NO_SECT) {
358		sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT)); /* Common */
359	}
360
361	return sym;
362}
363#endif /* __APPLE__ */
364
365/*
366 * Given the current symbol index (-1 to start at the beginning of the symbol
367 * table) and the type of symbol to match, this function returns the index of
368 * the next matching symbol (if any), and places the name of that symbol in
369 * *namep.  If no symbol is found, -1 is returned.
370 */
371static int
372next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,
373    char **namep)
374{
375	int i;
376
377	for (i = symidx + 1; i < cd->cd_nsyms; i++) {
378		GElf_Sym sym;
379		char *name;
380		int type;
381
382#if defined(__APPLE__)
383		if (cd->sh_link == SHN_MACHO) { /* Underlying file is Mach-o */
384			if (gelf_getsym_macho(cd->cd_symdata, i, &sym, (const char *)(cd->cd_strdata->d_buf)) == 0)
385				return (-1);
386		}
387		else if (cd->sh_link == SHN_MACHO_64) { /* Underlying file is Mach-o 64 */
388			if (gelf_getsym_macho_64(cd->cd_symdata, i, &sym, (const char *)(cd->cd_strdata->d_buf)) == 0)
389				return (-1);
390		}
391		else
392#endif /* __APPLE__ */
393		if (gelf_getsym(cd->cd_symdata, i, &sym) == 0)
394			return (-1);
395
396		name = (char *)cd->cd_strdata->d_buf + sym.st_name;
397		type = GELF_ST_TYPE(sym.st_info);
398
399		/*
400		 * Skip various types of symbol table entries.
401		 */
402		if (type != matchtype || ignore_symbol(&sym, name))
403			continue;
404
405		/* Found one */
406		*namep = name;
407		return (i);
408	}
409
410	return (-1);
411}
412
413static int
414read_data(const ctf_header_t *hp, const ctf_data_t *cd)
415{
416	/* LINTED - pointer alignment */
417	const ushort_t *idp = (ushort_t *)(cd->cd_ctfdata + hp->cth_objtoff);
418	ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / sizeof (ushort_t);
419
420	if (flags != F_STATS)
421		print_line("- Data Objects ");
422
423	if (hp->cth_objtoff & 1)
424		WARN("cth_objtoff is not aligned properly\n");
425	if (hp->cth_objtoff >= cd->cd_ctflen)
426		WARN("file is truncated or cth_objtoff is corrupt\n");
427	if (hp->cth_funcoff >= cd->cd_ctflen)
428		WARN("file is truncated or cth_funcoff is corrupt\n");
429	if (hp->cth_objtoff > hp->cth_funcoff)
430		WARN("file is corrupt -- cth_objtoff > cth_funcoff\n");
431
432	if (flags != F_STATS) {
433		int symidx, len, i;
434		char *name = NULL;
435
436		for (symidx = -1, i = 0; i < n; i++) {
437			int nextsym;
438
439			if (cd->cd_symdata == NULL || (nextsym = next_sym(cd,
440				symidx, STT_OBJECT, &name)) < 0)
441				name = NULL;
442			else
443				symidx = nextsym;
444
445			len = printf("  [%u] %u", i, *idp++);
446			if (name != NULL)
447				(void) printf("%*s%s (%u)", (15 - len), "",
448				    name, symidx);
449			(void) putchar('\n');
450		}
451	}
452
453	stats.s_ndata = n;
454	return (E_SUCCESS);
455}
456
457static int
458read_funcs(const ctf_header_t *hp, const ctf_data_t *cd)
459{
460	/* LINTED - pointer alignment */
461	const ushort_t *fp = (ushort_t *)(cd->cd_ctfdata + hp->cth_funcoff);
462
463	/* LINTED - pointer alignment */
464	const ushort_t *end = (ushort_t *)(cd->cd_ctfdata + hp->cth_typeoff);
465
466	ulong_t id;
467	int symidx;
468
469	if (flags != F_STATS)
470		print_line("- Functions ");
471
472	if (hp->cth_funcoff & 1)
473		WARN("cth_funcoff is not aligned properly\n");
474	if (hp->cth_funcoff >= cd->cd_ctflen)
475		WARN("file is truncated or cth_funcoff is corrupt\n");
476	if (hp->cth_typeoff >= cd->cd_ctflen)
477		WARN("file is truncated or cth_typeoff is corrupt\n");
478	if (hp->cth_funcoff > hp->cth_typeoff)
479		WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");
480
481	for (symidx = -1, id = 0; fp < end; id++) {
482		ushort_t info = *fp++;
483		ushort_t kind = CTF_INFO_KIND(info);
484		ushort_t n = CTF_INFO_VLEN(info);
485		ushort_t i;
486		int nextsym;
487		char *name;
488
489		if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx,
490		    STT_FUNC, &name)) < 0)
491			name = NULL;
492		else
493			symidx = nextsym;
494
495		if (kind == CTF_K_UNKNOWN && n == 0)
496			continue; /* skip padding */
497
498		if (kind != CTF_K_FUNCTION) {
499			(void) printf("  [%lu] unexpected kind -- %u\n",
500			    id, kind);
501			return (E_ERROR);
502		}
503
504		if (fp + n > end) {
505			(void) printf("  [%lu] vlen %u extends past section "
506			    "boundary\n", id, n);
507			return (E_ERROR);
508		}
509
510		if (flags != F_STATS) {
511			(void) printf("  [%lu] FUNC ", id);
512			if (name != NULL)
513				(void) printf("(%s) ", name);
514			(void) printf("returns: %u args: (", *fp++);
515
516			if (n != 0) {
517				(void) printf("%u", *fp++);
518				for (i = 1; i < n; i++)
519					(void) printf(", %u", *fp++);
520			}
521
522			(void) printf(")\n");
523		} else
524			fp += n + 1; /* skip to next function definition */
525
526		stats.s_nfunc++;
527		stats.s_nargs += n;
528		stats.s_argmax = MAX(stats.s_argmax, n);
529	}
530
531	return (E_SUCCESS);
532}
533
534static int
535read_types(const ctf_header_t *hp, const ctf_data_t *cd)
536{
537	/* LINTED - pointer alignment */
538	const ctf_type_t *tp = (ctf_type_t *)(cd->cd_ctfdata + hp->cth_typeoff);
539
540	/* LINTED - pointer alignment */
541	const ctf_type_t *end = (ctf_type_t *)(cd->cd_ctfdata + hp->cth_stroff);
542
543	ulong_t id;
544
545	if (flags != F_STATS)
546		print_line("- Types ");
547
548	if (hp->cth_typeoff & 3)
549		WARN("cth_typeoff is not aligned properly\n");
550	if (hp->cth_typeoff >= cd->cd_ctflen)
551		WARN("file is truncated or cth_typeoff is corrupt\n");
552	if (hp->cth_stroff >= cd->cd_ctflen)
553		WARN("file is truncated or cth_stroff is corrupt\n");
554	if (hp->cth_typeoff > hp->cth_stroff)
555		WARN("file is corrupt -- cth_typeoff > cth_stroff\n");
556
557	id = 1;
558	if (hp->cth_parlabel || hp->cth_parname)
559		id += 1 << CTF_PARENT_SHIFT;
560
561	for (/* */; tp < end; id++) {
562		ulong_t i, n = CTF_INFO_VLEN(tp->ctt_info);
563		size_t size, increment, vlen = 0;
564		int kind = CTF_INFO_KIND(tp->ctt_info);
565
566		union {
567			const void *ptr;
568			const ctf_array_t *ap;
569			const ctf_member_t *mp;
570			const ctf_lmember_t *lmp;
571			const ctf_enum_t *ep;
572			const ushort_t *argp;
573		} u;
574
575		if (flags != F_STATS) {
576			(void) printf("  %c%lu%c ",
577			    "[<"[CTF_INFO_ISROOT(tp->ctt_info)], id,
578			    "]>"[CTF_INFO_ISROOT(tp->ctt_info)]);
579		}
580
581		if (tp->ctt_size == CTF_LSIZE_SENT) {
582			increment = sizeof (ctf_type_t);
583			size = (size_t)CTF_TYPE_LSIZE(tp);
584		} else {
585			increment = sizeof (ctf_stype_t);
586			size = tp->ctt_size;
587		}
588		u.ptr = (caddr_t)tp + increment;
589
590		switch (kind) {
591		case CTF_K_INTEGER:
592			if (flags != F_STATS) {
593				uint_t encoding = *((const uint_t *)u.ptr);
594
595				(void) printf("INTEGER %s encoding=%s offset=%u"
596				    " bits=%u", ref_to_str(tp->ctt_name, hp,
597				    cd), int_encoding_to_str(
598				    CTF_INT_ENCODING(encoding)),
599				    CTF_INT_OFFSET(encoding),
600				    CTF_INT_BITS(encoding));
601			}
602			vlen = sizeof (uint_t);
603			break;
604
605		case CTF_K_FLOAT:
606			if (flags != F_STATS) {
607				uint_t encoding = *((const uint_t *)u.ptr);
608
609				(void) printf("FLOAT %s encoding=%s offset=%u "
610				    "bits=%u", ref_to_str(tp->ctt_name, hp,
611				    cd), fp_encoding_to_str(
612				    CTF_FP_ENCODING(encoding)),
613				    CTF_FP_OFFSET(encoding),
614				    CTF_FP_BITS(encoding));
615			}
616			vlen = sizeof (uint_t);
617			break;
618
619		case CTF_K_POINTER:
620			if (flags != F_STATS) {
621				(void) printf("POINTER %s refers to %u",
622				    ref_to_str(tp->ctt_name, hp, cd),
623				    tp->ctt_type);
624			}
625			break;
626
627		case CTF_K_ARRAY:
628			if (flags != F_STATS) {
629				(void) printf("ARRAY %s content: %u index: %u "
630				    "nelems: %u\n", ref_to_str(tp->ctt_name,
631				    hp, cd), u.ap->cta_contents,
632				    u.ap->cta_index, u.ap->cta_nelems);
633			}
634			vlen = sizeof (ctf_array_t);
635			break;
636
637		case CTF_K_FUNCTION:
638			if (flags != F_STATS) {
639				(void) printf("FUNCTION %s returns: %u args: (",
640				    ref_to_str(tp->ctt_name, hp, cd),
641				    tp->ctt_type);
642
643				if (n != 0) {
644					(void) printf("%u", *u.argp++);
645					for (i = 1; i < n; i++, u.argp++)
646						(void) printf(", %u", *u.argp);
647				}
648
649				(void) printf(")");
650			}
651
652			vlen = sizeof (ushort_t) * (n + (n & 1));
653			break;
654
655		case CTF_K_STRUCT:
656		case CTF_K_UNION:
657			if (kind == CTF_K_STRUCT) {
658				stats.s_nsmem += n;
659				stats.s_smmax = MAX(stats.s_smmax, n);
660				stats.s_nsbytes += size;
661				stats.s_sbmax = MAX(stats.s_sbmax, size);
662
663				if (flags != F_STATS)
664					(void) printf("STRUCT");
665			} else {
666				stats.s_numem += n;
667				stats.s_ummax = MAX(stats.s_ummax, n);
668				stats.s_nubytes += size;
669				stats.s_ubmax = MAX(stats.s_ubmax, size);
670
671				if (flags != F_STATS)
672					(void) printf("UNION");
673			}
674
675			if (flags != F_STATS) {
676				(void) printf(" %s (%d bytes)\n",
677				    ref_to_str(tp->ctt_name, hp, cd), size);
678
679				if (size >= CTF_LSTRUCT_THRESH) {
680					for (i = 0; i < n; i++, u.lmp++) {
681						(void) printf(
682						    "\t%s type=%u off=%llu\n",
683						    ref_to_str(u.lmp->ctlm_name,
684						    hp, cd), u.lmp->ctlm_type,
685						    CTF_LMEM_OFFSET(u.lmp));
686					}
687				} else {
688					for (i = 0; i < n; i++, u.mp++) {
689						(void) printf(
690						    "\t%s type=%u off=%u\n",
691						    ref_to_str(u.mp->ctm_name,
692						    hp, cd), u.mp->ctm_type,
693						    u.mp->ctm_offset);
694					}
695				}
696			}
697
698			vlen = n * (size >= CTF_LSTRUCT_THRESH ?
699			    sizeof (ctf_lmember_t) : sizeof (ctf_member_t));
700			break;
701
702		case CTF_K_ENUM:
703			if (flags != F_STATS) {
704				(void) printf("ENUM %s\n",
705				    ref_to_str(tp->ctt_name, hp, cd));
706
707				for (i = 0; i < n; i++, u.ep++) {
708					(void) printf("\t%s = %d\n",
709					    ref_to_str(u.ep->cte_name, hp, cd),
710					    u.ep->cte_value);
711				}
712			}
713
714			stats.s_nemem += n;
715			stats.s_emmax = MAX(stats.s_emmax, n);
716
717			vlen = sizeof (ctf_enum_t) * n;
718			break;
719
720		case CTF_K_FORWARD:
721			if (flags != F_STATS) {
722				(void) printf("FORWARD %s",
723				    ref_to_str(tp->ctt_name, hp, cd));
724			}
725			break;
726
727		case CTF_K_TYPEDEF:
728			if (flags != F_STATS) {
729				(void) printf("TYPEDEF %s refers to %u",
730				    ref_to_str(tp->ctt_name, hp, cd),
731				    tp->ctt_type);
732			}
733			break;
734
735		case CTF_K_VOLATILE:
736			if (flags != F_STATS) {
737				(void) printf("VOLATILE %s refers to %u",
738				    ref_to_str(tp->ctt_name, hp, cd),
739				    tp->ctt_type);
740			}
741			break;
742
743		case CTF_K_CONST:
744			if (flags != F_STATS) {
745				(void) printf("CONST %s refers to %u",
746				    ref_to_str(tp->ctt_name, hp, cd),
747				    tp->ctt_type);
748			}
749			break;
750
751		case CTF_K_RESTRICT:
752			if (flags != F_STATS) {
753				(void) printf("RESTRICT %s refers to %u",
754				    ref_to_str(tp->ctt_name, hp, cd),
755				    tp->ctt_type);
756			}
757			break;
758
759		case CTF_K_UNKNOWN:
760			break; /* hole in type id space */
761
762		default:
763			(void) printf("unexpected kind %u\n", kind);
764			return (E_ERROR);
765		}
766
767		if (flags != F_STATS)
768			(void) printf("\n");
769
770		stats.s_ntypes++;
771		stats.s_types[kind]++;
772
773		tp = (ctf_type_t *)((uintptr_t)tp + increment + vlen);
774	}
775
776	return (E_SUCCESS);
777}
778
779static int
780read_strtab(const ctf_header_t *hp, const ctf_data_t *cd)
781{
782	size_t n, off, len = hp->cth_strlen;
783	const char *s = cd->cd_ctfdata + hp->cth_stroff;
784
785	if (flags != F_STATS)
786		print_line("- String Table ");
787
788	if (hp->cth_stroff >= cd->cd_ctflen)
789		WARN("file is truncated or cth_stroff is corrupt\n");
790	if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen)
791		WARN("file is truncated or cth_strlen is corrupt\n");
792
793	for (off = 0; len != 0; off += n) {
794		if (flags != F_STATS) {
795			(void) printf("  [%lu] %s\n", (ulong_t)off,
796			    s[0] == '\0' ? "\\0" : s);
797		}
798		n = strlen(s) + 1;
799		len -= n;
800		s += n;
801
802		stats.s_nstr++;
803		stats.s_strlen += n;
804		stats.s_strmax = MAX(stats.s_strmax, n);
805	}
806
807	return (E_SUCCESS);
808}
809
810/*
811 * Remove unwanted symbols from strtab: replace them with "-    ".
812 */
813static int
814clean_strtab(ctf_header_t *hp, ctf_data_t *cd, strtab_t *strtab,
815		char **syms, int nsyms)
816{
817	size_t n, off, len = hp->cth_strlen;
818	char *s = cd->cd_ctfdata + hp->cth_stroff;
819	int i;
820
821	char buf[1024];
822	buf[0] = '-';
823	memset(buf + 1, ' ', 1023);
824
825	if (hp->cth_stroff >= cd->cd_ctflen)
826		WARN("file is truncated or cth_stroff is corrupt\n");
827	if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen)
828		WARN("file is truncated or cth_strlen is corrupt\n");
829
830	for (off = 0; len != 0; off += n) {
831		for (i = 0; i < nsyms; i++) {
832			/* clean out offending string */
833			if (!strcmp(s, syms[i]))
834				strncpy(s, buf, strlen(s));
835		}
836		/* add all strings to fresh strtab */
837		strtab_insert(strtab, s);
838		n = strlen(s) + 1;
839		len -= n;
840		s += n;
841	}
842
843	return 0;
844}
845
846/*
847 * Convert from one representation to another of the ctf buffer
848 */
849static void
850ctf_data_to_ctf_buf(ctf_header_t *hp, ctf_data_t *cd, ctf_buf_t *cb)
851{
852	/* create empty strtab (to be filled in clean_strtab) */
853	strtab_create(&cb->ctb_strtab);
854	cb->ctb_base = cd->cd_ctfdata;
855	cb->ctb_end = cd->cd_ctfdata + hp->cth_stroff;
856	cb->ctb_ptr = cb->ctb_end;
857	cb->ctb_size = cd->cd_ctflen - hp->cth_strlen;
858	/* not used for our purposes */
859	cb->nptent = 0;
860	cb->ntholes = 0;
861}
862
863/*
864 * Similar to write_ctf, but we don't have to reconstruct the whole CTF section
865 * from a tdata_t.
866 */
867static int
868write_ctfdata(int srcfd, Elf *srcelf, const char *srcname, const char *dstname, ctf_header_t *hp, ctf_buf_t *buf)
869{
870	struct stat st;
871	Elf *dstelf = NULL;
872	caddr_t data = NULL;
873	size_t len = 0;
874	int dstfd;
875
876	/* open + elf_begin destination file */
877	fstat(srcfd, &st);
878	if ((dstfd = open(dstname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0)
879		terminate("Cannot open temp file %s for writing", dstname);
880	if ((dstelf = elf_begin(dstfd, ELF_C_WRITE, NULL)) == NULL)
881		elfterminate(dstname, "Cannot write");
882
883	/* write out and/or compress header & data buffer */
884	if (hp->cth_flags & CTF_F_COMPRESS) {
885		data = write_compressed_buffer(hp, buf, &len);
886	} else {
887		data = write_buffer(hp, buf, &len);
888		/*
889		data = (caddr_t) xmalloc(sizeof(ctf_header_t) + cd->cd_ctflen);
890		bcopy(hp, data, sizeof(ctf_header_t));
891		len += sizeof(ctf_header_t);
892		bcopy(cd->cd_ctfdata, data + len, cd->cd_ctflen);
893		len += cd->cd_ctflen;
894		*/
895	}
896
897	/* send the data to the destination file */
898	write_file(srcelf, srcname, dstelf, dstname, data, len, 0);
899
900	free(data);
901	elf_end(dstelf);
902	(void) close(dstfd);
903	return 0;
904}
905
906static void
907long_stat(const char *name, ulong_t value)
908{
909	(void) printf("  %-36s= %lu\n", name, value);
910}
911
912static void
913fp_stat(const char *name, float value)
914{
915	(void) printf("  %-36s= %.2f\n", name, value);
916}
917
918static int
919print_stats(void)
920{
921	print_line("- CTF Statistics ");
922
923	long_stat("total number of data objects", stats.s_ndata);
924	(void) printf("\n");
925
926	long_stat("total number of functions", stats.s_nfunc);
927	long_stat("total number of function arguments", stats.s_nargs);
928	long_stat("maximum argument list length", stats.s_argmax);
929
930	if (stats.s_nfunc != 0) {
931		fp_stat("average argument list length",
932		    (float)stats.s_nargs / (float)stats.s_nfunc);
933	}
934
935	(void) printf("\n");
936
937	long_stat("total number of types", stats.s_ntypes);
938	long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]);
939	long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]);
940	long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]);
941	long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]);
942	long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]);
943	long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]);
944	long_stat("total number of unions", stats.s_types[CTF_K_UNION]);
945	long_stat("total number of enums", stats.s_types[CTF_K_ENUM]);
946	long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]);
947	long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]);
948	long_stat("total number of volatile types",
949	    stats.s_types[CTF_K_VOLATILE]);
950	long_stat("total number of const types", stats.s_types[CTF_K_CONST]);
951	long_stat("total number of restrict types",
952	    stats.s_types[CTF_K_RESTRICT]);
953	long_stat("total number of unknowns (holes)",
954	    stats.s_types[CTF_K_UNKNOWN]);
955
956	(void) printf("\n");
957
958	long_stat("total number of struct members", stats.s_nsmem);
959	long_stat("maximum number of struct members", stats.s_smmax);
960	long_stat("total size of all structs", stats.s_nsbytes);
961	long_stat("maximum size of a struct", stats.s_sbmax);
962
963	if (stats.s_types[CTF_K_STRUCT] != 0) {
964		fp_stat("average number of struct members",
965		    (float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]);
966		fp_stat("average size of a struct", (float)stats.s_nsbytes /
967		    (float)stats.s_types[CTF_K_STRUCT]);
968	}
969
970	(void) printf("\n");
971
972	long_stat("total number of union members", stats.s_numem);
973	long_stat("maximum number of union members", stats.s_ummax);
974	long_stat("total size of all unions", stats.s_nubytes);
975	long_stat("maximum size of a union", stats.s_ubmax);
976
977	if (stats.s_types[CTF_K_UNION] != 0) {
978		fp_stat("average number of union members",
979		    (float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]);
980		fp_stat("average size of a union", (float)stats.s_nubytes /
981		    (float)stats.s_types[CTF_K_UNION]);
982	}
983
984	(void) printf("\n");
985
986	long_stat("total number of enum members", stats.s_nemem);
987	long_stat("maximum number of enum members", stats.s_emmax);
988
989	if (stats.s_types[CTF_K_ENUM] != 0) {
990		fp_stat("average number of enum members",
991		    (float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]);
992	}
993
994	(void) printf("\n");
995
996	long_stat("total number of unique strings", stats.s_nstr);
997	long_stat("bytes of string data", stats.s_strlen);
998	long_stat("maximum string length", stats.s_strmax);
999
1000	if (stats.s_nstr != 0) {
1001		fp_stat("average string length",
1002		    (float)stats.s_strlen / (float)stats.s_nstr);
1003	}
1004
1005	(void) printf("\n");
1006	return (E_SUCCESS);
1007}
1008
1009static int
1010print_usage(FILE *fp, int verbose)
1011{
1012#if !defined(__APPLE__)
1013	(void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getpname());
1014#else
1015	(void) fprintf(fp, "Usage: %s [-dfhlrsSt] [-u file] file\n", progname);
1016#endif /* __APPLE__ */
1017
1018	if (verbose) {
1019		(void) fprintf(fp,
1020		    "\t-d  dump data object section\n"
1021		    "\t-f  dump function section\n"
1022		    "\t-h  dump file header\n"
1023		    "\t-l  dump label table\n"
1024#ifdef __APPLE__
1025		    "\t-r  remove listed symbols from CTF data\n"
1026#endif /* __APPLE__ */
1027		    "\t-s  dump string table\n"
1028		    "\t-S  dump statistics\n"
1029		    "\t-t  dump type section\n"
1030		    "\t-u  save uncompressed CTF to a file\n");
1031	}
1032
1033	return (E_USAGE);
1034}
1035
1036static Elf_Scn *
1037findelfscn(Elf *elf, GElf_Ehdr *ehdr, char *secname)
1038{
1039	GElf_Shdr shdr;
1040	Elf_Scn *scn;
1041	char *name;
1042
1043	for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) {
1044		if (gelf_getshdr(scn, &shdr) != NULL && (name =
1045		    elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL &&
1046		    strcmp(name, secname) == 0)
1047			return (scn);
1048	}
1049
1050	return (NULL);
1051}
1052
1053int
1054main(int argc, char *argv[])
1055{
1056	const char *filename = NULL;
1057	const char *ufile = NULL;
1058	int error = 0, doclean = 0;
1059	int c, fd, ufd;
1060
1061	ctf_data_t cd;
1062	const ctf_preamble_t *pp;
1063	ctf_header_t *hp;
1064	Elf *elf;
1065	GElf_Ehdr ehdr;
1066
1067	(void) elf_version(EV_CURRENT);
1068
1069	for (opterr = 0; optind < argc; optind++) {
1070		while ((c = getopt(argc, argv, "dfhlrsStu:")) != (int)EOF) {
1071			switch (c) {
1072			case 'd':
1073				flags |= F_DATA;
1074				break;
1075			case 'f':
1076				flags |= F_FUNC;
1077				break;
1078			case 'h':
1079				flags |= F_HDR;
1080				break;
1081			case 'l':
1082				flags |= F_LABEL;
1083				break;
1084			case 'r':
1085				doclean = 1;
1086				goto skiploop;
1087			case 's':
1088				flags |= F_STR;
1089				break;
1090			case 'S':
1091				flags |= F_STATS;
1092				break;
1093			case 't':
1094				flags |= F_TYPES;
1095				break;
1096			case 'u':
1097				ufile = optarg;
1098				break;
1099			default:
1100				if (optopt == '?')
1101					return (print_usage(stdout, 1));
1102				warn("illegal option -- %c\n", optopt);
1103				return (print_usage(stderr, 0));
1104			}
1105		}
1106
1107		if (optind < argc) {
1108			if (filename != NULL)
1109				return (print_usage(stderr, 0));
1110			filename = argv[optind];
1111		}
1112	}
1113
1114skiploop:
1115	if (doclean)
1116		filename = argv[argc - 1];
1117
1118	if (filename == NULL)
1119		return (print_usage(stderr, 0));
1120
1121	if (flags == 0 && ufile == NULL)
1122		flags = F_ALLMSK;
1123
1124	if ((fd = open(filename, O_RDONLY)) == -1)
1125		die("failed to open %s", filename);
1126
1127	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL &&
1128	    gelf_getehdr(elf, &ehdr) != NULL) {
1129
1130		Elf_Data *dp;
1131		Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf");
1132		Elf_Scn *symscn;
1133		GElf_Shdr ctfshdr;
1134
1135		if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL)
1136			die("%s does not contain .SUNW_ctf data\n", filename);
1137
1138		cd.cd_ctfdata = dp->d_buf;
1139		cd.cd_ctflen = dp->d_size;
1140
1141		/*
1142		 * If the sh_link field of the CTF section header is non-zero
1143		 * it indicates which section contains the symbol table that
1144		 * should be used. We default to the .symtab section if sh_link
1145		 * is zero or if there's an error reading the section header.
1146		 */
1147#if !defined(__APPLE__)
1148		if (gelf_getshdr(ctfscn, &ctfshdr) != NULL &&
1149		    ctfshdr.sh_link != 0) {
1150			symscn = elf_getscn(elf, ctfshdr.sh_link);
1151		} else {
1152			symscn = findelfscn(elf, &ehdr, ".symtab");
1153		}
1154#else
1155		if (gelf_getshdr(ctfscn, &ctfshdr) != NULL &&
1156		    ctfshdr.sh_link != 0 && ctfshdr.sh_link != SHN_MACHO && ctfshdr.sh_link != SHN_MACHO_64) {
1157			symscn = elf_getscn(elf, ctfshdr.sh_link);
1158		} else {
1159			symscn = findelfscn(elf, &ehdr, ".symtab");
1160		}
1161#endif /* __APPLE__ */
1162
1163		/* If we found a symbol table, find the corresponding strings */
1164		if (symscn != NULL) {
1165			GElf_Shdr shdr;
1166			Elf_Scn *symstrscn;
1167
1168			if (gelf_getshdr(symscn, &shdr) != NULL) {
1169#if !defined(__APPLE__)
1170				symstrscn = elf_getscn(elf, shdr.sh_link);
1171
1172				cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
1173				cd.cd_symdata = elf_getdata(symscn, NULL);
1174				cd.cd_strdata = elf_getdata(symstrscn, NULL);
1175#else
1176				if (SHN_MACHO == shdr.sh_link) { /* Underlying file is Mach-o */
1177					int dir_idx;
1178					cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
1179					cd.cd_symdata = elf_getdata(symscn, NULL);
1180
1181					if ((dir_idx = findelfsecidx(elf, filename, ".dir_str_table")) < 0 ||
1182						(symstrscn = elf_getscn(elf, dir_idx)) == NULL ||
1183						(cd.cd_strdata = elf_getdata(symstrscn, NULL)) == NULL)
1184						terminate("%s: Can't open direct string table\n", filename);
1185
1186					cd.sh_link = SHN_MACHO; /* Mark underlying file as Mach-o */
1187				} else if (SHN_MACHO_64 == shdr.sh_link) { /* Underlying file is Mach-o 64 */
1188					int dir_idx;
1189					cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
1190					cd.cd_symdata = elf_getdata(symscn, NULL);
1191
1192					if ((dir_idx = findelfsecidx(elf, filename, ".dir_str_table")) < 0 ||
1193						(symstrscn = elf_getscn(elf, dir_idx)) == NULL ||
1194						(cd.cd_strdata = elf_getdata(symstrscn, NULL)) == NULL)
1195						terminate("%s: Can't open direct string table\n", filename);
1196
1197					cd.sh_link = SHN_MACHO_64; /* Mark underlying file as Mach-o 64 */
1198				} else {
1199					symstrscn = elf_getscn(elf, shdr.sh_link);
1200
1201					cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
1202					cd.cd_symdata = elf_getdata(symscn, NULL);
1203					cd.cd_strdata = elf_getdata(symstrscn, NULL);
1204					cd.sh_link = shdr.sh_link;
1205				}
1206#endif /* __APPLE__ */
1207			}
1208		}
1209	} else {
1210		struct stat st;
1211
1212		if (fstat(fd, &st) == -1)
1213			die("failed to fstat %s", filename);
1214
1215		cd.cd_ctflen = st.st_size;
1216		cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ,
1217		    MAP_PRIVATE, fd, 0);
1218		if (cd.cd_ctfdata == MAP_FAILED)
1219			die("failed to mmap %s", filename);
1220	}
1221
1222	/*
1223	 * Get a pointer to the CTF data buffer and interpret the first portion
1224	 * as a ctf_header_t.  Validate the magic number and size.
1225	 */
1226
1227	if (cd.cd_ctflen < sizeof (ctf_preamble_t))
1228		die("%s does not contain a CTF preamble\n", filename);
1229
1230	/* LINTED - pointer alignment */
1231	pp = (const ctf_preamble_t *)cd.cd_ctfdata;
1232
1233	if (pp->ctp_magic != CTF_MAGIC)
1234		die("%s does not appear to contain CTF data\n", filename);
1235
1236	if (pp->ctp_version == CTF_VERSION) {
1237		/* LINTED - pointer alignment */
1238		hp = (ctf_header_t *)cd.cd_ctfdata;
1239		cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t);
1240
1241		if (cd.cd_ctflen < sizeof (ctf_header_t)) {
1242			die("%s does not contain a v%d CTF header\n", filename,
1243			    CTF_VERSION);
1244		}
1245
1246	} else {
1247		die("%s contains unsupported CTF version %d\n", filename,
1248		    pp->ctp_version);
1249	}
1250
1251	/*
1252	 * If the data buffer is compressed, then malloc a buffer large enough
1253	 * to hold the decompressed data, and use zlib to decompress it.
1254	 */
1255	if (hp->cth_flags & CTF_F_COMPRESS) {
1256		z_stream zstr;
1257		void *buf;
1258		int rc;
1259
1260		if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL)
1261			die("failed to allocate decompression buffer");
1262
1263		bzero(&zstr, sizeof (z_stream));
1264		zstr.next_in = (void *)cd.cd_ctfdata;
1265		zstr.avail_in = cd.cd_ctflen;
1266		zstr.next_out = buf;
1267		zstr.avail_out = hp->cth_stroff + hp->cth_strlen;
1268
1269		if ((rc = inflateInit(&zstr)) != Z_OK)
1270			die("failed to initialize zlib: %s\n", zError(rc));
1271
1272		if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END)
1273			die("failed to decompress CTF data: %s\n", zError(rc));
1274
1275		if ((rc = inflateEnd(&zstr)) != Z_OK)
1276			die("failed to finish decompression: %s\n", zError(rc));
1277
1278		if (zstr.total_out != hp->cth_stroff + hp->cth_strlen)
1279			die("CTF data is corrupt -- short decompression\n");
1280
1281		cd.cd_ctfdata = buf;
1282		cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen;
1283	}
1284
1285#ifdef __APPLE__
1286	if (doclean) {
1287		int nsyms = argc - 1 - optind;
1288		char **syms = &argv[optind];
1289		char *tmpname = (char *)mktmpname(filename, ".ctf");
1290		ctf_buf_t tmpbuf;
1291
1292		ctf_data_to_ctf_buf(hp, &cd, &tmpbuf);
1293		clean_strtab(hp, &cd, &tmpbuf.ctb_strtab, syms, nsyms);
1294
1295		write_ctfdata(fd, elf, filename, tmpname, hp, &tmpbuf);
1296		if (rename(tmpname, filename) != 0) {
1297			terminate("Couldn't rename temp file %s to %s", tmpname,
1298					filename);
1299		}
1300		free(tmpname);
1301		flags = 0;
1302	}
1303#endif /* __APPLE__ */
1304
1305	if (flags & F_HDR)
1306		error |= print_header(hp, &cd);
1307	if (flags & (F_LABEL))
1308		error |= print_labeltable(hp, &cd);
1309	if (flags & (F_DATA | F_STATS))
1310		error |= read_data(hp, &cd);
1311	if (flags & (F_FUNC | F_STATS))
1312		error |= read_funcs(hp, &cd);
1313	if (flags & (F_TYPES | F_STATS))
1314		error |= read_types(hp, &cd);
1315	if (flags & (F_STR | F_STATS))
1316		error |= read_strtab(hp, &cd);
1317	if (flags & F_STATS)
1318		error |= print_stats();
1319
1320	/*
1321	 * If the -u option is specified, write the uncompressed CTF data to a
1322	 * raw CTF file.  CTF data can already be extracted compressed by
1323	 * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.
1324	 */
1325	if (ufile != NULL) {
1326		ctf_header_t h;
1327
1328		bcopy(hp, &h, sizeof (h));
1329		h.cth_flags &= ~CTF_F_COMPRESS;
1330
1331		if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 ||
1332		    write(ufd, &h, sizeof (h)) != sizeof (h) ||
1333		    write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != cd.cd_ctflen) {
1334			warn("failed to write CTF data to '%s'", ufile);
1335			error |= E_ERROR;
1336		}
1337
1338		(void) close(ufd);
1339	}
1340
1341	if (elf != NULL)
1342		(void) elf_end(elf);
1343
1344	(void) close(fd);
1345	return (error);
1346}
1347