diff options
Diffstat (limited to 'usr/src/tools/ctf/dump/dump.c')
-rw-r--r-- | usr/src/tools/ctf/dump/dump.c | 1028 |
1 files changed, 0 insertions, 1028 deletions
diff --git a/usr/src/tools/ctf/dump/dump.c b/usr/src/tools/ctf/dump/dump.c deleted file mode 100644 index 5579bae596..0000000000 --- a/usr/src/tools/ctf/dump/dump.c +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/sysmacros.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include <strings.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <gelf.h> -#include <zlib.h> - -#include "ctf_headers.h" -#include "utils.h" -#include "symbol.h" - -#define WARN(x) { warn(x); return (E_ERROR); } - -/* - * Flags that indicate what data is to be displayed. An explicit `all' value is - * provided to allow the code to distinguish between a request for everything - * (currently requested by invoking ctfdump without flags) and individual - * requests for all of the types of data (an invocation with all flags). In the - * former case, we want to be able to implicitly adjust the definition of `all' - * based on the CTF version of the file being dumped. For example, if a v2 file - * is being dumped, `all' includes F_LABEL - a request to dump the label - * section. If a v1 file is being dumped, `all' does not include F_LABEL, - * because v1 CTF doesn't support labels. We need to be able to distinguish - * between `ctfdump foo', which has an implicit request for labels if `foo' - * supports them, and `ctfdump -l foo', which has an explicity request. In the - * latter case, we exit with an error if `foo' is a v1 CTF file. - */ -static enum { - F_DATA = 0x01, /* show data object section */ - F_FUNC = 0x02, /* show function section */ - F_HDR = 0x04, /* show header */ - F_STR = 0x08, /* show string table */ - F_TYPES = 0x10, /* show type section */ - F_STATS = 0x20, /* show statistics */ - F_LABEL = 0x40, /* show label section */ - F_ALL = 0x80, /* explicit request for `all' */ - F_ALLMSK = 0xff /* show all sections and statistics */ -} flags = 0; - -static struct { - ulong_t s_ndata; /* total number of data objects */ - ulong_t s_nfunc; /* total number of functions */ - ulong_t s_nargs; /* total number of function arguments */ - ulong_t s_argmax; /* longest argument list */ - ulong_t s_ntypes; /* total number of types */ - ulong_t s_types[16]; /* number of types by kind */ - ulong_t s_nsmem; /* total number of struct members */ - ulong_t s_nsbytes; /* total size of all structs */ - ulong_t s_smmax; /* largest struct in terms of members */ - ulong_t s_sbmax; /* largest struct in terms of bytes */ - ulong_t s_numem; /* total number of union members */ - ulong_t s_nubytes; /* total size of all unions */ - ulong_t s_ummax; /* largest union in terms of members */ - ulong_t s_ubmax; /* largest union in terms of bytes */ - ulong_t s_nemem; /* total number of enum members */ - ulong_t s_emmax; /* largest enum in terms of members */ - ulong_t s_nstr; /* total number of strings */ - size_t s_strlen; /* total length of all strings */ - size_t s_strmax; /* longest string length */ -} stats; - -typedef struct ctf_data { - caddr_t cd_ctfdata; /* Pointer to the CTF data */ - size_t cd_ctflen; /* Length of CTF data */ - - /* - * cd_symdata will be non-NULL if the CTF data is being retrieved from - * an ELF file with a symbol table. cd_strdata and cd_nsyms should be - * used only if cd_symdata is non-NULL. - */ - Elf_Data *cd_symdata; /* Symbol table */ - Elf_Data *cd_strdata; /* Symbol table strings */ - int cd_nsyms; /* Number of symbol table entries */ -} ctf_data_t; - -static const char * -ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd) -{ - size_t offset = CTF_NAME_OFFSET(name); - const char *s = cd->cd_ctfdata + hp->cth_stroff + offset; - - if (CTF_NAME_STID(name) != CTF_STRTAB_0) - return ("<< ??? - name in external strtab >>"); - - if (offset >= hp->cth_strlen) - return ("<< ??? - name exceeds strlab len >>"); - - if (hp->cth_stroff + offset >= cd->cd_ctflen) - return ("<< ??? - file truncated >>"); - - if (s[0] == '\0') - return ("(anon)"); - - return (s); -} - -static const char * -int_encoding_to_str(uint_t encoding) -{ - static char buf[32]; - - if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR | - CTF_INT_BOOL | CTF_INT_VARARGS)) != 0) - (void) snprintf(buf, sizeof (buf), " 0x%x", encoding); - else { - buf[0] = '\0'; - if (encoding & CTF_INT_SIGNED) - (void) strcat(buf, " SIGNED"); - if (encoding & CTF_INT_CHAR) - (void) strcat(buf, " CHAR"); - if (encoding & CTF_INT_BOOL) - (void) strcat(buf, " BOOL"); - if (encoding & CTF_INT_VARARGS) - (void) strcat(buf, " VARARGS"); - } - - return (buf + 1); -} - -static const char * -fp_encoding_to_str(uint_t encoding) -{ - static const char *const encs[] = { - NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX", - "LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY", - "DIMAGINARY", "LDIMAGINARY" - }; - - static char buf[16]; - - if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) { - (void) snprintf(buf, sizeof (buf), "%u", encoding); - return (buf); - } - - return (encs[encoding]); -} - -static void -print_line(const char *s) -{ - static const char line[] = "----------------------------------------" - "----------------------------------------"; - (void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line); -} - -static int -print_header(const ctf_header_t *hp, const ctf_data_t *cd) -{ - print_line("- CTF Header "); - - (void) printf(" cth_magic = 0x%04x\n", hp->cth_magic); - (void) printf(" cth_version = %u\n", hp->cth_version); - (void) printf(" cth_flags = 0x%02x\n", hp->cth_flags); - (void) printf(" cth_parlabel = %s\n", - ref_to_str(hp->cth_parlabel, hp, cd)); - (void) printf(" cth_parname = %s\n", - ref_to_str(hp->cth_parname, hp, cd)); - (void) printf(" cth_lbloff = %u\n", hp->cth_lbloff); - (void) printf(" cth_objtoff = %u\n", hp->cth_objtoff); - (void) printf(" cth_funcoff = %u\n", hp->cth_funcoff); - (void) printf(" cth_typeoff = %u\n", hp->cth_typeoff); - (void) printf(" cth_stroff = %u\n", hp->cth_stroff); - (void) printf(" cth_strlen = %u\n", hp->cth_strlen); - - return (E_SUCCESS); -} - -static int -print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd) -{ - /* LINTED - pointer alignment */ - const ctf_lblent_t *ctl = (ctf_lblent_t *)(cd->cd_ctfdata + - hp->cth_lbloff); - ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl); - - print_line("- Label Table "); - - if (hp->cth_lbloff & 3) - WARN("cth_lbloff is not aligned properly\n"); - if (hp->cth_lbloff >= cd->cd_ctflen) - WARN("file is truncated or cth_lbloff is corrupt\n"); - if (hp->cth_objtoff >= cd->cd_ctflen) - WARN("file is truncated or cth_objtoff is corrupt\n"); - if (hp->cth_lbloff > hp->cth_objtoff) - WARN("file is corrupt -- cth_lbloff > cth_objtoff\n"); - - for (i = 0; i < n; i++, ctl++) { - (void) printf(" %5u %s\n", ctl->ctl_typeidx, - ref_to_str(ctl->ctl_label, hp, cd)); - } - - return (E_SUCCESS); -} - -/* - * Given the current symbol index (-1 to start at the beginning of the symbol - * table) and the type of symbol to match, this function returns the index of - * the next matching symbol (if any), and places the name of that symbol in - * *namep. If no symbol is found, -1 is returned. - */ -static int -next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype, - char **namep) -{ - int i; - - for (i = symidx + 1; i < cd->cd_nsyms; i++) { - GElf_Sym sym; - char *name; - int type; - - if (gelf_getsym(cd->cd_symdata, i, &sym) == 0) - return (-1); - - name = (char *)cd->cd_strdata->d_buf + sym.st_name; - type = GELF_ST_TYPE(sym.st_info); - - /* - * Skip various types of symbol table entries. - */ - if (type != matchtype || ignore_symbol(&sym, name)) - continue; - - /* Found one */ - *namep = name; - return (i); - } - - return (-1); -} - -static int -read_data(const ctf_header_t *hp, const ctf_data_t *cd) -{ - /* LINTED - pointer alignment */ - const ushort_t *idp = (ushort_t *)(cd->cd_ctfdata + hp->cth_objtoff); - ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / sizeof (ushort_t); - - if (flags != F_STATS) - print_line("- Data Objects "); - - if (hp->cth_objtoff & 1) - WARN("cth_objtoff is not aligned properly\n"); - if (hp->cth_objtoff >= cd->cd_ctflen) - WARN("file is truncated or cth_objtoff is corrupt\n"); - if (hp->cth_funcoff >= cd->cd_ctflen) - WARN("file is truncated or cth_funcoff is corrupt\n"); - if (hp->cth_objtoff > hp->cth_funcoff) - WARN("file is corrupt -- cth_objtoff > cth_funcoff\n"); - - if (flags != F_STATS) { - int symidx, len, i; - char *name = NULL; - - for (symidx = -1, i = 0; i < n; i++) { - int nextsym; - - if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, - symidx, STT_OBJECT, &name)) < 0) - name = NULL; - else - symidx = nextsym; - - len = printf(" [%u] %u", i, *idp++); - if (name != NULL) - (void) printf("%*s%s (%u)", (15 - len), "", - name, symidx); - (void) putchar('\n'); - } - } - - stats.s_ndata = n; - return (E_SUCCESS); -} - -static int -read_funcs(const ctf_header_t *hp, const ctf_data_t *cd) -{ - /* LINTED - pointer alignment */ - const ushort_t *fp = (ushort_t *)(cd->cd_ctfdata + hp->cth_funcoff); - - /* LINTED - pointer alignment */ - const ushort_t *end = (ushort_t *)(cd->cd_ctfdata + hp->cth_typeoff); - - ulong_t id; - int symidx; - - if (flags != F_STATS) - print_line("- Functions "); - - if (hp->cth_funcoff & 1) - WARN("cth_funcoff is not aligned properly\n"); - if (hp->cth_funcoff >= cd->cd_ctflen) - WARN("file is truncated or cth_funcoff is corrupt\n"); - if (hp->cth_typeoff >= cd->cd_ctflen) - WARN("file is truncated or cth_typeoff is corrupt\n"); - if (hp->cth_funcoff > hp->cth_typeoff) - WARN("file is corrupt -- cth_funcoff > cth_typeoff\n"); - - for (symidx = -1, id = 0; fp < end; id++) { - ushort_t info = *fp++; - ushort_t kind = CTF_INFO_KIND(info); - ushort_t n = CTF_INFO_VLEN(info); - ushort_t i; - int nextsym; - char *name; - - if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx, - STT_FUNC, &name)) < 0) - name = NULL; - else - symidx = nextsym; - - if (kind == CTF_K_UNKNOWN && n == 0) - continue; /* skip padding */ - - if (kind != CTF_K_FUNCTION) { - (void) printf(" [%lu] unexpected kind -- %u\n", - id, kind); - return (E_ERROR); - } - - if (fp + n > end) { - (void) printf(" [%lu] vlen %u extends past section " - "boundary\n", id, n); - return (E_ERROR); - } - - if (flags != F_STATS) { - (void) printf(" [%lu] FUNC ", id); - if (name != NULL) - (void) printf("(%s) ", name); - (void) printf("returns: %u args: (", *fp++); - - if (n != 0) { - (void) printf("%u", *fp++); - for (i = 1; i < n; i++) - (void) printf(", %u", *fp++); - } - - (void) printf(")\n"); - } else - fp += n + 1; /* skip to next function definition */ - - stats.s_nfunc++; - stats.s_nargs += n; - stats.s_argmax = MAX(stats.s_argmax, n); - } - - return (E_SUCCESS); -} - -static int -read_types(const ctf_header_t *hp, const ctf_data_t *cd) -{ - /* LINTED - pointer alignment */ - const ctf_type_t *tp = (ctf_type_t *)(cd->cd_ctfdata + hp->cth_typeoff); - - /* LINTED - pointer alignment */ - const ctf_type_t *end = (ctf_type_t *)(cd->cd_ctfdata + hp->cth_stroff); - - ulong_t id; - - if (flags != F_STATS) - print_line("- Types "); - - if (hp->cth_typeoff & 3) - WARN("cth_typeoff is not aligned properly\n"); - if (hp->cth_typeoff >= cd->cd_ctflen) - WARN("file is truncated or cth_typeoff is corrupt\n"); - if (hp->cth_stroff >= cd->cd_ctflen) - WARN("file is truncated or cth_stroff is corrupt\n"); - if (hp->cth_typeoff > hp->cth_stroff) - WARN("file is corrupt -- cth_typeoff > cth_stroff\n"); - - id = 1; - if (hp->cth_parlabel || hp->cth_parname) - id += 1 << CTF_PARENT_SHIFT; - - for (/* */; tp < end; id++) { - ulong_t i, n = CTF_INFO_VLEN(tp->ctt_info); - size_t size, increment, vlen = 0; - int kind = CTF_INFO_KIND(tp->ctt_info); - - union { - const void *ptr; - const ctf_array_t *ap; - const ctf_member_t *mp; - const ctf_lmember_t *lmp; - const ctf_enum_t *ep; - const ushort_t *argp; - } u; - - if (flags != F_STATS) { - (void) printf(" %c%lu%c ", - "[<"[CTF_INFO_ISROOT(tp->ctt_info)], id, - "]>"[CTF_INFO_ISROOT(tp->ctt_info)]); - } - - if (tp->ctt_size == CTF_LSIZE_SENT) { - increment = sizeof (ctf_type_t); - size = (size_t)CTF_TYPE_LSIZE(tp); - } else { - increment = sizeof (ctf_stype_t); - size = tp->ctt_size; - } - u.ptr = (caddr_t)tp + increment; - - switch (kind) { - case CTF_K_INTEGER: - if (flags != F_STATS) { - uint_t encoding = *((const uint_t *)u.ptr); - - (void) printf("INTEGER %s encoding=%s offset=%u" - " bits=%u", ref_to_str(tp->ctt_name, hp, - cd), int_encoding_to_str( - CTF_INT_ENCODING(encoding)), - CTF_INT_OFFSET(encoding), - CTF_INT_BITS(encoding)); - } - vlen = sizeof (uint_t); - break; - - case CTF_K_FLOAT: - if (flags != F_STATS) { - uint_t encoding = *((const uint_t *)u.ptr); - - (void) printf("FLOAT %s encoding=%s offset=%u " - "bits=%u", ref_to_str(tp->ctt_name, hp, - cd), fp_encoding_to_str( - CTF_FP_ENCODING(encoding)), - CTF_FP_OFFSET(encoding), - CTF_FP_BITS(encoding)); - } - vlen = sizeof (uint_t); - break; - - case CTF_K_POINTER: - if (flags != F_STATS) { - (void) printf("POINTER %s refers to %u", - ref_to_str(tp->ctt_name, hp, cd), - tp->ctt_type); - } - break; - - case CTF_K_ARRAY: - if (flags != F_STATS) { - (void) printf("ARRAY %s content: %u index: %u " - "nelems: %u\n", ref_to_str(tp->ctt_name, - hp, cd), u.ap->cta_contents, - u.ap->cta_index, u.ap->cta_nelems); - } - vlen = sizeof (ctf_array_t); - break; - - case CTF_K_FUNCTION: - if (flags != F_STATS) { - (void) printf("FUNCTION %s returns: %u args: (", - ref_to_str(tp->ctt_name, hp, cd), - tp->ctt_type); - - if (n != 0) { - (void) printf("%u", *u.argp++); - for (i = 1; i < n; i++, u.argp++) - (void) printf(", %u", *u.argp); - } - - (void) printf(")"); - } - - vlen = sizeof (ushort_t) * (n + (n & 1)); - break; - - case CTF_K_STRUCT: - case CTF_K_UNION: - if (kind == CTF_K_STRUCT) { - stats.s_nsmem += n; - stats.s_smmax = MAX(stats.s_smmax, n); - stats.s_nsbytes += size; - stats.s_sbmax = MAX(stats.s_sbmax, size); - - if (flags != F_STATS) - (void) printf("STRUCT"); - } else { - stats.s_numem += n; - stats.s_ummax = MAX(stats.s_ummax, n); - stats.s_nubytes += size; - stats.s_ubmax = MAX(stats.s_ubmax, size); - - if (flags != F_STATS) - (void) printf("UNION"); - } - - if (flags != F_STATS) { - (void) printf(" %s (%d bytes)\n", - ref_to_str(tp->ctt_name, hp, cd), size); - - if (size >= CTF_LSTRUCT_THRESH) { - for (i = 0; i < n; i++, u.lmp++) { - (void) printf( - "\t%s type=%u off=%llu\n", - ref_to_str(u.lmp->ctlm_name, - hp, cd), u.lmp->ctlm_type, - CTF_LMEM_OFFSET(u.lmp)); - } - } else { - for (i = 0; i < n; i++, u.mp++) { - (void) printf( - "\t%s type=%u off=%u\n", - ref_to_str(u.mp->ctm_name, - hp, cd), u.mp->ctm_type, - u.mp->ctm_offset); - } - } - } - - vlen = n * (size >= CTF_LSTRUCT_THRESH ? - sizeof (ctf_lmember_t) : sizeof (ctf_member_t)); - break; - - case CTF_K_ENUM: - if (flags != F_STATS) { - (void) printf("ENUM %s\n", - ref_to_str(tp->ctt_name, hp, cd)); - - for (i = 0; i < n; i++, u.ep++) { - (void) printf("\t%s = %d\n", - ref_to_str(u.ep->cte_name, hp, cd), - u.ep->cte_value); - } - } - - stats.s_nemem += n; - stats.s_emmax = MAX(stats.s_emmax, n); - - vlen = sizeof (ctf_enum_t) * n; - break; - - case CTF_K_FORWARD: - if (flags != F_STATS) { - (void) printf("FORWARD %s", - ref_to_str(tp->ctt_name, hp, cd)); - } - break; - - case CTF_K_TYPEDEF: - if (flags != F_STATS) { - (void) printf("TYPEDEF %s refers to %u", - ref_to_str(tp->ctt_name, hp, cd), - tp->ctt_type); - } - break; - - case CTF_K_VOLATILE: - if (flags != F_STATS) { - (void) printf("VOLATILE %s refers to %u", - ref_to_str(tp->ctt_name, hp, cd), - tp->ctt_type); - } - break; - - case CTF_K_CONST: - if (flags != F_STATS) { - (void) printf("CONST %s refers to %u", - ref_to_str(tp->ctt_name, hp, cd), - tp->ctt_type); - } - break; - - case CTF_K_RESTRICT: - if (flags != F_STATS) { - (void) printf("RESTRICT %s refers to %u", - ref_to_str(tp->ctt_name, hp, cd), - tp->ctt_type); - } - break; - - case CTF_K_UNKNOWN: - break; /* hole in type id space */ - - default: - (void) printf("unexpected kind %u\n", kind); - return (E_ERROR); - } - - if (flags != F_STATS) - (void) printf("\n"); - - stats.s_ntypes++; - stats.s_types[kind]++; - - tp = (ctf_type_t *)((uintptr_t)tp + increment + vlen); - } - - return (E_SUCCESS); -} - -static int -read_strtab(const ctf_header_t *hp, const ctf_data_t *cd) -{ - size_t n, off, len = hp->cth_strlen; - const char *s = cd->cd_ctfdata + hp->cth_stroff; - - if (flags != F_STATS) - print_line("- String Table "); - - if (hp->cth_stroff >= cd->cd_ctflen) - WARN("file is truncated or cth_stroff is corrupt\n"); - if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen) - WARN("file is truncated or cth_strlen is corrupt\n"); - - for (off = 0; len != 0; off += n) { - if (flags != F_STATS) { - (void) printf(" [%lu] %s\n", (ulong_t)off, - s[0] == '\0' ? "\\0" : s); - } - n = strlen(s) + 1; - len -= n; - s += n; - - stats.s_nstr++; - stats.s_strlen += n; - stats.s_strmax = MAX(stats.s_strmax, n); - } - - return (E_SUCCESS); -} - -static void -long_stat(const char *name, ulong_t value) -{ - (void) printf(" %-36s= %lu\n", name, value); -} - -static void -fp_stat(const char *name, float value) -{ - (void) printf(" %-36s= %.2f\n", name, value); -} - -static int -print_stats(void) -{ - print_line("- CTF Statistics "); - - long_stat("total number of data objects", stats.s_ndata); - (void) printf("\n"); - - long_stat("total number of functions", stats.s_nfunc); - long_stat("total number of function arguments", stats.s_nargs); - long_stat("maximum argument list length", stats.s_argmax); - - if (stats.s_nfunc != 0) { - fp_stat("average argument list length", - (float)stats.s_nargs / (float)stats.s_nfunc); - } - - (void) printf("\n"); - - long_stat("total number of types", stats.s_ntypes); - long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]); - long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]); - long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]); - long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]); - long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]); - long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]); - long_stat("total number of unions", stats.s_types[CTF_K_UNION]); - long_stat("total number of enums", stats.s_types[CTF_K_ENUM]); - long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]); - long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]); - long_stat("total number of volatile types", - stats.s_types[CTF_K_VOLATILE]); - long_stat("total number of const types", stats.s_types[CTF_K_CONST]); - long_stat("total number of restrict types", - stats.s_types[CTF_K_RESTRICT]); - long_stat("total number of unknowns (holes)", - stats.s_types[CTF_K_UNKNOWN]); - - (void) printf("\n"); - - long_stat("total number of struct members", stats.s_nsmem); - long_stat("maximum number of struct members", stats.s_smmax); - long_stat("total size of all structs", stats.s_nsbytes); - long_stat("maximum size of a struct", stats.s_sbmax); - - if (stats.s_types[CTF_K_STRUCT] != 0) { - fp_stat("average number of struct members", - (float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]); - fp_stat("average size of a struct", (float)stats.s_nsbytes / - (float)stats.s_types[CTF_K_STRUCT]); - } - - (void) printf("\n"); - - long_stat("total number of union members", stats.s_numem); - long_stat("maximum number of union members", stats.s_ummax); - long_stat("total size of all unions", stats.s_nubytes); - long_stat("maximum size of a union", stats.s_ubmax); - - if (stats.s_types[CTF_K_UNION] != 0) { - fp_stat("average number of union members", - (float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]); - fp_stat("average size of a union", (float)stats.s_nubytes / - (float)stats.s_types[CTF_K_UNION]); - } - - (void) printf("\n"); - - long_stat("total number of enum members", stats.s_nemem); - long_stat("maximum number of enum members", stats.s_emmax); - - if (stats.s_types[CTF_K_ENUM] != 0) { - fp_stat("average number of enum members", - (float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]); - } - - (void) printf("\n"); - - long_stat("total number of unique strings", stats.s_nstr); - long_stat("bytes of string data", stats.s_strlen); - long_stat("maximum string length", stats.s_strmax); - - if (stats.s_nstr != 0) { - fp_stat("average string length", - (float)stats.s_strlen / (float)stats.s_nstr); - } - - (void) printf("\n"); - return (E_SUCCESS); -} - -static int -print_usage(FILE *fp, int verbose) -{ - (void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getpname()); - - if (verbose) { - (void) fprintf(fp, - "\t-d dump data object section\n" - "\t-f dump function section\n" - "\t-h dump file header\n" - "\t-l dump label table\n" - "\t-s dump string table\n" - "\t-S dump statistics\n" - "\t-t dump type section\n" - "\t-u save uncompressed CTF to a file\n"); - } - - return (E_USAGE); -} - -static Elf_Scn * -findelfscn(Elf *elf, GElf_Ehdr *ehdr, char *secname) -{ - GElf_Shdr shdr; - Elf_Scn *scn; - char *name; - - for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) { - if (gelf_getshdr(scn, &shdr) != NULL && (name = - elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL && - strcmp(name, secname) == 0) - return (scn); - } - - return (NULL); -} - -int -main(int argc, char *argv[]) -{ - const char *filename = NULL; - const char *ufile = NULL; - int error = 0; - int c, fd, ufd; - - ctf_data_t cd; - const ctf_preamble_t *pp; - ctf_header_t *hp; - Elf *elf; - GElf_Ehdr ehdr; - - (void) elf_version(EV_CURRENT); - - for (opterr = 0; optind < argc; optind++) { - while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) { - switch (c) { - case 'd': - flags |= F_DATA; - break; - case 'f': - flags |= F_FUNC; - break; - case 'h': - flags |= F_HDR; - break; - case 'l': - flags |= F_LABEL; - break; - case 's': - flags |= F_STR; - break; - case 'S': - flags |= F_STATS; - break; - case 't': - flags |= F_TYPES; - break; - case 'u': - ufile = optarg; - break; - default: - if (optopt == '?') - return (print_usage(stdout, 1)); - warn("illegal option -- %c\n", optopt); - return (print_usage(stderr, 0)); - } - } - - if (optind < argc) { - if (filename != NULL) - return (print_usage(stderr, 0)); - filename = argv[optind]; - } - } - - if (filename == NULL) - return (print_usage(stderr, 0)); - - if (flags == 0 && ufile == NULL) - flags = F_ALLMSK; - - if ((fd = open(filename, O_RDONLY)) == -1) - die("failed to open %s", filename); - - if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL && - gelf_getehdr(elf, &ehdr) != NULL) { - - Elf_Data *dp; - Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf"); - Elf_Scn *symscn; - GElf_Shdr ctfshdr; - - if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL) - die("%s does not contain .SUNW_ctf data\n", filename); - - cd.cd_ctfdata = dp->d_buf; - cd.cd_ctflen = dp->d_size; - - /* - * If the sh_link field of the CTF section header is non-zero - * it indicates which section contains the symbol table that - * should be used. We default to the .symtab section if sh_link - * is zero or if there's an error reading the section header. - */ - if (gelf_getshdr(ctfscn, &ctfshdr) != NULL && - ctfshdr.sh_link != 0) { - symscn = elf_getscn(elf, ctfshdr.sh_link); - } else { - symscn = findelfscn(elf, &ehdr, ".symtab"); - } - - /* If we found a symbol table, find the corresponding strings */ - if (symscn != NULL) { - GElf_Shdr shdr; - Elf_Scn *symstrscn; - - if (gelf_getshdr(symscn, &shdr) != NULL) { - symstrscn = elf_getscn(elf, shdr.sh_link); - - cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize; - cd.cd_symdata = elf_getdata(symscn, NULL); - cd.cd_strdata = elf_getdata(symstrscn, NULL); - } - } - } else { - struct stat st; - - if (fstat(fd, &st) == -1) - die("failed to fstat %s", filename); - - cd.cd_ctflen = st.st_size; - cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ, - MAP_PRIVATE, fd, 0); - if (cd.cd_ctfdata == MAP_FAILED) - die("failed to mmap %s", filename); - } - - /* - * Get a pointer to the CTF data buffer and interpret the first portion - * as a ctf_header_t. Validate the magic number and size. - */ - - if (cd.cd_ctflen < sizeof (ctf_preamble_t)) - die("%s does not contain a CTF preamble\n", filename); - - /* LINTED - pointer alignment */ - pp = (const ctf_preamble_t *)cd.cd_ctfdata; - - if (pp->ctp_magic != CTF_MAGIC) - die("%s does not appear to contain CTF data\n", filename); - - if (pp->ctp_version == CTF_VERSION) { - /* LINTED - pointer alignment */ - hp = (ctf_header_t *)cd.cd_ctfdata; - cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t); - - if (cd.cd_ctflen < sizeof (ctf_header_t)) { - die("%s does not contain a v%d CTF header\n", filename, - CTF_VERSION); - } - - } else { - die("%s contains unsupported CTF version %d\n", filename, - pp->ctp_version); - } - - /* - * If the data buffer is compressed, then malloc a buffer large enough - * to hold the decompressed data, and use zlib to decompress it. - */ - if (hp->cth_flags & CTF_F_COMPRESS) { - z_stream zstr; - void *buf; - int rc; - - if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL) - die("failed to allocate decompression buffer"); - - bzero(&zstr, sizeof (z_stream)); - zstr.next_in = (void *)cd.cd_ctfdata; - zstr.avail_in = cd.cd_ctflen; - zstr.next_out = buf; - zstr.avail_out = hp->cth_stroff + hp->cth_strlen; - - if ((rc = inflateInit(&zstr)) != Z_OK) - die("failed to initialize zlib: %s\n", zError(rc)); - - if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END) - die("failed to decompress CTF data: %s\n", zError(rc)); - - if ((rc = inflateEnd(&zstr)) != Z_OK) - die("failed to finish decompression: %s\n", zError(rc)); - - if (zstr.total_out != hp->cth_stroff + hp->cth_strlen) - die("CTF data is corrupt -- short decompression\n"); - - cd.cd_ctfdata = buf; - cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen; - } - - if (flags & F_HDR) - error |= print_header(hp, &cd); - if (flags & (F_LABEL)) - error |= print_labeltable(hp, &cd); - if (flags & (F_DATA | F_STATS)) - error |= read_data(hp, &cd); - if (flags & (F_FUNC | F_STATS)) - error |= read_funcs(hp, &cd); - if (flags & (F_TYPES | F_STATS)) - error |= read_types(hp, &cd); - if (flags & (F_STR | F_STATS)) - error |= read_strtab(hp, &cd); - if (flags & F_STATS) - error |= print_stats(); - - /* - * If the -u option is specified, write the uncompressed CTF data to a - * raw CTF file. CTF data can already be extracted compressed by - * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother. - */ - if (ufile != NULL) { - ctf_header_t h; - - bcopy(hp, &h, sizeof (h)); - h.cth_flags &= ~CTF_F_COMPRESS; - - if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 || - write(ufd, &h, sizeof (h)) != sizeof (h) || - write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != cd.cd_ctflen) { - warn("failed to write CTF data to '%s'", ufile); - error |= E_ERROR; - } - - (void) close(ufd); - } - - if (elf != NULL) - (void) elf_end(elf); - - (void) close(fd); - return (error); -} |