1*1618Srie /* 2*1618Srie * CDDL HEADER START 3*1618Srie * 4*1618Srie * The contents of this file are subject to the terms of the 5*1618Srie * Common Development and Distribution License (the "License"). 6*1618Srie * You may not use this file except in compliance with the License. 7*1618Srie * 8*1618Srie * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1618Srie * or http://www.opensolaris.org/os/licensing. 10*1618Srie * See the License for the specific language governing permissions 11*1618Srie * and limitations under the License. 12*1618Srie * 13*1618Srie * When distributing Covered Code, include this CDDL HEADER in each 14*1618Srie * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1618Srie * If applicable, add the following below this CDDL HEADER, with the 16*1618Srie * fields enclosed by brackets "[]" replaced with your own identifying 17*1618Srie * information: Portions Copyright [yyyy] [name of copyright owner] 18*1618Srie * 19*1618Srie * CDDL HEADER END 20*1618Srie */ 21*1618Srie 22*1618Srie /* 23*1618Srie * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*1618Srie * Use is subject to license terms. 25*1618Srie */ 26*1618Srie #pragma ident "%Z%%M% %I% %E% SMI" 27*1618Srie 28*1618Srie /* 29*1618Srie * Dump an elf file. 30*1618Srie */ 31*1618Srie #include <sys/param.h> 32*1618Srie #include <fcntl.h> 33*1618Srie #include <stdio.h> 34*1618Srie #include <libelf.h> 35*1618Srie #include <link.h> 36*1618Srie #include <stdarg.h> 37*1618Srie #include <unistd.h> 38*1618Srie #include <libgen.h> 39*1618Srie #include <libintl.h> 40*1618Srie #include <locale.h> 41*1618Srie #include <errno.h> 42*1618Srie #include <strings.h> 43*1618Srie #include <debug.h> 44*1618Srie #include <conv.h> 45*1618Srie #include <msg.h> 46*1618Srie #include <_elfdump.h> 47*1618Srie 48*1618Srie const Cache cache_init = {NULL, NULL, NULL}; 49*1618Srie 50*1618Srie const char * 51*1618Srie _elfdump_msg(Msg mid) 52*1618Srie { 53*1618Srie return (gettext(MSG_ORIG(mid))); 54*1618Srie } 55*1618Srie 56*1618Srie /* 57*1618Srie * Determine whether a symbol name should be demangled. 58*1618Srie */ 59*1618Srie const char * 60*1618Srie demangle(const char *name, uint_t flags) 61*1618Srie { 62*1618Srie if (flags & FLG_DEMANGLE) 63*1618Srie return (Elf_demangle_name(name)); 64*1618Srie else 65*1618Srie return ((char *)name); 66*1618Srie } 67*1618Srie 68*1618Srie /* 69*1618Srie * Define our own standard error routine. 70*1618Srie */ 71*1618Srie void 72*1618Srie failure(const char *file, const char *func) 73*1618Srie { 74*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE), 75*1618Srie file, func, elf_errmsg(elf_errno())); 76*1618Srie } 77*1618Srie 78*1618Srie /* 79*1618Srie * The full usage message 80*1618Srie */ 81*1618Srie static void 82*1618Srie detail_usage() 83*1618Srie { 84*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1)); 85*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2)); 86*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3)); 87*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4)); 88*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5)); 89*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6)); 90*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7)); 91*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8)); 92*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9)); 93*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9_1)); 94*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10)); 95*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11)); 96*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12)); 97*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13)); 98*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14)); 99*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15)); 100*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16)); 101*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17)); 102*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18)); 103*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19)); 104*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20)); 105*1618Srie } 106*1618Srie 107*1618Srie static void 108*1618Srie decide(const char *file, Elf *elf, uint_t flags, char *Nname, int wfd) 109*1618Srie { 110*1618Srie if (gelf_getclass(elf) == ELFCLASS64) 111*1618Srie regular64(file, elf, flags, Nname, wfd); 112*1618Srie else 113*1618Srie regular32(file, elf, flags, Nname, wfd); 114*1618Srie } 115*1618Srie 116*1618Srie static void 117*1618Srie archive(const char *file, int fd, Elf *elf, uint_t flags, char *Nname, 118*1618Srie int wfd) 119*1618Srie { 120*1618Srie Elf_Cmd cmd = ELF_C_READ; 121*1618Srie Elf_Arhdr *arhdr; 122*1618Srie Elf *_elf = 0; 123*1618Srie size_t ptr; 124*1618Srie Elf_Arsym *arsym = 0; 125*1618Srie 126*1618Srie /* 127*1618Srie * Determine if the archive sysmbol table itself is required. 128*1618Srie */ 129*1618Srie if ((flags & FLG_SYMBOLS) && ((Nname == NULL) || 130*1618Srie (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) { 131*1618Srie /* 132*1618Srie * Get the archive symbol table. 133*1618Srie */ 134*1618Srie if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 135*1618Srie /* 136*1618Srie * The arsym could be 0 even though there was no error. 137*1618Srie * Print the error message only when there was 138*1618Srie * real error from elf_getarsym(). 139*1618Srie */ 140*1618Srie failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 141*1618Srie return; 142*1618Srie } 143*1618Srie } 144*1618Srie 145*1618Srie /* 146*1618Srie * Print the archive symbol table only when the archive symbol 147*1618Srie * table exists and it was requested to print. 148*1618Srie */ 149*1618Srie if (arsym) { 150*1618Srie size_t cnt; 151*1618Srie char index[MAXNDXSIZE]; 152*1618Srie size_t offset = 0, _offset = 0; 153*1618Srie 154*1618Srie /* 155*1618Srie * Print out all the symbol entries. 156*1618Srie */ 157*1618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 158*1618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 159*1618Srie 160*1618Srie for (cnt = 0; cnt < ptr; cnt++, arsym++) { 161*1618Srie /* 162*1618Srie * For each object obtain an elf descriptor so that we 163*1618Srie * can establish the members name. Note, we have had 164*1618Srie * archives where the archive header has not been 165*1618Srie * obtainable so be lenient with errors. 166*1618Srie */ 167*1618Srie if ((offset == 0) || ((arsym->as_off != 0) && 168*1618Srie (arsym->as_off != _offset))) { 169*1618Srie 170*1618Srie if (_elf) 171*1618Srie (void) elf_end(_elf); 172*1618Srie 173*1618Srie if (elf_rand(elf, arsym->as_off) != 174*1618Srie arsym->as_off) { 175*1618Srie failure(file, MSG_ORIG(MSG_ELF_RAND)); 176*1618Srie arhdr = 0; 177*1618Srie } else if ((_elf = elf_begin(fd, 178*1618Srie ELF_C_READ, elf)) == 0) { 179*1618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 180*1618Srie arhdr = 0; 181*1618Srie } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 182*1618Srie failure(file, 183*1618Srie MSG_ORIG(MSG_ELF_GETARHDR)); 184*1618Srie arhdr = 0; 185*1618Srie } 186*1618Srie 187*1618Srie _offset = arsym->as_off; 188*1618Srie if (offset == 0) 189*1618Srie offset = _offset; 190*1618Srie } 191*1618Srie 192*1618Srie (void) snprintf(index, MAXNDXSIZE, 193*1618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 194*1618Srie if (arsym->as_off) 195*1618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 196*1618Srie /* LINTED */ 197*1618Srie (int)arsym->as_off, arhdr ? arhdr->ar_name : 198*1618Srie MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 199*1618Srie demangle(arsym->as_name, flags) : 200*1618Srie MSG_INTL(MSG_STR_NULL))); 201*1618Srie else 202*1618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 203*1618Srie /* LINTED */ 204*1618Srie (int)arsym->as_off); 205*1618Srie } 206*1618Srie 207*1618Srie if (_elf) 208*1618Srie (void) elf_end(_elf); 209*1618Srie 210*1618Srie /* 211*1618Srie * If we only need the archive symbol table return. 212*1618Srie */ 213*1618Srie if ((flags & FLG_SYMBOLS) && Nname && 214*1618Srie (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0)) 215*1618Srie return; 216*1618Srie 217*1618Srie /* 218*1618Srie * Reset elf descriptor in preparation for processing each 219*1618Srie * member. 220*1618Srie */ 221*1618Srie if (offset) 222*1618Srie (void) elf_rand(elf, offset); 223*1618Srie } 224*1618Srie 225*1618Srie /* 226*1618Srie * Process each object within the archive. 227*1618Srie */ 228*1618Srie while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 229*1618Srie char name[MAXPATHLEN]; 230*1618Srie 231*1618Srie if ((arhdr = elf_getarhdr(_elf)) == NULL) { 232*1618Srie failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 233*1618Srie return; 234*1618Srie } 235*1618Srie if (*arhdr->ar_name != '/') { 236*1618Srie (void) snprintf(name, MAXPATHLEN, 237*1618Srie MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 238*1618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 239*1618Srie 240*1618Srie switch (elf_kind(_elf)) { 241*1618Srie case ELF_K_AR: 242*1618Srie archive(name, fd, _elf, flags, Nname, wfd); 243*1618Srie break; 244*1618Srie case ELF_K_ELF: 245*1618Srie decide(name, _elf, flags, Nname, wfd); 246*1618Srie break; 247*1618Srie default: 248*1618Srie (void) fprintf(stderr, 249*1618Srie MSG_INTL(MSG_ERR_BADFILE), name); 250*1618Srie break; 251*1618Srie } 252*1618Srie } 253*1618Srie 254*1618Srie cmd = elf_next(_elf); 255*1618Srie (void) elf_end(_elf); 256*1618Srie } 257*1618Srie } 258*1618Srie 259*1618Srie int 260*1618Srie main(int argc, char **argv, char **envp) 261*1618Srie { 262*1618Srie Elf *elf; 263*1618Srie int var, fd, wfd = 0; 264*1618Srie char *Nname = NULL, *wname = 0; 265*1618Srie uint_t flags = 0; 266*1618Srie 267*1618Srie /* 268*1618Srie * If we're on a 64-bit kernel, try to exec a full 64-bit version of 269*1618Srie * the binary. If successful, conv_check_native() won't return. 270*1618Srie */ 271*1618Srie conv_check_native(argv, envp); 272*1618Srie 273*1618Srie /* 274*1618Srie * Establish locale. 275*1618Srie */ 276*1618Srie (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 277*1618Srie (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 278*1618Srie 279*1618Srie (void) setvbuf(stdout, NULL, _IOLBF, 0); 280*1618Srie (void) setvbuf(stderr, NULL, _IOLBF, 0); 281*1618Srie 282*1618Srie opterr = 0; 283*1618Srie while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 284*1618Srie switch (var) { 285*1618Srie case 'C': 286*1618Srie flags |= FLG_DEMANGLE; 287*1618Srie break; 288*1618Srie case 'c': 289*1618Srie flags |= FLG_SHDR; 290*1618Srie break; 291*1618Srie case 'd': 292*1618Srie flags |= FLG_DYNAMIC; 293*1618Srie break; 294*1618Srie case 'e': 295*1618Srie flags |= FLG_EHDR; 296*1618Srie break; 297*1618Srie case 'G': 298*1618Srie flags |= FLG_GOT; 299*1618Srie break; 300*1618Srie case 'g': 301*1618Srie flags |= FLG_GROUP; 302*1618Srie break; 303*1618Srie case 'H': 304*1618Srie flags |= FLG_CAP; 305*1618Srie break; 306*1618Srie case 'h': 307*1618Srie flags |= FLG_HASH; 308*1618Srie break; 309*1618Srie case 'i': 310*1618Srie flags |= FLG_INTERP; 311*1618Srie break; 312*1618Srie case 'k': 313*1618Srie flags |= FLG_CHECKSUM; 314*1618Srie break; 315*1618Srie case 'l': 316*1618Srie flags |= FLG_LONGNAME; 317*1618Srie break; 318*1618Srie case 'm': 319*1618Srie flags |= FLG_MOVE; 320*1618Srie break; 321*1618Srie case 'N': 322*1618Srie Nname = optarg; 323*1618Srie break; 324*1618Srie case 'n': 325*1618Srie flags |= FLG_NOTE; 326*1618Srie break; 327*1618Srie case 'p': 328*1618Srie flags |= FLG_PHDR; 329*1618Srie break; 330*1618Srie case 'r': 331*1618Srie flags |= FLG_RELOC; 332*1618Srie break; 333*1618Srie case 's': 334*1618Srie flags |= FLG_SYMBOLS; 335*1618Srie break; 336*1618Srie case 'u': 337*1618Srie flags |= FLG_UNWIND; 338*1618Srie break; 339*1618Srie case 'v': 340*1618Srie flags |= FLG_VERSIONS; 341*1618Srie break; 342*1618Srie case 'w': 343*1618Srie wname = optarg; 344*1618Srie break; 345*1618Srie case 'y': 346*1618Srie flags |= FLG_SYMINFO; 347*1618Srie break; 348*1618Srie case '?': 349*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 350*1618Srie basename(argv[0])); 351*1618Srie detail_usage(); 352*1618Srie return (1); 353*1618Srie default: 354*1618Srie break; 355*1618Srie } 356*1618Srie } 357*1618Srie 358*1618Srie /* 359*1618Srie * Validate any arguments. 360*1618Srie */ 361*1618Srie if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) { 362*1618Srie if (!wname && !Nname) { 363*1618Srie flags |= FLG_EVERYTHING; 364*1618Srie } else if (!wname || !Nname) { 365*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 366*1618Srie basename(argv[0])); 367*1618Srie return (1); 368*1618Srie } 369*1618Srie } 370*1618Srie 371*1618Srie if ((var = argc - optind) == 0) { 372*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 373*1618Srie basename(argv[0])); 374*1618Srie return (1); 375*1618Srie } 376*1618Srie 377*1618Srie /* 378*1618Srie * If the -l/-C option is specified, set up the liblddbg.so. 379*1618Srie */ 380*1618Srie if (flags & FLG_LONGNAME) 381*1618Srie dbg_desc->d_extra |= DBG_E_LONG; 382*1618Srie if (flags & FLG_DEMANGLE) 383*1618Srie dbg_desc->d_extra |= DBG_E_DEMANGLE; 384*1618Srie 385*1618Srie /* 386*1618Srie * If the -w option has indicated an output file open it. It's 387*1618Srie * arguable whether this option has much use when multiple files are 388*1618Srie * being processed. 389*1618Srie */ 390*1618Srie if (wname) { 391*1618Srie if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 392*1618Srie 0666)) < 0) { 393*1618Srie int err = errno; 394*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 395*1618Srie wname, strerror(err)); 396*1618Srie wfd = 0; 397*1618Srie } 398*1618Srie } 399*1618Srie 400*1618Srie /* 401*1618Srie * Open the input file and initialize the elf interface. 402*1618Srie */ 403*1618Srie for (; optind < argc; optind++) { 404*1618Srie const char *file = argv[optind]; 405*1618Srie 406*1618Srie if ((fd = open(argv[optind], O_RDONLY)) == -1) { 407*1618Srie int err = errno; 408*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 409*1618Srie file, strerror(err)); 410*1618Srie continue; 411*1618Srie } 412*1618Srie (void) elf_version(EV_CURRENT); 413*1618Srie if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 414*1618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 415*1618Srie (void) close(fd); 416*1618Srie continue; 417*1618Srie } 418*1618Srie 419*1618Srie if (var > 1) 420*1618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 421*1618Srie 422*1618Srie switch (elf_kind(elf)) { 423*1618Srie case ELF_K_AR: 424*1618Srie archive(file, fd, elf, flags, Nname, wfd); 425*1618Srie break; 426*1618Srie case ELF_K_ELF: 427*1618Srie decide(file, elf, flags, Nname, wfd); 428*1618Srie break; 429*1618Srie default: 430*1618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 431*1618Srie break; 432*1618Srie } 433*1618Srie 434*1618Srie (void) close(fd); 435*1618Srie (void) elf_end(elf); 436*1618Srie } 437*1618Srie 438*1618Srie if (wfd) 439*1618Srie (void) close(wfd); 440*1618Srie return (0); 441*1618Srie } 442