4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <sys/sysmacros.h>
42 #include "ctf_headers.h"
46 #define WARN(x) { warn(x); return (E_ERROR); }
49 * Flags that indicate what data is to be displayed. An explicit `all' value is
50 * provided to allow the code to distinguish between a request for everything
51 * (currently requested by invoking ctfdump without flags) and individual
52 * requests for all of the types of data (an invocation with all flags). In the
53 * former case, we want to be able to implicitly adjust the definition of `all'
54 * based on the CTF version of the file being dumped. For example, if a v2 file
55 * is being dumped, `all' includes F_LABEL - a request to dump the label
56 * section. If a v1 file is being dumped, `all' does not include F_LABEL,
57 * because v1 CTF doesn't support labels. We need to be able to distinguish
58 * between `ctfdump foo', which has an implicit request for labels if `foo'
59 * supports them, and `ctfdump -l foo', which has an explicity request. In the
60 * latter case, we exit with an error if `foo' is a v1 CTF file.
63 F_DATA = 0x01, /* show data object section */
64 F_FUNC = 0x02, /* show function section */
65 F_HDR = 0x04, /* show header */
66 F_STR = 0x08, /* show string table */
67 F_TYPES = 0x10, /* show type section */
68 F_STATS = 0x20, /* show statistics */
69 F_LABEL = 0x40, /* show label section */
70 F_ALL = 0x80, /* explicit request for `all' */
71 F_ALLMSK = 0xff /* show all sections and statistics */
75 ulong_t s_ndata; /* total number of data objects */
76 ulong_t s_nfunc; /* total number of functions */
77 ulong_t s_nargs; /* total number of function arguments */
78 ulong_t s_argmax; /* longest argument list */
79 ulong_t s_ntypes; /* total number of types */
80 ulong_t s_types[16]; /* number of types by kind */
81 ulong_t s_nsmem; /* total number of struct members */
82 ulong_t s_nsbytes; /* total size of all structs */
83 ulong_t s_smmax; /* largest struct in terms of members */
84 ulong_t s_sbmax; /* largest struct in terms of bytes */
85 ulong_t s_numem; /* total number of union members */
86 ulong_t s_nubytes; /* total size of all unions */
87 ulong_t s_ummax; /* largest union in terms of members */
88 ulong_t s_ubmax; /* largest union in terms of bytes */
89 ulong_t s_nemem; /* total number of enum members */
90 ulong_t s_emmax; /* largest enum in terms of members */
91 ulong_t s_nstr; /* total number of strings */
92 size_t s_strlen; /* total length of all strings */
93 size_t s_strmax; /* longest string length */
96 typedef struct ctf_data {
97 caddr_t cd_ctfdata; /* Pointer to the CTF data */
98 size_t cd_ctflen; /* Length of CTF data */
100 size_t cd_idwidth; /* Size of a type ID, in bytes */
103 * cd_symdata will be non-NULL if the CTF data is being retrieved from
104 * an ELF file with a symbol table. cd_strdata and cd_nsyms should be
105 * used only if cd_symdata is non-NULL.
107 Elf_Data *cd_symdata; /* Symbol table */
108 Elf_Data *cd_strdata; /* Symbol table strings */
109 int cd_nsyms; /* Number of symbol table entries */
113 ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd)
115 size_t offset = CTF_NAME_OFFSET(name);
116 const char *s = cd->cd_ctfdata + hp->cth_stroff + offset;
118 if (CTF_NAME_STID(name) != CTF_STRTAB_0)
119 return ("<< ??? - name in external strtab >>");
121 if (offset >= hp->cth_strlen)
122 return ("<< ??? - name exceeds strlab len >>");
124 if (hp->cth_stroff + offset >= cd->cd_ctflen)
125 return ("<< ??? - file truncated >>");
134 int_encoding_to_str(uint_t encoding)
138 if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR |
139 CTF_INT_BOOL | CTF_INT_VARARGS)) != 0)
140 (void) snprintf(buf, sizeof (buf), " 0x%x", encoding);
143 if (encoding & CTF_INT_SIGNED)
144 (void) strcat(buf, " SIGNED");
145 if (encoding & CTF_INT_CHAR)
146 (void) strcat(buf, " CHAR");
147 if (encoding & CTF_INT_BOOL)
148 (void) strcat(buf, " BOOL");
149 if (encoding & CTF_INT_VARARGS)
150 (void) strcat(buf, " VARARGS");
157 fp_encoding_to_str(uint_t encoding)
159 static const char *const encs[] = {
160 NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX",
161 "LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",
162 "DIMAGINARY", "LDIMAGINARY"
167 if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) {
168 (void) snprintf(buf, sizeof (buf), "%u", encoding);
172 return (encs[encoding]);
176 print_line(const char *s)
178 static const char line[] = "----------------------------------------"
179 "----------------------------------------";
180 (void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line);
184 print_header(const ctf_header_t *hp, const ctf_data_t *cd)
186 print_line("- CTF Header ");
188 (void) printf(" cth_magic = 0x%04x\n", hp->cth_magic);
189 (void) printf(" cth_version = %u\n", hp->cth_version);
190 (void) printf(" cth_flags = 0x%02x\n", hp->cth_flags);
191 (void) printf(" cth_parlabel = %s\n",
192 ref_to_str(hp->cth_parlabel, hp, cd));
193 (void) printf(" cth_parname = %s\n",
194 ref_to_str(hp->cth_parname, hp, cd));
195 (void) printf(" cth_lbloff = %u\n", hp->cth_lbloff);
196 (void) printf(" cth_objtoff = %u\n", hp->cth_objtoff);
197 (void) printf(" cth_funcoff = %u\n", hp->cth_funcoff);
198 (void) printf(" cth_typeoff = %u\n", hp->cth_typeoff);
199 (void) printf(" cth_stroff = %u\n", hp->cth_stroff);
200 (void) printf(" cth_strlen = %u\n", hp->cth_strlen);
206 print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd)
208 void *v = (void *) (cd->cd_ctfdata + hp->cth_lbloff);
209 const ctf_lblent_t *ctl = v;
210 ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl);
212 print_line("- Label Table ");
214 if (hp->cth_lbloff & 3)
215 WARN("cth_lbloff is not aligned properly\n");
216 if (hp->cth_lbloff >= cd->cd_ctflen)
217 WARN("file is truncated or cth_lbloff is corrupt\n");
218 if (hp->cth_objtoff >= cd->cd_ctflen)
219 WARN("file is truncated or cth_objtoff is corrupt\n");
220 if (hp->cth_lbloff > hp->cth_objtoff)
221 WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");
223 for (i = 0; i < n; i++, ctl++) {
224 (void) printf(" %5u %s\n", ctl->ctl_typeidx,
225 ref_to_str(ctl->ctl_label, hp, cd));
232 * Given the current symbol index (-1 to start at the beginning of the symbol
233 * table) and the type of symbol to match, this function returns the index of
234 * the next matching symbol (if any), and places the name of that symbol in
235 * *namep. If no symbol is found, -1 is returned.
238 next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype,
243 for (i = symidx + 1; i < cd->cd_nsyms; i++) {
248 if (gelf_getsym(cd->cd_symdata, i, &sym) == 0)
251 name = (char *)cd->cd_strdata->d_buf + sym.st_name;
252 type = GELF_ST_TYPE(sym.st_info);
255 * Skip various types of symbol table entries.
257 if (type != matchtype || ignore_symbol(&sym, name))
269 read_data(const ctf_header_t *hp, const ctf_data_t *cd)
271 const char *v = (void *) (cd->cd_ctfdata + hp->cth_objtoff);
272 ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / cd->cd_idwidth;
274 if (flags != F_STATS)
275 print_line("- Data Objects ");
277 if (hp->cth_objtoff & 1)
278 WARN("cth_objtoff is not aligned properly\n");
279 if (hp->cth_objtoff >= cd->cd_ctflen)
280 WARN("file is truncated or cth_objtoff is corrupt\n");
281 if (hp->cth_funcoff >= cd->cd_ctflen)
282 WARN("file is truncated or cth_funcoff is corrupt\n");
283 if (hp->cth_objtoff > hp->cth_funcoff)
284 WARN("file is corrupt -- cth_objtoff > cth_funcoff\n");
286 if (flags != F_STATS) {
290 for (symidx = -1, i = 0; i < (int) n; i++) {
294 if (cd->cd_symdata == NULL || (nextsym = next_sym(cd,
295 symidx, STT_OBJECT, &name)) < 0)
300 memcpy(&id, v, cd->cd_idwidth);
302 len = printf(" [%u] %u", i, id);
304 (void) printf("%*s%s (%u)", (15 - len), "",
306 (void) putchar('\n');
315 read_funcs(const ctf_header_t *hp, const ctf_data_t *cd)
317 const char *v = (void *) (cd->cd_ctfdata + hp->cth_funcoff);
320 const char *end = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
325 if (flags != F_STATS)
326 print_line("- Functions ");
328 if (hp->cth_funcoff & 1)
329 WARN("cth_funcoff is not aligned properly\n");
330 if (hp->cth_funcoff >= cd->cd_ctflen)
331 WARN("file is truncated or cth_funcoff is corrupt\n");
332 if (hp->cth_typeoff >= cd->cd_ctflen)
333 WARN("file is truncated or cth_typeoff is corrupt\n");
334 if (hp->cth_funcoff > hp->cth_typeoff)
335 WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");
337 for (symidx = -1, id = 0; v < end; id++) {
339 memcpy(&info, v, cd->cd_idwidth);
341 ushort_t kind = hp->cth_version == CTF_VERSION_2 ?
342 CTF_V2_INFO_KIND(info) : CTF_V3_INFO_KIND(info);
343 ushort_t n = hp->cth_version == CTF_VERSION_2 ?
344 CTF_V2_INFO_VLEN(info) : CTF_V3_INFO_VLEN(info);
349 if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx,
350 STT_FUNC, &name)) < 0)
355 if (kind == CTF_K_UNKNOWN && n == 0)
356 continue; /* skip padding */
358 if (kind != CTF_K_FUNCTION) {
359 (void) printf(" [%lu] unexpected kind -- %u\n",
364 if (v + n * cd->cd_idwidth > end) {
365 (void) printf(" [%lu] vlen %u extends past section "
366 "boundary\n", id, n);
370 if (flags != F_STATS) {
371 (void) printf(" [%lu] FUNC ", id);
373 (void) printf("(%s) ", name);
374 memcpy(&f, v, cd->cd_idwidth);
376 (void) printf("returns: %u args: (", f);
379 memcpy(&f, v, cd->cd_idwidth);
381 (void) printf("%u", f);
382 for (i = 1; i < n; i++) {
383 memcpy(&f, v, cd->cd_idwidth);
385 (void) printf(", %u", f);
389 (void) printf(")\n");
391 v += n * cd->cd_idwidth + 1; /* skip to next function definition */
395 stats.s_argmax = MAX(stats.s_argmax, n);
402 read_types(const ctf_header_t *hp, const ctf_data_t *cd)
404 const char *v = (void *) (cd->cd_ctfdata + hp->cth_typeoff);
405 const char *end = (void *) (cd->cd_ctfdata + hp->cth_stroff);
409 if (flags != F_STATS)
410 print_line("- Types ");
412 if (hp->cth_typeoff & 3)
413 WARN("cth_typeoff is not aligned properly\n");
414 if (hp->cth_typeoff >= cd->cd_ctflen)
415 WARN("file is truncated or cth_typeoff is corrupt\n");
416 if (hp->cth_stroff >= cd->cd_ctflen)
417 WARN("file is truncated or cth_stroff is corrupt\n");
418 if (hp->cth_typeoff > hp->cth_stroff)
419 WARN("file is corrupt -- cth_typeoff > cth_stroff\n");
421 version = hp->cth_version;
424 if (hp->cth_parlabel || hp->cth_parname)
425 id += 1ul << (hp->cth_version == CTF_VERSION_2 ?
426 CTF_V2_PARENT_SHIFT : CTF_V3_PARENT_SHIFT);
428 for (/* */; v < end; id++) {
429 struct ctf_type_v2 t2;
430 struct ctf_type_v3 t3;
432 size_t size, increment, vlen = 0;
433 uint_t isroot, name, type;
436 if (version == CTF_VERSION_2) {
437 memcpy(&t2, v, sizeof(t2));
439 n = CTF_V2_INFO_VLEN(t2.ctt_info);
440 isroot = CTF_V2_INFO_ISROOT(t2.ctt_info);
441 kind = CTF_V2_INFO_KIND(t2.ctt_info);
444 if (t2.ctt_size == CTF_V2_LSIZE_SENT) {
445 increment = sizeof (struct ctf_type_v2);
446 size = (size_t)CTF_TYPE_LSIZE(&t2);
448 increment = sizeof (struct ctf_stype_v2);
452 memcpy(&t3, v, sizeof(t3));
454 n = CTF_V3_INFO_VLEN(t3.ctt_info);
455 isroot = CTF_V3_INFO_ISROOT(t3.ctt_info);
456 kind = CTF_V3_INFO_KIND(t3.ctt_info);
459 if (t3.ctt_size == CTF_V3_LSIZE_SENT) {
460 increment = sizeof (struct ctf_type_v3);
461 size = (size_t)CTF_TYPE_LSIZE(&t3);
463 increment = sizeof (struct ctf_stype_v3);
470 struct ctf_array_v2 *ap2;
471 struct ctf_array_v3 *ap3;
472 const struct ctf_member_v2 *mp2;
473 const struct ctf_member_v3 *mp3;
474 const struct ctf_lmember_v2 *lmp2;
475 const struct ctf_lmember_v3 *lmp3;
476 const ctf_enum_t *ep;
479 u.ptr = v + increment;
481 if (flags != F_STATS) {
482 (void) printf(" %c%lu%c ",
483 "[<"[isroot], id, "]>"[isroot]);
488 if (flags != F_STATS) {
490 *((const uint_t *)(const void *)u.ptr);
492 (void) printf("INTEGER %s encoding=%s offset=%u"
493 " bits=%u", ref_to_str(name, hp, cd),
495 CTF_INT_ENCODING(encoding)),
496 CTF_INT_OFFSET(encoding),
497 CTF_INT_BITS(encoding));
499 vlen = sizeof (uint32_t);
503 if (flags != F_STATS) {
505 *((const uint_t *)(const void *)u.ptr);
507 (void) printf("FLOAT %s encoding=%s offset=%u "
508 "bits=%u", ref_to_str(name, hp, cd),
510 CTF_FP_ENCODING(encoding)),
511 CTF_FP_OFFSET(encoding),
512 CTF_FP_BITS(encoding));
514 vlen = sizeof (uint32_t);
518 if (flags != F_STATS) {
519 (void) printf("POINTER %s refers to %u",
520 ref_to_str(name, hp, cd), type);
525 uint_t contents, index, nelems;
527 if (version == CTF_VERSION_2) {
528 contents = u.ap2->cta_contents;
529 index = u.ap2->cta_index;
530 nelems = u.ap2->cta_nelems;
532 contents = u.ap3->cta_contents;
533 index = u.ap3->cta_index;
534 nelems = u.ap3->cta_nelems;
536 if (flags != F_STATS) {
537 (void) printf("ARRAY %s content: %u index: %u "
538 "nelems: %u\n", ref_to_str(name, hp, cd),
539 contents, index, nelems);
542 vlen = sizeof (struct ctf_array_v2);
544 vlen = sizeof (struct ctf_array_v3);
548 case CTF_K_FUNCTION: {
551 if (flags != F_STATS) {
552 (void) printf("FUNCTION %s returns: %u args: (",
553 ref_to_str(name, hp, cd), type);
556 memcpy(&arg, u.ptr, cd->cd_idwidth);
557 u.ptr += cd->cd_idwidth;
558 (void) printf("%u", arg);
560 i++, u.ptr += cd->cd_idwidth) {
563 (void) printf(", %u", arg);
570 vlen = roundup2(cd->cd_idwidth * n, 4);
576 if (kind == CTF_K_STRUCT) {
578 stats.s_smmax = MAX(stats.s_smmax, n);
579 stats.s_nsbytes += size;
580 stats.s_sbmax = MAX(stats.s_sbmax, size);
582 if (flags != F_STATS)
583 (void) printf("STRUCT");
586 stats.s_ummax = MAX(stats.s_ummax, n);
587 stats.s_nubytes += size;
588 stats.s_ubmax = MAX(stats.s_ubmax, size);
590 if (flags != F_STATS)
591 (void) printf("UNION");
594 if (flags != F_STATS) {
595 (void) printf(" %s (%zd bytes)\n",
596 ref_to_str(name, hp, cd), size);
598 if (version == CTF_VERSION_2) {
599 if (size >= CTF_V2_LSTRUCT_THRESH) {
600 for (i = 0; i < n; i++, u.lmp2++) {
602 "\t%s type=%u off=%llu\n",
603 ref_to_str(u.lmp2->ctlm_name,
604 hp, cd), u.lmp2->ctlm_type,
606 CTF_LMEM_OFFSET(u.lmp2));
609 for (i = 0; i < n; i++, u.mp2++) {
611 "\t%s type=%u off=%u\n",
612 ref_to_str(u.mp2->ctm_name,
613 hp, cd), u.mp2->ctm_type,
618 if (size >= CTF_V3_LSTRUCT_THRESH) {
619 for (i = 0; i < n; i++, u.lmp3++) {
621 "\t%s type=%u off=%llu\n",
622 ref_to_str(u.lmp3->ctlm_name,
623 hp, cd), u.lmp3->ctlm_type,
625 CTF_LMEM_OFFSET(u.lmp3));
628 for (i = 0; i < n; i++, u.mp3++) {
630 "\t%s type=%u off=%u\n",
631 ref_to_str(u.mp3->ctm_name,
632 hp, cd), u.mp3->ctm_type,
639 if (version == CTF_VERSION_2) {
640 vlen = n * (size >= CTF_V2_LSTRUCT_THRESH ?
641 sizeof (struct ctf_lmember_v2) :
642 sizeof (struct ctf_member_v2));
644 vlen = n * (size >= CTF_V3_LSTRUCT_THRESH ?
645 sizeof (struct ctf_lmember_v3) :
646 sizeof (struct ctf_member_v3));
651 if (flags != F_STATS) {
652 (void) printf("ENUM %s\n",
653 ref_to_str(name, hp, cd));
655 for (i = 0; i < n; i++, u.ep++) {
656 (void) printf("\t%s = %d\n",
657 ref_to_str(u.ep->cte_name, hp, cd),
663 stats.s_emmax = MAX(stats.s_emmax, n);
665 vlen = sizeof (ctf_enum_t) * n;
669 if (flags != F_STATS) {
670 (void) printf("FORWARD %s",
671 ref_to_str(name, hp, cd));
676 if (flags != F_STATS) {
677 (void) printf("TYPEDEF %s refers to %u",
678 ref_to_str(name, hp, cd), type);
683 if (flags != F_STATS) {
684 (void) printf("VOLATILE %s refers to %u",
685 ref_to_str(name, hp, cd), type);
690 if (flags != F_STATS) {
691 (void) printf("CONST %s refers to %u",
692 ref_to_str(name, hp, cd), type);
697 if (flags != F_STATS) {
698 (void) printf("RESTRICT %s refers to %u",
699 ref_to_str(name, hp, cd), type);
704 break; /* hole in type id space */
707 (void) printf("unexpected kind %u\n", kind);
711 if (flags != F_STATS)
715 stats.s_types[kind]++;
717 v += increment + vlen;
724 read_strtab(const ctf_header_t *hp, const ctf_data_t *cd)
726 size_t n, off, len = hp->cth_strlen;
727 const char *s = cd->cd_ctfdata + hp->cth_stroff;
729 if (flags != F_STATS)
730 print_line("- String Table ");
732 if (hp->cth_stroff >= cd->cd_ctflen)
733 WARN("file is truncated or cth_stroff is corrupt\n");
734 if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen)
735 WARN("file is truncated or cth_strlen is corrupt\n");
737 for (off = 0; len != 0; off += n) {
738 if (flags != F_STATS) {
739 (void) printf(" [%lu] %s\n", (ulong_t)off,
740 s[0] == '\0' ? "\\0" : s);
748 stats.s_strmax = MAX(stats.s_strmax, n);
755 long_stat(const char *name, ulong_t value)
757 (void) printf(" %-36s= %lu\n", name, value);
761 fp_stat(const char *name, float value)
763 (void) printf(" %-36s= %.2f\n", name, value);
769 print_line("- CTF Statistics ");
771 long_stat("total number of data objects", stats.s_ndata);
774 long_stat("total number of functions", stats.s_nfunc);
775 long_stat("total number of function arguments", stats.s_nargs);
776 long_stat("maximum argument list length", stats.s_argmax);
778 if (stats.s_nfunc != 0) {
779 fp_stat("average argument list length",
780 (float)stats.s_nargs / (float)stats.s_nfunc);
785 long_stat("total number of types", stats.s_ntypes);
786 long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]);
787 long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]);
788 long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]);
789 long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]);
790 long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]);
791 long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]);
792 long_stat("total number of unions", stats.s_types[CTF_K_UNION]);
793 long_stat("total number of enums", stats.s_types[CTF_K_ENUM]);
794 long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]);
795 long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]);
796 long_stat("total number of volatile types",
797 stats.s_types[CTF_K_VOLATILE]);
798 long_stat("total number of const types", stats.s_types[CTF_K_CONST]);
799 long_stat("total number of restrict types",
800 stats.s_types[CTF_K_RESTRICT]);
801 long_stat("total number of unknowns (holes)",
802 stats.s_types[CTF_K_UNKNOWN]);
806 long_stat("total number of struct members", stats.s_nsmem);
807 long_stat("maximum number of struct members", stats.s_smmax);
808 long_stat("total size of all structs", stats.s_nsbytes);
809 long_stat("maximum size of a struct", stats.s_sbmax);
811 if (stats.s_types[CTF_K_STRUCT] != 0) {
812 fp_stat("average number of struct members",
813 (float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]);
814 fp_stat("average size of a struct", (float)stats.s_nsbytes /
815 (float)stats.s_types[CTF_K_STRUCT]);
820 long_stat("total number of union members", stats.s_numem);
821 long_stat("maximum number of union members", stats.s_ummax);
822 long_stat("total size of all unions", stats.s_nubytes);
823 long_stat("maximum size of a union", stats.s_ubmax);
825 if (stats.s_types[CTF_K_UNION] != 0) {
826 fp_stat("average number of union members",
827 (float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]);
828 fp_stat("average size of a union", (float)stats.s_nubytes /
829 (float)stats.s_types[CTF_K_UNION]);
834 long_stat("total number of enum members", stats.s_nemem);
835 long_stat("maximum number of enum members", stats.s_emmax);
837 if (stats.s_types[CTF_K_ENUM] != 0) {
838 fp_stat("average number of enum members",
839 (float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]);
844 long_stat("total number of unique strings", stats.s_nstr);
845 long_stat("bytes of string data", stats.s_strlen);
846 long_stat("maximum string length", stats.s_strmax);
848 if (stats.s_nstr != 0) {
849 fp_stat("average string length",
850 (float)stats.s_strlen / (float)stats.s_nstr);
858 print_usage(FILE *fp, int verbose)
860 (void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getpname());
864 "\t-d dump data object section\n"
865 "\t-f dump function section\n"
866 "\t-h dump file header\n"
867 "\t-l dump label table\n"
868 "\t-s dump string table\n"
869 "\t-S dump statistics\n"
870 "\t-t dump type section\n"
871 "\t-u save uncompressed CTF to a file\n");
878 findelfscn(Elf *elf, GElf_Ehdr *ehdr, const char *secname)
884 for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) {
885 if (gelf_getshdr(scn, &shdr) != NULL && (name =
886 elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL &&
887 strcmp(name, secname) == 0)
895 main(int argc, char *argv[])
897 const char *filename = NULL;
898 const char *ufile = NULL;
903 const ctf_preamble_t *pp;
904 ctf_header_t *hp = NULL;
908 (void) elf_version(EV_CURRENT);
910 for (opterr = 0; optind < argc; optind++) {
911 while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) {
939 return (print_usage(stdout, 1));
940 warn("illegal option -- %c\n", optopt);
941 return (print_usage(stderr, 0));
946 if (filename != NULL)
947 return (print_usage(stderr, 0));
948 filename = argv[optind];
952 if (filename == NULL)
953 return (print_usage(stderr, 0));
955 if (flags == 0 && ufile == NULL)
958 if ((fd = open(filename, O_RDONLY)) == -1)
959 die("failed to open %s", filename);
961 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL &&
962 gelf_getehdr(elf, &ehdr) != NULL) {
965 Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf");
969 if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL)
970 die("%s does not contain .SUNW_ctf data\n", filename);
972 cd.cd_ctfdata = dp->d_buf;
973 cd.cd_ctflen = dp->d_size;
976 * If the sh_link field of the CTF section header is non-zero
977 * it indicates which section contains the symbol table that
978 * should be used. We default to the .symtab section if sh_link
979 * is zero or if there's an error reading the section header.
981 if (gelf_getshdr(ctfscn, &ctfshdr) != NULL &&
982 ctfshdr.sh_link != 0) {
983 symscn = elf_getscn(elf, ctfshdr.sh_link);
985 symscn = findelfscn(elf, &ehdr, ".symtab");
988 /* If we found a symbol table, find the corresponding strings */
989 if (symscn != NULL) {
993 if (gelf_getshdr(symscn, &shdr) != NULL) {
994 symstrscn = elf_getscn(elf, shdr.sh_link);
996 cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize;
997 cd.cd_symdata = elf_getdata(symscn, NULL);
998 cd.cd_strdata = elf_getdata(symstrscn, NULL);
1004 if (fstat(fd, &st) == -1)
1005 die("failed to fstat %s", filename);
1007 cd.cd_ctflen = st.st_size;
1008 cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ,
1009 MAP_PRIVATE, fd, 0);
1010 if (cd.cd_ctfdata == MAP_FAILED)
1011 die("failed to mmap %s", filename);
1015 * Get a pointer to the CTF data buffer and interpret the first portion
1016 * as a ctf_header_t. Validate the magic number and size.
1019 if (cd.cd_ctflen < sizeof (ctf_preamble_t))
1020 die("%s does not contain a CTF preamble\n", filename);
1022 void *v = (void *) cd.cd_ctfdata;
1025 if (pp->ctp_magic != CTF_MAGIC)
1026 die("%s does not appear to contain CTF data\n", filename);
1028 if (pp->ctp_version >= CTF_VERSION_2) {
1029 v = (void *) cd.cd_ctfdata;
1031 cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t);
1033 cd.cd_idwidth = pp->ctp_version == CTF_VERSION_2 ? 2 : 4;
1035 if (cd.cd_ctflen < sizeof (ctf_header_t)) {
1036 die("%s does not contain a v%d CTF header\n", filename,
1041 die("%s contains unsupported CTF version %d\n", filename,
1046 * If the data buffer is compressed, then malloc a buffer large enough
1047 * to hold the decompressed data, and use zlib to decompress it.
1049 if (hp->cth_flags & CTF_F_COMPRESS) {
1054 if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL)
1055 die("failed to allocate decompression buffer");
1057 bzero(&zstr, sizeof (z_stream));
1058 zstr.next_in = (void *)cd.cd_ctfdata;
1059 zstr.avail_in = cd.cd_ctflen;
1060 zstr.next_out = buf;
1061 zstr.avail_out = hp->cth_stroff + hp->cth_strlen;
1063 if ((rc = inflateInit(&zstr)) != Z_OK)
1064 die("failed to initialize zlib: %s\n", zError(rc));
1066 if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END)
1067 die("failed to decompress CTF data: %s\n", zError(rc));
1069 if ((rc = inflateEnd(&zstr)) != Z_OK)
1070 die("failed to finish decompression: %s\n", zError(rc));
1072 if (zstr.total_out != hp->cth_stroff + hp->cth_strlen)
1073 die("CTF data is corrupt -- short decompression\n");
1075 cd.cd_ctfdata = buf;
1076 cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen;
1080 error |= print_header(hp, &cd);
1081 if (flags & (F_LABEL))
1082 error |= print_labeltable(hp, &cd);
1083 if (flags & (F_DATA | F_STATS))
1084 error |= read_data(hp, &cd);
1085 if (flags & (F_FUNC | F_STATS))
1086 error |= read_funcs(hp, &cd);
1087 if (flags & (F_TYPES | F_STATS))
1088 error |= read_types(hp, &cd);
1089 if (flags & (F_STR | F_STATS))
1090 error |= read_strtab(hp, &cd);
1091 if (flags & F_STATS)
1092 error |= print_stats();
1095 * If the -u option is specified, write the uncompressed CTF data to a
1096 * raw CTF file. CTF data can already be extracted compressed by
1097 * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.
1099 if (ufile != NULL) {
1102 bcopy(hp, &h, sizeof (h));
1103 h.cth_flags &= ~CTF_F_COMPRESS;
1105 if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 ||
1106 write(ufd, &h, sizeof (h)) != sizeof (h) ||
1107 write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != (int) cd.cd_ctflen) {
1108 warn("failed to write CTF data to '%s'", ufile);
1116 (void) elf_end(elf);