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