10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * 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. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211324Srie 220Sstevel@tonic-gate /* 23*8747SAli.Bahrami@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * Dump an elf file. 290Sstevel@tonic-gate */ 301618Srie #include <sys/elf_386.h> 311618Srie #include <sys/elf_amd64.h> 321618Srie #include <sys/elf_SPARC.h> 336206Sab196087 #include <_libelf.h> 341618Srie #include <dwarf.h> 355549Srie #include <stdio.h> 360Sstevel@tonic-gate #include <unistd.h> 370Sstevel@tonic-gate #include <errno.h> 380Sstevel@tonic-gate #include <strings.h> 390Sstevel@tonic-gate #include <debug.h> 400Sstevel@tonic-gate #include <conv.h> 410Sstevel@tonic-gate #include <msg.h> 421618Srie #include <_elfdump.h> 430Sstevel@tonic-gate 443875Sab196087 453875Sab196087 /* 463875Sab196087 * VERSYM_STATE is used to maintain information about the VERSYM section 473875Sab196087 * in the object being analyzed. It is filled in by versions(), and used 483875Sab196087 * by init_symtbl_state() when displaying symbol information. 493875Sab196087 * 507682SAli.Bahrami@Sun.COM * There are three forms of symbol versioning known to us: 517682SAli.Bahrami@Sun.COM * 527682SAli.Bahrami@Sun.COM * 1) The original form, introduced with Solaris 2.5, in which 537682SAli.Bahrami@Sun.COM * the Versym contains indexes to Verdef records, and the 547682SAli.Bahrami@Sun.COM * Versym values for UNDEF symbols resolved by other objects 557682SAli.Bahrami@Sun.COM * are all set to 0. 567682SAli.Bahrami@Sun.COM * 2) The GNU form, which is backward compatible with the original 577682SAli.Bahrami@Sun.COM * Solaris form, but which adds several extensions: 587682SAli.Bahrami@Sun.COM * - The Versym also contains indexes to Verneed records, recording 597682SAli.Bahrami@Sun.COM * which object/version contributed the external symbol at 607682SAli.Bahrami@Sun.COM * link time. These indexes start with the next value following 617682SAli.Bahrami@Sun.COM * the final Verdef index. The index is written to the previously 627682SAli.Bahrami@Sun.COM * reserved vna_other field of the ELF Vernaux structure. 637682SAli.Bahrami@Sun.COM * - The top bit of the Versym value is no longer part of the index, 647682SAli.Bahrami@Sun.COM * but is used as a "hidden bit" to prevent binding to the symbol. 657682SAli.Bahrami@Sun.COM * - Multiple implementations of a given symbol, contained in varying 667682SAli.Bahrami@Sun.COM * versions are allowed, using special assembler pseudo ops, 677682SAli.Bahrami@Sun.COM * and encoded in the symbol name using '@' characters. 687682SAli.Bahrami@Sun.COM * 3) Modified Solaris form, in which we adopt the first GNU extension 697682SAli.Bahrami@Sun.COM * (Versym indexes to Verneed records), but not the others. 707682SAli.Bahrami@Sun.COM * 717682SAli.Bahrami@Sun.COM * elfdump can handle any of these cases. The presence of a DT_VERSYM 727682SAli.Bahrami@Sun.COM * dynamic element indicates a full GNU object. An object that lacks 737682SAli.Bahrami@Sun.COM * a DT_VERSYM entry, but which has non-zero vna_other fields in the Vernaux 747682SAli.Bahrami@Sun.COM * structures is a modified Solaris object. An object that has neither of 757682SAli.Bahrami@Sun.COM * these uses the original form. 767682SAli.Bahrami@Sun.COM * 774716Sab196087 * max_verndx contains the largest version index that can appear 784716Sab196087 * in a Versym entry. This can never be less than 1: In the case where 794716Sab196087 * there is no verdef/verneed sections, the [0] index is reserved 807682SAli.Bahrami@Sun.COM * for local symbols, and the [1] index for globals. If the original 817682SAli.Bahrami@Sun.COM * Solaris versioning rules are in effect and there is a verdef section, 827682SAli.Bahrami@Sun.COM * then max_verndex is the number of defined versions. If one of the 837682SAli.Bahrami@Sun.COM * other versioning forms is in effect, then: 847682SAli.Bahrami@Sun.COM * 1) If there is no verneed section, it is the same as for 857682SAli.Bahrami@Sun.COM * original Solaris versioning. 867682SAli.Bahrami@Sun.COM * 2) If there is a verneed section, the vna_other field of the 874716Sab196087 * Vernaux structs contain versions, and max_verndx is the 884716Sab196087 * largest such index. 894716Sab196087 * 907682SAli.Bahrami@Sun.COM * If gnu_full is True, the object uses the full GNU form of versioning. 917682SAli.Bahrami@Sun.COM * The value of the gnu_full field is based on the presence of 924716Sab196087 * a DT_VERSYM entry in the dynamic section: GNU ld produces these, and 934716Sab196087 * Solaris ld does not. 947682SAli.Bahrami@Sun.COM * 957682SAli.Bahrami@Sun.COM * The gnu_needed field is True if the Versym contains indexes to 967682SAli.Bahrami@Sun.COM * Verneed records, as indicated by non-zero vna_other fields in the Verneed 977682SAli.Bahrami@Sun.COM * section. If gnu_full is True, then gnu_needed will always be true. 987682SAli.Bahrami@Sun.COM * However, gnu_needed can be true without gnu_full. This is the modified 997682SAli.Bahrami@Sun.COM * Solaris form. 1003875Sab196087 */ 1013875Sab196087 typedef struct { 1023875Sab196087 Cache *cache; /* Pointer to cache entry for VERSYM */ 1033875Sab196087 Versym *data; /* Pointer to versym array */ 1047682SAli.Bahrami@Sun.COM int gnu_full; /* True if object uses GNU versioning rules */ 1057682SAli.Bahrami@Sun.COM int gnu_needed; /* True if object uses VERSYM indexes for */ 1067682SAli.Bahrami@Sun.COM /* VERNEED (subset of gnu_full) */ 1074716Sab196087 int max_verndx; /* largest versym index value */ 1083875Sab196087 } VERSYM_STATE; 1093875Sab196087 1103875Sab196087 /* 1113875Sab196087 * SYMTBL_STATE is used to maintain information about a single symbol 1123875Sab196087 * table section, for use by the routines that display symbol information. 1133875Sab196087 */ 1143875Sab196087 typedef struct { 1153875Sab196087 const char *file; /* Name of file */ 1163875Sab196087 Ehdr *ehdr; /* ELF header for file */ 1173875Sab196087 Cache *cache; /* Cache of all section headers */ 1183875Sab196087 Word shnum; /* # of sections in cache */ 1193875Sab196087 Cache *seccache; /* Cache of symbol table section hdr */ 1203875Sab196087 Word secndx; /* Index of symbol table section hdr */ 1213875Sab196087 const char *secname; /* Name of section */ 1223875Sab196087 uint_t flags; /* Command line option flags */ 1233875Sab196087 struct { /* Extended section index data */ 1243875Sab196087 int checked; /* TRUE if already checked for shxndx */ 1253875Sab196087 Word *data; /* NULL, or extended section index */ 1263875Sab196087 /* used for symbol table entries */ 1273875Sab196087 uint_t n; /* # items in shxndx.data */ 1283875Sab196087 } shxndx; 1293875Sab196087 VERSYM_STATE *versym; /* NULL, or associated VERSYM section */ 1303875Sab196087 Sym *sym; /* Array of symbols */ 1313875Sab196087 Word symn; /* # of symbols */ 1323875Sab196087 } SYMTBL_STATE; 1333875Sab196087 1343875Sab196087 1353875Sab196087 1360Sstevel@tonic-gate /* 1370Sstevel@tonic-gate * Focal point for verifying symbol names. 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate static const char * 1401618Srie string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name) 1410Sstevel@tonic-gate { 1424063Sab196087 /* 1434063Sab196087 * If an error in this routine is due to a property of the string 1444063Sab196087 * section, as opposed to a bad offset into the section (a property of 1454063Sab196087 * the referencing section), then we will detect the same error on 1464063Sab196087 * every call involving those sections. We use these static variables 1474063Sab196087 * to retain the information needed to only issue each such error once. 1484063Sab196087 */ 1494063Sab196087 static Cache *last_refsec; /* Last referencing section seen */ 1504063Sab196087 static int strsec_err; /* True if error issued */ 1514063Sab196087 1523492Sab196087 const char *strs; 1533492Sab196087 Word strn; 1540Sstevel@tonic-gate 1553466Srie if (strsec->c_data == NULL) 1563466Srie return (NULL); 1573466Srie 1583492Sab196087 strs = (char *)strsec->c_data->d_buf; 1593492Sab196087 strn = strsec->c_data->d_size; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1624063Sab196087 * We only print a diagnostic regarding a bad string table once per 1634063Sab196087 * input section being processed. If the refsec has changed, reset 1644063Sab196087 * our retained error state. 1650Sstevel@tonic-gate */ 1664063Sab196087 if (last_refsec != refsec) { 1674063Sab196087 last_refsec = refsec; 1684063Sab196087 strsec_err = 0; 1694063Sab196087 } 1704063Sab196087 1714063Sab196087 /* Verify that strsec really is a string table */ 1724063Sab196087 if (strsec->c_shdr->sh_type != SHT_STRTAB) { 1734063Sab196087 if (!strsec_err) { 1744063Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOTSTRTAB), 1754063Sab196087 file, strsec->c_ndx, refsec->c_ndx); 1764063Sab196087 strsec_err = 1; 1774063Sab196087 } 1784063Sab196087 return (MSG_INTL(MSG_STR_UNKNOWN)); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * Is the string table offset within range of the available strings? 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate if (name >= strn) { 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * Do we have a empty string table? 1870Sstevel@tonic-gate */ 1880Sstevel@tonic-gate if (strs == 0) { 1894063Sab196087 if (!strsec_err) { 1900Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1910Sstevel@tonic-gate file, strsec->c_name); 1924063Sab196087 strsec_err = 1; 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate } else { 1950Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF), 1961618Srie file, refsec->c_name, EC_WORD(ndx), strsec->c_name, 1971618Srie EC_WORD(name), EC_WORD(strn - 1)); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* 2010Sstevel@tonic-gate * Return the empty string so that the calling function can 2020Sstevel@tonic-gate * continue it's output diagnostics. 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate return (MSG_INTL(MSG_STR_UNKNOWN)); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate return (strs + name); 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* 2101618Srie * Relocations can reference section symbols and standard symbols. If the 2111618Srie * former, establish the section name. 2121618Srie */ 2131618Srie static const char * 2141618Srie relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum, 2157463SRod.Evans@Sun.COM Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file) 2161618Srie { 2177463SRod.Evans@Sun.COM Sym *sym; 2187463SRod.Evans@Sun.COM const char *name; 2191618Srie 2201618Srie if (symndx >= symnum) { 2211618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX), 2221618Srie file, EC_WORD(symndx), EC_WORD(relndx)); 2231618Srie return (MSG_INTL(MSG_STR_UNKNOWN)); 2241618Srie } 2251618Srie 2261618Srie sym = (Sym *)(syms + symndx); 2277463SRod.Evans@Sun.COM name = string(csec, symndx, strsec, file, sym->st_name); 2281618Srie 2291618Srie /* 2301618Srie * If the symbol represents a section offset construct an appropriate 2317463SRod.Evans@Sun.COM * string. Note, although section symbol table entries typically have 2327463SRod.Evans@Sun.COM * a NULL name pointer, entries do exist that point into the string 2337463SRod.Evans@Sun.COM * table to their own NULL strings. 2341618Srie */ 2357463SRod.Evans@Sun.COM if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) && 2367463SRod.Evans@Sun.COM ((sym->st_name == 0) || (*name == '\0'))) { 2377463SRod.Evans@Sun.COM (void) snprintf(secstr, secsz, MSG_INTL(MSG_STR_SECTION), 2387463SRod.Evans@Sun.COM cache[sym->st_shndx].c_name); 2391618Srie return ((const char *)secstr); 2401618Srie } 2411618Srie 2427463SRod.Evans@Sun.COM return (name); 2431618Srie } 2441618Srie 2451618Srie /* 2461618Srie * Focal point for establishing a string table section. Data such as the 2471618Srie * dynamic information simply points to a string table. Data such as 2481618Srie * relocations, reference a symbol table, which in turn is associated with a 2491618Srie * string table. 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate static int 2521618Srie stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file, 2531618Srie Word *symnum, Cache **symsec, Cache **strsec) 2541618Srie { 2551618Srie Shdr *shdr = cache[ndx].c_shdr; 2561618Srie 2571618Srie if (symtab) { 2581618Srie /* 2591618Srie * Validate the symbol table section. 2601618Srie */ 2611618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2621618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2631618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 2641618Srie return (0); 2651618Srie } 2663466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2673466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2683466Srie file, cache[ndx].c_name); 2693466Srie return (0); 2703466Srie } 2711618Srie 2721618Srie /* 2731618Srie * Obtain, and verify the symbol table data. 2741618Srie */ 2753466Srie if ((cache[ndx].c_data == NULL) || 2763466Srie (cache[ndx].c_data->d_buf == NULL)) { 2771618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2781618Srie file, cache[ndx].c_name); 2791618Srie return (0); 2801618Srie } 2811618Srie 2821618Srie /* 2831618Srie * Establish the string table index. 2841618Srie */ 2851618Srie ndx = shdr->sh_link; 2861618Srie shdr = cache[ndx].c_shdr; 2871618Srie 2881618Srie /* 2891618Srie * Return symbol table information. 2901618Srie */ 2911618Srie if (symnum) 2921618Srie *symnum = (shdr->sh_size / shdr->sh_entsize); 2931618Srie if (symsec) 2941618Srie *symsec = &cache[ndx]; 2951618Srie } 2961618Srie 2971618Srie /* 2981618Srie * Validate the associated string table section. 2991618Srie */ 3001618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3011618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3021618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 3031618Srie return (0); 3041618Srie } 3051618Srie 3061618Srie if (strsec) 3071618Srie *strsec = &cache[shdr->sh_link]; 3081618Srie 3091618Srie return (1); 3101618Srie } 3111618Srie 3121618Srie /* 3131618Srie * Lookup a symbol and set Sym accordingly. 3141618Srie */ 3151618Srie static int 3161618Srie symlookup(const char *name, Cache *cache, Word shnum, Sym **sym, 3170Sstevel@tonic-gate Cache *symtab, const char *file) 3180Sstevel@tonic-gate { 3191618Srie Shdr *shdr; 3201618Srie Word symn, cnt; 3211618Srie Sym *syms; 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (symtab == 0) 3240Sstevel@tonic-gate return (0); 3250Sstevel@tonic-gate 3261618Srie shdr = symtab->c_shdr; 3271618Srie 3280Sstevel@tonic-gate /* 3290Sstevel@tonic-gate * Determine the symbol data and number. 3300Sstevel@tonic-gate */ 3310Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 3320Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 3330Sstevel@tonic-gate file, symtab->c_name); 3340Sstevel@tonic-gate return (0); 3350Sstevel@tonic-gate } 3363466Srie if (symtab->c_data == NULL) 3373466Srie return (0); 3383466Srie 3390Sstevel@tonic-gate /* LINTED */ 3401618Srie symn = (Word)(shdr->sh_size / shdr->sh_entsize); 3411618Srie syms = (Sym *)symtab->c_data->d_buf; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * Get the associated string table section. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3470Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3481618Srie file, symtab->c_name, EC_WORD(shdr->sh_link)); 3490Sstevel@tonic-gate return (0); 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * Loop through the symbol table to find a match. 3540Sstevel@tonic-gate */ 3551618Srie for (cnt = 0; cnt < symn; syms++, cnt++) { 3561618Srie const char *symname; 3570Sstevel@tonic-gate 3581618Srie symname = string(symtab, cnt, &cache[shdr->sh_link], file, 3591618Srie syms->st_name); 3600Sstevel@tonic-gate 3611618Srie if (symname && (strcmp(name, symname) == 0)) { 3621618Srie *sym = syms; 3630Sstevel@tonic-gate return (1); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate return (0); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * Print section headers. 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate static void 3734168Sab196087 sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr) 3740Sstevel@tonic-gate { 3751618Srie size_t seccnt; 3760Sstevel@tonic-gate 3771618Srie for (seccnt = 1; seccnt < shnum; seccnt++) { 3781618Srie Cache *_cache = &cache[seccnt]; 3791618Srie Shdr *shdr = _cache->c_shdr; 3801618Srie const char *secname = _cache->c_name; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * Although numerous section header entries can be zero, it's 3843862Srie * usually a sign of trouble if the type is zero. 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate if (shdr->sh_type == 0) { 3870Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE), 3881618Srie file, secname, EC_WORD(shdr->sh_type)); 3890Sstevel@tonic-gate } 3903862Srie 3915411Sab196087 if (!match(MATCH_F_ALL, secname, seccnt, shdr->sh_type)) 3923862Srie continue; 3930Sstevel@tonic-gate 3941324Srie /* 3951324Srie * Identify any sections that are suspicious. A .got section 3961324Srie * shouldn't exist in a relocatable object. 3971324Srie */ 3981324Srie if (ehdr->e_type == ET_REL) { 3991618Srie if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT), 4001324Srie MSG_ELF_GOT_SIZE) == 0) { 4011324Srie (void) fprintf(stderr, 4021618Srie MSG_INTL(MSG_GOT_UNEXPECTED), file, 4031618Srie secname); 4041324Srie } 4051324Srie } 4061324Srie 4071618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 4081618Srie dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname); 4091618Srie Elf_shdr(0, ehdr->e_machine, shdr); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate 4131618Srie /* 4141618Srie * A couple of instances of unwind data are printed as tables of 8 data items 4151618Srie * expressed as 0x?? integers. 4161618Srie */ 4171618Srie #define UNWINDTBLSZ 10 + (8 * 5) + 1 4181618Srie 4191618Srie static void 4201618Srie unwindtbl(uint64_t *ndx, uint_t len, uchar_t *data, uint64_t doff, 4211618Srie const char *msg, const char *pre, size_t plen) 4221618Srie { 4231618Srie char buffer[UNWINDTBLSZ]; 4241618Srie uint_t boff = plen, cnt = 0; 4251618Srie 4261618Srie dbg_print(0, msg); 4271618Srie (void) strncpy(buffer, pre, UNWINDTBLSZ); 4281618Srie 4291618Srie while (*ndx < (len + 4)) { 4301618Srie if (cnt == 8) { 4311618Srie dbg_print(0, buffer); 4321618Srie boff = plen; 4331618Srie cnt = 0; 4341618Srie } 4351618Srie (void) snprintf(&buffer[boff], UNWINDTBLSZ - boff, 4361618Srie MSG_ORIG(MSG_UNW_TBLENTRY), data[doff + (*ndx)++]); 4371618Srie boff += 5; 4381618Srie cnt++; 4391618Srie } 4401618Srie if (cnt) 4411618Srie dbg_print(0, buffer); 4421618Srie } 4431618Srie 4441618Srie /* 4451618Srie * Obtain a specified Phdr entry. 4461618Srie */ 4471618Srie static Phdr * 4481618Srie getphdr(Word phnum, Word type, const char *file, Elf *elf) 4491618Srie { 4501618Srie Word cnt; 4511618Srie Phdr *phdr; 4521618Srie 4531618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 4541618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 4551618Srie return (0); 4561618Srie } 4571618Srie 4581618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 4591618Srie if (phdr->p_type == type) 4601618Srie return (phdr); 4611618Srie } 4621618Srie return (0); 4631618Srie } 4641618Srie 4650Sstevel@tonic-gate static void 4664168Sab196087 unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, 4674168Sab196087 Elf *elf) 4680Sstevel@tonic-gate { 4694734Sab196087 Conv_dwarf_ehe_buf_t dwarf_ehe_buf; 4701618Srie Word cnt; 4711618Srie Phdr *uphdr = 0; 4721618Srie 4730Sstevel@tonic-gate /* 4741618Srie * For the moment - UNWIND is only relevant for a AMD64 object. 4750Sstevel@tonic-gate */ 4760Sstevel@tonic-gate if (ehdr->e_machine != EM_AMD64) 4771618Srie return; 4780Sstevel@tonic-gate 4791618Srie if (phnum) 4801618Srie uphdr = getphdr(phnum, PT_SUNW_UNWIND, file, elf); 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 4831618Srie Cache *_cache = &cache[cnt]; 4841618Srie Shdr *shdr = _cache->c_shdr; 4851618Srie uchar_t *data; 4860Sstevel@tonic-gate size_t datasize; 4871618Srie uint64_t off, ndx, frame_ptr, fde_cnt, tabndx; 4881618Srie uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /* 4911618Srie * AMD64 - this is a strmcp() just to find the gcc produced 4921618Srie * sections. Soon gcc should be setting the section type - and 4931618Srie * we'll not need this strcmp(). 4940Sstevel@tonic-gate */ 4950Sstevel@tonic-gate if ((shdr->sh_type != SHT_AMD64_UNWIND) && 4960Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 4970Sstevel@tonic-gate MSG_SCN_FRM_SIZE) != 0) && 4980Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4990Sstevel@tonic-gate MSG_SCN_FRMHDR_SIZE) != 0)) 5000Sstevel@tonic-gate continue; 5014168Sab196087 5025411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 5030Sstevel@tonic-gate continue; 5040Sstevel@tonic-gate 5053466Srie if (_cache->c_data == NULL) 5063466Srie continue; 5073466Srie 5081618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 5091618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 5100Sstevel@tonic-gate 5111618Srie data = (uchar_t *)(_cache->c_data->d_buf); 5120Sstevel@tonic-gate datasize = _cache->c_data->d_size; 5130Sstevel@tonic-gate off = 0; 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate /* 5160Sstevel@tonic-gate * Is this a .eh_frame_hdr 5170Sstevel@tonic-gate */ 5181618Srie if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || 5190Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 5201618Srie MSG_SCN_FRMHDR_SIZE) == 0)) { 5211618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR)); 5221618Srie ndx = 0; 5230Sstevel@tonic-gate 5241618Srie vers = data[ndx++]; 5251618Srie frame_ptr_enc = data[ndx++]; 5261618Srie fde_cnt_enc = data[ndx++]; 5271618Srie table_enc = data[ndx++]; 5280Sstevel@tonic-gate 5291618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); 5300Sstevel@tonic-gate 5311618Srie frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, 5321618Srie ehdr->e_ident, shdr->sh_addr + ndx); 5330Sstevel@tonic-gate 5341618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC), 5354734Sab196087 conv_dwarf_ehe(frame_ptr_enc, &dwarf_ehe_buf), 5364734Sab196087 EC_XWORD(frame_ptr)); 5371618Srie 5381618Srie fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, 5391618Srie ehdr->e_ident, shdr->sh_addr + ndx); 5400Sstevel@tonic-gate 5411618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), 5424734Sab196087 conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf), 5434734Sab196087 EC_XWORD(fde_cnt)); 5441618Srie dbg_print(0, MSG_ORIG(MSG_UNW_TABENC), 5454734Sab196087 conv_dwarf_ehe(table_enc, &dwarf_ehe_buf)); 5461618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1)); 5471618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2)); 5480Sstevel@tonic-gate 5491618Srie for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 5501618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), 5511618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5521618Srie table_enc, ehdr->e_ident, shdr->sh_addr)), 5531618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5541618Srie table_enc, ehdr->e_ident, shdr->sh_addr))); 5551618Srie } 5561618Srie continue; 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate /* 5600Sstevel@tonic-gate * Walk the Eh_frame's 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate while (off < datasize) { 5634433Sab196087 uint_t cieid, cielength, cieversion; 5644433Sab196087 uint_t cieretaddr; 5651618Srie int cieRflag, cieLflag, ciePflag, cieZflag; 5661618Srie uint_t cieaugndx, length, id; 5670Sstevel@tonic-gate uint64_t ciecalign, ciedalign; 5680Sstevel@tonic-gate char *cieaugstr; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate ndx = 0; 5710Sstevel@tonic-gate /* 5726388Srie * Extract length in lsb format. A zero length 5736388Srie * indicates that this CIE is a terminator and that 5746388Srie * processing for this unwind information should end. 5756388Srie * However, skip this entry and keep processing, just 5766388Srie * in case there is any other information remaining in 5776388Srie * this section. Note, ld(1) will terminate the 5786388Srie * processing of the .eh_frame contents for this file 5796388Srie * after a zero length CIE, thus any information that 5806388Srie * does follow is ignored by ld(1), and is therefore 5816388Srie * questionable. 5820Sstevel@tonic-gate */ 5836388Srie if ((length = LSB32EXTRACT(data + off + ndx)) == 0) { 5846388Srie dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM)); 5856388Srie off += 4; 5866388Srie continue; 5876388Srie } 5880Sstevel@tonic-gate ndx += 4; 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * extract CIE id in lsb format 5920Sstevel@tonic-gate */ 5930Sstevel@tonic-gate id = LSB32EXTRACT(data + off + ndx); 5940Sstevel@tonic-gate ndx += 4; 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* 5971618Srie * A CIE record has a id of '0', otherwise this is a 5981618Srie * FDE entry and the 'id' is the CIE pointer. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate if (id == 0) { 6010Sstevel@tonic-gate uint64_t persVal; 6021618Srie 6030Sstevel@tonic-gate cielength = length; 6040Sstevel@tonic-gate cieid = id; 6051618Srie cieLflag = ciePflag = cieRflag = cieZflag = 0; 6060Sstevel@tonic-gate 6071618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIE), 6081618Srie EC_XWORD(shdr->sh_addr + off)); 6091618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH), 6101618Srie cielength, cieid); 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate cieversion = data[off + ndx]; 6130Sstevel@tonic-gate ndx += 1; 6140Sstevel@tonic-gate cieaugstr = (char *)(&data[off + ndx]); 6150Sstevel@tonic-gate ndx += strlen(cieaugstr) + 1; 6161618Srie 6171618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS), 6181618Srie cieversion, cieaugstr); 6191618Srie 6200Sstevel@tonic-gate ciecalign = uleb_extract(&data[off], &ndx); 6210Sstevel@tonic-gate ciedalign = sleb_extract(&data[off], &ndx); 6220Sstevel@tonic-gate cieretaddr = data[off + ndx]; 6230Sstevel@tonic-gate ndx += 1; 6241618Srie 6251618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN), 6261618Srie EC_XWORD(ciecalign), EC_XWORD(ciedalign), 6271618Srie cieretaddr); 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate if (cieaugstr[0]) 6304433Sab196087 dbg_print(0, 6314433Sab196087 MSG_ORIG(MSG_UNW_CIEAXVAL)); 6321618Srie 6330Sstevel@tonic-gate for (cieaugndx = 0; cieaugstr[cieaugndx]; 6340Sstevel@tonic-gate cieaugndx++) { 6350Sstevel@tonic-gate uint_t val; 6361618Srie 6370Sstevel@tonic-gate switch (cieaugstr[cieaugndx]) { 6380Sstevel@tonic-gate case 'z': 6394433Sab196087 val = uleb_extract(&data[off], 6404433Sab196087 &ndx); 6414433Sab196087 dbg_print(0, 6424433Sab196087 MSG_ORIG(MSG_UNW_CIEAXSIZ), 6434433Sab196087 val); 6444433Sab196087 cieZflag = 1; 6454433Sab196087 break; 6460Sstevel@tonic-gate case 'P': 6474433Sab196087 ciePflag = data[off + ndx]; 6484433Sab196087 ndx += 1; 6494433Sab196087 6504433Sab196087 persVal = dwarf_ehe_extract( 6514433Sab196087 &data[off], &ndx, ciePflag, 6524433Sab196087 ehdr->e_ident, 6534433Sab196087 shdr->sh_addr + off + ndx); 6544433Sab196087 dbg_print(0, 6554433Sab196087 MSG_ORIG(MSG_UNW_CIEAXPERS), 6564433Sab196087 ciePflag, 6574734Sab196087 conv_dwarf_ehe(ciePflag, 6584734Sab196087 &dwarf_ehe_buf), 6594433Sab196087 EC_XWORD(persVal)); 6604433Sab196087 break; 6610Sstevel@tonic-gate case 'R': 6624433Sab196087 val = data[off + ndx]; 6634433Sab196087 ndx += 1; 6644433Sab196087 dbg_print(0, 6654433Sab196087 MSG_ORIG(MSG_UNW_CIEAXCENC), 6664734Sab196087 val, conv_dwarf_ehe(val, 6674734Sab196087 &dwarf_ehe_buf)); 6684433Sab196087 cieRflag = val; 6694433Sab196087 break; 6700Sstevel@tonic-gate case 'L': 6714433Sab196087 val = data[off + ndx]; 6724433Sab196087 ndx += 1; 6734433Sab196087 dbg_print(0, 6744433Sab196087 MSG_ORIG(MSG_UNW_CIEAXLSDA), 6754734Sab196087 val, conv_dwarf_ehe(val, 6764734Sab196087 &dwarf_ehe_buf)); 6774433Sab196087 cieLflag = val; 6784433Sab196087 break; 6790Sstevel@tonic-gate default: 6804433Sab196087 dbg_print(0, 6814433Sab196087 MSG_ORIG(MSG_UNW_CIEAXUNEC), 6824433Sab196087 cieaugstr[cieaugndx]); 6834433Sab196087 break; 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate } 6861618Srie if ((cielength + 4) > ndx) 6871618Srie unwindtbl(&ndx, cielength, data, off, 6881618Srie MSG_ORIG(MSG_UNW_CIECFI), 6891618Srie MSG_ORIG(MSG_UNW_CIEPRE), 6901618Srie MSG_UNW_CIEPRE_SIZE); 6910Sstevel@tonic-gate off += cielength + 4; 6921618Srie 6930Sstevel@tonic-gate } else { 6940Sstevel@tonic-gate uint_t fdelength = length; 6950Sstevel@tonic-gate int fdecieptr = id; 6960Sstevel@tonic-gate uint64_t fdeinitloc, fdeaddrrange; 6970Sstevel@tonic-gate 6981618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDE), 6991618Srie EC_XWORD(shdr->sh_addr + off)); 7001618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH), 7010Sstevel@tonic-gate fdelength, fdecieptr); 7021618Srie 7030Sstevel@tonic-gate fdeinitloc = dwarf_ehe_extract(&data[off], 7040Sstevel@tonic-gate &ndx, cieRflag, ehdr->e_ident, 7050Sstevel@tonic-gate shdr->sh_addr + off + ndx); 7060Sstevel@tonic-gate fdeaddrrange = dwarf_ehe_extract(&data[off], 7070Sstevel@tonic-gate &ndx, (cieRflag & ~DW_EH_PE_pcrel), 7080Sstevel@tonic-gate ehdr->e_ident, 7090Sstevel@tonic-gate shdr->sh_addr + off + ndx); 7101618Srie 7111618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), 7121618Srie EC_XWORD(fdeinitloc), 7131618Srie EC_XWORD(fdeaddrrange)); 7141618Srie 7150Sstevel@tonic-gate if (cieaugstr[0]) 7161618Srie dbg_print(0, 7174433Sab196087 MSG_ORIG(MSG_UNW_FDEAXVAL)); 7180Sstevel@tonic-gate if (cieZflag) { 7190Sstevel@tonic-gate uint64_t val; 7200Sstevel@tonic-gate val = uleb_extract(&data[off], &ndx); 7211618Srie dbg_print(0, 7224433Sab196087 MSG_ORIG(MSG_UNW_FDEAXSIZE), 7231618Srie EC_XWORD(val)); 7240Sstevel@tonic-gate if (val & cieLflag) { 7254433Sab196087 fdeinitloc = dwarf_ehe_extract( 7264433Sab196087 &data[off], &ndx, cieLflag, 7274433Sab196087 ehdr->e_ident, 7284433Sab196087 shdr->sh_addr + off + ndx); 7294433Sab196087 dbg_print(0, 7304433Sab196087 MSG_ORIG(MSG_UNW_FDEAXLSDA), 7314433Sab196087 EC_XWORD(val)); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate } 7341618Srie if ((fdelength + 4) > ndx) 7351618Srie unwindtbl(&ndx, fdelength, data, off, 7361618Srie MSG_ORIG(MSG_UNW_FDECFI), 7371618Srie MSG_ORIG(MSG_UNW_FDEPRE), 7381618Srie MSG_UNW_FDEPRE_SIZE); 7390Sstevel@tonic-gate off += fdelength + 4; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate /* 7460Sstevel@tonic-gate * Print the hardware/software capabilities. For executables and shared objects 7470Sstevel@tonic-gate * this should be accompanied with a program header. 7480Sstevel@tonic-gate */ 7490Sstevel@tonic-gate static void 7501618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, 7511618Srie Elf *elf) 7520Sstevel@tonic-gate { 7531618Srie Word cnt; 7547833SRod.Evans@Sun.COM Shdr *cshdr = NULL; 7553466Srie Cache *ccache; 7561618Srie Off cphdr_off = 0; 7571618Srie Xword cphdr_sz; 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate /* 7600Sstevel@tonic-gate * Determine if a hardware/software capabilities header exists. 7610Sstevel@tonic-gate */ 7621618Srie if (phnum) { 7631618Srie Phdr *phdr; 7640Sstevel@tonic-gate 7651618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 7660Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 7670Sstevel@tonic-gate return; 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate 7701618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 7711618Srie if (phdr->p_type == PT_SUNWCAP) { 7721618Srie cphdr_off = phdr->p_offset; 7731618Srie cphdr_sz = phdr->p_filesz; 7741618Srie break; 7751618Srie } 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate /* 7800Sstevel@tonic-gate * Determine if a hardware/software capabilities section exists. 7810Sstevel@tonic-gate */ 7820Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 7831618Srie Cache *_cache = &cache[cnt]; 7841618Srie Shdr *shdr = _cache->c_shdr; 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_cap) 7870Sstevel@tonic-gate continue; 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 7900Sstevel@tonic-gate (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 7910Sstevel@tonic-gate continue; 7920Sstevel@tonic-gate 7933466Srie if (_cache->c_data == NULL) 7943466Srie continue; 7953466Srie 7960Sstevel@tonic-gate ccache = _cache; 7970Sstevel@tonic-gate cshdr = shdr; 7980Sstevel@tonic-gate break; 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate 8017833SRod.Evans@Sun.COM if ((cshdr == NULL) && (cphdr_off == 0)) 8020Sstevel@tonic-gate return; 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate /* 8050Sstevel@tonic-gate * Print the hardware/software capabilities section. 8060Sstevel@tonic-gate */ 8070Sstevel@tonic-gate if (cshdr) { 8081618Srie Word ndx, capn; 8093492Sab196087 Cap *cap = (Cap *)ccache->c_data->d_buf; 8100Sstevel@tonic-gate 8114665Sab196087 if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) { 8124665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8134665Sab196087 file, ccache->c_name); 8144665Sab196087 return; 8154665Sab196087 } 8164665Sab196087 8171618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8181618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 8190Sstevel@tonic-gate 8201618Srie Elf_cap_title(0); 8211618Srie 8221618Srie capn = (Word)(cshdr->sh_size / cshdr->sh_entsize); 8230Sstevel@tonic-gate 8241618Srie for (ndx = 0; ndx < capn; cap++, ndx++) { 8257833SRod.Evans@Sun.COM if (cap->c_tag == CA_SUNW_NULL) 8267833SRod.Evans@Sun.COM continue; 8277833SRod.Evans@Sun.COM 8287833SRod.Evans@Sun.COM Elf_cap_entry(0, cap, ndx, ehdr->e_machine); 8297833SRod.Evans@Sun.COM 8307833SRod.Evans@Sun.COM /* 8317833SRod.Evans@Sun.COM * An SF1_SUNW_ADDR32 software capability in a 32-bit 8327833SRod.Evans@Sun.COM * object is suspicious as it has no effect. 8337833SRod.Evans@Sun.COM */ 8347833SRod.Evans@Sun.COM if ((cap->c_tag == CA_SUNW_SF_1) && 8357833SRod.Evans@Sun.COM (ehdr->e_ident[EI_CLASS] == ELFCLASS32) && 8367833SRod.Evans@Sun.COM (cap->c_un.c_val & SF1_SUNW_ADDR32)) { 8377833SRod.Evans@Sun.COM (void) fprintf(stderr, 8387833SRod.Evans@Sun.COM MSG_INTL(MSG_WARN_INADDR32SF1), 8397833SRod.Evans@Sun.COM file, ccache->c_name); 8407833SRod.Evans@Sun.COM } 8410Sstevel@tonic-gate } 8420Sstevel@tonic-gate } else 8430Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate /* 8460Sstevel@tonic-gate * If this object is an executable or shared object, then the 8470Sstevel@tonic-gate * hardware/software capabilities section should have an accompanying 8480Sstevel@tonic-gate * program header. 8490Sstevel@tonic-gate */ 8500Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 8510Sstevel@tonic-gate if (cphdr_off == 0) 8520Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 8530Sstevel@tonic-gate file, ccache->c_name); 8540Sstevel@tonic-gate else if ((cphdr_off != cshdr->sh_offset) || 8550Sstevel@tonic-gate (cphdr_sz != cshdr->sh_size)) 8560Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 8570Sstevel@tonic-gate file, ccache->c_name); 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate } 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate /* 8620Sstevel@tonic-gate * Print the interpretor. 8630Sstevel@tonic-gate */ 8640Sstevel@tonic-gate static void 8651618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) 8660Sstevel@tonic-gate { 8671618Srie Word cnt; 8681618Srie Shdr *ishdr = 0; 8691618Srie Cache *icache; 8701618Srie Off iphdr_off = 0; 8711618Srie Xword iphdr_fsz; 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate /* 8740Sstevel@tonic-gate * Determine if an interp header exists. 8750Sstevel@tonic-gate */ 8761618Srie if (phnum) { 8771618Srie Phdr *phdr; 8780Sstevel@tonic-gate 8791618Srie if ((phdr = getphdr(phnum, PT_INTERP, file, elf)) != 0) { 8801618Srie iphdr_off = phdr->p_offset; 8811618Srie iphdr_fsz = phdr->p_filesz; 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate if (iphdr_off == 0) 8860Sstevel@tonic-gate return; 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate /* 8890Sstevel@tonic-gate * Determine if an interp section exists. 8900Sstevel@tonic-gate */ 8910Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8921618Srie Cache *_cache = &cache[cnt]; 8931618Srie Shdr *shdr = _cache->c_shdr; 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate /* 8960Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP 8970Sstevel@tonic-gate * string. The target section can't be in a NOBITS section. 8980Sstevel@tonic-gate */ 8990Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) || 9000Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) || 9011618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size)) 9020Sstevel@tonic-gate continue; 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate icache = _cache; 9050Sstevel@tonic-gate ishdr = shdr; 9060Sstevel@tonic-gate break; 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate /* 9100Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the 9110Sstevel@tonic-gate * program header, as this is the offset used by the kernel. 9120Sstevel@tonic-gate */ 9133466Srie if (ishdr && icache->c_data) { 9141618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 9151618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 9161618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), 9170Sstevel@tonic-gate (char *)icache->c_data->d_buf + 9180Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset)); 9190Sstevel@tonic-gate } else 9200Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate /* 9230Sstevel@tonic-gate * If there are any inconsistences between the program header and 9240Sstevel@tonic-gate * section information, flag them. 9250Sstevel@tonic-gate */ 9260Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) || 9271618Srie (iphdr_fsz != ishdr->sh_size))) { 9280Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 9290Sstevel@tonic-gate icache->c_name); 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate } 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate /* 9340Sstevel@tonic-gate * Print the syminfo section. 9350Sstevel@tonic-gate */ 9360Sstevel@tonic-gate static void 9371618Srie syminfo(Cache *cache, Word shnum, const char *file) 9380Sstevel@tonic-gate { 9391618Srie Shdr *infoshdr; 9401618Srie Syminfo *info; 9411618Srie Sym *syms; 9421618Srie Dyn *dyns; 9431618Srie Word infonum, cnt, ndx, symnum; 9441618Srie Cache *infocache = 0, *symsec, *strsec; 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 9471618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { 9481618Srie infocache = &cache[cnt]; 9490Sstevel@tonic-gate break; 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate } 9521618Srie if (infocache == 0) 9530Sstevel@tonic-gate return; 9540Sstevel@tonic-gate 9551618Srie infoshdr = infocache->c_shdr; 9561618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) { 9570Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 9581618Srie file, infocache->c_name); 9590Sstevel@tonic-gate return; 9600Sstevel@tonic-gate } 9613466Srie if (infocache->c_data == NULL) 9623466Srie return; 9633466Srie 9641618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize); 9651618Srie info = (Syminfo *)infocache->c_data->d_buf; 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate /* 9680Sstevel@tonic-gate * Get the data buffer of the associated dynamic section. 9690Sstevel@tonic-gate */ 9701618Srie if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) { 9710Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 9721618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info)); 9730Sstevel@tonic-gate return; 9740Sstevel@tonic-gate } 9753466Srie if (cache[infoshdr->sh_info].c_data == NULL) 9763466Srie return; 9773466Srie 9781618Srie dyns = cache[infoshdr->sh_info].c_data->d_buf; 9791618Srie if (dyns == 0) { 9800Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 9811618Srie file, cache[infoshdr->sh_info].c_name); 9820Sstevel@tonic-gate return; 9830Sstevel@tonic-gate } 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate /* 9861618Srie * Get the data buffer for the associated symbol table and string table. 9870Sstevel@tonic-gate */ 9881618Srie if (stringtbl(cache, 1, cnt, shnum, file, 9891618Srie &symnum, &symsec, &strsec) == 0) 9900Sstevel@tonic-gate return; 9910Sstevel@tonic-gate 9921618Srie syms = symsec->c_data->d_buf; 9930Sstevel@tonic-gate 9941618Srie /* 9951618Srie * Loop through the syminfo entries. 9961618Srie */ 9971618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 9981618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name); 9991618Srie Elf_syminfo_title(0); 10000Sstevel@tonic-gate 10011618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) { 10021618Srie Sym *sym; 10031618Srie const char *needed = 0, *name; 10041618Srie 10051618Srie if ((info->si_flags == 0) && (info->si_boundto == 0)) 10060Sstevel@tonic-gate continue; 10070Sstevel@tonic-gate 10081618Srie sym = &syms[ndx]; 10091618Srie name = string(infocache, ndx, strsec, file, sym->st_name); 10100Sstevel@tonic-gate 10111618Srie if (info->si_boundto < SYMINFO_BT_LOWRESERVE) { 10121618Srie Dyn *dyn = &dyns[info->si_boundto]; 10131618Srie 10141618Srie needed = string(infocache, info->si_boundto, 10151618Srie strsec, file, dyn->d_un.d_val); 10160Sstevel@tonic-gate } 10171618Srie Elf_syminfo_entry(0, ndx, info, name, needed); 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate } 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate /* 10220Sstevel@tonic-gate * Print version definition section entries. 10230Sstevel@tonic-gate */ 10240Sstevel@tonic-gate static void 10254716Sab196087 version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache, 10260Sstevel@tonic-gate const char *file) 10270Sstevel@tonic-gate { 10281618Srie Word cnt; 10291618Srie char index[MAXNDXSIZE]; 10300Sstevel@tonic-gate 10311618Srie Elf_ver_def_title(0); 10320Sstevel@tonic-gate 10334716Sab196087 for (cnt = 1; cnt <= vdf_num; cnt++, 10341618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 10357682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 10367682SAli.Bahrami@Sun.COM const char *name, *dep; 10377682SAli.Bahrami@Sun.COM Half vcnt = vdf->vd_cnt - 1; 10387682SAli.Bahrami@Sun.COM Half ndx = vdf->vd_ndx; 10397682SAli.Bahrami@Sun.COM Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate /* 10420Sstevel@tonic-gate * Obtain the name and first dependency (if any). 10430Sstevel@tonic-gate */ 10440Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name); 10451618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 10460Sstevel@tonic-gate if (vcnt) 10470Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name); 10480Sstevel@tonic-gate else 10490Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 10520Sstevel@tonic-gate EC_XWORD(ndx)); 10531618Srie Elf_ver_line_1(0, index, name, dep, 10547682SAli.Bahrami@Sun.COM conv_ver_flags(vdf->vd_flags, 0, &ver_flags_buf)); 10550Sstevel@tonic-gate 10560Sstevel@tonic-gate /* 10570Sstevel@tonic-gate * Print any additional dependencies. 10580Sstevel@tonic-gate */ 10590Sstevel@tonic-gate if (vcnt) { 10601618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 10610Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 10621618Srie vdap = (Verdaux *)((uintptr_t)vdap + 10630Sstevel@tonic-gate vdap->vda_next)) { 10640Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 10650Sstevel@tonic-gate vdap->vda_name); 10661618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep); 10670Sstevel@tonic-gate } 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate } 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate /* 10734716Sab196087 * Print version needed section entries. 10744716Sab196087 * 10754716Sab196087 * entry: 10764716Sab196087 * vnd - Address of verneed data 10774716Sab196087 * vnd_num - # of Verneed entries 10784716Sab196087 * vcache - Cache of verneed section being processed 10794716Sab196087 * scache - Cache of associated string table section 10804716Sab196087 * file - Name of object being processed. 10814716Sab196087 * versym - Information about versym section 10824716Sab196087 * 10834716Sab196087 * exit: 10844716Sab196087 * The versions have been printed. If GNU style versioning 10854716Sab196087 * is in effect, versym->max_verndx has been updated to 10864716Sab196087 * contain the largest version index seen. 10877682SAli.Bahrami@Sun.COM * 10887682SAli.Bahrami@Sun.COM * note: 10897682SAli.Bahrami@Sun.COM * The versym section of an object that follows the original 10907682SAli.Bahrami@Sun.COM * Solaris versioning rules only contains indexes into the verdef 10917682SAli.Bahrami@Sun.COM * section. Symbols defined in other objects (UNDEF) are given 10927682SAli.Bahrami@Sun.COM * a version of 0, indicating that they are not defined by 10937682SAli.Bahrami@Sun.COM * this file, and the Verneed entries do not have associated version 10947682SAli.Bahrami@Sun.COM * indexes. For these reasons, we do not display a version index 10957682SAli.Bahrami@Sun.COM * for original-style Verneed sections. 10967682SAli.Bahrami@Sun.COM * 10977682SAli.Bahrami@Sun.COM * The GNU versioning extensions alter this: Symbols defined in other 10987682SAli.Bahrami@Sun.COM * objects receive a version index in the range above those defined 10997682SAli.Bahrami@Sun.COM * by the Verdef section, and the vna_other field of the Vernaux 11007682SAli.Bahrami@Sun.COM * structs inside the Verneed section contain the version index for 11017682SAli.Bahrami@Sun.COM * that item. We therefore display the index when showing the 11027682SAli.Bahrami@Sun.COM * contents of a GNU style Verneed section. You should not 11037682SAli.Bahrami@Sun.COM * necessarily expect these indexes to appear in sorted 11047682SAli.Bahrami@Sun.COM * order --- it seems that the GNU ld assigns the versions as 11057682SAli.Bahrami@Sun.COM * symbols are encountered during linking, and then the results 11067682SAli.Bahrami@Sun.COM * are assembled into the Verneed section afterwards. 11070Sstevel@tonic-gate */ 11080Sstevel@tonic-gate static void 11094716Sab196087 version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache, 11104716Sab196087 const char *file, VERSYM_STATE *versym) 11110Sstevel@tonic-gate { 11124716Sab196087 Word cnt; 11134716Sab196087 char index[MAXNDXSIZE]; 11144716Sab196087 const char *index_str; 11154716Sab196087 11167682SAli.Bahrami@Sun.COM Elf_ver_need_title(0, versym->gnu_needed); 11174716Sab196087 11184716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 11191618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 11207682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 11217682SAli.Bahrami@Sun.COM const char *name, *dep; 11227682SAli.Bahrami@Sun.COM Half vcnt = vnd->vn_cnt; 11234433Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 11240Sstevel@tonic-gate 11250Sstevel@tonic-gate /* 11260Sstevel@tonic-gate * Obtain the name of the needed file and the version name 11270Sstevel@tonic-gate * within it that we're dependent on. Note that the count 11280Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus 11290Sstevel@tonic-gate * entry. 11300Sstevel@tonic-gate */ 11310Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file); 11320Sstevel@tonic-gate if (vcnt) 11330Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name); 11340Sstevel@tonic-gate else 11350Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL); 11360Sstevel@tonic-gate 11377682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) { /* Traditional form */ 11387682SAli.Bahrami@Sun.COM index_str = MSG_ORIG(MSG_STR_EMPTY); 11397682SAli.Bahrami@Sun.COM } else { /* GNU form */ 11407682SAli.Bahrami@Sun.COM index_str = index; 11414716Sab196087 /* Format the version index value */ 11424716Sab196087 (void) snprintf(index, MAXNDXSIZE, 11434716Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(vnap->vna_other)); 11444716Sab196087 if (vnap->vna_other > versym->max_verndx) 11454716Sab196087 versym->max_verndx = vnap->vna_other; 11464716Sab196087 } 11474716Sab196087 Elf_ver_line_1(0, index_str, name, dep, 11487682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 0, &ver_flags_buf)); 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate /* 11510Sstevel@tonic-gate * Print any additional version dependencies. 11520Sstevel@tonic-gate */ 11530Sstevel@tonic-gate if (vcnt) { 11541618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 11550Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 11561618Srie vnap = (Vernaux *)((uintptr_t)vnap + 11570Sstevel@tonic-gate vnap->vna_next)) { 11580Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 11590Sstevel@tonic-gate vnap->vna_name); 11607682SAli.Bahrami@Sun.COM if (vnap->vna_other > 0) { 11614716Sab196087 /* Format the next index value */ 11624716Sab196087 (void) snprintf(index, MAXNDXSIZE, 11634716Sab196087 MSG_ORIG(MSG_FMT_INDEX), 11644716Sab196087 EC_XWORD(vnap->vna_other)); 11657682SAli.Bahrami@Sun.COM Elf_ver_line_1(0, index, 11664716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 11677682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 11687682SAli.Bahrami@Sun.COM 0, &ver_flags_buf)); 11694716Sab196087 if (vnap->vna_other > 11704716Sab196087 versym->max_verndx) 11714716Sab196087 versym->max_verndx = 11724716Sab196087 vnap->vna_other; 11734716Sab196087 } else { 11744716Sab196087 Elf_ver_line_3(0, 11754716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 11767682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 11777682SAli.Bahrami@Sun.COM 0, &ver_flags_buf)); 11784716Sab196087 } 11794716Sab196087 } 11804716Sab196087 } 11814716Sab196087 } 11824716Sab196087 } 11834716Sab196087 11844716Sab196087 /* 11857682SAli.Bahrami@Sun.COM * Examine the Verneed section for information related to GNU 11867682SAli.Bahrami@Sun.COM * style Versym indexing: 11877682SAli.Bahrami@Sun.COM * - A non-zero vna_other field indicates that Versym indexes can 11887682SAli.Bahrami@Sun.COM * reference Verneed records. 11897682SAli.Bahrami@Sun.COM * - If the object uses GNU style Versym indexing, the 11907682SAli.Bahrami@Sun.COM * maximum index value is needed to detect bad Versym entries. 11914716Sab196087 * 11924716Sab196087 * entry: 11934716Sab196087 * vnd - Address of verneed data 11944716Sab196087 * vnd_num - # of Verneed entries 11954716Sab196087 * versym - Information about versym section 11964716Sab196087 * 11974716Sab196087 * exit: 11987682SAli.Bahrami@Sun.COM * If a non-zero vna_other field is seen, versym->gnu_needed is set. 11997682SAli.Bahrami@Sun.COM * 12004716Sab196087 * versym->max_verndx has been updated to contain the largest 12014716Sab196087 * version index seen. 12024716Sab196087 */ 12034716Sab196087 static void 12047682SAli.Bahrami@Sun.COM update_gnu_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym) 12054716Sab196087 { 12064716Sab196087 Word cnt; 12074716Sab196087 12084716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 12094716Sab196087 vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 12104716Sab196087 Half vcnt = vnd->vn_cnt; 12114716Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 12124716Sab196087 12137682SAli.Bahrami@Sun.COM /* 12147682SAli.Bahrami@Sun.COM * A non-zero value of vna_other indicates that this 12157682SAli.Bahrami@Sun.COM * object references VERNEED items from the VERSYM 12167682SAli.Bahrami@Sun.COM * array. 12177682SAli.Bahrami@Sun.COM */ 12187682SAli.Bahrami@Sun.COM if (vnap->vna_other != 0) { 12197682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 12207682SAli.Bahrami@Sun.COM if (vnap->vna_other > versym->max_verndx) 12217682SAli.Bahrami@Sun.COM versym->max_verndx = vnap->vna_other; 12227682SAli.Bahrami@Sun.COM } 12234716Sab196087 12244716Sab196087 /* 12254716Sab196087 * Check any additional version dependencies. 12264716Sab196087 */ 12274716Sab196087 if (vcnt) { 12284716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 12294716Sab196087 for (vcnt--; vcnt; vcnt--, 12304716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + 12314716Sab196087 vnap->vna_next)) { 12327682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) 12337682SAli.Bahrami@Sun.COM continue; 12347682SAli.Bahrami@Sun.COM 12357682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 12364716Sab196087 if (vnap->vna_other > versym->max_verndx) 12374716Sab196087 versym->max_verndx = vnap->vna_other; 12380Sstevel@tonic-gate } 12390Sstevel@tonic-gate } 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate /* 12443875Sab196087 * Display version section information if the flags require it. 12453875Sab196087 * Return version information needed by other output. 12463875Sab196087 * 12473875Sab196087 * entry: 12483875Sab196087 * cache - Cache of all section headers 12493875Sab196087 * shnum - # of sections in cache 12503875Sab196087 * file - Name of file 12513875Sab196087 * flags - Command line option flags 12523875Sab196087 * versym - VERSYM_STATE block to be filled in. 12530Sstevel@tonic-gate */ 12543875Sab196087 static void 12553875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags, 12563875Sab196087 VERSYM_STATE *versym) 12570Sstevel@tonic-gate { 12580Sstevel@tonic-gate GElf_Word cnt; 12594716Sab196087 Cache *verdef_cache = NULL, *verneed_cache = NULL; 12604716Sab196087 12614716Sab196087 12624716Sab196087 /* Gather information about the version sections */ 12633875Sab196087 bzero(versym, sizeof (*versym)); 12644716Sab196087 versym->max_verndx = 1; 12650Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 12661618Srie Cache *_cache = &cache[cnt]; 12671618Srie Shdr *shdr = _cache->c_shdr; 12684716Sab196087 Dyn *dyn; 12694716Sab196087 ulong_t numdyn; 12704716Sab196087 12714716Sab196087 switch (shdr->sh_type) { 12724716Sab196087 case SHT_DYNAMIC: 12734716Sab196087 /* 12744716Sab196087 * The GNU ld puts a DT_VERSYM entry in the dynamic 12754716Sab196087 * section so that the runtime linker can use it to 12764716Sab196087 * implement their versioning rules. They allow multiple 12774716Sab196087 * incompatible functions with the same name to exist 12784716Sab196087 * in different versions. The Solaris ld does not 12794716Sab196087 * support this mechanism, and as such, does not 12804716Sab196087 * produce DT_VERSYM. We use this fact to determine 12814716Sab196087 * which ld produced this object, and how to interpret 12824716Sab196087 * the version values. 12834716Sab196087 */ 12844716Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0) || 12854716Sab196087 (_cache->c_data == NULL)) 12864716Sab196087 continue; 12874716Sab196087 numdyn = shdr->sh_size / shdr->sh_entsize; 12884716Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 12894716Sab196087 for (; numdyn-- > 0; dyn++) 12904716Sab196087 if (dyn->d_tag == DT_VERSYM) { 12917682SAli.Bahrami@Sun.COM versym->gnu_full = 12927682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 12934716Sab196087 break; 12944716Sab196087 } 12954716Sab196087 break; 12964716Sab196087 12974716Sab196087 case SHT_SUNW_versym: 12984716Sab196087 /* Record data address for later symbol processing */ 12994716Sab196087 if (_cache->c_data != NULL) { 13004716Sab196087 versym->cache = _cache; 13014716Sab196087 versym->data = _cache->c_data->d_buf; 13024716Sab196087 continue; 13034716Sab196087 } 13044716Sab196087 break; 13054716Sab196087 13064716Sab196087 case SHT_SUNW_verdef: 13074716Sab196087 case SHT_SUNW_verneed: 13084716Sab196087 /* 13094716Sab196087 * Ensure the data is non-NULL and the number 13104716Sab196087 * of items is non-zero. Otherwise, we don't 13114716Sab196087 * understand the section, and will not use it. 13124716Sab196087 */ 13134716Sab196087 if ((_cache->c_data == NULL) || 13144716Sab196087 (_cache->c_data->d_buf == NULL)) { 13154716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 13164716Sab196087 file, _cache->c_name); 13174716Sab196087 continue; 13184716Sab196087 } 13194716Sab196087 if (shdr->sh_info == 0) { 13204716Sab196087 (void) fprintf(stderr, 13214716Sab196087 MSG_INTL(MSG_ERR_BADSHINFO), 13224716Sab196087 file, _cache->c_name, 13234716Sab196087 EC_WORD(shdr->sh_info)); 13244716Sab196087 continue; 13254716Sab196087 } 13264716Sab196087 13274716Sab196087 /* Make sure the string table index is in range */ 13284716Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 13294716Sab196087 (void) fprintf(stderr, 13304716Sab196087 MSG_INTL(MSG_ERR_BADSHLINK), file, 13314716Sab196087 _cache->c_name, EC_WORD(shdr->sh_link)); 13324716Sab196087 continue; 13334716Sab196087 } 13344716Sab196087 13354716Sab196087 /* 13364716Sab196087 * The section is usable. Save the cache entry. 13374716Sab196087 */ 13384716Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) { 13394716Sab196087 verdef_cache = _cache; 13404716Sab196087 /* 13414716Sab196087 * Under Solaris rules, if there is a verdef 13424716Sab196087 * section, the max versym index is number 13434716Sab196087 * of version definitions it supplies. 13444716Sab196087 */ 13454716Sab196087 versym->max_verndx = shdr->sh_info; 13464716Sab196087 } else { 13474716Sab196087 verneed_cache = _cache; 13484716Sab196087 } 13494716Sab196087 break; 13504716Sab196087 } 13514716Sab196087 } 13524716Sab196087 13537682SAli.Bahrami@Sun.COM /* 13547682SAli.Bahrami@Sun.COM * If there is a Verneed section, examine it for information 13557682SAli.Bahrami@Sun.COM * related to GNU style versioning. 13567682SAli.Bahrami@Sun.COM */ 13577682SAli.Bahrami@Sun.COM if (verneed_cache != NULL) 13587682SAli.Bahrami@Sun.COM update_gnu_verndx((Verneed *)verneed_cache->c_data->d_buf, 13597682SAli.Bahrami@Sun.COM verneed_cache->c_shdr->sh_info, versym); 13604716Sab196087 13614716Sab196087 /* 13624716Sab196087 * Now that all the information is available, display the 13637682SAli.Bahrami@Sun.COM * Verdef and Verneed section contents, if requested. 13644716Sab196087 */ 13657682SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_VERSIONS) == 0) 13667682SAli.Bahrami@Sun.COM return; 13674716Sab196087 if (verdef_cache != NULL) { 13684716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 13694716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), 13704716Sab196087 verdef_cache->c_name); 13714716Sab196087 version_def((Verdef *)verdef_cache->c_data->d_buf, 13724716Sab196087 verdef_cache->c_shdr->sh_info, verdef_cache, 13734716Sab196087 &cache[verdef_cache->c_shdr->sh_link], file); 13744716Sab196087 } 13754716Sab196087 if (verneed_cache != NULL) { 13764716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 13774716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), 13784716Sab196087 verneed_cache->c_name); 13790Sstevel@tonic-gate /* 13804716Sab196087 * If GNU versioning applies to this object, version_need() 13814716Sab196087 * will update versym->max_verndx, and it is not 13827682SAli.Bahrami@Sun.COM * necessary to call update_gnu_verndx(). 13830Sstevel@tonic-gate */ 13844716Sab196087 version_need((Verneed *)verneed_cache->c_data->d_buf, 13854716Sab196087 verneed_cache->c_shdr->sh_info, verneed_cache, 13864716Sab196087 &cache[verneed_cache->c_shdr->sh_link], file, versym); 13870Sstevel@tonic-gate } 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate 13900Sstevel@tonic-gate /* 13913492Sab196087 * Initialize a symbol table state structure 13923492Sab196087 * 13933492Sab196087 * entry: 13943492Sab196087 * state - State structure to be initialized 13953492Sab196087 * cache - Cache of all section headers 13963492Sab196087 * shnum - # of sections in cache 13973492Sab196087 * secndx - Index of symbol table section 13983492Sab196087 * ehdr - ELF header for file 13993875Sab196087 * versym - Information about versym section 14003492Sab196087 * file - Name of file 14013492Sab196087 * flags - Command line option flags 14021618Srie */ 14031618Srie static int 14043492Sab196087 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx, 14053875Sab196087 Ehdr *ehdr, VERSYM_STATE *versym, const char *file, uint_t flags) 14063492Sab196087 { 14073492Sab196087 Shdr *shdr; 14083492Sab196087 14093492Sab196087 state->file = file; 14103492Sab196087 state->ehdr = ehdr; 14113492Sab196087 state->cache = cache; 14123492Sab196087 state->shnum = shnum; 14133492Sab196087 state->seccache = &cache[secndx]; 14143492Sab196087 state->secndx = secndx; 14153492Sab196087 state->secname = state->seccache->c_name; 14163492Sab196087 state->flags = flags; 14173492Sab196087 state->shxndx.checked = 0; 14183492Sab196087 state->shxndx.data = NULL; 14193492Sab196087 state->shxndx.n = 0; 14203492Sab196087 14213492Sab196087 shdr = state->seccache->c_shdr; 14223492Sab196087 14233492Sab196087 /* 14243492Sab196087 * Check the symbol data and per-item size. 14253492Sab196087 */ 14263492Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 14273492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 14283492Sab196087 file, state->secname); 14293492Sab196087 return (0); 14303492Sab196087 } 14313492Sab196087 if (state->seccache->c_data == NULL) 14323492Sab196087 return (0); 14333492Sab196087 14343492Sab196087 /* LINTED */ 14353492Sab196087 state->symn = (Word)(shdr->sh_size / shdr->sh_entsize); 14363492Sab196087 state->sym = (Sym *)state->seccache->c_data->d_buf; 14373492Sab196087 14383492Sab196087 /* 14393492Sab196087 * Check associated string table section. 14403492Sab196087 */ 14413492Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 14423492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 14433492Sab196087 file, state->secname, EC_WORD(shdr->sh_link)); 14443492Sab196087 return (0); 14453492Sab196087 } 14463492Sab196087 14473492Sab196087 /* 14483492Sab196087 * Determine if there is a associated Versym section 14493492Sab196087 * with this Symbol Table. 14503492Sab196087 */ 14513875Sab196087 if (versym->cache && 14523875Sab196087 (versym->cache->c_shdr->sh_link == state->secndx)) 14533875Sab196087 state->versym = versym; 14543492Sab196087 else 14553492Sab196087 state->versym = NULL; 14563492Sab196087 14573492Sab196087 14583492Sab196087 return (1); 14593492Sab196087 } 14603492Sab196087 14613492Sab196087 /* 14623492Sab196087 * Determine the extended section index used for symbol tables entries. 14633492Sab196087 */ 14643492Sab196087 static void 14657463SRod.Evans@Sun.COM symbols_getxindex(SYMTBL_STATE *state) 14661618Srie { 14671618Srie uint_t symn; 14681618Srie Word symcnt; 14691618Srie 14703492Sab196087 state->shxndx.checked = 1; /* Note that we've been called */ 14713492Sab196087 for (symcnt = 1; symcnt < state->shnum; symcnt++) { 14723492Sab196087 Cache *_cache = &state->cache[symcnt]; 14731618Srie Shdr *shdr = _cache->c_shdr; 14741618Srie 14751618Srie if ((shdr->sh_type != SHT_SYMTAB_SHNDX) || 14763492Sab196087 (shdr->sh_link != state->secndx)) 14771618Srie continue; 14781618Srie 14791618Srie if ((shdr->sh_entsize) && 14801618Srie /* LINTED */ 14811618Srie ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0)) 14821618Srie continue; 14831618Srie 14843466Srie if (_cache->c_data == NULL) 14853466Srie continue; 14863466Srie 14873492Sab196087 state->shxndx.data = _cache->c_data->d_buf; 14883492Sab196087 state->shxndx.n = symn; 14893492Sab196087 return; 14901618Srie } 14911618Srie } 14921618Srie 14931618Srie /* 14943492Sab196087 * Produce a line of output for the given symbol 14953492Sab196087 * 14963492Sab196087 * entry: 14973875Sab196087 * state - Symbol table state 14983492Sab196087 * symndx - Index of symbol within the table 14994832Srie * info - Value of st_info (indicates local/global range) 15003492Sab196087 * symndx_disp - Index to display. This may not be the same 15013492Sab196087 * as symndx if the display is relative to the logical 15023492Sab196087 * combination of the SUNW_ldynsym/dynsym tables. 15033492Sab196087 * sym - Symbol to display 15040Sstevel@tonic-gate */ 15053492Sab196087 static void 15064832Srie output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx, 15074832Srie Sym *sym) 15080Sstevel@tonic-gate { 15093118Sab196087 /* 15103118Sab196087 * Symbol types for which we check that the specified 15113118Sab196087 * address/size land inside the target section. 15123118Sab196087 */ 15133492Sab196087 static const int addr_symtype[STT_NUM] = { 15143118Sab196087 0, /* STT_NOTYPE */ 15153118Sab196087 1, /* STT_OBJECT */ 15163118Sab196087 1, /* STT_FUNC */ 15173118Sab196087 0, /* STT_SECTION */ 15183118Sab196087 0, /* STT_FILE */ 15193118Sab196087 1, /* STT_COMMON */ 15203118Sab196087 0, /* STT_TLS */ 15213118Sab196087 }; 15223118Sab196087 #if STT_NUM != (STT_TLS + 1) 15233492Sab196087 #error "STT_NUM has grown. Update addr_symtype[]" 15243118Sab196087 #endif 15253118Sab196087 15264665Sab196087 char index[MAXNDXSIZE]; 15274665Sab196087 const char *symname, *sec; 15283875Sab196087 Versym verndx; 15294716Sab196087 int gnuver; 15303492Sab196087 uchar_t type; 15313492Sab196087 Shdr *tshdr; 15323492Sab196087 Word shndx; 15334734Sab196087 Conv_inv_buf_t inv_buf; 15343492Sab196087 15353492Sab196087 /* Ensure symbol index is in range */ 15363492Sab196087 if (symndx >= state->symn) { 15373492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX), 15383492Sab196087 state->file, state->secname, EC_WORD(symndx)); 15393492Sab196087 return; 15403492Sab196087 } 15413492Sab196087 15423492Sab196087 /* 15433492Sab196087 * If we are using extended symbol indexes, find the 15443492Sab196087 * corresponding SHN_SYMTAB_SHNDX table. 15453492Sab196087 */ 15463492Sab196087 if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0)) 15473492Sab196087 symbols_getxindex(state); 15483492Sab196087 15493492Sab196087 /* LINTED */ 15503492Sab196087 symname = string(state->seccache, symndx, 15513492Sab196087 &state->cache[state->seccache->c_shdr->sh_link], state->file, 15523492Sab196087 sym->st_name); 15533492Sab196087 15543492Sab196087 tshdr = 0; 15553492Sab196087 sec = NULL; 15563492Sab196087 15574665Sab196087 if (state->ehdr->e_type == ET_CORE) { 15583492Sab196087 sec = (char *)MSG_INTL(MSG_STR_UNKNOWN); 15595411Sab196087 } else if (state->flags & FLG_CTL_FAKESHDR) { 15604665Sab196087 /* 15614665Sab196087 * If we are using fake section headers derived from 15624665Sab196087 * the program headers, then the section indexes 15634665Sab196087 * in the symbols do not correspond to these headers. 15644665Sab196087 * The section names are not available, so all we can 15654665Sab196087 * do is to display them in numeric form. 15664665Sab196087 */ 15674734Sab196087 sec = conv_sym_shndx(sym->st_shndx, &inv_buf); 15684665Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 15693492Sab196087 (sym->st_shndx < state->shnum)) { 15703492Sab196087 shndx = sym->st_shndx; 15713492Sab196087 tshdr = state->cache[shndx].c_shdr; 15723492Sab196087 sec = state->cache[shndx].c_name; 15733492Sab196087 } else if (sym->st_shndx == SHN_XINDEX) { 15743492Sab196087 if (state->shxndx.data) { 15753492Sab196087 Word _shxndx; 15763492Sab196087 15773492Sab196087 if (symndx > state->shxndx.n) { 15784433Sab196087 (void) fprintf(stderr, 15794433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 15804433Sab196087 state->file, state->secname, 15814433Sab196087 EC_WORD(symndx)); 15823492Sab196087 } else if ((_shxndx = 15833492Sab196087 state->shxndx.data[symndx]) > state->shnum) { 15844433Sab196087 (void) fprintf(stderr, 15854433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 15864433Sab196087 state->file, state->secname, 15874433Sab196087 EC_WORD(symndx), EC_WORD(_shxndx)); 15883492Sab196087 } else { 15894433Sab196087 shndx = _shxndx; 15904433Sab196087 tshdr = state->cache[shndx].c_shdr; 15914433Sab196087 sec = state->cache[shndx].c_name; 15923492Sab196087 } 15933492Sab196087 } else { 15943492Sab196087 (void) fprintf(stderr, 15953492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 15963492Sab196087 state->file, state->secname, EC_WORD(symndx)); 15973492Sab196087 } 15983492Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 15993492Sab196087 (sym->st_shndx >= state->shnum)) { 16003492Sab196087 (void) fprintf(stderr, 16013492Sab196087 MSG_INTL(MSG_ERR_BADSYM5), state->file, 16026206Sab196087 state->secname, EC_WORD(symndx), 16036206Sab196087 demangle(symname, state->flags), sym->st_shndx); 16043492Sab196087 } 16050Sstevel@tonic-gate 16063492Sab196087 /* 16073492Sab196087 * If versioning is available display the 16083875Sab196087 * version index. If not, then use 0. 16093492Sab196087 */ 16103875Sab196087 if (state->versym) { 16114716Sab196087 Versym test_verndx; 16124716Sab196087 16134716Sab196087 verndx = test_verndx = state->versym->data[symndx]; 16147682SAli.Bahrami@Sun.COM gnuver = state->versym->gnu_full; 16153875Sab196087 16163875Sab196087 /* 16173875Sab196087 * Check to see if this is a defined symbol with a 16183875Sab196087 * version index that is outside the valid range for 16194716Sab196087 * the file. The interpretation of this depends on 16204716Sab196087 * the style of versioning used by the object. 16213875Sab196087 * 16224716Sab196087 * Versions >= VER_NDX_LORESERVE have special meanings, 16234716Sab196087 * and are exempt from this checking. 16244716Sab196087 * 16254716Sab196087 * GNU style version indexes use the top bit of the 16264716Sab196087 * 16-bit index value (0x8000) as the "hidden bit". 16274716Sab196087 * We must mask off this bit in order to compare 16284716Sab196087 * the version against the maximum value. 16293875Sab196087 */ 16304716Sab196087 if (gnuver) 16314716Sab196087 test_verndx &= ~0x8000; 16324716Sab196087 16334716Sab196087 if ((test_verndx > state->versym->max_verndx) && 16344716Sab196087 (verndx < VER_NDX_LORESERVE)) 16354716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER), 16364716Sab196087 state->file, state->secname, EC_WORD(symndx), 16374716Sab196087 EC_HALF(test_verndx), state->versym->max_verndx); 16383875Sab196087 } else { 16393492Sab196087 verndx = 0; 16404716Sab196087 gnuver = 0; 16413875Sab196087 } 16423492Sab196087 16433492Sab196087 /* 16443492Sab196087 * Error checking for TLS. 16453492Sab196087 */ 16463492Sab196087 type = ELF_ST_TYPE(sym->st_info); 16473492Sab196087 if (type == STT_TLS) { 16483492Sab196087 if (tshdr && 16493492Sab196087 (sym->st_shndx != SHN_UNDEF) && 16503492Sab196087 ((tshdr->sh_flags & SHF_TLS) == 0)) { 16513492Sab196087 (void) fprintf(stderr, 16523492Sab196087 MSG_INTL(MSG_ERR_BADSYM3), state->file, 16536206Sab196087 state->secname, EC_WORD(symndx), 16546206Sab196087 demangle(symname, state->flags)); 16553492Sab196087 } 16563492Sab196087 } else if ((type != STT_SECTION) && sym->st_size && 16573492Sab196087 tshdr && (tshdr->sh_flags & SHF_TLS)) { 16583492Sab196087 (void) fprintf(stderr, 16593492Sab196087 MSG_INTL(MSG_ERR_BADSYM4), state->file, 16606206Sab196087 state->secname, EC_WORD(symndx), 16616206Sab196087 demangle(symname, state->flags)); 16623492Sab196087 } 16633492Sab196087 16643492Sab196087 /* 16653492Sab196087 * If a symbol with non-zero size has a type that 16663492Sab196087 * specifies an address, then make sure the location 16673492Sab196087 * it references is actually contained within the 16683492Sab196087 * section. UNDEF symbols don't count in this case, 16693492Sab196087 * so we ignore them. 16703492Sab196087 * 16713492Sab196087 * The meaning of the st_value field in a symbol 16723492Sab196087 * depends on the type of object. For a relocatable 16733492Sab196087 * object, it is the offset within the section. 16743492Sab196087 * For sharable objects, it is the offset relative to 16753492Sab196087 * the base of the object, and for other types, it is 16763492Sab196087 * the virtual address. To get an offset within the 16773492Sab196087 * section for non-ET_REL files, we subtract the 16783492Sab196087 * base address of the section. 16793492Sab196087 */ 16803492Sab196087 if (addr_symtype[type] && (sym->st_size > 0) && 16813492Sab196087 (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) || 16823492Sab196087 (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) { 16833492Sab196087 Word v = sym->st_value; 16843492Sab196087 if (state->ehdr->e_type != ET_REL) 16854832Srie v -= tshdr->sh_addr; 16863492Sab196087 if (((v + sym->st_size) > tshdr->sh_size)) { 16873492Sab196087 (void) fprintf(stderr, 16883492Sab196087 MSG_INTL(MSG_ERR_BADSYM6), state->file, 16896206Sab196087 state->secname, EC_WORD(symndx), 16906206Sab196087 demangle(symname, state->flags), 16913492Sab196087 EC_WORD(shndx), EC_XWORD(tshdr->sh_size), 16923492Sab196087 EC_XWORD(sym->st_value), EC_XWORD(sym->st_size)); 16933492Sab196087 } 16943492Sab196087 } 16953492Sab196087 16964832Srie /* 16974832Srie * A typical symbol table uses the sh_info field to indicate one greater 16984832Srie * than the symbol table index of the last local symbol, STB_LOCAL. 16994832Srie * Therefore, symbol indexes less than sh_info should have local 17004832Srie * binding. Symbol indexes greater than, or equal to sh_info, should 17014832Srie * have global binding. Note, we exclude UNDEF/NOTY symbols with zero 17024832Srie * value and size, as these symbols may be the result of an mcs(1) 17034832Srie * section deletion. 17044832Srie */ 17054832Srie if (info) { 17064832Srie uchar_t bind = ELF_ST_BIND(sym->st_info); 17074832Srie 17084832Srie if ((symndx < info) && (bind != STB_LOCAL)) { 17094832Srie (void) fprintf(stderr, 17104832Srie MSG_INTL(MSG_ERR_BADSYM7), state->file, 17116206Sab196087 state->secname, EC_WORD(symndx), 17126206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 17134832Srie 17144832Srie } else if ((symndx >= info) && (bind == STB_LOCAL) && 17154832Srie ((sym->st_shndx != SHN_UNDEF) || 17164832Srie (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) || 17174832Srie (sym->st_size != 0) || (sym->st_value != 0))) { 17184832Srie (void) fprintf(stderr, 17194832Srie MSG_INTL(MSG_ERR_BADSYM8), state->file, 17206206Sab196087 state->secname, EC_WORD(symndx), 17216206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 17224832Srie } 17234832Srie } 17244832Srie 17253492Sab196087 (void) snprintf(index, MAXNDXSIZE, 17263492Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx)); 17273492Sab196087 Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, 17284716Sab196087 state->ehdr->e_machine, sym, verndx, gnuver, sec, symname); 17293492Sab196087 } 17303492Sab196087 17313492Sab196087 /* 17323492Sab196087 * Search for and process any symbol tables. 17333492Sab196087 */ 17343492Sab196087 void 17354168Sab196087 symbols(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 17364168Sab196087 const char *file, uint_t flags) 17373492Sab196087 { 17383492Sab196087 SYMTBL_STATE state; 17393492Sab196087 Cache *_cache; 17403492Sab196087 Word secndx; 17413492Sab196087 17423492Sab196087 for (secndx = 1; secndx < shnum; secndx++) { 17433492Sab196087 Word symcnt; 17443492Sab196087 Shdr *shdr; 17453492Sab196087 17463492Sab196087 _cache = &cache[secndx]; 17473492Sab196087 shdr = _cache->c_shdr; 17480Sstevel@tonic-gate 17490Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) && 17502766Sab196087 (shdr->sh_type != SHT_DYNSYM) && 17512766Sab196087 (shdr->sh_type != SHT_SUNW_LDYNSYM)) 17520Sstevel@tonic-gate continue; 17535411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, secndx, shdr->sh_type)) 17543466Srie continue; 17553466Srie 17563492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr, 17573875Sab196087 versym, file, flags)) 17580Sstevel@tonic-gate continue; 17590Sstevel@tonic-gate /* 17600Sstevel@tonic-gate * Loop through the symbol tables entries. 17610Sstevel@tonic-gate */ 17621618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17633492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname); 17641618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 17650Sstevel@tonic-gate 17663492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++) 17674832Srie output_symbol(&state, symcnt, shdr->sh_info, symcnt, 17683492Sab196087 state.sym + symcnt); 17693492Sab196087 } 17703492Sab196087 } 17710Sstevel@tonic-gate 17723492Sab196087 /* 17733492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections. 17743492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair. 17753492Sab196087 */ 17763492Sab196087 static void 17774168Sab196087 sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 17784168Sab196087 const char *file, uint_t flags) 17793492Sab196087 { 17803492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state; 17813492Sab196087 Cache *sortcache, *symcache; 17823492Sab196087 Shdr *sortshdr, *symshdr; 17833492Sab196087 Word sortsecndx, symsecndx; 17843492Sab196087 Word ldynsym_cnt; 17853492Sab196087 Word *ndx; 17863492Sab196087 Word ndxn; 17873492Sab196087 int output_cnt = 0; 17884734Sab196087 Conv_inv_buf_t inv_buf; 17890Sstevel@tonic-gate 17903492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) { 17910Sstevel@tonic-gate 17923492Sab196087 sortcache = &cache[sortsecndx]; 17933492Sab196087 sortshdr = sortcache->c_shdr; 17940Sstevel@tonic-gate 17953492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) && 17963492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort)) 17973492Sab196087 continue; 17985411Sab196087 if (!match(MATCH_F_ALL, sortcache->c_name, sortsecndx, 17995411Sab196087 sortshdr->sh_type)) 18003492Sab196087 continue; 18010Sstevel@tonic-gate 18023492Sab196087 /* 18033492Sab196087 * If the section references a SUNW_ldynsym, then we 18043492Sab196087 * expect to see the associated .dynsym immediately 18053492Sab196087 * following. If it references a .dynsym, there is no 18063492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't 18073492Sab196087 * know what to do with it. 18083492Sab196087 */ 18093492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) { 18103492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 18113492Sab196087 file, sortcache->c_name, 18123492Sab196087 EC_WORD(sortshdr->sh_link)); 18133492Sab196087 continue; 18143492Sab196087 } 18153492Sab196087 symcache = &cache[sortshdr->sh_link]; 18163492Sab196087 symshdr = symcache->c_shdr; 18173492Sab196087 symsecndx = sortshdr->sh_link; 18183492Sab196087 ldynsym_cnt = 0; 18193492Sab196087 switch (symshdr->sh_type) { 18203492Sab196087 case SHT_SUNW_LDYNSYM: 18213492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum, 18223875Sab196087 symsecndx, ehdr, versym, file, flags)) 18233492Sab196087 continue; 18243492Sab196087 ldynsym_cnt = ldynsym_state.symn; 18250Sstevel@tonic-gate /* 18263492Sab196087 * We know that the dynsym follows immediately 18273492Sab196087 * after the SUNW_ldynsym, and so, should be at 18283492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a 18293492Sab196087 * diagnostic tool, so we do the full paranoid 18303492Sab196087 * search instead. 18310Sstevel@tonic-gate */ 18323492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) { 18333492Sab196087 symcache = &cache[symsecndx]; 18343492Sab196087 symshdr = symcache->c_shdr; 18353492Sab196087 if (symshdr->sh_type == SHT_DYNSYM) 18363492Sab196087 break; 18373492Sab196087 } 18383492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */ 18390Sstevel@tonic-gate (void) fprintf(stderr, 18403492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM), 18413492Sab196087 file, sortcache->c_name); 18423492Sab196087 continue; 18430Sstevel@tonic-gate } 18443492Sab196087 /* Fallthrough to process associated dynsym */ 18457463SRod.Evans@Sun.COM /* FALLTHROUGH */ 18463492Sab196087 case SHT_DYNSYM: 18473492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum, 18483875Sab196087 symsecndx, ehdr, versym, file, flags)) 18493492Sab196087 continue; 18503492Sab196087 break; 18513492Sab196087 default: 18523492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC), 18533492Sab196087 file, sortcache->c_name, conv_sec_type( 18544734Sab196087 ehdr->e_machine, symshdr->sh_type, 0, &inv_buf)); 18553492Sab196087 continue; 18563492Sab196087 } 18570Sstevel@tonic-gate 18583492Sab196087 /* 18593492Sab196087 * Output header 18603492Sab196087 */ 18613492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 18623492Sab196087 if (ldynsym_cnt > 0) { 18633492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2), 18643492Sab196087 sortcache->c_name, ldynsym_state.secname, 18653492Sab196087 dynsym_state.secname); 18660Sstevel@tonic-gate /* 18673492Sab196087 * The data for .SUNW_ldynsym and dynsym sections 18683492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming 18693492Sab196087 * first. Check, and issue a warning if it isn't so. 18700Sstevel@tonic-gate */ 18714665Sab196087 if (((ldynsym_state.sym + ldynsym_state.symn) 18724665Sab196087 != dynsym_state.sym) && 18735411Sab196087 ((flags & FLG_CTL_FAKESHDR) == 0)) 18743492Sab196087 (void) fprintf(stderr, 18753492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file, 18763492Sab196087 ldynsym_state.secname, 18773492Sab196087 dynsym_state.secname); 18783492Sab196087 } else { 18793492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1), 18803492Sab196087 sortcache->c_name, dynsym_state.secname); 18813492Sab196087 } 18823492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 18833492Sab196087 18843492Sab196087 /* If not first one, insert a line of whitespace */ 18853492Sab196087 if (output_cnt++ > 0) 18863492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 18873118Sab196087 18883492Sab196087 /* 18893492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of 18903492Sab196087 * symbol indices. Iterate over the array entries, 18913492Sab196087 * dispaying the referenced symbols. 18923492Sab196087 */ 18933492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize; 18943492Sab196087 ndx = (Word *)sortcache->c_data->d_buf; 18953492Sab196087 for (; ndxn-- > 0; ndx++) { 18963492Sab196087 if (*ndx >= ldynsym_cnt) { 18973492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt; 18983492Sab196087 18994832Srie output_symbol(&dynsym_state, sec_ndx, 0, 19003492Sab196087 *ndx, dynsym_state.sym + sec_ndx); 19013492Sab196087 } else { 19024832Srie output_symbol(&ldynsym_state, *ndx, 0, 19033492Sab196087 *ndx, ldynsym_state.sym + *ndx); 19040Sstevel@tonic-gate } 19050Sstevel@tonic-gate } 19060Sstevel@tonic-gate } 19070Sstevel@tonic-gate } 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate /* 19100Sstevel@tonic-gate * Search for and process any relocation sections. 19110Sstevel@tonic-gate */ 19120Sstevel@tonic-gate static void 19137463SRod.Evans@Sun.COM reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 19140Sstevel@tonic-gate { 19151618Srie Word cnt; 19160Sstevel@tonic-gate 19170Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 19181618Srie Word type, symnum; 19191618Srie Xword relndx, relnum, relsize; 19201618Srie void *rels; 19211618Srie Sym *syms; 19221618Srie Cache *symsec, *strsec; 19230Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 19241618Srie Shdr *shdr = _cache->c_shdr; 19251618Srie char *relname = _cache->c_name; 19264734Sab196087 Conv_inv_buf_t inv_buf; 19270Sstevel@tonic-gate 19280Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) && 19290Sstevel@tonic-gate (type != SHT_REL)) 19300Sstevel@tonic-gate continue; 19315411Sab196087 if (!match(MATCH_F_ALL, relname, cnt, type)) 19320Sstevel@tonic-gate continue; 19330Sstevel@tonic-gate 19340Sstevel@tonic-gate /* 19351618Srie * Decide entry size. 19360Sstevel@tonic-gate */ 19371618Srie if (((relsize = shdr->sh_entsize) == 0) || 19381618Srie (relsize > shdr->sh_size)) { 19390Sstevel@tonic-gate if (type == SHT_RELA) 19401618Srie relsize = sizeof (Rela); 19410Sstevel@tonic-gate else 19421618Srie relsize = sizeof (Rel); 19430Sstevel@tonic-gate } 19440Sstevel@tonic-gate 19450Sstevel@tonic-gate /* 19460Sstevel@tonic-gate * Determine the number of relocations available. 19470Sstevel@tonic-gate */ 19480Sstevel@tonic-gate if (shdr->sh_size == 0) { 19490Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 19501618Srie file, relname); 19510Sstevel@tonic-gate continue; 19520Sstevel@tonic-gate } 19533466Srie if (_cache->c_data == NULL) 19543466Srie continue; 19553466Srie 19561618Srie rels = _cache->c_data->d_buf; 19571618Srie relnum = shdr->sh_size / relsize; 19580Sstevel@tonic-gate 19590Sstevel@tonic-gate /* 19601618Srie * Get the data buffer for the associated symbol table and 19611618Srie * string table. 19620Sstevel@tonic-gate */ 19631618Srie if (stringtbl(cache, 1, cnt, shnum, file, 19641618Srie &symnum, &symsec, &strsec) == 0) 19650Sstevel@tonic-gate continue; 19661618Srie 19671618Srie syms = symsec->c_data->d_buf; 19680Sstevel@tonic-gate 19690Sstevel@tonic-gate /* 19700Sstevel@tonic-gate * Loop through the relocation entries. 19710Sstevel@tonic-gate */ 19721618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 19731618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 19741618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type); 19750Sstevel@tonic-gate 19761618Srie for (relndx = 0; relndx < relnum; relndx++, 19771618Srie rels = (void *)((char *)rels + relsize)) { 19786206Sab196087 Half mach = ehdr->e_machine; 19790Sstevel@tonic-gate char section[BUFSIZ]; 19801618Srie const char *symname; 19811618Srie Word symndx, reltype; 19821618Srie Rela *rela; 19831618Srie Rel *rel; 19840Sstevel@tonic-gate 19850Sstevel@tonic-gate /* 19861618Srie * Unravel the relocation and determine the symbol with 19871618Srie * which this relocation is associated. 19880Sstevel@tonic-gate */ 19890Sstevel@tonic-gate if (type == SHT_RELA) { 19901618Srie rela = (Rela *)rels; 19911618Srie symndx = ELF_R_SYM(rela->r_info); 19926206Sab196087 reltype = ELF_R_TYPE(rela->r_info, mach); 19930Sstevel@tonic-gate } else { 19941618Srie rel = (Rel *)rels; 19951618Srie symndx = ELF_R_SYM(rel->r_info); 19966206Sab196087 reltype = ELF_R_TYPE(rel->r_info, mach); 19970Sstevel@tonic-gate } 19981618Srie 19991618Srie symname = relsymname(cache, _cache, strsec, symndx, 20007463SRod.Evans@Sun.COM symnum, relndx, syms, section, BUFSIZ, file); 20011618Srie 20021618Srie /* 20031618Srie * A zero symbol index is only valid for a few 20041618Srie * relocations. 20051618Srie */ 20061618Srie if (symndx == 0) { 20071618Srie int badrel = 0; 20080Sstevel@tonic-gate 20091618Srie if ((mach == EM_SPARC) || 20101618Srie (mach == EM_SPARC32PLUS) || 20111618Srie (mach == EM_SPARCV9)) { 20121618Srie if ((reltype != R_SPARC_NONE) && 20131618Srie (reltype != R_SPARC_REGISTER) && 20141618Srie (reltype != R_SPARC_RELATIVE)) 20151618Srie badrel++; 20161618Srie } else if (mach == EM_386) { 20171618Srie if ((reltype != R_386_NONE) && 20181618Srie (reltype != R_386_RELATIVE)) 20191618Srie badrel++; 20201618Srie } else if (mach == EM_AMD64) { 20211618Srie if ((reltype != R_AMD64_NONE) && 20221618Srie (reltype != R_AMD64_RELATIVE)) 20231618Srie badrel++; 20241618Srie } 20251618Srie 20261618Srie if (badrel) { 20271618Srie (void) fprintf(stderr, 20281618Srie MSG_INTL(MSG_ERR_BADREL1), file, 20294734Sab196087 conv_reloc_type(mach, reltype, 20304734Sab196087 0, &inv_buf)); 20310Sstevel@tonic-gate } 20320Sstevel@tonic-gate } 20330Sstevel@tonic-gate 20341618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP, 20351618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type, 20361618Srie rels, relname, symname, 0); 20370Sstevel@tonic-gate } 20380Sstevel@tonic-gate } 20390Sstevel@tonic-gate } 20400Sstevel@tonic-gate 20415230Sab196087 20425230Sab196087 /* 20435230Sab196087 * This value controls which test dyn_test() performs. 20445230Sab196087 */ 20455230Sab196087 typedef enum { DYN_TEST_ADDR, DYN_TEST_SIZE, DYN_TEST_ENTSIZE } dyn_test_t; 20465230Sab196087 20475230Sab196087 /* 20485230Sab196087 * Used by dynamic() to compare the value of a dynamic element against 20495230Sab196087 * the starting address of the section it references. 20505230Sab196087 * 20515230Sab196087 * entry: 20525230Sab196087 * test_type - Specify which dyn item is being tested. 20535230Sab196087 * sh_type - SHT_* type value for required section. 20545230Sab196087 * sec_cache - Cache entry for section, or NULL if the object lacks 20555230Sab196087 * a section of this type. 20565230Sab196087 * dyn - Dyn entry to be tested 20575230Sab196087 * dynsec_cnt - # of dynamic section being examined. The first 20585230Sab196087 * dynamic section is 1, the next is 2, and so on... 20595230Sab196087 * ehdr - ELF header for file 20605230Sab196087 * file - Name of file 20615230Sab196087 */ 20625230Sab196087 static void 20635230Sab196087 dyn_test(dyn_test_t test_type, Word sh_type, Cache *sec_cache, Dyn *dyn, 20645230Sab196087 Word dynsec_cnt, Ehdr *ehdr, const char *file) 20655230Sab196087 { 20665230Sab196087 Conv_inv_buf_t buf1, buf2; 20675230Sab196087 20685230Sab196087 /* 20695230Sab196087 * These tests are based around the implicit assumption that 20705230Sab196087 * there is only one dynamic section in an object, and also only 20715230Sab196087 * one of the sections it references. We have therefore gathered 20725230Sab196087 * all of the necessary information to test this in a single pass 20735230Sab196087 * over the section headers, which is very efficient. We are not 20745230Sab196087 * aware of any case where more than one dynamic section would 20755230Sab196087 * be meaningful in an ELF object, so this is a reasonable solution. 20765230Sab196087 * 20775230Sab196087 * To test multiple dynamic sections correctly would be more 20785230Sab196087 * expensive in code and time. We would have to build a data structure 20795230Sab196087 * containing all the dynamic elements. Then, we would use the address 20805230Sab196087 * to locate the section it references and ensure the section is of 20815230Sab196087 * the right type and that the address in the dynamic element is 20825230Sab196087 * to the start of the section. Then, we could check the size and 20835230Sab196087 * entsize values against those same sections. This is O(n^2), and 20845230Sab196087 * also complicated. 20855230Sab196087 * 20865230Sab196087 * In the highly unlikely case that there is more than one dynamic 20875230Sab196087 * section, we only test the first one, and simply allow the values 20885230Sab196087 * of the subsequent one to be displayed unchallenged. 20895230Sab196087 */ 20905230Sab196087 if (dynsec_cnt != 1) 20915230Sab196087 return; 20925230Sab196087 20935230Sab196087 /* 20945230Sab196087 * A DT_ item that references a section address should always find 20955230Sab196087 * the section in the file. 20965230Sab196087 */ 20975230Sab196087 if (sec_cache == NULL) { 20986299Sab196087 const char *name; 20996299Sab196087 21006299Sab196087 /* 21016299Sab196087 * Supply section names instead of section types for 21026299Sab196087 * things that reference progbits so that the error 21036299Sab196087 * message will make more sense. 21046299Sab196087 */ 21056299Sab196087 switch (dyn->d_tag) { 21066299Sab196087 case DT_INIT: 21076299Sab196087 name = MSG_ORIG(MSG_ELF_INIT); 21086299Sab196087 break; 21096299Sab196087 case DT_FINI: 21106299Sab196087 name = MSG_ORIG(MSG_ELF_FINI); 21116299Sab196087 break; 21126299Sab196087 default: 21136299Sab196087 name = conv_sec_type(ehdr->e_machine, sh_type, 21146299Sab196087 0, &buf1); 21156299Sab196087 break; 21166299Sab196087 } 21175230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNNOBCKSEC), file, 21186299Sab196087 name, conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf2)); 21195230Sab196087 return; 21205230Sab196087 } 21215230Sab196087 21225230Sab196087 21235230Sab196087 switch (test_type) { 21245230Sab196087 case DYN_TEST_ADDR: 21255230Sab196087 /* The section address should match the DT_ item value */ 21265230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_addr) 21275230Sab196087 (void) fprintf(stderr, 21285230Sab196087 MSG_INTL(MSG_ERR_DYNBADADDR), file, 21295230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 21305230Sab196087 EC_ADDR(dyn->d_un.d_val), sec_cache->c_ndx, 21315230Sab196087 sec_cache->c_name, 21325230Sab196087 EC_ADDR(sec_cache->c_shdr->sh_addr)); 21335230Sab196087 break; 21345230Sab196087 21355230Sab196087 case DYN_TEST_SIZE: 21365230Sab196087 /* The section size should match the DT_ item value */ 21375230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_size) 21385230Sab196087 (void) fprintf(stderr, 21395230Sab196087 MSG_INTL(MSG_ERR_DYNBADSIZE), file, 21405230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 21415230Sab196087 EC_XWORD(dyn->d_un.d_val), 21425230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 21435230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_size)); 21445230Sab196087 break; 21455230Sab196087 21465230Sab196087 case DYN_TEST_ENTSIZE: 21475230Sab196087 /* The sh_entsize value should match the DT_ item value */ 21485230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_entsize) 21495230Sab196087 (void) fprintf(stderr, 21505230Sab196087 MSG_INTL(MSG_ERR_DYNBADENTSIZE), file, 21515230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 21525230Sab196087 EC_XWORD(dyn->d_un.d_val), 21535230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 21545230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_entsize)); 21555230Sab196087 break; 21565230Sab196087 } 21575230Sab196087 } 21585230Sab196087 21595230Sab196087 21600Sstevel@tonic-gate /* 21616299Sab196087 * There are some DT_ entries that have corresponding symbols 21626299Sab196087 * (e.g. DT_INIT and _init). It is expected that these items will 21636299Sab196087 * both have the same value if both are present. This routine 21646299Sab196087 * examines the well known symbol tables for such symbols and 21656299Sab196087 * issues warnings for any that don't match. 21666299Sab196087 * 21676299Sab196087 * entry: 21686299Sab196087 * dyn - Dyn entry to be tested 21696299Sab196087 * symname - Name of symbol that corresponds to dyn 21706299Sab196087 * symtab_cache, dynsym_cache, ldynsym_cache - Symbol tables to check 21716299Sab196087 * cache - Cache of all section headers 21726299Sab196087 * shnum - # of sections in cache 21736299Sab196087 * ehdr - ELF header for file 21746299Sab196087 * file - Name of file 21756299Sab196087 */ 21766299Sab196087 static void 21776299Sab196087 dyn_symtest(Dyn *dyn, const char *symname, Cache *symtab_cache, 21786299Sab196087 Cache *dynsym_cache, Cache *ldynsym_cache, Cache *cache, 21796299Sab196087 Word shnum, Ehdr *ehdr, const char *file) 21806299Sab196087 { 21816299Sab196087 Conv_inv_buf_t buf; 21826299Sab196087 int i; 21836299Sab196087 Sym *sym; 21846299Sab196087 Cache *_cache; 21856299Sab196087 21866299Sab196087 for (i = 0; i < 3; i++) { 21876299Sab196087 switch (i) { 21886299Sab196087 case 0: 21896299Sab196087 _cache = symtab_cache; 21906299Sab196087 break; 21916299Sab196087 case 1: 21926299Sab196087 _cache = dynsym_cache; 21936299Sab196087 break; 21946299Sab196087 case 2: 21956299Sab196087 _cache = ldynsym_cache; 21966299Sab196087 break; 21976299Sab196087 } 21986299Sab196087 21996299Sab196087 if ((_cache != NULL) && 22006299Sab196087 symlookup(symname, cache, shnum, &sym, _cache, file) && 22016299Sab196087 (sym->st_value != dyn->d_un.d_val)) 22026299Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNSYMVAL), 22036299Sab196087 file, _cache->c_name, 22046299Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf), 22056299Sab196087 symname, EC_ADDR(sym->st_value)); 22066299Sab196087 } 22076299Sab196087 } 22086299Sab196087 22096299Sab196087 22106299Sab196087 /* 22110Sstevel@tonic-gate * Search for and process a .dynamic section. 22120Sstevel@tonic-gate */ 22130Sstevel@tonic-gate static void 22141618Srie dynamic(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 22150Sstevel@tonic-gate { 22165230Sab196087 struct { 22176299Sab196087 Cache *symtab; 22185230Sab196087 Cache *dynstr; 22195230Sab196087 Cache *dynsym; 22205230Sab196087 Cache *hash; 22215230Sab196087 Cache *fini; 22225230Sab196087 Cache *fini_array; 22235230Sab196087 Cache *init; 22245230Sab196087 Cache *init_array; 22255230Sab196087 Cache *preinit_array; 22265230Sab196087 Cache *rel; 22275230Sab196087 Cache *rela; 22285230Sab196087 Cache *sunw_cap; 22295230Sab196087 Cache *sunw_ldynsym; 22305230Sab196087 Cache *sunw_move; 22315230Sab196087 Cache *sunw_syminfo; 22325230Sab196087 Cache *sunw_symsort; 22335230Sab196087 Cache *sunw_tlssort; 22345230Sab196087 Cache *sunw_verdef; 22355230Sab196087 Cache *sunw_verneed; 22365230Sab196087 Cache *sunw_versym; 22375230Sab196087 } sec; 22385230Sab196087 Word dynsec_ndx; 22395230Sab196087 Word dynsec_num; 22405230Sab196087 int dynsec_cnt; 22411618Srie Word cnt; 22420Sstevel@tonic-gate 22435230Sab196087 /* 22445230Sab196087 * Make a pass over all the sections, gathering section information 22455230Sab196087 * we'll need below. 22465230Sab196087 */ 22475230Sab196087 dynsec_num = 0; 22485230Sab196087 bzero(&sec, sizeof (sec)); 22490Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 22505230Sab196087 Cache *_cache = &cache[cnt]; 22515230Sab196087 22525230Sab196087 switch (_cache->c_shdr->sh_type) { 22535230Sab196087 case SHT_DYNAMIC: 22545230Sab196087 if (dynsec_num == 0) { 22555230Sab196087 dynsec_ndx = cnt; 22565230Sab196087 22575230Sab196087 /* Does it have a valid string table? */ 22585230Sab196087 (void) stringtbl(cache, 0, cnt, shnum, file, 22595230Sab196087 0, 0, &sec.dynstr); 22605230Sab196087 } 22615230Sab196087 dynsec_num++; 22625230Sab196087 break; 22635230Sab196087 22645230Sab196087 22655230Sab196087 case SHT_PROGBITS: 22665230Sab196087 /* 22675230Sab196087 * We want to detect the .init and .fini sections, 22685230Sab196087 * if present. These are SHT_PROGBITS, so all we 22695230Sab196087 * have to go on is the section name. Normally comparing 22705230Sab196087 * names is a bad idea, but there are some special 22715230Sab196087 * names (i.e. .init/.fini/.interp) that are very 22725230Sab196087 * difficult to use in any other context, and for 22735230Sab196087 * these symbols, we do the heuristic match. 22745230Sab196087 */ 22755230Sab196087 if (strcmp(_cache->c_name, 22765230Sab196087 MSG_ORIG(MSG_ELF_INIT)) == 0) { 22775230Sab196087 if (sec.init == NULL) 22785230Sab196087 sec.init = _cache; 22795230Sab196087 } else if (strcmp(_cache->c_name, 22805230Sab196087 MSG_ORIG(MSG_ELF_FINI)) == 0) { 22815230Sab196087 if (sec.fini == NULL) 22825230Sab196087 sec.fini = _cache; 22835230Sab196087 } 22845230Sab196087 break; 22855230Sab196087 22865230Sab196087 case SHT_REL: 22875230Sab196087 /* 22885230Sab196087 * We want the SHT_REL section with the lowest 22895230Sab196087 * offset. The linker gathers them together, 22905230Sab196087 * and puts the address of the first one 22915230Sab196087 * into the DT_REL dynamic element. 22925230Sab196087 */ 22935230Sab196087 if ((sec.rel == NULL) || 22945230Sab196087 (_cache->c_shdr->sh_offset < 22955230Sab196087 sec.rel->c_shdr->sh_offset)) 22965230Sab196087 sec.rel = _cache; 22975230Sab196087 break; 22985230Sab196087 22995230Sab196087 case SHT_RELA: 23005230Sab196087 /* RELA is handled just like RELA above */ 23015230Sab196087 if ((sec.rela == NULL) || 23025230Sab196087 (_cache->c_shdr->sh_offset < 23035230Sab196087 sec.rela->c_shdr->sh_offset)) 23045230Sab196087 sec.rela = _cache; 23055230Sab196087 break; 23065230Sab196087 23075230Sab196087 /* 23085230Sab196087 * The GRAB macro is used for the simple case in which 23095230Sab196087 * we simply grab the first section of the desired type. 23105230Sab196087 */ 23115230Sab196087 #define GRAB(_sec_type, _sec_field) \ 23125230Sab196087 case _sec_type: \ 23135230Sab196087 if (sec._sec_field == NULL) \ 23145230Sab196087 sec._sec_field = _cache; \ 23155230Sab196087 break 23166299Sab196087 GRAB(SHT_SYMTAB, symtab); 23175230Sab196087 GRAB(SHT_DYNSYM, dynsym); 23185230Sab196087 GRAB(SHT_FINI_ARRAY, fini_array); 23195230Sab196087 GRAB(SHT_HASH, hash); 23205230Sab196087 GRAB(SHT_INIT_ARRAY, init_array); 23215230Sab196087 GRAB(SHT_SUNW_move, sunw_move); 23225230Sab196087 GRAB(SHT_PREINIT_ARRAY, preinit_array); 23235230Sab196087 GRAB(SHT_SUNW_cap, sunw_cap); 23245230Sab196087 GRAB(SHT_SUNW_LDYNSYM, sunw_ldynsym); 23255230Sab196087 GRAB(SHT_SUNW_syminfo, sunw_syminfo); 23265230Sab196087 GRAB(SHT_SUNW_symsort, sunw_symsort); 23275230Sab196087 GRAB(SHT_SUNW_tlssort, sunw_tlssort); 23285230Sab196087 GRAB(SHT_SUNW_verdef, sunw_verdef); 23295230Sab196087 GRAB(SHT_SUNW_verneed, sunw_verneed); 23305230Sab196087 GRAB(SHT_SUNW_versym, sunw_versym); 23315230Sab196087 #undef GRAB 23325230Sab196087 } 23335230Sab196087 } 23345230Sab196087 23355230Sab196087 /* 23365230Sab196087 * If no dynamic section, return immediately. If more than one 23375230Sab196087 * dynamic section, then something odd is going on and an error 23385230Sab196087 * is in order, but then continue on and display them all. 23395230Sab196087 */ 23405230Sab196087 if (dynsec_num == 0) 23415230Sab196087 return; 23425230Sab196087 if (dynsec_num > 1) 23435230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MULTDYN), 23445230Sab196087 file, EC_WORD(dynsec_num)); 23455230Sab196087 23465230Sab196087 23475230Sab196087 dynsec_cnt = 0; 23485230Sab196087 for (cnt = dynsec_ndx; (cnt < shnum) && (dynsec_cnt < dynsec_num); 23495230Sab196087 cnt++) { 23501618Srie Dyn *dyn; 23511618Srie ulong_t numdyn; 23523850Sab196087 int ndx, end_ndx; 23531618Srie Cache *_cache = &cache[cnt], *strsec; 23541618Srie Shdr *shdr = _cache->c_shdr; 23555230Sab196087 int dumped = 0; 23560Sstevel@tonic-gate 23570Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC) 23580Sstevel@tonic-gate continue; 23595230Sab196087 dynsec_cnt++; 23600Sstevel@tonic-gate 23610Sstevel@tonic-gate /* 23621618Srie * Verify the associated string table section. 23630Sstevel@tonic-gate */ 23641618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0) 23650Sstevel@tonic-gate continue; 23661618Srie 23673466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 23683466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 23693466Srie file, _cache->c_name); 23703466Srie continue; 23713466Srie } 23723466Srie if (_cache->c_data == NULL) 23733466Srie continue; 23743466Srie 23750Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize; 23761618Srie dyn = (Dyn *)_cache->c_data->d_buf; 23770Sstevel@tonic-gate 23785230Sab196087 /* 23795230Sab196087 * We expect the REL/RELA entries to reference the reloc 23805230Sab196087 * section with the lowest address. However, this is 23815230Sab196087 * not true for dumped objects. Detect if this object has 23825230Sab196087 * been dumped so that we can skip the reloc address test 23835230Sab196087 * in that case. 23845230Sab196087 */ 23855230Sab196087 for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 23865230Sab196087 if (dyn->d_tag == DT_FLAGS_1) { 23875230Sab196087 dumped = (dyn->d_un.d_val & DF_1_CONFALT) != 0; 23885230Sab196087 break; 23895230Sab196087 } 23905230Sab196087 } 23915230Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 23925230Sab196087 23931618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 23941618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 23950Sstevel@tonic-gate 23961618Srie Elf_dyn_title(0); 23970Sstevel@tonic-gate 23981618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 23994734Sab196087 union { 24006206Sab196087 Conv_inv_buf_t inv; 24014734Sab196087 Conv_dyn_flag_buf_t flag; 24024734Sab196087 Conv_dyn_flag1_buf_t flag1; 24034734Sab196087 Conv_dyn_posflag1_buf_t posflag1; 24044734Sab196087 Conv_dyn_feature1_buf_t feature1; 24054734Sab196087 } c_buf; 24065230Sab196087 const char *name = NULL; 24070Sstevel@tonic-gate 24080Sstevel@tonic-gate /* 24090Sstevel@tonic-gate * Print the information numerically, and if possible 24105230Sab196087 * as a string. If a string is available, name is 24115230Sab196087 * set to reference it. 24125230Sab196087 * 24135230Sab196087 * Also, take this opportunity to sanity check 24145230Sab196087 * the values of DT elements. In the code above, 24155230Sab196087 * we gathered information on sections that are 24165230Sab196087 * referenced by the dynamic section. Here, we 24175230Sab196087 * compare the attributes of those sections to 24185230Sab196087 * the DT_ items that reference them and report 24195230Sab196087 * on inconsistencies. 24205230Sab196087 * 24215230Sab196087 * Things not currently tested that could be improved 24225230Sab196087 * in later revisions include: 24235230Sab196087 * - We don't check PLT or GOT related items 24245230Sab196087 * - We don't handle computing the lengths of 24255230Sab196087 * relocation arrays. To handle this 24265230Sab196087 * requires examining data that spans 24275230Sab196087 * across sections, in a contiguous span 24285230Sab196087 * within a single segment. 24295230Sab196087 * - DT_VERDEFNUM and DT_VERNEEDNUM can't be 24305230Sab196087 * verified without parsing the sections. 24315230Sab196087 * - We don't handle DT_SUNW_SYMSZ, which would 24325230Sab196087 * be the sum of the lengths of .dynsym and 24335230Sab196087 * .SUNW_ldynsym 24345230Sab196087 * - DT_SUNW_STRPAD can't be verified other than 24355230Sab196087 * to check that it's not larger than 24365230Sab196087 * the string table. 24375230Sab196087 * - Some items come in "all or none" clusters 24385230Sab196087 * that give an address, element size, 24395230Sab196087 * and data length in bytes. We don't 24405230Sab196087 * verify that there are no missing items 24415230Sab196087 * in such groups. 24420Sstevel@tonic-gate */ 24433850Sab196087 switch (dyn->d_tag) { 24443850Sab196087 case DT_NULL: 24453850Sab196087 /* 24463850Sab196087 * Special case: DT_NULLs can come in groups 24473850Sab196087 * that we prefer to reduce to a single line. 24483850Sab196087 */ 24493850Sab196087 end_ndx = ndx; 24503850Sab196087 while ((end_ndx < (numdyn - 1)) && 24514433Sab196087 ((dyn + 1)->d_tag == DT_NULL)) { 24523850Sab196087 dyn++; 24533850Sab196087 end_ndx++; 24543850Sab196087 } 24553850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 24563850Sab196087 ndx = end_ndx; 24573850Sab196087 continue; 24583850Sab196087 24593850Sab196087 /* 24605230Sab196087 * String items all reference the dynstr. The string() 24615230Sab196087 * function does the necessary sanity checking. 24623850Sab196087 */ 24633850Sab196087 case DT_NEEDED: 24643850Sab196087 case DT_SONAME: 24653850Sab196087 case DT_FILTER: 24663850Sab196087 case DT_AUXILIARY: 24673850Sab196087 case DT_CONFIG: 24683850Sab196087 case DT_RPATH: 24693850Sab196087 case DT_RUNPATH: 24703850Sab196087 case DT_USED: 24713850Sab196087 case DT_DEPAUDIT: 24723850Sab196087 case DT_AUDIT: 24733850Sab196087 case DT_SUNW_AUXILIARY: 24743850Sab196087 case DT_SUNW_FILTER: 24751618Srie name = string(_cache, ndx, strsec, 24761618Srie file, dyn->d_un.d_ptr); 24773850Sab196087 break; 24783850Sab196087 24793850Sab196087 case DT_FLAGS: 24804734Sab196087 name = conv_dyn_flag(dyn->d_un.d_val, 24814734Sab196087 0, &c_buf.flag); 24823850Sab196087 break; 24833850Sab196087 case DT_FLAGS_1: 24845088Sab196087 name = conv_dyn_flag1(dyn->d_un.d_val, 0, 24854734Sab196087 &c_buf.flag1); 24863850Sab196087 break; 24873850Sab196087 case DT_POSFLAG_1: 24884734Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0, 24894734Sab196087 &c_buf.posflag1); 24903850Sab196087 break; 24913850Sab196087 case DT_FEATURE_1: 24924734Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0, 24934734Sab196087 &c_buf.feature1); 24943850Sab196087 break; 24953850Sab196087 case DT_DEPRECATED_SPARC_REGISTER: 24961618Srie name = MSG_INTL(MSG_STR_DEPRECATED); 24973850Sab196087 break; 24985230Sab196087 24996206Sab196087 case DT_SUNW_LDMACH: 25006206Sab196087 name = conv_ehdr_mach((Half)dyn->d_un.d_val, 0, 25016206Sab196087 &c_buf.inv); 25026206Sab196087 break; 25036206Sab196087 25045230Sab196087 /* 25055230Sab196087 * Cases below this point are strictly sanity checking, 25065230Sab196087 * and do not generate a name string. The TEST_ macros 25075230Sab196087 * are used to hide the boilerplate arguments neeeded 25085230Sab196087 * by dyn_test(). 25095230Sab196087 */ 25105230Sab196087 #define TEST_ADDR(_sh_type, _sec_field) \ 25115230Sab196087 dyn_test(DYN_TEST_ADDR, _sh_type, \ 25125230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 25135230Sab196087 #define TEST_SIZE(_sh_type, _sec_field) \ 25145230Sab196087 dyn_test(DYN_TEST_SIZE, _sh_type, \ 25155230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 25165230Sab196087 #define TEST_ENTSIZE(_sh_type, _sec_field) \ 25175230Sab196087 dyn_test(DYN_TEST_ENTSIZE, _sh_type, \ 25185230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 25195230Sab196087 25205230Sab196087 case DT_FINI: 25216299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_FINI), 25226299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 25236299Sab196087 cache, shnum, ehdr, file); 25245230Sab196087 TEST_ADDR(SHT_PROGBITS, fini); 25255230Sab196087 break; 25265230Sab196087 25275230Sab196087 case DT_FINI_ARRAY: 25285230Sab196087 TEST_ADDR(SHT_FINI_ARRAY, fini_array); 25295230Sab196087 break; 25305230Sab196087 25315230Sab196087 case DT_FINI_ARRAYSZ: 25325230Sab196087 TEST_SIZE(SHT_FINI_ARRAY, fini_array); 25335230Sab196087 break; 25345230Sab196087 25355230Sab196087 case DT_HASH: 25365230Sab196087 TEST_ADDR(SHT_HASH, hash); 25375230Sab196087 break; 25385230Sab196087 25395230Sab196087 case DT_INIT: 25406299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_INIT), 25416299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 25426299Sab196087 cache, shnum, ehdr, file); 25435230Sab196087 TEST_ADDR(SHT_PROGBITS, init); 25445230Sab196087 break; 25455230Sab196087 25465230Sab196087 case DT_INIT_ARRAY: 25475230Sab196087 TEST_ADDR(SHT_INIT_ARRAY, init_array); 25485230Sab196087 break; 25495230Sab196087 25505230Sab196087 case DT_INIT_ARRAYSZ: 25515230Sab196087 TEST_SIZE(SHT_INIT_ARRAY, init_array); 25525230Sab196087 break; 25535230Sab196087 25545230Sab196087 case DT_MOVEENT: 25555230Sab196087 TEST_ENTSIZE(SHT_SUNW_move, sunw_move); 25565230Sab196087 break; 25575230Sab196087 25585230Sab196087 case DT_MOVESZ: 25595230Sab196087 TEST_SIZE(SHT_SUNW_move, sunw_move); 25605230Sab196087 break; 25615230Sab196087 25625230Sab196087 case DT_MOVETAB: 25635230Sab196087 TEST_ADDR(SHT_SUNW_move, sunw_move); 25645230Sab196087 break; 25655230Sab196087 25665230Sab196087 case DT_PREINIT_ARRAY: 25675230Sab196087 TEST_ADDR(SHT_PREINIT_ARRAY, preinit_array); 25685230Sab196087 break; 25695230Sab196087 25705230Sab196087 case DT_PREINIT_ARRAYSZ: 25715230Sab196087 TEST_SIZE(SHT_PREINIT_ARRAY, preinit_array); 25725230Sab196087 break; 25735230Sab196087 25745230Sab196087 case DT_REL: 25755230Sab196087 if (!dumped) 25765230Sab196087 TEST_ADDR(SHT_REL, rel); 25775230Sab196087 break; 25785230Sab196087 25795230Sab196087 case DT_RELENT: 25805230Sab196087 TEST_ENTSIZE(SHT_REL, rel); 25815230Sab196087 break; 25825230Sab196087 25835230Sab196087 case DT_RELA: 25845230Sab196087 if (!dumped) 25855230Sab196087 TEST_ADDR(SHT_RELA, rela); 25865230Sab196087 break; 25875230Sab196087 25885230Sab196087 case DT_RELAENT: 25895230Sab196087 TEST_ENTSIZE(SHT_RELA, rela); 25905230Sab196087 break; 25915230Sab196087 25925230Sab196087 case DT_STRTAB: 25935230Sab196087 TEST_ADDR(SHT_STRTAB, dynstr); 25943850Sab196087 break; 25955230Sab196087 25965230Sab196087 case DT_STRSZ: 25975230Sab196087 TEST_SIZE(SHT_STRTAB, dynstr); 25985230Sab196087 break; 25995230Sab196087 26005230Sab196087 case DT_SUNW_CAP: 26015230Sab196087 TEST_ADDR(SHT_SUNW_cap, sunw_cap); 26025230Sab196087 break; 26035230Sab196087 26045230Sab196087 case DT_SUNW_SYMTAB: 26055230Sab196087 TEST_ADDR(SHT_SUNW_LDYNSYM, sunw_ldynsym); 26065230Sab196087 break; 26075230Sab196087 26085230Sab196087 case DT_SYMENT: 26095230Sab196087 TEST_ENTSIZE(SHT_DYNSYM, dynsym); 26105230Sab196087 break; 26115230Sab196087 26125230Sab196087 case DT_SYMINENT: 26135230Sab196087 TEST_ENTSIZE(SHT_SUNW_syminfo, sunw_syminfo); 26145230Sab196087 break; 26155230Sab196087 26165230Sab196087 case DT_SYMINFO: 26175230Sab196087 TEST_ADDR(SHT_SUNW_syminfo, sunw_syminfo); 26185230Sab196087 break; 26195230Sab196087 26205230Sab196087 case DT_SYMINSZ: 26215230Sab196087 TEST_SIZE(SHT_SUNW_syminfo, sunw_syminfo); 26225230Sab196087 break; 26235230Sab196087 26245230Sab196087 case DT_SYMTAB: 26255230Sab196087 TEST_ADDR(SHT_DYNSYM, dynsym); 26265230Sab196087 break; 26275230Sab196087 26285230Sab196087 case DT_SUNW_SORTENT: 26295230Sab196087 /* 26305230Sab196087 * This entry is related to both the symsort and 26315230Sab196087 * tlssort sections. 26325230Sab196087 */ 26335230Sab196087 { 26345230Sab196087 int test_tls = 26355230Sab196087 (sec.sunw_tlssort != NULL); 26365230Sab196087 int test_sym = 26375230Sab196087 (sec.sunw_symsort != NULL) || 26385230Sab196087 !test_tls; 26395230Sab196087 if (test_sym) 26405230Sab196087 TEST_ENTSIZE(SHT_SUNW_symsort, 26415230Sab196087 sunw_symsort); 26425230Sab196087 if (test_tls) 26435230Sab196087 TEST_ENTSIZE(SHT_SUNW_tlssort, 26445230Sab196087 sunw_tlssort); 26455230Sab196087 } 26465230Sab196087 break; 26475230Sab196087 26485230Sab196087 26495230Sab196087 case DT_SUNW_SYMSORT: 26505230Sab196087 TEST_ADDR(SHT_SUNW_symsort, sunw_symsort); 26515230Sab196087 break; 26525230Sab196087 26535230Sab196087 case DT_SUNW_SYMSORTSZ: 26545230Sab196087 TEST_SIZE(SHT_SUNW_symsort, sunw_symsort); 26555230Sab196087 break; 26565230Sab196087 26575230Sab196087 case DT_SUNW_TLSSORT: 26585230Sab196087 TEST_ADDR(SHT_SUNW_tlssort, sunw_tlssort); 26595230Sab196087 break; 26605230Sab196087 26615230Sab196087 case DT_SUNW_TLSSORTSZ: 26625230Sab196087 TEST_SIZE(SHT_SUNW_tlssort, sunw_tlssort); 26635230Sab196087 break; 26645230Sab196087 26655230Sab196087 case DT_VERDEF: 26665230Sab196087 TEST_ADDR(SHT_SUNW_verdef, sunw_verdef); 26675230Sab196087 break; 26685230Sab196087 26695230Sab196087 case DT_VERNEED: 26705230Sab196087 TEST_ADDR(SHT_SUNW_verneed, sunw_verneed); 26715230Sab196087 break; 26725230Sab196087 26735230Sab196087 case DT_VERSYM: 26745230Sab196087 TEST_ADDR(SHT_SUNW_versym, sunw_versym); 26755230Sab196087 break; 26765230Sab196087 #undef TEST_ADDR 26775230Sab196087 #undef TEST_SIZE 26785230Sab196087 #undef TEST_ENTSIZE 26793850Sab196087 } 26800Sstevel@tonic-gate 26815230Sab196087 if (name == NULL) 26825230Sab196087 name = MSG_ORIG(MSG_STR_EMPTY); 26831618Srie Elf_dyn_entry(0, dyn, ndx, name, ehdr->e_machine); 26840Sstevel@tonic-gate } 26850Sstevel@tonic-gate } 26860Sstevel@tonic-gate } 26870Sstevel@tonic-gate 26880Sstevel@tonic-gate /* 26890Sstevel@tonic-gate * Search for and process a MOVE section. 26900Sstevel@tonic-gate */ 26910Sstevel@tonic-gate static void 26924168Sab196087 move(Cache *cache, Word shnum, const char *file, uint_t flags) 26930Sstevel@tonic-gate { 26941618Srie Word cnt; 26951618Srie const char *fmt = 0; 26960Sstevel@tonic-gate 26970Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 26981618Srie Word movenum, symnum, ndx; 26991618Srie Sym *syms; 27001618Srie Cache *_cache = &cache[cnt]; 27011618Srie Shdr *shdr = _cache->c_shdr; 27021618Srie Cache *symsec, *strsec; 27031618Srie Move *move; 27040Sstevel@tonic-gate 27050Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move) 27060Sstevel@tonic-gate continue; 27075411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 27080Sstevel@tonic-gate continue; 27090Sstevel@tonic-gate 27100Sstevel@tonic-gate /* 27110Sstevel@tonic-gate * Determine the move data and number. 27120Sstevel@tonic-gate */ 27130Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 27140Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 27150Sstevel@tonic-gate file, _cache->c_name); 27160Sstevel@tonic-gate continue; 27170Sstevel@tonic-gate } 27183466Srie if (_cache->c_data == NULL) 27193466Srie continue; 27203466Srie 27211618Srie move = (Move *)_cache->c_data->d_buf; 27221618Srie movenum = shdr->sh_size / shdr->sh_entsize; 27230Sstevel@tonic-gate 27240Sstevel@tonic-gate /* 27251618Srie * Get the data buffer for the associated symbol table and 27261618Srie * string table. 27270Sstevel@tonic-gate */ 27281618Srie if (stringtbl(cache, 1, cnt, shnum, file, 27291618Srie &symnum, &symsec, &strsec) == 0) 27301618Srie return; 27311618Srie 27321618Srie syms = (Sym *)symsec->c_data->d_buf; 27330Sstevel@tonic-gate 27341618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 27351618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); 27361618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); 27370Sstevel@tonic-gate 27381618Srie if (fmt == 0) 27391618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY); 27400Sstevel@tonic-gate 27411618Srie for (ndx = 0; ndx < movenum; move++, ndx++) { 27421618Srie const char *symname; 27431618Srie char index[MAXNDXSIZE], section[BUFSIZ]; 27441618Srie Word symndx, shndx; 27451618Srie Sym *sym; 27460Sstevel@tonic-gate 27470Sstevel@tonic-gate /* 27480Sstevel@tonic-gate * Check for null entries 27490Sstevel@tonic-gate */ 27501618Srie if ((move->m_info == 0) && (move->m_value == 0) && 27511618Srie (move->m_poffset == 0) && (move->m_repeat == 0) && 27521618Srie (move->m_stride == 0)) { 27531618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY), 27541618Srie EC_XWORD(move->m_poffset), 0, 0, 0, 27551618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY)); 27560Sstevel@tonic-gate continue; 27570Sstevel@tonic-gate } 27581618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) || 27591618Srie (symndx >= symnum)) { 27600Sstevel@tonic-gate (void) fprintf(stderr, 27610Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file, 27621618Srie _cache->c_name, EC_XWORD(move->m_info)); 27631618Srie 27641618Srie (void) snprintf(index, MAXNDXSIZE, 27651618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 27661618Srie dbg_print(0, fmt, index, 27671618Srie EC_XWORD(move->m_poffset), 27681618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 27691618Srie move->m_stride, move->m_value, 27700Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN)); 27710Sstevel@tonic-gate continue; 27720Sstevel@tonic-gate } 27730Sstevel@tonic-gate 27741618Srie symname = relsymname(cache, _cache, strsec, 27757463SRod.Evans@Sun.COM symndx, symnum, ndx, syms, section, BUFSIZ, file); 27761618Srie sym = (Sym *)(syms + symndx); 27770Sstevel@tonic-gate 27780Sstevel@tonic-gate /* 27790Sstevel@tonic-gate * Additional sanity check. 27800Sstevel@tonic-gate */ 27811618Srie shndx = sym->st_shndx; 27820Sstevel@tonic-gate if (!((shndx == SHN_COMMON) || 27830Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) && 27841618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) { 27850Sstevel@tonic-gate (void) fprintf(stderr, 27861618Srie MSG_INTL(MSG_ERR_BADSYM2), file, 27876206Sab196087 _cache->c_name, EC_WORD(symndx), 27886206Sab196087 demangle(symname, flags)); 27890Sstevel@tonic-gate } 27900Sstevel@tonic-gate 27911618Srie (void) snprintf(index, MAXNDXSIZE, 27921618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 27931618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset), 27941618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 27951618Srie move->m_stride, move->m_value, 27961618Srie demangle(symname, flags)); 27970Sstevel@tonic-gate } 27980Sstevel@tonic-gate } 27990Sstevel@tonic-gate } 28000Sstevel@tonic-gate 28010Sstevel@tonic-gate /* 28026635Sab196087 * Callback function for use with conv_str_to_c_literal() below. 28036635Sab196087 */ 28046635Sab196087 /*ARGSUSED2*/ 28056635Sab196087 static void 28066635Sab196087 c_literal_cb(const void *ptr, size_t size, void *uvalue) 28076635Sab196087 { 28086635Sab196087 (void) fwrite(ptr, size, 1, stdout); 28096635Sab196087 } 28106635Sab196087 28116635Sab196087 /* 28120Sstevel@tonic-gate * Traverse a note section analyzing each note information block. 28130Sstevel@tonic-gate * The data buffers size is used to validate references before they are made, 28140Sstevel@tonic-gate * and is decremented as each element is processed. 28150Sstevel@tonic-gate */ 28160Sstevel@tonic-gate void 28176635Sab196087 note_entry(Cache *cache, Word *data, size_t size, Ehdr *ehdr, const char *file) 28180Sstevel@tonic-gate { 28196635Sab196087 size_t bsize = size; 28206635Sab196087 int cnt = 0; 28216635Sab196087 int is_corenote; 28226635Sab196087 int do_swap; 28236635Sab196087 Conv_inv_buf_t inv_buf; 28246635Sab196087 28256635Sab196087 do_swap = _elf_sys_encoding() != ehdr->e_ident[EI_DATA]; 28261618Srie 28270Sstevel@tonic-gate /* 28280Sstevel@tonic-gate * Print out a single `note' information block. 28290Sstevel@tonic-gate */ 28300Sstevel@tonic-gate while (size > 0) { 28311618Srie size_t namesz, descsz, type, pad, noteoff; 28320Sstevel@tonic-gate 28330Sstevel@tonic-gate noteoff = bsize - size; 28340Sstevel@tonic-gate /* 28350Sstevel@tonic-gate * Make sure we can at least reference the 3 initial entries 28360Sstevel@tonic-gate * (4-byte words) of the note information block. 28370Sstevel@tonic-gate */ 28381618Srie if (size >= (sizeof (Word) * 3)) 28391618Srie size -= (sizeof (Word) * 3); 28400Sstevel@tonic-gate else { 28411618Srie (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ), 28421618Srie file, cache->c_name, EC_WORD(noteoff)); 28430Sstevel@tonic-gate return; 28440Sstevel@tonic-gate } 28450Sstevel@tonic-gate 28460Sstevel@tonic-gate /* 28470Sstevel@tonic-gate * Make sure any specified name string can be referenced. 28480Sstevel@tonic-gate */ 28490Sstevel@tonic-gate if ((namesz = *data++) != 0) { 28500Sstevel@tonic-gate if (size >= namesz) 28510Sstevel@tonic-gate size -= namesz; 28520Sstevel@tonic-gate else { 28530Sstevel@tonic-gate (void) fprintf(stderr, 28541618Srie MSG_INTL(MSG_NOTE_BADNMSZ), file, 28551618Srie cache->c_name, EC_WORD(noteoff), 28561618Srie EC_WORD(namesz)); 28570Sstevel@tonic-gate return; 28580Sstevel@tonic-gate } 28590Sstevel@tonic-gate } 28601618Srie 28610Sstevel@tonic-gate /* 28620Sstevel@tonic-gate * Make sure any specified descriptor can be referenced. 28630Sstevel@tonic-gate */ 28640Sstevel@tonic-gate if ((descsz = *data++) != 0) { 28650Sstevel@tonic-gate /* 28660Sstevel@tonic-gate * If namesz isn't a 4-byte multiple, account for any 28670Sstevel@tonic-gate * padding that must exist before the descriptor. 28680Sstevel@tonic-gate */ 28691618Srie if ((pad = (namesz & (sizeof (Word) - 1))) != 0) { 28701618Srie pad = sizeof (Word) - pad; 28710Sstevel@tonic-gate size -= pad; 28720Sstevel@tonic-gate } 28730Sstevel@tonic-gate if (size >= descsz) 28740Sstevel@tonic-gate size -= descsz; 28750Sstevel@tonic-gate else { 28760Sstevel@tonic-gate (void) fprintf(stderr, 28771618Srie MSG_INTL(MSG_NOTE_BADDESZ), file, 28781618Srie cache->c_name, EC_WORD(noteoff), 28791618Srie EC_WORD(namesz)); 28800Sstevel@tonic-gate return; 28810Sstevel@tonic-gate } 28820Sstevel@tonic-gate } 28830Sstevel@tonic-gate 28840Sstevel@tonic-gate type = *data++; 28850Sstevel@tonic-gate 28866635Sab196087 /* 28876635Sab196087 * Is this a Solaris core note? Such notes all have 28886635Sab196087 * the name "CORE". 28896635Sab196087 */ 28906635Sab196087 is_corenote = (ehdr->e_type == ET_CORE) && 28916635Sab196087 (namesz == (MSG_STR_CORE_SIZE + 1)) && 28926635Sab196087 (strncmp(MSG_ORIG(MSG_STR_CORE), (char *)data, 28936635Sab196087 MSG_STR_CORE_SIZE + 1) == 0); 28946635Sab196087 28951618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 28966635Sab196087 dbg_print(0, MSG_INTL(MSG_FMT_NOTEENTNDX), EC_WORD(cnt)); 28976635Sab196087 cnt++; 28981618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz)); 28996635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz)); 29006635Sab196087 29016635Sab196087 if (is_corenote) 29026635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE_STR), 29036635Sab196087 conv_cnote_type(type, 0, &inv_buf)); 29046635Sab196087 else 29056635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type)); 29060Sstevel@tonic-gate if (namesz) { 29070Sstevel@tonic-gate char *name = (char *)data; 29080Sstevel@tonic-gate 29096635Sab196087 29106635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_NAME)); 29110Sstevel@tonic-gate /* 29126635Sab196087 * The name string can contain embedded 'null' 29136635Sab196087 * bytes and/or unprintable characters. Also, 29146635Sab196087 * the final NULL is documented in the ELF ABI 29156635Sab196087 * as being included in the namesz. So, display 29166635Sab196087 * the name using C literal string notation, and 29176635Sab196087 * include the terminating NULL in the output. 29186635Sab196087 * We don't show surrounding double quotes, as 29196635Sab196087 * that implies the termination that we are showing 29206635Sab196087 * explicitly. 29210Sstevel@tonic-gate */ 29226635Sab196087 (void) fwrite(MSG_ORIG(MSG_STR_8SP), 29236635Sab196087 MSG_STR_8SP_SIZE, 1, stdout); 29246635Sab196087 conv_str_to_c_literal(name, namesz, c_literal_cb, NULL); 29250Sstevel@tonic-gate name = name + ((namesz + (sizeof (Word) - 1)) & 29260Sstevel@tonic-gate ~(sizeof (Word) - 1)); 29270Sstevel@tonic-gate /* LINTED */ 29280Sstevel@tonic-gate data = (Word *)name; 29291618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 29300Sstevel@tonic-gate } 29310Sstevel@tonic-gate 29320Sstevel@tonic-gate /* 29330Sstevel@tonic-gate * If multiple information blocks exist within a .note section 29340Sstevel@tonic-gate * account for any padding that must exist before the next 29350Sstevel@tonic-gate * information block. 29360Sstevel@tonic-gate */ 29371618Srie if ((pad = (descsz & (sizeof (Word) - 1))) != 0) { 29381618Srie pad = sizeof (Word) - pad; 29390Sstevel@tonic-gate if (size > pad) 29400Sstevel@tonic-gate size -= pad; 29410Sstevel@tonic-gate } 29420Sstevel@tonic-gate 29430Sstevel@tonic-gate if (descsz) { 29446635Sab196087 int hexdump = 1; 29456635Sab196087 const char *desc = (const char *)data; 29460Sstevel@tonic-gate 29470Sstevel@tonic-gate /* 29486635Sab196087 * If this is a core note, let the corenote() 29496635Sab196087 * function handle it. 29500Sstevel@tonic-gate */ 29516635Sab196087 if (is_corenote) { 29526635Sab196087 /* We only issue the bad arch error once */ 29536635Sab196087 static int badnote_done = 0; 29546635Sab196087 corenote_ret_t corenote_ret; 29556635Sab196087 29566635Sab196087 corenote_ret = corenote(ehdr->e_machine, 29576635Sab196087 do_swap, type, desc, descsz); 29586635Sab196087 switch (corenote_ret) { 29596635Sab196087 case CORENOTE_R_OK: 29606635Sab196087 hexdump = 0; 29616635Sab196087 break; 29626635Sab196087 case CORENOTE_R_BADDATA: 29636635Sab196087 (void) fprintf(stderr, 29646635Sab196087 MSG_INTL(MSG_NOTE_BADCOREDATA), 29656635Sab196087 file); 29666635Sab196087 break; 29676635Sab196087 case CORENOTE_R_BADARCH: 29686635Sab196087 if (badnote_done) 29696635Sab196087 break; 29706635Sab196087 (void) fprintf(stderr, 29716635Sab196087 MSG_INTL(MSG_NOTE_BADCOREARCH), 29726635Sab196087 file, 29736635Sab196087 conv_ehdr_mach(ehdr->e_machine, 29746635Sab196087 0, &inv_buf)); 29756635Sab196087 break; 29760Sstevel@tonic-gate } 29770Sstevel@tonic-gate } 29786635Sab196087 29796635Sab196087 /* 29806635Sab196087 * The default thing when we don't understand 29816635Sab196087 * the note data is to display it as hex bytes. 29826635Sab196087 */ 29836635Sab196087 if (hexdump) { 29846635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESC)); 29856635Sab196087 dump_hex_bytes(desc, descsz, 8, 4, 4); 29860Sstevel@tonic-gate } 29876635Sab196087 desc += descsz + pad; 29886635Sab196087 29890Sstevel@tonic-gate /* LINTED */ 29900Sstevel@tonic-gate data = (Word *)desc; 29910Sstevel@tonic-gate } 29920Sstevel@tonic-gate } 29930Sstevel@tonic-gate } 29940Sstevel@tonic-gate 29950Sstevel@tonic-gate /* 29966635Sab196087 * Search for and process .note sections. 29976635Sab196087 * 29986635Sab196087 * Returns the number of note sections seen. 29990Sstevel@tonic-gate */ 30006635Sab196087 static Word 30016635Sab196087 note(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 30020Sstevel@tonic-gate { 30036635Sab196087 Word cnt, note_cnt = 0; 30040Sstevel@tonic-gate 30050Sstevel@tonic-gate /* 30060Sstevel@tonic-gate * Otherwise look for any .note sections. 30070Sstevel@tonic-gate */ 30080Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 30091618Srie Cache *_cache = &cache[cnt]; 30101618Srie Shdr *shdr = _cache->c_shdr; 30110Sstevel@tonic-gate 30120Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE) 30130Sstevel@tonic-gate continue; 30146635Sab196087 note_cnt++; 30155411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 30160Sstevel@tonic-gate continue; 30170Sstevel@tonic-gate 30180Sstevel@tonic-gate /* 30190Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're 30205230Sab196087 * properly aligned before proceeding, and issue an error 30215230Sab196087 * as necessary. 30225230Sab196087 * 30235230Sab196087 * Note that we will continue on to display the note even 30245230Sab196087 * if it has bad alignment. We can do this safely, because 30255230Sab196087 * libelf knows the alignment required for SHT_NOTE, and 30265230Sab196087 * takes steps to deliver a properly aligned buffer to us 30275230Sab196087 * even if the actual file is misaligned. 30280Sstevel@tonic-gate */ 30295230Sab196087 if (shdr->sh_offset & (sizeof (Word) - 1)) 30300Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 30310Sstevel@tonic-gate file, _cache->c_name); 30325230Sab196087 30333466Srie if (_cache->c_data == NULL) 30343466Srie continue; 30350Sstevel@tonic-gate 30361618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 30371618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 30380Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf, 30390Sstevel@tonic-gate /* LINTED */ 30406635Sab196087 (Word)_cache->c_data->d_size, ehdr, file); 30410Sstevel@tonic-gate } 30426635Sab196087 30436635Sab196087 return (note_cnt); 30440Sstevel@tonic-gate } 30450Sstevel@tonic-gate 30461618Srie /* 30471618Srie * Determine an individual hash entry. This may be the initial hash entry, 30481618Srie * or an associated chain entry. 30491618Srie */ 30501618Srie static void 30511618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx, 30521618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts, 30531618Srie uint_t flags, int chain) 30541618Srie { 30551618Srie Sym *sym; 30561618Srie const char *symname, *str; 30571618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE]; 30581618Srie ulong_t nbkt, nhash; 30591618Srie 30601618Srie if (symndx > symn) { 30611618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file, 30621618Srie EC_WORD(symndx), EC_WORD(hashndx)); 30631618Srie symname = MSG_INTL(MSG_STR_UNKNOWN); 30641618Srie } else { 30651618Srie sym = (Sym *)(syms + symndx); 30661618Srie symname = string(refsec, symndx, strsec, file, sym->st_name); 30671618Srie } 30681618Srie 30691618Srie if (chain == 0) { 30701618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 30711618Srie hashndx); 30721618Srie str = (const char *)_bucket; 30731618Srie } else 30741618Srie str = MSG_ORIG(MSG_STR_EMPTY); 30751618Srie 30761618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2), 30771618Srie EC_WORD(symndx)); 30781618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx, 30791618Srie demangle(symname, flags)); 30801618Srie 30811618Srie /* 30821618Srie * Determine if this string is in the correct bucket. 30831618Srie */ 30841618Srie nhash = elf_hash(symname); 30851618Srie nbkt = nhash % bkts; 30861618Srie 30871618Srie if (nbkt != hashndx) { 30881618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file, 30891618Srie hsecname, symname, EC_WORD(hashndx), nbkt); 30901618Srie } 30911618Srie } 30920Sstevel@tonic-gate 30930Sstevel@tonic-gate #define MAXCOUNT 500 30940Sstevel@tonic-gate 30950Sstevel@tonic-gate static void 30964168Sab196087 hash(Cache *cache, Word shnum, const char *file, uint_t flags) 30970Sstevel@tonic-gate { 30980Sstevel@tonic-gate static int count[MAXCOUNT]; 30991618Srie Word cnt; 31000Sstevel@tonic-gate ulong_t ndx, bkts; 31010Sstevel@tonic-gate char number[MAXNDXSIZE]; 31020Sstevel@tonic-gate 31030Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 31040Sstevel@tonic-gate uint_t *hash, *chain; 31050Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 31061618Srie Shdr *sshdr, *hshdr = _cache->c_shdr; 31071618Srie char *ssecname, *hsecname = _cache->c_name; 31081618Srie Sym *syms; 31091618Srie Word symn; 31100Sstevel@tonic-gate 31111618Srie if (hshdr->sh_type != SHT_HASH) 31120Sstevel@tonic-gate continue; 31130Sstevel@tonic-gate 31140Sstevel@tonic-gate /* 31150Sstevel@tonic-gate * Determine the hash table data and size. 31160Sstevel@tonic-gate */ 31171618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) { 31180Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 31191618Srie file, hsecname); 31200Sstevel@tonic-gate continue; 31210Sstevel@tonic-gate } 31223466Srie if (_cache->c_data == NULL) 31233466Srie continue; 31243466Srie 31250Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf; 31260Sstevel@tonic-gate bkts = *hash; 31270Sstevel@tonic-gate chain = hash + 2 + bkts; 31280Sstevel@tonic-gate hash += 2; 31290Sstevel@tonic-gate 31300Sstevel@tonic-gate /* 31310Sstevel@tonic-gate * Get the data buffer for the associated symbol table. 31320Sstevel@tonic-gate */ 31331618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) { 31340Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 31351618Srie file, hsecname, EC_WORD(hshdr->sh_link)); 31360Sstevel@tonic-gate continue; 31370Sstevel@tonic-gate } 31381618Srie 31391618Srie _cache = &cache[hshdr->sh_link]; 31401618Srie ssecname = _cache->c_name; 31411618Srie 31423466Srie if (_cache->c_data == NULL) 31433466Srie continue; 31443466Srie 31453466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) { 31460Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 31471618Srie file, ssecname); 31480Sstevel@tonic-gate continue; 31490Sstevel@tonic-gate } 31500Sstevel@tonic-gate 31511618Srie sshdr = _cache->c_shdr; 31521618Srie /* LINTED */ 31531618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize); 31541618Srie 31550Sstevel@tonic-gate /* 31560Sstevel@tonic-gate * Get the associated string table section. 31570Sstevel@tonic-gate */ 31581618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) { 31590Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 31601618Srie file, ssecname, EC_WORD(sshdr->sh_link)); 31610Sstevel@tonic-gate continue; 31620Sstevel@tonic-gate } 31630Sstevel@tonic-gate 31641618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 31651618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname); 31661618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO)); 31670Sstevel@tonic-gate 31680Sstevel@tonic-gate /* 31690Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate 31700Sstevel@tonic-gate * symbols. 31710Sstevel@tonic-gate */ 31720Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) { 31731618Srie Word _ndx, _cnt; 31740Sstevel@tonic-gate 31750Sstevel@tonic-gate if (*hash == 0) { 31760Sstevel@tonic-gate count[0]++; 31770Sstevel@tonic-gate continue; 31780Sstevel@tonic-gate } 31790Sstevel@tonic-gate 31801618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname, 31811618Srie ndx, *hash, symn, syms, file, bkts, flags, 0); 31820Sstevel@tonic-gate 31830Sstevel@tonic-gate /* 31840Sstevel@tonic-gate * Determine if any other symbols are chained to this 31850Sstevel@tonic-gate * bucket. 31860Sstevel@tonic-gate */ 31870Sstevel@tonic-gate _ndx = chain[*hash]; 31880Sstevel@tonic-gate _cnt = 1; 31890Sstevel@tonic-gate while (_ndx) { 31901618Srie hash_entry(_cache, &cache[sshdr->sh_link], 31911618Srie hsecname, ndx, _ndx, symn, syms, file, 31921618Srie bkts, flags, 1); 31930Sstevel@tonic-gate _ndx = chain[_ndx]; 31940Sstevel@tonic-gate _cnt++; 31950Sstevel@tonic-gate } 31960Sstevel@tonic-gate 31970Sstevel@tonic-gate if (_cnt >= MAXCOUNT) { 31980Sstevel@tonic-gate (void) fprintf(stderr, 31991324Srie MSG_INTL(MSG_HASH_OVERFLW), file, 32001618Srie _cache->c_name, EC_WORD(ndx), 32011618Srie EC_WORD(_cnt)); 32020Sstevel@tonic-gate } else 32030Sstevel@tonic-gate count[_cnt]++; 32040Sstevel@tonic-gate } 32050Sstevel@tonic-gate break; 32060Sstevel@tonic-gate } 32070Sstevel@tonic-gate 32080Sstevel@tonic-gate /* 32090Sstevel@tonic-gate * Print out the count information. 32100Sstevel@tonic-gate */ 32110Sstevel@tonic-gate bkts = cnt = 0; 32121618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 32131618Srie 32140Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) { 32151618Srie Word _cnt; 32160Sstevel@tonic-gate 32170Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0) 32180Sstevel@tonic-gate continue; 32190Sstevel@tonic-gate 32201618Srie (void) snprintf(number, MAXNDXSIZE, 32211618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt); 32221618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number, 32231618Srie EC_WORD(ndx)); 32240Sstevel@tonic-gate bkts += _cnt; 32251618Srie cnt += (Word)(ndx * _cnt); 32260Sstevel@tonic-gate } 32270Sstevel@tonic-gate if (cnt) { 32280Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 32291618Srie bkts); 32301618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number, 32311618Srie EC_WORD(cnt)); 32320Sstevel@tonic-gate } 32330Sstevel@tonic-gate } 32340Sstevel@tonic-gate 32350Sstevel@tonic-gate static void 32364168Sab196087 group(Cache *cache, Word shnum, const char *file, uint_t flags) 32370Sstevel@tonic-gate { 32381618Srie Word scnt; 32390Sstevel@tonic-gate 32401618Srie for (scnt = 1; scnt < shnum; scnt++) { 32411618Srie Cache *_cache = &cache[scnt]; 32421618Srie Shdr *shdr = _cache->c_shdr; 32431618Srie Word *grpdata, gcnt, grpcnt, symnum, unknown; 32441618Srie Cache *symsec, *strsec; 32451618Srie Sym *syms, *sym; 32461618Srie char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 32470Sstevel@tonic-gate 32480Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP) 32490Sstevel@tonic-gate continue; 32505411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, scnt, shdr->sh_type)) 32510Sstevel@tonic-gate continue; 32523466Srie if ((_cache->c_data == NULL) || 32533466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL)) 32540Sstevel@tonic-gate continue; 32551618Srie grpcnt = shdr->sh_size / sizeof (Word); 32561618Srie 32571618Srie /* 32581618Srie * Get the data buffer for the associated symbol table and 32591618Srie * string table. 32601618Srie */ 32611618Srie if (stringtbl(cache, 1, scnt, shnum, file, 32621618Srie &symnum, &symsec, &strsec) == 0) 32631618Srie return; 32641618Srie 32651618Srie syms = symsec->c_data->d_buf; 32661618Srie 32671618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 32681618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name); 32691618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE)); 32701618Srie 32711618Srie /* 32721618Srie * The first element of the group defines the group. The 32731618Srie * associated symbol is defined by the sh_link field. 32741618Srie */ 32751618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) { 32761618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 32771618Srie file, _cache->c_name, EC_WORD(shdr->sh_info)); 32781618Srie return; 32790Sstevel@tonic-gate } 32800Sstevel@tonic-gate 32811618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT)); 32821618Srie if (grpdata[0] & GRP_COMDAT) { 32831618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT)); 32840Sstevel@tonic-gate } 32851618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) { 32861618Srie size_t len = strlen(flgstrbuf); 32871618Srie 32881618Srie (void) snprintf(&flgstrbuf[len], 32891618Srie (MSG_GRP_COMDAT_SIZE + 10 - len), 32901618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown); 32910Sstevel@tonic-gate } 32921618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT)); 32931618Srie sym = (Sym *)(syms + shdr->sh_info); 32940Sstevel@tonic-gate 32951618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf, 32961618Srie demangle(string(_cache, 0, strsec, file, sym->st_name), 32971618Srie flags)); 32981618Srie 32991618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) { 33000Sstevel@tonic-gate char index[MAXNDXSIZE]; 33011618Srie const char *name; 33020Sstevel@tonic-gate 33030Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, 33041618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt)); 33051618Srie 33061618Srie if (grpdata[gcnt] >= shnum) 33071618Srie name = MSG_INTL(MSG_GRP_INVALSCN); 33081618Srie else 33091618Srie name = cache[grpdata[gcnt]].c_name; 33101618Srie 33111618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name, 33124433Sab196087 EC_XWORD(grpdata[gcnt])); 33130Sstevel@tonic-gate } 33140Sstevel@tonic-gate } 33150Sstevel@tonic-gate } 33160Sstevel@tonic-gate 33170Sstevel@tonic-gate static void 33187463SRod.Evans@Sun.COM got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 33190Sstevel@tonic-gate { 33205230Sab196087 Cache *gotcache = NULL, *symtab = NULL; 33211618Srie Addr gotbgn, gotend; 33221618Srie Shdr *gotshdr; 33231618Srie Word cnt, gotents, gotndx; 33240Sstevel@tonic-gate size_t gentsize; 33250Sstevel@tonic-gate Got_info *gottable; 33260Sstevel@tonic-gate char *gotdata; 33271618Srie Sym *gotsym; 33281618Srie Xword gotsymaddr; 33296206Sab196087 uint_t sys_encoding; 33300Sstevel@tonic-gate 33310Sstevel@tonic-gate /* 33321324Srie * First, find the got. 33330Sstevel@tonic-gate */ 33340Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 33355230Sab196087 if (strncmp(cache[cnt].c_name, MSG_ORIG(MSG_ELF_GOT), 33361324Srie MSG_ELF_GOT_SIZE) == 0) { 33375230Sab196087 gotcache = &cache[cnt]; 33380Sstevel@tonic-gate break; 33390Sstevel@tonic-gate } 33400Sstevel@tonic-gate } 33415230Sab196087 if (gotcache == NULL) 33420Sstevel@tonic-gate return; 33431324Srie 33441324Srie /* 33451324Srie * A got section within a relocatable object is suspicious. 33461324Srie */ 33471324Srie if (ehdr->e_type == ET_REL) { 33481324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file, 33495230Sab196087 gotcache->c_name); 33501324Srie } 33511324Srie 33521618Srie gotshdr = gotcache->c_shdr; 33530Sstevel@tonic-gate if (gotshdr->sh_size == 0) { 33540Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 33550Sstevel@tonic-gate file, gotcache->c_name); 33560Sstevel@tonic-gate return; 33570Sstevel@tonic-gate } 33581618Srie 33591618Srie gotbgn = gotshdr->sh_addr; 33600Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size; 33610Sstevel@tonic-gate 33620Sstevel@tonic-gate /* 33631618Srie * Some architectures don't properly set the sh_entsize for the GOT 33641618Srie * table. If it's not set, default to a size of a pointer. 33650Sstevel@tonic-gate */ 33661618Srie if ((gentsize = gotshdr->sh_entsize) == 0) 33671618Srie gentsize = sizeof (Xword); 33681618Srie 33693466Srie if (gotcache->c_data == NULL) 33703466Srie return; 33713466Srie 33720Sstevel@tonic-gate /* LINTED */ 33731618Srie gotents = (Word)(gotshdr->sh_size / gentsize); 33740Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf; 33750Sstevel@tonic-gate 33760Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 33770Sstevel@tonic-gate int err = errno; 33781618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file, 33791618Srie strerror(err)); 33800Sstevel@tonic-gate return; 33810Sstevel@tonic-gate } 33820Sstevel@tonic-gate 33830Sstevel@tonic-gate /* 33840Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations 33850Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a 33860Sstevel@tonic-gate * .rel[a].got section we check them all. 33870Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab 33880Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 33890Sstevel@tonic-gate */ 33900Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 33911618Srie Word type, symnum; 33921618Srie Xword relndx, relnum, relsize; 33931618Srie void *rels; 33941618Srie Sym *syms; 33951618Srie Cache *symsec, *strsec; 33961618Srie Cache *_cache = &cache[cnt]; 33971618Srie Shdr *shdr; 33980Sstevel@tonic-gate 33991618Srie shdr = _cache->c_shdr; 34001618Srie type = shdr->sh_type; 34010Sstevel@tonic-gate 34021618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) { 34030Sstevel@tonic-gate symtab = _cache; 34040Sstevel@tonic-gate continue; 34050Sstevel@tonic-gate } 34061618Srie if (type == SHT_SYMTAB) { 34070Sstevel@tonic-gate symtab = _cache; 34080Sstevel@tonic-gate continue; 34090Sstevel@tonic-gate } 34101618Srie if ((type != SHT_RELA) && (type != SHT_REL)) 34110Sstevel@tonic-gate continue; 34120Sstevel@tonic-gate 34130Sstevel@tonic-gate /* 34141618Srie * Decide entry size. 34150Sstevel@tonic-gate */ 34161618Srie if (((relsize = shdr->sh_entsize) == 0) || 34171618Srie (relsize > shdr->sh_size)) { 34181618Srie if (type == SHT_RELA) 34191618Srie relsize = sizeof (Rela); 34201618Srie else 34211618Srie relsize = sizeof (Rel); 34220Sstevel@tonic-gate } 34230Sstevel@tonic-gate 34240Sstevel@tonic-gate /* 34251618Srie * Determine the number of relocations available. 34260Sstevel@tonic-gate */ 34271618Srie if (shdr->sh_size == 0) { 34281618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 34291618Srie file, _cache->c_name); 34300Sstevel@tonic-gate continue; 34310Sstevel@tonic-gate } 34323466Srie if (_cache->c_data == NULL) 34333466Srie continue; 34343466Srie 34351618Srie rels = _cache->c_data->d_buf; 34361618Srie relnum = shdr->sh_size / relsize; 34370Sstevel@tonic-gate 34381618Srie /* 34391618Srie * Get the data buffer for the associated symbol table and 34401618Srie * string table. 34411618Srie */ 34421618Srie if (stringtbl(cache, 1, cnt, shnum, file, 34431618Srie &symnum, &symsec, &strsec) == 0) 34441618Srie continue; 34451618Srie 34461618Srie syms = symsec->c_data->d_buf; 34471618Srie 34481618Srie /* 34491618Srie * Loop through the relocation entries. 34501618Srie */ 34511618Srie for (relndx = 0; relndx < relnum; relndx++, 34521618Srie rels = (void *)((char *)rels + relsize)) { 34531618Srie char section[BUFSIZ]; 34541618Srie Addr offset; 34550Sstevel@tonic-gate Got_info *gip; 34561618Srie Word symndx, reltype; 34571618Srie Rela *rela; 34581618Srie Rel *rel; 34590Sstevel@tonic-gate 34601618Srie /* 34611618Srie * Unravel the relocation. 34621618Srie */ 34631618Srie if (type == SHT_RELA) { 34641618Srie rela = (Rela *)rels; 34651618Srie symndx = ELF_R_SYM(rela->r_info); 34666206Sab196087 reltype = ELF_R_TYPE(rela->r_info, 34676206Sab196087 ehdr->e_machine); 34681618Srie offset = rela->r_offset; 34690Sstevel@tonic-gate } else { 34701618Srie rel = (Rel *)rels; 34711618Srie symndx = ELF_R_SYM(rel->r_info); 34726206Sab196087 reltype = ELF_R_TYPE(rel->r_info, 34736206Sab196087 ehdr->e_machine); 34741618Srie offset = rel->r_offset; 34750Sstevel@tonic-gate } 34760Sstevel@tonic-gate 34770Sstevel@tonic-gate /* 34780Sstevel@tonic-gate * Only pay attention to relocations against the GOT. 34790Sstevel@tonic-gate */ 34804146Sab196087 if ((offset < gotbgn) || (offset >= gotend)) 34810Sstevel@tonic-gate continue; 34820Sstevel@tonic-gate 34830Sstevel@tonic-gate /* LINTED */ 34841618Srie gotndx = (Word)((offset - gotbgn) / 34850Sstevel@tonic-gate gotshdr->sh_entsize); 34860Sstevel@tonic-gate gip = &gottable[gotndx]; 34871618Srie 34881618Srie if (gip->g_reltype != 0) { 34890Sstevel@tonic-gate (void) fprintf(stderr, 34900Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file, 34911618Srie EC_WORD(gotndx), EC_ADDR(offset)); 34920Sstevel@tonic-gate continue; 34930Sstevel@tonic-gate } 34940Sstevel@tonic-gate 34951618Srie if (symndx) 34961618Srie gip->g_symname = relsymname(cache, _cache, 34971618Srie strsec, symndx, symnum, relndx, syms, 34987463SRod.Evans@Sun.COM section, BUFSIZ, file); 34991618Srie gip->g_reltype = reltype; 35001618Srie gip->g_rel = rels; 35010Sstevel@tonic-gate } 35020Sstevel@tonic-gate } 35030Sstevel@tonic-gate 35046299Sab196087 if (symlookup(MSG_ORIG(MSG_SYM_GOT), cache, shnum, &gotsym, symtab, 35051618Srie file)) 35061618Srie gotsymaddr = gotsym->st_value; 35070Sstevel@tonic-gate else 35081618Srie gotsymaddr = gotbgn; 35090Sstevel@tonic-gate 35101618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 35111618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name); 35121618Srie Elf_got_title(0); 35130Sstevel@tonic-gate 35146206Sab196087 sys_encoding = _elf_sys_encoding(); 35150Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) { 35160Sstevel@tonic-gate Got_info *gip; 35170Sstevel@tonic-gate Sword gindex; 35181618Srie Addr gaddr; 35191618Srie Xword gotentry; 35200Sstevel@tonic-gate 35210Sstevel@tonic-gate gip = &gottable[gotndx]; 35220Sstevel@tonic-gate 35230Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize); 35241618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize; 35250Sstevel@tonic-gate 35261618Srie if (gentsize == sizeof (Word)) 35270Sstevel@tonic-gate /* LINTED */ 35281618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx)); 35290Sstevel@tonic-gate else 35300Sstevel@tonic-gate /* LINTED */ 35311618Srie gotentry = *((Xword *)(gotdata) + gotndx); 35320Sstevel@tonic-gate 35331618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine, 35346206Sab196087 ehdr->e_ident[EI_DATA], sys_encoding, 35351618Srie gip->g_reltype, gip->g_rel, gip->g_symname); 35360Sstevel@tonic-gate } 35370Sstevel@tonic-gate free(gottable); 35380Sstevel@tonic-gate } 35390Sstevel@tonic-gate 35400Sstevel@tonic-gate void 35410Sstevel@tonic-gate checksum(Elf *elf) 35420Sstevel@tonic-gate { 35431618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 35441618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf)); 35450Sstevel@tonic-gate } 35460Sstevel@tonic-gate 35474242Sab196087 /* 35484242Sab196087 * This variable is used by regular() to communicate the address of 35494242Sab196087 * the section header cache to sort_shdr_ndx_arr(). Unfortunately, 35504242Sab196087 * the qsort() interface does not include a userdata argument by which 35514242Sab196087 * such arbitrary data can be passed, so we are stuck using global data. 35524242Sab196087 */ 35534242Sab196087 static Cache *sort_shdr_ndx_arr_cache; 35544242Sab196087 35554242Sab196087 35564242Sab196087 /* 35574242Sab196087 * Used with qsort() to sort the section indices so that they can be 35584242Sab196087 * used to access the section headers in order of increasing data offset. 35594242Sab196087 * 35604242Sab196087 * entry: 35614242Sab196087 * sort_shdr_ndx_arr_cache - Contains address of 35624242Sab196087 * section header cache. 35634242Sab196087 * v1, v2 - Point at elements of sort_shdr_bits array to be compared. 35644242Sab196087 * 35654242Sab196087 * exit: 35664242Sab196087 * Returns -1 (less than), 0 (equal) or 1 (greater than). 35674242Sab196087 */ 35684242Sab196087 static int 35694242Sab196087 sort_shdr_ndx_arr(const void *v1, const void *v2) 35704242Sab196087 { 35714242Sab196087 Cache *cache1 = sort_shdr_ndx_arr_cache + *((size_t *)v1); 35724242Sab196087 Cache *cache2 = sort_shdr_ndx_arr_cache + *((size_t *)v2); 35734242Sab196087 35744242Sab196087 if (cache1->c_shdr->sh_offset < cache2->c_shdr->sh_offset) 35754242Sab196087 return (-1); 35764242Sab196087 35774242Sab196087 if (cache1->c_shdr->sh_offset > cache2->c_shdr->sh_offset) 35784242Sab196087 return (1); 35794242Sab196087 35804242Sab196087 return (0); 35814242Sab196087 } 35824242Sab196087 35834242Sab196087 35844665Sab196087 static int 35854665Sab196087 shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, 35867463SRod.Evans@Sun.COM size_t shnum, Cache **cache_ret, Word flags) 35870Sstevel@tonic-gate { 35880Sstevel@tonic-gate Elf_Scn *scn; 35890Sstevel@tonic-gate Elf_Data *data; 35904665Sab196087 size_t ndx; 35914665Sab196087 Shdr *nameshdr; 35920Sstevel@tonic-gate char *names = 0; 35930Sstevel@tonic-gate Cache *cache, *_cache; 35944242Sab196087 size_t *shdr_ndx_arr, shdr_ndx_arr_cnt; 35950Sstevel@tonic-gate 35960Sstevel@tonic-gate 35970Sstevel@tonic-gate /* 35980Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section 35990Sstevel@tonic-gate * name strings. 36000Sstevel@tonic-gate */ 36014156Sab196087 if (shstrndx == SHN_UNDEF) { 36024156Sab196087 /* 36034156Sab196087 * It is rare, but legal, for an object to lack a 36044156Sab196087 * header string table section. 36054156Sab196087 */ 36064156Sab196087 names = NULL; 36074156Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHSTRSEC), file); 36084156Sab196087 } else if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 36090Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 36100Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 36110Sstevel@tonic-gate EC_XWORD(shstrndx)); 36121618Srie 36130Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) { 36140Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 36150Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 36160Sstevel@tonic-gate EC_XWORD(shstrndx)); 36171618Srie 36181618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) { 36190Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 36200Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 36213862Srie EC_WORD(elf_ndxscn(scn))); 36221618Srie 36231618Srie } else if ((names = data->d_buf) == 0) 36240Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 36250Sstevel@tonic-gate 36260Sstevel@tonic-gate /* 36273862Srie * Allocate a cache to maintain a descriptor for each section. 36280Sstevel@tonic-gate */ 36294665Sab196087 if ((*cache_ret = cache = malloc(shnum * sizeof (Cache))) == NULL) { 36300Sstevel@tonic-gate int err = errno; 36310Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 36320Sstevel@tonic-gate file, strerror(err)); 36334665Sab196087 return (0); 36340Sstevel@tonic-gate } 36350Sstevel@tonic-gate 36361618Srie *cache = cache_init; 36370Sstevel@tonic-gate _cache = cache; 36380Sstevel@tonic-gate _cache++; 36390Sstevel@tonic-gate 36403862Srie /* 36414242Sab196087 * Allocate an array that will hold the section index for 36424242Sab196087 * each section that has data in the ELF file: 36434242Sab196087 * 36444242Sab196087 * - Is not a NOBITS section 36454242Sab196087 * - Data has non-zero length 36464242Sab196087 * 36474242Sab196087 * Note that shnum is an upper bound on the size required. It 36484242Sab196087 * is likely that we won't use a few of these array elements. 36494242Sab196087 * Allocating a modest amount of extra memory in this case means 36504242Sab196087 * that we can avoid an extra loop to count the number of needed 36514242Sab196087 * items, and can fill this array immediately in the first loop 36524242Sab196087 * below. 36534242Sab196087 */ 36544242Sab196087 if ((shdr_ndx_arr = malloc(shnum * sizeof (*shdr_ndx_arr))) == NULL) { 36554242Sab196087 int err = errno; 36564242Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 36574242Sab196087 file, strerror(err)); 36584665Sab196087 return (0); 36594242Sab196087 } 36604242Sab196087 shdr_ndx_arr_cnt = 0; 36614242Sab196087 36624242Sab196087 /* 36633862Srie * Traverse the sections of the file. This gathering of data is 36643862Srie * carried out in two passes. First, the section headers are captured 36653862Srie * and the section header names are evaluated. A verification pass is 36663862Srie * then carried out over the section information. Files have been 36673862Srie * known to exhibit overlapping (and hence erroneous) section header 36683862Srie * information. 36693862Srie * 36703862Srie * Finally, the data for each section is obtained. This processing is 36713862Srie * carried out after section verification because should any section 36723862Srie * header overlap occur, and a file needs translating (ie. xlate'ing 36733862Srie * information from a non-native architecture file), then the process 36743862Srie * of translation can corrupt the section header information. Of 36753862Srie * course, if there is any section overlap, the data related to the 36763862Srie * sections is going to be compromised. However, it is the translation 36773862Srie * of this data that has caused problems with elfdump()'s ability to 36783862Srie * extract the data. 36793862Srie */ 36804242Sab196087 for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn); 36814242Sab196087 ndx++, _cache++) { 36823862Srie char scnndxnm[100]; 36833862Srie 36844242Sab196087 _cache->c_ndx = ndx; 36853862Srie _cache->c_scn = scn; 36863862Srie 36871618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) { 36880Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 36890Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 36903862Srie EC_WORD(elf_ndxscn(scn))); 36910Sstevel@tonic-gate } 36920Sstevel@tonic-gate 36933862Srie /* 36944242Sab196087 * If this section has data in the file, include it in 36954242Sab196087 * the array of sections to check for address overlap. 36964242Sab196087 */ 36974242Sab196087 if ((_cache->c_shdr->sh_size != 0) && 36984242Sab196087 (_cache->c_shdr->sh_type != SHT_NOBITS)) 36994242Sab196087 shdr_ndx_arr[shdr_ndx_arr_cnt++] = ndx; 37004242Sab196087 37014242Sab196087 /* 37023862Srie * If a shstrtab exists, assign the section name. 37033862Srie */ 37043862Srie if (names && _cache->c_shdr) { 37053862Srie if (_cache->c_shdr->sh_name && 37063862Srie /* LINTED */ 37073862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) { 37087463SRod.Evans@Sun.COM const char *symname; 37097463SRod.Evans@Sun.COM char *secname; 37107463SRod.Evans@Sun.COM 37117463SRod.Evans@Sun.COM secname = names + _cache->c_shdr->sh_name; 37127463SRod.Evans@Sun.COM 37137463SRod.Evans@Sun.COM /* 37147463SRod.Evans@Sun.COM * A SUN naming convention employs a "%" within 37157463SRod.Evans@Sun.COM * a section name to indicate a section/symbol 37167463SRod.Evans@Sun.COM * name. This originated from the compilers 37177463SRod.Evans@Sun.COM * -xF option, that places functions into their 37187463SRod.Evans@Sun.COM * own sections. This convention (which has no 37197463SRod.Evans@Sun.COM * formal standard) has also been followed for 37207463SRod.Evans@Sun.COM * COMDAT sections. To demangle the symbol 37217463SRod.Evans@Sun.COM * name, the name must be separated from the 37227463SRod.Evans@Sun.COM * section name. 37237463SRod.Evans@Sun.COM */ 37247463SRod.Evans@Sun.COM if (((flags & FLG_CTL_DEMANGLE) == 0) || 37257463SRod.Evans@Sun.COM ((symname = strchr(secname, '%')) == NULL)) 37267463SRod.Evans@Sun.COM _cache->c_name = secname; 37277463SRod.Evans@Sun.COM else { 37287463SRod.Evans@Sun.COM size_t secsz = ++symname - secname; 37297463SRod.Evans@Sun.COM size_t strsz; 37307463SRod.Evans@Sun.COM 37317463SRod.Evans@Sun.COM symname = demangle(symname, flags); 37327463SRod.Evans@Sun.COM strsz = secsz + strlen(symname) + 1; 37337463SRod.Evans@Sun.COM 37347463SRod.Evans@Sun.COM if ((_cache->c_name = 37357463SRod.Evans@Sun.COM malloc(strsz)) == NULL) { 37367463SRod.Evans@Sun.COM int err = errno; 37377463SRod.Evans@Sun.COM (void) fprintf(stderr, 37387463SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_MALLOC), 37397463SRod.Evans@Sun.COM file, strerror(err)); 37407463SRod.Evans@Sun.COM return (0); 37417463SRod.Evans@Sun.COM } 37427463SRod.Evans@Sun.COM (void) snprintf(_cache->c_name, strsz, 37437463SRod.Evans@Sun.COM MSG_ORIG(MSG_FMT_SECSYM), 37447463SRod.Evans@Sun.COM EC_WORD(secsz), secname, symname); 37457463SRod.Evans@Sun.COM } 37463862Srie continue; 37473862Srie } 37480Sstevel@tonic-gate 37490Sstevel@tonic-gate /* 37503862Srie * Generate an error if the section name index is zero 37513862Srie * or exceeds the shstrtab data. Fall through to 37523862Srie * fabricate a section name. 37530Sstevel@tonic-gate */ 37543862Srie if ((_cache->c_shdr->sh_name == 0) || 37550Sstevel@tonic-gate /* LINTED */ 37561618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) { 37570Sstevel@tonic-gate (void) fprintf(stderr, 37580Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file, 37594242Sab196087 EC_WORD(ndx), 37601618Srie EC_XWORD(_cache->c_shdr->sh_name)); 37610Sstevel@tonic-gate } 37623862Srie } 37633862Srie 37643862Srie /* 37653862Srie * If there exists no shstrtab data, or a section header has no 37663862Srie * name (an invalid index of 0), then compose a name for the 37673862Srie * section. 37683862Srie */ 37693862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm), 37704242Sab196087 MSG_INTL(MSG_FMT_SCNNDX), ndx); 37714242Sab196087 37724242Sab196087 if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == NULL) { 37733862Srie int err = errno; 37743862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 37753862Srie file, strerror(err)); 37764665Sab196087 return (0); 37773862Srie } 37783862Srie (void) strcpy(_cache->c_name, scnndxnm); 37793862Srie } 37803862Srie 37813862Srie /* 37823862Srie * Having collected all the sections, validate their address range. 37833862Srie * Cases have existed where the section information has been invalid. 37843862Srie * This can lead to all sorts of other, hard to diagnose errors, as 37853862Srie * each section is processed individually (ie. with elf_getdata()). 37863862Srie * Here, we carry out some address comparisons to catch a family of 37873862Srie * overlapping memory issues we have observed (likely, there are others 37883862Srie * that we have yet to discover). 37893862Srie * 37903862Srie * Note, should any memory overlap occur, obtaining any additional 37913862Srie * data from the file is questionable. However, it might still be 37923862Srie * possible to inspect the ELF header, Programs headers, or individual 37933862Srie * sections, so rather than bailing on an error condition, continue 37943862Srie * processing to see if any data can be salvaged. 37953862Srie */ 37964242Sab196087 if (shdr_ndx_arr_cnt > 1) { 37974242Sab196087 sort_shdr_ndx_arr_cache = cache; 37984242Sab196087 qsort(shdr_ndx_arr, shdr_ndx_arr_cnt, 37994242Sab196087 sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr); 38004242Sab196087 } 38014242Sab196087 for (ndx = 0; ndx < shdr_ndx_arr_cnt; ndx++) { 38024242Sab196087 Cache *_cache = cache + shdr_ndx_arr[ndx]; 38033862Srie Shdr *shdr = _cache->c_shdr; 38043862Srie Off bgn1, bgn = shdr->sh_offset; 38053862Srie Off end1, end = shdr->sh_offset + shdr->sh_size; 38064242Sab196087 size_t ndx1; 38074242Sab196087 38084242Sab196087 /* 38094242Sab196087 * Check the section against all following ones, reporting 38104242Sab196087 * any overlaps. Since we've sorted the sections by offset, 38114242Sab196087 * we can stop after the first comparison that fails. There 38124242Sab196087 * are no overlaps in a properly formed ELF file, in which 38134242Sab196087 * case this algorithm runs in O(n) time. This will degenerate 38144242Sab196087 * to O(n^2) for a completely broken file. Such a file is 38154242Sab196087 * (1) highly unlikely, and (2) unusable, so it is reasonable 38164242Sab196087 * for the analysis to take longer. 38174242Sab196087 */ 38184242Sab196087 for (ndx1 = ndx + 1; ndx1 < shdr_ndx_arr_cnt; ndx1++) { 38194242Sab196087 Cache *_cache1 = cache + shdr_ndx_arr[ndx1]; 38203862Srie Shdr *shdr1 = _cache1->c_shdr; 38213862Srie 38223862Srie bgn1 = shdr1->sh_offset; 38233862Srie end1 = shdr1->sh_offset + shdr1->sh_size; 38243862Srie 38253862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 38263862Srie ((bgn1 < end) && (end1 >= end))) { 38273862Srie (void) fprintf(stderr, 38283862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file, 38294242Sab196087 EC_WORD(elf_ndxscn(_cache->c_scn)), 38304242Sab196087 _cache->c_name, EC_OFF(bgn), EC_OFF(end), 38313862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)), 38324242Sab196087 _cache1->c_name, EC_OFF(bgn1), 38334242Sab196087 EC_OFF(end1)); 38344242Sab196087 } else { /* No overlap, so can stop */ 38354242Sab196087 break; 38360Sstevel@tonic-gate } 38370Sstevel@tonic-gate } 38380Sstevel@tonic-gate 38393862Srie /* 38404242Sab196087 * In addition to checking for sections overlapping 38414242Sab196087 * each other (done above), we should also make sure 38424242Sab196087 * the section doesn't overlap the section header array. 38433862Srie */ 38443862Srie bgn1 = ehdr->e_shoff; 38453862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum); 38463862Srie 38473862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 38483862Srie ((bgn1 < end) && (end1 >= end))) { 38493862Srie (void) fprintf(stderr, 38503862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1), 38513862Srie EC_OFF(end1), 38523862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 38533862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 38543862Srie } 38553862Srie } 38563862Srie 38573862Srie /* 38584242Sab196087 * Obtain the data for each section. 38593862Srie */ 38604242Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 38614242Sab196087 Cache *_cache = &cache[ndx]; 38623862Srie Elf_Scn *scn = _cache->c_scn; 38633862Srie 38640Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 38650Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 38660Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 38673862Srie EC_WORD(elf_ndxscn(scn))); 38680Sstevel@tonic-gate } 3869*8747SAli.Bahrami@Sun.COM 3870*8747SAli.Bahrami@Sun.COM /* 3871*8747SAli.Bahrami@Sun.COM * If a string table, verify that it has NULL first and 3872*8747SAli.Bahrami@Sun.COM * final bytes. 3873*8747SAli.Bahrami@Sun.COM */ 3874*8747SAli.Bahrami@Sun.COM if ((_cache->c_shdr->sh_type == SHT_STRTAB) && 3875*8747SAli.Bahrami@Sun.COM (_cache->c_data->d_buf != NULL) && 3876*8747SAli.Bahrami@Sun.COM (_cache->c_data->d_size > 0)) { 3877*8747SAli.Bahrami@Sun.COM const char *s = _cache->c_data->d_buf; 3878*8747SAli.Bahrami@Sun.COM 3879*8747SAli.Bahrami@Sun.COM if ((*s != '\0') || 3880*8747SAli.Bahrami@Sun.COM (*(s + _cache->c_data->d_size - 1) != '\0')) 3881*8747SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALSTR), 3882*8747SAli.Bahrami@Sun.COM file, _cache->c_name); 3883*8747SAli.Bahrami@Sun.COM } 38844665Sab196087 } 38854665Sab196087 38864665Sab196087 return (1); 38874665Sab196087 } 38884665Sab196087 38894665Sab196087 38904665Sab196087 38915411Sab196087 int 38925411Sab196087 regular(const char *file, int fd, Elf *elf, uint_t flags, 38935411Sab196087 const char *wname, int wfd) 38944665Sab196087 { 38954665Sab196087 Elf_Scn *scn; 38964665Sab196087 Ehdr *ehdr; 38974665Sab196087 size_t ndx, shstrndx, shnum, phnum; 38984665Sab196087 Shdr *shdr; 38994665Sab196087 Cache *cache; 39004665Sab196087 VERSYM_STATE versym; 39015411Sab196087 int ret = 0; 39025411Sab196087 int addr_align; 39034665Sab196087 39044665Sab196087 if ((ehdr = elf_getehdr(elf)) == NULL) { 39054665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 39065411Sab196087 return (ret); 39074665Sab196087 } 39084665Sab196087 39094665Sab196087 if (elf_getshnum(elf, &shnum) == 0) { 39104665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 39115411Sab196087 return (ret); 39124665Sab196087 } 39134665Sab196087 39144665Sab196087 if (elf_getshstrndx(elf, &shstrndx) == 0) { 39154665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 39165411Sab196087 return (ret); 39174665Sab196087 } 39184665Sab196087 39194665Sab196087 if (elf_getphnum(elf, &phnum) == 0) { 39204665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 39215411Sab196087 return (ret); 39224665Sab196087 } 39234665Sab196087 /* 39244665Sab196087 * If the user requested section headers derived from the 39254665Sab196087 * program headers (-P option) and this file doesn't have 39264665Sab196087 * any program headers (i.e. ET_REL), then we can't do it. 39274665Sab196087 */ 39285411Sab196087 if ((phnum == 0) && (flags & FLG_CTL_FAKESHDR)) { 39294665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_PNEEDSPH), file); 39305411Sab196087 return (ret); 39314665Sab196087 } 39324665Sab196087 39334665Sab196087 39344665Sab196087 if ((scn = elf_getscn(elf, 0)) != NULL) { 39354665Sab196087 if ((shdr = elf_getshdr(scn)) == NULL) { 39364665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 39374665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 39385411Sab196087 return (ret); 39394665Sab196087 } 39404665Sab196087 } else 39414665Sab196087 shdr = 0; 39424665Sab196087 39434665Sab196087 /* 39444665Sab196087 * Print the elf header. 39454665Sab196087 */ 39465411Sab196087 if (flags & FLG_SHOW_EHDR) 39474665Sab196087 Elf_ehdr(0, ehdr, shdr); 39484665Sab196087 39494665Sab196087 /* 39504665Sab196087 * If the section headers or program headers have inadequate 39514665Sab196087 * alignment for the class of object, print a warning. libelf 39524665Sab196087 * can handle such files, but programs that use them can crash 39534665Sab196087 * when they dereference unaligned items. 39545411Sab196087 * 39555411Sab196087 * Note that the AMD64 ABI, although it is a 64-bit architecture, 39565411Sab196087 * allows access to data types smaller than 128-bits to be on 39575411Sab196087 * word alignment. 39584665Sab196087 */ 39595411Sab196087 if (ehdr->e_machine == EM_AMD64) 39605411Sab196087 addr_align = sizeof (Word); 39615411Sab196087 else 39625411Sab196087 addr_align = sizeof (Addr); 39635411Sab196087 39645411Sab196087 if (ehdr->e_phoff & (addr_align - 1)) 39654665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADPHDRALIGN), file); 39665411Sab196087 if (ehdr->e_shoff & (addr_align - 1)) 39674665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHDRALIGN), file); 39684665Sab196087 39694665Sab196087 /* 39704665Sab196087 * Print the program headers. 39714665Sab196087 */ 39725411Sab196087 if ((flags & FLG_SHOW_PHDR) && (phnum != 0)) { 39735411Sab196087 Phdr *phdr; 39744665Sab196087 39754665Sab196087 if ((phdr = elf_getphdr(elf)) == NULL) { 39764665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 39775411Sab196087 return (ret); 39784665Sab196087 } 39794665Sab196087 39804665Sab196087 for (ndx = 0; ndx < phnum; phdr++, ndx++) { 39815411Sab196087 if (!match(MATCH_F_PHDR| MATCH_F_NDX | MATCH_F_TYPE, 39825411Sab196087 NULL, ndx, phdr->p_type)) 39834665Sab196087 continue; 39844665Sab196087 39854665Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 39864665Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx)); 39874665Sab196087 Elf_phdr(0, ehdr->e_machine, phdr); 39884665Sab196087 } 39894665Sab196087 } 39904665Sab196087 39914665Sab196087 /* 39925411Sab196087 * If we have flag bits set that explicitly require a show or calc 39935411Sab196087 * operation, but none of them require the section headers, then 39945411Sab196087 * we are done and can return now. 39954665Sab196087 */ 39965411Sab196087 if (((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) != 0) && 39975411Sab196087 ((flags & (FLG_MASK_SHOW_SHDR | FLG_MASK_CALC_SHDR)) == 0)) 39985411Sab196087 return (ret); 39995411Sab196087 40005411Sab196087 /* 40015411Sab196087 * If there are no section headers, then resort to synthesizing 40025411Sab196087 * section headers from the program headers. This is normally 40035411Sab196087 * only done by explicit request, but in this case there's no 40045411Sab196087 * reason not to go ahead, since the alternative is simply to quit. 40055411Sab196087 */ 40065411Sab196087 if ((shnum <= 1) && ((flags & FLG_CTL_FAKESHDR) == 0)) { 40075411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHDR), file); 40085411Sab196087 flags |= FLG_CTL_FAKESHDR; 40094665Sab196087 } 40104665Sab196087 40114665Sab196087 /* 40124665Sab196087 * Generate a cache of section headers and related information 40134665Sab196087 * for use by the rest of elfdump. If requested (or the file 40144665Sab196087 * contains no section headers), we generate a fake set of 40154665Sab196087 * headers from the information accessible from the program headers. 40164665Sab196087 * Otherwise, we use the real section headers contained in the file. 40174665Sab196087 */ 40184665Sab196087 40195411Sab196087 if (flags & FLG_CTL_FAKESHDR) { 40204665Sab196087 if (fake_shdr_cache(file, fd, elf, ehdr, &cache, &shnum) == 0) 40215411Sab196087 return (ret); 40224665Sab196087 } else { 40237463SRod.Evans@Sun.COM if (shdr_cache(file, elf, ehdr, shstrndx, shnum, 40247463SRod.Evans@Sun.COM &cache, flags) == 0) 40255411Sab196087 return (ret); 40264665Sab196087 } 40274665Sab196087 40284665Sab196087 /* 40295411Sab196087 * Everything from this point on requires section headers. 40305411Sab196087 * If we have no section headers, there is no reason to continue. 40315411Sab196087 */ 40325411Sab196087 if (shnum <= 1) 40335411Sab196087 goto done; 40345411Sab196087 40355411Sab196087 /* 40364665Sab196087 * If -w was specified, find and write out the section(s) data. 40374665Sab196087 */ 40384665Sab196087 if (wfd) { 40394665Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 40404665Sab196087 Cache *_cache = &cache[ndx]; 40414665Sab196087 40425411Sab196087 if (match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 40435411Sab196087 ndx, _cache->c_shdr->sh_type) && 40445411Sab196087 _cache->c_data && _cache->c_data->d_buf) { 40455411Sab196087 if (write(wfd, _cache->c_data->d_buf, 40465411Sab196087 _cache->c_data->d_size) != 40475411Sab196087 _cache->c_data->d_size) { 40485411Sab196087 int err = errno; 40495411Sab196087 (void) fprintf(stderr, 40505411Sab196087 MSG_INTL(MSG_ERR_WRITE), wname, 40515411Sab196087 strerror(err)); 40525411Sab196087 /* 40535411Sab196087 * Return an exit status of 1, because 40545411Sab196087 * the failure is not related to the 40555411Sab196087 * ELF file, but by system resources. 40565411Sab196087 */ 40575411Sab196087 ret = 1; 40585411Sab196087 goto done; 40595411Sab196087 } 40604665Sab196087 } 40610Sstevel@tonic-gate } 40620Sstevel@tonic-gate } 40630Sstevel@tonic-gate 40645411Sab196087 /* 40655411Sab196087 * If we have no flag bits set that explicitly require a show or calc 40665411Sab196087 * operation, but match options (-I, -N, -T) were used, then run 40675411Sab196087 * through the section headers and see if we can't deduce show flags 40685411Sab196087 * from the match options given. 40695411Sab196087 * 40705411Sab196087 * We don't do this if -w was specified, because (-I, -N, -T) used 40715411Sab196087 * with -w in lieu of some other option is supposed to be quiet. 40725411Sab196087 */ 40735411Sab196087 if ((wfd == 0) && (flags & FLG_CTL_MATCH) && 40745411Sab196087 ((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) == 0)) { 40755411Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 40765411Sab196087 Cache *_cache = &cache[ndx]; 40775411Sab196087 40785411Sab196087 if (!match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 40795411Sab196087 ndx, _cache->c_shdr->sh_type)) 40805411Sab196087 continue; 40815411Sab196087 40825411Sab196087 switch (_cache->c_shdr->sh_type) { 40835411Sab196087 case SHT_PROGBITS: 40845411Sab196087 /* 40855411Sab196087 * Heuristic time: It is usually bad form 40865411Sab196087 * to assume that specific section names 40875411Sab196087 * have a given meaning. However, the 40885411Sab196087 * ELF ABI does specify a few such names. Try 40895411Sab196087 * to match them: 40905411Sab196087 */ 40915411Sab196087 if (strcmp(_cache->c_name, 40925411Sab196087 MSG_ORIG(MSG_ELF_INTERP)) == 0) 40935411Sab196087 flags |= FLG_SHOW_INTERP; 40945411Sab196087 else if (strcmp(_cache->c_name, 40955411Sab196087 MSG_ORIG(MSG_ELF_GOT)) == 0) 40965411Sab196087 flags |= FLG_SHOW_GOT; 40975411Sab196087 break; 40985411Sab196087 40995411Sab196087 case SHT_SYMTAB: 41005411Sab196087 case SHT_DYNSYM: 41015411Sab196087 case SHT_SUNW_LDYNSYM: 41025411Sab196087 case SHT_SUNW_versym: 41035411Sab196087 case SHT_SYMTAB_SHNDX: 41045411Sab196087 flags |= FLG_SHOW_SYMBOLS; 41055411Sab196087 break; 41065411Sab196087 41075411Sab196087 case SHT_RELA: 41085411Sab196087 case SHT_REL: 41095411Sab196087 flags |= FLG_SHOW_RELOC; 41105411Sab196087 break; 41115411Sab196087 41125411Sab196087 case SHT_HASH: 41135411Sab196087 flags |= FLG_SHOW_HASH; 41145411Sab196087 break; 41155411Sab196087 41165411Sab196087 case SHT_DYNAMIC: 41175411Sab196087 flags |= FLG_SHOW_DYNAMIC; 41185411Sab196087 break; 41195411Sab196087 41205411Sab196087 case SHT_NOTE: 41215411Sab196087 flags |= FLG_SHOW_NOTE; 41225411Sab196087 break; 41235411Sab196087 41245411Sab196087 case SHT_GROUP: 41255411Sab196087 flags |= FLG_SHOW_GROUP; 41265411Sab196087 break; 41275411Sab196087 41285411Sab196087 case SHT_SUNW_symsort: 41295411Sab196087 case SHT_SUNW_tlssort: 41305411Sab196087 flags |= FLG_SHOW_SORT; 41315411Sab196087 break; 41325411Sab196087 41335411Sab196087 case SHT_SUNW_cap: 41345411Sab196087 flags |= FLG_SHOW_CAP; 41355411Sab196087 break; 41365411Sab196087 41375411Sab196087 case SHT_SUNW_move: 41385411Sab196087 flags |= FLG_SHOW_MOVE; 41395411Sab196087 break; 41405411Sab196087 41415411Sab196087 case SHT_SUNW_syminfo: 41425411Sab196087 flags |= FLG_SHOW_SYMINFO; 41435411Sab196087 break; 41445411Sab196087 41455411Sab196087 case SHT_SUNW_verdef: 41465411Sab196087 case SHT_SUNW_verneed: 41475411Sab196087 flags |= FLG_SHOW_VERSIONS; 41485411Sab196087 break; 41495411Sab196087 41505411Sab196087 case SHT_AMD64_UNWIND: 41515411Sab196087 flags |= FLG_SHOW_UNWIND; 41525411Sab196087 break; 41535411Sab196087 } 41545411Sab196087 } 41555411Sab196087 } 41565411Sab196087 41575411Sab196087 41585411Sab196087 if (flags & FLG_SHOW_SHDR) 41594168Sab196087 sections(file, cache, shnum, ehdr); 41600Sstevel@tonic-gate 41615411Sab196087 if (flags & FLG_SHOW_INTERP) 41621618Srie interp(file, cache, shnum, phnum, elf); 41630Sstevel@tonic-gate 41643875Sab196087 versions(cache, shnum, file, flags, &versym); 41650Sstevel@tonic-gate 41665411Sab196087 if (flags & FLG_SHOW_SYMBOLS) 41674168Sab196087 symbols(cache, shnum, ehdr, &versym, file, flags); 41680Sstevel@tonic-gate 41695411Sab196087 if (flags & FLG_SHOW_SORT) 41704168Sab196087 sunw_sort(cache, shnum, ehdr, &versym, file, flags); 41713492Sab196087 41725411Sab196087 if (flags & FLG_SHOW_HASH) 41734168Sab196087 hash(cache, shnum, file, flags); 41740Sstevel@tonic-gate 41755411Sab196087 if (flags & FLG_SHOW_GOT) 41767463SRod.Evans@Sun.COM got(cache, shnum, ehdr, file); 41770Sstevel@tonic-gate 41785411Sab196087 if (flags & FLG_SHOW_GROUP) 41794168Sab196087 group(cache, shnum, file, flags); 41800Sstevel@tonic-gate 41815411Sab196087 if (flags & FLG_SHOW_SYMINFO) 41820Sstevel@tonic-gate syminfo(cache, shnum, file); 41830Sstevel@tonic-gate 41845411Sab196087 if (flags & FLG_SHOW_RELOC) 41857463SRod.Evans@Sun.COM reloc(cache, shnum, ehdr, file); 41860Sstevel@tonic-gate 41875411Sab196087 if (flags & FLG_SHOW_DYNAMIC) 41881618Srie dynamic(cache, shnum, ehdr, file); 41890Sstevel@tonic-gate 41906635Sab196087 if (flags & FLG_SHOW_NOTE) { 41916635Sab196087 Word note_cnt; 41926635Sab196087 size_t note_shnum; 41936635Sab196087 Cache *note_cache; 41946635Sab196087 41956635Sab196087 note_cnt = note(cache, shnum, ehdr, file); 41966635Sab196087 41976635Sab196087 /* 41986635Sab196087 * Solaris core files have section headers, but these 41996635Sab196087 * headers do not include SHT_NOTE sections that reference 42006635Sab196087 * the core note sections. This means that note() won't 42016635Sab196087 * find the core notes. Fake section headers (-P option) 42026635Sab196087 * recover these sections, but it is inconvenient to require 42036635Sab196087 * users to specify -P in this situation. If the following 42046635Sab196087 * are all true: 42056635Sab196087 * 42066635Sab196087 * - No note sections were found 42076635Sab196087 * - This is a core file 42086635Sab196087 * - We are not already using fake section headers 42096635Sab196087 * 42106635Sab196087 * then we will automatically generate fake section headers 42116635Sab196087 * and then process them in a second call to note(). 42126635Sab196087 */ 42136635Sab196087 if ((note_cnt == 0) && (ehdr->e_type == ET_CORE) && 42146635Sab196087 !(flags & FLG_CTL_FAKESHDR) && 42156635Sab196087 (fake_shdr_cache(file, fd, elf, ehdr, 42166635Sab196087 ¬e_cache, ¬e_shnum) != 0)) { 42176635Sab196087 (void) note(note_cache, note_shnum, ehdr, file); 42186635Sab196087 fake_shdr_cache_free(note_cache, note_shnum); 42196635Sab196087 } 42206635Sab196087 } 42210Sstevel@tonic-gate 42225411Sab196087 if (flags & FLG_SHOW_MOVE) 42234168Sab196087 move(cache, shnum, file, flags); 42240Sstevel@tonic-gate 42255411Sab196087 if (flags & FLG_CALC_CHECKSUM) 42260Sstevel@tonic-gate checksum(elf); 42270Sstevel@tonic-gate 42285411Sab196087 if (flags & FLG_SHOW_CAP) 42291618Srie cap(file, cache, shnum, phnum, ehdr, elf); 42300Sstevel@tonic-gate 42315411Sab196087 if (flags & FLG_SHOW_UNWIND) 42324168Sab196087 unwind(cache, shnum, phnum, ehdr, file, elf); 42330Sstevel@tonic-gate 42344665Sab196087 42354665Sab196087 /* Release the memory used to cache section headers */ 42365411Sab196087 done: 42375411Sab196087 if (flags & FLG_CTL_FAKESHDR) 42384665Sab196087 fake_shdr_cache_free(cache, shnum); 42394665Sab196087 else 42404665Sab196087 free(cache); 42415411Sab196087 42425411Sab196087 return (ret); 42430Sstevel@tonic-gate } 4244