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 /* 231618Srie * Copyright 2006 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 481618Srie const Cache cache_init = {NULL, NULL, NULL}; 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)); 1051618Srie } 1061618Srie 1071618Srie static void 1081618Srie decide(const char *file, Elf *elf, uint_t flags, char *Nname, int wfd) 1091618Srie { 1101618Srie if (gelf_getclass(elf) == ELFCLASS64) 1111618Srie regular64(file, elf, flags, Nname, wfd); 1121618Srie else 1131618Srie regular32(file, elf, flags, Nname, wfd); 1141618Srie } 1151618Srie 1161618Srie static void 1171618Srie archive(const char *file, int fd, Elf *elf, uint_t flags, char *Nname, 1181618Srie int wfd) 1191618Srie { 1201618Srie Elf_Cmd cmd = ELF_C_READ; 1211618Srie Elf_Arhdr *arhdr; 1221618Srie Elf *_elf = 0; 1231618Srie size_t ptr; 1241618Srie Elf_Arsym *arsym = 0; 1251618Srie 1261618Srie /* 1271618Srie * Determine if the archive sysmbol table itself is required. 1281618Srie */ 1291618Srie if ((flags & FLG_SYMBOLS) && ((Nname == NULL) || 1301618Srie (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) { 1311618Srie /* 1321618Srie * Get the archive symbol table. 1331618Srie */ 1341618Srie if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 1351618Srie /* 1361618Srie * The arsym could be 0 even though there was no error. 1371618Srie * Print the error message only when there was 1381618Srie * real error from elf_getarsym(). 1391618Srie */ 1401618Srie failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 1411618Srie return; 1421618Srie } 1431618Srie } 1441618Srie 1451618Srie /* 1461618Srie * Print the archive symbol table only when the archive symbol 1471618Srie * table exists and it was requested to print. 1481618Srie */ 1491618Srie if (arsym) { 1501618Srie size_t cnt; 1511618Srie char index[MAXNDXSIZE]; 1521618Srie size_t offset = 0, _offset = 0; 1531618Srie 1541618Srie /* 1551618Srie * Print out all the symbol entries. 1561618Srie */ 1571618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 1581618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 1591618Srie 1601618Srie for (cnt = 0; cnt < ptr; cnt++, arsym++) { 1611618Srie /* 1621618Srie * For each object obtain an elf descriptor so that we 1631618Srie * can establish the members name. Note, we have had 1641618Srie * archives where the archive header has not been 1651618Srie * obtainable so be lenient with errors. 1661618Srie */ 1671618Srie if ((offset == 0) || ((arsym->as_off != 0) && 1681618Srie (arsym->as_off != _offset))) { 1691618Srie 1701618Srie if (_elf) 1711618Srie (void) elf_end(_elf); 1721618Srie 1731618Srie if (elf_rand(elf, arsym->as_off) != 1741618Srie arsym->as_off) { 1751618Srie failure(file, MSG_ORIG(MSG_ELF_RAND)); 1761618Srie arhdr = 0; 1771618Srie } else if ((_elf = elf_begin(fd, 1781618Srie ELF_C_READ, elf)) == 0) { 1791618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 1801618Srie arhdr = 0; 1811618Srie } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 1821618Srie failure(file, 1831618Srie MSG_ORIG(MSG_ELF_GETARHDR)); 1841618Srie arhdr = 0; 1851618Srie } 1861618Srie 1871618Srie _offset = arsym->as_off; 1881618Srie if (offset == 0) 1891618Srie offset = _offset; 1901618Srie } 1911618Srie 1921618Srie (void) snprintf(index, MAXNDXSIZE, 1931618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 1941618Srie if (arsym->as_off) 1951618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 1961618Srie /* LINTED */ 1971618Srie (int)arsym->as_off, arhdr ? arhdr->ar_name : 1981618Srie MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 1991618Srie demangle(arsym->as_name, flags) : 2001618Srie MSG_INTL(MSG_STR_NULL))); 2011618Srie else 2021618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 2031618Srie /* LINTED */ 2041618Srie (int)arsym->as_off); 2051618Srie } 2061618Srie 2071618Srie if (_elf) 2081618Srie (void) elf_end(_elf); 2091618Srie 2101618Srie /* 2111618Srie * If we only need the archive symbol table return. 2121618Srie */ 2131618Srie if ((flags & FLG_SYMBOLS) && Nname && 2141618Srie (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0)) 2151618Srie return; 2161618Srie 2171618Srie /* 2181618Srie * Reset elf descriptor in preparation for processing each 2191618Srie * member. 2201618Srie */ 2211618Srie if (offset) 2221618Srie (void) elf_rand(elf, offset); 2231618Srie } 2241618Srie 2251618Srie /* 2261618Srie * Process each object within the archive. 2271618Srie */ 2281618Srie while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 2291618Srie char name[MAXPATHLEN]; 2301618Srie 2311618Srie if ((arhdr = elf_getarhdr(_elf)) == NULL) { 2321618Srie failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 2331618Srie return; 2341618Srie } 2351618Srie if (*arhdr->ar_name != '/') { 2361618Srie (void) snprintf(name, MAXPATHLEN, 2371618Srie MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 2381618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 2391618Srie 2401618Srie switch (elf_kind(_elf)) { 2411618Srie case ELF_K_AR: 2421618Srie archive(name, fd, _elf, flags, Nname, wfd); 2431618Srie break; 2441618Srie case ELF_K_ELF: 2451618Srie decide(name, _elf, flags, Nname, wfd); 2461618Srie break; 2471618Srie default: 2481618Srie (void) fprintf(stderr, 2491618Srie MSG_INTL(MSG_ERR_BADFILE), name); 2501618Srie break; 2511618Srie } 2521618Srie } 2531618Srie 2541618Srie cmd = elf_next(_elf); 2551618Srie (void) elf_end(_elf); 2561618Srie } 2571618Srie } 2581618Srie 2591618Srie int 2601618Srie main(int argc, char **argv, char **envp) 2611618Srie { 2621618Srie Elf *elf; 2631618Srie int var, fd, wfd = 0; 2641618Srie char *Nname = NULL, *wname = 0; 2651618Srie uint_t flags = 0; 2661618Srie 2671618Srie /* 2681618Srie * If we're on a 64-bit kernel, try to exec a full 64-bit version of 2691618Srie * the binary. If successful, conv_check_native() won't return. 2701618Srie */ 271*2647Srie (void) conv_check_native(argv, envp); 2721618Srie 2731618Srie /* 2741618Srie * Establish locale. 2751618Srie */ 2761618Srie (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 2771618Srie (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 2781618Srie 2791618Srie (void) setvbuf(stdout, NULL, _IOLBF, 0); 2801618Srie (void) setvbuf(stderr, NULL, _IOLBF, 0); 2811618Srie 2821618Srie opterr = 0; 2831618Srie while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 2841618Srie switch (var) { 2851618Srie case 'C': 2861618Srie flags |= FLG_DEMANGLE; 2871618Srie break; 2881618Srie case 'c': 2891618Srie flags |= FLG_SHDR; 2901618Srie break; 2911618Srie case 'd': 2921618Srie flags |= FLG_DYNAMIC; 2931618Srie break; 2941618Srie case 'e': 2951618Srie flags |= FLG_EHDR; 2961618Srie break; 2971618Srie case 'G': 2981618Srie flags |= FLG_GOT; 2991618Srie break; 3001618Srie case 'g': 3011618Srie flags |= FLG_GROUP; 3021618Srie break; 3031618Srie case 'H': 3041618Srie flags |= FLG_CAP; 3051618Srie break; 3061618Srie case 'h': 3071618Srie flags |= FLG_HASH; 3081618Srie break; 3091618Srie case 'i': 3101618Srie flags |= FLG_INTERP; 3111618Srie break; 3121618Srie case 'k': 3131618Srie flags |= FLG_CHECKSUM; 3141618Srie break; 3151618Srie case 'l': 3161618Srie flags |= FLG_LONGNAME; 3171618Srie break; 3181618Srie case 'm': 3191618Srie flags |= FLG_MOVE; 3201618Srie break; 3211618Srie case 'N': 3221618Srie Nname = optarg; 3231618Srie break; 3241618Srie case 'n': 3251618Srie flags |= FLG_NOTE; 3261618Srie break; 3271618Srie case 'p': 3281618Srie flags |= FLG_PHDR; 3291618Srie break; 3301618Srie case 'r': 3311618Srie flags |= FLG_RELOC; 3321618Srie break; 3331618Srie case 's': 3341618Srie flags |= FLG_SYMBOLS; 3351618Srie break; 3361618Srie case 'u': 3371618Srie flags |= FLG_UNWIND; 3381618Srie break; 3391618Srie case 'v': 3401618Srie flags |= FLG_VERSIONS; 3411618Srie break; 3421618Srie case 'w': 3431618Srie wname = optarg; 3441618Srie break; 3451618Srie case 'y': 3461618Srie flags |= FLG_SYMINFO; 3471618Srie break; 3481618Srie case '?': 3491618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3501618Srie basename(argv[0])); 3511618Srie detail_usage(); 3521618Srie return (1); 3531618Srie default: 3541618Srie break; 3551618Srie } 3561618Srie } 3571618Srie 3581618Srie /* 3591618Srie * Validate any arguments. 3601618Srie */ 3611618Srie if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) { 3621618Srie if (!wname && !Nname) { 3631618Srie flags |= FLG_EVERYTHING; 3641618Srie } else if (!wname || !Nname) { 3651618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3661618Srie basename(argv[0])); 3671618Srie return (1); 3681618Srie } 3691618Srie } 3701618Srie 3711618Srie if ((var = argc - optind) == 0) { 3721618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3731618Srie basename(argv[0])); 3741618Srie return (1); 3751618Srie } 3761618Srie 3771618Srie /* 3781618Srie * If the -l/-C option is specified, set up the liblddbg.so. 3791618Srie */ 3801618Srie if (flags & FLG_LONGNAME) 3811618Srie dbg_desc->d_extra |= DBG_E_LONG; 3821618Srie if (flags & FLG_DEMANGLE) 3831618Srie dbg_desc->d_extra |= DBG_E_DEMANGLE; 3841618Srie 3851618Srie /* 3861618Srie * If the -w option has indicated an output file open it. It's 3871618Srie * arguable whether this option has much use when multiple files are 3881618Srie * being processed. 3891618Srie */ 3901618Srie if (wname) { 3911618Srie if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 3921618Srie 0666)) < 0) { 3931618Srie int err = errno; 3941618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 3951618Srie wname, strerror(err)); 3961618Srie wfd = 0; 3971618Srie } 3981618Srie } 3991618Srie 4001618Srie /* 4011618Srie * Open the input file and initialize the elf interface. 4021618Srie */ 4031618Srie for (; optind < argc; optind++) { 4041618Srie const char *file = argv[optind]; 4051618Srie 4061618Srie if ((fd = open(argv[optind], O_RDONLY)) == -1) { 4071618Srie int err = errno; 4081618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 4091618Srie file, strerror(err)); 4101618Srie continue; 4111618Srie } 4121618Srie (void) elf_version(EV_CURRENT); 4131618Srie if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 4141618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 4151618Srie (void) close(fd); 4161618Srie continue; 4171618Srie } 4181618Srie 4191618Srie if (var > 1) 4201618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 4211618Srie 4221618Srie switch (elf_kind(elf)) { 4231618Srie case ELF_K_AR: 4241618Srie archive(file, fd, elf, flags, Nname, wfd); 4251618Srie break; 4261618Srie case ELF_K_ELF: 4271618Srie decide(file, elf, flags, Nname, wfd); 4281618Srie break; 4291618Srie default: 4301618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 4311618Srie break; 4321618Srie } 4331618Srie 4341618Srie (void) close(fd); 4351618Srie (void) elf_end(elf); 4361618Srie } 4371618Srie 4381618Srie if (wfd) 4391618Srie (void) close(wfd); 4401618Srie return (0); 4411618Srie } 442