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 /* 233466Srie * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Dump an elf file. 300Sstevel@tonic-gate */ 311618Srie #include <machdep.h> 321618Srie #include <sys/elf_386.h> 331618Srie #include <sys/elf_amd64.h> 341618Srie #include <sys/elf_SPARC.h> 351618Srie #include <dwarf.h> 360Sstevel@tonic-gate #include <unistd.h> 370Sstevel@tonic-gate #include <errno.h> 380Sstevel@tonic-gate #include <strings.h> 390Sstevel@tonic-gate #include <debug.h> 400Sstevel@tonic-gate #include <conv.h> 410Sstevel@tonic-gate #include <msg.h> 421618Srie #include <_elfdump.h> 430Sstevel@tonic-gate 443875Sab196087 453875Sab196087 463875Sab196087 /* 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 * 51*4716Sab196087 * max_verndx contains the largest version index that can appear 52*4716Sab196087 * in a Versym entry. This can never be less than 1: In the case where 53*4716Sab196087 * there is no verdef/verneed sections, the [0] index is reserved 54*4716Sab196087 * for local symbols, and the [1] index for globals. If Solaris versioning 55*4716Sab196087 * rules are in effect and there is a verdef section, then the number 56*4716Sab196087 * of defined versions provides this number. If GNU versioning is in effect, 57*4716Sab196087 * then: 58*4716Sab196087 * - If there is no verneed section, it is the same as for 59*4716Sab196087 * Solaris versioning. 60*4716Sab196087 * - If there is a verneed section, the vna_other field of the 61*4716Sab196087 * Vernaux structs contain versions, and max_verndx is the 62*4716Sab196087 * largest such index. 63*4716Sab196087 * 64*4716Sab196087 * The value of the gnu field is based on the presence of 65*4716Sab196087 * a DT_VERSYM entry in the dynamic section: GNU ld produces these, and 66*4716Sab196087 * Solaris ld does not. 673875Sab196087 */ 683875Sab196087 typedef struct { 693875Sab196087 Cache *cache; /* Pointer to cache entry for VERSYM */ 703875Sab196087 Versym *data; /* Pointer to versym array */ 71*4716Sab196087 int gnu; /* True if object uses GNU versioning rules */ 72*4716Sab196087 int max_verndx; /* largest versym index value */ 733875Sab196087 } VERSYM_STATE; 743875Sab196087 753875Sab196087 /* 763875Sab196087 * SYMTBL_STATE is used to maintain information about a single symbol 773875Sab196087 * table section, for use by the routines that display symbol information. 783875Sab196087 */ 793875Sab196087 typedef struct { 803875Sab196087 const char *file; /* Name of file */ 813875Sab196087 Ehdr *ehdr; /* ELF header for file */ 823875Sab196087 Cache *cache; /* Cache of all section headers */ 833875Sab196087 Word shnum; /* # of sections in cache */ 843875Sab196087 Cache *seccache; /* Cache of symbol table section hdr */ 853875Sab196087 Word secndx; /* Index of symbol table section hdr */ 863875Sab196087 const char *secname; /* Name of section */ 873875Sab196087 uint_t flags; /* Command line option flags */ 883875Sab196087 struct { /* Extended section index data */ 893875Sab196087 int checked; /* TRUE if already checked for shxndx */ 903875Sab196087 Word *data; /* NULL, or extended section index */ 913875Sab196087 /* used for symbol table entries */ 923875Sab196087 uint_t n; /* # items in shxndx.data */ 933875Sab196087 } shxndx; 943875Sab196087 VERSYM_STATE *versym; /* NULL, or associated VERSYM section */ 953875Sab196087 Sym *sym; /* Array of symbols */ 963875Sab196087 Word symn; /* # of symbols */ 973875Sab196087 } SYMTBL_STATE; 983875Sab196087 993875Sab196087 1003875Sab196087 1010Sstevel@tonic-gate /* 1020Sstevel@tonic-gate * Focal point for verifying symbol names. 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate static const char * 1051618Srie string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name) 1060Sstevel@tonic-gate { 1074063Sab196087 /* 1084063Sab196087 * If an error in this routine is due to a property of the string 1094063Sab196087 * section, as opposed to a bad offset into the section (a property of 1104063Sab196087 * the referencing section), then we will detect the same error on 1114063Sab196087 * every call involving those sections. We use these static variables 1124063Sab196087 * to retain the information needed to only issue each such error once. 1134063Sab196087 */ 1144063Sab196087 static Cache *last_refsec; /* Last referencing section seen */ 1154063Sab196087 static int strsec_err; /* True if error issued */ 1164063Sab196087 1173492Sab196087 const char *strs; 1183492Sab196087 Word strn; 1190Sstevel@tonic-gate 1203466Srie if (strsec->c_data == NULL) 1213466Srie return (NULL); 1223466Srie 1233492Sab196087 strs = (char *)strsec->c_data->d_buf; 1243492Sab196087 strn = strsec->c_data->d_size; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate /* 1274063Sab196087 * We only print a diagnostic regarding a bad string table once per 1284063Sab196087 * input section being processed. If the refsec has changed, reset 1294063Sab196087 * our retained error state. 1300Sstevel@tonic-gate */ 1314063Sab196087 if (last_refsec != refsec) { 1324063Sab196087 last_refsec = refsec; 1334063Sab196087 strsec_err = 0; 1344063Sab196087 } 1354063Sab196087 1364063Sab196087 /* Verify that strsec really is a string table */ 1374063Sab196087 if (strsec->c_shdr->sh_type != SHT_STRTAB) { 1384063Sab196087 if (!strsec_err) { 1394063Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOTSTRTAB), 1404063Sab196087 file, strsec->c_ndx, refsec->c_ndx); 1414063Sab196087 strsec_err = 1; 1424063Sab196087 } 1434063Sab196087 return (MSG_INTL(MSG_STR_UNKNOWN)); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate /* 1470Sstevel@tonic-gate * Is the string table offset within range of the available strings? 1480Sstevel@tonic-gate */ 1490Sstevel@tonic-gate if (name >= strn) { 1500Sstevel@tonic-gate /* 1510Sstevel@tonic-gate * Do we have a empty string table? 1520Sstevel@tonic-gate */ 1530Sstevel@tonic-gate if (strs == 0) { 1544063Sab196087 if (!strsec_err) { 1550Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1560Sstevel@tonic-gate file, strsec->c_name); 1574063Sab196087 strsec_err = 1; 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate } else { 1600Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF), 1611618Srie file, refsec->c_name, EC_WORD(ndx), strsec->c_name, 1621618Srie EC_WORD(name), EC_WORD(strn - 1)); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate /* 1660Sstevel@tonic-gate * Return the empty string so that the calling function can 1670Sstevel@tonic-gate * continue it's output diagnostics. 1680Sstevel@tonic-gate */ 1690Sstevel@tonic-gate return (MSG_INTL(MSG_STR_UNKNOWN)); 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate return (strs + name); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate /* 1751618Srie * Relocations can reference section symbols and standard symbols. If the 1761618Srie * former, establish the section name. 1771618Srie */ 1781618Srie static const char * 1791618Srie relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum, 1801618Srie Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file, 1811618Srie uint_t flags) 1821618Srie { 1831618Srie Sym *sym; 1841618Srie 1851618Srie if (symndx >= symnum) { 1861618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX), 1871618Srie file, EC_WORD(symndx), EC_WORD(relndx)); 1881618Srie return (MSG_INTL(MSG_STR_UNKNOWN)); 1891618Srie } 1901618Srie 1911618Srie sym = (Sym *)(syms + symndx); 1921618Srie 1931618Srie /* 1941618Srie * If the symbol represents a section offset construct an appropriate 1951618Srie * string. 1961618Srie */ 1971618Srie if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) && (sym->st_name == 0)) { 1981618Srie if (flags & FLG_LONGNAME) 1991618Srie (void) snprintf(secstr, secsz, 2001618Srie MSG_INTL(MSG_STR_L_SECTION), 2011618Srie cache[sym->st_shndx].c_name); 2021618Srie else 2031618Srie (void) snprintf(secstr, secsz, 2041618Srie MSG_INTL(MSG_STR_SECTION), 2051618Srie cache[sym->st_shndx].c_name); 2061618Srie return ((const char *)secstr); 2071618Srie } 2081618Srie 2091618Srie return (string(csec, symndx, strsec, file, sym->st_name)); 2101618Srie } 2111618Srie 2121618Srie /* 2131618Srie * Focal point for establishing a string table section. Data such as the 2141618Srie * dynamic information simply points to a string table. Data such as 2151618Srie * relocations, reference a symbol table, which in turn is associated with a 2161618Srie * string table. 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate static int 2191618Srie stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file, 2201618Srie Word *symnum, Cache **symsec, Cache **strsec) 2211618Srie { 2221618Srie Shdr *shdr = cache[ndx].c_shdr; 2231618Srie 2241618Srie if (symtab) { 2251618Srie /* 2261618Srie * Validate the symbol table section. 2271618Srie */ 2281618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2291618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2301618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 2311618Srie return (0); 2321618Srie } 2333466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2343466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2353466Srie file, cache[ndx].c_name); 2363466Srie return (0); 2373466Srie } 2381618Srie 2391618Srie /* 2401618Srie * Obtain, and verify the symbol table data. 2411618Srie */ 2423466Srie if ((cache[ndx].c_data == NULL) || 2433466Srie (cache[ndx].c_data->d_buf == NULL)) { 2441618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2451618Srie file, cache[ndx].c_name); 2461618Srie return (0); 2471618Srie } 2481618Srie 2491618Srie /* 2501618Srie * Establish the string table index. 2511618Srie */ 2521618Srie ndx = shdr->sh_link; 2531618Srie shdr = cache[ndx].c_shdr; 2541618Srie 2551618Srie /* 2561618Srie * Return symbol table information. 2571618Srie */ 2581618Srie if (symnum) 2591618Srie *symnum = (shdr->sh_size / shdr->sh_entsize); 2601618Srie if (symsec) 2611618Srie *symsec = &cache[ndx]; 2621618Srie } 2631618Srie 2641618Srie /* 2651618Srie * Validate the associated string table section. 2661618Srie */ 2671618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2681618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2691618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 2701618Srie return (0); 2711618Srie } 2721618Srie 2731618Srie if (strsec) 2741618Srie *strsec = &cache[shdr->sh_link]; 2751618Srie 2761618Srie return (1); 2771618Srie } 2781618Srie 2791618Srie /* 2801618Srie * Lookup a symbol and set Sym accordingly. 2811618Srie */ 2821618Srie static int 2831618Srie symlookup(const char *name, Cache *cache, Word shnum, Sym **sym, 2840Sstevel@tonic-gate Cache *symtab, const char *file) 2850Sstevel@tonic-gate { 2861618Srie Shdr *shdr; 2871618Srie Word symn, cnt; 2881618Srie Sym *syms; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate if (symtab == 0) 2910Sstevel@tonic-gate return (0); 2920Sstevel@tonic-gate 2931618Srie shdr = symtab->c_shdr; 2941618Srie 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * Determine the symbol data and number. 2970Sstevel@tonic-gate */ 2980Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2990Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 3000Sstevel@tonic-gate file, symtab->c_name); 3010Sstevel@tonic-gate return (0); 3020Sstevel@tonic-gate } 3033466Srie if (symtab->c_data == NULL) 3043466Srie return (0); 3053466Srie 3060Sstevel@tonic-gate /* LINTED */ 3071618Srie symn = (Word)(shdr->sh_size / shdr->sh_entsize); 3081618Srie syms = (Sym *)symtab->c_data->d_buf; 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate /* 3110Sstevel@tonic-gate * Get the associated string table section. 3120Sstevel@tonic-gate */ 3130Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3140Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3151618Srie file, symtab->c_name, EC_WORD(shdr->sh_link)); 3160Sstevel@tonic-gate return (0); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate 3190Sstevel@tonic-gate /* 3200Sstevel@tonic-gate * Loop through the symbol table to find a match. 3210Sstevel@tonic-gate */ 3221618Srie for (cnt = 0; cnt < symn; syms++, cnt++) { 3231618Srie const char *symname; 3240Sstevel@tonic-gate 3251618Srie symname = string(symtab, cnt, &cache[shdr->sh_link], file, 3261618Srie syms->st_name); 3270Sstevel@tonic-gate 3281618Srie if (symname && (strcmp(name, symname) == 0)) { 3291618Srie *sym = syms; 3300Sstevel@tonic-gate return (1); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate } 3330Sstevel@tonic-gate return (0); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * Print section headers. 3380Sstevel@tonic-gate */ 3390Sstevel@tonic-gate static void 3404168Sab196087 sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr) 3410Sstevel@tonic-gate { 3421618Srie size_t seccnt; 3430Sstevel@tonic-gate 3441618Srie for (seccnt = 1; seccnt < shnum; seccnt++) { 3451618Srie Cache *_cache = &cache[seccnt]; 3461618Srie Shdr *shdr = _cache->c_shdr; 3471618Srie const char *secname = _cache->c_name; 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * Although numerous section header entries can be zero, it's 3513862Srie * usually a sign of trouble if the type is zero. 3520Sstevel@tonic-gate */ 3530Sstevel@tonic-gate if (shdr->sh_type == 0) { 3540Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE), 3551618Srie file, secname, EC_WORD(shdr->sh_type)); 3560Sstevel@tonic-gate } 3573862Srie 3584168Sab196087 if (!match(0, secname, seccnt)) 3593862Srie continue; 3600Sstevel@tonic-gate 3611324Srie /* 3621324Srie * Identify any sections that are suspicious. A .got section 3631324Srie * shouldn't exist in a relocatable object. 3641324Srie */ 3651324Srie if (ehdr->e_type == ET_REL) { 3661618Srie if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT), 3671324Srie MSG_ELF_GOT_SIZE) == 0) { 3681324Srie (void) fprintf(stderr, 3691618Srie MSG_INTL(MSG_GOT_UNEXPECTED), file, 3701618Srie secname); 3711324Srie } 3721324Srie } 3731324Srie 3741618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 3751618Srie dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname); 3761618Srie Elf_shdr(0, ehdr->e_machine, shdr); 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3801618Srie /* 3811618Srie * A couple of instances of unwind data are printed as tables of 8 data items 3821618Srie * expressed as 0x?? integers. 3831618Srie */ 3841618Srie #define UNWINDTBLSZ 10 + (8 * 5) + 1 3851618Srie 3861618Srie static void 3871618Srie unwindtbl(uint64_t *ndx, uint_t len, uchar_t *data, uint64_t doff, 3881618Srie const char *msg, const char *pre, size_t plen) 3891618Srie { 3901618Srie char buffer[UNWINDTBLSZ]; 3911618Srie uint_t boff = plen, cnt = 0; 3921618Srie 3931618Srie dbg_print(0, msg); 3941618Srie (void) strncpy(buffer, pre, UNWINDTBLSZ); 3951618Srie 3961618Srie while (*ndx < (len + 4)) { 3971618Srie if (cnt == 8) { 3981618Srie dbg_print(0, buffer); 3991618Srie boff = plen; 4001618Srie cnt = 0; 4011618Srie } 4021618Srie (void) snprintf(&buffer[boff], UNWINDTBLSZ - boff, 4031618Srie MSG_ORIG(MSG_UNW_TBLENTRY), data[doff + (*ndx)++]); 4041618Srie boff += 5; 4051618Srie cnt++; 4061618Srie } 4071618Srie if (cnt) 4081618Srie dbg_print(0, buffer); 4091618Srie } 4101618Srie 4111618Srie /* 4121618Srie * Obtain a specified Phdr entry. 4131618Srie */ 4141618Srie static Phdr * 4151618Srie getphdr(Word phnum, Word type, const char *file, Elf *elf) 4161618Srie { 4171618Srie Word cnt; 4181618Srie Phdr *phdr; 4191618Srie 4201618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 4211618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 4221618Srie return (0); 4231618Srie } 4241618Srie 4251618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 4261618Srie if (phdr->p_type == type) 4271618Srie return (phdr); 4281618Srie } 4291618Srie return (0); 4301618Srie } 4311618Srie 4320Sstevel@tonic-gate static void 4334168Sab196087 unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, 4344168Sab196087 Elf *elf) 4350Sstevel@tonic-gate { 4361618Srie Word cnt; 4371618Srie Phdr *uphdr = 0; 4381618Srie 4390Sstevel@tonic-gate /* 4401618Srie * For the moment - UNWIND is only relevant for a AMD64 object. 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate if (ehdr->e_machine != EM_AMD64) 4431618Srie return; 4440Sstevel@tonic-gate 4451618Srie if (phnum) 4461618Srie uphdr = getphdr(phnum, PT_SUNW_UNWIND, file, elf); 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 4491618Srie Cache *_cache = &cache[cnt]; 4501618Srie Shdr *shdr = _cache->c_shdr; 4511618Srie uchar_t *data; 4520Sstevel@tonic-gate size_t datasize; 4531618Srie uint64_t off, ndx, frame_ptr, fde_cnt, tabndx; 4541618Srie uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate /* 4571618Srie * AMD64 - this is a strmcp() just to find the gcc produced 4581618Srie * sections. Soon gcc should be setting the section type - and 4591618Srie * we'll not need this strcmp(). 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate if ((shdr->sh_type != SHT_AMD64_UNWIND) && 4620Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 4630Sstevel@tonic-gate MSG_SCN_FRM_SIZE) != 0) && 4640Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4650Sstevel@tonic-gate MSG_SCN_FRMHDR_SIZE) != 0)) 4660Sstevel@tonic-gate continue; 4674168Sab196087 4684168Sab196087 if (!match(0, _cache->c_name, cnt)) 4690Sstevel@tonic-gate continue; 4700Sstevel@tonic-gate 4713466Srie if (_cache->c_data == NULL) 4723466Srie continue; 4733466Srie 4741618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 4751618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 4760Sstevel@tonic-gate 4771618Srie data = (uchar_t *)(_cache->c_data->d_buf); 4780Sstevel@tonic-gate datasize = _cache->c_data->d_size; 4790Sstevel@tonic-gate off = 0; 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate /* 4820Sstevel@tonic-gate * Is this a .eh_frame_hdr 4830Sstevel@tonic-gate */ 4841618Srie if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || 4850Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4861618Srie MSG_SCN_FRMHDR_SIZE) == 0)) { 4871618Srie 4881618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR)); 4891618Srie ndx = 0; 4900Sstevel@tonic-gate 4911618Srie vers = data[ndx++]; 4921618Srie frame_ptr_enc = data[ndx++]; 4931618Srie fde_cnt_enc = data[ndx++]; 4941618Srie table_enc = data[ndx++]; 4950Sstevel@tonic-gate 4961618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); 4970Sstevel@tonic-gate 4981618Srie frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, 4991618Srie ehdr->e_ident, shdr->sh_addr + ndx); 5000Sstevel@tonic-gate 5011618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC), 5021618Srie conv_dwarf_ehe(frame_ptr_enc), EC_XWORD(frame_ptr)); 5031618Srie 5041618Srie fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, 5051618Srie ehdr->e_ident, shdr->sh_addr + ndx); 5060Sstevel@tonic-gate 5071618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), 5081618Srie conv_dwarf_ehe(fde_cnt_enc), EC_XWORD(fde_cnt)); 5091618Srie dbg_print(0, MSG_ORIG(MSG_UNW_TABENC), 5101618Srie conv_dwarf_ehe(table_enc)); 5111618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1)); 5121618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2)); 5130Sstevel@tonic-gate 5141618Srie for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 5151618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), 5161618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5171618Srie table_enc, ehdr->e_ident, shdr->sh_addr)), 5181618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5191618Srie table_enc, ehdr->e_ident, shdr->sh_addr))); 5201618Srie } 5211618Srie continue; 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * Walk the Eh_frame's 5260Sstevel@tonic-gate */ 5270Sstevel@tonic-gate while (off < datasize) { 5284433Sab196087 uint_t cieid, cielength, cieversion; 5294433Sab196087 uint_t cieretaddr; 5301618Srie int cieRflag, cieLflag, ciePflag, cieZflag; 5311618Srie uint_t cieaugndx, length, id; 5320Sstevel@tonic-gate uint64_t ciecalign, ciedalign; 5330Sstevel@tonic-gate char *cieaugstr; 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate ndx = 0; 5360Sstevel@tonic-gate /* 5370Sstevel@tonic-gate * extract length in lsb format 5380Sstevel@tonic-gate */ 5390Sstevel@tonic-gate length = LSB32EXTRACT(data + off + ndx); 5400Sstevel@tonic-gate ndx += 4; 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate /* 5430Sstevel@tonic-gate * extract CIE id in lsb format 5440Sstevel@tonic-gate */ 5450Sstevel@tonic-gate id = LSB32EXTRACT(data + off + ndx); 5460Sstevel@tonic-gate ndx += 4; 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate /* 5491618Srie * A CIE record has a id of '0', otherwise this is a 5501618Srie * FDE entry and the 'id' is the CIE pointer. 5510Sstevel@tonic-gate */ 5520Sstevel@tonic-gate if (id == 0) { 5530Sstevel@tonic-gate uint64_t persVal; 5541618Srie 5550Sstevel@tonic-gate cielength = length; 5560Sstevel@tonic-gate cieid = id; 5571618Srie cieLflag = ciePflag = cieRflag = cieZflag = 0; 5580Sstevel@tonic-gate 5591618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIE), 5601618Srie EC_XWORD(shdr->sh_addr + off)); 5611618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH), 5621618Srie cielength, cieid); 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate cieversion = data[off + ndx]; 5650Sstevel@tonic-gate ndx += 1; 5660Sstevel@tonic-gate cieaugstr = (char *)(&data[off + ndx]); 5670Sstevel@tonic-gate ndx += strlen(cieaugstr) + 1; 5681618Srie 5691618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS), 5701618Srie cieversion, cieaugstr); 5711618Srie 5720Sstevel@tonic-gate ciecalign = uleb_extract(&data[off], &ndx); 5730Sstevel@tonic-gate ciedalign = sleb_extract(&data[off], &ndx); 5740Sstevel@tonic-gate cieretaddr = data[off + ndx]; 5750Sstevel@tonic-gate ndx += 1; 5761618Srie 5771618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN), 5781618Srie EC_XWORD(ciecalign), EC_XWORD(ciedalign), 5791618Srie cieretaddr); 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate if (cieaugstr[0]) 5824433Sab196087 dbg_print(0, 5834433Sab196087 MSG_ORIG(MSG_UNW_CIEAXVAL)); 5841618Srie 5850Sstevel@tonic-gate for (cieaugndx = 0; cieaugstr[cieaugndx]; 5860Sstevel@tonic-gate cieaugndx++) { 5870Sstevel@tonic-gate uint_t val; 5881618Srie 5890Sstevel@tonic-gate switch (cieaugstr[cieaugndx]) { 5900Sstevel@tonic-gate case 'z': 5914433Sab196087 val = uleb_extract(&data[off], 5924433Sab196087 &ndx); 5934433Sab196087 dbg_print(0, 5944433Sab196087 MSG_ORIG(MSG_UNW_CIEAXSIZ), 5954433Sab196087 val); 5964433Sab196087 cieZflag = 1; 5974433Sab196087 break; 5980Sstevel@tonic-gate case 'P': 5994433Sab196087 ciePflag = data[off + ndx]; 6004433Sab196087 ndx += 1; 6014433Sab196087 6024433Sab196087 persVal = dwarf_ehe_extract( 6034433Sab196087 &data[off], &ndx, ciePflag, 6044433Sab196087 ehdr->e_ident, 6054433Sab196087 shdr->sh_addr + off + ndx); 6064433Sab196087 dbg_print(0, 6074433Sab196087 MSG_ORIG(MSG_UNW_CIEAXPERS), 6084433Sab196087 ciePflag, 6094433Sab196087 conv_dwarf_ehe(ciePflag), 6104433Sab196087 EC_XWORD(persVal)); 6114433Sab196087 break; 6120Sstevel@tonic-gate case 'R': 6134433Sab196087 val = data[off + ndx]; 6144433Sab196087 ndx += 1; 6154433Sab196087 dbg_print(0, 6164433Sab196087 MSG_ORIG(MSG_UNW_CIEAXCENC), 6174433Sab196087 val, conv_dwarf_ehe(val)); 6184433Sab196087 cieRflag = val; 6194433Sab196087 break; 6200Sstevel@tonic-gate case 'L': 6214433Sab196087 val = data[off + ndx]; 6224433Sab196087 ndx += 1; 6234433Sab196087 dbg_print(0, 6244433Sab196087 MSG_ORIG(MSG_UNW_CIEAXLSDA), 6254433Sab196087 val, conv_dwarf_ehe(val)); 6264433Sab196087 cieLflag = val; 6274433Sab196087 break; 6280Sstevel@tonic-gate default: 6294433Sab196087 dbg_print(0, 6304433Sab196087 MSG_ORIG(MSG_UNW_CIEAXUNEC), 6314433Sab196087 cieaugstr[cieaugndx]); 6324433Sab196087 break; 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate } 6351618Srie if ((cielength + 4) > ndx) 6361618Srie unwindtbl(&ndx, cielength, data, off, 6371618Srie MSG_ORIG(MSG_UNW_CIECFI), 6381618Srie MSG_ORIG(MSG_UNW_CIEPRE), 6391618Srie MSG_UNW_CIEPRE_SIZE); 6400Sstevel@tonic-gate off += cielength + 4; 6411618Srie 6420Sstevel@tonic-gate } else { 6430Sstevel@tonic-gate uint_t fdelength = length; 6440Sstevel@tonic-gate int fdecieptr = id; 6450Sstevel@tonic-gate uint64_t fdeinitloc, fdeaddrrange; 6460Sstevel@tonic-gate 6471618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDE), 6481618Srie EC_XWORD(shdr->sh_addr + off)); 6491618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH), 6500Sstevel@tonic-gate fdelength, fdecieptr); 6511618Srie 6520Sstevel@tonic-gate fdeinitloc = dwarf_ehe_extract(&data[off], 6530Sstevel@tonic-gate &ndx, cieRflag, ehdr->e_ident, 6540Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6550Sstevel@tonic-gate fdeaddrrange = dwarf_ehe_extract(&data[off], 6560Sstevel@tonic-gate &ndx, (cieRflag & ~DW_EH_PE_pcrel), 6570Sstevel@tonic-gate ehdr->e_ident, 6580Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6591618Srie 6601618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), 6611618Srie EC_XWORD(fdeinitloc), 6621618Srie EC_XWORD(fdeaddrrange)); 6631618Srie 6640Sstevel@tonic-gate if (cieaugstr[0]) 6651618Srie dbg_print(0, 6664433Sab196087 MSG_ORIG(MSG_UNW_FDEAXVAL)); 6670Sstevel@tonic-gate if (cieZflag) { 6680Sstevel@tonic-gate uint64_t val; 6690Sstevel@tonic-gate val = uleb_extract(&data[off], &ndx); 6701618Srie dbg_print(0, 6714433Sab196087 MSG_ORIG(MSG_UNW_FDEAXSIZE), 6721618Srie EC_XWORD(val)); 6730Sstevel@tonic-gate if (val & cieLflag) { 6744433Sab196087 fdeinitloc = dwarf_ehe_extract( 6754433Sab196087 &data[off], &ndx, cieLflag, 6764433Sab196087 ehdr->e_ident, 6774433Sab196087 shdr->sh_addr + off + ndx); 6784433Sab196087 dbg_print(0, 6794433Sab196087 MSG_ORIG(MSG_UNW_FDEAXLSDA), 6804433Sab196087 EC_XWORD(val)); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate } 6831618Srie if ((fdelength + 4) > ndx) 6841618Srie unwindtbl(&ndx, fdelength, data, off, 6851618Srie MSG_ORIG(MSG_UNW_FDECFI), 6861618Srie MSG_ORIG(MSG_UNW_FDEPRE), 6871618Srie MSG_UNW_FDEPRE_SIZE); 6880Sstevel@tonic-gate off += fdelength + 4; 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate } 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate /* 6950Sstevel@tonic-gate * Print the hardware/software capabilities. For executables and shared objects 6960Sstevel@tonic-gate * this should be accompanied with a program header. 6970Sstevel@tonic-gate */ 6980Sstevel@tonic-gate static void 6991618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, 7001618Srie Elf *elf) 7010Sstevel@tonic-gate { 7021618Srie Word cnt; 7033466Srie Shdr *cshdr = 0; 7043466Srie Cache *ccache; 7051618Srie Off cphdr_off = 0; 7061618Srie Xword cphdr_sz; 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate /* 7090Sstevel@tonic-gate * Determine if a hardware/software capabilities header exists. 7100Sstevel@tonic-gate */ 7111618Srie if (phnum) { 7121618Srie Phdr *phdr; 7130Sstevel@tonic-gate 7141618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 7150Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 7160Sstevel@tonic-gate return; 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate 7191618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 7201618Srie if (phdr->p_type == PT_SUNWCAP) { 7211618Srie cphdr_off = phdr->p_offset; 7221618Srie cphdr_sz = phdr->p_filesz; 7231618Srie break; 7241618Srie } 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate /* 7290Sstevel@tonic-gate * Determine if a hardware/software capabilities section exists. 7300Sstevel@tonic-gate */ 7310Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 7321618Srie Cache *_cache = &cache[cnt]; 7331618Srie Shdr *shdr = _cache->c_shdr; 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_cap) 7360Sstevel@tonic-gate continue; 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 7390Sstevel@tonic-gate (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 7400Sstevel@tonic-gate continue; 7410Sstevel@tonic-gate 7423466Srie if (_cache->c_data == NULL) 7433466Srie continue; 7443466Srie 7450Sstevel@tonic-gate ccache = _cache; 7460Sstevel@tonic-gate cshdr = shdr; 7470Sstevel@tonic-gate break; 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate if ((cshdr == 0) && (cphdr_off == 0)) 7510Sstevel@tonic-gate return; 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate /* 7540Sstevel@tonic-gate * Print the hardware/software capabilities section. 7550Sstevel@tonic-gate */ 7560Sstevel@tonic-gate if (cshdr) { 7571618Srie Word ndx, capn; 7583492Sab196087 Cap *cap = (Cap *)ccache->c_data->d_buf; 7590Sstevel@tonic-gate 7604665Sab196087 if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) { 7614665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 7624665Sab196087 file, ccache->c_name); 7634665Sab196087 return; 7644665Sab196087 } 7654665Sab196087 7661618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 7671618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 7680Sstevel@tonic-gate 7691618Srie Elf_cap_title(0); 7701618Srie 7711618Srie capn = (Word)(cshdr->sh_size / cshdr->sh_entsize); 7720Sstevel@tonic-gate 7731618Srie for (ndx = 0; ndx < capn; cap++, ndx++) { 7741618Srie if (cap->c_tag != CA_SUNW_NULL) 7751618Srie Elf_cap_entry(0, cap, ndx, ehdr->e_machine); 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate } else 7780Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate /* 7810Sstevel@tonic-gate * If this object is an executable or shared object, then the 7820Sstevel@tonic-gate * hardware/software capabilities section should have an accompanying 7830Sstevel@tonic-gate * program header. 7840Sstevel@tonic-gate */ 7850Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 7860Sstevel@tonic-gate if (cphdr_off == 0) 7870Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 7880Sstevel@tonic-gate file, ccache->c_name); 7890Sstevel@tonic-gate else if ((cphdr_off != cshdr->sh_offset) || 7900Sstevel@tonic-gate (cphdr_sz != cshdr->sh_size)) 7910Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 7920Sstevel@tonic-gate file, ccache->c_name); 7930Sstevel@tonic-gate } 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * Print the interpretor. 7980Sstevel@tonic-gate */ 7990Sstevel@tonic-gate static void 8001618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) 8010Sstevel@tonic-gate { 8021618Srie Word cnt; 8031618Srie Shdr *ishdr = 0; 8041618Srie Cache *icache; 8051618Srie Off iphdr_off = 0; 8061618Srie Xword iphdr_fsz; 8070Sstevel@tonic-gate 8080Sstevel@tonic-gate /* 8090Sstevel@tonic-gate * Determine if an interp header exists. 8100Sstevel@tonic-gate */ 8111618Srie if (phnum) { 8121618Srie Phdr *phdr; 8130Sstevel@tonic-gate 8141618Srie if ((phdr = getphdr(phnum, PT_INTERP, file, elf)) != 0) { 8151618Srie iphdr_off = phdr->p_offset; 8161618Srie iphdr_fsz = phdr->p_filesz; 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate if (iphdr_off == 0) 8210Sstevel@tonic-gate return; 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * Determine if an interp section exists. 8250Sstevel@tonic-gate */ 8260Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8271618Srie Cache *_cache = &cache[cnt]; 8281618Srie Shdr *shdr = _cache->c_shdr; 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate /* 8310Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP 8320Sstevel@tonic-gate * string. The target section can't be in a NOBITS section. 8330Sstevel@tonic-gate */ 8340Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) || 8350Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) || 8361618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size)) 8370Sstevel@tonic-gate continue; 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate icache = _cache; 8400Sstevel@tonic-gate ishdr = shdr; 8410Sstevel@tonic-gate break; 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate /* 8450Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the 8460Sstevel@tonic-gate * program header, as this is the offset used by the kernel. 8470Sstevel@tonic-gate */ 8483466Srie if (ishdr && icache->c_data) { 8491618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8501618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 8511618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), 8520Sstevel@tonic-gate (char *)icache->c_data->d_buf + 8530Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset)); 8540Sstevel@tonic-gate } else 8550Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate /* 8580Sstevel@tonic-gate * If there are any inconsistences between the program header and 8590Sstevel@tonic-gate * section information, flag them. 8600Sstevel@tonic-gate */ 8610Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) || 8621618Srie (iphdr_fsz != ishdr->sh_size))) { 8630Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 8640Sstevel@tonic-gate icache->c_name); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate } 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* 8690Sstevel@tonic-gate * Print the syminfo section. 8700Sstevel@tonic-gate */ 8710Sstevel@tonic-gate static void 8721618Srie syminfo(Cache *cache, Word shnum, const char *file) 8730Sstevel@tonic-gate { 8741618Srie Shdr *infoshdr; 8751618Srie Syminfo *info; 8761618Srie Sym *syms; 8771618Srie Dyn *dyns; 8781618Srie Word infonum, cnt, ndx, symnum; 8791618Srie Cache *infocache = 0, *symsec, *strsec; 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8821618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { 8831618Srie infocache = &cache[cnt]; 8840Sstevel@tonic-gate break; 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate } 8871618Srie if (infocache == 0) 8880Sstevel@tonic-gate return; 8890Sstevel@tonic-gate 8901618Srie infoshdr = infocache->c_shdr; 8911618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) { 8920Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8931618Srie file, infocache->c_name); 8940Sstevel@tonic-gate return; 8950Sstevel@tonic-gate } 8963466Srie if (infocache->c_data == NULL) 8973466Srie return; 8983466Srie 8991618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize); 9001618Srie info = (Syminfo *)infocache->c_data->d_buf; 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate /* 9030Sstevel@tonic-gate * Get the data buffer of the associated dynamic section. 9040Sstevel@tonic-gate */ 9051618Srie if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) { 9060Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 9071618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info)); 9080Sstevel@tonic-gate return; 9090Sstevel@tonic-gate } 9103466Srie if (cache[infoshdr->sh_info].c_data == NULL) 9113466Srie return; 9123466Srie 9131618Srie dyns = cache[infoshdr->sh_info].c_data->d_buf; 9141618Srie if (dyns == 0) { 9150Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 9161618Srie file, cache[infoshdr->sh_info].c_name); 9170Sstevel@tonic-gate return; 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate /* 9211618Srie * Get the data buffer for the associated symbol table and string table. 9220Sstevel@tonic-gate */ 9231618Srie if (stringtbl(cache, 1, cnt, shnum, file, 9241618Srie &symnum, &symsec, &strsec) == 0) 9250Sstevel@tonic-gate return; 9260Sstevel@tonic-gate 9271618Srie syms = symsec->c_data->d_buf; 9280Sstevel@tonic-gate 9291618Srie /* 9301618Srie * Loop through the syminfo entries. 9311618Srie */ 9321618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 9331618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name); 9341618Srie Elf_syminfo_title(0); 9350Sstevel@tonic-gate 9361618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) { 9371618Srie Sym *sym; 9381618Srie const char *needed = 0, *name; 9391618Srie 9401618Srie if ((info->si_flags == 0) && (info->si_boundto == 0)) 9410Sstevel@tonic-gate continue; 9420Sstevel@tonic-gate 9431618Srie sym = &syms[ndx]; 9441618Srie name = string(infocache, ndx, strsec, file, sym->st_name); 9450Sstevel@tonic-gate 9461618Srie if (info->si_boundto < SYMINFO_BT_LOWRESERVE) { 9471618Srie Dyn *dyn = &dyns[info->si_boundto]; 9481618Srie 9491618Srie needed = string(infocache, info->si_boundto, 9501618Srie strsec, file, dyn->d_un.d_val); 9510Sstevel@tonic-gate } 9521618Srie Elf_syminfo_entry(0, ndx, info, name, needed); 9530Sstevel@tonic-gate } 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate /* 9570Sstevel@tonic-gate * Print version definition section entries. 9580Sstevel@tonic-gate */ 9590Sstevel@tonic-gate static void 960*4716Sab196087 version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache, 9610Sstevel@tonic-gate const char *file) 9620Sstevel@tonic-gate { 9631618Srie Word cnt; 9641618Srie char index[MAXNDXSIZE]; 9650Sstevel@tonic-gate 9661618Srie Elf_ver_def_title(0); 9670Sstevel@tonic-gate 968*4716Sab196087 for (cnt = 1; cnt <= vdf_num; cnt++, 9691618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 9700Sstevel@tonic-gate const char *name, *dep; 9711618Srie Half vcnt = vdf->vd_cnt - 1; 9721618Srie Half ndx = vdf->vd_ndx; 9734433Sab196087 Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* 9760Sstevel@tonic-gate * Obtain the name and first dependency (if any). 9770Sstevel@tonic-gate */ 9780Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name); 9791618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9800Sstevel@tonic-gate if (vcnt) 9810Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name); 9820Sstevel@tonic-gate else 9830Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 9860Sstevel@tonic-gate EC_XWORD(ndx)); 9871618Srie Elf_ver_line_1(0, index, name, dep, 9881618Srie conv_ver_flags(vdf->vd_flags)); 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate /* 9910Sstevel@tonic-gate * Print any additional dependencies. 9920Sstevel@tonic-gate */ 9930Sstevel@tonic-gate if (vcnt) { 9941618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9950Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 9961618Srie vdap = (Verdaux *)((uintptr_t)vdap + 9970Sstevel@tonic-gate vdap->vda_next)) { 9980Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 9990Sstevel@tonic-gate vdap->vda_name); 10001618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep); 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate } 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate /* 1007*4716Sab196087 * Print version needed section entries. 1008*4716Sab196087 * 1009*4716Sab196087 * entry: 1010*4716Sab196087 * vnd - Address of verneed data 1011*4716Sab196087 * vnd_num - # of Verneed entries 1012*4716Sab196087 * vcache - Cache of verneed section being processed 1013*4716Sab196087 * scache - Cache of associated string table section 1014*4716Sab196087 * file - Name of object being processed. 1015*4716Sab196087 * versym - Information about versym section 1016*4716Sab196087 * 1017*4716Sab196087 * exit: 1018*4716Sab196087 * The versions have been printed. If GNU style versioning 1019*4716Sab196087 * is in effect, versym->max_verndx has been updated to 1020*4716Sab196087 * contain the largest version index seen. 10210Sstevel@tonic-gate */ 10220Sstevel@tonic-gate static void 1023*4716Sab196087 version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache, 1024*4716Sab196087 const char *file, VERSYM_STATE *versym) 10250Sstevel@tonic-gate { 1026*4716Sab196087 Word cnt; 1027*4716Sab196087 char index[MAXNDXSIZE]; 1028*4716Sab196087 const char *index_str; 1029*4716Sab196087 1030*4716Sab196087 Elf_ver_need_title(0, versym->gnu); 1031*4716Sab196087 1032*4716Sab196087 /* 1033*4716Sab196087 * The versym section in an object that follows Solaris versioning 1034*4716Sab196087 * rules contains indexes into the verdef section. Symbols defined 1035*4716Sab196087 * in other objects (UNDEF) are given a version of 0, indicating that 1036*4716Sab196087 * they are not defined by this file, and the Verneed entries do not 1037*4716Sab196087 * have associated version indexes. For these reasons, we do not 1038*4716Sab196087 * display a version index for Solaris Verneed sections. 1039*4716Sab196087 * 1040*4716Sab196087 * The GNU versioning rules are different: Symbols defined in other 1041*4716Sab196087 * objects receive a version index in the range above those defined 1042*4716Sab196087 * by the Verdef section, and the vna_other field of the Vernaux 1043*4716Sab196087 * structs inside the Verneed section contain the version index for 1044*4716Sab196087 * that item. We therefore display the index when showing the 1045*4716Sab196087 * contents of a GNU Verneed section. You should not expect these 1046*4716Sab196087 * indexes to appear in sorted order --- it seems that the GNU ld 1047*4716Sab196087 * assigns the versions as symbols are encountered during linking, 1048*4716Sab196087 * and then the results are assembled into the Verneed section 1049*4716Sab196087 * afterwards. 1050*4716Sab196087 */ 1051*4716Sab196087 if (versym->gnu) { 1052*4716Sab196087 index_str = index; 1053*4716Sab196087 } else { 1054*4716Sab196087 /* For Solaris versioning, display a NULL string */ 1055*4716Sab196087 index_str = MSG_ORIG(MSG_STR_EMPTY); 1056*4716Sab196087 } 1057*4716Sab196087 1058*4716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 10591618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 10600Sstevel@tonic-gate const char *name, *dep; 10611618Srie Half vcnt = vnd->vn_cnt; 10624433Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate /* 10650Sstevel@tonic-gate * Obtain the name of the needed file and the version name 10660Sstevel@tonic-gate * within it that we're dependent on. Note that the count 10670Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus 10680Sstevel@tonic-gate * entry. 10690Sstevel@tonic-gate */ 10700Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file); 10710Sstevel@tonic-gate if (vcnt) 10720Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name); 10730Sstevel@tonic-gate else 10740Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL); 10750Sstevel@tonic-gate 1076*4716Sab196087 if (versym->gnu) { 1077*4716Sab196087 /* Format the version index value */ 1078*4716Sab196087 (void) snprintf(index, MAXNDXSIZE, 1079*4716Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(vnap->vna_other)); 1080*4716Sab196087 if (vnap->vna_other > versym->max_verndx) 1081*4716Sab196087 versym->max_verndx = vnap->vna_other; 1082*4716Sab196087 } 1083*4716Sab196087 Elf_ver_line_1(0, index_str, name, dep, 10841618Srie conv_ver_flags(vnap->vna_flags)); 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate /* 10870Sstevel@tonic-gate * Print any additional version dependencies. 10880Sstevel@tonic-gate */ 10890Sstevel@tonic-gate if (vcnt) { 10901618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 10910Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 10921618Srie vnap = (Vernaux *)((uintptr_t)vnap + 10930Sstevel@tonic-gate vnap->vna_next)) { 10940Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 10950Sstevel@tonic-gate vnap->vna_name); 1096*4716Sab196087 if (versym->gnu) { 1097*4716Sab196087 /* Format the next index value */ 1098*4716Sab196087 (void) snprintf(index, MAXNDXSIZE, 1099*4716Sab196087 MSG_ORIG(MSG_FMT_INDEX), 1100*4716Sab196087 EC_XWORD(vnap->vna_other)); 1101*4716Sab196087 Elf_ver_line_1(0, index_str, 1102*4716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 1103*4716Sab196087 conv_ver_flags(vnap->vna_flags)); 1104*4716Sab196087 if (vnap->vna_other > 1105*4716Sab196087 versym->max_verndx) 1106*4716Sab196087 versym->max_verndx = 1107*4716Sab196087 vnap->vna_other; 1108*4716Sab196087 } else { 1109*4716Sab196087 Elf_ver_line_3(0, 1110*4716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 1111*4716Sab196087 conv_ver_flags(vnap->vna_flags)); 1112*4716Sab196087 } 1113*4716Sab196087 } 1114*4716Sab196087 } 1115*4716Sab196087 } 1116*4716Sab196087 } 1117*4716Sab196087 1118*4716Sab196087 /* 1119*4716Sab196087 * Compute the max_verndx value for a GNU style object with 1120*4716Sab196087 * a Verneed section. This is only needed if version_need() is not 1121*4716Sab196087 * called. 1122*4716Sab196087 * 1123*4716Sab196087 * entry: 1124*4716Sab196087 * vnd - Address of verneed data 1125*4716Sab196087 * vnd_num - # of Verneed entries 1126*4716Sab196087 * versym - Information about versym section 1127*4716Sab196087 * 1128*4716Sab196087 * exit: 1129*4716Sab196087 * versym->max_verndx has been updated to contain the largest 1130*4716Sab196087 * version index seen. 1131*4716Sab196087 */ 1132*4716Sab196087 static void 1133*4716Sab196087 update_gnu_max_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym) 1134*4716Sab196087 { 1135*4716Sab196087 Word cnt; 1136*4716Sab196087 1137*4716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 1138*4716Sab196087 vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 1139*4716Sab196087 Half vcnt = vnd->vn_cnt; 1140*4716Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 1141*4716Sab196087 1142*4716Sab196087 if (vnap->vna_other > versym->max_verndx) 1143*4716Sab196087 versym->max_verndx = vnap->vna_other; 1144*4716Sab196087 1145*4716Sab196087 /* 1146*4716Sab196087 * Check any additional version dependencies. 1147*4716Sab196087 */ 1148*4716Sab196087 if (vcnt) { 1149*4716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 1150*4716Sab196087 for (vcnt--; vcnt; vcnt--, 1151*4716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + 1152*4716Sab196087 vnap->vna_next)) { 1153*4716Sab196087 if (vnap->vna_other > versym->max_verndx) 1154*4716Sab196087 versym->max_verndx = vnap->vna_other; 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate } 11570Sstevel@tonic-gate } 11580Sstevel@tonic-gate } 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate /* 11613875Sab196087 * Display version section information if the flags require it. 11623875Sab196087 * Return version information needed by other output. 11633875Sab196087 * 11643875Sab196087 * entry: 11653875Sab196087 * cache - Cache of all section headers 11663875Sab196087 * shnum - # of sections in cache 11673875Sab196087 * file - Name of file 11683875Sab196087 * flags - Command line option flags 11693875Sab196087 * versym - VERSYM_STATE block to be filled in. 11700Sstevel@tonic-gate */ 11713875Sab196087 static void 11723875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags, 11733875Sab196087 VERSYM_STATE *versym) 11740Sstevel@tonic-gate { 11750Sstevel@tonic-gate GElf_Word cnt; 1176*4716Sab196087 Cache *verdef_cache = NULL, *verneed_cache = NULL; 1177*4716Sab196087 1178*4716Sab196087 1179*4716Sab196087 /* Gather information about the version sections */ 11803875Sab196087 bzero(versym, sizeof (*versym)); 1181*4716Sab196087 versym->max_verndx = 1; 11820Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 11831618Srie Cache *_cache = &cache[cnt]; 11841618Srie Shdr *shdr = _cache->c_shdr; 1185*4716Sab196087 Dyn *dyn; 1186*4716Sab196087 ulong_t numdyn; 1187*4716Sab196087 1188*4716Sab196087 switch (shdr->sh_type) { 1189*4716Sab196087 case SHT_DYNAMIC: 1190*4716Sab196087 /* 1191*4716Sab196087 * The GNU ld puts a DT_VERSYM entry in the dynamic 1192*4716Sab196087 * section so that the runtime linker can use it to 1193*4716Sab196087 * implement their versioning rules. They allow multiple 1194*4716Sab196087 * incompatible functions with the same name to exist 1195*4716Sab196087 * in different versions. The Solaris ld does not 1196*4716Sab196087 * support this mechanism, and as such, does not 1197*4716Sab196087 * produce DT_VERSYM. We use this fact to determine 1198*4716Sab196087 * which ld produced this object, and how to interpret 1199*4716Sab196087 * the version values. 1200*4716Sab196087 */ 1201*4716Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0) || 1202*4716Sab196087 (_cache->c_data == NULL)) 1203*4716Sab196087 continue; 1204*4716Sab196087 numdyn = shdr->sh_size / shdr->sh_entsize; 1205*4716Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 1206*4716Sab196087 for (; numdyn-- > 0; dyn++) 1207*4716Sab196087 if (dyn->d_tag == DT_VERSYM) { 1208*4716Sab196087 versym->gnu = 1; 1209*4716Sab196087 break; 1210*4716Sab196087 } 1211*4716Sab196087 break; 1212*4716Sab196087 1213*4716Sab196087 case SHT_SUNW_versym: 1214*4716Sab196087 /* Record data address for later symbol processing */ 1215*4716Sab196087 if (_cache->c_data != NULL) { 1216*4716Sab196087 versym->cache = _cache; 1217*4716Sab196087 versym->data = _cache->c_data->d_buf; 1218*4716Sab196087 continue; 1219*4716Sab196087 } 1220*4716Sab196087 break; 1221*4716Sab196087 1222*4716Sab196087 case SHT_SUNW_verdef: 1223*4716Sab196087 case SHT_SUNW_verneed: 1224*4716Sab196087 /* 1225*4716Sab196087 * Ensure the data is non-NULL and the number 1226*4716Sab196087 * of items is non-zero. Otherwise, we don't 1227*4716Sab196087 * understand the section, and will not use it. 1228*4716Sab196087 */ 1229*4716Sab196087 if ((_cache->c_data == NULL) || 1230*4716Sab196087 (_cache->c_data->d_buf == NULL)) { 1231*4716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1232*4716Sab196087 file, _cache->c_name); 1233*4716Sab196087 continue; 1234*4716Sab196087 } 1235*4716Sab196087 if (shdr->sh_info == 0) { 1236*4716Sab196087 (void) fprintf(stderr, 1237*4716Sab196087 MSG_INTL(MSG_ERR_BADSHINFO), 1238*4716Sab196087 file, _cache->c_name, 1239*4716Sab196087 EC_WORD(shdr->sh_info)); 1240*4716Sab196087 continue; 1241*4716Sab196087 } 1242*4716Sab196087 1243*4716Sab196087 /* Make sure the string table index is in range */ 1244*4716Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1245*4716Sab196087 (void) fprintf(stderr, 1246*4716Sab196087 MSG_INTL(MSG_ERR_BADSHLINK), file, 1247*4716Sab196087 _cache->c_name, EC_WORD(shdr->sh_link)); 1248*4716Sab196087 continue; 1249*4716Sab196087 } 1250*4716Sab196087 1251*4716Sab196087 /* 1252*4716Sab196087 * The section is usable. Save the cache entry. 1253*4716Sab196087 */ 1254*4716Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) { 1255*4716Sab196087 verdef_cache = _cache; 1256*4716Sab196087 /* 1257*4716Sab196087 * Under Solaris rules, if there is a verdef 1258*4716Sab196087 * section, the max versym index is number 1259*4716Sab196087 * of version definitions it supplies. 1260*4716Sab196087 */ 1261*4716Sab196087 versym->max_verndx = shdr->sh_info; 1262*4716Sab196087 } else { 1263*4716Sab196087 verneed_cache = _cache; 1264*4716Sab196087 } 1265*4716Sab196087 break; 1266*4716Sab196087 } 1267*4716Sab196087 } 1268*4716Sab196087 1269*4716Sab196087 if ((flags & FLG_VERSIONS) == 0) { 12703875Sab196087 /* 1271*4716Sab196087 * If GNU versioning applies to this object, and there 1272*4716Sab196087 * is a Verneed section, then examine it to determine 1273*4716Sab196087 * the maximum Versym version index for this file. 12743875Sab196087 */ 1275*4716Sab196087 if ((versym->gnu) && (verneed_cache != NULL)) 1276*4716Sab196087 update_gnu_max_verndx( 1277*4716Sab196087 (Verneed *)verneed_cache->c_data->d_buf, 1278*4716Sab196087 verneed_cache->c_shdr->sh_info, versym); 1279*4716Sab196087 return; 1280*4716Sab196087 } 1281*4716Sab196087 1282*4716Sab196087 /* 1283*4716Sab196087 * Now that all the information is available, display the 1284*4716Sab196087 * Verdef and Verneed section contents. 1285*4716Sab196087 */ 1286*4716Sab196087 if (verdef_cache != NULL) { 1287*4716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 1288*4716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), 1289*4716Sab196087 verdef_cache->c_name); 1290*4716Sab196087 version_def((Verdef *)verdef_cache->c_data->d_buf, 1291*4716Sab196087 verdef_cache->c_shdr->sh_info, verdef_cache, 1292*4716Sab196087 &cache[verdef_cache->c_shdr->sh_link], file); 1293*4716Sab196087 } 1294*4716Sab196087 if (verneed_cache != NULL) { 1295*4716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 1296*4716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), 1297*4716Sab196087 verneed_cache->c_name); 12980Sstevel@tonic-gate /* 1299*4716Sab196087 * If GNU versioning applies to this object, version_need() 1300*4716Sab196087 * will update versym->max_verndx, and it is not 1301*4716Sab196087 * necessary to call update_gnu_max_verndx(). 13020Sstevel@tonic-gate */ 1303*4716Sab196087 version_need((Verneed *)verneed_cache->c_data->d_buf, 1304*4716Sab196087 verneed_cache->c_shdr->sh_info, verneed_cache, 1305*4716Sab196087 &cache[verneed_cache->c_shdr->sh_link], file, versym); 13060Sstevel@tonic-gate } 13070Sstevel@tonic-gate } 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate /* 13103492Sab196087 * Initialize a symbol table state structure 13113492Sab196087 * 13123492Sab196087 * entry: 13133492Sab196087 * state - State structure to be initialized 13143492Sab196087 * cache - Cache of all section headers 13153492Sab196087 * shnum - # of sections in cache 13163492Sab196087 * secndx - Index of symbol table section 13173492Sab196087 * ehdr - ELF header for file 13183875Sab196087 * versym - Information about versym section 13193492Sab196087 * file - Name of file 13203492Sab196087 * flags - Command line option flags 13211618Srie */ 13221618Srie static int 13233492Sab196087 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx, 13243875Sab196087 Ehdr *ehdr, VERSYM_STATE *versym, const char *file, uint_t flags) 13253492Sab196087 { 13263492Sab196087 Shdr *shdr; 13273492Sab196087 13283492Sab196087 state->file = file; 13293492Sab196087 state->ehdr = ehdr; 13303492Sab196087 state->cache = cache; 13313492Sab196087 state->shnum = shnum; 13323492Sab196087 state->seccache = &cache[secndx]; 13333492Sab196087 state->secndx = secndx; 13343492Sab196087 state->secname = state->seccache->c_name; 13353492Sab196087 state->flags = flags; 13363492Sab196087 state->shxndx.checked = 0; 13373492Sab196087 state->shxndx.data = NULL; 13383492Sab196087 state->shxndx.n = 0; 13393492Sab196087 13403492Sab196087 shdr = state->seccache->c_shdr; 13413492Sab196087 13423492Sab196087 /* 13433492Sab196087 * Check the symbol data and per-item size. 13443492Sab196087 */ 13453492Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 13463492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 13473492Sab196087 file, state->secname); 13483492Sab196087 return (0); 13493492Sab196087 } 13503492Sab196087 if (state->seccache->c_data == NULL) 13513492Sab196087 return (0); 13523492Sab196087 13533492Sab196087 /* LINTED */ 13543492Sab196087 state->symn = (Word)(shdr->sh_size / shdr->sh_entsize); 13553492Sab196087 state->sym = (Sym *)state->seccache->c_data->d_buf; 13563492Sab196087 13573492Sab196087 /* 13583492Sab196087 * Check associated string table section. 13593492Sab196087 */ 13603492Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 13613492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 13623492Sab196087 file, state->secname, EC_WORD(shdr->sh_link)); 13633492Sab196087 return (0); 13643492Sab196087 } 13653492Sab196087 13663492Sab196087 /* 13673492Sab196087 * Determine if there is a associated Versym section 13683492Sab196087 * with this Symbol Table. 13693492Sab196087 */ 13703875Sab196087 if (versym->cache && 13713875Sab196087 (versym->cache->c_shdr->sh_link == state->secndx)) 13723875Sab196087 state->versym = versym; 13733492Sab196087 else 13743492Sab196087 state->versym = NULL; 13753492Sab196087 13763492Sab196087 13773492Sab196087 return (1); 13783492Sab196087 } 13793492Sab196087 13803492Sab196087 /* 13813492Sab196087 * Determine the extended section index used for symbol tables entries. 13823492Sab196087 */ 13833492Sab196087 static void 13843492Sab196087 symbols_getxindex(SYMTBL_STATE * state) 13851618Srie { 13861618Srie uint_t symn; 13871618Srie Word symcnt; 13881618Srie 13893492Sab196087 state->shxndx.checked = 1; /* Note that we've been called */ 13903492Sab196087 for (symcnt = 1; symcnt < state->shnum; symcnt++) { 13913492Sab196087 Cache *_cache = &state->cache[symcnt]; 13921618Srie Shdr *shdr = _cache->c_shdr; 13931618Srie 13941618Srie if ((shdr->sh_type != SHT_SYMTAB_SHNDX) || 13953492Sab196087 (shdr->sh_link != state->secndx)) 13961618Srie continue; 13971618Srie 13981618Srie if ((shdr->sh_entsize) && 13991618Srie /* LINTED */ 14001618Srie ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0)) 14011618Srie continue; 14021618Srie 14033466Srie if (_cache->c_data == NULL) 14043466Srie continue; 14053466Srie 14063492Sab196087 state->shxndx.data = _cache->c_data->d_buf; 14073492Sab196087 state->shxndx.n = symn; 14083492Sab196087 return; 14091618Srie } 14101618Srie } 14111618Srie 14121618Srie /* 14133492Sab196087 * Produce a line of output for the given symbol 14143492Sab196087 * 14153492Sab196087 * entry: 14163875Sab196087 * state - Symbol table state 14173492Sab196087 * symndx - Index of symbol within the table 14183492Sab196087 * symndx_disp - Index to display. This may not be the same 14193492Sab196087 * as symndx if the display is relative to the logical 14203492Sab196087 * combination of the SUNW_ldynsym/dynsym tables. 14213492Sab196087 * sym - Symbol to display 14220Sstevel@tonic-gate */ 14233492Sab196087 static void 14243492Sab196087 output_symbol(SYMTBL_STATE *state, Word symndx, Word disp_symndx, Sym *sym) 14250Sstevel@tonic-gate { 14263118Sab196087 /* 14273118Sab196087 * Symbol types for which we check that the specified 14283118Sab196087 * address/size land inside the target section. 14293118Sab196087 */ 14303492Sab196087 static const int addr_symtype[STT_NUM] = { 14313118Sab196087 0, /* STT_NOTYPE */ 14323118Sab196087 1, /* STT_OBJECT */ 14333118Sab196087 1, /* STT_FUNC */ 14343118Sab196087 0, /* STT_SECTION */ 14353118Sab196087 0, /* STT_FILE */ 14363118Sab196087 1, /* STT_COMMON */ 14373118Sab196087 0, /* STT_TLS */ 14383118Sab196087 }; 14393118Sab196087 #if STT_NUM != (STT_TLS + 1) 14403492Sab196087 #error "STT_NUM has grown. Update addr_symtype[]" 14413118Sab196087 #endif 14423118Sab196087 14434665Sab196087 char index[MAXNDXSIZE]; 14444665Sab196087 const char *symname, *sec; 14453875Sab196087 Versym verndx; 1446*4716Sab196087 int gnuver; 14473492Sab196087 uchar_t type; 14483492Sab196087 Shdr *tshdr; 14493492Sab196087 Word shndx; 14503492Sab196087 14513492Sab196087 /* Ensure symbol index is in range */ 14523492Sab196087 if (symndx >= state->symn) { 14533492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX), 14543492Sab196087 state->file, state->secname, EC_WORD(symndx)); 14553492Sab196087 return; 14563492Sab196087 } 14573492Sab196087 14583492Sab196087 /* 14593492Sab196087 * If we are using extended symbol indexes, find the 14603492Sab196087 * corresponding SHN_SYMTAB_SHNDX table. 14613492Sab196087 */ 14623492Sab196087 if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0)) 14633492Sab196087 symbols_getxindex(state); 14643492Sab196087 14653492Sab196087 /* LINTED */ 14663492Sab196087 symname = string(state->seccache, symndx, 14673492Sab196087 &state->cache[state->seccache->c_shdr->sh_link], state->file, 14683492Sab196087 sym->st_name); 14693492Sab196087 14703492Sab196087 tshdr = 0; 14713492Sab196087 sec = NULL; 14723492Sab196087 14734665Sab196087 if (state->ehdr->e_type == ET_CORE) { 14743492Sab196087 sec = (char *)MSG_INTL(MSG_STR_UNKNOWN); 14754665Sab196087 } else if (state->flags & FLG_FAKESHDR) { 14764665Sab196087 /* 14774665Sab196087 * If we are using fake section headers derived from 14784665Sab196087 * the program headers, then the section indexes 14794665Sab196087 * in the symbols do not correspond to these headers. 14804665Sab196087 * The section names are not available, so all we can 14814665Sab196087 * do is to display them in numeric form. 14824665Sab196087 */ 14834665Sab196087 sec = conv_sym_shndx(sym->st_shndx); 14844665Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 14853492Sab196087 (sym->st_shndx < state->shnum)) { 14863492Sab196087 shndx = sym->st_shndx; 14873492Sab196087 tshdr = state->cache[shndx].c_shdr; 14883492Sab196087 sec = state->cache[shndx].c_name; 14893492Sab196087 } else if (sym->st_shndx == SHN_XINDEX) { 14903492Sab196087 if (state->shxndx.data) { 14913492Sab196087 Word _shxndx; 14923492Sab196087 14933492Sab196087 if (symndx > state->shxndx.n) { 14944433Sab196087 (void) fprintf(stderr, 14954433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 14964433Sab196087 state->file, state->secname, 14974433Sab196087 EC_WORD(symndx)); 14983492Sab196087 } else if ((_shxndx = 14993492Sab196087 state->shxndx.data[symndx]) > state->shnum) { 15004433Sab196087 (void) fprintf(stderr, 15014433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 15024433Sab196087 state->file, state->secname, 15034433Sab196087 EC_WORD(symndx), EC_WORD(_shxndx)); 15043492Sab196087 } else { 15054433Sab196087 shndx = _shxndx; 15064433Sab196087 tshdr = state->cache[shndx].c_shdr; 15074433Sab196087 sec = state->cache[shndx].c_name; 15083492Sab196087 } 15093492Sab196087 } else { 15103492Sab196087 (void) fprintf(stderr, 15113492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 15123492Sab196087 state->file, state->secname, EC_WORD(symndx)); 15133492Sab196087 } 15143492Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 15153492Sab196087 (sym->st_shndx >= state->shnum)) { 15163492Sab196087 (void) fprintf(stderr, 15173492Sab196087 MSG_INTL(MSG_ERR_BADSYM5), state->file, 15183492Sab196087 state->secname, demangle(symname, state->flags), 15193492Sab196087 sym->st_shndx); 15203492Sab196087 } 15210Sstevel@tonic-gate 15223492Sab196087 /* 15233492Sab196087 * If versioning is available display the 15243875Sab196087 * version index. If not, then use 0. 15253492Sab196087 */ 15263875Sab196087 if (state->versym) { 1527*4716Sab196087 Versym test_verndx; 1528*4716Sab196087 1529*4716Sab196087 verndx = test_verndx = state->versym->data[symndx]; 1530*4716Sab196087 gnuver = state->versym->gnu; 15313875Sab196087 15323875Sab196087 /* 15333875Sab196087 * Check to see if this is a defined symbol with a 15343875Sab196087 * version index that is outside the valid range for 1535*4716Sab196087 * the file. The interpretation of this depends on 1536*4716Sab196087 * the style of versioning used by the object. 15373875Sab196087 * 1538*4716Sab196087 * Versions >= VER_NDX_LORESERVE have special meanings, 1539*4716Sab196087 * and are exempt from this checking. 1540*4716Sab196087 * 1541*4716Sab196087 * GNU style version indexes use the top bit of the 1542*4716Sab196087 * 16-bit index value (0x8000) as the "hidden bit". 1543*4716Sab196087 * We must mask off this bit in order to compare 1544*4716Sab196087 * the version against the maximum value. 15453875Sab196087 */ 1546*4716Sab196087 if (gnuver) 1547*4716Sab196087 test_verndx &= ~0x8000; 1548*4716Sab196087 1549*4716Sab196087 if ((test_verndx > state->versym->max_verndx) && 1550*4716Sab196087 (verndx < VER_NDX_LORESERVE)) 1551*4716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER), 1552*4716Sab196087 state->file, state->secname, EC_WORD(symndx), 1553*4716Sab196087 EC_HALF(test_verndx), state->versym->max_verndx); 15543875Sab196087 } else { 15553492Sab196087 verndx = 0; 1556*4716Sab196087 gnuver = 0; 15573875Sab196087 } 15583492Sab196087 15593492Sab196087 /* 15603492Sab196087 * Error checking for TLS. 15613492Sab196087 */ 15623492Sab196087 type = ELF_ST_TYPE(sym->st_info); 15633492Sab196087 if (type == STT_TLS) { 15643492Sab196087 if (tshdr && 15653492Sab196087 (sym->st_shndx != SHN_UNDEF) && 15663492Sab196087 ((tshdr->sh_flags & SHF_TLS) == 0)) { 15673492Sab196087 (void) fprintf(stderr, 15683492Sab196087 MSG_INTL(MSG_ERR_BADSYM3), state->file, 15693492Sab196087 state->secname, demangle(symname, state->flags)); 15703492Sab196087 } 15713492Sab196087 } else if ((type != STT_SECTION) && sym->st_size && 15723492Sab196087 tshdr && (tshdr->sh_flags & SHF_TLS)) { 15733492Sab196087 (void) fprintf(stderr, 15743492Sab196087 MSG_INTL(MSG_ERR_BADSYM4), state->file, 15753492Sab196087 state->secname, demangle(symname, state->flags)); 15763492Sab196087 } 15773492Sab196087 15783492Sab196087 /* 15793492Sab196087 * If a symbol with non-zero size has a type that 15803492Sab196087 * specifies an address, then make sure the location 15813492Sab196087 * it references is actually contained within the 15823492Sab196087 * section. UNDEF symbols don't count in this case, 15833492Sab196087 * so we ignore them. 15843492Sab196087 * 15853492Sab196087 * The meaning of the st_value field in a symbol 15863492Sab196087 * depends on the type of object. For a relocatable 15873492Sab196087 * object, it is the offset within the section. 15883492Sab196087 * For sharable objects, it is the offset relative to 15893492Sab196087 * the base of the object, and for other types, it is 15903492Sab196087 * the virtual address. To get an offset within the 15913492Sab196087 * section for non-ET_REL files, we subtract the 15923492Sab196087 * base address of the section. 15933492Sab196087 */ 15943492Sab196087 if (addr_symtype[type] && (sym->st_size > 0) && 15953492Sab196087 (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) || 15963492Sab196087 (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) { 15973492Sab196087 Word v = sym->st_value; 15983492Sab196087 if (state->ehdr->e_type != ET_REL) 15993492Sab196087 v -= tshdr->sh_addr; 16003492Sab196087 if (((v + sym->st_size) > tshdr->sh_size)) { 16013492Sab196087 (void) fprintf(stderr, 16023492Sab196087 MSG_INTL(MSG_ERR_BADSYM6), state->file, 16033492Sab196087 state->secname, demangle(symname, state->flags), 16043492Sab196087 EC_WORD(shndx), EC_XWORD(tshdr->sh_size), 16053492Sab196087 EC_XWORD(sym->st_value), EC_XWORD(sym->st_size)); 16063492Sab196087 } 16073492Sab196087 } 16083492Sab196087 16093492Sab196087 (void) snprintf(index, MAXNDXSIZE, 16103492Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx)); 16113492Sab196087 Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, 1612*4716Sab196087 state->ehdr->e_machine, sym, verndx, gnuver, sec, symname); 16133492Sab196087 } 16143492Sab196087 16153492Sab196087 /* 16163492Sab196087 * Search for and process any symbol tables. 16173492Sab196087 */ 16183492Sab196087 void 16194168Sab196087 symbols(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 16204168Sab196087 const char *file, uint_t flags) 16213492Sab196087 { 16223492Sab196087 SYMTBL_STATE state; 16233492Sab196087 Cache *_cache; 16243492Sab196087 Word secndx; 16253492Sab196087 16263492Sab196087 for (secndx = 1; secndx < shnum; secndx++) { 16273492Sab196087 Word symcnt; 16283492Sab196087 Shdr *shdr; 16293492Sab196087 16303492Sab196087 _cache = &cache[secndx]; 16313492Sab196087 shdr = _cache->c_shdr; 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) && 16342766Sab196087 (shdr->sh_type != SHT_DYNSYM) && 16352766Sab196087 (shdr->sh_type != SHT_SUNW_LDYNSYM)) 16360Sstevel@tonic-gate continue; 16374168Sab196087 if (!match(0, _cache->c_name, secndx)) 16383466Srie continue; 16393466Srie 16403492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr, 16413875Sab196087 versym, file, flags)) 16420Sstevel@tonic-gate continue; 16430Sstevel@tonic-gate /* 16440Sstevel@tonic-gate * Loop through the symbol tables entries. 16450Sstevel@tonic-gate */ 16461618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 16473492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname); 16481618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 16490Sstevel@tonic-gate 16503492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++) 16513492Sab196087 output_symbol(&state, symcnt, symcnt, 16523492Sab196087 state.sym + symcnt); 16533492Sab196087 } 16543492Sab196087 } 16550Sstevel@tonic-gate 16563492Sab196087 /* 16573492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections. 16583492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair. 16593492Sab196087 */ 16603492Sab196087 static void 16614168Sab196087 sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 16624168Sab196087 const char *file, uint_t flags) 16633492Sab196087 { 16643492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state; 16653492Sab196087 Cache *sortcache, *symcache; 16663492Sab196087 Shdr *sortshdr, *symshdr; 16673492Sab196087 Word sortsecndx, symsecndx; 16683492Sab196087 Word ldynsym_cnt; 16693492Sab196087 Word *ndx; 16703492Sab196087 Word ndxn; 16713492Sab196087 int output_cnt = 0; 16720Sstevel@tonic-gate 16733492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) { 16740Sstevel@tonic-gate 16753492Sab196087 sortcache = &cache[sortsecndx]; 16763492Sab196087 sortshdr = sortcache->c_shdr; 16770Sstevel@tonic-gate 16783492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) && 16793492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort)) 16803492Sab196087 continue; 16814168Sab196087 if (!match(0, sortcache->c_name, sortsecndx)) 16823492Sab196087 continue; 16830Sstevel@tonic-gate 16843492Sab196087 /* 16853492Sab196087 * If the section references a SUNW_ldynsym, then we 16863492Sab196087 * expect to see the associated .dynsym immediately 16873492Sab196087 * following. If it references a .dynsym, there is no 16883492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't 16893492Sab196087 * know what to do with it. 16903492Sab196087 */ 16913492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) { 16923492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 16933492Sab196087 file, sortcache->c_name, 16943492Sab196087 EC_WORD(sortshdr->sh_link)); 16953492Sab196087 continue; 16963492Sab196087 } 16973492Sab196087 symcache = &cache[sortshdr->sh_link]; 16983492Sab196087 symshdr = symcache->c_shdr; 16993492Sab196087 symsecndx = sortshdr->sh_link; 17003492Sab196087 ldynsym_cnt = 0; 17013492Sab196087 switch (symshdr->sh_type) { 17023492Sab196087 case SHT_SUNW_LDYNSYM: 17033492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum, 17043875Sab196087 symsecndx, ehdr, versym, file, flags)) 17053492Sab196087 continue; 17063492Sab196087 ldynsym_cnt = ldynsym_state.symn; 17070Sstevel@tonic-gate /* 17083492Sab196087 * We know that the dynsym follows immediately 17093492Sab196087 * after the SUNW_ldynsym, and so, should be at 17103492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a 17113492Sab196087 * diagnostic tool, so we do the full paranoid 17123492Sab196087 * search instead. 17130Sstevel@tonic-gate */ 17143492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) { 17153492Sab196087 symcache = &cache[symsecndx]; 17163492Sab196087 symshdr = symcache->c_shdr; 17173492Sab196087 if (symshdr->sh_type == SHT_DYNSYM) 17183492Sab196087 break; 17193492Sab196087 } 17203492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */ 17210Sstevel@tonic-gate (void) fprintf(stderr, 17223492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM), 17233492Sab196087 file, sortcache->c_name); 17243492Sab196087 continue; 17250Sstevel@tonic-gate } 17263492Sab196087 /* Fallthrough to process associated dynsym */ 17273492Sab196087 /*FALLTHROUGH*/ 17283492Sab196087 case SHT_DYNSYM: 17293492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum, 17303875Sab196087 symsecndx, ehdr, versym, file, flags)) 17313492Sab196087 continue; 17323492Sab196087 break; 17333492Sab196087 default: 17343492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC), 17353492Sab196087 file, sortcache->c_name, conv_sec_type( 17363492Sab196087 ehdr->e_machine, symshdr->sh_type, 0)); 17373492Sab196087 continue; 17383492Sab196087 } 17390Sstevel@tonic-gate 17403492Sab196087 /* 17413492Sab196087 * Output header 17423492Sab196087 */ 17433492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17443492Sab196087 if (ldynsym_cnt > 0) { 17453492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2), 17463492Sab196087 sortcache->c_name, ldynsym_state.secname, 17473492Sab196087 dynsym_state.secname); 17480Sstevel@tonic-gate /* 17493492Sab196087 * The data for .SUNW_ldynsym and dynsym sections 17503492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming 17513492Sab196087 * first. Check, and issue a warning if it isn't so. 17520Sstevel@tonic-gate */ 17534665Sab196087 if (((ldynsym_state.sym + ldynsym_state.symn) 17544665Sab196087 != dynsym_state.sym) && 17554665Sab196087 ((flags & FLG_FAKESHDR) == 0)) 17563492Sab196087 (void) fprintf(stderr, 17573492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file, 17583492Sab196087 ldynsym_state.secname, 17593492Sab196087 dynsym_state.secname); 17603492Sab196087 } else { 17613492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1), 17623492Sab196087 sortcache->c_name, dynsym_state.secname); 17633492Sab196087 } 17643492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 17653492Sab196087 17663492Sab196087 /* If not first one, insert a line of whitespace */ 17673492Sab196087 if (output_cnt++ > 0) 17683492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17693118Sab196087 17703492Sab196087 /* 17713492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of 17723492Sab196087 * symbol indices. Iterate over the array entries, 17733492Sab196087 * dispaying the referenced symbols. 17743492Sab196087 */ 17753492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize; 17763492Sab196087 ndx = (Word *)sortcache->c_data->d_buf; 17773492Sab196087 for (; ndxn-- > 0; ndx++) { 17783492Sab196087 if (*ndx >= ldynsym_cnt) { 17793492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt; 17803492Sab196087 17813492Sab196087 output_symbol(&dynsym_state, sec_ndx, 17823492Sab196087 *ndx, dynsym_state.sym + sec_ndx); 17833492Sab196087 } else { 17843492Sab196087 output_symbol(&ldynsym_state, *ndx, 17853492Sab196087 *ndx, ldynsym_state.sym + *ndx); 17860Sstevel@tonic-gate } 17870Sstevel@tonic-gate } 17880Sstevel@tonic-gate } 17890Sstevel@tonic-gate } 17900Sstevel@tonic-gate 17910Sstevel@tonic-gate /* 17920Sstevel@tonic-gate * Search for and process any relocation sections. 17930Sstevel@tonic-gate */ 17940Sstevel@tonic-gate static void 17954168Sab196087 reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *file, 17961618Srie uint_t flags) 17970Sstevel@tonic-gate { 17981618Srie Word cnt; 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 18011618Srie Word type, symnum; 18021618Srie Xword relndx, relnum, relsize; 18031618Srie void *rels; 18041618Srie Sym *syms; 18051618Srie Cache *symsec, *strsec; 18060Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 18071618Srie Shdr *shdr = _cache->c_shdr; 18081618Srie char *relname = _cache->c_name; 18090Sstevel@tonic-gate 18100Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) && 18110Sstevel@tonic-gate (type != SHT_REL)) 18120Sstevel@tonic-gate continue; 18134168Sab196087 if (!match(0, relname, cnt)) 18140Sstevel@tonic-gate continue; 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate /* 18171618Srie * Decide entry size. 18180Sstevel@tonic-gate */ 18191618Srie if (((relsize = shdr->sh_entsize) == 0) || 18201618Srie (relsize > shdr->sh_size)) { 18210Sstevel@tonic-gate if (type == SHT_RELA) 18221618Srie relsize = sizeof (Rela); 18230Sstevel@tonic-gate else 18241618Srie relsize = sizeof (Rel); 18250Sstevel@tonic-gate } 18260Sstevel@tonic-gate 18270Sstevel@tonic-gate /* 18280Sstevel@tonic-gate * Determine the number of relocations available. 18290Sstevel@tonic-gate */ 18300Sstevel@tonic-gate if (shdr->sh_size == 0) { 18310Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 18321618Srie file, relname); 18330Sstevel@tonic-gate continue; 18340Sstevel@tonic-gate } 18353466Srie if (_cache->c_data == NULL) 18363466Srie continue; 18373466Srie 18381618Srie rels = _cache->c_data->d_buf; 18391618Srie relnum = shdr->sh_size / relsize; 18400Sstevel@tonic-gate 18410Sstevel@tonic-gate /* 18421618Srie * Get the data buffer for the associated symbol table and 18431618Srie * string table. 18440Sstevel@tonic-gate */ 18451618Srie if (stringtbl(cache, 1, cnt, shnum, file, 18461618Srie &symnum, &symsec, &strsec) == 0) 18470Sstevel@tonic-gate continue; 18481618Srie 18491618Srie syms = symsec->c_data->d_buf; 18500Sstevel@tonic-gate 18510Sstevel@tonic-gate /* 18520Sstevel@tonic-gate * Loop through the relocation entries. 18530Sstevel@tonic-gate */ 18541618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 18551618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 18561618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type); 18570Sstevel@tonic-gate 18581618Srie for (relndx = 0; relndx < relnum; relndx++, 18591618Srie rels = (void *)((char *)rels + relsize)) { 18600Sstevel@tonic-gate char section[BUFSIZ]; 18611618Srie const char *symname; 18621618Srie Word symndx, reltype; 18631618Srie Rela *rela; 18641618Srie Rel *rel; 18650Sstevel@tonic-gate 18660Sstevel@tonic-gate /* 18671618Srie * Unravel the relocation and determine the symbol with 18681618Srie * which this relocation is associated. 18690Sstevel@tonic-gate */ 18700Sstevel@tonic-gate if (type == SHT_RELA) { 18711618Srie rela = (Rela *)rels; 18721618Srie symndx = ELF_R_SYM(rela->r_info); 18731618Srie reltype = ELF_R_TYPE(rela->r_info); 18740Sstevel@tonic-gate } else { 18751618Srie rel = (Rel *)rels; 18761618Srie symndx = ELF_R_SYM(rel->r_info); 18771618Srie reltype = ELF_R_TYPE(rel->r_info); 18780Sstevel@tonic-gate } 18791618Srie 18801618Srie symname = relsymname(cache, _cache, strsec, symndx, 18811618Srie symnum, relndx, syms, section, BUFSIZ, file, 18821618Srie flags); 18831618Srie 18841618Srie /* 18851618Srie * A zero symbol index is only valid for a few 18861618Srie * relocations. 18871618Srie */ 18881618Srie if (symndx == 0) { 18891618Srie Half mach = ehdr->e_machine; 18901618Srie int badrel = 0; 18910Sstevel@tonic-gate 18921618Srie if ((mach == EM_SPARC) || 18931618Srie (mach == EM_SPARC32PLUS) || 18941618Srie (mach == EM_SPARCV9)) { 18951618Srie if ((reltype != R_SPARC_NONE) && 18961618Srie (reltype != R_SPARC_REGISTER) && 18971618Srie (reltype != R_SPARC_RELATIVE)) 18981618Srie badrel++; 18991618Srie } else if (mach == EM_386) { 19001618Srie if ((reltype != R_386_NONE) && 19011618Srie (reltype != R_386_RELATIVE)) 19021618Srie badrel++; 19031618Srie } else if (mach == EM_AMD64) { 19041618Srie if ((reltype != R_AMD64_NONE) && 19051618Srie (reltype != R_AMD64_RELATIVE)) 19061618Srie badrel++; 19071618Srie } 19081618Srie 19091618Srie if (badrel) { 19101618Srie (void) fprintf(stderr, 19111618Srie MSG_INTL(MSG_ERR_BADREL1), file, 19121976Sab196087 conv_reloc_type(mach, reltype, 0)); 19130Sstevel@tonic-gate } 19140Sstevel@tonic-gate } 19150Sstevel@tonic-gate 19161618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP, 19171618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type, 19181618Srie rels, relname, symname, 0); 19190Sstevel@tonic-gate } 19200Sstevel@tonic-gate } 19210Sstevel@tonic-gate } 19220Sstevel@tonic-gate 19230Sstevel@tonic-gate /* 19240Sstevel@tonic-gate * Search for and process a .dynamic section. 19250Sstevel@tonic-gate */ 19260Sstevel@tonic-gate static void 19271618Srie dynamic(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 19280Sstevel@tonic-gate { 19291618Srie Word cnt; 19300Sstevel@tonic-gate 19310Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 19321618Srie Dyn *dyn; 19331618Srie ulong_t numdyn; 19343850Sab196087 int ndx, end_ndx; 19351618Srie Cache *_cache = &cache[cnt], *strsec; 19361618Srie Shdr *shdr = _cache->c_shdr; 19370Sstevel@tonic-gate 19380Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC) 19390Sstevel@tonic-gate continue; 19400Sstevel@tonic-gate 19410Sstevel@tonic-gate /* 19421618Srie * Verify the associated string table section. 19430Sstevel@tonic-gate */ 19441618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0) 19450Sstevel@tonic-gate continue; 19461618Srie 19473466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 19483466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 19493466Srie file, _cache->c_name); 19503466Srie continue; 19513466Srie } 19523466Srie if (_cache->c_data == NULL) 19533466Srie continue; 19543466Srie 19550Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize; 19561618Srie dyn = (Dyn *)_cache->c_data->d_buf; 19570Sstevel@tonic-gate 19581618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 19591618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 19600Sstevel@tonic-gate 19611618Srie Elf_dyn_title(0); 19620Sstevel@tonic-gate 19631618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 19641618Srie const char *name; 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate /* 19670Sstevel@tonic-gate * Print the information numerically, and if possible 19680Sstevel@tonic-gate * as a string. 19690Sstevel@tonic-gate */ 19703850Sab196087 switch (dyn->d_tag) { 19713850Sab196087 case DT_NULL: 19723850Sab196087 /* 19733850Sab196087 * Special case: DT_NULLs can come in groups 19743850Sab196087 * that we prefer to reduce to a single line. 19753850Sab196087 */ 19763850Sab196087 end_ndx = ndx; 19773850Sab196087 while ((end_ndx < (numdyn - 1)) && 19784433Sab196087 ((dyn + 1)->d_tag == DT_NULL)) { 19793850Sab196087 dyn++; 19803850Sab196087 end_ndx++; 19813850Sab196087 } 19823850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 19833850Sab196087 ndx = end_ndx; 19843850Sab196087 continue; 19853850Sab196087 19863850Sab196087 /* 19873850Sab196087 * Print the information numerically, and if possible 19883850Sab196087 * as a string. 19893850Sab196087 */ 19903850Sab196087 case DT_NEEDED: 19913850Sab196087 case DT_SONAME: 19923850Sab196087 case DT_FILTER: 19933850Sab196087 case DT_AUXILIARY: 19943850Sab196087 case DT_CONFIG: 19953850Sab196087 case DT_RPATH: 19963850Sab196087 case DT_RUNPATH: 19973850Sab196087 case DT_USED: 19983850Sab196087 case DT_DEPAUDIT: 19993850Sab196087 case DT_AUDIT: 20003850Sab196087 case DT_SUNW_AUXILIARY: 20013850Sab196087 case DT_SUNW_FILTER: 20021618Srie name = string(_cache, ndx, strsec, 20031618Srie file, dyn->d_un.d_ptr); 20043850Sab196087 break; 20053850Sab196087 20063850Sab196087 case DT_FLAGS: 20072352Sab196087 name = conv_dyn_flag(dyn->d_un.d_val, 0); 20083850Sab196087 break; 20093850Sab196087 case DT_FLAGS_1: 20101618Srie name = conv_dyn_flag1(dyn->d_un.d_val); 20113850Sab196087 break; 20123850Sab196087 case DT_POSFLAG_1: 20132352Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0); 20143850Sab196087 break; 20153850Sab196087 case DT_FEATURE_1: 20162352Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0); 20173850Sab196087 break; 20183850Sab196087 case DT_DEPRECATED_SPARC_REGISTER: 20191618Srie name = MSG_INTL(MSG_STR_DEPRECATED); 20203850Sab196087 break; 20213850Sab196087 default: 20221618Srie name = MSG_ORIG(MSG_STR_EMPTY); 20233850Sab196087 break; 20243850Sab196087 } 20250Sstevel@tonic-gate 20261618Srie Elf_dyn_entry(0, dyn, ndx, name, ehdr->e_machine); 20270Sstevel@tonic-gate } 20280Sstevel@tonic-gate } 20290Sstevel@tonic-gate } 20300Sstevel@tonic-gate 20310Sstevel@tonic-gate /* 20320Sstevel@tonic-gate * Search for and process a MOVE section. 20330Sstevel@tonic-gate */ 20340Sstevel@tonic-gate static void 20354168Sab196087 move(Cache *cache, Word shnum, const char *file, uint_t flags) 20360Sstevel@tonic-gate { 20371618Srie Word cnt; 20381618Srie const char *fmt = 0; 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 20411618Srie Word movenum, symnum, ndx; 20421618Srie Sym *syms; 20431618Srie Cache *_cache = &cache[cnt]; 20441618Srie Shdr *shdr = _cache->c_shdr; 20451618Srie Cache *symsec, *strsec; 20461618Srie Move *move; 20470Sstevel@tonic-gate 20480Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move) 20490Sstevel@tonic-gate continue; 20504168Sab196087 if (!match(0, _cache->c_name, cnt)) 20510Sstevel@tonic-gate continue; 20520Sstevel@tonic-gate 20530Sstevel@tonic-gate /* 20540Sstevel@tonic-gate * Determine the move data and number. 20550Sstevel@tonic-gate */ 20560Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 20570Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 20580Sstevel@tonic-gate file, _cache->c_name); 20590Sstevel@tonic-gate continue; 20600Sstevel@tonic-gate } 20613466Srie if (_cache->c_data == NULL) 20623466Srie continue; 20633466Srie 20641618Srie move = (Move *)_cache->c_data->d_buf; 20651618Srie movenum = shdr->sh_size / shdr->sh_entsize; 20660Sstevel@tonic-gate 20670Sstevel@tonic-gate /* 20681618Srie * Get the data buffer for the associated symbol table and 20691618Srie * string table. 20700Sstevel@tonic-gate */ 20711618Srie if (stringtbl(cache, 1, cnt, shnum, file, 20721618Srie &symnum, &symsec, &strsec) == 0) 20731618Srie return; 20741618Srie 20751618Srie syms = (Sym *)symsec->c_data->d_buf; 20760Sstevel@tonic-gate 20771618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 20781618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); 20791618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); 20800Sstevel@tonic-gate 20811618Srie if (fmt == 0) 20821618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY); 20830Sstevel@tonic-gate 20841618Srie for (ndx = 0; ndx < movenum; move++, ndx++) { 20851618Srie const char *symname; 20861618Srie char index[MAXNDXSIZE], section[BUFSIZ]; 20871618Srie Word symndx, shndx; 20881618Srie Sym *sym; 20890Sstevel@tonic-gate 20900Sstevel@tonic-gate /* 20910Sstevel@tonic-gate * Check for null entries 20920Sstevel@tonic-gate */ 20931618Srie if ((move->m_info == 0) && (move->m_value == 0) && 20941618Srie (move->m_poffset == 0) && (move->m_repeat == 0) && 20951618Srie (move->m_stride == 0)) { 20961618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY), 20971618Srie EC_XWORD(move->m_poffset), 0, 0, 0, 20981618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY)); 20990Sstevel@tonic-gate continue; 21000Sstevel@tonic-gate } 21011618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) || 21021618Srie (symndx >= symnum)) { 21030Sstevel@tonic-gate (void) fprintf(stderr, 21040Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file, 21051618Srie _cache->c_name, EC_XWORD(move->m_info)); 21061618Srie 21071618Srie (void) snprintf(index, MAXNDXSIZE, 21081618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 21091618Srie dbg_print(0, fmt, index, 21101618Srie EC_XWORD(move->m_poffset), 21111618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 21121618Srie move->m_stride, move->m_value, 21130Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN)); 21140Sstevel@tonic-gate continue; 21150Sstevel@tonic-gate } 21160Sstevel@tonic-gate 21171618Srie symname = relsymname(cache, _cache, strsec, 21181618Srie symndx, symnum, ndx, syms, section, BUFSIZ, file, 21191618Srie flags); 21201618Srie sym = (Sym *)(syms + symndx); 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate /* 21230Sstevel@tonic-gate * Additional sanity check. 21240Sstevel@tonic-gate */ 21251618Srie shndx = sym->st_shndx; 21260Sstevel@tonic-gate if (!((shndx == SHN_COMMON) || 21270Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) && 21281618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) { 21290Sstevel@tonic-gate (void) fprintf(stderr, 21301618Srie MSG_INTL(MSG_ERR_BADSYM2), file, 21311618Srie _cache->c_name, demangle(symname, flags)); 21320Sstevel@tonic-gate } 21330Sstevel@tonic-gate 21341618Srie (void) snprintf(index, MAXNDXSIZE, 21351618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 21361618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset), 21371618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 21381618Srie move->m_stride, move->m_value, 21391618Srie demangle(symname, flags)); 21400Sstevel@tonic-gate } 21410Sstevel@tonic-gate } 21420Sstevel@tonic-gate } 21430Sstevel@tonic-gate 21440Sstevel@tonic-gate /* 21450Sstevel@tonic-gate * Traverse a note section analyzing each note information block. 21460Sstevel@tonic-gate * The data buffers size is used to validate references before they are made, 21470Sstevel@tonic-gate * and is decremented as each element is processed. 21480Sstevel@tonic-gate */ 21490Sstevel@tonic-gate void 21501618Srie note_entry(Cache *cache, Word *data, size_t size, const char *file) 21510Sstevel@tonic-gate { 21521618Srie size_t bsize = size; 21531618Srie 21540Sstevel@tonic-gate /* 21550Sstevel@tonic-gate * Print out a single `note' information block. 21560Sstevel@tonic-gate */ 21570Sstevel@tonic-gate while (size > 0) { 21581618Srie size_t namesz, descsz, type, pad, noteoff; 21590Sstevel@tonic-gate 21600Sstevel@tonic-gate noteoff = bsize - size; 21610Sstevel@tonic-gate /* 21620Sstevel@tonic-gate * Make sure we can at least reference the 3 initial entries 21630Sstevel@tonic-gate * (4-byte words) of the note information block. 21640Sstevel@tonic-gate */ 21651618Srie if (size >= (sizeof (Word) * 3)) 21661618Srie size -= (sizeof (Word) * 3); 21670Sstevel@tonic-gate else { 21681618Srie (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ), 21691618Srie file, cache->c_name, EC_WORD(noteoff)); 21700Sstevel@tonic-gate return; 21710Sstevel@tonic-gate } 21720Sstevel@tonic-gate 21730Sstevel@tonic-gate /* 21740Sstevel@tonic-gate * Make sure any specified name string can be referenced. 21750Sstevel@tonic-gate */ 21760Sstevel@tonic-gate if ((namesz = *data++) != 0) { 21770Sstevel@tonic-gate if (size >= namesz) 21780Sstevel@tonic-gate size -= namesz; 21790Sstevel@tonic-gate else { 21800Sstevel@tonic-gate (void) fprintf(stderr, 21811618Srie MSG_INTL(MSG_NOTE_BADNMSZ), file, 21821618Srie cache->c_name, EC_WORD(noteoff), 21831618Srie EC_WORD(namesz)); 21840Sstevel@tonic-gate return; 21850Sstevel@tonic-gate } 21860Sstevel@tonic-gate } 21871618Srie 21880Sstevel@tonic-gate /* 21890Sstevel@tonic-gate * Make sure any specified descriptor can be referenced. 21900Sstevel@tonic-gate */ 21910Sstevel@tonic-gate if ((descsz = *data++) != 0) { 21920Sstevel@tonic-gate /* 21930Sstevel@tonic-gate * If namesz isn't a 4-byte multiple, account for any 21940Sstevel@tonic-gate * padding that must exist before the descriptor. 21950Sstevel@tonic-gate */ 21961618Srie if ((pad = (namesz & (sizeof (Word) - 1))) != 0) { 21971618Srie pad = sizeof (Word) - pad; 21980Sstevel@tonic-gate size -= pad; 21990Sstevel@tonic-gate } 22000Sstevel@tonic-gate if (size >= descsz) 22010Sstevel@tonic-gate size -= descsz; 22020Sstevel@tonic-gate else { 22030Sstevel@tonic-gate (void) fprintf(stderr, 22041618Srie MSG_INTL(MSG_NOTE_BADDESZ), file, 22051618Srie cache->c_name, EC_WORD(noteoff), 22061618Srie EC_WORD(namesz)); 22070Sstevel@tonic-gate return; 22080Sstevel@tonic-gate } 22090Sstevel@tonic-gate } 22100Sstevel@tonic-gate 22110Sstevel@tonic-gate type = *data++; 22120Sstevel@tonic-gate 22131618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 22141618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type)); 22150Sstevel@tonic-gate 22161618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz)); 22170Sstevel@tonic-gate if (namesz) { 22180Sstevel@tonic-gate char *name = (char *)data; 22190Sstevel@tonic-gate 22200Sstevel@tonic-gate /* 22210Sstevel@tonic-gate * Since the name string may have 'null' bytes 22220Sstevel@tonic-gate * in it (ia32 .string) - we just write the 22230Sstevel@tonic-gate * whole stream in a single fwrite. 22240Sstevel@tonic-gate */ 22250Sstevel@tonic-gate (void) fwrite(name, namesz, 1, stdout); 22260Sstevel@tonic-gate name = name + ((namesz + (sizeof (Word) - 1)) & 22270Sstevel@tonic-gate ~(sizeof (Word) - 1)); 22280Sstevel@tonic-gate /* LINTED */ 22290Sstevel@tonic-gate data = (Word *)name; 22301618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 22310Sstevel@tonic-gate } 22320Sstevel@tonic-gate 22330Sstevel@tonic-gate /* 22340Sstevel@tonic-gate * If multiple information blocks exist within a .note section 22350Sstevel@tonic-gate * account for any padding that must exist before the next 22360Sstevel@tonic-gate * information block. 22370Sstevel@tonic-gate */ 22381618Srie if ((pad = (descsz & (sizeof (Word) - 1))) != 0) { 22391618Srie pad = sizeof (Word) - pad; 22400Sstevel@tonic-gate if (size > pad) 22410Sstevel@tonic-gate size -= pad; 22420Sstevel@tonic-gate } 22430Sstevel@tonic-gate 22441618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz)); 22450Sstevel@tonic-gate if (descsz) { 22460Sstevel@tonic-gate int ndx, byte, word; 22471618Srie char string[58], *str = string; 22480Sstevel@tonic-gate uchar_t *desc = (uchar_t *)data; 22490Sstevel@tonic-gate 22500Sstevel@tonic-gate /* 22510Sstevel@tonic-gate * Dump descriptor bytes. 22520Sstevel@tonic-gate */ 22530Sstevel@tonic-gate for (ndx = byte = word = 0; descsz; descsz--, desc++) { 22540Sstevel@tonic-gate int tok = *desc; 22550Sstevel@tonic-gate 22560Sstevel@tonic-gate (void) snprintf(str, 58, MSG_ORIG(MSG_NOTE_TOK), 22570Sstevel@tonic-gate tok); 22580Sstevel@tonic-gate str += 3; 22590Sstevel@tonic-gate 22600Sstevel@tonic-gate if (++byte == 4) { 22610Sstevel@tonic-gate *str++ = ' ', *str++ = ' '; 22620Sstevel@tonic-gate word++; 22630Sstevel@tonic-gate byte = 0; 22640Sstevel@tonic-gate } 22650Sstevel@tonic-gate if (word == 4) { 22660Sstevel@tonic-gate *str = '\0'; 22671618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESC), 22680Sstevel@tonic-gate ndx, string); 22690Sstevel@tonic-gate word = 0; 22700Sstevel@tonic-gate ndx += 16; 22710Sstevel@tonic-gate str = string; 22720Sstevel@tonic-gate } 22730Sstevel@tonic-gate } 22740Sstevel@tonic-gate if (byte || word) { 22750Sstevel@tonic-gate *str = '\0'; 22761618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESC), 22771618Srie ndx, string); 22780Sstevel@tonic-gate } 22790Sstevel@tonic-gate 22800Sstevel@tonic-gate desc += pad; 22810Sstevel@tonic-gate /* LINTED */ 22820Sstevel@tonic-gate data = (Word *)desc; 22830Sstevel@tonic-gate } 22840Sstevel@tonic-gate } 22850Sstevel@tonic-gate } 22860Sstevel@tonic-gate 22870Sstevel@tonic-gate /* 22880Sstevel@tonic-gate * Search for and process a .note section. 22890Sstevel@tonic-gate */ 22900Sstevel@tonic-gate static void 22914168Sab196087 note(Cache *cache, Word shnum, const char *file) 22920Sstevel@tonic-gate { 22931618Srie Word cnt; 22940Sstevel@tonic-gate 22950Sstevel@tonic-gate /* 22960Sstevel@tonic-gate * Otherwise look for any .note sections. 22970Sstevel@tonic-gate */ 22980Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 22991618Srie Cache *_cache = &cache[cnt]; 23001618Srie Shdr *shdr = _cache->c_shdr; 23010Sstevel@tonic-gate 23020Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE) 23030Sstevel@tonic-gate continue; 23044168Sab196087 if (!match(0, _cache->c_name, cnt)) 23050Sstevel@tonic-gate continue; 23060Sstevel@tonic-gate 23070Sstevel@tonic-gate /* 23080Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're 23090Sstevel@tonic-gate * properly aligned before proceeding. 23100Sstevel@tonic-gate */ 23110Sstevel@tonic-gate if (shdr->sh_offset & (sizeof (Word) - 1)) { 23120Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 23130Sstevel@tonic-gate file, _cache->c_name); 23140Sstevel@tonic-gate continue; 23150Sstevel@tonic-gate } 23163466Srie if (_cache->c_data == NULL) 23173466Srie continue; 23180Sstevel@tonic-gate 23191618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 23201618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 23210Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf, 23220Sstevel@tonic-gate /* LINTED */ 23230Sstevel@tonic-gate (Word)_cache->c_data->d_size, file); 23240Sstevel@tonic-gate } 23250Sstevel@tonic-gate } 23260Sstevel@tonic-gate 23271618Srie /* 23281618Srie * Determine an individual hash entry. This may be the initial hash entry, 23291618Srie * or an associated chain entry. 23301618Srie */ 23311618Srie static void 23321618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx, 23331618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts, 23341618Srie uint_t flags, int chain) 23351618Srie { 23361618Srie Sym *sym; 23371618Srie const char *symname, *str; 23381618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE]; 23391618Srie ulong_t nbkt, nhash; 23401618Srie 23411618Srie if (symndx > symn) { 23421618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file, 23431618Srie EC_WORD(symndx), EC_WORD(hashndx)); 23441618Srie symname = MSG_INTL(MSG_STR_UNKNOWN); 23451618Srie } else { 23461618Srie sym = (Sym *)(syms + symndx); 23471618Srie symname = string(refsec, symndx, strsec, file, sym->st_name); 23481618Srie } 23491618Srie 23501618Srie if (chain == 0) { 23511618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 23521618Srie hashndx); 23531618Srie str = (const char *)_bucket; 23541618Srie } else 23551618Srie str = MSG_ORIG(MSG_STR_EMPTY); 23561618Srie 23571618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2), 23581618Srie EC_WORD(symndx)); 23591618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx, 23601618Srie demangle(symname, flags)); 23611618Srie 23621618Srie /* 23631618Srie * Determine if this string is in the correct bucket. 23641618Srie */ 23651618Srie nhash = elf_hash(symname); 23661618Srie nbkt = nhash % bkts; 23671618Srie 23681618Srie if (nbkt != hashndx) { 23691618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file, 23701618Srie hsecname, symname, EC_WORD(hashndx), nbkt); 23711618Srie } 23721618Srie } 23730Sstevel@tonic-gate 23740Sstevel@tonic-gate #define MAXCOUNT 500 23750Sstevel@tonic-gate 23760Sstevel@tonic-gate static void 23774168Sab196087 hash(Cache *cache, Word shnum, const char *file, uint_t flags) 23780Sstevel@tonic-gate { 23790Sstevel@tonic-gate static int count[MAXCOUNT]; 23801618Srie Word cnt; 23810Sstevel@tonic-gate ulong_t ndx, bkts; 23820Sstevel@tonic-gate char number[MAXNDXSIZE]; 23830Sstevel@tonic-gate 23840Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 23850Sstevel@tonic-gate uint_t *hash, *chain; 23860Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 23871618Srie Shdr *sshdr, *hshdr = _cache->c_shdr; 23881618Srie char *ssecname, *hsecname = _cache->c_name; 23891618Srie Sym *syms; 23901618Srie Word symn; 23910Sstevel@tonic-gate 23921618Srie if (hshdr->sh_type != SHT_HASH) 23930Sstevel@tonic-gate continue; 23940Sstevel@tonic-gate 23950Sstevel@tonic-gate /* 23960Sstevel@tonic-gate * Determine the hash table data and size. 23970Sstevel@tonic-gate */ 23981618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) { 23990Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 24001618Srie file, hsecname); 24010Sstevel@tonic-gate continue; 24020Sstevel@tonic-gate } 24033466Srie if (_cache->c_data == NULL) 24043466Srie continue; 24053466Srie 24060Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf; 24070Sstevel@tonic-gate bkts = *hash; 24080Sstevel@tonic-gate chain = hash + 2 + bkts; 24090Sstevel@tonic-gate hash += 2; 24100Sstevel@tonic-gate 24110Sstevel@tonic-gate /* 24120Sstevel@tonic-gate * Get the data buffer for the associated symbol table. 24130Sstevel@tonic-gate */ 24141618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) { 24150Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 24161618Srie file, hsecname, EC_WORD(hshdr->sh_link)); 24170Sstevel@tonic-gate continue; 24180Sstevel@tonic-gate } 24191618Srie 24201618Srie _cache = &cache[hshdr->sh_link]; 24211618Srie ssecname = _cache->c_name; 24221618Srie 24233466Srie if (_cache->c_data == NULL) 24243466Srie continue; 24253466Srie 24263466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) { 24270Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 24281618Srie file, ssecname); 24290Sstevel@tonic-gate continue; 24300Sstevel@tonic-gate } 24310Sstevel@tonic-gate 24321618Srie sshdr = _cache->c_shdr; 24331618Srie /* LINTED */ 24341618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize); 24351618Srie 24360Sstevel@tonic-gate /* 24370Sstevel@tonic-gate * Get the associated string table section. 24380Sstevel@tonic-gate */ 24391618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) { 24400Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 24411618Srie file, ssecname, EC_WORD(sshdr->sh_link)); 24420Sstevel@tonic-gate continue; 24430Sstevel@tonic-gate } 24440Sstevel@tonic-gate 24451618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 24461618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname); 24471618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO)); 24480Sstevel@tonic-gate 24490Sstevel@tonic-gate /* 24500Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate 24510Sstevel@tonic-gate * symbols. 24520Sstevel@tonic-gate */ 24530Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) { 24541618Srie Word _ndx, _cnt; 24550Sstevel@tonic-gate 24560Sstevel@tonic-gate if (*hash == 0) { 24570Sstevel@tonic-gate count[0]++; 24580Sstevel@tonic-gate continue; 24590Sstevel@tonic-gate } 24600Sstevel@tonic-gate 24611618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname, 24621618Srie ndx, *hash, symn, syms, file, bkts, flags, 0); 24630Sstevel@tonic-gate 24640Sstevel@tonic-gate /* 24650Sstevel@tonic-gate * Determine if any other symbols are chained to this 24660Sstevel@tonic-gate * bucket. 24670Sstevel@tonic-gate */ 24680Sstevel@tonic-gate _ndx = chain[*hash]; 24690Sstevel@tonic-gate _cnt = 1; 24700Sstevel@tonic-gate while (_ndx) { 24711618Srie hash_entry(_cache, &cache[sshdr->sh_link], 24721618Srie hsecname, ndx, _ndx, symn, syms, file, 24731618Srie bkts, flags, 1); 24740Sstevel@tonic-gate _ndx = chain[_ndx]; 24750Sstevel@tonic-gate _cnt++; 24760Sstevel@tonic-gate } 24770Sstevel@tonic-gate 24780Sstevel@tonic-gate if (_cnt >= MAXCOUNT) { 24790Sstevel@tonic-gate (void) fprintf(stderr, 24801324Srie MSG_INTL(MSG_HASH_OVERFLW), file, 24811618Srie _cache->c_name, EC_WORD(ndx), 24821618Srie EC_WORD(_cnt)); 24830Sstevel@tonic-gate } else 24840Sstevel@tonic-gate count[_cnt]++; 24850Sstevel@tonic-gate } 24860Sstevel@tonic-gate break; 24870Sstevel@tonic-gate } 24880Sstevel@tonic-gate 24890Sstevel@tonic-gate /* 24900Sstevel@tonic-gate * Print out the count information. 24910Sstevel@tonic-gate */ 24920Sstevel@tonic-gate bkts = cnt = 0; 24931618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 24941618Srie 24950Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) { 24961618Srie Word _cnt; 24970Sstevel@tonic-gate 24980Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0) 24990Sstevel@tonic-gate continue; 25000Sstevel@tonic-gate 25011618Srie (void) snprintf(number, MAXNDXSIZE, 25021618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt); 25031618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number, 25041618Srie EC_WORD(ndx)); 25050Sstevel@tonic-gate bkts += _cnt; 25061618Srie cnt += (Word)(ndx * _cnt); 25070Sstevel@tonic-gate } 25080Sstevel@tonic-gate if (cnt) { 25090Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 25101618Srie bkts); 25111618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number, 25121618Srie EC_WORD(cnt)); 25130Sstevel@tonic-gate } 25140Sstevel@tonic-gate } 25150Sstevel@tonic-gate 25160Sstevel@tonic-gate static void 25174168Sab196087 group(Cache *cache, Word shnum, const char *file, uint_t flags) 25180Sstevel@tonic-gate { 25191618Srie Word scnt; 25200Sstevel@tonic-gate 25211618Srie for (scnt = 1; scnt < shnum; scnt++) { 25221618Srie Cache *_cache = &cache[scnt]; 25231618Srie Shdr *shdr = _cache->c_shdr; 25241618Srie Word *grpdata, gcnt, grpcnt, symnum, unknown; 25251618Srie Cache *symsec, *strsec; 25261618Srie Sym *syms, *sym; 25271618Srie char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 25280Sstevel@tonic-gate 25290Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP) 25300Sstevel@tonic-gate continue; 25314168Sab196087 if (!match(0, _cache->c_name, scnt)) 25320Sstevel@tonic-gate continue; 25333466Srie if ((_cache->c_data == NULL) || 25343466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL)) 25350Sstevel@tonic-gate continue; 25361618Srie grpcnt = shdr->sh_size / sizeof (Word); 25371618Srie 25381618Srie /* 25391618Srie * Get the data buffer for the associated symbol table and 25401618Srie * string table. 25411618Srie */ 25421618Srie if (stringtbl(cache, 1, scnt, shnum, file, 25431618Srie &symnum, &symsec, &strsec) == 0) 25441618Srie return; 25451618Srie 25461618Srie syms = symsec->c_data->d_buf; 25471618Srie 25481618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 25491618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name); 25501618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE)); 25511618Srie 25521618Srie /* 25531618Srie * The first element of the group defines the group. The 25541618Srie * associated symbol is defined by the sh_link field. 25551618Srie */ 25561618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) { 25571618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 25581618Srie file, _cache->c_name, EC_WORD(shdr->sh_info)); 25591618Srie return; 25600Sstevel@tonic-gate } 25610Sstevel@tonic-gate 25621618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT)); 25631618Srie if (grpdata[0] & GRP_COMDAT) { 25641618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT)); 25650Sstevel@tonic-gate } 25661618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) { 25671618Srie size_t len = strlen(flgstrbuf); 25681618Srie 25691618Srie (void) snprintf(&flgstrbuf[len], 25701618Srie (MSG_GRP_COMDAT_SIZE + 10 - len), 25711618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown); 25720Sstevel@tonic-gate } 25731618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT)); 25741618Srie sym = (Sym *)(syms + shdr->sh_info); 25750Sstevel@tonic-gate 25761618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf, 25771618Srie demangle(string(_cache, 0, strsec, file, sym->st_name), 25781618Srie flags)); 25791618Srie 25801618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) { 25810Sstevel@tonic-gate char index[MAXNDXSIZE]; 25821618Srie const char *name; 25830Sstevel@tonic-gate 25840Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, 25851618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt)); 25861618Srie 25871618Srie if (grpdata[gcnt] >= shnum) 25881618Srie name = MSG_INTL(MSG_GRP_INVALSCN); 25891618Srie else 25901618Srie name = cache[grpdata[gcnt]].c_name; 25911618Srie 25921618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name, 25934433Sab196087 EC_XWORD(grpdata[gcnt])); 25940Sstevel@tonic-gate } 25950Sstevel@tonic-gate } 25960Sstevel@tonic-gate } 25970Sstevel@tonic-gate 25980Sstevel@tonic-gate static void 25991618Srie got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file, uint_t flags) 26000Sstevel@tonic-gate { 26010Sstevel@tonic-gate Cache *gotcache = 0, *symtab = 0, *_cache; 26021618Srie Addr gotbgn, gotend; 26031618Srie Shdr *gotshdr; 26041618Srie Word cnt, gotents, gotndx; 26050Sstevel@tonic-gate size_t gentsize; 26060Sstevel@tonic-gate Got_info *gottable; 26070Sstevel@tonic-gate char *gotdata; 26081618Srie Sym *gotsym; 26091618Srie Xword gotsymaddr; 26100Sstevel@tonic-gate 26110Sstevel@tonic-gate /* 26121324Srie * First, find the got. 26130Sstevel@tonic-gate */ 26140Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 26150Sstevel@tonic-gate _cache = &cache[cnt]; 26161324Srie if (strncmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT), 26171324Srie MSG_ELF_GOT_SIZE) == 0) { 26180Sstevel@tonic-gate gotcache = _cache; 26190Sstevel@tonic-gate break; 26200Sstevel@tonic-gate } 26210Sstevel@tonic-gate } 26221618Srie if (gotcache == 0) 26230Sstevel@tonic-gate return; 26241324Srie 26251324Srie /* 26261324Srie * A got section within a relocatable object is suspicious. 26271324Srie */ 26281324Srie if (ehdr->e_type == ET_REL) { 26291324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file, 26301324Srie _cache->c_name); 26311324Srie } 26321324Srie 26331618Srie gotshdr = gotcache->c_shdr; 26340Sstevel@tonic-gate if (gotshdr->sh_size == 0) { 26350Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 26360Sstevel@tonic-gate file, gotcache->c_name); 26370Sstevel@tonic-gate return; 26380Sstevel@tonic-gate } 26391618Srie 26401618Srie gotbgn = gotshdr->sh_addr; 26410Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size; 26420Sstevel@tonic-gate 26430Sstevel@tonic-gate /* 26441618Srie * Some architectures don't properly set the sh_entsize for the GOT 26451618Srie * table. If it's not set, default to a size of a pointer. 26460Sstevel@tonic-gate */ 26471618Srie if ((gentsize = gotshdr->sh_entsize) == 0) 26481618Srie gentsize = sizeof (Xword); 26491618Srie 26503466Srie if (gotcache->c_data == NULL) 26513466Srie return; 26523466Srie 26530Sstevel@tonic-gate /* LINTED */ 26541618Srie gotents = (Word)(gotshdr->sh_size / gentsize); 26550Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf; 26560Sstevel@tonic-gate 26570Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 26580Sstevel@tonic-gate int err = errno; 26591618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file, 26601618Srie strerror(err)); 26610Sstevel@tonic-gate return; 26620Sstevel@tonic-gate } 26630Sstevel@tonic-gate 26640Sstevel@tonic-gate /* 26650Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations 26660Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a 26670Sstevel@tonic-gate * .rel[a].got section we check them all. 26680Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab 26690Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 26700Sstevel@tonic-gate */ 26710Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 26721618Srie Word type, symnum; 26731618Srie Xword relndx, relnum, relsize; 26741618Srie void *rels; 26751618Srie Sym *syms; 26761618Srie Cache *symsec, *strsec; 26771618Srie Cache *_cache = &cache[cnt]; 26781618Srie Shdr *shdr; 26790Sstevel@tonic-gate 26801618Srie shdr = _cache->c_shdr; 26811618Srie type = shdr->sh_type; 26820Sstevel@tonic-gate 26831618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) { 26840Sstevel@tonic-gate symtab = _cache; 26850Sstevel@tonic-gate continue; 26860Sstevel@tonic-gate } 26871618Srie if (type == SHT_SYMTAB) { 26880Sstevel@tonic-gate symtab = _cache; 26890Sstevel@tonic-gate continue; 26900Sstevel@tonic-gate } 26911618Srie if ((type != SHT_RELA) && (type != SHT_REL)) 26920Sstevel@tonic-gate continue; 26930Sstevel@tonic-gate 26940Sstevel@tonic-gate /* 26951618Srie * Decide entry size. 26960Sstevel@tonic-gate */ 26971618Srie if (((relsize = shdr->sh_entsize) == 0) || 26981618Srie (relsize > shdr->sh_size)) { 26991618Srie if (type == SHT_RELA) 27001618Srie relsize = sizeof (Rela); 27011618Srie else 27021618Srie relsize = sizeof (Rel); 27030Sstevel@tonic-gate } 27040Sstevel@tonic-gate 27050Sstevel@tonic-gate /* 27061618Srie * Determine the number of relocations available. 27070Sstevel@tonic-gate */ 27081618Srie if (shdr->sh_size == 0) { 27091618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 27101618Srie file, _cache->c_name); 27110Sstevel@tonic-gate continue; 27120Sstevel@tonic-gate } 27133466Srie if (_cache->c_data == NULL) 27143466Srie continue; 27153466Srie 27161618Srie rels = _cache->c_data->d_buf; 27171618Srie relnum = shdr->sh_size / relsize; 27180Sstevel@tonic-gate 27191618Srie /* 27201618Srie * Get the data buffer for the associated symbol table and 27211618Srie * string table. 27221618Srie */ 27231618Srie if (stringtbl(cache, 1, cnt, shnum, file, 27241618Srie &symnum, &symsec, &strsec) == 0) 27251618Srie continue; 27261618Srie 27271618Srie syms = symsec->c_data->d_buf; 27281618Srie 27291618Srie /* 27301618Srie * Loop through the relocation entries. 27311618Srie */ 27321618Srie for (relndx = 0; relndx < relnum; relndx++, 27331618Srie rels = (void *)((char *)rels + relsize)) { 27341618Srie char section[BUFSIZ]; 27351618Srie Addr offset; 27360Sstevel@tonic-gate Got_info *gip; 27371618Srie Word symndx, reltype; 27381618Srie Rela *rela; 27391618Srie Rel *rel; 27400Sstevel@tonic-gate 27411618Srie /* 27421618Srie * Unravel the relocation. 27431618Srie */ 27441618Srie if (type == SHT_RELA) { 27451618Srie rela = (Rela *)rels; 27461618Srie symndx = ELF_R_SYM(rela->r_info); 27471618Srie reltype = ELF_R_TYPE(rela->r_info); 27481618Srie offset = rela->r_offset; 27490Sstevel@tonic-gate } else { 27501618Srie rel = (Rel *)rels; 27511618Srie symndx = ELF_R_SYM(rel->r_info); 27521618Srie reltype = ELF_R_TYPE(rel->r_info); 27531618Srie offset = rel->r_offset; 27540Sstevel@tonic-gate } 27550Sstevel@tonic-gate 27560Sstevel@tonic-gate /* 27570Sstevel@tonic-gate * Only pay attention to relocations against the GOT. 27580Sstevel@tonic-gate */ 27594146Sab196087 if ((offset < gotbgn) || (offset >= gotend)) 27600Sstevel@tonic-gate continue; 27610Sstevel@tonic-gate 27620Sstevel@tonic-gate /* LINTED */ 27631618Srie gotndx = (Word)((offset - gotbgn) / 27640Sstevel@tonic-gate gotshdr->sh_entsize); 27650Sstevel@tonic-gate gip = &gottable[gotndx]; 27661618Srie 27671618Srie if (gip->g_reltype != 0) { 27680Sstevel@tonic-gate (void) fprintf(stderr, 27690Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file, 27701618Srie EC_WORD(gotndx), EC_ADDR(offset)); 27710Sstevel@tonic-gate continue; 27720Sstevel@tonic-gate } 27730Sstevel@tonic-gate 27741618Srie if (symndx) 27751618Srie gip->g_symname = relsymname(cache, _cache, 27761618Srie strsec, symndx, symnum, relndx, syms, 27771618Srie section, BUFSIZ, file, flags); 27781618Srie gip->g_reltype = reltype; 27791618Srie gip->g_rel = rels; 27800Sstevel@tonic-gate } 27810Sstevel@tonic-gate } 27820Sstevel@tonic-gate 27831618Srie if (symlookup(MSG_ORIG(MSG_GOT_SYM), cache, shnum, &gotsym, symtab, 27841618Srie file)) 27851618Srie gotsymaddr = gotsym->st_value; 27860Sstevel@tonic-gate else 27871618Srie gotsymaddr = gotbgn; 27880Sstevel@tonic-gate 27891618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 27901618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name); 27911618Srie Elf_got_title(0); 27920Sstevel@tonic-gate 27930Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) { 27940Sstevel@tonic-gate Got_info *gip; 27950Sstevel@tonic-gate Sword gindex; 27961618Srie Addr gaddr; 27971618Srie Xword gotentry; 27980Sstevel@tonic-gate 27990Sstevel@tonic-gate gip = &gottable[gotndx]; 28000Sstevel@tonic-gate 28010Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize); 28021618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize; 28030Sstevel@tonic-gate 28041618Srie if (gentsize == sizeof (Word)) 28050Sstevel@tonic-gate /* LINTED */ 28061618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx)); 28070Sstevel@tonic-gate else 28080Sstevel@tonic-gate /* LINTED */ 28091618Srie gotentry = *((Xword *)(gotdata) + gotndx); 28100Sstevel@tonic-gate 28111618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine, 28121618Srie gip->g_reltype, gip->g_rel, gip->g_symname); 28130Sstevel@tonic-gate } 28140Sstevel@tonic-gate free(gottable); 28150Sstevel@tonic-gate } 28160Sstevel@tonic-gate 28170Sstevel@tonic-gate void 28180Sstevel@tonic-gate checksum(Elf *elf) 28190Sstevel@tonic-gate { 28201618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 28211618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf)); 28220Sstevel@tonic-gate } 28230Sstevel@tonic-gate 28244242Sab196087 /* 28254242Sab196087 * This variable is used by regular() to communicate the address of 28264242Sab196087 * the section header cache to sort_shdr_ndx_arr(). Unfortunately, 28274242Sab196087 * the qsort() interface does not include a userdata argument by which 28284242Sab196087 * such arbitrary data can be passed, so we are stuck using global data. 28294242Sab196087 */ 28304242Sab196087 static Cache *sort_shdr_ndx_arr_cache; 28314242Sab196087 28324242Sab196087 28334242Sab196087 /* 28344242Sab196087 * Used with qsort() to sort the section indices so that they can be 28354242Sab196087 * used to access the section headers in order of increasing data offset. 28364242Sab196087 * 28374242Sab196087 * entry: 28384242Sab196087 * sort_shdr_ndx_arr_cache - Contains address of 28394242Sab196087 * section header cache. 28404242Sab196087 * v1, v2 - Point at elements of sort_shdr_bits array to be compared. 28414242Sab196087 * 28424242Sab196087 * exit: 28434242Sab196087 * Returns -1 (less than), 0 (equal) or 1 (greater than). 28444242Sab196087 */ 28454242Sab196087 static int 28464242Sab196087 sort_shdr_ndx_arr(const void *v1, const void *v2) 28474242Sab196087 { 28484242Sab196087 Cache *cache1 = sort_shdr_ndx_arr_cache + *((size_t *)v1); 28494242Sab196087 Cache *cache2 = sort_shdr_ndx_arr_cache + *((size_t *)v2); 28504242Sab196087 28514242Sab196087 if (cache1->c_shdr->sh_offset < cache2->c_shdr->sh_offset) 28524242Sab196087 return (-1); 28534242Sab196087 28544242Sab196087 if (cache1->c_shdr->sh_offset > cache2->c_shdr->sh_offset) 28554242Sab196087 return (1); 28564242Sab196087 28574242Sab196087 return (0); 28584242Sab196087 } 28594242Sab196087 28604242Sab196087 28614665Sab196087 static int 28624665Sab196087 shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, 28634665Sab196087 size_t shnum, Cache **cache_ret) 28640Sstevel@tonic-gate { 28650Sstevel@tonic-gate Elf_Scn *scn; 28660Sstevel@tonic-gate Elf_Data *data; 28674665Sab196087 size_t ndx; 28684665Sab196087 Shdr *nameshdr; 28690Sstevel@tonic-gate char *names = 0; 28700Sstevel@tonic-gate Cache *cache, *_cache; 28714242Sab196087 size_t *shdr_ndx_arr, shdr_ndx_arr_cnt; 28720Sstevel@tonic-gate 28730Sstevel@tonic-gate 28740Sstevel@tonic-gate /* 28750Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section 28760Sstevel@tonic-gate * name strings. 28770Sstevel@tonic-gate */ 28784156Sab196087 if (shstrndx == SHN_UNDEF) { 28794156Sab196087 /* 28804156Sab196087 * It is rare, but legal, for an object to lack a 28814156Sab196087 * header string table section. 28824156Sab196087 */ 28834156Sab196087 names = NULL; 28844156Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHSTRSEC), file); 28854156Sab196087 } else if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 28860Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 28870Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 28880Sstevel@tonic-gate EC_XWORD(shstrndx)); 28891618Srie 28900Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) { 28910Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 28920Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 28930Sstevel@tonic-gate EC_XWORD(shstrndx)); 28941618Srie 28951618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) { 28960Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 28970Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 28983862Srie EC_WORD(elf_ndxscn(scn))); 28991618Srie 29001618Srie } else if ((names = data->d_buf) == 0) 29010Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 29020Sstevel@tonic-gate 29030Sstevel@tonic-gate /* 29043862Srie * Allocate a cache to maintain a descriptor for each section. 29050Sstevel@tonic-gate */ 29064665Sab196087 if ((*cache_ret = cache = malloc(shnum * sizeof (Cache))) == NULL) { 29070Sstevel@tonic-gate int err = errno; 29080Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 29090Sstevel@tonic-gate file, strerror(err)); 29104665Sab196087 return (0); 29110Sstevel@tonic-gate } 29120Sstevel@tonic-gate 29131618Srie *cache = cache_init; 29140Sstevel@tonic-gate _cache = cache; 29150Sstevel@tonic-gate _cache++; 29160Sstevel@tonic-gate 29173862Srie /* 29184242Sab196087 * Allocate an array that will hold the section index for 29194242Sab196087 * each section that has data in the ELF file: 29204242Sab196087 * 29214242Sab196087 * - Is not a NOBITS section 29224242Sab196087 * - Data has non-zero length 29234242Sab196087 * 29244242Sab196087 * Note that shnum is an upper bound on the size required. It 29254242Sab196087 * is likely that we won't use a few of these array elements. 29264242Sab196087 * Allocating a modest amount of extra memory in this case means 29274242Sab196087 * that we can avoid an extra loop to count the number of needed 29284242Sab196087 * items, and can fill this array immediately in the first loop 29294242Sab196087 * below. 29304242Sab196087 */ 29314242Sab196087 if ((shdr_ndx_arr = malloc(shnum * sizeof (*shdr_ndx_arr))) == NULL) { 29324242Sab196087 int err = errno; 29334242Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 29344242Sab196087 file, strerror(err)); 29354665Sab196087 return (0); 29364242Sab196087 } 29374242Sab196087 shdr_ndx_arr_cnt = 0; 29384242Sab196087 29394242Sab196087 /* 29403862Srie * Traverse the sections of the file. This gathering of data is 29413862Srie * carried out in two passes. First, the section headers are captured 29423862Srie * and the section header names are evaluated. A verification pass is 29433862Srie * then carried out over the section information. Files have been 29443862Srie * known to exhibit overlapping (and hence erroneous) section header 29453862Srie * information. 29463862Srie * 29473862Srie * Finally, the data for each section is obtained. This processing is 29483862Srie * carried out after section verification because should any section 29493862Srie * header overlap occur, and a file needs translating (ie. xlate'ing 29503862Srie * information from a non-native architecture file), then the process 29513862Srie * of translation can corrupt the section header information. Of 29523862Srie * course, if there is any section overlap, the data related to the 29533862Srie * sections is going to be compromised. However, it is the translation 29543862Srie * of this data that has caused problems with elfdump()'s ability to 29553862Srie * extract the data. 29563862Srie */ 29574242Sab196087 for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn); 29584242Sab196087 ndx++, _cache++) { 29593862Srie char scnndxnm[100]; 29603862Srie 29614242Sab196087 _cache->c_ndx = ndx; 29623862Srie _cache->c_scn = scn; 29633862Srie 29641618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) { 29650Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 29660Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 29673862Srie EC_WORD(elf_ndxscn(scn))); 29680Sstevel@tonic-gate } 29690Sstevel@tonic-gate 29703862Srie /* 29714242Sab196087 * If this section has data in the file, include it in 29724242Sab196087 * the array of sections to check for address overlap. 29734242Sab196087 */ 29744242Sab196087 if ((_cache->c_shdr->sh_size != 0) && 29754242Sab196087 (_cache->c_shdr->sh_type != SHT_NOBITS)) 29764242Sab196087 shdr_ndx_arr[shdr_ndx_arr_cnt++] = ndx; 29774242Sab196087 29784242Sab196087 /* 29793862Srie * If a shstrtab exists, assign the section name. 29803862Srie */ 29813862Srie if (names && _cache->c_shdr) { 29823862Srie if (_cache->c_shdr->sh_name && 29833862Srie /* LINTED */ 29843862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) { 29853862Srie _cache->c_name = 29863862Srie names + _cache->c_shdr->sh_name; 29873862Srie continue; 29883862Srie } 29890Sstevel@tonic-gate 29900Sstevel@tonic-gate /* 29913862Srie * Generate an error if the section name index is zero 29923862Srie * or exceeds the shstrtab data. Fall through to 29933862Srie * fabricate a section name. 29940Sstevel@tonic-gate */ 29953862Srie if ((_cache->c_shdr->sh_name == 0) || 29960Sstevel@tonic-gate /* LINTED */ 29971618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) { 29980Sstevel@tonic-gate (void) fprintf(stderr, 29990Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file, 30004242Sab196087 EC_WORD(ndx), 30011618Srie EC_XWORD(_cache->c_shdr->sh_name)); 30020Sstevel@tonic-gate } 30033862Srie } 30043862Srie 30053862Srie /* 30063862Srie * If there exists no shstrtab data, or a section header has no 30073862Srie * name (an invalid index of 0), then compose a name for the 30083862Srie * section. 30093862Srie */ 30103862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm), 30114242Sab196087 MSG_INTL(MSG_FMT_SCNNDX), ndx); 30124242Sab196087 30134242Sab196087 if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == NULL) { 30143862Srie int err = errno; 30153862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 30163862Srie file, strerror(err)); 30174665Sab196087 return (0); 30183862Srie } 30193862Srie (void) strcpy(_cache->c_name, scnndxnm); 30203862Srie } 30213862Srie 30223862Srie /* 30233862Srie * Having collected all the sections, validate their address range. 30243862Srie * Cases have existed where the section information has been invalid. 30253862Srie * This can lead to all sorts of other, hard to diagnose errors, as 30263862Srie * each section is processed individually (ie. with elf_getdata()). 30273862Srie * Here, we carry out some address comparisons to catch a family of 30283862Srie * overlapping memory issues we have observed (likely, there are others 30293862Srie * that we have yet to discover). 30303862Srie * 30313862Srie * Note, should any memory overlap occur, obtaining any additional 30323862Srie * data from the file is questionable. However, it might still be 30333862Srie * possible to inspect the ELF header, Programs headers, or individual 30343862Srie * sections, so rather than bailing on an error condition, continue 30353862Srie * processing to see if any data can be salvaged. 30363862Srie */ 30374242Sab196087 if (shdr_ndx_arr_cnt > 1) { 30384242Sab196087 sort_shdr_ndx_arr_cache = cache; 30394242Sab196087 qsort(shdr_ndx_arr, shdr_ndx_arr_cnt, 30404242Sab196087 sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr); 30414242Sab196087 } 30424242Sab196087 for (ndx = 0; ndx < shdr_ndx_arr_cnt; ndx++) { 30434242Sab196087 Cache *_cache = cache + shdr_ndx_arr[ndx]; 30443862Srie Shdr *shdr = _cache->c_shdr; 30453862Srie Off bgn1, bgn = shdr->sh_offset; 30463862Srie Off end1, end = shdr->sh_offset + shdr->sh_size; 30474242Sab196087 size_t ndx1; 30484242Sab196087 30494242Sab196087 /* 30504242Sab196087 * Check the section against all following ones, reporting 30514242Sab196087 * any overlaps. Since we've sorted the sections by offset, 30524242Sab196087 * we can stop after the first comparison that fails. There 30534242Sab196087 * are no overlaps in a properly formed ELF file, in which 30544242Sab196087 * case this algorithm runs in O(n) time. This will degenerate 30554242Sab196087 * to O(n^2) for a completely broken file. Such a file is 30564242Sab196087 * (1) highly unlikely, and (2) unusable, so it is reasonable 30574242Sab196087 * for the analysis to take longer. 30584242Sab196087 */ 30594242Sab196087 for (ndx1 = ndx + 1; ndx1 < shdr_ndx_arr_cnt; ndx1++) { 30604242Sab196087 Cache *_cache1 = cache + shdr_ndx_arr[ndx1]; 30613862Srie Shdr *shdr1 = _cache1->c_shdr; 30623862Srie 30633862Srie bgn1 = shdr1->sh_offset; 30643862Srie end1 = shdr1->sh_offset + shdr1->sh_size; 30653862Srie 30663862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 30673862Srie ((bgn1 < end) && (end1 >= end))) { 30683862Srie (void) fprintf(stderr, 30693862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file, 30704242Sab196087 EC_WORD(elf_ndxscn(_cache->c_scn)), 30714242Sab196087 _cache->c_name, EC_OFF(bgn), EC_OFF(end), 30723862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)), 30734242Sab196087 _cache1->c_name, EC_OFF(bgn1), 30744242Sab196087 EC_OFF(end1)); 30754242Sab196087 } else { /* No overlap, so can stop */ 30764242Sab196087 break; 30770Sstevel@tonic-gate } 30780Sstevel@tonic-gate } 30790Sstevel@tonic-gate 30803862Srie /* 30814242Sab196087 * In addition to checking for sections overlapping 30824242Sab196087 * each other (done above), we should also make sure 30834242Sab196087 * the section doesn't overlap the section header array. 30843862Srie */ 30853862Srie bgn1 = ehdr->e_shoff; 30863862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum); 30873862Srie 30883862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 30893862Srie ((bgn1 < end) && (end1 >= end))) { 30903862Srie (void) fprintf(stderr, 30913862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1), 30923862Srie EC_OFF(end1), 30933862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 30943862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 30953862Srie } 30963862Srie } 30973862Srie 30983862Srie /* 30994242Sab196087 * Obtain the data for each section. 31003862Srie */ 31014242Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 31024242Sab196087 Cache *_cache = &cache[ndx]; 31033862Srie Elf_Scn *scn = _cache->c_scn; 31043862Srie 31050Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 31060Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 31070Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 31083862Srie EC_WORD(elf_ndxscn(scn))); 31090Sstevel@tonic-gate } 31104665Sab196087 } 31114665Sab196087 31124665Sab196087 return (1); 31134665Sab196087 } 31144665Sab196087 31154665Sab196087 31164665Sab196087 31174665Sab196087 void 31184665Sab196087 regular(const char *file, int fd, Elf *elf, uint_t flags, int wfd) 31194665Sab196087 { 31204665Sab196087 Elf_Scn *scn; 31214665Sab196087 Ehdr *ehdr; 31224665Sab196087 size_t ndx, shstrndx, shnum, phnum; 31234665Sab196087 Shdr *shdr; 31244665Sab196087 Cache *cache; 31254665Sab196087 VERSYM_STATE versym; 31264665Sab196087 31274665Sab196087 if ((ehdr = elf_getehdr(elf)) == NULL) { 31284665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 31294665Sab196087 return; 31304665Sab196087 } 31314665Sab196087 31324665Sab196087 if (elf_getshnum(elf, &shnum) == 0) { 31334665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 31344665Sab196087 return; 31354665Sab196087 } 31364665Sab196087 31374665Sab196087 if (elf_getshstrndx(elf, &shstrndx) == 0) { 31384665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 31394665Sab196087 return; 31404665Sab196087 } 31414665Sab196087 31424665Sab196087 if (elf_getphnum(elf, &phnum) == 0) { 31434665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 31444665Sab196087 return; 31454665Sab196087 } 31464665Sab196087 /* 31474665Sab196087 * If the user requested section headers derived from the 31484665Sab196087 * program headers (-P option) and this file doesn't have 31494665Sab196087 * any program headers (i.e. ET_REL), then we can't do it. 31504665Sab196087 */ 31514665Sab196087 if ((phnum == 0) && (flags & FLG_FAKESHDR)) { 31524665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_PNEEDSPH), file); 31534665Sab196087 return; 31544665Sab196087 } 31554665Sab196087 31564665Sab196087 31574665Sab196087 if ((scn = elf_getscn(elf, 0)) != NULL) { 31584665Sab196087 if ((shdr = elf_getshdr(scn)) == NULL) { 31594665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 31604665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 31614665Sab196087 return; 31624665Sab196087 } 31634665Sab196087 } else 31644665Sab196087 shdr = 0; 31654665Sab196087 31664665Sab196087 /* 31674665Sab196087 * Print the elf header. 31684665Sab196087 */ 31694665Sab196087 if (flags & FLG_EHDR) 31704665Sab196087 Elf_ehdr(0, ehdr, shdr); 31714665Sab196087 31724665Sab196087 /* 31734665Sab196087 * If the section headers or program headers have inadequate 31744665Sab196087 * alignment for the class of object, print a warning. libelf 31754665Sab196087 * can handle such files, but programs that use them can crash 31764665Sab196087 * when they dereference unaligned items. 31774665Sab196087 */ 31784665Sab196087 if (ehdr->e_phoff & (sizeof (Addr) - 1)) 31794665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADPHDRALIGN), file); 31804665Sab196087 if (ehdr->e_shoff & (sizeof (Addr) - 1)) 31814665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHDRALIGN), file); 31824665Sab196087 31834665Sab196087 /* 31844665Sab196087 * Print the program headers. 31854665Sab196087 */ 31864665Sab196087 if ((flags & FLG_PHDR) && (phnum != 0)) { 31874665Sab196087 Phdr *phdr; 31884665Sab196087 31894665Sab196087 if ((phdr = elf_getphdr(elf)) == NULL) { 31904665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 31914665Sab196087 return; 31924665Sab196087 } 31934665Sab196087 31944665Sab196087 for (ndx = 0; ndx < phnum; phdr++, ndx++) { 31954665Sab196087 if (!match(0, conv_phdr_type(ehdr->e_machine, 31964665Sab196087 phdr->p_type, CONV_FMT_ALTFILE), ndx)) 31974665Sab196087 continue; 31984665Sab196087 31994665Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 32004665Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx)); 32014665Sab196087 Elf_phdr(0, ehdr->e_machine, phdr); 32024665Sab196087 } 32034665Sab196087 } 32044665Sab196087 32054665Sab196087 /* 32064665Sab196087 * Decide how to proceed if there are no sections, if there's just 32074665Sab196087 * one section (the first section can act as an extension of the 32084665Sab196087 * ELF header), or if only program header information was requested. 32094665Sab196087 */ 32104665Sab196087 if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) { 32114665Sab196087 /* If a core file, display the note and return */ 32124665Sab196087 if ((ehdr->e_type == ET_CORE) && (flags & FLG_NOTE)) { 32134665Sab196087 note(0, shnum, file); 32144665Sab196087 return; 32154665Sab196087 } 32164665Sab196087 32174665Sab196087 /* If only program header info was requested, we're done */ 32184665Sab196087 if (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0) 32194665Sab196087 return; 32200Sstevel@tonic-gate 32210Sstevel@tonic-gate /* 32224665Sab196087 * Section headers are missing. Resort to synthesizing 32234665Sab196087 * section headers from the program headers. 32240Sstevel@tonic-gate */ 32254665Sab196087 if ((flags & FLG_FAKESHDR) == 0) { 32264665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHDR), file); 32274665Sab196087 flags |= FLG_FAKESHDR; 32284665Sab196087 } 32294665Sab196087 } 32304665Sab196087 32314665Sab196087 /* 32324665Sab196087 * Generate a cache of section headers and related information 32334665Sab196087 * for use by the rest of elfdump. If requested (or the file 32344665Sab196087 * contains no section headers), we generate a fake set of 32354665Sab196087 * headers from the information accessible from the program headers. 32364665Sab196087 * Otherwise, we use the real section headers contained in the file. 32374665Sab196087 */ 32384665Sab196087 32394665Sab196087 if (flags & FLG_FAKESHDR) { 32404665Sab196087 if (fake_shdr_cache(file, fd, elf, ehdr, &cache, &shnum) == 0) 32414665Sab196087 return; 32424665Sab196087 } else { 32434665Sab196087 if (shdr_cache(file, elf, ehdr, shstrndx, shnum, &cache) == 0) 32444665Sab196087 return; 32454665Sab196087 } 32464665Sab196087 32474665Sab196087 /* 32484665Sab196087 * If -w was specified, find and write out the section(s) data. 32494665Sab196087 */ 32504665Sab196087 if (wfd) { 32514665Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 32524665Sab196087 Cache *_cache = &cache[ndx]; 32534665Sab196087 32544665Sab196087 if (match(1, _cache->c_name, ndx) && _cache->c_data) { 32554665Sab196087 (void) write(wfd, _cache->c_data->d_buf, 32564665Sab196087 _cache->c_data->d_size); 32574665Sab196087 } 32580Sstevel@tonic-gate } 32590Sstevel@tonic-gate } 32600Sstevel@tonic-gate 32610Sstevel@tonic-gate if (flags & FLG_SHDR) 32624168Sab196087 sections(file, cache, shnum, ehdr); 32630Sstevel@tonic-gate 32640Sstevel@tonic-gate if (flags & FLG_INTERP) 32651618Srie interp(file, cache, shnum, phnum, elf); 32660Sstevel@tonic-gate 32673875Sab196087 versions(cache, shnum, file, flags, &versym); 32680Sstevel@tonic-gate 32690Sstevel@tonic-gate if (flags & FLG_SYMBOLS) 32704168Sab196087 symbols(cache, shnum, ehdr, &versym, file, flags); 32710Sstevel@tonic-gate 32723492Sab196087 if (flags & FLG_SORT) 32734168Sab196087 sunw_sort(cache, shnum, ehdr, &versym, file, flags); 32743492Sab196087 32750Sstevel@tonic-gate if (flags & FLG_HASH) 32764168Sab196087 hash(cache, shnum, file, flags); 32770Sstevel@tonic-gate 32780Sstevel@tonic-gate if (flags & FLG_GOT) 32791618Srie got(cache, shnum, ehdr, file, flags); 32800Sstevel@tonic-gate 32810Sstevel@tonic-gate if (flags & FLG_GROUP) 32824168Sab196087 group(cache, shnum, file, flags); 32830Sstevel@tonic-gate 32840Sstevel@tonic-gate if (flags & FLG_SYMINFO) 32850Sstevel@tonic-gate syminfo(cache, shnum, file); 32860Sstevel@tonic-gate 32870Sstevel@tonic-gate if (flags & FLG_RELOC) 32884168Sab196087 reloc(cache, shnum, ehdr, file, flags); 32890Sstevel@tonic-gate 32900Sstevel@tonic-gate if (flags & FLG_DYNAMIC) 32911618Srie dynamic(cache, shnum, ehdr, file); 32920Sstevel@tonic-gate 32930Sstevel@tonic-gate if (flags & FLG_NOTE) 32944168Sab196087 note(cache, shnum, file); 32950Sstevel@tonic-gate 32960Sstevel@tonic-gate if (flags & FLG_MOVE) 32974168Sab196087 move(cache, shnum, file, flags); 32980Sstevel@tonic-gate 32990Sstevel@tonic-gate if (flags & FLG_CHECKSUM) 33000Sstevel@tonic-gate checksum(elf); 33010Sstevel@tonic-gate 33020Sstevel@tonic-gate if (flags & FLG_CAP) 33031618Srie cap(file, cache, shnum, phnum, ehdr, elf); 33040Sstevel@tonic-gate 33050Sstevel@tonic-gate if (flags & FLG_UNWIND) 33064168Sab196087 unwind(cache, shnum, phnum, ehdr, file, elf); 33070Sstevel@tonic-gate 33084665Sab196087 33094665Sab196087 /* Release the memory used to cache section headers */ 33104665Sab196087 if (flags & FLG_FAKESHDR) 33114665Sab196087 fake_shdr_cache_free(cache, shnum); 33124665Sab196087 else 33134665Sab196087 free(cache); 33140Sstevel@tonic-gate } 3315