Path: blob/main/cddl/contrib/opensolaris/tools/ctf/dump/dump.c
39562 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License, Version 1.0 only5* (the "License"). You may not use this file except in compliance6* with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or http://www.opensolaris.org/os/licensing.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright 2004 Sun Microsystems, Inc. All rights reserved.23* Use is subject to license terms.24*/2526#include <sys/types.h>27#include <sys/sysmacros.h>28#include <sys/stat.h>29#include <sys/mman.h>3031#include <err.h>32#include <strings.h>33#include <unistd.h>34#include <stdlib.h>35#include <stdio.h>36#include <fcntl.h>37#include <gelf.h>38#include <zlib.h>3940#include "ctf_headers.h"41#include "utils.h"42#include "symbol.h"4344#define WARN(x) { warn(x); return (E_ERROR); }4546/*47* Flags that indicate what data is to be displayed. An explicit `all' value is48* provided to allow the code to distinguish between a request for everything49* (currently requested by invoking ctfdump without flags) and individual50* requests for all of the types of data (an invocation with all flags). In the51* former case, we want to be able to implicitly adjust the definition of `all'52* based on the CTF version of the file being dumped. For example, if a v2 file53* is being dumped, `all' includes F_LABEL - a request to dump the label54* section. If a v1 file is being dumped, `all' does not include F_LABEL,55* because v1 CTF doesn't support labels. We need to be able to distinguish56* between `ctfdump foo', which has an implicit request for labels if `foo'57* supports them, and `ctfdump -l foo', which has an explicity request. In the58* latter case, we exit with an error if `foo' is a v1 CTF file.59*/60static enum {61F_DATA = 0x01, /* show data object section */62F_FUNC = 0x02, /* show function section */63F_HDR = 0x04, /* show header */64F_STR = 0x08, /* show string table */65F_TYPES = 0x10, /* show type section */66F_STATS = 0x20, /* show statistics */67F_LABEL = 0x40, /* show label section */68F_ALL = 0x80, /* explicit request for `all' */69F_ALLMSK = 0xff /* show all sections and statistics */70} flags = 0;7172static struct {73ulong_t s_ndata; /* total number of data objects */74ulong_t s_nfunc; /* total number of functions */75ulong_t s_nargs; /* total number of function arguments */76ulong_t s_argmax; /* longest argument list */77ulong_t s_ntypes; /* total number of types */78ulong_t s_types[16]; /* number of types by kind */79ulong_t s_nsmem; /* total number of struct members */80ulong_t s_nsbytes; /* total size of all structs */81ulong_t s_smmax; /* largest struct in terms of members */82ulong_t s_sbmax; /* largest struct in terms of bytes */83ulong_t s_numem; /* total number of union members */84ulong_t s_nubytes; /* total size of all unions */85ulong_t s_ummax; /* largest union in terms of members */86ulong_t s_ubmax; /* largest union in terms of bytes */87ulong_t s_nemem; /* total number of enum members */88ulong_t s_emmax; /* largest enum in terms of members */89ulong_t s_nstr; /* total number of strings */90size_t s_strlen; /* total length of all strings */91size_t s_strmax; /* longest string length */92} stats;9394typedef struct ctf_data {95caddr_t cd_ctfdata; /* Pointer to the CTF data */96size_t cd_ctflen; /* Length of CTF data */9798size_t cd_idwidth; /* Size of a type ID, in bytes */99100/*101* cd_symdata will be non-NULL if the CTF data is being retrieved from102* an ELF file with a symbol table. cd_strdata and cd_nsyms should be103* used only if cd_symdata is non-NULL.104*/105Elf_Data *cd_symdata; /* Symbol table */106Elf_Data *cd_strdata; /* Symbol table strings */107int cd_nsyms; /* Number of symbol table entries */108} ctf_data_t;109110static const char *111ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd)112{113size_t offset = CTF_NAME_OFFSET(name);114const char *s = cd->cd_ctfdata + hp->cth_stroff + offset;115116if (CTF_NAME_STID(name) != CTF_STRTAB_0)117return ("<< ??? - name in external strtab >>");118119if (offset >= hp->cth_strlen)120return ("<< ??? - name exceeds strlab len >>");121122if (hp->cth_stroff + offset >= cd->cd_ctflen)123return ("<< ??? - file truncated >>");124125if (s[0] == '\0')126return ("(anon)");127128return (s);129}130131static const char *132int_encoding_to_str(uint_t encoding)133{134static char buf[32];135136if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR |137CTF_INT_BOOL | CTF_INT_VARARGS)) != 0)138(void) snprintf(buf, sizeof (buf), " 0x%x", encoding);139else {140buf[0] = '\0';141if (encoding & CTF_INT_SIGNED)142(void) strcat(buf, " SIGNED");143if (encoding & CTF_INT_CHAR)144(void) strcat(buf, " CHAR");145if (encoding & CTF_INT_BOOL)146(void) strcat(buf, " BOOL");147if (encoding & CTF_INT_VARARGS)148(void) strcat(buf, " VARARGS");149}150151return (buf + 1);152}153154static const char *155fp_encoding_to_str(uint_t encoding)156{157static const char *const encs[] = {158NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX",159"LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",160"DIMAGINARY", "LDIMAGINARY"161};162163static char buf[16];164165if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) {166(void) snprintf(buf, sizeof (buf), "%u", encoding);167return (buf);168}169170return (encs[encoding]);171}172173static void174print_line(const char *s)175{176static const char line[] = "----------------------------------------"177"----------------------------------------";178(void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line);179}180181static int182print_header(const ctf_header_t *hp, const ctf_data_t *cd)183{184print_line("- CTF Header ");185186(void) printf(" cth_magic = 0x%04x\n", hp->cth_magic);187(void) printf(" cth_version = %u\n", hp->cth_version);188(void) printf(" cth_flags = 0x%02x\n", hp->cth_flags);189(void) printf(" cth_parlabel = %s\n",190ref_to_str(hp->cth_parlabel, hp, cd));191(void) printf(" cth_parname = %s\n",192ref_to_str(hp->cth_parname, hp, cd));193(void) printf(" cth_lbloff = %u\n", hp->cth_lbloff);194(void) printf(" cth_objtoff = %u\n", hp->cth_objtoff);195(void) printf(" cth_funcoff = %u\n", hp->cth_funcoff);196(void) printf(" cth_typeoff = %u\n", hp->cth_typeoff);197(void) printf(" cth_stroff = %u\n", hp->cth_stroff);198(void) printf(" cth_strlen = %u\n", hp->cth_strlen);199200return (E_SUCCESS);201}202203static int204print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd)205{206void *v = (void *) (cd->cd_ctfdata + hp->cth_lbloff);207const ctf_lblent_t *ctl = v;208ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl);209210print_line("- Label Table ");211212if (hp->cth_lbloff & 3)213WARN("cth_lbloff is not aligned properly\n");214if (hp->cth_lbloff >= cd->cd_ctflen)215WARN("file is truncated or cth_lbloff is corrupt\n");216if (hp->cth_objtoff >= cd->cd_ctflen)217WARN("file is truncated or cth_objtoff is corrupt\n");218if (hp->cth_lbloff > hp->cth_objtoff)219WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");220221for (i = 0; i < n; i++, ctl++) {222(void) printf(" %5u %s\n", ctl->ctl_typeidx,223ref_to_str(ctl->ctl_label, hp, cd));224}225226return (E_SUCCESS);227}228229/*230* Given the current symbol index (-1 to start at the beginning of the symbol231* table) and the type of symbol to match, this function returns the index of232* the next matching symbol (if any), and places the name of that symbol in233* *namep. If no symbol is found, -1 is returned.234*/235static int236next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,237char **namep)238{239int i;240241for (i = symidx + 1; i < cd->cd_nsyms; i++) {242GElf_Sym sym;243char *name;244int type;245246if (gelf_getsym(cd->cd_symdata, i, &sym) == 0)247return (-1);248249name = (char *)cd->cd_strdata->d_buf + sym.st_name;250type = GELF_ST_TYPE(sym.st_info);251252/*253* Skip various types of symbol table entries.254*/255if (type != matchtype || ignore_symbol(&sym, name))256continue;257258/* Found one */259*namep = name;260return (i);261}262263return (-1);264}265266static int267read_data(const ctf_header_t *hp, const ctf_data_t *cd)268{269const char *v = (void *) (cd->cd_ctfdata + hp->cth_objtoff);270ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / cd->cd_idwidth;271272if (flags != F_STATS)273print_line("- Data Objects ");274275if (hp->cth_objtoff & 1)276WARN("cth_objtoff is not aligned properly\n");277if (hp->cth_objtoff >= cd->cd_ctflen)278WARN("file is truncated or cth_objtoff is corrupt\n");279if (hp->cth_funcoff >= cd->cd_ctflen)280WARN("file is truncated or cth_funcoff is corrupt\n");281if (hp->cth_objtoff > hp->cth_funcoff)282WARN("file is corrupt -- cth_objtoff > cth_funcoff\n");283284if (flags != F_STATS) {285int symidx, len, i;286char *name = NULL;287288for (symidx = -1, i = 0; i < (int) n; i++) {289uint32_t id = 0;290int nextsym;291292if (cd->cd_symdata == NULL || (nextsym = next_sym(cd,293symidx, STT_OBJECT, &name)) < 0)294name = NULL;295else296symidx = nextsym;297298memcpy(&id, v, cd->cd_idwidth);299v += cd->cd_idwidth;300len = printf(" [%u] %u", i, id);301if (name != NULL)302(void) printf("%*s%s (%u)", (15 - len), "",303name, symidx);304(void) putchar('\n');305}306}307308stats.s_ndata = n;309return (E_SUCCESS);310}311312static int313read_funcs(const ctf_header_t *hp, const ctf_data_t *cd)314{315const char *v = (void *) (cd->cd_ctfdata + hp->cth_funcoff);316uint_t f = 0, info;317318const char *end = (void *) (cd->cd_ctfdata + hp->cth_typeoff);319320ulong_t id;321int symidx;322323if (flags != F_STATS)324print_line("- Functions ");325326if (hp->cth_funcoff & 1)327WARN("cth_funcoff is not aligned properly\n");328if (hp->cth_funcoff >= cd->cd_ctflen)329WARN("file is truncated or cth_funcoff is corrupt\n");330if (hp->cth_typeoff >= cd->cd_ctflen)331WARN("file is truncated or cth_typeoff is corrupt\n");332if (hp->cth_funcoff > hp->cth_typeoff)333WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");334335for (symidx = -1, id = 0; v < end; id++) {336info = 0;337memcpy(&info, v, cd->cd_idwidth);338v += cd->cd_idwidth;339ushort_t kind = hp->cth_version == CTF_VERSION_2 ?340CTF_V2_INFO_KIND(info) : CTF_V3_INFO_KIND(info);341ushort_t n = hp->cth_version == CTF_VERSION_2 ?342CTF_V2_INFO_VLEN(info) : CTF_V3_INFO_VLEN(info);343ushort_t i;344int nextsym;345char *name;346347if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx,348STT_FUNC, &name)) < 0)349name = NULL;350else351symidx = nextsym;352353if (kind == CTF_K_UNKNOWN && n == 0)354continue; /* skip padding */355356if (kind != CTF_K_FUNCTION) {357(void) printf(" [%lu] unexpected kind -- %u\n",358id, kind);359return (E_ERROR);360}361362if (v + n * cd->cd_idwidth > end) {363(void) printf(" [%lu] vlen %u extends past section "364"boundary\n", id, n);365return (E_ERROR);366}367368if (flags != F_STATS) {369(void) printf(" [%lu] FUNC ", id);370if (name != NULL)371(void) printf("(%s) ", name);372memcpy(&f, v, cd->cd_idwidth);373v += cd->cd_idwidth;374(void) printf("returns: %u args: (", f);375376if (n != 0) {377memcpy(&f, v, cd->cd_idwidth);378v += cd->cd_idwidth;379(void) printf("%u", f);380for (i = 1; i < n; i++) {381memcpy(&f, v, cd->cd_idwidth);382v += cd->cd_idwidth;383(void) printf(", %u", f);384}385}386387(void) printf(")\n");388} else389v += n * cd->cd_idwidth + 1; /* skip to next function definition */390391stats.s_nfunc++;392stats.s_nargs += n;393stats.s_argmax = MAX(stats.s_argmax, n);394}395396return (E_SUCCESS);397}398399static int400read_types(const ctf_header_t *hp, const ctf_data_t *cd)401{402const char *v = (void *) (cd->cd_ctfdata + hp->cth_typeoff);403const char *end = (void *) (cd->cd_ctfdata + hp->cth_stroff);404ulong_t id;405uint_t version;406407if (flags != F_STATS)408print_line("- Types ");409410if (hp->cth_typeoff & 3)411WARN("cth_typeoff is not aligned properly\n");412if (hp->cth_typeoff >= cd->cd_ctflen)413WARN("file is truncated or cth_typeoff is corrupt\n");414if (hp->cth_stroff >= cd->cd_ctflen)415WARN("file is truncated or cth_stroff is corrupt\n");416if (hp->cth_typeoff > hp->cth_stroff)417WARN("file is corrupt -- cth_typeoff > cth_stroff\n");418419version = hp->cth_version;420421id = 1;422if (hp->cth_parlabel || hp->cth_parname)423id += 1ul << (hp->cth_version == CTF_VERSION_2 ?424CTF_V2_PARENT_SHIFT : CTF_V3_PARENT_SHIFT);425426for (/* */; v < end; id++) {427struct ctf_type_v2 t2;428struct ctf_type_v3 t3;429ulong_t i, n;430size_t size, increment, vlen = 0;431uint_t isroot, name, type;432int kind;433434if (version == CTF_VERSION_2) {435memcpy(&t2, v, sizeof(t2));436name = t2.ctt_name;437n = CTF_V2_INFO_VLEN(t2.ctt_info);438isroot = CTF_V2_INFO_ISROOT(t2.ctt_info);439kind = CTF_V2_INFO_KIND(t2.ctt_info);440type = t2.ctt_type;441442if (t2.ctt_size == CTF_V2_LSIZE_SENT) {443increment = sizeof (struct ctf_type_v2);444size = (size_t)CTF_TYPE_LSIZE(&t2);445} else {446increment = sizeof (struct ctf_stype_v2);447size = t2.ctt_size;448}449} else {450memcpy(&t3, v, sizeof(t3));451name = t3.ctt_name;452n = CTF_V3_INFO_VLEN(t3.ctt_info);453isroot = CTF_V3_INFO_ISROOT(t3.ctt_info);454kind = CTF_V3_INFO_KIND(t3.ctt_info);455type = t3.ctt_type;456457if (t3.ctt_size == CTF_V3_LSIZE_SENT) {458increment = sizeof (struct ctf_type_v3);459size = (size_t)CTF_TYPE_LSIZE(&t3);460} else {461increment = sizeof (struct ctf_stype_v3);462size = t3.ctt_size;463}464}465466union {467const char *ptr;468struct ctf_array_v2 *ap2;469struct ctf_array_v3 *ap3;470const struct ctf_member_v2 *mp2;471const struct ctf_member_v3 *mp3;472const struct ctf_lmember_v2 *lmp2;473const struct ctf_lmember_v3 *lmp3;474const ctf_enum_t *ep;475} u;476477u.ptr = v + increment;478479if (flags != F_STATS) {480(void) printf(" %c%lu%c ",481"[<"[isroot], id, "]>"[isroot]);482}483484switch (kind) {485case CTF_K_INTEGER:486if (flags != F_STATS) {487uint_t encoding =488*((const uint_t *)(const void *)u.ptr);489490(void) printf("INTEGER %s encoding=%s offset=%u"491" bits=%u", ref_to_str(name, hp, cd),492int_encoding_to_str(493CTF_INT_ENCODING(encoding)),494CTF_INT_OFFSET(encoding),495CTF_INT_BITS(encoding));496}497vlen = sizeof (uint32_t);498break;499500case CTF_K_FLOAT:501if (flags != F_STATS) {502uint_t encoding =503*((const uint_t *)(const void *)u.ptr);504505(void) printf("FLOAT %s encoding=%s offset=%u "506"bits=%u", ref_to_str(name, hp, cd),507fp_encoding_to_str(508CTF_FP_ENCODING(encoding)),509CTF_FP_OFFSET(encoding),510CTF_FP_BITS(encoding));511}512vlen = sizeof (uint32_t);513break;514515case CTF_K_POINTER:516if (flags != F_STATS) {517(void) printf("POINTER %s refers to %u",518ref_to_str(name, hp, cd), type);519}520break;521522case CTF_K_ARRAY: {523uint_t contents, index, nelems;524525if (version == CTF_VERSION_2) {526contents = u.ap2->cta_contents;527index = u.ap2->cta_index;528nelems = u.ap2->cta_nelems;529} else {530contents = u.ap3->cta_contents;531index = u.ap3->cta_index;532nelems = u.ap3->cta_nelems;533}534if (flags != F_STATS) {535(void) printf("ARRAY %s content: %u index: %u "536"nelems: %u\n", ref_to_str(name, hp, cd),537contents, index, nelems);538}539if (version == 2)540vlen = sizeof (struct ctf_array_v2);541else542vlen = sizeof (struct ctf_array_v3);543break;544}545546case CTF_K_FUNCTION: {547uint_t arg = 0;548549if (flags != F_STATS) {550(void) printf("FUNCTION %s returns: %u args: (",551ref_to_str(name, hp, cd), type);552553if (n != 0) {554memcpy(&arg, u.ptr, cd->cd_idwidth);555u.ptr += cd->cd_idwidth;556(void) printf("%u", arg);557for (i = 1; i < n;558i++, u.ptr += cd->cd_idwidth) {559memcpy(&arg, u.ptr,560cd->cd_idwidth);561(void) printf(", %u", arg);562}563}564565(void) printf(")");566}567568vlen = roundup2(cd->cd_idwidth * n, 4);569break;570}571572case CTF_K_STRUCT:573case CTF_K_UNION:574if (kind == CTF_K_STRUCT) {575stats.s_nsmem += n;576stats.s_smmax = MAX(stats.s_smmax, n);577stats.s_nsbytes += size;578stats.s_sbmax = MAX(stats.s_sbmax, size);579580if (flags != F_STATS)581(void) printf("STRUCT");582} else {583stats.s_numem += n;584stats.s_ummax = MAX(stats.s_ummax, n);585stats.s_nubytes += size;586stats.s_ubmax = MAX(stats.s_ubmax, size);587588if (flags != F_STATS)589(void) printf("UNION");590}591592if (flags != F_STATS) {593(void) printf(" %s (%zd bytes)\n",594ref_to_str(name, hp, cd), size);595596if (version == CTF_VERSION_2) {597if (size >= CTF_V2_LSTRUCT_THRESH) {598for (i = 0; i < n; i++, u.lmp2++) {599(void) printf(600"\t%s type=%u off=%llu\n",601ref_to_str(u.lmp2->ctlm_name,602hp, cd), u.lmp2->ctlm_type,603(unsigned long long)604CTF_LMEM_OFFSET(u.lmp2));605}606} else {607for (i = 0; i < n; i++, u.mp2++) {608(void) printf(609"\t%s type=%u off=%u\n",610ref_to_str(u.mp2->ctm_name,611hp, cd), u.mp2->ctm_type,612u.mp2->ctm_offset);613}614}615} else {616if (size >= CTF_V3_LSTRUCT_THRESH) {617for (i = 0; i < n; i++, u.lmp3++) {618(void) printf(619"\t%s type=%u off=%llu\n",620ref_to_str(u.lmp3->ctlm_name,621hp, cd), u.lmp3->ctlm_type,622(unsigned long long)623CTF_LMEM_OFFSET(u.lmp3));624}625} else {626for (i = 0; i < n; i++, u.mp3++) {627(void) printf(628"\t%s type=%u off=%u\n",629ref_to_str(u.mp3->ctm_name,630hp, cd), u.mp3->ctm_type,631u.mp3->ctm_offset);632}633}634}635}636637if (version == CTF_VERSION_2) {638vlen = n * (size >= CTF_V2_LSTRUCT_THRESH ?639sizeof (struct ctf_lmember_v2) :640sizeof (struct ctf_member_v2));641} else {642vlen = n * (size >= CTF_V3_LSTRUCT_THRESH ?643sizeof (struct ctf_lmember_v3) :644sizeof (struct ctf_member_v3));645}646break;647648case CTF_K_ENUM:649if (flags != F_STATS) {650(void) printf("ENUM %s\n",651ref_to_str(name, hp, cd));652653for (i = 0; i < n; i++, u.ep++) {654(void) printf("\t%s = %d\n",655ref_to_str(u.ep->cte_name, hp, cd),656u.ep->cte_value);657}658}659660stats.s_nemem += n;661stats.s_emmax = MAX(stats.s_emmax, n);662663vlen = sizeof (ctf_enum_t) * n;664break;665666case CTF_K_FORWARD:667if (flags != F_STATS) {668(void) printf("FORWARD %s",669ref_to_str(name, hp, cd));670}671break;672673case CTF_K_TYPEDEF:674if (flags != F_STATS) {675(void) printf("TYPEDEF %s refers to %u",676ref_to_str(name, hp, cd), type);677}678break;679680case CTF_K_VOLATILE:681if (flags != F_STATS) {682(void) printf("VOLATILE %s refers to %u",683ref_to_str(name, hp, cd), type);684}685break;686687case CTF_K_CONST:688if (flags != F_STATS) {689(void) printf("CONST %s refers to %u",690ref_to_str(name, hp, cd), type);691}692break;693694case CTF_K_RESTRICT:695if (flags != F_STATS) {696(void) printf("RESTRICT %s refers to %u",697ref_to_str(name, hp, cd), type);698}699break;700701case CTF_K_UNKNOWN:702break; /* hole in type id space */703704default:705(void) printf("unexpected kind %u\n", kind);706return (E_ERROR);707}708709if (flags != F_STATS)710(void) printf("\n");711712stats.s_ntypes++;713stats.s_types[kind]++;714715v += increment + vlen;716}717718return (E_SUCCESS);719}720721static int722read_strtab(const ctf_header_t *hp, const ctf_data_t *cd)723{724size_t n, off, len = hp->cth_strlen;725const char *s = cd->cd_ctfdata + hp->cth_stroff;726727if (flags != F_STATS)728print_line("- String Table ");729730if (hp->cth_stroff >= cd->cd_ctflen)731WARN("file is truncated or cth_stroff is corrupt\n");732if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen)733WARN("file is truncated or cth_strlen is corrupt\n");734735for (off = 0; len != 0; off += n) {736if (flags != F_STATS) {737(void) printf(" [%lu] %s\n", (ulong_t)off,738s[0] == '\0' ? "\\0" : s);739}740n = strlen(s) + 1;741len -= n;742s += n;743744stats.s_nstr++;745stats.s_strlen += n;746stats.s_strmax = MAX(stats.s_strmax, n);747}748749return (E_SUCCESS);750}751752static void753long_stat(const char *name, ulong_t value)754{755(void) printf(" %-36s= %lu\n", name, value);756}757758static void759fp_stat(const char *name, float value)760{761(void) printf(" %-36s= %.2f\n", name, value);762}763764static int765print_stats(void)766{767print_line("- CTF Statistics ");768769long_stat("total number of data objects", stats.s_ndata);770(void) printf("\n");771772long_stat("total number of functions", stats.s_nfunc);773long_stat("total number of function arguments", stats.s_nargs);774long_stat("maximum argument list length", stats.s_argmax);775776if (stats.s_nfunc != 0) {777fp_stat("average argument list length",778(float)stats.s_nargs / (float)stats.s_nfunc);779}780781(void) printf("\n");782783long_stat("total number of types", stats.s_ntypes);784long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]);785long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]);786long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]);787long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]);788long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]);789long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]);790long_stat("total number of unions", stats.s_types[CTF_K_UNION]);791long_stat("total number of enums", stats.s_types[CTF_K_ENUM]);792long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]);793long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]);794long_stat("total number of volatile types",795stats.s_types[CTF_K_VOLATILE]);796long_stat("total number of const types", stats.s_types[CTF_K_CONST]);797long_stat("total number of restrict types",798stats.s_types[CTF_K_RESTRICT]);799long_stat("total number of unknowns (holes)",800stats.s_types[CTF_K_UNKNOWN]);801802(void) printf("\n");803804long_stat("total number of struct members", stats.s_nsmem);805long_stat("maximum number of struct members", stats.s_smmax);806long_stat("total size of all structs", stats.s_nsbytes);807long_stat("maximum size of a struct", stats.s_sbmax);808809if (stats.s_types[CTF_K_STRUCT] != 0) {810fp_stat("average number of struct members",811(float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]);812fp_stat("average size of a struct", (float)stats.s_nsbytes /813(float)stats.s_types[CTF_K_STRUCT]);814}815816(void) printf("\n");817818long_stat("total number of union members", stats.s_numem);819long_stat("maximum number of union members", stats.s_ummax);820long_stat("total size of all unions", stats.s_nubytes);821long_stat("maximum size of a union", stats.s_ubmax);822823if (stats.s_types[CTF_K_UNION] != 0) {824fp_stat("average number of union members",825(float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]);826fp_stat("average size of a union", (float)stats.s_nubytes /827(float)stats.s_types[CTF_K_UNION]);828}829830(void) printf("\n");831832long_stat("total number of enum members", stats.s_nemem);833long_stat("maximum number of enum members", stats.s_emmax);834835if (stats.s_types[CTF_K_ENUM] != 0) {836fp_stat("average number of enum members",837(float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]);838}839840(void) printf("\n");841842long_stat("total number of unique strings", stats.s_nstr);843long_stat("bytes of string data", stats.s_strlen);844long_stat("maximum string length", stats.s_strmax);845846if (stats.s_nstr != 0) {847fp_stat("average string length",848(float)stats.s_strlen / (float)stats.s_nstr);849}850851(void) printf("\n");852return (E_SUCCESS);853}854855static int856print_usage(FILE *fp, int verbose)857{858(void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getprogname());859860if (verbose) {861(void) fprintf(fp,862"\t-d dump data object section\n"863"\t-f dump function section\n"864"\t-h dump file header\n"865"\t-l dump label table\n"866"\t-s dump string table\n"867"\t-S dump statistics\n"868"\t-t dump type section\n"869"\t-u save uncompressed CTF to a file\n");870}871872return (E_USAGE);873}874875static Elf_Scn *876findelfscn(Elf *elf, GElf_Ehdr *ehdr, const char *secname)877{878GElf_Shdr shdr;879Elf_Scn *scn;880char *name;881882for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) {883if (gelf_getshdr(scn, &shdr) != NULL && (name =884elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL &&885strcmp(name, secname) == 0)886return (scn);887}888889return (NULL);890}891892int893main(int argc, char *argv[])894{895const char *filename = NULL;896const char *ufile = NULL;897int error = 0;898int c, fd, ufd;899900ctf_data_t cd;901const ctf_preamble_t *pp;902ctf_header_t *hp = NULL;903Elf *elf;904GElf_Ehdr ehdr;905906(void) elf_version(EV_CURRENT);907908for (opterr = 0; optind < argc; optind++) {909while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) {910switch (c) {911case 'd':912flags |= F_DATA;913break;914case 'f':915flags |= F_FUNC;916break;917case 'h':918flags |= F_HDR;919break;920case 'l':921flags |= F_LABEL;922break;923case 's':924flags |= F_STR;925break;926case 'S':927flags |= F_STATS;928break;929case 't':930flags |= F_TYPES;931break;932case 'u':933ufile = optarg;934break;935default:936if (optopt == '?')937return (print_usage(stdout, 1));938warn("illegal option -- %c\n", optopt);939return (print_usage(stderr, 0));940}941}942943if (optind < argc) {944if (filename != NULL)945return (print_usage(stderr, 0));946filename = argv[optind];947}948}949950if (filename == NULL)951return (print_usage(stderr, 0));952953if (flags == 0 && ufile == NULL)954flags = F_ALLMSK;955956if ((fd = open(filename, O_RDONLY)) == -1)957die("failed to open %s", filename);958959if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL &&960gelf_getehdr(elf, &ehdr) != NULL) {961962Elf_Data *dp = NULL;963Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf");964Elf_Scn *symscn;965GElf_Shdr ctfshdr;966967if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL)968die("%s does not contain .SUNW_ctf data\n", filename);969970cd.cd_ctfdata = dp->d_buf;971cd.cd_ctflen = dp->d_size;972973/*974* If the sh_link field of the CTF section header is non-zero975* it indicates which section contains the symbol table that976* should be used. We default to the .symtab section if sh_link977* is zero or if there's an error reading the section header.978*/979if (gelf_getshdr(ctfscn, &ctfshdr) != NULL &&980ctfshdr.sh_link != 0) {981symscn = elf_getscn(elf, ctfshdr.sh_link);982} else {983symscn = findelfscn(elf, &ehdr, ".symtab");984}985986/* If we found a symbol table, find the corresponding strings */987if (symscn != NULL) {988GElf_Shdr shdr;989Elf_Scn *symstrscn;990991if (gelf_getshdr(symscn, &shdr) != NULL) {992symstrscn = elf_getscn(elf, shdr.sh_link);993994cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;995cd.cd_symdata = elf_getdata(symscn, NULL);996cd.cd_strdata = elf_getdata(symstrscn, NULL);997}998}999} else {1000struct stat st;10011002if (fstat(fd, &st) == -1)1003die("failed to fstat %s", filename);10041005cd.cd_ctflen = st.st_size;1006cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ,1007MAP_PRIVATE, fd, 0);1008if (cd.cd_ctfdata == MAP_FAILED)1009die("failed to mmap %s", filename);1010}10111012/*1013* Get a pointer to the CTF data buffer and interpret the first portion1014* as a ctf_header_t. Validate the magic number and size.1015*/10161017if (cd.cd_ctflen < sizeof (ctf_preamble_t))1018die("%s does not contain a CTF preamble\n", filename);10191020void *v = (void *) cd.cd_ctfdata;1021pp = v;10221023if (pp->ctp_magic != CTF_MAGIC)1024die("%s does not appear to contain CTF data\n", filename);10251026if (pp->ctp_version >= CTF_VERSION_2) {1027v = (void *) cd.cd_ctfdata;1028hp = v;1029cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t);10301031cd.cd_idwidth = pp->ctp_version == CTF_VERSION_2 ? 2 : 4;10321033if (cd.cd_ctflen < sizeof (ctf_header_t)) {1034die("%s does not contain a v%d CTF header\n", filename,1035pp->ctp_version);1036}10371038} else {1039die("%s contains unsupported CTF version %d\n", filename,1040pp->ctp_version);1041}10421043/*1044* If the data buffer is compressed, then malloc a buffer large enough1045* to hold the decompressed data, and use zlib to decompress it.1046*/1047if (hp->cth_flags & CTF_F_COMPRESS) {1048z_stream zstr;1049void *buf;1050int rc;10511052if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL)1053die("failed to allocate decompression buffer");10541055bzero(&zstr, sizeof (z_stream));1056zstr.next_in = (void *)cd.cd_ctfdata;1057zstr.avail_in = cd.cd_ctflen;1058zstr.next_out = buf;1059zstr.avail_out = hp->cth_stroff + hp->cth_strlen;10601061if ((rc = inflateInit(&zstr)) != Z_OK)1062die("failed to initialize zlib: %s\n", zError(rc));10631064if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END)1065die("failed to decompress CTF data: %s\n", zError(rc));10661067if ((rc = inflateEnd(&zstr)) != Z_OK)1068die("failed to finish decompression: %s\n", zError(rc));10691070if (zstr.total_out != hp->cth_stroff + hp->cth_strlen)1071die("CTF data is corrupt -- short decompression\n");10721073cd.cd_ctfdata = buf;1074cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen;1075}10761077if (flags & F_HDR)1078error |= print_header(hp, &cd);1079if (flags & (F_LABEL))1080error |= print_labeltable(hp, &cd);1081if (flags & (F_DATA | F_STATS))1082error |= read_data(hp, &cd);1083if (flags & (F_FUNC | F_STATS))1084error |= read_funcs(hp, &cd);1085if (flags & (F_TYPES | F_STATS))1086error |= read_types(hp, &cd);1087if (flags & (F_STR | F_STATS))1088error |= read_strtab(hp, &cd);1089if (flags & F_STATS)1090error |= print_stats();10911092/*1093* If the -u option is specified, write the uncompressed CTF data to a1094* raw CTF file. CTF data can already be extracted compressed by1095* applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.1096*/1097if (ufile != NULL) {1098ctf_header_t h;10991100bcopy(hp, &h, sizeof (h));1101h.cth_flags &= ~CTF_F_COMPRESS;11021103if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 ||1104write(ufd, &h, sizeof (h)) != sizeof (h) ||1105write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != (int) cd.cd_ctflen) {1106warn("failed to write CTF data to '%s'", ufile);1107error |= E_ERROR;1108}11091110(void) close(ufd);1111}11121113if (elf != NULL)1114(void) elf_end(elf);11151116(void) close(fd);1117return (error);1118}111911201121