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 /* 238747SAli.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 */ 118*9273SAli.Bahrami@Sun.COM uchar_t osabi; /* OSABI to use */ 1193875Sab196087 Word shnum; /* # of sections in cache */ 1203875Sab196087 Cache *seccache; /* Cache of symbol table section hdr */ 1213875Sab196087 Word secndx; /* Index of symbol table section hdr */ 1223875Sab196087 const char *secname; /* Name of section */ 1233875Sab196087 uint_t flags; /* Command line option flags */ 1243875Sab196087 struct { /* Extended section index data */ 1253875Sab196087 int checked; /* TRUE if already checked for shxndx */ 1263875Sab196087 Word *data; /* NULL, or extended section index */ 1273875Sab196087 /* used for symbol table entries */ 1283875Sab196087 uint_t n; /* # items in shxndx.data */ 1293875Sab196087 } shxndx; 1303875Sab196087 VERSYM_STATE *versym; /* NULL, or associated VERSYM section */ 1313875Sab196087 Sym *sym; /* Array of symbols */ 1323875Sab196087 Word symn; /* # of symbols */ 1333875Sab196087 } SYMTBL_STATE; 1343875Sab196087 1353875Sab196087 1363875Sab196087 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * Focal point for verifying symbol names. 1390Sstevel@tonic-gate */ 1400Sstevel@tonic-gate static const char * 1411618Srie string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name) 1420Sstevel@tonic-gate { 1434063Sab196087 /* 1444063Sab196087 * If an error in this routine is due to a property of the string 1454063Sab196087 * section, as opposed to a bad offset into the section (a property of 1464063Sab196087 * the referencing section), then we will detect the same error on 1474063Sab196087 * every call involving those sections. We use these static variables 1484063Sab196087 * to retain the information needed to only issue each such error once. 1494063Sab196087 */ 1504063Sab196087 static Cache *last_refsec; /* Last referencing section seen */ 1514063Sab196087 static int strsec_err; /* True if error issued */ 1524063Sab196087 1533492Sab196087 const char *strs; 1543492Sab196087 Word strn; 1550Sstevel@tonic-gate 1563466Srie if (strsec->c_data == NULL) 1573466Srie return (NULL); 1583466Srie 1593492Sab196087 strs = (char *)strsec->c_data->d_buf; 1603492Sab196087 strn = strsec->c_data->d_size; 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate /* 1634063Sab196087 * We only print a diagnostic regarding a bad string table once per 1644063Sab196087 * input section being processed. If the refsec has changed, reset 1654063Sab196087 * our retained error state. 1660Sstevel@tonic-gate */ 1674063Sab196087 if (last_refsec != refsec) { 1684063Sab196087 last_refsec = refsec; 1694063Sab196087 strsec_err = 0; 1704063Sab196087 } 1714063Sab196087 1724063Sab196087 /* Verify that strsec really is a string table */ 1734063Sab196087 if (strsec->c_shdr->sh_type != SHT_STRTAB) { 1744063Sab196087 if (!strsec_err) { 1754063Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOTSTRTAB), 1764063Sab196087 file, strsec->c_ndx, refsec->c_ndx); 1774063Sab196087 strsec_err = 1; 1784063Sab196087 } 1794063Sab196087 return (MSG_INTL(MSG_STR_UNKNOWN)); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* 1830Sstevel@tonic-gate * Is the string table offset within range of the available strings? 1840Sstevel@tonic-gate */ 1850Sstevel@tonic-gate if (name >= strn) { 1860Sstevel@tonic-gate /* 1870Sstevel@tonic-gate * Do we have a empty string table? 1880Sstevel@tonic-gate */ 1899085SAli.Bahrami@Sun.COM if (strs == NULL) { 1904063Sab196087 if (!strsec_err) { 1910Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1920Sstevel@tonic-gate file, strsec->c_name); 1934063Sab196087 strsec_err = 1; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate } else { 1960Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF), 1971618Srie file, refsec->c_name, EC_WORD(ndx), strsec->c_name, 1981618Srie EC_WORD(name), EC_WORD(strn - 1)); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * Return the empty string so that the calling function can 2030Sstevel@tonic-gate * continue it's output diagnostics. 2040Sstevel@tonic-gate */ 2050Sstevel@tonic-gate return (MSG_INTL(MSG_STR_UNKNOWN)); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate return (strs + name); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2111618Srie * Relocations can reference section symbols and standard symbols. If the 2121618Srie * former, establish the section name. 2131618Srie */ 2141618Srie static const char * 2151618Srie relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum, 2167463SRod.Evans@Sun.COM Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file) 2171618Srie { 2187463SRod.Evans@Sun.COM Sym *sym; 2197463SRod.Evans@Sun.COM const char *name; 2201618Srie 2211618Srie if (symndx >= symnum) { 2221618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX), 2231618Srie file, EC_WORD(symndx), EC_WORD(relndx)); 2241618Srie return (MSG_INTL(MSG_STR_UNKNOWN)); 2251618Srie } 2261618Srie 2271618Srie sym = (Sym *)(syms + symndx); 2287463SRod.Evans@Sun.COM name = string(csec, symndx, strsec, file, sym->st_name); 2291618Srie 2301618Srie /* 2311618Srie * If the symbol represents a section offset construct an appropriate 2327463SRod.Evans@Sun.COM * string. Note, although section symbol table entries typically have 2337463SRod.Evans@Sun.COM * a NULL name pointer, entries do exist that point into the string 2347463SRod.Evans@Sun.COM * table to their own NULL strings. 2351618Srie */ 2367463SRod.Evans@Sun.COM if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) && 2377463SRod.Evans@Sun.COM ((sym->st_name == 0) || (*name == '\0'))) { 2387463SRod.Evans@Sun.COM (void) snprintf(secstr, secsz, MSG_INTL(MSG_STR_SECTION), 2397463SRod.Evans@Sun.COM cache[sym->st_shndx].c_name); 2401618Srie return ((const char *)secstr); 2411618Srie } 2421618Srie 2437463SRod.Evans@Sun.COM return (name); 2441618Srie } 2451618Srie 2461618Srie /* 2471618Srie * Focal point for establishing a string table section. Data such as the 2481618Srie * dynamic information simply points to a string table. Data such as 2491618Srie * relocations, reference a symbol table, which in turn is associated with a 2501618Srie * string table. 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate static int 2531618Srie stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file, 2541618Srie Word *symnum, Cache **symsec, Cache **strsec) 2551618Srie { 2561618Srie Shdr *shdr = cache[ndx].c_shdr; 2571618Srie 2581618Srie if (symtab) { 2591618Srie /* 2601618Srie * Validate the symbol table section. 2611618Srie */ 2621618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2631618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2641618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 2651618Srie return (0); 2661618Srie } 2673466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2683466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2693466Srie file, cache[ndx].c_name); 2703466Srie return (0); 2713466Srie } 2721618Srie 2731618Srie /* 2741618Srie * Obtain, and verify the symbol table data. 2751618Srie */ 2763466Srie if ((cache[ndx].c_data == NULL) || 2773466Srie (cache[ndx].c_data->d_buf == NULL)) { 2781618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2791618Srie file, cache[ndx].c_name); 2801618Srie return (0); 2811618Srie } 2821618Srie 2831618Srie /* 2841618Srie * Establish the string table index. 2851618Srie */ 2861618Srie ndx = shdr->sh_link; 2871618Srie shdr = cache[ndx].c_shdr; 2881618Srie 2891618Srie /* 2901618Srie * Return symbol table information. 2911618Srie */ 2921618Srie if (symnum) 2931618Srie *symnum = (shdr->sh_size / shdr->sh_entsize); 2941618Srie if (symsec) 2951618Srie *symsec = &cache[ndx]; 2961618Srie } 2971618Srie 2981618Srie /* 2991618Srie * Validate the associated string table section. 3001618Srie */ 3011618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3021618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3031618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 3041618Srie return (0); 3051618Srie } 3061618Srie 3071618Srie if (strsec) 3081618Srie *strsec = &cache[shdr->sh_link]; 3091618Srie 3101618Srie return (1); 3111618Srie } 3121618Srie 3131618Srie /* 3141618Srie * Lookup a symbol and set Sym accordingly. 3151618Srie */ 3161618Srie static int 3171618Srie symlookup(const char *name, Cache *cache, Word shnum, Sym **sym, 3180Sstevel@tonic-gate Cache *symtab, const char *file) 3190Sstevel@tonic-gate { 3201618Srie Shdr *shdr; 3211618Srie Word symn, cnt; 3221618Srie Sym *syms; 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate if (symtab == 0) 3250Sstevel@tonic-gate return (0); 3260Sstevel@tonic-gate 3271618Srie shdr = symtab->c_shdr; 3281618Srie 3290Sstevel@tonic-gate /* 3300Sstevel@tonic-gate * Determine the symbol data and number. 3310Sstevel@tonic-gate */ 3320Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 3330Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 3340Sstevel@tonic-gate file, symtab->c_name); 3350Sstevel@tonic-gate return (0); 3360Sstevel@tonic-gate } 3373466Srie if (symtab->c_data == NULL) 3383466Srie return (0); 3393466Srie 3400Sstevel@tonic-gate /* LINTED */ 3411618Srie symn = (Word)(shdr->sh_size / shdr->sh_entsize); 3421618Srie syms = (Sym *)symtab->c_data->d_buf; 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate /* 3450Sstevel@tonic-gate * Get the associated string table section. 3460Sstevel@tonic-gate */ 3470Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3480Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3491618Srie file, symtab->c_name, EC_WORD(shdr->sh_link)); 3500Sstevel@tonic-gate return (0); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate /* 3540Sstevel@tonic-gate * Loop through the symbol table to find a match. 3550Sstevel@tonic-gate */ 3561618Srie for (cnt = 0; cnt < symn; syms++, cnt++) { 3571618Srie const char *symname; 3580Sstevel@tonic-gate 3591618Srie symname = string(symtab, cnt, &cache[shdr->sh_link], file, 3601618Srie syms->st_name); 3610Sstevel@tonic-gate 3621618Srie if (symname && (strcmp(name, symname) == 0)) { 3631618Srie *sym = syms; 3640Sstevel@tonic-gate return (1); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate return (0); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate /* 3710Sstevel@tonic-gate * Print section headers. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate static void 374*9273SAli.Bahrami@Sun.COM sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi) 3750Sstevel@tonic-gate { 3761618Srie size_t seccnt; 3770Sstevel@tonic-gate 3781618Srie for (seccnt = 1; seccnt < shnum; seccnt++) { 3791618Srie Cache *_cache = &cache[seccnt]; 3801618Srie Shdr *shdr = _cache->c_shdr; 3811618Srie const char *secname = _cache->c_name; 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate /* 3840Sstevel@tonic-gate * Although numerous section header entries can be zero, it's 3853862Srie * usually a sign of trouble if the type is zero. 3860Sstevel@tonic-gate */ 3870Sstevel@tonic-gate if (shdr->sh_type == 0) { 3880Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE), 3891618Srie file, secname, EC_WORD(shdr->sh_type)); 3900Sstevel@tonic-gate } 3913862Srie 3925411Sab196087 if (!match(MATCH_F_ALL, secname, seccnt, shdr->sh_type)) 3933862Srie continue; 3940Sstevel@tonic-gate 3951324Srie /* 3961324Srie * Identify any sections that are suspicious. A .got section 3971324Srie * shouldn't exist in a relocatable object. 3981324Srie */ 3991324Srie if (ehdr->e_type == ET_REL) { 4001618Srie if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT), 4011324Srie MSG_ELF_GOT_SIZE) == 0) { 4021324Srie (void) fprintf(stderr, 4031618Srie MSG_INTL(MSG_GOT_UNEXPECTED), file, 4041618Srie secname); 4051324Srie } 4061324Srie } 4071324Srie 4081618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 4091618Srie dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname); 410*9273SAli.Bahrami@Sun.COM Elf_shdr(0, osabi, ehdr->e_machine, shdr); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4141618Srie /* 4151618Srie * Obtain a specified Phdr entry. 4161618Srie */ 4171618Srie static Phdr * 4189085SAli.Bahrami@Sun.COM getphdr(Word phnum, Word *type_arr, Word type_cnt, const char *file, Elf *elf) 4191618Srie { 4209085SAli.Bahrami@Sun.COM Word cnt, tcnt; 4211618Srie Phdr *phdr; 4221618Srie 4231618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 4241618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 4259085SAli.Bahrami@Sun.COM return (NULL); 4261618Srie } 4271618Srie 4281618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 4299085SAli.Bahrami@Sun.COM for (tcnt = 0; tcnt < type_cnt; tcnt++) { 4309085SAli.Bahrami@Sun.COM if (phdr->p_type == type_arr[tcnt]) 4319085SAli.Bahrami@Sun.COM return (phdr); 4329085SAli.Bahrami@Sun.COM } 4331618Srie } 4349085SAli.Bahrami@Sun.COM return (NULL); 4351618Srie } 4361618Srie 4370Sstevel@tonic-gate static void 438*9273SAli.Bahrami@Sun.COM unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, uchar_t osabi, 439*9273SAli.Bahrami@Sun.COM const char *file, Elf *elf, uint_t flags) 4400Sstevel@tonic-gate { 4419085SAli.Bahrami@Sun.COM #if defined(_ELF64) 4429085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_64 4439085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_64 4449085SAli.Bahrami@Sun.COM #else 4459085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_32 4469085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_32 4479085SAli.Bahrami@Sun.COM #endif 4489085SAli.Bahrami@Sun.COM 4499085SAli.Bahrami@Sun.COM static Word phdr_types[] = { PT_SUNW_UNWIND, PT_SUNW_EH_FRAME }; 4509085SAli.Bahrami@Sun.COM 4519085SAli.Bahrami@Sun.COM int frame_cnt = 0, hdr_cnt = 0, frame_ndx, hdr_ndx; 4529085SAli.Bahrami@Sun.COM uint64_t save_frame_ptr, save_frame_base; 4534734Sab196087 Conv_dwarf_ehe_buf_t dwarf_ehe_buf; 4549085SAli.Bahrami@Sun.COM Word cnt; 4559085SAli.Bahrami@Sun.COM Phdr *uphdr = NULL; 4561618Srie 4570Sstevel@tonic-gate /* 4589085SAli.Bahrami@Sun.COM * Historical background: .eh_frame and .eh_frame_hdr sections 4599085SAli.Bahrami@Sun.COM * come from the GNU compilers (particularly C++), and are used 4609085SAli.Bahrami@Sun.COM * under all architectures. Their format is based on DWARF. When 4619085SAli.Bahrami@Sun.COM * the amd64 ABI was defined, these sections were adopted wholesale 4629085SAli.Bahrami@Sun.COM * from the existing practice. 4639085SAli.Bahrami@Sun.COM * 4649085SAli.Bahrami@Sun.COM * When amd64 support was added to Solaris, support for these 4659085SAli.Bahrami@Sun.COM * sections was added, using the SHT_AMD64_UNWIND section type 4669085SAli.Bahrami@Sun.COM * to identify them. At first, we ignored them in objects for 4679085SAli.Bahrami@Sun.COM * non-amd64 targets, but later broadened our support to include 4689085SAli.Bahrami@Sun.COM * other architectures in order to better support gcc-generated 4699085SAli.Bahrami@Sun.COM * objects. 4709085SAli.Bahrami@Sun.COM * 4719085SAli.Bahrami@Sun.COM * We match these sections by name, rather than section type, 4729085SAli.Bahrami@Sun.COM * because they can come in as either SHT_AMD64_UNWIND, or as 4739085SAli.Bahrami@Sun.COM * SHT_PROGBITS, and because we need to distinquish between 4749085SAli.Bahrami@Sun.COM * the two types (.eh_frame and .eh_frame_hdr). 4750Sstevel@tonic-gate */ 4760Sstevel@tonic-gate 4771618Srie if (phnum) 4789085SAli.Bahrami@Sun.COM uphdr = getphdr(phnum, phdr_types, 4799085SAli.Bahrami@Sun.COM sizeof (phdr_types) / sizeof (*phdr_types), file, elf); 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 4821618Srie Cache *_cache = &cache[cnt]; 4831618Srie Shdr *shdr = _cache->c_shdr; 4841618Srie uchar_t *data; 4850Sstevel@tonic-gate size_t datasize; 4869085SAli.Bahrami@Sun.COM uint64_t ndx, frame_ptr, fde_cnt, tabndx; 4871618Srie uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate /* 490*9273SAli.Bahrami@Sun.COM * Skip sections of the wrong type. 491*9273SAli.Bahrami@Sun.COM * 492*9273SAli.Bahrami@Sun.COM * On Solaris, these are SHT_AMD64_UNWIND for amd64, 493*9273SAli.Bahrami@Sun.COM * and SHT_PROGBITS for other platforms. For Linux, and 494*9273SAli.Bahrami@Sun.COM * presumably other operating systems that use the GNU 495*9273SAli.Bahrami@Sun.COM * toolchain, SHT_PROGBITS is used on all platforms. 496*9273SAli.Bahrami@Sun.COM * 497*9273SAli.Bahrami@Sun.COM * Skip anything other than these two types. The name 498*9273SAli.Bahrami@Sun.COM * test below will thin out the SHT_PROGBITS that don't apply. 4990Sstevel@tonic-gate */ 500*9273SAli.Bahrami@Sun.COM if ((shdr->sh_type != SHT_PROGBITS) && 501*9273SAli.Bahrami@Sun.COM (shdr->sh_type != SHT_AMD64_UNWIND)) 5029085SAli.Bahrami@Sun.COM continue; 5039085SAli.Bahrami@Sun.COM 5049085SAli.Bahrami@Sun.COM /* 5059085SAli.Bahrami@Sun.COM * Only sections with names starting with .eh_frame or 5069085SAli.Bahrami@Sun.COM * .eh_frame_hdr are of interest. We do a prefix comparison, 5079085SAli.Bahrami@Sun.COM * allowing for naming conventions like .eh_frame.foo, hence 5089085SAli.Bahrami@Sun.COM * the use of strncmp() rather than strcmp(). This means that 5099085SAli.Bahrami@Sun.COM * we only really need to test for .eh_frame, as it's a 5109085SAli.Bahrami@Sun.COM * prefix of .eh_frame_hdr. 5119085SAli.Bahrami@Sun.COM */ 5129085SAli.Bahrami@Sun.COM if (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 5139085SAli.Bahrami@Sun.COM MSG_SCN_FRM_SIZE) != 0) 5140Sstevel@tonic-gate continue; 5154168Sab196087 5165411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 5170Sstevel@tonic-gate continue; 5180Sstevel@tonic-gate 5193466Srie if (_cache->c_data == NULL) 5203466Srie continue; 5213466Srie 5221618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 5231618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 5240Sstevel@tonic-gate 5251618Srie data = (uchar_t *)(_cache->c_data->d_buf); 5260Sstevel@tonic-gate datasize = _cache->c_data->d_size; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate * Is this a .eh_frame_hdr 5300Sstevel@tonic-gate */ 5311618Srie if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || 5320Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 5331618Srie MSG_SCN_FRMHDR_SIZE) == 0)) { 5349085SAli.Bahrami@Sun.COM /* 5359085SAli.Bahrami@Sun.COM * There can only be a single .eh_frame_hdr. 5369085SAli.Bahrami@Sun.COM * Flag duplicates. 5379085SAli.Bahrami@Sun.COM */ 5389085SAli.Bahrami@Sun.COM if (++hdr_cnt > 1) 5399085SAli.Bahrami@Sun.COM (void) fprintf(stderr, 5409085SAli.Bahrami@Sun.COM MSG_INTL(MSG_ERR_MULTEHFRMHDR), file, 5419085SAli.Bahrami@Sun.COM EC_WORD(cnt), _cache->c_name); 5429085SAli.Bahrami@Sun.COM 5431618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR)); 5441618Srie ndx = 0; 5450Sstevel@tonic-gate 5461618Srie vers = data[ndx++]; 5471618Srie frame_ptr_enc = data[ndx++]; 5481618Srie fde_cnt_enc = data[ndx++]; 5491618Srie table_enc = data[ndx++]; 5500Sstevel@tonic-gate 5511618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); 5520Sstevel@tonic-gate 5531618Srie frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, 5549085SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx); 5559085SAli.Bahrami@Sun.COM if (hdr_cnt == 1) { 5569085SAli.Bahrami@Sun.COM hdr_ndx = cnt; 5579085SAli.Bahrami@Sun.COM save_frame_ptr = frame_ptr; 5589085SAli.Bahrami@Sun.COM } 5590Sstevel@tonic-gate 5601618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC), 5614734Sab196087 conv_dwarf_ehe(frame_ptr_enc, &dwarf_ehe_buf), 5624734Sab196087 EC_XWORD(frame_ptr)); 5631618Srie 5641618Srie fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, 5659085SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx); 5660Sstevel@tonic-gate 5671618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), 5684734Sab196087 conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf), 5694734Sab196087 EC_XWORD(fde_cnt)); 5701618Srie dbg_print(0, MSG_ORIG(MSG_UNW_TABENC), 5714734Sab196087 conv_dwarf_ehe(table_enc, &dwarf_ehe_buf)); 5721618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1)); 5731618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2)); 5740Sstevel@tonic-gate 5751618Srie for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 5761618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), 5771618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5789085SAli.Bahrami@Sun.COM table_enc, ehdr->e_ident, shdr->sh_addr, 5799085SAli.Bahrami@Sun.COM ndx)), 5801618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5819085SAli.Bahrami@Sun.COM table_enc, ehdr->e_ident, shdr->sh_addr, 5829085SAli.Bahrami@Sun.COM ndx))); 5831618Srie } 5849085SAli.Bahrami@Sun.COM } else { /* Display the .eh_frame section */ 5859085SAli.Bahrami@Sun.COM frame_cnt++; 5869085SAli.Bahrami@Sun.COM if (frame_cnt == 1) { 5879085SAli.Bahrami@Sun.COM frame_ndx = cnt; 5889085SAli.Bahrami@Sun.COM save_frame_base = shdr->sh_addr; 5899085SAli.Bahrami@Sun.COM } else if ((frame_cnt > 1) && 5909085SAli.Bahrami@Sun.COM (ehdr->e_type != ET_REL)) { 5919085SAli.Bahrami@Sun.COM Conv_inv_buf_t inv_buf; 5929085SAli.Bahrami@Sun.COM 5939085SAli.Bahrami@Sun.COM (void) fprintf(stderr, 5949085SAli.Bahrami@Sun.COM MSG_INTL(MSG_WARN_MULTEHFRM), file, 5959085SAli.Bahrami@Sun.COM EC_WORD(cnt), _cache->c_name, 596*9273SAli.Bahrami@Sun.COM conv_ehdr_type(osabi, ehdr->e_type, 597*9273SAli.Bahrami@Sun.COM 0, &inv_buf)); 5989085SAli.Bahrami@Sun.COM } 5999085SAli.Bahrami@Sun.COM dump_eh_frame(data, datasize, shdr->sh_addr, 6009085SAli.Bahrami@Sun.COM ehdr->e_machine, ehdr->e_ident); 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate /* 6049131SRod.Evans@Sun.COM * If we've seen the .eh_frame_hdr and the first .eh_frame 6059131SRod.Evans@Sun.COM * section, compare the header frame_ptr to the address of the 6069131SRod.Evans@Sun.COM * actual frame section to ensure the link-editor got this 6079131SRod.Evans@Sun.COM * right. Note, this diagnostic is only produced when unwind 6089131SRod.Evans@Sun.COM * information is explicitly asked for, as shared objects built 6099131SRod.Evans@Sun.COM * with an older ld(1) may reveal this inconsistency. Although 6109131SRod.Evans@Sun.COM * an inconsistency, it doesn't seem to have any adverse effect 6119131SRod.Evans@Sun.COM * on existing tools. 6120Sstevel@tonic-gate */ 6139131SRod.Evans@Sun.COM if (((flags & FLG_MASK_SHOW) != FLG_MASK_SHOW) && 6149131SRod.Evans@Sun.COM (hdr_cnt > 0) && (frame_cnt > 0) && 6159085SAli.Bahrami@Sun.COM (save_frame_ptr != save_frame_base)) 6169085SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADEHFRMPTR), 6179085SAli.Bahrami@Sun.COM file, EC_WORD(hdr_ndx), cache[hdr_ndx].c_name, 6189085SAli.Bahrami@Sun.COM EC_XWORD(save_frame_ptr), EC_WORD(frame_ndx), 6199085SAli.Bahrami@Sun.COM cache[frame_ndx].c_name, EC_XWORD(save_frame_base)); 6200Sstevel@tonic-gate } 6219085SAli.Bahrami@Sun.COM 6229085SAli.Bahrami@Sun.COM #undef MSG_UNW_BINSRTAB2 6239085SAli.Bahrami@Sun.COM #undef MSG_UNW_BINSRTABENT 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate /* 6270Sstevel@tonic-gate * Print the hardware/software capabilities. For executables and shared objects 6280Sstevel@tonic-gate * this should be accompanied with a program header. 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate static void 6311618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, 6321618Srie Elf *elf) 6330Sstevel@tonic-gate { 6341618Srie Word cnt; 6357833SRod.Evans@Sun.COM Shdr *cshdr = NULL; 6363466Srie Cache *ccache; 6371618Srie Off cphdr_off = 0; 6381618Srie Xword cphdr_sz; 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate /* 6410Sstevel@tonic-gate * Determine if a hardware/software capabilities header exists. 6420Sstevel@tonic-gate */ 6431618Srie if (phnum) { 6441618Srie Phdr *phdr; 6450Sstevel@tonic-gate 6461618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 6470Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 6480Sstevel@tonic-gate return; 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6511618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 6521618Srie if (phdr->p_type == PT_SUNWCAP) { 6531618Srie cphdr_off = phdr->p_offset; 6541618Srie cphdr_sz = phdr->p_filesz; 6551618Srie break; 6561618Srie } 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate /* 6610Sstevel@tonic-gate * Determine if a hardware/software capabilities section exists. 6620Sstevel@tonic-gate */ 6630Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 6641618Srie Cache *_cache = &cache[cnt]; 6651618Srie Shdr *shdr = _cache->c_shdr; 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_cap) 6680Sstevel@tonic-gate continue; 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 6710Sstevel@tonic-gate (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 6720Sstevel@tonic-gate continue; 6730Sstevel@tonic-gate 6743466Srie if (_cache->c_data == NULL) 6753466Srie continue; 6763466Srie 6770Sstevel@tonic-gate ccache = _cache; 6780Sstevel@tonic-gate cshdr = shdr; 6790Sstevel@tonic-gate break; 6800Sstevel@tonic-gate } 6810Sstevel@tonic-gate 6827833SRod.Evans@Sun.COM if ((cshdr == NULL) && (cphdr_off == 0)) 6830Sstevel@tonic-gate return; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * Print the hardware/software capabilities section. 6870Sstevel@tonic-gate */ 6880Sstevel@tonic-gate if (cshdr) { 6891618Srie Word ndx, capn; 6903492Sab196087 Cap *cap = (Cap *)ccache->c_data->d_buf; 6910Sstevel@tonic-gate 6924665Sab196087 if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) { 6934665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 6944665Sab196087 file, ccache->c_name); 6954665Sab196087 return; 6964665Sab196087 } 6974665Sab196087 6981618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 6991618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 7000Sstevel@tonic-gate 7011618Srie Elf_cap_title(0); 7021618Srie 7031618Srie capn = (Word)(cshdr->sh_size / cshdr->sh_entsize); 7040Sstevel@tonic-gate 7051618Srie for (ndx = 0; ndx < capn; cap++, ndx++) { 7067833SRod.Evans@Sun.COM if (cap->c_tag == CA_SUNW_NULL) 7077833SRod.Evans@Sun.COM continue; 7087833SRod.Evans@Sun.COM 7097833SRod.Evans@Sun.COM Elf_cap_entry(0, cap, ndx, ehdr->e_machine); 7107833SRod.Evans@Sun.COM 7117833SRod.Evans@Sun.COM /* 7127833SRod.Evans@Sun.COM * An SF1_SUNW_ADDR32 software capability in a 32-bit 7137833SRod.Evans@Sun.COM * object is suspicious as it has no effect. 7147833SRod.Evans@Sun.COM */ 7157833SRod.Evans@Sun.COM if ((cap->c_tag == CA_SUNW_SF_1) && 7167833SRod.Evans@Sun.COM (ehdr->e_ident[EI_CLASS] == ELFCLASS32) && 7177833SRod.Evans@Sun.COM (cap->c_un.c_val & SF1_SUNW_ADDR32)) { 7187833SRod.Evans@Sun.COM (void) fprintf(stderr, 7197833SRod.Evans@Sun.COM MSG_INTL(MSG_WARN_INADDR32SF1), 7207833SRod.Evans@Sun.COM file, ccache->c_name); 7217833SRod.Evans@Sun.COM } 7220Sstevel@tonic-gate } 7230Sstevel@tonic-gate } else 7240Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate /* 7270Sstevel@tonic-gate * If this object is an executable or shared object, then the 7280Sstevel@tonic-gate * hardware/software capabilities section should have an accompanying 7290Sstevel@tonic-gate * program header. 7300Sstevel@tonic-gate */ 7310Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 7320Sstevel@tonic-gate if (cphdr_off == 0) 7330Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 7340Sstevel@tonic-gate file, ccache->c_name); 7350Sstevel@tonic-gate else if ((cphdr_off != cshdr->sh_offset) || 7360Sstevel@tonic-gate (cphdr_sz != cshdr->sh_size)) 7370Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 7380Sstevel@tonic-gate file, ccache->c_name); 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate /* 7430Sstevel@tonic-gate * Print the interpretor. 7440Sstevel@tonic-gate */ 7450Sstevel@tonic-gate static void 7461618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) 7470Sstevel@tonic-gate { 7489085SAli.Bahrami@Sun.COM static Word phdr_types[] = { PT_INTERP }; 7499085SAli.Bahrami@Sun.COM 7509085SAli.Bahrami@Sun.COM 7511618Srie Word cnt; 7529085SAli.Bahrami@Sun.COM Shdr *ishdr = NULL; 7531618Srie Cache *icache; 7541618Srie Off iphdr_off = 0; 7551618Srie Xword iphdr_fsz; 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate /* 7580Sstevel@tonic-gate * Determine if an interp header exists. 7590Sstevel@tonic-gate */ 7601618Srie if (phnum) { 7611618Srie Phdr *phdr; 7620Sstevel@tonic-gate 7639085SAli.Bahrami@Sun.COM phdr = getphdr(phnum, phdr_types, 7649085SAli.Bahrami@Sun.COM sizeof (phdr_types) / sizeof (*phdr_types), file, elf); 7659085SAli.Bahrami@Sun.COM if (phdr != NULL) { 7661618Srie iphdr_off = phdr->p_offset; 7671618Srie iphdr_fsz = phdr->p_filesz; 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate } 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate if (iphdr_off == 0) 7720Sstevel@tonic-gate return; 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate /* 7750Sstevel@tonic-gate * Determine if an interp section exists. 7760Sstevel@tonic-gate */ 7770Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 7781618Srie Cache *_cache = &cache[cnt]; 7791618Srie Shdr *shdr = _cache->c_shdr; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate /* 7820Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP 7830Sstevel@tonic-gate * string. The target section can't be in a NOBITS section. 7840Sstevel@tonic-gate */ 7850Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) || 7860Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) || 7871618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size)) 7880Sstevel@tonic-gate continue; 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate icache = _cache; 7910Sstevel@tonic-gate ishdr = shdr; 7920Sstevel@tonic-gate break; 7930Sstevel@tonic-gate } 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate /* 7960Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the 7970Sstevel@tonic-gate * program header, as this is the offset used by the kernel. 7980Sstevel@tonic-gate */ 7993466Srie if (ishdr && icache->c_data) { 8001618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8011618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 8021618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), 8030Sstevel@tonic-gate (char *)icache->c_data->d_buf + 8040Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset)); 8050Sstevel@tonic-gate } else 8060Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate /* 8090Sstevel@tonic-gate * If there are any inconsistences between the program header and 8100Sstevel@tonic-gate * section information, flag them. 8110Sstevel@tonic-gate */ 8120Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) || 8131618Srie (iphdr_fsz != ishdr->sh_size))) { 8140Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 8150Sstevel@tonic-gate icache->c_name); 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate /* 8200Sstevel@tonic-gate * Print the syminfo section. 8210Sstevel@tonic-gate */ 8220Sstevel@tonic-gate static void 8231618Srie syminfo(Cache *cache, Word shnum, const char *file) 8240Sstevel@tonic-gate { 8251618Srie Shdr *infoshdr; 8261618Srie Syminfo *info; 8271618Srie Sym *syms; 8281618Srie Dyn *dyns; 8291618Srie Word infonum, cnt, ndx, symnum; 8309085SAli.Bahrami@Sun.COM Cache *infocache = NULL, *symsec, *strsec; 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8331618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { 8341618Srie infocache = &cache[cnt]; 8350Sstevel@tonic-gate break; 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate } 8389085SAli.Bahrami@Sun.COM if (infocache == NULL) 8390Sstevel@tonic-gate return; 8400Sstevel@tonic-gate 8411618Srie infoshdr = infocache->c_shdr; 8421618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) { 8430Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8441618Srie file, infocache->c_name); 8450Sstevel@tonic-gate return; 8460Sstevel@tonic-gate } 8473466Srie if (infocache->c_data == NULL) 8483466Srie return; 8493466Srie 8501618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize); 8511618Srie info = (Syminfo *)infocache->c_data->d_buf; 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate /* 8540Sstevel@tonic-gate * Get the data buffer of the associated dynamic section. 8550Sstevel@tonic-gate */ 8561618Srie if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) { 8570Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 8581618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info)); 8590Sstevel@tonic-gate return; 8600Sstevel@tonic-gate } 8613466Srie if (cache[infoshdr->sh_info].c_data == NULL) 8623466Srie return; 8633466Srie 8641618Srie dyns = cache[infoshdr->sh_info].c_data->d_buf; 8659085SAli.Bahrami@Sun.COM if (dyns == NULL) { 8660Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8671618Srie file, cache[infoshdr->sh_info].c_name); 8680Sstevel@tonic-gate return; 8690Sstevel@tonic-gate } 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate /* 8721618Srie * Get the data buffer for the associated symbol table and string table. 8730Sstevel@tonic-gate */ 8741618Srie if (stringtbl(cache, 1, cnt, shnum, file, 8751618Srie &symnum, &symsec, &strsec) == 0) 8760Sstevel@tonic-gate return; 8770Sstevel@tonic-gate 8781618Srie syms = symsec->c_data->d_buf; 8790Sstevel@tonic-gate 8801618Srie /* 8811618Srie * Loop through the syminfo entries. 8821618Srie */ 8831618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8841618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name); 8851618Srie Elf_syminfo_title(0); 8860Sstevel@tonic-gate 8871618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) { 8881618Srie Sym *sym; 8899085SAli.Bahrami@Sun.COM const char *needed = NULL, *name; 8901618Srie 8911618Srie if ((info->si_flags == 0) && (info->si_boundto == 0)) 8920Sstevel@tonic-gate continue; 8930Sstevel@tonic-gate 8941618Srie sym = &syms[ndx]; 8951618Srie name = string(infocache, ndx, strsec, file, sym->st_name); 8960Sstevel@tonic-gate 8971618Srie if (info->si_boundto < SYMINFO_BT_LOWRESERVE) { 8981618Srie Dyn *dyn = &dyns[info->si_boundto]; 8991618Srie 9001618Srie needed = string(infocache, info->si_boundto, 9011618Srie strsec, file, dyn->d_un.d_val); 9020Sstevel@tonic-gate } 9031618Srie Elf_syminfo_entry(0, ndx, info, name, needed); 9040Sstevel@tonic-gate } 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate /* 9080Sstevel@tonic-gate * Print version definition section entries. 9090Sstevel@tonic-gate */ 9100Sstevel@tonic-gate static void 9114716Sab196087 version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache, 9120Sstevel@tonic-gate const char *file) 9130Sstevel@tonic-gate { 9141618Srie Word cnt; 9151618Srie char index[MAXNDXSIZE]; 9160Sstevel@tonic-gate 9171618Srie Elf_ver_def_title(0); 9180Sstevel@tonic-gate 9194716Sab196087 for (cnt = 1; cnt <= vdf_num; cnt++, 9201618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 9217682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 9227682SAli.Bahrami@Sun.COM const char *name, *dep; 9237682SAli.Bahrami@Sun.COM Half vcnt = vdf->vd_cnt - 1; 9247682SAli.Bahrami@Sun.COM Half ndx = vdf->vd_ndx; 9257682SAli.Bahrami@Sun.COM Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate /* 9280Sstevel@tonic-gate * Obtain the name and first dependency (if any). 9290Sstevel@tonic-gate */ 9300Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name); 9311618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9320Sstevel@tonic-gate if (vcnt) 9330Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name); 9340Sstevel@tonic-gate else 9350Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 9380Sstevel@tonic-gate EC_XWORD(ndx)); 9391618Srie Elf_ver_line_1(0, index, name, dep, 9407682SAli.Bahrami@Sun.COM conv_ver_flags(vdf->vd_flags, 0, &ver_flags_buf)); 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate /* 9430Sstevel@tonic-gate * Print any additional dependencies. 9440Sstevel@tonic-gate */ 9450Sstevel@tonic-gate if (vcnt) { 9461618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9470Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 9481618Srie vdap = (Verdaux *)((uintptr_t)vdap + 9490Sstevel@tonic-gate vdap->vda_next)) { 9500Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 9510Sstevel@tonic-gate vdap->vda_name); 9521618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep); 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate /* 9594716Sab196087 * Print version needed section entries. 9604716Sab196087 * 9614716Sab196087 * entry: 9624716Sab196087 * vnd - Address of verneed data 9634716Sab196087 * vnd_num - # of Verneed entries 9644716Sab196087 * vcache - Cache of verneed section being processed 9654716Sab196087 * scache - Cache of associated string table section 9664716Sab196087 * file - Name of object being processed. 9674716Sab196087 * versym - Information about versym section 9684716Sab196087 * 9694716Sab196087 * exit: 9704716Sab196087 * The versions have been printed. If GNU style versioning 9714716Sab196087 * is in effect, versym->max_verndx has been updated to 9724716Sab196087 * contain the largest version index seen. 9737682SAli.Bahrami@Sun.COM * 9747682SAli.Bahrami@Sun.COM * note: 9757682SAli.Bahrami@Sun.COM * The versym section of an object that follows the original 9767682SAli.Bahrami@Sun.COM * Solaris versioning rules only contains indexes into the verdef 9777682SAli.Bahrami@Sun.COM * section. Symbols defined in other objects (UNDEF) are given 9787682SAli.Bahrami@Sun.COM * a version of 0, indicating that they are not defined by 9797682SAli.Bahrami@Sun.COM * this file, and the Verneed entries do not have associated version 9807682SAli.Bahrami@Sun.COM * indexes. For these reasons, we do not display a version index 9817682SAli.Bahrami@Sun.COM * for original-style Verneed sections. 9827682SAli.Bahrami@Sun.COM * 9837682SAli.Bahrami@Sun.COM * The GNU versioning extensions alter this: Symbols defined in other 9847682SAli.Bahrami@Sun.COM * objects receive a version index in the range above those defined 9857682SAli.Bahrami@Sun.COM * by the Verdef section, and the vna_other field of the Vernaux 9867682SAli.Bahrami@Sun.COM * structs inside the Verneed section contain the version index for 9877682SAli.Bahrami@Sun.COM * that item. We therefore display the index when showing the 9887682SAli.Bahrami@Sun.COM * contents of a GNU style Verneed section. You should not 9897682SAli.Bahrami@Sun.COM * necessarily expect these indexes to appear in sorted 9907682SAli.Bahrami@Sun.COM * order --- it seems that the GNU ld assigns the versions as 9917682SAli.Bahrami@Sun.COM * symbols are encountered during linking, and then the results 9927682SAli.Bahrami@Sun.COM * are assembled into the Verneed section afterwards. 9930Sstevel@tonic-gate */ 9940Sstevel@tonic-gate static void 9954716Sab196087 version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache, 9964716Sab196087 const char *file, VERSYM_STATE *versym) 9970Sstevel@tonic-gate { 9984716Sab196087 Word cnt; 9994716Sab196087 char index[MAXNDXSIZE]; 10004716Sab196087 const char *index_str; 10014716Sab196087 10027682SAli.Bahrami@Sun.COM Elf_ver_need_title(0, versym->gnu_needed); 10034716Sab196087 10044716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 10051618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 10067682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 10077682SAli.Bahrami@Sun.COM const char *name, *dep; 10087682SAli.Bahrami@Sun.COM Half vcnt = vnd->vn_cnt; 10094433Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate /* 10120Sstevel@tonic-gate * Obtain the name of the needed file and the version name 10130Sstevel@tonic-gate * within it that we're dependent on. Note that the count 10140Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus 10150Sstevel@tonic-gate * entry. 10160Sstevel@tonic-gate */ 10170Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file); 10180Sstevel@tonic-gate if (vcnt) 10190Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name); 10200Sstevel@tonic-gate else 10210Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL); 10220Sstevel@tonic-gate 10237682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) { /* Traditional form */ 10247682SAli.Bahrami@Sun.COM index_str = MSG_ORIG(MSG_STR_EMPTY); 10257682SAli.Bahrami@Sun.COM } else { /* GNU form */ 10267682SAli.Bahrami@Sun.COM index_str = index; 10274716Sab196087 /* Format the version index value */ 10284716Sab196087 (void) snprintf(index, MAXNDXSIZE, 10294716Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(vnap->vna_other)); 10304716Sab196087 if (vnap->vna_other > versym->max_verndx) 10314716Sab196087 versym->max_verndx = vnap->vna_other; 10324716Sab196087 } 10334716Sab196087 Elf_ver_line_1(0, index_str, name, dep, 10347682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 0, &ver_flags_buf)); 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate /* 10370Sstevel@tonic-gate * Print any additional version dependencies. 10380Sstevel@tonic-gate */ 10390Sstevel@tonic-gate if (vcnt) { 10401618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 10410Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 10421618Srie vnap = (Vernaux *)((uintptr_t)vnap + 10430Sstevel@tonic-gate vnap->vna_next)) { 10440Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 10450Sstevel@tonic-gate vnap->vna_name); 10467682SAli.Bahrami@Sun.COM if (vnap->vna_other > 0) { 10474716Sab196087 /* Format the next index value */ 10484716Sab196087 (void) snprintf(index, MAXNDXSIZE, 10494716Sab196087 MSG_ORIG(MSG_FMT_INDEX), 10504716Sab196087 EC_XWORD(vnap->vna_other)); 10517682SAli.Bahrami@Sun.COM Elf_ver_line_1(0, index, 10524716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 10537682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 10547682SAli.Bahrami@Sun.COM 0, &ver_flags_buf)); 10554716Sab196087 if (vnap->vna_other > 10564716Sab196087 versym->max_verndx) 10574716Sab196087 versym->max_verndx = 10584716Sab196087 vnap->vna_other; 10594716Sab196087 } else { 10604716Sab196087 Elf_ver_line_3(0, 10614716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 10627682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 10637682SAli.Bahrami@Sun.COM 0, &ver_flags_buf)); 10644716Sab196087 } 10654716Sab196087 } 10664716Sab196087 } 10674716Sab196087 } 10684716Sab196087 } 10694716Sab196087 10704716Sab196087 /* 10717682SAli.Bahrami@Sun.COM * Examine the Verneed section for information related to GNU 10727682SAli.Bahrami@Sun.COM * style Versym indexing: 10737682SAli.Bahrami@Sun.COM * - A non-zero vna_other field indicates that Versym indexes can 10747682SAli.Bahrami@Sun.COM * reference Verneed records. 10757682SAli.Bahrami@Sun.COM * - If the object uses GNU style Versym indexing, the 10767682SAli.Bahrami@Sun.COM * maximum index value is needed to detect bad Versym entries. 10774716Sab196087 * 10784716Sab196087 * entry: 10794716Sab196087 * vnd - Address of verneed data 10804716Sab196087 * vnd_num - # of Verneed entries 10814716Sab196087 * versym - Information about versym section 10824716Sab196087 * 10834716Sab196087 * exit: 10847682SAli.Bahrami@Sun.COM * If a non-zero vna_other field is seen, versym->gnu_needed is set. 10857682SAli.Bahrami@Sun.COM * 10864716Sab196087 * versym->max_verndx has been updated to contain the largest 10874716Sab196087 * version index seen. 10884716Sab196087 */ 10894716Sab196087 static void 10907682SAli.Bahrami@Sun.COM update_gnu_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym) 10914716Sab196087 { 10924716Sab196087 Word cnt; 10934716Sab196087 10944716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 10954716Sab196087 vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 10964716Sab196087 Half vcnt = vnd->vn_cnt; 10974716Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 10984716Sab196087 10997682SAli.Bahrami@Sun.COM /* 11007682SAli.Bahrami@Sun.COM * A non-zero value of vna_other indicates that this 11017682SAli.Bahrami@Sun.COM * object references VERNEED items from the VERSYM 11027682SAli.Bahrami@Sun.COM * array. 11037682SAli.Bahrami@Sun.COM */ 11047682SAli.Bahrami@Sun.COM if (vnap->vna_other != 0) { 11057682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 11067682SAli.Bahrami@Sun.COM if (vnap->vna_other > versym->max_verndx) 11077682SAli.Bahrami@Sun.COM versym->max_verndx = vnap->vna_other; 11087682SAli.Bahrami@Sun.COM } 11094716Sab196087 11104716Sab196087 /* 11114716Sab196087 * Check any additional version dependencies. 11124716Sab196087 */ 11134716Sab196087 if (vcnt) { 11144716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 11154716Sab196087 for (vcnt--; vcnt; vcnt--, 11164716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + 11174716Sab196087 vnap->vna_next)) { 11187682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) 11197682SAli.Bahrami@Sun.COM continue; 11207682SAli.Bahrami@Sun.COM 11217682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 11224716Sab196087 if (vnap->vna_other > versym->max_verndx) 11234716Sab196087 versym->max_verndx = vnap->vna_other; 11240Sstevel@tonic-gate } 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate } 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate /* 11303875Sab196087 * Display version section information if the flags require it. 11313875Sab196087 * Return version information needed by other output. 11323875Sab196087 * 11333875Sab196087 * entry: 11343875Sab196087 * cache - Cache of all section headers 11353875Sab196087 * shnum - # of sections in cache 11363875Sab196087 * file - Name of file 11373875Sab196087 * flags - Command line option flags 11383875Sab196087 * versym - VERSYM_STATE block to be filled in. 11390Sstevel@tonic-gate */ 11403875Sab196087 static void 11413875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags, 11423875Sab196087 VERSYM_STATE *versym) 11430Sstevel@tonic-gate { 11440Sstevel@tonic-gate GElf_Word cnt; 11454716Sab196087 Cache *verdef_cache = NULL, *verneed_cache = NULL; 11464716Sab196087 11474716Sab196087 11484716Sab196087 /* Gather information about the version sections */ 11493875Sab196087 bzero(versym, sizeof (*versym)); 11504716Sab196087 versym->max_verndx = 1; 11510Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 11521618Srie Cache *_cache = &cache[cnt]; 11531618Srie Shdr *shdr = _cache->c_shdr; 11544716Sab196087 Dyn *dyn; 11554716Sab196087 ulong_t numdyn; 11564716Sab196087 11574716Sab196087 switch (shdr->sh_type) { 11584716Sab196087 case SHT_DYNAMIC: 11594716Sab196087 /* 11604716Sab196087 * The GNU ld puts a DT_VERSYM entry in the dynamic 11614716Sab196087 * section so that the runtime linker can use it to 11624716Sab196087 * implement their versioning rules. They allow multiple 11634716Sab196087 * incompatible functions with the same name to exist 11644716Sab196087 * in different versions. The Solaris ld does not 11654716Sab196087 * support this mechanism, and as such, does not 11664716Sab196087 * produce DT_VERSYM. We use this fact to determine 11674716Sab196087 * which ld produced this object, and how to interpret 11684716Sab196087 * the version values. 11694716Sab196087 */ 11704716Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0) || 11714716Sab196087 (_cache->c_data == NULL)) 11724716Sab196087 continue; 11734716Sab196087 numdyn = shdr->sh_size / shdr->sh_entsize; 11744716Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 11754716Sab196087 for (; numdyn-- > 0; dyn++) 11764716Sab196087 if (dyn->d_tag == DT_VERSYM) { 11777682SAli.Bahrami@Sun.COM versym->gnu_full = 11787682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 11794716Sab196087 break; 11804716Sab196087 } 11814716Sab196087 break; 11824716Sab196087 11834716Sab196087 case SHT_SUNW_versym: 11844716Sab196087 /* Record data address for later symbol processing */ 11854716Sab196087 if (_cache->c_data != NULL) { 11864716Sab196087 versym->cache = _cache; 11874716Sab196087 versym->data = _cache->c_data->d_buf; 11884716Sab196087 continue; 11894716Sab196087 } 11904716Sab196087 break; 11914716Sab196087 11924716Sab196087 case SHT_SUNW_verdef: 11934716Sab196087 case SHT_SUNW_verneed: 11944716Sab196087 /* 11954716Sab196087 * Ensure the data is non-NULL and the number 11964716Sab196087 * of items is non-zero. Otherwise, we don't 11974716Sab196087 * understand the section, and will not use it. 11984716Sab196087 */ 11994716Sab196087 if ((_cache->c_data == NULL) || 12004716Sab196087 (_cache->c_data->d_buf == NULL)) { 12014716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 12024716Sab196087 file, _cache->c_name); 12034716Sab196087 continue; 12044716Sab196087 } 12054716Sab196087 if (shdr->sh_info == 0) { 12064716Sab196087 (void) fprintf(stderr, 12074716Sab196087 MSG_INTL(MSG_ERR_BADSHINFO), 12084716Sab196087 file, _cache->c_name, 12094716Sab196087 EC_WORD(shdr->sh_info)); 12104716Sab196087 continue; 12114716Sab196087 } 12124716Sab196087 12134716Sab196087 /* Make sure the string table index is in range */ 12144716Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 12154716Sab196087 (void) fprintf(stderr, 12164716Sab196087 MSG_INTL(MSG_ERR_BADSHLINK), file, 12174716Sab196087 _cache->c_name, EC_WORD(shdr->sh_link)); 12184716Sab196087 continue; 12194716Sab196087 } 12204716Sab196087 12214716Sab196087 /* 12224716Sab196087 * The section is usable. Save the cache entry. 12234716Sab196087 */ 12244716Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) { 12254716Sab196087 verdef_cache = _cache; 12264716Sab196087 /* 12274716Sab196087 * Under Solaris rules, if there is a verdef 12284716Sab196087 * section, the max versym index is number 12294716Sab196087 * of version definitions it supplies. 12304716Sab196087 */ 12314716Sab196087 versym->max_verndx = shdr->sh_info; 12324716Sab196087 } else { 12334716Sab196087 verneed_cache = _cache; 12344716Sab196087 } 12354716Sab196087 break; 12364716Sab196087 } 12374716Sab196087 } 12384716Sab196087 12397682SAli.Bahrami@Sun.COM /* 12407682SAli.Bahrami@Sun.COM * If there is a Verneed section, examine it for information 12417682SAli.Bahrami@Sun.COM * related to GNU style versioning. 12427682SAli.Bahrami@Sun.COM */ 12437682SAli.Bahrami@Sun.COM if (verneed_cache != NULL) 12447682SAli.Bahrami@Sun.COM update_gnu_verndx((Verneed *)verneed_cache->c_data->d_buf, 12457682SAli.Bahrami@Sun.COM verneed_cache->c_shdr->sh_info, versym); 12464716Sab196087 12474716Sab196087 /* 12484716Sab196087 * Now that all the information is available, display the 12497682SAli.Bahrami@Sun.COM * Verdef and Verneed section contents, if requested. 12504716Sab196087 */ 12517682SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_VERSIONS) == 0) 12527682SAli.Bahrami@Sun.COM return; 12534716Sab196087 if (verdef_cache != NULL) { 12544716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 12554716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), 12564716Sab196087 verdef_cache->c_name); 12574716Sab196087 version_def((Verdef *)verdef_cache->c_data->d_buf, 12584716Sab196087 verdef_cache->c_shdr->sh_info, verdef_cache, 12594716Sab196087 &cache[verdef_cache->c_shdr->sh_link], file); 12604716Sab196087 } 12614716Sab196087 if (verneed_cache != NULL) { 12624716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 12634716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), 12644716Sab196087 verneed_cache->c_name); 12650Sstevel@tonic-gate /* 12664716Sab196087 * If GNU versioning applies to this object, version_need() 12674716Sab196087 * will update versym->max_verndx, and it is not 12687682SAli.Bahrami@Sun.COM * necessary to call update_gnu_verndx(). 12690Sstevel@tonic-gate */ 12704716Sab196087 version_need((Verneed *)verneed_cache->c_data->d_buf, 12714716Sab196087 verneed_cache->c_shdr->sh_info, verneed_cache, 12724716Sab196087 &cache[verneed_cache->c_shdr->sh_link], file, versym); 12730Sstevel@tonic-gate } 12740Sstevel@tonic-gate } 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate /* 12773492Sab196087 * Initialize a symbol table state structure 12783492Sab196087 * 12793492Sab196087 * entry: 12803492Sab196087 * state - State structure to be initialized 12813492Sab196087 * cache - Cache of all section headers 12823492Sab196087 * shnum - # of sections in cache 12833492Sab196087 * secndx - Index of symbol table section 12843492Sab196087 * ehdr - ELF header for file 12853875Sab196087 * versym - Information about versym section 12863492Sab196087 * file - Name of file 12873492Sab196087 * flags - Command line option flags 12881618Srie */ 12891618Srie static int 12903492Sab196087 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx, 1291*9273SAli.Bahrami@Sun.COM Ehdr *ehdr, uchar_t osabi, VERSYM_STATE *versym, const char *file, 1292*9273SAli.Bahrami@Sun.COM uint_t flags) 12933492Sab196087 { 12943492Sab196087 Shdr *shdr; 12953492Sab196087 12963492Sab196087 state->file = file; 12973492Sab196087 state->ehdr = ehdr; 12983492Sab196087 state->cache = cache; 1299*9273SAli.Bahrami@Sun.COM state->osabi = osabi; 13003492Sab196087 state->shnum = shnum; 13013492Sab196087 state->seccache = &cache[secndx]; 13023492Sab196087 state->secndx = secndx; 13033492Sab196087 state->secname = state->seccache->c_name; 13043492Sab196087 state->flags = flags; 13053492Sab196087 state->shxndx.checked = 0; 13063492Sab196087 state->shxndx.data = NULL; 13073492Sab196087 state->shxndx.n = 0; 13083492Sab196087 13093492Sab196087 shdr = state->seccache->c_shdr; 13103492Sab196087 13113492Sab196087 /* 13123492Sab196087 * Check the symbol data and per-item size. 13133492Sab196087 */ 13143492Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 13153492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 13163492Sab196087 file, state->secname); 13173492Sab196087 return (0); 13183492Sab196087 } 13193492Sab196087 if (state->seccache->c_data == NULL) 13203492Sab196087 return (0); 13213492Sab196087 13223492Sab196087 /* LINTED */ 13233492Sab196087 state->symn = (Word)(shdr->sh_size / shdr->sh_entsize); 13243492Sab196087 state->sym = (Sym *)state->seccache->c_data->d_buf; 13253492Sab196087 13263492Sab196087 /* 13273492Sab196087 * Check associated string table section. 13283492Sab196087 */ 13293492Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 13303492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 13313492Sab196087 file, state->secname, EC_WORD(shdr->sh_link)); 13323492Sab196087 return (0); 13333492Sab196087 } 13343492Sab196087 13353492Sab196087 /* 13363492Sab196087 * Determine if there is a associated Versym section 13373492Sab196087 * with this Symbol Table. 13383492Sab196087 */ 13393875Sab196087 if (versym->cache && 13403875Sab196087 (versym->cache->c_shdr->sh_link == state->secndx)) 13413875Sab196087 state->versym = versym; 13423492Sab196087 else 13433492Sab196087 state->versym = NULL; 13443492Sab196087 13453492Sab196087 13463492Sab196087 return (1); 13473492Sab196087 } 13483492Sab196087 13493492Sab196087 /* 13503492Sab196087 * Determine the extended section index used for symbol tables entries. 13513492Sab196087 */ 13523492Sab196087 static void 13537463SRod.Evans@Sun.COM symbols_getxindex(SYMTBL_STATE *state) 13541618Srie { 13551618Srie uint_t symn; 13561618Srie Word symcnt; 13571618Srie 13583492Sab196087 state->shxndx.checked = 1; /* Note that we've been called */ 13593492Sab196087 for (symcnt = 1; symcnt < state->shnum; symcnt++) { 13603492Sab196087 Cache *_cache = &state->cache[symcnt]; 13611618Srie Shdr *shdr = _cache->c_shdr; 13621618Srie 13631618Srie if ((shdr->sh_type != SHT_SYMTAB_SHNDX) || 13643492Sab196087 (shdr->sh_link != state->secndx)) 13651618Srie continue; 13661618Srie 13671618Srie if ((shdr->sh_entsize) && 13681618Srie /* LINTED */ 13691618Srie ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0)) 13701618Srie continue; 13711618Srie 13723466Srie if (_cache->c_data == NULL) 13733466Srie continue; 13743466Srie 13753492Sab196087 state->shxndx.data = _cache->c_data->d_buf; 13763492Sab196087 state->shxndx.n = symn; 13773492Sab196087 return; 13781618Srie } 13791618Srie } 13801618Srie 13811618Srie /* 13823492Sab196087 * Produce a line of output for the given symbol 13833492Sab196087 * 13843492Sab196087 * entry: 13853875Sab196087 * state - Symbol table state 13863492Sab196087 * symndx - Index of symbol within the table 13874832Srie * info - Value of st_info (indicates local/global range) 13883492Sab196087 * symndx_disp - Index to display. This may not be the same 13893492Sab196087 * as symndx if the display is relative to the logical 13903492Sab196087 * combination of the SUNW_ldynsym/dynsym tables. 13913492Sab196087 * sym - Symbol to display 13920Sstevel@tonic-gate */ 13933492Sab196087 static void 13944832Srie output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx, 13954832Srie Sym *sym) 13960Sstevel@tonic-gate { 13973118Sab196087 /* 13983118Sab196087 * Symbol types for which we check that the specified 13993118Sab196087 * address/size land inside the target section. 14003118Sab196087 */ 14019085SAli.Bahrami@Sun.COM static const int addr_symtype[] = { 14023118Sab196087 0, /* STT_NOTYPE */ 14033118Sab196087 1, /* STT_OBJECT */ 14043118Sab196087 1, /* STT_FUNC */ 14053118Sab196087 0, /* STT_SECTION */ 14063118Sab196087 0, /* STT_FILE */ 14073118Sab196087 1, /* STT_COMMON */ 14083118Sab196087 0, /* STT_TLS */ 14099085SAli.Bahrami@Sun.COM 0, /* STT_IFUNC */ 14109085SAli.Bahrami@Sun.COM 0, /* 8 */ 14119085SAli.Bahrami@Sun.COM 0, /* 9 */ 14129085SAli.Bahrami@Sun.COM 0, /* 10 */ 14139085SAli.Bahrami@Sun.COM 0, /* 11 */ 14149085SAli.Bahrami@Sun.COM 0, /* 12 */ 14159085SAli.Bahrami@Sun.COM 0, /* STT_SPARC_REGISTER */ 14169085SAli.Bahrami@Sun.COM 0, /* 14 */ 14179085SAli.Bahrami@Sun.COM 0, /* 15 */ 14183118Sab196087 }; 14199085SAli.Bahrami@Sun.COM #if STT_NUM != (STT_IFUNC + 1) 14203492Sab196087 #error "STT_NUM has grown. Update addr_symtype[]" 14213118Sab196087 #endif 14223118Sab196087 14234665Sab196087 char index[MAXNDXSIZE]; 14244665Sab196087 const char *symname, *sec; 14253875Sab196087 Versym verndx; 14264716Sab196087 int gnuver; 14273492Sab196087 uchar_t type; 14283492Sab196087 Shdr *tshdr; 14293492Sab196087 Word shndx; 14304734Sab196087 Conv_inv_buf_t inv_buf; 14313492Sab196087 14323492Sab196087 /* Ensure symbol index is in range */ 14333492Sab196087 if (symndx >= state->symn) { 14343492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX), 14353492Sab196087 state->file, state->secname, EC_WORD(symndx)); 14363492Sab196087 return; 14373492Sab196087 } 14383492Sab196087 14393492Sab196087 /* 14403492Sab196087 * If we are using extended symbol indexes, find the 14413492Sab196087 * corresponding SHN_SYMTAB_SHNDX table. 14423492Sab196087 */ 14433492Sab196087 if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0)) 14443492Sab196087 symbols_getxindex(state); 14453492Sab196087 14463492Sab196087 /* LINTED */ 14473492Sab196087 symname = string(state->seccache, symndx, 14483492Sab196087 &state->cache[state->seccache->c_shdr->sh_link], state->file, 14493492Sab196087 sym->st_name); 14503492Sab196087 14519085SAli.Bahrami@Sun.COM tshdr = NULL; 14523492Sab196087 sec = NULL; 14533492Sab196087 14544665Sab196087 if (state->ehdr->e_type == ET_CORE) { 14553492Sab196087 sec = (char *)MSG_INTL(MSG_STR_UNKNOWN); 14565411Sab196087 } else if (state->flags & FLG_CTL_FAKESHDR) { 14574665Sab196087 /* 14584665Sab196087 * If we are using fake section headers derived from 14594665Sab196087 * the program headers, then the section indexes 14604665Sab196087 * in the symbols do not correspond to these headers. 14614665Sab196087 * The section names are not available, so all we can 14624665Sab196087 * do is to display them in numeric form. 14634665Sab196087 */ 1464*9273SAli.Bahrami@Sun.COM sec = conv_sym_shndx(state->osabi, state->ehdr->e_machine, 1465*9273SAli.Bahrami@Sun.COM sym->st_shndx, CONV_FMT_DECIMAL, &inv_buf); 14664665Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 14673492Sab196087 (sym->st_shndx < state->shnum)) { 14683492Sab196087 shndx = sym->st_shndx; 14693492Sab196087 tshdr = state->cache[shndx].c_shdr; 14703492Sab196087 sec = state->cache[shndx].c_name; 14713492Sab196087 } else if (sym->st_shndx == SHN_XINDEX) { 14723492Sab196087 if (state->shxndx.data) { 14733492Sab196087 Word _shxndx; 14743492Sab196087 14753492Sab196087 if (symndx > state->shxndx.n) { 14764433Sab196087 (void) fprintf(stderr, 14774433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 14784433Sab196087 state->file, state->secname, 14794433Sab196087 EC_WORD(symndx)); 14803492Sab196087 } else if ((_shxndx = 14813492Sab196087 state->shxndx.data[symndx]) > state->shnum) { 14824433Sab196087 (void) fprintf(stderr, 14834433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 14844433Sab196087 state->file, state->secname, 14854433Sab196087 EC_WORD(symndx), EC_WORD(_shxndx)); 14863492Sab196087 } else { 14874433Sab196087 shndx = _shxndx; 14884433Sab196087 tshdr = state->cache[shndx].c_shdr; 14894433Sab196087 sec = state->cache[shndx].c_name; 14903492Sab196087 } 14913492Sab196087 } else { 14923492Sab196087 (void) fprintf(stderr, 14933492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 14943492Sab196087 state->file, state->secname, EC_WORD(symndx)); 14953492Sab196087 } 14963492Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 14973492Sab196087 (sym->st_shndx >= state->shnum)) { 14983492Sab196087 (void) fprintf(stderr, 14993492Sab196087 MSG_INTL(MSG_ERR_BADSYM5), state->file, 15006206Sab196087 state->secname, EC_WORD(symndx), 15016206Sab196087 demangle(symname, state->flags), sym->st_shndx); 15023492Sab196087 } 15030Sstevel@tonic-gate 15043492Sab196087 /* 15053492Sab196087 * If versioning is available display the 15063875Sab196087 * version index. If not, then use 0. 15073492Sab196087 */ 15083875Sab196087 if (state->versym) { 15094716Sab196087 Versym test_verndx; 15104716Sab196087 15114716Sab196087 verndx = test_verndx = state->versym->data[symndx]; 15127682SAli.Bahrami@Sun.COM gnuver = state->versym->gnu_full; 15133875Sab196087 15143875Sab196087 /* 15153875Sab196087 * Check to see if this is a defined symbol with a 15163875Sab196087 * version index that is outside the valid range for 15174716Sab196087 * the file. The interpretation of this depends on 15184716Sab196087 * the style of versioning used by the object. 15193875Sab196087 * 15204716Sab196087 * Versions >= VER_NDX_LORESERVE have special meanings, 15214716Sab196087 * and are exempt from this checking. 15224716Sab196087 * 15234716Sab196087 * GNU style version indexes use the top bit of the 15244716Sab196087 * 16-bit index value (0x8000) as the "hidden bit". 15254716Sab196087 * We must mask off this bit in order to compare 15264716Sab196087 * the version against the maximum value. 15273875Sab196087 */ 15284716Sab196087 if (gnuver) 15294716Sab196087 test_verndx &= ~0x8000; 15304716Sab196087 15314716Sab196087 if ((test_verndx > state->versym->max_verndx) && 15324716Sab196087 (verndx < VER_NDX_LORESERVE)) 15334716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER), 15344716Sab196087 state->file, state->secname, EC_WORD(symndx), 15354716Sab196087 EC_HALF(test_verndx), state->versym->max_verndx); 15363875Sab196087 } else { 15373492Sab196087 verndx = 0; 15384716Sab196087 gnuver = 0; 15393875Sab196087 } 15403492Sab196087 15413492Sab196087 /* 15423492Sab196087 * Error checking for TLS. 15433492Sab196087 */ 15443492Sab196087 type = ELF_ST_TYPE(sym->st_info); 15453492Sab196087 if (type == STT_TLS) { 15463492Sab196087 if (tshdr && 15473492Sab196087 (sym->st_shndx != SHN_UNDEF) && 15483492Sab196087 ((tshdr->sh_flags & SHF_TLS) == 0)) { 15493492Sab196087 (void) fprintf(stderr, 15503492Sab196087 MSG_INTL(MSG_ERR_BADSYM3), state->file, 15516206Sab196087 state->secname, EC_WORD(symndx), 15526206Sab196087 demangle(symname, state->flags)); 15533492Sab196087 } 15543492Sab196087 } else if ((type != STT_SECTION) && sym->st_size && 15553492Sab196087 tshdr && (tshdr->sh_flags & SHF_TLS)) { 15563492Sab196087 (void) fprintf(stderr, 15573492Sab196087 MSG_INTL(MSG_ERR_BADSYM4), state->file, 15586206Sab196087 state->secname, EC_WORD(symndx), 15596206Sab196087 demangle(symname, state->flags)); 15603492Sab196087 } 15613492Sab196087 15623492Sab196087 /* 15633492Sab196087 * If a symbol with non-zero size has a type that 15643492Sab196087 * specifies an address, then make sure the location 15653492Sab196087 * it references is actually contained within the 15663492Sab196087 * section. UNDEF symbols don't count in this case, 15673492Sab196087 * so we ignore them. 15683492Sab196087 * 15693492Sab196087 * The meaning of the st_value field in a symbol 15703492Sab196087 * depends on the type of object. For a relocatable 15713492Sab196087 * object, it is the offset within the section. 15723492Sab196087 * For sharable objects, it is the offset relative to 15733492Sab196087 * the base of the object, and for other types, it is 15743492Sab196087 * the virtual address. To get an offset within the 15753492Sab196087 * section for non-ET_REL files, we subtract the 15763492Sab196087 * base address of the section. 15773492Sab196087 */ 15783492Sab196087 if (addr_symtype[type] && (sym->st_size > 0) && 15793492Sab196087 (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) || 15803492Sab196087 (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) { 15813492Sab196087 Word v = sym->st_value; 15823492Sab196087 if (state->ehdr->e_type != ET_REL) 15834832Srie v -= tshdr->sh_addr; 15843492Sab196087 if (((v + sym->st_size) > tshdr->sh_size)) { 15853492Sab196087 (void) fprintf(stderr, 15863492Sab196087 MSG_INTL(MSG_ERR_BADSYM6), state->file, 15876206Sab196087 state->secname, EC_WORD(symndx), 15886206Sab196087 demangle(symname, state->flags), 15893492Sab196087 EC_WORD(shndx), EC_XWORD(tshdr->sh_size), 15903492Sab196087 EC_XWORD(sym->st_value), EC_XWORD(sym->st_size)); 15913492Sab196087 } 15923492Sab196087 } 15933492Sab196087 15944832Srie /* 15954832Srie * A typical symbol table uses the sh_info field to indicate one greater 15964832Srie * than the symbol table index of the last local symbol, STB_LOCAL. 15974832Srie * Therefore, symbol indexes less than sh_info should have local 15984832Srie * binding. Symbol indexes greater than, or equal to sh_info, should 15994832Srie * have global binding. Note, we exclude UNDEF/NOTY symbols with zero 16004832Srie * value and size, as these symbols may be the result of an mcs(1) 16014832Srie * section deletion. 16024832Srie */ 16034832Srie if (info) { 16044832Srie uchar_t bind = ELF_ST_BIND(sym->st_info); 16054832Srie 16064832Srie if ((symndx < info) && (bind != STB_LOCAL)) { 16074832Srie (void) fprintf(stderr, 16084832Srie MSG_INTL(MSG_ERR_BADSYM7), state->file, 16096206Sab196087 state->secname, EC_WORD(symndx), 16106206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 16114832Srie 16124832Srie } else if ((symndx >= info) && (bind == STB_LOCAL) && 16134832Srie ((sym->st_shndx != SHN_UNDEF) || 16144832Srie (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) || 16154832Srie (sym->st_size != 0) || (sym->st_value != 0))) { 16164832Srie (void) fprintf(stderr, 16174832Srie MSG_INTL(MSG_ERR_BADSYM8), state->file, 16186206Sab196087 state->secname, EC_WORD(symndx), 16196206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 16204832Srie } 16214832Srie } 16224832Srie 16233492Sab196087 (void) snprintf(index, MAXNDXSIZE, 16243492Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx)); 1625*9273SAli.Bahrami@Sun.COM Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, state->osabi, 16264716Sab196087 state->ehdr->e_machine, sym, verndx, gnuver, sec, symname); 16273492Sab196087 } 16283492Sab196087 16293492Sab196087 /* 16303492Sab196087 * Search for and process any symbol tables. 16313492Sab196087 */ 16323492Sab196087 void 1633*9273SAli.Bahrami@Sun.COM symbols(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, 1634*9273SAli.Bahrami@Sun.COM VERSYM_STATE *versym, const char *file, uint_t flags) 16353492Sab196087 { 16363492Sab196087 SYMTBL_STATE state; 16373492Sab196087 Cache *_cache; 16383492Sab196087 Word secndx; 16393492Sab196087 16403492Sab196087 for (secndx = 1; secndx < shnum; secndx++) { 16413492Sab196087 Word symcnt; 16423492Sab196087 Shdr *shdr; 16433492Sab196087 16443492Sab196087 _cache = &cache[secndx]; 16453492Sab196087 shdr = _cache->c_shdr; 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) && 16482766Sab196087 (shdr->sh_type != SHT_DYNSYM) && 1649*9273SAli.Bahrami@Sun.COM ((shdr->sh_type != SHT_SUNW_LDYNSYM) || 1650*9273SAli.Bahrami@Sun.COM (osabi != ELFOSABI_SOLARIS))) 16510Sstevel@tonic-gate continue; 16525411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, secndx, shdr->sh_type)) 16533466Srie continue; 16543466Srie 16553492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr, 1656*9273SAli.Bahrami@Sun.COM osabi, versym, file, flags)) 16570Sstevel@tonic-gate continue; 16580Sstevel@tonic-gate /* 16590Sstevel@tonic-gate * Loop through the symbol tables entries. 16600Sstevel@tonic-gate */ 16611618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 16623492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname); 16631618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 16640Sstevel@tonic-gate 16653492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++) 16664832Srie output_symbol(&state, symcnt, shdr->sh_info, symcnt, 16673492Sab196087 state.sym + symcnt); 16683492Sab196087 } 16693492Sab196087 } 16700Sstevel@tonic-gate 16713492Sab196087 /* 16723492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections. 16733492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair. 16743492Sab196087 */ 16753492Sab196087 static void 1676*9273SAli.Bahrami@Sun.COM sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, 1677*9273SAli.Bahrami@Sun.COM VERSYM_STATE *versym, const char *file, uint_t flags) 16783492Sab196087 { 16793492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state; 16803492Sab196087 Cache *sortcache, *symcache; 16813492Sab196087 Shdr *sortshdr, *symshdr; 16823492Sab196087 Word sortsecndx, symsecndx; 16833492Sab196087 Word ldynsym_cnt; 16843492Sab196087 Word *ndx; 16853492Sab196087 Word ndxn; 16863492Sab196087 int output_cnt = 0; 16874734Sab196087 Conv_inv_buf_t inv_buf; 16880Sstevel@tonic-gate 16893492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) { 16900Sstevel@tonic-gate 16913492Sab196087 sortcache = &cache[sortsecndx]; 16923492Sab196087 sortshdr = sortcache->c_shdr; 16930Sstevel@tonic-gate 16943492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) && 16953492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort)) 16963492Sab196087 continue; 16975411Sab196087 if (!match(MATCH_F_ALL, sortcache->c_name, sortsecndx, 16985411Sab196087 sortshdr->sh_type)) 16993492Sab196087 continue; 17000Sstevel@tonic-gate 17013492Sab196087 /* 17023492Sab196087 * If the section references a SUNW_ldynsym, then we 17033492Sab196087 * expect to see the associated .dynsym immediately 17043492Sab196087 * following. If it references a .dynsym, there is no 17053492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't 17063492Sab196087 * know what to do with it. 17073492Sab196087 */ 17083492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) { 17093492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 17103492Sab196087 file, sortcache->c_name, 17113492Sab196087 EC_WORD(sortshdr->sh_link)); 17123492Sab196087 continue; 17133492Sab196087 } 17143492Sab196087 symcache = &cache[sortshdr->sh_link]; 17153492Sab196087 symshdr = symcache->c_shdr; 17163492Sab196087 symsecndx = sortshdr->sh_link; 17173492Sab196087 ldynsym_cnt = 0; 17183492Sab196087 switch (symshdr->sh_type) { 17193492Sab196087 case SHT_SUNW_LDYNSYM: 17203492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum, 1721*9273SAli.Bahrami@Sun.COM symsecndx, ehdr, osabi, versym, file, flags)) 17223492Sab196087 continue; 17233492Sab196087 ldynsym_cnt = ldynsym_state.symn; 17240Sstevel@tonic-gate /* 17253492Sab196087 * We know that the dynsym follows immediately 17263492Sab196087 * after the SUNW_ldynsym, and so, should be at 17273492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a 17283492Sab196087 * diagnostic tool, so we do the full paranoid 17293492Sab196087 * search instead. 17300Sstevel@tonic-gate */ 17313492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) { 17323492Sab196087 symcache = &cache[symsecndx]; 17333492Sab196087 symshdr = symcache->c_shdr; 17343492Sab196087 if (symshdr->sh_type == SHT_DYNSYM) 17353492Sab196087 break; 17363492Sab196087 } 17373492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */ 17380Sstevel@tonic-gate (void) fprintf(stderr, 17393492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM), 17403492Sab196087 file, sortcache->c_name); 17413492Sab196087 continue; 17420Sstevel@tonic-gate } 17433492Sab196087 /* Fallthrough to process associated dynsym */ 17447463SRod.Evans@Sun.COM /* FALLTHROUGH */ 17453492Sab196087 case SHT_DYNSYM: 17463492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum, 1747*9273SAli.Bahrami@Sun.COM symsecndx, ehdr, osabi, versym, file, flags)) 17483492Sab196087 continue; 17493492Sab196087 break; 17503492Sab196087 default: 17513492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC), 1752*9273SAli.Bahrami@Sun.COM file, sortcache->c_name, 1753*9273SAli.Bahrami@Sun.COM conv_sec_type(osabi, ehdr->e_machine, 1754*9273SAli.Bahrami@Sun.COM symshdr->sh_type, 0, &inv_buf)); 17553492Sab196087 continue; 17563492Sab196087 } 17570Sstevel@tonic-gate 17583492Sab196087 /* 17593492Sab196087 * Output header 17603492Sab196087 */ 17613492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17623492Sab196087 if (ldynsym_cnt > 0) { 17633492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2), 17643492Sab196087 sortcache->c_name, ldynsym_state.secname, 17653492Sab196087 dynsym_state.secname); 17660Sstevel@tonic-gate /* 17673492Sab196087 * The data for .SUNW_ldynsym and dynsym sections 17683492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming 17693492Sab196087 * first. Check, and issue a warning if it isn't so. 17700Sstevel@tonic-gate */ 17714665Sab196087 if (((ldynsym_state.sym + ldynsym_state.symn) 17724665Sab196087 != dynsym_state.sym) && 17735411Sab196087 ((flags & FLG_CTL_FAKESHDR) == 0)) 17743492Sab196087 (void) fprintf(stderr, 17753492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file, 17763492Sab196087 ldynsym_state.secname, 17773492Sab196087 dynsym_state.secname); 17783492Sab196087 } else { 17793492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1), 17803492Sab196087 sortcache->c_name, dynsym_state.secname); 17813492Sab196087 } 17823492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 17833492Sab196087 17843492Sab196087 /* If not first one, insert a line of whitespace */ 17853492Sab196087 if (output_cnt++ > 0) 17863492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17873118Sab196087 17883492Sab196087 /* 17893492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of 17903492Sab196087 * symbol indices. Iterate over the array entries, 17913492Sab196087 * dispaying the referenced symbols. 17923492Sab196087 */ 17933492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize; 17943492Sab196087 ndx = (Word *)sortcache->c_data->d_buf; 17953492Sab196087 for (; ndxn-- > 0; ndx++) { 17963492Sab196087 if (*ndx >= ldynsym_cnt) { 17973492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt; 17983492Sab196087 17994832Srie output_symbol(&dynsym_state, sec_ndx, 0, 18003492Sab196087 *ndx, dynsym_state.sym + sec_ndx); 18013492Sab196087 } else { 18024832Srie output_symbol(&ldynsym_state, *ndx, 0, 18033492Sab196087 *ndx, ldynsym_state.sym + *ndx); 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate } 18060Sstevel@tonic-gate } 18070Sstevel@tonic-gate } 18080Sstevel@tonic-gate 18090Sstevel@tonic-gate /* 18100Sstevel@tonic-gate * Search for and process any relocation sections. 18110Sstevel@tonic-gate */ 18120Sstevel@tonic-gate static void 18137463SRod.Evans@Sun.COM reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 18140Sstevel@tonic-gate { 18151618Srie Word cnt; 18160Sstevel@tonic-gate 18170Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 18181618Srie Word type, symnum; 18191618Srie Xword relndx, relnum, relsize; 18201618Srie void *rels; 18211618Srie Sym *syms; 18221618Srie Cache *symsec, *strsec; 18230Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 18241618Srie Shdr *shdr = _cache->c_shdr; 18251618Srie char *relname = _cache->c_name; 18264734Sab196087 Conv_inv_buf_t inv_buf; 18270Sstevel@tonic-gate 18280Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) && 18290Sstevel@tonic-gate (type != SHT_REL)) 18300Sstevel@tonic-gate continue; 18315411Sab196087 if (!match(MATCH_F_ALL, relname, cnt, type)) 18320Sstevel@tonic-gate continue; 18330Sstevel@tonic-gate 18340Sstevel@tonic-gate /* 18351618Srie * Decide entry size. 18360Sstevel@tonic-gate */ 18371618Srie if (((relsize = shdr->sh_entsize) == 0) || 18381618Srie (relsize > shdr->sh_size)) { 18390Sstevel@tonic-gate if (type == SHT_RELA) 18401618Srie relsize = sizeof (Rela); 18410Sstevel@tonic-gate else 18421618Srie relsize = sizeof (Rel); 18430Sstevel@tonic-gate } 18440Sstevel@tonic-gate 18450Sstevel@tonic-gate /* 18460Sstevel@tonic-gate * Determine the number of relocations available. 18470Sstevel@tonic-gate */ 18480Sstevel@tonic-gate if (shdr->sh_size == 0) { 18490Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 18501618Srie file, relname); 18510Sstevel@tonic-gate continue; 18520Sstevel@tonic-gate } 18533466Srie if (_cache->c_data == NULL) 18543466Srie continue; 18553466Srie 18561618Srie rels = _cache->c_data->d_buf; 18571618Srie relnum = shdr->sh_size / relsize; 18580Sstevel@tonic-gate 18590Sstevel@tonic-gate /* 18601618Srie * Get the data buffer for the associated symbol table and 18611618Srie * string table. 18620Sstevel@tonic-gate */ 18631618Srie if (stringtbl(cache, 1, cnt, shnum, file, 18641618Srie &symnum, &symsec, &strsec) == 0) 18650Sstevel@tonic-gate continue; 18661618Srie 18671618Srie syms = symsec->c_data->d_buf; 18680Sstevel@tonic-gate 18690Sstevel@tonic-gate /* 18700Sstevel@tonic-gate * Loop through the relocation entries. 18710Sstevel@tonic-gate */ 18721618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 18731618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 18741618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type); 18750Sstevel@tonic-gate 18761618Srie for (relndx = 0; relndx < relnum; relndx++, 18771618Srie rels = (void *)((char *)rels + relsize)) { 18786206Sab196087 Half mach = ehdr->e_machine; 18790Sstevel@tonic-gate char section[BUFSIZ]; 18801618Srie const char *symname; 18811618Srie Word symndx, reltype; 18821618Srie Rela *rela; 18831618Srie Rel *rel; 18840Sstevel@tonic-gate 18850Sstevel@tonic-gate /* 18861618Srie * Unravel the relocation and determine the symbol with 18871618Srie * which this relocation is associated. 18880Sstevel@tonic-gate */ 18890Sstevel@tonic-gate if (type == SHT_RELA) { 18901618Srie rela = (Rela *)rels; 18911618Srie symndx = ELF_R_SYM(rela->r_info); 18926206Sab196087 reltype = ELF_R_TYPE(rela->r_info, mach); 18930Sstevel@tonic-gate } else { 18941618Srie rel = (Rel *)rels; 18951618Srie symndx = ELF_R_SYM(rel->r_info); 18966206Sab196087 reltype = ELF_R_TYPE(rel->r_info, mach); 18970Sstevel@tonic-gate } 18981618Srie 18991618Srie symname = relsymname(cache, _cache, strsec, symndx, 19007463SRod.Evans@Sun.COM symnum, relndx, syms, section, BUFSIZ, file); 19011618Srie 19021618Srie /* 19031618Srie * A zero symbol index is only valid for a few 19041618Srie * relocations. 19051618Srie */ 19061618Srie if (symndx == 0) { 19071618Srie int badrel = 0; 19080Sstevel@tonic-gate 19091618Srie if ((mach == EM_SPARC) || 19101618Srie (mach == EM_SPARC32PLUS) || 19111618Srie (mach == EM_SPARCV9)) { 19121618Srie if ((reltype != R_SPARC_NONE) && 19131618Srie (reltype != R_SPARC_REGISTER) && 19141618Srie (reltype != R_SPARC_RELATIVE)) 19151618Srie badrel++; 19161618Srie } else if (mach == EM_386) { 19171618Srie if ((reltype != R_386_NONE) && 19181618Srie (reltype != R_386_RELATIVE)) 19191618Srie badrel++; 19201618Srie } else if (mach == EM_AMD64) { 19211618Srie if ((reltype != R_AMD64_NONE) && 19221618Srie (reltype != R_AMD64_RELATIVE)) 19231618Srie badrel++; 19241618Srie } 19251618Srie 19261618Srie if (badrel) { 19271618Srie (void) fprintf(stderr, 19281618Srie MSG_INTL(MSG_ERR_BADREL1), file, 19294734Sab196087 conv_reloc_type(mach, reltype, 19304734Sab196087 0, &inv_buf)); 19310Sstevel@tonic-gate } 19320Sstevel@tonic-gate } 19330Sstevel@tonic-gate 19341618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP, 19351618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type, 19361618Srie rels, relname, symname, 0); 19370Sstevel@tonic-gate } 19380Sstevel@tonic-gate } 19390Sstevel@tonic-gate } 19400Sstevel@tonic-gate 19415230Sab196087 19425230Sab196087 /* 19435230Sab196087 * This value controls which test dyn_test() performs. 19445230Sab196087 */ 19455230Sab196087 typedef enum { DYN_TEST_ADDR, DYN_TEST_SIZE, DYN_TEST_ENTSIZE } dyn_test_t; 19465230Sab196087 19475230Sab196087 /* 19485230Sab196087 * Used by dynamic() to compare the value of a dynamic element against 19495230Sab196087 * the starting address of the section it references. 19505230Sab196087 * 19515230Sab196087 * entry: 19525230Sab196087 * test_type - Specify which dyn item is being tested. 19535230Sab196087 * sh_type - SHT_* type value for required section. 19545230Sab196087 * sec_cache - Cache entry for section, or NULL if the object lacks 19555230Sab196087 * a section of this type. 19565230Sab196087 * dyn - Dyn entry to be tested 19575230Sab196087 * dynsec_cnt - # of dynamic section being examined. The first 19585230Sab196087 * dynamic section is 1, the next is 2, and so on... 19595230Sab196087 * ehdr - ELF header for file 19605230Sab196087 * file - Name of file 19615230Sab196087 */ 19625230Sab196087 static void 19635230Sab196087 dyn_test(dyn_test_t test_type, Word sh_type, Cache *sec_cache, Dyn *dyn, 1964*9273SAli.Bahrami@Sun.COM Word dynsec_cnt, Ehdr *ehdr, uchar_t osabi, const char *file) 19655230Sab196087 { 19665230Sab196087 Conv_inv_buf_t buf1, buf2; 19675230Sab196087 19685230Sab196087 /* 19695230Sab196087 * These tests are based around the implicit assumption that 19705230Sab196087 * there is only one dynamic section in an object, and also only 19715230Sab196087 * one of the sections it references. We have therefore gathered 19725230Sab196087 * all of the necessary information to test this in a single pass 19735230Sab196087 * over the section headers, which is very efficient. We are not 19745230Sab196087 * aware of any case where more than one dynamic section would 19755230Sab196087 * be meaningful in an ELF object, so this is a reasonable solution. 19765230Sab196087 * 19775230Sab196087 * To test multiple dynamic sections correctly would be more 19785230Sab196087 * expensive in code and time. We would have to build a data structure 19795230Sab196087 * containing all the dynamic elements. Then, we would use the address 19805230Sab196087 * to locate the section it references and ensure the section is of 19815230Sab196087 * the right type and that the address in the dynamic element is 19825230Sab196087 * to the start of the section. Then, we could check the size and 19835230Sab196087 * entsize values against those same sections. This is O(n^2), and 19845230Sab196087 * also complicated. 19855230Sab196087 * 19865230Sab196087 * In the highly unlikely case that there is more than one dynamic 19875230Sab196087 * section, we only test the first one, and simply allow the values 19885230Sab196087 * of the subsequent one to be displayed unchallenged. 19895230Sab196087 */ 19905230Sab196087 if (dynsec_cnt != 1) 19915230Sab196087 return; 19925230Sab196087 19935230Sab196087 /* 19945230Sab196087 * A DT_ item that references a section address should always find 19955230Sab196087 * the section in the file. 19965230Sab196087 */ 19975230Sab196087 if (sec_cache == NULL) { 19986299Sab196087 const char *name; 19996299Sab196087 20006299Sab196087 /* 20016299Sab196087 * Supply section names instead of section types for 20026299Sab196087 * things that reference progbits so that the error 20036299Sab196087 * message will make more sense. 20046299Sab196087 */ 20056299Sab196087 switch (dyn->d_tag) { 20066299Sab196087 case DT_INIT: 20076299Sab196087 name = MSG_ORIG(MSG_ELF_INIT); 20086299Sab196087 break; 20096299Sab196087 case DT_FINI: 20106299Sab196087 name = MSG_ORIG(MSG_ELF_FINI); 20116299Sab196087 break; 20126299Sab196087 default: 2013*9273SAli.Bahrami@Sun.COM name = conv_sec_type(osabi, ehdr->e_machine, 2014*9273SAli.Bahrami@Sun.COM sh_type, 0, &buf1); 20156299Sab196087 break; 20166299Sab196087 } 20175230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNNOBCKSEC), file, 2018*9273SAli.Bahrami@Sun.COM name, conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine, 2019*9273SAli.Bahrami@Sun.COM 0, &buf2)); 20205230Sab196087 return; 20215230Sab196087 } 20225230Sab196087 20235230Sab196087 20245230Sab196087 switch (test_type) { 20255230Sab196087 case DYN_TEST_ADDR: 20265230Sab196087 /* The section address should match the DT_ item value */ 20275230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_addr) 20285230Sab196087 (void) fprintf(stderr, 20295230Sab196087 MSG_INTL(MSG_ERR_DYNBADADDR), file, 2030*9273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine, 2031*9273SAli.Bahrami@Sun.COM 0, &buf1), EC_ADDR(dyn->d_un.d_val), 2032*9273SAli.Bahrami@Sun.COM sec_cache->c_ndx, sec_cache->c_name, 20335230Sab196087 EC_ADDR(sec_cache->c_shdr->sh_addr)); 20345230Sab196087 break; 20355230Sab196087 20365230Sab196087 case DYN_TEST_SIZE: 20375230Sab196087 /* The section size should match the DT_ item value */ 20385230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_size) 20395230Sab196087 (void) fprintf(stderr, 20405230Sab196087 MSG_INTL(MSG_ERR_DYNBADSIZE), file, 2041*9273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine, 2042*9273SAli.Bahrami@Sun.COM 0, &buf1), EC_XWORD(dyn->d_un.d_val), 20435230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 20445230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_size)); 20455230Sab196087 break; 20465230Sab196087 20475230Sab196087 case DYN_TEST_ENTSIZE: 20485230Sab196087 /* The sh_entsize value should match the DT_ item value */ 20495230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_entsize) 20505230Sab196087 (void) fprintf(stderr, 20515230Sab196087 MSG_INTL(MSG_ERR_DYNBADENTSIZE), file, 2052*9273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine, 2053*9273SAli.Bahrami@Sun.COM 0, &buf1), EC_XWORD(dyn->d_un.d_val), 20545230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 20555230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_entsize)); 20565230Sab196087 break; 20575230Sab196087 } 20585230Sab196087 } 20595230Sab196087 20605230Sab196087 20610Sstevel@tonic-gate /* 20626299Sab196087 * There are some DT_ entries that have corresponding symbols 20636299Sab196087 * (e.g. DT_INIT and _init). It is expected that these items will 20646299Sab196087 * both have the same value if both are present. This routine 20656299Sab196087 * examines the well known symbol tables for such symbols and 20666299Sab196087 * issues warnings for any that don't match. 20676299Sab196087 * 20686299Sab196087 * entry: 20696299Sab196087 * dyn - Dyn entry to be tested 20706299Sab196087 * symname - Name of symbol that corresponds to dyn 20716299Sab196087 * symtab_cache, dynsym_cache, ldynsym_cache - Symbol tables to check 20726299Sab196087 * cache - Cache of all section headers 20736299Sab196087 * shnum - # of sections in cache 20746299Sab196087 * ehdr - ELF header for file 20756299Sab196087 * file - Name of file 20766299Sab196087 */ 20776299Sab196087 static void 20786299Sab196087 dyn_symtest(Dyn *dyn, const char *symname, Cache *symtab_cache, 20796299Sab196087 Cache *dynsym_cache, Cache *ldynsym_cache, Cache *cache, 2080*9273SAli.Bahrami@Sun.COM Word shnum, Ehdr *ehdr, uchar_t osabi, const char *file) 20816299Sab196087 { 20826299Sab196087 Conv_inv_buf_t buf; 20836299Sab196087 int i; 20846299Sab196087 Sym *sym; 20856299Sab196087 Cache *_cache; 20866299Sab196087 20876299Sab196087 for (i = 0; i < 3; i++) { 20886299Sab196087 switch (i) { 20896299Sab196087 case 0: 20906299Sab196087 _cache = symtab_cache; 20916299Sab196087 break; 20926299Sab196087 case 1: 20936299Sab196087 _cache = dynsym_cache; 20946299Sab196087 break; 20956299Sab196087 case 2: 20966299Sab196087 _cache = ldynsym_cache; 20976299Sab196087 break; 20986299Sab196087 } 20996299Sab196087 21006299Sab196087 if ((_cache != NULL) && 21016299Sab196087 symlookup(symname, cache, shnum, &sym, _cache, file) && 21026299Sab196087 (sym->st_value != dyn->d_un.d_val)) 21036299Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNSYMVAL), 2104*9273SAli.Bahrami@Sun.COM file, _cache->c_name, conv_dyn_tag(dyn->d_tag, 2105*9273SAli.Bahrami@Sun.COM osabi, ehdr->e_machine, 0, &buf), 21066299Sab196087 symname, EC_ADDR(sym->st_value)); 21076299Sab196087 } 21086299Sab196087 } 21096299Sab196087 21106299Sab196087 21116299Sab196087 /* 21120Sstevel@tonic-gate * Search for and process a .dynamic section. 21130Sstevel@tonic-gate */ 21140Sstevel@tonic-gate static void 2115*9273SAli.Bahrami@Sun.COM dynamic(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, const char *file) 21160Sstevel@tonic-gate { 21175230Sab196087 struct { 21186299Sab196087 Cache *symtab; 21195230Sab196087 Cache *dynstr; 21205230Sab196087 Cache *dynsym; 21215230Sab196087 Cache *hash; 21225230Sab196087 Cache *fini; 21235230Sab196087 Cache *fini_array; 21245230Sab196087 Cache *init; 21255230Sab196087 Cache *init_array; 21265230Sab196087 Cache *preinit_array; 21275230Sab196087 Cache *rel; 21285230Sab196087 Cache *rela; 21295230Sab196087 Cache *sunw_cap; 21305230Sab196087 Cache *sunw_ldynsym; 21315230Sab196087 Cache *sunw_move; 21325230Sab196087 Cache *sunw_syminfo; 21335230Sab196087 Cache *sunw_symsort; 21345230Sab196087 Cache *sunw_tlssort; 21355230Sab196087 Cache *sunw_verdef; 21365230Sab196087 Cache *sunw_verneed; 21375230Sab196087 Cache *sunw_versym; 21385230Sab196087 } sec; 21395230Sab196087 Word dynsec_ndx; 21405230Sab196087 Word dynsec_num; 21415230Sab196087 int dynsec_cnt; 21421618Srie Word cnt; 2143*9273SAli.Bahrami@Sun.COM int osabi_solaris = osabi == ELFOSABI_SOLARIS; 21440Sstevel@tonic-gate 21455230Sab196087 /* 21465230Sab196087 * Make a pass over all the sections, gathering section information 21475230Sab196087 * we'll need below. 21485230Sab196087 */ 21495230Sab196087 dynsec_num = 0; 21505230Sab196087 bzero(&sec, sizeof (sec)); 21510Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 21525230Sab196087 Cache *_cache = &cache[cnt]; 21535230Sab196087 21545230Sab196087 switch (_cache->c_shdr->sh_type) { 21555230Sab196087 case SHT_DYNAMIC: 21565230Sab196087 if (dynsec_num == 0) { 21575230Sab196087 dynsec_ndx = cnt; 21585230Sab196087 21595230Sab196087 /* Does it have a valid string table? */ 21605230Sab196087 (void) stringtbl(cache, 0, cnt, shnum, file, 21615230Sab196087 0, 0, &sec.dynstr); 21625230Sab196087 } 21635230Sab196087 dynsec_num++; 21645230Sab196087 break; 21655230Sab196087 21665230Sab196087 21675230Sab196087 case SHT_PROGBITS: 21685230Sab196087 /* 21695230Sab196087 * We want to detect the .init and .fini sections, 21705230Sab196087 * if present. These are SHT_PROGBITS, so all we 21715230Sab196087 * have to go on is the section name. Normally comparing 21725230Sab196087 * names is a bad idea, but there are some special 21735230Sab196087 * names (i.e. .init/.fini/.interp) that are very 21745230Sab196087 * difficult to use in any other context, and for 21755230Sab196087 * these symbols, we do the heuristic match. 21765230Sab196087 */ 21775230Sab196087 if (strcmp(_cache->c_name, 21785230Sab196087 MSG_ORIG(MSG_ELF_INIT)) == 0) { 21795230Sab196087 if (sec.init == NULL) 21805230Sab196087 sec.init = _cache; 21815230Sab196087 } else if (strcmp(_cache->c_name, 21825230Sab196087 MSG_ORIG(MSG_ELF_FINI)) == 0) { 21835230Sab196087 if (sec.fini == NULL) 21845230Sab196087 sec.fini = _cache; 21855230Sab196087 } 21865230Sab196087 break; 21875230Sab196087 21885230Sab196087 case SHT_REL: 21895230Sab196087 /* 21905230Sab196087 * We want the SHT_REL section with the lowest 21915230Sab196087 * offset. The linker gathers them together, 21925230Sab196087 * and puts the address of the first one 21935230Sab196087 * into the DT_REL dynamic element. 21945230Sab196087 */ 21955230Sab196087 if ((sec.rel == NULL) || 21965230Sab196087 (_cache->c_shdr->sh_offset < 21975230Sab196087 sec.rel->c_shdr->sh_offset)) 21985230Sab196087 sec.rel = _cache; 21995230Sab196087 break; 22005230Sab196087 22015230Sab196087 case SHT_RELA: 22025230Sab196087 /* RELA is handled just like RELA above */ 22035230Sab196087 if ((sec.rela == NULL) || 22045230Sab196087 (_cache->c_shdr->sh_offset < 22055230Sab196087 sec.rela->c_shdr->sh_offset)) 22065230Sab196087 sec.rela = _cache; 22075230Sab196087 break; 22085230Sab196087 22095230Sab196087 /* 22105230Sab196087 * The GRAB macro is used for the simple case in which 22115230Sab196087 * we simply grab the first section of the desired type. 22125230Sab196087 */ 22135230Sab196087 #define GRAB(_sec_type, _sec_field) \ 22145230Sab196087 case _sec_type: \ 22155230Sab196087 if (sec._sec_field == NULL) \ 22165230Sab196087 sec._sec_field = _cache; \ 22175230Sab196087 break 22186299Sab196087 GRAB(SHT_SYMTAB, symtab); 22195230Sab196087 GRAB(SHT_DYNSYM, dynsym); 22205230Sab196087 GRAB(SHT_FINI_ARRAY, fini_array); 22215230Sab196087 GRAB(SHT_HASH, hash); 22225230Sab196087 GRAB(SHT_INIT_ARRAY, init_array); 22235230Sab196087 GRAB(SHT_SUNW_move, sunw_move); 22245230Sab196087 GRAB(SHT_PREINIT_ARRAY, preinit_array); 22255230Sab196087 GRAB(SHT_SUNW_cap, sunw_cap); 22265230Sab196087 GRAB(SHT_SUNW_LDYNSYM, sunw_ldynsym); 22275230Sab196087 GRAB(SHT_SUNW_syminfo, sunw_syminfo); 22285230Sab196087 GRAB(SHT_SUNW_symsort, sunw_symsort); 22295230Sab196087 GRAB(SHT_SUNW_tlssort, sunw_tlssort); 22305230Sab196087 GRAB(SHT_SUNW_verdef, sunw_verdef); 22315230Sab196087 GRAB(SHT_SUNW_verneed, sunw_verneed); 22325230Sab196087 GRAB(SHT_SUNW_versym, sunw_versym); 22335230Sab196087 #undef GRAB 22345230Sab196087 } 22355230Sab196087 } 22365230Sab196087 22375230Sab196087 /* 22385230Sab196087 * If no dynamic section, return immediately. If more than one 22395230Sab196087 * dynamic section, then something odd is going on and an error 22405230Sab196087 * is in order, but then continue on and display them all. 22415230Sab196087 */ 22425230Sab196087 if (dynsec_num == 0) 22435230Sab196087 return; 22445230Sab196087 if (dynsec_num > 1) 22455230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MULTDYN), 22465230Sab196087 file, EC_WORD(dynsec_num)); 22475230Sab196087 22485230Sab196087 22495230Sab196087 dynsec_cnt = 0; 22505230Sab196087 for (cnt = dynsec_ndx; (cnt < shnum) && (dynsec_cnt < dynsec_num); 22515230Sab196087 cnt++) { 22521618Srie Dyn *dyn; 22531618Srie ulong_t numdyn; 22543850Sab196087 int ndx, end_ndx; 22551618Srie Cache *_cache = &cache[cnt], *strsec; 22561618Srie Shdr *shdr = _cache->c_shdr; 22575230Sab196087 int dumped = 0; 22580Sstevel@tonic-gate 22590Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC) 22600Sstevel@tonic-gate continue; 22615230Sab196087 dynsec_cnt++; 22620Sstevel@tonic-gate 22630Sstevel@tonic-gate /* 22641618Srie * Verify the associated string table section. 22650Sstevel@tonic-gate */ 22661618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0) 22670Sstevel@tonic-gate continue; 22681618Srie 22693466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 22703466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 22713466Srie file, _cache->c_name); 22723466Srie continue; 22733466Srie } 22743466Srie if (_cache->c_data == NULL) 22753466Srie continue; 22763466Srie 22770Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize; 22781618Srie dyn = (Dyn *)_cache->c_data->d_buf; 22790Sstevel@tonic-gate 22805230Sab196087 /* 22815230Sab196087 * We expect the REL/RELA entries to reference the reloc 22825230Sab196087 * section with the lowest address. However, this is 22835230Sab196087 * not true for dumped objects. Detect if this object has 22845230Sab196087 * been dumped so that we can skip the reloc address test 22855230Sab196087 * in that case. 22865230Sab196087 */ 22875230Sab196087 for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 22885230Sab196087 if (dyn->d_tag == DT_FLAGS_1) { 22895230Sab196087 dumped = (dyn->d_un.d_val & DF_1_CONFALT) != 0; 22905230Sab196087 break; 22915230Sab196087 } 22925230Sab196087 } 22935230Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 22945230Sab196087 22951618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 22961618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 22970Sstevel@tonic-gate 22981618Srie Elf_dyn_title(0); 22990Sstevel@tonic-gate 23001618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 23014734Sab196087 union { 23026206Sab196087 Conv_inv_buf_t inv; 23034734Sab196087 Conv_dyn_flag_buf_t flag; 23044734Sab196087 Conv_dyn_flag1_buf_t flag1; 23054734Sab196087 Conv_dyn_posflag1_buf_t posflag1; 23064734Sab196087 Conv_dyn_feature1_buf_t feature1; 23074734Sab196087 } c_buf; 23085230Sab196087 const char *name = NULL; 23090Sstevel@tonic-gate 23100Sstevel@tonic-gate /* 23110Sstevel@tonic-gate * Print the information numerically, and if possible 23125230Sab196087 * as a string. If a string is available, name is 23135230Sab196087 * set to reference it. 23145230Sab196087 * 23155230Sab196087 * Also, take this opportunity to sanity check 23165230Sab196087 * the values of DT elements. In the code above, 23175230Sab196087 * we gathered information on sections that are 23185230Sab196087 * referenced by the dynamic section. Here, we 23195230Sab196087 * compare the attributes of those sections to 23205230Sab196087 * the DT_ items that reference them and report 23215230Sab196087 * on inconsistencies. 23225230Sab196087 * 23235230Sab196087 * Things not currently tested that could be improved 23245230Sab196087 * in later revisions include: 23255230Sab196087 * - We don't check PLT or GOT related items 23265230Sab196087 * - We don't handle computing the lengths of 23275230Sab196087 * relocation arrays. To handle this 23285230Sab196087 * requires examining data that spans 23295230Sab196087 * across sections, in a contiguous span 23305230Sab196087 * within a single segment. 23315230Sab196087 * - DT_VERDEFNUM and DT_VERNEEDNUM can't be 23325230Sab196087 * verified without parsing the sections. 23335230Sab196087 * - We don't handle DT_SUNW_SYMSZ, which would 23345230Sab196087 * be the sum of the lengths of .dynsym and 23355230Sab196087 * .SUNW_ldynsym 23365230Sab196087 * - DT_SUNW_STRPAD can't be verified other than 23375230Sab196087 * to check that it's not larger than 23385230Sab196087 * the string table. 23395230Sab196087 * - Some items come in "all or none" clusters 23405230Sab196087 * that give an address, element size, 23415230Sab196087 * and data length in bytes. We don't 23425230Sab196087 * verify that there are no missing items 23435230Sab196087 * in such groups. 23440Sstevel@tonic-gate */ 23453850Sab196087 switch (dyn->d_tag) { 23463850Sab196087 case DT_NULL: 23473850Sab196087 /* 23483850Sab196087 * Special case: DT_NULLs can come in groups 23493850Sab196087 * that we prefer to reduce to a single line. 23503850Sab196087 */ 23513850Sab196087 end_ndx = ndx; 23523850Sab196087 while ((end_ndx < (numdyn - 1)) && 23534433Sab196087 ((dyn + 1)->d_tag == DT_NULL)) { 23543850Sab196087 dyn++; 23553850Sab196087 end_ndx++; 23563850Sab196087 } 23573850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 23583850Sab196087 ndx = end_ndx; 23593850Sab196087 continue; 23603850Sab196087 23613850Sab196087 /* 23625230Sab196087 * String items all reference the dynstr. The string() 23635230Sab196087 * function does the necessary sanity checking. 23643850Sab196087 */ 23653850Sab196087 case DT_NEEDED: 23663850Sab196087 case DT_SONAME: 23673850Sab196087 case DT_FILTER: 23683850Sab196087 case DT_AUXILIARY: 23693850Sab196087 case DT_CONFIG: 23703850Sab196087 case DT_RPATH: 23713850Sab196087 case DT_RUNPATH: 23723850Sab196087 case DT_USED: 23733850Sab196087 case DT_DEPAUDIT: 23743850Sab196087 case DT_AUDIT: 2375*9273SAli.Bahrami@Sun.COM name = string(_cache, ndx, strsec, 2376*9273SAli.Bahrami@Sun.COM file, dyn->d_un.d_ptr); 2377*9273SAli.Bahrami@Sun.COM break; 2378*9273SAli.Bahrami@Sun.COM 23793850Sab196087 case DT_SUNW_AUXILIARY: 23803850Sab196087 case DT_SUNW_FILTER: 2381*9273SAli.Bahrami@Sun.COM if (osabi_solaris) 2382*9273SAli.Bahrami@Sun.COM name = string(_cache, ndx, strsec, 2383*9273SAli.Bahrami@Sun.COM file, dyn->d_un.d_ptr); 23843850Sab196087 break; 23853850Sab196087 23863850Sab196087 case DT_FLAGS: 23874734Sab196087 name = conv_dyn_flag(dyn->d_un.d_val, 23884734Sab196087 0, &c_buf.flag); 23893850Sab196087 break; 23903850Sab196087 case DT_FLAGS_1: 23915088Sab196087 name = conv_dyn_flag1(dyn->d_un.d_val, 0, 23924734Sab196087 &c_buf.flag1); 23933850Sab196087 break; 23943850Sab196087 case DT_POSFLAG_1: 23954734Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0, 23964734Sab196087 &c_buf.posflag1); 23973850Sab196087 break; 23983850Sab196087 case DT_FEATURE_1: 23994734Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0, 24004734Sab196087 &c_buf.feature1); 24013850Sab196087 break; 24023850Sab196087 case DT_DEPRECATED_SPARC_REGISTER: 24031618Srie name = MSG_INTL(MSG_STR_DEPRECATED); 24043850Sab196087 break; 24055230Sab196087 24066206Sab196087 case DT_SUNW_LDMACH: 2407*9273SAli.Bahrami@Sun.COM if (!osabi_solaris) 2408*9273SAli.Bahrami@Sun.COM break; 2409*9273SAli.Bahrami@Sun.COM name = conv_ehdr_mach((Half)dyn->d_un.d_val, 2410*9273SAli.Bahrami@Sun.COM 0, &c_buf.inv); 24116206Sab196087 break; 24126206Sab196087 24135230Sab196087 /* 24145230Sab196087 * Cases below this point are strictly sanity checking, 24155230Sab196087 * and do not generate a name string. The TEST_ macros 24165230Sab196087 * are used to hide the boilerplate arguments neeeded 24175230Sab196087 * by dyn_test(). 24185230Sab196087 */ 24195230Sab196087 #define TEST_ADDR(_sh_type, _sec_field) \ 24205230Sab196087 dyn_test(DYN_TEST_ADDR, _sh_type, \ 2421*9273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \ 2422*9273SAli.Bahrami@Sun.COM osabi, file) 24235230Sab196087 #define TEST_SIZE(_sh_type, _sec_field) \ 24245230Sab196087 dyn_test(DYN_TEST_SIZE, _sh_type, \ 2425*9273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \ 2426*9273SAli.Bahrami@Sun.COM osabi, file) 24275230Sab196087 #define TEST_ENTSIZE(_sh_type, _sec_field) \ 24285230Sab196087 dyn_test(DYN_TEST_ENTSIZE, _sh_type, \ 2429*9273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \ 2430*9273SAli.Bahrami@Sun.COM osabi, file) 24315230Sab196087 24325230Sab196087 case DT_FINI: 24336299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_FINI), 24346299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 2435*9273SAli.Bahrami@Sun.COM cache, shnum, ehdr, osabi, file); 24365230Sab196087 TEST_ADDR(SHT_PROGBITS, fini); 24375230Sab196087 break; 24385230Sab196087 24395230Sab196087 case DT_FINI_ARRAY: 24405230Sab196087 TEST_ADDR(SHT_FINI_ARRAY, fini_array); 24415230Sab196087 break; 24425230Sab196087 24435230Sab196087 case DT_FINI_ARRAYSZ: 24445230Sab196087 TEST_SIZE(SHT_FINI_ARRAY, fini_array); 24455230Sab196087 break; 24465230Sab196087 24475230Sab196087 case DT_HASH: 24485230Sab196087 TEST_ADDR(SHT_HASH, hash); 24495230Sab196087 break; 24505230Sab196087 24515230Sab196087 case DT_INIT: 24526299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_INIT), 24536299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 2454*9273SAli.Bahrami@Sun.COM cache, shnum, ehdr, osabi, file); 24555230Sab196087 TEST_ADDR(SHT_PROGBITS, init); 24565230Sab196087 break; 24575230Sab196087 24585230Sab196087 case DT_INIT_ARRAY: 24595230Sab196087 TEST_ADDR(SHT_INIT_ARRAY, init_array); 24605230Sab196087 break; 24615230Sab196087 24625230Sab196087 case DT_INIT_ARRAYSZ: 24635230Sab196087 TEST_SIZE(SHT_INIT_ARRAY, init_array); 24645230Sab196087 break; 24655230Sab196087 24665230Sab196087 case DT_MOVEENT: 24675230Sab196087 TEST_ENTSIZE(SHT_SUNW_move, sunw_move); 24685230Sab196087 break; 24695230Sab196087 24705230Sab196087 case DT_MOVESZ: 24715230Sab196087 TEST_SIZE(SHT_SUNW_move, sunw_move); 24725230Sab196087 break; 24735230Sab196087 24745230Sab196087 case DT_MOVETAB: 24755230Sab196087 TEST_ADDR(SHT_SUNW_move, sunw_move); 24765230Sab196087 break; 24775230Sab196087 24785230Sab196087 case DT_PREINIT_ARRAY: 24795230Sab196087 TEST_ADDR(SHT_PREINIT_ARRAY, preinit_array); 24805230Sab196087 break; 24815230Sab196087 24825230Sab196087 case DT_PREINIT_ARRAYSZ: 24835230Sab196087 TEST_SIZE(SHT_PREINIT_ARRAY, preinit_array); 24845230Sab196087 break; 24855230Sab196087 24865230Sab196087 case DT_REL: 24875230Sab196087 if (!dumped) 24885230Sab196087 TEST_ADDR(SHT_REL, rel); 24895230Sab196087 break; 24905230Sab196087 24915230Sab196087 case DT_RELENT: 24925230Sab196087 TEST_ENTSIZE(SHT_REL, rel); 24935230Sab196087 break; 24945230Sab196087 24955230Sab196087 case DT_RELA: 24965230Sab196087 if (!dumped) 24975230Sab196087 TEST_ADDR(SHT_RELA, rela); 24985230Sab196087 break; 24995230Sab196087 25005230Sab196087 case DT_RELAENT: 25015230Sab196087 TEST_ENTSIZE(SHT_RELA, rela); 25025230Sab196087 break; 25035230Sab196087 25045230Sab196087 case DT_STRTAB: 25055230Sab196087 TEST_ADDR(SHT_STRTAB, dynstr); 25063850Sab196087 break; 25075230Sab196087 25085230Sab196087 case DT_STRSZ: 25095230Sab196087 TEST_SIZE(SHT_STRTAB, dynstr); 25105230Sab196087 break; 25115230Sab196087 25125230Sab196087 case DT_SUNW_CAP: 25135230Sab196087 TEST_ADDR(SHT_SUNW_cap, sunw_cap); 25145230Sab196087 break; 25155230Sab196087 25165230Sab196087 case DT_SUNW_SYMTAB: 25175230Sab196087 TEST_ADDR(SHT_SUNW_LDYNSYM, sunw_ldynsym); 25185230Sab196087 break; 25195230Sab196087 25205230Sab196087 case DT_SYMENT: 25215230Sab196087 TEST_ENTSIZE(SHT_DYNSYM, dynsym); 25225230Sab196087 break; 25235230Sab196087 25245230Sab196087 case DT_SYMINENT: 25255230Sab196087 TEST_ENTSIZE(SHT_SUNW_syminfo, sunw_syminfo); 25265230Sab196087 break; 25275230Sab196087 25285230Sab196087 case DT_SYMINFO: 25295230Sab196087 TEST_ADDR(SHT_SUNW_syminfo, sunw_syminfo); 25305230Sab196087 break; 25315230Sab196087 25325230Sab196087 case DT_SYMINSZ: 25335230Sab196087 TEST_SIZE(SHT_SUNW_syminfo, sunw_syminfo); 25345230Sab196087 break; 25355230Sab196087 25365230Sab196087 case DT_SYMTAB: 25375230Sab196087 TEST_ADDR(SHT_DYNSYM, dynsym); 25385230Sab196087 break; 25395230Sab196087 25405230Sab196087 case DT_SUNW_SORTENT: 25415230Sab196087 /* 25425230Sab196087 * This entry is related to both the symsort and 25435230Sab196087 * tlssort sections. 25445230Sab196087 */ 2545*9273SAli.Bahrami@Sun.COM if (osabi_solaris) { 25465230Sab196087 int test_tls = 25475230Sab196087 (sec.sunw_tlssort != NULL); 25485230Sab196087 int test_sym = 25495230Sab196087 (sec.sunw_symsort != NULL) || 25505230Sab196087 !test_tls; 25515230Sab196087 if (test_sym) 25525230Sab196087 TEST_ENTSIZE(SHT_SUNW_symsort, 25535230Sab196087 sunw_symsort); 25545230Sab196087 if (test_tls) 25555230Sab196087 TEST_ENTSIZE(SHT_SUNW_tlssort, 25565230Sab196087 sunw_tlssort); 25575230Sab196087 } 25585230Sab196087 break; 25595230Sab196087 25605230Sab196087 25615230Sab196087 case DT_SUNW_SYMSORT: 2562*9273SAli.Bahrami@Sun.COM if (osabi_solaris) 2563*9273SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_symsort, 2564*9273SAli.Bahrami@Sun.COM sunw_symsort); 25655230Sab196087 break; 25665230Sab196087 25675230Sab196087 case DT_SUNW_SYMSORTSZ: 2568*9273SAli.Bahrami@Sun.COM if (osabi_solaris) 2569*9273SAli.Bahrami@Sun.COM TEST_SIZE(SHT_SUNW_symsort, 2570*9273SAli.Bahrami@Sun.COM sunw_symsort); 25715230Sab196087 break; 25725230Sab196087 25735230Sab196087 case DT_SUNW_TLSSORT: 2574*9273SAli.Bahrami@Sun.COM if (osabi_solaris) 2575*9273SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_tlssort, 2576*9273SAli.Bahrami@Sun.COM sunw_tlssort); 25775230Sab196087 break; 25785230Sab196087 25795230Sab196087 case DT_SUNW_TLSSORTSZ: 2580*9273SAli.Bahrami@Sun.COM if (osabi_solaris) 2581*9273SAli.Bahrami@Sun.COM TEST_SIZE(SHT_SUNW_tlssort, 2582*9273SAli.Bahrami@Sun.COM sunw_tlssort); 25835230Sab196087 break; 25845230Sab196087 25855230Sab196087 case DT_VERDEF: 25865230Sab196087 TEST_ADDR(SHT_SUNW_verdef, sunw_verdef); 25875230Sab196087 break; 25885230Sab196087 25895230Sab196087 case DT_VERNEED: 25905230Sab196087 TEST_ADDR(SHT_SUNW_verneed, sunw_verneed); 25915230Sab196087 break; 25925230Sab196087 25935230Sab196087 case DT_VERSYM: 25945230Sab196087 TEST_ADDR(SHT_SUNW_versym, sunw_versym); 25955230Sab196087 break; 25965230Sab196087 #undef TEST_ADDR 25975230Sab196087 #undef TEST_SIZE 25985230Sab196087 #undef TEST_ENTSIZE 25993850Sab196087 } 26000Sstevel@tonic-gate 26015230Sab196087 if (name == NULL) 26025230Sab196087 name = MSG_ORIG(MSG_STR_EMPTY); 2603*9273SAli.Bahrami@Sun.COM Elf_dyn_entry(0, dyn, ndx, name, 2604*9273SAli.Bahrami@Sun.COM osabi, ehdr->e_machine); 26050Sstevel@tonic-gate } 26060Sstevel@tonic-gate } 26070Sstevel@tonic-gate } 26080Sstevel@tonic-gate 26090Sstevel@tonic-gate /* 26100Sstevel@tonic-gate * Search for and process a MOVE section. 26110Sstevel@tonic-gate */ 26120Sstevel@tonic-gate static void 26134168Sab196087 move(Cache *cache, Word shnum, const char *file, uint_t flags) 26140Sstevel@tonic-gate { 26151618Srie Word cnt; 26169085SAli.Bahrami@Sun.COM const char *fmt = NULL; 26170Sstevel@tonic-gate 26180Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 26191618Srie Word movenum, symnum, ndx; 26201618Srie Sym *syms; 26211618Srie Cache *_cache = &cache[cnt]; 26221618Srie Shdr *shdr = _cache->c_shdr; 26231618Srie Cache *symsec, *strsec; 26241618Srie Move *move; 26250Sstevel@tonic-gate 26260Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move) 26270Sstevel@tonic-gate continue; 26285411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 26290Sstevel@tonic-gate continue; 26300Sstevel@tonic-gate 26310Sstevel@tonic-gate /* 26320Sstevel@tonic-gate * Determine the move data and number. 26330Sstevel@tonic-gate */ 26340Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 26350Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 26360Sstevel@tonic-gate file, _cache->c_name); 26370Sstevel@tonic-gate continue; 26380Sstevel@tonic-gate } 26393466Srie if (_cache->c_data == NULL) 26403466Srie continue; 26413466Srie 26421618Srie move = (Move *)_cache->c_data->d_buf; 26431618Srie movenum = shdr->sh_size / shdr->sh_entsize; 26440Sstevel@tonic-gate 26450Sstevel@tonic-gate /* 26461618Srie * Get the data buffer for the associated symbol table and 26471618Srie * string table. 26480Sstevel@tonic-gate */ 26491618Srie if (stringtbl(cache, 1, cnt, shnum, file, 26501618Srie &symnum, &symsec, &strsec) == 0) 26511618Srie return; 26521618Srie 26531618Srie syms = (Sym *)symsec->c_data->d_buf; 26540Sstevel@tonic-gate 26551618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 26561618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); 26571618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); 26580Sstevel@tonic-gate 26599085SAli.Bahrami@Sun.COM if (fmt == NULL) 26601618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY); 26610Sstevel@tonic-gate 26621618Srie for (ndx = 0; ndx < movenum; move++, ndx++) { 26631618Srie const char *symname; 26641618Srie char index[MAXNDXSIZE], section[BUFSIZ]; 26651618Srie Word symndx, shndx; 26661618Srie Sym *sym; 26670Sstevel@tonic-gate 26680Sstevel@tonic-gate /* 26690Sstevel@tonic-gate * Check for null entries 26700Sstevel@tonic-gate */ 26711618Srie if ((move->m_info == 0) && (move->m_value == 0) && 26721618Srie (move->m_poffset == 0) && (move->m_repeat == 0) && 26731618Srie (move->m_stride == 0)) { 26741618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY), 26751618Srie EC_XWORD(move->m_poffset), 0, 0, 0, 26761618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY)); 26770Sstevel@tonic-gate continue; 26780Sstevel@tonic-gate } 26791618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) || 26801618Srie (symndx >= symnum)) { 26810Sstevel@tonic-gate (void) fprintf(stderr, 26820Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file, 26831618Srie _cache->c_name, EC_XWORD(move->m_info)); 26841618Srie 26851618Srie (void) snprintf(index, MAXNDXSIZE, 26861618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 26871618Srie dbg_print(0, fmt, index, 26881618Srie EC_XWORD(move->m_poffset), 26891618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 26901618Srie move->m_stride, move->m_value, 26910Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN)); 26920Sstevel@tonic-gate continue; 26930Sstevel@tonic-gate } 26940Sstevel@tonic-gate 26951618Srie symname = relsymname(cache, _cache, strsec, 26967463SRod.Evans@Sun.COM symndx, symnum, ndx, syms, section, BUFSIZ, file); 26971618Srie sym = (Sym *)(syms + symndx); 26980Sstevel@tonic-gate 26990Sstevel@tonic-gate /* 27000Sstevel@tonic-gate * Additional sanity check. 27010Sstevel@tonic-gate */ 27021618Srie shndx = sym->st_shndx; 27030Sstevel@tonic-gate if (!((shndx == SHN_COMMON) || 27040Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) && 27051618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) { 27060Sstevel@tonic-gate (void) fprintf(stderr, 27071618Srie MSG_INTL(MSG_ERR_BADSYM2), file, 27086206Sab196087 _cache->c_name, EC_WORD(symndx), 27096206Sab196087 demangle(symname, flags)); 27100Sstevel@tonic-gate } 27110Sstevel@tonic-gate 27121618Srie (void) snprintf(index, MAXNDXSIZE, 27131618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 27141618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset), 27151618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 27161618Srie move->m_stride, move->m_value, 27171618Srie demangle(symname, flags)); 27180Sstevel@tonic-gate } 27190Sstevel@tonic-gate } 27200Sstevel@tonic-gate } 27210Sstevel@tonic-gate 27220Sstevel@tonic-gate /* 2723*9273SAli.Bahrami@Sun.COM * parse_note_t is used to track the state used by parse_note_entry() 2724*9273SAli.Bahrami@Sun.COM * between calls, and also to return the results of each call. 2725*9273SAli.Bahrami@Sun.COM */ 2726*9273SAli.Bahrami@Sun.COM typedef struct { 2727*9273SAli.Bahrami@Sun.COM /* pns_ fields track progress through the data */ 2728*9273SAli.Bahrami@Sun.COM const char *pns_file; /* File name */ 2729*9273SAli.Bahrami@Sun.COM Cache *pns_cache; /* Note section cache entry */ 2730*9273SAli.Bahrami@Sun.COM size_t pns_size; /* # unprocessed data bytes */ 2731*9273SAli.Bahrami@Sun.COM Word *pns_data; /* # to next unused data byte */ 2732*9273SAli.Bahrami@Sun.COM 2733*9273SAli.Bahrami@Sun.COM /* pn_ fields return the results for a single call */ 2734*9273SAli.Bahrami@Sun.COM Word pn_namesz; /* Value of note namesz field */ 2735*9273SAli.Bahrami@Sun.COM Word pn_descsz; /* Value of note descsz field */ 2736*9273SAli.Bahrami@Sun.COM Word pn_type; /* Value of note type field */ 2737*9273SAli.Bahrami@Sun.COM const char *pn_name; /* if (namesz > 0) ptr to name bytes */ 2738*9273SAli.Bahrami@Sun.COM const char *pn_desc; /* if (descsx > 0) ptr to data bytes */ 2739*9273SAli.Bahrami@Sun.COM } parse_note_t; 2740*9273SAli.Bahrami@Sun.COM 2741*9273SAli.Bahrami@Sun.COM /* 2742*9273SAli.Bahrami@Sun.COM * Extract the various sub-parts of a note entry, and advance the 2743*9273SAli.Bahrami@Sun.COM * data pointer past it. 2744*9273SAli.Bahrami@Sun.COM * 2745*9273SAli.Bahrami@Sun.COM * entry: 2746*9273SAli.Bahrami@Sun.COM * The state pns_ fields contain current values for the Note section 2747*9273SAli.Bahrami@Sun.COM * 2748*9273SAli.Bahrami@Sun.COM * exit: 2749*9273SAli.Bahrami@Sun.COM * On success, True (1) is returned, the state pns_ fields have been 2750*9273SAli.Bahrami@Sun.COM * advanced to point at the start of the next entry, and the information 2751*9273SAli.Bahrami@Sun.COM * for the recovered note entry is found in the state pn_ fields. 2752*9273SAli.Bahrami@Sun.COM * 2753*9273SAli.Bahrami@Sun.COM * On failure, False (0) is returned. The values contained in state 2754*9273SAli.Bahrami@Sun.COM * are undefined. 2755*9273SAli.Bahrami@Sun.COM */ 2756*9273SAli.Bahrami@Sun.COM static int 2757*9273SAli.Bahrami@Sun.COM parse_note_entry(parse_note_t *state) 2758*9273SAli.Bahrami@Sun.COM { 2759*9273SAli.Bahrami@Sun.COM size_t pad, noteoff; 2760*9273SAli.Bahrami@Sun.COM 2761*9273SAli.Bahrami@Sun.COM noteoff = (Word)state->pns_cache->c_data->d_size - state->pns_size; 2762*9273SAli.Bahrami@Sun.COM /* 2763*9273SAli.Bahrami@Sun.COM * Make sure we can at least reference the 3 initial entries 2764*9273SAli.Bahrami@Sun.COM * (4-byte words) of the note information block. 2765*9273SAli.Bahrami@Sun.COM */ 2766*9273SAli.Bahrami@Sun.COM if (state->pns_size >= (sizeof (Word) * 3)) { 2767*9273SAli.Bahrami@Sun.COM state->pns_size -= (sizeof (Word) * 3); 2768*9273SAli.Bahrami@Sun.COM } else { 2769*9273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ), 2770*9273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name, 2771*9273SAli.Bahrami@Sun.COM EC_WORD(noteoff)); 2772*9273SAli.Bahrami@Sun.COM return (0); 2773*9273SAli.Bahrami@Sun.COM } 2774*9273SAli.Bahrami@Sun.COM 2775*9273SAli.Bahrami@Sun.COM /* 2776*9273SAli.Bahrami@Sun.COM * Make sure any specified name string can be referenced. 2777*9273SAli.Bahrami@Sun.COM */ 2778*9273SAli.Bahrami@Sun.COM if ((state->pn_namesz = *state->pns_data++) != 0) { 2779*9273SAli.Bahrami@Sun.COM if (state->pns_size >= state->pn_namesz) { 2780*9273SAli.Bahrami@Sun.COM state->pns_size -= state->pn_namesz; 2781*9273SAli.Bahrami@Sun.COM } else { 2782*9273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADNMSZ), 2783*9273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name, 2784*9273SAli.Bahrami@Sun.COM EC_WORD(noteoff), EC_WORD(state->pn_namesz)); 2785*9273SAli.Bahrami@Sun.COM return (0); 2786*9273SAli.Bahrami@Sun.COM } 2787*9273SAli.Bahrami@Sun.COM } 2788*9273SAli.Bahrami@Sun.COM 2789*9273SAli.Bahrami@Sun.COM /* 2790*9273SAli.Bahrami@Sun.COM * Make sure any specified descriptor can be referenced. 2791*9273SAli.Bahrami@Sun.COM */ 2792*9273SAli.Bahrami@Sun.COM if ((state->pn_descsz = *state->pns_data++) != 0) { 2793*9273SAli.Bahrami@Sun.COM /* 2794*9273SAli.Bahrami@Sun.COM * If namesz isn't a 4-byte multiple, account for any 2795*9273SAli.Bahrami@Sun.COM * padding that must exist before the descriptor. 2796*9273SAli.Bahrami@Sun.COM */ 2797*9273SAli.Bahrami@Sun.COM if ((pad = (state->pn_namesz & (sizeof (Word) - 1))) != 0) { 2798*9273SAli.Bahrami@Sun.COM pad = sizeof (Word) - pad; 2799*9273SAli.Bahrami@Sun.COM state->pns_size -= pad; 2800*9273SAli.Bahrami@Sun.COM } 2801*9273SAli.Bahrami@Sun.COM if (state->pns_size >= state->pn_descsz) { 2802*9273SAli.Bahrami@Sun.COM state->pns_size -= state->pn_descsz; 2803*9273SAli.Bahrami@Sun.COM } else { 2804*9273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDESZ), 2805*9273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name, 2806*9273SAli.Bahrami@Sun.COM EC_WORD(noteoff), EC_WORD(state->pn_namesz)); 2807*9273SAli.Bahrami@Sun.COM return (0); 2808*9273SAli.Bahrami@Sun.COM } 2809*9273SAli.Bahrami@Sun.COM } 2810*9273SAli.Bahrami@Sun.COM 2811*9273SAli.Bahrami@Sun.COM state->pn_type = *state->pns_data++; 2812*9273SAli.Bahrami@Sun.COM 2813*9273SAli.Bahrami@Sun.COM /* Name */ 2814*9273SAli.Bahrami@Sun.COM if (state->pn_namesz) { 2815*9273SAli.Bahrami@Sun.COM state->pn_name = (char *)state->pns_data; 2816*9273SAli.Bahrami@Sun.COM pad = (state->pn_namesz + 2817*9273SAli.Bahrami@Sun.COM (sizeof (Word) - 1)) & ~(sizeof (Word) - 1); 2818*9273SAli.Bahrami@Sun.COM /* LINTED */ 2819*9273SAli.Bahrami@Sun.COM state->pns_data = (Word *)(state->pn_name + pad); 2820*9273SAli.Bahrami@Sun.COM } 2821*9273SAli.Bahrami@Sun.COM 2822*9273SAli.Bahrami@Sun.COM /* 2823*9273SAli.Bahrami@Sun.COM * If multiple information blocks exist within a .note section 2824*9273SAli.Bahrami@Sun.COM * account for any padding that must exist before the next 2825*9273SAli.Bahrami@Sun.COM * information block. 2826*9273SAli.Bahrami@Sun.COM */ 2827*9273SAli.Bahrami@Sun.COM if ((pad = (state->pn_descsz & (sizeof (Word) - 1))) != 0) { 2828*9273SAli.Bahrami@Sun.COM pad = sizeof (Word) - pad; 2829*9273SAli.Bahrami@Sun.COM if (state->pns_size > pad) 2830*9273SAli.Bahrami@Sun.COM state->pns_size -= pad; 2831*9273SAli.Bahrami@Sun.COM } 2832*9273SAli.Bahrami@Sun.COM 2833*9273SAli.Bahrami@Sun.COM /* Data */ 2834*9273SAli.Bahrami@Sun.COM if (state->pn_descsz) { 2835*9273SAli.Bahrami@Sun.COM state->pn_desc = (const char *)state->pns_data; 2836*9273SAli.Bahrami@Sun.COM /* LINTED */ 2837*9273SAli.Bahrami@Sun.COM state->pns_data = (Word *)(state->pn_desc + 2838*9273SAli.Bahrami@Sun.COM state->pn_descsz + pad); 2839*9273SAli.Bahrami@Sun.COM } 2840*9273SAli.Bahrami@Sun.COM 2841*9273SAli.Bahrami@Sun.COM return (1); 2842*9273SAli.Bahrami@Sun.COM } 2843*9273SAli.Bahrami@Sun.COM 2844*9273SAli.Bahrami@Sun.COM /* 28456635Sab196087 * Callback function for use with conv_str_to_c_literal() below. 28466635Sab196087 */ 28476635Sab196087 /*ARGSUSED2*/ 28486635Sab196087 static void 28496635Sab196087 c_literal_cb(const void *ptr, size_t size, void *uvalue) 28506635Sab196087 { 28516635Sab196087 (void) fwrite(ptr, size, 1, stdout); 28526635Sab196087 } 28536635Sab196087 28546635Sab196087 /* 28550Sstevel@tonic-gate * Traverse a note section analyzing each note information block. 28560Sstevel@tonic-gate * The data buffers size is used to validate references before they are made, 28570Sstevel@tonic-gate * and is decremented as each element is processed. 28580Sstevel@tonic-gate */ 28590Sstevel@tonic-gate void 28606635Sab196087 note_entry(Cache *cache, Word *data, size_t size, Ehdr *ehdr, const char *file) 28610Sstevel@tonic-gate { 28626635Sab196087 int cnt = 0; 28636635Sab196087 int is_corenote; 28646635Sab196087 int do_swap; 28656635Sab196087 Conv_inv_buf_t inv_buf; 2866*9273SAli.Bahrami@Sun.COM parse_note_t pnstate; 2867*9273SAli.Bahrami@Sun.COM 2868*9273SAli.Bahrami@Sun.COM pnstate.pns_file = file; 2869*9273SAli.Bahrami@Sun.COM pnstate.pns_cache = cache; 2870*9273SAli.Bahrami@Sun.COM pnstate.pns_size = size; 2871*9273SAli.Bahrami@Sun.COM pnstate.pns_data = data; 2872*9273SAli.Bahrami@Sun.COM do_swap = _elf_sys_encoding() != ehdr->e_ident[EI_DATA]; 28731618Srie 28740Sstevel@tonic-gate /* 28750Sstevel@tonic-gate * Print out a single `note' information block. 28760Sstevel@tonic-gate */ 2877*9273SAli.Bahrami@Sun.COM while (pnstate.pns_size > 0) { 2878*9273SAli.Bahrami@Sun.COM 2879*9273SAli.Bahrami@Sun.COM if (parse_note_entry(&pnstate) == 0) 28800Sstevel@tonic-gate return; 28810Sstevel@tonic-gate 28826635Sab196087 /* 28836635Sab196087 * Is this a Solaris core note? Such notes all have 28846635Sab196087 * the name "CORE". 28856635Sab196087 */ 28866635Sab196087 is_corenote = (ehdr->e_type == ET_CORE) && 2887*9273SAli.Bahrami@Sun.COM (pnstate.pn_namesz == (MSG_STR_CORE_SIZE + 1)) && 2888*9273SAli.Bahrami@Sun.COM (strncmp(MSG_ORIG(MSG_STR_CORE), pnstate.pn_name, 28896635Sab196087 MSG_STR_CORE_SIZE + 1) == 0); 28906635Sab196087 28911618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 28926635Sab196087 dbg_print(0, MSG_INTL(MSG_FMT_NOTEENTNDX), EC_WORD(cnt)); 28936635Sab196087 cnt++; 2894*9273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), 2895*9273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_namesz)); 2896*9273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), 2897*9273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_descsz)); 28986635Sab196087 28996635Sab196087 if (is_corenote) 29006635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE_STR), 2901*9273SAli.Bahrami@Sun.COM conv_cnote_type(pnstate.pn_type, 0, &inv_buf)); 29026635Sab196087 else 2903*9273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), 2904*9273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_type)); 2905*9273SAli.Bahrami@Sun.COM if (pnstate.pn_namesz) { 29066635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_NAME)); 29070Sstevel@tonic-gate /* 29086635Sab196087 * The name string can contain embedded 'null' 29096635Sab196087 * bytes and/or unprintable characters. Also, 29106635Sab196087 * the final NULL is documented in the ELF ABI 29116635Sab196087 * as being included in the namesz. So, display 29126635Sab196087 * the name using C literal string notation, and 29136635Sab196087 * include the terminating NULL in the output. 29146635Sab196087 * We don't show surrounding double quotes, as 29156635Sab196087 * that implies the termination that we are showing 29166635Sab196087 * explicitly. 29170Sstevel@tonic-gate */ 29186635Sab196087 (void) fwrite(MSG_ORIG(MSG_STR_8SP), 29196635Sab196087 MSG_STR_8SP_SIZE, 1, stdout); 2920*9273SAli.Bahrami@Sun.COM conv_str_to_c_literal(pnstate.pn_name, 2921*9273SAli.Bahrami@Sun.COM pnstate.pn_namesz, c_literal_cb, NULL); 29221618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 29230Sstevel@tonic-gate } 29240Sstevel@tonic-gate 2925*9273SAli.Bahrami@Sun.COM if (pnstate.pn_descsz) { 29266635Sab196087 int hexdump = 1; 29270Sstevel@tonic-gate 29280Sstevel@tonic-gate /* 29296635Sab196087 * If this is a core note, let the corenote() 29306635Sab196087 * function handle it. 29310Sstevel@tonic-gate */ 29326635Sab196087 if (is_corenote) { 29336635Sab196087 /* We only issue the bad arch error once */ 29346635Sab196087 static int badnote_done = 0; 29356635Sab196087 corenote_ret_t corenote_ret; 29366635Sab196087 29376635Sab196087 corenote_ret = corenote(ehdr->e_machine, 2938*9273SAli.Bahrami@Sun.COM do_swap, pnstate.pn_type, pnstate.pn_desc, 2939*9273SAli.Bahrami@Sun.COM pnstate.pn_descsz); 29406635Sab196087 switch (corenote_ret) { 29416635Sab196087 case CORENOTE_R_OK: 29426635Sab196087 hexdump = 0; 29436635Sab196087 break; 29446635Sab196087 case CORENOTE_R_BADDATA: 29456635Sab196087 (void) fprintf(stderr, 29466635Sab196087 MSG_INTL(MSG_NOTE_BADCOREDATA), 29476635Sab196087 file); 29486635Sab196087 break; 29496635Sab196087 case CORENOTE_R_BADARCH: 29506635Sab196087 if (badnote_done) 29516635Sab196087 break; 29526635Sab196087 (void) fprintf(stderr, 29536635Sab196087 MSG_INTL(MSG_NOTE_BADCOREARCH), 29546635Sab196087 file, 29556635Sab196087 conv_ehdr_mach(ehdr->e_machine, 29566635Sab196087 0, &inv_buf)); 29576635Sab196087 break; 29580Sstevel@tonic-gate } 29590Sstevel@tonic-gate } 29606635Sab196087 29616635Sab196087 /* 29626635Sab196087 * The default thing when we don't understand 29636635Sab196087 * the note data is to display it as hex bytes. 29646635Sab196087 */ 29656635Sab196087 if (hexdump) { 29666635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESC)); 2967*9273SAli.Bahrami@Sun.COM dump_hex_bytes(pnstate.pn_desc, 2968*9273SAli.Bahrami@Sun.COM pnstate.pn_descsz, 8, 4, 4); 29690Sstevel@tonic-gate } 29700Sstevel@tonic-gate } 29710Sstevel@tonic-gate } 29720Sstevel@tonic-gate } 29730Sstevel@tonic-gate 29740Sstevel@tonic-gate /* 29756635Sab196087 * Search for and process .note sections. 29766635Sab196087 * 29776635Sab196087 * Returns the number of note sections seen. 29780Sstevel@tonic-gate */ 29796635Sab196087 static Word 29806635Sab196087 note(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 29810Sstevel@tonic-gate { 29826635Sab196087 Word cnt, note_cnt = 0; 29830Sstevel@tonic-gate 29840Sstevel@tonic-gate /* 29850Sstevel@tonic-gate * Otherwise look for any .note sections. 29860Sstevel@tonic-gate */ 29870Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 29881618Srie Cache *_cache = &cache[cnt]; 29891618Srie Shdr *shdr = _cache->c_shdr; 29900Sstevel@tonic-gate 29910Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE) 29920Sstevel@tonic-gate continue; 29936635Sab196087 note_cnt++; 29945411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 29950Sstevel@tonic-gate continue; 29960Sstevel@tonic-gate 29970Sstevel@tonic-gate /* 29980Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're 29995230Sab196087 * properly aligned before proceeding, and issue an error 30005230Sab196087 * as necessary. 30015230Sab196087 * 30025230Sab196087 * Note that we will continue on to display the note even 30035230Sab196087 * if it has bad alignment. We can do this safely, because 30045230Sab196087 * libelf knows the alignment required for SHT_NOTE, and 30055230Sab196087 * takes steps to deliver a properly aligned buffer to us 30065230Sab196087 * even if the actual file is misaligned. 30070Sstevel@tonic-gate */ 30085230Sab196087 if (shdr->sh_offset & (sizeof (Word) - 1)) 30090Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 30100Sstevel@tonic-gate file, _cache->c_name); 30115230Sab196087 30123466Srie if (_cache->c_data == NULL) 30133466Srie continue; 30140Sstevel@tonic-gate 30151618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 30161618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 30170Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf, 30180Sstevel@tonic-gate /* LINTED */ 30196635Sab196087 (Word)_cache->c_data->d_size, ehdr, file); 30200Sstevel@tonic-gate } 30216635Sab196087 30226635Sab196087 return (note_cnt); 30230Sstevel@tonic-gate } 30240Sstevel@tonic-gate 30251618Srie /* 3026*9273SAli.Bahrami@Sun.COM * The Linux Standard Base defines a special note named .note.ABI-tag 3027*9273SAli.Bahrami@Sun.COM * that is used to maintain Linux ABI information. Presence of this section 3028*9273SAli.Bahrami@Sun.COM * is a strong indication that the object should be considered to be 3029*9273SAli.Bahrami@Sun.COM * ELFOSABI_LINUX. 3030*9273SAli.Bahrami@Sun.COM * 3031*9273SAli.Bahrami@Sun.COM * This function returns True (1) if such a note is seen, and False (0) 3032*9273SAli.Bahrami@Sun.COM * otherwise. 3033*9273SAli.Bahrami@Sun.COM */ 3034*9273SAli.Bahrami@Sun.COM static int 3035*9273SAli.Bahrami@Sun.COM has_linux_abi_note(Cache *cache, Word shnum, const char *file) 3036*9273SAli.Bahrami@Sun.COM { 3037*9273SAli.Bahrami@Sun.COM Word cnt; 3038*9273SAli.Bahrami@Sun.COM 3039*9273SAli.Bahrami@Sun.COM for (cnt = 1; cnt < shnum; cnt++) { 3040*9273SAli.Bahrami@Sun.COM parse_note_t pnstate; 3041*9273SAli.Bahrami@Sun.COM Cache *_cache = &cache[cnt]; 3042*9273SAli.Bahrami@Sun.COM Shdr *shdr = _cache->c_shdr; 3043*9273SAli.Bahrami@Sun.COM 3044*9273SAli.Bahrami@Sun.COM /* 3045*9273SAli.Bahrami@Sun.COM * Section must be SHT_NOTE, must have the name 3046*9273SAli.Bahrami@Sun.COM * .note.ABI-tag, and must have data. 3047*9273SAli.Bahrami@Sun.COM */ 3048*9273SAli.Bahrami@Sun.COM if ((shdr->sh_type != SHT_NOTE) || 3049*9273SAli.Bahrami@Sun.COM (strcmp(MSG_ORIG(MSG_STR_NOTEABITAG), 3050*9273SAli.Bahrami@Sun.COM _cache->c_name) != 0) || (_cache->c_data == NULL)) 3051*9273SAli.Bahrami@Sun.COM continue; 3052*9273SAli.Bahrami@Sun.COM 3053*9273SAli.Bahrami@Sun.COM pnstate.pns_file = file; 3054*9273SAli.Bahrami@Sun.COM pnstate.pns_cache = _cache; 3055*9273SAli.Bahrami@Sun.COM pnstate.pns_size = _cache->c_data->d_size; 3056*9273SAli.Bahrami@Sun.COM pnstate.pns_data = (Word *)_cache->c_data->d_buf; 3057*9273SAli.Bahrami@Sun.COM 3058*9273SAli.Bahrami@Sun.COM while (pnstate.pns_size > 0) { 3059*9273SAli.Bahrami@Sun.COM Word *w; 3060*9273SAli.Bahrami@Sun.COM 3061*9273SAli.Bahrami@Sun.COM if (parse_note_entry(&pnstate) == 0) 3062*9273SAli.Bahrami@Sun.COM break; 3063*9273SAli.Bahrami@Sun.COM 3064*9273SAli.Bahrami@Sun.COM /* 3065*9273SAli.Bahrami@Sun.COM * The type must be 1, and the name must be "GNU". 3066*9273SAli.Bahrami@Sun.COM * The descsz must be at least 16 bytes. 3067*9273SAli.Bahrami@Sun.COM */ 3068*9273SAli.Bahrami@Sun.COM if ((pnstate.pn_type != 1) || 3069*9273SAli.Bahrami@Sun.COM (pnstate.pn_namesz != (MSG_STR_GNU_SIZE + 1)) || 3070*9273SAli.Bahrami@Sun.COM (strncmp(MSG_ORIG(MSG_STR_GNU), pnstate.pn_name, 3071*9273SAli.Bahrami@Sun.COM MSG_STR_CORE_SIZE + 1) != 0) || 3072*9273SAli.Bahrami@Sun.COM (pnstate.pn_descsz < 16)) 3073*9273SAli.Bahrami@Sun.COM continue; 3074*9273SAli.Bahrami@Sun.COM 3075*9273SAli.Bahrami@Sun.COM /* 3076*9273SAli.Bahrami@Sun.COM * desc contains 4 32-bit fields. Field 0 must be 0, 3077*9273SAli.Bahrami@Sun.COM * indicating Linux. The second, third, and fourth 3078*9273SAli.Bahrami@Sun.COM * fields represent the earliest Linux kernel 3079*9273SAli.Bahrami@Sun.COM * version compatible with this object. 3080*9273SAli.Bahrami@Sun.COM */ 3081*9273SAli.Bahrami@Sun.COM /*LINTED*/ 3082*9273SAli.Bahrami@Sun.COM w = (Word *) pnstate.pn_desc; 3083*9273SAli.Bahrami@Sun.COM if (*w == 0) 3084*9273SAli.Bahrami@Sun.COM return (1); 3085*9273SAli.Bahrami@Sun.COM } 3086*9273SAli.Bahrami@Sun.COM } 3087*9273SAli.Bahrami@Sun.COM 3088*9273SAli.Bahrami@Sun.COM return (0); 3089*9273SAli.Bahrami@Sun.COM } 3090*9273SAli.Bahrami@Sun.COM 3091*9273SAli.Bahrami@Sun.COM /* 30921618Srie * Determine an individual hash entry. This may be the initial hash entry, 30931618Srie * or an associated chain entry. 30941618Srie */ 30951618Srie static void 30961618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx, 30971618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts, 30981618Srie uint_t flags, int chain) 30991618Srie { 31001618Srie Sym *sym; 31011618Srie const char *symname, *str; 31021618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE]; 31031618Srie ulong_t nbkt, nhash; 31041618Srie 31051618Srie if (symndx > symn) { 31061618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file, 31071618Srie EC_WORD(symndx), EC_WORD(hashndx)); 31081618Srie symname = MSG_INTL(MSG_STR_UNKNOWN); 31091618Srie } else { 31101618Srie sym = (Sym *)(syms + symndx); 31111618Srie symname = string(refsec, symndx, strsec, file, sym->st_name); 31121618Srie } 31131618Srie 31141618Srie if (chain == 0) { 31151618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 31161618Srie hashndx); 31171618Srie str = (const char *)_bucket; 31181618Srie } else 31191618Srie str = MSG_ORIG(MSG_STR_EMPTY); 31201618Srie 31211618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2), 31221618Srie EC_WORD(symndx)); 31231618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx, 31241618Srie demangle(symname, flags)); 31251618Srie 31261618Srie /* 31271618Srie * Determine if this string is in the correct bucket. 31281618Srie */ 31291618Srie nhash = elf_hash(symname); 31301618Srie nbkt = nhash % bkts; 31311618Srie 31321618Srie if (nbkt != hashndx) { 31331618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file, 31341618Srie hsecname, symname, EC_WORD(hashndx), nbkt); 31351618Srie } 31361618Srie } 31370Sstevel@tonic-gate 31380Sstevel@tonic-gate #define MAXCOUNT 500 31390Sstevel@tonic-gate 31400Sstevel@tonic-gate static void 31414168Sab196087 hash(Cache *cache, Word shnum, const char *file, uint_t flags) 31420Sstevel@tonic-gate { 31430Sstevel@tonic-gate static int count[MAXCOUNT]; 31441618Srie Word cnt; 31450Sstevel@tonic-gate ulong_t ndx, bkts; 31460Sstevel@tonic-gate char number[MAXNDXSIZE]; 31470Sstevel@tonic-gate 31480Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 31490Sstevel@tonic-gate uint_t *hash, *chain; 31500Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 31511618Srie Shdr *sshdr, *hshdr = _cache->c_shdr; 31521618Srie char *ssecname, *hsecname = _cache->c_name; 31531618Srie Sym *syms; 31541618Srie Word symn; 31550Sstevel@tonic-gate 31561618Srie if (hshdr->sh_type != SHT_HASH) 31570Sstevel@tonic-gate continue; 31580Sstevel@tonic-gate 31590Sstevel@tonic-gate /* 31600Sstevel@tonic-gate * Determine the hash table data and size. 31610Sstevel@tonic-gate */ 31621618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) { 31630Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 31641618Srie file, hsecname); 31650Sstevel@tonic-gate continue; 31660Sstevel@tonic-gate } 31673466Srie if (_cache->c_data == NULL) 31683466Srie continue; 31693466Srie 31700Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf; 31710Sstevel@tonic-gate bkts = *hash; 31720Sstevel@tonic-gate chain = hash + 2 + bkts; 31730Sstevel@tonic-gate hash += 2; 31740Sstevel@tonic-gate 31750Sstevel@tonic-gate /* 31760Sstevel@tonic-gate * Get the data buffer for the associated symbol table. 31770Sstevel@tonic-gate */ 31781618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) { 31790Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 31801618Srie file, hsecname, EC_WORD(hshdr->sh_link)); 31810Sstevel@tonic-gate continue; 31820Sstevel@tonic-gate } 31831618Srie 31841618Srie _cache = &cache[hshdr->sh_link]; 31851618Srie ssecname = _cache->c_name; 31861618Srie 31873466Srie if (_cache->c_data == NULL) 31883466Srie continue; 31893466Srie 31903466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) { 31910Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 31921618Srie file, ssecname); 31930Sstevel@tonic-gate continue; 31940Sstevel@tonic-gate } 31950Sstevel@tonic-gate 31961618Srie sshdr = _cache->c_shdr; 31971618Srie /* LINTED */ 31981618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize); 31991618Srie 32000Sstevel@tonic-gate /* 32010Sstevel@tonic-gate * Get the associated string table section. 32020Sstevel@tonic-gate */ 32031618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) { 32040Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 32051618Srie file, ssecname, EC_WORD(sshdr->sh_link)); 32060Sstevel@tonic-gate continue; 32070Sstevel@tonic-gate } 32080Sstevel@tonic-gate 32091618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 32101618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname); 32111618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO)); 32120Sstevel@tonic-gate 32130Sstevel@tonic-gate /* 32140Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate 32150Sstevel@tonic-gate * symbols. 32160Sstevel@tonic-gate */ 32170Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) { 32181618Srie Word _ndx, _cnt; 32190Sstevel@tonic-gate 32200Sstevel@tonic-gate if (*hash == 0) { 32210Sstevel@tonic-gate count[0]++; 32220Sstevel@tonic-gate continue; 32230Sstevel@tonic-gate } 32240Sstevel@tonic-gate 32251618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname, 32261618Srie ndx, *hash, symn, syms, file, bkts, flags, 0); 32270Sstevel@tonic-gate 32280Sstevel@tonic-gate /* 32290Sstevel@tonic-gate * Determine if any other symbols are chained to this 32300Sstevel@tonic-gate * bucket. 32310Sstevel@tonic-gate */ 32320Sstevel@tonic-gate _ndx = chain[*hash]; 32330Sstevel@tonic-gate _cnt = 1; 32340Sstevel@tonic-gate while (_ndx) { 32351618Srie hash_entry(_cache, &cache[sshdr->sh_link], 32361618Srie hsecname, ndx, _ndx, symn, syms, file, 32371618Srie bkts, flags, 1); 32380Sstevel@tonic-gate _ndx = chain[_ndx]; 32390Sstevel@tonic-gate _cnt++; 32400Sstevel@tonic-gate } 32410Sstevel@tonic-gate 32420Sstevel@tonic-gate if (_cnt >= MAXCOUNT) { 32430Sstevel@tonic-gate (void) fprintf(stderr, 32441324Srie MSG_INTL(MSG_HASH_OVERFLW), file, 32451618Srie _cache->c_name, EC_WORD(ndx), 32461618Srie EC_WORD(_cnt)); 32470Sstevel@tonic-gate } else 32480Sstevel@tonic-gate count[_cnt]++; 32490Sstevel@tonic-gate } 32500Sstevel@tonic-gate break; 32510Sstevel@tonic-gate } 32520Sstevel@tonic-gate 32530Sstevel@tonic-gate /* 32540Sstevel@tonic-gate * Print out the count information. 32550Sstevel@tonic-gate */ 32560Sstevel@tonic-gate bkts = cnt = 0; 32571618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 32581618Srie 32590Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) { 32601618Srie Word _cnt; 32610Sstevel@tonic-gate 32620Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0) 32630Sstevel@tonic-gate continue; 32640Sstevel@tonic-gate 32651618Srie (void) snprintf(number, MAXNDXSIZE, 32661618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt); 32671618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number, 32681618Srie EC_WORD(ndx)); 32690Sstevel@tonic-gate bkts += _cnt; 32701618Srie cnt += (Word)(ndx * _cnt); 32710Sstevel@tonic-gate } 32720Sstevel@tonic-gate if (cnt) { 32730Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 32741618Srie bkts); 32751618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number, 32761618Srie EC_WORD(cnt)); 32770Sstevel@tonic-gate } 32780Sstevel@tonic-gate } 32790Sstevel@tonic-gate 32800Sstevel@tonic-gate static void 32814168Sab196087 group(Cache *cache, Word shnum, const char *file, uint_t flags) 32820Sstevel@tonic-gate { 32831618Srie Word scnt; 32840Sstevel@tonic-gate 32851618Srie for (scnt = 1; scnt < shnum; scnt++) { 32861618Srie Cache *_cache = &cache[scnt]; 32871618Srie Shdr *shdr = _cache->c_shdr; 32881618Srie Word *grpdata, gcnt, grpcnt, symnum, unknown; 32891618Srie Cache *symsec, *strsec; 32901618Srie Sym *syms, *sym; 32911618Srie char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 32920Sstevel@tonic-gate 32930Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP) 32940Sstevel@tonic-gate continue; 32955411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, scnt, shdr->sh_type)) 32960Sstevel@tonic-gate continue; 32973466Srie if ((_cache->c_data == NULL) || 32983466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL)) 32990Sstevel@tonic-gate continue; 33001618Srie grpcnt = shdr->sh_size / sizeof (Word); 33011618Srie 33021618Srie /* 33031618Srie * Get the data buffer for the associated symbol table and 33041618Srie * string table. 33051618Srie */ 33061618Srie if (stringtbl(cache, 1, scnt, shnum, file, 33071618Srie &symnum, &symsec, &strsec) == 0) 33081618Srie return; 33091618Srie 33101618Srie syms = symsec->c_data->d_buf; 33111618Srie 33121618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 33131618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name); 33141618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE)); 33151618Srie 33161618Srie /* 33171618Srie * The first element of the group defines the group. The 33181618Srie * associated symbol is defined by the sh_link field. 33191618Srie */ 33201618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) { 33211618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 33221618Srie file, _cache->c_name, EC_WORD(shdr->sh_info)); 33231618Srie return; 33240Sstevel@tonic-gate } 33250Sstevel@tonic-gate 33261618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT)); 33271618Srie if (grpdata[0] & GRP_COMDAT) { 33281618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT)); 33290Sstevel@tonic-gate } 33301618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) { 33311618Srie size_t len = strlen(flgstrbuf); 33321618Srie 33331618Srie (void) snprintf(&flgstrbuf[len], 33341618Srie (MSG_GRP_COMDAT_SIZE + 10 - len), 33351618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown); 33360Sstevel@tonic-gate } 33371618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT)); 33381618Srie sym = (Sym *)(syms + shdr->sh_info); 33390Sstevel@tonic-gate 33401618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf, 33411618Srie demangle(string(_cache, 0, strsec, file, sym->st_name), 33421618Srie flags)); 33431618Srie 33441618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) { 33450Sstevel@tonic-gate char index[MAXNDXSIZE]; 33461618Srie const char *name; 33470Sstevel@tonic-gate 33480Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, 33491618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt)); 33501618Srie 33511618Srie if (grpdata[gcnt] >= shnum) 33521618Srie name = MSG_INTL(MSG_GRP_INVALSCN); 33531618Srie else 33541618Srie name = cache[grpdata[gcnt]].c_name; 33551618Srie 33561618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name, 33574433Sab196087 EC_XWORD(grpdata[gcnt])); 33580Sstevel@tonic-gate } 33590Sstevel@tonic-gate } 33600Sstevel@tonic-gate } 33610Sstevel@tonic-gate 33620Sstevel@tonic-gate static void 33637463SRod.Evans@Sun.COM got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 33640Sstevel@tonic-gate { 33655230Sab196087 Cache *gotcache = NULL, *symtab = NULL; 33661618Srie Addr gotbgn, gotend; 33671618Srie Shdr *gotshdr; 33681618Srie Word cnt, gotents, gotndx; 33690Sstevel@tonic-gate size_t gentsize; 33700Sstevel@tonic-gate Got_info *gottable; 33710Sstevel@tonic-gate char *gotdata; 33721618Srie Sym *gotsym; 33731618Srie Xword gotsymaddr; 33746206Sab196087 uint_t sys_encoding; 33750Sstevel@tonic-gate 33760Sstevel@tonic-gate /* 33771324Srie * First, find the got. 33780Sstevel@tonic-gate */ 33790Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 33805230Sab196087 if (strncmp(cache[cnt].c_name, MSG_ORIG(MSG_ELF_GOT), 33811324Srie MSG_ELF_GOT_SIZE) == 0) { 33825230Sab196087 gotcache = &cache[cnt]; 33830Sstevel@tonic-gate break; 33840Sstevel@tonic-gate } 33850Sstevel@tonic-gate } 33865230Sab196087 if (gotcache == NULL) 33870Sstevel@tonic-gate return; 33881324Srie 33891324Srie /* 33901324Srie * A got section within a relocatable object is suspicious. 33911324Srie */ 33921324Srie if (ehdr->e_type == ET_REL) { 33931324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file, 33945230Sab196087 gotcache->c_name); 33951324Srie } 33961324Srie 33971618Srie gotshdr = gotcache->c_shdr; 33980Sstevel@tonic-gate if (gotshdr->sh_size == 0) { 33990Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 34000Sstevel@tonic-gate file, gotcache->c_name); 34010Sstevel@tonic-gate return; 34020Sstevel@tonic-gate } 34031618Srie 34041618Srie gotbgn = gotshdr->sh_addr; 34050Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size; 34060Sstevel@tonic-gate 34070Sstevel@tonic-gate /* 34081618Srie * Some architectures don't properly set the sh_entsize for the GOT 34091618Srie * table. If it's not set, default to a size of a pointer. 34100Sstevel@tonic-gate */ 34111618Srie if ((gentsize = gotshdr->sh_entsize) == 0) 34121618Srie gentsize = sizeof (Xword); 34131618Srie 34143466Srie if (gotcache->c_data == NULL) 34153466Srie return; 34163466Srie 34170Sstevel@tonic-gate /* LINTED */ 34181618Srie gotents = (Word)(gotshdr->sh_size / gentsize); 34190Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf; 34200Sstevel@tonic-gate 34210Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 34220Sstevel@tonic-gate int err = errno; 34231618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file, 34241618Srie strerror(err)); 34250Sstevel@tonic-gate return; 34260Sstevel@tonic-gate } 34270Sstevel@tonic-gate 34280Sstevel@tonic-gate /* 34290Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations 34300Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a 34310Sstevel@tonic-gate * .rel[a].got section we check them all. 34320Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab 34330Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 34340Sstevel@tonic-gate */ 34350Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 34361618Srie Word type, symnum; 34371618Srie Xword relndx, relnum, relsize; 34381618Srie void *rels; 34391618Srie Sym *syms; 34401618Srie Cache *symsec, *strsec; 34411618Srie Cache *_cache = &cache[cnt]; 34421618Srie Shdr *shdr; 34430Sstevel@tonic-gate 34441618Srie shdr = _cache->c_shdr; 34451618Srie type = shdr->sh_type; 34460Sstevel@tonic-gate 34471618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) { 34480Sstevel@tonic-gate symtab = _cache; 34490Sstevel@tonic-gate continue; 34500Sstevel@tonic-gate } 34511618Srie if (type == SHT_SYMTAB) { 34520Sstevel@tonic-gate symtab = _cache; 34530Sstevel@tonic-gate continue; 34540Sstevel@tonic-gate } 34551618Srie if ((type != SHT_RELA) && (type != SHT_REL)) 34560Sstevel@tonic-gate continue; 34570Sstevel@tonic-gate 34580Sstevel@tonic-gate /* 34591618Srie * Decide entry size. 34600Sstevel@tonic-gate */ 34611618Srie if (((relsize = shdr->sh_entsize) == 0) || 34621618Srie (relsize > shdr->sh_size)) { 34631618Srie if (type == SHT_RELA) 34641618Srie relsize = sizeof (Rela); 34651618Srie else 34661618Srie relsize = sizeof (Rel); 34670Sstevel@tonic-gate } 34680Sstevel@tonic-gate 34690Sstevel@tonic-gate /* 34701618Srie * Determine the number of relocations available. 34710Sstevel@tonic-gate */ 34721618Srie if (shdr->sh_size == 0) { 34731618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 34741618Srie file, _cache->c_name); 34750Sstevel@tonic-gate continue; 34760Sstevel@tonic-gate } 34773466Srie if (_cache->c_data == NULL) 34783466Srie continue; 34793466Srie 34801618Srie rels = _cache->c_data->d_buf; 34811618Srie relnum = shdr->sh_size / relsize; 34820Sstevel@tonic-gate 34831618Srie /* 34841618Srie * Get the data buffer for the associated symbol table and 34851618Srie * string table. 34861618Srie */ 34871618Srie if (stringtbl(cache, 1, cnt, shnum, file, 34881618Srie &symnum, &symsec, &strsec) == 0) 34891618Srie continue; 34901618Srie 34911618Srie syms = symsec->c_data->d_buf; 34921618Srie 34931618Srie /* 34941618Srie * Loop through the relocation entries. 34951618Srie */ 34961618Srie for (relndx = 0; relndx < relnum; relndx++, 34971618Srie rels = (void *)((char *)rels + relsize)) { 34981618Srie char section[BUFSIZ]; 34991618Srie Addr offset; 35000Sstevel@tonic-gate Got_info *gip; 35011618Srie Word symndx, reltype; 35021618Srie Rela *rela; 35031618Srie Rel *rel; 35040Sstevel@tonic-gate 35051618Srie /* 35061618Srie * Unravel the relocation. 35071618Srie */ 35081618Srie if (type == SHT_RELA) { 35091618Srie rela = (Rela *)rels; 35101618Srie symndx = ELF_R_SYM(rela->r_info); 35116206Sab196087 reltype = ELF_R_TYPE(rela->r_info, 35126206Sab196087 ehdr->e_machine); 35131618Srie offset = rela->r_offset; 35140Sstevel@tonic-gate } else { 35151618Srie rel = (Rel *)rels; 35161618Srie symndx = ELF_R_SYM(rel->r_info); 35176206Sab196087 reltype = ELF_R_TYPE(rel->r_info, 35186206Sab196087 ehdr->e_machine); 35191618Srie offset = rel->r_offset; 35200Sstevel@tonic-gate } 35210Sstevel@tonic-gate 35220Sstevel@tonic-gate /* 35230Sstevel@tonic-gate * Only pay attention to relocations against the GOT. 35240Sstevel@tonic-gate */ 35254146Sab196087 if ((offset < gotbgn) || (offset >= gotend)) 35260Sstevel@tonic-gate continue; 35270Sstevel@tonic-gate 35280Sstevel@tonic-gate /* LINTED */ 35291618Srie gotndx = (Word)((offset - gotbgn) / 35300Sstevel@tonic-gate gotshdr->sh_entsize); 35310Sstevel@tonic-gate gip = &gottable[gotndx]; 35321618Srie 35331618Srie if (gip->g_reltype != 0) { 35340Sstevel@tonic-gate (void) fprintf(stderr, 35350Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file, 35361618Srie EC_WORD(gotndx), EC_ADDR(offset)); 35370Sstevel@tonic-gate continue; 35380Sstevel@tonic-gate } 35390Sstevel@tonic-gate 35401618Srie if (symndx) 35411618Srie gip->g_symname = relsymname(cache, _cache, 35421618Srie strsec, symndx, symnum, relndx, syms, 35437463SRod.Evans@Sun.COM section, BUFSIZ, file); 35441618Srie gip->g_reltype = reltype; 35451618Srie gip->g_rel = rels; 35460Sstevel@tonic-gate } 35470Sstevel@tonic-gate } 35480Sstevel@tonic-gate 35496299Sab196087 if (symlookup(MSG_ORIG(MSG_SYM_GOT), cache, shnum, &gotsym, symtab, 35501618Srie file)) 35511618Srie gotsymaddr = gotsym->st_value; 35520Sstevel@tonic-gate else 35531618Srie gotsymaddr = gotbgn; 35540Sstevel@tonic-gate 35551618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 35561618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name); 35571618Srie Elf_got_title(0); 35580Sstevel@tonic-gate 35596206Sab196087 sys_encoding = _elf_sys_encoding(); 35600Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) { 35610Sstevel@tonic-gate Got_info *gip; 35620Sstevel@tonic-gate Sword gindex; 35631618Srie Addr gaddr; 35641618Srie Xword gotentry; 35650Sstevel@tonic-gate 35660Sstevel@tonic-gate gip = &gottable[gotndx]; 35670Sstevel@tonic-gate 35680Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize); 35691618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize; 35700Sstevel@tonic-gate 35711618Srie if (gentsize == sizeof (Word)) 35720Sstevel@tonic-gate /* LINTED */ 35731618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx)); 35740Sstevel@tonic-gate else 35750Sstevel@tonic-gate /* LINTED */ 35761618Srie gotentry = *((Xword *)(gotdata) + gotndx); 35770Sstevel@tonic-gate 35781618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine, 35796206Sab196087 ehdr->e_ident[EI_DATA], sys_encoding, 35801618Srie gip->g_reltype, gip->g_rel, gip->g_symname); 35810Sstevel@tonic-gate } 35820Sstevel@tonic-gate free(gottable); 35830Sstevel@tonic-gate } 35840Sstevel@tonic-gate 35850Sstevel@tonic-gate void 35860Sstevel@tonic-gate checksum(Elf *elf) 35870Sstevel@tonic-gate { 35881618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 35891618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf)); 35900Sstevel@tonic-gate } 35910Sstevel@tonic-gate 35924242Sab196087 /* 35934242Sab196087 * This variable is used by regular() to communicate the address of 35944242Sab196087 * the section header cache to sort_shdr_ndx_arr(). Unfortunately, 35954242Sab196087 * the qsort() interface does not include a userdata argument by which 35964242Sab196087 * such arbitrary data can be passed, so we are stuck using global data. 35974242Sab196087 */ 35984242Sab196087 static Cache *sort_shdr_ndx_arr_cache; 35994242Sab196087 36004242Sab196087 36014242Sab196087 /* 36024242Sab196087 * Used with qsort() to sort the section indices so that they can be 36034242Sab196087 * used to access the section headers in order of increasing data offset. 36044242Sab196087 * 36054242Sab196087 * entry: 36064242Sab196087 * sort_shdr_ndx_arr_cache - Contains address of 36074242Sab196087 * section header cache. 36084242Sab196087 * v1, v2 - Point at elements of sort_shdr_bits array to be compared. 36094242Sab196087 * 36104242Sab196087 * exit: 36114242Sab196087 * Returns -1 (less than), 0 (equal) or 1 (greater than). 36124242Sab196087 */ 36134242Sab196087 static int 36144242Sab196087 sort_shdr_ndx_arr(const void *v1, const void *v2) 36154242Sab196087 { 36164242Sab196087 Cache *cache1 = sort_shdr_ndx_arr_cache + *((size_t *)v1); 36174242Sab196087 Cache *cache2 = sort_shdr_ndx_arr_cache + *((size_t *)v2); 36184242Sab196087 36194242Sab196087 if (cache1->c_shdr->sh_offset < cache2->c_shdr->sh_offset) 36204242Sab196087 return (-1); 36214242Sab196087 36224242Sab196087 if (cache1->c_shdr->sh_offset > cache2->c_shdr->sh_offset) 36234242Sab196087 return (1); 36244242Sab196087 36254242Sab196087 return (0); 36264242Sab196087 } 36274242Sab196087 36284242Sab196087 36294665Sab196087 static int 36304665Sab196087 shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, 36317463SRod.Evans@Sun.COM size_t shnum, Cache **cache_ret, Word flags) 36320Sstevel@tonic-gate { 36330Sstevel@tonic-gate Elf_Scn *scn; 36340Sstevel@tonic-gate Elf_Data *data; 36354665Sab196087 size_t ndx; 36364665Sab196087 Shdr *nameshdr; 36379085SAli.Bahrami@Sun.COM char *names = NULL; 36380Sstevel@tonic-gate Cache *cache, *_cache; 36394242Sab196087 size_t *shdr_ndx_arr, shdr_ndx_arr_cnt; 36400Sstevel@tonic-gate 36410Sstevel@tonic-gate 36420Sstevel@tonic-gate /* 36430Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section 36440Sstevel@tonic-gate * name strings. 36450Sstevel@tonic-gate */ 36464156Sab196087 if (shstrndx == SHN_UNDEF) { 36474156Sab196087 /* 36484156Sab196087 * It is rare, but legal, for an object to lack a 36494156Sab196087 * header string table section. 36504156Sab196087 */ 36514156Sab196087 names = NULL; 36524156Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHSTRSEC), file); 36534156Sab196087 } else if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 36540Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 36550Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 36560Sstevel@tonic-gate EC_XWORD(shstrndx)); 36571618Srie 36580Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) { 36590Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 36600Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 36610Sstevel@tonic-gate EC_XWORD(shstrndx)); 36621618Srie 36631618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) { 36640Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 36650Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 36663862Srie EC_WORD(elf_ndxscn(scn))); 36671618Srie 36689085SAli.Bahrami@Sun.COM } else if ((names = data->d_buf) == NULL) 36690Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 36700Sstevel@tonic-gate 36710Sstevel@tonic-gate /* 36723862Srie * Allocate a cache to maintain a descriptor for each section. 36730Sstevel@tonic-gate */ 36744665Sab196087 if ((*cache_ret = cache = malloc(shnum * sizeof (Cache))) == NULL) { 36750Sstevel@tonic-gate int err = errno; 36760Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 36770Sstevel@tonic-gate file, strerror(err)); 36784665Sab196087 return (0); 36790Sstevel@tonic-gate } 36800Sstevel@tonic-gate 36811618Srie *cache = cache_init; 36820Sstevel@tonic-gate _cache = cache; 36830Sstevel@tonic-gate _cache++; 36840Sstevel@tonic-gate 36853862Srie /* 36864242Sab196087 * Allocate an array that will hold the section index for 36874242Sab196087 * each section that has data in the ELF file: 36884242Sab196087 * 36894242Sab196087 * - Is not a NOBITS section 36904242Sab196087 * - Data has non-zero length 36914242Sab196087 * 36924242Sab196087 * Note that shnum is an upper bound on the size required. It 36934242Sab196087 * is likely that we won't use a few of these array elements. 36944242Sab196087 * Allocating a modest amount of extra memory in this case means 36954242Sab196087 * that we can avoid an extra loop to count the number of needed 36964242Sab196087 * items, and can fill this array immediately in the first loop 36974242Sab196087 * below. 36984242Sab196087 */ 36994242Sab196087 if ((shdr_ndx_arr = malloc(shnum * sizeof (*shdr_ndx_arr))) == NULL) { 37004242Sab196087 int err = errno; 37014242Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 37024242Sab196087 file, strerror(err)); 37034665Sab196087 return (0); 37044242Sab196087 } 37054242Sab196087 shdr_ndx_arr_cnt = 0; 37064242Sab196087 37074242Sab196087 /* 37083862Srie * Traverse the sections of the file. This gathering of data is 37093862Srie * carried out in two passes. First, the section headers are captured 37103862Srie * and the section header names are evaluated. A verification pass is 37113862Srie * then carried out over the section information. Files have been 37123862Srie * known to exhibit overlapping (and hence erroneous) section header 37133862Srie * information. 37143862Srie * 37153862Srie * Finally, the data for each section is obtained. This processing is 37163862Srie * carried out after section verification because should any section 37173862Srie * header overlap occur, and a file needs translating (ie. xlate'ing 37183862Srie * information from a non-native architecture file), then the process 37193862Srie * of translation can corrupt the section header information. Of 37203862Srie * course, if there is any section overlap, the data related to the 37213862Srie * sections is going to be compromised. However, it is the translation 37223862Srie * of this data that has caused problems with elfdump()'s ability to 37233862Srie * extract the data. 37243862Srie */ 37254242Sab196087 for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn); 37264242Sab196087 ndx++, _cache++) { 37273862Srie char scnndxnm[100]; 37283862Srie 37294242Sab196087 _cache->c_ndx = ndx; 37303862Srie _cache->c_scn = scn; 37313862Srie 37321618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) { 37330Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 37340Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 37353862Srie EC_WORD(elf_ndxscn(scn))); 37360Sstevel@tonic-gate } 37370Sstevel@tonic-gate 37383862Srie /* 37394242Sab196087 * If this section has data in the file, include it in 37404242Sab196087 * the array of sections to check for address overlap. 37414242Sab196087 */ 37424242Sab196087 if ((_cache->c_shdr->sh_size != 0) && 37434242Sab196087 (_cache->c_shdr->sh_type != SHT_NOBITS)) 37444242Sab196087 shdr_ndx_arr[shdr_ndx_arr_cnt++] = ndx; 37454242Sab196087 37464242Sab196087 /* 37473862Srie * If a shstrtab exists, assign the section name. 37483862Srie */ 37493862Srie if (names && _cache->c_shdr) { 37503862Srie if (_cache->c_shdr->sh_name && 37513862Srie /* LINTED */ 37523862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) { 37537463SRod.Evans@Sun.COM const char *symname; 37547463SRod.Evans@Sun.COM char *secname; 37557463SRod.Evans@Sun.COM 37567463SRod.Evans@Sun.COM secname = names + _cache->c_shdr->sh_name; 37577463SRod.Evans@Sun.COM 37587463SRod.Evans@Sun.COM /* 37597463SRod.Evans@Sun.COM * A SUN naming convention employs a "%" within 37607463SRod.Evans@Sun.COM * a section name to indicate a section/symbol 37617463SRod.Evans@Sun.COM * name. This originated from the compilers 37627463SRod.Evans@Sun.COM * -xF option, that places functions into their 37637463SRod.Evans@Sun.COM * own sections. This convention (which has no 37647463SRod.Evans@Sun.COM * formal standard) has also been followed for 37657463SRod.Evans@Sun.COM * COMDAT sections. To demangle the symbol 37667463SRod.Evans@Sun.COM * name, the name must be separated from the 37677463SRod.Evans@Sun.COM * section name. 37687463SRod.Evans@Sun.COM */ 37697463SRod.Evans@Sun.COM if (((flags & FLG_CTL_DEMANGLE) == 0) || 37707463SRod.Evans@Sun.COM ((symname = strchr(secname, '%')) == NULL)) 37717463SRod.Evans@Sun.COM _cache->c_name = secname; 37727463SRod.Evans@Sun.COM else { 37737463SRod.Evans@Sun.COM size_t secsz = ++symname - secname; 37747463SRod.Evans@Sun.COM size_t strsz; 37757463SRod.Evans@Sun.COM 37767463SRod.Evans@Sun.COM symname = demangle(symname, flags); 37777463SRod.Evans@Sun.COM strsz = secsz + strlen(symname) + 1; 37787463SRod.Evans@Sun.COM 37797463SRod.Evans@Sun.COM if ((_cache->c_name = 37807463SRod.Evans@Sun.COM malloc(strsz)) == NULL) { 37817463SRod.Evans@Sun.COM int err = errno; 37827463SRod.Evans@Sun.COM (void) fprintf(stderr, 37837463SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_MALLOC), 37847463SRod.Evans@Sun.COM file, strerror(err)); 37857463SRod.Evans@Sun.COM return (0); 37867463SRod.Evans@Sun.COM } 37877463SRod.Evans@Sun.COM (void) snprintf(_cache->c_name, strsz, 37887463SRod.Evans@Sun.COM MSG_ORIG(MSG_FMT_SECSYM), 37897463SRod.Evans@Sun.COM EC_WORD(secsz), secname, symname); 37907463SRod.Evans@Sun.COM } 37919085SAli.Bahrami@Sun.COM 37923862Srie continue; 37933862Srie } 37940Sstevel@tonic-gate 37950Sstevel@tonic-gate /* 37963862Srie * Generate an error if the section name index is zero 37973862Srie * or exceeds the shstrtab data. Fall through to 37983862Srie * fabricate a section name. 37990Sstevel@tonic-gate */ 38003862Srie if ((_cache->c_shdr->sh_name == 0) || 38010Sstevel@tonic-gate /* LINTED */ 38021618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) { 38030Sstevel@tonic-gate (void) fprintf(stderr, 38040Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file, 38054242Sab196087 EC_WORD(ndx), 38061618Srie EC_XWORD(_cache->c_shdr->sh_name)); 38070Sstevel@tonic-gate } 38083862Srie } 38093862Srie 38103862Srie /* 38113862Srie * If there exists no shstrtab data, or a section header has no 38123862Srie * name (an invalid index of 0), then compose a name for the 38133862Srie * section. 38143862Srie */ 38153862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm), 38164242Sab196087 MSG_INTL(MSG_FMT_SCNNDX), ndx); 38174242Sab196087 38184242Sab196087 if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == NULL) { 38193862Srie int err = errno; 38203862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 38213862Srie file, strerror(err)); 38224665Sab196087 return (0); 38233862Srie } 38243862Srie (void) strcpy(_cache->c_name, scnndxnm); 38253862Srie } 38263862Srie 38273862Srie /* 38283862Srie * Having collected all the sections, validate their address range. 38293862Srie * Cases have existed where the section information has been invalid. 38303862Srie * This can lead to all sorts of other, hard to diagnose errors, as 38313862Srie * each section is processed individually (ie. with elf_getdata()). 38323862Srie * Here, we carry out some address comparisons to catch a family of 38333862Srie * overlapping memory issues we have observed (likely, there are others 38343862Srie * that we have yet to discover). 38353862Srie * 38363862Srie * Note, should any memory overlap occur, obtaining any additional 38373862Srie * data from the file is questionable. However, it might still be 38383862Srie * possible to inspect the ELF header, Programs headers, or individual 38393862Srie * sections, so rather than bailing on an error condition, continue 38403862Srie * processing to see if any data can be salvaged. 38413862Srie */ 38424242Sab196087 if (shdr_ndx_arr_cnt > 1) { 38434242Sab196087 sort_shdr_ndx_arr_cache = cache; 38444242Sab196087 qsort(shdr_ndx_arr, shdr_ndx_arr_cnt, 38454242Sab196087 sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr); 38464242Sab196087 } 38474242Sab196087 for (ndx = 0; ndx < shdr_ndx_arr_cnt; ndx++) { 38484242Sab196087 Cache *_cache = cache + shdr_ndx_arr[ndx]; 38493862Srie Shdr *shdr = _cache->c_shdr; 38503862Srie Off bgn1, bgn = shdr->sh_offset; 38513862Srie Off end1, end = shdr->sh_offset + shdr->sh_size; 38524242Sab196087 size_t ndx1; 38534242Sab196087 38544242Sab196087 /* 38554242Sab196087 * Check the section against all following ones, reporting 38564242Sab196087 * any overlaps. Since we've sorted the sections by offset, 38574242Sab196087 * we can stop after the first comparison that fails. There 38584242Sab196087 * are no overlaps in a properly formed ELF file, in which 38594242Sab196087 * case this algorithm runs in O(n) time. This will degenerate 38604242Sab196087 * to O(n^2) for a completely broken file. Such a file is 38614242Sab196087 * (1) highly unlikely, and (2) unusable, so it is reasonable 38624242Sab196087 * for the analysis to take longer. 38634242Sab196087 */ 38644242Sab196087 for (ndx1 = ndx + 1; ndx1 < shdr_ndx_arr_cnt; ndx1++) { 38654242Sab196087 Cache *_cache1 = cache + shdr_ndx_arr[ndx1]; 38663862Srie Shdr *shdr1 = _cache1->c_shdr; 38673862Srie 38683862Srie bgn1 = shdr1->sh_offset; 38693862Srie end1 = shdr1->sh_offset + shdr1->sh_size; 38703862Srie 38713862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 38723862Srie ((bgn1 < end) && (end1 >= end))) { 38733862Srie (void) fprintf(stderr, 38743862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file, 38754242Sab196087 EC_WORD(elf_ndxscn(_cache->c_scn)), 38764242Sab196087 _cache->c_name, EC_OFF(bgn), EC_OFF(end), 38773862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)), 38784242Sab196087 _cache1->c_name, EC_OFF(bgn1), 38794242Sab196087 EC_OFF(end1)); 38804242Sab196087 } else { /* No overlap, so can stop */ 38814242Sab196087 break; 38820Sstevel@tonic-gate } 38830Sstevel@tonic-gate } 38840Sstevel@tonic-gate 38853862Srie /* 38864242Sab196087 * In addition to checking for sections overlapping 38874242Sab196087 * each other (done above), we should also make sure 38884242Sab196087 * the section doesn't overlap the section header array. 38893862Srie */ 38903862Srie bgn1 = ehdr->e_shoff; 38913862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum); 38923862Srie 38933862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 38943862Srie ((bgn1 < end) && (end1 >= end))) { 38953862Srie (void) fprintf(stderr, 38963862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1), 38973862Srie EC_OFF(end1), 38983862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 38993862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 39003862Srie } 39013862Srie } 39023862Srie 39033862Srie /* 39044242Sab196087 * Obtain the data for each section. 39053862Srie */ 39064242Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 39074242Sab196087 Cache *_cache = &cache[ndx]; 39083862Srie Elf_Scn *scn = _cache->c_scn; 39093862Srie 39100Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 39110Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 39120Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 39133862Srie EC_WORD(elf_ndxscn(scn))); 39140Sstevel@tonic-gate } 39158747SAli.Bahrami@Sun.COM 39168747SAli.Bahrami@Sun.COM /* 39178747SAli.Bahrami@Sun.COM * If a string table, verify that it has NULL first and 39188747SAli.Bahrami@Sun.COM * final bytes. 39198747SAli.Bahrami@Sun.COM */ 39208747SAli.Bahrami@Sun.COM if ((_cache->c_shdr->sh_type == SHT_STRTAB) && 39218747SAli.Bahrami@Sun.COM (_cache->c_data->d_buf != NULL) && 39228747SAli.Bahrami@Sun.COM (_cache->c_data->d_size > 0)) { 39238747SAli.Bahrami@Sun.COM const char *s = _cache->c_data->d_buf; 39248747SAli.Bahrami@Sun.COM 39258747SAli.Bahrami@Sun.COM if ((*s != '\0') || 39268747SAli.Bahrami@Sun.COM (*(s + _cache->c_data->d_size - 1) != '\0')) 39278747SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALSTR), 39288747SAli.Bahrami@Sun.COM file, _cache->c_name); 39298747SAli.Bahrami@Sun.COM } 39304665Sab196087 } 39314665Sab196087 39324665Sab196087 return (1); 39334665Sab196087 } 39344665Sab196087 39354665Sab196087 39364665Sab196087 3937*9273SAli.Bahrami@Sun.COM /* 3938*9273SAli.Bahrami@Sun.COM * Generate a cache of section headers and related information 3939*9273SAli.Bahrami@Sun.COM * for use by the rest of elfdump. If requested (or the file 3940*9273SAli.Bahrami@Sun.COM * contains no section headers), we generate a fake set of 3941*9273SAli.Bahrami@Sun.COM * headers from the information accessible from the program headers. 3942*9273SAli.Bahrami@Sun.COM * Otherwise, we use the real section headers contained in the file. 3943*9273SAli.Bahrami@Sun.COM */ 3944*9273SAli.Bahrami@Sun.COM static int 3945*9273SAli.Bahrami@Sun.COM create_cache(const char *file, int fd, Elf *elf, Ehdr *ehdr, Cache **cache, 3946*9273SAli.Bahrami@Sun.COM size_t shstrndx, size_t *shnum, uint_t *flags) 3947*9273SAli.Bahrami@Sun.COM { 3948*9273SAli.Bahrami@Sun.COM /* 3949*9273SAli.Bahrami@Sun.COM * If there are no section headers, then resort to synthesizing 3950*9273SAli.Bahrami@Sun.COM * section headers from the program headers. This is normally 3951*9273SAli.Bahrami@Sun.COM * only done by explicit request, but in this case there's no 3952*9273SAli.Bahrami@Sun.COM * reason not to go ahead, since the alternative is simply to quit. 3953*9273SAli.Bahrami@Sun.COM */ 3954*9273SAli.Bahrami@Sun.COM if ((*shnum <= 1) && ((*flags & FLG_CTL_FAKESHDR) == 0)) { 3955*9273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHDR), file); 3956*9273SAli.Bahrami@Sun.COM *flags |= FLG_CTL_FAKESHDR; 3957*9273SAli.Bahrami@Sun.COM } 3958*9273SAli.Bahrami@Sun.COM 3959*9273SAli.Bahrami@Sun.COM if (*flags & FLG_CTL_FAKESHDR) { 3960*9273SAli.Bahrami@Sun.COM if (fake_shdr_cache(file, fd, elf, ehdr, cache, shnum) == 0) 3961*9273SAli.Bahrami@Sun.COM return (0); 3962*9273SAli.Bahrami@Sun.COM } else { 3963*9273SAli.Bahrami@Sun.COM if (shdr_cache(file, elf, ehdr, shstrndx, *shnum, 3964*9273SAli.Bahrami@Sun.COM cache, *flags) == 0) 3965*9273SAli.Bahrami@Sun.COM return (0); 3966*9273SAli.Bahrami@Sun.COM } 3967*9273SAli.Bahrami@Sun.COM 3968*9273SAli.Bahrami@Sun.COM return (1); 3969*9273SAli.Bahrami@Sun.COM } 3970*9273SAli.Bahrami@Sun.COM 39715411Sab196087 int 39725411Sab196087 regular(const char *file, int fd, Elf *elf, uint_t flags, 3973*9273SAli.Bahrami@Sun.COM const char *wname, int wfd, uchar_t osabi) 39744665Sab196087 { 3975*9273SAli.Bahrami@Sun.COM enum { CACHE_NEEDED, CACHE_OK, CACHE_FAIL} cache_state = CACHE_NEEDED; 39764665Sab196087 Elf_Scn *scn; 39774665Sab196087 Ehdr *ehdr; 39784665Sab196087 size_t ndx, shstrndx, shnum, phnum; 39794665Sab196087 Shdr *shdr; 39804665Sab196087 Cache *cache; 39814665Sab196087 VERSYM_STATE versym; 39825411Sab196087 int ret = 0; 39835411Sab196087 int addr_align; 39844665Sab196087 39854665Sab196087 if ((ehdr = elf_getehdr(elf)) == NULL) { 39864665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 39875411Sab196087 return (ret); 39884665Sab196087 } 39894665Sab196087 39904665Sab196087 if (elf_getshnum(elf, &shnum) == 0) { 39914665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 39925411Sab196087 return (ret); 39934665Sab196087 } 39944665Sab196087 39954665Sab196087 if (elf_getshstrndx(elf, &shstrndx) == 0) { 39964665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 39975411Sab196087 return (ret); 39984665Sab196087 } 39994665Sab196087 40004665Sab196087 if (elf_getphnum(elf, &phnum) == 0) { 40014665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 40025411Sab196087 return (ret); 40034665Sab196087 } 40044665Sab196087 /* 40054665Sab196087 * If the user requested section headers derived from the 40064665Sab196087 * program headers (-P option) and this file doesn't have 40074665Sab196087 * any program headers (i.e. ET_REL), then we can't do it. 40084665Sab196087 */ 40095411Sab196087 if ((phnum == 0) && (flags & FLG_CTL_FAKESHDR)) { 40104665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_PNEEDSPH), file); 40115411Sab196087 return (ret); 40124665Sab196087 } 40134665Sab196087 40144665Sab196087 40154665Sab196087 if ((scn = elf_getscn(elf, 0)) != NULL) { 40164665Sab196087 if ((shdr = elf_getshdr(scn)) == NULL) { 40174665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 40184665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 40195411Sab196087 return (ret); 40204665Sab196087 } 40214665Sab196087 } else 40229085SAli.Bahrami@Sun.COM shdr = NULL; 40234665Sab196087 40244665Sab196087 /* 40254665Sab196087 * Print the elf header. 40264665Sab196087 */ 40275411Sab196087 if (flags & FLG_SHOW_EHDR) 40284665Sab196087 Elf_ehdr(0, ehdr, shdr); 40294665Sab196087 40304665Sab196087 /* 40314665Sab196087 * If the section headers or program headers have inadequate 40324665Sab196087 * alignment for the class of object, print a warning. libelf 40334665Sab196087 * can handle such files, but programs that use them can crash 40344665Sab196087 * when they dereference unaligned items. 40355411Sab196087 * 40365411Sab196087 * Note that the AMD64 ABI, although it is a 64-bit architecture, 40375411Sab196087 * allows access to data types smaller than 128-bits to be on 40385411Sab196087 * word alignment. 40394665Sab196087 */ 40405411Sab196087 if (ehdr->e_machine == EM_AMD64) 40415411Sab196087 addr_align = sizeof (Word); 40425411Sab196087 else 40435411Sab196087 addr_align = sizeof (Addr); 40445411Sab196087 40455411Sab196087 if (ehdr->e_phoff & (addr_align - 1)) 40464665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADPHDRALIGN), file); 40475411Sab196087 if (ehdr->e_shoff & (addr_align - 1)) 40484665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHDRALIGN), file); 40494665Sab196087 4050*9273SAli.Bahrami@Sun.COM 4051*9273SAli.Bahrami@Sun.COM /* 4052*9273SAli.Bahrami@Sun.COM * Determine the Operating System ABI (osabi) we will use to 4053*9273SAli.Bahrami@Sun.COM * interpret the object. 4054*9273SAli.Bahrami@Sun.COM */ 4055*9273SAli.Bahrami@Sun.COM if (flags & FLG_CTL_OSABI) { 4056*9273SAli.Bahrami@Sun.COM /* 4057*9273SAli.Bahrami@Sun.COM * If the user explicitly specifies '-O none', we need 4058*9273SAli.Bahrami@Sun.COM * to display a completely generic view of the file. 4059*9273SAli.Bahrami@Sun.COM * However, libconv is written to assume that ELFOSABI_NONE 4060*9273SAli.Bahrami@Sun.COM * is equivalent to ELFOSABI_SOLARIS. To get the desired 4061*9273SAli.Bahrami@Sun.COM * effect, we use an osabi that libconv has no knowledge of. 4062*9273SAli.Bahrami@Sun.COM */ 4063*9273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE) 4064*9273SAli.Bahrami@Sun.COM osabi = ELFOSABI_UNKNOWN4; 4065*9273SAli.Bahrami@Sun.COM } else { 4066*9273SAli.Bahrami@Sun.COM /* Determine osabi from file */ 4067*9273SAli.Bahrami@Sun.COM osabi = ehdr->e_ident[EI_OSABI]; 4068*9273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE) { 4069*9273SAli.Bahrami@Sun.COM /* 4070*9273SAli.Bahrami@Sun.COM * Chicken/Egg scenario: 4071*9273SAli.Bahrami@Sun.COM * 4072*9273SAli.Bahrami@Sun.COM * Ideally, we wait to create the section header cache 4073*9273SAli.Bahrami@Sun.COM * until after the program headers are printed. If we 4074*9273SAli.Bahrami@Sun.COM * only output program headers, we can skip building 4075*9273SAli.Bahrami@Sun.COM * the cache entirely. 4076*9273SAli.Bahrami@Sun.COM * 4077*9273SAli.Bahrami@Sun.COM * Proper interpretation of program headers requires 4078*9273SAli.Bahrami@Sun.COM * the osabi, which is supposed to be in the ELF header. 4079*9273SAli.Bahrami@Sun.COM * However, many systems (Solaris and Linux included) 4080*9273SAli.Bahrami@Sun.COM * have a history of setting the osabi to the generic 4081*9273SAli.Bahrami@Sun.COM * SysV ABI (ELFOSABI_NONE). We assume ELFOSABI_SOLARIS 4082*9273SAli.Bahrami@Sun.COM * in such cases, but would like to check the object 4083*9273SAli.Bahrami@Sun.COM * to see if it has a Linux .note.ABI-tag section, 4084*9273SAli.Bahrami@Sun.COM * which implies ELFOSABI_LINUX. This requires a 4085*9273SAli.Bahrami@Sun.COM * section header cache. 4086*9273SAli.Bahrami@Sun.COM * 4087*9273SAli.Bahrami@Sun.COM * To break the cycle, we create section headers now 4088*9273SAli.Bahrami@Sun.COM * if osabi is ELFOSABI_NONE, and later otherwise. 4089*9273SAli.Bahrami@Sun.COM * If it succeeds, we use them, if not, we defer 4090*9273SAli.Bahrami@Sun.COM * exiting until after the program headers are out. 4091*9273SAli.Bahrami@Sun.COM */ 4092*9273SAli.Bahrami@Sun.COM if (create_cache(file, fd, elf, ehdr, &cache, 4093*9273SAli.Bahrami@Sun.COM shstrndx, &shnum, &flags) == 0) { 4094*9273SAli.Bahrami@Sun.COM cache_state = CACHE_FAIL; 4095*9273SAli.Bahrami@Sun.COM } else { 4096*9273SAli.Bahrami@Sun.COM cache_state = CACHE_OK; 4097*9273SAli.Bahrami@Sun.COM if (has_linux_abi_note(cache, shnum, file)) { 4098*9273SAli.Bahrami@Sun.COM Conv_inv_buf_t ibuf1, ibuf2; 4099*9273SAli.Bahrami@Sun.COM 4100*9273SAli.Bahrami@Sun.COM (void) fprintf(stderr, 4101*9273SAli.Bahrami@Sun.COM MSG_INTL(MSG_INFO_LINUXOSABI), file, 4102*9273SAli.Bahrami@Sun.COM conv_ehdr_osabi(osabi, 0, &ibuf1), 4103*9273SAli.Bahrami@Sun.COM conv_ehdr_osabi(ELFOSABI_LINUX, 4104*9273SAli.Bahrami@Sun.COM 0, &ibuf2)); 4105*9273SAli.Bahrami@Sun.COM osabi = ELFOSABI_LINUX; 4106*9273SAli.Bahrami@Sun.COM } 4107*9273SAli.Bahrami@Sun.COM } 4108*9273SAli.Bahrami@Sun.COM } 4109*9273SAli.Bahrami@Sun.COM /* 4110*9273SAli.Bahrami@Sun.COM * We treat ELFOSABI_NONE identically to ELFOSABI_SOLARIS. 4111*9273SAli.Bahrami@Sun.COM * Mapping NONE to SOLARIS simplifies the required test. 4112*9273SAli.Bahrami@Sun.COM */ 4113*9273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE) 4114*9273SAli.Bahrami@Sun.COM osabi = ELFOSABI_SOLARIS; 4115*9273SAli.Bahrami@Sun.COM } 4116*9273SAli.Bahrami@Sun.COM 41174665Sab196087 /* 41184665Sab196087 * Print the program headers. 41194665Sab196087 */ 41205411Sab196087 if ((flags & FLG_SHOW_PHDR) && (phnum != 0)) { 41215411Sab196087 Phdr *phdr; 41224665Sab196087 41234665Sab196087 if ((phdr = elf_getphdr(elf)) == NULL) { 41244665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 41255411Sab196087 return (ret); 41264665Sab196087 } 41274665Sab196087 41284665Sab196087 for (ndx = 0; ndx < phnum; phdr++, ndx++) { 41295411Sab196087 if (!match(MATCH_F_PHDR| MATCH_F_NDX | MATCH_F_TYPE, 41305411Sab196087 NULL, ndx, phdr->p_type)) 41314665Sab196087 continue; 41324665Sab196087 41334665Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 41344665Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx)); 4135*9273SAli.Bahrami@Sun.COM Elf_phdr(0, osabi, ehdr->e_machine, phdr); 41364665Sab196087 } 41374665Sab196087 } 41384665Sab196087 41394665Sab196087 /* 41405411Sab196087 * If we have flag bits set that explicitly require a show or calc 41415411Sab196087 * operation, but none of them require the section headers, then 41425411Sab196087 * we are done and can return now. 41434665Sab196087 */ 41445411Sab196087 if (((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) != 0) && 41455411Sab196087 ((flags & (FLG_MASK_SHOW_SHDR | FLG_MASK_CALC_SHDR)) == 0)) 41465411Sab196087 return (ret); 41475411Sab196087 41485411Sab196087 /* 41495411Sab196087 * Everything from this point on requires section headers. 41505411Sab196087 * If we have no section headers, there is no reason to continue. 4151*9273SAli.Bahrami@Sun.COM * 4152*9273SAli.Bahrami@Sun.COM * If we tried above to create the section header cache and failed, 4153*9273SAli.Bahrami@Sun.COM * it is time to exit. Otherwise, create it if needed. 41545411Sab196087 */ 4155*9273SAli.Bahrami@Sun.COM switch (cache_state) { 4156*9273SAli.Bahrami@Sun.COM case CACHE_NEEDED: 4157*9273SAli.Bahrami@Sun.COM if (create_cache(file, fd, elf, ehdr, &cache, shstrndx, 4158*9273SAli.Bahrami@Sun.COM &shnum, &flags) == 0) 4159*9273SAli.Bahrami@Sun.COM return (ret); 4160*9273SAli.Bahrami@Sun.COM break; 4161*9273SAli.Bahrami@Sun.COM case CACHE_FAIL: 4162*9273SAli.Bahrami@Sun.COM return (ret); 4163*9273SAli.Bahrami@Sun.COM } 41645411Sab196087 if (shnum <= 1) 41655411Sab196087 goto done; 41665411Sab196087 41675411Sab196087 /* 41684665Sab196087 * If -w was specified, find and write out the section(s) data. 41694665Sab196087 */ 41704665Sab196087 if (wfd) { 41714665Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 41724665Sab196087 Cache *_cache = &cache[ndx]; 41734665Sab196087 41745411Sab196087 if (match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 41755411Sab196087 ndx, _cache->c_shdr->sh_type) && 41765411Sab196087 _cache->c_data && _cache->c_data->d_buf) { 41775411Sab196087 if (write(wfd, _cache->c_data->d_buf, 41785411Sab196087 _cache->c_data->d_size) != 41795411Sab196087 _cache->c_data->d_size) { 41805411Sab196087 int err = errno; 41815411Sab196087 (void) fprintf(stderr, 41825411Sab196087 MSG_INTL(MSG_ERR_WRITE), wname, 41835411Sab196087 strerror(err)); 41845411Sab196087 /* 41855411Sab196087 * Return an exit status of 1, because 41865411Sab196087 * the failure is not related to the 41875411Sab196087 * ELF file, but by system resources. 41885411Sab196087 */ 41895411Sab196087 ret = 1; 41905411Sab196087 goto done; 41915411Sab196087 } 41924665Sab196087 } 41930Sstevel@tonic-gate } 41940Sstevel@tonic-gate } 41950Sstevel@tonic-gate 41965411Sab196087 /* 41975411Sab196087 * If we have no flag bits set that explicitly require a show or calc 41985411Sab196087 * operation, but match options (-I, -N, -T) were used, then run 41995411Sab196087 * through the section headers and see if we can't deduce show flags 42005411Sab196087 * from the match options given. 42015411Sab196087 * 42025411Sab196087 * We don't do this if -w was specified, because (-I, -N, -T) used 42035411Sab196087 * with -w in lieu of some other option is supposed to be quiet. 42045411Sab196087 */ 42055411Sab196087 if ((wfd == 0) && (flags & FLG_CTL_MATCH) && 42065411Sab196087 ((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) == 0)) { 42075411Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 42085411Sab196087 Cache *_cache = &cache[ndx]; 42095411Sab196087 42105411Sab196087 if (!match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 42115411Sab196087 ndx, _cache->c_shdr->sh_type)) 42125411Sab196087 continue; 42135411Sab196087 42145411Sab196087 switch (_cache->c_shdr->sh_type) { 42155411Sab196087 case SHT_PROGBITS: 42165411Sab196087 /* 42175411Sab196087 * Heuristic time: It is usually bad form 42189085SAli.Bahrami@Sun.COM * to assume the meaning/format of a PROGBITS 42199085SAli.Bahrami@Sun.COM * section based on its name. However, there 42209085SAli.Bahrami@Sun.COM * are exceptions: The ELF ABI specifies 42219085SAli.Bahrami@Sun.COM * .interp and .got sections by name. Existing 42229085SAli.Bahrami@Sun.COM * practice has similarly pinned down the 42239085SAli.Bahrami@Sun.COM * meaning of unwind sections (.eh_frame and 42249085SAli.Bahrami@Sun.COM * .eh_frame_hdr). 42259085SAli.Bahrami@Sun.COM * 42269085SAli.Bahrami@Sun.COM * Check for these special names. 42275411Sab196087 */ 42285411Sab196087 if (strcmp(_cache->c_name, 42295411Sab196087 MSG_ORIG(MSG_ELF_INTERP)) == 0) 42305411Sab196087 flags |= FLG_SHOW_INTERP; 42315411Sab196087 else if (strcmp(_cache->c_name, 42325411Sab196087 MSG_ORIG(MSG_ELF_GOT)) == 0) 42335411Sab196087 flags |= FLG_SHOW_GOT; 42349085SAli.Bahrami@Sun.COM else if (strncmp(_cache->c_name, 42359085SAli.Bahrami@Sun.COM MSG_ORIG(MSG_SCN_FRM), 42369085SAli.Bahrami@Sun.COM MSG_SCN_FRM_SIZE) == 0) 42379085SAli.Bahrami@Sun.COM flags |= FLG_SHOW_UNWIND; 42385411Sab196087 break; 42395411Sab196087 42405411Sab196087 case SHT_SYMTAB: 42415411Sab196087 case SHT_DYNSYM: 42425411Sab196087 case SHT_SUNW_LDYNSYM: 42435411Sab196087 case SHT_SUNW_versym: 42445411Sab196087 case SHT_SYMTAB_SHNDX: 42455411Sab196087 flags |= FLG_SHOW_SYMBOLS; 42465411Sab196087 break; 42475411Sab196087 42485411Sab196087 case SHT_RELA: 42495411Sab196087 case SHT_REL: 42505411Sab196087 flags |= FLG_SHOW_RELOC; 42515411Sab196087 break; 42525411Sab196087 42535411Sab196087 case SHT_HASH: 42545411Sab196087 flags |= FLG_SHOW_HASH; 42555411Sab196087 break; 42565411Sab196087 42575411Sab196087 case SHT_DYNAMIC: 42585411Sab196087 flags |= FLG_SHOW_DYNAMIC; 42595411Sab196087 break; 42605411Sab196087 42615411Sab196087 case SHT_NOTE: 42625411Sab196087 flags |= FLG_SHOW_NOTE; 42635411Sab196087 break; 42645411Sab196087 42655411Sab196087 case SHT_GROUP: 42665411Sab196087 flags |= FLG_SHOW_GROUP; 42675411Sab196087 break; 42685411Sab196087 42695411Sab196087 case SHT_SUNW_symsort: 42705411Sab196087 case SHT_SUNW_tlssort: 42715411Sab196087 flags |= FLG_SHOW_SORT; 42725411Sab196087 break; 42735411Sab196087 42745411Sab196087 case SHT_SUNW_cap: 42755411Sab196087 flags |= FLG_SHOW_CAP; 42765411Sab196087 break; 42775411Sab196087 42785411Sab196087 case SHT_SUNW_move: 42795411Sab196087 flags |= FLG_SHOW_MOVE; 42805411Sab196087 break; 42815411Sab196087 42825411Sab196087 case SHT_SUNW_syminfo: 42835411Sab196087 flags |= FLG_SHOW_SYMINFO; 42845411Sab196087 break; 42855411Sab196087 42865411Sab196087 case SHT_SUNW_verdef: 42875411Sab196087 case SHT_SUNW_verneed: 42885411Sab196087 flags |= FLG_SHOW_VERSIONS; 42895411Sab196087 break; 42905411Sab196087 42915411Sab196087 case SHT_AMD64_UNWIND: 42925411Sab196087 flags |= FLG_SHOW_UNWIND; 42935411Sab196087 break; 42945411Sab196087 } 42955411Sab196087 } 42965411Sab196087 } 42975411Sab196087 42985411Sab196087 42995411Sab196087 if (flags & FLG_SHOW_SHDR) 4300*9273SAli.Bahrami@Sun.COM sections(file, cache, shnum, ehdr, osabi); 43010Sstevel@tonic-gate 43025411Sab196087 if (flags & FLG_SHOW_INTERP) 43031618Srie interp(file, cache, shnum, phnum, elf); 43040Sstevel@tonic-gate 4305*9273SAli.Bahrami@Sun.COM if ((osabi == ELFOSABI_SOLARIS) || (osabi == ELFOSABI_LINUX)) 4306*9273SAli.Bahrami@Sun.COM versions(cache, shnum, file, flags, &versym); 43070Sstevel@tonic-gate 43085411Sab196087 if (flags & FLG_SHOW_SYMBOLS) 4309*9273SAli.Bahrami@Sun.COM symbols(cache, shnum, ehdr, osabi, &versym, file, flags); 4310*9273SAli.Bahrami@Sun.COM 4311*9273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_SORT) && (osabi == ELFOSABI_SOLARIS)) 4312*9273SAli.Bahrami@Sun.COM sunw_sort(cache, shnum, ehdr, osabi, &versym, file, flags); 43133492Sab196087 43145411Sab196087 if (flags & FLG_SHOW_HASH) 43154168Sab196087 hash(cache, shnum, file, flags); 43160Sstevel@tonic-gate 43175411Sab196087 if (flags & FLG_SHOW_GOT) 43187463SRod.Evans@Sun.COM got(cache, shnum, ehdr, file); 43190Sstevel@tonic-gate 43205411Sab196087 if (flags & FLG_SHOW_GROUP) 43214168Sab196087 group(cache, shnum, file, flags); 43220Sstevel@tonic-gate 43235411Sab196087 if (flags & FLG_SHOW_SYMINFO) 43240Sstevel@tonic-gate syminfo(cache, shnum, file); 43250Sstevel@tonic-gate 43265411Sab196087 if (flags & FLG_SHOW_RELOC) 43277463SRod.Evans@Sun.COM reloc(cache, shnum, ehdr, file); 43280Sstevel@tonic-gate 43295411Sab196087 if (flags & FLG_SHOW_DYNAMIC) 4330*9273SAli.Bahrami@Sun.COM dynamic(cache, shnum, ehdr, osabi, file); 43310Sstevel@tonic-gate 43326635Sab196087 if (flags & FLG_SHOW_NOTE) { 43336635Sab196087 Word note_cnt; 43346635Sab196087 size_t note_shnum; 43356635Sab196087 Cache *note_cache; 43366635Sab196087 43376635Sab196087 note_cnt = note(cache, shnum, ehdr, file); 43386635Sab196087 43396635Sab196087 /* 43406635Sab196087 * Solaris core files have section headers, but these 43416635Sab196087 * headers do not include SHT_NOTE sections that reference 43426635Sab196087 * the core note sections. This means that note() won't 43436635Sab196087 * find the core notes. Fake section headers (-P option) 43446635Sab196087 * recover these sections, but it is inconvenient to require 43456635Sab196087 * users to specify -P in this situation. If the following 43466635Sab196087 * are all true: 43476635Sab196087 * 43486635Sab196087 * - No note sections were found 43496635Sab196087 * - This is a core file 43506635Sab196087 * - We are not already using fake section headers 43516635Sab196087 * 43526635Sab196087 * then we will automatically generate fake section headers 43536635Sab196087 * and then process them in a second call to note(). 43546635Sab196087 */ 43556635Sab196087 if ((note_cnt == 0) && (ehdr->e_type == ET_CORE) && 43566635Sab196087 !(flags & FLG_CTL_FAKESHDR) && 43576635Sab196087 (fake_shdr_cache(file, fd, elf, ehdr, 43586635Sab196087 ¬e_cache, ¬e_shnum) != 0)) { 43596635Sab196087 (void) note(note_cache, note_shnum, ehdr, file); 43606635Sab196087 fake_shdr_cache_free(note_cache, note_shnum); 43616635Sab196087 } 43626635Sab196087 } 43630Sstevel@tonic-gate 4364*9273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_MOVE) && (osabi == ELFOSABI_SOLARIS)) 43654168Sab196087 move(cache, shnum, file, flags); 43660Sstevel@tonic-gate 43675411Sab196087 if (flags & FLG_CALC_CHECKSUM) 43680Sstevel@tonic-gate checksum(elf); 43690Sstevel@tonic-gate 4370*9273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_CAP) && (osabi == ELFOSABI_SOLARIS)) 43711618Srie cap(file, cache, shnum, phnum, ehdr, elf); 43720Sstevel@tonic-gate 4373*9273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_UNWIND) && 4374*9273SAli.Bahrami@Sun.COM ((osabi == ELFOSABI_SOLARIS) || (osabi == ELFOSABI_LINUX))) 4375*9273SAli.Bahrami@Sun.COM unwind(cache, shnum, phnum, ehdr, osabi, file, elf, flags); 43760Sstevel@tonic-gate 43774665Sab196087 43784665Sab196087 /* Release the memory used to cache section headers */ 43795411Sab196087 done: 43805411Sab196087 if (flags & FLG_CTL_FAKESHDR) 43814665Sab196087 fake_shdr_cache_free(cache, shnum); 43824665Sab196087 else 43834665Sab196087 free(cache); 43845411Sab196087 43855411Sab196087 return (ret); 43860Sstevel@tonic-gate } 4387