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 */ 30*9406SAli.Bahrami@Sun.COM #include <stddef.h> 311618Srie #include <sys/elf_386.h> 321618Srie #include <sys/elf_amd64.h> 331618Srie #include <sys/elf_SPARC.h> 346206Sab196087 #include <_libelf.h> 351618Srie #include <dwarf.h> 365549Srie #include <stdio.h> 370Sstevel@tonic-gate #include <unistd.h> 380Sstevel@tonic-gate #include <errno.h> 390Sstevel@tonic-gate #include <strings.h> 400Sstevel@tonic-gate #include <debug.h> 410Sstevel@tonic-gate #include <conv.h> 420Sstevel@tonic-gate #include <msg.h> 431618Srie #include <_elfdump.h> 440Sstevel@tonic-gate 453875Sab196087 463875Sab196087 /* 473875Sab196087 * VERSYM_STATE is used to maintain information about the VERSYM section 483875Sab196087 * in the object being analyzed. It is filled in by versions(), and used 493875Sab196087 * by init_symtbl_state() when displaying symbol information. 503875Sab196087 * 517682SAli.Bahrami@Sun.COM * There are three forms of symbol versioning known to us: 527682SAli.Bahrami@Sun.COM * 537682SAli.Bahrami@Sun.COM * 1) The original form, introduced with Solaris 2.5, in which 547682SAli.Bahrami@Sun.COM * the Versym contains indexes to Verdef records, and the 557682SAli.Bahrami@Sun.COM * Versym values for UNDEF symbols resolved by other objects 567682SAli.Bahrami@Sun.COM * are all set to 0. 577682SAli.Bahrami@Sun.COM * 2) The GNU form, which is backward compatible with the original 587682SAli.Bahrami@Sun.COM * Solaris form, but which adds several extensions: 597682SAli.Bahrami@Sun.COM * - The Versym also contains indexes to Verneed records, recording 607682SAli.Bahrami@Sun.COM * which object/version contributed the external symbol at 617682SAli.Bahrami@Sun.COM * link time. These indexes start with the next value following 627682SAli.Bahrami@Sun.COM * the final Verdef index. The index is written to the previously 637682SAli.Bahrami@Sun.COM * reserved vna_other field of the ELF Vernaux structure. 647682SAli.Bahrami@Sun.COM * - The top bit of the Versym value is no longer part of the index, 657682SAli.Bahrami@Sun.COM * but is used as a "hidden bit" to prevent binding to the symbol. 667682SAli.Bahrami@Sun.COM * - Multiple implementations of a given symbol, contained in varying 677682SAli.Bahrami@Sun.COM * versions are allowed, using special assembler pseudo ops, 687682SAli.Bahrami@Sun.COM * and encoded in the symbol name using '@' characters. 697682SAli.Bahrami@Sun.COM * 3) Modified Solaris form, in which we adopt the first GNU extension 707682SAli.Bahrami@Sun.COM * (Versym indexes to Verneed records), but not the others. 717682SAli.Bahrami@Sun.COM * 727682SAli.Bahrami@Sun.COM * elfdump can handle any of these cases. The presence of a DT_VERSYM 737682SAli.Bahrami@Sun.COM * dynamic element indicates a full GNU object. An object that lacks 747682SAli.Bahrami@Sun.COM * a DT_VERSYM entry, but which has non-zero vna_other fields in the Vernaux 757682SAli.Bahrami@Sun.COM * structures is a modified Solaris object. An object that has neither of 767682SAli.Bahrami@Sun.COM * these uses the original form. 777682SAli.Bahrami@Sun.COM * 784716Sab196087 * max_verndx contains the largest version index that can appear 794716Sab196087 * in a Versym entry. This can never be less than 1: In the case where 804716Sab196087 * there is no verdef/verneed sections, the [0] index is reserved 817682SAli.Bahrami@Sun.COM * for local symbols, and the [1] index for globals. If the original 827682SAli.Bahrami@Sun.COM * Solaris versioning rules are in effect and there is a verdef section, 837682SAli.Bahrami@Sun.COM * then max_verndex is the number of defined versions. If one of the 847682SAli.Bahrami@Sun.COM * other versioning forms is in effect, then: 857682SAli.Bahrami@Sun.COM * 1) If there is no verneed section, it is the same as for 867682SAli.Bahrami@Sun.COM * original Solaris versioning. 877682SAli.Bahrami@Sun.COM * 2) If there is a verneed section, the vna_other field of the 884716Sab196087 * Vernaux structs contain versions, and max_verndx is the 894716Sab196087 * largest such index. 904716Sab196087 * 917682SAli.Bahrami@Sun.COM * If gnu_full is True, the object uses the full GNU form of versioning. 927682SAli.Bahrami@Sun.COM * The value of the gnu_full field is based on the presence of 934716Sab196087 * a DT_VERSYM entry in the dynamic section: GNU ld produces these, and 944716Sab196087 * Solaris ld does not. 957682SAli.Bahrami@Sun.COM * 967682SAli.Bahrami@Sun.COM * The gnu_needed field is True if the Versym contains indexes to 977682SAli.Bahrami@Sun.COM * Verneed records, as indicated by non-zero vna_other fields in the Verneed 987682SAli.Bahrami@Sun.COM * section. If gnu_full is True, then gnu_needed will always be true. 997682SAli.Bahrami@Sun.COM * However, gnu_needed can be true without gnu_full. This is the modified 1007682SAli.Bahrami@Sun.COM * Solaris form. 1013875Sab196087 */ 1023875Sab196087 typedef struct { 1033875Sab196087 Cache *cache; /* Pointer to cache entry for VERSYM */ 1043875Sab196087 Versym *data; /* Pointer to versym array */ 1057682SAli.Bahrami@Sun.COM int gnu_full; /* True if object uses GNU versioning rules */ 1067682SAli.Bahrami@Sun.COM int gnu_needed; /* True if object uses VERSYM indexes for */ 1077682SAli.Bahrami@Sun.COM /* VERNEED (subset of gnu_full) */ 1084716Sab196087 int max_verndx; /* largest versym index value */ 1093875Sab196087 } VERSYM_STATE; 1103875Sab196087 1113875Sab196087 /* 1123875Sab196087 * SYMTBL_STATE is used to maintain information about a single symbol 1133875Sab196087 * table section, for use by the routines that display symbol information. 1143875Sab196087 */ 1153875Sab196087 typedef struct { 1163875Sab196087 const char *file; /* Name of file */ 1173875Sab196087 Ehdr *ehdr; /* ELF header for file */ 1183875Sab196087 Cache *cache; /* Cache of all section headers */ 1199273SAli.Bahrami@Sun.COM uchar_t osabi; /* OSABI to use */ 1203875Sab196087 Word shnum; /* # of sections in cache */ 1213875Sab196087 Cache *seccache; /* Cache of symbol table section hdr */ 1223875Sab196087 Word secndx; /* Index of symbol table section hdr */ 1233875Sab196087 const char *secname; /* Name of section */ 1243875Sab196087 uint_t flags; /* Command line option flags */ 1253875Sab196087 struct { /* Extended section index data */ 1263875Sab196087 int checked; /* TRUE if already checked for shxndx */ 1273875Sab196087 Word *data; /* NULL, or extended section index */ 1283875Sab196087 /* used for symbol table entries */ 1293875Sab196087 uint_t n; /* # items in shxndx.data */ 1303875Sab196087 } shxndx; 1313875Sab196087 VERSYM_STATE *versym; /* NULL, or associated VERSYM section */ 1323875Sab196087 Sym *sym; /* Array of symbols */ 1333875Sab196087 Word symn; /* # of symbols */ 1343875Sab196087 } SYMTBL_STATE; 1353875Sab196087 136*9406SAli.Bahrami@Sun.COM /* 137*9406SAli.Bahrami@Sun.COM * A variable of this type is used to track information related to 138*9406SAli.Bahrami@Sun.COM * .eh_frame and .eh_frame_hdr sections across calls to unwind_eh_frame(). 139*9406SAli.Bahrami@Sun.COM */ 140*9406SAli.Bahrami@Sun.COM typedef struct { 141*9406SAli.Bahrami@Sun.COM Word frame_cnt; /* # .eh_frame sections seen */ 142*9406SAli.Bahrami@Sun.COM Word frame_ndx; /* Section index of 1st .eh_frame */ 143*9406SAli.Bahrami@Sun.COM Word hdr_cnt; /* # .eh_frame_hdr sections seen */ 144*9406SAli.Bahrami@Sun.COM Word hdr_ndx; /* Section index of 1st .eh_frame_hdr */ 145*9406SAli.Bahrami@Sun.COM uint64_t frame_ptr; /* Value of FramePtr field from first */ 146*9406SAli.Bahrami@Sun.COM /* .eh_frame_hdr section */ 147*9406SAli.Bahrami@Sun.COM uint64_t frame_base; /* Data addr of 1st .eh_frame */ 148*9406SAli.Bahrami@Sun.COM } gnu_eh_state_t; 149*9406SAli.Bahrami@Sun.COM 150*9406SAli.Bahrami@Sun.COM /* 151*9406SAli.Bahrami@Sun.COM * C++ .exception_ranges entries make use of the signed ptrdiff_t 152*9406SAli.Bahrami@Sun.COM * type to record self-relative pointer values. We need a type 153*9406SAli.Bahrami@Sun.COM * for this that is matched to the ELFCLASS being processed. 154*9406SAli.Bahrami@Sun.COM */ 155*9406SAli.Bahrami@Sun.COM #if defined(_ELF64) 156*9406SAli.Bahrami@Sun.COM typedef int64_t PTRDIFF_T; 157*9406SAli.Bahrami@Sun.COM #else 158*9406SAli.Bahrami@Sun.COM typedef int32_t PTRDIFF_T; 159*9406SAli.Bahrami@Sun.COM #endif 160*9406SAli.Bahrami@Sun.COM 161*9406SAli.Bahrami@Sun.COM /* 162*9406SAli.Bahrami@Sun.COM * The Sun C++ ABI uses this struct to define each .exception_ranges 163*9406SAli.Bahrami@Sun.COM * entry. From the ABI: 164*9406SAli.Bahrami@Sun.COM * 165*9406SAli.Bahrami@Sun.COM * The field ret_addr is a self relative pointer to the start of the address 166*9406SAli.Bahrami@Sun.COM * range. The name was chosen because in the current implementation the range 167*9406SAli.Bahrami@Sun.COM * typically starts at the return address for a call site. 168*9406SAli.Bahrami@Sun.COM * 169*9406SAli.Bahrami@Sun.COM * The field length is the difference, in bytes, between the pc of the last 170*9406SAli.Bahrami@Sun.COM * instruction covered by the exception range and the first. When only a 171*9406SAli.Bahrami@Sun.COM * single call site is represented without optimization, this will equal zero. 172*9406SAli.Bahrami@Sun.COM * 173*9406SAli.Bahrami@Sun.COM * The field handler_addr is a relative pointer which stores the difference 174*9406SAli.Bahrami@Sun.COM * between the start of the exception range and the address of all code to 175*9406SAli.Bahrami@Sun.COM * catch exceptions and perform the cleanup for stack unwinding. 176*9406SAli.Bahrami@Sun.COM * 177*9406SAli.Bahrami@Sun.COM * The field type_block is a relative pointer which stores the difference 178*9406SAli.Bahrami@Sun.COM * between the start of the exception range and the address of an array used 179*9406SAli.Bahrami@Sun.COM * for storing a list of the types of exceptions which can be caught within 180*9406SAli.Bahrami@Sun.COM * the exception range. 181*9406SAli.Bahrami@Sun.COM */ 182*9406SAli.Bahrami@Sun.COM typedef struct { 183*9406SAli.Bahrami@Sun.COM PTRDIFF_T ret_addr; 184*9406SAli.Bahrami@Sun.COM Xword length; 185*9406SAli.Bahrami@Sun.COM PTRDIFF_T handler_addr; 186*9406SAli.Bahrami@Sun.COM PTRDIFF_T type_block; 187*9406SAli.Bahrami@Sun.COM Xword reserved; 188*9406SAli.Bahrami@Sun.COM } exception_range_entry; 1893875Sab196087 1900Sstevel@tonic-gate /* 1910Sstevel@tonic-gate * Focal point for verifying symbol names. 1920Sstevel@tonic-gate */ 1930Sstevel@tonic-gate static const char * 1941618Srie string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name) 1950Sstevel@tonic-gate { 1964063Sab196087 /* 1974063Sab196087 * If an error in this routine is due to a property of the string 1984063Sab196087 * section, as opposed to a bad offset into the section (a property of 1994063Sab196087 * the referencing section), then we will detect the same error on 2004063Sab196087 * every call involving those sections. We use these static variables 2014063Sab196087 * to retain the information needed to only issue each such error once. 2024063Sab196087 */ 2034063Sab196087 static Cache *last_refsec; /* Last referencing section seen */ 2044063Sab196087 static int strsec_err; /* True if error issued */ 2054063Sab196087 2063492Sab196087 const char *strs; 2073492Sab196087 Word strn; 2080Sstevel@tonic-gate 2093466Srie if (strsec->c_data == NULL) 2103466Srie return (NULL); 2113466Srie 2123492Sab196087 strs = (char *)strsec->c_data->d_buf; 2133492Sab196087 strn = strsec->c_data->d_size; 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate /* 2164063Sab196087 * We only print a diagnostic regarding a bad string table once per 2174063Sab196087 * input section being processed. If the refsec has changed, reset 2184063Sab196087 * our retained error state. 2190Sstevel@tonic-gate */ 2204063Sab196087 if (last_refsec != refsec) { 2214063Sab196087 last_refsec = refsec; 2224063Sab196087 strsec_err = 0; 2234063Sab196087 } 2244063Sab196087 2254063Sab196087 /* Verify that strsec really is a string table */ 2264063Sab196087 if (strsec->c_shdr->sh_type != SHT_STRTAB) { 2274063Sab196087 if (!strsec_err) { 2284063Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOTSTRTAB), 2294063Sab196087 file, strsec->c_ndx, refsec->c_ndx); 2304063Sab196087 strsec_err = 1; 2314063Sab196087 } 2324063Sab196087 return (MSG_INTL(MSG_STR_UNKNOWN)); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * Is the string table offset within range of the available strings? 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate if (name >= strn) { 2390Sstevel@tonic-gate /* 2400Sstevel@tonic-gate * Do we have a empty string table? 2410Sstevel@tonic-gate */ 2429085SAli.Bahrami@Sun.COM if (strs == NULL) { 2434063Sab196087 if (!strsec_err) { 2440Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2450Sstevel@tonic-gate file, strsec->c_name); 2464063Sab196087 strsec_err = 1; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate } else { 2490Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF), 2501618Srie file, refsec->c_name, EC_WORD(ndx), strsec->c_name, 2511618Srie EC_WORD(name), EC_WORD(strn - 1)); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate /* 2550Sstevel@tonic-gate * Return the empty string so that the calling function can 2560Sstevel@tonic-gate * continue it's output diagnostics. 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate return (MSG_INTL(MSG_STR_UNKNOWN)); 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate return (strs + name); 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate /* 2641618Srie * Relocations can reference section symbols and standard symbols. If the 2651618Srie * former, establish the section name. 2661618Srie */ 2671618Srie static const char * 2681618Srie relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum, 2697463SRod.Evans@Sun.COM Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file) 2701618Srie { 2717463SRod.Evans@Sun.COM Sym *sym; 2727463SRod.Evans@Sun.COM const char *name; 2731618Srie 2741618Srie if (symndx >= symnum) { 2751618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX), 2761618Srie file, EC_WORD(symndx), EC_WORD(relndx)); 2771618Srie return (MSG_INTL(MSG_STR_UNKNOWN)); 2781618Srie } 2791618Srie 2801618Srie sym = (Sym *)(syms + symndx); 2817463SRod.Evans@Sun.COM name = string(csec, symndx, strsec, file, sym->st_name); 2821618Srie 2831618Srie /* 2841618Srie * If the symbol represents a section offset construct an appropriate 2857463SRod.Evans@Sun.COM * string. Note, although section symbol table entries typically have 2867463SRod.Evans@Sun.COM * a NULL name pointer, entries do exist that point into the string 2877463SRod.Evans@Sun.COM * table to their own NULL strings. 2881618Srie */ 2897463SRod.Evans@Sun.COM if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) && 2907463SRod.Evans@Sun.COM ((sym->st_name == 0) || (*name == '\0'))) { 2917463SRod.Evans@Sun.COM (void) snprintf(secstr, secsz, MSG_INTL(MSG_STR_SECTION), 2927463SRod.Evans@Sun.COM cache[sym->st_shndx].c_name); 2931618Srie return ((const char *)secstr); 2941618Srie } 2951618Srie 2967463SRod.Evans@Sun.COM return (name); 2971618Srie } 2981618Srie 2991618Srie /* 3001618Srie * Focal point for establishing a string table section. Data such as the 3011618Srie * dynamic information simply points to a string table. Data such as 3021618Srie * relocations, reference a symbol table, which in turn is associated with a 3031618Srie * string table. 3040Sstevel@tonic-gate */ 3050Sstevel@tonic-gate static int 3061618Srie stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file, 3071618Srie Word *symnum, Cache **symsec, Cache **strsec) 3081618Srie { 3091618Srie Shdr *shdr = cache[ndx].c_shdr; 3101618Srie 3111618Srie if (symtab) { 3121618Srie /* 3131618Srie * Validate the symbol table section. 3141618Srie */ 3151618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3161618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3171618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 3181618Srie return (0); 3191618Srie } 3203466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 3213466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 3223466Srie file, cache[ndx].c_name); 3233466Srie return (0); 3243466Srie } 3251618Srie 3261618Srie /* 3271618Srie * Obtain, and verify the symbol table data. 3281618Srie */ 3293466Srie if ((cache[ndx].c_data == NULL) || 3303466Srie (cache[ndx].c_data->d_buf == NULL)) { 3311618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 3321618Srie file, cache[ndx].c_name); 3331618Srie return (0); 3341618Srie } 3351618Srie 3361618Srie /* 3371618Srie * Establish the string table index. 3381618Srie */ 3391618Srie ndx = shdr->sh_link; 3401618Srie shdr = cache[ndx].c_shdr; 3411618Srie 3421618Srie /* 3431618Srie * Return symbol table information. 3441618Srie */ 3451618Srie if (symnum) 3461618Srie *symnum = (shdr->sh_size / shdr->sh_entsize); 3471618Srie if (symsec) 3481618Srie *symsec = &cache[ndx]; 3491618Srie } 3501618Srie 3511618Srie /* 3521618Srie * Validate the associated string table section. 3531618Srie */ 3541618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3551618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3561618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 3571618Srie return (0); 3581618Srie } 3591618Srie 3601618Srie if (strsec) 3611618Srie *strsec = &cache[shdr->sh_link]; 3621618Srie 3631618Srie return (1); 3641618Srie } 3651618Srie 3661618Srie /* 3671618Srie * Lookup a symbol and set Sym accordingly. 3681618Srie */ 3691618Srie static int 3701618Srie symlookup(const char *name, Cache *cache, Word shnum, Sym **sym, 3710Sstevel@tonic-gate Cache *symtab, const char *file) 3720Sstevel@tonic-gate { 3731618Srie Shdr *shdr; 3741618Srie Word symn, cnt; 3751618Srie Sym *syms; 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate if (symtab == 0) 3780Sstevel@tonic-gate return (0); 3790Sstevel@tonic-gate 3801618Srie shdr = symtab->c_shdr; 3811618Srie 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * Determine the symbol data and number. 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 3860Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 3870Sstevel@tonic-gate file, symtab->c_name); 3880Sstevel@tonic-gate return (0); 3890Sstevel@tonic-gate } 3903466Srie if (symtab->c_data == NULL) 3913466Srie return (0); 3923466Srie 3930Sstevel@tonic-gate /* LINTED */ 3941618Srie symn = (Word)(shdr->sh_size / shdr->sh_entsize); 3951618Srie syms = (Sym *)symtab->c_data->d_buf; 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate /* 3980Sstevel@tonic-gate * Get the associated string table section. 3990Sstevel@tonic-gate */ 4000Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 4010Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 4021618Srie file, symtab->c_name, EC_WORD(shdr->sh_link)); 4030Sstevel@tonic-gate return (0); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate /* 4070Sstevel@tonic-gate * Loop through the symbol table to find a match. 4080Sstevel@tonic-gate */ 4091618Srie for (cnt = 0; cnt < symn; syms++, cnt++) { 4101618Srie const char *symname; 4110Sstevel@tonic-gate 4121618Srie symname = string(symtab, cnt, &cache[shdr->sh_link], file, 4131618Srie syms->st_name); 4140Sstevel@tonic-gate 4151618Srie if (symname && (strcmp(name, symname) == 0)) { 4161618Srie *sym = syms; 4170Sstevel@tonic-gate return (1); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate return (0); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate /* 4240Sstevel@tonic-gate * Print section headers. 4250Sstevel@tonic-gate */ 4260Sstevel@tonic-gate static void 4279273SAli.Bahrami@Sun.COM sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi) 4280Sstevel@tonic-gate { 4291618Srie size_t seccnt; 4300Sstevel@tonic-gate 4311618Srie for (seccnt = 1; seccnt < shnum; seccnt++) { 4321618Srie Cache *_cache = &cache[seccnt]; 4331618Srie Shdr *shdr = _cache->c_shdr; 4341618Srie const char *secname = _cache->c_name; 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate /* 4370Sstevel@tonic-gate * Although numerous section header entries can be zero, it's 4383862Srie * usually a sign of trouble if the type is zero. 4390Sstevel@tonic-gate */ 4400Sstevel@tonic-gate if (shdr->sh_type == 0) { 4410Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE), 4421618Srie file, secname, EC_WORD(shdr->sh_type)); 4430Sstevel@tonic-gate } 4443862Srie 4455411Sab196087 if (!match(MATCH_F_ALL, secname, seccnt, shdr->sh_type)) 4463862Srie continue; 4470Sstevel@tonic-gate 4481324Srie /* 4491324Srie * Identify any sections that are suspicious. A .got section 4501324Srie * shouldn't exist in a relocatable object. 4511324Srie */ 4521324Srie if (ehdr->e_type == ET_REL) { 4531618Srie if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT), 4541324Srie MSG_ELF_GOT_SIZE) == 0) { 4551324Srie (void) fprintf(stderr, 4561618Srie MSG_INTL(MSG_GOT_UNEXPECTED), file, 4571618Srie secname); 4581324Srie } 4591324Srie } 4601324Srie 4611618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 4621618Srie dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname); 4639273SAli.Bahrami@Sun.COM Elf_shdr(0, osabi, ehdr->e_machine, shdr); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate 4671618Srie /* 4681618Srie * Obtain a specified Phdr entry. 4691618Srie */ 4701618Srie static Phdr * 4719085SAli.Bahrami@Sun.COM getphdr(Word phnum, Word *type_arr, Word type_cnt, const char *file, Elf *elf) 4721618Srie { 4739085SAli.Bahrami@Sun.COM Word cnt, tcnt; 4741618Srie Phdr *phdr; 4751618Srie 4761618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 4771618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 4789085SAli.Bahrami@Sun.COM return (NULL); 4791618Srie } 4801618Srie 4811618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 4829085SAli.Bahrami@Sun.COM for (tcnt = 0; tcnt < type_cnt; tcnt++) { 4839085SAli.Bahrami@Sun.COM if (phdr->p_type == type_arr[tcnt]) 4849085SAli.Bahrami@Sun.COM return (phdr); 4859085SAli.Bahrami@Sun.COM } 4861618Srie } 4879085SAli.Bahrami@Sun.COM return (NULL); 4881618Srie } 4891618Srie 490*9406SAli.Bahrami@Sun.COM /* 491*9406SAli.Bahrami@Sun.COM * Display the contents of GNU/amd64 .eh_frame and .eh_frame_hdr 492*9406SAli.Bahrami@Sun.COM * sections. 493*9406SAli.Bahrami@Sun.COM * 494*9406SAli.Bahrami@Sun.COM * entry: 495*9406SAli.Bahrami@Sun.COM * cache - Cache of all section headers 496*9406SAli.Bahrami@Sun.COM * shndx - Index of .eh_frame or .eh_frame_hdr section to be displayed 497*9406SAli.Bahrami@Sun.COM * uphdr - NULL, or unwind program header associated with 498*9406SAli.Bahrami@Sun.COM * the .eh_frame_hdr section. 499*9406SAli.Bahrami@Sun.COM * ehdr - ELF header for file 500*9406SAli.Bahrami@Sun.COM * eh_state - Data used across calls to this routine. The 501*9406SAli.Bahrami@Sun.COM * caller should zero it before the first call, and 502*9406SAli.Bahrami@Sun.COM * pass it on every call. 503*9406SAli.Bahrami@Sun.COM * osabi - OSABI to use in displaying information 504*9406SAli.Bahrami@Sun.COM * file - Name of file 505*9406SAli.Bahrami@Sun.COM * flags - Command line option flags 506*9406SAli.Bahrami@Sun.COM */ 5070Sstevel@tonic-gate static void 508*9406SAli.Bahrami@Sun.COM unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr, 509*9406SAli.Bahrami@Sun.COM gnu_eh_state_t *eh_state, uchar_t osabi, const char *file, uint_t flags) 5100Sstevel@tonic-gate { 5119085SAli.Bahrami@Sun.COM #if defined(_ELF64) 5129085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_64 5139085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_64 5149085SAli.Bahrami@Sun.COM #else 5159085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_32 5169085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_32 5179085SAli.Bahrami@Sun.COM #endif 5189085SAli.Bahrami@Sun.COM 519*9406SAli.Bahrami@Sun.COM Cache *_cache = &cache[shndx]; 520*9406SAli.Bahrami@Sun.COM Shdr *shdr = _cache->c_shdr; 521*9406SAli.Bahrami@Sun.COM uchar_t *data = (uchar_t *)(_cache->c_data->d_buf); 522*9406SAli.Bahrami@Sun.COM size_t datasize = _cache->c_data->d_size; 523*9406SAli.Bahrami@Sun.COM Conv_dwarf_ehe_buf_t dwarf_ehe_buf; 524*9406SAli.Bahrami@Sun.COM uint64_t ndx, frame_ptr, fde_cnt, tabndx; 525*9406SAli.Bahrami@Sun.COM uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; 526*9406SAli.Bahrami@Sun.COM uint64_t initloc, initloc0; 527*9406SAli.Bahrami@Sun.COM 528*9406SAli.Bahrami@Sun.COM 529*9406SAli.Bahrami@Sun.COM /* 530*9406SAli.Bahrami@Sun.COM * Is this a .eh_frame_hdr? 531*9406SAli.Bahrami@Sun.COM */ 532*9406SAli.Bahrami@Sun.COM if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || 533*9406SAli.Bahrami@Sun.COM (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 534*9406SAli.Bahrami@Sun.COM MSG_SCN_FRMHDR_SIZE) == 0)) { 535*9406SAli.Bahrami@Sun.COM /* 536*9406SAli.Bahrami@Sun.COM * There can only be a single .eh_frame_hdr. 537*9406SAli.Bahrami@Sun.COM * Flag duplicates. 538*9406SAli.Bahrami@Sun.COM */ 539*9406SAli.Bahrami@Sun.COM if (++eh_state->hdr_cnt > 1) 540*9406SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_MULTEHFRMHDR), 541*9406SAli.Bahrami@Sun.COM file, EC_WORD(shndx), _cache->c_name); 542*9406SAli.Bahrami@Sun.COM 543*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR)); 544*9406SAli.Bahrami@Sun.COM ndx = 0; 545*9406SAli.Bahrami@Sun.COM 546*9406SAli.Bahrami@Sun.COM vers = data[ndx++]; 547*9406SAli.Bahrami@Sun.COM frame_ptr_enc = data[ndx++]; 548*9406SAli.Bahrami@Sun.COM fde_cnt_enc = data[ndx++]; 549*9406SAli.Bahrami@Sun.COM table_enc = data[ndx++]; 550*9406SAli.Bahrami@Sun.COM 551*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); 552*9406SAli.Bahrami@Sun.COM 553*9406SAli.Bahrami@Sun.COM frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, 554*9406SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx); 555*9406SAli.Bahrami@Sun.COM if (eh_state->hdr_cnt == 1) { 556*9406SAli.Bahrami@Sun.COM eh_state->hdr_ndx = shndx; 557*9406SAli.Bahrami@Sun.COM eh_state->frame_ptr = frame_ptr; 558*9406SAli.Bahrami@Sun.COM } 559*9406SAli.Bahrami@Sun.COM 560*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC), 561*9406SAli.Bahrami@Sun.COM conv_dwarf_ehe(frame_ptr_enc, &dwarf_ehe_buf), 562*9406SAli.Bahrami@Sun.COM EC_XWORD(frame_ptr)); 563*9406SAli.Bahrami@Sun.COM 564*9406SAli.Bahrami@Sun.COM fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, 565*9406SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx); 566*9406SAli.Bahrami@Sun.COM 567*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), 568*9406SAli.Bahrami@Sun.COM conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf), 569*9406SAli.Bahrami@Sun.COM EC_XWORD(fde_cnt)); 570*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_TABENC), 571*9406SAli.Bahrami@Sun.COM conv_dwarf_ehe(table_enc, &dwarf_ehe_buf)); 572*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1)); 573*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2)); 574*9406SAli.Bahrami@Sun.COM 575*9406SAli.Bahrami@Sun.COM for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 576*9406SAli.Bahrami@Sun.COM initloc = dwarf_ehe_extract(data, &ndx, table_enc, 577*9406SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx); 578*9406SAli.Bahrami@Sun.COM /*LINTED:E_VAR_USED_BEFORE_SET*/ 579*9406SAli.Bahrami@Sun.COM if ((tabndx != 0) && (initloc0 > initloc)) 580*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_INTL(MSG_ERR_BADSORT), 581*9406SAli.Bahrami@Sun.COM file, _cache->c_name, EC_WORD(tabndx)); 582*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), 583*9406SAli.Bahrami@Sun.COM EC_XWORD(initloc), 584*9406SAli.Bahrami@Sun.COM EC_XWORD(dwarf_ehe_extract(data, &ndx, 585*9406SAli.Bahrami@Sun.COM table_enc, ehdr->e_ident, shdr->sh_addr, 586*9406SAli.Bahrami@Sun.COM ndx))); 587*9406SAli.Bahrami@Sun.COM initloc0 = initloc; 588*9406SAli.Bahrami@Sun.COM } 589*9406SAli.Bahrami@Sun.COM } else { /* Display the .eh_frame section */ 590*9406SAli.Bahrami@Sun.COM eh_state->frame_cnt++; 591*9406SAli.Bahrami@Sun.COM if (eh_state->frame_cnt == 1) { 592*9406SAli.Bahrami@Sun.COM eh_state->frame_ndx = shndx; 593*9406SAli.Bahrami@Sun.COM eh_state->frame_base = shdr->sh_addr; 594*9406SAli.Bahrami@Sun.COM } else if ((eh_state->frame_cnt > 1) && 595*9406SAli.Bahrami@Sun.COM (ehdr->e_type != ET_REL)) { 596*9406SAli.Bahrami@Sun.COM Conv_inv_buf_t inv_buf; 597*9406SAli.Bahrami@Sun.COM 598*9406SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_WARN_MULTEHFRM), 599*9406SAli.Bahrami@Sun.COM file, EC_WORD(shndx), _cache->c_name, 600*9406SAli.Bahrami@Sun.COM conv_ehdr_type(osabi, ehdr->e_type, 0, &inv_buf)); 601*9406SAli.Bahrami@Sun.COM } 602*9406SAli.Bahrami@Sun.COM dump_eh_frame(data, datasize, shdr->sh_addr, 603*9406SAli.Bahrami@Sun.COM ehdr->e_machine, ehdr->e_ident); 604*9406SAli.Bahrami@Sun.COM } 605*9406SAli.Bahrami@Sun.COM 606*9406SAli.Bahrami@Sun.COM /* 607*9406SAli.Bahrami@Sun.COM * If we've seen the .eh_frame_hdr and the first .eh_frame section, 608*9406SAli.Bahrami@Sun.COM * compare the header frame_ptr to the address of the actual frame 609*9406SAli.Bahrami@Sun.COM * section to ensure the link-editor got this right. Note, this 610*9406SAli.Bahrami@Sun.COM * diagnostic is only produced when unwind information is explicitly 611*9406SAli.Bahrami@Sun.COM * asked for, as shared objects built with an older ld(1) may reveal 612*9406SAli.Bahrami@Sun.COM * this inconsistency. Although an inconsistency, it doesn't seem to 613*9406SAli.Bahrami@Sun.COM * have any adverse effect on existing tools. 614*9406SAli.Bahrami@Sun.COM */ 615*9406SAli.Bahrami@Sun.COM if (((flags & FLG_MASK_SHOW) != FLG_MASK_SHOW) && 616*9406SAli.Bahrami@Sun.COM (eh_state->hdr_cnt > 0) && (eh_state->frame_cnt > 0) && 617*9406SAli.Bahrami@Sun.COM (eh_state->frame_ptr != eh_state->frame_base)) 618*9406SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADEHFRMPTR), 619*9406SAli.Bahrami@Sun.COM file, EC_WORD(eh_state->hdr_ndx), 620*9406SAli.Bahrami@Sun.COM cache[eh_state->hdr_ndx].c_name, 621*9406SAli.Bahrami@Sun.COM EC_XWORD(eh_state->frame_ptr), 622*9406SAli.Bahrami@Sun.COM EC_WORD(eh_state->frame_ndx), 623*9406SAli.Bahrami@Sun.COM cache[eh_state->frame_ndx].c_name, 624*9406SAli.Bahrami@Sun.COM EC_XWORD(eh_state->frame_base)); 625*9406SAli.Bahrami@Sun.COM #undef MSG_UNW_BINSRTAB2 626*9406SAli.Bahrami@Sun.COM #undef MSG_UNW_BINSRTABENT 627*9406SAli.Bahrami@Sun.COM } 628*9406SAli.Bahrami@Sun.COM 629*9406SAli.Bahrami@Sun.COM /* 630*9406SAli.Bahrami@Sun.COM * Convert a self relative pointer into an address. A self relative 631*9406SAli.Bahrami@Sun.COM * pointer adds the address where the pointer resides to the offset 632*9406SAli.Bahrami@Sun.COM * contained in the pointer. The benefit is that the value of the 633*9406SAli.Bahrami@Sun.COM * pointer does not require relocation. 634*9406SAli.Bahrami@Sun.COM * 635*9406SAli.Bahrami@Sun.COM * entry: 636*9406SAli.Bahrami@Sun.COM * base_addr - Address of the pointer. 637*9406SAli.Bahrami@Sun.COM * delta - Offset relative to base_addr giving desired address 638*9406SAli.Bahrami@Sun.COM * 639*9406SAli.Bahrami@Sun.COM * exit: 640*9406SAli.Bahrami@Sun.COM * The computed address is returned. 641*9406SAli.Bahrami@Sun.COM * 642*9406SAli.Bahrami@Sun.COM * note: 643*9406SAli.Bahrami@Sun.COM * base_addr is an unsigned value, while ret_addr is signed. This routine 644*9406SAli.Bahrami@Sun.COM * used explicit testing and casting to explicitly control type 645*9406SAli.Bahrami@Sun.COM * conversion, and ensure that we handle the maximum possible range. 646*9406SAli.Bahrami@Sun.COM */ 647*9406SAli.Bahrami@Sun.COM static Addr 648*9406SAli.Bahrami@Sun.COM srelptr(Addr base_addr, PTRDIFF_T delta) 649*9406SAli.Bahrami@Sun.COM { 650*9406SAli.Bahrami@Sun.COM if (delta < 0) 651*9406SAli.Bahrami@Sun.COM return (base_addr - (Addr) (-delta)); 652*9406SAli.Bahrami@Sun.COM 653*9406SAli.Bahrami@Sun.COM return (base_addr + (Addr) delta); 654*9406SAli.Bahrami@Sun.COM } 655*9406SAli.Bahrami@Sun.COM 656*9406SAli.Bahrami@Sun.COM /* 657*9406SAli.Bahrami@Sun.COM * Byte swap a PTRDIFF_T value. 658*9406SAli.Bahrami@Sun.COM */ 659*9406SAli.Bahrami@Sun.COM static PTRDIFF_T 660*9406SAli.Bahrami@Sun.COM swap_ptrdiff(PTRDIFF_T value) 661*9406SAli.Bahrami@Sun.COM { 662*9406SAli.Bahrami@Sun.COM PTRDIFF_T r; 663*9406SAli.Bahrami@Sun.COM uchar_t *dst = (uchar_t *)&r; 664*9406SAli.Bahrami@Sun.COM uchar_t *src = (uchar_t *)&value; 665*9406SAli.Bahrami@Sun.COM 666*9406SAli.Bahrami@Sun.COM UL_ASSIGN_BSWAP_XWORD(dst, src); 667*9406SAli.Bahrami@Sun.COM return (r); 668*9406SAli.Bahrami@Sun.COM } 669*9406SAli.Bahrami@Sun.COM 670*9406SAli.Bahrami@Sun.COM /* 671*9406SAli.Bahrami@Sun.COM * Display exception_range_entry items from the .exception_ranges section 672*9406SAli.Bahrami@Sun.COM * of a Sun C++ object. 673*9406SAli.Bahrami@Sun.COM */ 674*9406SAli.Bahrami@Sun.COM static void 675*9406SAli.Bahrami@Sun.COM unwind_exception_ranges(Cache *_cache, const char *file, int do_swap) 676*9406SAli.Bahrami@Sun.COM { 677*9406SAli.Bahrami@Sun.COM /* 678*9406SAli.Bahrami@Sun.COM * Translate a PTRDIFF_T self-relative address field of 679*9406SAli.Bahrami@Sun.COM * an exception_range_entry struct into an address. 680*9406SAli.Bahrami@Sun.COM * 681*9406SAli.Bahrami@Sun.COM * entry: 682*9406SAli.Bahrami@Sun.COM * exc_addr - Address of base of exception_range_entry struct 683*9406SAli.Bahrami@Sun.COM * cur_ent - Pointer to data in the struct to be translated 684*9406SAli.Bahrami@Sun.COM * 685*9406SAli.Bahrami@Sun.COM * _f - Field of struct to be translated 686*9406SAli.Bahrami@Sun.COM */ 687*9406SAli.Bahrami@Sun.COM #define SRELPTR(_f) \ 688*9406SAli.Bahrami@Sun.COM srelptr(exc_addr + offsetof(exception_range_entry, _f), cur_ent->_f) 689*9406SAli.Bahrami@Sun.COM 690*9406SAli.Bahrami@Sun.COM #if defined(_ELF64) 691*9406SAli.Bahrami@Sun.COM #define MSG_EXR_TITLE MSG_EXR_TITLE_64 692*9406SAli.Bahrami@Sun.COM #define MSG_EXR_ENTRY MSG_EXR_ENTRY_64 693*9406SAli.Bahrami@Sun.COM #else 694*9406SAli.Bahrami@Sun.COM #define MSG_EXR_TITLE MSG_EXR_TITLE_32 695*9406SAli.Bahrami@Sun.COM #define MSG_EXR_ENTRY MSG_EXR_ENTRY_32 696*9406SAli.Bahrami@Sun.COM #endif 697*9406SAli.Bahrami@Sun.COM 698*9406SAli.Bahrami@Sun.COM exception_range_entry scratch, *ent, *cur_ent = &scratch; 699*9406SAli.Bahrami@Sun.COM char index[MAXNDXSIZE]; 700*9406SAli.Bahrami@Sun.COM Word i, nelts; 701*9406SAli.Bahrami@Sun.COM Addr addr, addr0, offset = 0; 702*9406SAli.Bahrami@Sun.COM Addr exc_addr = _cache->c_shdr->sh_addr; 703*9406SAli.Bahrami@Sun.COM 704*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_INTL(MSG_EXR_TITLE)); 705*9406SAli.Bahrami@Sun.COM ent = (exception_range_entry *)(_cache->c_data->d_buf); 706*9406SAli.Bahrami@Sun.COM nelts = _cache->c_data->d_size / sizeof (exception_range_entry); 707*9406SAli.Bahrami@Sun.COM 708*9406SAli.Bahrami@Sun.COM for (i = 0; i < nelts; i++, ent++) { 709*9406SAli.Bahrami@Sun.COM if (do_swap) { 710*9406SAli.Bahrami@Sun.COM /* 711*9406SAli.Bahrami@Sun.COM * Copy byte swapped values into the scratch buffer. 712*9406SAli.Bahrami@Sun.COM * The reserved field is not used, so we skip it. 713*9406SAli.Bahrami@Sun.COM */ 714*9406SAli.Bahrami@Sun.COM scratch.ret_addr = swap_ptrdiff(ent->ret_addr); 715*9406SAli.Bahrami@Sun.COM scratch.length = BSWAP_XWORD(ent->length); 716*9406SAli.Bahrami@Sun.COM scratch.handler_addr = swap_ptrdiff(ent->handler_addr); 717*9406SAli.Bahrami@Sun.COM scratch.type_block = swap_ptrdiff(ent->type_block); 718*9406SAli.Bahrami@Sun.COM } else { 719*9406SAli.Bahrami@Sun.COM cur_ent = ent; 720*9406SAli.Bahrami@Sun.COM } 721*9406SAli.Bahrami@Sun.COM 722*9406SAli.Bahrami@Sun.COM /* 723*9406SAli.Bahrami@Sun.COM * The table is required to be sorted by the address 724*9406SAli.Bahrami@Sun.COM * derived from ret_addr, to allow binary searching. Ensure 725*9406SAli.Bahrami@Sun.COM * that addresses grow monotonically. 726*9406SAli.Bahrami@Sun.COM */ 727*9406SAli.Bahrami@Sun.COM addr = SRELPTR(ret_addr); 728*9406SAli.Bahrami@Sun.COM /*LINTED:E_VAR_USED_BEFORE_SET*/ 729*9406SAli.Bahrami@Sun.COM if ((i != 0) && (addr0 > addr)) 730*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_INTL(MSG_ERR_BADSORT), 731*9406SAli.Bahrami@Sun.COM file, _cache->c_name, EC_WORD(i)); 732*9406SAli.Bahrami@Sun.COM 733*9406SAli.Bahrami@Sun.COM (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 734*9406SAli.Bahrami@Sun.COM EC_XWORD(i)); 735*9406SAli.Bahrami@Sun.COM dbg_print(0, MSG_INTL(MSG_EXR_ENTRY), index, EC_ADDR(offset), 736*9406SAli.Bahrami@Sun.COM EC_ADDR(addr), EC_ADDR(cur_ent->length), 737*9406SAli.Bahrami@Sun.COM EC_ADDR(SRELPTR(handler_addr)), 738*9406SAli.Bahrami@Sun.COM EC_ADDR(SRELPTR(type_block))); 739*9406SAli.Bahrami@Sun.COM 740*9406SAli.Bahrami@Sun.COM addr0 = addr; 741*9406SAli.Bahrami@Sun.COM exc_addr += sizeof (exception_range_entry); 742*9406SAli.Bahrami@Sun.COM offset += sizeof (exception_range_entry); 743*9406SAli.Bahrami@Sun.COM } 744*9406SAli.Bahrami@Sun.COM 745*9406SAli.Bahrami@Sun.COM #undef SRELPTR 746*9406SAli.Bahrami@Sun.COM #undef MSG_EXR_TITLE 747*9406SAli.Bahrami@Sun.COM #undef MSG_EXR_ENTRY 748*9406SAli.Bahrami@Sun.COM } 749*9406SAli.Bahrami@Sun.COM 750*9406SAli.Bahrami@Sun.COM /* 751*9406SAli.Bahrami@Sun.COM * Display information from unwind/exception sections: 752*9406SAli.Bahrami@Sun.COM * 753*9406SAli.Bahrami@Sun.COM * - GNU/amd64 .eh_frame and .eh_frame_hdr 754*9406SAli.Bahrami@Sun.COM * - Sun C++ .exception_ranges 755*9406SAli.Bahrami@Sun.COM * 756*9406SAli.Bahrami@Sun.COM */ 757*9406SAli.Bahrami@Sun.COM static void 758*9406SAli.Bahrami@Sun.COM unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, uchar_t osabi, 759*9406SAli.Bahrami@Sun.COM const char *file, Elf *elf, uint_t flags) 760*9406SAli.Bahrami@Sun.COM { 7619085SAli.Bahrami@Sun.COM static Word phdr_types[] = { PT_SUNW_UNWIND, PT_SUNW_EH_FRAME }; 7629085SAli.Bahrami@Sun.COM 7639085SAli.Bahrami@Sun.COM Word cnt; 7649085SAli.Bahrami@Sun.COM Phdr *uphdr = NULL; 765*9406SAli.Bahrami@Sun.COM gnu_eh_state_t eh_state; 7661618Srie 7670Sstevel@tonic-gate /* 7689085SAli.Bahrami@Sun.COM * Historical background: .eh_frame and .eh_frame_hdr sections 7699085SAli.Bahrami@Sun.COM * come from the GNU compilers (particularly C++), and are used 7709085SAli.Bahrami@Sun.COM * under all architectures. Their format is based on DWARF. When 7719085SAli.Bahrami@Sun.COM * the amd64 ABI was defined, these sections were adopted wholesale 7729085SAli.Bahrami@Sun.COM * from the existing practice. 7739085SAli.Bahrami@Sun.COM * 7749085SAli.Bahrami@Sun.COM * When amd64 support was added to Solaris, support for these 7759085SAli.Bahrami@Sun.COM * sections was added, using the SHT_AMD64_UNWIND section type 7769085SAli.Bahrami@Sun.COM * to identify them. At first, we ignored them in objects for 7779085SAli.Bahrami@Sun.COM * non-amd64 targets, but later broadened our support to include 7789085SAli.Bahrami@Sun.COM * other architectures in order to better support gcc-generated 7799085SAli.Bahrami@Sun.COM * objects. 7809085SAli.Bahrami@Sun.COM * 781*9406SAli.Bahrami@Sun.COM * .exception_ranges implement the same basic concepts, but 782*9406SAli.Bahrami@Sun.COM * were invented at Sun for the Sun C++ compiler. 783*9406SAli.Bahrami@Sun.COM * 7849085SAli.Bahrami@Sun.COM * We match these sections by name, rather than section type, 7859085SAli.Bahrami@Sun.COM * because they can come in as either SHT_AMD64_UNWIND, or as 786*9406SAli.Bahrami@Sun.COM * SHT_PROGBITS, and because the type isn't enough to determine 787*9406SAli.Bahrami@Sun.COM * how they should be interprteted. 7880Sstevel@tonic-gate */ 7890Sstevel@tonic-gate 790*9406SAli.Bahrami@Sun.COM /* Find the program header for .eh_frame_hdr if present */ 7911618Srie if (phnum) 7929085SAli.Bahrami@Sun.COM uphdr = getphdr(phnum, phdr_types, 7939085SAli.Bahrami@Sun.COM sizeof (phdr_types) / sizeof (*phdr_types), file, elf); 7940Sstevel@tonic-gate 795*9406SAli.Bahrami@Sun.COM /* 796*9406SAli.Bahrami@Sun.COM * eh_state is used to retain data used by unwind_eh_frame() 797*9406SAli.Bahrami@Sun.COM * accross calls. 798*9406SAli.Bahrami@Sun.COM */ 799*9406SAli.Bahrami@Sun.COM bzero(&eh_state, sizeof (eh_state)); 800*9406SAli.Bahrami@Sun.COM 8010Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8021618Srie Cache *_cache = &cache[cnt]; 8031618Srie Shdr *shdr = _cache->c_shdr; 804*9406SAli.Bahrami@Sun.COM int is_exrange; 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate /* 807*9406SAli.Bahrami@Sun.COM * Skip sections of the wrong type. On amd64, they 808*9406SAli.Bahrami@Sun.COM * can be SHT_AMD64_UNWIND. On all platforms, they 809*9406SAli.Bahrami@Sun.COM * can be SHT_PROGBITS (including amd64, if using 810*9406SAli.Bahrami@Sun.COM * the GNU compilers). 8119273SAli.Bahrami@Sun.COM * 8129273SAli.Bahrami@Sun.COM * Skip anything other than these two types. The name 8139273SAli.Bahrami@Sun.COM * test below will thin out the SHT_PROGBITS that don't apply. 8140Sstevel@tonic-gate */ 8159273SAli.Bahrami@Sun.COM if ((shdr->sh_type != SHT_PROGBITS) && 8169273SAli.Bahrami@Sun.COM (shdr->sh_type != SHT_AMD64_UNWIND)) 8179085SAli.Bahrami@Sun.COM continue; 8189085SAli.Bahrami@Sun.COM 8199085SAli.Bahrami@Sun.COM /* 820*9406SAli.Bahrami@Sun.COM * Only sections with certain well known names are of interest. 821*9406SAli.Bahrami@Sun.COM * These are: 822*9406SAli.Bahrami@Sun.COM * 823*9406SAli.Bahrami@Sun.COM * .eh_frame - amd64/GNU-compiler unwind sections 824*9406SAli.Bahrami@Sun.COM * .eh_frame_hdr - Sorted table referencing .eh_frame 825*9406SAli.Bahrami@Sun.COM * .exception_ranges - Sun C++ unwind sections 826*9406SAli.Bahrami@Sun.COM * 827*9406SAli.Bahrami@Sun.COM * We do a prefix comparison, allowing for naming conventions 828*9406SAli.Bahrami@Sun.COM * like .eh_frame.foo, hence the use of strncmp() rather than 829*9406SAli.Bahrami@Sun.COM * strcmp(). This means that we only really need to test for 830*9406SAli.Bahrami@Sun.COM * .eh_frame, as it's a prefix of .eh_frame_hdr. 8319085SAli.Bahrami@Sun.COM */ 832*9406SAli.Bahrami@Sun.COM is_exrange = strncmp(_cache->c_name, 833*9406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_SCN_EXRANGE), MSG_SCN_EXRANGE_SIZE) == 0; 834*9406SAli.Bahrami@Sun.COM if ((strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 835*9406SAli.Bahrami@Sun.COM MSG_SCN_FRM_SIZE) != 0) && !is_exrange) 8360Sstevel@tonic-gate continue; 8374168Sab196087 8385411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 8390Sstevel@tonic-gate continue; 8400Sstevel@tonic-gate 8413466Srie if (_cache->c_data == NULL) 8423466Srie continue; 8433466Srie 8441618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8451618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 8460Sstevel@tonic-gate 847*9406SAli.Bahrami@Sun.COM if (is_exrange) 848*9406SAli.Bahrami@Sun.COM unwind_exception_ranges(_cache, file, 849*9406SAli.Bahrami@Sun.COM _elf_sys_encoding() != ehdr->e_ident[EI_DATA]); 850*9406SAli.Bahrami@Sun.COM else 851*9406SAli.Bahrami@Sun.COM unwind_eh_frame(cache, cnt, uphdr, ehdr, &eh_state, 852*9406SAli.Bahrami@Sun.COM osabi, file, flags); 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate } 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate /* 8570Sstevel@tonic-gate * Print the hardware/software capabilities. For executables and shared objects 8580Sstevel@tonic-gate * this should be accompanied with a program header. 8590Sstevel@tonic-gate */ 8600Sstevel@tonic-gate static void 8611618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, 8621618Srie Elf *elf) 8630Sstevel@tonic-gate { 8641618Srie Word cnt; 8657833SRod.Evans@Sun.COM Shdr *cshdr = NULL; 8663466Srie Cache *ccache; 8671618Srie Off cphdr_off = 0; 8681618Srie Xword cphdr_sz; 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate /* 8710Sstevel@tonic-gate * Determine if a hardware/software capabilities header exists. 8720Sstevel@tonic-gate */ 8731618Srie if (phnum) { 8741618Srie Phdr *phdr; 8750Sstevel@tonic-gate 8761618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 8770Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 8780Sstevel@tonic-gate return; 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate 8811618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 8821618Srie if (phdr->p_type == PT_SUNWCAP) { 8831618Srie cphdr_off = phdr->p_offset; 8841618Srie cphdr_sz = phdr->p_filesz; 8851618Srie break; 8861618Srie } 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * Determine if a hardware/software capabilities section exists. 8920Sstevel@tonic-gate */ 8930Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8941618Srie Cache *_cache = &cache[cnt]; 8951618Srie Shdr *shdr = _cache->c_shdr; 8960Sstevel@tonic-gate 8970Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_cap) 8980Sstevel@tonic-gate continue; 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 9010Sstevel@tonic-gate (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 9020Sstevel@tonic-gate continue; 9030Sstevel@tonic-gate 9043466Srie if (_cache->c_data == NULL) 9053466Srie continue; 9063466Srie 9070Sstevel@tonic-gate ccache = _cache; 9080Sstevel@tonic-gate cshdr = shdr; 9090Sstevel@tonic-gate break; 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate 9127833SRod.Evans@Sun.COM if ((cshdr == NULL) && (cphdr_off == 0)) 9130Sstevel@tonic-gate return; 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate /* 9160Sstevel@tonic-gate * Print the hardware/software capabilities section. 9170Sstevel@tonic-gate */ 9180Sstevel@tonic-gate if (cshdr) { 9191618Srie Word ndx, capn; 9203492Sab196087 Cap *cap = (Cap *)ccache->c_data->d_buf; 9210Sstevel@tonic-gate 9224665Sab196087 if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) { 9234665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 9244665Sab196087 file, ccache->c_name); 9254665Sab196087 return; 9264665Sab196087 } 9274665Sab196087 9281618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 9291618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 9300Sstevel@tonic-gate 9311618Srie Elf_cap_title(0); 9321618Srie 9331618Srie capn = (Word)(cshdr->sh_size / cshdr->sh_entsize); 9340Sstevel@tonic-gate 9351618Srie for (ndx = 0; ndx < capn; cap++, ndx++) { 9367833SRod.Evans@Sun.COM if (cap->c_tag == CA_SUNW_NULL) 9377833SRod.Evans@Sun.COM continue; 9387833SRod.Evans@Sun.COM 9397833SRod.Evans@Sun.COM Elf_cap_entry(0, cap, ndx, ehdr->e_machine); 9407833SRod.Evans@Sun.COM 9417833SRod.Evans@Sun.COM /* 9427833SRod.Evans@Sun.COM * An SF1_SUNW_ADDR32 software capability in a 32-bit 9437833SRod.Evans@Sun.COM * object is suspicious as it has no effect. 9447833SRod.Evans@Sun.COM */ 9457833SRod.Evans@Sun.COM if ((cap->c_tag == CA_SUNW_SF_1) && 9467833SRod.Evans@Sun.COM (ehdr->e_ident[EI_CLASS] == ELFCLASS32) && 9477833SRod.Evans@Sun.COM (cap->c_un.c_val & SF1_SUNW_ADDR32)) { 9487833SRod.Evans@Sun.COM (void) fprintf(stderr, 9497833SRod.Evans@Sun.COM MSG_INTL(MSG_WARN_INADDR32SF1), 9507833SRod.Evans@Sun.COM file, ccache->c_name); 9517833SRod.Evans@Sun.COM } 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate } else 9540Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate /* 9570Sstevel@tonic-gate * If this object is an executable or shared object, then the 9580Sstevel@tonic-gate * hardware/software capabilities section should have an accompanying 9590Sstevel@tonic-gate * program header. 9600Sstevel@tonic-gate */ 9610Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 9620Sstevel@tonic-gate if (cphdr_off == 0) 9630Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 9640Sstevel@tonic-gate file, ccache->c_name); 9650Sstevel@tonic-gate else if ((cphdr_off != cshdr->sh_offset) || 9660Sstevel@tonic-gate (cphdr_sz != cshdr->sh_size)) 9670Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 9680Sstevel@tonic-gate file, ccache->c_name); 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate /* 9730Sstevel@tonic-gate * Print the interpretor. 9740Sstevel@tonic-gate */ 9750Sstevel@tonic-gate static void 9761618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) 9770Sstevel@tonic-gate { 9789085SAli.Bahrami@Sun.COM static Word phdr_types[] = { PT_INTERP }; 9799085SAli.Bahrami@Sun.COM 9809085SAli.Bahrami@Sun.COM 9811618Srie Word cnt; 9829085SAli.Bahrami@Sun.COM Shdr *ishdr = NULL; 9831618Srie Cache *icache; 9841618Srie Off iphdr_off = 0; 9851618Srie Xword iphdr_fsz; 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate /* 9880Sstevel@tonic-gate * Determine if an interp header exists. 9890Sstevel@tonic-gate */ 9901618Srie if (phnum) { 9911618Srie Phdr *phdr; 9920Sstevel@tonic-gate 9939085SAli.Bahrami@Sun.COM phdr = getphdr(phnum, phdr_types, 9949085SAli.Bahrami@Sun.COM sizeof (phdr_types) / sizeof (*phdr_types), file, elf); 9959085SAli.Bahrami@Sun.COM if (phdr != NULL) { 9961618Srie iphdr_off = phdr->p_offset; 9971618Srie iphdr_fsz = phdr->p_filesz; 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate if (iphdr_off == 0) 10020Sstevel@tonic-gate return; 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate /* 10050Sstevel@tonic-gate * Determine if an interp section exists. 10060Sstevel@tonic-gate */ 10070Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 10081618Srie Cache *_cache = &cache[cnt]; 10091618Srie Shdr *shdr = _cache->c_shdr; 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate /* 10120Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP 10130Sstevel@tonic-gate * string. The target section can't be in a NOBITS section. 10140Sstevel@tonic-gate */ 10150Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) || 10160Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) || 10171618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size)) 10180Sstevel@tonic-gate continue; 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate icache = _cache; 10210Sstevel@tonic-gate ishdr = shdr; 10220Sstevel@tonic-gate break; 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate /* 10260Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the 10270Sstevel@tonic-gate * program header, as this is the offset used by the kernel. 10280Sstevel@tonic-gate */ 10293466Srie if (ishdr && icache->c_data) { 10301618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 10311618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 10321618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), 10330Sstevel@tonic-gate (char *)icache->c_data->d_buf + 10340Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset)); 10350Sstevel@tonic-gate } else 10360Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate /* 10390Sstevel@tonic-gate * If there are any inconsistences between the program header and 10400Sstevel@tonic-gate * section information, flag them. 10410Sstevel@tonic-gate */ 10420Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) || 10431618Srie (iphdr_fsz != ishdr->sh_size))) { 10440Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 10450Sstevel@tonic-gate icache->c_name); 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate } 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate /* 10500Sstevel@tonic-gate * Print the syminfo section. 10510Sstevel@tonic-gate */ 10520Sstevel@tonic-gate static void 10531618Srie syminfo(Cache *cache, Word shnum, const char *file) 10540Sstevel@tonic-gate { 10551618Srie Shdr *infoshdr; 10561618Srie Syminfo *info; 10571618Srie Sym *syms; 10581618Srie Dyn *dyns; 10591618Srie Word infonum, cnt, ndx, symnum; 10609085SAli.Bahrami@Sun.COM Cache *infocache = NULL, *symsec, *strsec; 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 10631618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { 10641618Srie infocache = &cache[cnt]; 10650Sstevel@tonic-gate break; 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate } 10689085SAli.Bahrami@Sun.COM if (infocache == NULL) 10690Sstevel@tonic-gate return; 10700Sstevel@tonic-gate 10711618Srie infoshdr = infocache->c_shdr; 10721618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) { 10730Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 10741618Srie file, infocache->c_name); 10750Sstevel@tonic-gate return; 10760Sstevel@tonic-gate } 10773466Srie if (infocache->c_data == NULL) 10783466Srie return; 10793466Srie 10801618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize); 10811618Srie info = (Syminfo *)infocache->c_data->d_buf; 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate /* 10840Sstevel@tonic-gate * Get the data buffer of the associated dynamic section. 10850Sstevel@tonic-gate */ 10861618Srie if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) { 10870Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 10881618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info)); 10890Sstevel@tonic-gate return; 10900Sstevel@tonic-gate } 10913466Srie if (cache[infoshdr->sh_info].c_data == NULL) 10923466Srie return; 10933466Srie 10941618Srie dyns = cache[infoshdr->sh_info].c_data->d_buf; 10959085SAli.Bahrami@Sun.COM if (dyns == NULL) { 10960Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 10971618Srie file, cache[infoshdr->sh_info].c_name); 10980Sstevel@tonic-gate return; 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate /* 11021618Srie * Get the data buffer for the associated symbol table and string table. 11030Sstevel@tonic-gate */ 11041618Srie if (stringtbl(cache, 1, cnt, shnum, file, 11051618Srie &symnum, &symsec, &strsec) == 0) 11060Sstevel@tonic-gate return; 11070Sstevel@tonic-gate 11081618Srie syms = symsec->c_data->d_buf; 11090Sstevel@tonic-gate 11101618Srie /* 11111618Srie * Loop through the syminfo entries. 11121618Srie */ 11131618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 11141618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name); 11151618Srie Elf_syminfo_title(0); 11160Sstevel@tonic-gate 11171618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) { 11181618Srie Sym *sym; 11199085SAli.Bahrami@Sun.COM const char *needed = NULL, *name; 11201618Srie 11211618Srie if ((info->si_flags == 0) && (info->si_boundto == 0)) 11220Sstevel@tonic-gate continue; 11230Sstevel@tonic-gate 11241618Srie sym = &syms[ndx]; 11251618Srie name = string(infocache, ndx, strsec, file, sym->st_name); 11260Sstevel@tonic-gate 11271618Srie if (info->si_boundto < SYMINFO_BT_LOWRESERVE) { 11281618Srie Dyn *dyn = &dyns[info->si_boundto]; 11291618Srie 11301618Srie needed = string(infocache, info->si_boundto, 11311618Srie strsec, file, dyn->d_un.d_val); 11320Sstevel@tonic-gate } 11331618Srie Elf_syminfo_entry(0, ndx, info, name, needed); 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate } 11360Sstevel@tonic-gate 11370Sstevel@tonic-gate /* 11380Sstevel@tonic-gate * Print version definition section entries. 11390Sstevel@tonic-gate */ 11400Sstevel@tonic-gate static void 11414716Sab196087 version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache, 11420Sstevel@tonic-gate const char *file) 11430Sstevel@tonic-gate { 11441618Srie Word cnt; 11451618Srie char index[MAXNDXSIZE]; 11460Sstevel@tonic-gate 11471618Srie Elf_ver_def_title(0); 11480Sstevel@tonic-gate 11494716Sab196087 for (cnt = 1; cnt <= vdf_num; cnt++, 11501618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 11517682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 11527682SAli.Bahrami@Sun.COM const char *name, *dep; 11537682SAli.Bahrami@Sun.COM Half vcnt = vdf->vd_cnt - 1; 11547682SAli.Bahrami@Sun.COM Half ndx = vdf->vd_ndx; 11557682SAli.Bahrami@Sun.COM Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate /* 11580Sstevel@tonic-gate * Obtain the name and first dependency (if any). 11590Sstevel@tonic-gate */ 11600Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name); 11611618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 11620Sstevel@tonic-gate if (vcnt) 11630Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name); 11640Sstevel@tonic-gate else 11650Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 11680Sstevel@tonic-gate EC_XWORD(ndx)); 11691618Srie Elf_ver_line_1(0, index, name, dep, 11707682SAli.Bahrami@Sun.COM conv_ver_flags(vdf->vd_flags, 0, &ver_flags_buf)); 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate /* 11730Sstevel@tonic-gate * Print any additional dependencies. 11740Sstevel@tonic-gate */ 11750Sstevel@tonic-gate if (vcnt) { 11761618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 11770Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 11781618Srie vdap = (Verdaux *)((uintptr_t)vdap + 11790Sstevel@tonic-gate vdap->vda_next)) { 11800Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 11810Sstevel@tonic-gate vdap->vda_name); 11821618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep); 11830Sstevel@tonic-gate } 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate } 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate /* 11894716Sab196087 * Print version needed section entries. 11904716Sab196087 * 11914716Sab196087 * entry: 11924716Sab196087 * vnd - Address of verneed data 11934716Sab196087 * vnd_num - # of Verneed entries 11944716Sab196087 * vcache - Cache of verneed section being processed 11954716Sab196087 * scache - Cache of associated string table section 11964716Sab196087 * file - Name of object being processed. 11974716Sab196087 * versym - Information about versym section 11984716Sab196087 * 11994716Sab196087 * exit: 12004716Sab196087 * The versions have been printed. If GNU style versioning 12014716Sab196087 * is in effect, versym->max_verndx has been updated to 12024716Sab196087 * contain the largest version index seen. 12037682SAli.Bahrami@Sun.COM * 12047682SAli.Bahrami@Sun.COM * note: 12057682SAli.Bahrami@Sun.COM * The versym section of an object that follows the original 12067682SAli.Bahrami@Sun.COM * Solaris versioning rules only contains indexes into the verdef 12077682SAli.Bahrami@Sun.COM * section. Symbols defined in other objects (UNDEF) are given 12087682SAli.Bahrami@Sun.COM * a version of 0, indicating that they are not defined by 12097682SAli.Bahrami@Sun.COM * this file, and the Verneed entries do not have associated version 12107682SAli.Bahrami@Sun.COM * indexes. For these reasons, we do not display a version index 12117682SAli.Bahrami@Sun.COM * for original-style Verneed sections. 12127682SAli.Bahrami@Sun.COM * 12137682SAli.Bahrami@Sun.COM * The GNU versioning extensions alter this: Symbols defined in other 12147682SAli.Bahrami@Sun.COM * objects receive a version index in the range above those defined 12157682SAli.Bahrami@Sun.COM * by the Verdef section, and the vna_other field of the Vernaux 12167682SAli.Bahrami@Sun.COM * structs inside the Verneed section contain the version index for 12177682SAli.Bahrami@Sun.COM * that item. We therefore display the index when showing the 12187682SAli.Bahrami@Sun.COM * contents of a GNU style Verneed section. You should not 12197682SAli.Bahrami@Sun.COM * necessarily expect these indexes to appear in sorted 12207682SAli.Bahrami@Sun.COM * order --- it seems that the GNU ld assigns the versions as 12217682SAli.Bahrami@Sun.COM * symbols are encountered during linking, and then the results 12227682SAli.Bahrami@Sun.COM * are assembled into the Verneed section afterwards. 12230Sstevel@tonic-gate */ 12240Sstevel@tonic-gate static void 12254716Sab196087 version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache, 12264716Sab196087 const char *file, VERSYM_STATE *versym) 12270Sstevel@tonic-gate { 12284716Sab196087 Word cnt; 12294716Sab196087 char index[MAXNDXSIZE]; 12304716Sab196087 const char *index_str; 12314716Sab196087 12327682SAli.Bahrami@Sun.COM Elf_ver_need_title(0, versym->gnu_needed); 12334716Sab196087 12344716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 12351618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 12367682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 12377682SAli.Bahrami@Sun.COM const char *name, *dep; 12387682SAli.Bahrami@Sun.COM Half vcnt = vnd->vn_cnt; 12394433Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate /* 12420Sstevel@tonic-gate * Obtain the name of the needed file and the version name 12430Sstevel@tonic-gate * within it that we're dependent on. Note that the count 12440Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus 12450Sstevel@tonic-gate * entry. 12460Sstevel@tonic-gate */ 12470Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file); 12480Sstevel@tonic-gate if (vcnt) 12490Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name); 12500Sstevel@tonic-gate else 12510Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL); 12520Sstevel@tonic-gate 12537682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) { /* Traditional form */ 12547682SAli.Bahrami@Sun.COM index_str = MSG_ORIG(MSG_STR_EMPTY); 12557682SAli.Bahrami@Sun.COM } else { /* GNU form */ 12567682SAli.Bahrami@Sun.COM index_str = index; 12574716Sab196087 /* Format the version index value */ 12584716Sab196087 (void) snprintf(index, MAXNDXSIZE, 12594716Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(vnap->vna_other)); 12604716Sab196087 if (vnap->vna_other > versym->max_verndx) 12614716Sab196087 versym->max_verndx = vnap->vna_other; 12624716Sab196087 } 12634716Sab196087 Elf_ver_line_1(0, index_str, name, dep, 12647682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 0, &ver_flags_buf)); 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate /* 12670Sstevel@tonic-gate * Print any additional version dependencies. 12680Sstevel@tonic-gate */ 12690Sstevel@tonic-gate if (vcnt) { 12701618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 12710Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 12721618Srie vnap = (Vernaux *)((uintptr_t)vnap + 12730Sstevel@tonic-gate vnap->vna_next)) { 12740Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 12750Sstevel@tonic-gate vnap->vna_name); 12767682SAli.Bahrami@Sun.COM if (vnap->vna_other > 0) { 12774716Sab196087 /* Format the next index value */ 12784716Sab196087 (void) snprintf(index, MAXNDXSIZE, 12794716Sab196087 MSG_ORIG(MSG_FMT_INDEX), 12804716Sab196087 EC_XWORD(vnap->vna_other)); 12817682SAli.Bahrami@Sun.COM Elf_ver_line_1(0, index, 12824716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 12837682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 12847682SAli.Bahrami@Sun.COM 0, &ver_flags_buf)); 12854716Sab196087 if (vnap->vna_other > 12864716Sab196087 versym->max_verndx) 12874716Sab196087 versym->max_verndx = 12884716Sab196087 vnap->vna_other; 12894716Sab196087 } else { 12904716Sab196087 Elf_ver_line_3(0, 12914716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 12927682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 12937682SAli.Bahrami@Sun.COM 0, &ver_flags_buf)); 12944716Sab196087 } 12954716Sab196087 } 12964716Sab196087 } 12974716Sab196087 } 12984716Sab196087 } 12994716Sab196087 13004716Sab196087 /* 13017682SAli.Bahrami@Sun.COM * Examine the Verneed section for information related to GNU 13027682SAli.Bahrami@Sun.COM * style Versym indexing: 13037682SAli.Bahrami@Sun.COM * - A non-zero vna_other field indicates that Versym indexes can 13047682SAli.Bahrami@Sun.COM * reference Verneed records. 13057682SAli.Bahrami@Sun.COM * - If the object uses GNU style Versym indexing, the 13067682SAli.Bahrami@Sun.COM * maximum index value is needed to detect bad Versym entries. 13074716Sab196087 * 13084716Sab196087 * entry: 13094716Sab196087 * vnd - Address of verneed data 13104716Sab196087 * vnd_num - # of Verneed entries 13114716Sab196087 * versym - Information about versym section 13124716Sab196087 * 13134716Sab196087 * exit: 13147682SAli.Bahrami@Sun.COM * If a non-zero vna_other field is seen, versym->gnu_needed is set. 13157682SAli.Bahrami@Sun.COM * 13164716Sab196087 * versym->max_verndx has been updated to contain the largest 13174716Sab196087 * version index seen. 13184716Sab196087 */ 13194716Sab196087 static void 13207682SAli.Bahrami@Sun.COM update_gnu_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym) 13214716Sab196087 { 13224716Sab196087 Word cnt; 13234716Sab196087 13244716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 13254716Sab196087 vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 13264716Sab196087 Half vcnt = vnd->vn_cnt; 13274716Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 13284716Sab196087 13297682SAli.Bahrami@Sun.COM /* 13307682SAli.Bahrami@Sun.COM * A non-zero value of vna_other indicates that this 13317682SAli.Bahrami@Sun.COM * object references VERNEED items from the VERSYM 13327682SAli.Bahrami@Sun.COM * array. 13337682SAli.Bahrami@Sun.COM */ 13347682SAli.Bahrami@Sun.COM if (vnap->vna_other != 0) { 13357682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 13367682SAli.Bahrami@Sun.COM if (vnap->vna_other > versym->max_verndx) 13377682SAli.Bahrami@Sun.COM versym->max_verndx = vnap->vna_other; 13387682SAli.Bahrami@Sun.COM } 13394716Sab196087 13404716Sab196087 /* 13414716Sab196087 * Check any additional version dependencies. 13424716Sab196087 */ 13434716Sab196087 if (vcnt) { 13444716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 13454716Sab196087 for (vcnt--; vcnt; vcnt--, 13464716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + 13474716Sab196087 vnap->vna_next)) { 13487682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) 13497682SAli.Bahrami@Sun.COM continue; 13507682SAli.Bahrami@Sun.COM 13517682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 13524716Sab196087 if (vnap->vna_other > versym->max_verndx) 13534716Sab196087 versym->max_verndx = vnap->vna_other; 13540Sstevel@tonic-gate } 13550Sstevel@tonic-gate } 13560Sstevel@tonic-gate } 13570Sstevel@tonic-gate } 13580Sstevel@tonic-gate 13590Sstevel@tonic-gate /* 13603875Sab196087 * Display version section information if the flags require it. 13613875Sab196087 * Return version information needed by other output. 13623875Sab196087 * 13633875Sab196087 * entry: 13643875Sab196087 * cache - Cache of all section headers 13653875Sab196087 * shnum - # of sections in cache 13663875Sab196087 * file - Name of file 13673875Sab196087 * flags - Command line option flags 13683875Sab196087 * versym - VERSYM_STATE block to be filled in. 13690Sstevel@tonic-gate */ 13703875Sab196087 static void 13713875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags, 13723875Sab196087 VERSYM_STATE *versym) 13730Sstevel@tonic-gate { 13740Sstevel@tonic-gate GElf_Word cnt; 13754716Sab196087 Cache *verdef_cache = NULL, *verneed_cache = NULL; 13764716Sab196087 13774716Sab196087 13784716Sab196087 /* Gather information about the version sections */ 13793875Sab196087 bzero(versym, sizeof (*versym)); 13804716Sab196087 versym->max_verndx = 1; 13810Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 13821618Srie Cache *_cache = &cache[cnt]; 13831618Srie Shdr *shdr = _cache->c_shdr; 13844716Sab196087 Dyn *dyn; 13854716Sab196087 ulong_t numdyn; 13864716Sab196087 13874716Sab196087 switch (shdr->sh_type) { 13884716Sab196087 case SHT_DYNAMIC: 13894716Sab196087 /* 13904716Sab196087 * The GNU ld puts a DT_VERSYM entry in the dynamic 13914716Sab196087 * section so that the runtime linker can use it to 13924716Sab196087 * implement their versioning rules. They allow multiple 13934716Sab196087 * incompatible functions with the same name to exist 13944716Sab196087 * in different versions. The Solaris ld does not 13954716Sab196087 * support this mechanism, and as such, does not 13964716Sab196087 * produce DT_VERSYM. We use this fact to determine 13974716Sab196087 * which ld produced this object, and how to interpret 13984716Sab196087 * the version values. 13994716Sab196087 */ 14004716Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0) || 14014716Sab196087 (_cache->c_data == NULL)) 14024716Sab196087 continue; 14034716Sab196087 numdyn = shdr->sh_size / shdr->sh_entsize; 14044716Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 14054716Sab196087 for (; numdyn-- > 0; dyn++) 14064716Sab196087 if (dyn->d_tag == DT_VERSYM) { 14077682SAli.Bahrami@Sun.COM versym->gnu_full = 14087682SAli.Bahrami@Sun.COM versym->gnu_needed = 1; 14094716Sab196087 break; 14104716Sab196087 } 14114716Sab196087 break; 14124716Sab196087 14134716Sab196087 case SHT_SUNW_versym: 14144716Sab196087 /* Record data address for later symbol processing */ 14154716Sab196087 if (_cache->c_data != NULL) { 14164716Sab196087 versym->cache = _cache; 14174716Sab196087 versym->data = _cache->c_data->d_buf; 14184716Sab196087 continue; 14194716Sab196087 } 14204716Sab196087 break; 14214716Sab196087 14224716Sab196087 case SHT_SUNW_verdef: 14234716Sab196087 case SHT_SUNW_verneed: 14244716Sab196087 /* 14254716Sab196087 * Ensure the data is non-NULL and the number 14264716Sab196087 * of items is non-zero. Otherwise, we don't 14274716Sab196087 * understand the section, and will not use it. 14284716Sab196087 */ 14294716Sab196087 if ((_cache->c_data == NULL) || 14304716Sab196087 (_cache->c_data->d_buf == NULL)) { 14314716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 14324716Sab196087 file, _cache->c_name); 14334716Sab196087 continue; 14344716Sab196087 } 14354716Sab196087 if (shdr->sh_info == 0) { 14364716Sab196087 (void) fprintf(stderr, 14374716Sab196087 MSG_INTL(MSG_ERR_BADSHINFO), 14384716Sab196087 file, _cache->c_name, 14394716Sab196087 EC_WORD(shdr->sh_info)); 14404716Sab196087 continue; 14414716Sab196087 } 14424716Sab196087 14434716Sab196087 /* Make sure the string table index is in range */ 14444716Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 14454716Sab196087 (void) fprintf(stderr, 14464716Sab196087 MSG_INTL(MSG_ERR_BADSHLINK), file, 14474716Sab196087 _cache->c_name, EC_WORD(shdr->sh_link)); 14484716Sab196087 continue; 14494716Sab196087 } 14504716Sab196087 14514716Sab196087 /* 14524716Sab196087 * The section is usable. Save the cache entry. 14534716Sab196087 */ 14544716Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) { 14554716Sab196087 verdef_cache = _cache; 14564716Sab196087 /* 14574716Sab196087 * Under Solaris rules, if there is a verdef 14584716Sab196087 * section, the max versym index is number 14594716Sab196087 * of version definitions it supplies. 14604716Sab196087 */ 14614716Sab196087 versym->max_verndx = shdr->sh_info; 14624716Sab196087 } else { 14634716Sab196087 verneed_cache = _cache; 14644716Sab196087 } 14654716Sab196087 break; 14664716Sab196087 } 14674716Sab196087 } 14684716Sab196087 14697682SAli.Bahrami@Sun.COM /* 14707682SAli.Bahrami@Sun.COM * If there is a Verneed section, examine it for information 14717682SAli.Bahrami@Sun.COM * related to GNU style versioning. 14727682SAli.Bahrami@Sun.COM */ 14737682SAli.Bahrami@Sun.COM if (verneed_cache != NULL) 14747682SAli.Bahrami@Sun.COM update_gnu_verndx((Verneed *)verneed_cache->c_data->d_buf, 14757682SAli.Bahrami@Sun.COM verneed_cache->c_shdr->sh_info, versym); 14764716Sab196087 14774716Sab196087 /* 14784716Sab196087 * Now that all the information is available, display the 14797682SAli.Bahrami@Sun.COM * Verdef and Verneed section contents, if requested. 14804716Sab196087 */ 14817682SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_VERSIONS) == 0) 14827682SAli.Bahrami@Sun.COM return; 14834716Sab196087 if (verdef_cache != NULL) { 14844716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 14854716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), 14864716Sab196087 verdef_cache->c_name); 14874716Sab196087 version_def((Verdef *)verdef_cache->c_data->d_buf, 14884716Sab196087 verdef_cache->c_shdr->sh_info, verdef_cache, 14894716Sab196087 &cache[verdef_cache->c_shdr->sh_link], file); 14904716Sab196087 } 14914716Sab196087 if (verneed_cache != NULL) { 14924716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 14934716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), 14944716Sab196087 verneed_cache->c_name); 14950Sstevel@tonic-gate /* 14964716Sab196087 * If GNU versioning applies to this object, version_need() 14974716Sab196087 * will update versym->max_verndx, and it is not 14987682SAli.Bahrami@Sun.COM * necessary to call update_gnu_verndx(). 14990Sstevel@tonic-gate */ 15004716Sab196087 version_need((Verneed *)verneed_cache->c_data->d_buf, 15014716Sab196087 verneed_cache->c_shdr->sh_info, verneed_cache, 15024716Sab196087 &cache[verneed_cache->c_shdr->sh_link], file, versym); 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate /* 15073492Sab196087 * Initialize a symbol table state structure 15083492Sab196087 * 15093492Sab196087 * entry: 15103492Sab196087 * state - State structure to be initialized 15113492Sab196087 * cache - Cache of all section headers 15123492Sab196087 * shnum - # of sections in cache 15133492Sab196087 * secndx - Index of symbol table section 15143492Sab196087 * ehdr - ELF header for file 15153875Sab196087 * versym - Information about versym section 15163492Sab196087 * file - Name of file 15173492Sab196087 * flags - Command line option flags 15181618Srie */ 15191618Srie static int 15203492Sab196087 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx, 15219273SAli.Bahrami@Sun.COM Ehdr *ehdr, uchar_t osabi, VERSYM_STATE *versym, const char *file, 15229273SAli.Bahrami@Sun.COM uint_t flags) 15233492Sab196087 { 15243492Sab196087 Shdr *shdr; 15253492Sab196087 15263492Sab196087 state->file = file; 15273492Sab196087 state->ehdr = ehdr; 15283492Sab196087 state->cache = cache; 15299273SAli.Bahrami@Sun.COM state->osabi = osabi; 15303492Sab196087 state->shnum = shnum; 15313492Sab196087 state->seccache = &cache[secndx]; 15323492Sab196087 state->secndx = secndx; 15333492Sab196087 state->secname = state->seccache->c_name; 15343492Sab196087 state->flags = flags; 15353492Sab196087 state->shxndx.checked = 0; 15363492Sab196087 state->shxndx.data = NULL; 15373492Sab196087 state->shxndx.n = 0; 15383492Sab196087 15393492Sab196087 shdr = state->seccache->c_shdr; 15403492Sab196087 15413492Sab196087 /* 15423492Sab196087 * Check the symbol data and per-item size. 15433492Sab196087 */ 15443492Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 15453492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 15463492Sab196087 file, state->secname); 15473492Sab196087 return (0); 15483492Sab196087 } 15493492Sab196087 if (state->seccache->c_data == NULL) 15503492Sab196087 return (0); 15513492Sab196087 15523492Sab196087 /* LINTED */ 15533492Sab196087 state->symn = (Word)(shdr->sh_size / shdr->sh_entsize); 15543492Sab196087 state->sym = (Sym *)state->seccache->c_data->d_buf; 15553492Sab196087 15563492Sab196087 /* 15573492Sab196087 * Check associated string table section. 15583492Sab196087 */ 15593492Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 15603492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 15613492Sab196087 file, state->secname, EC_WORD(shdr->sh_link)); 15623492Sab196087 return (0); 15633492Sab196087 } 15643492Sab196087 15653492Sab196087 /* 15663492Sab196087 * Determine if there is a associated Versym section 15673492Sab196087 * with this Symbol Table. 15683492Sab196087 */ 15693875Sab196087 if (versym->cache && 15703875Sab196087 (versym->cache->c_shdr->sh_link == state->secndx)) 15713875Sab196087 state->versym = versym; 15723492Sab196087 else 15733492Sab196087 state->versym = NULL; 15743492Sab196087 15753492Sab196087 15763492Sab196087 return (1); 15773492Sab196087 } 15783492Sab196087 15793492Sab196087 /* 15803492Sab196087 * Determine the extended section index used for symbol tables entries. 15813492Sab196087 */ 15823492Sab196087 static void 15837463SRod.Evans@Sun.COM symbols_getxindex(SYMTBL_STATE *state) 15841618Srie { 15851618Srie uint_t symn; 15861618Srie Word symcnt; 15871618Srie 15883492Sab196087 state->shxndx.checked = 1; /* Note that we've been called */ 15893492Sab196087 for (symcnt = 1; symcnt < state->shnum; symcnt++) { 15903492Sab196087 Cache *_cache = &state->cache[symcnt]; 15911618Srie Shdr *shdr = _cache->c_shdr; 15921618Srie 15931618Srie if ((shdr->sh_type != SHT_SYMTAB_SHNDX) || 15943492Sab196087 (shdr->sh_link != state->secndx)) 15951618Srie continue; 15961618Srie 15971618Srie if ((shdr->sh_entsize) && 15981618Srie /* LINTED */ 15991618Srie ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0)) 16001618Srie continue; 16011618Srie 16023466Srie if (_cache->c_data == NULL) 16033466Srie continue; 16043466Srie 16053492Sab196087 state->shxndx.data = _cache->c_data->d_buf; 16063492Sab196087 state->shxndx.n = symn; 16073492Sab196087 return; 16081618Srie } 16091618Srie } 16101618Srie 16111618Srie /* 16123492Sab196087 * Produce a line of output for the given symbol 16133492Sab196087 * 16143492Sab196087 * entry: 16153875Sab196087 * state - Symbol table state 16163492Sab196087 * symndx - Index of symbol within the table 16174832Srie * info - Value of st_info (indicates local/global range) 16183492Sab196087 * symndx_disp - Index to display. This may not be the same 16193492Sab196087 * as symndx if the display is relative to the logical 16203492Sab196087 * combination of the SUNW_ldynsym/dynsym tables. 16213492Sab196087 * sym - Symbol to display 16220Sstevel@tonic-gate */ 16233492Sab196087 static void 16244832Srie output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx, 16254832Srie Sym *sym) 16260Sstevel@tonic-gate { 16273118Sab196087 /* 16283118Sab196087 * Symbol types for which we check that the specified 16293118Sab196087 * address/size land inside the target section. 16303118Sab196087 */ 16319085SAli.Bahrami@Sun.COM static const int addr_symtype[] = { 16323118Sab196087 0, /* STT_NOTYPE */ 16333118Sab196087 1, /* STT_OBJECT */ 16343118Sab196087 1, /* STT_FUNC */ 16353118Sab196087 0, /* STT_SECTION */ 16363118Sab196087 0, /* STT_FILE */ 16373118Sab196087 1, /* STT_COMMON */ 16383118Sab196087 0, /* STT_TLS */ 16399085SAli.Bahrami@Sun.COM 0, /* STT_IFUNC */ 16409085SAli.Bahrami@Sun.COM 0, /* 8 */ 16419085SAli.Bahrami@Sun.COM 0, /* 9 */ 16429085SAli.Bahrami@Sun.COM 0, /* 10 */ 16439085SAli.Bahrami@Sun.COM 0, /* 11 */ 16449085SAli.Bahrami@Sun.COM 0, /* 12 */ 16459085SAli.Bahrami@Sun.COM 0, /* STT_SPARC_REGISTER */ 16469085SAli.Bahrami@Sun.COM 0, /* 14 */ 16479085SAli.Bahrami@Sun.COM 0, /* 15 */ 16483118Sab196087 }; 16499085SAli.Bahrami@Sun.COM #if STT_NUM != (STT_IFUNC + 1) 16503492Sab196087 #error "STT_NUM has grown. Update addr_symtype[]" 16513118Sab196087 #endif 16523118Sab196087 16534665Sab196087 char index[MAXNDXSIZE]; 16544665Sab196087 const char *symname, *sec; 16553875Sab196087 Versym verndx; 16564716Sab196087 int gnuver; 16573492Sab196087 uchar_t type; 16583492Sab196087 Shdr *tshdr; 16593492Sab196087 Word shndx; 16604734Sab196087 Conv_inv_buf_t inv_buf; 16613492Sab196087 16623492Sab196087 /* Ensure symbol index is in range */ 16633492Sab196087 if (symndx >= state->symn) { 16643492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX), 16653492Sab196087 state->file, state->secname, EC_WORD(symndx)); 16663492Sab196087 return; 16673492Sab196087 } 16683492Sab196087 16693492Sab196087 /* 16703492Sab196087 * If we are using extended symbol indexes, find the 16713492Sab196087 * corresponding SHN_SYMTAB_SHNDX table. 16723492Sab196087 */ 16733492Sab196087 if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0)) 16743492Sab196087 symbols_getxindex(state); 16753492Sab196087 16763492Sab196087 /* LINTED */ 16773492Sab196087 symname = string(state->seccache, symndx, 16783492Sab196087 &state->cache[state->seccache->c_shdr->sh_link], state->file, 16793492Sab196087 sym->st_name); 16803492Sab196087 16819085SAli.Bahrami@Sun.COM tshdr = NULL; 16823492Sab196087 sec = NULL; 16833492Sab196087 16844665Sab196087 if (state->ehdr->e_type == ET_CORE) { 16853492Sab196087 sec = (char *)MSG_INTL(MSG_STR_UNKNOWN); 16865411Sab196087 } else if (state->flags & FLG_CTL_FAKESHDR) { 16874665Sab196087 /* 16884665Sab196087 * If we are using fake section headers derived from 16894665Sab196087 * the program headers, then the section indexes 16904665Sab196087 * in the symbols do not correspond to these headers. 16914665Sab196087 * The section names are not available, so all we can 16924665Sab196087 * do is to display them in numeric form. 16934665Sab196087 */ 16949273SAli.Bahrami@Sun.COM sec = conv_sym_shndx(state->osabi, state->ehdr->e_machine, 16959273SAli.Bahrami@Sun.COM sym->st_shndx, CONV_FMT_DECIMAL, &inv_buf); 16964665Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 16973492Sab196087 (sym->st_shndx < state->shnum)) { 16983492Sab196087 shndx = sym->st_shndx; 16993492Sab196087 tshdr = state->cache[shndx].c_shdr; 17003492Sab196087 sec = state->cache[shndx].c_name; 17013492Sab196087 } else if (sym->st_shndx == SHN_XINDEX) { 17023492Sab196087 if (state->shxndx.data) { 17033492Sab196087 Word _shxndx; 17043492Sab196087 17053492Sab196087 if (symndx > state->shxndx.n) { 17064433Sab196087 (void) fprintf(stderr, 17074433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 17084433Sab196087 state->file, state->secname, 17094433Sab196087 EC_WORD(symndx)); 17103492Sab196087 } else if ((_shxndx = 17113492Sab196087 state->shxndx.data[symndx]) > state->shnum) { 17124433Sab196087 (void) fprintf(stderr, 17134433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 17144433Sab196087 state->file, state->secname, 17154433Sab196087 EC_WORD(symndx), EC_WORD(_shxndx)); 17163492Sab196087 } else { 17174433Sab196087 shndx = _shxndx; 17184433Sab196087 tshdr = state->cache[shndx].c_shdr; 17194433Sab196087 sec = state->cache[shndx].c_name; 17203492Sab196087 } 17213492Sab196087 } else { 17223492Sab196087 (void) fprintf(stderr, 17233492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 17243492Sab196087 state->file, state->secname, EC_WORD(symndx)); 17253492Sab196087 } 17263492Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 17273492Sab196087 (sym->st_shndx >= state->shnum)) { 17283492Sab196087 (void) fprintf(stderr, 17293492Sab196087 MSG_INTL(MSG_ERR_BADSYM5), state->file, 17306206Sab196087 state->secname, EC_WORD(symndx), 17316206Sab196087 demangle(symname, state->flags), sym->st_shndx); 17323492Sab196087 } 17330Sstevel@tonic-gate 17343492Sab196087 /* 17353492Sab196087 * If versioning is available display the 17363875Sab196087 * version index. If not, then use 0. 17373492Sab196087 */ 17383875Sab196087 if (state->versym) { 17394716Sab196087 Versym test_verndx; 17404716Sab196087 17414716Sab196087 verndx = test_verndx = state->versym->data[symndx]; 17427682SAli.Bahrami@Sun.COM gnuver = state->versym->gnu_full; 17433875Sab196087 17443875Sab196087 /* 17453875Sab196087 * Check to see if this is a defined symbol with a 17463875Sab196087 * version index that is outside the valid range for 17474716Sab196087 * the file. The interpretation of this depends on 17484716Sab196087 * the style of versioning used by the object. 17493875Sab196087 * 17504716Sab196087 * Versions >= VER_NDX_LORESERVE have special meanings, 17514716Sab196087 * and are exempt from this checking. 17524716Sab196087 * 17534716Sab196087 * GNU style version indexes use the top bit of the 17544716Sab196087 * 16-bit index value (0x8000) as the "hidden bit". 17554716Sab196087 * We must mask off this bit in order to compare 17564716Sab196087 * the version against the maximum value. 17573875Sab196087 */ 17584716Sab196087 if (gnuver) 17594716Sab196087 test_verndx &= ~0x8000; 17604716Sab196087 17614716Sab196087 if ((test_verndx > state->versym->max_verndx) && 17624716Sab196087 (verndx < VER_NDX_LORESERVE)) 17634716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER), 17644716Sab196087 state->file, state->secname, EC_WORD(symndx), 17654716Sab196087 EC_HALF(test_verndx), state->versym->max_verndx); 17663875Sab196087 } else { 17673492Sab196087 verndx = 0; 17684716Sab196087 gnuver = 0; 17693875Sab196087 } 17703492Sab196087 17713492Sab196087 /* 17723492Sab196087 * Error checking for TLS. 17733492Sab196087 */ 17743492Sab196087 type = ELF_ST_TYPE(sym->st_info); 17753492Sab196087 if (type == STT_TLS) { 17763492Sab196087 if (tshdr && 17773492Sab196087 (sym->st_shndx != SHN_UNDEF) && 17783492Sab196087 ((tshdr->sh_flags & SHF_TLS) == 0)) { 17793492Sab196087 (void) fprintf(stderr, 17803492Sab196087 MSG_INTL(MSG_ERR_BADSYM3), state->file, 17816206Sab196087 state->secname, EC_WORD(symndx), 17826206Sab196087 demangle(symname, state->flags)); 17833492Sab196087 } 17843492Sab196087 } else if ((type != STT_SECTION) && sym->st_size && 17853492Sab196087 tshdr && (tshdr->sh_flags & SHF_TLS)) { 17863492Sab196087 (void) fprintf(stderr, 17873492Sab196087 MSG_INTL(MSG_ERR_BADSYM4), state->file, 17886206Sab196087 state->secname, EC_WORD(symndx), 17896206Sab196087 demangle(symname, state->flags)); 17903492Sab196087 } 17913492Sab196087 17923492Sab196087 /* 17933492Sab196087 * If a symbol with non-zero size has a type that 17943492Sab196087 * specifies an address, then make sure the location 17953492Sab196087 * it references is actually contained within the 17963492Sab196087 * section. UNDEF symbols don't count in this case, 17973492Sab196087 * so we ignore them. 17983492Sab196087 * 17993492Sab196087 * The meaning of the st_value field in a symbol 18003492Sab196087 * depends on the type of object. For a relocatable 18013492Sab196087 * object, it is the offset within the section. 18023492Sab196087 * For sharable objects, it is the offset relative to 18033492Sab196087 * the base of the object, and for other types, it is 18043492Sab196087 * the virtual address. To get an offset within the 18053492Sab196087 * section for non-ET_REL files, we subtract the 18063492Sab196087 * base address of the section. 18073492Sab196087 */ 18083492Sab196087 if (addr_symtype[type] && (sym->st_size > 0) && 18093492Sab196087 (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) || 18103492Sab196087 (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) { 18113492Sab196087 Word v = sym->st_value; 18123492Sab196087 if (state->ehdr->e_type != ET_REL) 18134832Srie v -= tshdr->sh_addr; 18143492Sab196087 if (((v + sym->st_size) > tshdr->sh_size)) { 18153492Sab196087 (void) fprintf(stderr, 18163492Sab196087 MSG_INTL(MSG_ERR_BADSYM6), state->file, 18176206Sab196087 state->secname, EC_WORD(symndx), 18186206Sab196087 demangle(symname, state->flags), 18193492Sab196087 EC_WORD(shndx), EC_XWORD(tshdr->sh_size), 18203492Sab196087 EC_XWORD(sym->st_value), EC_XWORD(sym->st_size)); 18213492Sab196087 } 18223492Sab196087 } 18233492Sab196087 18244832Srie /* 18254832Srie * A typical symbol table uses the sh_info field to indicate one greater 18264832Srie * than the symbol table index of the last local symbol, STB_LOCAL. 18274832Srie * Therefore, symbol indexes less than sh_info should have local 18284832Srie * binding. Symbol indexes greater than, or equal to sh_info, should 18294832Srie * have global binding. Note, we exclude UNDEF/NOTY symbols with zero 18304832Srie * value and size, as these symbols may be the result of an mcs(1) 18314832Srie * section deletion. 18324832Srie */ 18334832Srie if (info) { 18344832Srie uchar_t bind = ELF_ST_BIND(sym->st_info); 18354832Srie 18364832Srie if ((symndx < info) && (bind != STB_LOCAL)) { 18374832Srie (void) fprintf(stderr, 18384832Srie MSG_INTL(MSG_ERR_BADSYM7), state->file, 18396206Sab196087 state->secname, EC_WORD(symndx), 18406206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 18414832Srie 18424832Srie } else if ((symndx >= info) && (bind == STB_LOCAL) && 18434832Srie ((sym->st_shndx != SHN_UNDEF) || 18444832Srie (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) || 18454832Srie (sym->st_size != 0) || (sym->st_value != 0))) { 18464832Srie (void) fprintf(stderr, 18474832Srie MSG_INTL(MSG_ERR_BADSYM8), state->file, 18486206Sab196087 state->secname, EC_WORD(symndx), 18496206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 18504832Srie } 18514832Srie } 18524832Srie 18533492Sab196087 (void) snprintf(index, MAXNDXSIZE, 18543492Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx)); 18559273SAli.Bahrami@Sun.COM Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, state->osabi, 18564716Sab196087 state->ehdr->e_machine, sym, verndx, gnuver, sec, symname); 18573492Sab196087 } 18583492Sab196087 18593492Sab196087 /* 18603492Sab196087 * Search for and process any symbol tables. 18613492Sab196087 */ 18623492Sab196087 void 18639273SAli.Bahrami@Sun.COM symbols(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, 18649273SAli.Bahrami@Sun.COM VERSYM_STATE *versym, const char *file, uint_t flags) 18653492Sab196087 { 18663492Sab196087 SYMTBL_STATE state; 18673492Sab196087 Cache *_cache; 18683492Sab196087 Word secndx; 18693492Sab196087 18703492Sab196087 for (secndx = 1; secndx < shnum; secndx++) { 18713492Sab196087 Word symcnt; 18723492Sab196087 Shdr *shdr; 18733492Sab196087 18743492Sab196087 _cache = &cache[secndx]; 18753492Sab196087 shdr = _cache->c_shdr; 18760Sstevel@tonic-gate 18770Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) && 18782766Sab196087 (shdr->sh_type != SHT_DYNSYM) && 18799273SAli.Bahrami@Sun.COM ((shdr->sh_type != SHT_SUNW_LDYNSYM) || 18809273SAli.Bahrami@Sun.COM (osabi != ELFOSABI_SOLARIS))) 18810Sstevel@tonic-gate continue; 18825411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, secndx, shdr->sh_type)) 18833466Srie continue; 18843466Srie 18853492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr, 18869273SAli.Bahrami@Sun.COM osabi, versym, file, flags)) 18870Sstevel@tonic-gate continue; 18880Sstevel@tonic-gate /* 18890Sstevel@tonic-gate * Loop through the symbol tables entries. 18900Sstevel@tonic-gate */ 18911618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 18923492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname); 18931618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 18940Sstevel@tonic-gate 18953492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++) 18964832Srie output_symbol(&state, symcnt, shdr->sh_info, symcnt, 18973492Sab196087 state.sym + symcnt); 18983492Sab196087 } 18993492Sab196087 } 19000Sstevel@tonic-gate 19013492Sab196087 /* 19023492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections. 19033492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair. 19043492Sab196087 */ 19053492Sab196087 static void 19069273SAli.Bahrami@Sun.COM sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, 19079273SAli.Bahrami@Sun.COM VERSYM_STATE *versym, const char *file, uint_t flags) 19083492Sab196087 { 19093492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state; 19103492Sab196087 Cache *sortcache, *symcache; 19113492Sab196087 Shdr *sortshdr, *symshdr; 19123492Sab196087 Word sortsecndx, symsecndx; 19133492Sab196087 Word ldynsym_cnt; 19143492Sab196087 Word *ndx; 19153492Sab196087 Word ndxn; 19163492Sab196087 int output_cnt = 0; 19174734Sab196087 Conv_inv_buf_t inv_buf; 19180Sstevel@tonic-gate 19193492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) { 19200Sstevel@tonic-gate 19213492Sab196087 sortcache = &cache[sortsecndx]; 19223492Sab196087 sortshdr = sortcache->c_shdr; 19230Sstevel@tonic-gate 19243492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) && 19253492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort)) 19263492Sab196087 continue; 19275411Sab196087 if (!match(MATCH_F_ALL, sortcache->c_name, sortsecndx, 19285411Sab196087 sortshdr->sh_type)) 19293492Sab196087 continue; 19300Sstevel@tonic-gate 19313492Sab196087 /* 19323492Sab196087 * If the section references a SUNW_ldynsym, then we 19333492Sab196087 * expect to see the associated .dynsym immediately 19343492Sab196087 * following. If it references a .dynsym, there is no 19353492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't 19363492Sab196087 * know what to do with it. 19373492Sab196087 */ 19383492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) { 19393492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 19403492Sab196087 file, sortcache->c_name, 19413492Sab196087 EC_WORD(sortshdr->sh_link)); 19423492Sab196087 continue; 19433492Sab196087 } 19443492Sab196087 symcache = &cache[sortshdr->sh_link]; 19453492Sab196087 symshdr = symcache->c_shdr; 19463492Sab196087 symsecndx = sortshdr->sh_link; 19473492Sab196087 ldynsym_cnt = 0; 19483492Sab196087 switch (symshdr->sh_type) { 19493492Sab196087 case SHT_SUNW_LDYNSYM: 19503492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum, 19519273SAli.Bahrami@Sun.COM symsecndx, ehdr, osabi, versym, file, flags)) 19523492Sab196087 continue; 19533492Sab196087 ldynsym_cnt = ldynsym_state.symn; 19540Sstevel@tonic-gate /* 19553492Sab196087 * We know that the dynsym follows immediately 19563492Sab196087 * after the SUNW_ldynsym, and so, should be at 19573492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a 19583492Sab196087 * diagnostic tool, so we do the full paranoid 19593492Sab196087 * search instead. 19600Sstevel@tonic-gate */ 19613492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) { 19623492Sab196087 symcache = &cache[symsecndx]; 19633492Sab196087 symshdr = symcache->c_shdr; 19643492Sab196087 if (symshdr->sh_type == SHT_DYNSYM) 19653492Sab196087 break; 19663492Sab196087 } 19673492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */ 19680Sstevel@tonic-gate (void) fprintf(stderr, 19693492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM), 19703492Sab196087 file, sortcache->c_name); 19713492Sab196087 continue; 19720Sstevel@tonic-gate } 19733492Sab196087 /* Fallthrough to process associated dynsym */ 19747463SRod.Evans@Sun.COM /* FALLTHROUGH */ 19753492Sab196087 case SHT_DYNSYM: 19763492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum, 19779273SAli.Bahrami@Sun.COM symsecndx, ehdr, osabi, versym, file, flags)) 19783492Sab196087 continue; 19793492Sab196087 break; 19803492Sab196087 default: 19813492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC), 19829273SAli.Bahrami@Sun.COM file, sortcache->c_name, 19839273SAli.Bahrami@Sun.COM conv_sec_type(osabi, ehdr->e_machine, 19849273SAli.Bahrami@Sun.COM symshdr->sh_type, 0, &inv_buf)); 19853492Sab196087 continue; 19863492Sab196087 } 19870Sstevel@tonic-gate 19883492Sab196087 /* 19893492Sab196087 * Output header 19903492Sab196087 */ 19913492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 19923492Sab196087 if (ldynsym_cnt > 0) { 19933492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2), 19943492Sab196087 sortcache->c_name, ldynsym_state.secname, 19953492Sab196087 dynsym_state.secname); 19960Sstevel@tonic-gate /* 19973492Sab196087 * The data for .SUNW_ldynsym and dynsym sections 19983492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming 19993492Sab196087 * first. Check, and issue a warning if it isn't so. 20000Sstevel@tonic-gate */ 20014665Sab196087 if (((ldynsym_state.sym + ldynsym_state.symn) 20024665Sab196087 != dynsym_state.sym) && 20035411Sab196087 ((flags & FLG_CTL_FAKESHDR) == 0)) 20043492Sab196087 (void) fprintf(stderr, 20053492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file, 20063492Sab196087 ldynsym_state.secname, 20073492Sab196087 dynsym_state.secname); 20083492Sab196087 } else { 20093492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1), 20103492Sab196087 sortcache->c_name, dynsym_state.secname); 20113492Sab196087 } 20123492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 20133492Sab196087 20143492Sab196087 /* If not first one, insert a line of whitespace */ 20153492Sab196087 if (output_cnt++ > 0) 20163492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 20173118Sab196087 20183492Sab196087 /* 20193492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of 20203492Sab196087 * symbol indices. Iterate over the array entries, 20213492Sab196087 * dispaying the referenced symbols. 20223492Sab196087 */ 20233492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize; 20243492Sab196087 ndx = (Word *)sortcache->c_data->d_buf; 20253492Sab196087 for (; ndxn-- > 0; ndx++) { 20263492Sab196087 if (*ndx >= ldynsym_cnt) { 20273492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt; 20283492Sab196087 20294832Srie output_symbol(&dynsym_state, sec_ndx, 0, 20303492Sab196087 *ndx, dynsym_state.sym + sec_ndx); 20313492Sab196087 } else { 20324832Srie output_symbol(&ldynsym_state, *ndx, 0, 20333492Sab196087 *ndx, ldynsym_state.sym + *ndx); 20340Sstevel@tonic-gate } 20350Sstevel@tonic-gate } 20360Sstevel@tonic-gate } 20370Sstevel@tonic-gate } 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate /* 20400Sstevel@tonic-gate * Search for and process any relocation sections. 20410Sstevel@tonic-gate */ 20420Sstevel@tonic-gate static void 20437463SRod.Evans@Sun.COM reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 20440Sstevel@tonic-gate { 20451618Srie Word cnt; 20460Sstevel@tonic-gate 20470Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 20481618Srie Word type, symnum; 20491618Srie Xword relndx, relnum, relsize; 20501618Srie void *rels; 20511618Srie Sym *syms; 20521618Srie Cache *symsec, *strsec; 20530Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 20541618Srie Shdr *shdr = _cache->c_shdr; 20551618Srie char *relname = _cache->c_name; 20564734Sab196087 Conv_inv_buf_t inv_buf; 20570Sstevel@tonic-gate 20580Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) && 20590Sstevel@tonic-gate (type != SHT_REL)) 20600Sstevel@tonic-gate continue; 20615411Sab196087 if (!match(MATCH_F_ALL, relname, cnt, type)) 20620Sstevel@tonic-gate continue; 20630Sstevel@tonic-gate 20640Sstevel@tonic-gate /* 20651618Srie * Decide entry size. 20660Sstevel@tonic-gate */ 20671618Srie if (((relsize = shdr->sh_entsize) == 0) || 20681618Srie (relsize > shdr->sh_size)) { 20690Sstevel@tonic-gate if (type == SHT_RELA) 20701618Srie relsize = sizeof (Rela); 20710Sstevel@tonic-gate else 20721618Srie relsize = sizeof (Rel); 20730Sstevel@tonic-gate } 20740Sstevel@tonic-gate 20750Sstevel@tonic-gate /* 20760Sstevel@tonic-gate * Determine the number of relocations available. 20770Sstevel@tonic-gate */ 20780Sstevel@tonic-gate if (shdr->sh_size == 0) { 20790Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 20801618Srie file, relname); 20810Sstevel@tonic-gate continue; 20820Sstevel@tonic-gate } 20833466Srie if (_cache->c_data == NULL) 20843466Srie continue; 20853466Srie 20861618Srie rels = _cache->c_data->d_buf; 20871618Srie relnum = shdr->sh_size / relsize; 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate /* 20901618Srie * Get the data buffer for the associated symbol table and 20911618Srie * string table. 20920Sstevel@tonic-gate */ 20931618Srie if (stringtbl(cache, 1, cnt, shnum, file, 20941618Srie &symnum, &symsec, &strsec) == 0) 20950Sstevel@tonic-gate continue; 20961618Srie 20971618Srie syms = symsec->c_data->d_buf; 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate /* 21000Sstevel@tonic-gate * Loop through the relocation entries. 21010Sstevel@tonic-gate */ 21021618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 21031618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 21041618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type); 21050Sstevel@tonic-gate 21061618Srie for (relndx = 0; relndx < relnum; relndx++, 21071618Srie rels = (void *)((char *)rels + relsize)) { 21086206Sab196087 Half mach = ehdr->e_machine; 21090Sstevel@tonic-gate char section[BUFSIZ]; 21101618Srie const char *symname; 21111618Srie Word symndx, reltype; 21121618Srie Rela *rela; 21131618Srie Rel *rel; 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate /* 21161618Srie * Unravel the relocation and determine the symbol with 21171618Srie * which this relocation is associated. 21180Sstevel@tonic-gate */ 21190Sstevel@tonic-gate if (type == SHT_RELA) { 21201618Srie rela = (Rela *)rels; 21211618Srie symndx = ELF_R_SYM(rela->r_info); 21226206Sab196087 reltype = ELF_R_TYPE(rela->r_info, mach); 21230Sstevel@tonic-gate } else { 21241618Srie rel = (Rel *)rels; 21251618Srie symndx = ELF_R_SYM(rel->r_info); 21266206Sab196087 reltype = ELF_R_TYPE(rel->r_info, mach); 21270Sstevel@tonic-gate } 21281618Srie 21291618Srie symname = relsymname(cache, _cache, strsec, symndx, 21307463SRod.Evans@Sun.COM symnum, relndx, syms, section, BUFSIZ, file); 21311618Srie 21321618Srie /* 21331618Srie * A zero symbol index is only valid for a few 21341618Srie * relocations. 21351618Srie */ 21361618Srie if (symndx == 0) { 21371618Srie int badrel = 0; 21380Sstevel@tonic-gate 21391618Srie if ((mach == EM_SPARC) || 21401618Srie (mach == EM_SPARC32PLUS) || 21411618Srie (mach == EM_SPARCV9)) { 21421618Srie if ((reltype != R_SPARC_NONE) && 21431618Srie (reltype != R_SPARC_REGISTER) && 21441618Srie (reltype != R_SPARC_RELATIVE)) 21451618Srie badrel++; 21461618Srie } else if (mach == EM_386) { 21471618Srie if ((reltype != R_386_NONE) && 21481618Srie (reltype != R_386_RELATIVE)) 21491618Srie badrel++; 21501618Srie } else if (mach == EM_AMD64) { 21511618Srie if ((reltype != R_AMD64_NONE) && 21521618Srie (reltype != R_AMD64_RELATIVE)) 21531618Srie badrel++; 21541618Srie } 21551618Srie 21561618Srie if (badrel) { 21571618Srie (void) fprintf(stderr, 21581618Srie MSG_INTL(MSG_ERR_BADREL1), file, 21594734Sab196087 conv_reloc_type(mach, reltype, 21604734Sab196087 0, &inv_buf)); 21610Sstevel@tonic-gate } 21620Sstevel@tonic-gate } 21630Sstevel@tonic-gate 21641618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP, 21651618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type, 21661618Srie rels, relname, symname, 0); 21670Sstevel@tonic-gate } 21680Sstevel@tonic-gate } 21690Sstevel@tonic-gate } 21700Sstevel@tonic-gate 21715230Sab196087 21725230Sab196087 /* 21735230Sab196087 * This value controls which test dyn_test() performs. 21745230Sab196087 */ 21755230Sab196087 typedef enum { DYN_TEST_ADDR, DYN_TEST_SIZE, DYN_TEST_ENTSIZE } dyn_test_t; 21765230Sab196087 21775230Sab196087 /* 21785230Sab196087 * Used by dynamic() to compare the value of a dynamic element against 21795230Sab196087 * the starting address of the section it references. 21805230Sab196087 * 21815230Sab196087 * entry: 21825230Sab196087 * test_type - Specify which dyn item is being tested. 21835230Sab196087 * sh_type - SHT_* type value for required section. 21845230Sab196087 * sec_cache - Cache entry for section, or NULL if the object lacks 21855230Sab196087 * a section of this type. 21865230Sab196087 * dyn - Dyn entry to be tested 21875230Sab196087 * dynsec_cnt - # of dynamic section being examined. The first 21885230Sab196087 * dynamic section is 1, the next is 2, and so on... 21895230Sab196087 * ehdr - ELF header for file 21905230Sab196087 * file - Name of file 21915230Sab196087 */ 21925230Sab196087 static void 21935230Sab196087 dyn_test(dyn_test_t test_type, Word sh_type, Cache *sec_cache, Dyn *dyn, 21949273SAli.Bahrami@Sun.COM Word dynsec_cnt, Ehdr *ehdr, uchar_t osabi, const char *file) 21955230Sab196087 { 21965230Sab196087 Conv_inv_buf_t buf1, buf2; 21975230Sab196087 21985230Sab196087 /* 21995230Sab196087 * These tests are based around the implicit assumption that 22005230Sab196087 * there is only one dynamic section in an object, and also only 22015230Sab196087 * one of the sections it references. We have therefore gathered 22025230Sab196087 * all of the necessary information to test this in a single pass 22035230Sab196087 * over the section headers, which is very efficient. We are not 22045230Sab196087 * aware of any case where more than one dynamic section would 22055230Sab196087 * be meaningful in an ELF object, so this is a reasonable solution. 22065230Sab196087 * 22075230Sab196087 * To test multiple dynamic sections correctly would be more 22085230Sab196087 * expensive in code and time. We would have to build a data structure 22095230Sab196087 * containing all the dynamic elements. Then, we would use the address 22105230Sab196087 * to locate the section it references and ensure the section is of 22115230Sab196087 * the right type and that the address in the dynamic element is 22125230Sab196087 * to the start of the section. Then, we could check the size and 22135230Sab196087 * entsize values against those same sections. This is O(n^2), and 22145230Sab196087 * also complicated. 22155230Sab196087 * 22165230Sab196087 * In the highly unlikely case that there is more than one dynamic 22175230Sab196087 * section, we only test the first one, and simply allow the values 22185230Sab196087 * of the subsequent one to be displayed unchallenged. 22195230Sab196087 */ 22205230Sab196087 if (dynsec_cnt != 1) 22215230Sab196087 return; 22225230Sab196087 22235230Sab196087 /* 22245230Sab196087 * A DT_ item that references a section address should always find 22255230Sab196087 * the section in the file. 22265230Sab196087 */ 22275230Sab196087 if (sec_cache == NULL) { 22286299Sab196087 const char *name; 22296299Sab196087 22306299Sab196087 /* 22316299Sab196087 * Supply section names instead of section types for 22326299Sab196087 * things that reference progbits so that the error 22336299Sab196087 * message will make more sense. 22346299Sab196087 */ 22356299Sab196087 switch (dyn->d_tag) { 22366299Sab196087 case DT_INIT: 22376299Sab196087 name = MSG_ORIG(MSG_ELF_INIT); 22386299Sab196087 break; 22396299Sab196087 case DT_FINI: 22406299Sab196087 name = MSG_ORIG(MSG_ELF_FINI); 22416299Sab196087 break; 22426299Sab196087 default: 22439273SAli.Bahrami@Sun.COM name = conv_sec_type(osabi, ehdr->e_machine, 22449273SAli.Bahrami@Sun.COM sh_type, 0, &buf1); 22456299Sab196087 break; 22466299Sab196087 } 22475230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNNOBCKSEC), file, 22489273SAli.Bahrami@Sun.COM name, conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine, 22499273SAli.Bahrami@Sun.COM 0, &buf2)); 22505230Sab196087 return; 22515230Sab196087 } 22525230Sab196087 22535230Sab196087 22545230Sab196087 switch (test_type) { 22555230Sab196087 case DYN_TEST_ADDR: 22565230Sab196087 /* The section address should match the DT_ item value */ 22575230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_addr) 22585230Sab196087 (void) fprintf(stderr, 22595230Sab196087 MSG_INTL(MSG_ERR_DYNBADADDR), file, 22609273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine, 22619273SAli.Bahrami@Sun.COM 0, &buf1), EC_ADDR(dyn->d_un.d_val), 22629273SAli.Bahrami@Sun.COM sec_cache->c_ndx, sec_cache->c_name, 22635230Sab196087 EC_ADDR(sec_cache->c_shdr->sh_addr)); 22645230Sab196087 break; 22655230Sab196087 22665230Sab196087 case DYN_TEST_SIZE: 22675230Sab196087 /* The section size should match the DT_ item value */ 22685230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_size) 22695230Sab196087 (void) fprintf(stderr, 22705230Sab196087 MSG_INTL(MSG_ERR_DYNBADSIZE), file, 22719273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine, 22729273SAli.Bahrami@Sun.COM 0, &buf1), EC_XWORD(dyn->d_un.d_val), 22735230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 22745230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_size)); 22755230Sab196087 break; 22765230Sab196087 22775230Sab196087 case DYN_TEST_ENTSIZE: 22785230Sab196087 /* The sh_entsize value should match the DT_ item value */ 22795230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_entsize) 22805230Sab196087 (void) fprintf(stderr, 22815230Sab196087 MSG_INTL(MSG_ERR_DYNBADENTSIZE), file, 22829273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine, 22839273SAli.Bahrami@Sun.COM 0, &buf1), EC_XWORD(dyn->d_un.d_val), 22845230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 22855230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_entsize)); 22865230Sab196087 break; 22875230Sab196087 } 22885230Sab196087 } 22895230Sab196087 22905230Sab196087 22910Sstevel@tonic-gate /* 22926299Sab196087 * There are some DT_ entries that have corresponding symbols 22936299Sab196087 * (e.g. DT_INIT and _init). It is expected that these items will 22946299Sab196087 * both have the same value if both are present. This routine 22956299Sab196087 * examines the well known symbol tables for such symbols and 22966299Sab196087 * issues warnings for any that don't match. 22976299Sab196087 * 22986299Sab196087 * entry: 22996299Sab196087 * dyn - Dyn entry to be tested 23006299Sab196087 * symname - Name of symbol that corresponds to dyn 23016299Sab196087 * symtab_cache, dynsym_cache, ldynsym_cache - Symbol tables to check 23026299Sab196087 * cache - Cache of all section headers 23036299Sab196087 * shnum - # of sections in cache 23046299Sab196087 * ehdr - ELF header for file 23056299Sab196087 * file - Name of file 23066299Sab196087 */ 23076299Sab196087 static void 23086299Sab196087 dyn_symtest(Dyn *dyn, const char *symname, Cache *symtab_cache, 23096299Sab196087 Cache *dynsym_cache, Cache *ldynsym_cache, Cache *cache, 23109273SAli.Bahrami@Sun.COM Word shnum, Ehdr *ehdr, uchar_t osabi, const char *file) 23116299Sab196087 { 23126299Sab196087 Conv_inv_buf_t buf; 23136299Sab196087 int i; 23146299Sab196087 Sym *sym; 23156299Sab196087 Cache *_cache; 23166299Sab196087 23176299Sab196087 for (i = 0; i < 3; i++) { 23186299Sab196087 switch (i) { 23196299Sab196087 case 0: 23206299Sab196087 _cache = symtab_cache; 23216299Sab196087 break; 23226299Sab196087 case 1: 23236299Sab196087 _cache = dynsym_cache; 23246299Sab196087 break; 23256299Sab196087 case 2: 23266299Sab196087 _cache = ldynsym_cache; 23276299Sab196087 break; 23286299Sab196087 } 23296299Sab196087 23306299Sab196087 if ((_cache != NULL) && 23316299Sab196087 symlookup(symname, cache, shnum, &sym, _cache, file) && 23326299Sab196087 (sym->st_value != dyn->d_un.d_val)) 23336299Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNSYMVAL), 23349273SAli.Bahrami@Sun.COM file, _cache->c_name, conv_dyn_tag(dyn->d_tag, 23359273SAli.Bahrami@Sun.COM osabi, ehdr->e_machine, 0, &buf), 23366299Sab196087 symname, EC_ADDR(sym->st_value)); 23376299Sab196087 } 23386299Sab196087 } 23396299Sab196087 23406299Sab196087 23416299Sab196087 /* 23420Sstevel@tonic-gate * Search for and process a .dynamic section. 23430Sstevel@tonic-gate */ 23440Sstevel@tonic-gate static void 23459273SAli.Bahrami@Sun.COM dynamic(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, const char *file) 23460Sstevel@tonic-gate { 23475230Sab196087 struct { 23486299Sab196087 Cache *symtab; 23495230Sab196087 Cache *dynstr; 23505230Sab196087 Cache *dynsym; 23515230Sab196087 Cache *hash; 23525230Sab196087 Cache *fini; 23535230Sab196087 Cache *fini_array; 23545230Sab196087 Cache *init; 23555230Sab196087 Cache *init_array; 23565230Sab196087 Cache *preinit_array; 23575230Sab196087 Cache *rel; 23585230Sab196087 Cache *rela; 23595230Sab196087 Cache *sunw_cap; 23605230Sab196087 Cache *sunw_ldynsym; 23615230Sab196087 Cache *sunw_move; 23625230Sab196087 Cache *sunw_syminfo; 23635230Sab196087 Cache *sunw_symsort; 23645230Sab196087 Cache *sunw_tlssort; 23655230Sab196087 Cache *sunw_verdef; 23665230Sab196087 Cache *sunw_verneed; 23675230Sab196087 Cache *sunw_versym; 23685230Sab196087 } sec; 23695230Sab196087 Word dynsec_ndx; 23705230Sab196087 Word dynsec_num; 23715230Sab196087 int dynsec_cnt; 23721618Srie Word cnt; 23739273SAli.Bahrami@Sun.COM int osabi_solaris = osabi == ELFOSABI_SOLARIS; 23740Sstevel@tonic-gate 23755230Sab196087 /* 23765230Sab196087 * Make a pass over all the sections, gathering section information 23775230Sab196087 * we'll need below. 23785230Sab196087 */ 23795230Sab196087 dynsec_num = 0; 23805230Sab196087 bzero(&sec, sizeof (sec)); 23810Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 23825230Sab196087 Cache *_cache = &cache[cnt]; 23835230Sab196087 23845230Sab196087 switch (_cache->c_shdr->sh_type) { 23855230Sab196087 case SHT_DYNAMIC: 23865230Sab196087 if (dynsec_num == 0) { 23875230Sab196087 dynsec_ndx = cnt; 23885230Sab196087 23895230Sab196087 /* Does it have a valid string table? */ 23905230Sab196087 (void) stringtbl(cache, 0, cnt, shnum, file, 23915230Sab196087 0, 0, &sec.dynstr); 23925230Sab196087 } 23935230Sab196087 dynsec_num++; 23945230Sab196087 break; 23955230Sab196087 23965230Sab196087 23975230Sab196087 case SHT_PROGBITS: 23985230Sab196087 /* 23995230Sab196087 * We want to detect the .init and .fini sections, 24005230Sab196087 * if present. These are SHT_PROGBITS, so all we 24015230Sab196087 * have to go on is the section name. Normally comparing 24025230Sab196087 * names is a bad idea, but there are some special 24035230Sab196087 * names (i.e. .init/.fini/.interp) that are very 24045230Sab196087 * difficult to use in any other context, and for 24055230Sab196087 * these symbols, we do the heuristic match. 24065230Sab196087 */ 24075230Sab196087 if (strcmp(_cache->c_name, 24085230Sab196087 MSG_ORIG(MSG_ELF_INIT)) == 0) { 24095230Sab196087 if (sec.init == NULL) 24105230Sab196087 sec.init = _cache; 24115230Sab196087 } else if (strcmp(_cache->c_name, 24125230Sab196087 MSG_ORIG(MSG_ELF_FINI)) == 0) { 24135230Sab196087 if (sec.fini == NULL) 24145230Sab196087 sec.fini = _cache; 24155230Sab196087 } 24165230Sab196087 break; 24175230Sab196087 24185230Sab196087 case SHT_REL: 24195230Sab196087 /* 24205230Sab196087 * We want the SHT_REL section with the lowest 24215230Sab196087 * offset. The linker gathers them together, 24225230Sab196087 * and puts the address of the first one 24235230Sab196087 * into the DT_REL dynamic element. 24245230Sab196087 */ 24255230Sab196087 if ((sec.rel == NULL) || 24265230Sab196087 (_cache->c_shdr->sh_offset < 24275230Sab196087 sec.rel->c_shdr->sh_offset)) 24285230Sab196087 sec.rel = _cache; 24295230Sab196087 break; 24305230Sab196087 24315230Sab196087 case SHT_RELA: 24325230Sab196087 /* RELA is handled just like RELA above */ 24335230Sab196087 if ((sec.rela == NULL) || 24345230Sab196087 (_cache->c_shdr->sh_offset < 24355230Sab196087 sec.rela->c_shdr->sh_offset)) 24365230Sab196087 sec.rela = _cache; 24375230Sab196087 break; 24385230Sab196087 24395230Sab196087 /* 24405230Sab196087 * The GRAB macro is used for the simple case in which 24415230Sab196087 * we simply grab the first section of the desired type. 24425230Sab196087 */ 24435230Sab196087 #define GRAB(_sec_type, _sec_field) \ 24445230Sab196087 case _sec_type: \ 24455230Sab196087 if (sec._sec_field == NULL) \ 24465230Sab196087 sec._sec_field = _cache; \ 24475230Sab196087 break 24486299Sab196087 GRAB(SHT_SYMTAB, symtab); 24495230Sab196087 GRAB(SHT_DYNSYM, dynsym); 24505230Sab196087 GRAB(SHT_FINI_ARRAY, fini_array); 24515230Sab196087 GRAB(SHT_HASH, hash); 24525230Sab196087 GRAB(SHT_INIT_ARRAY, init_array); 24535230Sab196087 GRAB(SHT_SUNW_move, sunw_move); 24545230Sab196087 GRAB(SHT_PREINIT_ARRAY, preinit_array); 24555230Sab196087 GRAB(SHT_SUNW_cap, sunw_cap); 24565230Sab196087 GRAB(SHT_SUNW_LDYNSYM, sunw_ldynsym); 24575230Sab196087 GRAB(SHT_SUNW_syminfo, sunw_syminfo); 24585230Sab196087 GRAB(SHT_SUNW_symsort, sunw_symsort); 24595230Sab196087 GRAB(SHT_SUNW_tlssort, sunw_tlssort); 24605230Sab196087 GRAB(SHT_SUNW_verdef, sunw_verdef); 24615230Sab196087 GRAB(SHT_SUNW_verneed, sunw_verneed); 24625230Sab196087 GRAB(SHT_SUNW_versym, sunw_versym); 24635230Sab196087 #undef GRAB 24645230Sab196087 } 24655230Sab196087 } 24665230Sab196087 24675230Sab196087 /* 24685230Sab196087 * If no dynamic section, return immediately. If more than one 24695230Sab196087 * dynamic section, then something odd is going on and an error 24705230Sab196087 * is in order, but then continue on and display them all. 24715230Sab196087 */ 24725230Sab196087 if (dynsec_num == 0) 24735230Sab196087 return; 24745230Sab196087 if (dynsec_num > 1) 24755230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MULTDYN), 24765230Sab196087 file, EC_WORD(dynsec_num)); 24775230Sab196087 24785230Sab196087 24795230Sab196087 dynsec_cnt = 0; 24805230Sab196087 for (cnt = dynsec_ndx; (cnt < shnum) && (dynsec_cnt < dynsec_num); 24815230Sab196087 cnt++) { 24821618Srie Dyn *dyn; 24831618Srie ulong_t numdyn; 24843850Sab196087 int ndx, end_ndx; 24851618Srie Cache *_cache = &cache[cnt], *strsec; 24861618Srie Shdr *shdr = _cache->c_shdr; 24875230Sab196087 int dumped = 0; 24880Sstevel@tonic-gate 24890Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC) 24900Sstevel@tonic-gate continue; 24915230Sab196087 dynsec_cnt++; 24920Sstevel@tonic-gate 24930Sstevel@tonic-gate /* 24941618Srie * Verify the associated string table section. 24950Sstevel@tonic-gate */ 24961618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0) 24970Sstevel@tonic-gate continue; 24981618Srie 24993466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 25003466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 25013466Srie file, _cache->c_name); 25023466Srie continue; 25033466Srie } 25043466Srie if (_cache->c_data == NULL) 25053466Srie continue; 25063466Srie 25070Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize; 25081618Srie dyn = (Dyn *)_cache->c_data->d_buf; 25090Sstevel@tonic-gate 25105230Sab196087 /* 25115230Sab196087 * We expect the REL/RELA entries to reference the reloc 25125230Sab196087 * section with the lowest address. However, this is 25135230Sab196087 * not true for dumped objects. Detect if this object has 25145230Sab196087 * been dumped so that we can skip the reloc address test 25155230Sab196087 * in that case. 25165230Sab196087 */ 25175230Sab196087 for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 25185230Sab196087 if (dyn->d_tag == DT_FLAGS_1) { 25195230Sab196087 dumped = (dyn->d_un.d_val & DF_1_CONFALT) != 0; 25205230Sab196087 break; 25215230Sab196087 } 25225230Sab196087 } 25235230Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 25245230Sab196087 25251618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 25261618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 25270Sstevel@tonic-gate 25281618Srie Elf_dyn_title(0); 25290Sstevel@tonic-gate 25301618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 25314734Sab196087 union { 25326206Sab196087 Conv_inv_buf_t inv; 25334734Sab196087 Conv_dyn_flag_buf_t flag; 25344734Sab196087 Conv_dyn_flag1_buf_t flag1; 25354734Sab196087 Conv_dyn_posflag1_buf_t posflag1; 25364734Sab196087 Conv_dyn_feature1_buf_t feature1; 25374734Sab196087 } c_buf; 25385230Sab196087 const char *name = NULL; 25390Sstevel@tonic-gate 25400Sstevel@tonic-gate /* 25410Sstevel@tonic-gate * Print the information numerically, and if possible 25425230Sab196087 * as a string. If a string is available, name is 25435230Sab196087 * set to reference it. 25445230Sab196087 * 25455230Sab196087 * Also, take this opportunity to sanity check 25465230Sab196087 * the values of DT elements. In the code above, 25475230Sab196087 * we gathered information on sections that are 25485230Sab196087 * referenced by the dynamic section. Here, we 25495230Sab196087 * compare the attributes of those sections to 25505230Sab196087 * the DT_ items that reference them and report 25515230Sab196087 * on inconsistencies. 25525230Sab196087 * 25535230Sab196087 * Things not currently tested that could be improved 25545230Sab196087 * in later revisions include: 25555230Sab196087 * - We don't check PLT or GOT related items 25565230Sab196087 * - We don't handle computing the lengths of 25575230Sab196087 * relocation arrays. To handle this 25585230Sab196087 * requires examining data that spans 25595230Sab196087 * across sections, in a contiguous span 25605230Sab196087 * within a single segment. 25615230Sab196087 * - DT_VERDEFNUM and DT_VERNEEDNUM can't be 25625230Sab196087 * verified without parsing the sections. 25635230Sab196087 * - We don't handle DT_SUNW_SYMSZ, which would 25645230Sab196087 * be the sum of the lengths of .dynsym and 25655230Sab196087 * .SUNW_ldynsym 25665230Sab196087 * - DT_SUNW_STRPAD can't be verified other than 25675230Sab196087 * to check that it's not larger than 25685230Sab196087 * the string table. 25695230Sab196087 * - Some items come in "all or none" clusters 25705230Sab196087 * that give an address, element size, 25715230Sab196087 * and data length in bytes. We don't 25725230Sab196087 * verify that there are no missing items 25735230Sab196087 * in such groups. 25740Sstevel@tonic-gate */ 25753850Sab196087 switch (dyn->d_tag) { 25763850Sab196087 case DT_NULL: 25773850Sab196087 /* 25783850Sab196087 * Special case: DT_NULLs can come in groups 25793850Sab196087 * that we prefer to reduce to a single line. 25803850Sab196087 */ 25813850Sab196087 end_ndx = ndx; 25823850Sab196087 while ((end_ndx < (numdyn - 1)) && 25834433Sab196087 ((dyn + 1)->d_tag == DT_NULL)) { 25843850Sab196087 dyn++; 25853850Sab196087 end_ndx++; 25863850Sab196087 } 25873850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 25883850Sab196087 ndx = end_ndx; 25893850Sab196087 continue; 25903850Sab196087 25913850Sab196087 /* 25925230Sab196087 * String items all reference the dynstr. The string() 25935230Sab196087 * function does the necessary sanity checking. 25943850Sab196087 */ 25953850Sab196087 case DT_NEEDED: 25963850Sab196087 case DT_SONAME: 25973850Sab196087 case DT_FILTER: 25983850Sab196087 case DT_AUXILIARY: 25993850Sab196087 case DT_CONFIG: 26003850Sab196087 case DT_RPATH: 26013850Sab196087 case DT_RUNPATH: 26023850Sab196087 case DT_USED: 26033850Sab196087 case DT_DEPAUDIT: 26043850Sab196087 case DT_AUDIT: 26059273SAli.Bahrami@Sun.COM name = string(_cache, ndx, strsec, 26069273SAli.Bahrami@Sun.COM file, dyn->d_un.d_ptr); 26079273SAli.Bahrami@Sun.COM break; 26089273SAli.Bahrami@Sun.COM 26093850Sab196087 case DT_SUNW_AUXILIARY: 26103850Sab196087 case DT_SUNW_FILTER: 26119273SAli.Bahrami@Sun.COM if (osabi_solaris) 26129273SAli.Bahrami@Sun.COM name = string(_cache, ndx, strsec, 26139273SAli.Bahrami@Sun.COM file, dyn->d_un.d_ptr); 26143850Sab196087 break; 26153850Sab196087 26163850Sab196087 case DT_FLAGS: 26174734Sab196087 name = conv_dyn_flag(dyn->d_un.d_val, 26184734Sab196087 0, &c_buf.flag); 26193850Sab196087 break; 26203850Sab196087 case DT_FLAGS_1: 26215088Sab196087 name = conv_dyn_flag1(dyn->d_un.d_val, 0, 26224734Sab196087 &c_buf.flag1); 26233850Sab196087 break; 26243850Sab196087 case DT_POSFLAG_1: 26254734Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0, 26264734Sab196087 &c_buf.posflag1); 26273850Sab196087 break; 26283850Sab196087 case DT_FEATURE_1: 26294734Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0, 26304734Sab196087 &c_buf.feature1); 26313850Sab196087 break; 26323850Sab196087 case DT_DEPRECATED_SPARC_REGISTER: 26331618Srie name = MSG_INTL(MSG_STR_DEPRECATED); 26343850Sab196087 break; 26355230Sab196087 26366206Sab196087 case DT_SUNW_LDMACH: 26379273SAli.Bahrami@Sun.COM if (!osabi_solaris) 26389273SAli.Bahrami@Sun.COM break; 26399273SAli.Bahrami@Sun.COM name = conv_ehdr_mach((Half)dyn->d_un.d_val, 26409273SAli.Bahrami@Sun.COM 0, &c_buf.inv); 26416206Sab196087 break; 26426206Sab196087 26435230Sab196087 /* 26445230Sab196087 * Cases below this point are strictly sanity checking, 26455230Sab196087 * and do not generate a name string. The TEST_ macros 26465230Sab196087 * are used to hide the boilerplate arguments neeeded 26475230Sab196087 * by dyn_test(). 26485230Sab196087 */ 26495230Sab196087 #define TEST_ADDR(_sh_type, _sec_field) \ 26505230Sab196087 dyn_test(DYN_TEST_ADDR, _sh_type, \ 26519273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \ 26529273SAli.Bahrami@Sun.COM osabi, file) 26535230Sab196087 #define TEST_SIZE(_sh_type, _sec_field) \ 26545230Sab196087 dyn_test(DYN_TEST_SIZE, _sh_type, \ 26559273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \ 26569273SAli.Bahrami@Sun.COM osabi, file) 26575230Sab196087 #define TEST_ENTSIZE(_sh_type, _sec_field) \ 26585230Sab196087 dyn_test(DYN_TEST_ENTSIZE, _sh_type, \ 26599273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \ 26609273SAli.Bahrami@Sun.COM osabi, file) 26615230Sab196087 26625230Sab196087 case DT_FINI: 26636299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_FINI), 26646299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 26659273SAli.Bahrami@Sun.COM cache, shnum, ehdr, osabi, file); 26665230Sab196087 TEST_ADDR(SHT_PROGBITS, fini); 26675230Sab196087 break; 26685230Sab196087 26695230Sab196087 case DT_FINI_ARRAY: 26705230Sab196087 TEST_ADDR(SHT_FINI_ARRAY, fini_array); 26715230Sab196087 break; 26725230Sab196087 26735230Sab196087 case DT_FINI_ARRAYSZ: 26745230Sab196087 TEST_SIZE(SHT_FINI_ARRAY, fini_array); 26755230Sab196087 break; 26765230Sab196087 26775230Sab196087 case DT_HASH: 26785230Sab196087 TEST_ADDR(SHT_HASH, hash); 26795230Sab196087 break; 26805230Sab196087 26815230Sab196087 case DT_INIT: 26826299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_INIT), 26836299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 26849273SAli.Bahrami@Sun.COM cache, shnum, ehdr, osabi, file); 26855230Sab196087 TEST_ADDR(SHT_PROGBITS, init); 26865230Sab196087 break; 26875230Sab196087 26885230Sab196087 case DT_INIT_ARRAY: 26895230Sab196087 TEST_ADDR(SHT_INIT_ARRAY, init_array); 26905230Sab196087 break; 26915230Sab196087 26925230Sab196087 case DT_INIT_ARRAYSZ: 26935230Sab196087 TEST_SIZE(SHT_INIT_ARRAY, init_array); 26945230Sab196087 break; 26955230Sab196087 26965230Sab196087 case DT_MOVEENT: 26975230Sab196087 TEST_ENTSIZE(SHT_SUNW_move, sunw_move); 26985230Sab196087 break; 26995230Sab196087 27005230Sab196087 case DT_MOVESZ: 27015230Sab196087 TEST_SIZE(SHT_SUNW_move, sunw_move); 27025230Sab196087 break; 27035230Sab196087 27045230Sab196087 case DT_MOVETAB: 27055230Sab196087 TEST_ADDR(SHT_SUNW_move, sunw_move); 27065230Sab196087 break; 27075230Sab196087 27085230Sab196087 case DT_PREINIT_ARRAY: 27095230Sab196087 TEST_ADDR(SHT_PREINIT_ARRAY, preinit_array); 27105230Sab196087 break; 27115230Sab196087 27125230Sab196087 case DT_PREINIT_ARRAYSZ: 27135230Sab196087 TEST_SIZE(SHT_PREINIT_ARRAY, preinit_array); 27145230Sab196087 break; 27155230Sab196087 27165230Sab196087 case DT_REL: 27175230Sab196087 if (!dumped) 27185230Sab196087 TEST_ADDR(SHT_REL, rel); 27195230Sab196087 break; 27205230Sab196087 27215230Sab196087 case DT_RELENT: 27225230Sab196087 TEST_ENTSIZE(SHT_REL, rel); 27235230Sab196087 break; 27245230Sab196087 27255230Sab196087 case DT_RELA: 27265230Sab196087 if (!dumped) 27275230Sab196087 TEST_ADDR(SHT_RELA, rela); 27285230Sab196087 break; 27295230Sab196087 27305230Sab196087 case DT_RELAENT: 27315230Sab196087 TEST_ENTSIZE(SHT_RELA, rela); 27325230Sab196087 break; 27335230Sab196087 27345230Sab196087 case DT_STRTAB: 27355230Sab196087 TEST_ADDR(SHT_STRTAB, dynstr); 27363850Sab196087 break; 27375230Sab196087 27385230Sab196087 case DT_STRSZ: 27395230Sab196087 TEST_SIZE(SHT_STRTAB, dynstr); 27405230Sab196087 break; 27415230Sab196087 27425230Sab196087 case DT_SUNW_CAP: 27435230Sab196087 TEST_ADDR(SHT_SUNW_cap, sunw_cap); 27445230Sab196087 break; 27455230Sab196087 27465230Sab196087 case DT_SUNW_SYMTAB: 27475230Sab196087 TEST_ADDR(SHT_SUNW_LDYNSYM, sunw_ldynsym); 27485230Sab196087 break; 27495230Sab196087 27505230Sab196087 case DT_SYMENT: 27515230Sab196087 TEST_ENTSIZE(SHT_DYNSYM, dynsym); 27525230Sab196087 break; 27535230Sab196087 27545230Sab196087 case DT_SYMINENT: 27555230Sab196087 TEST_ENTSIZE(SHT_SUNW_syminfo, sunw_syminfo); 27565230Sab196087 break; 27575230Sab196087 27585230Sab196087 case DT_SYMINFO: 27595230Sab196087 TEST_ADDR(SHT_SUNW_syminfo, sunw_syminfo); 27605230Sab196087 break; 27615230Sab196087 27625230Sab196087 case DT_SYMINSZ: 27635230Sab196087 TEST_SIZE(SHT_SUNW_syminfo, sunw_syminfo); 27645230Sab196087 break; 27655230Sab196087 27665230Sab196087 case DT_SYMTAB: 27675230Sab196087 TEST_ADDR(SHT_DYNSYM, dynsym); 27685230Sab196087 break; 27695230Sab196087 27705230Sab196087 case DT_SUNW_SORTENT: 27715230Sab196087 /* 27725230Sab196087 * This entry is related to both the symsort and 27735230Sab196087 * tlssort sections. 27745230Sab196087 */ 27759273SAli.Bahrami@Sun.COM if (osabi_solaris) { 27765230Sab196087 int test_tls = 27775230Sab196087 (sec.sunw_tlssort != NULL); 27785230Sab196087 int test_sym = 27795230Sab196087 (sec.sunw_symsort != NULL) || 27805230Sab196087 !test_tls; 27815230Sab196087 if (test_sym) 27825230Sab196087 TEST_ENTSIZE(SHT_SUNW_symsort, 27835230Sab196087 sunw_symsort); 27845230Sab196087 if (test_tls) 27855230Sab196087 TEST_ENTSIZE(SHT_SUNW_tlssort, 27865230Sab196087 sunw_tlssort); 27875230Sab196087 } 27885230Sab196087 break; 27895230Sab196087 27905230Sab196087 27915230Sab196087 case DT_SUNW_SYMSORT: 27929273SAli.Bahrami@Sun.COM if (osabi_solaris) 27939273SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_symsort, 27949273SAli.Bahrami@Sun.COM sunw_symsort); 27955230Sab196087 break; 27965230Sab196087 27975230Sab196087 case DT_SUNW_SYMSORTSZ: 27989273SAli.Bahrami@Sun.COM if (osabi_solaris) 27999273SAli.Bahrami@Sun.COM TEST_SIZE(SHT_SUNW_symsort, 28009273SAli.Bahrami@Sun.COM sunw_symsort); 28015230Sab196087 break; 28025230Sab196087 28035230Sab196087 case DT_SUNW_TLSSORT: 28049273SAli.Bahrami@Sun.COM if (osabi_solaris) 28059273SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_tlssort, 28069273SAli.Bahrami@Sun.COM sunw_tlssort); 28075230Sab196087 break; 28085230Sab196087 28095230Sab196087 case DT_SUNW_TLSSORTSZ: 28109273SAli.Bahrami@Sun.COM if (osabi_solaris) 28119273SAli.Bahrami@Sun.COM TEST_SIZE(SHT_SUNW_tlssort, 28129273SAli.Bahrami@Sun.COM sunw_tlssort); 28135230Sab196087 break; 28145230Sab196087 28155230Sab196087 case DT_VERDEF: 28165230Sab196087 TEST_ADDR(SHT_SUNW_verdef, sunw_verdef); 28175230Sab196087 break; 28185230Sab196087 28195230Sab196087 case DT_VERNEED: 28205230Sab196087 TEST_ADDR(SHT_SUNW_verneed, sunw_verneed); 28215230Sab196087 break; 28225230Sab196087 28235230Sab196087 case DT_VERSYM: 28245230Sab196087 TEST_ADDR(SHT_SUNW_versym, sunw_versym); 28255230Sab196087 break; 28265230Sab196087 #undef TEST_ADDR 28275230Sab196087 #undef TEST_SIZE 28285230Sab196087 #undef TEST_ENTSIZE 28293850Sab196087 } 28300Sstevel@tonic-gate 28315230Sab196087 if (name == NULL) 28325230Sab196087 name = MSG_ORIG(MSG_STR_EMPTY); 28339273SAli.Bahrami@Sun.COM Elf_dyn_entry(0, dyn, ndx, name, 28349273SAli.Bahrami@Sun.COM osabi, ehdr->e_machine); 28350Sstevel@tonic-gate } 28360Sstevel@tonic-gate } 28370Sstevel@tonic-gate } 28380Sstevel@tonic-gate 28390Sstevel@tonic-gate /* 28400Sstevel@tonic-gate * Search for and process a MOVE section. 28410Sstevel@tonic-gate */ 28420Sstevel@tonic-gate static void 28434168Sab196087 move(Cache *cache, Word shnum, const char *file, uint_t flags) 28440Sstevel@tonic-gate { 28451618Srie Word cnt; 28469085SAli.Bahrami@Sun.COM const char *fmt = NULL; 28470Sstevel@tonic-gate 28480Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 28491618Srie Word movenum, symnum, ndx; 28501618Srie Sym *syms; 28511618Srie Cache *_cache = &cache[cnt]; 28521618Srie Shdr *shdr = _cache->c_shdr; 28531618Srie Cache *symsec, *strsec; 28541618Srie Move *move; 28550Sstevel@tonic-gate 28560Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move) 28570Sstevel@tonic-gate continue; 28585411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 28590Sstevel@tonic-gate continue; 28600Sstevel@tonic-gate 28610Sstevel@tonic-gate /* 28620Sstevel@tonic-gate * Determine the move data and number. 28630Sstevel@tonic-gate */ 28640Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 28650Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 28660Sstevel@tonic-gate file, _cache->c_name); 28670Sstevel@tonic-gate continue; 28680Sstevel@tonic-gate } 28693466Srie if (_cache->c_data == NULL) 28703466Srie continue; 28713466Srie 28721618Srie move = (Move *)_cache->c_data->d_buf; 28731618Srie movenum = shdr->sh_size / shdr->sh_entsize; 28740Sstevel@tonic-gate 28750Sstevel@tonic-gate /* 28761618Srie * Get the data buffer for the associated symbol table and 28771618Srie * string table. 28780Sstevel@tonic-gate */ 28791618Srie if (stringtbl(cache, 1, cnt, shnum, file, 28801618Srie &symnum, &symsec, &strsec) == 0) 28811618Srie return; 28821618Srie 28831618Srie syms = (Sym *)symsec->c_data->d_buf; 28840Sstevel@tonic-gate 28851618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 28861618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); 28871618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); 28880Sstevel@tonic-gate 28899085SAli.Bahrami@Sun.COM if (fmt == NULL) 28901618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY); 28910Sstevel@tonic-gate 28921618Srie for (ndx = 0; ndx < movenum; move++, ndx++) { 28931618Srie const char *symname; 28941618Srie char index[MAXNDXSIZE], section[BUFSIZ]; 28951618Srie Word symndx, shndx; 28961618Srie Sym *sym; 28970Sstevel@tonic-gate 28980Sstevel@tonic-gate /* 28990Sstevel@tonic-gate * Check for null entries 29000Sstevel@tonic-gate */ 29011618Srie if ((move->m_info == 0) && (move->m_value == 0) && 29021618Srie (move->m_poffset == 0) && (move->m_repeat == 0) && 29031618Srie (move->m_stride == 0)) { 29041618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY), 29051618Srie EC_XWORD(move->m_poffset), 0, 0, 0, 29061618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY)); 29070Sstevel@tonic-gate continue; 29080Sstevel@tonic-gate } 29091618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) || 29101618Srie (symndx >= symnum)) { 29110Sstevel@tonic-gate (void) fprintf(stderr, 29120Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file, 29131618Srie _cache->c_name, EC_XWORD(move->m_info)); 29141618Srie 29151618Srie (void) snprintf(index, MAXNDXSIZE, 29161618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 29171618Srie dbg_print(0, fmt, index, 29181618Srie EC_XWORD(move->m_poffset), 29191618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 29201618Srie move->m_stride, move->m_value, 29210Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN)); 29220Sstevel@tonic-gate continue; 29230Sstevel@tonic-gate } 29240Sstevel@tonic-gate 29251618Srie symname = relsymname(cache, _cache, strsec, 29267463SRod.Evans@Sun.COM symndx, symnum, ndx, syms, section, BUFSIZ, file); 29271618Srie sym = (Sym *)(syms + symndx); 29280Sstevel@tonic-gate 29290Sstevel@tonic-gate /* 29300Sstevel@tonic-gate * Additional sanity check. 29310Sstevel@tonic-gate */ 29321618Srie shndx = sym->st_shndx; 29330Sstevel@tonic-gate if (!((shndx == SHN_COMMON) || 29340Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) && 29351618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) { 29360Sstevel@tonic-gate (void) fprintf(stderr, 29371618Srie MSG_INTL(MSG_ERR_BADSYM2), file, 29386206Sab196087 _cache->c_name, EC_WORD(symndx), 29396206Sab196087 demangle(symname, flags)); 29400Sstevel@tonic-gate } 29410Sstevel@tonic-gate 29421618Srie (void) snprintf(index, MAXNDXSIZE, 29431618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 29441618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset), 29451618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 29461618Srie move->m_stride, move->m_value, 29471618Srie demangle(symname, flags)); 29480Sstevel@tonic-gate } 29490Sstevel@tonic-gate } 29500Sstevel@tonic-gate } 29510Sstevel@tonic-gate 29520Sstevel@tonic-gate /* 29539273SAli.Bahrami@Sun.COM * parse_note_t is used to track the state used by parse_note_entry() 29549273SAli.Bahrami@Sun.COM * between calls, and also to return the results of each call. 29559273SAli.Bahrami@Sun.COM */ 29569273SAli.Bahrami@Sun.COM typedef struct { 29579273SAli.Bahrami@Sun.COM /* pns_ fields track progress through the data */ 29589273SAli.Bahrami@Sun.COM const char *pns_file; /* File name */ 29599273SAli.Bahrami@Sun.COM Cache *pns_cache; /* Note section cache entry */ 29609273SAli.Bahrami@Sun.COM size_t pns_size; /* # unprocessed data bytes */ 29619273SAli.Bahrami@Sun.COM Word *pns_data; /* # to next unused data byte */ 29629273SAli.Bahrami@Sun.COM 29639273SAli.Bahrami@Sun.COM /* pn_ fields return the results for a single call */ 29649273SAli.Bahrami@Sun.COM Word pn_namesz; /* Value of note namesz field */ 29659273SAli.Bahrami@Sun.COM Word pn_descsz; /* Value of note descsz field */ 29669273SAli.Bahrami@Sun.COM Word pn_type; /* Value of note type field */ 29679273SAli.Bahrami@Sun.COM const char *pn_name; /* if (namesz > 0) ptr to name bytes */ 29689273SAli.Bahrami@Sun.COM const char *pn_desc; /* if (descsx > 0) ptr to data bytes */ 29699273SAli.Bahrami@Sun.COM } parse_note_t; 29709273SAli.Bahrami@Sun.COM 29719273SAli.Bahrami@Sun.COM /* 29729273SAli.Bahrami@Sun.COM * Extract the various sub-parts of a note entry, and advance the 29739273SAli.Bahrami@Sun.COM * data pointer past it. 29749273SAli.Bahrami@Sun.COM * 29759273SAli.Bahrami@Sun.COM * entry: 29769273SAli.Bahrami@Sun.COM * The state pns_ fields contain current values for the Note section 29779273SAli.Bahrami@Sun.COM * 29789273SAli.Bahrami@Sun.COM * exit: 29799273SAli.Bahrami@Sun.COM * On success, True (1) is returned, the state pns_ fields have been 29809273SAli.Bahrami@Sun.COM * advanced to point at the start of the next entry, and the information 29819273SAli.Bahrami@Sun.COM * for the recovered note entry is found in the state pn_ fields. 29829273SAli.Bahrami@Sun.COM * 29839273SAli.Bahrami@Sun.COM * On failure, False (0) is returned. The values contained in state 29849273SAli.Bahrami@Sun.COM * are undefined. 29859273SAli.Bahrami@Sun.COM */ 29869273SAli.Bahrami@Sun.COM static int 29879273SAli.Bahrami@Sun.COM parse_note_entry(parse_note_t *state) 29889273SAli.Bahrami@Sun.COM { 29899273SAli.Bahrami@Sun.COM size_t pad, noteoff; 29909273SAli.Bahrami@Sun.COM 29919273SAli.Bahrami@Sun.COM noteoff = (Word)state->pns_cache->c_data->d_size - state->pns_size; 29929273SAli.Bahrami@Sun.COM /* 29939273SAli.Bahrami@Sun.COM * Make sure we can at least reference the 3 initial entries 29949273SAli.Bahrami@Sun.COM * (4-byte words) of the note information block. 29959273SAli.Bahrami@Sun.COM */ 29969273SAli.Bahrami@Sun.COM if (state->pns_size >= (sizeof (Word) * 3)) { 29979273SAli.Bahrami@Sun.COM state->pns_size -= (sizeof (Word) * 3); 29989273SAli.Bahrami@Sun.COM } else { 29999273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ), 30009273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name, 30019273SAli.Bahrami@Sun.COM EC_WORD(noteoff)); 30029273SAli.Bahrami@Sun.COM return (0); 30039273SAli.Bahrami@Sun.COM } 30049273SAli.Bahrami@Sun.COM 30059273SAli.Bahrami@Sun.COM /* 30069273SAli.Bahrami@Sun.COM * Make sure any specified name string can be referenced. 30079273SAli.Bahrami@Sun.COM */ 30089273SAli.Bahrami@Sun.COM if ((state->pn_namesz = *state->pns_data++) != 0) { 30099273SAli.Bahrami@Sun.COM if (state->pns_size >= state->pn_namesz) { 30109273SAli.Bahrami@Sun.COM state->pns_size -= state->pn_namesz; 30119273SAli.Bahrami@Sun.COM } else { 30129273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADNMSZ), 30139273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name, 30149273SAli.Bahrami@Sun.COM EC_WORD(noteoff), EC_WORD(state->pn_namesz)); 30159273SAli.Bahrami@Sun.COM return (0); 30169273SAli.Bahrami@Sun.COM } 30179273SAli.Bahrami@Sun.COM } 30189273SAli.Bahrami@Sun.COM 30199273SAli.Bahrami@Sun.COM /* 30209273SAli.Bahrami@Sun.COM * Make sure any specified descriptor can be referenced. 30219273SAli.Bahrami@Sun.COM */ 30229273SAli.Bahrami@Sun.COM if ((state->pn_descsz = *state->pns_data++) != 0) { 30239273SAli.Bahrami@Sun.COM /* 30249273SAli.Bahrami@Sun.COM * If namesz isn't a 4-byte multiple, account for any 30259273SAli.Bahrami@Sun.COM * padding that must exist before the descriptor. 30269273SAli.Bahrami@Sun.COM */ 30279273SAli.Bahrami@Sun.COM if ((pad = (state->pn_namesz & (sizeof (Word) - 1))) != 0) { 30289273SAli.Bahrami@Sun.COM pad = sizeof (Word) - pad; 30299273SAli.Bahrami@Sun.COM state->pns_size -= pad; 30309273SAli.Bahrami@Sun.COM } 30319273SAli.Bahrami@Sun.COM if (state->pns_size >= state->pn_descsz) { 30329273SAli.Bahrami@Sun.COM state->pns_size -= state->pn_descsz; 30339273SAli.Bahrami@Sun.COM } else { 30349273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDESZ), 30359273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name, 30369273SAli.Bahrami@Sun.COM EC_WORD(noteoff), EC_WORD(state->pn_namesz)); 30379273SAli.Bahrami@Sun.COM return (0); 30389273SAli.Bahrami@Sun.COM } 30399273SAli.Bahrami@Sun.COM } 30409273SAli.Bahrami@Sun.COM 30419273SAli.Bahrami@Sun.COM state->pn_type = *state->pns_data++; 30429273SAli.Bahrami@Sun.COM 30439273SAli.Bahrami@Sun.COM /* Name */ 30449273SAli.Bahrami@Sun.COM if (state->pn_namesz) { 30459273SAli.Bahrami@Sun.COM state->pn_name = (char *)state->pns_data; 30469273SAli.Bahrami@Sun.COM pad = (state->pn_namesz + 30479273SAli.Bahrami@Sun.COM (sizeof (Word) - 1)) & ~(sizeof (Word) - 1); 30489273SAli.Bahrami@Sun.COM /* LINTED */ 30499273SAli.Bahrami@Sun.COM state->pns_data = (Word *)(state->pn_name + pad); 30509273SAli.Bahrami@Sun.COM } 30519273SAli.Bahrami@Sun.COM 30529273SAli.Bahrami@Sun.COM /* 30539273SAli.Bahrami@Sun.COM * If multiple information blocks exist within a .note section 30549273SAli.Bahrami@Sun.COM * account for any padding that must exist before the next 30559273SAli.Bahrami@Sun.COM * information block. 30569273SAli.Bahrami@Sun.COM */ 30579273SAli.Bahrami@Sun.COM if ((pad = (state->pn_descsz & (sizeof (Word) - 1))) != 0) { 30589273SAli.Bahrami@Sun.COM pad = sizeof (Word) - pad; 30599273SAli.Bahrami@Sun.COM if (state->pns_size > pad) 30609273SAli.Bahrami@Sun.COM state->pns_size -= pad; 30619273SAli.Bahrami@Sun.COM } 30629273SAli.Bahrami@Sun.COM 30639273SAli.Bahrami@Sun.COM /* Data */ 30649273SAli.Bahrami@Sun.COM if (state->pn_descsz) { 30659273SAli.Bahrami@Sun.COM state->pn_desc = (const char *)state->pns_data; 30669273SAli.Bahrami@Sun.COM /* LINTED */ 30679273SAli.Bahrami@Sun.COM state->pns_data = (Word *)(state->pn_desc + 30689273SAli.Bahrami@Sun.COM state->pn_descsz + pad); 30699273SAli.Bahrami@Sun.COM } 30709273SAli.Bahrami@Sun.COM 30719273SAli.Bahrami@Sun.COM return (1); 30729273SAli.Bahrami@Sun.COM } 30739273SAli.Bahrami@Sun.COM 30749273SAli.Bahrami@Sun.COM /* 30756635Sab196087 * Callback function for use with conv_str_to_c_literal() below. 30766635Sab196087 */ 30776635Sab196087 /*ARGSUSED2*/ 30786635Sab196087 static void 30796635Sab196087 c_literal_cb(const void *ptr, size_t size, void *uvalue) 30806635Sab196087 { 30816635Sab196087 (void) fwrite(ptr, size, 1, stdout); 30826635Sab196087 } 30836635Sab196087 30846635Sab196087 /* 30850Sstevel@tonic-gate * Traverse a note section analyzing each note information block. 30860Sstevel@tonic-gate * The data buffers size is used to validate references before they are made, 30870Sstevel@tonic-gate * and is decremented as each element is processed. 30880Sstevel@tonic-gate */ 30890Sstevel@tonic-gate void 30906635Sab196087 note_entry(Cache *cache, Word *data, size_t size, Ehdr *ehdr, const char *file) 30910Sstevel@tonic-gate { 30926635Sab196087 int cnt = 0; 30936635Sab196087 int is_corenote; 30946635Sab196087 int do_swap; 30956635Sab196087 Conv_inv_buf_t inv_buf; 30969273SAli.Bahrami@Sun.COM parse_note_t pnstate; 30979273SAli.Bahrami@Sun.COM 30989273SAli.Bahrami@Sun.COM pnstate.pns_file = file; 30999273SAli.Bahrami@Sun.COM pnstate.pns_cache = cache; 31009273SAli.Bahrami@Sun.COM pnstate.pns_size = size; 31019273SAli.Bahrami@Sun.COM pnstate.pns_data = data; 31029273SAli.Bahrami@Sun.COM do_swap = _elf_sys_encoding() != ehdr->e_ident[EI_DATA]; 31031618Srie 31040Sstevel@tonic-gate /* 31050Sstevel@tonic-gate * Print out a single `note' information block. 31060Sstevel@tonic-gate */ 31079273SAli.Bahrami@Sun.COM while (pnstate.pns_size > 0) { 31089273SAli.Bahrami@Sun.COM 31099273SAli.Bahrami@Sun.COM if (parse_note_entry(&pnstate) == 0) 31100Sstevel@tonic-gate return; 31110Sstevel@tonic-gate 31126635Sab196087 /* 31136635Sab196087 * Is this a Solaris core note? Such notes all have 31146635Sab196087 * the name "CORE". 31156635Sab196087 */ 31166635Sab196087 is_corenote = (ehdr->e_type == ET_CORE) && 31179273SAli.Bahrami@Sun.COM (pnstate.pn_namesz == (MSG_STR_CORE_SIZE + 1)) && 31189273SAli.Bahrami@Sun.COM (strncmp(MSG_ORIG(MSG_STR_CORE), pnstate.pn_name, 31196635Sab196087 MSG_STR_CORE_SIZE + 1) == 0); 31206635Sab196087 31211618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 31226635Sab196087 dbg_print(0, MSG_INTL(MSG_FMT_NOTEENTNDX), EC_WORD(cnt)); 31236635Sab196087 cnt++; 31249273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), 31259273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_namesz)); 31269273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), 31279273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_descsz)); 31286635Sab196087 31296635Sab196087 if (is_corenote) 31306635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE_STR), 31319273SAli.Bahrami@Sun.COM conv_cnote_type(pnstate.pn_type, 0, &inv_buf)); 31326635Sab196087 else 31339273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), 31349273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_type)); 31359273SAli.Bahrami@Sun.COM if (pnstate.pn_namesz) { 31366635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_NAME)); 31370Sstevel@tonic-gate /* 31386635Sab196087 * The name string can contain embedded 'null' 31396635Sab196087 * bytes and/or unprintable characters. Also, 31406635Sab196087 * the final NULL is documented in the ELF ABI 31416635Sab196087 * as being included in the namesz. So, display 31426635Sab196087 * the name using C literal string notation, and 31436635Sab196087 * include the terminating NULL in the output. 31446635Sab196087 * We don't show surrounding double quotes, as 31456635Sab196087 * that implies the termination that we are showing 31466635Sab196087 * explicitly. 31470Sstevel@tonic-gate */ 31486635Sab196087 (void) fwrite(MSG_ORIG(MSG_STR_8SP), 31496635Sab196087 MSG_STR_8SP_SIZE, 1, stdout); 31509273SAli.Bahrami@Sun.COM conv_str_to_c_literal(pnstate.pn_name, 31519273SAli.Bahrami@Sun.COM pnstate.pn_namesz, c_literal_cb, NULL); 31521618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 31530Sstevel@tonic-gate } 31540Sstevel@tonic-gate 31559273SAli.Bahrami@Sun.COM if (pnstate.pn_descsz) { 31566635Sab196087 int hexdump = 1; 31570Sstevel@tonic-gate 31580Sstevel@tonic-gate /* 31596635Sab196087 * If this is a core note, let the corenote() 31606635Sab196087 * function handle it. 31610Sstevel@tonic-gate */ 31626635Sab196087 if (is_corenote) { 31636635Sab196087 /* We only issue the bad arch error once */ 31646635Sab196087 static int badnote_done = 0; 31656635Sab196087 corenote_ret_t corenote_ret; 31666635Sab196087 31676635Sab196087 corenote_ret = corenote(ehdr->e_machine, 31689273SAli.Bahrami@Sun.COM do_swap, pnstate.pn_type, pnstate.pn_desc, 31699273SAli.Bahrami@Sun.COM pnstate.pn_descsz); 31706635Sab196087 switch (corenote_ret) { 31716635Sab196087 case CORENOTE_R_OK: 31726635Sab196087 hexdump = 0; 31736635Sab196087 break; 31746635Sab196087 case CORENOTE_R_BADDATA: 31756635Sab196087 (void) fprintf(stderr, 31766635Sab196087 MSG_INTL(MSG_NOTE_BADCOREDATA), 31776635Sab196087 file); 31786635Sab196087 break; 31796635Sab196087 case CORENOTE_R_BADARCH: 31806635Sab196087 if (badnote_done) 31816635Sab196087 break; 31826635Sab196087 (void) fprintf(stderr, 31836635Sab196087 MSG_INTL(MSG_NOTE_BADCOREARCH), 31846635Sab196087 file, 31856635Sab196087 conv_ehdr_mach(ehdr->e_machine, 31866635Sab196087 0, &inv_buf)); 31876635Sab196087 break; 31880Sstevel@tonic-gate } 31890Sstevel@tonic-gate } 31906635Sab196087 31916635Sab196087 /* 31926635Sab196087 * The default thing when we don't understand 31936635Sab196087 * the note data is to display it as hex bytes. 31946635Sab196087 */ 31956635Sab196087 if (hexdump) { 31966635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESC)); 31979273SAli.Bahrami@Sun.COM dump_hex_bytes(pnstate.pn_desc, 31989273SAli.Bahrami@Sun.COM pnstate.pn_descsz, 8, 4, 4); 31990Sstevel@tonic-gate } 32000Sstevel@tonic-gate } 32010Sstevel@tonic-gate } 32020Sstevel@tonic-gate } 32030Sstevel@tonic-gate 32040Sstevel@tonic-gate /* 32056635Sab196087 * Search for and process .note sections. 32066635Sab196087 * 32076635Sab196087 * Returns the number of note sections seen. 32080Sstevel@tonic-gate */ 32096635Sab196087 static Word 32106635Sab196087 note(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 32110Sstevel@tonic-gate { 32126635Sab196087 Word cnt, note_cnt = 0; 32130Sstevel@tonic-gate 32140Sstevel@tonic-gate /* 32150Sstevel@tonic-gate * Otherwise look for any .note sections. 32160Sstevel@tonic-gate */ 32170Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 32181618Srie Cache *_cache = &cache[cnt]; 32191618Srie Shdr *shdr = _cache->c_shdr; 32200Sstevel@tonic-gate 32210Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE) 32220Sstevel@tonic-gate continue; 32236635Sab196087 note_cnt++; 32245411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 32250Sstevel@tonic-gate continue; 32260Sstevel@tonic-gate 32270Sstevel@tonic-gate /* 32280Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're 32295230Sab196087 * properly aligned before proceeding, and issue an error 32305230Sab196087 * as necessary. 32315230Sab196087 * 32325230Sab196087 * Note that we will continue on to display the note even 32335230Sab196087 * if it has bad alignment. We can do this safely, because 32345230Sab196087 * libelf knows the alignment required for SHT_NOTE, and 32355230Sab196087 * takes steps to deliver a properly aligned buffer to us 32365230Sab196087 * even if the actual file is misaligned. 32370Sstevel@tonic-gate */ 32385230Sab196087 if (shdr->sh_offset & (sizeof (Word) - 1)) 32390Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 32400Sstevel@tonic-gate file, _cache->c_name); 32415230Sab196087 32423466Srie if (_cache->c_data == NULL) 32433466Srie continue; 32440Sstevel@tonic-gate 32451618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 32461618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 32470Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf, 32480Sstevel@tonic-gate /* LINTED */ 32496635Sab196087 (Word)_cache->c_data->d_size, ehdr, file); 32500Sstevel@tonic-gate } 32516635Sab196087 32526635Sab196087 return (note_cnt); 32530Sstevel@tonic-gate } 32540Sstevel@tonic-gate 32551618Srie /* 32569273SAli.Bahrami@Sun.COM * The Linux Standard Base defines a special note named .note.ABI-tag 32579273SAli.Bahrami@Sun.COM * that is used to maintain Linux ABI information. Presence of this section 32589273SAli.Bahrami@Sun.COM * is a strong indication that the object should be considered to be 32599273SAli.Bahrami@Sun.COM * ELFOSABI_LINUX. 32609273SAli.Bahrami@Sun.COM * 32619273SAli.Bahrami@Sun.COM * This function returns True (1) if such a note is seen, and False (0) 32629273SAli.Bahrami@Sun.COM * otherwise. 32639273SAli.Bahrami@Sun.COM */ 32649273SAli.Bahrami@Sun.COM static int 32659273SAli.Bahrami@Sun.COM has_linux_abi_note(Cache *cache, Word shnum, const char *file) 32669273SAli.Bahrami@Sun.COM { 32679273SAli.Bahrami@Sun.COM Word cnt; 32689273SAli.Bahrami@Sun.COM 32699273SAli.Bahrami@Sun.COM for (cnt = 1; cnt < shnum; cnt++) { 32709273SAli.Bahrami@Sun.COM parse_note_t pnstate; 32719273SAli.Bahrami@Sun.COM Cache *_cache = &cache[cnt]; 32729273SAli.Bahrami@Sun.COM Shdr *shdr = _cache->c_shdr; 32739273SAli.Bahrami@Sun.COM 32749273SAli.Bahrami@Sun.COM /* 32759273SAli.Bahrami@Sun.COM * Section must be SHT_NOTE, must have the name 32769273SAli.Bahrami@Sun.COM * .note.ABI-tag, and must have data. 32779273SAli.Bahrami@Sun.COM */ 32789273SAli.Bahrami@Sun.COM if ((shdr->sh_type != SHT_NOTE) || 32799273SAli.Bahrami@Sun.COM (strcmp(MSG_ORIG(MSG_STR_NOTEABITAG), 32809273SAli.Bahrami@Sun.COM _cache->c_name) != 0) || (_cache->c_data == NULL)) 32819273SAli.Bahrami@Sun.COM continue; 32829273SAli.Bahrami@Sun.COM 32839273SAli.Bahrami@Sun.COM pnstate.pns_file = file; 32849273SAli.Bahrami@Sun.COM pnstate.pns_cache = _cache; 32859273SAli.Bahrami@Sun.COM pnstate.pns_size = _cache->c_data->d_size; 32869273SAli.Bahrami@Sun.COM pnstate.pns_data = (Word *)_cache->c_data->d_buf; 32879273SAli.Bahrami@Sun.COM 32889273SAli.Bahrami@Sun.COM while (pnstate.pns_size > 0) { 32899273SAli.Bahrami@Sun.COM Word *w; 32909273SAli.Bahrami@Sun.COM 32919273SAli.Bahrami@Sun.COM if (parse_note_entry(&pnstate) == 0) 32929273SAli.Bahrami@Sun.COM break; 32939273SAli.Bahrami@Sun.COM 32949273SAli.Bahrami@Sun.COM /* 32959273SAli.Bahrami@Sun.COM * The type must be 1, and the name must be "GNU". 32969273SAli.Bahrami@Sun.COM * The descsz must be at least 16 bytes. 32979273SAli.Bahrami@Sun.COM */ 32989273SAli.Bahrami@Sun.COM if ((pnstate.pn_type != 1) || 32999273SAli.Bahrami@Sun.COM (pnstate.pn_namesz != (MSG_STR_GNU_SIZE + 1)) || 33009273SAli.Bahrami@Sun.COM (strncmp(MSG_ORIG(MSG_STR_GNU), pnstate.pn_name, 33019273SAli.Bahrami@Sun.COM MSG_STR_CORE_SIZE + 1) != 0) || 33029273SAli.Bahrami@Sun.COM (pnstate.pn_descsz < 16)) 33039273SAli.Bahrami@Sun.COM continue; 33049273SAli.Bahrami@Sun.COM 33059273SAli.Bahrami@Sun.COM /* 33069273SAli.Bahrami@Sun.COM * desc contains 4 32-bit fields. Field 0 must be 0, 33079273SAli.Bahrami@Sun.COM * indicating Linux. The second, third, and fourth 33089273SAli.Bahrami@Sun.COM * fields represent the earliest Linux kernel 33099273SAli.Bahrami@Sun.COM * version compatible with this object. 33109273SAli.Bahrami@Sun.COM */ 33119273SAli.Bahrami@Sun.COM /*LINTED*/ 33129273SAli.Bahrami@Sun.COM w = (Word *) pnstate.pn_desc; 33139273SAli.Bahrami@Sun.COM if (*w == 0) 33149273SAli.Bahrami@Sun.COM return (1); 33159273SAli.Bahrami@Sun.COM } 33169273SAli.Bahrami@Sun.COM } 33179273SAli.Bahrami@Sun.COM 33189273SAli.Bahrami@Sun.COM return (0); 33199273SAli.Bahrami@Sun.COM } 33209273SAli.Bahrami@Sun.COM 33219273SAli.Bahrami@Sun.COM /* 33221618Srie * Determine an individual hash entry. This may be the initial hash entry, 33231618Srie * or an associated chain entry. 33241618Srie */ 33251618Srie static void 33261618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx, 33271618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts, 33281618Srie uint_t flags, int chain) 33291618Srie { 33301618Srie Sym *sym; 33311618Srie const char *symname, *str; 33321618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE]; 33331618Srie ulong_t nbkt, nhash; 33341618Srie 33351618Srie if (symndx > symn) { 33361618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file, 33371618Srie EC_WORD(symndx), EC_WORD(hashndx)); 33381618Srie symname = MSG_INTL(MSG_STR_UNKNOWN); 33391618Srie } else { 33401618Srie sym = (Sym *)(syms + symndx); 33411618Srie symname = string(refsec, symndx, strsec, file, sym->st_name); 33421618Srie } 33431618Srie 33441618Srie if (chain == 0) { 33451618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 33461618Srie hashndx); 33471618Srie str = (const char *)_bucket; 33481618Srie } else 33491618Srie str = MSG_ORIG(MSG_STR_EMPTY); 33501618Srie 33511618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2), 33521618Srie EC_WORD(symndx)); 33531618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx, 33541618Srie demangle(symname, flags)); 33551618Srie 33561618Srie /* 33571618Srie * Determine if this string is in the correct bucket. 33581618Srie */ 33591618Srie nhash = elf_hash(symname); 33601618Srie nbkt = nhash % bkts; 33611618Srie 33621618Srie if (nbkt != hashndx) { 33631618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file, 33641618Srie hsecname, symname, EC_WORD(hashndx), nbkt); 33651618Srie } 33661618Srie } 33670Sstevel@tonic-gate 33680Sstevel@tonic-gate #define MAXCOUNT 500 33690Sstevel@tonic-gate 33700Sstevel@tonic-gate static void 33714168Sab196087 hash(Cache *cache, Word shnum, const char *file, uint_t flags) 33720Sstevel@tonic-gate { 33730Sstevel@tonic-gate static int count[MAXCOUNT]; 33741618Srie Word cnt; 33750Sstevel@tonic-gate ulong_t ndx, bkts; 33760Sstevel@tonic-gate char number[MAXNDXSIZE]; 33770Sstevel@tonic-gate 33780Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 33790Sstevel@tonic-gate uint_t *hash, *chain; 33800Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 33811618Srie Shdr *sshdr, *hshdr = _cache->c_shdr; 33821618Srie char *ssecname, *hsecname = _cache->c_name; 33831618Srie Sym *syms; 33841618Srie Word symn; 33850Sstevel@tonic-gate 33861618Srie if (hshdr->sh_type != SHT_HASH) 33870Sstevel@tonic-gate continue; 33880Sstevel@tonic-gate 33890Sstevel@tonic-gate /* 33900Sstevel@tonic-gate * Determine the hash table data and size. 33910Sstevel@tonic-gate */ 33921618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) { 33930Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 33941618Srie file, hsecname); 33950Sstevel@tonic-gate continue; 33960Sstevel@tonic-gate } 33973466Srie if (_cache->c_data == NULL) 33983466Srie continue; 33993466Srie 34000Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf; 34010Sstevel@tonic-gate bkts = *hash; 34020Sstevel@tonic-gate chain = hash + 2 + bkts; 34030Sstevel@tonic-gate hash += 2; 34040Sstevel@tonic-gate 34050Sstevel@tonic-gate /* 34060Sstevel@tonic-gate * Get the data buffer for the associated symbol table. 34070Sstevel@tonic-gate */ 34081618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) { 34090Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 34101618Srie file, hsecname, EC_WORD(hshdr->sh_link)); 34110Sstevel@tonic-gate continue; 34120Sstevel@tonic-gate } 34131618Srie 34141618Srie _cache = &cache[hshdr->sh_link]; 34151618Srie ssecname = _cache->c_name; 34161618Srie 34173466Srie if (_cache->c_data == NULL) 34183466Srie continue; 34193466Srie 34203466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) { 34210Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 34221618Srie file, ssecname); 34230Sstevel@tonic-gate continue; 34240Sstevel@tonic-gate } 34250Sstevel@tonic-gate 34261618Srie sshdr = _cache->c_shdr; 34271618Srie /* LINTED */ 34281618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize); 34291618Srie 34300Sstevel@tonic-gate /* 34310Sstevel@tonic-gate * Get the associated string table section. 34320Sstevel@tonic-gate */ 34331618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) { 34340Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 34351618Srie file, ssecname, EC_WORD(sshdr->sh_link)); 34360Sstevel@tonic-gate continue; 34370Sstevel@tonic-gate } 34380Sstevel@tonic-gate 34391618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 34401618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname); 34411618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO)); 34420Sstevel@tonic-gate 34430Sstevel@tonic-gate /* 34440Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate 34450Sstevel@tonic-gate * symbols. 34460Sstevel@tonic-gate */ 34470Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) { 34481618Srie Word _ndx, _cnt; 34490Sstevel@tonic-gate 34500Sstevel@tonic-gate if (*hash == 0) { 34510Sstevel@tonic-gate count[0]++; 34520Sstevel@tonic-gate continue; 34530Sstevel@tonic-gate } 34540Sstevel@tonic-gate 34551618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname, 34561618Srie ndx, *hash, symn, syms, file, bkts, flags, 0); 34570Sstevel@tonic-gate 34580Sstevel@tonic-gate /* 34590Sstevel@tonic-gate * Determine if any other symbols are chained to this 34600Sstevel@tonic-gate * bucket. 34610Sstevel@tonic-gate */ 34620Sstevel@tonic-gate _ndx = chain[*hash]; 34630Sstevel@tonic-gate _cnt = 1; 34640Sstevel@tonic-gate while (_ndx) { 34651618Srie hash_entry(_cache, &cache[sshdr->sh_link], 34661618Srie hsecname, ndx, _ndx, symn, syms, file, 34671618Srie bkts, flags, 1); 34680Sstevel@tonic-gate _ndx = chain[_ndx]; 34690Sstevel@tonic-gate _cnt++; 34700Sstevel@tonic-gate } 34710Sstevel@tonic-gate 34720Sstevel@tonic-gate if (_cnt >= MAXCOUNT) { 34730Sstevel@tonic-gate (void) fprintf(stderr, 34741324Srie MSG_INTL(MSG_HASH_OVERFLW), file, 34751618Srie _cache->c_name, EC_WORD(ndx), 34761618Srie EC_WORD(_cnt)); 34770Sstevel@tonic-gate } else 34780Sstevel@tonic-gate count[_cnt]++; 34790Sstevel@tonic-gate } 34800Sstevel@tonic-gate break; 34810Sstevel@tonic-gate } 34820Sstevel@tonic-gate 34830Sstevel@tonic-gate /* 34840Sstevel@tonic-gate * Print out the count information. 34850Sstevel@tonic-gate */ 34860Sstevel@tonic-gate bkts = cnt = 0; 34871618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 34881618Srie 34890Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) { 34901618Srie Word _cnt; 34910Sstevel@tonic-gate 34920Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0) 34930Sstevel@tonic-gate continue; 34940Sstevel@tonic-gate 34951618Srie (void) snprintf(number, MAXNDXSIZE, 34961618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt); 34971618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number, 34981618Srie EC_WORD(ndx)); 34990Sstevel@tonic-gate bkts += _cnt; 35001618Srie cnt += (Word)(ndx * _cnt); 35010Sstevel@tonic-gate } 35020Sstevel@tonic-gate if (cnt) { 35030Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 35041618Srie bkts); 35051618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number, 35061618Srie EC_WORD(cnt)); 35070Sstevel@tonic-gate } 35080Sstevel@tonic-gate } 35090Sstevel@tonic-gate 35100Sstevel@tonic-gate static void 35114168Sab196087 group(Cache *cache, Word shnum, const char *file, uint_t flags) 35120Sstevel@tonic-gate { 35131618Srie Word scnt; 35140Sstevel@tonic-gate 35151618Srie for (scnt = 1; scnt < shnum; scnt++) { 35161618Srie Cache *_cache = &cache[scnt]; 35171618Srie Shdr *shdr = _cache->c_shdr; 35181618Srie Word *grpdata, gcnt, grpcnt, symnum, unknown; 35191618Srie Cache *symsec, *strsec; 35201618Srie Sym *syms, *sym; 35211618Srie char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 35220Sstevel@tonic-gate 35230Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP) 35240Sstevel@tonic-gate continue; 35255411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, scnt, shdr->sh_type)) 35260Sstevel@tonic-gate continue; 35273466Srie if ((_cache->c_data == NULL) || 35283466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL)) 35290Sstevel@tonic-gate continue; 35301618Srie grpcnt = shdr->sh_size / sizeof (Word); 35311618Srie 35321618Srie /* 35331618Srie * Get the data buffer for the associated symbol table and 35341618Srie * string table. 35351618Srie */ 35361618Srie if (stringtbl(cache, 1, scnt, shnum, file, 35371618Srie &symnum, &symsec, &strsec) == 0) 35381618Srie return; 35391618Srie 35401618Srie syms = symsec->c_data->d_buf; 35411618Srie 35421618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 35431618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name); 35441618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE)); 35451618Srie 35461618Srie /* 35471618Srie * The first element of the group defines the group. The 35481618Srie * associated symbol is defined by the sh_link field. 35491618Srie */ 35501618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) { 35511618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 35521618Srie file, _cache->c_name, EC_WORD(shdr->sh_info)); 35531618Srie return; 35540Sstevel@tonic-gate } 35550Sstevel@tonic-gate 35561618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT)); 35571618Srie if (grpdata[0] & GRP_COMDAT) { 35581618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT)); 35590Sstevel@tonic-gate } 35601618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) { 35611618Srie size_t len = strlen(flgstrbuf); 35621618Srie 35631618Srie (void) snprintf(&flgstrbuf[len], 35641618Srie (MSG_GRP_COMDAT_SIZE + 10 - len), 35651618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown); 35660Sstevel@tonic-gate } 35671618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT)); 35681618Srie sym = (Sym *)(syms + shdr->sh_info); 35690Sstevel@tonic-gate 35701618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf, 35711618Srie demangle(string(_cache, 0, strsec, file, sym->st_name), 35721618Srie flags)); 35731618Srie 35741618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) { 35750Sstevel@tonic-gate char index[MAXNDXSIZE]; 35761618Srie const char *name; 35770Sstevel@tonic-gate 35780Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, 35791618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt)); 35801618Srie 35811618Srie if (grpdata[gcnt] >= shnum) 35821618Srie name = MSG_INTL(MSG_GRP_INVALSCN); 35831618Srie else 35841618Srie name = cache[grpdata[gcnt]].c_name; 35851618Srie 35861618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name, 35874433Sab196087 EC_XWORD(grpdata[gcnt])); 35880Sstevel@tonic-gate } 35890Sstevel@tonic-gate } 35900Sstevel@tonic-gate } 35910Sstevel@tonic-gate 35920Sstevel@tonic-gate static void 35937463SRod.Evans@Sun.COM got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 35940Sstevel@tonic-gate { 35955230Sab196087 Cache *gotcache = NULL, *symtab = NULL; 35961618Srie Addr gotbgn, gotend; 35971618Srie Shdr *gotshdr; 35981618Srie Word cnt, gotents, gotndx; 35990Sstevel@tonic-gate size_t gentsize; 36000Sstevel@tonic-gate Got_info *gottable; 36010Sstevel@tonic-gate char *gotdata; 36021618Srie Sym *gotsym; 36031618Srie Xword gotsymaddr; 36046206Sab196087 uint_t sys_encoding; 36050Sstevel@tonic-gate 36060Sstevel@tonic-gate /* 36071324Srie * First, find the got. 36080Sstevel@tonic-gate */ 36090Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 36105230Sab196087 if (strncmp(cache[cnt].c_name, MSG_ORIG(MSG_ELF_GOT), 36111324Srie MSG_ELF_GOT_SIZE) == 0) { 36125230Sab196087 gotcache = &cache[cnt]; 36130Sstevel@tonic-gate break; 36140Sstevel@tonic-gate } 36150Sstevel@tonic-gate } 36165230Sab196087 if (gotcache == NULL) 36170Sstevel@tonic-gate return; 36181324Srie 36191324Srie /* 36201324Srie * A got section within a relocatable object is suspicious. 36211324Srie */ 36221324Srie if (ehdr->e_type == ET_REL) { 36231324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file, 36245230Sab196087 gotcache->c_name); 36251324Srie } 36261324Srie 36271618Srie gotshdr = gotcache->c_shdr; 36280Sstevel@tonic-gate if (gotshdr->sh_size == 0) { 36290Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 36300Sstevel@tonic-gate file, gotcache->c_name); 36310Sstevel@tonic-gate return; 36320Sstevel@tonic-gate } 36331618Srie 36341618Srie gotbgn = gotshdr->sh_addr; 36350Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size; 36360Sstevel@tonic-gate 36370Sstevel@tonic-gate /* 36381618Srie * Some architectures don't properly set the sh_entsize for the GOT 36391618Srie * table. If it's not set, default to a size of a pointer. 36400Sstevel@tonic-gate */ 36411618Srie if ((gentsize = gotshdr->sh_entsize) == 0) 36421618Srie gentsize = sizeof (Xword); 36431618Srie 36443466Srie if (gotcache->c_data == NULL) 36453466Srie return; 36463466Srie 36470Sstevel@tonic-gate /* LINTED */ 36481618Srie gotents = (Word)(gotshdr->sh_size / gentsize); 36490Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf; 36500Sstevel@tonic-gate 36510Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 36520Sstevel@tonic-gate int err = errno; 36531618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file, 36541618Srie strerror(err)); 36550Sstevel@tonic-gate return; 36560Sstevel@tonic-gate } 36570Sstevel@tonic-gate 36580Sstevel@tonic-gate /* 36590Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations 36600Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a 36610Sstevel@tonic-gate * .rel[a].got section we check them all. 36620Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab 36630Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 36640Sstevel@tonic-gate */ 36650Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 36661618Srie Word type, symnum; 36671618Srie Xword relndx, relnum, relsize; 36681618Srie void *rels; 36691618Srie Sym *syms; 36701618Srie Cache *symsec, *strsec; 36711618Srie Cache *_cache = &cache[cnt]; 36721618Srie Shdr *shdr; 36730Sstevel@tonic-gate 36741618Srie shdr = _cache->c_shdr; 36751618Srie type = shdr->sh_type; 36760Sstevel@tonic-gate 36771618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) { 36780Sstevel@tonic-gate symtab = _cache; 36790Sstevel@tonic-gate continue; 36800Sstevel@tonic-gate } 36811618Srie if (type == SHT_SYMTAB) { 36820Sstevel@tonic-gate symtab = _cache; 36830Sstevel@tonic-gate continue; 36840Sstevel@tonic-gate } 36851618Srie if ((type != SHT_RELA) && (type != SHT_REL)) 36860Sstevel@tonic-gate continue; 36870Sstevel@tonic-gate 36880Sstevel@tonic-gate /* 36891618Srie * Decide entry size. 36900Sstevel@tonic-gate */ 36911618Srie if (((relsize = shdr->sh_entsize) == 0) || 36921618Srie (relsize > shdr->sh_size)) { 36931618Srie if (type == SHT_RELA) 36941618Srie relsize = sizeof (Rela); 36951618Srie else 36961618Srie relsize = sizeof (Rel); 36970Sstevel@tonic-gate } 36980Sstevel@tonic-gate 36990Sstevel@tonic-gate /* 37001618Srie * Determine the number of relocations available. 37010Sstevel@tonic-gate */ 37021618Srie if (shdr->sh_size == 0) { 37031618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 37041618Srie file, _cache->c_name); 37050Sstevel@tonic-gate continue; 37060Sstevel@tonic-gate } 37073466Srie if (_cache->c_data == NULL) 37083466Srie continue; 37093466Srie 37101618Srie rels = _cache->c_data->d_buf; 37111618Srie relnum = shdr->sh_size / relsize; 37120Sstevel@tonic-gate 37131618Srie /* 37141618Srie * Get the data buffer for the associated symbol table and 37151618Srie * string table. 37161618Srie */ 37171618Srie if (stringtbl(cache, 1, cnt, shnum, file, 37181618Srie &symnum, &symsec, &strsec) == 0) 37191618Srie continue; 37201618Srie 37211618Srie syms = symsec->c_data->d_buf; 37221618Srie 37231618Srie /* 37241618Srie * Loop through the relocation entries. 37251618Srie */ 37261618Srie for (relndx = 0; relndx < relnum; relndx++, 37271618Srie rels = (void *)((char *)rels + relsize)) { 37281618Srie char section[BUFSIZ]; 37291618Srie Addr offset; 37300Sstevel@tonic-gate Got_info *gip; 37311618Srie Word symndx, reltype; 37321618Srie Rela *rela; 37331618Srie Rel *rel; 37340Sstevel@tonic-gate 37351618Srie /* 37361618Srie * Unravel the relocation. 37371618Srie */ 37381618Srie if (type == SHT_RELA) { 37391618Srie rela = (Rela *)rels; 37401618Srie symndx = ELF_R_SYM(rela->r_info); 37416206Sab196087 reltype = ELF_R_TYPE(rela->r_info, 37426206Sab196087 ehdr->e_machine); 37431618Srie offset = rela->r_offset; 37440Sstevel@tonic-gate } else { 37451618Srie rel = (Rel *)rels; 37461618Srie symndx = ELF_R_SYM(rel->r_info); 37476206Sab196087 reltype = ELF_R_TYPE(rel->r_info, 37486206Sab196087 ehdr->e_machine); 37491618Srie offset = rel->r_offset; 37500Sstevel@tonic-gate } 37510Sstevel@tonic-gate 37520Sstevel@tonic-gate /* 37530Sstevel@tonic-gate * Only pay attention to relocations against the GOT. 37540Sstevel@tonic-gate */ 37554146Sab196087 if ((offset < gotbgn) || (offset >= gotend)) 37560Sstevel@tonic-gate continue; 37570Sstevel@tonic-gate 37580Sstevel@tonic-gate /* LINTED */ 37591618Srie gotndx = (Word)((offset - gotbgn) / 37600Sstevel@tonic-gate gotshdr->sh_entsize); 37610Sstevel@tonic-gate gip = &gottable[gotndx]; 37621618Srie 37631618Srie if (gip->g_reltype != 0) { 37640Sstevel@tonic-gate (void) fprintf(stderr, 37650Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file, 37661618Srie EC_WORD(gotndx), EC_ADDR(offset)); 37670Sstevel@tonic-gate continue; 37680Sstevel@tonic-gate } 37690Sstevel@tonic-gate 37701618Srie if (symndx) 37711618Srie gip->g_symname = relsymname(cache, _cache, 37721618Srie strsec, symndx, symnum, relndx, syms, 37737463SRod.Evans@Sun.COM section, BUFSIZ, file); 37741618Srie gip->g_reltype = reltype; 37751618Srie gip->g_rel = rels; 37760Sstevel@tonic-gate } 37770Sstevel@tonic-gate } 37780Sstevel@tonic-gate 37796299Sab196087 if (symlookup(MSG_ORIG(MSG_SYM_GOT), cache, shnum, &gotsym, symtab, 37801618Srie file)) 37811618Srie gotsymaddr = gotsym->st_value; 37820Sstevel@tonic-gate else 37831618Srie gotsymaddr = gotbgn; 37840Sstevel@tonic-gate 37851618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 37861618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name); 37871618Srie Elf_got_title(0); 37880Sstevel@tonic-gate 37896206Sab196087 sys_encoding = _elf_sys_encoding(); 37900Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) { 37910Sstevel@tonic-gate Got_info *gip; 37920Sstevel@tonic-gate Sword gindex; 37931618Srie Addr gaddr; 37941618Srie Xword gotentry; 37950Sstevel@tonic-gate 37960Sstevel@tonic-gate gip = &gottable[gotndx]; 37970Sstevel@tonic-gate 37980Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize); 37991618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize; 38000Sstevel@tonic-gate 38011618Srie if (gentsize == sizeof (Word)) 38020Sstevel@tonic-gate /* LINTED */ 38031618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx)); 38040Sstevel@tonic-gate else 38050Sstevel@tonic-gate /* LINTED */ 38061618Srie gotentry = *((Xword *)(gotdata) + gotndx); 38070Sstevel@tonic-gate 38081618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine, 38096206Sab196087 ehdr->e_ident[EI_DATA], sys_encoding, 38101618Srie gip->g_reltype, gip->g_rel, gip->g_symname); 38110Sstevel@tonic-gate } 38120Sstevel@tonic-gate free(gottable); 38130Sstevel@tonic-gate } 38140Sstevel@tonic-gate 38150Sstevel@tonic-gate void 38160Sstevel@tonic-gate checksum(Elf *elf) 38170Sstevel@tonic-gate { 38181618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 38191618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf)); 38200Sstevel@tonic-gate } 38210Sstevel@tonic-gate 38224242Sab196087 /* 38234242Sab196087 * This variable is used by regular() to communicate the address of 38244242Sab196087 * the section header cache to sort_shdr_ndx_arr(). Unfortunately, 38254242Sab196087 * the qsort() interface does not include a userdata argument by which 38264242Sab196087 * such arbitrary data can be passed, so we are stuck using global data. 38274242Sab196087 */ 38284242Sab196087 static Cache *sort_shdr_ndx_arr_cache; 38294242Sab196087 38304242Sab196087 38314242Sab196087 /* 38324242Sab196087 * Used with qsort() to sort the section indices so that they can be 38334242Sab196087 * used to access the section headers in order of increasing data offset. 38344242Sab196087 * 38354242Sab196087 * entry: 38364242Sab196087 * sort_shdr_ndx_arr_cache - Contains address of 38374242Sab196087 * section header cache. 38384242Sab196087 * v1, v2 - Point at elements of sort_shdr_bits array to be compared. 38394242Sab196087 * 38404242Sab196087 * exit: 38414242Sab196087 * Returns -1 (less than), 0 (equal) or 1 (greater than). 38424242Sab196087 */ 38434242Sab196087 static int 38444242Sab196087 sort_shdr_ndx_arr(const void *v1, const void *v2) 38454242Sab196087 { 38464242Sab196087 Cache *cache1 = sort_shdr_ndx_arr_cache + *((size_t *)v1); 38474242Sab196087 Cache *cache2 = sort_shdr_ndx_arr_cache + *((size_t *)v2); 38484242Sab196087 38494242Sab196087 if (cache1->c_shdr->sh_offset < cache2->c_shdr->sh_offset) 38504242Sab196087 return (-1); 38514242Sab196087 38524242Sab196087 if (cache1->c_shdr->sh_offset > cache2->c_shdr->sh_offset) 38534242Sab196087 return (1); 38544242Sab196087 38554242Sab196087 return (0); 38564242Sab196087 } 38574242Sab196087 38584242Sab196087 38594665Sab196087 static int 38604665Sab196087 shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, 38617463SRod.Evans@Sun.COM size_t shnum, Cache **cache_ret, Word flags) 38620Sstevel@tonic-gate { 38630Sstevel@tonic-gate Elf_Scn *scn; 38640Sstevel@tonic-gate Elf_Data *data; 38654665Sab196087 size_t ndx; 38664665Sab196087 Shdr *nameshdr; 38679085SAli.Bahrami@Sun.COM char *names = NULL; 38680Sstevel@tonic-gate Cache *cache, *_cache; 38694242Sab196087 size_t *shdr_ndx_arr, shdr_ndx_arr_cnt; 38700Sstevel@tonic-gate 38710Sstevel@tonic-gate 38720Sstevel@tonic-gate /* 38730Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section 38740Sstevel@tonic-gate * name strings. 38750Sstevel@tonic-gate */ 38764156Sab196087 if (shstrndx == SHN_UNDEF) { 38774156Sab196087 /* 38784156Sab196087 * It is rare, but legal, for an object to lack a 38794156Sab196087 * header string table section. 38804156Sab196087 */ 38814156Sab196087 names = NULL; 38824156Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHSTRSEC), file); 38834156Sab196087 } else if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 38840Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 38850Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 38860Sstevel@tonic-gate EC_XWORD(shstrndx)); 38871618Srie 38880Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) { 38890Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 38900Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 38910Sstevel@tonic-gate EC_XWORD(shstrndx)); 38921618Srie 38931618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) { 38940Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 38950Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 38963862Srie EC_WORD(elf_ndxscn(scn))); 38971618Srie 38989085SAli.Bahrami@Sun.COM } else if ((names = data->d_buf) == NULL) 38990Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 39000Sstevel@tonic-gate 39010Sstevel@tonic-gate /* 39023862Srie * Allocate a cache to maintain a descriptor for each section. 39030Sstevel@tonic-gate */ 39044665Sab196087 if ((*cache_ret = cache = malloc(shnum * sizeof (Cache))) == NULL) { 39050Sstevel@tonic-gate int err = errno; 39060Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 39070Sstevel@tonic-gate file, strerror(err)); 39084665Sab196087 return (0); 39090Sstevel@tonic-gate } 39100Sstevel@tonic-gate 39111618Srie *cache = cache_init; 39120Sstevel@tonic-gate _cache = cache; 39130Sstevel@tonic-gate _cache++; 39140Sstevel@tonic-gate 39153862Srie /* 39164242Sab196087 * Allocate an array that will hold the section index for 39174242Sab196087 * each section that has data in the ELF file: 39184242Sab196087 * 39194242Sab196087 * - Is not a NOBITS section 39204242Sab196087 * - Data has non-zero length 39214242Sab196087 * 39224242Sab196087 * Note that shnum is an upper bound on the size required. It 39234242Sab196087 * is likely that we won't use a few of these array elements. 39244242Sab196087 * Allocating a modest amount of extra memory in this case means 39254242Sab196087 * that we can avoid an extra loop to count the number of needed 39264242Sab196087 * items, and can fill this array immediately in the first loop 39274242Sab196087 * below. 39284242Sab196087 */ 39294242Sab196087 if ((shdr_ndx_arr = malloc(shnum * sizeof (*shdr_ndx_arr))) == NULL) { 39304242Sab196087 int err = errno; 39314242Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 39324242Sab196087 file, strerror(err)); 39334665Sab196087 return (0); 39344242Sab196087 } 39354242Sab196087 shdr_ndx_arr_cnt = 0; 39364242Sab196087 39374242Sab196087 /* 39383862Srie * Traverse the sections of the file. This gathering of data is 39393862Srie * carried out in two passes. First, the section headers are captured 39403862Srie * and the section header names are evaluated. A verification pass is 39413862Srie * then carried out over the section information. Files have been 39423862Srie * known to exhibit overlapping (and hence erroneous) section header 39433862Srie * information. 39443862Srie * 39453862Srie * Finally, the data for each section is obtained. This processing is 39463862Srie * carried out after section verification because should any section 39473862Srie * header overlap occur, and a file needs translating (ie. xlate'ing 39483862Srie * information from a non-native architecture file), then the process 39493862Srie * of translation can corrupt the section header information. Of 39503862Srie * course, if there is any section overlap, the data related to the 39513862Srie * sections is going to be compromised. However, it is the translation 39523862Srie * of this data that has caused problems with elfdump()'s ability to 39533862Srie * extract the data. 39543862Srie */ 39554242Sab196087 for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn); 39564242Sab196087 ndx++, _cache++) { 39573862Srie char scnndxnm[100]; 39583862Srie 39594242Sab196087 _cache->c_ndx = ndx; 39603862Srie _cache->c_scn = scn; 39613862Srie 39621618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) { 39630Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 39640Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 39653862Srie EC_WORD(elf_ndxscn(scn))); 39660Sstevel@tonic-gate } 39670Sstevel@tonic-gate 39683862Srie /* 39694242Sab196087 * If this section has data in the file, include it in 39704242Sab196087 * the array of sections to check for address overlap. 39714242Sab196087 */ 39724242Sab196087 if ((_cache->c_shdr->sh_size != 0) && 39734242Sab196087 (_cache->c_shdr->sh_type != SHT_NOBITS)) 39744242Sab196087 shdr_ndx_arr[shdr_ndx_arr_cnt++] = ndx; 39754242Sab196087 39764242Sab196087 /* 39773862Srie * If a shstrtab exists, assign the section name. 39783862Srie */ 39793862Srie if (names && _cache->c_shdr) { 39803862Srie if (_cache->c_shdr->sh_name && 39813862Srie /* LINTED */ 39823862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) { 39837463SRod.Evans@Sun.COM const char *symname; 39847463SRod.Evans@Sun.COM char *secname; 39857463SRod.Evans@Sun.COM 39867463SRod.Evans@Sun.COM secname = names + _cache->c_shdr->sh_name; 39877463SRod.Evans@Sun.COM 39887463SRod.Evans@Sun.COM /* 39897463SRod.Evans@Sun.COM * A SUN naming convention employs a "%" within 39907463SRod.Evans@Sun.COM * a section name to indicate a section/symbol 39917463SRod.Evans@Sun.COM * name. This originated from the compilers 39927463SRod.Evans@Sun.COM * -xF option, that places functions into their 39937463SRod.Evans@Sun.COM * own sections. This convention (which has no 39947463SRod.Evans@Sun.COM * formal standard) has also been followed for 39957463SRod.Evans@Sun.COM * COMDAT sections. To demangle the symbol 39967463SRod.Evans@Sun.COM * name, the name must be separated from the 39977463SRod.Evans@Sun.COM * section name. 39987463SRod.Evans@Sun.COM */ 39997463SRod.Evans@Sun.COM if (((flags & FLG_CTL_DEMANGLE) == 0) || 40007463SRod.Evans@Sun.COM ((symname = strchr(secname, '%')) == NULL)) 40017463SRod.Evans@Sun.COM _cache->c_name = secname; 40027463SRod.Evans@Sun.COM else { 40037463SRod.Evans@Sun.COM size_t secsz = ++symname - secname; 40047463SRod.Evans@Sun.COM size_t strsz; 40057463SRod.Evans@Sun.COM 40067463SRod.Evans@Sun.COM symname = demangle(symname, flags); 40077463SRod.Evans@Sun.COM strsz = secsz + strlen(symname) + 1; 40087463SRod.Evans@Sun.COM 40097463SRod.Evans@Sun.COM if ((_cache->c_name = 40107463SRod.Evans@Sun.COM malloc(strsz)) == NULL) { 40117463SRod.Evans@Sun.COM int err = errno; 40127463SRod.Evans@Sun.COM (void) fprintf(stderr, 40137463SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_MALLOC), 40147463SRod.Evans@Sun.COM file, strerror(err)); 40157463SRod.Evans@Sun.COM return (0); 40167463SRod.Evans@Sun.COM } 40177463SRod.Evans@Sun.COM (void) snprintf(_cache->c_name, strsz, 40187463SRod.Evans@Sun.COM MSG_ORIG(MSG_FMT_SECSYM), 40197463SRod.Evans@Sun.COM EC_WORD(secsz), secname, symname); 40207463SRod.Evans@Sun.COM } 40219085SAli.Bahrami@Sun.COM 40223862Srie continue; 40233862Srie } 40240Sstevel@tonic-gate 40250Sstevel@tonic-gate /* 40263862Srie * Generate an error if the section name index is zero 40273862Srie * or exceeds the shstrtab data. Fall through to 40283862Srie * fabricate a section name. 40290Sstevel@tonic-gate */ 40303862Srie if ((_cache->c_shdr->sh_name == 0) || 40310Sstevel@tonic-gate /* LINTED */ 40321618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) { 40330Sstevel@tonic-gate (void) fprintf(stderr, 40340Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file, 40354242Sab196087 EC_WORD(ndx), 40361618Srie EC_XWORD(_cache->c_shdr->sh_name)); 40370Sstevel@tonic-gate } 40383862Srie } 40393862Srie 40403862Srie /* 40413862Srie * If there exists no shstrtab data, or a section header has no 40423862Srie * name (an invalid index of 0), then compose a name for the 40433862Srie * section. 40443862Srie */ 40453862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm), 40464242Sab196087 MSG_INTL(MSG_FMT_SCNNDX), ndx); 40474242Sab196087 40484242Sab196087 if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == NULL) { 40493862Srie int err = errno; 40503862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 40513862Srie file, strerror(err)); 40524665Sab196087 return (0); 40533862Srie } 40543862Srie (void) strcpy(_cache->c_name, scnndxnm); 40553862Srie } 40563862Srie 40573862Srie /* 40583862Srie * Having collected all the sections, validate their address range. 40593862Srie * Cases have existed where the section information has been invalid. 40603862Srie * This can lead to all sorts of other, hard to diagnose errors, as 40613862Srie * each section is processed individually (ie. with elf_getdata()). 40623862Srie * Here, we carry out some address comparisons to catch a family of 40633862Srie * overlapping memory issues we have observed (likely, there are others 40643862Srie * that we have yet to discover). 40653862Srie * 40663862Srie * Note, should any memory overlap occur, obtaining any additional 40673862Srie * data from the file is questionable. However, it might still be 40683862Srie * possible to inspect the ELF header, Programs headers, or individual 40693862Srie * sections, so rather than bailing on an error condition, continue 40703862Srie * processing to see if any data can be salvaged. 40713862Srie */ 40724242Sab196087 if (shdr_ndx_arr_cnt > 1) { 40734242Sab196087 sort_shdr_ndx_arr_cache = cache; 40744242Sab196087 qsort(shdr_ndx_arr, shdr_ndx_arr_cnt, 40754242Sab196087 sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr); 40764242Sab196087 } 40774242Sab196087 for (ndx = 0; ndx < shdr_ndx_arr_cnt; ndx++) { 40784242Sab196087 Cache *_cache = cache + shdr_ndx_arr[ndx]; 40793862Srie Shdr *shdr = _cache->c_shdr; 40803862Srie Off bgn1, bgn = shdr->sh_offset; 40813862Srie Off end1, end = shdr->sh_offset + shdr->sh_size; 40824242Sab196087 size_t ndx1; 40834242Sab196087 40844242Sab196087 /* 40854242Sab196087 * Check the section against all following ones, reporting 40864242Sab196087 * any overlaps. Since we've sorted the sections by offset, 40874242Sab196087 * we can stop after the first comparison that fails. There 40884242Sab196087 * are no overlaps in a properly formed ELF file, in which 40894242Sab196087 * case this algorithm runs in O(n) time. This will degenerate 40904242Sab196087 * to O(n^2) for a completely broken file. Such a file is 40914242Sab196087 * (1) highly unlikely, and (2) unusable, so it is reasonable 40924242Sab196087 * for the analysis to take longer. 40934242Sab196087 */ 40944242Sab196087 for (ndx1 = ndx + 1; ndx1 < shdr_ndx_arr_cnt; ndx1++) { 40954242Sab196087 Cache *_cache1 = cache + shdr_ndx_arr[ndx1]; 40963862Srie Shdr *shdr1 = _cache1->c_shdr; 40973862Srie 40983862Srie bgn1 = shdr1->sh_offset; 40993862Srie end1 = shdr1->sh_offset + shdr1->sh_size; 41003862Srie 41013862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 41023862Srie ((bgn1 < end) && (end1 >= end))) { 41033862Srie (void) fprintf(stderr, 41043862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file, 41054242Sab196087 EC_WORD(elf_ndxscn(_cache->c_scn)), 41064242Sab196087 _cache->c_name, EC_OFF(bgn), EC_OFF(end), 41073862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)), 41084242Sab196087 _cache1->c_name, EC_OFF(bgn1), 41094242Sab196087 EC_OFF(end1)); 41104242Sab196087 } else { /* No overlap, so can stop */ 41114242Sab196087 break; 41120Sstevel@tonic-gate } 41130Sstevel@tonic-gate } 41140Sstevel@tonic-gate 41153862Srie /* 41164242Sab196087 * In addition to checking for sections overlapping 41174242Sab196087 * each other (done above), we should also make sure 41184242Sab196087 * the section doesn't overlap the section header array. 41193862Srie */ 41203862Srie bgn1 = ehdr->e_shoff; 41213862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum); 41223862Srie 41233862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 41243862Srie ((bgn1 < end) && (end1 >= end))) { 41253862Srie (void) fprintf(stderr, 41263862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1), 41273862Srie EC_OFF(end1), 41283862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 41293862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 41303862Srie } 41313862Srie } 41323862Srie 41333862Srie /* 41344242Sab196087 * Obtain the data for each section. 41353862Srie */ 41364242Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 41374242Sab196087 Cache *_cache = &cache[ndx]; 41383862Srie Elf_Scn *scn = _cache->c_scn; 41393862Srie 41400Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 41410Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 41420Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 41433862Srie EC_WORD(elf_ndxscn(scn))); 41440Sstevel@tonic-gate } 41458747SAli.Bahrami@Sun.COM 41468747SAli.Bahrami@Sun.COM /* 41478747SAli.Bahrami@Sun.COM * If a string table, verify that it has NULL first and 41488747SAli.Bahrami@Sun.COM * final bytes. 41498747SAli.Bahrami@Sun.COM */ 41508747SAli.Bahrami@Sun.COM if ((_cache->c_shdr->sh_type == SHT_STRTAB) && 41518747SAli.Bahrami@Sun.COM (_cache->c_data->d_buf != NULL) && 41528747SAli.Bahrami@Sun.COM (_cache->c_data->d_size > 0)) { 41538747SAli.Bahrami@Sun.COM const char *s = _cache->c_data->d_buf; 41548747SAli.Bahrami@Sun.COM 41558747SAli.Bahrami@Sun.COM if ((*s != '\0') || 41568747SAli.Bahrami@Sun.COM (*(s + _cache->c_data->d_size - 1) != '\0')) 41578747SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALSTR), 41588747SAli.Bahrami@Sun.COM file, _cache->c_name); 41598747SAli.Bahrami@Sun.COM } 41604665Sab196087 } 41614665Sab196087 41624665Sab196087 return (1); 41634665Sab196087 } 41644665Sab196087 41654665Sab196087 41664665Sab196087 41679273SAli.Bahrami@Sun.COM /* 41689273SAli.Bahrami@Sun.COM * Generate a cache of section headers and related information 41699273SAli.Bahrami@Sun.COM * for use by the rest of elfdump. If requested (or the file 41709273SAli.Bahrami@Sun.COM * contains no section headers), we generate a fake set of 41719273SAli.Bahrami@Sun.COM * headers from the information accessible from the program headers. 41729273SAli.Bahrami@Sun.COM * Otherwise, we use the real section headers contained in the file. 41739273SAli.Bahrami@Sun.COM */ 41749273SAli.Bahrami@Sun.COM static int 41759273SAli.Bahrami@Sun.COM create_cache(const char *file, int fd, Elf *elf, Ehdr *ehdr, Cache **cache, 41769273SAli.Bahrami@Sun.COM size_t shstrndx, size_t *shnum, uint_t *flags) 41779273SAli.Bahrami@Sun.COM { 41789273SAli.Bahrami@Sun.COM /* 41799273SAli.Bahrami@Sun.COM * If there are no section headers, then resort to synthesizing 41809273SAli.Bahrami@Sun.COM * section headers from the program headers. This is normally 41819273SAli.Bahrami@Sun.COM * only done by explicit request, but in this case there's no 41829273SAli.Bahrami@Sun.COM * reason not to go ahead, since the alternative is simply to quit. 41839273SAli.Bahrami@Sun.COM */ 41849273SAli.Bahrami@Sun.COM if ((*shnum <= 1) && ((*flags & FLG_CTL_FAKESHDR) == 0)) { 41859273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHDR), file); 41869273SAli.Bahrami@Sun.COM *flags |= FLG_CTL_FAKESHDR; 41879273SAli.Bahrami@Sun.COM } 41889273SAli.Bahrami@Sun.COM 41899273SAli.Bahrami@Sun.COM if (*flags & FLG_CTL_FAKESHDR) { 41909273SAli.Bahrami@Sun.COM if (fake_shdr_cache(file, fd, elf, ehdr, cache, shnum) == 0) 41919273SAli.Bahrami@Sun.COM return (0); 41929273SAli.Bahrami@Sun.COM } else { 41939273SAli.Bahrami@Sun.COM if (shdr_cache(file, elf, ehdr, shstrndx, *shnum, 41949273SAli.Bahrami@Sun.COM cache, *flags) == 0) 41959273SAli.Bahrami@Sun.COM return (0); 41969273SAli.Bahrami@Sun.COM } 41979273SAli.Bahrami@Sun.COM 41989273SAli.Bahrami@Sun.COM return (1); 41999273SAli.Bahrami@Sun.COM } 42009273SAli.Bahrami@Sun.COM 42015411Sab196087 int 42025411Sab196087 regular(const char *file, int fd, Elf *elf, uint_t flags, 42039273SAli.Bahrami@Sun.COM const char *wname, int wfd, uchar_t osabi) 42044665Sab196087 { 42059273SAli.Bahrami@Sun.COM enum { CACHE_NEEDED, CACHE_OK, CACHE_FAIL} cache_state = CACHE_NEEDED; 42064665Sab196087 Elf_Scn *scn; 42074665Sab196087 Ehdr *ehdr; 42084665Sab196087 size_t ndx, shstrndx, shnum, phnum; 42094665Sab196087 Shdr *shdr; 42104665Sab196087 Cache *cache; 42114665Sab196087 VERSYM_STATE versym; 42125411Sab196087 int ret = 0; 42135411Sab196087 int addr_align; 42144665Sab196087 42154665Sab196087 if ((ehdr = elf_getehdr(elf)) == NULL) { 42164665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 42175411Sab196087 return (ret); 42184665Sab196087 } 42194665Sab196087 42204665Sab196087 if (elf_getshnum(elf, &shnum) == 0) { 42214665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 42225411Sab196087 return (ret); 42234665Sab196087 } 42244665Sab196087 42254665Sab196087 if (elf_getshstrndx(elf, &shstrndx) == 0) { 42264665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 42275411Sab196087 return (ret); 42284665Sab196087 } 42294665Sab196087 42304665Sab196087 if (elf_getphnum(elf, &phnum) == 0) { 42314665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 42325411Sab196087 return (ret); 42334665Sab196087 } 42344665Sab196087 /* 42354665Sab196087 * If the user requested section headers derived from the 42364665Sab196087 * program headers (-P option) and this file doesn't have 42374665Sab196087 * any program headers (i.e. ET_REL), then we can't do it. 42384665Sab196087 */ 42395411Sab196087 if ((phnum == 0) && (flags & FLG_CTL_FAKESHDR)) { 42404665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_PNEEDSPH), file); 42415411Sab196087 return (ret); 42424665Sab196087 } 42434665Sab196087 42444665Sab196087 42454665Sab196087 if ((scn = elf_getscn(elf, 0)) != NULL) { 42464665Sab196087 if ((shdr = elf_getshdr(scn)) == NULL) { 42474665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 42484665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 42495411Sab196087 return (ret); 42504665Sab196087 } 42514665Sab196087 } else 42529085SAli.Bahrami@Sun.COM shdr = NULL; 42534665Sab196087 42544665Sab196087 /* 42554665Sab196087 * Print the elf header. 42564665Sab196087 */ 42575411Sab196087 if (flags & FLG_SHOW_EHDR) 42584665Sab196087 Elf_ehdr(0, ehdr, shdr); 42594665Sab196087 42604665Sab196087 /* 42614665Sab196087 * If the section headers or program headers have inadequate 42624665Sab196087 * alignment for the class of object, print a warning. libelf 42634665Sab196087 * can handle such files, but programs that use them can crash 42644665Sab196087 * when they dereference unaligned items. 42655411Sab196087 * 42665411Sab196087 * Note that the AMD64 ABI, although it is a 64-bit architecture, 42675411Sab196087 * allows access to data types smaller than 128-bits to be on 42685411Sab196087 * word alignment. 42694665Sab196087 */ 42705411Sab196087 if (ehdr->e_machine == EM_AMD64) 42715411Sab196087 addr_align = sizeof (Word); 42725411Sab196087 else 42735411Sab196087 addr_align = sizeof (Addr); 42745411Sab196087 42755411Sab196087 if (ehdr->e_phoff & (addr_align - 1)) 42764665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADPHDRALIGN), file); 42775411Sab196087 if (ehdr->e_shoff & (addr_align - 1)) 42784665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHDRALIGN), file); 42794665Sab196087 42809273SAli.Bahrami@Sun.COM 42819273SAli.Bahrami@Sun.COM /* 42829273SAli.Bahrami@Sun.COM * Determine the Operating System ABI (osabi) we will use to 42839273SAli.Bahrami@Sun.COM * interpret the object. 42849273SAli.Bahrami@Sun.COM */ 42859273SAli.Bahrami@Sun.COM if (flags & FLG_CTL_OSABI) { 42869273SAli.Bahrami@Sun.COM /* 42879273SAli.Bahrami@Sun.COM * If the user explicitly specifies '-O none', we need 42889273SAli.Bahrami@Sun.COM * to display a completely generic view of the file. 42899273SAli.Bahrami@Sun.COM * However, libconv is written to assume that ELFOSABI_NONE 42909273SAli.Bahrami@Sun.COM * is equivalent to ELFOSABI_SOLARIS. To get the desired 42919273SAli.Bahrami@Sun.COM * effect, we use an osabi that libconv has no knowledge of. 42929273SAli.Bahrami@Sun.COM */ 42939273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE) 42949273SAli.Bahrami@Sun.COM osabi = ELFOSABI_UNKNOWN4; 42959273SAli.Bahrami@Sun.COM } else { 42969273SAli.Bahrami@Sun.COM /* Determine osabi from file */ 42979273SAli.Bahrami@Sun.COM osabi = ehdr->e_ident[EI_OSABI]; 42989273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE) { 42999273SAli.Bahrami@Sun.COM /* 43009273SAli.Bahrami@Sun.COM * Chicken/Egg scenario: 43019273SAli.Bahrami@Sun.COM * 43029273SAli.Bahrami@Sun.COM * Ideally, we wait to create the section header cache 43039273SAli.Bahrami@Sun.COM * until after the program headers are printed. If we 43049273SAli.Bahrami@Sun.COM * only output program headers, we can skip building 43059273SAli.Bahrami@Sun.COM * the cache entirely. 43069273SAli.Bahrami@Sun.COM * 43079273SAli.Bahrami@Sun.COM * Proper interpretation of program headers requires 43089273SAli.Bahrami@Sun.COM * the osabi, which is supposed to be in the ELF header. 43099273SAli.Bahrami@Sun.COM * However, many systems (Solaris and Linux included) 43109273SAli.Bahrami@Sun.COM * have a history of setting the osabi to the generic 43119273SAli.Bahrami@Sun.COM * SysV ABI (ELFOSABI_NONE). We assume ELFOSABI_SOLARIS 43129273SAli.Bahrami@Sun.COM * in such cases, but would like to check the object 43139273SAli.Bahrami@Sun.COM * to see if it has a Linux .note.ABI-tag section, 43149273SAli.Bahrami@Sun.COM * which implies ELFOSABI_LINUX. This requires a 43159273SAli.Bahrami@Sun.COM * section header cache. 43169273SAli.Bahrami@Sun.COM * 43179273SAli.Bahrami@Sun.COM * To break the cycle, we create section headers now 43189273SAli.Bahrami@Sun.COM * if osabi is ELFOSABI_NONE, and later otherwise. 43199273SAli.Bahrami@Sun.COM * If it succeeds, we use them, if not, we defer 43209273SAli.Bahrami@Sun.COM * exiting until after the program headers are out. 43219273SAli.Bahrami@Sun.COM */ 43229273SAli.Bahrami@Sun.COM if (create_cache(file, fd, elf, ehdr, &cache, 43239273SAli.Bahrami@Sun.COM shstrndx, &shnum, &flags) == 0) { 43249273SAli.Bahrami@Sun.COM cache_state = CACHE_FAIL; 43259273SAli.Bahrami@Sun.COM } else { 43269273SAli.Bahrami@Sun.COM cache_state = CACHE_OK; 43279273SAli.Bahrami@Sun.COM if (has_linux_abi_note(cache, shnum, file)) { 43289273SAli.Bahrami@Sun.COM Conv_inv_buf_t ibuf1, ibuf2; 43299273SAli.Bahrami@Sun.COM 43309273SAli.Bahrami@Sun.COM (void) fprintf(stderr, 43319273SAli.Bahrami@Sun.COM MSG_INTL(MSG_INFO_LINUXOSABI), file, 43329273SAli.Bahrami@Sun.COM conv_ehdr_osabi(osabi, 0, &ibuf1), 43339273SAli.Bahrami@Sun.COM conv_ehdr_osabi(ELFOSABI_LINUX, 43349273SAli.Bahrami@Sun.COM 0, &ibuf2)); 43359273SAli.Bahrami@Sun.COM osabi = ELFOSABI_LINUX; 43369273SAli.Bahrami@Sun.COM } 43379273SAli.Bahrami@Sun.COM } 43389273SAli.Bahrami@Sun.COM } 43399273SAli.Bahrami@Sun.COM /* 43409273SAli.Bahrami@Sun.COM * We treat ELFOSABI_NONE identically to ELFOSABI_SOLARIS. 43419273SAli.Bahrami@Sun.COM * Mapping NONE to SOLARIS simplifies the required test. 43429273SAli.Bahrami@Sun.COM */ 43439273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE) 43449273SAli.Bahrami@Sun.COM osabi = ELFOSABI_SOLARIS; 43459273SAli.Bahrami@Sun.COM } 43469273SAli.Bahrami@Sun.COM 43474665Sab196087 /* 43484665Sab196087 * Print the program headers. 43494665Sab196087 */ 43505411Sab196087 if ((flags & FLG_SHOW_PHDR) && (phnum != 0)) { 43515411Sab196087 Phdr *phdr; 43524665Sab196087 43534665Sab196087 if ((phdr = elf_getphdr(elf)) == NULL) { 43544665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 43555411Sab196087 return (ret); 43564665Sab196087 } 43574665Sab196087 43584665Sab196087 for (ndx = 0; ndx < phnum; phdr++, ndx++) { 43595411Sab196087 if (!match(MATCH_F_PHDR| MATCH_F_NDX | MATCH_F_TYPE, 43605411Sab196087 NULL, ndx, phdr->p_type)) 43614665Sab196087 continue; 43624665Sab196087 43634665Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 43644665Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx)); 43659273SAli.Bahrami@Sun.COM Elf_phdr(0, osabi, ehdr->e_machine, phdr); 43664665Sab196087 } 43674665Sab196087 } 43684665Sab196087 43694665Sab196087 /* 43705411Sab196087 * If we have flag bits set that explicitly require a show or calc 43715411Sab196087 * operation, but none of them require the section headers, then 43725411Sab196087 * we are done and can return now. 43734665Sab196087 */ 43745411Sab196087 if (((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) != 0) && 43755411Sab196087 ((flags & (FLG_MASK_SHOW_SHDR | FLG_MASK_CALC_SHDR)) == 0)) 43765411Sab196087 return (ret); 43775411Sab196087 43785411Sab196087 /* 43795411Sab196087 * Everything from this point on requires section headers. 43805411Sab196087 * If we have no section headers, there is no reason to continue. 43819273SAli.Bahrami@Sun.COM * 43829273SAli.Bahrami@Sun.COM * If we tried above to create the section header cache and failed, 43839273SAli.Bahrami@Sun.COM * it is time to exit. Otherwise, create it if needed. 43845411Sab196087 */ 43859273SAli.Bahrami@Sun.COM switch (cache_state) { 43869273SAli.Bahrami@Sun.COM case CACHE_NEEDED: 43879273SAli.Bahrami@Sun.COM if (create_cache(file, fd, elf, ehdr, &cache, shstrndx, 43889273SAli.Bahrami@Sun.COM &shnum, &flags) == 0) 43899273SAli.Bahrami@Sun.COM return (ret); 43909273SAli.Bahrami@Sun.COM break; 43919273SAli.Bahrami@Sun.COM case CACHE_FAIL: 43929273SAli.Bahrami@Sun.COM return (ret); 43939273SAli.Bahrami@Sun.COM } 43945411Sab196087 if (shnum <= 1) 43955411Sab196087 goto done; 43965411Sab196087 43975411Sab196087 /* 43984665Sab196087 * If -w was specified, find and write out the section(s) data. 43994665Sab196087 */ 44004665Sab196087 if (wfd) { 44014665Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 44024665Sab196087 Cache *_cache = &cache[ndx]; 44034665Sab196087 44045411Sab196087 if (match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 44055411Sab196087 ndx, _cache->c_shdr->sh_type) && 44065411Sab196087 _cache->c_data && _cache->c_data->d_buf) { 44075411Sab196087 if (write(wfd, _cache->c_data->d_buf, 44085411Sab196087 _cache->c_data->d_size) != 44095411Sab196087 _cache->c_data->d_size) { 44105411Sab196087 int err = errno; 44115411Sab196087 (void) fprintf(stderr, 44125411Sab196087 MSG_INTL(MSG_ERR_WRITE), wname, 44135411Sab196087 strerror(err)); 44145411Sab196087 /* 44155411Sab196087 * Return an exit status of 1, because 44165411Sab196087 * the failure is not related to the 44175411Sab196087 * ELF file, but by system resources. 44185411Sab196087 */ 44195411Sab196087 ret = 1; 44205411Sab196087 goto done; 44215411Sab196087 } 44224665Sab196087 } 44230Sstevel@tonic-gate } 44240Sstevel@tonic-gate } 44250Sstevel@tonic-gate 44265411Sab196087 /* 44275411Sab196087 * If we have no flag bits set that explicitly require a show or calc 44285411Sab196087 * operation, but match options (-I, -N, -T) were used, then run 44295411Sab196087 * through the section headers and see if we can't deduce show flags 44305411Sab196087 * from the match options given. 44315411Sab196087 * 44325411Sab196087 * We don't do this if -w was specified, because (-I, -N, -T) used 44335411Sab196087 * with -w in lieu of some other option is supposed to be quiet. 44345411Sab196087 */ 44355411Sab196087 if ((wfd == 0) && (flags & FLG_CTL_MATCH) && 44365411Sab196087 ((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) == 0)) { 44375411Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 44385411Sab196087 Cache *_cache = &cache[ndx]; 44395411Sab196087 44405411Sab196087 if (!match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 44415411Sab196087 ndx, _cache->c_shdr->sh_type)) 44425411Sab196087 continue; 44435411Sab196087 44445411Sab196087 switch (_cache->c_shdr->sh_type) { 44455411Sab196087 case SHT_PROGBITS: 44465411Sab196087 /* 44475411Sab196087 * Heuristic time: It is usually bad form 44489085SAli.Bahrami@Sun.COM * to assume the meaning/format of a PROGBITS 44499085SAli.Bahrami@Sun.COM * section based on its name. However, there 4450*9406SAli.Bahrami@Sun.COM * are ABI mandated exceptions. Check for 4451*9406SAli.Bahrami@Sun.COM * these special names. 44525411Sab196087 */ 4453*9406SAli.Bahrami@Sun.COM 4454*9406SAli.Bahrami@Sun.COM /* The ELF ABI specifies .interp and .got */ 4455*9406SAli.Bahrami@Sun.COM if (strcmp(_cache->c_name, 4456*9406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_ELF_INTERP)) == 0) { 4457*9406SAli.Bahrami@Sun.COM flags |= FLG_SHOW_INTERP; 4458*9406SAli.Bahrami@Sun.COM break; 4459*9406SAli.Bahrami@Sun.COM } 44605411Sab196087 if (strcmp(_cache->c_name, 4461*9406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_ELF_GOT)) == 0) { 44625411Sab196087 flags |= FLG_SHOW_GOT; 4463*9406SAli.Bahrami@Sun.COM break; 4464*9406SAli.Bahrami@Sun.COM } 4465*9406SAli.Bahrami@Sun.COM /* 4466*9406SAli.Bahrami@Sun.COM * The GNU compilers, and amd64 ABI, define 4467*9406SAli.Bahrami@Sun.COM * .eh_frame and .eh_frame_hdr. The Sun 4468*9406SAli.Bahrami@Sun.COM * C++ ABI defines .exception_ranges. 4469*9406SAli.Bahrami@Sun.COM */ 4470*9406SAli.Bahrami@Sun.COM if ((strncmp(_cache->c_name, 44719085SAli.Bahrami@Sun.COM MSG_ORIG(MSG_SCN_FRM), 4472*9406SAli.Bahrami@Sun.COM MSG_SCN_FRM_SIZE) == 0) || 4473*9406SAli.Bahrami@Sun.COM (strncmp(_cache->c_name, 4474*9406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_SCN_EXRANGE), 4475*9406SAli.Bahrami@Sun.COM MSG_SCN_EXRANGE_SIZE) == 0)) { 44769085SAli.Bahrami@Sun.COM flags |= FLG_SHOW_UNWIND; 4477*9406SAli.Bahrami@Sun.COM break; 4478*9406SAli.Bahrami@Sun.COM } 44795411Sab196087 break; 44805411Sab196087 44815411Sab196087 case SHT_SYMTAB: 44825411Sab196087 case SHT_DYNSYM: 44835411Sab196087 case SHT_SUNW_LDYNSYM: 44845411Sab196087 case SHT_SUNW_versym: 44855411Sab196087 case SHT_SYMTAB_SHNDX: 44865411Sab196087 flags |= FLG_SHOW_SYMBOLS; 44875411Sab196087 break; 44885411Sab196087 44895411Sab196087 case SHT_RELA: 44905411Sab196087 case SHT_REL: 44915411Sab196087 flags |= FLG_SHOW_RELOC; 44925411Sab196087 break; 44935411Sab196087 44945411Sab196087 case SHT_HASH: 44955411Sab196087 flags |= FLG_SHOW_HASH; 44965411Sab196087 break; 44975411Sab196087 44985411Sab196087 case SHT_DYNAMIC: 44995411Sab196087 flags |= FLG_SHOW_DYNAMIC; 45005411Sab196087 break; 45015411Sab196087 45025411Sab196087 case SHT_NOTE: 45035411Sab196087 flags |= FLG_SHOW_NOTE; 45045411Sab196087 break; 45055411Sab196087 45065411Sab196087 case SHT_GROUP: 45075411Sab196087 flags |= FLG_SHOW_GROUP; 45085411Sab196087 break; 45095411Sab196087 45105411Sab196087 case SHT_SUNW_symsort: 45115411Sab196087 case SHT_SUNW_tlssort: 45125411Sab196087 flags |= FLG_SHOW_SORT; 45135411Sab196087 break; 45145411Sab196087 45155411Sab196087 case SHT_SUNW_cap: 45165411Sab196087 flags |= FLG_SHOW_CAP; 45175411Sab196087 break; 45185411Sab196087 45195411Sab196087 case SHT_SUNW_move: 45205411Sab196087 flags |= FLG_SHOW_MOVE; 45215411Sab196087 break; 45225411Sab196087 45235411Sab196087 case SHT_SUNW_syminfo: 45245411Sab196087 flags |= FLG_SHOW_SYMINFO; 45255411Sab196087 break; 45265411Sab196087 45275411Sab196087 case SHT_SUNW_verdef: 45285411Sab196087 case SHT_SUNW_verneed: 45295411Sab196087 flags |= FLG_SHOW_VERSIONS; 45305411Sab196087 break; 45315411Sab196087 45325411Sab196087 case SHT_AMD64_UNWIND: 45335411Sab196087 flags |= FLG_SHOW_UNWIND; 45345411Sab196087 break; 45355411Sab196087 } 45365411Sab196087 } 45375411Sab196087 } 45385411Sab196087 45395411Sab196087 45405411Sab196087 if (flags & FLG_SHOW_SHDR) 45419273SAli.Bahrami@Sun.COM sections(file, cache, shnum, ehdr, osabi); 45420Sstevel@tonic-gate 45435411Sab196087 if (flags & FLG_SHOW_INTERP) 45441618Srie interp(file, cache, shnum, phnum, elf); 45450Sstevel@tonic-gate 45469273SAli.Bahrami@Sun.COM if ((osabi == ELFOSABI_SOLARIS) || (osabi == ELFOSABI_LINUX)) 45479273SAli.Bahrami@Sun.COM versions(cache, shnum, file, flags, &versym); 45480Sstevel@tonic-gate 45495411Sab196087 if (flags & FLG_SHOW_SYMBOLS) 45509273SAli.Bahrami@Sun.COM symbols(cache, shnum, ehdr, osabi, &versym, file, flags); 45519273SAli.Bahrami@Sun.COM 45529273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_SORT) && (osabi == ELFOSABI_SOLARIS)) 45539273SAli.Bahrami@Sun.COM sunw_sort(cache, shnum, ehdr, osabi, &versym, file, flags); 45543492Sab196087 45555411Sab196087 if (flags & FLG_SHOW_HASH) 45564168Sab196087 hash(cache, shnum, file, flags); 45570Sstevel@tonic-gate 45585411Sab196087 if (flags & FLG_SHOW_GOT) 45597463SRod.Evans@Sun.COM got(cache, shnum, ehdr, file); 45600Sstevel@tonic-gate 45615411Sab196087 if (flags & FLG_SHOW_GROUP) 45624168Sab196087 group(cache, shnum, file, flags); 45630Sstevel@tonic-gate 45645411Sab196087 if (flags & FLG_SHOW_SYMINFO) 45650Sstevel@tonic-gate syminfo(cache, shnum, file); 45660Sstevel@tonic-gate 45675411Sab196087 if (flags & FLG_SHOW_RELOC) 45687463SRod.Evans@Sun.COM reloc(cache, shnum, ehdr, file); 45690Sstevel@tonic-gate 45705411Sab196087 if (flags & FLG_SHOW_DYNAMIC) 45719273SAli.Bahrami@Sun.COM dynamic(cache, shnum, ehdr, osabi, file); 45720Sstevel@tonic-gate 45736635Sab196087 if (flags & FLG_SHOW_NOTE) { 45746635Sab196087 Word note_cnt; 45756635Sab196087 size_t note_shnum; 45766635Sab196087 Cache *note_cache; 45776635Sab196087 45786635Sab196087 note_cnt = note(cache, shnum, ehdr, file); 45796635Sab196087 45806635Sab196087 /* 45816635Sab196087 * Solaris core files have section headers, but these 45826635Sab196087 * headers do not include SHT_NOTE sections that reference 45836635Sab196087 * the core note sections. This means that note() won't 45846635Sab196087 * find the core notes. Fake section headers (-P option) 45856635Sab196087 * recover these sections, but it is inconvenient to require 45866635Sab196087 * users to specify -P in this situation. If the following 45876635Sab196087 * are all true: 45886635Sab196087 * 45896635Sab196087 * - No note sections were found 45906635Sab196087 * - This is a core file 45916635Sab196087 * - We are not already using fake section headers 45926635Sab196087 * 45936635Sab196087 * then we will automatically generate fake section headers 45946635Sab196087 * and then process them in a second call to note(). 45956635Sab196087 */ 45966635Sab196087 if ((note_cnt == 0) && (ehdr->e_type == ET_CORE) && 45976635Sab196087 !(flags & FLG_CTL_FAKESHDR) && 45986635Sab196087 (fake_shdr_cache(file, fd, elf, ehdr, 45996635Sab196087 ¬e_cache, ¬e_shnum) != 0)) { 46006635Sab196087 (void) note(note_cache, note_shnum, ehdr, file); 46016635Sab196087 fake_shdr_cache_free(note_cache, note_shnum); 46026635Sab196087 } 46036635Sab196087 } 46040Sstevel@tonic-gate 46059273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_MOVE) && (osabi == ELFOSABI_SOLARIS)) 46064168Sab196087 move(cache, shnum, file, flags); 46070Sstevel@tonic-gate 46085411Sab196087 if (flags & FLG_CALC_CHECKSUM) 46090Sstevel@tonic-gate checksum(elf); 46100Sstevel@tonic-gate 46119273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_CAP) && (osabi == ELFOSABI_SOLARIS)) 46121618Srie cap(file, cache, shnum, phnum, ehdr, elf); 46130Sstevel@tonic-gate 46149273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_UNWIND) && 46159273SAli.Bahrami@Sun.COM ((osabi == ELFOSABI_SOLARIS) || (osabi == ELFOSABI_LINUX))) 46169273SAli.Bahrami@Sun.COM unwind(cache, shnum, phnum, ehdr, osabi, file, elf, flags); 46170Sstevel@tonic-gate 46184665Sab196087 46194665Sab196087 /* Release the memory used to cache section headers */ 46205411Sab196087 done: 46215411Sab196087 if (flags & FLG_CTL_FAKESHDR) 46224665Sab196087 fake_shdr_cache_free(cache, shnum); 46234665Sab196087 else 46244665Sab196087 free(cache); 46255411Sab196087 46265411Sab196087 return (ret); 46270Sstevel@tonic-gate } 4628