11618Srie /* 21618Srie * CDDL HEADER START 31618Srie * 41618Srie * The contents of this file are subject to the terms of the 51618Srie * Common Development and Distribution License (the "License"). 61618Srie * You may not use this file except in compliance with the License. 71618Srie * 81618Srie * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91618Srie * or http://www.opensolaris.org/os/licensing. 101618Srie * See the License for the specific language governing permissions 111618Srie * and limitations under the License. 121618Srie * 131618Srie * When distributing Covered Code, include this CDDL HEADER in each 141618Srie * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151618Srie * If applicable, add the following below this CDDL HEADER, with the 161618Srie * fields enclosed by brackets "[]" replaced with your own identifying 171618Srie * information: Portions Copyright [yyyy] [name of copyright owner] 181618Srie * 191618Srie * CDDL HEADER END 201618Srie */ 211618Srie 221618Srie /* 233492Sab196087 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 241618Srie * Use is subject to license terms. 251618Srie */ 261618Srie #pragma ident "%Z%%M% %I% %E% SMI" 271618Srie 281618Srie /* 291618Srie * Dump an elf file. 301618Srie */ 311618Srie #include <sys/param.h> 321618Srie #include <fcntl.h> 331618Srie #include <stdio.h> 341618Srie #include <libelf.h> 351618Srie #include <link.h> 361618Srie #include <stdarg.h> 371618Srie #include <unistd.h> 381618Srie #include <libgen.h> 391618Srie #include <libintl.h> 401618Srie #include <locale.h> 411618Srie #include <errno.h> 421618Srie #include <strings.h> 431618Srie #include <debug.h> 441618Srie #include <conv.h> 451618Srie #include <msg.h> 461618Srie #include <_elfdump.h> 471618Srie 48*4063Sab196087 const Cache cache_init = {NULL, NULL, NULL, NULL, 0}; 491618Srie 501618Srie const char * 511618Srie _elfdump_msg(Msg mid) 521618Srie { 531618Srie return (gettext(MSG_ORIG(mid))); 541618Srie } 551618Srie 561618Srie /* 571618Srie * Determine whether a symbol name should be demangled. 581618Srie */ 591618Srie const char * 601618Srie demangle(const char *name, uint_t flags) 611618Srie { 621618Srie if (flags & FLG_DEMANGLE) 631618Srie return (Elf_demangle_name(name)); 641618Srie else 651618Srie return ((char *)name); 661618Srie } 671618Srie 681618Srie /* 691618Srie * Define our own standard error routine. 701618Srie */ 711618Srie void 721618Srie failure(const char *file, const char *func) 731618Srie { 741618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE), 751618Srie file, func, elf_errmsg(elf_errno())); 761618Srie } 771618Srie 781618Srie /* 791618Srie * The full usage message 801618Srie */ 811618Srie static void 821618Srie detail_usage() 831618Srie { 841618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1)); 851618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2)); 861618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3)); 871618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4)); 881618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5)); 891618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6)); 901618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7)); 911618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8)); 921618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9)); 931618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9_1)); 941618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10)); 951618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11)); 961618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12)); 971618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13)); 981618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14)); 991618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15)); 1001618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16)); 1011618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17)); 1021618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18)); 1031618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19)); 1041618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20)); 1053492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21)); 1061618Srie } 1071618Srie 1081618Srie static void 1091618Srie decide(const char *file, Elf *elf, uint_t flags, char *Nname, int wfd) 1101618Srie { 1111618Srie if (gelf_getclass(elf) == ELFCLASS64) 1121618Srie regular64(file, elf, flags, Nname, wfd); 1131618Srie else 1141618Srie regular32(file, elf, flags, Nname, wfd); 1151618Srie } 1161618Srie 1171618Srie static void 1181618Srie archive(const char *file, int fd, Elf *elf, uint_t flags, char *Nname, 1191618Srie int wfd) 1201618Srie { 1211618Srie Elf_Cmd cmd = ELF_C_READ; 1221618Srie Elf_Arhdr *arhdr; 1231618Srie Elf *_elf = 0; 1241618Srie size_t ptr; 1251618Srie Elf_Arsym *arsym = 0; 1261618Srie 1271618Srie /* 1283492Sab196087 * Determine if the archive symbol table itself is required. 1291618Srie */ 1301618Srie if ((flags & FLG_SYMBOLS) && ((Nname == NULL) || 1311618Srie (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) { 1321618Srie /* 1331618Srie * Get the archive symbol table. 1341618Srie */ 1351618Srie if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 1361618Srie /* 1371618Srie * The arsym could be 0 even though there was no error. 1381618Srie * Print the error message only when there was 1391618Srie * real error from elf_getarsym(). 1401618Srie */ 1411618Srie failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 1421618Srie return; 1431618Srie } 1441618Srie } 1451618Srie 1461618Srie /* 1471618Srie * Print the archive symbol table only when the archive symbol 1481618Srie * table exists and it was requested to print. 1491618Srie */ 1501618Srie if (arsym) { 1511618Srie size_t cnt; 1521618Srie char index[MAXNDXSIZE]; 1531618Srie size_t offset = 0, _offset = 0; 1541618Srie 1551618Srie /* 1561618Srie * Print out all the symbol entries. 1571618Srie */ 1581618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 1591618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 1601618Srie 1611618Srie for (cnt = 0; cnt < ptr; cnt++, arsym++) { 1621618Srie /* 1631618Srie * For each object obtain an elf descriptor so that we 1641618Srie * can establish the members name. Note, we have had 1651618Srie * archives where the archive header has not been 1661618Srie * obtainable so be lenient with errors. 1671618Srie */ 1681618Srie if ((offset == 0) || ((arsym->as_off != 0) && 1691618Srie (arsym->as_off != _offset))) { 1701618Srie 1711618Srie if (_elf) 1721618Srie (void) elf_end(_elf); 1731618Srie 1741618Srie if (elf_rand(elf, arsym->as_off) != 1751618Srie arsym->as_off) { 1761618Srie failure(file, MSG_ORIG(MSG_ELF_RAND)); 1771618Srie arhdr = 0; 1781618Srie } else if ((_elf = elf_begin(fd, 1791618Srie ELF_C_READ, elf)) == 0) { 1801618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 1811618Srie arhdr = 0; 1821618Srie } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 1831618Srie failure(file, 1841618Srie MSG_ORIG(MSG_ELF_GETARHDR)); 1851618Srie arhdr = 0; 1861618Srie } 1871618Srie 1881618Srie _offset = arsym->as_off; 1891618Srie if (offset == 0) 1901618Srie offset = _offset; 1911618Srie } 1921618Srie 1931618Srie (void) snprintf(index, MAXNDXSIZE, 1941618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 1951618Srie if (arsym->as_off) 1961618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 1971618Srie /* LINTED */ 1981618Srie (int)arsym->as_off, arhdr ? arhdr->ar_name : 1991618Srie MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 2001618Srie demangle(arsym->as_name, flags) : 2011618Srie MSG_INTL(MSG_STR_NULL))); 2021618Srie else 2031618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 2041618Srie /* LINTED */ 2051618Srie (int)arsym->as_off); 2061618Srie } 2071618Srie 2081618Srie if (_elf) 2091618Srie (void) elf_end(_elf); 2101618Srie 2111618Srie /* 2121618Srie * If we only need the archive symbol table return. 2131618Srie */ 2141618Srie if ((flags & FLG_SYMBOLS) && Nname && 2151618Srie (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0)) 2161618Srie return; 2171618Srie 2181618Srie /* 2191618Srie * Reset elf descriptor in preparation for processing each 2201618Srie * member. 2211618Srie */ 2221618Srie if (offset) 2231618Srie (void) elf_rand(elf, offset); 2241618Srie } 2251618Srie 2261618Srie /* 2271618Srie * Process each object within the archive. 2281618Srie */ 2291618Srie while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 2301618Srie char name[MAXPATHLEN]; 2311618Srie 2321618Srie if ((arhdr = elf_getarhdr(_elf)) == NULL) { 2331618Srie failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 2341618Srie return; 2351618Srie } 2361618Srie if (*arhdr->ar_name != '/') { 2371618Srie (void) snprintf(name, MAXPATHLEN, 2381618Srie MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 2391618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 2401618Srie 2411618Srie switch (elf_kind(_elf)) { 2421618Srie case ELF_K_AR: 2431618Srie archive(name, fd, _elf, flags, Nname, wfd); 2441618Srie break; 2451618Srie case ELF_K_ELF: 2461618Srie decide(name, _elf, flags, Nname, wfd); 2471618Srie break; 2481618Srie default: 2491618Srie (void) fprintf(stderr, 2501618Srie MSG_INTL(MSG_ERR_BADFILE), name); 2511618Srie break; 2521618Srie } 2531618Srie } 2541618Srie 2551618Srie cmd = elf_next(_elf); 2561618Srie (void) elf_end(_elf); 2571618Srie } 2581618Srie } 2591618Srie 2601618Srie int 2611618Srie main(int argc, char **argv, char **envp) 2621618Srie { 2631618Srie Elf *elf; 2641618Srie int var, fd, wfd = 0; 2651618Srie char *Nname = NULL, *wname = 0; 2661618Srie uint_t flags = 0; 2671618Srie 2681618Srie /* 2691618Srie * If we're on a 64-bit kernel, try to exec a full 64-bit version of 2701618Srie * the binary. If successful, conv_check_native() won't return. 2711618Srie */ 2722647Srie (void) conv_check_native(argv, envp); 2731618Srie 2741618Srie /* 2751618Srie * Establish locale. 2761618Srie */ 2771618Srie (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 2781618Srie (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 2791618Srie 2801618Srie (void) setvbuf(stdout, NULL, _IOLBF, 0); 2811618Srie (void) setvbuf(stderr, NULL, _IOLBF, 0); 2821618Srie 2831618Srie opterr = 0; 2841618Srie while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 2851618Srie switch (var) { 2861618Srie case 'C': 2871618Srie flags |= FLG_DEMANGLE; 2881618Srie break; 2891618Srie case 'c': 2901618Srie flags |= FLG_SHDR; 2911618Srie break; 2921618Srie case 'd': 2931618Srie flags |= FLG_DYNAMIC; 2941618Srie break; 2951618Srie case 'e': 2961618Srie flags |= FLG_EHDR; 2971618Srie break; 2981618Srie case 'G': 2991618Srie flags |= FLG_GOT; 3001618Srie break; 3011618Srie case 'g': 3021618Srie flags |= FLG_GROUP; 3031618Srie break; 3041618Srie case 'H': 3051618Srie flags |= FLG_CAP; 3061618Srie break; 3071618Srie case 'h': 3081618Srie flags |= FLG_HASH; 3091618Srie break; 3101618Srie case 'i': 3111618Srie flags |= FLG_INTERP; 3121618Srie break; 3131618Srie case 'k': 3141618Srie flags |= FLG_CHECKSUM; 3151618Srie break; 3161618Srie case 'l': 3171618Srie flags |= FLG_LONGNAME; 3181618Srie break; 3191618Srie case 'm': 3201618Srie flags |= FLG_MOVE; 3211618Srie break; 3221618Srie case 'N': 3231618Srie Nname = optarg; 3241618Srie break; 3251618Srie case 'n': 3261618Srie flags |= FLG_NOTE; 3271618Srie break; 3281618Srie case 'p': 3291618Srie flags |= FLG_PHDR; 3301618Srie break; 3311618Srie case 'r': 3321618Srie flags |= FLG_RELOC; 3331618Srie break; 3343492Sab196087 case 'S': 3353492Sab196087 flags |= FLG_SORT; 3363492Sab196087 break; 3371618Srie case 's': 3381618Srie flags |= FLG_SYMBOLS; 3391618Srie break; 3401618Srie case 'u': 3411618Srie flags |= FLG_UNWIND; 3421618Srie break; 3431618Srie case 'v': 3441618Srie flags |= FLG_VERSIONS; 3451618Srie break; 3461618Srie case 'w': 3471618Srie wname = optarg; 3481618Srie break; 3491618Srie case 'y': 3501618Srie flags |= FLG_SYMINFO; 3511618Srie break; 3521618Srie case '?': 3531618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3541618Srie basename(argv[0])); 3551618Srie detail_usage(); 3561618Srie return (1); 3571618Srie default: 3581618Srie break; 3591618Srie } 3601618Srie } 3611618Srie 3621618Srie /* 3631618Srie * Validate any arguments. 3641618Srie */ 3651618Srie if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) { 3661618Srie if (!wname && !Nname) { 3671618Srie flags |= FLG_EVERYTHING; 3681618Srie } else if (!wname || !Nname) { 3691618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3701618Srie basename(argv[0])); 3711618Srie return (1); 3721618Srie } 3731618Srie } 3741618Srie 3751618Srie if ((var = argc - optind) == 0) { 3761618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3771618Srie basename(argv[0])); 3781618Srie return (1); 3791618Srie } 3801618Srie 3811618Srie /* 3821618Srie * If the -l/-C option is specified, set up the liblddbg.so. 3831618Srie */ 3841618Srie if (flags & FLG_LONGNAME) 3851618Srie dbg_desc->d_extra |= DBG_E_LONG; 3861618Srie if (flags & FLG_DEMANGLE) 3871618Srie dbg_desc->d_extra |= DBG_E_DEMANGLE; 3881618Srie 3891618Srie /* 3901618Srie * If the -w option has indicated an output file open it. It's 3911618Srie * arguable whether this option has much use when multiple files are 3921618Srie * being processed. 3931618Srie */ 3941618Srie if (wname) { 3951618Srie if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 3961618Srie 0666)) < 0) { 3971618Srie int err = errno; 3981618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 3991618Srie wname, strerror(err)); 4001618Srie wfd = 0; 4011618Srie } 4021618Srie } 4031618Srie 4041618Srie /* 4051618Srie * Open the input file and initialize the elf interface. 4061618Srie */ 4071618Srie for (; optind < argc; optind++) { 4081618Srie const char *file = argv[optind]; 4091618Srie 4101618Srie if ((fd = open(argv[optind], O_RDONLY)) == -1) { 4111618Srie int err = errno; 4121618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 4131618Srie file, strerror(err)); 4141618Srie continue; 4151618Srie } 4161618Srie (void) elf_version(EV_CURRENT); 4171618Srie if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 4181618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 4191618Srie (void) close(fd); 4201618Srie continue; 4211618Srie } 4221618Srie 4231618Srie if (var > 1) 4241618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 4251618Srie 4261618Srie switch (elf_kind(elf)) { 4271618Srie case ELF_K_AR: 4281618Srie archive(file, fd, elf, flags, Nname, wfd); 4291618Srie break; 4301618Srie case ELF_K_ELF: 4311618Srie decide(file, elf, flags, Nname, wfd); 4321618Srie break; 4331618Srie default: 4341618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 4351618Srie break; 4361618Srie } 4371618Srie 4381618Srie (void) close(fd); 4391618Srie (void) elf_end(elf); 4401618Srie } 4411618Srie 4421618Srie if (wfd) 4431618Srie (void) close(wfd); 4441618Srie return (0); 4451618Srie } 446