1178481Sjb/* 2178481Sjb * CDDL HEADER START 3178481Sjb * 4178481Sjb * The contents of this file are subject to the terms of the 5178481Sjb * Common Development and Distribution License, Version 1.0 only 6178481Sjb * (the "License"). You may not use this file except in compliance 7178481Sjb * with the License. 8178481Sjb * 9178481Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10178481Sjb * or http://www.opensolaris.org/os/licensing. 11178481Sjb * See the License for the specific language governing permissions 12178481Sjb * and limitations under the License. 13178481Sjb * 14178481Sjb * When distributing Covered Code, include this CDDL HEADER in each 15178481Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16178481Sjb * If applicable, add the following below this CDDL HEADER, with the 17178481Sjb * fields enclosed by brackets "[]" replaced with your own identifying 18178481Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 19178481Sjb * 20178481Sjb * CDDL HEADER END 21178481Sjb */ 22178481Sjb/* 23178481Sjb * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24178481Sjb * Use is subject to license terms. 25178481Sjb */ 26178481Sjb 27178481Sjb#pragma ident "%Z%%M% %I% %E% SMI" 28178481Sjb 29178481Sjb#include <sys/types.h> 30178481Sjb#include <sys/sysmacros.h> 31178481Sjb#include <sys/stat.h> 32178481Sjb#include <sys/mman.h> 33178481Sjb 34178481Sjb#include <strings.h> 35178481Sjb#include <unistd.h> 36178481Sjb#include <stdlib.h> 37178481Sjb#include <stdio.h> 38178481Sjb#include <fcntl.h> 39178481Sjb#include <gelf.h> 40178481Sjb#include <zlib.h> 41178481Sjb 42178481Sjb#include "ctf_headers.h" 43178481Sjb#include "utils.h" 44178481Sjb#include "symbol.h" 45178481Sjb 46178481Sjb#define WARN(x) { warn(x); return (E_ERROR); } 47178481Sjb 48178481Sjb/* 49178481Sjb * Flags that indicate what data is to be displayed. An explicit `all' value is 50178481Sjb * provided to allow the code to distinguish between a request for everything 51178481Sjb * (currently requested by invoking ctfdump without flags) and individual 52178481Sjb * requests for all of the types of data (an invocation with all flags). In the 53178481Sjb * former case, we want to be able to implicitly adjust the definition of `all' 54178481Sjb * based on the CTF version of the file being dumped. For example, if a v2 file 55178481Sjb * is being dumped, `all' includes F_LABEL - a request to dump the label 56178481Sjb * section. If a v1 file is being dumped, `all' does not include F_LABEL, 57178481Sjb * because v1 CTF doesn't support labels. We need to be able to distinguish 58178481Sjb * between `ctfdump foo', which has an implicit request for labels if `foo' 59178481Sjb * supports them, and `ctfdump -l foo', which has an explicity request. In the 60178481Sjb * latter case, we exit with an error if `foo' is a v1 CTF file. 61178481Sjb */ 62178481Sjbstatic enum { 63178481Sjb F_DATA = 0x01, /* show data object section */ 64178481Sjb F_FUNC = 0x02, /* show function section */ 65178481Sjb F_HDR = 0x04, /* show header */ 66178481Sjb F_STR = 0x08, /* show string table */ 67178481Sjb F_TYPES = 0x10, /* show type section */ 68178481Sjb F_STATS = 0x20, /* show statistics */ 69178481Sjb F_LABEL = 0x40, /* show label section */ 70178481Sjb F_ALL = 0x80, /* explicit request for `all' */ 71178481Sjb F_ALLMSK = 0xff /* show all sections and statistics */ 72178481Sjb} flags = 0; 73178481Sjb 74178481Sjbstatic struct { 75178481Sjb ulong_t s_ndata; /* total number of data objects */ 76178481Sjb ulong_t s_nfunc; /* total number of functions */ 77178481Sjb ulong_t s_nargs; /* total number of function arguments */ 78178481Sjb ulong_t s_argmax; /* longest argument list */ 79178481Sjb ulong_t s_ntypes; /* total number of types */ 80178481Sjb ulong_t s_types[16]; /* number of types by kind */ 81178481Sjb ulong_t s_nsmem; /* total number of struct members */ 82178481Sjb ulong_t s_nsbytes; /* total size of all structs */ 83178481Sjb ulong_t s_smmax; /* largest struct in terms of members */ 84178481Sjb ulong_t s_sbmax; /* largest struct in terms of bytes */ 85178481Sjb ulong_t s_numem; /* total number of union members */ 86178481Sjb ulong_t s_nubytes; /* total size of all unions */ 87178481Sjb ulong_t s_ummax; /* largest union in terms of members */ 88178481Sjb ulong_t s_ubmax; /* largest union in terms of bytes */ 89178481Sjb ulong_t s_nemem; /* total number of enum members */ 90178481Sjb ulong_t s_emmax; /* largest enum in terms of members */ 91178481Sjb ulong_t s_nstr; /* total number of strings */ 92178481Sjb size_t s_strlen; /* total length of all strings */ 93178481Sjb size_t s_strmax; /* longest string length */ 94178481Sjb} stats; 95178481Sjb 96178481Sjbtypedef struct ctf_data { 97178481Sjb caddr_t cd_ctfdata; /* Pointer to the CTF data */ 98178481Sjb size_t cd_ctflen; /* Length of CTF data */ 99178481Sjb 100178481Sjb /* 101178481Sjb * cd_symdata will be non-NULL if the CTF data is being retrieved from 102178481Sjb * an ELF file with a symbol table. cd_strdata and cd_nsyms should be 103178481Sjb * used only if cd_symdata is non-NULL. 104178481Sjb */ 105178481Sjb Elf_Data *cd_symdata; /* Symbol table */ 106178481Sjb Elf_Data *cd_strdata; /* Symbol table strings */ 107178481Sjb int cd_nsyms; /* Number of symbol table entries */ 108178481Sjb} ctf_data_t; 109178481Sjb 110178481Sjbstatic const char * 111178481Sjbref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd) 112178481Sjb{ 113178481Sjb size_t offset = CTF_NAME_OFFSET(name); 114178481Sjb const char *s = cd->cd_ctfdata + hp->cth_stroff + offset; 115178481Sjb 116178481Sjb if (CTF_NAME_STID(name) != CTF_STRTAB_0) 117178481Sjb return ("<< ??? - name in external strtab >>"); 118178481Sjb 119178481Sjb if (offset >= hp->cth_strlen) 120178481Sjb return ("<< ??? - name exceeds strlab len >>"); 121178481Sjb 122178481Sjb if (hp->cth_stroff + offset >= cd->cd_ctflen) 123178481Sjb return ("<< ??? - file truncated >>"); 124178481Sjb 125178481Sjb if (s[0] == '\0') 126178481Sjb return ("(anon)"); 127178481Sjb 128178481Sjb return (s); 129178481Sjb} 130178481Sjb 131178481Sjbstatic const char * 132178481Sjbint_encoding_to_str(uint_t encoding) 133178481Sjb{ 134178481Sjb static char buf[32]; 135178481Sjb 136178481Sjb if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR | 137178481Sjb CTF_INT_BOOL | CTF_INT_VARARGS)) != 0) 138178481Sjb (void) snprintf(buf, sizeof (buf), " 0x%x", encoding); 139178481Sjb else { 140178481Sjb buf[0] = '\0'; 141178481Sjb if (encoding & CTF_INT_SIGNED) 142178481Sjb (void) strcat(buf, " SIGNED"); 143178481Sjb if (encoding & CTF_INT_CHAR) 144178481Sjb (void) strcat(buf, " CHAR"); 145178481Sjb if (encoding & CTF_INT_BOOL) 146178481Sjb (void) strcat(buf, " BOOL"); 147178481Sjb if (encoding & CTF_INT_VARARGS) 148178481Sjb (void) strcat(buf, " VARARGS"); 149178481Sjb } 150178481Sjb 151178481Sjb return (buf + 1); 152178481Sjb} 153178481Sjb 154178481Sjbstatic const char * 155178481Sjbfp_encoding_to_str(uint_t encoding) 156178481Sjb{ 157178481Sjb static const char *const encs[] = { 158178481Sjb NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX", 159178481Sjb "LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY", 160178481Sjb "DIMAGINARY", "LDIMAGINARY" 161178481Sjb }; 162178481Sjb 163178481Sjb static char buf[16]; 164178481Sjb 165178481Sjb if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) { 166178481Sjb (void) snprintf(buf, sizeof (buf), "%u", encoding); 167178481Sjb return (buf); 168178481Sjb } 169178481Sjb 170178481Sjb return (encs[encoding]); 171178481Sjb} 172178481Sjb 173178481Sjbstatic void 174178481Sjbprint_line(const char *s) 175178481Sjb{ 176178481Sjb static const char line[] = "----------------------------------------" 177178481Sjb "----------------------------------------"; 178178481Sjb (void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line); 179178481Sjb} 180178481Sjb 181178481Sjbstatic int 182178481Sjbprint_header(const ctf_header_t *hp, const ctf_data_t *cd) 183178481Sjb{ 184178481Sjb print_line("- CTF Header "); 185178481Sjb 186178481Sjb (void) printf(" cth_magic = 0x%04x\n", hp->cth_magic); 187178481Sjb (void) printf(" cth_version = %u\n", hp->cth_version); 188178481Sjb (void) printf(" cth_flags = 0x%02x\n", hp->cth_flags); 189178481Sjb (void) printf(" cth_parlabel = %s\n", 190178481Sjb ref_to_str(hp->cth_parlabel, hp, cd)); 191178481Sjb (void) printf(" cth_parname = %s\n", 192178481Sjb ref_to_str(hp->cth_parname, hp, cd)); 193178481Sjb (void) printf(" cth_lbloff = %u\n", hp->cth_lbloff); 194178481Sjb (void) printf(" cth_objtoff = %u\n", hp->cth_objtoff); 195178481Sjb (void) printf(" cth_funcoff = %u\n", hp->cth_funcoff); 196178481Sjb (void) printf(" cth_typeoff = %u\n", hp->cth_typeoff); 197178481Sjb (void) printf(" cth_stroff = %u\n", hp->cth_stroff); 198178481Sjb (void) printf(" cth_strlen = %u\n", hp->cth_strlen); 199178481Sjb 200178481Sjb return (E_SUCCESS); 201178481Sjb} 202178481Sjb 203178481Sjbstatic int 204178481Sjbprint_labeltable(const ctf_header_t *hp, const ctf_data_t *cd) 205178481Sjb{ 206178542Sjb void *v = (void *) (cd->cd_ctfdata + hp->cth_lbloff); 207178542Sjb const ctf_lblent_t *ctl = v; 208178481Sjb ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl); 209178481Sjb 210178481Sjb print_line("- Label Table "); 211178481Sjb 212178481Sjb if (hp->cth_lbloff & 3) 213178481Sjb WARN("cth_lbloff is not aligned properly\n"); 214178481Sjb if (hp->cth_lbloff >= cd->cd_ctflen) 215178481Sjb WARN("file is truncated or cth_lbloff is corrupt\n"); 216178481Sjb if (hp->cth_objtoff >= cd->cd_ctflen) 217178481Sjb WARN("file is truncated or cth_objtoff is corrupt\n"); 218178481Sjb if (hp->cth_lbloff > hp->cth_objtoff) 219178481Sjb WARN("file is corrupt -- cth_lbloff > cth_objtoff\n"); 220178481Sjb 221178481Sjb for (i = 0; i < n; i++, ctl++) { 222178481Sjb (void) printf(" %5u %s\n", ctl->ctl_typeidx, 223178481Sjb ref_to_str(ctl->ctl_label, hp, cd)); 224178481Sjb } 225178481Sjb 226178481Sjb return (E_SUCCESS); 227178481Sjb} 228178481Sjb 229178481Sjb/* 230178481Sjb * Given the current symbol index (-1 to start at the beginning of the symbol 231178481Sjb * table) and the type of symbol to match, this function returns the index of 232178481Sjb * the next matching symbol (if any), and places the name of that symbol in 233178481Sjb * *namep. If no symbol is found, -1 is returned. 234178481Sjb */ 235178481Sjbstatic int 236178481Sjbnext_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype, 237178481Sjb char **namep) 238178481Sjb{ 239178481Sjb int i; 240178481Sjb 241178481Sjb for (i = symidx + 1; i < cd->cd_nsyms; i++) { 242178481Sjb GElf_Sym sym; 243178481Sjb char *name; 244178481Sjb int type; 245178481Sjb 246178481Sjb if (gelf_getsym(cd->cd_symdata, i, &sym) == 0) 247178481Sjb return (-1); 248178481Sjb 249178481Sjb name = (char *)cd->cd_strdata->d_buf + sym.st_name; 250178481Sjb type = GELF_ST_TYPE(sym.st_info); 251178481Sjb 252178481Sjb /* 253178481Sjb * Skip various types of symbol table entries. 254178481Sjb */ 255178481Sjb if (type != matchtype || ignore_symbol(&sym, name)) 256178481Sjb continue; 257178481Sjb 258178481Sjb /* Found one */ 259178481Sjb *namep = name; 260178481Sjb return (i); 261178481Sjb } 262178481Sjb 263178481Sjb return (-1); 264178481Sjb} 265178481Sjb 266178481Sjbstatic int 267178481Sjbread_data(const ctf_header_t *hp, const ctf_data_t *cd) 268178481Sjb{ 269178542Sjb void *v = (void *) (cd->cd_ctfdata + hp->cth_objtoff); 270178542Sjb const ushort_t *idp = v; 271178481Sjb ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / sizeof (ushort_t); 272178481Sjb 273178481Sjb if (flags != F_STATS) 274178481Sjb print_line("- Data Objects "); 275178481Sjb 276178481Sjb if (hp->cth_objtoff & 1) 277178481Sjb WARN("cth_objtoff is not aligned properly\n"); 278178481Sjb if (hp->cth_objtoff >= cd->cd_ctflen) 279178481Sjb WARN("file is truncated or cth_objtoff is corrupt\n"); 280178481Sjb if (hp->cth_funcoff >= cd->cd_ctflen) 281178481Sjb WARN("file is truncated or cth_funcoff is corrupt\n"); 282178481Sjb if (hp->cth_objtoff > hp->cth_funcoff) 283178481Sjb WARN("file is corrupt -- cth_objtoff > cth_funcoff\n"); 284178481Sjb 285178481Sjb if (flags != F_STATS) { 286178481Sjb int symidx, len, i; 287178481Sjb char *name = NULL; 288178481Sjb 289178542Sjb for (symidx = -1, i = 0; i < (int) n; i++) { 290178481Sjb int nextsym; 291178481Sjb 292178481Sjb if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, 293178481Sjb symidx, STT_OBJECT, &name)) < 0) 294178481Sjb name = NULL; 295178481Sjb else 296178481Sjb symidx = nextsym; 297178481Sjb 298178481Sjb len = printf(" [%u] %u", i, *idp++); 299178481Sjb if (name != NULL) 300178481Sjb (void) printf("%*s%s (%u)", (15 - len), "", 301178481Sjb name, symidx); 302178481Sjb (void) putchar('\n'); 303178481Sjb } 304178481Sjb } 305178481Sjb 306178481Sjb stats.s_ndata = n; 307178481Sjb return (E_SUCCESS); 308178481Sjb} 309178481Sjb 310178481Sjbstatic int 311178481Sjbread_funcs(const ctf_header_t *hp, const ctf_data_t *cd) 312178481Sjb{ 313178542Sjb void *v = (void *) (cd->cd_ctfdata + hp->cth_funcoff); 314178542Sjb const ushort_t *fp = v; 315178481Sjb 316178542Sjb v = (void *) (cd->cd_ctfdata + hp->cth_typeoff); 317178542Sjb const ushort_t *end = v; 318178481Sjb 319178481Sjb ulong_t id; 320178481Sjb int symidx; 321178481Sjb 322178481Sjb if (flags != F_STATS) 323178481Sjb print_line("- Functions "); 324178481Sjb 325178481Sjb if (hp->cth_funcoff & 1) 326178481Sjb WARN("cth_funcoff is not aligned properly\n"); 327178481Sjb if (hp->cth_funcoff >= cd->cd_ctflen) 328178481Sjb WARN("file is truncated or cth_funcoff is corrupt\n"); 329178481Sjb if (hp->cth_typeoff >= cd->cd_ctflen) 330178481Sjb WARN("file is truncated or cth_typeoff is corrupt\n"); 331178481Sjb if (hp->cth_funcoff > hp->cth_typeoff) 332178481Sjb WARN("file is corrupt -- cth_funcoff > cth_typeoff\n"); 333178481Sjb 334178481Sjb for (symidx = -1, id = 0; fp < end; id++) { 335178481Sjb ushort_t info = *fp++; 336178481Sjb ushort_t kind = CTF_INFO_KIND(info); 337178481Sjb ushort_t n = CTF_INFO_VLEN(info); 338178481Sjb ushort_t i; 339178481Sjb int nextsym; 340178481Sjb char *name; 341178481Sjb 342178481Sjb if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx, 343178481Sjb STT_FUNC, &name)) < 0) 344178481Sjb name = NULL; 345178481Sjb else 346178481Sjb symidx = nextsym; 347178481Sjb 348178481Sjb if (kind == CTF_K_UNKNOWN && n == 0) 349178481Sjb continue; /* skip padding */ 350178481Sjb 351178481Sjb if (kind != CTF_K_FUNCTION) { 352178481Sjb (void) printf(" [%lu] unexpected kind -- %u\n", 353178481Sjb id, kind); 354178481Sjb return (E_ERROR); 355178481Sjb } 356178481Sjb 357178481Sjb if (fp + n > end) { 358178481Sjb (void) printf(" [%lu] vlen %u extends past section " 359178481Sjb "boundary\n", id, n); 360178481Sjb return (E_ERROR); 361178481Sjb } 362178481Sjb 363178481Sjb if (flags != F_STATS) { 364178481Sjb (void) printf(" [%lu] FUNC ", id); 365178481Sjb if (name != NULL) 366178481Sjb (void) printf("(%s) ", name); 367178481Sjb (void) printf("returns: %u args: (", *fp++); 368178481Sjb 369178481Sjb if (n != 0) { 370178481Sjb (void) printf("%u", *fp++); 371178481Sjb for (i = 1; i < n; i++) 372178481Sjb (void) printf(", %u", *fp++); 373178481Sjb } 374178481Sjb 375178481Sjb (void) printf(")\n"); 376178481Sjb } else 377178481Sjb fp += n + 1; /* skip to next function definition */ 378178481Sjb 379178481Sjb stats.s_nfunc++; 380178481Sjb stats.s_nargs += n; 381178481Sjb stats.s_argmax = MAX(stats.s_argmax, n); 382178481Sjb } 383178481Sjb 384178481Sjb return (E_SUCCESS); 385178481Sjb} 386178481Sjb 387178481Sjbstatic int 388178481Sjbread_types(const ctf_header_t *hp, const ctf_data_t *cd) 389178481Sjb{ 390178542Sjb void *v = (void *) (cd->cd_ctfdata + hp->cth_typeoff); 391178542Sjb const ctf_type_t *tp = v; 392178481Sjb 393178542Sjb v = (void *) (cd->cd_ctfdata + hp->cth_stroff); 394178542Sjb const ctf_type_t *end = v; 395178481Sjb 396178481Sjb ulong_t id; 397178481Sjb 398178481Sjb if (flags != F_STATS) 399178481Sjb print_line("- Types "); 400178481Sjb 401178481Sjb if (hp->cth_typeoff & 3) 402178481Sjb WARN("cth_typeoff is not aligned properly\n"); 403178481Sjb if (hp->cth_typeoff >= cd->cd_ctflen) 404178481Sjb WARN("file is truncated or cth_typeoff is corrupt\n"); 405178481Sjb if (hp->cth_stroff >= cd->cd_ctflen) 406178481Sjb WARN("file is truncated or cth_stroff is corrupt\n"); 407178481Sjb if (hp->cth_typeoff > hp->cth_stroff) 408178481Sjb WARN("file is corrupt -- cth_typeoff > cth_stroff\n"); 409178481Sjb 410178481Sjb id = 1; 411178481Sjb if (hp->cth_parlabel || hp->cth_parname) 412178481Sjb id += 1 << CTF_PARENT_SHIFT; 413178481Sjb 414178481Sjb for (/* */; tp < end; id++) { 415178481Sjb ulong_t i, n = CTF_INFO_VLEN(tp->ctt_info); 416178481Sjb size_t size, increment, vlen = 0; 417178481Sjb int kind = CTF_INFO_KIND(tp->ctt_info); 418178481Sjb 419178481Sjb union { 420178481Sjb const void *ptr; 421178542Sjb ctf_array_t *ap; 422178481Sjb const ctf_member_t *mp; 423178481Sjb const ctf_lmember_t *lmp; 424178481Sjb const ctf_enum_t *ep; 425178481Sjb const ushort_t *argp; 426178481Sjb } u; 427178481Sjb 428178481Sjb if (flags != F_STATS) { 429178481Sjb (void) printf(" %c%lu%c ", 430178481Sjb "[<"[CTF_INFO_ISROOT(tp->ctt_info)], id, 431178481Sjb "]>"[CTF_INFO_ISROOT(tp->ctt_info)]); 432178481Sjb } 433178481Sjb 434178481Sjb if (tp->ctt_size == CTF_LSIZE_SENT) { 435178481Sjb increment = sizeof (ctf_type_t); 436178481Sjb size = (size_t)CTF_TYPE_LSIZE(tp); 437178481Sjb } else { 438178481Sjb increment = sizeof (ctf_stype_t); 439178481Sjb size = tp->ctt_size; 440178481Sjb } 441178542Sjb u.ptr = (const char *)tp + increment; 442178481Sjb 443178481Sjb switch (kind) { 444178481Sjb case CTF_K_INTEGER: 445178481Sjb if (flags != F_STATS) { 446178481Sjb uint_t encoding = *((const uint_t *)u.ptr); 447178481Sjb 448178481Sjb (void) printf("INTEGER %s encoding=%s offset=%u" 449178481Sjb " bits=%u", ref_to_str(tp->ctt_name, hp, 450178481Sjb cd), int_encoding_to_str( 451178481Sjb CTF_INT_ENCODING(encoding)), 452178481Sjb CTF_INT_OFFSET(encoding), 453178481Sjb CTF_INT_BITS(encoding)); 454178481Sjb } 455178481Sjb vlen = sizeof (uint_t); 456178481Sjb break; 457178481Sjb 458178481Sjb case CTF_K_FLOAT: 459178481Sjb if (flags != F_STATS) { 460178481Sjb uint_t encoding = *((const uint_t *)u.ptr); 461178481Sjb 462178481Sjb (void) printf("FLOAT %s encoding=%s offset=%u " 463178481Sjb "bits=%u", ref_to_str(tp->ctt_name, hp, 464178481Sjb cd), fp_encoding_to_str( 465178481Sjb CTF_FP_ENCODING(encoding)), 466178481Sjb CTF_FP_OFFSET(encoding), 467178481Sjb CTF_FP_BITS(encoding)); 468178481Sjb } 469178481Sjb vlen = sizeof (uint_t); 470178481Sjb break; 471178481Sjb 472178481Sjb case CTF_K_POINTER: 473178481Sjb if (flags != F_STATS) { 474178481Sjb (void) printf("POINTER %s refers to %u", 475178481Sjb ref_to_str(tp->ctt_name, hp, cd), 476178481Sjb tp->ctt_type); 477178481Sjb } 478178481Sjb break; 479178481Sjb 480178481Sjb case CTF_K_ARRAY: 481178481Sjb if (flags != F_STATS) { 482178481Sjb (void) printf("ARRAY %s content: %u index: %u " 483178481Sjb "nelems: %u\n", ref_to_str(tp->ctt_name, 484178481Sjb hp, cd), u.ap->cta_contents, 485178481Sjb u.ap->cta_index, u.ap->cta_nelems); 486178481Sjb } 487178481Sjb vlen = sizeof (ctf_array_t); 488178481Sjb break; 489178481Sjb 490178481Sjb case CTF_K_FUNCTION: 491178481Sjb if (flags != F_STATS) { 492178481Sjb (void) printf("FUNCTION %s returns: %u args: (", 493178481Sjb ref_to_str(tp->ctt_name, hp, cd), 494178481Sjb tp->ctt_type); 495178481Sjb 496178481Sjb if (n != 0) { 497178481Sjb (void) printf("%u", *u.argp++); 498178481Sjb for (i = 1; i < n; i++, u.argp++) 499178481Sjb (void) printf(", %u", *u.argp); 500178481Sjb } 501178481Sjb 502178481Sjb (void) printf(")"); 503178481Sjb } 504178481Sjb 505178481Sjb vlen = sizeof (ushort_t) * (n + (n & 1)); 506178481Sjb break; 507178481Sjb 508178481Sjb case CTF_K_STRUCT: 509178481Sjb case CTF_K_UNION: 510178481Sjb if (kind == CTF_K_STRUCT) { 511178481Sjb stats.s_nsmem += n; 512178481Sjb stats.s_smmax = MAX(stats.s_smmax, n); 513178481Sjb stats.s_nsbytes += size; 514178481Sjb stats.s_sbmax = MAX(stats.s_sbmax, size); 515178481Sjb 516178481Sjb if (flags != F_STATS) 517178481Sjb (void) printf("STRUCT"); 518178481Sjb } else { 519178481Sjb stats.s_numem += n; 520178481Sjb stats.s_ummax = MAX(stats.s_ummax, n); 521178481Sjb stats.s_nubytes += size; 522178481Sjb stats.s_ubmax = MAX(stats.s_ubmax, size); 523178481Sjb 524178481Sjb if (flags != F_STATS) 525178481Sjb (void) printf("UNION"); 526178481Sjb } 527178481Sjb 528178481Sjb if (flags != F_STATS) { 529178542Sjb (void) printf(" %s (%zd bytes)\n", 530178481Sjb ref_to_str(tp->ctt_name, hp, cd), size); 531178481Sjb 532178481Sjb if (size >= CTF_LSTRUCT_THRESH) { 533178481Sjb for (i = 0; i < n; i++, u.lmp++) { 534178481Sjb (void) printf( 535178481Sjb "\t%s type=%u off=%llu\n", 536178481Sjb ref_to_str(u.lmp->ctlm_name, 537178481Sjb hp, cd), u.lmp->ctlm_type, 538178542Sjb (unsigned long long) 539178481Sjb CTF_LMEM_OFFSET(u.lmp)); 540178481Sjb } 541178481Sjb } else { 542178481Sjb for (i = 0; i < n; i++, u.mp++) { 543178481Sjb (void) printf( 544178481Sjb "\t%s type=%u off=%u\n", 545178481Sjb ref_to_str(u.mp->ctm_name, 546178481Sjb hp, cd), u.mp->ctm_type, 547178481Sjb u.mp->ctm_offset); 548178481Sjb } 549178481Sjb } 550178481Sjb } 551178481Sjb 552178481Sjb vlen = n * (size >= CTF_LSTRUCT_THRESH ? 553178481Sjb sizeof (ctf_lmember_t) : sizeof (ctf_member_t)); 554178481Sjb break; 555178481Sjb 556178481Sjb case CTF_K_ENUM: 557178481Sjb if (flags != F_STATS) { 558178481Sjb (void) printf("ENUM %s\n", 559178481Sjb ref_to_str(tp->ctt_name, hp, cd)); 560178481Sjb 561178481Sjb for (i = 0; i < n; i++, u.ep++) { 562178481Sjb (void) printf("\t%s = %d\n", 563178481Sjb ref_to_str(u.ep->cte_name, hp, cd), 564178481Sjb u.ep->cte_value); 565178481Sjb } 566178481Sjb } 567178481Sjb 568178481Sjb stats.s_nemem += n; 569178481Sjb stats.s_emmax = MAX(stats.s_emmax, n); 570178481Sjb 571178481Sjb vlen = sizeof (ctf_enum_t) * n; 572178481Sjb break; 573178481Sjb 574178481Sjb case CTF_K_FORWARD: 575178481Sjb if (flags != F_STATS) { 576178481Sjb (void) printf("FORWARD %s", 577178481Sjb ref_to_str(tp->ctt_name, hp, cd)); 578178481Sjb } 579178481Sjb break; 580178481Sjb 581178481Sjb case CTF_K_TYPEDEF: 582178481Sjb if (flags != F_STATS) { 583178481Sjb (void) printf("TYPEDEF %s refers to %u", 584178481Sjb ref_to_str(tp->ctt_name, hp, cd), 585178481Sjb tp->ctt_type); 586178481Sjb } 587178481Sjb break; 588178481Sjb 589178481Sjb case CTF_K_VOLATILE: 590178481Sjb if (flags != F_STATS) { 591178481Sjb (void) printf("VOLATILE %s refers to %u", 592178481Sjb ref_to_str(tp->ctt_name, hp, cd), 593178481Sjb tp->ctt_type); 594178481Sjb } 595178481Sjb break; 596178481Sjb 597178481Sjb case CTF_K_CONST: 598178481Sjb if (flags != F_STATS) { 599178481Sjb (void) printf("CONST %s refers to %u", 600178481Sjb ref_to_str(tp->ctt_name, hp, cd), 601178481Sjb tp->ctt_type); 602178481Sjb } 603178481Sjb break; 604178481Sjb 605178481Sjb case CTF_K_RESTRICT: 606178481Sjb if (flags != F_STATS) { 607178481Sjb (void) printf("RESTRICT %s refers to %u", 608178481Sjb ref_to_str(tp->ctt_name, hp, cd), 609178481Sjb tp->ctt_type); 610178481Sjb } 611178481Sjb break; 612178481Sjb 613178481Sjb case CTF_K_UNKNOWN: 614178481Sjb break; /* hole in type id space */ 615178481Sjb 616178481Sjb default: 617178481Sjb (void) printf("unexpected kind %u\n", kind); 618178481Sjb return (E_ERROR); 619178481Sjb } 620178481Sjb 621178481Sjb if (flags != F_STATS) 622178481Sjb (void) printf("\n"); 623178481Sjb 624178481Sjb stats.s_ntypes++; 625178481Sjb stats.s_types[kind]++; 626178481Sjb 627178481Sjb tp = (ctf_type_t *)((uintptr_t)tp + increment + vlen); 628178481Sjb } 629178481Sjb 630178481Sjb return (E_SUCCESS); 631178481Sjb} 632178481Sjb 633178481Sjbstatic int 634178481Sjbread_strtab(const ctf_header_t *hp, const ctf_data_t *cd) 635178481Sjb{ 636178481Sjb size_t n, off, len = hp->cth_strlen; 637178481Sjb const char *s = cd->cd_ctfdata + hp->cth_stroff; 638178481Sjb 639178481Sjb if (flags != F_STATS) 640178481Sjb print_line("- String Table "); 641178481Sjb 642178481Sjb if (hp->cth_stroff >= cd->cd_ctflen) 643178481Sjb WARN("file is truncated or cth_stroff is corrupt\n"); 644178481Sjb if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen) 645178481Sjb WARN("file is truncated or cth_strlen is corrupt\n"); 646178481Sjb 647178481Sjb for (off = 0; len != 0; off += n) { 648178481Sjb if (flags != F_STATS) { 649178481Sjb (void) printf(" [%lu] %s\n", (ulong_t)off, 650178481Sjb s[0] == '\0' ? "\\0" : s); 651178481Sjb } 652178481Sjb n = strlen(s) + 1; 653178481Sjb len -= n; 654178481Sjb s += n; 655178481Sjb 656178481Sjb stats.s_nstr++; 657178481Sjb stats.s_strlen += n; 658178481Sjb stats.s_strmax = MAX(stats.s_strmax, n); 659178481Sjb } 660178481Sjb 661178481Sjb return (E_SUCCESS); 662178481Sjb} 663178481Sjb 664178481Sjbstatic void 665178481Sjblong_stat(const char *name, ulong_t value) 666178481Sjb{ 667178481Sjb (void) printf(" %-36s= %lu\n", name, value); 668178481Sjb} 669178481Sjb 670178481Sjbstatic void 671178481Sjbfp_stat(const char *name, float value) 672178481Sjb{ 673178481Sjb (void) printf(" %-36s= %.2f\n", name, value); 674178481Sjb} 675178481Sjb 676178481Sjbstatic int 677178481Sjbprint_stats(void) 678178481Sjb{ 679178481Sjb print_line("- CTF Statistics "); 680178481Sjb 681178481Sjb long_stat("total number of data objects", stats.s_ndata); 682178481Sjb (void) printf("\n"); 683178481Sjb 684178481Sjb long_stat("total number of functions", stats.s_nfunc); 685178481Sjb long_stat("total number of function arguments", stats.s_nargs); 686178481Sjb long_stat("maximum argument list length", stats.s_argmax); 687178481Sjb 688178481Sjb if (stats.s_nfunc != 0) { 689178481Sjb fp_stat("average argument list length", 690178481Sjb (float)stats.s_nargs / (float)stats.s_nfunc); 691178481Sjb } 692178481Sjb 693178481Sjb (void) printf("\n"); 694178481Sjb 695178481Sjb long_stat("total number of types", stats.s_ntypes); 696178481Sjb long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]); 697178481Sjb long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]); 698178481Sjb long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]); 699178481Sjb long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]); 700178481Sjb long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]); 701178481Sjb long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]); 702178481Sjb long_stat("total number of unions", stats.s_types[CTF_K_UNION]); 703178481Sjb long_stat("total number of enums", stats.s_types[CTF_K_ENUM]); 704178481Sjb long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]); 705178481Sjb long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]); 706178481Sjb long_stat("total number of volatile types", 707178481Sjb stats.s_types[CTF_K_VOLATILE]); 708178481Sjb long_stat("total number of const types", stats.s_types[CTF_K_CONST]); 709178481Sjb long_stat("total number of restrict types", 710178481Sjb stats.s_types[CTF_K_RESTRICT]); 711178481Sjb long_stat("total number of unknowns (holes)", 712178481Sjb stats.s_types[CTF_K_UNKNOWN]); 713178481Sjb 714178481Sjb (void) printf("\n"); 715178481Sjb 716178481Sjb long_stat("total number of struct members", stats.s_nsmem); 717178481Sjb long_stat("maximum number of struct members", stats.s_smmax); 718178481Sjb long_stat("total size of all structs", stats.s_nsbytes); 719178481Sjb long_stat("maximum size of a struct", stats.s_sbmax); 720178481Sjb 721178481Sjb if (stats.s_types[CTF_K_STRUCT] != 0) { 722178481Sjb fp_stat("average number of struct members", 723178481Sjb (float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]); 724178481Sjb fp_stat("average size of a struct", (float)stats.s_nsbytes / 725178481Sjb (float)stats.s_types[CTF_K_STRUCT]); 726178481Sjb } 727178481Sjb 728178481Sjb (void) printf("\n"); 729178481Sjb 730178481Sjb long_stat("total number of union members", stats.s_numem); 731178481Sjb long_stat("maximum number of union members", stats.s_ummax); 732178481Sjb long_stat("total size of all unions", stats.s_nubytes); 733178481Sjb long_stat("maximum size of a union", stats.s_ubmax); 734178481Sjb 735178481Sjb if (stats.s_types[CTF_K_UNION] != 0) { 736178481Sjb fp_stat("average number of union members", 737178481Sjb (float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]); 738178481Sjb fp_stat("average size of a union", (float)stats.s_nubytes / 739178481Sjb (float)stats.s_types[CTF_K_UNION]); 740178481Sjb } 741178481Sjb 742178481Sjb (void) printf("\n"); 743178481Sjb 744178481Sjb long_stat("total number of enum members", stats.s_nemem); 745178481Sjb long_stat("maximum number of enum members", stats.s_emmax); 746178481Sjb 747178481Sjb if (stats.s_types[CTF_K_ENUM] != 0) { 748178481Sjb fp_stat("average number of enum members", 749178481Sjb (float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]); 750178481Sjb } 751178481Sjb 752178481Sjb (void) printf("\n"); 753178481Sjb 754178481Sjb long_stat("total number of unique strings", stats.s_nstr); 755178481Sjb long_stat("bytes of string data", stats.s_strlen); 756178481Sjb long_stat("maximum string length", stats.s_strmax); 757178481Sjb 758178481Sjb if (stats.s_nstr != 0) { 759178481Sjb fp_stat("average string length", 760178481Sjb (float)stats.s_strlen / (float)stats.s_nstr); 761178481Sjb } 762178481Sjb 763178481Sjb (void) printf("\n"); 764178481Sjb return (E_SUCCESS); 765178481Sjb} 766178481Sjb 767178481Sjbstatic int 768178481Sjbprint_usage(FILE *fp, int verbose) 769178481Sjb{ 770178481Sjb (void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getpname()); 771178481Sjb 772178481Sjb if (verbose) { 773178481Sjb (void) fprintf(fp, 774178481Sjb "\t-d dump data object section\n" 775178481Sjb "\t-f dump function section\n" 776178481Sjb "\t-h dump file header\n" 777178481Sjb "\t-l dump label table\n" 778178481Sjb "\t-s dump string table\n" 779178481Sjb "\t-S dump statistics\n" 780178481Sjb "\t-t dump type section\n" 781178481Sjb "\t-u save uncompressed CTF to a file\n"); 782178481Sjb } 783178481Sjb 784178481Sjb return (E_USAGE); 785178481Sjb} 786178481Sjb 787178481Sjbstatic Elf_Scn * 788178542Sjbfindelfscn(Elf *elf, GElf_Ehdr *ehdr, const char *secname) 789178481Sjb{ 790178481Sjb GElf_Shdr shdr; 791178481Sjb Elf_Scn *scn; 792178481Sjb char *name; 793178481Sjb 794178481Sjb for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) { 795178481Sjb if (gelf_getshdr(scn, &shdr) != NULL && (name = 796178481Sjb elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL && 797178481Sjb strcmp(name, secname) == 0) 798178481Sjb return (scn); 799178481Sjb } 800178481Sjb 801178481Sjb return (NULL); 802178481Sjb} 803178481Sjb 804178481Sjbint 805178481Sjbmain(int argc, char *argv[]) 806178481Sjb{ 807178481Sjb const char *filename = NULL; 808178481Sjb const char *ufile = NULL; 809178481Sjb int error = 0; 810178481Sjb int c, fd, ufd; 811178481Sjb 812178481Sjb ctf_data_t cd; 813178481Sjb const ctf_preamble_t *pp; 814178542Sjb ctf_header_t *hp = NULL; 815178481Sjb Elf *elf; 816178481Sjb GElf_Ehdr ehdr; 817178481Sjb 818178481Sjb (void) elf_version(EV_CURRENT); 819178481Sjb 820178481Sjb for (opterr = 0; optind < argc; optind++) { 821178481Sjb while ((c = getopt(argc, argv, "dfhlsStu:")) != (int)EOF) { 822178481Sjb switch (c) { 823178481Sjb case 'd': 824178481Sjb flags |= F_DATA; 825178481Sjb break; 826178481Sjb case 'f': 827178481Sjb flags |= F_FUNC; 828178481Sjb break; 829178481Sjb case 'h': 830178481Sjb flags |= F_HDR; 831178481Sjb break; 832178481Sjb case 'l': 833178481Sjb flags |= F_LABEL; 834178481Sjb break; 835178481Sjb case 's': 836178481Sjb flags |= F_STR; 837178481Sjb break; 838178481Sjb case 'S': 839178481Sjb flags |= F_STATS; 840178481Sjb break; 841178481Sjb case 't': 842178481Sjb flags |= F_TYPES; 843178481Sjb break; 844178481Sjb case 'u': 845178481Sjb ufile = optarg; 846178481Sjb break; 847178481Sjb default: 848178481Sjb if (optopt == '?') 849178481Sjb return (print_usage(stdout, 1)); 850178481Sjb warn("illegal option -- %c\n", optopt); 851178481Sjb return (print_usage(stderr, 0)); 852178481Sjb } 853178481Sjb } 854178481Sjb 855178481Sjb if (optind < argc) { 856178481Sjb if (filename != NULL) 857178481Sjb return (print_usage(stderr, 0)); 858178481Sjb filename = argv[optind]; 859178481Sjb } 860178481Sjb } 861178481Sjb 862178481Sjb if (filename == NULL) 863178481Sjb return (print_usage(stderr, 0)); 864178481Sjb 865178481Sjb if (flags == 0 && ufile == NULL) 866178481Sjb flags = F_ALLMSK; 867178481Sjb 868178481Sjb if ((fd = open(filename, O_RDONLY)) == -1) 869178481Sjb die("failed to open %s", filename); 870178481Sjb 871178481Sjb if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL && 872178481Sjb gelf_getehdr(elf, &ehdr) != NULL) { 873178481Sjb 874178542Sjb Elf_Data *dp = NULL; 875178481Sjb Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf"); 876178481Sjb Elf_Scn *symscn; 877178481Sjb GElf_Shdr ctfshdr; 878178481Sjb 879178481Sjb if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL) 880178481Sjb die("%s does not contain .SUNW_ctf data\n", filename); 881178481Sjb 882178481Sjb cd.cd_ctfdata = dp->d_buf; 883178481Sjb cd.cd_ctflen = dp->d_size; 884178481Sjb 885178481Sjb /* 886178481Sjb * If the sh_link field of the CTF section header is non-zero 887178481Sjb * it indicates which section contains the symbol table that 888178481Sjb * should be used. We default to the .symtab section if sh_link 889178481Sjb * is zero or if there's an error reading the section header. 890178481Sjb */ 891178481Sjb if (gelf_getshdr(ctfscn, &ctfshdr) != NULL && 892178481Sjb ctfshdr.sh_link != 0) { 893178481Sjb symscn = elf_getscn(elf, ctfshdr.sh_link); 894178481Sjb } else { 895178481Sjb symscn = findelfscn(elf, &ehdr, ".symtab"); 896178481Sjb } 897178481Sjb 898178481Sjb /* If we found a symbol table, find the corresponding strings */ 899178481Sjb if (symscn != NULL) { 900178481Sjb GElf_Shdr shdr; 901178481Sjb Elf_Scn *symstrscn; 902178481Sjb 903178481Sjb if (gelf_getshdr(symscn, &shdr) != NULL) { 904178481Sjb symstrscn = elf_getscn(elf, shdr.sh_link); 905178481Sjb 906178481Sjb cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize; 907178481Sjb cd.cd_symdata = elf_getdata(symscn, NULL); 908178481Sjb cd.cd_strdata = elf_getdata(symstrscn, NULL); 909178481Sjb } 910178481Sjb } 911178481Sjb } else { 912178481Sjb struct stat st; 913178481Sjb 914178481Sjb if (fstat(fd, &st) == -1) 915178481Sjb die("failed to fstat %s", filename); 916178481Sjb 917178481Sjb cd.cd_ctflen = st.st_size; 918178481Sjb cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ, 919178481Sjb MAP_PRIVATE, fd, 0); 920178481Sjb if (cd.cd_ctfdata == MAP_FAILED) 921178481Sjb die("failed to mmap %s", filename); 922178481Sjb } 923178481Sjb 924178481Sjb /* 925178481Sjb * Get a pointer to the CTF data buffer and interpret the first portion 926178481Sjb * as a ctf_header_t. Validate the magic number and size. 927178481Sjb */ 928178481Sjb 929178481Sjb if (cd.cd_ctflen < sizeof (ctf_preamble_t)) 930178481Sjb die("%s does not contain a CTF preamble\n", filename); 931178481Sjb 932178542Sjb void *v = (void *) cd.cd_ctfdata; 933178542Sjb pp = v; 934178481Sjb 935178481Sjb if (pp->ctp_magic != CTF_MAGIC) 936178481Sjb die("%s does not appear to contain CTF data\n", filename); 937178481Sjb 938178481Sjb if (pp->ctp_version == CTF_VERSION) { 939178542Sjb v = (void *) cd.cd_ctfdata; 940178542Sjb hp = v; 941178481Sjb cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t); 942178481Sjb 943178481Sjb if (cd.cd_ctflen < sizeof (ctf_header_t)) { 944178481Sjb die("%s does not contain a v%d CTF header\n", filename, 945178481Sjb CTF_VERSION); 946178481Sjb } 947178481Sjb 948178481Sjb } else { 949178481Sjb die("%s contains unsupported CTF version %d\n", filename, 950178481Sjb pp->ctp_version); 951178481Sjb } 952178481Sjb 953178481Sjb /* 954178481Sjb * If the data buffer is compressed, then malloc a buffer large enough 955178481Sjb * to hold the decompressed data, and use zlib to decompress it. 956178481Sjb */ 957178481Sjb if (hp->cth_flags & CTF_F_COMPRESS) { 958178481Sjb z_stream zstr; 959178481Sjb void *buf; 960178481Sjb int rc; 961178481Sjb 962178481Sjb if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL) 963178481Sjb die("failed to allocate decompression buffer"); 964178481Sjb 965178481Sjb bzero(&zstr, sizeof (z_stream)); 966178481Sjb zstr.next_in = (void *)cd.cd_ctfdata; 967178481Sjb zstr.avail_in = cd.cd_ctflen; 968178481Sjb zstr.next_out = buf; 969178481Sjb zstr.avail_out = hp->cth_stroff + hp->cth_strlen; 970178481Sjb 971178481Sjb if ((rc = inflateInit(&zstr)) != Z_OK) 972178481Sjb die("failed to initialize zlib: %s\n", zError(rc)); 973178481Sjb 974178481Sjb if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END) 975178481Sjb die("failed to decompress CTF data: %s\n", zError(rc)); 976178481Sjb 977178481Sjb if ((rc = inflateEnd(&zstr)) != Z_OK) 978178481Sjb die("failed to finish decompression: %s\n", zError(rc)); 979178481Sjb 980178481Sjb if (zstr.total_out != hp->cth_stroff + hp->cth_strlen) 981178481Sjb die("CTF data is corrupt -- short decompression\n"); 982178481Sjb 983178481Sjb cd.cd_ctfdata = buf; 984178481Sjb cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen; 985178481Sjb } 986178481Sjb 987178481Sjb if (flags & F_HDR) 988178481Sjb error |= print_header(hp, &cd); 989178481Sjb if (flags & (F_LABEL)) 990178481Sjb error |= print_labeltable(hp, &cd); 991178481Sjb if (flags & (F_DATA | F_STATS)) 992178481Sjb error |= read_data(hp, &cd); 993178481Sjb if (flags & (F_FUNC | F_STATS)) 994178481Sjb error |= read_funcs(hp, &cd); 995178481Sjb if (flags & (F_TYPES | F_STATS)) 996178481Sjb error |= read_types(hp, &cd); 997178481Sjb if (flags & (F_STR | F_STATS)) 998178481Sjb error |= read_strtab(hp, &cd); 999178481Sjb if (flags & F_STATS) 1000178481Sjb error |= print_stats(); 1001178481Sjb 1002178481Sjb /* 1003178481Sjb * If the -u option is specified, write the uncompressed CTF data to a 1004178481Sjb * raw CTF file. CTF data can already be extracted compressed by 1005178481Sjb * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother. 1006178481Sjb */ 1007178481Sjb if (ufile != NULL) { 1008178481Sjb ctf_header_t h; 1009178481Sjb 1010178481Sjb bcopy(hp, &h, sizeof (h)); 1011178481Sjb h.cth_flags &= ~CTF_F_COMPRESS; 1012178481Sjb 1013178481Sjb if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 || 1014178481Sjb write(ufd, &h, sizeof (h)) != sizeof (h) || 1015178542Sjb write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != (int) cd.cd_ctflen) { 1016178481Sjb warn("failed to write CTF data to '%s'", ufile); 1017178481Sjb error |= E_ERROR; 1018178481Sjb } 1019178481Sjb 1020178481Sjb (void) close(ufd); 1021178481Sjb } 1022178481Sjb 1023178481Sjb if (elf != NULL) 1024178481Sjb (void) elf_end(elf); 1025178481Sjb 1026178481Sjb (void) close(fd); 1027178481Sjb return (error); 1028178481Sjb} 1029