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 */
101 * cd_symdata will be non-NULL if the CTF data is being retrieved from
102 * an ELF file with a symbol table. cd_strdata and cd_nsyms should be
103 * used only if cd_symdata is non-NULL.
105 Elf_Data
*cd_symdata
; /* Symbol table */
106 Elf_Data
*cd_strdata
; /* Symbol table strings */
107 int cd_nsyms
; /* Number of symbol table entries */
111 ref_to_str(uint_t name
, const ctf_header_t
*hp
, const ctf_data_t
*cd
)
113 size_t offset
= CTF_NAME_OFFSET(name
);
114 const char *s
= cd
->cd_ctfdata
+ hp
->cth_stroff
+ offset
;
116 if (CTF_NAME_STID(name
) != CTF_STRTAB_0
)
117 return ("<< ??? - name in external strtab >>");
119 if (offset
>= hp
->cth_strlen
)
120 return ("<< ??? - name exceeds strlab len >>");
122 if (hp
->cth_stroff
+ offset
>= cd
->cd_ctflen
)
123 return ("<< ??? - file truncated >>");
132 int_encoding_to_str(uint_t encoding
)
136 if (encoding
== 0 || (encoding
& ~(CTF_INT_SIGNED
| CTF_INT_CHAR
|
137 CTF_INT_BOOL
| CTF_INT_VARARGS
)) != 0)
138 (void) snprintf(buf
, sizeof (buf
), " 0x%x", encoding
);
141 if (encoding
& CTF_INT_SIGNED
)
142 (void) strcat(buf
, " SIGNED");
143 if (encoding
& CTF_INT_CHAR
)
144 (void) strcat(buf
, " CHAR");
145 if (encoding
& CTF_INT_BOOL
)
146 (void) strcat(buf
, " BOOL");
147 if (encoding
& CTF_INT_VARARGS
)
148 (void) strcat(buf
, " VARARGS");
155 fp_encoding_to_str(uint_t encoding
)
157 static const char *const encs
[] = {
158 NULL
, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX",
159 "LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY",
160 "DIMAGINARY", "LDIMAGINARY"
165 if (encoding
< 1 || encoding
>= (sizeof (encs
) / sizeof (char *))) {
166 (void) snprintf(buf
, sizeof (buf
), "%u", encoding
);
170 return (encs
[encoding
]);
174 print_line(const char *s
)
176 static const char line
[] = "----------------------------------------"
177 "----------------------------------------";
178 (void) printf("\n%s%.*s\n\n", s
, (int)(78 - strlen(s
)), line
);
182 print_header(const ctf_header_t
*hp
, const ctf_data_t
*cd
)
184 print_line("- CTF Header ");
186 (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",
190 ref_to_str(hp
->cth_parlabel
, hp
, cd
));
191 (void) printf(" cth_parname = %s\n",
192 ref_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
);
204 print_labeltable(const ctf_header_t
*hp
, const ctf_data_t
*cd
)
206 /* LINTED - pointer alignment */
207 const ctf_lblent_t
*ctl
= (ctf_lblent_t
*)(cd
->cd_ctfdata
+
209 ulong_t i
, n
= (hp
->cth_objtoff
- hp
->cth_lbloff
) / sizeof (*ctl
);
211 print_line("- Label Table ");
213 if (hp
->cth_lbloff
& 3)
214 WARN("cth_lbloff is not aligned properly\n");
215 if (hp
->cth_lbloff
>= cd
->cd_ctflen
)
216 WARN("file is truncated or cth_lbloff is corrupt\n");
217 if (hp
->cth_objtoff
>= cd
->cd_ctflen
)
218 WARN("file is truncated or cth_objtoff is corrupt\n");
219 if (hp
->cth_lbloff
> hp
->cth_objtoff
)
220 WARN("file is corrupt -- cth_lbloff > cth_objtoff\n");
222 for (i
= 0; i
< n
; i
++, ctl
++) {
223 (void) printf(" %5u %s\n", ctl
->ctl_typeidx
,
224 ref_to_str(ctl
->ctl_label
, hp
, cd
));
231 * Given the current symbol index (-1 to start at the beginning of the symbol
232 * table) and the type of symbol to match, this function returns the index of
233 * the next matching symbol (if any), and places the name of that symbol in
234 * *namep. If no symbol is found, -1 is returned.
237 next_sym(const ctf_data_t
*cd
, const int symidx
, const uchar_t matchtype
,
242 for (i
= symidx
+ 1; i
< cd
->cd_nsyms
; i
++) {
247 if (gelf_getsym(cd
->cd_symdata
, i
, &sym
) == 0)
250 name
= (char *)cd
->cd_strdata
->d_buf
+ sym
.st_name
;
251 type
= GELF_ST_TYPE(sym
.st_info
);
254 * Skip various types of symbol table entries.
256 if (type
!= matchtype
|| ignore_symbol(&sym
, name
))
268 read_data(const ctf_header_t
*hp
, const ctf_data_t
*cd
)
270 /* LINTED - pointer alignment */
271 const ushort_t
*idp
= (ushort_t
*)(cd
->cd_ctfdata
+ hp
->cth_objtoff
);
272 ulong_t n
= (hp
->cth_funcoff
- hp
->cth_objtoff
) / sizeof (ushort_t
);
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
< n
; i
++) {
293 if (cd
->cd_symdata
== NULL
|| (nextsym
= next_sym(cd
,
294 symidx
, STT_OBJECT
, &name
)) < 0)
299 len
= printf(" [%u] %u", i
, *idp
++);
301 (void) printf("%*s%s (%u)", (15 - len
), "",
303 (void) putchar('\n');
312 read_funcs(const ctf_header_t
*hp
, const ctf_data_t
*cd
)
314 /* LINTED - pointer alignment */
315 const ushort_t
*fp
= (ushort_t
*)(cd
->cd_ctfdata
+ hp
->cth_funcoff
);
317 /* LINTED - pointer alignment */
318 const ushort_t
*end
= (ushort_t
*)(cd
->cd_ctfdata
+ hp
->cth_typeoff
);
323 if (flags
!= F_STATS
)
324 print_line("- Functions ");
326 if (hp
->cth_funcoff
& 1)
327 WARN("cth_funcoff is not aligned properly\n");
328 if (hp
->cth_funcoff
>= cd
->cd_ctflen
)
329 WARN("file is truncated or cth_funcoff is corrupt\n");
330 if (hp
->cth_typeoff
>= cd
->cd_ctflen
)
331 WARN("file is truncated or cth_typeoff is corrupt\n");
332 if (hp
->cth_funcoff
> hp
->cth_typeoff
)
333 WARN("file is corrupt -- cth_funcoff > cth_typeoff\n");
335 for (symidx
= -1, id
= 0; fp
< end
; id
++) {
336 ushort_t info
= *fp
++;
337 ushort_t kind
= CTF_INFO_KIND(info
);
338 ushort_t n
= CTF_INFO_VLEN(info
);
343 if (cd
->cd_symdata
== NULL
|| (nextsym
= next_sym(cd
, symidx
,
344 STT_FUNC
, &name
)) < 0)
349 if (kind
== CTF_K_UNKNOWN
&& n
== 0)
350 continue; /* skip padding */
352 if (kind
!= CTF_K_FUNCTION
) {
353 (void) printf(" [%lu] unexpected kind -- %u\n",
359 (void) printf(" [%lu] vlen %u extends past section "
360 "boundary\n", id
, n
);
364 if (flags
!= F_STATS
) {
365 (void) printf(" [%lu] FUNC ", id
);
367 (void) printf("(%s) ", name
);
368 (void) printf("returns: %u args: (", *fp
++);
371 (void) printf("%u", *fp
++);
372 for (i
= 1; i
< n
; i
++)
373 (void) printf(", %u", *fp
++);
376 (void) printf(")\n");
378 fp
+= n
+ 1; /* skip to next function definition */
382 stats
.s_argmax
= MAX(stats
.s_argmax
, n
);
389 read_types(const ctf_header_t
*hp
, const ctf_data_t
*cd
)
391 /* LINTED - pointer alignment */
392 const ctf_type_t
*tp
= (ctf_type_t
*)(cd
->cd_ctfdata
+ hp
->cth_typeoff
);
394 /* LINTED - pointer alignment */
395 const ctf_type_t
*end
= (ctf_type_t
*)(cd
->cd_ctfdata
+ hp
->cth_stroff
);
399 if (flags
!= F_STATS
)
400 print_line("- Types ");
402 if (hp
->cth_typeoff
& 3)
403 WARN("cth_typeoff is not aligned properly\n");
404 if (hp
->cth_typeoff
>= cd
->cd_ctflen
)
405 WARN("file is truncated or cth_typeoff is corrupt\n");
406 if (hp
->cth_stroff
>= cd
->cd_ctflen
)
407 WARN("file is truncated or cth_stroff is corrupt\n");
408 if (hp
->cth_typeoff
> hp
->cth_stroff
)
409 WARN("file is corrupt -- cth_typeoff > cth_stroff\n");
412 if (hp
->cth_parlabel
|| hp
->cth_parname
)
413 id
+= 1 << CTF_PARENT_SHIFT
;
415 for (/* */; tp
< end
; id
++) {
416 ulong_t i
, n
= CTF_INFO_VLEN(tp
->ctt_info
);
417 size_t size
, increment
, vlen
= 0;
418 int kind
= CTF_INFO_KIND(tp
->ctt_info
);
422 const ctf_array_t
*ap
;
423 const ctf_member_t
*mp
;
424 const ctf_lmember_t
*lmp
;
425 const ctf_enum_t
*ep
;
426 const ushort_t
*argp
;
429 if (flags
!= F_STATS
) {
430 (void) printf(" %c%lu%c ",
431 "[<"[CTF_INFO_ISROOT(tp
->ctt_info
)], id
,
432 "]>"[CTF_INFO_ISROOT(tp
->ctt_info
)]);
435 if (tp
->ctt_size
== CTF_LSIZE_SENT
) {
436 increment
= sizeof (ctf_type_t
);
437 size
= (size_t)CTF_TYPE_LSIZE(tp
);
439 increment
= sizeof (ctf_stype_t
);
442 u
.ptr
= (caddr_t
)tp
+ increment
;
446 if (flags
!= F_STATS
) {
447 uint_t encoding
= *((const uint_t
*)u
.ptr
);
449 (void) printf("INTEGER %s encoding=%s offset=%u"
450 " bits=%u", ref_to_str(tp
->ctt_name
, hp
,
451 cd
), int_encoding_to_str(
452 CTF_INT_ENCODING(encoding
)),
453 CTF_INT_OFFSET(encoding
),
454 CTF_INT_BITS(encoding
));
456 vlen
= sizeof (uint_t
);
460 if (flags
!= F_STATS
) {
461 uint_t encoding
= *((const uint_t
*)u
.ptr
);
463 (void) printf("FLOAT %s encoding=%s offset=%u "
464 "bits=%u", ref_to_str(tp
->ctt_name
, hp
,
465 cd
), fp_encoding_to_str(
466 CTF_FP_ENCODING(encoding
)),
467 CTF_FP_OFFSET(encoding
),
468 CTF_FP_BITS(encoding
));
470 vlen
= sizeof (uint_t
);
474 if (flags
!= F_STATS
) {
475 (void) printf("POINTER %s refers to %u",
476 ref_to_str(tp
->ctt_name
, hp
, cd
),
482 if (flags
!= F_STATS
) {
483 (void) printf("ARRAY %s content: %u index: %u "
484 "nelems: %u\n", ref_to_str(tp
->ctt_name
,
485 hp
, cd
), u
.ap
->cta_contents
,
486 u
.ap
->cta_index
, u
.ap
->cta_nelems
);
488 vlen
= sizeof (ctf_array_t
);
492 if (flags
!= F_STATS
) {
493 (void) printf("FUNCTION %s returns: %u args: (",
494 ref_to_str(tp
->ctt_name
, hp
, cd
),
498 (void) printf("%u", *u
.argp
++);
499 for (i
= 1; i
< n
; i
++, u
.argp
++)
500 (void) printf(", %u", *u
.argp
);
506 vlen
= sizeof (ushort_t
) * (n
+ (n
& 1));
511 if (kind
== CTF_K_STRUCT
) {
513 stats
.s_smmax
= MAX(stats
.s_smmax
, n
);
514 stats
.s_nsbytes
+= size
;
515 stats
.s_sbmax
= MAX(stats
.s_sbmax
, size
);
517 if (flags
!= F_STATS
)
518 (void) printf("STRUCT");
521 stats
.s_ummax
= MAX(stats
.s_ummax
, n
);
522 stats
.s_nubytes
+= size
;
523 stats
.s_ubmax
= MAX(stats
.s_ubmax
, size
);
525 if (flags
!= F_STATS
)
526 (void) printf("UNION");
529 if (flags
!= F_STATS
) {
530 (void) printf(" %s (%d bytes)\n",
531 ref_to_str(tp
->ctt_name
, hp
, cd
), size
);
533 if (size
>= CTF_LSTRUCT_THRESH
) {
534 for (i
= 0; i
< n
; i
++, u
.lmp
++) {
536 "\t%s type=%u off=%llu\n",
537 ref_to_str(u
.lmp
->ctlm_name
,
538 hp
, cd
), u
.lmp
->ctlm_type
,
539 CTF_LMEM_OFFSET(u
.lmp
));
542 for (i
= 0; i
< n
; i
++, u
.mp
++) {
544 "\t%s type=%u off=%u\n",
545 ref_to_str(u
.mp
->ctm_name
,
546 hp
, cd
), u
.mp
->ctm_type
,
552 vlen
= n
* (size
>= CTF_LSTRUCT_THRESH
?
553 sizeof (ctf_lmember_t
) : sizeof (ctf_member_t
));
557 if (flags
!= F_STATS
) {
558 (void) printf("ENUM %s\n",
559 ref_to_str(tp
->ctt_name
, hp
, cd
));
561 for (i
= 0; i
< n
; i
++, u
.ep
++) {
562 (void) printf("\t%s = %d\n",
563 ref_to_str(u
.ep
->cte_name
, hp
, cd
),
569 stats
.s_emmax
= MAX(stats
.s_emmax
, n
);
571 vlen
= sizeof (ctf_enum_t
) * n
;
575 if (flags
!= F_STATS
) {
576 (void) printf("FORWARD %s",
577 ref_to_str(tp
->ctt_name
, hp
, cd
));
582 if (flags
!= F_STATS
) {
583 (void) printf("TYPEDEF %s refers to %u",
584 ref_to_str(tp
->ctt_name
, hp
, cd
),
590 if (flags
!= F_STATS
) {
591 (void) printf("VOLATILE %s refers to %u",
592 ref_to_str(tp
->ctt_name
, hp
, cd
),
598 if (flags
!= F_STATS
) {
599 (void) printf("CONST %s refers to %u",
600 ref_to_str(tp
->ctt_name
, hp
, cd
),
606 if (flags
!= F_STATS
) {
607 (void) printf("RESTRICT %s refers to %u",
608 ref_to_str(tp
->ctt_name
, hp
, cd
),
614 break; /* hole in type id space */
617 (void) printf("unexpected kind %u\n", kind
);
621 if (flags
!= F_STATS
)
625 stats
.s_types
[kind
]++;
627 tp
= (ctf_type_t
*)((uintptr_t)tp
+ increment
+ vlen
);
634 read_strtab(const ctf_header_t
*hp
, const ctf_data_t
*cd
)
636 size_t n
, off
, len
= hp
->cth_strlen
;
637 const char *s
= cd
->cd_ctfdata
+ hp
->cth_stroff
;
639 if (flags
!= F_STATS
)
640 print_line("- String Table ");
642 if (hp
->cth_stroff
>= cd
->cd_ctflen
)
643 WARN("file is truncated or cth_stroff is corrupt\n");
644 if (hp
->cth_stroff
+ hp
->cth_strlen
> cd
->cd_ctflen
)
645 WARN("file is truncated or cth_strlen is corrupt\n");
647 for (off
= 0; len
!= 0; off
+= n
) {
648 if (flags
!= F_STATS
) {
649 (void) printf(" [%lu] %s\n", (ulong_t
)off
,
650 s
[0] == '\0' ? "\\0" : s
);
658 stats
.s_strmax
= MAX(stats
.s_strmax
, n
);
665 long_stat(const char *name
, ulong_t value
)
667 (void) printf(" %-36s= %lu\n", name
, value
);
671 fp_stat(const char *name
, float value
)
673 (void) printf(" %-36s= %.2f\n", name
, value
);
679 print_line("- CTF Statistics ");
681 long_stat("total number of data objects", stats
.s_ndata
);
684 long_stat("total number of functions", stats
.s_nfunc
);
685 long_stat("total number of function arguments", stats
.s_nargs
);
686 long_stat("maximum argument list length", stats
.s_argmax
);
688 if (stats
.s_nfunc
!= 0) {
689 fp_stat("average argument list length",
690 (float)stats
.s_nargs
/ (float)stats
.s_nfunc
);
695 long_stat("total number of types", stats
.s_ntypes
);
696 long_stat("total number of integers", stats
.s_types
[CTF_K_INTEGER
]);
697 long_stat("total number of floats", stats
.s_types
[CTF_K_FLOAT
]);
698 long_stat("total number of pointers", stats
.s_types
[CTF_K_POINTER
]);
699 long_stat("total number of arrays", stats
.s_types
[CTF_K_ARRAY
]);
700 long_stat("total number of func types", stats
.s_types
[CTF_K_FUNCTION
]);
701 long_stat("total number of structs", stats
.s_types
[CTF_K_STRUCT
]);
702 long_stat("total number of unions", stats
.s_types
[CTF_K_UNION
]);
703 long_stat("total number of enums", stats
.s_types
[CTF_K_ENUM
]);
704 long_stat("total number of forward tags", stats
.s_types
[CTF_K_FORWARD
]);
705 long_stat("total number of typedefs", stats
.s_types
[CTF_K_TYPEDEF
]);
706 long_stat("total number of volatile types",
707 stats
.s_types
[CTF_K_VOLATILE
]);
708 long_stat("total number of const types", stats
.s_types
[CTF_K_CONST
]);
709 long_stat("total number of restrict types",
710 stats
.s_types
[CTF_K_RESTRICT
]);
711 long_stat("total number of unknowns (holes)",
712 stats
.s_types
[CTF_K_UNKNOWN
]);
716 long_stat("total number of struct members", stats
.s_nsmem
);
717 long_stat("maximum number of struct members", stats
.s_smmax
);
718 long_stat("total size of all structs", stats
.s_nsbytes
);
719 long_stat("maximum size of a struct", stats
.s_sbmax
);
721 if (stats
.s_types
[CTF_K_STRUCT
] != 0) {
722 fp_stat("average number of struct members",
723 (float)stats
.s_nsmem
/ (float)stats
.s_types
[CTF_K_STRUCT
]);
724 fp_stat("average size of a struct", (float)stats
.s_nsbytes
/
725 (float)stats
.s_types
[CTF_K_STRUCT
]);
730 long_stat("total number of union members", stats
.s_numem
);
731 long_stat("maximum number of union members", stats
.s_ummax
);
732 long_stat("total size of all unions", stats
.s_nubytes
);
733 long_stat("maximum size of a union", stats
.s_ubmax
);
735 if (stats
.s_types
[CTF_K_UNION
] != 0) {
736 fp_stat("average number of union members",
737 (float)stats
.s_numem
/ (float)stats
.s_types
[CTF_K_UNION
]);
738 fp_stat("average size of a union", (float)stats
.s_nubytes
/
739 (float)stats
.s_types
[CTF_K_UNION
]);
744 long_stat("total number of enum members", stats
.s_nemem
);
745 long_stat("maximum number of enum members", stats
.s_emmax
);
747 if (stats
.s_types
[CTF_K_ENUM
] != 0) {
748 fp_stat("average number of enum members",
749 (float)stats
.s_nemem
/ (float)stats
.s_types
[CTF_K_ENUM
]);
754 long_stat("total number of unique strings", stats
.s_nstr
);
755 long_stat("bytes of string data", stats
.s_strlen
);
756 long_stat("maximum string length", stats
.s_strmax
);
758 if (stats
.s_nstr
!= 0) {
759 fp_stat("average string length",
760 (float)stats
.s_strlen
/ (float)stats
.s_nstr
);
768 print_usage(FILE *fp
, int verbose
)
770 (void) fprintf(fp
, "Usage: %s [-dfhlsSt] [-u file] file\n", getpname());
774 "\t-d dump data object section\n"
775 "\t-f dump function section\n"
776 "\t-h dump file header\n"
777 "\t-l dump label table\n"
778 "\t-s dump string table\n"
779 "\t-S dump statistics\n"
780 "\t-t dump type section\n"
781 "\t-u save uncompressed CTF to a file\n");
788 findelfscn(Elf
*elf
, GElf_Ehdr
*ehdr
, char *secname
)
794 for (scn
= NULL
; (scn
= elf_nextscn(elf
, scn
)) != NULL
; ) {
795 if (gelf_getshdr(scn
, &shdr
) != NULL
&& (name
=
796 elf_strptr(elf
, ehdr
->e_shstrndx
, shdr
.sh_name
)) != NULL
&&
797 strcmp(name
, secname
) == 0)
805 main(int argc
, char *argv
[])
807 const char *filename
= NULL
;
808 const char *ufile
= NULL
;
813 const ctf_preamble_t
*pp
;
818 (void) elf_version(EV_CURRENT
);
820 for (opterr
= 0; optind
< argc
; optind
++) {
821 while ((c
= getopt(argc
, argv
, "dfhlsStu:")) != (int)EOF
) {
849 return (print_usage(stdout
, 1));
850 warn("illegal option -- %c\n", optopt
);
851 return (print_usage(stderr
, 0));
856 if (filename
!= NULL
)
857 return (print_usage(stderr
, 0));
858 filename
= argv
[optind
];
862 if (filename
== NULL
)
863 return (print_usage(stderr
, 0));
865 if (flags
== 0 && ufile
== NULL
)
868 if ((fd
= open(filename
, O_RDONLY
)) == -1)
869 die("failed to open %s", filename
);
871 if ((elf
= elf_begin(fd
, ELF_C_READ
, NULL
)) != NULL
&&
872 gelf_getehdr(elf
, &ehdr
) != NULL
) {
875 Elf_Scn
*ctfscn
= findelfscn(elf
, &ehdr
, ".SUNW_ctf");
879 if (ctfscn
== NULL
|| (dp
= elf_getdata(ctfscn
, NULL
)) == NULL
)
880 die("%s does not contain .SUNW_ctf data\n", filename
);
882 cd
.cd_ctfdata
= dp
->d_buf
;
883 cd
.cd_ctflen
= dp
->d_size
;
886 * If the sh_link field of the CTF section header is non-zero
887 * it indicates which section contains the symbol table that
888 * should be used. We default to the .symtab section if sh_link
889 * is zero or if there's an error reading the section header.
891 if (gelf_getshdr(ctfscn
, &ctfshdr
) != NULL
&&
892 ctfshdr
.sh_link
!= 0) {
893 symscn
= elf_getscn(elf
, ctfshdr
.sh_link
);
895 symscn
= findelfscn(elf
, &ehdr
, ".symtab");
898 /* If we found a symbol table, find the corresponding strings */
899 if (symscn
!= NULL
) {
903 if (gelf_getshdr(symscn
, &shdr
) != NULL
) {
904 symstrscn
= elf_getscn(elf
, shdr
.sh_link
);
906 cd
.cd_nsyms
= shdr
.sh_size
/ shdr
.sh_entsize
;
907 cd
.cd_symdata
= elf_getdata(symscn
, NULL
);
908 cd
.cd_strdata
= elf_getdata(symstrscn
, NULL
);
914 if (fstat(fd
, &st
) == -1)
915 die("failed to fstat %s", filename
);
917 cd
.cd_ctflen
= st
.st_size
;
918 cd
.cd_ctfdata
= mmap(NULL
, cd
.cd_ctflen
, PROT_READ
,
920 if (cd
.cd_ctfdata
== MAP_FAILED
)
921 die("failed to mmap %s", filename
);
925 * Get a pointer to the CTF data buffer and interpret the first portion
926 * as a ctf_header_t. Validate the magic number and size.
929 if (cd
.cd_ctflen
< sizeof (ctf_preamble_t
))
930 die("%s does not contain a CTF preamble\n", filename
);
932 /* LINTED - pointer alignment */
933 pp
= (const ctf_preamble_t
*)cd
.cd_ctfdata
;
935 if (pp
->ctp_magic
!= CTF_MAGIC
)
936 die("%s does not appear to contain CTF data\n", filename
);
938 if (pp
->ctp_version
== CTF_VERSION
) {
939 /* LINTED - pointer alignment */
940 hp
= (ctf_header_t
*)cd
.cd_ctfdata
;
941 cd
.cd_ctfdata
= (caddr_t
)cd
.cd_ctfdata
+ sizeof (ctf_header_t
);
943 if (cd
.cd_ctflen
< sizeof (ctf_header_t
)) {
944 die("%s does not contain a v%d CTF header\n", filename
,
949 die("%s contains unsupported CTF version %d\n", filename
,
954 * If the data buffer is compressed, then malloc a buffer large enough
955 * to hold the decompressed data, and use zlib to decompress it.
957 if (hp
->cth_flags
& CTF_F_COMPRESS
) {
962 if ((buf
= malloc(hp
->cth_stroff
+ hp
->cth_strlen
)) == NULL
)
963 die("failed to allocate decompression buffer");
965 bzero(&zstr
, sizeof (z_stream
));
966 zstr
.next_in
= (void *)cd
.cd_ctfdata
;
967 zstr
.avail_in
= cd
.cd_ctflen
;
969 zstr
.avail_out
= hp
->cth_stroff
+ hp
->cth_strlen
;
971 if ((rc
= inflateInit(&zstr
)) != Z_OK
)
972 die("failed to initialize zlib: %s\n", zError(rc
));
974 if ((rc
= inflate(&zstr
, Z_FINISH
)) != Z_STREAM_END
)
975 die("failed to decompress CTF data: %s\n", zError(rc
));
977 if ((rc
= inflateEnd(&zstr
)) != Z_OK
)
978 die("failed to finish decompression: %s\n", zError(rc
));
980 if (zstr
.total_out
!= hp
->cth_stroff
+ hp
->cth_strlen
)
981 die("CTF data is corrupt -- short decompression\n");
984 cd
.cd_ctflen
= hp
->cth_stroff
+ hp
->cth_strlen
;
988 error
|= print_header(hp
, &cd
);
989 if (flags
& (F_LABEL
))
990 error
|= print_labeltable(hp
, &cd
);
991 if (flags
& (F_DATA
| F_STATS
))
992 error
|= read_data(hp
, &cd
);
993 if (flags
& (F_FUNC
| F_STATS
))
994 error
|= read_funcs(hp
, &cd
);
995 if (flags
& (F_TYPES
| F_STATS
))
996 error
|= read_types(hp
, &cd
);
997 if (flags
& (F_STR
| F_STATS
))
998 error
|= read_strtab(hp
, &cd
);
1000 error
|= print_stats();
1003 * If the -u option is specified, write the uncompressed CTF data to a
1004 * raw CTF file. CTF data can already be extracted compressed by
1005 * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother.
1007 if (ufile
!= NULL
) {
1010 bcopy(hp
, &h
, sizeof (h
));
1011 h
.cth_flags
&= ~CTF_F_COMPRESS
;
1013 if ((ufd
= open(ufile
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0666)) < 0 ||
1014 write(ufd
, &h
, sizeof (h
)) != sizeof (h
) ||
1015 write(ufd
, cd
.cd_ctfdata
, cd
.cd_ctflen
) != cd
.cd_ctflen
) {
1016 warn("failed to write CTF data to '%s'", ufile
);
1024 (void) elf_end(elf
);