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