1/* 2 * CDDL HEADER START 3 * 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 7 * with the License. 8 * 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. 13 * 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] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "@(#)dump.c 1.12 05/06/08 SMI" 28 29#if !defined(__APPLE__) 30#include <sys/types.h> 31#include <sys/sysmacros.h> 32#include <sys/stat.h> 33#include <sys/mman.h> 34#else 35#include <sys/types.h> 36//#include <sys/sysmacros.h> 37#include <sys/stat.h> 38#include <sys/mman.h> 39 40#include "darwin_shim.h" 41#include <mach-o/loader.h> 42#include <mach-o/nlist.h> 43#include <mach-o/stab.h> 44 45int debug_level; 46const char *progname = "ctfdump"; 47#endif /* __APPLE__ */ 48 49#include <strings.h> 50#include <unistd.h> 51#include <stdlib.h> 52#include <stdio.h> 53#include <fcntl.h> 54#include <gelf.h> 55#include <zlib.h> 56 57#include "ctf_headers.h" 58#include "strtab.h" 59#include "ctftools.h" 60#include "utils.h" 61#include "symbol.h" 62 63#ifdef __APPLE__ 64extern caddr_t write_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp); 65extern caddr_t write_compressed_buffer(ctf_header_t *h, ctf_buf_t *buf, size_t *resszp); 66struct ctf_buf { 67 strtab_t ctb_strtab; /* string table */ 68 caddr_t ctb_base; /* pointer to base of buffer */ 69 caddr_t ctb_end; /* pointer to end of buffer */ 70 caddr_t ctb_ptr; /* pointer to empty buffer space */ 71 size_t ctb_size; /* size of buffer */ 72 int nptent; /* number of processed types */ 73 int ntholes; /* number of type holes */ 74}; 75 76#endif /* __APPLE__ */ 77 78#define WARN(x) { warn(x); return (E_ERROR); } 79 80/* 81 * Flags that indicate what data is to be displayed. An explicit `all' value is 82 * provided to allow the code to distinguish between a request for everything 83 * (currently requested by invoking ctfdump without flags) and individual 84 * requests for all of the types of data (an invocation with all flags). In the 85 * former case, we want to be able to implicitly adjust the definition of `all' 86 * based on the CTF version of the file being dumped. For example, if a v2 file 87 * is being dumped, `all' includes F_LABEL - a request to dump the label 88 * section. If a v1 file is being dumped, `all' does not include F_LABEL, 89 * because v1 CTF doesn't support labels. We need to be able to distinguish 90 * between `ctfdump foo', which has an implicit request for labels if `foo' 91 * supports them, and `ctfdump -l foo', which has an explicity request. In the 92 * latter case, we exit with an error if `foo' is a v1 CTF file. 93 */ 94static enum { 95 F_DATA = 0x01, /* show data object section */ 96 F_FUNC = 0x02, /* show function section */ 97 F_HDR = 0x04, /* show header */ 98 F_STR = 0x08, /* show string table */ 99 F_TYPES = 0x10, /* show type section */ 100 F_STATS = 0x20, /* show statistics */ 101 F_LABEL = 0x40, /* show label section */ 102 F_ALL = 0x80, /* explicit request for `all' */ 103 F_ALLMSK = 0xff /* show all sections and statistics */ 104} flags = 0; 105 106static struct { 107 ulong_t s_ndata; /* total number of data objects */ 108 ulong_t s_nfunc; /* total number of functions */ 109 ulong_t s_nargs; /* total number of function arguments */ 110 ulong_t s_argmax; /* longest argument list */ 111 ulong_t s_ntypes; /* total number of types */ 112 ulong_t s_types[16]; /* number of types by kind */ 113 ulong_t s_nsmem; /* total number of struct members */ 114 ulong_t s_nsbytes; /* total size of all structs */ 115 ulong_t s_smmax; /* largest struct in terms of members */ 116 ulong_t s_sbmax; /* largest struct in terms of bytes */ 117 ulong_t s_numem; /* total number of union members */ 118 ulong_t s_nubytes; /* total size of all unions */ 119 ulong_t s_ummax; /* largest union in terms of members */ 120 ulong_t s_ubmax; /* largest union in terms of bytes */ 121 ulong_t s_nemem; /* total number of enum members */ 122 ulong_t s_emmax; /* largest enum in terms of members */ 123 ulong_t s_nstr; /* total number of strings */ 124 size_t s_strlen; /* total length of all strings */ 125 size_t s_strmax; /* longest string length */ 126} stats; 127 128typedef struct ctf_data { 129 caddr_t cd_ctfdata; /* Pointer to the CTF data */ 130 size_t cd_ctflen; /* Length of CTF data */ 131 132 /* 133 * cd_symdata will be non-NULL if the CTF data is being retrieved from 134 * an ELF file with a symbol table. cd_strdata and cd_nsyms should be 135 * used only if cd_symdata is non-NULL. 136 */ 137 Elf_Data *cd_symdata; /* Symbol table */ 138 Elf_Data *cd_strdata; /* Symbol table strings */ 139 int cd_nsyms; /* Number of symbol table entries */ 140#if defined (__APPLE__) 141 Elf32_Word sh_link; 142#endif /* __APPLE__ */ 143} ctf_data_t; 144 145static const char * 146ref_to_str(uint_t name, const ctf_header_t *hp, const ctf_data_t *cd) 147{ 148 size_t offset = CTF_NAME_OFFSET(name); 149 const char *s = cd->cd_ctfdata + hp->cth_stroff + offset; 150 151 if (CTF_NAME_STID(name) != CTF_STRTAB_0) 152 return ("<< ??? - name in external strtab >>"); 153 154 if (offset >= hp->cth_strlen) 155 return ("<< ??? - name exceeds strlab len >>"); 156 157 if (hp->cth_stroff + offset >= cd->cd_ctflen) 158 return ("<< ??? - file truncated >>"); 159 160 if (s[0] == '\0') 161 return ("(anon)"); 162 163 return (s); 164} 165 166static const char * 167int_encoding_to_str(uint_t encoding) 168{ 169 static char buf[32]; 170 171 if (encoding == 0 || (encoding & ~(CTF_INT_SIGNED | CTF_INT_CHAR | 172 CTF_INT_BOOL | CTF_INT_VARARGS)) != 0) 173 (void) snprintf(buf, sizeof (buf), " 0x%x", encoding); 174 else { 175 buf[0] = '\0'; 176 if (encoding & CTF_INT_SIGNED) 177 (void) strcat(buf, " SIGNED"); 178 if (encoding & CTF_INT_CHAR) 179 (void) strcat(buf, " CHAR"); 180 if (encoding & CTF_INT_BOOL) 181 (void) strcat(buf, " BOOL"); 182 if (encoding & CTF_INT_VARARGS) 183 (void) strcat(buf, " VARARGS"); 184 } 185 186 return (buf + 1); 187} 188 189static const char * 190fp_encoding_to_str(uint_t encoding) 191{ 192 static const char *const encs[] = { 193 NULL, "SINGLE", "DOUBLE", "COMPLEX", "DCOMPLEX", "LDCOMPLEX", 194 "LDOUBLE", "INTERVAL", "DINTERVAL", "LDINTERVAL", "IMAGINARY", 195 "DIMAGINARY", "LDIMAGINARY" 196 }; 197 198 static char buf[16]; 199 200 if (encoding < 1 || encoding >= (sizeof (encs) / sizeof (char *))) { 201 (void) snprintf(buf, sizeof (buf), "%u", encoding); 202 return (buf); 203 } 204 205 return (encs[encoding]); 206} 207 208static void 209print_line(const char *s) 210{ 211 static const char line[] = "----------------------------------------" 212 "----------------------------------------"; 213 (void) printf("\n%s%.*s\n\n", s, (int)(78 - strlen(s)), line); 214} 215 216static int 217print_header(const ctf_header_t *hp, const ctf_data_t *cd) 218{ 219 print_line("- CTF Header "); 220 221 (void) printf(" cth_magic = 0x%04x\n", hp->cth_magic); 222 (void) printf(" cth_version = %u\n", hp->cth_version); 223 (void) printf(" cth_flags = 0x%02x\n", hp->cth_flags); 224 (void) printf(" cth_parlabel = %s\n", 225 ref_to_str(hp->cth_parlabel, hp, cd)); 226 (void) printf(" cth_parname = %s\n", 227 ref_to_str(hp->cth_parname, hp, cd)); 228 (void) printf(" cth_lbloff = %u\n", hp->cth_lbloff); 229 (void) printf(" cth_objtoff = %u\n", hp->cth_objtoff); 230 (void) printf(" cth_funcoff = %u\n", hp->cth_funcoff); 231 (void) printf(" cth_typeoff = %u\n", hp->cth_typeoff); 232 (void) printf(" cth_stroff = %u\n", hp->cth_stroff); 233 (void) printf(" cth_strlen = %u\n", hp->cth_strlen); 234 235 return (E_SUCCESS); 236} 237 238static int 239print_labeltable(const ctf_header_t *hp, const ctf_data_t *cd) 240{ 241 /* LINTED - pointer alignment */ 242 const ctf_lblent_t *ctl = (ctf_lblent_t *)(cd->cd_ctfdata + 243 hp->cth_lbloff); 244 ulong_t i, n = (hp->cth_objtoff - hp->cth_lbloff) / sizeof (*ctl); 245 246 print_line("- Label Table "); 247 248 if (hp->cth_lbloff & 3) 249 WARN("cth_lbloff is not aligned properly\n"); 250 if (hp->cth_lbloff >= cd->cd_ctflen) 251 WARN("file is truncated or cth_lbloff is corrupt\n"); 252 if (hp->cth_objtoff >= cd->cd_ctflen) 253 WARN("file is truncated or cth_objtoff is corrupt\n"); 254 if (hp->cth_lbloff > hp->cth_objtoff) 255 WARN("file is corrupt -- cth_lbloff > cth_objtoff\n"); 256 257 for (i = 0; i < n; i++, ctl++) { 258 (void) printf(" %5u %s\n", ctl->ctl_typeidx, 259 ref_to_str(ctl->ctl_label, hp, cd)); 260 } 261 262 return (E_SUCCESS); 263} 264 265#if defined(__APPLE__) 266static GElf_Sym * 267gelf_getsym_macho(Elf_Data * data, int ndx, GElf_Sym * sym, const char *base) 268{ 269 const struct nlist *nsym = (const struct nlist *)(data->d_buf); 270 const char *name; 271 char *tmp; 272 273 nsym += ndx; 274 name = base + nsym->n_un.n_strx; 275 276 if (0 == nsym->n_un.n_strx) // iff a null, "", name. 277 name = "null name"; // return NULL; 278 279 if ('_' == name[0]) 280 name++; // Lop off omnipresent underscore to match DWARF convention 281 282 sym->st_name = (GElf_Sxword)(name - base); 283 sym->st_value = nsym->n_value; 284 sym->st_size = 0; 285 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_NOTYPE)); 286 sym->st_other = 0; 287 sym->st_shndx = SHN_MACHO; /* Mark underlying file as Mach-o */ 288 289 if (nsym->n_type & N_STAB) { /* Detect C++ methods */ 290 291 switch(nsym->n_type) { 292 case N_FUN: 293 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC)); 294 break; 295 case N_GSYM: 296 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT)); 297 break; 298 default: 299 break; 300 } 301 302 } else if ((N_ABS | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT)) || 303 (N_SECT | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT))) { 304 305 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (nsym->n_desc)); 306 } else if ((N_UNDF | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT)) && 307 nsym->n_sect == NO_SECT) { 308 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT)); /* Common */ 309 } 310 311 return sym; 312} 313 314static GElf_Sym * 315gelf_getsym_macho_64(Elf_Data * data, int ndx, GElf_Sym * sym, const char *base) 316{ 317 const struct nlist_64 *nsym = (const struct nlist_64 *)(data->d_buf); 318 const char *name; 319 char *tmp; 320 321 nsym += ndx; 322 name = base + nsym->n_un.n_strx; 323 324 if (0 == nsym->n_un.n_strx) // iff a null, "", name. 325 name = "null name"; // return NULL; 326 327 if ('_' == name[0]) 328 name++; // Lop off omnipresent underscore to match DWARF convention 329 330 sym->st_name = (GElf_Sxword)(name - base); 331 sym->st_value = nsym->n_value; 332 sym->st_size = 0; 333 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_NOTYPE)); 334 sym->st_other = 0; 335 sym->st_shndx = SHN_MACHO_64; /* Mark underlying file as Mach-o */ 336 337 if (nsym->n_type & N_STAB) { /* Detect C++ methods */ 338 339 switch(nsym->n_type) { 340 case N_FUN: 341 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC)); 342 break; 343 case N_GSYM: 344 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT)); 345 break; 346 default: 347 break; 348 } 349 350 } else if ((N_ABS | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT)) || 351 (N_SECT | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT))) { 352 353 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (nsym->n_desc)); 354 } else if ((N_UNDF | N_EXT) == (nsym->n_type & (N_TYPE | N_EXT)) && 355 nsym->n_sect == NO_SECT) { 356 sym->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_OBJECT)); /* Common */ 357 } 358 359 return sym; 360} 361#endif /* __APPLE__ */ 362 363/* 364 * Given the current symbol index (-1 to start at the beginning of the symbol 365 * table) and the type of symbol to match, this function returns the index of 366 * the next matching symbol (if any), and places the name of that symbol in 367 * *namep. If no symbol is found, -1 is returned. 368 */ 369static int 370next_sym(const ctf_data_t *cd, const int symidx, const uchar_t matchtype, 371 char **namep) 372{ 373 int i; 374 375 for (i = symidx + 1; i < cd->cd_nsyms; i++) { 376 GElf_Sym sym; 377 char *name; 378 int type; 379 380#if defined(__APPLE__) 381 if (cd->sh_link == SHN_MACHO) { /* Underlying file is Mach-o */ 382 if (gelf_getsym_macho(cd->cd_symdata, i, &sym, (const char *)(cd->cd_strdata->d_buf)) == 0) 383 return (-1); 384 } 385 else if (cd->sh_link == SHN_MACHO_64) { /* Underlying file is Mach-o 64 */ 386 if (gelf_getsym_macho_64(cd->cd_symdata, i, &sym, (const char *)(cd->cd_strdata->d_buf)) == 0) 387 return (-1); 388 } 389 else 390#endif /* __APPLE__ */ 391 if (gelf_getsym(cd->cd_symdata, i, &sym) == 0) 392 return (-1); 393 394 name = (char *)cd->cd_strdata->d_buf + sym.st_name; 395 type = GELF_ST_TYPE(sym.st_info); 396 397 /* 398 * Skip various types of symbol table entries. 399 */ 400 if (type != matchtype || ignore_symbol(&sym, name)) 401 continue; 402 403 /* Found one */ 404 *namep = name; 405 return (i); 406 } 407 408 return (-1); 409} 410 411static int 412read_data(const ctf_header_t *hp, const ctf_data_t *cd) 413{ 414 /* LINTED - pointer alignment */ 415 const ushort_t *idp = (ushort_t *)(cd->cd_ctfdata + hp->cth_objtoff); 416 ulong_t n = (hp->cth_funcoff - hp->cth_objtoff) / sizeof (ushort_t); 417 418 if (flags != F_STATS) 419 print_line("- Data Objects "); 420 421 if (hp->cth_objtoff & 1) 422 WARN("cth_objtoff is not aligned properly\n"); 423 if (hp->cth_objtoff >= cd->cd_ctflen) 424 WARN("file is truncated or cth_objtoff is corrupt\n"); 425 if (hp->cth_funcoff >= cd->cd_ctflen) 426 WARN("file is truncated or cth_funcoff is corrupt\n"); 427 if (hp->cth_objtoff > hp->cth_funcoff) 428 WARN("file is corrupt -- cth_objtoff > cth_funcoff\n"); 429 430 if (flags != F_STATS) { 431 int symidx, len, i; 432 char *name = NULL; 433 434 for (symidx = -1, i = 0; i < n; i++) { 435 int nextsym; 436 437 if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, 438 symidx, STT_OBJECT, &name)) < 0) 439 name = NULL; 440 else 441 symidx = nextsym; 442 443 len = printf(" [%u] %u", i, *idp++); 444 if (name != NULL) 445 (void) printf("%*s%s (%u)", (15 - len), "", 446 name, symidx); 447 (void) putchar('\n'); 448 } 449 } 450 451 stats.s_ndata = n; 452 return (E_SUCCESS); 453} 454 455static int 456read_funcs(const ctf_header_t *hp, const ctf_data_t *cd) 457{ 458 /* LINTED - pointer alignment */ 459 const ushort_t *fp = (ushort_t *)(cd->cd_ctfdata + hp->cth_funcoff); 460 461 /* LINTED - pointer alignment */ 462 const ushort_t *end = (ushort_t *)(cd->cd_ctfdata + hp->cth_typeoff); 463 464 ulong_t id; 465 int symidx; 466 467 if (flags != F_STATS) 468 print_line("- Functions "); 469 470 if (hp->cth_funcoff & 1) 471 WARN("cth_funcoff is not aligned properly\n"); 472 if (hp->cth_funcoff >= cd->cd_ctflen) 473 WARN("file is truncated or cth_funcoff is corrupt\n"); 474 if (hp->cth_typeoff >= cd->cd_ctflen) 475 WARN("file is truncated or cth_typeoff is corrupt\n"); 476 if (hp->cth_funcoff > hp->cth_typeoff) 477 WARN("file is corrupt -- cth_funcoff > cth_typeoff\n"); 478 479 for (symidx = -1, id = 0; fp < end; id++) { 480 ushort_t info = *fp++; 481 ushort_t kind = CTF_INFO_KIND(info); 482 ushort_t n = CTF_INFO_VLEN(info); 483 ushort_t i; 484 int nextsym; 485 char *name; 486 487 if (cd->cd_symdata == NULL || (nextsym = next_sym(cd, symidx, 488 STT_FUNC, &name)) < 0) 489 name = NULL; 490 else 491 symidx = nextsym; 492 493 if (kind == CTF_K_UNKNOWN && n == 0) 494 continue; /* skip padding */ 495 496 if (kind != CTF_K_FUNCTION) { 497 (void) printf(" [%lu] unexpected kind -- %u\n", 498 id, kind); 499 return (E_ERROR); 500 } 501 502 if (fp + n > end) { 503 (void) printf(" [%lu] vlen %u extends past section " 504 "boundary\n", id, n); 505 return (E_ERROR); 506 } 507 508 if (flags != F_STATS) { 509 (void) printf(" [%lu] FUNC ", id); 510 if (name != NULL) 511 (void) printf("(%s) ", name); 512 (void) printf("returns: %u args: (", *fp++); 513 514 if (n != 0) { 515 (void) printf("%u", *fp++); 516 for (i = 1; i < n; i++) 517 (void) printf(", %u", *fp++); 518 } 519 520 (void) printf(")\n"); 521 } else 522 fp += n + 1; /* skip to next function definition */ 523 524 stats.s_nfunc++; 525 stats.s_nargs += n; 526 stats.s_argmax = MAX(stats.s_argmax, n); 527 } 528 529 return (E_SUCCESS); 530} 531 532static int 533read_types(const ctf_header_t *hp, const ctf_data_t *cd) 534{ 535 /* LINTED - pointer alignment */ 536 const ctf_type_t *tp = (ctf_type_t *)(cd->cd_ctfdata + hp->cth_typeoff); 537 538 /* LINTED - pointer alignment */ 539 const ctf_type_t *end = (ctf_type_t *)(cd->cd_ctfdata + hp->cth_stroff); 540 541 ulong_t id; 542 543 if (flags != F_STATS) 544 print_line("- Types "); 545 546 if (hp->cth_typeoff & 3) 547 WARN("cth_typeoff is not aligned properly\n"); 548 if (hp->cth_typeoff >= cd->cd_ctflen) 549 WARN("file is truncated or cth_typeoff is corrupt\n"); 550 if (hp->cth_stroff >= cd->cd_ctflen) 551 WARN("file is truncated or cth_stroff is corrupt\n"); 552 if (hp->cth_typeoff > hp->cth_stroff) 553 WARN("file is corrupt -- cth_typeoff > cth_stroff\n"); 554 555 id = 1; 556 if (hp->cth_parlabel || hp->cth_parname) 557 id += 1 << CTF_PARENT_SHIFT; 558 559 for (/* */; tp < end; id++) { 560 ulong_t i, n = CTF_INFO_VLEN(tp->ctt_info); 561 size_t size, increment, vlen = 0; 562 int kind = CTF_INFO_KIND(tp->ctt_info); 563 564 union { 565 const void *ptr; 566 const ctf_array_t *ap; 567 const ctf_member_t *mp; 568 const ctf_lmember_t *lmp; 569 const ctf_enum_t *ep; 570 const ushort_t *argp; 571 } u; 572 573 if (flags != F_STATS) { 574 (void) printf(" %c%lu%c ", 575 "[<"[CTF_INFO_ISROOT(tp->ctt_info)], id, 576 "]>"[CTF_INFO_ISROOT(tp->ctt_info)]); 577 } 578 579 if (tp->ctt_size == CTF_LSIZE_SENT) { 580 increment = sizeof (ctf_type_t); 581 size = (size_t)CTF_TYPE_LSIZE(tp); 582 } else { 583 increment = sizeof (ctf_stype_t); 584 size = tp->ctt_size; 585 } 586 u.ptr = (caddr_t)tp + increment; 587 588 switch (kind) { 589 case CTF_K_INTEGER: 590 if (flags != F_STATS) { 591 uint_t encoding = *((const uint_t *)u.ptr); 592 593 (void) printf("INTEGER %s encoding=%s offset=%u" 594 " bits=%u", ref_to_str(tp->ctt_name, hp, 595 cd), int_encoding_to_str( 596 CTF_INT_ENCODING(encoding)), 597 CTF_INT_OFFSET(encoding), 598 CTF_INT_BITS(encoding)); 599 } 600 vlen = sizeof (uint_t); 601 break; 602 603 case CTF_K_FLOAT: 604 if (flags != F_STATS) { 605 uint_t encoding = *((const uint_t *)u.ptr); 606 607 (void) printf("FLOAT %s encoding=%s offset=%u " 608 "bits=%u", ref_to_str(tp->ctt_name, hp, 609 cd), fp_encoding_to_str( 610 CTF_FP_ENCODING(encoding)), 611 CTF_FP_OFFSET(encoding), 612 CTF_FP_BITS(encoding)); 613 } 614 vlen = sizeof (uint_t); 615 break; 616 617 case CTF_K_POINTER: 618 if (flags != F_STATS) { 619 (void) printf("POINTER %s refers to %u", 620 ref_to_str(tp->ctt_name, hp, cd), 621 tp->ctt_type); 622 } 623 break; 624 625 case CTF_K_ARRAY: 626 if (flags != F_STATS) { 627 (void) printf("ARRAY %s content: %u index: %u " 628 "nelems: %u\n", ref_to_str(tp->ctt_name, 629 hp, cd), u.ap->cta_contents, 630 u.ap->cta_index, u.ap->cta_nelems); 631 } 632 vlen = sizeof (ctf_array_t); 633 break; 634 635 case CTF_K_FUNCTION: 636 if (flags != F_STATS) { 637 (void) printf("FUNCTION %s returns: %u args: (", 638 ref_to_str(tp->ctt_name, hp, cd), 639 tp->ctt_type); 640 641 if (n != 0) { 642 (void) printf("%u", *u.argp++); 643 for (i = 1; i < n; i++, u.argp++) 644 (void) printf(", %u", *u.argp); 645 } 646 647 (void) printf(")"); 648 } 649 650 vlen = sizeof (ushort_t) * (n + (n & 1)); 651 break; 652 653 case CTF_K_STRUCT: 654 case CTF_K_UNION: 655 if (kind == CTF_K_STRUCT) { 656 stats.s_nsmem += n; 657 stats.s_smmax = MAX(stats.s_smmax, n); 658 stats.s_nsbytes += size; 659 stats.s_sbmax = MAX(stats.s_sbmax, size); 660 661 if (flags != F_STATS) 662 (void) printf("STRUCT"); 663 } else { 664 stats.s_numem += n; 665 stats.s_ummax = MAX(stats.s_ummax, n); 666 stats.s_nubytes += size; 667 stats.s_ubmax = MAX(stats.s_ubmax, size); 668 669 if (flags != F_STATS) 670 (void) printf("UNION"); 671 } 672 673 if (flags != F_STATS) { 674 (void) printf(" %s (%d bytes)\n", 675 ref_to_str(tp->ctt_name, hp, cd), size); 676 677 if (size >= CTF_LSTRUCT_THRESH) { 678 for (i = 0; i < n; i++, u.lmp++) { 679 (void) printf( 680 "\t%s type=%u off=%llu\n", 681 ref_to_str(u.lmp->ctlm_name, 682 hp, cd), u.lmp->ctlm_type, 683 CTF_LMEM_OFFSET(u.lmp)); 684 } 685 } else { 686 for (i = 0; i < n; i++, u.mp++) { 687 (void) printf( 688 "\t%s type=%u off=%u\n", 689 ref_to_str(u.mp->ctm_name, 690 hp, cd), u.mp->ctm_type, 691 u.mp->ctm_offset); 692 } 693 } 694 } 695 696 vlen = n * (size >= CTF_LSTRUCT_THRESH ? 697 sizeof (ctf_lmember_t) : sizeof (ctf_member_t)); 698 break; 699 700 case CTF_K_ENUM: 701 if (flags != F_STATS) { 702 (void) printf("ENUM %s\n", 703 ref_to_str(tp->ctt_name, hp, cd)); 704 705 for (i = 0; i < n; i++, u.ep++) { 706 (void) printf("\t%s = %d\n", 707 ref_to_str(u.ep->cte_name, hp, cd), 708 u.ep->cte_value); 709 } 710 } 711 712 stats.s_nemem += n; 713 stats.s_emmax = MAX(stats.s_emmax, n); 714 715 vlen = sizeof (ctf_enum_t) * n; 716 break; 717 718 case CTF_K_FORWARD: 719 if (flags != F_STATS) { 720 (void) printf("FORWARD %s", 721 ref_to_str(tp->ctt_name, hp, cd)); 722 } 723 break; 724 725 case CTF_K_TYPEDEF: 726 if (flags != F_STATS) { 727 (void) printf("TYPEDEF %s refers to %u", 728 ref_to_str(tp->ctt_name, hp, cd), 729 tp->ctt_type); 730 } 731 break; 732 733 case CTF_K_VOLATILE: 734 if (flags != F_STATS) { 735 (void) printf("VOLATILE %s refers to %u", 736 ref_to_str(tp->ctt_name, hp, cd), 737 tp->ctt_type); 738 } 739 break; 740 741 case CTF_K_CONST: 742 if (flags != F_STATS) { 743 (void) printf("CONST %s refers to %u", 744 ref_to_str(tp->ctt_name, hp, cd), 745 tp->ctt_type); 746 } 747 break; 748 749 case CTF_K_RESTRICT: 750 if (flags != F_STATS) { 751 (void) printf("RESTRICT %s refers to %u", 752 ref_to_str(tp->ctt_name, hp, cd), 753 tp->ctt_type); 754 } 755 break; 756 757 case CTF_K_UNKNOWN: 758 break; /* hole in type id space */ 759 760 default: 761 (void) printf("unexpected kind %u\n", kind); 762 return (E_ERROR); 763 } 764 765 if (flags != F_STATS) 766 (void) printf("\n"); 767 768 stats.s_ntypes++; 769 stats.s_types[kind]++; 770 771 tp = (ctf_type_t *)((uintptr_t)tp + increment + vlen); 772 } 773 774 return (E_SUCCESS); 775} 776 777static int 778read_strtab(const ctf_header_t *hp, const ctf_data_t *cd) 779{ 780 size_t n, off, len = hp->cth_strlen; 781 const char *s = cd->cd_ctfdata + hp->cth_stroff; 782 783 if (flags != F_STATS) 784 print_line("- String Table "); 785 786 if (hp->cth_stroff >= cd->cd_ctflen) 787 WARN("file is truncated or cth_stroff is corrupt\n"); 788 if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen) 789 WARN("file is truncated or cth_strlen is corrupt\n"); 790 791 for (off = 0; len != 0; off += n) { 792 if (flags != F_STATS) { 793 (void) printf(" [%lu] %s\n", (ulong_t)off, 794 s[0] == '\0' ? "\\0" : s); 795 } 796 n = strlen(s) + 1; 797 len -= n; 798 s += n; 799 800 stats.s_nstr++; 801 stats.s_strlen += n; 802 stats.s_strmax = MAX(stats.s_strmax, n); 803 } 804 805 return (E_SUCCESS); 806} 807 808/* 809 * Remove unwanted symbols from strtab: replace them with "- ". 810 */ 811static int 812clean_strtab(ctf_header_t *hp, ctf_data_t *cd, strtab_t *strtab, 813 char **syms, int nsyms) 814{ 815 size_t n, off, len = hp->cth_strlen; 816 char *s = cd->cd_ctfdata + hp->cth_stroff; 817 int i; 818 819 char buf[1024]; 820 buf[0] = '-'; 821 memset(buf + 1, ' ', 1023); 822 823 if (hp->cth_stroff >= cd->cd_ctflen) 824 WARN("file is truncated or cth_stroff is corrupt\n"); 825 if (hp->cth_stroff + hp->cth_strlen > cd->cd_ctflen) 826 WARN("file is truncated or cth_strlen is corrupt\n"); 827 828 for (off = 0; len != 0; off += n) { 829 for (i = 0; i < nsyms; i++) { 830 /* clean out offending string */ 831 if (!strcmp(s, syms[i])) 832 strncpy(s, buf, strlen(s)); 833 } 834 /* add all strings to fresh strtab */ 835 strtab_insert(strtab, s); 836 n = strlen(s) + 1; 837 len -= n; 838 s += n; 839 } 840 841 return 0; 842} 843 844/* 845 * Convert from one representation to another of the ctf buffer 846 */ 847static void 848ctf_data_to_ctf_buf(ctf_header_t *hp, ctf_data_t *cd, ctf_buf_t *cb) 849{ 850 /* create empty strtab (to be filled in clean_strtab) */ 851 strtab_create(&cb->ctb_strtab); 852 cb->ctb_base = cd->cd_ctfdata; 853 cb->ctb_end = cd->cd_ctfdata + hp->cth_stroff; 854 cb->ctb_ptr = cb->ctb_end; 855 cb->ctb_size = cd->cd_ctflen - hp->cth_strlen; 856 /* not used for our purposes */ 857 cb->nptent = 0; 858 cb->ntholes = 0; 859} 860 861/* 862 * Similar to write_ctf, but we don't have to reconstruct the whole CTF section 863 * from a tdata_t. 864 */ 865static int 866write_ctfdata(int srcfd, Elf *srcelf, const char *srcname, const char *dstname, ctf_header_t *hp, ctf_buf_t *buf) 867{ 868 struct stat st; 869 Elf *dstelf = NULL; 870 caddr_t data = NULL; 871 size_t len = 0; 872 int dstfd; 873 874 /* open + elf_begin destination file */ 875 fstat(srcfd, &st); 876 if ((dstfd = open(dstname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) 877 terminate("Cannot open temp file %s for writing", dstname); 878 if ((dstelf = elf_begin(dstfd, ELF_C_WRITE, NULL)) == NULL) 879 elfterminate(dstname, "Cannot write"); 880 881 /* write out and/or compress header & data buffer */ 882 if (hp->cth_flags & CTF_F_COMPRESS) { 883 data = write_compressed_buffer(hp, buf, &len); 884 } else { 885 data = write_buffer(hp, buf, &len); 886 /* 887 data = (caddr_t) xmalloc(sizeof(ctf_header_t) + cd->cd_ctflen); 888 bcopy(hp, data, sizeof(ctf_header_t)); 889 len += sizeof(ctf_header_t); 890 bcopy(cd->cd_ctfdata, data + len, cd->cd_ctflen); 891 len += cd->cd_ctflen; 892 */ 893 } 894 895 /* send the data to the destination file */ 896 write_file(srcelf, srcname, dstelf, dstname, data, len, 0); 897 898 free(data); 899 elf_end(dstelf); 900 (void) close(dstfd); 901 return 0; 902} 903 904static void 905long_stat(const char *name, ulong_t value) 906{ 907 (void) printf(" %-36s= %lu\n", name, value); 908} 909 910static void 911fp_stat(const char *name, float value) 912{ 913 (void) printf(" %-36s= %.2f\n", name, value); 914} 915 916static int 917print_stats(void) 918{ 919 print_line("- CTF Statistics "); 920 921 long_stat("total number of data objects", stats.s_ndata); 922 (void) printf("\n"); 923 924 long_stat("total number of functions", stats.s_nfunc); 925 long_stat("total number of function arguments", stats.s_nargs); 926 long_stat("maximum argument list length", stats.s_argmax); 927 928 if (stats.s_nfunc != 0) { 929 fp_stat("average argument list length", 930 (float)stats.s_nargs / (float)stats.s_nfunc); 931 } 932 933 (void) printf("\n"); 934 935 long_stat("total number of types", stats.s_ntypes); 936 long_stat("total number of integers", stats.s_types[CTF_K_INTEGER]); 937 long_stat("total number of floats", stats.s_types[CTF_K_FLOAT]); 938 long_stat("total number of pointers", stats.s_types[CTF_K_POINTER]); 939 long_stat("total number of arrays", stats.s_types[CTF_K_ARRAY]); 940 long_stat("total number of func types", stats.s_types[CTF_K_FUNCTION]); 941 long_stat("total number of structs", stats.s_types[CTF_K_STRUCT]); 942 long_stat("total number of unions", stats.s_types[CTF_K_UNION]); 943 long_stat("total number of enums", stats.s_types[CTF_K_ENUM]); 944 long_stat("total number of forward tags", stats.s_types[CTF_K_FORWARD]); 945 long_stat("total number of typedefs", stats.s_types[CTF_K_TYPEDEF]); 946 long_stat("total number of volatile types", 947 stats.s_types[CTF_K_VOLATILE]); 948 long_stat("total number of const types", stats.s_types[CTF_K_CONST]); 949 long_stat("total number of restrict types", 950 stats.s_types[CTF_K_RESTRICT]); 951 long_stat("total number of unknowns (holes)", 952 stats.s_types[CTF_K_UNKNOWN]); 953 954 (void) printf("\n"); 955 956 long_stat("total number of struct members", stats.s_nsmem); 957 long_stat("maximum number of struct members", stats.s_smmax); 958 long_stat("total size of all structs", stats.s_nsbytes); 959 long_stat("maximum size of a struct", stats.s_sbmax); 960 961 if (stats.s_types[CTF_K_STRUCT] != 0) { 962 fp_stat("average number of struct members", 963 (float)stats.s_nsmem / (float)stats.s_types[CTF_K_STRUCT]); 964 fp_stat("average size of a struct", (float)stats.s_nsbytes / 965 (float)stats.s_types[CTF_K_STRUCT]); 966 } 967 968 (void) printf("\n"); 969 970 long_stat("total number of union members", stats.s_numem); 971 long_stat("maximum number of union members", stats.s_ummax); 972 long_stat("total size of all unions", stats.s_nubytes); 973 long_stat("maximum size of a union", stats.s_ubmax); 974 975 if (stats.s_types[CTF_K_UNION] != 0) { 976 fp_stat("average number of union members", 977 (float)stats.s_numem / (float)stats.s_types[CTF_K_UNION]); 978 fp_stat("average size of a union", (float)stats.s_nubytes / 979 (float)stats.s_types[CTF_K_UNION]); 980 } 981 982 (void) printf("\n"); 983 984 long_stat("total number of enum members", stats.s_nemem); 985 long_stat("maximum number of enum members", stats.s_emmax); 986 987 if (stats.s_types[CTF_K_ENUM] != 0) { 988 fp_stat("average number of enum members", 989 (float)stats.s_nemem / (float)stats.s_types[CTF_K_ENUM]); 990 } 991 992 (void) printf("\n"); 993 994 long_stat("total number of unique strings", stats.s_nstr); 995 long_stat("bytes of string data", stats.s_strlen); 996 long_stat("maximum string length", stats.s_strmax); 997 998 if (stats.s_nstr != 0) { 999 fp_stat("average string length", 1000 (float)stats.s_strlen / (float)stats.s_nstr); 1001 } 1002 1003 (void) printf("\n"); 1004 return (E_SUCCESS); 1005} 1006 1007static int 1008print_usage(FILE *fp, int verbose) 1009{ 1010#if !defined(__APPLE__) 1011 (void) fprintf(fp, "Usage: %s [-dfhlsSt] [-u file] file\n", getpname()); 1012#else 1013 (void) fprintf(fp, "Usage: %s [-dfhlrsSt] [-u file] file\n", progname); 1014#endif /* __APPLE__ */ 1015 1016 if (verbose) { 1017 (void) fprintf(fp, 1018 "\t-d dump data object section\n" 1019 "\t-f dump function section\n" 1020 "\t-h dump file header\n" 1021 "\t-l dump label table\n" 1022#ifdef __APPLE__ 1023 "\t-r remove listed symbols from CTF data\n" 1024#endif /* __APPLE__ */ 1025 "\t-s dump string table\n" 1026 "\t-S dump statistics\n" 1027 "\t-t dump type section\n" 1028 "\t-u save uncompressed CTF to a file\n"); 1029 } 1030 1031 return (E_USAGE); 1032} 1033 1034static Elf_Scn * 1035findelfscn(Elf *elf, GElf_Ehdr *ehdr, char *secname) 1036{ 1037 GElf_Shdr shdr; 1038 Elf_Scn *scn; 1039 char *name; 1040 1041 for (scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; ) { 1042 if (gelf_getshdr(scn, &shdr) != NULL && (name = 1043 elf_strptr(elf, ehdr->e_shstrndx, shdr.sh_name)) != NULL && 1044 strcmp(name, secname) == 0) 1045 return (scn); 1046 } 1047 1048 return (NULL); 1049} 1050 1051int 1052main(int argc, char *argv[]) 1053{ 1054 const char *filename = NULL; 1055 const char *ufile = NULL; 1056 int error = 0, doclean = 0; 1057 int c, fd, ufd; 1058 1059 ctf_data_t cd; 1060 const ctf_preamble_t *pp; 1061 ctf_header_t *hp; 1062 Elf *elf; 1063 GElf_Ehdr ehdr; 1064 1065 (void) elf_version(EV_CURRENT); 1066 1067 for (opterr = 0; optind < argc; optind++) { 1068 while ((c = getopt(argc, argv, "dfhlrsStu:")) != (int)EOF) { 1069 switch (c) { 1070 case 'd': 1071 flags |= F_DATA; 1072 break; 1073 case 'f': 1074 flags |= F_FUNC; 1075 break; 1076 case 'h': 1077 flags |= F_HDR; 1078 break; 1079 case 'l': 1080 flags |= F_LABEL; 1081 break; 1082 case 'r': 1083 doclean = 1; 1084 goto skiploop; 1085 case 's': 1086 flags |= F_STR; 1087 break; 1088 case 'S': 1089 flags |= F_STATS; 1090 break; 1091 case 't': 1092 flags |= F_TYPES; 1093 break; 1094 case 'u': 1095 ufile = optarg; 1096 break; 1097 default: 1098 if (optopt == '?') 1099 return (print_usage(stdout, 1)); 1100 warn("illegal option -- %c\n", optopt); 1101 return (print_usage(stderr, 0)); 1102 } 1103 } 1104 1105 if (optind < argc) { 1106 if (filename != NULL) 1107 return (print_usage(stderr, 0)); 1108 filename = argv[optind]; 1109 } 1110 } 1111 1112skiploop: 1113 if (doclean) 1114 filename = argv[argc - 1]; 1115 1116 if (filename == NULL) 1117 return (print_usage(stderr, 0)); 1118 1119 if (flags == 0 && ufile == NULL) 1120 flags = F_ALLMSK; 1121 1122 if ((fd = open(filename, O_RDONLY)) == -1) 1123 die("failed to open %s", filename); 1124 1125 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) != NULL && 1126 gelf_getehdr(elf, &ehdr) != NULL) { 1127 1128 Elf_Data *dp; 1129 Elf_Scn *ctfscn = findelfscn(elf, &ehdr, ".SUNW_ctf"); 1130 Elf_Scn *symscn; 1131 GElf_Shdr ctfshdr; 1132 1133 if (ctfscn == NULL || (dp = elf_getdata(ctfscn, NULL)) == NULL) 1134 die("%s does not contain .SUNW_ctf data\n", filename); 1135 1136 cd.cd_ctfdata = dp->d_buf; 1137 cd.cd_ctflen = dp->d_size; 1138 1139 /* 1140 * If the sh_link field of the CTF section header is non-zero 1141 * it indicates which section contains the symbol table that 1142 * should be used. We default to the .symtab section if sh_link 1143 * is zero or if there's an error reading the section header. 1144 */ 1145#if !defined(__APPLE__) 1146 if (gelf_getshdr(ctfscn, &ctfshdr) != NULL && 1147 ctfshdr.sh_link != 0) { 1148 symscn = elf_getscn(elf, ctfshdr.sh_link); 1149 } else { 1150 symscn = findelfscn(elf, &ehdr, ".symtab"); 1151 } 1152#else 1153 if (gelf_getshdr(ctfscn, &ctfshdr) != NULL && 1154 ctfshdr.sh_link != 0 && ctfshdr.sh_link != SHN_MACHO && ctfshdr.sh_link != SHN_MACHO_64) { 1155 symscn = elf_getscn(elf, ctfshdr.sh_link); 1156 } else { 1157 symscn = findelfscn(elf, &ehdr, ".symtab"); 1158 } 1159#endif /* __APPLE__ */ 1160 1161 /* If we found a symbol table, find the corresponding strings */ 1162 if (symscn != NULL) { 1163 GElf_Shdr shdr; 1164 Elf_Scn *symstrscn; 1165 1166 if (gelf_getshdr(symscn, &shdr) != NULL) { 1167#if !defined(__APPLE__) 1168 symstrscn = elf_getscn(elf, shdr.sh_link); 1169 1170 cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize; 1171 cd.cd_symdata = elf_getdata(symscn, NULL); 1172 cd.cd_strdata = elf_getdata(symstrscn, NULL); 1173#else 1174 if (SHN_MACHO == shdr.sh_link) { /* Underlying file is Mach-o */ 1175 int dir_idx; 1176 cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize; 1177 cd.cd_symdata = elf_getdata(symscn, NULL); 1178 1179 if ((dir_idx = findelfsecidx(elf, filename, ".dir_str_table")) < 0 || 1180 (symstrscn = elf_getscn(elf, dir_idx)) == NULL || 1181 (cd.cd_strdata = elf_getdata(symstrscn, NULL)) == NULL) 1182 terminate("%s: Can't open direct string table\n", filename); 1183 1184 cd.sh_link = SHN_MACHO; /* Mark underlying file as Mach-o */ 1185 } else if (SHN_MACHO_64 == shdr.sh_link) { /* Underlying file is Mach-o 64 */ 1186 int dir_idx; 1187 cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize; 1188 cd.cd_symdata = elf_getdata(symscn, NULL); 1189 1190 if ((dir_idx = findelfsecidx(elf, filename, ".dir_str_table")) < 0 || 1191 (symstrscn = elf_getscn(elf, dir_idx)) == NULL || 1192 (cd.cd_strdata = elf_getdata(symstrscn, NULL)) == NULL) 1193 terminate("%s: Can't open direct string table\n", filename); 1194 1195 cd.sh_link = SHN_MACHO_64; /* Mark underlying file as Mach-o 64 */ 1196 } else { 1197 symstrscn = elf_getscn(elf, shdr.sh_link); 1198 1199 cd.cd_nsyms = shdr.sh_size / shdr.sh_entsize; 1200 cd.cd_symdata = elf_getdata(symscn, NULL); 1201 cd.cd_strdata = elf_getdata(symstrscn, NULL); 1202 cd.sh_link = shdr.sh_link; 1203 } 1204#endif /* __APPLE__ */ 1205 } 1206 } 1207 } else { 1208 struct stat st; 1209 1210 if (fstat(fd, &st) == -1) 1211 die("failed to fstat %s", filename); 1212 1213 cd.cd_ctflen = st.st_size; 1214 cd.cd_ctfdata = mmap(NULL, cd.cd_ctflen, PROT_READ, 1215 MAP_PRIVATE, fd, 0); 1216 if (cd.cd_ctfdata == MAP_FAILED) 1217 die("failed to mmap %s", filename); 1218 } 1219 1220 /* 1221 * Get a pointer to the CTF data buffer and interpret the first portion 1222 * as a ctf_header_t. Validate the magic number and size. 1223 */ 1224 1225 if (cd.cd_ctflen < sizeof (ctf_preamble_t)) 1226 die("%s does not contain a CTF preamble\n", filename); 1227 1228 /* LINTED - pointer alignment */ 1229 pp = (const ctf_preamble_t *)cd.cd_ctfdata; 1230 1231 if (pp->ctp_magic != CTF_MAGIC) 1232 die("%s does not appear to contain CTF data\n", filename); 1233 1234 if (pp->ctp_version == CTF_VERSION) { 1235 /* LINTED - pointer alignment */ 1236 hp = (ctf_header_t *)cd.cd_ctfdata; 1237 cd.cd_ctfdata = (caddr_t)cd.cd_ctfdata + sizeof (ctf_header_t); 1238 1239 if (cd.cd_ctflen < sizeof (ctf_header_t)) { 1240 die("%s does not contain a v%d CTF header\n", filename, 1241 CTF_VERSION); 1242 } 1243 1244 } else { 1245 die("%s contains unsupported CTF version %d\n", filename, 1246 pp->ctp_version); 1247 } 1248 1249 /* 1250 * If the data buffer is compressed, then malloc a buffer large enough 1251 * to hold the decompressed data, and use zlib to decompress it. 1252 */ 1253 if (hp->cth_flags & CTF_F_COMPRESS) { 1254 z_stream zstr; 1255 void *buf; 1256 int rc; 1257 1258 if ((buf = malloc(hp->cth_stroff + hp->cth_strlen)) == NULL) 1259 die("failed to allocate decompression buffer"); 1260 1261 bzero(&zstr, sizeof (z_stream)); 1262 zstr.next_in = (void *)cd.cd_ctfdata; 1263 zstr.avail_in = cd.cd_ctflen; 1264 zstr.next_out = buf; 1265 zstr.avail_out = hp->cth_stroff + hp->cth_strlen; 1266 1267 if ((rc = inflateInit(&zstr)) != Z_OK) 1268 die("failed to initialize zlib: %s\n", zError(rc)); 1269 1270 if ((rc = inflate(&zstr, Z_FINISH)) != Z_STREAM_END) 1271 die("failed to decompress CTF data: %s\n", zError(rc)); 1272 1273 if ((rc = inflateEnd(&zstr)) != Z_OK) 1274 die("failed to finish decompression: %s\n", zError(rc)); 1275 1276 if (zstr.total_out != hp->cth_stroff + hp->cth_strlen) 1277 die("CTF data is corrupt -- short decompression\n"); 1278 1279 cd.cd_ctfdata = buf; 1280 cd.cd_ctflen = hp->cth_stroff + hp->cth_strlen; 1281 } 1282 1283#ifdef __APPLE__ 1284 if (doclean) { 1285 int nsyms = argc - 1 - optind; 1286 char **syms = &argv[optind]; 1287 char *tmpname = (char *)mktmpname(filename, ".ctf"); 1288 ctf_buf_t tmpbuf; 1289 1290 ctf_data_to_ctf_buf(hp, &cd, &tmpbuf); 1291 clean_strtab(hp, &cd, &tmpbuf.ctb_strtab, syms, nsyms); 1292 1293 write_ctfdata(fd, elf, filename, tmpname, hp, &tmpbuf); 1294 if (rename(tmpname, filename) != 0) { 1295 terminate("Couldn't rename temp file %s to %s", tmpname, 1296 filename); 1297 } 1298 free(tmpname); 1299 flags = 0; 1300 } 1301#endif /* __APPLE__ */ 1302 1303 if (flags & F_HDR) 1304 error |= print_header(hp, &cd); 1305 if (flags & (F_LABEL)) 1306 error |= print_labeltable(hp, &cd); 1307 if (flags & (F_DATA | F_STATS)) 1308 error |= read_data(hp, &cd); 1309 if (flags & (F_FUNC | F_STATS)) 1310 error |= read_funcs(hp, &cd); 1311 if (flags & (F_TYPES | F_STATS)) 1312 error |= read_types(hp, &cd); 1313 if (flags & (F_STR | F_STATS)) 1314 error |= read_strtab(hp, &cd); 1315 if (flags & F_STATS) 1316 error |= print_stats(); 1317 1318 /* 1319 * If the -u option is specified, write the uncompressed CTF data to a 1320 * raw CTF file. CTF data can already be extracted compressed by 1321 * applying elfdump -w -N .SUNW_ctf to an ELF file, so we don't bother. 1322 */ 1323 if (ufile != NULL) { 1324 ctf_header_t h; 1325 1326 bcopy(hp, &h, sizeof (h)); 1327 h.cth_flags &= ~CTF_F_COMPRESS; 1328 1329 if ((ufd = open(ufile, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0 || 1330 write(ufd, &h, sizeof (h)) != sizeof (h) || 1331 write(ufd, cd.cd_ctfdata, cd.cd_ctflen) != cd.cd_ctflen) { 1332 warn("failed to write CTF data to '%s'", ufile); 1333 error |= E_ERROR; 1334 } 1335 1336 (void) close(ufd); 1337 } 1338 1339 if (elf != NULL) 1340 (void) elf_end(elf); 1341 1342 (void) close(fd); 1343 return (error); 1344} 1345