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