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 /* 236206Sab196087 * Copyright 2008 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 <sys/elf_386.h> 321618Srie #include <sys/elf_amd64.h> 331618Srie #include <sys/elf_SPARC.h> 346206Sab196087 #include <_libelf.h> 351618Srie #include <dwarf.h> 365549Srie #include <stdio.h> 370Sstevel@tonic-gate #include <unistd.h> 380Sstevel@tonic-gate #include <errno.h> 390Sstevel@tonic-gate #include <strings.h> 400Sstevel@tonic-gate #include <debug.h> 410Sstevel@tonic-gate #include <conv.h> 420Sstevel@tonic-gate #include <msg.h> 431618Srie #include <_elfdump.h> 440Sstevel@tonic-gate 453875Sab196087 463875Sab196087 /* 473875Sab196087 * VERSYM_STATE is used to maintain information about the VERSYM section 483875Sab196087 * in the object being analyzed. It is filled in by versions(), and used 493875Sab196087 * by init_symtbl_state() when displaying symbol information. 503875Sab196087 * 514716Sab196087 * max_verndx contains the largest version index that can appear 524716Sab196087 * in a Versym entry. This can never be less than 1: In the case where 534716Sab196087 * there is no verdef/verneed sections, the [0] index is reserved 544716Sab196087 * for local symbols, and the [1] index for globals. If Solaris versioning 554716Sab196087 * rules are in effect and there is a verdef section, then the number 564716Sab196087 * of defined versions provides this number. If GNU versioning is in effect, 574716Sab196087 * then: 584716Sab196087 * - If there is no verneed section, it is the same as for 594716Sab196087 * Solaris versioning. 604716Sab196087 * - If there is a verneed section, the vna_other field of the 614716Sab196087 * Vernaux structs contain versions, and max_verndx is the 624716Sab196087 * largest such index. 634716Sab196087 * 644716Sab196087 * The value of the gnu field is based on the presence of 654716Sab196087 * a DT_VERSYM entry in the dynamic section: GNU ld produces these, and 664716Sab196087 * Solaris ld does not. 673875Sab196087 */ 683875Sab196087 typedef struct { 693875Sab196087 Cache *cache; /* Pointer to cache entry for VERSYM */ 703875Sab196087 Versym *data; /* Pointer to versym array */ 714716Sab196087 int gnu; /* True if object uses GNU versioning rules */ 724716Sab196087 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)) { 1985411Sab196087 if (flags & FLG_CTL_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 3585411Sab196087 if (!match(MATCH_F_ALL, secname, seccnt, shdr->sh_type)) 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 { 4364734Sab196087 Conv_dwarf_ehe_buf_t dwarf_ehe_buf; 4371618Srie Word cnt; 4381618Srie Phdr *uphdr = 0; 4391618Srie 4400Sstevel@tonic-gate /* 4411618Srie * For the moment - UNWIND is only relevant for a AMD64 object. 4420Sstevel@tonic-gate */ 4430Sstevel@tonic-gate if (ehdr->e_machine != EM_AMD64) 4441618Srie return; 4450Sstevel@tonic-gate 4461618Srie if (phnum) 4471618Srie uphdr = getphdr(phnum, PT_SUNW_UNWIND, file, elf); 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 4501618Srie Cache *_cache = &cache[cnt]; 4511618Srie Shdr *shdr = _cache->c_shdr; 4521618Srie uchar_t *data; 4530Sstevel@tonic-gate size_t datasize; 4541618Srie uint64_t off, ndx, frame_ptr, fde_cnt, tabndx; 4551618Srie uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* 4581618Srie * AMD64 - this is a strmcp() just to find the gcc produced 4591618Srie * sections. Soon gcc should be setting the section type - and 4601618Srie * we'll not need this strcmp(). 4610Sstevel@tonic-gate */ 4620Sstevel@tonic-gate if ((shdr->sh_type != SHT_AMD64_UNWIND) && 4630Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 4640Sstevel@tonic-gate MSG_SCN_FRM_SIZE) != 0) && 4650Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4660Sstevel@tonic-gate MSG_SCN_FRMHDR_SIZE) != 0)) 4670Sstevel@tonic-gate continue; 4684168Sab196087 4695411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 4700Sstevel@tonic-gate continue; 4710Sstevel@tonic-gate 4723466Srie if (_cache->c_data == NULL) 4733466Srie continue; 4743466Srie 4751618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 4761618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 4770Sstevel@tonic-gate 4781618Srie data = (uchar_t *)(_cache->c_data->d_buf); 4790Sstevel@tonic-gate datasize = _cache->c_data->d_size; 4800Sstevel@tonic-gate off = 0; 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate /* 4830Sstevel@tonic-gate * Is this a .eh_frame_hdr 4840Sstevel@tonic-gate */ 4851618Srie if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || 4860Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4871618Srie MSG_SCN_FRMHDR_SIZE) == 0)) { 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), 5024734Sab196087 conv_dwarf_ehe(frame_ptr_enc, &dwarf_ehe_buf), 5034734Sab196087 EC_XWORD(frame_ptr)); 5041618Srie 5051618Srie fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, 5061618Srie ehdr->e_ident, shdr->sh_addr + ndx); 5070Sstevel@tonic-gate 5081618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), 5094734Sab196087 conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf), 5104734Sab196087 EC_XWORD(fde_cnt)); 5111618Srie dbg_print(0, MSG_ORIG(MSG_UNW_TABENC), 5124734Sab196087 conv_dwarf_ehe(table_enc, &dwarf_ehe_buf)); 5131618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1)); 5141618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2)); 5150Sstevel@tonic-gate 5161618Srie for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 5171618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), 5181618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5191618Srie table_enc, ehdr->e_ident, shdr->sh_addr)), 5201618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5211618Srie table_enc, ehdr->e_ident, shdr->sh_addr))); 5221618Srie } 5231618Srie continue; 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* 5270Sstevel@tonic-gate * Walk the Eh_frame's 5280Sstevel@tonic-gate */ 5290Sstevel@tonic-gate while (off < datasize) { 5304433Sab196087 uint_t cieid, cielength, cieversion; 5314433Sab196087 uint_t cieretaddr; 5321618Srie int cieRflag, cieLflag, ciePflag, cieZflag; 5331618Srie uint_t cieaugndx, length, id; 5340Sstevel@tonic-gate uint64_t ciecalign, ciedalign; 5350Sstevel@tonic-gate char *cieaugstr; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate ndx = 0; 5380Sstevel@tonic-gate /* 5396388Srie * Extract length in lsb format. A zero length 5406388Srie * indicates that this CIE is a terminator and that 5416388Srie * processing for this unwind information should end. 5426388Srie * However, skip this entry and keep processing, just 5436388Srie * in case there is any other information remaining in 5446388Srie * this section. Note, ld(1) will terminate the 5456388Srie * processing of the .eh_frame contents for this file 5466388Srie * after a zero length CIE, thus any information that 5476388Srie * does follow is ignored by ld(1), and is therefore 5486388Srie * questionable. 5490Sstevel@tonic-gate */ 5506388Srie if ((length = LSB32EXTRACT(data + off + ndx)) == 0) { 5516388Srie dbg_print(0, MSG_ORIG(MSG_UNW_ZEROTERM)); 5526388Srie off += 4; 5536388Srie continue; 5546388Srie } 5550Sstevel@tonic-gate ndx += 4; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate /* 5580Sstevel@tonic-gate * extract CIE id in lsb format 5590Sstevel@tonic-gate */ 5600Sstevel@tonic-gate id = LSB32EXTRACT(data + off + ndx); 5610Sstevel@tonic-gate ndx += 4; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate /* 5641618Srie * A CIE record has a id of '0', otherwise this is a 5651618Srie * FDE entry and the 'id' is the CIE pointer. 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate if (id == 0) { 5680Sstevel@tonic-gate uint64_t persVal; 5691618Srie 5700Sstevel@tonic-gate cielength = length; 5710Sstevel@tonic-gate cieid = id; 5721618Srie cieLflag = ciePflag = cieRflag = cieZflag = 0; 5730Sstevel@tonic-gate 5741618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIE), 5751618Srie EC_XWORD(shdr->sh_addr + off)); 5761618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH), 5771618Srie cielength, cieid); 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate cieversion = data[off + ndx]; 5800Sstevel@tonic-gate ndx += 1; 5810Sstevel@tonic-gate cieaugstr = (char *)(&data[off + ndx]); 5820Sstevel@tonic-gate ndx += strlen(cieaugstr) + 1; 5831618Srie 5841618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS), 5851618Srie cieversion, cieaugstr); 5861618Srie 5870Sstevel@tonic-gate ciecalign = uleb_extract(&data[off], &ndx); 5880Sstevel@tonic-gate ciedalign = sleb_extract(&data[off], &ndx); 5890Sstevel@tonic-gate cieretaddr = data[off + ndx]; 5900Sstevel@tonic-gate ndx += 1; 5911618Srie 5921618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN), 5931618Srie EC_XWORD(ciecalign), EC_XWORD(ciedalign), 5941618Srie cieretaddr); 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate if (cieaugstr[0]) 5974433Sab196087 dbg_print(0, 5984433Sab196087 MSG_ORIG(MSG_UNW_CIEAXVAL)); 5991618Srie 6000Sstevel@tonic-gate for (cieaugndx = 0; cieaugstr[cieaugndx]; 6010Sstevel@tonic-gate cieaugndx++) { 6020Sstevel@tonic-gate uint_t val; 6031618Srie 6040Sstevel@tonic-gate switch (cieaugstr[cieaugndx]) { 6050Sstevel@tonic-gate case 'z': 6064433Sab196087 val = uleb_extract(&data[off], 6074433Sab196087 &ndx); 6084433Sab196087 dbg_print(0, 6094433Sab196087 MSG_ORIG(MSG_UNW_CIEAXSIZ), 6104433Sab196087 val); 6114433Sab196087 cieZflag = 1; 6124433Sab196087 break; 6130Sstevel@tonic-gate case 'P': 6144433Sab196087 ciePflag = data[off + ndx]; 6154433Sab196087 ndx += 1; 6164433Sab196087 6174433Sab196087 persVal = dwarf_ehe_extract( 6184433Sab196087 &data[off], &ndx, ciePflag, 6194433Sab196087 ehdr->e_ident, 6204433Sab196087 shdr->sh_addr + off + ndx); 6214433Sab196087 dbg_print(0, 6224433Sab196087 MSG_ORIG(MSG_UNW_CIEAXPERS), 6234433Sab196087 ciePflag, 6244734Sab196087 conv_dwarf_ehe(ciePflag, 6254734Sab196087 &dwarf_ehe_buf), 6264433Sab196087 EC_XWORD(persVal)); 6274433Sab196087 break; 6280Sstevel@tonic-gate case 'R': 6294433Sab196087 val = data[off + ndx]; 6304433Sab196087 ndx += 1; 6314433Sab196087 dbg_print(0, 6324433Sab196087 MSG_ORIG(MSG_UNW_CIEAXCENC), 6334734Sab196087 val, conv_dwarf_ehe(val, 6344734Sab196087 &dwarf_ehe_buf)); 6354433Sab196087 cieRflag = val; 6364433Sab196087 break; 6370Sstevel@tonic-gate case 'L': 6384433Sab196087 val = data[off + ndx]; 6394433Sab196087 ndx += 1; 6404433Sab196087 dbg_print(0, 6414433Sab196087 MSG_ORIG(MSG_UNW_CIEAXLSDA), 6424734Sab196087 val, conv_dwarf_ehe(val, 6434734Sab196087 &dwarf_ehe_buf)); 6444433Sab196087 cieLflag = val; 6454433Sab196087 break; 6460Sstevel@tonic-gate default: 6474433Sab196087 dbg_print(0, 6484433Sab196087 MSG_ORIG(MSG_UNW_CIEAXUNEC), 6494433Sab196087 cieaugstr[cieaugndx]); 6504433Sab196087 break; 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate } 6531618Srie if ((cielength + 4) > ndx) 6541618Srie unwindtbl(&ndx, cielength, data, off, 6551618Srie MSG_ORIG(MSG_UNW_CIECFI), 6561618Srie MSG_ORIG(MSG_UNW_CIEPRE), 6571618Srie MSG_UNW_CIEPRE_SIZE); 6580Sstevel@tonic-gate off += cielength + 4; 6591618Srie 6600Sstevel@tonic-gate } else { 6610Sstevel@tonic-gate uint_t fdelength = length; 6620Sstevel@tonic-gate int fdecieptr = id; 6630Sstevel@tonic-gate uint64_t fdeinitloc, fdeaddrrange; 6640Sstevel@tonic-gate 6651618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDE), 6661618Srie EC_XWORD(shdr->sh_addr + off)); 6671618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH), 6680Sstevel@tonic-gate fdelength, fdecieptr); 6691618Srie 6700Sstevel@tonic-gate fdeinitloc = dwarf_ehe_extract(&data[off], 6710Sstevel@tonic-gate &ndx, cieRflag, ehdr->e_ident, 6720Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6730Sstevel@tonic-gate fdeaddrrange = dwarf_ehe_extract(&data[off], 6740Sstevel@tonic-gate &ndx, (cieRflag & ~DW_EH_PE_pcrel), 6750Sstevel@tonic-gate ehdr->e_ident, 6760Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6771618Srie 6781618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), 6791618Srie EC_XWORD(fdeinitloc), 6801618Srie EC_XWORD(fdeaddrrange)); 6811618Srie 6820Sstevel@tonic-gate if (cieaugstr[0]) 6831618Srie dbg_print(0, 6844433Sab196087 MSG_ORIG(MSG_UNW_FDEAXVAL)); 6850Sstevel@tonic-gate if (cieZflag) { 6860Sstevel@tonic-gate uint64_t val; 6870Sstevel@tonic-gate val = uleb_extract(&data[off], &ndx); 6881618Srie dbg_print(0, 6894433Sab196087 MSG_ORIG(MSG_UNW_FDEAXSIZE), 6901618Srie EC_XWORD(val)); 6910Sstevel@tonic-gate if (val & cieLflag) { 6924433Sab196087 fdeinitloc = dwarf_ehe_extract( 6934433Sab196087 &data[off], &ndx, cieLflag, 6944433Sab196087 ehdr->e_ident, 6954433Sab196087 shdr->sh_addr + off + ndx); 6964433Sab196087 dbg_print(0, 6974433Sab196087 MSG_ORIG(MSG_UNW_FDEAXLSDA), 6984433Sab196087 EC_XWORD(val)); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate } 7011618Srie if ((fdelength + 4) > ndx) 7021618Srie unwindtbl(&ndx, fdelength, data, off, 7031618Srie MSG_ORIG(MSG_UNW_FDECFI), 7041618Srie MSG_ORIG(MSG_UNW_FDEPRE), 7051618Srie MSG_UNW_FDEPRE_SIZE); 7060Sstevel@tonic-gate off += fdelength + 4; 7070Sstevel@tonic-gate } 7080Sstevel@tonic-gate } 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate /* 7130Sstevel@tonic-gate * Print the hardware/software capabilities. For executables and shared objects 7140Sstevel@tonic-gate * this should be accompanied with a program header. 7150Sstevel@tonic-gate */ 7160Sstevel@tonic-gate static void 7171618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, 7181618Srie Elf *elf) 7190Sstevel@tonic-gate { 7201618Srie Word cnt; 7213466Srie Shdr *cshdr = 0; 7223466Srie Cache *ccache; 7231618Srie Off cphdr_off = 0; 7241618Srie Xword cphdr_sz; 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate /* 7270Sstevel@tonic-gate * Determine if a hardware/software capabilities header exists. 7280Sstevel@tonic-gate */ 7291618Srie if (phnum) { 7301618Srie Phdr *phdr; 7310Sstevel@tonic-gate 7321618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 7330Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 7340Sstevel@tonic-gate return; 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate 7371618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 7381618Srie if (phdr->p_type == PT_SUNWCAP) { 7391618Srie cphdr_off = phdr->p_offset; 7401618Srie cphdr_sz = phdr->p_filesz; 7411618Srie break; 7421618Srie } 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate /* 7470Sstevel@tonic-gate * Determine if a hardware/software capabilities section exists. 7480Sstevel@tonic-gate */ 7490Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 7501618Srie Cache *_cache = &cache[cnt]; 7511618Srie Shdr *shdr = _cache->c_shdr; 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_cap) 7540Sstevel@tonic-gate continue; 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 7570Sstevel@tonic-gate (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 7580Sstevel@tonic-gate continue; 7590Sstevel@tonic-gate 7603466Srie if (_cache->c_data == NULL) 7613466Srie continue; 7623466Srie 7630Sstevel@tonic-gate ccache = _cache; 7640Sstevel@tonic-gate cshdr = shdr; 7650Sstevel@tonic-gate break; 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate if ((cshdr == 0) && (cphdr_off == 0)) 7690Sstevel@tonic-gate return; 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate /* 7720Sstevel@tonic-gate * Print the hardware/software capabilities section. 7730Sstevel@tonic-gate */ 7740Sstevel@tonic-gate if (cshdr) { 7751618Srie Word ndx, capn; 7763492Sab196087 Cap *cap = (Cap *)ccache->c_data->d_buf; 7770Sstevel@tonic-gate 7784665Sab196087 if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) { 7794665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 7804665Sab196087 file, ccache->c_name); 7814665Sab196087 return; 7824665Sab196087 } 7834665Sab196087 7841618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 7851618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 7860Sstevel@tonic-gate 7871618Srie Elf_cap_title(0); 7881618Srie 7891618Srie capn = (Word)(cshdr->sh_size / cshdr->sh_entsize); 7900Sstevel@tonic-gate 7911618Srie for (ndx = 0; ndx < capn; cap++, ndx++) { 7921618Srie if (cap->c_tag != CA_SUNW_NULL) 7931618Srie Elf_cap_entry(0, cap, ndx, ehdr->e_machine); 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate } else 7960Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate /* 7990Sstevel@tonic-gate * If this object is an executable or shared object, then the 8000Sstevel@tonic-gate * hardware/software capabilities section should have an accompanying 8010Sstevel@tonic-gate * program header. 8020Sstevel@tonic-gate */ 8030Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 8040Sstevel@tonic-gate if (cphdr_off == 0) 8050Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 8060Sstevel@tonic-gate file, ccache->c_name); 8070Sstevel@tonic-gate else if ((cphdr_off != cshdr->sh_offset) || 8080Sstevel@tonic-gate (cphdr_sz != cshdr->sh_size)) 8090Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 8100Sstevel@tonic-gate file, ccache->c_name); 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate } 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate /* 8150Sstevel@tonic-gate * Print the interpretor. 8160Sstevel@tonic-gate */ 8170Sstevel@tonic-gate static void 8181618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) 8190Sstevel@tonic-gate { 8201618Srie Word cnt; 8211618Srie Shdr *ishdr = 0; 8221618Srie Cache *icache; 8231618Srie Off iphdr_off = 0; 8241618Srie Xword iphdr_fsz; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate /* 8270Sstevel@tonic-gate * Determine if an interp header exists. 8280Sstevel@tonic-gate */ 8291618Srie if (phnum) { 8301618Srie Phdr *phdr; 8310Sstevel@tonic-gate 8321618Srie if ((phdr = getphdr(phnum, PT_INTERP, file, elf)) != 0) { 8331618Srie iphdr_off = phdr->p_offset; 8341618Srie iphdr_fsz = phdr->p_filesz; 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate } 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate if (iphdr_off == 0) 8390Sstevel@tonic-gate return; 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate /* 8420Sstevel@tonic-gate * Determine if an interp section exists. 8430Sstevel@tonic-gate */ 8440Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8451618Srie Cache *_cache = &cache[cnt]; 8461618Srie Shdr *shdr = _cache->c_shdr; 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP 8500Sstevel@tonic-gate * string. The target section can't be in a NOBITS section. 8510Sstevel@tonic-gate */ 8520Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) || 8530Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) || 8541618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size)) 8550Sstevel@tonic-gate continue; 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate icache = _cache; 8580Sstevel@tonic-gate ishdr = shdr; 8590Sstevel@tonic-gate break; 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate /* 8630Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the 8640Sstevel@tonic-gate * program header, as this is the offset used by the kernel. 8650Sstevel@tonic-gate */ 8663466Srie if (ishdr && icache->c_data) { 8671618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8681618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 8691618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), 8700Sstevel@tonic-gate (char *)icache->c_data->d_buf + 8710Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset)); 8720Sstevel@tonic-gate } else 8730Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate /* 8760Sstevel@tonic-gate * If there are any inconsistences between the program header and 8770Sstevel@tonic-gate * section information, flag them. 8780Sstevel@tonic-gate */ 8790Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) || 8801618Srie (iphdr_fsz != ishdr->sh_size))) { 8810Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 8820Sstevel@tonic-gate icache->c_name); 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate /* 8870Sstevel@tonic-gate * Print the syminfo section. 8880Sstevel@tonic-gate */ 8890Sstevel@tonic-gate static void 8901618Srie syminfo(Cache *cache, Word shnum, const char *file) 8910Sstevel@tonic-gate { 8921618Srie Shdr *infoshdr; 8931618Srie Syminfo *info; 8941618Srie Sym *syms; 8951618Srie Dyn *dyns; 8961618Srie Word infonum, cnt, ndx, symnum; 8971618Srie Cache *infocache = 0, *symsec, *strsec; 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 9001618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { 9011618Srie infocache = &cache[cnt]; 9020Sstevel@tonic-gate break; 9030Sstevel@tonic-gate } 9040Sstevel@tonic-gate } 9051618Srie if (infocache == 0) 9060Sstevel@tonic-gate return; 9070Sstevel@tonic-gate 9081618Srie infoshdr = infocache->c_shdr; 9091618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) { 9100Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 9111618Srie file, infocache->c_name); 9120Sstevel@tonic-gate return; 9130Sstevel@tonic-gate } 9143466Srie if (infocache->c_data == NULL) 9153466Srie return; 9163466Srie 9171618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize); 9181618Srie info = (Syminfo *)infocache->c_data->d_buf; 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate /* 9210Sstevel@tonic-gate * Get the data buffer of the associated dynamic section. 9220Sstevel@tonic-gate */ 9231618Srie if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) { 9240Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 9251618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info)); 9260Sstevel@tonic-gate return; 9270Sstevel@tonic-gate } 9283466Srie if (cache[infoshdr->sh_info].c_data == NULL) 9293466Srie return; 9303466Srie 9311618Srie dyns = cache[infoshdr->sh_info].c_data->d_buf; 9321618Srie if (dyns == 0) { 9330Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 9341618Srie file, cache[infoshdr->sh_info].c_name); 9350Sstevel@tonic-gate return; 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate /* 9391618Srie * Get the data buffer for the associated symbol table and string table. 9400Sstevel@tonic-gate */ 9411618Srie if (stringtbl(cache, 1, cnt, shnum, file, 9421618Srie &symnum, &symsec, &strsec) == 0) 9430Sstevel@tonic-gate return; 9440Sstevel@tonic-gate 9451618Srie syms = symsec->c_data->d_buf; 9460Sstevel@tonic-gate 9471618Srie /* 9481618Srie * Loop through the syminfo entries. 9491618Srie */ 9501618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 9511618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name); 9521618Srie Elf_syminfo_title(0); 9530Sstevel@tonic-gate 9541618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) { 9551618Srie Sym *sym; 9561618Srie const char *needed = 0, *name; 9571618Srie 9581618Srie if ((info->si_flags == 0) && (info->si_boundto == 0)) 9590Sstevel@tonic-gate continue; 9600Sstevel@tonic-gate 9611618Srie sym = &syms[ndx]; 9621618Srie name = string(infocache, ndx, strsec, file, sym->st_name); 9630Sstevel@tonic-gate 9641618Srie if (info->si_boundto < SYMINFO_BT_LOWRESERVE) { 9651618Srie Dyn *dyn = &dyns[info->si_boundto]; 9661618Srie 9671618Srie needed = string(infocache, info->si_boundto, 9681618Srie strsec, file, dyn->d_un.d_val); 9690Sstevel@tonic-gate } 9701618Srie Elf_syminfo_entry(0, ndx, info, name, needed); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate /* 9750Sstevel@tonic-gate * Print version definition section entries. 9760Sstevel@tonic-gate */ 9770Sstevel@tonic-gate static void 9784716Sab196087 version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache, 9790Sstevel@tonic-gate const char *file) 9800Sstevel@tonic-gate { 9811618Srie Word cnt; 9821618Srie char index[MAXNDXSIZE]; 9830Sstevel@tonic-gate 9841618Srie Elf_ver_def_title(0); 9850Sstevel@tonic-gate 9864716Sab196087 for (cnt = 1; cnt <= vdf_num; cnt++, 9871618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 9880Sstevel@tonic-gate const char *name, *dep; 9891618Srie Half vcnt = vdf->vd_cnt - 1; 9901618Srie Half ndx = vdf->vd_ndx; 9914433Sab196087 Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate /* 9940Sstevel@tonic-gate * Obtain the name and first dependency (if any). 9950Sstevel@tonic-gate */ 9960Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name); 9971618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9980Sstevel@tonic-gate if (vcnt) 9990Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name); 10000Sstevel@tonic-gate else 10010Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 10040Sstevel@tonic-gate EC_XWORD(ndx)); 10051618Srie Elf_ver_line_1(0, index, name, dep, 10061618Srie conv_ver_flags(vdf->vd_flags)); 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate /* 10090Sstevel@tonic-gate * Print any additional dependencies. 10100Sstevel@tonic-gate */ 10110Sstevel@tonic-gate if (vcnt) { 10121618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 10130Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 10141618Srie vdap = (Verdaux *)((uintptr_t)vdap + 10150Sstevel@tonic-gate vdap->vda_next)) { 10160Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 10170Sstevel@tonic-gate vdap->vda_name); 10181618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep); 10190Sstevel@tonic-gate } 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate /* 10254716Sab196087 * Print version needed section entries. 10264716Sab196087 * 10274716Sab196087 * entry: 10284716Sab196087 * vnd - Address of verneed data 10294716Sab196087 * vnd_num - # of Verneed entries 10304716Sab196087 * vcache - Cache of verneed section being processed 10314716Sab196087 * scache - Cache of associated string table section 10324716Sab196087 * file - Name of object being processed. 10334716Sab196087 * versym - Information about versym section 10344716Sab196087 * 10354716Sab196087 * exit: 10364716Sab196087 * The versions have been printed. If GNU style versioning 10374716Sab196087 * is in effect, versym->max_verndx has been updated to 10384716Sab196087 * contain the largest version index seen. 10390Sstevel@tonic-gate */ 10400Sstevel@tonic-gate static void 10414716Sab196087 version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache, 10424716Sab196087 const char *file, VERSYM_STATE *versym) 10430Sstevel@tonic-gate { 10444716Sab196087 Word cnt; 10454716Sab196087 char index[MAXNDXSIZE]; 10464716Sab196087 const char *index_str; 10474716Sab196087 10484716Sab196087 Elf_ver_need_title(0, versym->gnu); 10494716Sab196087 10504716Sab196087 /* 10514716Sab196087 * The versym section in an object that follows Solaris versioning 10524716Sab196087 * rules contains indexes into the verdef section. Symbols defined 10534716Sab196087 * in other objects (UNDEF) are given a version of 0, indicating that 10544716Sab196087 * they are not defined by this file, and the Verneed entries do not 10554716Sab196087 * have associated version indexes. For these reasons, we do not 10564716Sab196087 * display a version index for Solaris Verneed sections. 10574716Sab196087 * 10584716Sab196087 * The GNU versioning rules are different: Symbols defined in other 10594716Sab196087 * objects receive a version index in the range above those defined 10604716Sab196087 * by the Verdef section, and the vna_other field of the Vernaux 10614716Sab196087 * structs inside the Verneed section contain the version index for 10624716Sab196087 * that item. We therefore display the index when showing the 10634716Sab196087 * contents of a GNU Verneed section. You should not expect these 10644716Sab196087 * indexes to appear in sorted order --- it seems that the GNU ld 10654716Sab196087 * assigns the versions as symbols are encountered during linking, 10664716Sab196087 * and then the results are assembled into the Verneed section 10674716Sab196087 * afterwards. 10684716Sab196087 */ 10694716Sab196087 if (versym->gnu) { 10704716Sab196087 index_str = index; 10714716Sab196087 } else { 10724716Sab196087 /* For Solaris versioning, display a NULL string */ 10734716Sab196087 index_str = MSG_ORIG(MSG_STR_EMPTY); 10744716Sab196087 } 10754716Sab196087 10764716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 10771618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 10780Sstevel@tonic-gate const char *name, *dep; 10791618Srie Half vcnt = vnd->vn_cnt; 10804433Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate /* 10830Sstevel@tonic-gate * Obtain the name of the needed file and the version name 10840Sstevel@tonic-gate * within it that we're dependent on. Note that the count 10850Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus 10860Sstevel@tonic-gate * entry. 10870Sstevel@tonic-gate */ 10880Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file); 10890Sstevel@tonic-gate if (vcnt) 10900Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name); 10910Sstevel@tonic-gate else 10920Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL); 10930Sstevel@tonic-gate 10944716Sab196087 if (versym->gnu) { 10954716Sab196087 /* Format the version index value */ 10964716Sab196087 (void) snprintf(index, MAXNDXSIZE, 10974716Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(vnap->vna_other)); 10984716Sab196087 if (vnap->vna_other > versym->max_verndx) 10994716Sab196087 versym->max_verndx = vnap->vna_other; 11004716Sab196087 } 11014716Sab196087 Elf_ver_line_1(0, index_str, name, dep, 11021618Srie conv_ver_flags(vnap->vna_flags)); 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate /* 11050Sstevel@tonic-gate * Print any additional version dependencies. 11060Sstevel@tonic-gate */ 11070Sstevel@tonic-gate if (vcnt) { 11081618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 11090Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 11101618Srie vnap = (Vernaux *)((uintptr_t)vnap + 11110Sstevel@tonic-gate vnap->vna_next)) { 11120Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 11130Sstevel@tonic-gate vnap->vna_name); 11144716Sab196087 if (versym->gnu) { 11154716Sab196087 /* Format the next index value */ 11164716Sab196087 (void) snprintf(index, MAXNDXSIZE, 11174716Sab196087 MSG_ORIG(MSG_FMT_INDEX), 11184716Sab196087 EC_XWORD(vnap->vna_other)); 11194716Sab196087 Elf_ver_line_1(0, index_str, 11204716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 11214716Sab196087 conv_ver_flags(vnap->vna_flags)); 11224716Sab196087 if (vnap->vna_other > 11234716Sab196087 versym->max_verndx) 11244716Sab196087 versym->max_verndx = 11254716Sab196087 vnap->vna_other; 11264716Sab196087 } else { 11274716Sab196087 Elf_ver_line_3(0, 11284716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep, 11294716Sab196087 conv_ver_flags(vnap->vna_flags)); 11304716Sab196087 } 11314716Sab196087 } 11324716Sab196087 } 11334716Sab196087 } 11344716Sab196087 } 11354716Sab196087 11364716Sab196087 /* 11374716Sab196087 * Compute the max_verndx value for a GNU style object with 11384716Sab196087 * a Verneed section. This is only needed if version_need() is not 11394716Sab196087 * called. 11404716Sab196087 * 11414716Sab196087 * entry: 11424716Sab196087 * vnd - Address of verneed data 11434716Sab196087 * vnd_num - # of Verneed entries 11444716Sab196087 * versym - Information about versym section 11454716Sab196087 * 11464716Sab196087 * exit: 11474716Sab196087 * versym->max_verndx has been updated to contain the largest 11484716Sab196087 * version index seen. 11494716Sab196087 */ 11504716Sab196087 static void 11514716Sab196087 update_gnu_max_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym) 11524716Sab196087 { 11534716Sab196087 Word cnt; 11544716Sab196087 11554716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++, 11564716Sab196087 vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 11574716Sab196087 Half vcnt = vnd->vn_cnt; 11584716Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 11594716Sab196087 11604716Sab196087 if (vnap->vna_other > versym->max_verndx) 11614716Sab196087 versym->max_verndx = vnap->vna_other; 11624716Sab196087 11634716Sab196087 /* 11644716Sab196087 * Check any additional version dependencies. 11654716Sab196087 */ 11664716Sab196087 if (vcnt) { 11674716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 11684716Sab196087 for (vcnt--; vcnt; vcnt--, 11694716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + 11704716Sab196087 vnap->vna_next)) { 11714716Sab196087 if (vnap->vna_other > versym->max_verndx) 11724716Sab196087 versym->max_verndx = vnap->vna_other; 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate /* 11793875Sab196087 * Display version section information if the flags require it. 11803875Sab196087 * Return version information needed by other output. 11813875Sab196087 * 11823875Sab196087 * entry: 11833875Sab196087 * cache - Cache of all section headers 11843875Sab196087 * shnum - # of sections in cache 11853875Sab196087 * file - Name of file 11863875Sab196087 * flags - Command line option flags 11873875Sab196087 * versym - VERSYM_STATE block to be filled in. 11880Sstevel@tonic-gate */ 11893875Sab196087 static void 11903875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags, 11913875Sab196087 VERSYM_STATE *versym) 11920Sstevel@tonic-gate { 11930Sstevel@tonic-gate GElf_Word cnt; 11944716Sab196087 Cache *verdef_cache = NULL, *verneed_cache = NULL; 11954716Sab196087 11964716Sab196087 11974716Sab196087 /* Gather information about the version sections */ 11983875Sab196087 bzero(versym, sizeof (*versym)); 11994716Sab196087 versym->max_verndx = 1; 12000Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 12011618Srie Cache *_cache = &cache[cnt]; 12021618Srie Shdr *shdr = _cache->c_shdr; 12034716Sab196087 Dyn *dyn; 12044716Sab196087 ulong_t numdyn; 12054716Sab196087 12064716Sab196087 switch (shdr->sh_type) { 12074716Sab196087 case SHT_DYNAMIC: 12084716Sab196087 /* 12094716Sab196087 * The GNU ld puts a DT_VERSYM entry in the dynamic 12104716Sab196087 * section so that the runtime linker can use it to 12114716Sab196087 * implement their versioning rules. They allow multiple 12124716Sab196087 * incompatible functions with the same name to exist 12134716Sab196087 * in different versions. The Solaris ld does not 12144716Sab196087 * support this mechanism, and as such, does not 12154716Sab196087 * produce DT_VERSYM. We use this fact to determine 12164716Sab196087 * which ld produced this object, and how to interpret 12174716Sab196087 * the version values. 12184716Sab196087 */ 12194716Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0) || 12204716Sab196087 (_cache->c_data == NULL)) 12214716Sab196087 continue; 12224716Sab196087 numdyn = shdr->sh_size / shdr->sh_entsize; 12234716Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 12244716Sab196087 for (; numdyn-- > 0; dyn++) 12254716Sab196087 if (dyn->d_tag == DT_VERSYM) { 12264716Sab196087 versym->gnu = 1; 12274716Sab196087 break; 12284716Sab196087 } 12294716Sab196087 break; 12304716Sab196087 12314716Sab196087 case SHT_SUNW_versym: 12324716Sab196087 /* Record data address for later symbol processing */ 12334716Sab196087 if (_cache->c_data != NULL) { 12344716Sab196087 versym->cache = _cache; 12354716Sab196087 versym->data = _cache->c_data->d_buf; 12364716Sab196087 continue; 12374716Sab196087 } 12384716Sab196087 break; 12394716Sab196087 12404716Sab196087 case SHT_SUNW_verdef: 12414716Sab196087 case SHT_SUNW_verneed: 12424716Sab196087 /* 12434716Sab196087 * Ensure the data is non-NULL and the number 12444716Sab196087 * of items is non-zero. Otherwise, we don't 12454716Sab196087 * understand the section, and will not use it. 12464716Sab196087 */ 12474716Sab196087 if ((_cache->c_data == NULL) || 12484716Sab196087 (_cache->c_data->d_buf == NULL)) { 12494716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 12504716Sab196087 file, _cache->c_name); 12514716Sab196087 continue; 12524716Sab196087 } 12534716Sab196087 if (shdr->sh_info == 0) { 12544716Sab196087 (void) fprintf(stderr, 12554716Sab196087 MSG_INTL(MSG_ERR_BADSHINFO), 12564716Sab196087 file, _cache->c_name, 12574716Sab196087 EC_WORD(shdr->sh_info)); 12584716Sab196087 continue; 12594716Sab196087 } 12604716Sab196087 12614716Sab196087 /* Make sure the string table index is in range */ 12624716Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 12634716Sab196087 (void) fprintf(stderr, 12644716Sab196087 MSG_INTL(MSG_ERR_BADSHLINK), file, 12654716Sab196087 _cache->c_name, EC_WORD(shdr->sh_link)); 12664716Sab196087 continue; 12674716Sab196087 } 12684716Sab196087 12694716Sab196087 /* 12704716Sab196087 * The section is usable. Save the cache entry. 12714716Sab196087 */ 12724716Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) { 12734716Sab196087 verdef_cache = _cache; 12744716Sab196087 /* 12754716Sab196087 * Under Solaris rules, if there is a verdef 12764716Sab196087 * section, the max versym index is number 12774716Sab196087 * of version definitions it supplies. 12784716Sab196087 */ 12794716Sab196087 versym->max_verndx = shdr->sh_info; 12804716Sab196087 } else { 12814716Sab196087 verneed_cache = _cache; 12824716Sab196087 } 12834716Sab196087 break; 12844716Sab196087 } 12854716Sab196087 } 12864716Sab196087 12875411Sab196087 if ((flags & FLG_SHOW_VERSIONS) == 0) { 12883875Sab196087 /* 12894716Sab196087 * If GNU versioning applies to this object, and there 12904716Sab196087 * is a Verneed section, then examine it to determine 12914716Sab196087 * the maximum Versym version index for this file. 12923875Sab196087 */ 12934716Sab196087 if ((versym->gnu) && (verneed_cache != NULL)) 12944716Sab196087 update_gnu_max_verndx( 12954716Sab196087 (Verneed *)verneed_cache->c_data->d_buf, 12964716Sab196087 verneed_cache->c_shdr->sh_info, versym); 12974716Sab196087 return; 12984716Sab196087 } 12994716Sab196087 13004716Sab196087 /* 13014716Sab196087 * Now that all the information is available, display the 13024716Sab196087 * Verdef and Verneed section contents. 13034716Sab196087 */ 13044716Sab196087 if (verdef_cache != NULL) { 13054716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 13064716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), 13074716Sab196087 verdef_cache->c_name); 13084716Sab196087 version_def((Verdef *)verdef_cache->c_data->d_buf, 13094716Sab196087 verdef_cache->c_shdr->sh_info, verdef_cache, 13104716Sab196087 &cache[verdef_cache->c_shdr->sh_link], file); 13114716Sab196087 } 13124716Sab196087 if (verneed_cache != NULL) { 13134716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 13144716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), 13154716Sab196087 verneed_cache->c_name); 13160Sstevel@tonic-gate /* 13174716Sab196087 * If GNU versioning applies to this object, version_need() 13184716Sab196087 * will update versym->max_verndx, and it is not 13194716Sab196087 * necessary to call update_gnu_max_verndx(). 13200Sstevel@tonic-gate */ 13214716Sab196087 version_need((Verneed *)verneed_cache->c_data->d_buf, 13224716Sab196087 verneed_cache->c_shdr->sh_info, verneed_cache, 13234716Sab196087 &cache[verneed_cache->c_shdr->sh_link], file, versym); 13240Sstevel@tonic-gate } 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate /* 13283492Sab196087 * Initialize a symbol table state structure 13293492Sab196087 * 13303492Sab196087 * entry: 13313492Sab196087 * state - State structure to be initialized 13323492Sab196087 * cache - Cache of all section headers 13333492Sab196087 * shnum - # of sections in cache 13343492Sab196087 * secndx - Index of symbol table section 13353492Sab196087 * ehdr - ELF header for file 13363875Sab196087 * versym - Information about versym section 13373492Sab196087 * file - Name of file 13383492Sab196087 * flags - Command line option flags 13391618Srie */ 13401618Srie static int 13413492Sab196087 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx, 13423875Sab196087 Ehdr *ehdr, VERSYM_STATE *versym, const char *file, uint_t flags) 13433492Sab196087 { 13443492Sab196087 Shdr *shdr; 13453492Sab196087 13463492Sab196087 state->file = file; 13473492Sab196087 state->ehdr = ehdr; 13483492Sab196087 state->cache = cache; 13493492Sab196087 state->shnum = shnum; 13503492Sab196087 state->seccache = &cache[secndx]; 13513492Sab196087 state->secndx = secndx; 13523492Sab196087 state->secname = state->seccache->c_name; 13533492Sab196087 state->flags = flags; 13543492Sab196087 state->shxndx.checked = 0; 13553492Sab196087 state->shxndx.data = NULL; 13563492Sab196087 state->shxndx.n = 0; 13573492Sab196087 13583492Sab196087 shdr = state->seccache->c_shdr; 13593492Sab196087 13603492Sab196087 /* 13613492Sab196087 * Check the symbol data and per-item size. 13623492Sab196087 */ 13633492Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 13643492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 13653492Sab196087 file, state->secname); 13663492Sab196087 return (0); 13673492Sab196087 } 13683492Sab196087 if (state->seccache->c_data == NULL) 13693492Sab196087 return (0); 13703492Sab196087 13713492Sab196087 /* LINTED */ 13723492Sab196087 state->symn = (Word)(shdr->sh_size / shdr->sh_entsize); 13733492Sab196087 state->sym = (Sym *)state->seccache->c_data->d_buf; 13743492Sab196087 13753492Sab196087 /* 13763492Sab196087 * Check associated string table section. 13773492Sab196087 */ 13783492Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 13793492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 13803492Sab196087 file, state->secname, EC_WORD(shdr->sh_link)); 13813492Sab196087 return (0); 13823492Sab196087 } 13833492Sab196087 13843492Sab196087 /* 13853492Sab196087 * Determine if there is a associated Versym section 13863492Sab196087 * with this Symbol Table. 13873492Sab196087 */ 13883875Sab196087 if (versym->cache && 13893875Sab196087 (versym->cache->c_shdr->sh_link == state->secndx)) 13903875Sab196087 state->versym = versym; 13913492Sab196087 else 13923492Sab196087 state->versym = NULL; 13933492Sab196087 13943492Sab196087 13953492Sab196087 return (1); 13963492Sab196087 } 13973492Sab196087 13983492Sab196087 /* 13993492Sab196087 * Determine the extended section index used for symbol tables entries. 14003492Sab196087 */ 14013492Sab196087 static void 14023492Sab196087 symbols_getxindex(SYMTBL_STATE * state) 14031618Srie { 14041618Srie uint_t symn; 14051618Srie Word symcnt; 14061618Srie 14073492Sab196087 state->shxndx.checked = 1; /* Note that we've been called */ 14083492Sab196087 for (symcnt = 1; symcnt < state->shnum; symcnt++) { 14093492Sab196087 Cache *_cache = &state->cache[symcnt]; 14101618Srie Shdr *shdr = _cache->c_shdr; 14111618Srie 14121618Srie if ((shdr->sh_type != SHT_SYMTAB_SHNDX) || 14133492Sab196087 (shdr->sh_link != state->secndx)) 14141618Srie continue; 14151618Srie 14161618Srie if ((shdr->sh_entsize) && 14171618Srie /* LINTED */ 14181618Srie ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0)) 14191618Srie continue; 14201618Srie 14213466Srie if (_cache->c_data == NULL) 14223466Srie continue; 14233466Srie 14243492Sab196087 state->shxndx.data = _cache->c_data->d_buf; 14253492Sab196087 state->shxndx.n = symn; 14263492Sab196087 return; 14271618Srie } 14281618Srie } 14291618Srie 14301618Srie /* 14313492Sab196087 * Produce a line of output for the given symbol 14323492Sab196087 * 14333492Sab196087 * entry: 14343875Sab196087 * state - Symbol table state 14353492Sab196087 * symndx - Index of symbol within the table 14364832Srie * info - Value of st_info (indicates local/global range) 14373492Sab196087 * symndx_disp - Index to display. This may not be the same 14383492Sab196087 * as symndx if the display is relative to the logical 14393492Sab196087 * combination of the SUNW_ldynsym/dynsym tables. 14403492Sab196087 * sym - Symbol to display 14410Sstevel@tonic-gate */ 14423492Sab196087 static void 14434832Srie output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx, 14444832Srie Sym *sym) 14450Sstevel@tonic-gate { 14463118Sab196087 /* 14473118Sab196087 * Symbol types for which we check that the specified 14483118Sab196087 * address/size land inside the target section. 14493118Sab196087 */ 14503492Sab196087 static const int addr_symtype[STT_NUM] = { 14513118Sab196087 0, /* STT_NOTYPE */ 14523118Sab196087 1, /* STT_OBJECT */ 14533118Sab196087 1, /* STT_FUNC */ 14543118Sab196087 0, /* STT_SECTION */ 14553118Sab196087 0, /* STT_FILE */ 14563118Sab196087 1, /* STT_COMMON */ 14573118Sab196087 0, /* STT_TLS */ 14583118Sab196087 }; 14593118Sab196087 #if STT_NUM != (STT_TLS + 1) 14603492Sab196087 #error "STT_NUM has grown. Update addr_symtype[]" 14613118Sab196087 #endif 14623118Sab196087 14634665Sab196087 char index[MAXNDXSIZE]; 14644665Sab196087 const char *symname, *sec; 14653875Sab196087 Versym verndx; 14664716Sab196087 int gnuver; 14673492Sab196087 uchar_t type; 14683492Sab196087 Shdr *tshdr; 14693492Sab196087 Word shndx; 14704734Sab196087 Conv_inv_buf_t inv_buf; 14713492Sab196087 14723492Sab196087 /* Ensure symbol index is in range */ 14733492Sab196087 if (symndx >= state->symn) { 14743492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX), 14753492Sab196087 state->file, state->secname, EC_WORD(symndx)); 14763492Sab196087 return; 14773492Sab196087 } 14783492Sab196087 14793492Sab196087 /* 14803492Sab196087 * If we are using extended symbol indexes, find the 14813492Sab196087 * corresponding SHN_SYMTAB_SHNDX table. 14823492Sab196087 */ 14833492Sab196087 if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0)) 14843492Sab196087 symbols_getxindex(state); 14853492Sab196087 14863492Sab196087 /* LINTED */ 14873492Sab196087 symname = string(state->seccache, symndx, 14883492Sab196087 &state->cache[state->seccache->c_shdr->sh_link], state->file, 14893492Sab196087 sym->st_name); 14903492Sab196087 14913492Sab196087 tshdr = 0; 14923492Sab196087 sec = NULL; 14933492Sab196087 14944665Sab196087 if (state->ehdr->e_type == ET_CORE) { 14953492Sab196087 sec = (char *)MSG_INTL(MSG_STR_UNKNOWN); 14965411Sab196087 } else if (state->flags & FLG_CTL_FAKESHDR) { 14974665Sab196087 /* 14984665Sab196087 * If we are using fake section headers derived from 14994665Sab196087 * the program headers, then the section indexes 15004665Sab196087 * in the symbols do not correspond to these headers. 15014665Sab196087 * The section names are not available, so all we can 15024665Sab196087 * do is to display them in numeric form. 15034665Sab196087 */ 15044734Sab196087 sec = conv_sym_shndx(sym->st_shndx, &inv_buf); 15054665Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 15063492Sab196087 (sym->st_shndx < state->shnum)) { 15073492Sab196087 shndx = sym->st_shndx; 15083492Sab196087 tshdr = state->cache[shndx].c_shdr; 15093492Sab196087 sec = state->cache[shndx].c_name; 15103492Sab196087 } else if (sym->st_shndx == SHN_XINDEX) { 15113492Sab196087 if (state->shxndx.data) { 15123492Sab196087 Word _shxndx; 15133492Sab196087 15143492Sab196087 if (symndx > state->shxndx.n) { 15154433Sab196087 (void) fprintf(stderr, 15164433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 15174433Sab196087 state->file, state->secname, 15184433Sab196087 EC_WORD(symndx)); 15193492Sab196087 } else if ((_shxndx = 15203492Sab196087 state->shxndx.data[symndx]) > state->shnum) { 15214433Sab196087 (void) fprintf(stderr, 15224433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 15234433Sab196087 state->file, state->secname, 15244433Sab196087 EC_WORD(symndx), EC_WORD(_shxndx)); 15253492Sab196087 } else { 15264433Sab196087 shndx = _shxndx; 15274433Sab196087 tshdr = state->cache[shndx].c_shdr; 15284433Sab196087 sec = state->cache[shndx].c_name; 15293492Sab196087 } 15303492Sab196087 } else { 15313492Sab196087 (void) fprintf(stderr, 15323492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 15333492Sab196087 state->file, state->secname, EC_WORD(symndx)); 15343492Sab196087 } 15353492Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 15363492Sab196087 (sym->st_shndx >= state->shnum)) { 15373492Sab196087 (void) fprintf(stderr, 15383492Sab196087 MSG_INTL(MSG_ERR_BADSYM5), state->file, 15396206Sab196087 state->secname, EC_WORD(symndx), 15406206Sab196087 demangle(symname, state->flags), sym->st_shndx); 15413492Sab196087 } 15420Sstevel@tonic-gate 15433492Sab196087 /* 15443492Sab196087 * If versioning is available display the 15453875Sab196087 * version index. If not, then use 0. 15463492Sab196087 */ 15473875Sab196087 if (state->versym) { 15484716Sab196087 Versym test_verndx; 15494716Sab196087 15504716Sab196087 verndx = test_verndx = state->versym->data[symndx]; 15514716Sab196087 gnuver = state->versym->gnu; 15523875Sab196087 15533875Sab196087 /* 15543875Sab196087 * Check to see if this is a defined symbol with a 15553875Sab196087 * version index that is outside the valid range for 15564716Sab196087 * the file. The interpretation of this depends on 15574716Sab196087 * the style of versioning used by the object. 15583875Sab196087 * 15594716Sab196087 * Versions >= VER_NDX_LORESERVE have special meanings, 15604716Sab196087 * and are exempt from this checking. 15614716Sab196087 * 15624716Sab196087 * GNU style version indexes use the top bit of the 15634716Sab196087 * 16-bit index value (0x8000) as the "hidden bit". 15644716Sab196087 * We must mask off this bit in order to compare 15654716Sab196087 * the version against the maximum value. 15663875Sab196087 */ 15674716Sab196087 if (gnuver) 15684716Sab196087 test_verndx &= ~0x8000; 15694716Sab196087 15704716Sab196087 if ((test_verndx > state->versym->max_verndx) && 15714716Sab196087 (verndx < VER_NDX_LORESERVE)) 15724716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER), 15734716Sab196087 state->file, state->secname, EC_WORD(symndx), 15744716Sab196087 EC_HALF(test_verndx), state->versym->max_verndx); 15753875Sab196087 } else { 15763492Sab196087 verndx = 0; 15774716Sab196087 gnuver = 0; 15783875Sab196087 } 15793492Sab196087 15803492Sab196087 /* 15813492Sab196087 * Error checking for TLS. 15823492Sab196087 */ 15833492Sab196087 type = ELF_ST_TYPE(sym->st_info); 15843492Sab196087 if (type == STT_TLS) { 15853492Sab196087 if (tshdr && 15863492Sab196087 (sym->st_shndx != SHN_UNDEF) && 15873492Sab196087 ((tshdr->sh_flags & SHF_TLS) == 0)) { 15883492Sab196087 (void) fprintf(stderr, 15893492Sab196087 MSG_INTL(MSG_ERR_BADSYM3), state->file, 15906206Sab196087 state->secname, EC_WORD(symndx), 15916206Sab196087 demangle(symname, state->flags)); 15923492Sab196087 } 15933492Sab196087 } else if ((type != STT_SECTION) && sym->st_size && 15943492Sab196087 tshdr && (tshdr->sh_flags & SHF_TLS)) { 15953492Sab196087 (void) fprintf(stderr, 15963492Sab196087 MSG_INTL(MSG_ERR_BADSYM4), state->file, 15976206Sab196087 state->secname, EC_WORD(symndx), 15986206Sab196087 demangle(symname, state->flags)); 15993492Sab196087 } 16003492Sab196087 16013492Sab196087 /* 16023492Sab196087 * If a symbol with non-zero size has a type that 16033492Sab196087 * specifies an address, then make sure the location 16043492Sab196087 * it references is actually contained within the 16053492Sab196087 * section. UNDEF symbols don't count in this case, 16063492Sab196087 * so we ignore them. 16073492Sab196087 * 16083492Sab196087 * The meaning of the st_value field in a symbol 16093492Sab196087 * depends on the type of object. For a relocatable 16103492Sab196087 * object, it is the offset within the section. 16113492Sab196087 * For sharable objects, it is the offset relative to 16123492Sab196087 * the base of the object, and for other types, it is 16133492Sab196087 * the virtual address. To get an offset within the 16143492Sab196087 * section for non-ET_REL files, we subtract the 16153492Sab196087 * base address of the section. 16163492Sab196087 */ 16173492Sab196087 if (addr_symtype[type] && (sym->st_size > 0) && 16183492Sab196087 (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) || 16193492Sab196087 (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) { 16203492Sab196087 Word v = sym->st_value; 16213492Sab196087 if (state->ehdr->e_type != ET_REL) 16224832Srie v -= tshdr->sh_addr; 16233492Sab196087 if (((v + sym->st_size) > tshdr->sh_size)) { 16243492Sab196087 (void) fprintf(stderr, 16253492Sab196087 MSG_INTL(MSG_ERR_BADSYM6), state->file, 16266206Sab196087 state->secname, EC_WORD(symndx), 16276206Sab196087 demangle(symname, state->flags), 16283492Sab196087 EC_WORD(shndx), EC_XWORD(tshdr->sh_size), 16293492Sab196087 EC_XWORD(sym->st_value), EC_XWORD(sym->st_size)); 16303492Sab196087 } 16313492Sab196087 } 16323492Sab196087 16334832Srie /* 16344832Srie * A typical symbol table uses the sh_info field to indicate one greater 16354832Srie * than the symbol table index of the last local symbol, STB_LOCAL. 16364832Srie * Therefore, symbol indexes less than sh_info should have local 16374832Srie * binding. Symbol indexes greater than, or equal to sh_info, should 16384832Srie * have global binding. Note, we exclude UNDEF/NOTY symbols with zero 16394832Srie * value and size, as these symbols may be the result of an mcs(1) 16404832Srie * section deletion. 16414832Srie */ 16424832Srie if (info) { 16434832Srie uchar_t bind = ELF_ST_BIND(sym->st_info); 16444832Srie 16454832Srie if ((symndx < info) && (bind != STB_LOCAL)) { 16464832Srie (void) fprintf(stderr, 16474832Srie MSG_INTL(MSG_ERR_BADSYM7), state->file, 16486206Sab196087 state->secname, EC_WORD(symndx), 16496206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 16504832Srie 16514832Srie } else if ((symndx >= info) && (bind == STB_LOCAL) && 16524832Srie ((sym->st_shndx != SHN_UNDEF) || 16534832Srie (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) || 16544832Srie (sym->st_size != 0) || (sym->st_value != 0))) { 16554832Srie (void) fprintf(stderr, 16564832Srie MSG_INTL(MSG_ERR_BADSYM8), state->file, 16576206Sab196087 state->secname, EC_WORD(symndx), 16586206Sab196087 demangle(symname, state->flags), EC_XWORD(info)); 16594832Srie } 16604832Srie } 16614832Srie 16623492Sab196087 (void) snprintf(index, MAXNDXSIZE, 16633492Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx)); 16643492Sab196087 Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, 16654716Sab196087 state->ehdr->e_machine, sym, verndx, gnuver, sec, symname); 16663492Sab196087 } 16673492Sab196087 16683492Sab196087 /* 16693492Sab196087 * Search for and process any symbol tables. 16703492Sab196087 */ 16713492Sab196087 void 16724168Sab196087 symbols(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 16734168Sab196087 const char *file, uint_t flags) 16743492Sab196087 { 16753492Sab196087 SYMTBL_STATE state; 16763492Sab196087 Cache *_cache; 16773492Sab196087 Word secndx; 16783492Sab196087 16793492Sab196087 for (secndx = 1; secndx < shnum; secndx++) { 16803492Sab196087 Word symcnt; 16813492Sab196087 Shdr *shdr; 16823492Sab196087 16833492Sab196087 _cache = &cache[secndx]; 16843492Sab196087 shdr = _cache->c_shdr; 16850Sstevel@tonic-gate 16860Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) && 16872766Sab196087 (shdr->sh_type != SHT_DYNSYM) && 16882766Sab196087 (shdr->sh_type != SHT_SUNW_LDYNSYM)) 16890Sstevel@tonic-gate continue; 16905411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, secndx, shdr->sh_type)) 16913466Srie continue; 16923466Srie 16933492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr, 16943875Sab196087 versym, file, flags)) 16950Sstevel@tonic-gate continue; 16960Sstevel@tonic-gate /* 16970Sstevel@tonic-gate * Loop through the symbol tables entries. 16980Sstevel@tonic-gate */ 16991618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17003492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname); 17011618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 17020Sstevel@tonic-gate 17033492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++) 17044832Srie output_symbol(&state, symcnt, shdr->sh_info, symcnt, 17053492Sab196087 state.sym + symcnt); 17063492Sab196087 } 17073492Sab196087 } 17080Sstevel@tonic-gate 17093492Sab196087 /* 17103492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections. 17113492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair. 17123492Sab196087 */ 17133492Sab196087 static void 17144168Sab196087 sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 17154168Sab196087 const char *file, uint_t flags) 17163492Sab196087 { 17173492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state; 17183492Sab196087 Cache *sortcache, *symcache; 17193492Sab196087 Shdr *sortshdr, *symshdr; 17203492Sab196087 Word sortsecndx, symsecndx; 17213492Sab196087 Word ldynsym_cnt; 17223492Sab196087 Word *ndx; 17233492Sab196087 Word ndxn; 17243492Sab196087 int output_cnt = 0; 17254734Sab196087 Conv_inv_buf_t inv_buf; 17260Sstevel@tonic-gate 17273492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) { 17280Sstevel@tonic-gate 17293492Sab196087 sortcache = &cache[sortsecndx]; 17303492Sab196087 sortshdr = sortcache->c_shdr; 17310Sstevel@tonic-gate 17323492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) && 17333492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort)) 17343492Sab196087 continue; 17355411Sab196087 if (!match(MATCH_F_ALL, sortcache->c_name, sortsecndx, 17365411Sab196087 sortshdr->sh_type)) 17373492Sab196087 continue; 17380Sstevel@tonic-gate 17393492Sab196087 /* 17403492Sab196087 * If the section references a SUNW_ldynsym, then we 17413492Sab196087 * expect to see the associated .dynsym immediately 17423492Sab196087 * following. If it references a .dynsym, there is no 17433492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't 17443492Sab196087 * know what to do with it. 17453492Sab196087 */ 17463492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) { 17473492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 17483492Sab196087 file, sortcache->c_name, 17493492Sab196087 EC_WORD(sortshdr->sh_link)); 17503492Sab196087 continue; 17513492Sab196087 } 17523492Sab196087 symcache = &cache[sortshdr->sh_link]; 17533492Sab196087 symshdr = symcache->c_shdr; 17543492Sab196087 symsecndx = sortshdr->sh_link; 17553492Sab196087 ldynsym_cnt = 0; 17563492Sab196087 switch (symshdr->sh_type) { 17573492Sab196087 case SHT_SUNW_LDYNSYM: 17583492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum, 17593875Sab196087 symsecndx, ehdr, versym, file, flags)) 17603492Sab196087 continue; 17613492Sab196087 ldynsym_cnt = ldynsym_state.symn; 17620Sstevel@tonic-gate /* 17633492Sab196087 * We know that the dynsym follows immediately 17643492Sab196087 * after the SUNW_ldynsym, and so, should be at 17653492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a 17663492Sab196087 * diagnostic tool, so we do the full paranoid 17673492Sab196087 * search instead. 17680Sstevel@tonic-gate */ 17693492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) { 17703492Sab196087 symcache = &cache[symsecndx]; 17713492Sab196087 symshdr = symcache->c_shdr; 17723492Sab196087 if (symshdr->sh_type == SHT_DYNSYM) 17733492Sab196087 break; 17743492Sab196087 } 17753492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */ 17760Sstevel@tonic-gate (void) fprintf(stderr, 17773492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM), 17783492Sab196087 file, sortcache->c_name); 17793492Sab196087 continue; 17800Sstevel@tonic-gate } 17813492Sab196087 /* Fallthrough to process associated dynsym */ 17823492Sab196087 /*FALLTHROUGH*/ 17833492Sab196087 case SHT_DYNSYM: 17843492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum, 17853875Sab196087 symsecndx, ehdr, versym, file, flags)) 17863492Sab196087 continue; 17873492Sab196087 break; 17883492Sab196087 default: 17893492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC), 17903492Sab196087 file, sortcache->c_name, conv_sec_type( 17914734Sab196087 ehdr->e_machine, symshdr->sh_type, 0, &inv_buf)); 17923492Sab196087 continue; 17933492Sab196087 } 17940Sstevel@tonic-gate 17953492Sab196087 /* 17963492Sab196087 * Output header 17973492Sab196087 */ 17983492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17993492Sab196087 if (ldynsym_cnt > 0) { 18003492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2), 18013492Sab196087 sortcache->c_name, ldynsym_state.secname, 18023492Sab196087 dynsym_state.secname); 18030Sstevel@tonic-gate /* 18043492Sab196087 * The data for .SUNW_ldynsym and dynsym sections 18053492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming 18063492Sab196087 * first. Check, and issue a warning if it isn't so. 18070Sstevel@tonic-gate */ 18084665Sab196087 if (((ldynsym_state.sym + ldynsym_state.symn) 18094665Sab196087 != dynsym_state.sym) && 18105411Sab196087 ((flags & FLG_CTL_FAKESHDR) == 0)) 18113492Sab196087 (void) fprintf(stderr, 18123492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file, 18133492Sab196087 ldynsym_state.secname, 18143492Sab196087 dynsym_state.secname); 18153492Sab196087 } else { 18163492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1), 18173492Sab196087 sortcache->c_name, dynsym_state.secname); 18183492Sab196087 } 18193492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 18203492Sab196087 18213492Sab196087 /* If not first one, insert a line of whitespace */ 18223492Sab196087 if (output_cnt++ > 0) 18233492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 18243118Sab196087 18253492Sab196087 /* 18263492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of 18273492Sab196087 * symbol indices. Iterate over the array entries, 18283492Sab196087 * dispaying the referenced symbols. 18293492Sab196087 */ 18303492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize; 18313492Sab196087 ndx = (Word *)sortcache->c_data->d_buf; 18323492Sab196087 for (; ndxn-- > 0; ndx++) { 18333492Sab196087 if (*ndx >= ldynsym_cnt) { 18343492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt; 18353492Sab196087 18364832Srie output_symbol(&dynsym_state, sec_ndx, 0, 18373492Sab196087 *ndx, dynsym_state.sym + sec_ndx); 18383492Sab196087 } else { 18394832Srie output_symbol(&ldynsym_state, *ndx, 0, 18403492Sab196087 *ndx, ldynsym_state.sym + *ndx); 18410Sstevel@tonic-gate } 18420Sstevel@tonic-gate } 18430Sstevel@tonic-gate } 18440Sstevel@tonic-gate } 18450Sstevel@tonic-gate 18460Sstevel@tonic-gate /* 18470Sstevel@tonic-gate * Search for and process any relocation sections. 18480Sstevel@tonic-gate */ 18490Sstevel@tonic-gate static void 18504168Sab196087 reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *file, 18511618Srie uint_t flags) 18520Sstevel@tonic-gate { 18531618Srie Word cnt; 18540Sstevel@tonic-gate 18550Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 18561618Srie Word type, symnum; 18571618Srie Xword relndx, relnum, relsize; 18581618Srie void *rels; 18591618Srie Sym *syms; 18601618Srie Cache *symsec, *strsec; 18610Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 18621618Srie Shdr *shdr = _cache->c_shdr; 18631618Srie char *relname = _cache->c_name; 18644734Sab196087 Conv_inv_buf_t inv_buf; 18650Sstevel@tonic-gate 18660Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) && 18670Sstevel@tonic-gate (type != SHT_REL)) 18680Sstevel@tonic-gate continue; 18695411Sab196087 if (!match(MATCH_F_ALL, relname, cnt, type)) 18700Sstevel@tonic-gate continue; 18710Sstevel@tonic-gate 18720Sstevel@tonic-gate /* 18731618Srie * Decide entry size. 18740Sstevel@tonic-gate */ 18751618Srie if (((relsize = shdr->sh_entsize) == 0) || 18761618Srie (relsize > shdr->sh_size)) { 18770Sstevel@tonic-gate if (type == SHT_RELA) 18781618Srie relsize = sizeof (Rela); 18790Sstevel@tonic-gate else 18801618Srie relsize = sizeof (Rel); 18810Sstevel@tonic-gate } 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate /* 18840Sstevel@tonic-gate * Determine the number of relocations available. 18850Sstevel@tonic-gate */ 18860Sstevel@tonic-gate if (shdr->sh_size == 0) { 18870Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 18881618Srie file, relname); 18890Sstevel@tonic-gate continue; 18900Sstevel@tonic-gate } 18913466Srie if (_cache->c_data == NULL) 18923466Srie continue; 18933466Srie 18941618Srie rels = _cache->c_data->d_buf; 18951618Srie relnum = shdr->sh_size / relsize; 18960Sstevel@tonic-gate 18970Sstevel@tonic-gate /* 18981618Srie * Get the data buffer for the associated symbol table and 18991618Srie * string table. 19000Sstevel@tonic-gate */ 19011618Srie if (stringtbl(cache, 1, cnt, shnum, file, 19021618Srie &symnum, &symsec, &strsec) == 0) 19030Sstevel@tonic-gate continue; 19041618Srie 19051618Srie syms = symsec->c_data->d_buf; 19060Sstevel@tonic-gate 19070Sstevel@tonic-gate /* 19080Sstevel@tonic-gate * Loop through the relocation entries. 19090Sstevel@tonic-gate */ 19101618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 19111618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 19121618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type); 19130Sstevel@tonic-gate 19141618Srie for (relndx = 0; relndx < relnum; relndx++, 19151618Srie rels = (void *)((char *)rels + relsize)) { 19166206Sab196087 Half mach = ehdr->e_machine; 19170Sstevel@tonic-gate char section[BUFSIZ]; 19181618Srie const char *symname; 19191618Srie Word symndx, reltype; 19201618Srie Rela *rela; 19211618Srie Rel *rel; 19220Sstevel@tonic-gate 19230Sstevel@tonic-gate /* 19241618Srie * Unravel the relocation and determine the symbol with 19251618Srie * which this relocation is associated. 19260Sstevel@tonic-gate */ 19270Sstevel@tonic-gate if (type == SHT_RELA) { 19281618Srie rela = (Rela *)rels; 19291618Srie symndx = ELF_R_SYM(rela->r_info); 19306206Sab196087 reltype = ELF_R_TYPE(rela->r_info, mach); 19310Sstevel@tonic-gate } else { 19321618Srie rel = (Rel *)rels; 19331618Srie symndx = ELF_R_SYM(rel->r_info); 19346206Sab196087 reltype = ELF_R_TYPE(rel->r_info, mach); 19350Sstevel@tonic-gate } 19361618Srie 19371618Srie symname = relsymname(cache, _cache, strsec, symndx, 19381618Srie symnum, relndx, syms, section, BUFSIZ, file, 19391618Srie flags); 19401618Srie 19411618Srie /* 19421618Srie * A zero symbol index is only valid for a few 19431618Srie * relocations. 19441618Srie */ 19451618Srie if (symndx == 0) { 19461618Srie int badrel = 0; 19470Sstevel@tonic-gate 19481618Srie if ((mach == EM_SPARC) || 19491618Srie (mach == EM_SPARC32PLUS) || 19501618Srie (mach == EM_SPARCV9)) { 19511618Srie if ((reltype != R_SPARC_NONE) && 19521618Srie (reltype != R_SPARC_REGISTER) && 19531618Srie (reltype != R_SPARC_RELATIVE)) 19541618Srie badrel++; 19551618Srie } else if (mach == EM_386) { 19561618Srie if ((reltype != R_386_NONE) && 19571618Srie (reltype != R_386_RELATIVE)) 19581618Srie badrel++; 19591618Srie } else if (mach == EM_AMD64) { 19601618Srie if ((reltype != R_AMD64_NONE) && 19611618Srie (reltype != R_AMD64_RELATIVE)) 19621618Srie badrel++; 19631618Srie } 19641618Srie 19651618Srie if (badrel) { 19661618Srie (void) fprintf(stderr, 19671618Srie MSG_INTL(MSG_ERR_BADREL1), file, 19684734Sab196087 conv_reloc_type(mach, reltype, 19694734Sab196087 0, &inv_buf)); 19700Sstevel@tonic-gate } 19710Sstevel@tonic-gate } 19720Sstevel@tonic-gate 19731618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP, 19741618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type, 19751618Srie rels, relname, symname, 0); 19760Sstevel@tonic-gate } 19770Sstevel@tonic-gate } 19780Sstevel@tonic-gate } 19790Sstevel@tonic-gate 19805230Sab196087 19815230Sab196087 /* 19825230Sab196087 * This value controls which test dyn_test() performs. 19835230Sab196087 */ 19845230Sab196087 typedef enum { DYN_TEST_ADDR, DYN_TEST_SIZE, DYN_TEST_ENTSIZE } dyn_test_t; 19855230Sab196087 19865230Sab196087 /* 19875230Sab196087 * Used by dynamic() to compare the value of a dynamic element against 19885230Sab196087 * the starting address of the section it references. 19895230Sab196087 * 19905230Sab196087 * entry: 19915230Sab196087 * test_type - Specify which dyn item is being tested. 19925230Sab196087 * sh_type - SHT_* type value for required section. 19935230Sab196087 * sec_cache - Cache entry for section, or NULL if the object lacks 19945230Sab196087 * a section of this type. 19955230Sab196087 * dyn - Dyn entry to be tested 19965230Sab196087 * dynsec_cnt - # of dynamic section being examined. The first 19975230Sab196087 * dynamic section is 1, the next is 2, and so on... 19985230Sab196087 * ehdr - ELF header for file 19995230Sab196087 * file - Name of file 20005230Sab196087 */ 20015230Sab196087 static void 20025230Sab196087 dyn_test(dyn_test_t test_type, Word sh_type, Cache *sec_cache, Dyn *dyn, 20035230Sab196087 Word dynsec_cnt, Ehdr *ehdr, const char *file) 20045230Sab196087 { 20055230Sab196087 Conv_inv_buf_t buf1, buf2; 20065230Sab196087 20075230Sab196087 /* 20085230Sab196087 * These tests are based around the implicit assumption that 20095230Sab196087 * there is only one dynamic section in an object, and also only 20105230Sab196087 * one of the sections it references. We have therefore gathered 20115230Sab196087 * all of the necessary information to test this in a single pass 20125230Sab196087 * over the section headers, which is very efficient. We are not 20135230Sab196087 * aware of any case where more than one dynamic section would 20145230Sab196087 * be meaningful in an ELF object, so this is a reasonable solution. 20155230Sab196087 * 20165230Sab196087 * To test multiple dynamic sections correctly would be more 20175230Sab196087 * expensive in code and time. We would have to build a data structure 20185230Sab196087 * containing all the dynamic elements. Then, we would use the address 20195230Sab196087 * to locate the section it references and ensure the section is of 20205230Sab196087 * the right type and that the address in the dynamic element is 20215230Sab196087 * to the start of the section. Then, we could check the size and 20225230Sab196087 * entsize values against those same sections. This is O(n^2), and 20235230Sab196087 * also complicated. 20245230Sab196087 * 20255230Sab196087 * In the highly unlikely case that there is more than one dynamic 20265230Sab196087 * section, we only test the first one, and simply allow the values 20275230Sab196087 * of the subsequent one to be displayed unchallenged. 20285230Sab196087 */ 20295230Sab196087 if (dynsec_cnt != 1) 20305230Sab196087 return; 20315230Sab196087 20325230Sab196087 /* 20335230Sab196087 * A DT_ item that references a section address should always find 20345230Sab196087 * the section in the file. 20355230Sab196087 */ 20365230Sab196087 if (sec_cache == NULL) { 20376299Sab196087 const char *name; 20386299Sab196087 20396299Sab196087 /* 20406299Sab196087 * Supply section names instead of section types for 20416299Sab196087 * things that reference progbits so that the error 20426299Sab196087 * message will make more sense. 20436299Sab196087 */ 20446299Sab196087 switch (dyn->d_tag) { 20456299Sab196087 case DT_INIT: 20466299Sab196087 name = MSG_ORIG(MSG_ELF_INIT); 20476299Sab196087 break; 20486299Sab196087 case DT_FINI: 20496299Sab196087 name = MSG_ORIG(MSG_ELF_FINI); 20506299Sab196087 break; 20516299Sab196087 default: 20526299Sab196087 name = conv_sec_type(ehdr->e_machine, sh_type, 20536299Sab196087 0, &buf1); 20546299Sab196087 break; 20556299Sab196087 } 20565230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNNOBCKSEC), file, 20576299Sab196087 name, conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf2)); 20585230Sab196087 return; 20595230Sab196087 } 20605230Sab196087 20615230Sab196087 20625230Sab196087 switch (test_type) { 20635230Sab196087 case DYN_TEST_ADDR: 20645230Sab196087 /* The section address should match the DT_ item value */ 20655230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_addr) 20665230Sab196087 (void) fprintf(stderr, 20675230Sab196087 MSG_INTL(MSG_ERR_DYNBADADDR), file, 20685230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 20695230Sab196087 EC_ADDR(dyn->d_un.d_val), sec_cache->c_ndx, 20705230Sab196087 sec_cache->c_name, 20715230Sab196087 EC_ADDR(sec_cache->c_shdr->sh_addr)); 20725230Sab196087 break; 20735230Sab196087 20745230Sab196087 case DYN_TEST_SIZE: 20755230Sab196087 /* The section size should match the DT_ item value */ 20765230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_size) 20775230Sab196087 (void) fprintf(stderr, 20785230Sab196087 MSG_INTL(MSG_ERR_DYNBADSIZE), file, 20795230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 20805230Sab196087 EC_XWORD(dyn->d_un.d_val), 20815230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 20825230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_size)); 20835230Sab196087 break; 20845230Sab196087 20855230Sab196087 case DYN_TEST_ENTSIZE: 20865230Sab196087 /* The sh_entsize value should match the DT_ item value */ 20875230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_entsize) 20885230Sab196087 (void) fprintf(stderr, 20895230Sab196087 MSG_INTL(MSG_ERR_DYNBADENTSIZE), file, 20905230Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf1), 20915230Sab196087 EC_XWORD(dyn->d_un.d_val), 20925230Sab196087 sec_cache->c_ndx, sec_cache->c_name, 20935230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_entsize)); 20945230Sab196087 break; 20955230Sab196087 } 20965230Sab196087 } 20975230Sab196087 20985230Sab196087 20990Sstevel@tonic-gate /* 21006299Sab196087 * There are some DT_ entries that have corresponding symbols 21016299Sab196087 * (e.g. DT_INIT and _init). It is expected that these items will 21026299Sab196087 * both have the same value if both are present. This routine 21036299Sab196087 * examines the well known symbol tables for such symbols and 21046299Sab196087 * issues warnings for any that don't match. 21056299Sab196087 * 21066299Sab196087 * entry: 21076299Sab196087 * dyn - Dyn entry to be tested 21086299Sab196087 * symname - Name of symbol that corresponds to dyn 21096299Sab196087 * symtab_cache, dynsym_cache, ldynsym_cache - Symbol tables to check 21106299Sab196087 * cache - Cache of all section headers 21116299Sab196087 * shnum - # of sections in cache 21126299Sab196087 * ehdr - ELF header for file 21136299Sab196087 * file - Name of file 21146299Sab196087 */ 21156299Sab196087 21166299Sab196087 static void 21176299Sab196087 dyn_symtest(Dyn *dyn, const char *symname, Cache *symtab_cache, 21186299Sab196087 Cache *dynsym_cache, Cache *ldynsym_cache, Cache *cache, 21196299Sab196087 Word shnum, Ehdr *ehdr, const char *file) 21206299Sab196087 { 21216299Sab196087 Conv_inv_buf_t buf; 21226299Sab196087 int i; 21236299Sab196087 Sym *sym; 21246299Sab196087 Cache *_cache; 21256299Sab196087 21266299Sab196087 for (i = 0; i < 3; i++) { 21276299Sab196087 switch (i) { 21286299Sab196087 case 0: 21296299Sab196087 _cache = symtab_cache; 21306299Sab196087 break; 21316299Sab196087 case 1: 21326299Sab196087 _cache = dynsym_cache; 21336299Sab196087 break; 21346299Sab196087 case 2: 21356299Sab196087 _cache = ldynsym_cache; 21366299Sab196087 break; 21376299Sab196087 } 21386299Sab196087 21396299Sab196087 if ((_cache != NULL) && 21406299Sab196087 symlookup(symname, cache, shnum, &sym, _cache, file) && 21416299Sab196087 (sym->st_value != dyn->d_un.d_val)) 21426299Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNSYMVAL), 21436299Sab196087 file, _cache->c_name, 21446299Sab196087 conv_dyn_tag(dyn->d_tag, ehdr->e_machine, 0, &buf), 21456299Sab196087 symname, EC_ADDR(sym->st_value)); 21466299Sab196087 } 21476299Sab196087 } 21486299Sab196087 21496299Sab196087 21506299Sab196087 /* 21510Sstevel@tonic-gate * Search for and process a .dynamic section. 21520Sstevel@tonic-gate */ 21530Sstevel@tonic-gate static void 21541618Srie dynamic(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 21550Sstevel@tonic-gate { 21565230Sab196087 struct { 21576299Sab196087 Cache *symtab; 21585230Sab196087 Cache *dynstr; 21595230Sab196087 Cache *dynsym; 21605230Sab196087 Cache *hash; 21615230Sab196087 Cache *fini; 21625230Sab196087 Cache *fini_array; 21635230Sab196087 Cache *init; 21645230Sab196087 Cache *init_array; 21655230Sab196087 Cache *preinit_array; 21665230Sab196087 Cache *rel; 21675230Sab196087 Cache *rela; 21685230Sab196087 Cache *sunw_cap; 21695230Sab196087 Cache *sunw_ldynsym; 21705230Sab196087 Cache *sunw_move; 21715230Sab196087 Cache *sunw_syminfo; 21725230Sab196087 Cache *sunw_symsort; 21735230Sab196087 Cache *sunw_tlssort; 21745230Sab196087 Cache *sunw_verdef; 21755230Sab196087 Cache *sunw_verneed; 21765230Sab196087 Cache *sunw_versym; 21775230Sab196087 } sec; 21785230Sab196087 Word dynsec_ndx; 21795230Sab196087 Word dynsec_num; 21805230Sab196087 int dynsec_cnt; 21811618Srie Word cnt; 21820Sstevel@tonic-gate 21835230Sab196087 /* 21845230Sab196087 * Make a pass over all the sections, gathering section information 21855230Sab196087 * we'll need below. 21865230Sab196087 */ 21875230Sab196087 dynsec_num = 0; 21885230Sab196087 bzero(&sec, sizeof (sec)); 21890Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 21905230Sab196087 Cache *_cache = &cache[cnt]; 21915230Sab196087 21925230Sab196087 switch (_cache->c_shdr->sh_type) { 21935230Sab196087 case SHT_DYNAMIC: 21945230Sab196087 if (dynsec_num == 0) { 21955230Sab196087 dynsec_ndx = cnt; 21965230Sab196087 21975230Sab196087 /* Does it have a valid string table? */ 21985230Sab196087 (void) stringtbl(cache, 0, cnt, shnum, file, 21995230Sab196087 0, 0, &sec.dynstr); 22005230Sab196087 } 22015230Sab196087 dynsec_num++; 22025230Sab196087 break; 22035230Sab196087 22045230Sab196087 22055230Sab196087 case SHT_PROGBITS: 22065230Sab196087 /* 22075230Sab196087 * We want to detect the .init and .fini sections, 22085230Sab196087 * if present. These are SHT_PROGBITS, so all we 22095230Sab196087 * have to go on is the section name. Normally comparing 22105230Sab196087 * names is a bad idea, but there are some special 22115230Sab196087 * names (i.e. .init/.fini/.interp) that are very 22125230Sab196087 * difficult to use in any other context, and for 22135230Sab196087 * these symbols, we do the heuristic match. 22145230Sab196087 */ 22155230Sab196087 if (strcmp(_cache->c_name, 22165230Sab196087 MSG_ORIG(MSG_ELF_INIT)) == 0) { 22175230Sab196087 if (sec.init == NULL) 22185230Sab196087 sec.init = _cache; 22195230Sab196087 } else if (strcmp(_cache->c_name, 22205230Sab196087 MSG_ORIG(MSG_ELF_FINI)) == 0) { 22215230Sab196087 if (sec.fini == NULL) 22225230Sab196087 sec.fini = _cache; 22235230Sab196087 } 22245230Sab196087 break; 22255230Sab196087 22265230Sab196087 case SHT_REL: 22275230Sab196087 /* 22285230Sab196087 * We want the SHT_REL section with the lowest 22295230Sab196087 * offset. The linker gathers them together, 22305230Sab196087 * and puts the address of the first one 22315230Sab196087 * into the DT_REL dynamic element. 22325230Sab196087 */ 22335230Sab196087 if ((sec.rel == NULL) || 22345230Sab196087 (_cache->c_shdr->sh_offset < 22355230Sab196087 sec.rel->c_shdr->sh_offset)) 22365230Sab196087 sec.rel = _cache; 22375230Sab196087 break; 22385230Sab196087 22395230Sab196087 case SHT_RELA: 22405230Sab196087 /* RELA is handled just like RELA above */ 22415230Sab196087 if ((sec.rela == NULL) || 22425230Sab196087 (_cache->c_shdr->sh_offset < 22435230Sab196087 sec.rela->c_shdr->sh_offset)) 22445230Sab196087 sec.rela = _cache; 22455230Sab196087 break; 22465230Sab196087 22475230Sab196087 /* 22485230Sab196087 * The GRAB macro is used for the simple case in which 22495230Sab196087 * we simply grab the first section of the desired type. 22505230Sab196087 */ 22515230Sab196087 #define GRAB(_sec_type, _sec_field) \ 22525230Sab196087 case _sec_type: \ 22535230Sab196087 if (sec._sec_field == NULL) \ 22545230Sab196087 sec._sec_field = _cache; \ 22555230Sab196087 break 22566299Sab196087 GRAB(SHT_SYMTAB, symtab); 22575230Sab196087 GRAB(SHT_DYNSYM, dynsym); 22585230Sab196087 GRAB(SHT_FINI_ARRAY, fini_array); 22595230Sab196087 GRAB(SHT_HASH, hash); 22605230Sab196087 GRAB(SHT_INIT_ARRAY, init_array); 22615230Sab196087 GRAB(SHT_SUNW_move, sunw_move); 22625230Sab196087 GRAB(SHT_PREINIT_ARRAY, preinit_array); 22635230Sab196087 GRAB(SHT_SUNW_cap, sunw_cap); 22645230Sab196087 GRAB(SHT_SUNW_LDYNSYM, sunw_ldynsym); 22655230Sab196087 GRAB(SHT_SUNW_syminfo, sunw_syminfo); 22665230Sab196087 GRAB(SHT_SUNW_symsort, sunw_symsort); 22675230Sab196087 GRAB(SHT_SUNW_tlssort, sunw_tlssort); 22685230Sab196087 GRAB(SHT_SUNW_verdef, sunw_verdef); 22695230Sab196087 GRAB(SHT_SUNW_verneed, sunw_verneed); 22705230Sab196087 GRAB(SHT_SUNW_versym, sunw_versym); 22715230Sab196087 #undef GRAB 22725230Sab196087 } 22735230Sab196087 } 22745230Sab196087 22755230Sab196087 /* 22765230Sab196087 * If no dynamic section, return immediately. If more than one 22775230Sab196087 * dynamic section, then something odd is going on and an error 22785230Sab196087 * is in order, but then continue on and display them all. 22795230Sab196087 */ 22805230Sab196087 if (dynsec_num == 0) 22815230Sab196087 return; 22825230Sab196087 if (dynsec_num > 1) 22835230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MULTDYN), 22845230Sab196087 file, EC_WORD(dynsec_num)); 22855230Sab196087 22865230Sab196087 22875230Sab196087 dynsec_cnt = 0; 22885230Sab196087 for (cnt = dynsec_ndx; (cnt < shnum) && (dynsec_cnt < dynsec_num); 22895230Sab196087 cnt++) { 22901618Srie Dyn *dyn; 22911618Srie ulong_t numdyn; 22923850Sab196087 int ndx, end_ndx; 22931618Srie Cache *_cache = &cache[cnt], *strsec; 22941618Srie Shdr *shdr = _cache->c_shdr; 22955230Sab196087 int dumped = 0; 22960Sstevel@tonic-gate 22970Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC) 22980Sstevel@tonic-gate continue; 22995230Sab196087 dynsec_cnt++; 23000Sstevel@tonic-gate 23010Sstevel@tonic-gate /* 23021618Srie * Verify the associated string table section. 23030Sstevel@tonic-gate */ 23041618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0) 23050Sstevel@tonic-gate continue; 23061618Srie 23073466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 23083466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 23093466Srie file, _cache->c_name); 23103466Srie continue; 23113466Srie } 23123466Srie if (_cache->c_data == NULL) 23133466Srie continue; 23143466Srie 23150Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize; 23161618Srie dyn = (Dyn *)_cache->c_data->d_buf; 23170Sstevel@tonic-gate 23185230Sab196087 /* 23195230Sab196087 * We expect the REL/RELA entries to reference the reloc 23205230Sab196087 * section with the lowest address. However, this is 23215230Sab196087 * not true for dumped objects. Detect if this object has 23225230Sab196087 * been dumped so that we can skip the reloc address test 23235230Sab196087 * in that case. 23245230Sab196087 */ 23255230Sab196087 for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 23265230Sab196087 if (dyn->d_tag == DT_FLAGS_1) { 23275230Sab196087 dumped = (dyn->d_un.d_val & DF_1_CONFALT) != 0; 23285230Sab196087 break; 23295230Sab196087 } 23305230Sab196087 } 23315230Sab196087 dyn = (Dyn *)_cache->c_data->d_buf; 23325230Sab196087 23331618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 23341618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 23350Sstevel@tonic-gate 23361618Srie Elf_dyn_title(0); 23370Sstevel@tonic-gate 23381618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 23394734Sab196087 union { 23406206Sab196087 Conv_inv_buf_t inv; 23414734Sab196087 Conv_dyn_flag_buf_t flag; 23424734Sab196087 Conv_dyn_flag1_buf_t flag1; 23434734Sab196087 Conv_dyn_posflag1_buf_t posflag1; 23444734Sab196087 Conv_dyn_feature1_buf_t feature1; 23454734Sab196087 } c_buf; 23465230Sab196087 const char *name = NULL; 23470Sstevel@tonic-gate 23480Sstevel@tonic-gate /* 23490Sstevel@tonic-gate * Print the information numerically, and if possible 23505230Sab196087 * as a string. If a string is available, name is 23515230Sab196087 * set to reference it. 23525230Sab196087 * 23535230Sab196087 * Also, take this opportunity to sanity check 23545230Sab196087 * the values of DT elements. In the code above, 23555230Sab196087 * we gathered information on sections that are 23565230Sab196087 * referenced by the dynamic section. Here, we 23575230Sab196087 * compare the attributes of those sections to 23585230Sab196087 * the DT_ items that reference them and report 23595230Sab196087 * on inconsistencies. 23605230Sab196087 * 23615230Sab196087 * Things not currently tested that could be improved 23625230Sab196087 * in later revisions include: 23635230Sab196087 * - We don't check PLT or GOT related items 23645230Sab196087 * - We don't handle computing the lengths of 23655230Sab196087 * relocation arrays. To handle this 23665230Sab196087 * requires examining data that spans 23675230Sab196087 * across sections, in a contiguous span 23685230Sab196087 * within a single segment. 23695230Sab196087 * - DT_VERDEFNUM and DT_VERNEEDNUM can't be 23705230Sab196087 * verified without parsing the sections. 23715230Sab196087 * - We don't handle DT_SUNW_SYMSZ, which would 23725230Sab196087 * be the sum of the lengths of .dynsym and 23735230Sab196087 * .SUNW_ldynsym 23745230Sab196087 * - DT_SUNW_STRPAD can't be verified other than 23755230Sab196087 * to check that it's not larger than 23765230Sab196087 * the string table. 23775230Sab196087 * - Some items come in "all or none" clusters 23785230Sab196087 * that give an address, element size, 23795230Sab196087 * and data length in bytes. We don't 23805230Sab196087 * verify that there are no missing items 23815230Sab196087 * in such groups. 23820Sstevel@tonic-gate */ 23833850Sab196087 switch (dyn->d_tag) { 23843850Sab196087 case DT_NULL: 23853850Sab196087 /* 23863850Sab196087 * Special case: DT_NULLs can come in groups 23873850Sab196087 * that we prefer to reduce to a single line. 23883850Sab196087 */ 23893850Sab196087 end_ndx = ndx; 23903850Sab196087 while ((end_ndx < (numdyn - 1)) && 23914433Sab196087 ((dyn + 1)->d_tag == DT_NULL)) { 23923850Sab196087 dyn++; 23933850Sab196087 end_ndx++; 23943850Sab196087 } 23953850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 23963850Sab196087 ndx = end_ndx; 23973850Sab196087 continue; 23983850Sab196087 23993850Sab196087 /* 24005230Sab196087 * String items all reference the dynstr. The string() 24015230Sab196087 * function does the necessary sanity checking. 24023850Sab196087 */ 24033850Sab196087 case DT_NEEDED: 24043850Sab196087 case DT_SONAME: 24053850Sab196087 case DT_FILTER: 24063850Sab196087 case DT_AUXILIARY: 24073850Sab196087 case DT_CONFIG: 24083850Sab196087 case DT_RPATH: 24093850Sab196087 case DT_RUNPATH: 24103850Sab196087 case DT_USED: 24113850Sab196087 case DT_DEPAUDIT: 24123850Sab196087 case DT_AUDIT: 24133850Sab196087 case DT_SUNW_AUXILIARY: 24143850Sab196087 case DT_SUNW_FILTER: 24151618Srie name = string(_cache, ndx, strsec, 24161618Srie file, dyn->d_un.d_ptr); 24173850Sab196087 break; 24183850Sab196087 24193850Sab196087 case DT_FLAGS: 24204734Sab196087 name = conv_dyn_flag(dyn->d_un.d_val, 24214734Sab196087 0, &c_buf.flag); 24223850Sab196087 break; 24233850Sab196087 case DT_FLAGS_1: 24245088Sab196087 name = conv_dyn_flag1(dyn->d_un.d_val, 0, 24254734Sab196087 &c_buf.flag1); 24263850Sab196087 break; 24273850Sab196087 case DT_POSFLAG_1: 24284734Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0, 24294734Sab196087 &c_buf.posflag1); 24303850Sab196087 break; 24313850Sab196087 case DT_FEATURE_1: 24324734Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0, 24334734Sab196087 &c_buf.feature1); 24343850Sab196087 break; 24353850Sab196087 case DT_DEPRECATED_SPARC_REGISTER: 24361618Srie name = MSG_INTL(MSG_STR_DEPRECATED); 24373850Sab196087 break; 24385230Sab196087 24396206Sab196087 case DT_SUNW_LDMACH: 24406206Sab196087 name = conv_ehdr_mach((Half)dyn->d_un.d_val, 0, 24416206Sab196087 &c_buf.inv); 24426206Sab196087 break; 24436206Sab196087 24445230Sab196087 /* 24455230Sab196087 * Cases below this point are strictly sanity checking, 24465230Sab196087 * and do not generate a name string. The TEST_ macros 24475230Sab196087 * are used to hide the boilerplate arguments neeeded 24485230Sab196087 * by dyn_test(). 24495230Sab196087 */ 24505230Sab196087 #define TEST_ADDR(_sh_type, _sec_field) \ 24515230Sab196087 dyn_test(DYN_TEST_ADDR, _sh_type, \ 24525230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 24535230Sab196087 #define TEST_SIZE(_sh_type, _sec_field) \ 24545230Sab196087 dyn_test(DYN_TEST_SIZE, _sh_type, \ 24555230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 24565230Sab196087 #define TEST_ENTSIZE(_sh_type, _sec_field) \ 24575230Sab196087 dyn_test(DYN_TEST_ENTSIZE, _sh_type, \ 24585230Sab196087 sec._sec_field, dyn, dynsec_cnt, ehdr, file) 24595230Sab196087 24605230Sab196087 case DT_FINI: 24616299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_FINI), 24626299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 24636299Sab196087 cache, shnum, ehdr, file); 24645230Sab196087 TEST_ADDR(SHT_PROGBITS, fini); 24655230Sab196087 break; 24665230Sab196087 24675230Sab196087 case DT_FINI_ARRAY: 24685230Sab196087 TEST_ADDR(SHT_FINI_ARRAY, fini_array); 24695230Sab196087 break; 24705230Sab196087 24715230Sab196087 case DT_FINI_ARRAYSZ: 24725230Sab196087 TEST_SIZE(SHT_FINI_ARRAY, fini_array); 24735230Sab196087 break; 24745230Sab196087 24755230Sab196087 case DT_HASH: 24765230Sab196087 TEST_ADDR(SHT_HASH, hash); 24775230Sab196087 break; 24785230Sab196087 24795230Sab196087 case DT_INIT: 24806299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_INIT), 24816299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym, 24826299Sab196087 cache, shnum, ehdr, file); 24835230Sab196087 TEST_ADDR(SHT_PROGBITS, init); 24845230Sab196087 break; 24855230Sab196087 24865230Sab196087 case DT_INIT_ARRAY: 24875230Sab196087 TEST_ADDR(SHT_INIT_ARRAY, init_array); 24885230Sab196087 break; 24895230Sab196087 24905230Sab196087 case DT_INIT_ARRAYSZ: 24915230Sab196087 TEST_SIZE(SHT_INIT_ARRAY, init_array); 24925230Sab196087 break; 24935230Sab196087 24945230Sab196087 case DT_MOVEENT: 24955230Sab196087 TEST_ENTSIZE(SHT_SUNW_move, sunw_move); 24965230Sab196087 break; 24975230Sab196087 24985230Sab196087 case DT_MOVESZ: 24995230Sab196087 TEST_SIZE(SHT_SUNW_move, sunw_move); 25005230Sab196087 break; 25015230Sab196087 25025230Sab196087 case DT_MOVETAB: 25035230Sab196087 TEST_ADDR(SHT_SUNW_move, sunw_move); 25045230Sab196087 break; 25055230Sab196087 25065230Sab196087 case DT_PREINIT_ARRAY: 25075230Sab196087 TEST_ADDR(SHT_PREINIT_ARRAY, preinit_array); 25085230Sab196087 break; 25095230Sab196087 25105230Sab196087 case DT_PREINIT_ARRAYSZ: 25115230Sab196087 TEST_SIZE(SHT_PREINIT_ARRAY, preinit_array); 25125230Sab196087 break; 25135230Sab196087 25145230Sab196087 case DT_REL: 25155230Sab196087 if (!dumped) 25165230Sab196087 TEST_ADDR(SHT_REL, rel); 25175230Sab196087 break; 25185230Sab196087 25195230Sab196087 case DT_RELENT: 25205230Sab196087 TEST_ENTSIZE(SHT_REL, rel); 25215230Sab196087 break; 25225230Sab196087 25235230Sab196087 case DT_RELA: 25245230Sab196087 if (!dumped) 25255230Sab196087 TEST_ADDR(SHT_RELA, rela); 25265230Sab196087 break; 25275230Sab196087 25285230Sab196087 case DT_RELAENT: 25295230Sab196087 TEST_ENTSIZE(SHT_RELA, rela); 25305230Sab196087 break; 25315230Sab196087 25325230Sab196087 case DT_STRTAB: 25335230Sab196087 TEST_ADDR(SHT_STRTAB, dynstr); 25343850Sab196087 break; 25355230Sab196087 25365230Sab196087 case DT_STRSZ: 25375230Sab196087 TEST_SIZE(SHT_STRTAB, dynstr); 25385230Sab196087 break; 25395230Sab196087 25405230Sab196087 case DT_SUNW_CAP: 25415230Sab196087 TEST_ADDR(SHT_SUNW_cap, sunw_cap); 25425230Sab196087 break; 25435230Sab196087 25445230Sab196087 case DT_SUNW_SYMTAB: 25455230Sab196087 TEST_ADDR(SHT_SUNW_LDYNSYM, sunw_ldynsym); 25465230Sab196087 break; 25475230Sab196087 25485230Sab196087 case DT_SYMENT: 25495230Sab196087 TEST_ENTSIZE(SHT_DYNSYM, dynsym); 25505230Sab196087 break; 25515230Sab196087 25525230Sab196087 case DT_SYMINENT: 25535230Sab196087 TEST_ENTSIZE(SHT_SUNW_syminfo, sunw_syminfo); 25545230Sab196087 break; 25555230Sab196087 25565230Sab196087 case DT_SYMINFO: 25575230Sab196087 TEST_ADDR(SHT_SUNW_syminfo, sunw_syminfo); 25585230Sab196087 break; 25595230Sab196087 25605230Sab196087 case DT_SYMINSZ: 25615230Sab196087 TEST_SIZE(SHT_SUNW_syminfo, sunw_syminfo); 25625230Sab196087 break; 25635230Sab196087 25645230Sab196087 case DT_SYMTAB: 25655230Sab196087 TEST_ADDR(SHT_DYNSYM, dynsym); 25665230Sab196087 break; 25675230Sab196087 25685230Sab196087 case DT_SUNW_SORTENT: 25695230Sab196087 /* 25705230Sab196087 * This entry is related to both the symsort and 25715230Sab196087 * tlssort sections. 25725230Sab196087 */ 25735230Sab196087 { 25745230Sab196087 int test_tls = 25755230Sab196087 (sec.sunw_tlssort != NULL); 25765230Sab196087 int test_sym = 25775230Sab196087 (sec.sunw_symsort != NULL) || 25785230Sab196087 !test_tls; 25795230Sab196087 if (test_sym) 25805230Sab196087 TEST_ENTSIZE(SHT_SUNW_symsort, 25815230Sab196087 sunw_symsort); 25825230Sab196087 if (test_tls) 25835230Sab196087 TEST_ENTSIZE(SHT_SUNW_tlssort, 25845230Sab196087 sunw_tlssort); 25855230Sab196087 } 25865230Sab196087 break; 25875230Sab196087 25885230Sab196087 25895230Sab196087 case DT_SUNW_SYMSORT: 25905230Sab196087 TEST_ADDR(SHT_SUNW_symsort, sunw_symsort); 25915230Sab196087 break; 25925230Sab196087 25935230Sab196087 case DT_SUNW_SYMSORTSZ: 25945230Sab196087 TEST_SIZE(SHT_SUNW_symsort, sunw_symsort); 25955230Sab196087 break; 25965230Sab196087 25975230Sab196087 case DT_SUNW_TLSSORT: 25985230Sab196087 TEST_ADDR(SHT_SUNW_tlssort, sunw_tlssort); 25995230Sab196087 break; 26005230Sab196087 26015230Sab196087 case DT_SUNW_TLSSORTSZ: 26025230Sab196087 TEST_SIZE(SHT_SUNW_tlssort, sunw_tlssort); 26035230Sab196087 break; 26045230Sab196087 26055230Sab196087 case DT_VERDEF: 26065230Sab196087 TEST_ADDR(SHT_SUNW_verdef, sunw_verdef); 26075230Sab196087 break; 26085230Sab196087 26095230Sab196087 case DT_VERNEED: 26105230Sab196087 TEST_ADDR(SHT_SUNW_verneed, sunw_verneed); 26115230Sab196087 break; 26125230Sab196087 26135230Sab196087 case DT_VERSYM: 26145230Sab196087 TEST_ADDR(SHT_SUNW_versym, sunw_versym); 26155230Sab196087 break; 26165230Sab196087 #undef TEST_ADDR 26175230Sab196087 #undef TEST_SIZE 26185230Sab196087 #undef TEST_ENTSIZE 26193850Sab196087 } 26200Sstevel@tonic-gate 26215230Sab196087 if (name == NULL) 26225230Sab196087 name = MSG_ORIG(MSG_STR_EMPTY); 26231618Srie Elf_dyn_entry(0, dyn, ndx, name, ehdr->e_machine); 26240Sstevel@tonic-gate } 26250Sstevel@tonic-gate } 26260Sstevel@tonic-gate } 26270Sstevel@tonic-gate 26280Sstevel@tonic-gate /* 26290Sstevel@tonic-gate * Search for and process a MOVE section. 26300Sstevel@tonic-gate */ 26310Sstevel@tonic-gate static void 26324168Sab196087 move(Cache *cache, Word shnum, const char *file, uint_t flags) 26330Sstevel@tonic-gate { 26341618Srie Word cnt; 26351618Srie const char *fmt = 0; 26360Sstevel@tonic-gate 26370Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 26381618Srie Word movenum, symnum, ndx; 26391618Srie Sym *syms; 26401618Srie Cache *_cache = &cache[cnt]; 26411618Srie Shdr *shdr = _cache->c_shdr; 26421618Srie Cache *symsec, *strsec; 26431618Srie Move *move; 26440Sstevel@tonic-gate 26450Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move) 26460Sstevel@tonic-gate continue; 26475411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 26480Sstevel@tonic-gate continue; 26490Sstevel@tonic-gate 26500Sstevel@tonic-gate /* 26510Sstevel@tonic-gate * Determine the move data and number. 26520Sstevel@tonic-gate */ 26530Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 26540Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 26550Sstevel@tonic-gate file, _cache->c_name); 26560Sstevel@tonic-gate continue; 26570Sstevel@tonic-gate } 26583466Srie if (_cache->c_data == NULL) 26593466Srie continue; 26603466Srie 26611618Srie move = (Move *)_cache->c_data->d_buf; 26621618Srie movenum = shdr->sh_size / shdr->sh_entsize; 26630Sstevel@tonic-gate 26640Sstevel@tonic-gate /* 26651618Srie * Get the data buffer for the associated symbol table and 26661618Srie * string table. 26670Sstevel@tonic-gate */ 26681618Srie if (stringtbl(cache, 1, cnt, shnum, file, 26691618Srie &symnum, &symsec, &strsec) == 0) 26701618Srie return; 26711618Srie 26721618Srie syms = (Sym *)symsec->c_data->d_buf; 26730Sstevel@tonic-gate 26741618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 26751618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); 26761618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); 26770Sstevel@tonic-gate 26781618Srie if (fmt == 0) 26791618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY); 26800Sstevel@tonic-gate 26811618Srie for (ndx = 0; ndx < movenum; move++, ndx++) { 26821618Srie const char *symname; 26831618Srie char index[MAXNDXSIZE], section[BUFSIZ]; 26841618Srie Word symndx, shndx; 26851618Srie Sym *sym; 26860Sstevel@tonic-gate 26870Sstevel@tonic-gate /* 26880Sstevel@tonic-gate * Check for null entries 26890Sstevel@tonic-gate */ 26901618Srie if ((move->m_info == 0) && (move->m_value == 0) && 26911618Srie (move->m_poffset == 0) && (move->m_repeat == 0) && 26921618Srie (move->m_stride == 0)) { 26931618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY), 26941618Srie EC_XWORD(move->m_poffset), 0, 0, 0, 26951618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY)); 26960Sstevel@tonic-gate continue; 26970Sstevel@tonic-gate } 26981618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) || 26991618Srie (symndx >= symnum)) { 27000Sstevel@tonic-gate (void) fprintf(stderr, 27010Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file, 27021618Srie _cache->c_name, EC_XWORD(move->m_info)); 27031618Srie 27041618Srie (void) snprintf(index, MAXNDXSIZE, 27051618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 27061618Srie dbg_print(0, fmt, index, 27071618Srie EC_XWORD(move->m_poffset), 27081618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 27091618Srie move->m_stride, move->m_value, 27100Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN)); 27110Sstevel@tonic-gate continue; 27120Sstevel@tonic-gate } 27130Sstevel@tonic-gate 27141618Srie symname = relsymname(cache, _cache, strsec, 27151618Srie symndx, symnum, ndx, syms, section, BUFSIZ, file, 27161618Srie flags); 27171618Srie sym = (Sym *)(syms + symndx); 27180Sstevel@tonic-gate 27190Sstevel@tonic-gate /* 27200Sstevel@tonic-gate * Additional sanity check. 27210Sstevel@tonic-gate */ 27221618Srie shndx = sym->st_shndx; 27230Sstevel@tonic-gate if (!((shndx == SHN_COMMON) || 27240Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) && 27251618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) { 27260Sstevel@tonic-gate (void) fprintf(stderr, 27271618Srie MSG_INTL(MSG_ERR_BADSYM2), file, 27286206Sab196087 _cache->c_name, EC_WORD(symndx), 27296206Sab196087 demangle(symname, flags)); 27300Sstevel@tonic-gate } 27310Sstevel@tonic-gate 27321618Srie (void) snprintf(index, MAXNDXSIZE, 27331618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 27341618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset), 27351618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 27361618Srie move->m_stride, move->m_value, 27371618Srie demangle(symname, flags)); 27380Sstevel@tonic-gate } 27390Sstevel@tonic-gate } 27400Sstevel@tonic-gate } 27410Sstevel@tonic-gate 27420Sstevel@tonic-gate /* 2743*6635Sab196087 * Callback function for use with conv_str_to_c_literal() below. 2744*6635Sab196087 */ 2745*6635Sab196087 /*ARGSUSED2*/ 2746*6635Sab196087 static void 2747*6635Sab196087 c_literal_cb(const void *ptr, size_t size, void *uvalue) 2748*6635Sab196087 { 2749*6635Sab196087 (void) fwrite(ptr, size, 1, stdout); 2750*6635Sab196087 } 2751*6635Sab196087 2752*6635Sab196087 /* 27530Sstevel@tonic-gate * Traverse a note section analyzing each note information block. 27540Sstevel@tonic-gate * The data buffers size is used to validate references before they are made, 27550Sstevel@tonic-gate * and is decremented as each element is processed. 27560Sstevel@tonic-gate */ 27570Sstevel@tonic-gate void 2758*6635Sab196087 note_entry(Cache *cache, Word *data, size_t size, Ehdr *ehdr, const char *file) 27590Sstevel@tonic-gate { 2760*6635Sab196087 size_t bsize = size; 2761*6635Sab196087 int cnt = 0; 2762*6635Sab196087 int is_corenote; 2763*6635Sab196087 int do_swap; 2764*6635Sab196087 Conv_inv_buf_t inv_buf; 2765*6635Sab196087 2766*6635Sab196087 do_swap = _elf_sys_encoding() != ehdr->e_ident[EI_DATA]; 27671618Srie 27680Sstevel@tonic-gate /* 27690Sstevel@tonic-gate * Print out a single `note' information block. 27700Sstevel@tonic-gate */ 27710Sstevel@tonic-gate while (size > 0) { 27721618Srie size_t namesz, descsz, type, pad, noteoff; 27730Sstevel@tonic-gate 27740Sstevel@tonic-gate noteoff = bsize - size; 27750Sstevel@tonic-gate /* 27760Sstevel@tonic-gate * Make sure we can at least reference the 3 initial entries 27770Sstevel@tonic-gate * (4-byte words) of the note information block. 27780Sstevel@tonic-gate */ 27791618Srie if (size >= (sizeof (Word) * 3)) 27801618Srie size -= (sizeof (Word) * 3); 27810Sstevel@tonic-gate else { 27821618Srie (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ), 27831618Srie file, cache->c_name, EC_WORD(noteoff)); 27840Sstevel@tonic-gate return; 27850Sstevel@tonic-gate } 27860Sstevel@tonic-gate 27870Sstevel@tonic-gate /* 27880Sstevel@tonic-gate * Make sure any specified name string can be referenced. 27890Sstevel@tonic-gate */ 27900Sstevel@tonic-gate if ((namesz = *data++) != 0) { 27910Sstevel@tonic-gate if (size >= namesz) 27920Sstevel@tonic-gate size -= namesz; 27930Sstevel@tonic-gate else { 27940Sstevel@tonic-gate (void) fprintf(stderr, 27951618Srie MSG_INTL(MSG_NOTE_BADNMSZ), file, 27961618Srie cache->c_name, EC_WORD(noteoff), 27971618Srie EC_WORD(namesz)); 27980Sstevel@tonic-gate return; 27990Sstevel@tonic-gate } 28000Sstevel@tonic-gate } 28011618Srie 28020Sstevel@tonic-gate /* 28030Sstevel@tonic-gate * Make sure any specified descriptor can be referenced. 28040Sstevel@tonic-gate */ 28050Sstevel@tonic-gate if ((descsz = *data++) != 0) { 28060Sstevel@tonic-gate /* 28070Sstevel@tonic-gate * If namesz isn't a 4-byte multiple, account for any 28080Sstevel@tonic-gate * padding that must exist before the descriptor. 28090Sstevel@tonic-gate */ 28101618Srie if ((pad = (namesz & (sizeof (Word) - 1))) != 0) { 28111618Srie pad = sizeof (Word) - pad; 28120Sstevel@tonic-gate size -= pad; 28130Sstevel@tonic-gate } 28140Sstevel@tonic-gate if (size >= descsz) 28150Sstevel@tonic-gate size -= descsz; 28160Sstevel@tonic-gate else { 28170Sstevel@tonic-gate (void) fprintf(stderr, 28181618Srie MSG_INTL(MSG_NOTE_BADDESZ), file, 28191618Srie cache->c_name, EC_WORD(noteoff), 28201618Srie EC_WORD(namesz)); 28210Sstevel@tonic-gate return; 28220Sstevel@tonic-gate } 28230Sstevel@tonic-gate } 28240Sstevel@tonic-gate 28250Sstevel@tonic-gate type = *data++; 28260Sstevel@tonic-gate 2827*6635Sab196087 /* 2828*6635Sab196087 * Is this a Solaris core note? Such notes all have 2829*6635Sab196087 * the name "CORE". 2830*6635Sab196087 */ 2831*6635Sab196087 is_corenote = (ehdr->e_type == ET_CORE) && 2832*6635Sab196087 (namesz == (MSG_STR_CORE_SIZE + 1)) && 2833*6635Sab196087 (strncmp(MSG_ORIG(MSG_STR_CORE), (char *)data, 2834*6635Sab196087 MSG_STR_CORE_SIZE + 1) == 0); 2835*6635Sab196087 28361618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 2837*6635Sab196087 dbg_print(0, MSG_INTL(MSG_FMT_NOTEENTNDX), EC_WORD(cnt)); 2838*6635Sab196087 cnt++; 28391618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz)); 2840*6635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz)); 2841*6635Sab196087 2842*6635Sab196087 if (is_corenote) 2843*6635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE_STR), 2844*6635Sab196087 conv_cnote_type(type, 0, &inv_buf)); 2845*6635Sab196087 else 2846*6635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type)); 28470Sstevel@tonic-gate if (namesz) { 28480Sstevel@tonic-gate char *name = (char *)data; 28490Sstevel@tonic-gate 2850*6635Sab196087 2851*6635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_NAME)); 28520Sstevel@tonic-gate /* 2853*6635Sab196087 * The name string can contain embedded 'null' 2854*6635Sab196087 * bytes and/or unprintable characters. Also, 2855*6635Sab196087 * the final NULL is documented in the ELF ABI 2856*6635Sab196087 * as being included in the namesz. So, display 2857*6635Sab196087 * the name using C literal string notation, and 2858*6635Sab196087 * include the terminating NULL in the output. 2859*6635Sab196087 * We don't show surrounding double quotes, as 2860*6635Sab196087 * that implies the termination that we are showing 2861*6635Sab196087 * explicitly. 28620Sstevel@tonic-gate */ 2863*6635Sab196087 (void) fwrite(MSG_ORIG(MSG_STR_8SP), 2864*6635Sab196087 MSG_STR_8SP_SIZE, 1, stdout); 2865*6635Sab196087 conv_str_to_c_literal(name, namesz, c_literal_cb, NULL); 28660Sstevel@tonic-gate name = name + ((namesz + (sizeof (Word) - 1)) & 28670Sstevel@tonic-gate ~(sizeof (Word) - 1)); 28680Sstevel@tonic-gate /* LINTED */ 28690Sstevel@tonic-gate data = (Word *)name; 28701618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 28710Sstevel@tonic-gate } 28720Sstevel@tonic-gate 28730Sstevel@tonic-gate /* 28740Sstevel@tonic-gate * If multiple information blocks exist within a .note section 28750Sstevel@tonic-gate * account for any padding that must exist before the next 28760Sstevel@tonic-gate * information block. 28770Sstevel@tonic-gate */ 28781618Srie if ((pad = (descsz & (sizeof (Word) - 1))) != 0) { 28791618Srie pad = sizeof (Word) - pad; 28800Sstevel@tonic-gate if (size > pad) 28810Sstevel@tonic-gate size -= pad; 28820Sstevel@tonic-gate } 28830Sstevel@tonic-gate 28840Sstevel@tonic-gate if (descsz) { 2885*6635Sab196087 int hexdump = 1; 2886*6635Sab196087 const char *desc = (const char *)data; 28870Sstevel@tonic-gate 28880Sstevel@tonic-gate /* 2889*6635Sab196087 * If this is a core note, let the corenote() 2890*6635Sab196087 * function handle it. 28910Sstevel@tonic-gate */ 2892*6635Sab196087 if (is_corenote) { 2893*6635Sab196087 /* We only issue the bad arch error once */ 2894*6635Sab196087 static int badnote_done = 0; 2895*6635Sab196087 corenote_ret_t corenote_ret; 2896*6635Sab196087 2897*6635Sab196087 corenote_ret = corenote(ehdr->e_machine, 2898*6635Sab196087 do_swap, type, desc, descsz); 2899*6635Sab196087 switch (corenote_ret) { 2900*6635Sab196087 case CORENOTE_R_OK: 2901*6635Sab196087 hexdump = 0; 2902*6635Sab196087 break; 2903*6635Sab196087 case CORENOTE_R_BADDATA: 2904*6635Sab196087 (void) fprintf(stderr, 2905*6635Sab196087 MSG_INTL(MSG_NOTE_BADCOREDATA), 2906*6635Sab196087 file); 2907*6635Sab196087 break; 2908*6635Sab196087 case CORENOTE_R_BADARCH: 2909*6635Sab196087 if (badnote_done) 2910*6635Sab196087 break; 2911*6635Sab196087 (void) fprintf(stderr, 2912*6635Sab196087 MSG_INTL(MSG_NOTE_BADCOREARCH), 2913*6635Sab196087 file, 2914*6635Sab196087 conv_ehdr_mach(ehdr->e_machine, 2915*6635Sab196087 0, &inv_buf)); 2916*6635Sab196087 break; 29170Sstevel@tonic-gate } 29180Sstevel@tonic-gate } 2919*6635Sab196087 2920*6635Sab196087 /* 2921*6635Sab196087 * The default thing when we don't understand 2922*6635Sab196087 * the note data is to display it as hex bytes. 2923*6635Sab196087 */ 2924*6635Sab196087 if (hexdump) { 2925*6635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESC)); 2926*6635Sab196087 dump_hex_bytes(desc, descsz, 8, 4, 4); 29270Sstevel@tonic-gate } 2928*6635Sab196087 desc += descsz + pad; 2929*6635Sab196087 29300Sstevel@tonic-gate /* LINTED */ 29310Sstevel@tonic-gate data = (Word *)desc; 29320Sstevel@tonic-gate } 29330Sstevel@tonic-gate } 29340Sstevel@tonic-gate } 29350Sstevel@tonic-gate 29360Sstevel@tonic-gate /* 2937*6635Sab196087 * Search for and process .note sections. 2938*6635Sab196087 * 2939*6635Sab196087 * Returns the number of note sections seen. 29400Sstevel@tonic-gate */ 2941*6635Sab196087 static Word 2942*6635Sab196087 note(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 29430Sstevel@tonic-gate { 2944*6635Sab196087 Word cnt, note_cnt = 0; 29450Sstevel@tonic-gate 29460Sstevel@tonic-gate /* 29470Sstevel@tonic-gate * Otherwise look for any .note sections. 29480Sstevel@tonic-gate */ 29490Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 29501618Srie Cache *_cache = &cache[cnt]; 29511618Srie Shdr *shdr = _cache->c_shdr; 29520Sstevel@tonic-gate 29530Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE) 29540Sstevel@tonic-gate continue; 2955*6635Sab196087 note_cnt++; 29565411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type)) 29570Sstevel@tonic-gate continue; 29580Sstevel@tonic-gate 29590Sstevel@tonic-gate /* 29600Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're 29615230Sab196087 * properly aligned before proceeding, and issue an error 29625230Sab196087 * as necessary. 29635230Sab196087 * 29645230Sab196087 * Note that we will continue on to display the note even 29655230Sab196087 * if it has bad alignment. We can do this safely, because 29665230Sab196087 * libelf knows the alignment required for SHT_NOTE, and 29675230Sab196087 * takes steps to deliver a properly aligned buffer to us 29685230Sab196087 * even if the actual file is misaligned. 29690Sstevel@tonic-gate */ 29705230Sab196087 if (shdr->sh_offset & (sizeof (Word) - 1)) 29710Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 29720Sstevel@tonic-gate file, _cache->c_name); 29735230Sab196087 29743466Srie if (_cache->c_data == NULL) 29753466Srie continue; 29760Sstevel@tonic-gate 29771618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 29781618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 29790Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf, 29800Sstevel@tonic-gate /* LINTED */ 2981*6635Sab196087 (Word)_cache->c_data->d_size, ehdr, file); 29820Sstevel@tonic-gate } 2983*6635Sab196087 2984*6635Sab196087 return (note_cnt); 29850Sstevel@tonic-gate } 29860Sstevel@tonic-gate 29871618Srie /* 29881618Srie * Determine an individual hash entry. This may be the initial hash entry, 29891618Srie * or an associated chain entry. 29901618Srie */ 29911618Srie static void 29921618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx, 29931618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts, 29941618Srie uint_t flags, int chain) 29951618Srie { 29961618Srie Sym *sym; 29971618Srie const char *symname, *str; 29981618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE]; 29991618Srie ulong_t nbkt, nhash; 30001618Srie 30011618Srie if (symndx > symn) { 30021618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file, 30031618Srie EC_WORD(symndx), EC_WORD(hashndx)); 30041618Srie symname = MSG_INTL(MSG_STR_UNKNOWN); 30051618Srie } else { 30061618Srie sym = (Sym *)(syms + symndx); 30071618Srie symname = string(refsec, symndx, strsec, file, sym->st_name); 30081618Srie } 30091618Srie 30101618Srie if (chain == 0) { 30111618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 30121618Srie hashndx); 30131618Srie str = (const char *)_bucket; 30141618Srie } else 30151618Srie str = MSG_ORIG(MSG_STR_EMPTY); 30161618Srie 30171618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2), 30181618Srie EC_WORD(symndx)); 30191618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx, 30201618Srie demangle(symname, flags)); 30211618Srie 30221618Srie /* 30231618Srie * Determine if this string is in the correct bucket. 30241618Srie */ 30251618Srie nhash = elf_hash(symname); 30261618Srie nbkt = nhash % bkts; 30271618Srie 30281618Srie if (nbkt != hashndx) { 30291618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file, 30301618Srie hsecname, symname, EC_WORD(hashndx), nbkt); 30311618Srie } 30321618Srie } 30330Sstevel@tonic-gate 30340Sstevel@tonic-gate #define MAXCOUNT 500 30350Sstevel@tonic-gate 30360Sstevel@tonic-gate static void 30374168Sab196087 hash(Cache *cache, Word shnum, const char *file, uint_t flags) 30380Sstevel@tonic-gate { 30390Sstevel@tonic-gate static int count[MAXCOUNT]; 30401618Srie Word cnt; 30410Sstevel@tonic-gate ulong_t ndx, bkts; 30420Sstevel@tonic-gate char number[MAXNDXSIZE]; 30430Sstevel@tonic-gate 30440Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 30450Sstevel@tonic-gate uint_t *hash, *chain; 30460Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 30471618Srie Shdr *sshdr, *hshdr = _cache->c_shdr; 30481618Srie char *ssecname, *hsecname = _cache->c_name; 30491618Srie Sym *syms; 30501618Srie Word symn; 30510Sstevel@tonic-gate 30521618Srie if (hshdr->sh_type != SHT_HASH) 30530Sstevel@tonic-gate continue; 30540Sstevel@tonic-gate 30550Sstevel@tonic-gate /* 30560Sstevel@tonic-gate * Determine the hash table data and size. 30570Sstevel@tonic-gate */ 30581618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) { 30590Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 30601618Srie file, hsecname); 30610Sstevel@tonic-gate continue; 30620Sstevel@tonic-gate } 30633466Srie if (_cache->c_data == NULL) 30643466Srie continue; 30653466Srie 30660Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf; 30670Sstevel@tonic-gate bkts = *hash; 30680Sstevel@tonic-gate chain = hash + 2 + bkts; 30690Sstevel@tonic-gate hash += 2; 30700Sstevel@tonic-gate 30710Sstevel@tonic-gate /* 30720Sstevel@tonic-gate * Get the data buffer for the associated symbol table. 30730Sstevel@tonic-gate */ 30741618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) { 30750Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 30761618Srie file, hsecname, EC_WORD(hshdr->sh_link)); 30770Sstevel@tonic-gate continue; 30780Sstevel@tonic-gate } 30791618Srie 30801618Srie _cache = &cache[hshdr->sh_link]; 30811618Srie ssecname = _cache->c_name; 30821618Srie 30833466Srie if (_cache->c_data == NULL) 30843466Srie continue; 30853466Srie 30863466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) { 30870Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 30881618Srie file, ssecname); 30890Sstevel@tonic-gate continue; 30900Sstevel@tonic-gate } 30910Sstevel@tonic-gate 30921618Srie sshdr = _cache->c_shdr; 30931618Srie /* LINTED */ 30941618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize); 30951618Srie 30960Sstevel@tonic-gate /* 30970Sstevel@tonic-gate * Get the associated string table section. 30980Sstevel@tonic-gate */ 30991618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) { 31000Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 31011618Srie file, ssecname, EC_WORD(sshdr->sh_link)); 31020Sstevel@tonic-gate continue; 31030Sstevel@tonic-gate } 31040Sstevel@tonic-gate 31051618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 31061618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname); 31071618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO)); 31080Sstevel@tonic-gate 31090Sstevel@tonic-gate /* 31100Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate 31110Sstevel@tonic-gate * symbols. 31120Sstevel@tonic-gate */ 31130Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) { 31141618Srie Word _ndx, _cnt; 31150Sstevel@tonic-gate 31160Sstevel@tonic-gate if (*hash == 0) { 31170Sstevel@tonic-gate count[0]++; 31180Sstevel@tonic-gate continue; 31190Sstevel@tonic-gate } 31200Sstevel@tonic-gate 31211618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname, 31221618Srie ndx, *hash, symn, syms, file, bkts, flags, 0); 31230Sstevel@tonic-gate 31240Sstevel@tonic-gate /* 31250Sstevel@tonic-gate * Determine if any other symbols are chained to this 31260Sstevel@tonic-gate * bucket. 31270Sstevel@tonic-gate */ 31280Sstevel@tonic-gate _ndx = chain[*hash]; 31290Sstevel@tonic-gate _cnt = 1; 31300Sstevel@tonic-gate while (_ndx) { 31311618Srie hash_entry(_cache, &cache[sshdr->sh_link], 31321618Srie hsecname, ndx, _ndx, symn, syms, file, 31331618Srie bkts, flags, 1); 31340Sstevel@tonic-gate _ndx = chain[_ndx]; 31350Sstevel@tonic-gate _cnt++; 31360Sstevel@tonic-gate } 31370Sstevel@tonic-gate 31380Sstevel@tonic-gate if (_cnt >= MAXCOUNT) { 31390Sstevel@tonic-gate (void) fprintf(stderr, 31401324Srie MSG_INTL(MSG_HASH_OVERFLW), file, 31411618Srie _cache->c_name, EC_WORD(ndx), 31421618Srie EC_WORD(_cnt)); 31430Sstevel@tonic-gate } else 31440Sstevel@tonic-gate count[_cnt]++; 31450Sstevel@tonic-gate } 31460Sstevel@tonic-gate break; 31470Sstevel@tonic-gate } 31480Sstevel@tonic-gate 31490Sstevel@tonic-gate /* 31500Sstevel@tonic-gate * Print out the count information. 31510Sstevel@tonic-gate */ 31520Sstevel@tonic-gate bkts = cnt = 0; 31531618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 31541618Srie 31550Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) { 31561618Srie Word _cnt; 31570Sstevel@tonic-gate 31580Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0) 31590Sstevel@tonic-gate continue; 31600Sstevel@tonic-gate 31611618Srie (void) snprintf(number, MAXNDXSIZE, 31621618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt); 31631618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number, 31641618Srie EC_WORD(ndx)); 31650Sstevel@tonic-gate bkts += _cnt; 31661618Srie cnt += (Word)(ndx * _cnt); 31670Sstevel@tonic-gate } 31680Sstevel@tonic-gate if (cnt) { 31690Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 31701618Srie bkts); 31711618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number, 31721618Srie EC_WORD(cnt)); 31730Sstevel@tonic-gate } 31740Sstevel@tonic-gate } 31750Sstevel@tonic-gate 31760Sstevel@tonic-gate static void 31774168Sab196087 group(Cache *cache, Word shnum, const char *file, uint_t flags) 31780Sstevel@tonic-gate { 31791618Srie Word scnt; 31800Sstevel@tonic-gate 31811618Srie for (scnt = 1; scnt < shnum; scnt++) { 31821618Srie Cache *_cache = &cache[scnt]; 31831618Srie Shdr *shdr = _cache->c_shdr; 31841618Srie Word *grpdata, gcnt, grpcnt, symnum, unknown; 31851618Srie Cache *symsec, *strsec; 31861618Srie Sym *syms, *sym; 31871618Srie char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 31880Sstevel@tonic-gate 31890Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP) 31900Sstevel@tonic-gate continue; 31915411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, scnt, shdr->sh_type)) 31920Sstevel@tonic-gate continue; 31933466Srie if ((_cache->c_data == NULL) || 31943466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL)) 31950Sstevel@tonic-gate continue; 31961618Srie grpcnt = shdr->sh_size / sizeof (Word); 31971618Srie 31981618Srie /* 31991618Srie * Get the data buffer for the associated symbol table and 32001618Srie * string table. 32011618Srie */ 32021618Srie if (stringtbl(cache, 1, scnt, shnum, file, 32031618Srie &symnum, &symsec, &strsec) == 0) 32041618Srie return; 32051618Srie 32061618Srie syms = symsec->c_data->d_buf; 32071618Srie 32081618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 32091618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name); 32101618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE)); 32111618Srie 32121618Srie /* 32131618Srie * The first element of the group defines the group. The 32141618Srie * associated symbol is defined by the sh_link field. 32151618Srie */ 32161618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) { 32171618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 32181618Srie file, _cache->c_name, EC_WORD(shdr->sh_info)); 32191618Srie return; 32200Sstevel@tonic-gate } 32210Sstevel@tonic-gate 32221618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT)); 32231618Srie if (grpdata[0] & GRP_COMDAT) { 32241618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT)); 32250Sstevel@tonic-gate } 32261618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) { 32271618Srie size_t len = strlen(flgstrbuf); 32281618Srie 32291618Srie (void) snprintf(&flgstrbuf[len], 32301618Srie (MSG_GRP_COMDAT_SIZE + 10 - len), 32311618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown); 32320Sstevel@tonic-gate } 32331618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT)); 32341618Srie sym = (Sym *)(syms + shdr->sh_info); 32350Sstevel@tonic-gate 32361618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf, 32371618Srie demangle(string(_cache, 0, strsec, file, sym->st_name), 32381618Srie flags)); 32391618Srie 32401618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) { 32410Sstevel@tonic-gate char index[MAXNDXSIZE]; 32421618Srie const char *name; 32430Sstevel@tonic-gate 32440Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, 32451618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt)); 32461618Srie 32471618Srie if (grpdata[gcnt] >= shnum) 32481618Srie name = MSG_INTL(MSG_GRP_INVALSCN); 32491618Srie else 32501618Srie name = cache[grpdata[gcnt]].c_name; 32511618Srie 32521618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name, 32534433Sab196087 EC_XWORD(grpdata[gcnt])); 32540Sstevel@tonic-gate } 32550Sstevel@tonic-gate } 32560Sstevel@tonic-gate } 32570Sstevel@tonic-gate 32580Sstevel@tonic-gate static void 32591618Srie got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file, uint_t flags) 32600Sstevel@tonic-gate { 32615230Sab196087 Cache *gotcache = NULL, *symtab = NULL; 32621618Srie Addr gotbgn, gotend; 32631618Srie Shdr *gotshdr; 32641618Srie Word cnt, gotents, gotndx; 32650Sstevel@tonic-gate size_t gentsize; 32660Sstevel@tonic-gate Got_info *gottable; 32670Sstevel@tonic-gate char *gotdata; 32681618Srie Sym *gotsym; 32691618Srie Xword gotsymaddr; 32706206Sab196087 uint_t sys_encoding; 32710Sstevel@tonic-gate 32720Sstevel@tonic-gate /* 32731324Srie * First, find the got. 32740Sstevel@tonic-gate */ 32750Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 32765230Sab196087 if (strncmp(cache[cnt].c_name, MSG_ORIG(MSG_ELF_GOT), 32771324Srie MSG_ELF_GOT_SIZE) == 0) { 32785230Sab196087 gotcache = &cache[cnt]; 32790Sstevel@tonic-gate break; 32800Sstevel@tonic-gate } 32810Sstevel@tonic-gate } 32825230Sab196087 if (gotcache == NULL) 32830Sstevel@tonic-gate return; 32841324Srie 32851324Srie /* 32861324Srie * A got section within a relocatable object is suspicious. 32871324Srie */ 32881324Srie if (ehdr->e_type == ET_REL) { 32891324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file, 32905230Sab196087 gotcache->c_name); 32911324Srie } 32921324Srie 32931618Srie gotshdr = gotcache->c_shdr; 32940Sstevel@tonic-gate if (gotshdr->sh_size == 0) { 32950Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 32960Sstevel@tonic-gate file, gotcache->c_name); 32970Sstevel@tonic-gate return; 32980Sstevel@tonic-gate } 32991618Srie 33001618Srie gotbgn = gotshdr->sh_addr; 33010Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size; 33020Sstevel@tonic-gate 33030Sstevel@tonic-gate /* 33041618Srie * Some architectures don't properly set the sh_entsize for the GOT 33051618Srie * table. If it's not set, default to a size of a pointer. 33060Sstevel@tonic-gate */ 33071618Srie if ((gentsize = gotshdr->sh_entsize) == 0) 33081618Srie gentsize = sizeof (Xword); 33091618Srie 33103466Srie if (gotcache->c_data == NULL) 33113466Srie return; 33123466Srie 33130Sstevel@tonic-gate /* LINTED */ 33141618Srie gotents = (Word)(gotshdr->sh_size / gentsize); 33150Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf; 33160Sstevel@tonic-gate 33170Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 33180Sstevel@tonic-gate int err = errno; 33191618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file, 33201618Srie strerror(err)); 33210Sstevel@tonic-gate return; 33220Sstevel@tonic-gate } 33230Sstevel@tonic-gate 33240Sstevel@tonic-gate /* 33250Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations 33260Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a 33270Sstevel@tonic-gate * .rel[a].got section we check them all. 33280Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab 33290Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 33300Sstevel@tonic-gate */ 33310Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 33321618Srie Word type, symnum; 33331618Srie Xword relndx, relnum, relsize; 33341618Srie void *rels; 33351618Srie Sym *syms; 33361618Srie Cache *symsec, *strsec; 33371618Srie Cache *_cache = &cache[cnt]; 33381618Srie Shdr *shdr; 33390Sstevel@tonic-gate 33401618Srie shdr = _cache->c_shdr; 33411618Srie type = shdr->sh_type; 33420Sstevel@tonic-gate 33431618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) { 33440Sstevel@tonic-gate symtab = _cache; 33450Sstevel@tonic-gate continue; 33460Sstevel@tonic-gate } 33471618Srie if (type == SHT_SYMTAB) { 33480Sstevel@tonic-gate symtab = _cache; 33490Sstevel@tonic-gate continue; 33500Sstevel@tonic-gate } 33511618Srie if ((type != SHT_RELA) && (type != SHT_REL)) 33520Sstevel@tonic-gate continue; 33530Sstevel@tonic-gate 33540Sstevel@tonic-gate /* 33551618Srie * Decide entry size. 33560Sstevel@tonic-gate */ 33571618Srie if (((relsize = shdr->sh_entsize) == 0) || 33581618Srie (relsize > shdr->sh_size)) { 33591618Srie if (type == SHT_RELA) 33601618Srie relsize = sizeof (Rela); 33611618Srie else 33621618Srie relsize = sizeof (Rel); 33630Sstevel@tonic-gate } 33640Sstevel@tonic-gate 33650Sstevel@tonic-gate /* 33661618Srie * Determine the number of relocations available. 33670Sstevel@tonic-gate */ 33681618Srie if (shdr->sh_size == 0) { 33691618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 33701618Srie file, _cache->c_name); 33710Sstevel@tonic-gate continue; 33720Sstevel@tonic-gate } 33733466Srie if (_cache->c_data == NULL) 33743466Srie continue; 33753466Srie 33761618Srie rels = _cache->c_data->d_buf; 33771618Srie relnum = shdr->sh_size / relsize; 33780Sstevel@tonic-gate 33791618Srie /* 33801618Srie * Get the data buffer for the associated symbol table and 33811618Srie * string table. 33821618Srie */ 33831618Srie if (stringtbl(cache, 1, cnt, shnum, file, 33841618Srie &symnum, &symsec, &strsec) == 0) 33851618Srie continue; 33861618Srie 33871618Srie syms = symsec->c_data->d_buf; 33881618Srie 33891618Srie /* 33901618Srie * Loop through the relocation entries. 33911618Srie */ 33921618Srie for (relndx = 0; relndx < relnum; relndx++, 33931618Srie rels = (void *)((char *)rels + relsize)) { 33941618Srie char section[BUFSIZ]; 33951618Srie Addr offset; 33960Sstevel@tonic-gate Got_info *gip; 33971618Srie Word symndx, reltype; 33981618Srie Rela *rela; 33991618Srie Rel *rel; 34000Sstevel@tonic-gate 34011618Srie /* 34021618Srie * Unravel the relocation. 34031618Srie */ 34041618Srie if (type == SHT_RELA) { 34051618Srie rela = (Rela *)rels; 34061618Srie symndx = ELF_R_SYM(rela->r_info); 34076206Sab196087 reltype = ELF_R_TYPE(rela->r_info, 34086206Sab196087 ehdr->e_machine); 34091618Srie offset = rela->r_offset; 34100Sstevel@tonic-gate } else { 34111618Srie rel = (Rel *)rels; 34121618Srie symndx = ELF_R_SYM(rel->r_info); 34136206Sab196087 reltype = ELF_R_TYPE(rel->r_info, 34146206Sab196087 ehdr->e_machine); 34151618Srie offset = rel->r_offset; 34160Sstevel@tonic-gate } 34170Sstevel@tonic-gate 34180Sstevel@tonic-gate /* 34190Sstevel@tonic-gate * Only pay attention to relocations against the GOT. 34200Sstevel@tonic-gate */ 34214146Sab196087 if ((offset < gotbgn) || (offset >= gotend)) 34220Sstevel@tonic-gate continue; 34230Sstevel@tonic-gate 34240Sstevel@tonic-gate /* LINTED */ 34251618Srie gotndx = (Word)((offset - gotbgn) / 34260Sstevel@tonic-gate gotshdr->sh_entsize); 34270Sstevel@tonic-gate gip = &gottable[gotndx]; 34281618Srie 34291618Srie if (gip->g_reltype != 0) { 34300Sstevel@tonic-gate (void) fprintf(stderr, 34310Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file, 34321618Srie EC_WORD(gotndx), EC_ADDR(offset)); 34330Sstevel@tonic-gate continue; 34340Sstevel@tonic-gate } 34350Sstevel@tonic-gate 34361618Srie if (symndx) 34371618Srie gip->g_symname = relsymname(cache, _cache, 34381618Srie strsec, symndx, symnum, relndx, syms, 34391618Srie section, BUFSIZ, file, flags); 34401618Srie gip->g_reltype = reltype; 34411618Srie gip->g_rel = rels; 34420Sstevel@tonic-gate } 34430Sstevel@tonic-gate } 34440Sstevel@tonic-gate 34456299Sab196087 if (symlookup(MSG_ORIG(MSG_SYM_GOT), cache, shnum, &gotsym, symtab, 34461618Srie file)) 34471618Srie gotsymaddr = gotsym->st_value; 34480Sstevel@tonic-gate else 34491618Srie gotsymaddr = gotbgn; 34500Sstevel@tonic-gate 34511618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 34521618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name); 34531618Srie Elf_got_title(0); 34540Sstevel@tonic-gate 34556206Sab196087 sys_encoding = _elf_sys_encoding(); 34560Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) { 34570Sstevel@tonic-gate Got_info *gip; 34580Sstevel@tonic-gate Sword gindex; 34591618Srie Addr gaddr; 34601618Srie Xword gotentry; 34610Sstevel@tonic-gate 34620Sstevel@tonic-gate gip = &gottable[gotndx]; 34630Sstevel@tonic-gate 34640Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize); 34651618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize; 34660Sstevel@tonic-gate 34671618Srie if (gentsize == sizeof (Word)) 34680Sstevel@tonic-gate /* LINTED */ 34691618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx)); 34700Sstevel@tonic-gate else 34710Sstevel@tonic-gate /* LINTED */ 34721618Srie gotentry = *((Xword *)(gotdata) + gotndx); 34730Sstevel@tonic-gate 34741618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine, 34756206Sab196087 ehdr->e_ident[EI_DATA], sys_encoding, 34761618Srie gip->g_reltype, gip->g_rel, gip->g_symname); 34770Sstevel@tonic-gate } 34780Sstevel@tonic-gate free(gottable); 34790Sstevel@tonic-gate } 34800Sstevel@tonic-gate 34810Sstevel@tonic-gate void 34820Sstevel@tonic-gate checksum(Elf *elf) 34830Sstevel@tonic-gate { 34841618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 34851618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf)); 34860Sstevel@tonic-gate } 34870Sstevel@tonic-gate 34884242Sab196087 /* 34894242Sab196087 * This variable is used by regular() to communicate the address of 34904242Sab196087 * the section header cache to sort_shdr_ndx_arr(). Unfortunately, 34914242Sab196087 * the qsort() interface does not include a userdata argument by which 34924242Sab196087 * such arbitrary data can be passed, so we are stuck using global data. 34934242Sab196087 */ 34944242Sab196087 static Cache *sort_shdr_ndx_arr_cache; 34954242Sab196087 34964242Sab196087 34974242Sab196087 /* 34984242Sab196087 * Used with qsort() to sort the section indices so that they can be 34994242Sab196087 * used to access the section headers in order of increasing data offset. 35004242Sab196087 * 35014242Sab196087 * entry: 35024242Sab196087 * sort_shdr_ndx_arr_cache - Contains address of 35034242Sab196087 * section header cache. 35044242Sab196087 * v1, v2 - Point at elements of sort_shdr_bits array to be compared. 35054242Sab196087 * 35064242Sab196087 * exit: 35074242Sab196087 * Returns -1 (less than), 0 (equal) or 1 (greater than). 35084242Sab196087 */ 35094242Sab196087 static int 35104242Sab196087 sort_shdr_ndx_arr(const void *v1, const void *v2) 35114242Sab196087 { 35124242Sab196087 Cache *cache1 = sort_shdr_ndx_arr_cache + *((size_t *)v1); 35134242Sab196087 Cache *cache2 = sort_shdr_ndx_arr_cache + *((size_t *)v2); 35144242Sab196087 35154242Sab196087 if (cache1->c_shdr->sh_offset < cache2->c_shdr->sh_offset) 35164242Sab196087 return (-1); 35174242Sab196087 35184242Sab196087 if (cache1->c_shdr->sh_offset > cache2->c_shdr->sh_offset) 35194242Sab196087 return (1); 35204242Sab196087 35214242Sab196087 return (0); 35224242Sab196087 } 35234242Sab196087 35244242Sab196087 35254665Sab196087 static int 35264665Sab196087 shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, 35274665Sab196087 size_t shnum, Cache **cache_ret) 35280Sstevel@tonic-gate { 35290Sstevel@tonic-gate Elf_Scn *scn; 35300Sstevel@tonic-gate Elf_Data *data; 35314665Sab196087 size_t ndx; 35324665Sab196087 Shdr *nameshdr; 35330Sstevel@tonic-gate char *names = 0; 35340Sstevel@tonic-gate Cache *cache, *_cache; 35354242Sab196087 size_t *shdr_ndx_arr, shdr_ndx_arr_cnt; 35360Sstevel@tonic-gate 35370Sstevel@tonic-gate 35380Sstevel@tonic-gate /* 35390Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section 35400Sstevel@tonic-gate * name strings. 35410Sstevel@tonic-gate */ 35424156Sab196087 if (shstrndx == SHN_UNDEF) { 35434156Sab196087 /* 35444156Sab196087 * It is rare, but legal, for an object to lack a 35454156Sab196087 * header string table section. 35464156Sab196087 */ 35474156Sab196087 names = NULL; 35484156Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHSTRSEC), file); 35494156Sab196087 } else if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 35500Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 35510Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 35520Sstevel@tonic-gate EC_XWORD(shstrndx)); 35531618Srie 35540Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) { 35550Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 35560Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 35570Sstevel@tonic-gate EC_XWORD(shstrndx)); 35581618Srie 35591618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) { 35600Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 35610Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 35623862Srie EC_WORD(elf_ndxscn(scn))); 35631618Srie 35641618Srie } else if ((names = data->d_buf) == 0) 35650Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 35660Sstevel@tonic-gate 35670Sstevel@tonic-gate /* 35683862Srie * Allocate a cache to maintain a descriptor for each section. 35690Sstevel@tonic-gate */ 35704665Sab196087 if ((*cache_ret = cache = malloc(shnum * sizeof (Cache))) == NULL) { 35710Sstevel@tonic-gate int err = errno; 35720Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 35730Sstevel@tonic-gate file, strerror(err)); 35744665Sab196087 return (0); 35750Sstevel@tonic-gate } 35760Sstevel@tonic-gate 35771618Srie *cache = cache_init; 35780Sstevel@tonic-gate _cache = cache; 35790Sstevel@tonic-gate _cache++; 35800Sstevel@tonic-gate 35813862Srie /* 35824242Sab196087 * Allocate an array that will hold the section index for 35834242Sab196087 * each section that has data in the ELF file: 35844242Sab196087 * 35854242Sab196087 * - Is not a NOBITS section 35864242Sab196087 * - Data has non-zero length 35874242Sab196087 * 35884242Sab196087 * Note that shnum is an upper bound on the size required. It 35894242Sab196087 * is likely that we won't use a few of these array elements. 35904242Sab196087 * Allocating a modest amount of extra memory in this case means 35914242Sab196087 * that we can avoid an extra loop to count the number of needed 35924242Sab196087 * items, and can fill this array immediately in the first loop 35934242Sab196087 * below. 35944242Sab196087 */ 35954242Sab196087 if ((shdr_ndx_arr = malloc(shnum * sizeof (*shdr_ndx_arr))) == NULL) { 35964242Sab196087 int err = errno; 35974242Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 35984242Sab196087 file, strerror(err)); 35994665Sab196087 return (0); 36004242Sab196087 } 36014242Sab196087 shdr_ndx_arr_cnt = 0; 36024242Sab196087 36034242Sab196087 /* 36043862Srie * Traverse the sections of the file. This gathering of data is 36053862Srie * carried out in two passes. First, the section headers are captured 36063862Srie * and the section header names are evaluated. A verification pass is 36073862Srie * then carried out over the section information. Files have been 36083862Srie * known to exhibit overlapping (and hence erroneous) section header 36093862Srie * information. 36103862Srie * 36113862Srie * Finally, the data for each section is obtained. This processing is 36123862Srie * carried out after section verification because should any section 36133862Srie * header overlap occur, and a file needs translating (ie. xlate'ing 36143862Srie * information from a non-native architecture file), then the process 36153862Srie * of translation can corrupt the section header information. Of 36163862Srie * course, if there is any section overlap, the data related to the 36173862Srie * sections is going to be compromised. However, it is the translation 36183862Srie * of this data that has caused problems with elfdump()'s ability to 36193862Srie * extract the data. 36203862Srie */ 36214242Sab196087 for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn); 36224242Sab196087 ndx++, _cache++) { 36233862Srie char scnndxnm[100]; 36243862Srie 36254242Sab196087 _cache->c_ndx = ndx; 36263862Srie _cache->c_scn = scn; 36273862Srie 36281618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) { 36290Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 36300Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 36313862Srie EC_WORD(elf_ndxscn(scn))); 36320Sstevel@tonic-gate } 36330Sstevel@tonic-gate 36343862Srie /* 36354242Sab196087 * If this section has data in the file, include it in 36364242Sab196087 * the array of sections to check for address overlap. 36374242Sab196087 */ 36384242Sab196087 if ((_cache->c_shdr->sh_size != 0) && 36394242Sab196087 (_cache->c_shdr->sh_type != SHT_NOBITS)) 36404242Sab196087 shdr_ndx_arr[shdr_ndx_arr_cnt++] = ndx; 36414242Sab196087 36424242Sab196087 /* 36433862Srie * If a shstrtab exists, assign the section name. 36443862Srie */ 36453862Srie if (names && _cache->c_shdr) { 36463862Srie if (_cache->c_shdr->sh_name && 36473862Srie /* LINTED */ 36483862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) { 36493862Srie _cache->c_name = 36503862Srie names + _cache->c_shdr->sh_name; 36513862Srie continue; 36523862Srie } 36530Sstevel@tonic-gate 36540Sstevel@tonic-gate /* 36553862Srie * Generate an error if the section name index is zero 36563862Srie * or exceeds the shstrtab data. Fall through to 36573862Srie * fabricate a section name. 36580Sstevel@tonic-gate */ 36593862Srie if ((_cache->c_shdr->sh_name == 0) || 36600Sstevel@tonic-gate /* LINTED */ 36611618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) { 36620Sstevel@tonic-gate (void) fprintf(stderr, 36630Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file, 36644242Sab196087 EC_WORD(ndx), 36651618Srie EC_XWORD(_cache->c_shdr->sh_name)); 36660Sstevel@tonic-gate } 36673862Srie } 36683862Srie 36693862Srie /* 36703862Srie * If there exists no shstrtab data, or a section header has no 36713862Srie * name (an invalid index of 0), then compose a name for the 36723862Srie * section. 36733862Srie */ 36743862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm), 36754242Sab196087 MSG_INTL(MSG_FMT_SCNNDX), ndx); 36764242Sab196087 36774242Sab196087 if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == NULL) { 36783862Srie int err = errno; 36793862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 36803862Srie file, strerror(err)); 36814665Sab196087 return (0); 36823862Srie } 36833862Srie (void) strcpy(_cache->c_name, scnndxnm); 36843862Srie } 36853862Srie 36863862Srie /* 36873862Srie * Having collected all the sections, validate their address range. 36883862Srie * Cases have existed where the section information has been invalid. 36893862Srie * This can lead to all sorts of other, hard to diagnose errors, as 36903862Srie * each section is processed individually (ie. with elf_getdata()). 36913862Srie * Here, we carry out some address comparisons to catch a family of 36923862Srie * overlapping memory issues we have observed (likely, there are others 36933862Srie * that we have yet to discover). 36943862Srie * 36953862Srie * Note, should any memory overlap occur, obtaining any additional 36963862Srie * data from the file is questionable. However, it might still be 36973862Srie * possible to inspect the ELF header, Programs headers, or individual 36983862Srie * sections, so rather than bailing on an error condition, continue 36993862Srie * processing to see if any data can be salvaged. 37003862Srie */ 37014242Sab196087 if (shdr_ndx_arr_cnt > 1) { 37024242Sab196087 sort_shdr_ndx_arr_cache = cache; 37034242Sab196087 qsort(shdr_ndx_arr, shdr_ndx_arr_cnt, 37044242Sab196087 sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr); 37054242Sab196087 } 37064242Sab196087 for (ndx = 0; ndx < shdr_ndx_arr_cnt; ndx++) { 37074242Sab196087 Cache *_cache = cache + shdr_ndx_arr[ndx]; 37083862Srie Shdr *shdr = _cache->c_shdr; 37093862Srie Off bgn1, bgn = shdr->sh_offset; 37103862Srie Off end1, end = shdr->sh_offset + shdr->sh_size; 37114242Sab196087 size_t ndx1; 37124242Sab196087 37134242Sab196087 /* 37144242Sab196087 * Check the section against all following ones, reporting 37154242Sab196087 * any overlaps. Since we've sorted the sections by offset, 37164242Sab196087 * we can stop after the first comparison that fails. There 37174242Sab196087 * are no overlaps in a properly formed ELF file, in which 37184242Sab196087 * case this algorithm runs in O(n) time. This will degenerate 37194242Sab196087 * to O(n^2) for a completely broken file. Such a file is 37204242Sab196087 * (1) highly unlikely, and (2) unusable, so it is reasonable 37214242Sab196087 * for the analysis to take longer. 37224242Sab196087 */ 37234242Sab196087 for (ndx1 = ndx + 1; ndx1 < shdr_ndx_arr_cnt; ndx1++) { 37244242Sab196087 Cache *_cache1 = cache + shdr_ndx_arr[ndx1]; 37253862Srie Shdr *shdr1 = _cache1->c_shdr; 37263862Srie 37273862Srie bgn1 = shdr1->sh_offset; 37283862Srie end1 = shdr1->sh_offset + shdr1->sh_size; 37293862Srie 37303862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 37313862Srie ((bgn1 < end) && (end1 >= end))) { 37323862Srie (void) fprintf(stderr, 37333862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file, 37344242Sab196087 EC_WORD(elf_ndxscn(_cache->c_scn)), 37354242Sab196087 _cache->c_name, EC_OFF(bgn), EC_OFF(end), 37363862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)), 37374242Sab196087 _cache1->c_name, EC_OFF(bgn1), 37384242Sab196087 EC_OFF(end1)); 37394242Sab196087 } else { /* No overlap, so can stop */ 37404242Sab196087 break; 37410Sstevel@tonic-gate } 37420Sstevel@tonic-gate } 37430Sstevel@tonic-gate 37443862Srie /* 37454242Sab196087 * In addition to checking for sections overlapping 37464242Sab196087 * each other (done above), we should also make sure 37474242Sab196087 * the section doesn't overlap the section header array. 37483862Srie */ 37493862Srie bgn1 = ehdr->e_shoff; 37503862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum); 37513862Srie 37523862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 37533862Srie ((bgn1 < end) && (end1 >= end))) { 37543862Srie (void) fprintf(stderr, 37553862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1), 37563862Srie EC_OFF(end1), 37573862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 37583862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 37593862Srie } 37603862Srie } 37613862Srie 37623862Srie /* 37634242Sab196087 * Obtain the data for each section. 37643862Srie */ 37654242Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 37664242Sab196087 Cache *_cache = &cache[ndx]; 37673862Srie Elf_Scn *scn = _cache->c_scn; 37683862Srie 37690Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 37700Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 37710Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 37723862Srie EC_WORD(elf_ndxscn(scn))); 37730Sstevel@tonic-gate } 37744665Sab196087 } 37754665Sab196087 37764665Sab196087 return (1); 37774665Sab196087 } 37784665Sab196087 37794665Sab196087 37804665Sab196087 37815411Sab196087 int 37825411Sab196087 regular(const char *file, int fd, Elf *elf, uint_t flags, 37835411Sab196087 const char *wname, int wfd) 37844665Sab196087 { 37854665Sab196087 Elf_Scn *scn; 37864665Sab196087 Ehdr *ehdr; 37874665Sab196087 size_t ndx, shstrndx, shnum, phnum; 37884665Sab196087 Shdr *shdr; 37894665Sab196087 Cache *cache; 37904665Sab196087 VERSYM_STATE versym; 37915411Sab196087 int ret = 0; 37925411Sab196087 int addr_align; 37934665Sab196087 37944665Sab196087 if ((ehdr = elf_getehdr(elf)) == NULL) { 37954665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 37965411Sab196087 return (ret); 37974665Sab196087 } 37984665Sab196087 37994665Sab196087 if (elf_getshnum(elf, &shnum) == 0) { 38004665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 38015411Sab196087 return (ret); 38024665Sab196087 } 38034665Sab196087 38044665Sab196087 if (elf_getshstrndx(elf, &shstrndx) == 0) { 38054665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 38065411Sab196087 return (ret); 38074665Sab196087 } 38084665Sab196087 38094665Sab196087 if (elf_getphnum(elf, &phnum) == 0) { 38104665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 38115411Sab196087 return (ret); 38124665Sab196087 } 38134665Sab196087 /* 38144665Sab196087 * If the user requested section headers derived from the 38154665Sab196087 * program headers (-P option) and this file doesn't have 38164665Sab196087 * any program headers (i.e. ET_REL), then we can't do it. 38174665Sab196087 */ 38185411Sab196087 if ((phnum == 0) && (flags & FLG_CTL_FAKESHDR)) { 38194665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_PNEEDSPH), file); 38205411Sab196087 return (ret); 38214665Sab196087 } 38224665Sab196087 38234665Sab196087 38244665Sab196087 if ((scn = elf_getscn(elf, 0)) != NULL) { 38254665Sab196087 if ((shdr = elf_getshdr(scn)) == NULL) { 38264665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 38274665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 38285411Sab196087 return (ret); 38294665Sab196087 } 38304665Sab196087 } else 38314665Sab196087 shdr = 0; 38324665Sab196087 38334665Sab196087 /* 38344665Sab196087 * Print the elf header. 38354665Sab196087 */ 38365411Sab196087 if (flags & FLG_SHOW_EHDR) 38374665Sab196087 Elf_ehdr(0, ehdr, shdr); 38384665Sab196087 38394665Sab196087 /* 38404665Sab196087 * If the section headers or program headers have inadequate 38414665Sab196087 * alignment for the class of object, print a warning. libelf 38424665Sab196087 * can handle such files, but programs that use them can crash 38434665Sab196087 * when they dereference unaligned items. 38445411Sab196087 * 38455411Sab196087 * Note that the AMD64 ABI, although it is a 64-bit architecture, 38465411Sab196087 * allows access to data types smaller than 128-bits to be on 38475411Sab196087 * word alignment. 38484665Sab196087 */ 38495411Sab196087 if (ehdr->e_machine == EM_AMD64) 38505411Sab196087 addr_align = sizeof (Word); 38515411Sab196087 else 38525411Sab196087 addr_align = sizeof (Addr); 38535411Sab196087 38545411Sab196087 if (ehdr->e_phoff & (addr_align - 1)) 38554665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADPHDRALIGN), file); 38565411Sab196087 if (ehdr->e_shoff & (addr_align - 1)) 38574665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHDRALIGN), file); 38584665Sab196087 38594665Sab196087 /* 38604665Sab196087 * Print the program headers. 38614665Sab196087 */ 38625411Sab196087 if ((flags & FLG_SHOW_PHDR) && (phnum != 0)) { 38635411Sab196087 Phdr *phdr; 38644665Sab196087 38654665Sab196087 if ((phdr = elf_getphdr(elf)) == NULL) { 38664665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 38675411Sab196087 return (ret); 38684665Sab196087 } 38694665Sab196087 38704665Sab196087 for (ndx = 0; ndx < phnum; phdr++, ndx++) { 38715411Sab196087 if (!match(MATCH_F_PHDR| MATCH_F_NDX | MATCH_F_TYPE, 38725411Sab196087 NULL, ndx, phdr->p_type)) 38734665Sab196087 continue; 38744665Sab196087 38754665Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 38764665Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx)); 38774665Sab196087 Elf_phdr(0, ehdr->e_machine, phdr); 38784665Sab196087 } 38794665Sab196087 } 38804665Sab196087 38814665Sab196087 /* 38825411Sab196087 * If we have flag bits set that explicitly require a show or calc 38835411Sab196087 * operation, but none of them require the section headers, then 38845411Sab196087 * we are done and can return now. 38854665Sab196087 */ 38865411Sab196087 if (((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) != 0) && 38875411Sab196087 ((flags & (FLG_MASK_SHOW_SHDR | FLG_MASK_CALC_SHDR)) == 0)) 38885411Sab196087 return (ret); 38895411Sab196087 38905411Sab196087 /* 38915411Sab196087 * If there are no section headers, then resort to synthesizing 38925411Sab196087 * section headers from the program headers. This is normally 38935411Sab196087 * only done by explicit request, but in this case there's no 38945411Sab196087 * reason not to go ahead, since the alternative is simply to quit. 38955411Sab196087 */ 38965411Sab196087 if ((shnum <= 1) && ((flags & FLG_CTL_FAKESHDR) == 0)) { 38975411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHDR), file); 38985411Sab196087 flags |= FLG_CTL_FAKESHDR; 38994665Sab196087 } 39004665Sab196087 39014665Sab196087 /* 39024665Sab196087 * Generate a cache of section headers and related information 39034665Sab196087 * for use by the rest of elfdump. If requested (or the file 39044665Sab196087 * contains no section headers), we generate a fake set of 39054665Sab196087 * headers from the information accessible from the program headers. 39064665Sab196087 * Otherwise, we use the real section headers contained in the file. 39074665Sab196087 */ 39084665Sab196087 39095411Sab196087 if (flags & FLG_CTL_FAKESHDR) { 39104665Sab196087 if (fake_shdr_cache(file, fd, elf, ehdr, &cache, &shnum) == 0) 39115411Sab196087 return (ret); 39124665Sab196087 } else { 39134665Sab196087 if (shdr_cache(file, elf, ehdr, shstrndx, shnum, &cache) == 0) 39145411Sab196087 return (ret); 39154665Sab196087 } 39164665Sab196087 39174665Sab196087 /* 39185411Sab196087 * Everything from this point on requires section headers. 39195411Sab196087 * If we have no section headers, there is no reason to continue. 39205411Sab196087 */ 39215411Sab196087 if (shnum <= 1) 39225411Sab196087 goto done; 39235411Sab196087 39245411Sab196087 /* 39254665Sab196087 * If -w was specified, find and write out the section(s) data. 39264665Sab196087 */ 39274665Sab196087 if (wfd) { 39284665Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 39294665Sab196087 Cache *_cache = &cache[ndx]; 39304665Sab196087 39315411Sab196087 if (match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 39325411Sab196087 ndx, _cache->c_shdr->sh_type) && 39335411Sab196087 _cache->c_data && _cache->c_data->d_buf) { 39345411Sab196087 if (write(wfd, _cache->c_data->d_buf, 39355411Sab196087 _cache->c_data->d_size) != 39365411Sab196087 _cache->c_data->d_size) { 39375411Sab196087 int err = errno; 39385411Sab196087 (void) fprintf(stderr, 39395411Sab196087 MSG_INTL(MSG_ERR_WRITE), wname, 39405411Sab196087 strerror(err)); 39415411Sab196087 /* 39425411Sab196087 * Return an exit status of 1, because 39435411Sab196087 * the failure is not related to the 39445411Sab196087 * ELF file, but by system resources. 39455411Sab196087 */ 39465411Sab196087 ret = 1; 39475411Sab196087 goto done; 39485411Sab196087 } 39494665Sab196087 } 39500Sstevel@tonic-gate } 39510Sstevel@tonic-gate } 39520Sstevel@tonic-gate 39535411Sab196087 /* 39545411Sab196087 * If we have no flag bits set that explicitly require a show or calc 39555411Sab196087 * operation, but match options (-I, -N, -T) were used, then run 39565411Sab196087 * through the section headers and see if we can't deduce show flags 39575411Sab196087 * from the match options given. 39585411Sab196087 * 39595411Sab196087 * We don't do this if -w was specified, because (-I, -N, -T) used 39605411Sab196087 * with -w in lieu of some other option is supposed to be quiet. 39615411Sab196087 */ 39625411Sab196087 if ((wfd == 0) && (flags & FLG_CTL_MATCH) && 39635411Sab196087 ((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) == 0)) { 39645411Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 39655411Sab196087 Cache *_cache = &cache[ndx]; 39665411Sab196087 39675411Sab196087 if (!match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name, 39685411Sab196087 ndx, _cache->c_shdr->sh_type)) 39695411Sab196087 continue; 39705411Sab196087 39715411Sab196087 switch (_cache->c_shdr->sh_type) { 39725411Sab196087 case SHT_PROGBITS: 39735411Sab196087 /* 39745411Sab196087 * Heuristic time: It is usually bad form 39755411Sab196087 * to assume that specific section names 39765411Sab196087 * have a given meaning. However, the 39775411Sab196087 * ELF ABI does specify a few such names. Try 39785411Sab196087 * to match them: 39795411Sab196087 */ 39805411Sab196087 if (strcmp(_cache->c_name, 39815411Sab196087 MSG_ORIG(MSG_ELF_INTERP)) == 0) 39825411Sab196087 flags |= FLG_SHOW_INTERP; 39835411Sab196087 else if (strcmp(_cache->c_name, 39845411Sab196087 MSG_ORIG(MSG_ELF_GOT)) == 0) 39855411Sab196087 flags |= FLG_SHOW_GOT; 39865411Sab196087 break; 39875411Sab196087 39885411Sab196087 case SHT_SYMTAB: 39895411Sab196087 case SHT_DYNSYM: 39905411Sab196087 case SHT_SUNW_LDYNSYM: 39915411Sab196087 case SHT_SUNW_versym: 39925411Sab196087 case SHT_SYMTAB_SHNDX: 39935411Sab196087 flags |= FLG_SHOW_SYMBOLS; 39945411Sab196087 break; 39955411Sab196087 39965411Sab196087 case SHT_RELA: 39975411Sab196087 case SHT_REL: 39985411Sab196087 flags |= FLG_SHOW_RELOC; 39995411Sab196087 break; 40005411Sab196087 40015411Sab196087 case SHT_HASH: 40025411Sab196087 flags |= FLG_SHOW_HASH; 40035411Sab196087 break; 40045411Sab196087 40055411Sab196087 case SHT_DYNAMIC: 40065411Sab196087 flags |= FLG_SHOW_DYNAMIC; 40075411Sab196087 break; 40085411Sab196087 40095411Sab196087 case SHT_NOTE: 40105411Sab196087 flags |= FLG_SHOW_NOTE; 40115411Sab196087 break; 40125411Sab196087 40135411Sab196087 case SHT_GROUP: 40145411Sab196087 flags |= FLG_SHOW_GROUP; 40155411Sab196087 break; 40165411Sab196087 40175411Sab196087 case SHT_SUNW_symsort: 40185411Sab196087 case SHT_SUNW_tlssort: 40195411Sab196087 flags |= FLG_SHOW_SORT; 40205411Sab196087 break; 40215411Sab196087 40225411Sab196087 case SHT_SUNW_cap: 40235411Sab196087 flags |= FLG_SHOW_CAP; 40245411Sab196087 break; 40255411Sab196087 40265411Sab196087 case SHT_SUNW_move: 40275411Sab196087 flags |= FLG_SHOW_MOVE; 40285411Sab196087 break; 40295411Sab196087 40305411Sab196087 case SHT_SUNW_syminfo: 40315411Sab196087 flags |= FLG_SHOW_SYMINFO; 40325411Sab196087 break; 40335411Sab196087 40345411Sab196087 case SHT_SUNW_verdef: 40355411Sab196087 case SHT_SUNW_verneed: 40365411Sab196087 flags |= FLG_SHOW_VERSIONS; 40375411Sab196087 break; 40385411Sab196087 40395411Sab196087 case SHT_AMD64_UNWIND: 40405411Sab196087 flags |= FLG_SHOW_UNWIND; 40415411Sab196087 break; 40425411Sab196087 } 40435411Sab196087 } 40445411Sab196087 } 40455411Sab196087 40465411Sab196087 40475411Sab196087 if (flags & FLG_SHOW_SHDR) 40484168Sab196087 sections(file, cache, shnum, ehdr); 40490Sstevel@tonic-gate 40505411Sab196087 if (flags & FLG_SHOW_INTERP) 40511618Srie interp(file, cache, shnum, phnum, elf); 40520Sstevel@tonic-gate 40533875Sab196087 versions(cache, shnum, file, flags, &versym); 40540Sstevel@tonic-gate 40555411Sab196087 if (flags & FLG_SHOW_SYMBOLS) 40564168Sab196087 symbols(cache, shnum, ehdr, &versym, file, flags); 40570Sstevel@tonic-gate 40585411Sab196087 if (flags & FLG_SHOW_SORT) 40594168Sab196087 sunw_sort(cache, shnum, ehdr, &versym, file, flags); 40603492Sab196087 40615411Sab196087 if (flags & FLG_SHOW_HASH) 40624168Sab196087 hash(cache, shnum, file, flags); 40630Sstevel@tonic-gate 40645411Sab196087 if (flags & FLG_SHOW_GOT) 40651618Srie got(cache, shnum, ehdr, file, flags); 40660Sstevel@tonic-gate 40675411Sab196087 if (flags & FLG_SHOW_GROUP) 40684168Sab196087 group(cache, shnum, file, flags); 40690Sstevel@tonic-gate 40705411Sab196087 if (flags & FLG_SHOW_SYMINFO) 40710Sstevel@tonic-gate syminfo(cache, shnum, file); 40720Sstevel@tonic-gate 40735411Sab196087 if (flags & FLG_SHOW_RELOC) 40744168Sab196087 reloc(cache, shnum, ehdr, file, flags); 40750Sstevel@tonic-gate 40765411Sab196087 if (flags & FLG_SHOW_DYNAMIC) 40771618Srie dynamic(cache, shnum, ehdr, file); 40780Sstevel@tonic-gate 4079*6635Sab196087 if (flags & FLG_SHOW_NOTE) { 4080*6635Sab196087 Word note_cnt; 4081*6635Sab196087 size_t note_shnum; 4082*6635Sab196087 Cache *note_cache; 4083*6635Sab196087 4084*6635Sab196087 note_cnt = note(cache, shnum, ehdr, file); 4085*6635Sab196087 4086*6635Sab196087 /* 4087*6635Sab196087 * Solaris core files have section headers, but these 4088*6635Sab196087 * headers do not include SHT_NOTE sections that reference 4089*6635Sab196087 * the core note sections. This means that note() won't 4090*6635Sab196087 * find the core notes. Fake section headers (-P option) 4091*6635Sab196087 * recover these sections, but it is inconvenient to require 4092*6635Sab196087 * users to specify -P in this situation. If the following 4093*6635Sab196087 * are all true: 4094*6635Sab196087 * 4095*6635Sab196087 * - No note sections were found 4096*6635Sab196087 * - This is a core file 4097*6635Sab196087 * - We are not already using fake section headers 4098*6635Sab196087 * 4099*6635Sab196087 * then we will automatically generate fake section headers 4100*6635Sab196087 * and then process them in a second call to note(). 4101*6635Sab196087 */ 4102*6635Sab196087 if ((note_cnt == 0) && (ehdr->e_type == ET_CORE) && 4103*6635Sab196087 !(flags & FLG_CTL_FAKESHDR) && 4104*6635Sab196087 (fake_shdr_cache(file, fd, elf, ehdr, 4105*6635Sab196087 ¬e_cache, ¬e_shnum) != 0)) { 4106*6635Sab196087 (void) note(note_cache, note_shnum, ehdr, file); 4107*6635Sab196087 fake_shdr_cache_free(note_cache, note_shnum); 4108*6635Sab196087 } 4109*6635Sab196087 } 41100Sstevel@tonic-gate 41115411Sab196087 if (flags & FLG_SHOW_MOVE) 41124168Sab196087 move(cache, shnum, file, flags); 41130Sstevel@tonic-gate 41145411Sab196087 if (flags & FLG_CALC_CHECKSUM) 41150Sstevel@tonic-gate checksum(elf); 41160Sstevel@tonic-gate 41175411Sab196087 if (flags & FLG_SHOW_CAP) 41181618Srie cap(file, cache, shnum, phnum, ehdr, elf); 41190Sstevel@tonic-gate 41205411Sab196087 if (flags & FLG_SHOW_UNWIND) 41214168Sab196087 unwind(cache, shnum, phnum, ehdr, file, elf); 41220Sstevel@tonic-gate 41234665Sab196087 41244665Sab196087 /* Release the memory used to cache section headers */ 41255411Sab196087 done: 41265411Sab196087 if (flags & FLG_CTL_FAKESHDR) 41274665Sab196087 fake_shdr_cache_free(cache, shnum); 41284665Sab196087 else 41294665Sab196087 free(cache); 41305411Sab196087 41315411Sab196087 return (ret); 41320Sstevel@tonic-gate } 4133