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 */ 1183875Sab196087 Word shnum; /* # of sections in cache */ 1193875Sab196087 Cache *seccache; /* Cache of symbol table section hdr */ 1203875Sab196087 Word secndx; /* Index of symbol table section hdr */ 1213875Sab196087 const char *secname; /* Name of section */ 1223875Sab196087 uint_t flags; /* Command line option flags */ 1233875Sab196087 struct { /* Extended section index data */ 1243875Sab196087 int checked; /* TRUE if already checked for shxndx */ 1253875Sab196087 Word *data; /* NULL, or extended section index */ 1263875Sab196087 /* used for symbol table entries */ 1273875Sab196087 uint_t n; /* # items in shxndx.data */ 1283875Sab196087 } shxndx; 1293875Sab196087 VERSYM_STATE *versym; /* NULL, or associated VERSYM section */ 1303875Sab196087 Sym *sym; /* Array of symbols */ 1313875Sab196087 Word symn; /* # of symbols */ 1323875Sab196087 } SYMTBL_STATE; 1333875Sab196087 1343875Sab196087 1353875Sab196087 1360Sstevel@tonic-gate /* 1370Sstevel@tonic-gate * Focal point for verifying symbol names. 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate static const char * 1401618Srie string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name) 1410Sstevel@tonic-gate { 1424063Sab196087 /* 1434063Sab196087 * If an error in this routine is due to a property of the string 1444063Sab196087 * section, as opposed to a bad offset into the section (a property of 1454063Sab196087 * the referencing section), then we will detect the same error on 1464063Sab196087 * every call involving those sections. We use these static variables 1474063Sab196087 * to retain the information needed to only issue each such error once. 1484063Sab196087 */ 1494063Sab196087 static Cache *last_refsec; /* Last referencing section seen */ 1504063Sab196087 static int strsec_err; /* True if error issued */ 1514063Sab196087 1523492Sab196087 const char *strs; 1533492Sab196087 Word strn; 1540Sstevel@tonic-gate 1553466Srie if (strsec->c_data == NULL) 1563466Srie return (NULL); 1573466Srie 1583492Sab196087 strs = (char *)strsec->c_data->d_buf; 1593492Sab196087 strn = strsec->c_data->d_size; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1624063Sab196087 * We only print a diagnostic regarding a bad string table once per 1634063Sab196087 * input section being processed. If the refsec has changed, reset 1644063Sab196087 * our retained error state. 1650Sstevel@tonic-gate */ 1664063Sab196087 if (last_refsec != refsec) { 1674063Sab196087 last_refsec = refsec; 1684063Sab196087 strsec_err = 0; 1694063Sab196087 } 1704063Sab196087 1714063Sab196087 /* Verify that strsec really is a string table */ 1724063Sab196087 if (strsec->c_shdr->sh_type != SHT_STRTAB) { 1734063Sab196087 if (!strsec_err) { 1744063Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOTSTRTAB), 1754063Sab196087 file, strsec->c_ndx, refsec->c_ndx); 1764063Sab196087 strsec_err = 1; 1774063Sab196087 } 1784063Sab196087 return (MSG_INTL(MSG_STR_UNKNOWN)); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * Is the string table offset within range of the available strings? 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate if (name >= strn) { 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * Do we have a empty string table? 1870Sstevel@tonic-gate */ 1889085SAli.Bahrami@Sun.COM if (strs == NULL) { 1894063Sab196087 if (!strsec_err) { 1900Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1910Sstevel@tonic-gate file, strsec->c_name); 1924063Sab196087 strsec_err = 1; 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate } else { 1950Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF), 1961618Srie file, refsec->c_name, EC_WORD(ndx), strsec->c_name, 1971618Srie EC_WORD(name), EC_WORD(strn - 1)); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate /* 2010Sstevel@tonic-gate * Return the empty string so that the calling function can 2020Sstevel@tonic-gate * continue it's output diagnostics. 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate return (MSG_INTL(MSG_STR_UNKNOWN)); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate return (strs + name); 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* 2101618Srie * Relocations can reference section symbols and standard symbols. If the 2111618Srie * former, establish the section name. 2121618Srie */ 2131618Srie static const char * 2141618Srie relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum, 2157463SRod.Evans@Sun.COM Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file) 2161618Srie { 2177463SRod.Evans@Sun.COM Sym *sym; 2187463SRod.Evans@Sun.COM const char *name; 2191618Srie 2201618Srie if (symndx >= symnum) { 2211618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX), 2221618Srie file, EC_WORD(symndx), EC_WORD(relndx)); 2231618Srie return (MSG_INTL(MSG_STR_UNKNOWN)); 2241618Srie } 2251618Srie 2261618Srie sym = (Sym *)(syms + symndx); 2277463SRod.Evans@Sun.COM name = string(csec, symndx, strsec, file, sym->st_name); 2281618Srie 2291618Srie /* 2301618Srie * If the symbol represents a section offset construct an appropriate 2317463SRod.Evans@Sun.COM * string. Note, although section symbol table entries typically have 2327463SRod.Evans@Sun.COM * a NULL name pointer, entries do exist that point into the string 2337463SRod.Evans@Sun.COM * table to their own NULL strings. 2341618Srie */ 2357463SRod.Evans@Sun.COM if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) && 2367463SRod.Evans@Sun.COM ((sym->st_name == 0) || (*name == '\0'))) { 2377463SRod.Evans@Sun.COM (void) snprintf(secstr, secsz, MSG_INTL(MSG_STR_SECTION), 2387463SRod.Evans@Sun.COM cache[sym->st_shndx].c_name); 2391618Srie return ((const char *)secstr); 2401618Srie } 2411618Srie 2427463SRod.Evans@Sun.COM return (name); 2431618Srie } 2441618Srie 2451618Srie /* 2461618Srie * Focal point for establishing a string table section. Data such as the 2471618Srie * dynamic information simply points to a string table. Data such as 2481618Srie * relocations, reference a symbol table, which in turn is associated with a 2491618Srie * string table. 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate static int 2521618Srie stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file, 2531618Srie Word *symnum, Cache **symsec, Cache **strsec) 2541618Srie { 2551618Srie Shdr *shdr = cache[ndx].c_shdr; 2561618Srie 2571618Srie if (symtab) { 2581618Srie /* 2591618Srie * Validate the symbol table section. 2601618Srie */ 2611618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2621618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2631618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 2641618Srie return (0); 2651618Srie } 2663466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2673466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2683466Srie file, cache[ndx].c_name); 2693466Srie return (0); 2703466Srie } 2711618Srie 2721618Srie /* 2731618Srie * Obtain, and verify the symbol table data. 2741618Srie */ 2753466Srie if ((cache[ndx].c_data == NULL) || 2763466Srie (cache[ndx].c_data->d_buf == NULL)) { 2771618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2781618Srie file, cache[ndx].c_name); 2791618Srie return (0); 2801618Srie } 2811618Srie 2821618Srie /* 2831618Srie * Establish the string table index. 2841618Srie */ 2851618Srie ndx = shdr->sh_link; 2861618Srie shdr = cache[ndx].c_shdr; 2871618Srie 2881618Srie /* 2891618Srie * Return symbol table information. 2901618Srie */ 2911618Srie if (symnum) 2921618Srie *symnum = (shdr->sh_size / shdr->sh_entsize); 2931618Srie if (symsec) 2941618Srie *symsec = &cache[ndx]; 2951618Srie } 2961618Srie 2971618Srie /* 2981618Srie * Validate the associated string table section. 2991618Srie */ 3001618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3011618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3021618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 3031618Srie return (0); 3041618Srie } 3051618Srie 3061618Srie if (strsec) 3071618Srie *strsec = &cache[shdr->sh_link]; 3081618Srie 3091618Srie return (1); 3101618Srie } 3111618Srie 3121618Srie /* 3131618Srie * Lookup a symbol and set Sym accordingly. 3141618Srie */ 3151618Srie static int 3161618Srie symlookup(const char *name, Cache *cache, Word shnum, Sym **sym, 3170Sstevel@tonic-gate Cache *symtab, const char *file) 3180Sstevel@tonic-gate { 3191618Srie Shdr *shdr; 3201618Srie Word symn, cnt; 3211618Srie Sym *syms; 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (symtab == 0) 3240Sstevel@tonic-gate return (0); 3250Sstevel@tonic-gate 3261618Srie shdr = symtab->c_shdr; 3271618Srie 3280Sstevel@tonic-gate /* 3290Sstevel@tonic-gate * Determine the symbol data and number. 3300Sstevel@tonic-gate */ 3310Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 3320Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 3330Sstevel@tonic-gate file, symtab->c_name); 3340Sstevel@tonic-gate return (0); 3350Sstevel@tonic-gate } 3363466Srie if (symtab->c_data == NULL) 3373466Srie return (0); 3383466Srie 3390Sstevel@tonic-gate /* LINTED */ 3401618Srie symn = (Word)(shdr->sh_size / shdr->sh_entsize); 3411618Srie syms = (Sym *)symtab->c_data->d_buf; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * Get the associated string table section. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3470Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3481618Srie file, symtab->c_name, EC_WORD(shdr->sh_link)); 3490Sstevel@tonic-gate return (0); 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * Loop through the symbol table to find a match. 3540Sstevel@tonic-gate */ 3551618Srie for (cnt = 0; cnt < symn; syms++, cnt++) { 3561618Srie const char *symname; 3570Sstevel@tonic-gate 3581618Srie symname = string(symtab, cnt, &cache[shdr->sh_link], file, 3591618Srie syms->st_name); 3600Sstevel@tonic-gate 3611618Srie if (symname && (strcmp(name, symname) == 0)) { 3621618Srie *sym = syms; 3630Sstevel@tonic-gate return (1); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate return (0); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * Print section headers. 3710Sstevel@tonic-gate */ 3720Sstevel@tonic-gate static void 3734168Sab196087 sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr) 3740Sstevel@tonic-gate { 3751618Srie size_t seccnt; 3760Sstevel@tonic-gate 3771618Srie for (seccnt = 1; seccnt < shnum; seccnt++) { 3781618Srie Cache *_cache = &cache[seccnt]; 3791618Srie Shdr *shdr = _cache->c_shdr; 3801618Srie const char *secname = _cache->c_name; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * Although numerous section header entries can be zero, it's 3843862Srie * usually a sign of trouble if the type is zero. 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate if (shdr->sh_type == 0) { 3870Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE), 3881618Srie file, secname, EC_WORD(shdr->sh_type)); 3890Sstevel@tonic-gate } 3903862Srie 3915411Sab196087 if (!match(MATCH_F_ALL, secname, seccnt, shdr->sh_type)) 3923862Srie continue; 3930Sstevel@tonic-gate 3941324Srie /* 3951324Srie * Identify any sections that are suspicious. A .got section 3961324Srie * shouldn't exist in a relocatable object. 3971324Srie */ 3981324Srie if (ehdr->e_type == ET_REL) { 3991618Srie if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT), 4001324Srie MSG_ELF_GOT_SIZE) == 0) { 4011324Srie (void) fprintf(stderr, 4021618Srie MSG_INTL(MSG_GOT_UNEXPECTED), file, 4031618Srie secname); 4041324Srie } 4051324Srie } 4061324Srie 4071618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 4081618Srie dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname); 4091618Srie Elf_shdr(0, ehdr->e_machine, shdr); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate 4131618Srie /* 4141618Srie * Obtain a specified Phdr entry. 4151618Srie */ 4161618Srie static Phdr * 4179085SAli.Bahrami@Sun.COM getphdr(Word phnum, Word *type_arr, Word type_cnt, const char *file, Elf *elf) 4181618Srie { 4199085SAli.Bahrami@Sun.COM Word cnt, tcnt; 4201618Srie Phdr *phdr; 4211618Srie 4221618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 4231618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 4249085SAli.Bahrami@Sun.COM return (NULL); 4251618Srie } 4261618Srie 4271618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 4289085SAli.Bahrami@Sun.COM for (tcnt = 0; tcnt < type_cnt; tcnt++) { 4299085SAli.Bahrami@Sun.COM if (phdr->p_type == type_arr[tcnt]) 4309085SAli.Bahrami@Sun.COM return (phdr); 4319085SAli.Bahrami@Sun.COM } 4321618Srie } 4339085SAli.Bahrami@Sun.COM return (NULL); 4341618Srie } 4351618Srie 4360Sstevel@tonic-gate static void 4374168Sab196087 unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, 438*9131SRod.Evans@Sun.COM Elf *elf, uint_t flags) 4390Sstevel@tonic-gate { 4409085SAli.Bahrami@Sun.COM #if defined(_ELF64) 4419085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_64 4429085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_64 4439085SAli.Bahrami@Sun.COM #else 4449085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_32 4459085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_32 4469085SAli.Bahrami@Sun.COM #endif 4479085SAli.Bahrami@Sun.COM 4489085SAli.Bahrami@Sun.COM static Word phdr_types[] = { PT_SUNW_UNWIND, PT_SUNW_EH_FRAME }; 4499085SAli.Bahrami@Sun.COM 4509085SAli.Bahrami@Sun.COM int frame_cnt = 0, hdr_cnt = 0, frame_ndx, hdr_ndx; 4519085SAli.Bahrami@Sun.COM uint64_t save_frame_ptr, save_frame_base; 4524734Sab196087 Conv_dwarf_ehe_buf_t dwarf_ehe_buf; 4539085SAli.Bahrami@Sun.COM Word cnt; 4549085SAli.Bahrami@Sun.COM Phdr *uphdr = NULL; 4551618Srie 4560Sstevel@tonic-gate /* 4579085SAli.Bahrami@Sun.COM * Historical background: .eh_frame and .eh_frame_hdr sections 4589085SAli.Bahrami@Sun.COM * come from the GNU compilers (particularly C++), and are used 4599085SAli.Bahrami@Sun.COM * under all architectures. Their format is based on DWARF. When 4609085SAli.Bahrami@Sun.COM * the amd64 ABI was defined, these sections were adopted wholesale 4619085SAli.Bahrami@Sun.COM * from the existing practice. 4629085SAli.Bahrami@Sun.COM * 4639085SAli.Bahrami@Sun.COM * When amd64 support was added to Solaris, support for these 4649085SAli.Bahrami@Sun.COM * sections was added, using the SHT_AMD64_UNWIND section type 4659085SAli.Bahrami@Sun.COM * to identify them. At first, we ignored them in objects for 4669085SAli.Bahrami@Sun.COM * non-amd64 targets, but later broadened our support to include 4679085SAli.Bahrami@Sun.COM * other architectures in order to better support gcc-generated 4689085SAli.Bahrami@Sun.COM * objects. 4699085SAli.Bahrami@Sun.COM * 4709085SAli.Bahrami@Sun.COM * We match these sections by name, rather than section type, 4719085SAli.Bahrami@Sun.COM * because they can come in as either SHT_AMD64_UNWIND, or as 4729085SAli.Bahrami@Sun.COM * SHT_PROGBITS, and because we need to distinquish between 4739085SAli.Bahrami@Sun.COM * the two types (.eh_frame and .eh_frame_hdr). 4740Sstevel@tonic-gate */ 4750Sstevel@tonic-gate 4761618Srie if (phnum) 4779085SAli.Bahrami@Sun.COM uphdr = getphdr(phnum, phdr_types, 4789085SAli.Bahrami@Sun.COM sizeof (phdr_types) / sizeof (*phdr_types), file, elf); 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 4811618Srie Cache *_cache = &cache[cnt]; 4821618Srie Shdr *shdr = _cache->c_shdr; 4831618Srie uchar_t *data; 4840Sstevel@tonic-gate size_t datasize; 4859085SAli.Bahrami@Sun.COM uint64_t ndx, frame_ptr, fde_cnt, tabndx; 4861618Srie uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate /* 4899085SAli.Bahrami@Sun.COM * Skip sections of the wrong type. On amd64, Solaris tags 4909085SAli.Bahrami@Sun.COM * these as SHT_AMD64_UNWIND, while gcc started out issuing 4919085SAli.Bahrami@Sun.COM * them as SHT_PROGBITS and switched over when the amd64 ABI 4929085SAli.Bahrami@Sun.COM * was finalized. On non-amd64, they're all SHT_PROGBITS. 4930Sstevel@tonic-gate */ 4949085SAli.Bahrami@Sun.COM switch (shdr->sh_type) { 4959085SAli.Bahrami@Sun.COM case SHT_PROGBITS: 4969085SAli.Bahrami@Sun.COM if (ehdr->e_machine == EM_AMD64) 4979085SAli.Bahrami@Sun.COM continue; 4989085SAli.Bahrami@Sun.COM break; 4999085SAli.Bahrami@Sun.COM case SHT_AMD64_UNWIND: 5009085SAli.Bahrami@Sun.COM if (ehdr->e_machine != EM_AMD64) 5019085SAli.Bahrami@Sun.COM continue; 5029085SAli.Bahrami@Sun.COM break; 5039085SAli.Bahrami@Sun.COM default: 5049085SAli.Bahrami@Sun.COM continue; 5059085SAli.Bahrami@Sun.COM } 5069085SAli.Bahrami@Sun.COM 5079085SAli.Bahrami@Sun.COM /* 5089085SAli.Bahrami@Sun.COM * Only sections with names starting with .eh_frame or 5099085SAli.Bahrami@Sun.COM * .eh_frame_hdr are of interest. We do a prefix comparison, 5109085SAli.Bahrami@Sun.COM * allowing for naming conventions like .eh_frame.foo, hence 5119085SAli.Bahrami@Sun.COM * the use of strncmp() rather than strcmp(). This means that 5129085SAli.Bahrami@Sun.COM * we only really need to test for .eh_frame, as it's a 5139085SAli.Bahrami@Sun.COM * prefix of .eh_frame_hdr. 5149085SAli.Bahrami@Sun.COM */ 5159085SAli.Bahrami@Sun.COM if (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 5169085SAli.Bahrami@Sun.COM MSG_SCN_FRM_SIZE) != 0) 5170Sstevel@tonic-gate continue; 5184168Sab196087 5195411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 5200Sstevel@tonic-gate continue; 5210Sstevel@tonic-gate 5223466Srie if (_cache->c_data == NULL) 5233466Srie continue; 5243466Srie 5251618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 5261618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 5270Sstevel@tonic-gate 5281618Srie data = (uchar_t *)(_cache->c_data->d_buf); 5290Sstevel@tonic-gate datasize = _cache->c_data->d_size; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate /* 5320Sstevel@tonic-gate * Is this a .eh_frame_hdr 5330Sstevel@tonic-gate */ 5341618Srie if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || 5350Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 5361618Srie MSG_SCN_FRMHDR_SIZE) == 0)) { 5379085SAli.Bahrami@Sun.COM /* 5389085SAli.Bahrami@Sun.COM * There can only be a single .eh_frame_hdr. 5399085SAli.Bahrami@Sun.COM * Flag duplicates. 5409085SAli.Bahrami@Sun.COM */ 5419085SAli.Bahrami@Sun.COM if (++hdr_cnt > 1) 5429085SAli.Bahrami@Sun.COM (void) fprintf(stderr, 5439085SAli.Bahrami@Sun.COM MSG_INTL(MSG_ERR_MULTEHFRMHDR), file, 5449085SAli.Bahrami@Sun.COM EC_WORD(cnt), _cache->c_name); 5459085SAli.Bahrami@Sun.COM 5461618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR)); 5471618Srie ndx = 0; 5480Sstevel@tonic-gate 5491618Srie vers = data[ndx++]; 5501618Srie frame_ptr_enc = data[ndx++]; 5511618Srie fde_cnt_enc = data[ndx++]; 5521618Srie table_enc = data[ndx++]; 5530Sstevel@tonic-gate 5541618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); 5550Sstevel@tonic-gate 5561618Srie frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, 5579085SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx); 5589085SAli.Bahrami@Sun.COM if (hdr_cnt == 1) { 5599085SAli.Bahrami@Sun.COM hdr_ndx = cnt; 5609085SAli.Bahrami@Sun.COM save_frame_ptr = frame_ptr; 5619085SAli.Bahrami@Sun.COM } 5620Sstevel@tonic-gate 5631618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC), 5644734Sab196087 conv_dwarf_ehe(frame_ptr_enc, &dwarf_ehe_buf), 5654734Sab196087 EC_XWORD(frame_ptr)); 5661618Srie 5671618Srie fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, 5689085SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx); 5690Sstevel@tonic-gate 5701618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), 5714734Sab196087 conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf), 5724734Sab196087 EC_XWORD(fde_cnt)); 5731618Srie dbg_print(0, MSG_ORIG(MSG_UNW_TABENC), 5744734Sab196087 conv_dwarf_ehe(table_enc, &dwarf_ehe_buf)); 5751618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1)); 5761618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2)); 5770Sstevel@tonic-gate 5781618Srie for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 5791618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), 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 EC_XWORD(dwarf_ehe_extract(data, &ndx, 5849085SAli.Bahrami@Sun.COM table_enc, ehdr->e_ident, shdr->sh_addr, 5859085SAli.Bahrami@Sun.COM ndx))); 5861618Srie } 5879085SAli.Bahrami@Sun.COM } else { /* Display the .eh_frame section */ 5889085SAli.Bahrami@Sun.COM frame_cnt++; 5899085SAli.Bahrami@Sun.COM if (frame_cnt == 1) { 5909085SAli.Bahrami@Sun.COM frame_ndx = cnt; 5919085SAli.Bahrami@Sun.COM save_frame_base = shdr->sh_addr; 5929085SAli.Bahrami@Sun.COM } else if ((frame_cnt > 1) && 5939085SAli.Bahrami@Sun.COM (ehdr->e_type != ET_REL)) { 5949085SAli.Bahrami@Sun.COM Conv_inv_buf_t inv_buf; 5959085SAli.Bahrami@Sun.COM 5969085SAli.Bahrami@Sun.COM (void) fprintf(stderr, 5979085SAli.Bahrami@Sun.COM MSG_INTL(MSG_WARN_MULTEHFRM), file, 5989085SAli.Bahrami@Sun.COM EC_WORD(cnt), _cache->c_name, 5999085SAli.Bahrami@Sun.COM conv_ehdr_type(ehdr->e_type, 0, &inv_buf)); 6009085SAli.Bahrami@Sun.COM } 6019085SAli.Bahrami@Sun.COM dump_eh_frame(data, datasize, shdr->sh_addr, 6029085SAli.Bahrami@Sun.COM ehdr->e_machine, ehdr->e_ident); 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate /* 606*9131SRod.Evans@Sun.COM * If we've seen the .eh_frame_hdr and the first .eh_frame 607*9131SRod.Evans@Sun.COM * section, compare the header frame_ptr to the address of the 608*9131SRod.Evans@Sun.COM * actual frame section to ensure the link-editor got this 609*9131SRod.Evans@Sun.COM * right. Note, this diagnostic is only produced when unwind 610*9131SRod.Evans@Sun.COM * information is explicitly asked for, as shared objects built 611*9131SRod.Evans@Sun.COM * with an older ld(1) may reveal this inconsistency. Although 612*9131SRod.Evans@Sun.COM * an inconsistency, it doesn't seem to have any adverse effect 613*9131SRod.Evans@Sun.COM * on existing tools. 6140Sstevel@tonic-gate */ 615*9131SRod.Evans@Sun.COM if (((flags & FLG_MASK_SHOW) != FLG_MASK_SHOW) && 616*9131SRod.Evans@Sun.COM (hdr_cnt > 0) && (frame_cnt > 0) && 6179085SAli.Bahrami@Sun.COM (save_frame_ptr != save_frame_base)) 6189085SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADEHFRMPTR), 6199085SAli.Bahrami@Sun.COM file, EC_WORD(hdr_ndx), cache[hdr_ndx].c_name, 6209085SAli.Bahrami@Sun.COM EC_XWORD(save_frame_ptr), EC_WORD(frame_ndx), 6219085SAli.Bahrami@Sun.COM cache[frame_ndx].c_name, EC_XWORD(save_frame_base)); 6220Sstevel@tonic-gate } 6239085SAli.Bahrami@Sun.COM 6249085SAli.Bahrami@Sun.COM #undef MSG_UNW_BINSRTAB2 6259085SAli.Bahrami@Sun.COM #undef MSG_UNW_BINSRTABENT 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* 6290Sstevel@tonic-gate * Print the hardware/software capabilities. For executables and shared objects 6300Sstevel@tonic-gate * this should be accompanied with a program header. 6310Sstevel@tonic-gate */ 6320Sstevel@tonic-gate static void 6331618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, 6341618Srie Elf *elf) 6350Sstevel@tonic-gate { 6361618Srie Word cnt; 6377833SRod.Evans@Sun.COM Shdr *cshdr = NULL; 6383466Srie Cache *ccache; 6391618Srie Off cphdr_off = 0; 6401618Srie Xword cphdr_sz; 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate /* 6430Sstevel@tonic-gate * Determine if a hardware/software capabilities header exists. 6440Sstevel@tonic-gate */ 6451618Srie if (phnum) { 6461618Srie Phdr *phdr; 6470Sstevel@tonic-gate 6481618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 6490Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 6500Sstevel@tonic-gate return; 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6531618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 6541618Srie if (phdr->p_type == PT_SUNWCAP) { 6551618Srie cphdr_off = phdr->p_offset; 6561618Srie cphdr_sz = phdr->p_filesz; 6571618Srie break; 6581618Srie } 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate /* 6630Sstevel@tonic-gate * Determine if a hardware/software capabilities section exists. 6640Sstevel@tonic-gate */ 6650Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 6661618Srie Cache *_cache = &cache[cnt]; 6671618Srie Shdr *shdr = _cache->c_shdr; 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_cap) 6700Sstevel@tonic-gate continue; 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 6730Sstevel@tonic-gate (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 6740Sstevel@tonic-gate continue; 6750Sstevel@tonic-gate 6763466Srie if (_cache->c_data == NULL) 6773466Srie continue; 6783466Srie 6790Sstevel@tonic-gate ccache = _cache; 6800Sstevel@tonic-gate cshdr = shdr; 6810Sstevel@tonic-gate break; 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6847833SRod.Evans@Sun.COM if ((cshdr == NULL) && (cphdr_off == 0)) 6850Sstevel@tonic-gate return; 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* 6880Sstevel@tonic-gate * Print the hardware/software capabilities section. 6890Sstevel@tonic-gate */ 6900Sstevel@tonic-gate if (cshdr) { 6911618Srie Word ndx, capn; 6923492Sab196087 Cap *cap = (Cap *)ccache->c_data->d_buf; 6930Sstevel@tonic-gate 6944665Sab196087 if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) { 6954665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 6964665Sab196087 file, ccache->c_name); 6974665Sab196087 return; 6984665Sab196087 } 6994665Sab196087 7001618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 7011618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 7020Sstevel@tonic-gate 7031618Srie Elf_cap_title(0); 7041618Srie 7051618Srie capn = (Word)(cshdr->sh_size / cshdr->sh_entsize); 7060Sstevel@tonic-gate 7071618Srie for (ndx = 0; ndx < capn; cap++, ndx++) { 7087833SRod.Evans@Sun.COM if (cap->c_tag == CA_SUNW_NULL) 7097833SRod.Evans@Sun.COM continue; 7107833SRod.Evans@Sun.COM 7117833SRod.Evans@Sun.COM Elf_cap_entry(0, cap, ndx, ehdr->e_machine); 7127833SRod.Evans@Sun.COM 7137833SRod.Evans@Sun.COM /* 7147833SRod.Evans@Sun.COM * An SF1_SUNW_ADDR32 software capability in a 32-bit 7157833SRod.Evans@Sun.COM * object is suspicious as it has no effect. 7167833SRod.Evans@Sun.COM */ 7177833SRod.Evans@Sun.COM if ((cap->c_tag == CA_SUNW_SF_1) && 7187833SRod.Evans@Sun.COM (ehdr->e_ident[EI_CLASS] == ELFCLASS32) && 7197833SRod.Evans@Sun.COM (cap->c_un.c_val & SF1_SUNW_ADDR32)) { 7207833SRod.Evans@Sun.COM (void) fprintf(stderr, 7217833SRod.Evans@Sun.COM MSG_INTL(MSG_WARN_INADDR32SF1), 7227833SRod.Evans@Sun.COM file, ccache->c_name); 7237833SRod.Evans@Sun.COM } 7240Sstevel@tonic-gate } 7250Sstevel@tonic-gate } else 7260Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate /* 7290Sstevel@tonic-gate * If this object is an executable or shared object, then the 7300Sstevel@tonic-gate * hardware/software capabilities section should have an accompanying 7310Sstevel@tonic-gate * program header. 7320Sstevel@tonic-gate */ 7330Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 7340Sstevel@tonic-gate if (cphdr_off == 0) 7350Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 7360Sstevel@tonic-gate file, ccache->c_name); 7370Sstevel@tonic-gate else if ((cphdr_off != cshdr->sh_offset) || 7380Sstevel@tonic-gate (cphdr_sz != cshdr->sh_size)) 7390Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 7400Sstevel@tonic-gate file, ccache->c_name); 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate /* 7450Sstevel@tonic-gate * Print the interpretor. 7460Sstevel@tonic-gate */ 7470Sstevel@tonic-gate static void 7481618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) 7490Sstevel@tonic-gate { 7509085SAli.Bahrami@Sun.COM static Word phdr_types[] = { PT_INTERP }; 7519085SAli.Bahrami@Sun.COM 7529085SAli.Bahrami@Sun.COM 7531618Srie Word cnt; 7549085SAli.Bahrami@Sun.COM Shdr *ishdr = NULL; 7551618Srie Cache *icache; 7561618Srie Off iphdr_off = 0; 7571618Srie Xword iphdr_fsz; 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate /* 7600Sstevel@tonic-gate * Determine if an interp header exists. 7610Sstevel@tonic-gate */ 7621618Srie if (phnum) { 7631618Srie Phdr *phdr; 7640Sstevel@tonic-gate 7659085SAli.Bahrami@Sun.COM phdr = getphdr(phnum, phdr_types, 7669085SAli.Bahrami@Sun.COM sizeof (phdr_types) / sizeof (*phdr_types), file, elf); 7679085SAli.Bahrami@Sun.COM if (phdr != NULL) { 7681618Srie iphdr_off = phdr->p_offset; 7691618Srie iphdr_fsz = phdr->p_filesz; 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate if (iphdr_off == 0) 7740Sstevel@tonic-gate return; 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate /* 7770Sstevel@tonic-gate * Determine if an interp section exists. 7780Sstevel@tonic-gate */ 7790Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 7801618Srie Cache *_cache = &cache[cnt]; 7811618Srie Shdr *shdr = _cache->c_shdr; 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate /* 7840Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP 7850Sstevel@tonic-gate * string. The target section can't be in a NOBITS section. 7860Sstevel@tonic-gate */ 7870Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) || 7880Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) || 7891618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size)) 7900Sstevel@tonic-gate continue; 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate icache = _cache; 7930Sstevel@tonic-gate ishdr = shdr; 7940Sstevel@tonic-gate break; 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate /* 7980Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the 7990Sstevel@tonic-gate * program header, as this is the offset used by the kernel. 8000Sstevel@tonic-gate */ 8013466Srie if (ishdr && icache->c_data) { 8021618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8031618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 8041618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), 8050Sstevel@tonic-gate (char *)icache->c_data->d_buf + 8060Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset)); 8070Sstevel@tonic-gate } else 8080Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate /* 8110Sstevel@tonic-gate * If there are any inconsistences between the program header and 8120Sstevel@tonic-gate * section information, flag them. 8130Sstevel@tonic-gate */ 8140Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) || 8151618Srie (iphdr_fsz != ishdr->sh_size))) { 8160Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 8170Sstevel@tonic-gate icache->c_name); 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate 8210Sstevel@tonic-gate /* 8220Sstevel@tonic-gate * Print the syminfo section. 8230Sstevel@tonic-gate */ 8240Sstevel@tonic-gate static void 8251618Srie syminfo(Cache *cache, Word shnum, const char *file) 8260Sstevel@tonic-gate { 8271618Srie Shdr *infoshdr; 8281618Srie Syminfo *info; 8291618Srie Sym *syms; 8301618Srie Dyn *dyns; 8311618Srie Word infonum, cnt, ndx, symnum; 8329085SAli.Bahrami@Sun.COM Cache *infocache = NULL, *symsec, *strsec; 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8351618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { 8361618Srie infocache = &cache[cnt]; 8370Sstevel@tonic-gate break; 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate } 8409085SAli.Bahrami@Sun.COM if (infocache == NULL) 8410Sstevel@tonic-gate return; 8420Sstevel@tonic-gate 8431618Srie infoshdr = infocache->c_shdr; 8441618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) { 8450Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8461618Srie file, infocache->c_name); 8470Sstevel@tonic-gate return; 8480Sstevel@tonic-gate } 8493466Srie if (infocache->c_data == NULL) 8503466Srie return; 8513466Srie 8521618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize); 8531618Srie info = (Syminfo *)infocache->c_data->d_buf; 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate /* 8560Sstevel@tonic-gate * Get the data buffer of the associated dynamic section. 8570Sstevel@tonic-gate */ 8581618Srie if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) { 8590Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 8601618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info)); 8610Sstevel@tonic-gate return; 8620Sstevel@tonic-gate } 8633466Srie if (cache[infoshdr->sh_info].c_data == NULL) 8643466Srie return; 8653466Srie 8661618Srie dyns = cache[infoshdr->sh_info].c_data->d_buf; 8679085SAli.Bahrami@Sun.COM if (dyns == NULL) { 8680Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8691618Srie file, cache[infoshdr->sh_info].c_name); 8700Sstevel@tonic-gate return; 8710Sstevel@tonic-gate } 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate /* 8741618Srie * Get the data buffer for the associated symbol table and string table. 8750Sstevel@tonic-gate */ 8761618Srie if (stringtbl(cache, 1, cnt, shnum, file, 8771618Srie &symnum, &symsec, &strsec) == 0) 8780Sstevel@tonic-gate return; 8790Sstevel@tonic-gate 8801618Srie syms = symsec->c_data->d_buf; 8810Sstevel@tonic-gate 8821618Srie /* 8831618Srie * Loop through the syminfo entries. 8841618Srie */ 8851618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8861618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name); 8871618Srie Elf_syminfo_title(0); 8880Sstevel@tonic-gate 8891618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) { 8901618Srie Sym *sym; 8919085SAli.Bahrami@Sun.COM const char *needed = NULL, *name; 8921618Srie 8931618Srie if ((info->si_flags == 0) && (info->si_boundto == 0)) 8940Sstevel@tonic-gate continue; 8950Sstevel@tonic-gate 8961618Srie sym = &syms[ndx]; 8971618Srie name = string(infocache, ndx, strsec, file, sym->st_name); 8980Sstevel@tonic-gate 8991618Srie if (info->si_boundto < SYMINFO_BT_LOWRESERVE) { 9001618Srie Dyn *dyn = &dyns[info->si_boundto]; 9011618Srie 9021618Srie needed = string(infocache, info->si_boundto, 9031618Srie strsec, file, dyn->d_un.d_val); 9040Sstevel@tonic-gate } 9051618Srie Elf_syminfo_entry(0, ndx, info, name, needed); 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate } 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate /* 9100Sstevel@tonic-gate * Print version definition section entries. 9110Sstevel@tonic-gate */ 9120Sstevel@tonic-gate static void 9134716Sab196087 version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache, 9140Sstevel@tonic-gate const char *file) 9150Sstevel@tonic-gate { 9161618Srie Word cnt; 9171618Srie char index[MAXNDXSIZE]; 9180Sstevel@tonic-gate 9191618Srie Elf_ver_def_title(0); 9200Sstevel@tonic-gate 9214716Sab196087 for (cnt = 1; cnt <= vdf_num; cnt++, 9221618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 9237682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 9247682SAli.Bahrami@Sun.COM const char *name, *dep; 9257682SAli.Bahrami@Sun.COM Half vcnt = vdf->vd_cnt - 1; 9267682SAli.Bahrami@Sun.COM Half ndx = vdf->vd_ndx; 9277682SAli.Bahrami@Sun.COM Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate /* 9300Sstevel@tonic-gate * Obtain the name and first dependency (if any). 9310Sstevel@tonic-gate */ 9320Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name); 9331618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9340Sstevel@tonic-gate if (vcnt) 9350Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name); 9360Sstevel@tonic-gate else 9370Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 9400Sstevel@tonic-gate EC_XWORD(ndx)); 9411618Srie Elf_ver_line_1(0, index, name, dep, 9427682SAli.Bahrami@Sun.COM conv_ver_flags(vdf->vd_flags, 0, &ver_flags_buf)); 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate /* 9450Sstevel@tonic-gate * Print any additional dependencies. 9460Sstevel@tonic-gate */ 9470Sstevel@tonic-gate if (vcnt) { 9481618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9490Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 9501618Srie vdap = (Verdaux *)((uintptr_t)vdap + 9510Sstevel@tonic-gate vdap->vda_next)) { 9520Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 9530Sstevel@tonic-gate vdap->vda_name); 9541618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep); 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate } 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate /* 9614716Sab196087 * Print version needed section entries. 9624716Sab196087 * 9634716Sab196087 * entry: 9644716Sab196087 * vnd - Address of verneed data 9654716Sab196087 * vnd_num - # of Verneed entries 9664716Sab196087 * vcache - Cache of verneed section being processed 9674716Sab196087 * scache - Cache of associated string table section 9684716Sab196087 * file - Name of object being processed. 9694716Sab196087 * versym - Information about versym section 9704716Sab196087 * 9714716Sab196087 * exit: 9724716Sab196087 * The versions have been printed. If GNU style versioning 9734716Sab196087 * is in effect, versym->max_verndx has been updated to 9744716Sab196087 * contain the largest version index seen. 9757682SAli.Bahrami@Sun.COM * 9767682SAli.Bahrami@Sun.COM * note: 9777682SAli.Bahrami@Sun.COM * The versym section of an object that follows the original 9787682SAli.Bahrami@Sun.COM * Solaris versioning rules only contains indexes into the verdef 9797682SAli.Bahrami@Sun.COM * section. Symbols defined in other objects (UNDEF) are given 9807682SAli.Bahrami@Sun.COM * a version of 0, indicating that they are not defined by 9817682SAli.Bahrami@Sun.COM * this file, and the Verneed entries do not have associated version 9827682SAli.Bahrami@Sun.COM * indexes. For these reasons, we do not display a version index 9837682SAli.Bahrami@Sun.COM * for original-style Verneed sections. 9847682SAli.Bahrami@Sun.COM * 9857682SAli.Bahrami@Sun.COM * The GNU versioning extensions alter this: Symbols defined in other 9867682SAli.Bahrami@Sun.COM * objects receive a version index in the range above those defined 9877682SAli.Bahrami@Sun.COM * by the Verdef section, and the vna_other field of the Vernaux 9887682SAli.Bahrami@Sun.COM * structs inside the Verneed section contain the version index for 9897682SAli.Bahrami@Sun.COM * that item. We therefore display the index when showing the 9907682SAli.Bahrami@Sun.COM * contents of a GNU style Verneed section. You should not 9917682SAli.Bahrami@Sun.COM * necessarily expect these indexes to appear in sorted 9927682SAli.Bahrami@Sun.COM * order --- it seems that the GNU ld assigns the versions as 9937682SAli.Bahrami@Sun.COM * symbols are encountered during linking, and then the results 9947682SAli.Bahrami@Sun.COM * are assembled into the Verneed section afterwards. 9950Sstevel@tonic-gate */ 9960Sstevel@tonic-gate static void 9974716Sab196087 version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache, 9984716Sab196087 const char *file, VERSYM_STATE *versym) 9990Sstevel@tonic-gate { 10004716Sab196087 Word cnt; 10014716Sab196087 char index[MAXNDXSIZE]; 10024716Sab196087 const char *index_str; 10034716Sab196087 10047682SAli.Bahrami@Sun.COM Elf_ver_need_title(0, versym->gnu_needed); 10054716Sab196087 10064716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 10071618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 10087682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 10097682SAli.Bahrami@Sun.COM const char *name, *dep; 10107682SAli.Bahrami@Sun.COM Half vcnt = vnd->vn_cnt; 10114433Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 10120Sstevel@tonic-gate 10130Sstevel@tonic-gate /* 10140Sstevel@tonic-gate * Obtain the name of the needed file and the version name 10150Sstevel@tonic-gate * within it that we're dependent on. Note that the count 10160Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus 10170Sstevel@tonic-gate * entry. 10180Sstevel@tonic-gate */ 10190Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file); 10200Sstevel@tonic-gate if (vcnt) 10210Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name); 10220Sstevel@tonic-gate else 10230Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL); 10240Sstevel@tonic-gate 10257682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) { /* Traditional form */ 10267682SAli.Bahrami@Sun.COM index_str = MSG_ORIG(MSG_STR_EMPTY); 10277682SAli.Bahrami@Sun.COM } else { /* GNU form */ 10287682SAli.Bahrami@Sun.COM index_str = index; 10294716Sab196087 /* Format the version index value */ 10304716Sab196087 (void) snprintf(index, MAXNDXSIZE, 10314716Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(vnap->vna_other)); 10324716Sab196087 if (vnap->vna_other > versym->max_verndx) 10334716Sab196087 versym->max_verndx = vnap->vna_other; 10344716Sab196087 } 10354716Sab196087 Elf_ver_line_1(0, index_str, name, dep, 10367682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 0, &ver_flags_buf)); 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate /* 10390Sstevel@tonic-gate * Print any additional version dependencies. 10400Sstevel@tonic-gate */ 10410Sstevel@tonic-gate if (vcnt) { 10421618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 10430Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 10441618Srie vnap = (Vernaux *)((uintptr_t)vnap + 10450Sstevel@tonic-gate vnap->vna_next)) { 10460Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 10470Sstevel@tonic-gate vnap->vna_name); 10487682SAli.Bahrami@Sun.COM if (vnap->vna_other > 0) { 10494716Sab196087 /* Format the next index value */ 10504716Sab196087 (void) snprintf(index, MAXNDXSIZE, 10514716Sab196087 MSG_ORIG(MSG_FMT_INDEX), 10524716Sab196087 EC_XWORD(vnap->vna_other)); 10537682SAli.Bahrami@Sun.COM Elf_ver_line_1(0, index, 10544716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 10557682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 10567682SAli.Bahrami@Sun.COM 0, &ver_flags_buf)); 10574716Sab196087 if (vnap->vna_other > 10584716Sab196087 versym->max_verndx) 10594716Sab196087 versym->max_verndx = 10604716Sab196087 vnap->vna_other; 10614716Sab196087 } else { 10624716Sab196087 Elf_ver_line_3(0, 10634716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 10647682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 10657682SAli.Bahrami@Sun.COM 0, &ver_flags_buf)); 10664716Sab196087 } 10674716Sab196087 } 10684716Sab196087 } 10694716Sab196087 } 10704716Sab196087 } 10714716Sab196087 10724716Sab196087 /* 10737682SAli.Bahrami@Sun.COM * Examine the Verneed section for information related to GNU 10747682SAli.Bahrami@Sun.COM * style Versym indexing: 10757682SAli.Bahrami@Sun.COM * - A non-zero vna_other field indicates that Versym indexes can 10767682SAli.Bahrami@Sun.COM * reference Verneed records. 10777682SAli.Bahrami@Sun.COM * - If the object uses GNU style Versym indexing, the 10787682SAli.Bahrami@Sun.COM * maximum index value is needed to detect bad Versym entries. 10794716Sab196087 * 10804716Sab196087 * entry: 10814716Sab196087 * vnd - Address of verneed data 10824716Sab196087 * vnd_num - # of Verneed entries 10834716Sab196087 * versym - Information about versym section 10844716Sab196087 * 10854716Sab196087 * exit: 10867682SAli.Bahrami@Sun.COM * If a non-zero vna_other field is seen, versym->gnu_needed is set. 10877682SAli.Bahrami@Sun.COM * 10884716Sab196087 * versym->max_verndx has been updated to contain the largest 10894716Sab196087 * version index seen. 10904716Sab196087 */ 10914716Sab196087 static void 10927682SAli.Bahrami@Sun.COM update_gnu_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym) 10934716Sab196087 { 10944716Sab196087 Word cnt; 10954716Sab196087 10964716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 10974716Sab196087 vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 10984716Sab196087 Half vcnt = vnd->vn_cnt; 10994716Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 11004716Sab196087 11017682SAli.Bahrami@Sun.COM /* 11027682SAli.Bahrami@Sun.COM * A non-zero value of vna_other indicates that this 11037682SAli.Bahrami@Sun.COM * object references VERNEED items from the VERSYM 11047682SAli.Bahrami@Sun.COM * array. 11057682SAli.Bahrami@Sun.COM */ 11067682SAli.Bahrami@Sun.COM if (vnap->vna_other != 0) { 11077682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 11087682SAli.Bahrami@Sun.COM if (vnap->vna_other > versym->max_verndx) 11097682SAli.Bahrami@Sun.COM versym->max_verndx = vnap->vna_other; 11107682SAli.Bahrami@Sun.COM } 11114716Sab196087 11124716Sab196087 /* 11134716Sab196087 * Check any additional version dependencies. 11144716Sab196087 */ 11154716Sab196087 if (vcnt) { 11164716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 11174716Sab196087 for (vcnt--; vcnt; vcnt--, 11184716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + 11194716Sab196087 vnap->vna_next)) { 11207682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) 11217682SAli.Bahrami@Sun.COM continue; 11227682SAli.Bahrami@Sun.COM 11237682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 11244716Sab196087 if (vnap->vna_other > versym->max_verndx) 11254716Sab196087 versym->max_verndx = vnap->vna_other; 11260Sstevel@tonic-gate } 11270Sstevel@tonic-gate } 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate /* 11323875Sab196087 * Display version section information if the flags require it. 11333875Sab196087 * Return version information needed by other output. 11343875Sab196087 * 11353875Sab196087 * entry: 11363875Sab196087 * cache - Cache of all section headers 11373875Sab196087 * shnum - # of sections in cache 11383875Sab196087 * file - Name of file 11393875Sab196087 * flags - Command line option flags 11403875Sab196087 * versym - VERSYM_STATE block to be filled in. 11410Sstevel@tonic-gate */ 11423875Sab196087 static void 11433875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags, 11443875Sab196087 VERSYM_STATE *versym) 11450Sstevel@tonic-gate { 11460Sstevel@tonic-gate GElf_Word cnt; 11474716Sab196087 Cache *verdef_cache = NULL, *verneed_cache = NULL; 11484716Sab196087 11494716Sab196087 11504716Sab196087 /* Gather information about the version sections */ 11513875Sab196087 bzero(versym, sizeof (*versym)); 11524716Sab196087 versym->max_verndx = 1; 11530Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 11541618Srie Cache *_cache = &cache[cnt]; 11551618Srie Shdr *shdr = _cache->c_shdr; 11564716Sab196087 Dyn *dyn; 11574716Sab196087 ulong_t numdyn; 11584716Sab196087 11594716Sab196087 switch (shdr->sh_type) { 11604716Sab196087 case SHT_DYNAMIC: 11614716Sab196087 /* 11624716Sab196087 * The GNU ld puts a DT_VERSYM entry in the dynamic 11634716Sab196087 * section so that the runtime linker can use it to 11644716Sab196087 * implement their versioning rules. They allow multiple 11654716Sab196087 * incompatible functions with the same name to exist 11664716Sab196087 * in different versions. The Solaris ld does not 11674716Sab196087 * support this mechanism, and as such, does not 11684716Sab196087 * produce DT_VERSYM. We use this fact to determine 11694716Sab196087 * which ld produced this object, and how to interpret 11704716Sab196087 * the version values. 11714716Sab196087 */ 11724716Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0) || 11734716Sab196087 (_cache->c_data == NULL)) 11744716Sab196087 continue; 11754716Sab196087 numdyn = shdr->sh_size / shdr->sh_entsize; 11764716Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 11774716Sab196087 for (; numdyn-- > 0; dyn++) 11784716Sab196087 if (dyn->d_tag == DT_VERSYM) { 11797682SAli.Bahrami@Sun.COM versym->gnu_full = 11807682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 11814716Sab196087 break; 11824716Sab196087 } 11834716Sab196087 break; 11844716Sab196087 11854716Sab196087 case SHT_SUNW_versym: 11864716Sab196087 /* Record data address for later symbol processing */ 11874716Sab196087 if (_cache->c_data != NULL) { 11884716Sab196087 versym->cache = _cache; 11894716Sab196087 versym->data = _cache->c_data->d_buf; 11904716Sab196087 continue; 11914716Sab196087 } 11924716Sab196087 break; 11934716Sab196087 11944716Sab196087 case SHT_SUNW_verdef: 11954716Sab196087 case SHT_SUNW_verneed: 11964716Sab196087 /* 11974716Sab196087 * Ensure the data is non-NULL and the number 11984716Sab196087 * of items is non-zero. Otherwise, we don't 11994716Sab196087 * understand the section, and will not use it. 12004716Sab196087 */ 12014716Sab196087 if ((_cache->c_data == NULL) || 12024716Sab196087 (_cache->c_data->d_buf == NULL)) { 12034716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 12044716Sab196087 file, _cache->c_name); 12054716Sab196087 continue; 12064716Sab196087 } 12074716Sab196087 if (shdr->sh_info == 0) { 12084716Sab196087 (void) fprintf(stderr, 12094716Sab196087 MSG_INTL(MSG_ERR_BADSHINFO), 12104716Sab196087 file, _cache->c_name, 12114716Sab196087 EC_WORD(shdr->sh_info)); 12124716Sab196087 continue; 12134716Sab196087 } 12144716Sab196087 12154716Sab196087 /* Make sure the string table index is in range */ 12164716Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 12174716Sab196087 (void) fprintf(stderr, 12184716Sab196087 MSG_INTL(MSG_ERR_BADSHLINK), file, 12194716Sab196087 _cache->c_name, EC_WORD(shdr->sh_link)); 12204716Sab196087 continue; 12214716Sab196087 } 12224716Sab196087 12234716Sab196087 /* 12244716Sab196087 * The section is usable. Save the cache entry. 12254716Sab196087 */ 12264716Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) { 12274716Sab196087 verdef_cache = _cache; 12284716Sab196087 /* 12294716Sab196087 * Under Solaris rules, if there is a verdef 12304716Sab196087 * section, the max versym index is number 12314716Sab196087 * of version definitions it supplies. 12324716Sab196087 */ 12334716Sab196087 versym->max_verndx = shdr->sh_info; 12344716Sab196087 } else { 12354716Sab196087 verneed_cache = _cache; 12364716Sab196087 } 12374716Sab196087 break; 12384716Sab196087 } 12394716Sab196087 } 12404716Sab196087 12417682SAli.Bahrami@Sun.COM /* 12427682SAli.Bahrami@Sun.COM * If there is a Verneed section, examine it for information 12437682SAli.Bahrami@Sun.COM * related to GNU style versioning. 12447682SAli.Bahrami@Sun.COM */ 12457682SAli.Bahrami@Sun.COM if (verneed_cache != NULL) 12467682SAli.Bahrami@Sun.COM update_gnu_verndx((Verneed *)verneed_cache->c_data->d_buf, 12477682SAli.Bahrami@Sun.COM verneed_cache->c_shdr->sh_info, versym); 12484716Sab196087 12494716Sab196087 /* 12504716Sab196087 * Now that all the information is available, display the 12517682SAli.Bahrami@Sun.COM * Verdef and Verneed section contents, if requested. 12524716Sab196087 */ 12537682SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_VERSIONS) == 0) 12547682SAli.Bahrami@Sun.COM return; 12554716Sab196087 if (verdef_cache != NULL) { 12564716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 12574716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), 12584716Sab196087 verdef_cache->c_name); 12594716Sab196087 version_def((Verdef *)verdef_cache->c_data->d_buf, 12604716Sab196087 verdef_cache->c_shdr->sh_info, verdef_cache, 12614716Sab196087 &cache[verdef_cache->c_shdr->sh_link], file); 12624716Sab196087 } 12634716Sab196087 if (verneed_cache != NULL) { 12644716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 12654716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), 12664716Sab196087 verneed_cache->c_name); 12670Sstevel@tonic-gate /* 12684716Sab196087 * If GNU versioning applies to this object, version_need() 12694716Sab196087 * will update versym->max_verndx, and it is not 12707682SAli.Bahrami@Sun.COM * necessary to call update_gnu_verndx(). 12710Sstevel@tonic-gate */ 12724716Sab196087 version_need((Verneed *)verneed_cache->c_data->d_buf, 12734716Sab196087 verneed_cache->c_shdr->sh_info, verneed_cache, 12744716Sab196087 &cache[verneed_cache->c_shdr->sh_link], file, versym); 12750Sstevel@tonic-gate } 12760Sstevel@tonic-gate } 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate /* 12793492Sab196087 * Initialize a symbol table state structure 12803492Sab196087 * 12813492Sab196087 * entry: 12823492Sab196087 * state - State structure to be initialized 12833492Sab196087 * cache - Cache of all section headers 12843492Sab196087 * shnum - # of sections in cache 12853492Sab196087 * secndx - Index of symbol table section 12863492Sab196087 * ehdr - ELF header for file 12873875Sab196087 * versym - Information about versym section 12883492Sab196087 * file - Name of file 12893492Sab196087 * flags - Command line option flags 12901618Srie */ 12911618Srie static int 12923492Sab196087 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx, 12933875Sab196087 Ehdr *ehdr, VERSYM_STATE *versym, const char *file, uint_t flags) 12943492Sab196087 { 12953492Sab196087 Shdr *shdr; 12963492Sab196087 12973492Sab196087 state->file = file; 12983492Sab196087 state->ehdr = ehdr; 12993492Sab196087 state->cache = cache; 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 */ 14644734Sab196087 sec = conv_sym_shndx(sym->st_shndx, &inv_buf); 14654665Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 14663492Sab196087 (sym->st_shndx < state->shnum)) { 14673492Sab196087 shndx = sym->st_shndx; 14683492Sab196087 tshdr = state->cache[shndx].c_shdr; 14693492Sab196087 sec = state->cache[shndx].c_name; 14703492Sab196087 } else if (sym->st_shndx == SHN_XINDEX) { 14713492Sab196087 if (state->shxndx.data) { 14723492Sab196087 Word _shxndx; 14733492Sab196087 14743492Sab196087 if (symndx > state->shxndx.n) { 14754433Sab196087 (void) fprintf(stderr, 14764433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 14774433Sab196087 state->file, state->secname, 14784433Sab196087 EC_WORD(symndx)); 14793492Sab196087 } else if ((_shxndx = 14803492Sab196087 state->shxndx.data[symndx]) > state->shnum) { 14814433Sab196087 (void) fprintf(stderr, 14824433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 14834433Sab196087 state->file, state->secname, 14844433Sab196087 EC_WORD(symndx), EC_WORD(_shxndx)); 14853492Sab196087 } else { 14864433Sab196087 shndx = _shxndx; 14874433Sab196087 tshdr = state->cache[shndx].c_shdr; 14884433Sab196087 sec = state->cache[shndx].c_name; 14893492Sab196087 } 14903492Sab196087 } else { 14913492Sab196087 (void) fprintf(stderr, 14923492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 14933492Sab196087 state->file, state->secname, EC_WORD(symndx)); 14943492Sab196087 } 14953492Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 14963492Sab196087 (sym->st_shndx >= state->shnum)) { 14973492Sab196087 (void) fprintf(stderr, 14983492Sab196087 MSG_INTL(MSG_ERR_BADSYM5), state->file, 14996206Sab196087 state->secname, EC_WORD(symndx), 15006206Sab196087 demangle(symname, state->flags), sym->st_shndx); 15013492Sab196087 } 15020Sstevel@tonic-gate 15033492Sab196087 /* 15043492Sab196087 * If versioning is available display the 15053875Sab196087 * version index. If not, then use 0. 15063492Sab196087 */ 15073875Sab196087 if (state->versym) { 15084716Sab196087 Versym test_verndx; 15094716Sab196087 15104716Sab196087 verndx = test_verndx = state->versym->data[symndx]; 15117682SAli.Bahrami@Sun.COM gnuver = state->versym->gnu_full; 15123875Sab196087 15133875Sab196087 /* 15143875Sab196087 * Check to see if this is a defined symbol with a 15153875Sab196087 * version index that is outside the valid range for 15164716Sab196087 * the file. The interpretation of this depends on 15174716Sab196087 * the style of versioning used by the object. 15183875Sab196087 * 15194716Sab196087 * Versions >= VER_NDX_LORESERVE have special meanings, 15204716Sab196087 * and are exempt from this checking. 15214716Sab196087 * 15224716Sab196087 * GNU style version indexes use the top bit of the 15234716Sab196087 * 16-bit index value (0x8000) as the "hidden bit". 15244716Sab196087 * We must mask off this bit in order to compare 15254716Sab196087 * the version against the maximum value. 15263875Sab196087 */ 15274716Sab196087 if (gnuver) 15284716Sab196087 test_verndx &= ~0x8000; 15294716Sab196087 15304716Sab196087 if ((test_verndx > state->versym->max_verndx) && 15314716Sab196087 (verndx < VER_NDX_LORESERVE)) 15324716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER), 15334716Sab196087 state->file, state->secname, EC_WORD(symndx), 15344716Sab196087 EC_HALF(test_verndx), state->versym->max_verndx); 15353875Sab196087 } else { 15363492Sab196087 verndx = 0; 15374716Sab196087 gnuver = 0; 15383875Sab196087 } 15393492Sab196087 15403492Sab196087 /* 15413492Sab196087 * Error checking for TLS. 15423492Sab196087 */ 15433492Sab196087 type = ELF_ST_TYPE(sym->st_info); 15443492Sab196087 if (type == STT_TLS) { 15453492Sab196087 if (tshdr && 15463492Sab196087 (sym->st_shndx != SHN_UNDEF) && 15473492Sab196087 ((tshdr->sh_flags & SHF_TLS) == 0)) { 15483492Sab196087 (void) fprintf(stderr, 15493492Sab196087 MSG_INTL(MSG_ERR_BADSYM3), state->file, 15506206Sab196087 state->secname, EC_WORD(symndx), 15516206Sab196087 demangle(symname, state->flags)); 15523492Sab196087 } 15533492Sab196087 } else if ((type != STT_SECTION) && sym->st_size && 15543492Sab196087 tshdr && (tshdr->sh_flags & SHF_TLS)) { 15553492Sab196087 (void) fprintf(stderr, 15563492Sab196087 MSG_INTL(MSG_ERR_BADSYM4), state->file, 15576206Sab196087 state->secname, EC_WORD(symndx), 15586206Sab196087 demangle(symname, state->flags)); 15593492Sab196087 } 15603492Sab196087 15613492Sab196087 /* 15623492Sab196087 * If a symbol with non-zero size has a type that 15633492Sab196087 * specifies an address, then make sure the location 15643492Sab196087 * it references is actually contained within the 15653492Sab196087 * section. UNDEF symbols don't count in this case, 15663492Sab196087 * so we ignore them. 15673492Sab196087 * 15683492Sab196087 * The meaning of the st_value field in a symbol 15693492Sab196087 * depends on the type of object. For a relocatable 15703492Sab196087 * object, it is the offset within the section. 15713492Sab196087 * For sharable objects, it is the offset relative to 15723492Sab196087 * the base of the object, and for other types, it is 15733492Sab196087 * the virtual address. To get an offset within the 15743492Sab196087 * section for non-ET_REL files, we subtract the 15753492Sab196087 * base address of the section. 15763492Sab196087 */ 15773492Sab196087 if (addr_symtype[type] && (sym->st_size > 0) && 15783492Sab196087 (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) || 15793492Sab196087 (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) { 15803492Sab196087 Word v = sym->st_value; 15813492Sab196087 if (state->ehdr->e_type != ET_REL) 15824832Srie v -= tshdr->sh_addr; 15833492Sab196087 if (((v + sym->st_size) > tshdr->sh_size)) { 15843492Sab196087 (void) fprintf(stderr, 15853492Sab196087 MSG_INTL(MSG_ERR_BADSYM6), state->file, 15866206Sab196087 state->secname, EC_WORD(symndx), 15876206Sab196087 demangle(symname, state->flags), 15883492Sab196087 EC_WORD(shndx), EC_XWORD(tshdr->sh_size), 15893492Sab196087 EC_XWORD(sym->st_value), EC_XWORD(sym->st_size)); 15903492Sab196087 } 15913492Sab196087 } 15923492Sab196087 15934832Srie /* 15944832Srie * A typical symbol table uses the sh_info field to indicate one greater 15954832Srie * than the symbol table index of the last local symbol, STB_LOCAL. 15964832Srie * Therefore, symbol indexes less than sh_info should have local 15974832Srie * binding. Symbol indexes greater than, or equal to sh_info, should 15984832Srie * have global binding. Note, we exclude UNDEF/NOTY symbols with zero 15994832Srie * value and size, as these symbols may be the result of an mcs(1) 16004832Srie * section deletion. 16014832Srie */ 16024832Srie if (info) { 16034832Srie uchar_t bind = ELF_ST_BIND(sym->st_info); 16044832Srie 16054832Srie if ((symndx < info) && (bind != STB_LOCAL)) { 16064832Srie (void) fprintf(stderr, 16074832Srie MSG_INTL(MSG_ERR_BADSYM7), state->file, 16086206Sab196087 state->secname, EC_WORD(symndx), 16096206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 16104832Srie 16114832Srie } else if ((symndx >= info) && (bind == STB_LOCAL) && 16124832Srie ((sym->st_shndx != SHN_UNDEF) || 16134832Srie (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) || 16144832Srie (sym->st_size != 0) || (sym->st_value != 0))) { 16154832Srie (void) fprintf(stderr, 16164832Srie MSG_INTL(MSG_ERR_BADSYM8), state->file, 16176206Sab196087 state->secname, EC_WORD(symndx), 16186206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 16194832Srie } 16204832Srie } 16214832Srie 16223492Sab196087 (void) snprintf(index, MAXNDXSIZE, 16233492Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx)); 16243492Sab196087 Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, 16254716Sab196087 state->ehdr->e_machine, sym, verndx, gnuver, sec, symname); 16263492Sab196087 } 16273492Sab196087 16283492Sab196087 /* 16293492Sab196087 * Search for and process any symbol tables. 16303492Sab196087 */ 16313492Sab196087 void 16324168Sab196087 symbols(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 16334168Sab196087 const char *file, uint_t flags) 16343492Sab196087 { 16353492Sab196087 SYMTBL_STATE state; 16363492Sab196087 Cache *_cache; 16373492Sab196087 Word secndx; 16383492Sab196087 16393492Sab196087 for (secndx = 1; secndx < shnum; secndx++) { 16403492Sab196087 Word symcnt; 16413492Sab196087 Shdr *shdr; 16423492Sab196087 16433492Sab196087 _cache = &cache[secndx]; 16443492Sab196087 shdr = _cache->c_shdr; 16450Sstevel@tonic-gate 16460Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) && 16472766Sab196087 (shdr->sh_type != SHT_DYNSYM) && 16482766Sab196087 (shdr->sh_type != SHT_SUNW_LDYNSYM)) 16490Sstevel@tonic-gate continue; 16505411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, secndx, shdr->sh_type)) 16513466Srie continue; 16523466Srie 16533492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr, 16543875Sab196087 versym, file, flags)) 16550Sstevel@tonic-gate continue; 16560Sstevel@tonic-gate /* 16570Sstevel@tonic-gate * Loop through the symbol tables entries. 16580Sstevel@tonic-gate */ 16591618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 16603492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname); 16611618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 16620Sstevel@tonic-gate 16633492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++) 16644832Srie output_symbol(&state, symcnt, shdr->sh_info, symcnt, 16653492Sab196087 state.sym + symcnt); 16663492Sab196087 } 16673492Sab196087 } 16680Sstevel@tonic-gate 16693492Sab196087 /* 16703492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections. 16713492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair. 16723492Sab196087 */ 16733492Sab196087 static void 16744168Sab196087 sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 16754168Sab196087 const char *file, uint_t flags) 16763492Sab196087 { 16773492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state; 16783492Sab196087 Cache *sortcache, *symcache; 16793492Sab196087 Shdr *sortshdr, *symshdr; 16803492Sab196087 Word sortsecndx, symsecndx; 16813492Sab196087 Word ldynsym_cnt; 16823492Sab196087 Word *ndx; 16833492Sab196087 Word ndxn; 16843492Sab196087 int output_cnt = 0; 16854734Sab196087 Conv_inv_buf_t inv_buf; 16860Sstevel@tonic-gate 16873492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) { 16880Sstevel@tonic-gate 16893492Sab196087 sortcache = &cache[sortsecndx]; 16903492Sab196087 sortshdr = sortcache->c_shdr; 16910Sstevel@tonic-gate 16923492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) && 16933492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort)) 16943492Sab196087 continue; 16955411Sab196087 if (!match(MATCH_F_ALL, sortcache->c_name, sortsecndx, 16965411Sab196087 sortshdr->sh_type)) 16973492Sab196087 continue; 16980Sstevel@tonic-gate 16993492Sab196087 /* 17003492Sab196087 * If the section references a SUNW_ldynsym, then we 17013492Sab196087 * expect to see the associated .dynsym immediately 17023492Sab196087 * following. If it references a .dynsym, there is no 17033492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't 17043492Sab196087 * know what to do with it. 17053492Sab196087 */ 17063492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) { 17073492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 17083492Sab196087 file, sortcache->c_name, 17093492Sab196087 EC_WORD(sortshdr->sh_link)); 17103492Sab196087 continue; 17113492Sab196087 } 17123492Sab196087 symcache = &cache[sortshdr->sh_link]; 17133492Sab196087 symshdr = symcache->c_shdr; 17143492Sab196087 symsecndx = sortshdr->sh_link; 17153492Sab196087 ldynsym_cnt = 0; 17163492Sab196087 switch (symshdr->sh_type) { 17173492Sab196087 case SHT_SUNW_LDYNSYM: 17183492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum, 17193875Sab196087 symsecndx, ehdr, versym, file, flags)) 17203492Sab196087 continue; 17213492Sab196087 ldynsym_cnt = ldynsym_state.symn; 17220Sstevel@tonic-gate /* 17233492Sab196087 * We know that the dynsym follows immediately 17243492Sab196087 * after the SUNW_ldynsym, and so, should be at 17253492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a 17263492Sab196087 * diagnostic tool, so we do the full paranoid 17273492Sab196087 * search instead. 17280Sstevel@tonic-gate */ 17293492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) { 17303492Sab196087 symcache = &cache[symsecndx]; 17313492Sab196087 symshdr = symcache->c_shdr; 17323492Sab196087 if (symshdr->sh_type == SHT_DYNSYM) 17333492Sab196087 break; 17343492Sab196087 } 17353492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */ 17360Sstevel@tonic-gate (void) fprintf(stderr, 17373492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM), 17383492Sab196087 file, sortcache->c_name); 17393492Sab196087 continue; 17400Sstevel@tonic-gate } 17413492Sab196087 /* Fallthrough to process associated dynsym */ 17427463SRod.Evans@Sun.COM /* FALLTHROUGH */ 17433492Sab196087 case SHT_DYNSYM: 17443492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum, 17453875Sab196087 symsecndx, ehdr, versym, file, flags)) 17463492Sab196087 continue; 17473492Sab196087 break; 17483492Sab196087 default: 17493492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC), 17503492Sab196087 file, sortcache->c_name, conv_sec_type( 17514734Sab196087 ehdr->e_machine, symshdr->sh_type, 0, &inv_buf)); 17523492Sab196087 continue; 17533492Sab196087 } 17540Sstevel@tonic-gate 17553492Sab196087 /* 17563492Sab196087 * Output header 17573492Sab196087 */ 17583492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17593492Sab196087 if (ldynsym_cnt > 0) { 17603492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2), 17613492Sab196087 sortcache->c_name, ldynsym_state.secname, 17623492Sab196087 dynsym_state.secname); 17630Sstevel@tonic-gate /* 17643492Sab196087 * The data for .SUNW_ldynsym and dynsym sections 17653492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming 17663492Sab196087 * first. Check, and issue a warning if it isn't so. 17670Sstevel@tonic-gate */ 17684665Sab196087 if (((ldynsym_state.sym + ldynsym_state.symn) 17694665Sab196087 != dynsym_state.sym) && 17705411Sab196087 ((flags & FLG_CTL_FAKESHDR) == 0)) 17713492Sab196087 (void) fprintf(stderr, 17723492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file, 17733492Sab196087 ldynsym_state.secname, 17743492Sab196087 dynsym_state.secname); 17753492Sab196087 } else { 17763492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1), 17773492Sab196087 sortcache->c_name, dynsym_state.secname); 17783492Sab196087 } 17793492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 17803492Sab196087 17813492Sab196087 /* If not first one, insert a line of whitespace */ 17823492Sab196087 if (output_cnt++ > 0) 17833492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17843118Sab196087 17853492Sab196087 /* 17863492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of 17873492Sab196087 * symbol indices. Iterate over the array entries, 17883492Sab196087 * dispaying the referenced symbols. 17893492Sab196087 */ 17903492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize; 17913492Sab196087 ndx = (Word *)sortcache->c_data->d_buf; 17923492Sab196087 for (; ndxn-- > 0; ndx++) { 17933492Sab196087 if (*ndx >= ldynsym_cnt) { 17943492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt; 17953492Sab196087 17964832Srie output_symbol(&dynsym_state, sec_ndx, 0, 17973492Sab196087 *ndx, dynsym_state.sym + sec_ndx); 17983492Sab196087 } else { 17994832Srie output_symbol(&ldynsym_state, *ndx, 0, 18003492Sab196087 *ndx, ldynsym_state.sym + *ndx); 18010Sstevel@tonic-gate } 18020Sstevel@tonic-gate } 18030Sstevel@tonic-gate } 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate 18060Sstevel@tonic-gate /* 18070Sstevel@tonic-gate * Search for and process any relocation sections. 18080Sstevel@tonic-gate */ 18090Sstevel@tonic-gate static void 18107463SRod.Evans@Sun.COM reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 18110Sstevel@tonic-gate { 18121618Srie Word cnt; 18130Sstevel@tonic-gate 18140Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 18151618Srie Word type, symnum; 18161618Srie Xword relndx, relnum, relsize; 18171618Srie void *rels; 18181618Srie Sym *syms; 18191618Srie Cache *symsec, *strsec; 18200Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 18211618Srie Shdr *shdr = _cache->c_shdr; 18221618Srie char *relname = _cache->c_name; 18234734Sab196087 Conv_inv_buf_t inv_buf; 18240Sstevel@tonic-gate 18250Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) && 18260Sstevel@tonic-gate (type != SHT_REL)) 18270Sstevel@tonic-gate continue; 18285411Sab196087 if (!match(MATCH_F_ALL, relname, cnt, type)) 18290Sstevel@tonic-gate continue; 18300Sstevel@tonic-gate 18310Sstevel@tonic-gate /* 18321618Srie * Decide entry size. 18330Sstevel@tonic-gate */ 18341618Srie if (((relsize = shdr->sh_entsize) == 0) || 18351618Srie (relsize > shdr->sh_size)) { 18360Sstevel@tonic-gate if (type == SHT_RELA) 18371618Srie relsize = sizeof (Rela); 18380Sstevel@tonic-gate else 18391618Srie relsize = sizeof (Rel); 18400Sstevel@tonic-gate } 18410Sstevel@tonic-gate 18420Sstevel@tonic-gate /* 18430Sstevel@tonic-gate * Determine the number of relocations available. 18440Sstevel@tonic-gate */ 18450Sstevel@tonic-gate if (shdr->sh_size == 0) { 18460Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 18471618Srie file, relname); 18480Sstevel@tonic-gate continue; 18490Sstevel@tonic-gate } 18503466Srie if (_cache->c_data == NULL) 18513466Srie continue; 18523466Srie 18531618Srie rels = _cache->c_data->d_buf; 18541618Srie relnum = shdr->sh_size / relsize; 18550Sstevel@tonic-gate 18560Sstevel@tonic-gate /* 18571618Srie * Get the data buffer for the associated symbol table and 18581618Srie * string table. 18590Sstevel@tonic-gate */ 18601618Srie if (stringtbl(cache, 1, cnt, shnum, file, 18611618Srie &symnum, &symsec, &strsec) == 0) 18620Sstevel@tonic-gate continue; 18631618Srie 18641618Srie syms = symsec->c_data->d_buf; 18650Sstevel@tonic-gate 18660Sstevel@tonic-gate /* 18670Sstevel@tonic-gate * Loop through the relocation entries. 18680Sstevel@tonic-gate */ 18691618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 18701618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 18711618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type); 18720Sstevel@tonic-gate 18731618Srie for (relndx = 0; relndx < relnum; relndx++, 18741618Srie rels = (void *)((char *)rels + relsize)) { 18756206Sab196087 Half mach = ehdr->e_machine; 18760Sstevel@tonic-gate char section[BUFSIZ]; 18771618Srie const char *symname; 18781618Srie Word symndx, reltype; 18791618Srie Rela *rela; 18801618Srie Rel *rel; 18810Sstevel@tonic-gate 18820Sstevel@tonic-gate /* 18831618Srie * Unravel the relocation and determine the symbol with 18841618Srie * which this relocation is associated. 18850Sstevel@tonic-gate */ 18860Sstevel@tonic-gate if (type == SHT_RELA) { 18871618Srie rela = (Rela *)rels; 18881618Srie symndx = ELF_R_SYM(rela->r_info); 18896206Sab196087 reltype = ELF_R_TYPE(rela->r_info, mach); 18900Sstevel@tonic-gate } else { 18911618Srie rel = (Rel *)rels; 18921618Srie symndx = ELF_R_SYM(rel->r_info); 18936206Sab196087 reltype = ELF_R_TYPE(rel->r_info, mach); 18940Sstevel@tonic-gate } 18951618Srie 18961618Srie symname = relsymname(cache, _cache, strsec, symndx, 18977463SRod.Evans@Sun.COM symnum, relndx, syms, section, BUFSIZ, file); 18981618Srie 18991618Srie /* 19001618Srie * A zero symbol index is only valid for a few 19011618Srie * relocations. 19021618Srie */ 19031618Srie if (symndx == 0) { 19041618Srie int badrel = 0; 19050Sstevel@tonic-gate 19061618Srie if ((mach == EM_SPARC) || 19071618Srie (mach == EM_SPARC32PLUS) || 19081618Srie (mach == EM_SPARCV9)) { 19091618Srie if ((reltype != R_SPARC_NONE) && 19101618Srie (reltype != R_SPARC_REGISTER) && 19111618Srie (reltype != R_SPARC_RELATIVE)) 19121618Srie badrel++; 19131618Srie } else if (mach == EM_386) { 19141618Srie if ((reltype != R_386_NONE) && 19151618Srie (reltype != R_386_RELATIVE)) 19161618Srie badrel++; 19171618Srie } else if (mach == EM_AMD64) { 19181618Srie if ((reltype != R_AMD64_NONE) && 19191618Srie (reltype != R_AMD64_RELATIVE)) 19201618Srie badrel++; 19211618Srie } 19221618Srie 19231618Srie if (badrel) { 19241618Srie (void) fprintf(stderr, 19251618Srie MSG_INTL(MSG_ERR_BADREL1), file, 19264734Sab196087 conv_reloc_type(mach, reltype, 19274734Sab196087 0, &inv_buf)); 19280Sstevel@tonic-gate } 19290Sstevel@tonic-gate } 19300Sstevel@tonic-gate 19311618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP, 19321618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type, 19331618Srie rels, relname, symname, 0); 19340Sstevel@tonic-gate } 19350Sstevel@tonic-gate } 19360Sstevel@tonic-gate } 19370Sstevel@tonic-gate 19385230Sab196087 19395230Sab196087 /* 19405230Sab196087 * This value controls which test dyn_test() performs. 19415230Sab196087 */ 19425230Sab196087 typedef enum { DYN_TEST_ADDR, DYN_TEST_SIZE, DYN_TEST_ENTSIZE } dyn_test_t; 19435230Sab196087 19445230Sab196087 /* 19455230Sab196087 * Used by dynamic() to compare the value of a dynamic element against 19465230Sab196087 * the starting address of the section it references. 19475230Sab196087 * 19485230Sab196087 * entry: 19495230Sab196087 * test_type - Specify which dyn item is being tested. 19505230Sab196087 * sh_type - SHT_* type value for required section. 19515230Sab196087 * sec_cache - Cache entry for section, or NULL if the object lacks 19525230Sab196087 * a section of this type. 19535230Sab196087 * dyn - Dyn entry to be tested 19545230Sab196087 * dynsec_cnt - # of dynamic section being examined. The first 19555230Sab196087 * dynamic section is 1, the next is 2, and so on... 19565230Sab196087 * ehdr - ELF header for file 19575230Sab196087 * file - Name of file 19585230Sab196087 */ 19595230Sab196087 static void 19605230Sab196087 dyn_test(dyn_test_t test_type, Word sh_type, Cache *sec_cache, Dyn *dyn, 19615230Sab196087 Word dynsec_cnt, Ehdr *ehdr, const char *file) 19625230Sab196087 { 19635230Sab196087 Conv_inv_buf_t buf1, buf2; 19645230Sab196087 19655230Sab196087 /* 19665230Sab196087 * These tests are based around the implicit assumption that 19675230Sab196087 * there is only one dynamic section in an object, and also only 19685230Sab196087 * one of the sections it references. We have therefore gathered 19695230Sab196087 * all of the necessary information to test this in a single pass 19705230Sab196087 * over the section headers, which is very efficient. We are not 19715230Sab196087 * aware of any case where more than one dynamic section would 19725230Sab196087 * be meaningful in an ELF object, so this is a reasonable solution. 19735230Sab196087 * 19745230Sab196087 * To test multiple dynamic sections correctly would be more 19755230Sab196087 * expensive in code and time. We would have to build a data structure 19765230Sab196087 * containing all the dynamic elements. Then, we would use the address 19775230Sab196087 * to locate the section it references and ensure the section is of 19785230Sab196087 * the right type and that the address in the dynamic element is 19795230Sab196087 * to the start of the section. Then, we could check the size and 19805230Sab196087 * entsize values against those same sections. This is O(n^2), and 19815230Sab196087 * also complicated. 19825230Sab196087 * 19835230Sab196087 * In the highly unlikely case that there is more than one dynamic 19845230Sab196087 * section, we only test the first one, and simply allow the values 19855230Sab196087 * of the subsequent one to be displayed unchallenged. 19865230Sab196087 */ 19875230Sab196087 if (dynsec_cnt != 1) 19885230Sab196087 return; 19895230Sab196087 19905230Sab196087 /* 19915230Sab196087 * A DT_ item that references a section address should always find 19925230Sab196087 * the section in the file. 19935230Sab196087 */ 19945230Sab196087 if (sec_cache == NULL) { 19956299Sab196087 const char *name; 19966299Sab196087 19976299Sab196087 /* 19986299Sab196087 * Supply section names instead of section types for 19996299Sab196087 * things that reference progbits so that the error 20006299Sab196087 * message will make more sense. 20016299Sab196087 */ 20026299Sab196087 switch (dyn->d_tag) { 20036299Sab196087 case DT_INIT: 20046299Sab196087 name = MSG_ORIG(MSG_ELF_INIT); 20056299Sab196087 break; 20066299Sab196087 case DT_FINI: 20076299Sab196087 name = MSG_ORIG(MSG_ELF_FINI); 20086299Sab196087 break; 20096299Sab196087 default: 20106299Sab196087 name = conv_sec_type(ehdr->e_machine, sh_type, 20116299Sab196087 0, &buf1); 20126299Sab196087 break; 20136299Sab196087 } 20145230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNNOBCKSEC), file, 20156299Sab196087 name, conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf2)); 20165230Sab196087 return; 20175230Sab196087 } 20185230Sab196087 20195230Sab196087 20205230Sab196087 switch (test_type) { 20215230Sab196087 case DYN_TEST_ADDR: 20225230Sab196087 /* The section address should match the DT_ item value */ 20235230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_addr) 20245230Sab196087 (void) fprintf(stderr, 20255230Sab196087 MSG_INTL(MSG_ERR_DYNBADADDR), file, 20265230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 20275230Sab196087 EC_ADDR(dyn->d_un.d_val), sec_cache->c_ndx, 20285230Sab196087 sec_cache->c_name, 20295230Sab196087 EC_ADDR(sec_cache->c_shdr->sh_addr)); 20305230Sab196087 break; 20315230Sab196087 20325230Sab196087 case DYN_TEST_SIZE: 20335230Sab196087 /* The section size should match the DT_ item value */ 20345230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_size) 20355230Sab196087 (void) fprintf(stderr, 20365230Sab196087 MSG_INTL(MSG_ERR_DYNBADSIZE), file, 20375230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 20385230Sab196087 EC_XWORD(dyn->d_un.d_val), 20395230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 20405230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_size)); 20415230Sab196087 break; 20425230Sab196087 20435230Sab196087 case DYN_TEST_ENTSIZE: 20445230Sab196087 /* The sh_entsize value should match the DT_ item value */ 20455230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_entsize) 20465230Sab196087 (void) fprintf(stderr, 20475230Sab196087 MSG_INTL(MSG_ERR_DYNBADENTSIZE), file, 20485230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 20495230Sab196087 EC_XWORD(dyn->d_un.d_val), 20505230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 20515230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_entsize)); 20525230Sab196087 break; 20535230Sab196087 } 20545230Sab196087 } 20555230Sab196087 20565230Sab196087 20570Sstevel@tonic-gate /* 20586299Sab196087 * There are some DT_ entries that have corresponding symbols 20596299Sab196087 * (e.g. DT_INIT and _init). It is expected that these items will 20606299Sab196087 * both have the same value if both are present. This routine 20616299Sab196087 * examines the well known symbol tables for such symbols and 20626299Sab196087 * issues warnings for any that don't match. 20636299Sab196087 * 20646299Sab196087 * entry: 20656299Sab196087 * dyn - Dyn entry to be tested 20666299Sab196087 * symname - Name of symbol that corresponds to dyn 20676299Sab196087 * symtab_cache, dynsym_cache, ldynsym_cache - Symbol tables to check 20686299Sab196087 * cache - Cache of all section headers 20696299Sab196087 * shnum - # of sections in cache 20706299Sab196087 * ehdr - ELF header for file 20716299Sab196087 * file - Name of file 20726299Sab196087 */ 20736299Sab196087 static void 20746299Sab196087 dyn_symtest(Dyn *dyn, const char *symname, Cache *symtab_cache, 20756299Sab196087 Cache *dynsym_cache, Cache *ldynsym_cache, Cache *cache, 20766299Sab196087 Word shnum, Ehdr *ehdr, const char *file) 20776299Sab196087 { 20786299Sab196087 Conv_inv_buf_t buf; 20796299Sab196087 int i; 20806299Sab196087 Sym *sym; 20816299Sab196087 Cache *_cache; 20826299Sab196087 20836299Sab196087 for (i = 0; i < 3; i++) { 20846299Sab196087 switch (i) { 20856299Sab196087 case 0: 20866299Sab196087 _cache = symtab_cache; 20876299Sab196087 break; 20886299Sab196087 case 1: 20896299Sab196087 _cache = dynsym_cache; 20906299Sab196087 break; 20916299Sab196087 case 2: 20926299Sab196087 _cache = ldynsym_cache; 20936299Sab196087 break; 20946299Sab196087 } 20956299Sab196087 20966299Sab196087 if ((_cache != NULL) && 20976299Sab196087 symlookup(symname, cache, shnum, &sym, _cache, file) && 20986299Sab196087 (sym->st_value != dyn->d_un.d_val)) 20996299Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNSYMVAL), 21006299Sab196087 file, _cache->c_name, 21016299Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf), 21026299Sab196087 symname, EC_ADDR(sym->st_value)); 21036299Sab196087 } 21046299Sab196087 } 21056299Sab196087 21066299Sab196087 21076299Sab196087 /* 21080Sstevel@tonic-gate * Search for and process a .dynamic section. 21090Sstevel@tonic-gate */ 21100Sstevel@tonic-gate static void 21111618Srie dynamic(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 21120Sstevel@tonic-gate { 21135230Sab196087 struct { 21146299Sab196087 Cache *symtab; 21155230Sab196087 Cache *dynstr; 21165230Sab196087 Cache *dynsym; 21175230Sab196087 Cache *hash; 21185230Sab196087 Cache *fini; 21195230Sab196087 Cache *fini_array; 21205230Sab196087 Cache *init; 21215230Sab196087 Cache *init_array; 21225230Sab196087 Cache *preinit_array; 21235230Sab196087 Cache *rel; 21245230Sab196087 Cache *rela; 21255230Sab196087 Cache *sunw_cap; 21265230Sab196087 Cache *sunw_ldynsym; 21275230Sab196087 Cache *sunw_move; 21285230Sab196087 Cache *sunw_syminfo; 21295230Sab196087 Cache *sunw_symsort; 21305230Sab196087 Cache *sunw_tlssort; 21315230Sab196087 Cache *sunw_verdef; 21325230Sab196087 Cache *sunw_verneed; 21335230Sab196087 Cache *sunw_versym; 21345230Sab196087 } sec; 21355230Sab196087 Word dynsec_ndx; 21365230Sab196087 Word dynsec_num; 21375230Sab196087 int dynsec_cnt; 21381618Srie Word cnt; 21390Sstevel@tonic-gate 21405230Sab196087 /* 21415230Sab196087 * Make a pass over all the sections, gathering section information 21425230Sab196087 * we'll need below. 21435230Sab196087 */ 21445230Sab196087 dynsec_num = 0; 21455230Sab196087 bzero(&sec, sizeof (sec)); 21460Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 21475230Sab196087 Cache *_cache = &cache[cnt]; 21485230Sab196087 21495230Sab196087 switch (_cache->c_shdr->sh_type) { 21505230Sab196087 case SHT_DYNAMIC: 21515230Sab196087 if (dynsec_num == 0) { 21525230Sab196087 dynsec_ndx = cnt; 21535230Sab196087 21545230Sab196087 /* Does it have a valid string table? */ 21555230Sab196087 (void) stringtbl(cache, 0, cnt, shnum, file, 21565230Sab196087 0, 0, &sec.dynstr); 21575230Sab196087 } 21585230Sab196087 dynsec_num++; 21595230Sab196087 break; 21605230Sab196087 21615230Sab196087 21625230Sab196087 case SHT_PROGBITS: 21635230Sab196087 /* 21645230Sab196087 * We want to detect the .init and .fini sections, 21655230Sab196087 * if present. These are SHT_PROGBITS, so all we 21665230Sab196087 * have to go on is the section name. Normally comparing 21675230Sab196087 * names is a bad idea, but there are some special 21685230Sab196087 * names (i.e. .init/.fini/.interp) that are very 21695230Sab196087 * difficult to use in any other context, and for 21705230Sab196087 * these symbols, we do the heuristic match. 21715230Sab196087 */ 21725230Sab196087 if (strcmp(_cache->c_name, 21735230Sab196087 MSG_ORIG(MSG_ELF_INIT)) == 0) { 21745230Sab196087 if (sec.init == NULL) 21755230Sab196087 sec.init = _cache; 21765230Sab196087 } else if (strcmp(_cache->c_name, 21775230Sab196087 MSG_ORIG(MSG_ELF_FINI)) == 0) { 21785230Sab196087 if (sec.fini == NULL) 21795230Sab196087 sec.fini = _cache; 21805230Sab196087 } 21815230Sab196087 break; 21825230Sab196087 21835230Sab196087 case SHT_REL: 21845230Sab196087 /* 21855230Sab196087 * We want the SHT_REL section with the lowest 21865230Sab196087 * offset. The linker gathers them together, 21875230Sab196087 * and puts the address of the first one 21885230Sab196087 * into the DT_REL dynamic element. 21895230Sab196087 */ 21905230Sab196087 if ((sec.rel == NULL) || 21915230Sab196087 (_cache->c_shdr->sh_offset < 21925230Sab196087 sec.rel->c_shdr->sh_offset)) 21935230Sab196087 sec.rel = _cache; 21945230Sab196087 break; 21955230Sab196087 21965230Sab196087 case SHT_RELA: 21975230Sab196087 /* RELA is handled just like RELA above */ 21985230Sab196087 if ((sec.rela == NULL) || 21995230Sab196087 (_cache->c_shdr->sh_offset < 22005230Sab196087 sec.rela->c_shdr->sh_offset)) 22015230Sab196087 sec.rela = _cache; 22025230Sab196087 break; 22035230Sab196087 22045230Sab196087 /* 22055230Sab196087 * The GRAB macro is used for the simple case in which 22065230Sab196087 * we simply grab the first section of the desired type. 22075230Sab196087 */ 22085230Sab196087 #define GRAB(_sec_type, _sec_field) \ 22095230Sab196087 case _sec_type: \ 22105230Sab196087 if (sec._sec_field == NULL) \ 22115230Sab196087 sec._sec_field = _cache; \ 22125230Sab196087 break 22136299Sab196087 GRAB(SHT_SYMTAB, symtab); 22145230Sab196087 GRAB(SHT_DYNSYM, dynsym); 22155230Sab196087 GRAB(SHT_FINI_ARRAY, fini_array); 22165230Sab196087 GRAB(SHT_HASH, hash); 22175230Sab196087 GRAB(SHT_INIT_ARRAY, init_array); 22185230Sab196087 GRAB(SHT_SUNW_move, sunw_move); 22195230Sab196087 GRAB(SHT_PREINIT_ARRAY, preinit_array); 22205230Sab196087 GRAB(SHT_SUNW_cap, sunw_cap); 22215230Sab196087 GRAB(SHT_SUNW_LDYNSYM, sunw_ldynsym); 22225230Sab196087 GRAB(SHT_SUNW_syminfo, sunw_syminfo); 22235230Sab196087 GRAB(SHT_SUNW_symsort, sunw_symsort); 22245230Sab196087 GRAB(SHT_SUNW_tlssort, sunw_tlssort); 22255230Sab196087 GRAB(SHT_SUNW_verdef, sunw_verdef); 22265230Sab196087 GRAB(SHT_SUNW_verneed, sunw_verneed); 22275230Sab196087 GRAB(SHT_SUNW_versym, sunw_versym); 22285230Sab196087 #undef GRAB 22295230Sab196087 } 22305230Sab196087 } 22315230Sab196087 22325230Sab196087 /* 22335230Sab196087 * If no dynamic section, return immediately. If more than one 22345230Sab196087 * dynamic section, then something odd is going on and an error 22355230Sab196087 * is in order, but then continue on and display them all. 22365230Sab196087 */ 22375230Sab196087 if (dynsec_num == 0) 22385230Sab196087 return; 22395230Sab196087 if (dynsec_num > 1) 22405230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MULTDYN), 22415230Sab196087 file, EC_WORD(dynsec_num)); 22425230Sab196087 22435230Sab196087 22445230Sab196087 dynsec_cnt = 0; 22455230Sab196087 for (cnt = dynsec_ndx; (cnt < shnum) && (dynsec_cnt < dynsec_num); 22465230Sab196087 cnt++) { 22471618Srie Dyn *dyn; 22481618Srie ulong_t numdyn; 22493850Sab196087 int ndx, end_ndx; 22501618Srie Cache *_cache = &cache[cnt], *strsec; 22511618Srie Shdr *shdr = _cache->c_shdr; 22525230Sab196087 int dumped = 0; 22530Sstevel@tonic-gate 22540Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC) 22550Sstevel@tonic-gate continue; 22565230Sab196087 dynsec_cnt++; 22570Sstevel@tonic-gate 22580Sstevel@tonic-gate /* 22591618Srie * Verify the associated string table section. 22600Sstevel@tonic-gate */ 22611618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0) 22620Sstevel@tonic-gate continue; 22631618Srie 22643466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 22653466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 22663466Srie file, _cache->c_name); 22673466Srie continue; 22683466Srie } 22693466Srie if (_cache->c_data == NULL) 22703466Srie continue; 22713466Srie 22720Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize; 22731618Srie dyn = (Dyn *)_cache->c_data->d_buf; 22740Sstevel@tonic-gate 22755230Sab196087 /* 22765230Sab196087 * We expect the REL/RELA entries to reference the reloc 22775230Sab196087 * section with the lowest address. However, this is 22785230Sab196087 * not true for dumped objects. Detect if this object has 22795230Sab196087 * been dumped so that we can skip the reloc address test 22805230Sab196087 * in that case. 22815230Sab196087 */ 22825230Sab196087 for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 22835230Sab196087 if (dyn->d_tag == DT_FLAGS_1) { 22845230Sab196087 dumped = (dyn->d_un.d_val & DF_1_CONFALT) != 0; 22855230Sab196087 break; 22865230Sab196087 } 22875230Sab196087 } 22885230Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 22895230Sab196087 22901618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 22911618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 22920Sstevel@tonic-gate 22931618Srie Elf_dyn_title(0); 22940Sstevel@tonic-gate 22951618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 22964734Sab196087 union { 22976206Sab196087 Conv_inv_buf_t inv; 22984734Sab196087 Conv_dyn_flag_buf_t flag; 22994734Sab196087 Conv_dyn_flag1_buf_t flag1; 23004734Sab196087 Conv_dyn_posflag1_buf_t posflag1; 23014734Sab196087 Conv_dyn_feature1_buf_t feature1; 23024734Sab196087 } c_buf; 23035230Sab196087 const char *name = NULL; 23040Sstevel@tonic-gate 23050Sstevel@tonic-gate /* 23060Sstevel@tonic-gate * Print the information numerically, and if possible 23075230Sab196087 * as a string. If a string is available, name is 23085230Sab196087 * set to reference it. 23095230Sab196087 * 23105230Sab196087 * Also, take this opportunity to sanity check 23115230Sab196087 * the values of DT elements. In the code above, 23125230Sab196087 * we gathered information on sections that are 23135230Sab196087 * referenced by the dynamic section. Here, we 23145230Sab196087 * compare the attributes of those sections to 23155230Sab196087 * the DT_ items that reference them and report 23165230Sab196087 * on inconsistencies. 23175230Sab196087 * 23185230Sab196087 * Things not currently tested that could be improved 23195230Sab196087 * in later revisions include: 23205230Sab196087 * - We don't check PLT or GOT related items 23215230Sab196087 * - We don't handle computing the lengths of 23225230Sab196087 * relocation arrays. To handle this 23235230Sab196087 * requires examining data that spans 23245230Sab196087 * across sections, in a contiguous span 23255230Sab196087 * within a single segment. 23265230Sab196087 * - DT_VERDEFNUM and DT_VERNEEDNUM can't be 23275230Sab196087 * verified without parsing the sections. 23285230Sab196087 * - We don't handle DT_SUNW_SYMSZ, which would 23295230Sab196087 * be the sum of the lengths of .dynsym and 23305230Sab196087 * .SUNW_ldynsym 23315230Sab196087 * - DT_SUNW_STRPAD can't be verified other than 23325230Sab196087 * to check that it's not larger than 23335230Sab196087 * the string table. 23345230Sab196087 * - Some items come in "all or none" clusters 23355230Sab196087 * that give an address, element size, 23365230Sab196087 * and data length in bytes. We don't 23375230Sab196087 * verify that there are no missing items 23385230Sab196087 * in such groups. 23390Sstevel@tonic-gate */ 23403850Sab196087 switch (dyn->d_tag) { 23413850Sab196087 case DT_NULL: 23423850Sab196087 /* 23433850Sab196087 * Special case: DT_NULLs can come in groups 23443850Sab196087 * that we prefer to reduce to a single line. 23453850Sab196087 */ 23463850Sab196087 end_ndx = ndx; 23473850Sab196087 while ((end_ndx < (numdyn - 1)) && 23484433Sab196087 ((dyn + 1)->d_tag == DT_NULL)) { 23493850Sab196087 dyn++; 23503850Sab196087 end_ndx++; 23513850Sab196087 } 23523850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 23533850Sab196087 ndx = end_ndx; 23543850Sab196087 continue; 23553850Sab196087 23563850Sab196087 /* 23575230Sab196087 * String items all reference the dynstr. The string() 23585230Sab196087 * function does the necessary sanity checking. 23593850Sab196087 */ 23603850Sab196087 case DT_NEEDED: 23613850Sab196087 case DT_SONAME: 23623850Sab196087 case DT_FILTER: 23633850Sab196087 case DT_AUXILIARY: 23643850Sab196087 case DT_CONFIG: 23653850Sab196087 case DT_RPATH: 23663850Sab196087 case DT_RUNPATH: 23673850Sab196087 case DT_USED: 23683850Sab196087 case DT_DEPAUDIT: 23693850Sab196087 case DT_AUDIT: 23703850Sab196087 case DT_SUNW_AUXILIARY: 23713850Sab196087 case DT_SUNW_FILTER: 23721618Srie name = string(_cache, ndx, strsec, 23731618Srie file, dyn->d_un.d_ptr); 23743850Sab196087 break; 23753850Sab196087 23763850Sab196087 case DT_FLAGS: 23774734Sab196087 name = conv_dyn_flag(dyn->d_un.d_val, 23784734Sab196087 0, &c_buf.flag); 23793850Sab196087 break; 23803850Sab196087 case DT_FLAGS_1: 23815088Sab196087 name = conv_dyn_flag1(dyn->d_un.d_val, 0, 23824734Sab196087 &c_buf.flag1); 23833850Sab196087 break; 23843850Sab196087 case DT_POSFLAG_1: 23854734Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0, 23864734Sab196087 &c_buf.posflag1); 23873850Sab196087 break; 23883850Sab196087 case DT_FEATURE_1: 23894734Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0, 23904734Sab196087 &c_buf.feature1); 23913850Sab196087 break; 23923850Sab196087 case DT_DEPRECATED_SPARC_REGISTER: 23931618Srie name = MSG_INTL(MSG_STR_DEPRECATED); 23943850Sab196087 break; 23955230Sab196087 23966206Sab196087 case DT_SUNW_LDMACH: 23976206Sab196087 name = conv_ehdr_mach((Half)dyn->d_un.d_val, 0, 23986206Sab196087 &c_buf.inv); 23996206Sab196087 break; 24006206Sab196087 24015230Sab196087 /* 24025230Sab196087 * Cases below this point are strictly sanity checking, 24035230Sab196087 * and do not generate a name string. The TEST_ macros 24045230Sab196087 * are used to hide the boilerplate arguments neeeded 24055230Sab196087 * by dyn_test(). 24065230Sab196087 */ 24075230Sab196087 #define TEST_ADDR(_sh_type, _sec_field) \ 24085230Sab196087 dyn_test(DYN_TEST_ADDR, _sh_type, \ 24095230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 24105230Sab196087 #define TEST_SIZE(_sh_type, _sec_field) \ 24115230Sab196087 dyn_test(DYN_TEST_SIZE, _sh_type, \ 24125230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 24135230Sab196087 #define TEST_ENTSIZE(_sh_type, _sec_field) \ 24145230Sab196087 dyn_test(DYN_TEST_ENTSIZE, _sh_type, \ 24155230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 24165230Sab196087 24175230Sab196087 case DT_FINI: 24186299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_FINI), 24196299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 24206299Sab196087 cache, shnum, ehdr, file); 24215230Sab196087 TEST_ADDR(SHT_PROGBITS, fini); 24225230Sab196087 break; 24235230Sab196087 24245230Sab196087 case DT_FINI_ARRAY: 24255230Sab196087 TEST_ADDR(SHT_FINI_ARRAY, fini_array); 24265230Sab196087 break; 24275230Sab196087 24285230Sab196087 case DT_FINI_ARRAYSZ: 24295230Sab196087 TEST_SIZE(SHT_FINI_ARRAY, fini_array); 24305230Sab196087 break; 24315230Sab196087 24325230Sab196087 case DT_HASH: 24335230Sab196087 TEST_ADDR(SHT_HASH, hash); 24345230Sab196087 break; 24355230Sab196087 24365230Sab196087 case DT_INIT: 24376299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_INIT), 24386299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 24396299Sab196087 cache, shnum, ehdr, file); 24405230Sab196087 TEST_ADDR(SHT_PROGBITS, init); 24415230Sab196087 break; 24425230Sab196087 24435230Sab196087 case DT_INIT_ARRAY: 24445230Sab196087 TEST_ADDR(SHT_INIT_ARRAY, init_array); 24455230Sab196087 break; 24465230Sab196087 24475230Sab196087 case DT_INIT_ARRAYSZ: 24485230Sab196087 TEST_SIZE(SHT_INIT_ARRAY, init_array); 24495230Sab196087 break; 24505230Sab196087 24515230Sab196087 case DT_MOVEENT: 24525230Sab196087 TEST_ENTSIZE(SHT_SUNW_move, sunw_move); 24535230Sab196087 break; 24545230Sab196087 24555230Sab196087 case DT_MOVESZ: 24565230Sab196087 TEST_SIZE(SHT_SUNW_move, sunw_move); 24575230Sab196087 break; 24585230Sab196087 24595230Sab196087 case DT_MOVETAB: 24605230Sab196087 TEST_ADDR(SHT_SUNW_move, sunw_move); 24615230Sab196087 break; 24625230Sab196087 24635230Sab196087 case DT_PREINIT_ARRAY: 24645230Sab196087 TEST_ADDR(SHT_PREINIT_ARRAY, preinit_array); 24655230Sab196087 break; 24665230Sab196087 24675230Sab196087 case DT_PREINIT_ARRAYSZ: 24685230Sab196087 TEST_SIZE(SHT_PREINIT_ARRAY, preinit_array); 24695230Sab196087 break; 24705230Sab196087 24715230Sab196087 case DT_REL: 24725230Sab196087 if (!dumped) 24735230Sab196087 TEST_ADDR(SHT_REL, rel); 24745230Sab196087 break; 24755230Sab196087 24765230Sab196087 case DT_RELENT: 24775230Sab196087 TEST_ENTSIZE(SHT_REL, rel); 24785230Sab196087 break; 24795230Sab196087 24805230Sab196087 case DT_RELA: 24815230Sab196087 if (!dumped) 24825230Sab196087 TEST_ADDR(SHT_RELA, rela); 24835230Sab196087 break; 24845230Sab196087 24855230Sab196087 case DT_RELAENT: 24865230Sab196087 TEST_ENTSIZE(SHT_RELA, rela); 24875230Sab196087 break; 24885230Sab196087 24895230Sab196087 case DT_STRTAB: 24905230Sab196087 TEST_ADDR(SHT_STRTAB, dynstr); 24913850Sab196087 break; 24925230Sab196087 24935230Sab196087 case DT_STRSZ: 24945230Sab196087 TEST_SIZE(SHT_STRTAB, dynstr); 24955230Sab196087 break; 24965230Sab196087 24975230Sab196087 case DT_SUNW_CAP: 24985230Sab196087 TEST_ADDR(SHT_SUNW_cap, sunw_cap); 24995230Sab196087 break; 25005230Sab196087 25015230Sab196087 case DT_SUNW_SYMTAB: 25025230Sab196087 TEST_ADDR(SHT_SUNW_LDYNSYM, sunw_ldynsym); 25035230Sab196087 break; 25045230Sab196087 25055230Sab196087 case DT_SYMENT: 25065230Sab196087 TEST_ENTSIZE(SHT_DYNSYM, dynsym); 25075230Sab196087 break; 25085230Sab196087 25095230Sab196087 case DT_SYMINENT: 25105230Sab196087 TEST_ENTSIZE(SHT_SUNW_syminfo, sunw_syminfo); 25115230Sab196087 break; 25125230Sab196087 25135230Sab196087 case DT_SYMINFO: 25145230Sab196087 TEST_ADDR(SHT_SUNW_syminfo, sunw_syminfo); 25155230Sab196087 break; 25165230Sab196087 25175230Sab196087 case DT_SYMINSZ: 25185230Sab196087 TEST_SIZE(SHT_SUNW_syminfo, sunw_syminfo); 25195230Sab196087 break; 25205230Sab196087 25215230Sab196087 case DT_SYMTAB: 25225230Sab196087 TEST_ADDR(SHT_DYNSYM, dynsym); 25235230Sab196087 break; 25245230Sab196087 25255230Sab196087 case DT_SUNW_SORTENT: 25265230Sab196087 /* 25275230Sab196087 * This entry is related to both the symsort and 25285230Sab196087 * tlssort sections. 25295230Sab196087 */ 25305230Sab196087 { 25315230Sab196087 int test_tls = 25325230Sab196087 (sec.sunw_tlssort != NULL); 25335230Sab196087 int test_sym = 25345230Sab196087 (sec.sunw_symsort != NULL) || 25355230Sab196087 !test_tls; 25365230Sab196087 if (test_sym) 25375230Sab196087 TEST_ENTSIZE(SHT_SUNW_symsort, 25385230Sab196087 sunw_symsort); 25395230Sab196087 if (test_tls) 25405230Sab196087 TEST_ENTSIZE(SHT_SUNW_tlssort, 25415230Sab196087 sunw_tlssort); 25425230Sab196087 } 25435230Sab196087 break; 25445230Sab196087 25455230Sab196087 25465230Sab196087 case DT_SUNW_SYMSORT: 25475230Sab196087 TEST_ADDR(SHT_SUNW_symsort, sunw_symsort); 25485230Sab196087 break; 25495230Sab196087 25505230Sab196087 case DT_SUNW_SYMSORTSZ: 25515230Sab196087 TEST_SIZE(SHT_SUNW_symsort, sunw_symsort); 25525230Sab196087 break; 25535230Sab196087 25545230Sab196087 case DT_SUNW_TLSSORT: 25555230Sab196087 TEST_ADDR(SHT_SUNW_tlssort, sunw_tlssort); 25565230Sab196087 break; 25575230Sab196087 25585230Sab196087 case DT_SUNW_TLSSORTSZ: 25595230Sab196087 TEST_SIZE(SHT_SUNW_tlssort, sunw_tlssort); 25605230Sab196087 break; 25615230Sab196087 25625230Sab196087 case DT_VERDEF: 25635230Sab196087 TEST_ADDR(SHT_SUNW_verdef, sunw_verdef); 25645230Sab196087 break; 25655230Sab196087 25665230Sab196087 case DT_VERNEED: 25675230Sab196087 TEST_ADDR(SHT_SUNW_verneed, sunw_verneed); 25685230Sab196087 break; 25695230Sab196087 25705230Sab196087 case DT_VERSYM: 25715230Sab196087 TEST_ADDR(SHT_SUNW_versym, sunw_versym); 25725230Sab196087 break; 25735230Sab196087 #undef TEST_ADDR 25745230Sab196087 #undef TEST_SIZE 25755230Sab196087 #undef TEST_ENTSIZE 25763850Sab196087 } 25770Sstevel@tonic-gate 25785230Sab196087 if (name == NULL) 25795230Sab196087 name = MSG_ORIG(MSG_STR_EMPTY); 25801618Srie Elf_dyn_entry(0, dyn, ndx, name, ehdr->e_machine); 25810Sstevel@tonic-gate } 25820Sstevel@tonic-gate } 25830Sstevel@tonic-gate } 25840Sstevel@tonic-gate 25850Sstevel@tonic-gate /* 25860Sstevel@tonic-gate * Search for and process a MOVE section. 25870Sstevel@tonic-gate */ 25880Sstevel@tonic-gate static void 25894168Sab196087 move(Cache *cache, Word shnum, const char *file, uint_t flags) 25900Sstevel@tonic-gate { 25911618Srie Word cnt; 25929085SAli.Bahrami@Sun.COM const char *fmt = NULL; 25930Sstevel@tonic-gate 25940Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 25951618Srie Word movenum, symnum, ndx; 25961618Srie Sym *syms; 25971618Srie Cache *_cache = &cache[cnt]; 25981618Srie Shdr *shdr = _cache->c_shdr; 25991618Srie Cache *symsec, *strsec; 26001618Srie Move *move; 26010Sstevel@tonic-gate 26020Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move) 26030Sstevel@tonic-gate continue; 26045411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 26050Sstevel@tonic-gate continue; 26060Sstevel@tonic-gate 26070Sstevel@tonic-gate /* 26080Sstevel@tonic-gate * Determine the move data and number. 26090Sstevel@tonic-gate */ 26100Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 26110Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 26120Sstevel@tonic-gate file, _cache->c_name); 26130Sstevel@tonic-gate continue; 26140Sstevel@tonic-gate } 26153466Srie if (_cache->c_data == NULL) 26163466Srie continue; 26173466Srie 26181618Srie move = (Move *)_cache->c_data->d_buf; 26191618Srie movenum = shdr->sh_size / shdr->sh_entsize; 26200Sstevel@tonic-gate 26210Sstevel@tonic-gate /* 26221618Srie * Get the data buffer for the associated symbol table and 26231618Srie * string table. 26240Sstevel@tonic-gate */ 26251618Srie if (stringtbl(cache, 1, cnt, shnum, file, 26261618Srie &symnum, &symsec, &strsec) == 0) 26271618Srie return; 26281618Srie 26291618Srie syms = (Sym *)symsec->c_data->d_buf; 26300Sstevel@tonic-gate 26311618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 26321618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); 26331618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); 26340Sstevel@tonic-gate 26359085SAli.Bahrami@Sun.COM if (fmt == NULL) 26361618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY); 26370Sstevel@tonic-gate 26381618Srie for (ndx = 0; ndx < movenum; move++, ndx++) { 26391618Srie const char *symname; 26401618Srie char index[MAXNDXSIZE], section[BUFSIZ]; 26411618Srie Word symndx, shndx; 26421618Srie Sym *sym; 26430Sstevel@tonic-gate 26440Sstevel@tonic-gate /* 26450Sstevel@tonic-gate * Check for null entries 26460Sstevel@tonic-gate */ 26471618Srie if ((move->m_info == 0) && (move->m_value == 0) && 26481618Srie (move->m_poffset == 0) && (move->m_repeat == 0) && 26491618Srie (move->m_stride == 0)) { 26501618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY), 26511618Srie EC_XWORD(move->m_poffset), 0, 0, 0, 26521618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY)); 26530Sstevel@tonic-gate continue; 26540Sstevel@tonic-gate } 26551618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) || 26561618Srie (symndx >= symnum)) { 26570Sstevel@tonic-gate (void) fprintf(stderr, 26580Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file, 26591618Srie _cache->c_name, EC_XWORD(move->m_info)); 26601618Srie 26611618Srie (void) snprintf(index, MAXNDXSIZE, 26621618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 26631618Srie dbg_print(0, fmt, index, 26641618Srie EC_XWORD(move->m_poffset), 26651618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 26661618Srie move->m_stride, move->m_value, 26670Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN)); 26680Sstevel@tonic-gate continue; 26690Sstevel@tonic-gate } 26700Sstevel@tonic-gate 26711618Srie symname = relsymname(cache, _cache, strsec, 26727463SRod.Evans@Sun.COM symndx, symnum, ndx, syms, section, BUFSIZ, file); 26731618Srie sym = (Sym *)(syms + symndx); 26740Sstevel@tonic-gate 26750Sstevel@tonic-gate /* 26760Sstevel@tonic-gate * Additional sanity check. 26770Sstevel@tonic-gate */ 26781618Srie shndx = sym->st_shndx; 26790Sstevel@tonic-gate if (!((shndx == SHN_COMMON) || 26800Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) && 26811618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) { 26820Sstevel@tonic-gate (void) fprintf(stderr, 26831618Srie MSG_INTL(MSG_ERR_BADSYM2), file, 26846206Sab196087 _cache->c_name, EC_WORD(symndx), 26856206Sab196087 demangle(symname, flags)); 26860Sstevel@tonic-gate } 26870Sstevel@tonic-gate 26881618Srie (void) snprintf(index, MAXNDXSIZE, 26891618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 26901618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset), 26911618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 26921618Srie move->m_stride, move->m_value, 26931618Srie demangle(symname, flags)); 26940Sstevel@tonic-gate } 26950Sstevel@tonic-gate } 26960Sstevel@tonic-gate } 26970Sstevel@tonic-gate 26980Sstevel@tonic-gate /* 26996635Sab196087 * Callback function for use with conv_str_to_c_literal() below. 27006635Sab196087 */ 27016635Sab196087 /*ARGSUSED2*/ 27026635Sab196087 static void 27036635Sab196087 c_literal_cb(const void *ptr, size_t size, void *uvalue) 27046635Sab196087 { 27056635Sab196087 (void) fwrite(ptr, size, 1, stdout); 27066635Sab196087 } 27076635Sab196087 27086635Sab196087 /* 27090Sstevel@tonic-gate * Traverse a note section analyzing each note information block. 27100Sstevel@tonic-gate * The data buffers size is used to validate references before they are made, 27110Sstevel@tonic-gate * and is decremented as each element is processed. 27120Sstevel@tonic-gate */ 27130Sstevel@tonic-gate void 27146635Sab196087 note_entry(Cache *cache, Word *data, size_t size, Ehdr *ehdr, const char *file) 27150Sstevel@tonic-gate { 27166635Sab196087 size_t bsize = size; 27176635Sab196087 int cnt = 0; 27186635Sab196087 int is_corenote; 27196635Sab196087 int do_swap; 27206635Sab196087 Conv_inv_buf_t inv_buf; 27216635Sab196087 27226635Sab196087 do_swap = _elf_sys_encoding() != ehdr->e_ident[EI_DATA]; 27231618Srie 27240Sstevel@tonic-gate /* 27250Sstevel@tonic-gate * Print out a single `note' information block. 27260Sstevel@tonic-gate */ 27270Sstevel@tonic-gate while (size > 0) { 27281618Srie size_t namesz, descsz, type, pad, noteoff; 27290Sstevel@tonic-gate 27300Sstevel@tonic-gate noteoff = bsize - size; 27310Sstevel@tonic-gate /* 27320Sstevel@tonic-gate * Make sure we can at least reference the 3 initial entries 27330Sstevel@tonic-gate * (4-byte words) of the note information block. 27340Sstevel@tonic-gate */ 27351618Srie if (size >= (sizeof (Word) * 3)) 27361618Srie size -= (sizeof (Word) * 3); 27370Sstevel@tonic-gate else { 27381618Srie (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ), 27391618Srie file, cache->c_name, EC_WORD(noteoff)); 27400Sstevel@tonic-gate return; 27410Sstevel@tonic-gate } 27420Sstevel@tonic-gate 27430Sstevel@tonic-gate /* 27440Sstevel@tonic-gate * Make sure any specified name string can be referenced. 27450Sstevel@tonic-gate */ 27460Sstevel@tonic-gate if ((namesz = *data++) != 0) { 27470Sstevel@tonic-gate if (size >= namesz) 27480Sstevel@tonic-gate size -= namesz; 27490Sstevel@tonic-gate else { 27500Sstevel@tonic-gate (void) fprintf(stderr, 27511618Srie MSG_INTL(MSG_NOTE_BADNMSZ), file, 27521618Srie cache->c_name, EC_WORD(noteoff), 27531618Srie EC_WORD(namesz)); 27540Sstevel@tonic-gate return; 27550Sstevel@tonic-gate } 27560Sstevel@tonic-gate } 27571618Srie 27580Sstevel@tonic-gate /* 27590Sstevel@tonic-gate * Make sure any specified descriptor can be referenced. 27600Sstevel@tonic-gate */ 27610Sstevel@tonic-gate if ((descsz = *data++) != 0) { 27620Sstevel@tonic-gate /* 27630Sstevel@tonic-gate * If namesz isn't a 4-byte multiple, account for any 27640Sstevel@tonic-gate * padding that must exist before the descriptor. 27650Sstevel@tonic-gate */ 27661618Srie if ((pad = (namesz & (sizeof (Word) - 1))) != 0) { 27671618Srie pad = sizeof (Word) - pad; 27680Sstevel@tonic-gate size -= pad; 27690Sstevel@tonic-gate } 27700Sstevel@tonic-gate if (size >= descsz) 27710Sstevel@tonic-gate size -= descsz; 27720Sstevel@tonic-gate else { 27730Sstevel@tonic-gate (void) fprintf(stderr, 27741618Srie MSG_INTL(MSG_NOTE_BADDESZ), file, 27751618Srie cache->c_name, EC_WORD(noteoff), 27761618Srie EC_WORD(namesz)); 27770Sstevel@tonic-gate return; 27780Sstevel@tonic-gate } 27790Sstevel@tonic-gate } 27800Sstevel@tonic-gate 27810Sstevel@tonic-gate type = *data++; 27820Sstevel@tonic-gate 27836635Sab196087 /* 27846635Sab196087 * Is this a Solaris core note? Such notes all have 27856635Sab196087 * the name "CORE". 27866635Sab196087 */ 27876635Sab196087 is_corenote = (ehdr->e_type == ET_CORE) && 27886635Sab196087 (namesz == (MSG_STR_CORE_SIZE + 1)) && 27896635Sab196087 (strncmp(MSG_ORIG(MSG_STR_CORE), (char *)data, 27906635Sab196087 MSG_STR_CORE_SIZE + 1) == 0); 27916635Sab196087 27921618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 27936635Sab196087 dbg_print(0, MSG_INTL(MSG_FMT_NOTEENTNDX), EC_WORD(cnt)); 27946635Sab196087 cnt++; 27951618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz)); 27966635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz)); 27976635Sab196087 27986635Sab196087 if (is_corenote) 27996635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE_STR), 28006635Sab196087 conv_cnote_type(type, 0, &inv_buf)); 28016635Sab196087 else 28026635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type)); 28030Sstevel@tonic-gate if (namesz) { 28040Sstevel@tonic-gate char *name = (char *)data; 28050Sstevel@tonic-gate 28066635Sab196087 28076635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_NAME)); 28080Sstevel@tonic-gate /* 28096635Sab196087 * The name string can contain embedded 'null' 28106635Sab196087 * bytes and/or unprintable characters. Also, 28116635Sab196087 * the final NULL is documented in the ELF ABI 28126635Sab196087 * as being included in the namesz. So, display 28136635Sab196087 * the name using C literal string notation, and 28146635Sab196087 * include the terminating NULL in the output. 28156635Sab196087 * We don't show surrounding double quotes, as 28166635Sab196087 * that implies the termination that we are showing 28176635Sab196087 * explicitly. 28180Sstevel@tonic-gate */ 28196635Sab196087 (void) fwrite(MSG_ORIG(MSG_STR_8SP), 28206635Sab196087 MSG_STR_8SP_SIZE, 1, stdout); 28216635Sab196087 conv_str_to_c_literal(name, namesz, c_literal_cb, NULL); 28220Sstevel@tonic-gate name = name + ((namesz + (sizeof (Word) - 1)) & 28230Sstevel@tonic-gate ~(sizeof (Word) - 1)); 28240Sstevel@tonic-gate /* LINTED */ 28250Sstevel@tonic-gate data = (Word *)name; 28261618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 28270Sstevel@tonic-gate } 28280Sstevel@tonic-gate 28290Sstevel@tonic-gate /* 28300Sstevel@tonic-gate * If multiple information blocks exist within a .note section 28310Sstevel@tonic-gate * account for any padding that must exist before the next 28320Sstevel@tonic-gate * information block. 28330Sstevel@tonic-gate */ 28341618Srie if ((pad = (descsz & (sizeof (Word) - 1))) != 0) { 28351618Srie pad = sizeof (Word) - pad; 28360Sstevel@tonic-gate if (size > pad) 28370Sstevel@tonic-gate size -= pad; 28380Sstevel@tonic-gate } 28390Sstevel@tonic-gate 28400Sstevel@tonic-gate if (descsz) { 28416635Sab196087 int hexdump = 1; 28426635Sab196087 const char *desc = (const char *)data; 28430Sstevel@tonic-gate 28440Sstevel@tonic-gate /* 28456635Sab196087 * If this is a core note, let the corenote() 28466635Sab196087 * function handle it. 28470Sstevel@tonic-gate */ 28486635Sab196087 if (is_corenote) { 28496635Sab196087 /* We only issue the bad arch error once */ 28506635Sab196087 static int badnote_done = 0; 28516635Sab196087 corenote_ret_t corenote_ret; 28526635Sab196087 28536635Sab196087 corenote_ret = corenote(ehdr->e_machine, 28546635Sab196087 do_swap, type, desc, descsz); 28556635Sab196087 switch (corenote_ret) { 28566635Sab196087 case CORENOTE_R_OK: 28576635Sab196087 hexdump = 0; 28586635Sab196087 break; 28596635Sab196087 case CORENOTE_R_BADDATA: 28606635Sab196087 (void) fprintf(stderr, 28616635Sab196087 MSG_INTL(MSG_NOTE_BADCOREDATA), 28626635Sab196087 file); 28636635Sab196087 break; 28646635Sab196087 case CORENOTE_R_BADARCH: 28656635Sab196087 if (badnote_done) 28666635Sab196087 break; 28676635Sab196087 (void) fprintf(stderr, 28686635Sab196087 MSG_INTL(MSG_NOTE_BADCOREARCH), 28696635Sab196087 file, 28706635Sab196087 conv_ehdr_mach(ehdr->e_machine, 28716635Sab196087 0, &inv_buf)); 28726635Sab196087 break; 28730Sstevel@tonic-gate } 28740Sstevel@tonic-gate } 28756635Sab196087 28766635Sab196087 /* 28776635Sab196087 * The default thing when we don't understand 28786635Sab196087 * the note data is to display it as hex bytes. 28796635Sab196087 */ 28806635Sab196087 if (hexdump) { 28816635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESC)); 28826635Sab196087 dump_hex_bytes(desc, descsz, 8, 4, 4); 28830Sstevel@tonic-gate } 28846635Sab196087 desc += descsz + pad; 28856635Sab196087 28860Sstevel@tonic-gate /* LINTED */ 28870Sstevel@tonic-gate data = (Word *)desc; 28880Sstevel@tonic-gate } 28890Sstevel@tonic-gate } 28900Sstevel@tonic-gate } 28910Sstevel@tonic-gate 28920Sstevel@tonic-gate /* 28936635Sab196087 * Search for and process .note sections. 28946635Sab196087 * 28956635Sab196087 * Returns the number of note sections seen. 28960Sstevel@tonic-gate */ 28976635Sab196087 static Word 28986635Sab196087 note(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 28990Sstevel@tonic-gate { 29006635Sab196087 Word cnt, note_cnt = 0; 29010Sstevel@tonic-gate 29020Sstevel@tonic-gate /* 29030Sstevel@tonic-gate * Otherwise look for any .note sections. 29040Sstevel@tonic-gate */ 29050Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 29061618Srie Cache *_cache = &cache[cnt]; 29071618Srie Shdr *shdr = _cache->c_shdr; 29080Sstevel@tonic-gate 29090Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE) 29100Sstevel@tonic-gate continue; 29116635Sab196087 note_cnt++; 29125411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 29130Sstevel@tonic-gate continue; 29140Sstevel@tonic-gate 29150Sstevel@tonic-gate /* 29160Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're 29175230Sab196087 * properly aligned before proceeding, and issue an error 29185230Sab196087 * as necessary. 29195230Sab196087 * 29205230Sab196087 * Note that we will continue on to display the note even 29215230Sab196087 * if it has bad alignment. We can do this safely, because 29225230Sab196087 * libelf knows the alignment required for SHT_NOTE, and 29235230Sab196087 * takes steps to deliver a properly aligned buffer to us 29245230Sab196087 * even if the actual file is misaligned. 29250Sstevel@tonic-gate */ 29265230Sab196087 if (shdr->sh_offset & (sizeof (Word) - 1)) 29270Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 29280Sstevel@tonic-gate file, _cache->c_name); 29295230Sab196087 29303466Srie if (_cache->c_data == NULL) 29313466Srie continue; 29320Sstevel@tonic-gate 29331618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 29341618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 29350Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf, 29360Sstevel@tonic-gate /* LINTED */ 29376635Sab196087 (Word)_cache->c_data->d_size, ehdr, file); 29380Sstevel@tonic-gate } 29396635Sab196087 29406635Sab196087 return (note_cnt); 29410Sstevel@tonic-gate } 29420Sstevel@tonic-gate 29431618Srie /* 29441618Srie * Determine an individual hash entry. This may be the initial hash entry, 29451618Srie * or an associated chain entry. 29461618Srie */ 29471618Srie static void 29481618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx, 29491618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts, 29501618Srie uint_t flags, int chain) 29511618Srie { 29521618Srie Sym *sym; 29531618Srie const char *symname, *str; 29541618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE]; 29551618Srie ulong_t nbkt, nhash; 29561618Srie 29571618Srie if (symndx > symn) { 29581618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file, 29591618Srie EC_WORD(symndx), EC_WORD(hashndx)); 29601618Srie symname = MSG_INTL(MSG_STR_UNKNOWN); 29611618Srie } else { 29621618Srie sym = (Sym *)(syms + symndx); 29631618Srie symname = string(refsec, symndx, strsec, file, sym->st_name); 29641618Srie } 29651618Srie 29661618Srie if (chain == 0) { 29671618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 29681618Srie hashndx); 29691618Srie str = (const char *)_bucket; 29701618Srie } else 29711618Srie str = MSG_ORIG(MSG_STR_EMPTY); 29721618Srie 29731618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2), 29741618Srie EC_WORD(symndx)); 29751618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx, 29761618Srie demangle(symname, flags)); 29771618Srie 29781618Srie /* 29791618Srie * Determine if this string is in the correct bucket. 29801618Srie */ 29811618Srie nhash = elf_hash(symname); 29821618Srie nbkt = nhash % bkts; 29831618Srie 29841618Srie if (nbkt != hashndx) { 29851618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file, 29861618Srie hsecname, symname, EC_WORD(hashndx), nbkt); 29871618Srie } 29881618Srie } 29890Sstevel@tonic-gate 29900Sstevel@tonic-gate #define MAXCOUNT 500 29910Sstevel@tonic-gate 29920Sstevel@tonic-gate static void 29934168Sab196087 hash(Cache *cache, Word shnum, const char *file, uint_t flags) 29940Sstevel@tonic-gate { 29950Sstevel@tonic-gate static int count[MAXCOUNT]; 29961618Srie Word cnt; 29970Sstevel@tonic-gate ulong_t ndx, bkts; 29980Sstevel@tonic-gate char number[MAXNDXSIZE]; 29990Sstevel@tonic-gate 30000Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 30010Sstevel@tonic-gate uint_t *hash, *chain; 30020Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 30031618Srie Shdr *sshdr, *hshdr = _cache->c_shdr; 30041618Srie char *ssecname, *hsecname = _cache->c_name; 30051618Srie Sym *syms; 30061618Srie Word symn; 30070Sstevel@tonic-gate 30081618Srie if (hshdr->sh_type != SHT_HASH) 30090Sstevel@tonic-gate continue; 30100Sstevel@tonic-gate 30110Sstevel@tonic-gate /* 30120Sstevel@tonic-gate * Determine the hash table data and size. 30130Sstevel@tonic-gate */ 30141618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) { 30150Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 30161618Srie file, hsecname); 30170Sstevel@tonic-gate continue; 30180Sstevel@tonic-gate } 30193466Srie if (_cache->c_data == NULL) 30203466Srie continue; 30213466Srie 30220Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf; 30230Sstevel@tonic-gate bkts = *hash; 30240Sstevel@tonic-gate chain = hash + 2 + bkts; 30250Sstevel@tonic-gate hash += 2; 30260Sstevel@tonic-gate 30270Sstevel@tonic-gate /* 30280Sstevel@tonic-gate * Get the data buffer for the associated symbol table. 30290Sstevel@tonic-gate */ 30301618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) { 30310Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 30321618Srie file, hsecname, EC_WORD(hshdr->sh_link)); 30330Sstevel@tonic-gate continue; 30340Sstevel@tonic-gate } 30351618Srie 30361618Srie _cache = &cache[hshdr->sh_link]; 30371618Srie ssecname = _cache->c_name; 30381618Srie 30393466Srie if (_cache->c_data == NULL) 30403466Srie continue; 30413466Srie 30423466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) { 30430Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 30441618Srie file, ssecname); 30450Sstevel@tonic-gate continue; 30460Sstevel@tonic-gate } 30470Sstevel@tonic-gate 30481618Srie sshdr = _cache->c_shdr; 30491618Srie /* LINTED */ 30501618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize); 30511618Srie 30520Sstevel@tonic-gate /* 30530Sstevel@tonic-gate * Get the associated string table section. 30540Sstevel@tonic-gate */ 30551618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) { 30560Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 30571618Srie file, ssecname, EC_WORD(sshdr->sh_link)); 30580Sstevel@tonic-gate continue; 30590Sstevel@tonic-gate } 30600Sstevel@tonic-gate 30611618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 30621618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname); 30631618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO)); 30640Sstevel@tonic-gate 30650Sstevel@tonic-gate /* 30660Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate 30670Sstevel@tonic-gate * symbols. 30680Sstevel@tonic-gate */ 30690Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) { 30701618Srie Word _ndx, _cnt; 30710Sstevel@tonic-gate 30720Sstevel@tonic-gate if (*hash == 0) { 30730Sstevel@tonic-gate count[0]++; 30740Sstevel@tonic-gate continue; 30750Sstevel@tonic-gate } 30760Sstevel@tonic-gate 30771618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname, 30781618Srie ndx, *hash, symn, syms, file, bkts, flags, 0); 30790Sstevel@tonic-gate 30800Sstevel@tonic-gate /* 30810Sstevel@tonic-gate * Determine if any other symbols are chained to this 30820Sstevel@tonic-gate * bucket. 30830Sstevel@tonic-gate */ 30840Sstevel@tonic-gate _ndx = chain[*hash]; 30850Sstevel@tonic-gate _cnt = 1; 30860Sstevel@tonic-gate while (_ndx) { 30871618Srie hash_entry(_cache, &cache[sshdr->sh_link], 30881618Srie hsecname, ndx, _ndx, symn, syms, file, 30891618Srie bkts, flags, 1); 30900Sstevel@tonic-gate _ndx = chain[_ndx]; 30910Sstevel@tonic-gate _cnt++; 30920Sstevel@tonic-gate } 30930Sstevel@tonic-gate 30940Sstevel@tonic-gate if (_cnt >= MAXCOUNT) { 30950Sstevel@tonic-gate (void) fprintf(stderr, 30961324Srie MSG_INTL(MSG_HASH_OVERFLW), file, 30971618Srie _cache->c_name, EC_WORD(ndx), 30981618Srie EC_WORD(_cnt)); 30990Sstevel@tonic-gate } else 31000Sstevel@tonic-gate count[_cnt]++; 31010Sstevel@tonic-gate } 31020Sstevel@tonic-gate break; 31030Sstevel@tonic-gate } 31040Sstevel@tonic-gate 31050Sstevel@tonic-gate /* 31060Sstevel@tonic-gate * Print out the count information. 31070Sstevel@tonic-gate */ 31080Sstevel@tonic-gate bkts = cnt = 0; 31091618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 31101618Srie 31110Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) { 31121618Srie Word _cnt; 31130Sstevel@tonic-gate 31140Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0) 31150Sstevel@tonic-gate continue; 31160Sstevel@tonic-gate 31171618Srie (void) snprintf(number, MAXNDXSIZE, 31181618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt); 31191618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number, 31201618Srie EC_WORD(ndx)); 31210Sstevel@tonic-gate bkts += _cnt; 31221618Srie cnt += (Word)(ndx * _cnt); 31230Sstevel@tonic-gate } 31240Sstevel@tonic-gate if (cnt) { 31250Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 31261618Srie bkts); 31271618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number, 31281618Srie EC_WORD(cnt)); 31290Sstevel@tonic-gate } 31300Sstevel@tonic-gate } 31310Sstevel@tonic-gate 31320Sstevel@tonic-gate static void 31334168Sab196087 group(Cache *cache, Word shnum, const char *file, uint_t flags) 31340Sstevel@tonic-gate { 31351618Srie Word scnt; 31360Sstevel@tonic-gate 31371618Srie for (scnt = 1; scnt < shnum; scnt++) { 31381618Srie Cache *_cache = &cache[scnt]; 31391618Srie Shdr *shdr = _cache->c_shdr; 31401618Srie Word *grpdata, gcnt, grpcnt, symnum, unknown; 31411618Srie Cache *symsec, *strsec; 31421618Srie Sym *syms, *sym; 31431618Srie char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 31440Sstevel@tonic-gate 31450Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP) 31460Sstevel@tonic-gate continue; 31475411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, scnt, shdr->sh_type)) 31480Sstevel@tonic-gate continue; 31493466Srie if ((_cache->c_data == NULL) || 31503466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL)) 31510Sstevel@tonic-gate continue; 31521618Srie grpcnt = shdr->sh_size / sizeof (Word); 31531618Srie 31541618Srie /* 31551618Srie * Get the data buffer for the associated symbol table and 31561618Srie * string table. 31571618Srie */ 31581618Srie if (stringtbl(cache, 1, scnt, shnum, file, 31591618Srie &symnum, &symsec, &strsec) == 0) 31601618Srie return; 31611618Srie 31621618Srie syms = symsec->c_data->d_buf; 31631618Srie 31641618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 31651618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name); 31661618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE)); 31671618Srie 31681618Srie /* 31691618Srie * The first element of the group defines the group. The 31701618Srie * associated symbol is defined by the sh_link field. 31711618Srie */ 31721618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) { 31731618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 31741618Srie file, _cache->c_name, EC_WORD(shdr->sh_info)); 31751618Srie return; 31760Sstevel@tonic-gate } 31770Sstevel@tonic-gate 31781618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT)); 31791618Srie if (grpdata[0] & GRP_COMDAT) { 31801618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT)); 31810Sstevel@tonic-gate } 31821618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) { 31831618Srie size_t len = strlen(flgstrbuf); 31841618Srie 31851618Srie (void) snprintf(&flgstrbuf[len], 31861618Srie (MSG_GRP_COMDAT_SIZE + 10 - len), 31871618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown); 31880Sstevel@tonic-gate } 31891618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT)); 31901618Srie sym = (Sym *)(syms + shdr->sh_info); 31910Sstevel@tonic-gate 31921618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf, 31931618Srie demangle(string(_cache, 0, strsec, file, sym->st_name), 31941618Srie flags)); 31951618Srie 31961618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) { 31970Sstevel@tonic-gate char index[MAXNDXSIZE]; 31981618Srie const char *name; 31990Sstevel@tonic-gate 32000Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, 32011618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt)); 32021618Srie 32031618Srie if (grpdata[gcnt] >= shnum) 32041618Srie name = MSG_INTL(MSG_GRP_INVALSCN); 32051618Srie else 32061618Srie name = cache[grpdata[gcnt]].c_name; 32071618Srie 32081618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name, 32094433Sab196087 EC_XWORD(grpdata[gcnt])); 32100Sstevel@tonic-gate } 32110Sstevel@tonic-gate } 32120Sstevel@tonic-gate } 32130Sstevel@tonic-gate 32140Sstevel@tonic-gate static void 32157463SRod.Evans@Sun.COM got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 32160Sstevel@tonic-gate { 32175230Sab196087 Cache *gotcache = NULL, *symtab = NULL; 32181618Srie Addr gotbgn, gotend; 32191618Srie Shdr *gotshdr; 32201618Srie Word cnt, gotents, gotndx; 32210Sstevel@tonic-gate size_t gentsize; 32220Sstevel@tonic-gate Got_info *gottable; 32230Sstevel@tonic-gate char *gotdata; 32241618Srie Sym *gotsym; 32251618Srie Xword gotsymaddr; 32266206Sab196087 uint_t sys_encoding; 32270Sstevel@tonic-gate 32280Sstevel@tonic-gate /* 32291324Srie * First, find the got. 32300Sstevel@tonic-gate */ 32310Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 32325230Sab196087 if (strncmp(cache[cnt].c_name, MSG_ORIG(MSG_ELF_GOT), 32331324Srie MSG_ELF_GOT_SIZE) == 0) { 32345230Sab196087 gotcache = &cache[cnt]; 32350Sstevel@tonic-gate break; 32360Sstevel@tonic-gate } 32370Sstevel@tonic-gate } 32385230Sab196087 if (gotcache == NULL) 32390Sstevel@tonic-gate return; 32401324Srie 32411324Srie /* 32421324Srie * A got section within a relocatable object is suspicious. 32431324Srie */ 32441324Srie if (ehdr->e_type == ET_REL) { 32451324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file, 32465230Sab196087 gotcache->c_name); 32471324Srie } 32481324Srie 32491618Srie gotshdr = gotcache->c_shdr; 32500Sstevel@tonic-gate if (gotshdr->sh_size == 0) { 32510Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 32520Sstevel@tonic-gate file, gotcache->c_name); 32530Sstevel@tonic-gate return; 32540Sstevel@tonic-gate } 32551618Srie 32561618Srie gotbgn = gotshdr->sh_addr; 32570Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size; 32580Sstevel@tonic-gate 32590Sstevel@tonic-gate /* 32601618Srie * Some architectures don't properly set the sh_entsize for the GOT 32611618Srie * table. If it's not set, default to a size of a pointer. 32620Sstevel@tonic-gate */ 32631618Srie if ((gentsize = gotshdr->sh_entsize) == 0) 32641618Srie gentsize = sizeof (Xword); 32651618Srie 32663466Srie if (gotcache->c_data == NULL) 32673466Srie return; 32683466Srie 32690Sstevel@tonic-gate /* LINTED */ 32701618Srie gotents = (Word)(gotshdr->sh_size / gentsize); 32710Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf; 32720Sstevel@tonic-gate 32730Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 32740Sstevel@tonic-gate int err = errno; 32751618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file, 32761618Srie strerror(err)); 32770Sstevel@tonic-gate return; 32780Sstevel@tonic-gate } 32790Sstevel@tonic-gate 32800Sstevel@tonic-gate /* 32810Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations 32820Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a 32830Sstevel@tonic-gate * .rel[a].got section we check them all. 32840Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab 32850Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 32860Sstevel@tonic-gate */ 32870Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 32881618Srie Word type, symnum; 32891618Srie Xword relndx, relnum, relsize; 32901618Srie void *rels; 32911618Srie Sym *syms; 32921618Srie Cache *symsec, *strsec; 32931618Srie Cache *_cache = &cache[cnt]; 32941618Srie Shdr *shdr; 32950Sstevel@tonic-gate 32961618Srie shdr = _cache->c_shdr; 32971618Srie type = shdr->sh_type; 32980Sstevel@tonic-gate 32991618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) { 33000Sstevel@tonic-gate symtab = _cache; 33010Sstevel@tonic-gate continue; 33020Sstevel@tonic-gate } 33031618Srie if (type == SHT_SYMTAB) { 33040Sstevel@tonic-gate symtab = _cache; 33050Sstevel@tonic-gate continue; 33060Sstevel@tonic-gate } 33071618Srie if ((type != SHT_RELA) && (type != SHT_REL)) 33080Sstevel@tonic-gate continue; 33090Sstevel@tonic-gate 33100Sstevel@tonic-gate /* 33111618Srie * Decide entry size. 33120Sstevel@tonic-gate */ 33131618Srie if (((relsize = shdr->sh_entsize) == 0) || 33141618Srie (relsize > shdr->sh_size)) { 33151618Srie if (type == SHT_RELA) 33161618Srie relsize = sizeof (Rela); 33171618Srie else 33181618Srie relsize = sizeof (Rel); 33190Sstevel@tonic-gate } 33200Sstevel@tonic-gate 33210Sstevel@tonic-gate /* 33221618Srie * Determine the number of relocations available. 33230Sstevel@tonic-gate */ 33241618Srie if (shdr->sh_size == 0) { 33251618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 33261618Srie file, _cache->c_name); 33270Sstevel@tonic-gate continue; 33280Sstevel@tonic-gate } 33293466Srie if (_cache->c_data == NULL) 33303466Srie continue; 33313466Srie 33321618Srie rels = _cache->c_data->d_buf; 33331618Srie relnum = shdr->sh_size / relsize; 33340Sstevel@tonic-gate 33351618Srie /* 33361618Srie * Get the data buffer for the associated symbol table and 33371618Srie * string table. 33381618Srie */ 33391618Srie if (stringtbl(cache, 1, cnt, shnum, file, 33401618Srie &symnum, &symsec, &strsec) == 0) 33411618Srie continue; 33421618Srie 33431618Srie syms = symsec->c_data->d_buf; 33441618Srie 33451618Srie /* 33461618Srie * Loop through the relocation entries. 33471618Srie */ 33481618Srie for (relndx = 0; relndx < relnum; relndx++, 33491618Srie rels = (void *)((char *)rels + relsize)) { 33501618Srie char section[BUFSIZ]; 33511618Srie Addr offset; 33520Sstevel@tonic-gate Got_info *gip; 33531618Srie Word symndx, reltype; 33541618Srie Rela *rela; 33551618Srie Rel *rel; 33560Sstevel@tonic-gate 33571618Srie /* 33581618Srie * Unravel the relocation. 33591618Srie */ 33601618Srie if (type == SHT_RELA) { 33611618Srie rela = (Rela *)rels; 33621618Srie symndx = ELF_R_SYM(rela->r_info); 33636206Sab196087 reltype = ELF_R_TYPE(rela->r_info, 33646206Sab196087 ehdr->e_machine); 33651618Srie offset = rela->r_offset; 33660Sstevel@tonic-gate } else { 33671618Srie rel = (Rel *)rels; 33681618Srie symndx = ELF_R_SYM(rel->r_info); 33696206Sab196087 reltype = ELF_R_TYPE(rel->r_info, 33706206Sab196087 ehdr->e_machine); 33711618Srie offset = rel->r_offset; 33720Sstevel@tonic-gate } 33730Sstevel@tonic-gate 33740Sstevel@tonic-gate /* 33750Sstevel@tonic-gate * Only pay attention to relocations against the GOT. 33760Sstevel@tonic-gate */ 33774146Sab196087 if ((offset < gotbgn) || (offset >= gotend)) 33780Sstevel@tonic-gate continue; 33790Sstevel@tonic-gate 33800Sstevel@tonic-gate /* LINTED */ 33811618Srie gotndx = (Word)((offset - gotbgn) / 33820Sstevel@tonic-gate gotshdr->sh_entsize); 33830Sstevel@tonic-gate gip = &gottable[gotndx]; 33841618Srie 33851618Srie if (gip->g_reltype != 0) { 33860Sstevel@tonic-gate (void) fprintf(stderr, 33870Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file, 33881618Srie EC_WORD(gotndx), EC_ADDR(offset)); 33890Sstevel@tonic-gate continue; 33900Sstevel@tonic-gate } 33910Sstevel@tonic-gate 33921618Srie if (symndx) 33931618Srie gip->g_symname = relsymname(cache, _cache, 33941618Srie strsec, symndx, symnum, relndx, syms, 33957463SRod.Evans@Sun.COM section, BUFSIZ, file); 33961618Srie gip->g_reltype = reltype; 33971618Srie gip->g_rel = rels; 33980Sstevel@tonic-gate } 33990Sstevel@tonic-gate } 34000Sstevel@tonic-gate 34016299Sab196087 if (symlookup(MSG_ORIG(MSG_SYM_GOT), cache, shnum, &gotsym, symtab, 34021618Srie file)) 34031618Srie gotsymaddr = gotsym->st_value; 34040Sstevel@tonic-gate else 34051618Srie gotsymaddr = gotbgn; 34060Sstevel@tonic-gate 34071618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 34081618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name); 34091618Srie Elf_got_title(0); 34100Sstevel@tonic-gate 34116206Sab196087 sys_encoding = _elf_sys_encoding(); 34120Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) { 34130Sstevel@tonic-gate Got_info *gip; 34140Sstevel@tonic-gate Sword gindex; 34151618Srie Addr gaddr; 34161618Srie Xword gotentry; 34170Sstevel@tonic-gate 34180Sstevel@tonic-gate gip = &gottable[gotndx]; 34190Sstevel@tonic-gate 34200Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize); 34211618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize; 34220Sstevel@tonic-gate 34231618Srie if (gentsize == sizeof (Word)) 34240Sstevel@tonic-gate /* LINTED */ 34251618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx)); 34260Sstevel@tonic-gate else 34270Sstevel@tonic-gate /* LINTED */ 34281618Srie gotentry = *((Xword *)(gotdata) + gotndx); 34290Sstevel@tonic-gate 34301618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine, 34316206Sab196087 ehdr->e_ident[EI_DATA], sys_encoding, 34321618Srie gip->g_reltype, gip->g_rel, gip->g_symname); 34330Sstevel@tonic-gate } 34340Sstevel@tonic-gate free(gottable); 34350Sstevel@tonic-gate } 34360Sstevel@tonic-gate 34370Sstevel@tonic-gate void 34380Sstevel@tonic-gate checksum(Elf *elf) 34390Sstevel@tonic-gate { 34401618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 34411618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf)); 34420Sstevel@tonic-gate } 34430Sstevel@tonic-gate 34444242Sab196087 /* 34454242Sab196087 * This variable is used by regular() to communicate the address of 34464242Sab196087 * the section header cache to sort_shdr_ndx_arr(). Unfortunately, 34474242Sab196087 * the qsort() interface does not include a userdata argument by which 34484242Sab196087 * such arbitrary data can be passed, so we are stuck using global data. 34494242Sab196087 */ 34504242Sab196087 static Cache *sort_shdr_ndx_arr_cache; 34514242Sab196087 34524242Sab196087 34534242Sab196087 /* 34544242Sab196087 * Used with qsort() to sort the section indices so that they can be 34554242Sab196087 * used to access the section headers in order of increasing data offset. 34564242Sab196087 * 34574242Sab196087 * entry: 34584242Sab196087 * sort_shdr_ndx_arr_cache - Contains address of 34594242Sab196087 * section header cache. 34604242Sab196087 * v1, v2 - Point at elements of sort_shdr_bits array to be compared. 34614242Sab196087 * 34624242Sab196087 * exit: 34634242Sab196087 * Returns -1 (less than), 0 (equal) or 1 (greater than). 34644242Sab196087 */ 34654242Sab196087 static int 34664242Sab196087 sort_shdr_ndx_arr(const void *v1, const void *v2) 34674242Sab196087 { 34684242Sab196087 Cache *cache1 = sort_shdr_ndx_arr_cache + *((size_t *)v1); 34694242Sab196087 Cache *cache2 = sort_shdr_ndx_arr_cache + *((size_t *)v2); 34704242Sab196087 34714242Sab196087 if (cache1->c_shdr->sh_offset < cache2->c_shdr->sh_offset) 34724242Sab196087 return (-1); 34734242Sab196087 34744242Sab196087 if (cache1->c_shdr->sh_offset > cache2->c_shdr->sh_offset) 34754242Sab196087 return (1); 34764242Sab196087 34774242Sab196087 return (0); 34784242Sab196087 } 34794242Sab196087 34804242Sab196087 34814665Sab196087 static int 34824665Sab196087 shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, 34837463SRod.Evans@Sun.COM size_t shnum, Cache **cache_ret, Word flags) 34840Sstevel@tonic-gate { 34850Sstevel@tonic-gate Elf_Scn *scn; 34860Sstevel@tonic-gate Elf_Data *data; 34874665Sab196087 size_t ndx; 34884665Sab196087 Shdr *nameshdr; 34899085SAli.Bahrami@Sun.COM char *names = NULL; 34900Sstevel@tonic-gate Cache *cache, *_cache; 34914242Sab196087 size_t *shdr_ndx_arr, shdr_ndx_arr_cnt; 34920Sstevel@tonic-gate 34930Sstevel@tonic-gate 34940Sstevel@tonic-gate /* 34950Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section 34960Sstevel@tonic-gate * name strings. 34970Sstevel@tonic-gate */ 34984156Sab196087 if (shstrndx == SHN_UNDEF) { 34994156Sab196087 /* 35004156Sab196087 * It is rare, but legal, for an object to lack a 35014156Sab196087 * header string table section. 35024156Sab196087 */ 35034156Sab196087 names = NULL; 35044156Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHSTRSEC), file); 35054156Sab196087 } else if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 35060Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 35070Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 35080Sstevel@tonic-gate EC_XWORD(shstrndx)); 35091618Srie 35100Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) { 35110Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 35120Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 35130Sstevel@tonic-gate EC_XWORD(shstrndx)); 35141618Srie 35151618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) { 35160Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 35170Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 35183862Srie EC_WORD(elf_ndxscn(scn))); 35191618Srie 35209085SAli.Bahrami@Sun.COM } else if ((names = data->d_buf) == NULL) 35210Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 35220Sstevel@tonic-gate 35230Sstevel@tonic-gate /* 35243862Srie * Allocate a cache to maintain a descriptor for each section. 35250Sstevel@tonic-gate */ 35264665Sab196087 if ((*cache_ret = cache = malloc(shnum * sizeof (Cache))) == NULL) { 35270Sstevel@tonic-gate int err = errno; 35280Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 35290Sstevel@tonic-gate file, strerror(err)); 35304665Sab196087 return (0); 35310Sstevel@tonic-gate } 35320Sstevel@tonic-gate 35331618Srie *cache = cache_init; 35340Sstevel@tonic-gate _cache = cache; 35350Sstevel@tonic-gate _cache++; 35360Sstevel@tonic-gate 35373862Srie /* 35384242Sab196087 * Allocate an array that will hold the section index for 35394242Sab196087 * each section that has data in the ELF file: 35404242Sab196087 * 35414242Sab196087 * - Is not a NOBITS section 35424242Sab196087 * - Data has non-zero length 35434242Sab196087 * 35444242Sab196087 * Note that shnum is an upper bound on the size required. It 35454242Sab196087 * is likely that we won't use a few of these array elements. 35464242Sab196087 * Allocating a modest amount of extra memory in this case means 35474242Sab196087 * that we can avoid an extra loop to count the number of needed 35484242Sab196087 * items, and can fill this array immediately in the first loop 35494242Sab196087 * below. 35504242Sab196087 */ 35514242Sab196087 if ((shdr_ndx_arr = malloc(shnum * sizeof (*shdr_ndx_arr))) == NULL) { 35524242Sab196087 int err = errno; 35534242Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 35544242Sab196087 file, strerror(err)); 35554665Sab196087 return (0); 35564242Sab196087 } 35574242Sab196087 shdr_ndx_arr_cnt = 0; 35584242Sab196087 35594242Sab196087 /* 35603862Srie * Traverse the sections of the file. This gathering of data is 35613862Srie * carried out in two passes. First, the section headers are captured 35623862Srie * and the section header names are evaluated. A verification pass is 35633862Srie * then carried out over the section information. Files have been 35643862Srie * known to exhibit overlapping (and hence erroneous) section header 35653862Srie * information. 35663862Srie * 35673862Srie * Finally, the data for each section is obtained. This processing is 35683862Srie * carried out after section verification because should any section 35693862Srie * header overlap occur, and a file needs translating (ie. xlate'ing 35703862Srie * information from a non-native architecture file), then the process 35713862Srie * of translation can corrupt the section header information. Of 35723862Srie * course, if there is any section overlap, the data related to the 35733862Srie * sections is going to be compromised. However, it is the translation 35743862Srie * of this data that has caused problems with elfdump()'s ability to 35753862Srie * extract the data. 35763862Srie */ 35774242Sab196087 for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn); 35784242Sab196087 ndx++, _cache++) { 35793862Srie char scnndxnm[100]; 35803862Srie 35814242Sab196087 _cache->c_ndx = ndx; 35823862Srie _cache->c_scn = scn; 35833862Srie 35841618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) { 35850Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 35860Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 35873862Srie EC_WORD(elf_ndxscn(scn))); 35880Sstevel@tonic-gate } 35890Sstevel@tonic-gate 35903862Srie /* 35914242Sab196087 * If this section has data in the file, include it in 35924242Sab196087 * the array of sections to check for address overlap. 35934242Sab196087 */ 35944242Sab196087 if ((_cache->c_shdr->sh_size != 0) && 35954242Sab196087 (_cache->c_shdr->sh_type != SHT_NOBITS)) 35964242Sab196087 shdr_ndx_arr[shdr_ndx_arr_cnt++] = ndx; 35974242Sab196087 35984242Sab196087 /* 35993862Srie * If a shstrtab exists, assign the section name. 36003862Srie */ 36013862Srie if (names && _cache->c_shdr) { 36023862Srie if (_cache->c_shdr->sh_name && 36033862Srie /* LINTED */ 36043862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) { 36057463SRod.Evans@Sun.COM const char *symname; 36067463SRod.Evans@Sun.COM char *secname; 36077463SRod.Evans@Sun.COM 36087463SRod.Evans@Sun.COM secname = names + _cache->c_shdr->sh_name; 36097463SRod.Evans@Sun.COM 36107463SRod.Evans@Sun.COM /* 36117463SRod.Evans@Sun.COM * A SUN naming convention employs a "%" within 36127463SRod.Evans@Sun.COM * a section name to indicate a section/symbol 36137463SRod.Evans@Sun.COM * name. This originated from the compilers 36147463SRod.Evans@Sun.COM * -xF option, that places functions into their 36157463SRod.Evans@Sun.COM * own sections. This convention (which has no 36167463SRod.Evans@Sun.COM * formal standard) has also been followed for 36177463SRod.Evans@Sun.COM * COMDAT sections. To demangle the symbol 36187463SRod.Evans@Sun.COM * name, the name must be separated from the 36197463SRod.Evans@Sun.COM * section name. 36207463SRod.Evans@Sun.COM */ 36217463SRod.Evans@Sun.COM if (((flags & FLG_CTL_DEMANGLE) == 0) || 36227463SRod.Evans@Sun.COM ((symname = strchr(secname, '%')) == NULL)) 36237463SRod.Evans@Sun.COM _cache->c_name = secname; 36247463SRod.Evans@Sun.COM else { 36257463SRod.Evans@Sun.COM size_t secsz = ++symname - secname; 36267463SRod.Evans@Sun.COM size_t strsz; 36277463SRod.Evans@Sun.COM 36287463SRod.Evans@Sun.COM symname = demangle(symname, flags); 36297463SRod.Evans@Sun.COM strsz = secsz + strlen(symname) + 1; 36307463SRod.Evans@Sun.COM 36317463SRod.Evans@Sun.COM if ((_cache->c_name = 36327463SRod.Evans@Sun.COM malloc(strsz)) == NULL) { 36337463SRod.Evans@Sun.COM int err = errno; 36347463SRod.Evans@Sun.COM (void) fprintf(stderr, 36357463SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_MALLOC), 36367463SRod.Evans@Sun.COM file, strerror(err)); 36377463SRod.Evans@Sun.COM return (0); 36387463SRod.Evans@Sun.COM } 36397463SRod.Evans@Sun.COM (void) snprintf(_cache->c_name, strsz, 36407463SRod.Evans@Sun.COM MSG_ORIG(MSG_FMT_SECSYM), 36417463SRod.Evans@Sun.COM EC_WORD(secsz), secname, symname); 36427463SRod.Evans@Sun.COM } 36439085SAli.Bahrami@Sun.COM 36443862Srie continue; 36453862Srie } 36460Sstevel@tonic-gate 36470Sstevel@tonic-gate /* 36483862Srie * Generate an error if the section name index is zero 36493862Srie * or exceeds the shstrtab data. Fall through to 36503862Srie * fabricate a section name. 36510Sstevel@tonic-gate */ 36523862Srie if ((_cache->c_shdr->sh_name == 0) || 36530Sstevel@tonic-gate /* LINTED */ 36541618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) { 36550Sstevel@tonic-gate (void) fprintf(stderr, 36560Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file, 36574242Sab196087 EC_WORD(ndx), 36581618Srie EC_XWORD(_cache->c_shdr->sh_name)); 36590Sstevel@tonic-gate } 36603862Srie } 36613862Srie 36623862Srie /* 36633862Srie * If there exists no shstrtab data, or a section header has no 36643862Srie * name (an invalid index of 0), then compose a name for the 36653862Srie * section. 36663862Srie */ 36673862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm), 36684242Sab196087 MSG_INTL(MSG_FMT_SCNNDX), ndx); 36694242Sab196087 36704242Sab196087 if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == NULL) { 36713862Srie int err = errno; 36723862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 36733862Srie file, strerror(err)); 36744665Sab196087 return (0); 36753862Srie } 36763862Srie (void) strcpy(_cache->c_name, scnndxnm); 36773862Srie } 36783862Srie 36793862Srie /* 36803862Srie * Having collected all the sections, validate their address range. 36813862Srie * Cases have existed where the section information has been invalid. 36823862Srie * This can lead to all sorts of other, hard to diagnose errors, as 36833862Srie * each section is processed individually (ie. with elf_getdata()). 36843862Srie * Here, we carry out some address comparisons to catch a family of 36853862Srie * overlapping memory issues we have observed (likely, there are others 36863862Srie * that we have yet to discover). 36873862Srie * 36883862Srie * Note, should any memory overlap occur, obtaining any additional 36893862Srie * data from the file is questionable. However, it might still be 36903862Srie * possible to inspect the ELF header, Programs headers, or individual 36913862Srie * sections, so rather than bailing on an error condition, continue 36923862Srie * processing to see if any data can be salvaged. 36933862Srie */ 36944242Sab196087 if (shdr_ndx_arr_cnt > 1) { 36954242Sab196087 sort_shdr_ndx_arr_cache = cache; 36964242Sab196087 qsort(shdr_ndx_arr, shdr_ndx_arr_cnt, 36974242Sab196087 sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr); 36984242Sab196087 } 36994242Sab196087 for (ndx = 0; ndx < shdr_ndx_arr_cnt; ndx++) { 37004242Sab196087 Cache *_cache = cache + shdr_ndx_arr[ndx]; 37013862Srie Shdr *shdr = _cache->c_shdr; 37023862Srie Off bgn1, bgn = shdr->sh_offset; 37033862Srie Off end1, end = shdr->sh_offset + shdr->sh_size; 37044242Sab196087 size_t ndx1; 37054242Sab196087 37064242Sab196087 /* 37074242Sab196087 * Check the section against all following ones, reporting 37084242Sab196087 * any overlaps. Since we've sorted the sections by offset, 37094242Sab196087 * we can stop after the first comparison that fails. There 37104242Sab196087 * are no overlaps in a properly formed ELF file, in which 37114242Sab196087 * case this algorithm runs in O(n) time. This will degenerate 37124242Sab196087 * to O(n^2) for a completely broken file. Such a file is 37134242Sab196087 * (1) highly unlikely, and (2) unusable, so it is reasonable 37144242Sab196087 * for the analysis to take longer. 37154242Sab196087 */ 37164242Sab196087 for (ndx1 = ndx + 1; ndx1 < shdr_ndx_arr_cnt; ndx1++) { 37174242Sab196087 Cache *_cache1 = cache + shdr_ndx_arr[ndx1]; 37183862Srie Shdr *shdr1 = _cache1->c_shdr; 37193862Srie 37203862Srie bgn1 = shdr1->sh_offset; 37213862Srie end1 = shdr1->sh_offset + shdr1->sh_size; 37223862Srie 37233862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 37243862Srie ((bgn1 < end) && (end1 >= end))) { 37253862Srie (void) fprintf(stderr, 37263862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file, 37274242Sab196087 EC_WORD(elf_ndxscn(_cache->c_scn)), 37284242Sab196087 _cache->c_name, EC_OFF(bgn), EC_OFF(end), 37293862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)), 37304242Sab196087 _cache1->c_name, EC_OFF(bgn1), 37314242Sab196087 EC_OFF(end1)); 37324242Sab196087 } else { /* No overlap, so can stop */ 37334242Sab196087 break; 37340Sstevel@tonic-gate } 37350Sstevel@tonic-gate } 37360Sstevel@tonic-gate 37373862Srie /* 37384242Sab196087 * In addition to checking for sections overlapping 37394242Sab196087 * each other (done above), we should also make sure 37404242Sab196087 * the section doesn't overlap the section header array. 37413862Srie */ 37423862Srie bgn1 = ehdr->e_shoff; 37433862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum); 37443862Srie 37453862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 37463862Srie ((bgn1 < end) && (end1 >= end))) { 37473862Srie (void) fprintf(stderr, 37483862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1), 37493862Srie EC_OFF(end1), 37503862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 37513862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 37523862Srie } 37533862Srie } 37543862Srie 37553862Srie /* 37564242Sab196087 * Obtain the data for each section. 37573862Srie */ 37584242Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 37594242Sab196087 Cache *_cache = &cache[ndx]; 37603862Srie Elf_Scn *scn = _cache->c_scn; 37613862Srie 37620Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 37630Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 37640Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 37653862Srie EC_WORD(elf_ndxscn(scn))); 37660Sstevel@tonic-gate } 37678747SAli.Bahrami@Sun.COM 37688747SAli.Bahrami@Sun.COM /* 37698747SAli.Bahrami@Sun.COM * If a string table, verify that it has NULL first and 37708747SAli.Bahrami@Sun.COM * final bytes. 37718747SAli.Bahrami@Sun.COM */ 37728747SAli.Bahrami@Sun.COM if ((_cache->c_shdr->sh_type == SHT_STRTAB) && 37738747SAli.Bahrami@Sun.COM (_cache->c_data->d_buf != NULL) && 37748747SAli.Bahrami@Sun.COM (_cache->c_data->d_size > 0)) { 37758747SAli.Bahrami@Sun.COM const char *s = _cache->c_data->d_buf; 37768747SAli.Bahrami@Sun.COM 37778747SAli.Bahrami@Sun.COM if ((*s != '\0') || 37788747SAli.Bahrami@Sun.COM (*(s + _cache->c_data->d_size - 1) != '\0')) 37798747SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALSTR), 37808747SAli.Bahrami@Sun.COM file, _cache->c_name); 37818747SAli.Bahrami@Sun.COM } 37824665Sab196087 } 37834665Sab196087 37844665Sab196087 return (1); 37854665Sab196087 } 37864665Sab196087 37874665Sab196087 37884665Sab196087 37895411Sab196087 int 37905411Sab196087 regular(const char *file, int fd, Elf *elf, uint_t flags, 37915411Sab196087 const char *wname, int wfd) 37924665Sab196087 { 37934665Sab196087 Elf_Scn *scn; 37944665Sab196087 Ehdr *ehdr; 37954665Sab196087 size_t ndx, shstrndx, shnum, phnum; 37964665Sab196087 Shdr *shdr; 37974665Sab196087 Cache *cache; 37984665Sab196087 VERSYM_STATE versym; 37995411Sab196087 int ret = 0; 38005411Sab196087 int addr_align; 38014665Sab196087 38024665Sab196087 if ((ehdr = elf_getehdr(elf)) == NULL) { 38034665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 38045411Sab196087 return (ret); 38054665Sab196087 } 38064665Sab196087 38074665Sab196087 if (elf_getshnum(elf, &shnum) == 0) { 38084665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 38095411Sab196087 return (ret); 38104665Sab196087 } 38114665Sab196087 38124665Sab196087 if (elf_getshstrndx(elf, &shstrndx) == 0) { 38134665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 38145411Sab196087 return (ret); 38154665Sab196087 } 38164665Sab196087 38174665Sab196087 if (elf_getphnum(elf, &phnum) == 0) { 38184665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 38195411Sab196087 return (ret); 38204665Sab196087 } 38214665Sab196087 /* 38224665Sab196087 * If the user requested section headers derived from the 38234665Sab196087 * program headers (-P option) and this file doesn't have 38244665Sab196087 * any program headers (i.e. ET_REL), then we can't do it. 38254665Sab196087 */ 38265411Sab196087 if ((phnum == 0) && (flags & FLG_CTL_FAKESHDR)) { 38274665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_PNEEDSPH), file); 38285411Sab196087 return (ret); 38294665Sab196087 } 38304665Sab196087 38314665Sab196087 38324665Sab196087 if ((scn = elf_getscn(elf, 0)) != NULL) { 38334665Sab196087 if ((shdr = elf_getshdr(scn)) == NULL) { 38344665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 38354665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 38365411Sab196087 return (ret); 38374665Sab196087 } 38384665Sab196087 } else 38399085SAli.Bahrami@Sun.COM shdr = NULL; 38404665Sab196087 38414665Sab196087 /* 38424665Sab196087 * Print the elf header. 38434665Sab196087 */ 38445411Sab196087 if (flags & FLG_SHOW_EHDR) 38454665Sab196087 Elf_ehdr(0, ehdr, shdr); 38464665Sab196087 38474665Sab196087 /* 38484665Sab196087 * If the section headers or program headers have inadequate 38494665Sab196087 * alignment for the class of object, print a warning. libelf 38504665Sab196087 * can handle such files, but programs that use them can crash 38514665Sab196087 * when they dereference unaligned items. 38525411Sab196087 * 38535411Sab196087 * Note that the AMD64 ABI, although it is a 64-bit architecture, 38545411Sab196087 * allows access to data types smaller than 128-bits to be on 38555411Sab196087 * word alignment. 38564665Sab196087 */ 38575411Sab196087 if (ehdr->e_machine == EM_AMD64) 38585411Sab196087 addr_align = sizeof (Word); 38595411Sab196087 else 38605411Sab196087 addr_align = sizeof (Addr); 38615411Sab196087 38625411Sab196087 if (ehdr->e_phoff & (addr_align - 1)) 38634665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADPHDRALIGN), file); 38645411Sab196087 if (ehdr->e_shoff & (addr_align - 1)) 38654665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHDRALIGN), file); 38664665Sab196087 38674665Sab196087 /* 38684665Sab196087 * Print the program headers. 38694665Sab196087 */ 38705411Sab196087 if ((flags & FLG_SHOW_PHDR) && (phnum != 0)) { 38715411Sab196087 Phdr *phdr; 38724665Sab196087 38734665Sab196087 if ((phdr = elf_getphdr(elf)) == NULL) { 38744665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 38755411Sab196087 return (ret); 38764665Sab196087 } 38774665Sab196087 38784665Sab196087 for (ndx = 0; ndx < phnum; phdr++, ndx++) { 38795411Sab196087 if (!match(MATCH_F_PHDR| MATCH_F_NDX | MATCH_F_TYPE, 38805411Sab196087 NULL, ndx, phdr->p_type)) 38814665Sab196087 continue; 38824665Sab196087 38834665Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 38844665Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx)); 38854665Sab196087 Elf_phdr(0, ehdr->e_machine, phdr); 38864665Sab196087 } 38874665Sab196087 } 38884665Sab196087 38894665Sab196087 /* 38905411Sab196087 * If we have flag bits set that explicitly require a show or calc 38915411Sab196087 * operation, but none of them require the section headers, then 38925411Sab196087 * we are done and can return now. 38934665Sab196087 */ 38945411Sab196087 if (((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) != 0) && 38955411Sab196087 ((flags & (FLG_MASK_SHOW_SHDR | FLG_MASK_CALC_SHDR)) == 0)) 38965411Sab196087 return (ret); 38975411Sab196087 38985411Sab196087 /* 38995411Sab196087 * If there are no section headers, then resort to synthesizing 39005411Sab196087 * section headers from the program headers. This is normally 39015411Sab196087 * only done by explicit request, but in this case there's no 39025411Sab196087 * reason not to go ahead, since the alternative is simply to quit. 39035411Sab196087 */ 39045411Sab196087 if ((shnum <= 1) && ((flags & FLG_CTL_FAKESHDR) == 0)) { 39055411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHDR), file); 39065411Sab196087 flags |= FLG_CTL_FAKESHDR; 39074665Sab196087 } 39084665Sab196087 39094665Sab196087 /* 39104665Sab196087 * Generate a cache of section headers and related information 39114665Sab196087 * for use by the rest of elfdump. If requested (or the file 39124665Sab196087 * contains no section headers), we generate a fake set of 39134665Sab196087 * headers from the information accessible from the program headers. 39144665Sab196087 * Otherwise, we use the real section headers contained in the file. 39154665Sab196087 */ 39164665Sab196087 39175411Sab196087 if (flags & FLG_CTL_FAKESHDR) { 39184665Sab196087 if (fake_shdr_cache(file, fd, elf, ehdr, &cache, &shnum) == 0) 39195411Sab196087 return (ret); 39204665Sab196087 } else { 39217463SRod.Evans@Sun.COM if (shdr_cache(file, elf, ehdr, shstrndx, shnum, 39227463SRod.Evans@Sun.COM &cache, flags) == 0) 39235411Sab196087 return (ret); 39244665Sab196087 } 39254665Sab196087 39264665Sab196087 /* 39275411Sab196087 * Everything from this point on requires section headers. 39285411Sab196087 * If we have no section headers, there is no reason to continue. 39295411Sab196087 */ 39305411Sab196087 if (shnum <= 1) 39315411Sab196087 goto done; 39325411Sab196087 39335411Sab196087 /* 39344665Sab196087 * If -w was specified, find and write out the section(s) data. 39354665Sab196087 */ 39364665Sab196087 if (wfd) { 39374665Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 39384665Sab196087 Cache *_cache = &cache[ndx]; 39394665Sab196087 39405411Sab196087 if (match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 39415411Sab196087 ndx, _cache->c_shdr->sh_type) && 39425411Sab196087 _cache->c_data && _cache->c_data->d_buf) { 39435411Sab196087 if (write(wfd, _cache->c_data->d_buf, 39445411Sab196087 _cache->c_data->d_size) != 39455411Sab196087 _cache->c_data->d_size) { 39465411Sab196087 int err = errno; 39475411Sab196087 (void) fprintf(stderr, 39485411Sab196087 MSG_INTL(MSG_ERR_WRITE), wname, 39495411Sab196087 strerror(err)); 39505411Sab196087 /* 39515411Sab196087 * Return an exit status of 1, because 39525411Sab196087 * the failure is not related to the 39535411Sab196087 * ELF file, but by system resources. 39545411Sab196087 */ 39555411Sab196087 ret = 1; 39565411Sab196087 goto done; 39575411Sab196087 } 39584665Sab196087 } 39590Sstevel@tonic-gate } 39600Sstevel@tonic-gate } 39610Sstevel@tonic-gate 39625411Sab196087 /* 39635411Sab196087 * If we have no flag bits set that explicitly require a show or calc 39645411Sab196087 * operation, but match options (-I, -N, -T) were used, then run 39655411Sab196087 * through the section headers and see if we can't deduce show flags 39665411Sab196087 * from the match options given. 39675411Sab196087 * 39685411Sab196087 * We don't do this if -w was specified, because (-I, -N, -T) used 39695411Sab196087 * with -w in lieu of some other option is supposed to be quiet. 39705411Sab196087 */ 39715411Sab196087 if ((wfd == 0) && (flags & FLG_CTL_MATCH) && 39725411Sab196087 ((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) == 0)) { 39735411Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 39745411Sab196087 Cache *_cache = &cache[ndx]; 39755411Sab196087 39765411Sab196087 if (!match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 39775411Sab196087 ndx, _cache->c_shdr->sh_type)) 39785411Sab196087 continue; 39795411Sab196087 39805411Sab196087 switch (_cache->c_shdr->sh_type) { 39815411Sab196087 case SHT_PROGBITS: 39825411Sab196087 /* 39835411Sab196087 * Heuristic time: It is usually bad form 39849085SAli.Bahrami@Sun.COM * to assume the meaning/format of a PROGBITS 39859085SAli.Bahrami@Sun.COM * section based on its name. However, there 39869085SAli.Bahrami@Sun.COM * are exceptions: The ELF ABI specifies 39879085SAli.Bahrami@Sun.COM * .interp and .got sections by name. Existing 39889085SAli.Bahrami@Sun.COM * practice has similarly pinned down the 39899085SAli.Bahrami@Sun.COM * meaning of unwind sections (.eh_frame and 39909085SAli.Bahrami@Sun.COM * .eh_frame_hdr). 39919085SAli.Bahrami@Sun.COM * 39929085SAli.Bahrami@Sun.COM * Check for these special names. 39935411Sab196087 */ 39945411Sab196087 if (strcmp(_cache->c_name, 39955411Sab196087 MSG_ORIG(MSG_ELF_INTERP)) == 0) 39965411Sab196087 flags |= FLG_SHOW_INTERP; 39975411Sab196087 else if (strcmp(_cache->c_name, 39985411Sab196087 MSG_ORIG(MSG_ELF_GOT)) == 0) 39995411Sab196087 flags |= FLG_SHOW_GOT; 40009085SAli.Bahrami@Sun.COM else if (strncmp(_cache->c_name, 40019085SAli.Bahrami@Sun.COM MSG_ORIG(MSG_SCN_FRM), 40029085SAli.Bahrami@Sun.COM MSG_SCN_FRM_SIZE) == 0) 40039085SAli.Bahrami@Sun.COM flags |= FLG_SHOW_UNWIND; 40045411Sab196087 break; 40055411Sab196087 40065411Sab196087 case SHT_SYMTAB: 40075411Sab196087 case SHT_DYNSYM: 40085411Sab196087 case SHT_SUNW_LDYNSYM: 40095411Sab196087 case SHT_SUNW_versym: 40105411Sab196087 case SHT_SYMTAB_SHNDX: 40115411Sab196087 flags |= FLG_SHOW_SYMBOLS; 40125411Sab196087 break; 40135411Sab196087 40145411Sab196087 case SHT_RELA: 40155411Sab196087 case SHT_REL: 40165411Sab196087 flags |= FLG_SHOW_RELOC; 40175411Sab196087 break; 40185411Sab196087 40195411Sab196087 case SHT_HASH: 40205411Sab196087 flags |= FLG_SHOW_HASH; 40215411Sab196087 break; 40225411Sab196087 40235411Sab196087 case SHT_DYNAMIC: 40245411Sab196087 flags |= FLG_SHOW_DYNAMIC; 40255411Sab196087 break; 40265411Sab196087 40275411Sab196087 case SHT_NOTE: 40285411Sab196087 flags |= FLG_SHOW_NOTE; 40295411Sab196087 break; 40305411Sab196087 40315411Sab196087 case SHT_GROUP: 40325411Sab196087 flags |= FLG_SHOW_GROUP; 40335411Sab196087 break; 40345411Sab196087 40355411Sab196087 case SHT_SUNW_symsort: 40365411Sab196087 case SHT_SUNW_tlssort: 40375411Sab196087 flags |= FLG_SHOW_SORT; 40385411Sab196087 break; 40395411Sab196087 40405411Sab196087 case SHT_SUNW_cap: 40415411Sab196087 flags |= FLG_SHOW_CAP; 40425411Sab196087 break; 40435411Sab196087 40445411Sab196087 case SHT_SUNW_move: 40455411Sab196087 flags |= FLG_SHOW_MOVE; 40465411Sab196087 break; 40475411Sab196087 40485411Sab196087 case SHT_SUNW_syminfo: 40495411Sab196087 flags |= FLG_SHOW_SYMINFO; 40505411Sab196087 break; 40515411Sab196087 40525411Sab196087 case SHT_SUNW_verdef: 40535411Sab196087 case SHT_SUNW_verneed: 40545411Sab196087 flags |= FLG_SHOW_VERSIONS; 40555411Sab196087 break; 40565411Sab196087 40575411Sab196087 case SHT_AMD64_UNWIND: 40585411Sab196087 flags |= FLG_SHOW_UNWIND; 40595411Sab196087 break; 40605411Sab196087 } 40615411Sab196087 } 40625411Sab196087 } 40635411Sab196087 40645411Sab196087 40655411Sab196087 if (flags & FLG_SHOW_SHDR) 40664168Sab196087 sections(file, cache, shnum, ehdr); 40670Sstevel@tonic-gate 40685411Sab196087 if (flags & FLG_SHOW_INTERP) 40691618Srie interp(file, cache, shnum, phnum, elf); 40700Sstevel@tonic-gate 40713875Sab196087 versions(cache, shnum, file, flags, &versym); 40720Sstevel@tonic-gate 40735411Sab196087 if (flags & FLG_SHOW_SYMBOLS) 40744168Sab196087 symbols(cache, shnum, ehdr, &versym, file, flags); 40750Sstevel@tonic-gate 40765411Sab196087 if (flags & FLG_SHOW_SORT) 40774168Sab196087 sunw_sort(cache, shnum, ehdr, &versym, file, flags); 40783492Sab196087 40795411Sab196087 if (flags & FLG_SHOW_HASH) 40804168Sab196087 hash(cache, shnum, file, flags); 40810Sstevel@tonic-gate 40825411Sab196087 if (flags & FLG_SHOW_GOT) 40837463SRod.Evans@Sun.COM got(cache, shnum, ehdr, file); 40840Sstevel@tonic-gate 40855411Sab196087 if (flags & FLG_SHOW_GROUP) 40864168Sab196087 group(cache, shnum, file, flags); 40870Sstevel@tonic-gate 40885411Sab196087 if (flags & FLG_SHOW_SYMINFO) 40890Sstevel@tonic-gate syminfo(cache, shnum, file); 40900Sstevel@tonic-gate 40915411Sab196087 if (flags & FLG_SHOW_RELOC) 40927463SRod.Evans@Sun.COM reloc(cache, shnum, ehdr, file); 40930Sstevel@tonic-gate 40945411Sab196087 if (flags & FLG_SHOW_DYNAMIC) 40951618Srie dynamic(cache, shnum, ehdr, file); 40960Sstevel@tonic-gate 40976635Sab196087 if (flags & FLG_SHOW_NOTE) { 40986635Sab196087 Word note_cnt; 40996635Sab196087 size_t note_shnum; 41006635Sab196087 Cache *note_cache; 41016635Sab196087 41026635Sab196087 note_cnt = note(cache, shnum, ehdr, file); 41036635Sab196087 41046635Sab196087 /* 41056635Sab196087 * Solaris core files have section headers, but these 41066635Sab196087 * headers do not include SHT_NOTE sections that reference 41076635Sab196087 * the core note sections. This means that note() won't 41086635Sab196087 * find the core notes. Fake section headers (-P option) 41096635Sab196087 * recover these sections, but it is inconvenient to require 41106635Sab196087 * users to specify -P in this situation. If the following 41116635Sab196087 * are all true: 41126635Sab196087 * 41136635Sab196087 * - No note sections were found 41146635Sab196087 * - This is a core file 41156635Sab196087 * - We are not already using fake section headers 41166635Sab196087 * 41176635Sab196087 * then we will automatically generate fake section headers 41186635Sab196087 * and then process them in a second call to note(). 41196635Sab196087 */ 41206635Sab196087 if ((note_cnt == 0) && (ehdr->e_type == ET_CORE) && 41216635Sab196087 !(flags & FLG_CTL_FAKESHDR) && 41226635Sab196087 (fake_shdr_cache(file, fd, elf, ehdr, 41236635Sab196087 ¬e_cache, ¬e_shnum) != 0)) { 41246635Sab196087 (void) note(note_cache, note_shnum, ehdr, file); 41256635Sab196087 fake_shdr_cache_free(note_cache, note_shnum); 41266635Sab196087 } 41276635Sab196087 } 41280Sstevel@tonic-gate 41295411Sab196087 if (flags & FLG_SHOW_MOVE) 41304168Sab196087 move(cache, shnum, file, flags); 41310Sstevel@tonic-gate 41325411Sab196087 if (flags & FLG_CALC_CHECKSUM) 41330Sstevel@tonic-gate checksum(elf); 41340Sstevel@tonic-gate 41355411Sab196087 if (flags & FLG_SHOW_CAP) 41361618Srie cap(file, cache, shnum, phnum, ehdr, elf); 41370Sstevel@tonic-gate 41385411Sab196087 if (flags & FLG_SHOW_UNWIND) 4139*9131SRod.Evans@Sun.COM unwind(cache, shnum, phnum, ehdr, file, elf, flags); 41400Sstevel@tonic-gate 41414665Sab196087 41424665Sab196087 /* Release the memory used to cache section headers */ 41435411Sab196087 done: 41445411Sab196087 if (flags & FLG_CTL_FAKESHDR) 41454665Sab196087 fake_shdr_cache_free(cache, shnum); 41464665Sab196087 else 41474665Sab196087 free(cache); 41485411Sab196087 41495411Sab196087 return (ret); 41500Sstevel@tonic-gate } 4151