10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51618Srie * Common Development and Distribution License (the "License"). 61618Srie * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211324Srie 220Sstevel@tonic-gate /* 233466Srie * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate /* 290Sstevel@tonic-gate * Dump an elf file. 300Sstevel@tonic-gate */ 311618Srie #include <machdep.h> 321618Srie #include <sys/elf_386.h> 331618Srie #include <sys/elf_amd64.h> 341618Srie #include <sys/elf_SPARC.h> 351618Srie #include <dwarf.h> 360Sstevel@tonic-gate #include <unistd.h> 370Sstevel@tonic-gate #include <errno.h> 380Sstevel@tonic-gate #include <strings.h> 390Sstevel@tonic-gate #include <debug.h> 400Sstevel@tonic-gate #include <conv.h> 410Sstevel@tonic-gate #include <msg.h> 421618Srie #include <_elfdump.h> 430Sstevel@tonic-gate 443875Sab196087 453875Sab196087 463875Sab196087 /* 473875Sab196087 * VERSYM_STATE is used to maintain information about the VERSYM section 483875Sab196087 * in the object being analyzed. It is filled in by versions(), and used 493875Sab196087 * by init_symtbl_state() when displaying symbol information. 503875Sab196087 * 513875Sab196087 * Note that the value of the gnu field is a hueristic guess, 523875Sab196087 * based on the section names. 533875Sab196087 */ 543875Sab196087 typedef struct { 553875Sab196087 Cache *cache; /* Pointer to cache entry for VERSYM */ 563875Sab196087 Versym *data; /* Pointer to versym array */ 573875Sab196087 int num_verdef; /* # of versions defined in object */ 583875Sab196087 int gnu; /* True if we think obj produced by GNU tools */ 593875Sab196087 } VERSYM_STATE; 603875Sab196087 613875Sab196087 /* 623875Sab196087 * SYMTBL_STATE is used to maintain information about a single symbol 633875Sab196087 * table section, for use by the routines that display symbol information. 643875Sab196087 */ 653875Sab196087 typedef struct { 663875Sab196087 const char *file; /* Name of file */ 673875Sab196087 Ehdr *ehdr; /* ELF header for file */ 683875Sab196087 Cache *cache; /* Cache of all section headers */ 693875Sab196087 Word shnum; /* # of sections in cache */ 703875Sab196087 Cache *seccache; /* Cache of symbol table section hdr */ 713875Sab196087 Word secndx; /* Index of symbol table section hdr */ 723875Sab196087 const char *secname; /* Name of section */ 733875Sab196087 uint_t flags; /* Command line option flags */ 743875Sab196087 struct { /* Extended section index data */ 753875Sab196087 int checked; /* TRUE if already checked for shxndx */ 763875Sab196087 Word *data; /* NULL, or extended section index */ 773875Sab196087 /* used for symbol table entries */ 783875Sab196087 uint_t n; /* # items in shxndx.data */ 793875Sab196087 } shxndx; 803875Sab196087 VERSYM_STATE *versym; /* NULL, or associated VERSYM section */ 813875Sab196087 Sym *sym; /* Array of symbols */ 823875Sab196087 Word symn; /* # of symbols */ 833875Sab196087 } SYMTBL_STATE; 843875Sab196087 853875Sab196087 863875Sab196087 870Sstevel@tonic-gate /* 880Sstevel@tonic-gate * Focal point for verifying symbol names. 890Sstevel@tonic-gate */ 900Sstevel@tonic-gate static const char * 911618Srie string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name) 920Sstevel@tonic-gate { 934063Sab196087 /* 944063Sab196087 * If an error in this routine is due to a property of the string 954063Sab196087 * section, as opposed to a bad offset into the section (a property of 964063Sab196087 * the referencing section), then we will detect the same error on 974063Sab196087 * every call involving those sections. We use these static variables 984063Sab196087 * to retain the information needed to only issue each such error once. 994063Sab196087 */ 1004063Sab196087 static Cache *last_refsec; /* Last referencing section seen */ 1014063Sab196087 static int strsec_err; /* True if error issued */ 1024063Sab196087 1033492Sab196087 const char *strs; 1043492Sab196087 Word strn; 1050Sstevel@tonic-gate 1063466Srie if (strsec->c_data == NULL) 1073466Srie return (NULL); 1083466Srie 1093492Sab196087 strs = (char *)strsec->c_data->d_buf; 1103492Sab196087 strn = strsec->c_data->d_size; 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate /* 1134063Sab196087 * We only print a diagnostic regarding a bad string table once per 1144063Sab196087 * input section being processed. If the refsec has changed, reset 1154063Sab196087 * our retained error state. 1160Sstevel@tonic-gate */ 1174063Sab196087 if (last_refsec != refsec) { 1184063Sab196087 last_refsec = refsec; 1194063Sab196087 strsec_err = 0; 1204063Sab196087 } 1214063Sab196087 1224063Sab196087 /* Verify that strsec really is a string table */ 1234063Sab196087 if (strsec->c_shdr->sh_type != SHT_STRTAB) { 1244063Sab196087 if (!strsec_err) { 1254063Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOTSTRTAB), 1264063Sab196087 file, strsec->c_ndx, refsec->c_ndx); 1274063Sab196087 strsec_err = 1; 1284063Sab196087 } 1294063Sab196087 return (MSG_INTL(MSG_STR_UNKNOWN)); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* 1330Sstevel@tonic-gate * Is the string table offset within range of the available strings? 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate if (name >= strn) { 1360Sstevel@tonic-gate /* 1370Sstevel@tonic-gate * Do we have a empty string table? 1380Sstevel@tonic-gate */ 1390Sstevel@tonic-gate if (strs == 0) { 1404063Sab196087 if (!strsec_err) { 1410Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1420Sstevel@tonic-gate file, strsec->c_name); 1434063Sab196087 strsec_err = 1; 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate } else { 1460Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF), 1471618Srie file, refsec->c_name, EC_WORD(ndx), strsec->c_name, 1481618Srie EC_WORD(name), EC_WORD(strn - 1)); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * Return the empty string so that the calling function can 1530Sstevel@tonic-gate * continue it's output diagnostics. 1540Sstevel@tonic-gate */ 1550Sstevel@tonic-gate return (MSG_INTL(MSG_STR_UNKNOWN)); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate return (strs + name); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* 1611618Srie * Relocations can reference section symbols and standard symbols. If the 1621618Srie * former, establish the section name. 1631618Srie */ 1641618Srie static const char * 1651618Srie relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum, 1661618Srie Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file, 1671618Srie uint_t flags) 1681618Srie { 1691618Srie Sym *sym; 1701618Srie 1711618Srie if (symndx >= symnum) { 1721618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX), 1731618Srie file, EC_WORD(symndx), EC_WORD(relndx)); 1741618Srie return (MSG_INTL(MSG_STR_UNKNOWN)); 1751618Srie } 1761618Srie 1771618Srie sym = (Sym *)(syms + symndx); 1781618Srie 1791618Srie /* 1801618Srie * If the symbol represents a section offset construct an appropriate 1811618Srie * string. 1821618Srie */ 1831618Srie if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) && (sym->st_name == 0)) { 1841618Srie if (flags & FLG_LONGNAME) 1851618Srie (void) snprintf(secstr, secsz, 1861618Srie MSG_INTL(MSG_STR_L_SECTION), 1871618Srie cache[sym->st_shndx].c_name); 1881618Srie else 1891618Srie (void) snprintf(secstr, secsz, 1901618Srie MSG_INTL(MSG_STR_SECTION), 1911618Srie cache[sym->st_shndx].c_name); 1921618Srie return ((const char *)secstr); 1931618Srie } 1941618Srie 1951618Srie return (string(csec, symndx, strsec, file, sym->st_name)); 1961618Srie } 1971618Srie 1981618Srie /* 1991618Srie * Focal point for establishing a string table section. Data such as the 2001618Srie * dynamic information simply points to a string table. Data such as 2011618Srie * relocations, reference a symbol table, which in turn is associated with a 2021618Srie * string table. 2030Sstevel@tonic-gate */ 2040Sstevel@tonic-gate static int 2051618Srie stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file, 2061618Srie Word *symnum, Cache **symsec, Cache **strsec) 2071618Srie { 2081618Srie Shdr *shdr = cache[ndx].c_shdr; 2091618Srie 2101618Srie if (symtab) { 2111618Srie /* 2121618Srie * Validate the symbol table section. 2131618Srie */ 2141618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2151618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2161618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 2171618Srie return (0); 2181618Srie } 2193466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2203466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2213466Srie file, cache[ndx].c_name); 2223466Srie return (0); 2233466Srie } 2241618Srie 2251618Srie /* 2261618Srie * Obtain, and verify the symbol table data. 2271618Srie */ 2283466Srie if ((cache[ndx].c_data == NULL) || 2293466Srie (cache[ndx].c_data->d_buf == NULL)) { 2301618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2311618Srie file, cache[ndx].c_name); 2321618Srie return (0); 2331618Srie } 2341618Srie 2351618Srie /* 2361618Srie * Establish the string table index. 2371618Srie */ 2381618Srie ndx = shdr->sh_link; 2391618Srie shdr = cache[ndx].c_shdr; 2401618Srie 2411618Srie /* 2421618Srie * Return symbol table information. 2431618Srie */ 2441618Srie if (symnum) 2451618Srie *symnum = (shdr->sh_size / shdr->sh_entsize); 2461618Srie if (symsec) 2471618Srie *symsec = &cache[ndx]; 2481618Srie } 2491618Srie 2501618Srie /* 2511618Srie * Validate the associated string table section. 2521618Srie */ 2531618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2541618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2551618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 2561618Srie return (0); 2571618Srie } 2581618Srie 2591618Srie if (strsec) 2601618Srie *strsec = &cache[shdr->sh_link]; 2611618Srie 2621618Srie return (1); 2631618Srie } 2641618Srie 2651618Srie /* 2661618Srie * Lookup a symbol and set Sym accordingly. 2671618Srie */ 2681618Srie static int 2691618Srie symlookup(const char *name, Cache *cache, Word shnum, Sym **sym, 2700Sstevel@tonic-gate Cache *symtab, const char *file) 2710Sstevel@tonic-gate { 2721618Srie Shdr *shdr; 2731618Srie Word symn, cnt; 2741618Srie Sym *syms; 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate if (symtab == 0) 2770Sstevel@tonic-gate return (0); 2780Sstevel@tonic-gate 2791618Srie shdr = symtab->c_shdr; 2801618Srie 2810Sstevel@tonic-gate /* 2820Sstevel@tonic-gate * Determine the symbol data and number. 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2850Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2860Sstevel@tonic-gate file, symtab->c_name); 2870Sstevel@tonic-gate return (0); 2880Sstevel@tonic-gate } 2893466Srie if (symtab->c_data == NULL) 2903466Srie return (0); 2913466Srie 2920Sstevel@tonic-gate /* LINTED */ 2931618Srie symn = (Word)(shdr->sh_size / shdr->sh_entsize); 2941618Srie syms = (Sym *)symtab->c_data->d_buf; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /* 2970Sstevel@tonic-gate * Get the associated string table section. 2980Sstevel@tonic-gate */ 2990Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 3000Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 3011618Srie file, symtab->c_name, EC_WORD(shdr->sh_link)); 3020Sstevel@tonic-gate return (0); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate /* 3060Sstevel@tonic-gate * Loop through the symbol table to find a match. 3070Sstevel@tonic-gate */ 3081618Srie for (cnt = 0; cnt < symn; syms++, cnt++) { 3091618Srie const char *symname; 3100Sstevel@tonic-gate 3111618Srie symname = string(symtab, cnt, &cache[shdr->sh_link], file, 3121618Srie syms->st_name); 3130Sstevel@tonic-gate 3141618Srie if (symname && (strcmp(name, symname) == 0)) { 3151618Srie *sym = syms; 3160Sstevel@tonic-gate return (1); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate } 3190Sstevel@tonic-gate return (0); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * Print section headers. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate static void 3264168Sab196087 sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr) 3270Sstevel@tonic-gate { 3281618Srie size_t seccnt; 3290Sstevel@tonic-gate 3301618Srie for (seccnt = 1; seccnt < shnum; seccnt++) { 3311618Srie Cache *_cache = &cache[seccnt]; 3321618Srie Shdr *shdr = _cache->c_shdr; 3331618Srie const char *secname = _cache->c_name; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * Although numerous section header entries can be zero, it's 3373862Srie * usually a sign of trouble if the type is zero. 3380Sstevel@tonic-gate */ 3390Sstevel@tonic-gate if (shdr->sh_type == 0) { 3400Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE), 3411618Srie file, secname, EC_WORD(shdr->sh_type)); 3420Sstevel@tonic-gate } 3433862Srie 3444168Sab196087 if (!match(0, secname, seccnt)) 3453862Srie continue; 3460Sstevel@tonic-gate 3471324Srie /* 3481324Srie * Identify any sections that are suspicious. A .got section 3491324Srie * shouldn't exist in a relocatable object. 3501324Srie */ 3511324Srie if (ehdr->e_type == ET_REL) { 3521618Srie if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT), 3531324Srie MSG_ELF_GOT_SIZE) == 0) { 3541324Srie (void) fprintf(stderr, 3551618Srie MSG_INTL(MSG_GOT_UNEXPECTED), file, 3561618Srie secname); 3571324Srie } 3581324Srie } 3591324Srie 3601618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 3611618Srie dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname); 3621618Srie Elf_shdr(0, ehdr->e_machine, shdr); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3661618Srie /* 3671618Srie * A couple of instances of unwind data are printed as tables of 8 data items 3681618Srie * expressed as 0x?? integers. 3691618Srie */ 3701618Srie #define UNWINDTBLSZ 10 + (8 * 5) + 1 3711618Srie 3721618Srie static void 3731618Srie unwindtbl(uint64_t *ndx, uint_t len, uchar_t *data, uint64_t doff, 3741618Srie const char *msg, const char *pre, size_t plen) 3751618Srie { 3761618Srie char buffer[UNWINDTBLSZ]; 3771618Srie uint_t boff = plen, cnt = 0; 3781618Srie 3791618Srie dbg_print(0, msg); 3801618Srie (void) strncpy(buffer, pre, UNWINDTBLSZ); 3811618Srie 3821618Srie while (*ndx < (len + 4)) { 3831618Srie if (cnt == 8) { 3841618Srie dbg_print(0, buffer); 3851618Srie boff = plen; 3861618Srie cnt = 0; 3871618Srie } 3881618Srie (void) snprintf(&buffer[boff], UNWINDTBLSZ - boff, 3891618Srie MSG_ORIG(MSG_UNW_TBLENTRY), data[doff + (*ndx)++]); 3901618Srie boff += 5; 3911618Srie cnt++; 3921618Srie } 3931618Srie if (cnt) 3941618Srie dbg_print(0, buffer); 3951618Srie } 3961618Srie 3971618Srie /* 3981618Srie * Obtain a specified Phdr entry. 3991618Srie */ 4001618Srie static Phdr * 4011618Srie getphdr(Word phnum, Word type, const char *file, Elf *elf) 4021618Srie { 4031618Srie Word cnt; 4041618Srie Phdr *phdr; 4051618Srie 4061618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 4071618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 4081618Srie return (0); 4091618Srie } 4101618Srie 4111618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 4121618Srie if (phdr->p_type == type) 4131618Srie return (phdr); 4141618Srie } 4151618Srie return (0); 4161618Srie } 4171618Srie 4180Sstevel@tonic-gate static void 4194168Sab196087 unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *file, 4204168Sab196087 Elf *elf) 4210Sstevel@tonic-gate { 4221618Srie Word cnt; 4231618Srie Phdr *uphdr = 0; 4241618Srie 4250Sstevel@tonic-gate /* 4261618Srie * For the moment - UNWIND is only relevant for a AMD64 object. 4270Sstevel@tonic-gate */ 4280Sstevel@tonic-gate if (ehdr->e_machine != EM_AMD64) 4291618Srie return; 4300Sstevel@tonic-gate 4311618Srie if (phnum) 4321618Srie uphdr = getphdr(phnum, PT_SUNW_UNWIND, file, elf); 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 4351618Srie Cache *_cache = &cache[cnt]; 4361618Srie Shdr *shdr = _cache->c_shdr; 4371618Srie uchar_t *data; 4380Sstevel@tonic-gate size_t datasize; 4391618Srie uint64_t off, ndx, frame_ptr, fde_cnt, tabndx; 4401618Srie uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /* 4431618Srie * AMD64 - this is a strmcp() just to find the gcc produced 4441618Srie * sections. Soon gcc should be setting the section type - and 4451618Srie * we'll not need this strcmp(). 4460Sstevel@tonic-gate */ 4470Sstevel@tonic-gate if ((shdr->sh_type != SHT_AMD64_UNWIND) && 4480Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 4490Sstevel@tonic-gate MSG_SCN_FRM_SIZE) != 0) && 4500Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4510Sstevel@tonic-gate MSG_SCN_FRMHDR_SIZE) != 0)) 4520Sstevel@tonic-gate continue; 4534168Sab196087 4544168Sab196087 if (!match(0, _cache->c_name, cnt)) 4550Sstevel@tonic-gate continue; 4560Sstevel@tonic-gate 4573466Srie if (_cache->c_data == NULL) 4583466Srie continue; 4593466Srie 4601618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 4611618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 4620Sstevel@tonic-gate 4631618Srie data = (uchar_t *)(_cache->c_data->d_buf); 4640Sstevel@tonic-gate datasize = _cache->c_data->d_size; 4650Sstevel@tonic-gate off = 0; 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate /* 4680Sstevel@tonic-gate * Is this a .eh_frame_hdr 4690Sstevel@tonic-gate */ 4701618Srie if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || 4710Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4721618Srie MSG_SCN_FRMHDR_SIZE) == 0)) { 4731618Srie 4741618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR)); 4751618Srie ndx = 0; 4760Sstevel@tonic-gate 4771618Srie vers = data[ndx++]; 4781618Srie frame_ptr_enc = data[ndx++]; 4791618Srie fde_cnt_enc = data[ndx++]; 4801618Srie table_enc = data[ndx++]; 4810Sstevel@tonic-gate 4821618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); 4830Sstevel@tonic-gate 4841618Srie frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, 4851618Srie ehdr->e_ident, shdr->sh_addr + ndx); 4860Sstevel@tonic-gate 4871618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC), 4881618Srie conv_dwarf_ehe(frame_ptr_enc), EC_XWORD(frame_ptr)); 4891618Srie 4901618Srie fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, 4911618Srie ehdr->e_ident, shdr->sh_addr + ndx); 4920Sstevel@tonic-gate 4931618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), 4941618Srie conv_dwarf_ehe(fde_cnt_enc), EC_XWORD(fde_cnt)); 4951618Srie dbg_print(0, MSG_ORIG(MSG_UNW_TABENC), 4961618Srie conv_dwarf_ehe(table_enc)); 4971618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1)); 4981618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2)); 4990Sstevel@tonic-gate 5001618Srie for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 5011618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), 5021618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5031618Srie table_enc, ehdr->e_ident, shdr->sh_addr)), 5041618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 5051618Srie table_enc, ehdr->e_ident, shdr->sh_addr))); 5061618Srie } 5071618Srie continue; 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* 5110Sstevel@tonic-gate * Walk the Eh_frame's 5120Sstevel@tonic-gate */ 5130Sstevel@tonic-gate while (off < datasize) { 5144433Sab196087 uint_t cieid, cielength, cieversion; 5154433Sab196087 uint_t cieretaddr; 5161618Srie int cieRflag, cieLflag, ciePflag, cieZflag; 5171618Srie uint_t cieaugndx, length, id; 5180Sstevel@tonic-gate uint64_t ciecalign, ciedalign; 5190Sstevel@tonic-gate char *cieaugstr; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate ndx = 0; 5220Sstevel@tonic-gate /* 5230Sstevel@tonic-gate * extract length in lsb format 5240Sstevel@tonic-gate */ 5250Sstevel@tonic-gate length = LSB32EXTRACT(data + off + ndx); 5260Sstevel@tonic-gate ndx += 4; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate * extract CIE id in lsb format 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate id = LSB32EXTRACT(data + off + ndx); 5320Sstevel@tonic-gate ndx += 4; 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate /* 5351618Srie * A CIE record has a id of '0', otherwise this is a 5361618Srie * FDE entry and the 'id' is the CIE pointer. 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate if (id == 0) { 5390Sstevel@tonic-gate uint64_t persVal; 5401618Srie 5410Sstevel@tonic-gate cielength = length; 5420Sstevel@tonic-gate cieid = id; 5431618Srie cieLflag = ciePflag = cieRflag = cieZflag = 0; 5440Sstevel@tonic-gate 5451618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIE), 5461618Srie EC_XWORD(shdr->sh_addr + off)); 5471618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH), 5481618Srie cielength, cieid); 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate cieversion = data[off + ndx]; 5510Sstevel@tonic-gate ndx += 1; 5520Sstevel@tonic-gate cieaugstr = (char *)(&data[off + ndx]); 5530Sstevel@tonic-gate ndx += strlen(cieaugstr) + 1; 5541618Srie 5551618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS), 5561618Srie cieversion, cieaugstr); 5571618Srie 5580Sstevel@tonic-gate ciecalign = uleb_extract(&data[off], &ndx); 5590Sstevel@tonic-gate ciedalign = sleb_extract(&data[off], &ndx); 5600Sstevel@tonic-gate cieretaddr = data[off + ndx]; 5610Sstevel@tonic-gate ndx += 1; 5621618Srie 5631618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN), 5641618Srie EC_XWORD(ciecalign), EC_XWORD(ciedalign), 5651618Srie cieretaddr); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate if (cieaugstr[0]) 5684433Sab196087 dbg_print(0, 5694433Sab196087 MSG_ORIG(MSG_UNW_CIEAXVAL)); 5701618Srie 5710Sstevel@tonic-gate for (cieaugndx = 0; cieaugstr[cieaugndx]; 5720Sstevel@tonic-gate cieaugndx++) { 5730Sstevel@tonic-gate uint_t val; 5741618Srie 5750Sstevel@tonic-gate switch (cieaugstr[cieaugndx]) { 5760Sstevel@tonic-gate case 'z': 5774433Sab196087 val = uleb_extract(&data[off], 5784433Sab196087 &ndx); 5794433Sab196087 dbg_print(0, 5804433Sab196087 MSG_ORIG(MSG_UNW_CIEAXSIZ), 5814433Sab196087 val); 5824433Sab196087 cieZflag = 1; 5834433Sab196087 break; 5840Sstevel@tonic-gate case 'P': 5854433Sab196087 ciePflag = data[off + ndx]; 5864433Sab196087 ndx += 1; 5874433Sab196087 5884433Sab196087 persVal = dwarf_ehe_extract( 5894433Sab196087 &data[off], &ndx, ciePflag, 5904433Sab196087 ehdr->e_ident, 5914433Sab196087 shdr->sh_addr + off + ndx); 5924433Sab196087 dbg_print(0, 5934433Sab196087 MSG_ORIG(MSG_UNW_CIEAXPERS), 5944433Sab196087 ciePflag, 5954433Sab196087 conv_dwarf_ehe(ciePflag), 5964433Sab196087 EC_XWORD(persVal)); 5974433Sab196087 break; 5980Sstevel@tonic-gate case 'R': 5994433Sab196087 val = data[off + ndx]; 6004433Sab196087 ndx += 1; 6014433Sab196087 dbg_print(0, 6024433Sab196087 MSG_ORIG(MSG_UNW_CIEAXCENC), 6034433Sab196087 val, conv_dwarf_ehe(val)); 6044433Sab196087 cieRflag = val; 6054433Sab196087 break; 6060Sstevel@tonic-gate case 'L': 6074433Sab196087 val = data[off + ndx]; 6084433Sab196087 ndx += 1; 6094433Sab196087 dbg_print(0, 6104433Sab196087 MSG_ORIG(MSG_UNW_CIEAXLSDA), 6114433Sab196087 val, conv_dwarf_ehe(val)); 6124433Sab196087 cieLflag = val; 6134433Sab196087 break; 6140Sstevel@tonic-gate default: 6154433Sab196087 dbg_print(0, 6164433Sab196087 MSG_ORIG(MSG_UNW_CIEAXUNEC), 6174433Sab196087 cieaugstr[cieaugndx]); 6184433Sab196087 break; 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate } 6211618Srie if ((cielength + 4) > ndx) 6221618Srie unwindtbl(&ndx, cielength, data, off, 6231618Srie MSG_ORIG(MSG_UNW_CIECFI), 6241618Srie MSG_ORIG(MSG_UNW_CIEPRE), 6251618Srie MSG_UNW_CIEPRE_SIZE); 6260Sstevel@tonic-gate off += cielength + 4; 6271618Srie 6280Sstevel@tonic-gate } else { 6290Sstevel@tonic-gate uint_t fdelength = length; 6300Sstevel@tonic-gate int fdecieptr = id; 6310Sstevel@tonic-gate uint64_t fdeinitloc, fdeaddrrange; 6320Sstevel@tonic-gate 6331618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDE), 6341618Srie EC_XWORD(shdr->sh_addr + off)); 6351618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH), 6360Sstevel@tonic-gate fdelength, fdecieptr); 6371618Srie 6380Sstevel@tonic-gate fdeinitloc = dwarf_ehe_extract(&data[off], 6390Sstevel@tonic-gate &ndx, cieRflag, ehdr->e_ident, 6400Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6410Sstevel@tonic-gate fdeaddrrange = dwarf_ehe_extract(&data[off], 6420Sstevel@tonic-gate &ndx, (cieRflag & ~DW_EH_PE_pcrel), 6430Sstevel@tonic-gate ehdr->e_ident, 6440Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6451618Srie 6461618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), 6471618Srie EC_XWORD(fdeinitloc), 6481618Srie EC_XWORD(fdeaddrrange)); 6491618Srie 6500Sstevel@tonic-gate if (cieaugstr[0]) 6511618Srie dbg_print(0, 6524433Sab196087 MSG_ORIG(MSG_UNW_FDEAXVAL)); 6530Sstevel@tonic-gate if (cieZflag) { 6540Sstevel@tonic-gate uint64_t val; 6550Sstevel@tonic-gate val = uleb_extract(&data[off], &ndx); 6561618Srie dbg_print(0, 6574433Sab196087 MSG_ORIG(MSG_UNW_FDEAXSIZE), 6581618Srie EC_XWORD(val)); 6590Sstevel@tonic-gate if (val & cieLflag) { 6604433Sab196087 fdeinitloc = dwarf_ehe_extract( 6614433Sab196087 &data[off], &ndx, cieLflag, 6624433Sab196087 ehdr->e_ident, 6634433Sab196087 shdr->sh_addr + off + ndx); 6644433Sab196087 dbg_print(0, 6654433Sab196087 MSG_ORIG(MSG_UNW_FDEAXLSDA), 6664433Sab196087 EC_XWORD(val)); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate } 6691618Srie if ((fdelength + 4) > ndx) 6701618Srie unwindtbl(&ndx, fdelength, data, off, 6711618Srie MSG_ORIG(MSG_UNW_FDECFI), 6721618Srie MSG_ORIG(MSG_UNW_FDEPRE), 6731618Srie MSG_UNW_FDEPRE_SIZE); 6740Sstevel@tonic-gate off += fdelength + 4; 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate /* 6810Sstevel@tonic-gate * Print the hardware/software capabilities. For executables and shared objects 6820Sstevel@tonic-gate * this should be accompanied with a program header. 6830Sstevel@tonic-gate */ 6840Sstevel@tonic-gate static void 6851618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, 6861618Srie Elf *elf) 6870Sstevel@tonic-gate { 6881618Srie Word cnt; 6893466Srie Shdr *cshdr = 0; 6903466Srie Cache *ccache; 6911618Srie Off cphdr_off = 0; 6921618Srie Xword cphdr_sz; 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate /* 6950Sstevel@tonic-gate * Determine if a hardware/software capabilities header exists. 6960Sstevel@tonic-gate */ 6971618Srie if (phnum) { 6981618Srie Phdr *phdr; 6990Sstevel@tonic-gate 7001618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 7010Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 7020Sstevel@tonic-gate return; 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7051618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 7061618Srie if (phdr->p_type == PT_SUNWCAP) { 7071618Srie cphdr_off = phdr->p_offset; 7081618Srie cphdr_sz = phdr->p_filesz; 7091618Srie break; 7101618Srie } 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate } 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate /* 7150Sstevel@tonic-gate * Determine if a hardware/software capabilities section exists. 7160Sstevel@tonic-gate */ 7170Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 7181618Srie Cache *_cache = &cache[cnt]; 7191618Srie Shdr *shdr = _cache->c_shdr; 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_cap) 7220Sstevel@tonic-gate continue; 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 7250Sstevel@tonic-gate (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 7260Sstevel@tonic-gate continue; 7270Sstevel@tonic-gate 7283466Srie if (_cache->c_data == NULL) 7293466Srie continue; 7303466Srie 7310Sstevel@tonic-gate ccache = _cache; 7320Sstevel@tonic-gate cshdr = shdr; 7330Sstevel@tonic-gate break; 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate if ((cshdr == 0) && (cphdr_off == 0)) 7370Sstevel@tonic-gate return; 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate /* 7400Sstevel@tonic-gate * Print the hardware/software capabilities section. 7410Sstevel@tonic-gate */ 7420Sstevel@tonic-gate if (cshdr) { 7431618Srie Word ndx, capn; 7443492Sab196087 Cap *cap = (Cap *)ccache->c_data->d_buf; 7450Sstevel@tonic-gate 746*4665Sab196087 if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) { 747*4665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 748*4665Sab196087 file, ccache->c_name); 749*4665Sab196087 return; 750*4665Sab196087 } 751*4665Sab196087 7521618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 7531618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 7540Sstevel@tonic-gate 7551618Srie Elf_cap_title(0); 7561618Srie 7571618Srie capn = (Word)(cshdr->sh_size / cshdr->sh_entsize); 7580Sstevel@tonic-gate 7591618Srie for (ndx = 0; ndx < capn; cap++, ndx++) { 7601618Srie if (cap->c_tag != CA_SUNW_NULL) 7611618Srie Elf_cap_entry(0, cap, ndx, ehdr->e_machine); 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate } else 7640Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate /* 7670Sstevel@tonic-gate * If this object is an executable or shared object, then the 7680Sstevel@tonic-gate * hardware/software capabilities section should have an accompanying 7690Sstevel@tonic-gate * program header. 7700Sstevel@tonic-gate */ 7710Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 7720Sstevel@tonic-gate if (cphdr_off == 0) 7730Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 7740Sstevel@tonic-gate file, ccache->c_name); 7750Sstevel@tonic-gate else if ((cphdr_off != cshdr->sh_offset) || 7760Sstevel@tonic-gate (cphdr_sz != cshdr->sh_size)) 7770Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 7780Sstevel@tonic-gate file, ccache->c_name); 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate } 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate /* 7830Sstevel@tonic-gate * Print the interpretor. 7840Sstevel@tonic-gate */ 7850Sstevel@tonic-gate static void 7861618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) 7870Sstevel@tonic-gate { 7881618Srie Word cnt; 7891618Srie Shdr *ishdr = 0; 7901618Srie Cache *icache; 7911618Srie Off iphdr_off = 0; 7921618Srie Xword iphdr_fsz; 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate /* 7950Sstevel@tonic-gate * Determine if an interp header exists. 7960Sstevel@tonic-gate */ 7971618Srie if (phnum) { 7981618Srie Phdr *phdr; 7990Sstevel@tonic-gate 8001618Srie if ((phdr = getphdr(phnum, PT_INTERP, file, elf)) != 0) { 8011618Srie iphdr_off = phdr->p_offset; 8021618Srie iphdr_fsz = phdr->p_filesz; 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate } 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate if (iphdr_off == 0) 8070Sstevel@tonic-gate return; 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate /* 8100Sstevel@tonic-gate * Determine if an interp section exists. 8110Sstevel@tonic-gate */ 8120Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8131618Srie Cache *_cache = &cache[cnt]; 8141618Srie Shdr *shdr = _cache->c_shdr; 8150Sstevel@tonic-gate 8160Sstevel@tonic-gate /* 8170Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP 8180Sstevel@tonic-gate * string. The target section can't be in a NOBITS section. 8190Sstevel@tonic-gate */ 8200Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) || 8210Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) || 8221618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size)) 8230Sstevel@tonic-gate continue; 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate icache = _cache; 8260Sstevel@tonic-gate ishdr = shdr; 8270Sstevel@tonic-gate break; 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate /* 8310Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the 8320Sstevel@tonic-gate * program header, as this is the offset used by the kernel. 8330Sstevel@tonic-gate */ 8343466Srie if (ishdr && icache->c_data) { 8351618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8361618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 8371618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), 8380Sstevel@tonic-gate (char *)icache->c_data->d_buf + 8390Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset)); 8400Sstevel@tonic-gate } else 8410Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate /* 8440Sstevel@tonic-gate * If there are any inconsistences between the program header and 8450Sstevel@tonic-gate * section information, flag them. 8460Sstevel@tonic-gate */ 8470Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) || 8481618Srie (iphdr_fsz != ishdr->sh_size))) { 8490Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 8500Sstevel@tonic-gate icache->c_name); 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate 8540Sstevel@tonic-gate /* 8550Sstevel@tonic-gate * Print the syminfo section. 8560Sstevel@tonic-gate */ 8570Sstevel@tonic-gate static void 8581618Srie syminfo(Cache *cache, Word shnum, const char *file) 8590Sstevel@tonic-gate { 8601618Srie Shdr *infoshdr; 8611618Srie Syminfo *info; 8621618Srie Sym *syms; 8631618Srie Dyn *dyns; 8641618Srie Word infonum, cnt, ndx, symnum; 8651618Srie Cache *infocache = 0, *symsec, *strsec; 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8681618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { 8691618Srie infocache = &cache[cnt]; 8700Sstevel@tonic-gate break; 8710Sstevel@tonic-gate } 8720Sstevel@tonic-gate } 8731618Srie if (infocache == 0) 8740Sstevel@tonic-gate return; 8750Sstevel@tonic-gate 8761618Srie infoshdr = infocache->c_shdr; 8771618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) { 8780Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8791618Srie file, infocache->c_name); 8800Sstevel@tonic-gate return; 8810Sstevel@tonic-gate } 8823466Srie if (infocache->c_data == NULL) 8833466Srie return; 8843466Srie 8851618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize); 8861618Srie info = (Syminfo *)infocache->c_data->d_buf; 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate /* 8890Sstevel@tonic-gate * Get the data buffer of the associated dynamic section. 8900Sstevel@tonic-gate */ 8911618Srie if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) { 8920Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 8931618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info)); 8940Sstevel@tonic-gate return; 8950Sstevel@tonic-gate } 8963466Srie if (cache[infoshdr->sh_info].c_data == NULL) 8973466Srie return; 8983466Srie 8991618Srie dyns = cache[infoshdr->sh_info].c_data->d_buf; 9001618Srie if (dyns == 0) { 9010Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 9021618Srie file, cache[infoshdr->sh_info].c_name); 9030Sstevel@tonic-gate return; 9040Sstevel@tonic-gate } 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate /* 9071618Srie * Get the data buffer for the associated symbol table and string table. 9080Sstevel@tonic-gate */ 9091618Srie if (stringtbl(cache, 1, cnt, shnum, file, 9101618Srie &symnum, &symsec, &strsec) == 0) 9110Sstevel@tonic-gate return; 9120Sstevel@tonic-gate 9131618Srie syms = symsec->c_data->d_buf; 9140Sstevel@tonic-gate 9151618Srie /* 9161618Srie * Loop through the syminfo entries. 9171618Srie */ 9181618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 9191618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name); 9201618Srie Elf_syminfo_title(0); 9210Sstevel@tonic-gate 9221618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) { 9231618Srie Sym *sym; 9241618Srie const char *needed = 0, *name; 9251618Srie 9261618Srie if ((info->si_flags == 0) && (info->si_boundto == 0)) 9270Sstevel@tonic-gate continue; 9280Sstevel@tonic-gate 9291618Srie sym = &syms[ndx]; 9301618Srie name = string(infocache, ndx, strsec, file, sym->st_name); 9310Sstevel@tonic-gate 9321618Srie if (info->si_boundto < SYMINFO_BT_LOWRESERVE) { 9331618Srie Dyn *dyn = &dyns[info->si_boundto]; 9341618Srie 9351618Srie needed = string(infocache, info->si_boundto, 9361618Srie strsec, file, dyn->d_un.d_val); 9370Sstevel@tonic-gate } 9381618Srie Elf_syminfo_entry(0, ndx, info, name, needed); 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate /* 9430Sstevel@tonic-gate * Print version definition section entries. 9440Sstevel@tonic-gate */ 9450Sstevel@tonic-gate static void 9461618Srie version_def(Verdef *vdf, Word shnum, Cache *vcache, Cache *scache, 9470Sstevel@tonic-gate const char *file) 9480Sstevel@tonic-gate { 9491618Srie Word cnt; 9501618Srie char index[MAXNDXSIZE]; 9510Sstevel@tonic-gate 9521618Srie Elf_ver_def_title(0); 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate for (cnt = 1; cnt <= shnum; cnt++, 9551618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 9560Sstevel@tonic-gate const char *name, *dep; 9571618Srie Half vcnt = vdf->vd_cnt - 1; 9581618Srie Half ndx = vdf->vd_ndx; 9594433Sab196087 Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate /* 9620Sstevel@tonic-gate * Obtain the name and first dependency (if any). 9630Sstevel@tonic-gate */ 9640Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name); 9651618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9660Sstevel@tonic-gate if (vcnt) 9670Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name); 9680Sstevel@tonic-gate else 9690Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 9720Sstevel@tonic-gate EC_XWORD(ndx)); 9731618Srie Elf_ver_line_1(0, index, name, dep, 9741618Srie conv_ver_flags(vdf->vd_flags)); 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate /* 9770Sstevel@tonic-gate * Print any additional dependencies. 9780Sstevel@tonic-gate */ 9790Sstevel@tonic-gate if (vcnt) { 9801618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9810Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 9821618Srie vdap = (Verdaux *)((uintptr_t)vdap + 9830Sstevel@tonic-gate vdap->vda_next)) { 9840Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 9850Sstevel@tonic-gate vdap->vda_name); 9861618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate } 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate /* 9930Sstevel@tonic-gate * Print a version needed section entries. 9940Sstevel@tonic-gate */ 9950Sstevel@tonic-gate static void 9961618Srie version_need(Verneed *vnd, Word shnum, Cache *vcache, Cache *scache, 9970Sstevel@tonic-gate const char *file) 9980Sstevel@tonic-gate { 9991618Srie Word cnt; 10000Sstevel@tonic-gate 10011618Srie Elf_ver_need_title(0); 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate for (cnt = 1; cnt <= shnum; cnt++, 10041618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 10050Sstevel@tonic-gate const char *name, *dep; 10061618Srie Half vcnt = vnd->vn_cnt; 10074433Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux); 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate /* 10100Sstevel@tonic-gate * Obtain the name of the needed file and the version name 10110Sstevel@tonic-gate * within it that we're dependent on. Note that the count 10120Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus 10130Sstevel@tonic-gate * entry. 10140Sstevel@tonic-gate */ 10150Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file); 10160Sstevel@tonic-gate if (vcnt) 10170Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name); 10180Sstevel@tonic-gate else 10190Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL); 10200Sstevel@tonic-gate 10211618Srie Elf_ver_line_1(0, MSG_ORIG(MSG_STR_EMPTY), name, dep, 10221618Srie conv_ver_flags(vnap->vna_flags)); 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate /* 10250Sstevel@tonic-gate * Print any additional version dependencies. 10260Sstevel@tonic-gate */ 10270Sstevel@tonic-gate if (vcnt) { 10281618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 10290Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 10301618Srie vnap = (Vernaux *)((uintptr_t)vnap + 10310Sstevel@tonic-gate vnap->vna_next)) { 10320Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 10330Sstevel@tonic-gate vnap->vna_name); 10341618Srie Elf_ver_line_3(0, MSG_ORIG(MSG_STR_EMPTY), dep, 10351618Srie conv_ver_flags(vnap->vna_flags)); 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate } 10380Sstevel@tonic-gate } 10390Sstevel@tonic-gate } 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate /* 10423875Sab196087 * Display version section information if the flags require it. 10433875Sab196087 * Return version information needed by other output. 10443875Sab196087 * 10453875Sab196087 * entry: 10463875Sab196087 * cache - Cache of all section headers 10473875Sab196087 * shnum - # of sections in cache 10483875Sab196087 * file - Name of file 10493875Sab196087 * flags - Command line option flags 10503875Sab196087 * versym - VERSYM_STATE block to be filled in. 10510Sstevel@tonic-gate */ 10523875Sab196087 static void 10533875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags, 10543875Sab196087 VERSYM_STATE *versym) 10550Sstevel@tonic-gate { 10560Sstevel@tonic-gate GElf_Word cnt; 10573875Sab196087 const char *gnu_prefix; 10583875Sab196087 size_t gnu_prefix_len; 10593875Sab196087 10603875Sab196087 bzero(versym, sizeof (*versym)); 10613875Sab196087 gnu_prefix = MSG_ORIG(MSG_GNU_VERNAMPREFIX); 10623875Sab196087 gnu_prefix_len = strlen(gnu_prefix); 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 10651618Srie void *ver; 10660Sstevel@tonic-gate uint_t num; 10671618Srie Cache *_cache = &cache[cnt]; 10681618Srie Shdr *shdr = _cache->c_shdr; 10691618Srie const char *secname = _cache->c_name; 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate /* 10723875Sab196087 * If the section names starts with the .gnu.version prefix, 10733875Sab196087 * then this object was almost certainly produced by the 10743875Sab196087 * GNU ld and not the native Solaris ld. 10750Sstevel@tonic-gate */ 10763875Sab196087 if (strncmp(gnu_prefix, secname, gnu_prefix_len) == 0) 10773875Sab196087 versym->gnu = 1; 10783875Sab196087 10793875Sab196087 /* 10803875Sab196087 * If this is the version symbol table record its data 10813875Sab196087 * address for later symbol processing. 10823875Sab196087 */ 10833875Sab196087 if ((shdr->sh_type == SHT_SUNW_versym) && 10843875Sab196087 (_cache->c_data != NULL)) { 10853875Sab196087 versym->cache = _cache; 10863875Sab196087 versym->data = _cache->c_data->d_buf; 10870Sstevel@tonic-gate continue; 10880Sstevel@tonic-gate } 10890Sstevel@tonic-gate 10903875Sab196087 /* 10913875Sab196087 * If this is a version definition section, retain # of 10923875Sab196087 * version definitions for later symbol processing. 10933875Sab196087 */ 10943875Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) 10953875Sab196087 versym->num_verdef = shdr->sh_info; 10963875Sab196087 10970Sstevel@tonic-gate if ((flags & FLG_VERSIONS) == 0) 10980Sstevel@tonic-gate continue; 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate if ((shdr->sh_type != SHT_SUNW_verdef) && 11010Sstevel@tonic-gate (shdr->sh_type != SHT_SUNW_verneed)) 11020Sstevel@tonic-gate continue; 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate /* 11050Sstevel@tonic-gate * Determine the version section data and number. 11060Sstevel@tonic-gate */ 11073466Srie if ((_cache->c_data == NULL) || 11083466Srie ((ver = (void *)_cache->c_data->d_buf) == NULL)) { 11090Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 11101618Srie file, secname); 11110Sstevel@tonic-gate continue; 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate if ((num = shdr->sh_info) == 0) { 11140Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 11151618Srie file, secname, EC_WORD(shdr->sh_info)); 11160Sstevel@tonic-gate continue; 11170Sstevel@tonic-gate } 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate /* 11200Sstevel@tonic-gate * Get the data buffer for the associated string table. 11210Sstevel@tonic-gate */ 11220Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 11230Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 11241618Srie file, secname, EC_WORD(shdr->sh_link)); 11250Sstevel@tonic-gate continue; 11260Sstevel@tonic-gate } 11270Sstevel@tonic-gate 11281618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 11290Sstevel@tonic-gate if (shdr->sh_type == SHT_SUNW_verdef) { 11301618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), secname); 11311618Srie version_def((Verdef *)ver, num, _cache, 11320Sstevel@tonic-gate &cache[shdr->sh_link], file); 11330Sstevel@tonic-gate } else if (shdr->sh_type == SHT_SUNW_verneed) { 11341618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), secname); 11351618Srie version_need((Verneed *)ver, num, _cache, 11360Sstevel@tonic-gate &cache[shdr->sh_link], file); 11370Sstevel@tonic-gate } 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate } 11400Sstevel@tonic-gate 11410Sstevel@tonic-gate /* 11423492Sab196087 * Initialize a symbol table state structure 11433492Sab196087 * 11443492Sab196087 * entry: 11453492Sab196087 * state - State structure to be initialized 11463492Sab196087 * cache - Cache of all section headers 11473492Sab196087 * shnum - # of sections in cache 11483492Sab196087 * secndx - Index of symbol table section 11493492Sab196087 * ehdr - ELF header for file 11503875Sab196087 * versym - Information about versym section 11513492Sab196087 * file - Name of file 11523492Sab196087 * flags - Command line option flags 11531618Srie */ 11541618Srie static int 11553492Sab196087 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx, 11563875Sab196087 Ehdr *ehdr, VERSYM_STATE *versym, const char *file, uint_t flags) 11573492Sab196087 { 11583492Sab196087 Shdr *shdr; 11593492Sab196087 11603492Sab196087 state->file = file; 11613492Sab196087 state->ehdr = ehdr; 11623492Sab196087 state->cache = cache; 11633492Sab196087 state->shnum = shnum; 11643492Sab196087 state->seccache = &cache[secndx]; 11653492Sab196087 state->secndx = secndx; 11663492Sab196087 state->secname = state->seccache->c_name; 11673492Sab196087 state->flags = flags; 11683492Sab196087 state->shxndx.checked = 0; 11693492Sab196087 state->shxndx.data = NULL; 11703492Sab196087 state->shxndx.n = 0; 11713492Sab196087 11723492Sab196087 shdr = state->seccache->c_shdr; 11733492Sab196087 11743492Sab196087 /* 11753492Sab196087 * Check the symbol data and per-item size. 11763492Sab196087 */ 11773492Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 11783492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 11793492Sab196087 file, state->secname); 11803492Sab196087 return (0); 11813492Sab196087 } 11823492Sab196087 if (state->seccache->c_data == NULL) 11833492Sab196087 return (0); 11843492Sab196087 11853492Sab196087 /* LINTED */ 11863492Sab196087 state->symn = (Word)(shdr->sh_size / shdr->sh_entsize); 11873492Sab196087 state->sym = (Sym *)state->seccache->c_data->d_buf; 11883492Sab196087 11893492Sab196087 /* 11903492Sab196087 * Check associated string table section. 11913492Sab196087 */ 11923492Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 11933492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 11943492Sab196087 file, state->secname, EC_WORD(shdr->sh_link)); 11953492Sab196087 return (0); 11963492Sab196087 } 11973492Sab196087 11983492Sab196087 /* 11993492Sab196087 * Determine if there is a associated Versym section 12003492Sab196087 * with this Symbol Table. 12013492Sab196087 */ 12023875Sab196087 if (versym->cache && 12033875Sab196087 (versym->cache->c_shdr->sh_link == state->secndx)) 12043875Sab196087 state->versym = versym; 12053492Sab196087 else 12063492Sab196087 state->versym = NULL; 12073492Sab196087 12083492Sab196087 12093492Sab196087 return (1); 12103492Sab196087 } 12113492Sab196087 12123492Sab196087 /* 12133492Sab196087 * Determine the extended section index used for symbol tables entries. 12143492Sab196087 */ 12153492Sab196087 static void 12163492Sab196087 symbols_getxindex(SYMTBL_STATE * state) 12171618Srie { 12181618Srie uint_t symn; 12191618Srie Word symcnt; 12201618Srie 12213492Sab196087 state->shxndx.checked = 1; /* Note that we've been called */ 12223492Sab196087 for (symcnt = 1; symcnt < state->shnum; symcnt++) { 12233492Sab196087 Cache *_cache = &state->cache[symcnt]; 12241618Srie Shdr *shdr = _cache->c_shdr; 12251618Srie 12261618Srie if ((shdr->sh_type != SHT_SYMTAB_SHNDX) || 12273492Sab196087 (shdr->sh_link != state->secndx)) 12281618Srie continue; 12291618Srie 12301618Srie if ((shdr->sh_entsize) && 12311618Srie /* LINTED */ 12321618Srie ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0)) 12331618Srie continue; 12341618Srie 12353466Srie if (_cache->c_data == NULL) 12363466Srie continue; 12373466Srie 12383492Sab196087 state->shxndx.data = _cache->c_data->d_buf; 12393492Sab196087 state->shxndx.n = symn; 12403492Sab196087 return; 12411618Srie } 12421618Srie } 12431618Srie 12441618Srie /* 12453492Sab196087 * Produce a line of output for the given symbol 12463492Sab196087 * 12473492Sab196087 * entry: 12483875Sab196087 * state - Symbol table state 12493492Sab196087 * symndx - Index of symbol within the table 12503492Sab196087 * symndx_disp - Index to display. This may not be the same 12513492Sab196087 * as symndx if the display is relative to the logical 12523492Sab196087 * combination of the SUNW_ldynsym/dynsym tables. 12533492Sab196087 * sym - Symbol to display 12540Sstevel@tonic-gate */ 12553492Sab196087 static void 12563492Sab196087 output_symbol(SYMTBL_STATE *state, Word symndx, Word disp_symndx, Sym *sym) 12570Sstevel@tonic-gate { 12583118Sab196087 /* 12593118Sab196087 * Symbol types for which we check that the specified 12603118Sab196087 * address/size land inside the target section. 12613118Sab196087 */ 12623492Sab196087 static const int addr_symtype[STT_NUM] = { 12633118Sab196087 0, /* STT_NOTYPE */ 12643118Sab196087 1, /* STT_OBJECT */ 12653118Sab196087 1, /* STT_FUNC */ 12663118Sab196087 0, /* STT_SECTION */ 12673118Sab196087 0, /* STT_FILE */ 12683118Sab196087 1, /* STT_COMMON */ 12693118Sab196087 0, /* STT_TLS */ 12703118Sab196087 }; 12713118Sab196087 #if STT_NUM != (STT_TLS + 1) 12723492Sab196087 #error "STT_NUM has grown. Update addr_symtype[]" 12733118Sab196087 #endif 12743118Sab196087 1275*4665Sab196087 char index[MAXNDXSIZE]; 1276*4665Sab196087 const char *symname, *sec; 12773875Sab196087 Versym verndx; 12783492Sab196087 uchar_t type; 12793492Sab196087 Shdr *tshdr; 12803492Sab196087 Word shndx; 12813492Sab196087 12823492Sab196087 /* Ensure symbol index is in range */ 12833492Sab196087 if (symndx >= state->symn) { 12843492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX), 12853492Sab196087 state->file, state->secname, EC_WORD(symndx)); 12863492Sab196087 return; 12873492Sab196087 } 12883492Sab196087 12893492Sab196087 /* 12903492Sab196087 * If we are using extended symbol indexes, find the 12913492Sab196087 * corresponding SHN_SYMTAB_SHNDX table. 12923492Sab196087 */ 12933492Sab196087 if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0)) 12943492Sab196087 symbols_getxindex(state); 12953492Sab196087 12963492Sab196087 /* LINTED */ 12973492Sab196087 symname = string(state->seccache, symndx, 12983492Sab196087 &state->cache[state->seccache->c_shdr->sh_link], state->file, 12993492Sab196087 sym->st_name); 13003492Sab196087 13013492Sab196087 tshdr = 0; 13023492Sab196087 sec = NULL; 13033492Sab196087 1304*4665Sab196087 if (state->ehdr->e_type == ET_CORE) { 13053492Sab196087 sec = (char *)MSG_INTL(MSG_STR_UNKNOWN); 1306*4665Sab196087 } else if (state->flags & FLG_FAKESHDR) { 1307*4665Sab196087 /* 1308*4665Sab196087 * If we are using fake section headers derived from 1309*4665Sab196087 * the program headers, then the section indexes 1310*4665Sab196087 * in the symbols do not correspond to these headers. 1311*4665Sab196087 * The section names are not available, so all we can 1312*4665Sab196087 * do is to display them in numeric form. 1313*4665Sab196087 */ 1314*4665Sab196087 sec = conv_sym_shndx(sym->st_shndx); 1315*4665Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 13163492Sab196087 (sym->st_shndx < state->shnum)) { 13173492Sab196087 shndx = sym->st_shndx; 13183492Sab196087 tshdr = state->cache[shndx].c_shdr; 13193492Sab196087 sec = state->cache[shndx].c_name; 13203492Sab196087 } else if (sym->st_shndx == SHN_XINDEX) { 13213492Sab196087 if (state->shxndx.data) { 13223492Sab196087 Word _shxndx; 13233492Sab196087 13243492Sab196087 if (symndx > state->shxndx.n) { 13254433Sab196087 (void) fprintf(stderr, 13264433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 13274433Sab196087 state->file, state->secname, 13284433Sab196087 EC_WORD(symndx)); 13293492Sab196087 } else if ((_shxndx = 13303492Sab196087 state->shxndx.data[symndx]) > state->shnum) { 13314433Sab196087 (void) fprintf(stderr, 13324433Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 13334433Sab196087 state->file, state->secname, 13344433Sab196087 EC_WORD(symndx), EC_WORD(_shxndx)); 13353492Sab196087 } else { 13364433Sab196087 shndx = _shxndx; 13374433Sab196087 tshdr = state->cache[shndx].c_shdr; 13384433Sab196087 sec = state->cache[shndx].c_name; 13393492Sab196087 } 13403492Sab196087 } else { 13413492Sab196087 (void) fprintf(stderr, 13423492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 13433492Sab196087 state->file, state->secname, EC_WORD(symndx)); 13443492Sab196087 } 13453492Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 13463492Sab196087 (sym->st_shndx >= state->shnum)) { 13473492Sab196087 (void) fprintf(stderr, 13483492Sab196087 MSG_INTL(MSG_ERR_BADSYM5), state->file, 13493492Sab196087 state->secname, demangle(symname, state->flags), 13503492Sab196087 sym->st_shndx); 13513492Sab196087 } 13520Sstevel@tonic-gate 13533492Sab196087 /* 13543492Sab196087 * If versioning is available display the 13553875Sab196087 * version index. If not, then use 0. 13563492Sab196087 */ 13573875Sab196087 if (state->versym) { 13583875Sab196087 verndx = state->versym->data[symndx]; 13593875Sab196087 13603875Sab196087 /* 13613875Sab196087 * Check to see if this is a defined symbol with a 13623875Sab196087 * version index that is outside the valid range for 13633875Sab196087 * the file. If so, then there are two possiblities: 13643875Sab196087 * 13653875Sab196087 * - Files produced by the GNU ld use the top (16th) bit 13663875Sab196087 * as a "hidden symbol" marker. If we have 13673875Sab196087 * detected that this object comes from GNU ld, 13683875Sab196087 * then check to see if this is the case and that 13693875Sab196087 * the resulting masked version is in range. If so, 13703875Sab196087 * issue a warning describing it. 13713875Sab196087 * - If this is not a GNU "hidden bit" issue, then 13723875Sab196087 * issue a generic "out of range" error. 13733875Sab196087 */ 13744433Sab196087 if (VERNDX_INVALID_DIAG(sym->st_shndx, 13754433Sab196087 state->versym->num_verdef, state->versym->data, symndx)) { 13763875Sab196087 if (state->versym->gnu && (verndx & 0x8000) && 13773875Sab196087 ((verndx & ~0x8000) <= 13783875Sab196087 state->versym->num_verdef)) { 13793875Sab196087 (void) fprintf(stderr, 13803875Sab196087 MSG_INTL(MSG_WARN_GNUVER), state->file, 13813875Sab196087 state->secname, EC_WORD(symndx), 13823875Sab196087 EC_HALF(verndx & ~0x8000)); 13833875Sab196087 } else { /* Generic version range error */ 13843875Sab196087 (void) fprintf(stderr, 13853875Sab196087 MSG_INTL(MSG_ERR_BADVER), state->file, 13863875Sab196087 state->secname, EC_WORD(symndx), 13873875Sab196087 EC_HALF(verndx), state->versym->num_verdef); 13883875Sab196087 } 13893875Sab196087 } 13903875Sab196087 } else { 13913492Sab196087 verndx = 0; 13923875Sab196087 } 13933492Sab196087 13943492Sab196087 /* 13953492Sab196087 * Error checking for TLS. 13963492Sab196087 */ 13973492Sab196087 type = ELF_ST_TYPE(sym->st_info); 13983492Sab196087 if (type == STT_TLS) { 13993492Sab196087 if (tshdr && 14003492Sab196087 (sym->st_shndx != SHN_UNDEF) && 14013492Sab196087 ((tshdr->sh_flags & SHF_TLS) == 0)) { 14023492Sab196087 (void) fprintf(stderr, 14033492Sab196087 MSG_INTL(MSG_ERR_BADSYM3), state->file, 14043492Sab196087 state->secname, demangle(symname, state->flags)); 14053492Sab196087 } 14063492Sab196087 } else if ((type != STT_SECTION) && sym->st_size && 14073492Sab196087 tshdr && (tshdr->sh_flags & SHF_TLS)) { 14083492Sab196087 (void) fprintf(stderr, 14093492Sab196087 MSG_INTL(MSG_ERR_BADSYM4), state->file, 14103492Sab196087 state->secname, demangle(symname, state->flags)); 14113492Sab196087 } 14123492Sab196087 14133492Sab196087 /* 14143492Sab196087 * If a symbol with non-zero size has a type that 14153492Sab196087 * specifies an address, then make sure the location 14163492Sab196087 * it references is actually contained within the 14173492Sab196087 * section. UNDEF symbols don't count in this case, 14183492Sab196087 * so we ignore them. 14193492Sab196087 * 14203492Sab196087 * The meaning of the st_value field in a symbol 14213492Sab196087 * depends on the type of object. For a relocatable 14223492Sab196087 * object, it is the offset within the section. 14233492Sab196087 * For sharable objects, it is the offset relative to 14243492Sab196087 * the base of the object, and for other types, it is 14253492Sab196087 * the virtual address. To get an offset within the 14263492Sab196087 * section for non-ET_REL files, we subtract the 14273492Sab196087 * base address of the section. 14283492Sab196087 */ 14293492Sab196087 if (addr_symtype[type] && (sym->st_size > 0) && 14303492Sab196087 (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) || 14313492Sab196087 (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) { 14323492Sab196087 Word v = sym->st_value; 14333492Sab196087 if (state->ehdr->e_type != ET_REL) 14343492Sab196087 v -= tshdr->sh_addr; 14353492Sab196087 if (((v + sym->st_size) > tshdr->sh_size)) { 14363492Sab196087 (void) fprintf(stderr, 14373492Sab196087 MSG_INTL(MSG_ERR_BADSYM6), state->file, 14383492Sab196087 state->secname, demangle(symname, state->flags), 14393492Sab196087 EC_WORD(shndx), EC_XWORD(tshdr->sh_size), 14403492Sab196087 EC_XWORD(sym->st_value), EC_XWORD(sym->st_size)); 14413492Sab196087 } 14423492Sab196087 } 14433492Sab196087 14443492Sab196087 (void) snprintf(index, MAXNDXSIZE, 14453492Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx)); 14463492Sab196087 Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, 14473492Sab196087 state->ehdr->e_machine, sym, verndx, sec, symname); 14483492Sab196087 } 14493492Sab196087 14503492Sab196087 /* 14513492Sab196087 * Search for and process any symbol tables. 14523492Sab196087 */ 14533492Sab196087 void 14544168Sab196087 symbols(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 14554168Sab196087 const char *file, uint_t flags) 14563492Sab196087 { 14573492Sab196087 SYMTBL_STATE state; 14583492Sab196087 Cache *_cache; 14593492Sab196087 Word secndx; 14603492Sab196087 14613492Sab196087 for (secndx = 1; secndx < shnum; secndx++) { 14623492Sab196087 Word symcnt; 14633492Sab196087 Shdr *shdr; 14643492Sab196087 14653492Sab196087 _cache = &cache[secndx]; 14663492Sab196087 shdr = _cache->c_shdr; 14670Sstevel@tonic-gate 14680Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) && 14692766Sab196087 (shdr->sh_type != SHT_DYNSYM) && 14702766Sab196087 (shdr->sh_type != SHT_SUNW_LDYNSYM)) 14710Sstevel@tonic-gate continue; 14724168Sab196087 if (!match(0, _cache->c_name, secndx)) 14733466Srie continue; 14743466Srie 14753492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr, 14763875Sab196087 versym, file, flags)) 14770Sstevel@tonic-gate continue; 14780Sstevel@tonic-gate /* 14790Sstevel@tonic-gate * Loop through the symbol tables entries. 14800Sstevel@tonic-gate */ 14811618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 14823492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname); 14831618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 14840Sstevel@tonic-gate 14853492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++) 14863492Sab196087 output_symbol(&state, symcnt, symcnt, 14873492Sab196087 state.sym + symcnt); 14883492Sab196087 } 14893492Sab196087 } 14900Sstevel@tonic-gate 14913492Sab196087 /* 14923492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections. 14933492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair. 14943492Sab196087 */ 14953492Sab196087 static void 14964168Sab196087 sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, VERSYM_STATE *versym, 14974168Sab196087 const char *file, uint_t flags) 14983492Sab196087 { 14993492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state; 15003492Sab196087 Cache *sortcache, *symcache; 15013492Sab196087 Shdr *sortshdr, *symshdr; 15023492Sab196087 Word sortsecndx, symsecndx; 15033492Sab196087 Word ldynsym_cnt; 15043492Sab196087 Word *ndx; 15053492Sab196087 Word ndxn; 15063492Sab196087 int output_cnt = 0; 15070Sstevel@tonic-gate 15083492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) { 15090Sstevel@tonic-gate 15103492Sab196087 sortcache = &cache[sortsecndx]; 15113492Sab196087 sortshdr = sortcache->c_shdr; 15120Sstevel@tonic-gate 15133492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) && 15143492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort)) 15153492Sab196087 continue; 15164168Sab196087 if (!match(0, sortcache->c_name, sortsecndx)) 15173492Sab196087 continue; 15180Sstevel@tonic-gate 15193492Sab196087 /* 15203492Sab196087 * If the section references a SUNW_ldynsym, then we 15213492Sab196087 * expect to see the associated .dynsym immediately 15223492Sab196087 * following. If it references a .dynsym, there is no 15233492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't 15243492Sab196087 * know what to do with it. 15253492Sab196087 */ 15263492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) { 15273492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 15283492Sab196087 file, sortcache->c_name, 15293492Sab196087 EC_WORD(sortshdr->sh_link)); 15303492Sab196087 continue; 15313492Sab196087 } 15323492Sab196087 symcache = &cache[sortshdr->sh_link]; 15333492Sab196087 symshdr = symcache->c_shdr; 15343492Sab196087 symsecndx = sortshdr->sh_link; 15353492Sab196087 ldynsym_cnt = 0; 15363492Sab196087 switch (symshdr->sh_type) { 15373492Sab196087 case SHT_SUNW_LDYNSYM: 15383492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum, 15393875Sab196087 symsecndx, ehdr, versym, file, flags)) 15403492Sab196087 continue; 15413492Sab196087 ldynsym_cnt = ldynsym_state.symn; 15420Sstevel@tonic-gate /* 15433492Sab196087 * We know that the dynsym follows immediately 15443492Sab196087 * after the SUNW_ldynsym, and so, should be at 15453492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a 15463492Sab196087 * diagnostic tool, so we do the full paranoid 15473492Sab196087 * search instead. 15480Sstevel@tonic-gate */ 15493492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) { 15503492Sab196087 symcache = &cache[symsecndx]; 15513492Sab196087 symshdr = symcache->c_shdr; 15523492Sab196087 if (symshdr->sh_type == SHT_DYNSYM) 15533492Sab196087 break; 15543492Sab196087 } 15553492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */ 15560Sstevel@tonic-gate (void) fprintf(stderr, 15573492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM), 15583492Sab196087 file, sortcache->c_name); 15593492Sab196087 continue; 15600Sstevel@tonic-gate } 15613492Sab196087 /* Fallthrough to process associated dynsym */ 15623492Sab196087 /*FALLTHROUGH*/ 15633492Sab196087 case SHT_DYNSYM: 15643492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum, 15653875Sab196087 symsecndx, ehdr, versym, file, flags)) 15663492Sab196087 continue; 15673492Sab196087 break; 15683492Sab196087 default: 15693492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC), 15703492Sab196087 file, sortcache->c_name, conv_sec_type( 15713492Sab196087 ehdr->e_machine, symshdr->sh_type, 0)); 15723492Sab196087 continue; 15733492Sab196087 } 15740Sstevel@tonic-gate 15753492Sab196087 /* 15763492Sab196087 * Output header 15773492Sab196087 */ 15783492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 15793492Sab196087 if (ldynsym_cnt > 0) { 15803492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2), 15813492Sab196087 sortcache->c_name, ldynsym_state.secname, 15823492Sab196087 dynsym_state.secname); 15830Sstevel@tonic-gate /* 15843492Sab196087 * The data for .SUNW_ldynsym and dynsym sections 15853492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming 15863492Sab196087 * first. Check, and issue a warning if it isn't so. 15870Sstevel@tonic-gate */ 1588*4665Sab196087 if (((ldynsym_state.sym + ldynsym_state.symn) 1589*4665Sab196087 != dynsym_state.sym) && 1590*4665Sab196087 ((flags & FLG_FAKESHDR) == 0)) 15913492Sab196087 (void) fprintf(stderr, 15923492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file, 15933492Sab196087 ldynsym_state.secname, 15943492Sab196087 dynsym_state.secname); 15953492Sab196087 } else { 15963492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1), 15973492Sab196087 sortcache->c_name, dynsym_state.secname); 15983492Sab196087 } 15993492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 16003492Sab196087 16013492Sab196087 /* If not first one, insert a line of whitespace */ 16023492Sab196087 if (output_cnt++ > 0) 16033492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 16043118Sab196087 16053492Sab196087 /* 16063492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of 16073492Sab196087 * symbol indices. Iterate over the array entries, 16083492Sab196087 * dispaying the referenced symbols. 16093492Sab196087 */ 16103492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize; 16113492Sab196087 ndx = (Word *)sortcache->c_data->d_buf; 16123492Sab196087 for (; ndxn-- > 0; ndx++) { 16133492Sab196087 if (*ndx >= ldynsym_cnt) { 16143492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt; 16153492Sab196087 16163492Sab196087 output_symbol(&dynsym_state, sec_ndx, 16173492Sab196087 *ndx, dynsym_state.sym + sec_ndx); 16183492Sab196087 } else { 16193492Sab196087 output_symbol(&ldynsym_state, *ndx, 16203492Sab196087 *ndx, ldynsym_state.sym + *ndx); 16210Sstevel@tonic-gate } 16220Sstevel@tonic-gate } 16230Sstevel@tonic-gate } 16240Sstevel@tonic-gate } 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate /* 16270Sstevel@tonic-gate * Search for and process any relocation sections. 16280Sstevel@tonic-gate */ 16290Sstevel@tonic-gate static void 16304168Sab196087 reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *file, 16311618Srie uint_t flags) 16320Sstevel@tonic-gate { 16331618Srie Word cnt; 16340Sstevel@tonic-gate 16350Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 16361618Srie Word type, symnum; 16371618Srie Xword relndx, relnum, relsize; 16381618Srie void *rels; 16391618Srie Sym *syms; 16401618Srie Cache *symsec, *strsec; 16410Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 16421618Srie Shdr *shdr = _cache->c_shdr; 16431618Srie char *relname = _cache->c_name; 16440Sstevel@tonic-gate 16450Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) && 16460Sstevel@tonic-gate (type != SHT_REL)) 16470Sstevel@tonic-gate continue; 16484168Sab196087 if (!match(0, relname, cnt)) 16490Sstevel@tonic-gate continue; 16500Sstevel@tonic-gate 16510Sstevel@tonic-gate /* 16521618Srie * Decide entry size. 16530Sstevel@tonic-gate */ 16541618Srie if (((relsize = shdr->sh_entsize) == 0) || 16551618Srie (relsize > shdr->sh_size)) { 16560Sstevel@tonic-gate if (type == SHT_RELA) 16571618Srie relsize = sizeof (Rela); 16580Sstevel@tonic-gate else 16591618Srie relsize = sizeof (Rel); 16600Sstevel@tonic-gate } 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate /* 16630Sstevel@tonic-gate * Determine the number of relocations available. 16640Sstevel@tonic-gate */ 16650Sstevel@tonic-gate if (shdr->sh_size == 0) { 16660Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 16671618Srie file, relname); 16680Sstevel@tonic-gate continue; 16690Sstevel@tonic-gate } 16703466Srie if (_cache->c_data == NULL) 16713466Srie continue; 16723466Srie 16731618Srie rels = _cache->c_data->d_buf; 16741618Srie relnum = shdr->sh_size / relsize; 16750Sstevel@tonic-gate 16760Sstevel@tonic-gate /* 16771618Srie * Get the data buffer for the associated symbol table and 16781618Srie * string table. 16790Sstevel@tonic-gate */ 16801618Srie if (stringtbl(cache, 1, cnt, shnum, file, 16811618Srie &symnum, &symsec, &strsec) == 0) 16820Sstevel@tonic-gate continue; 16831618Srie 16841618Srie syms = symsec->c_data->d_buf; 16850Sstevel@tonic-gate 16860Sstevel@tonic-gate /* 16870Sstevel@tonic-gate * Loop through the relocation entries. 16880Sstevel@tonic-gate */ 16891618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 16901618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 16911618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type); 16920Sstevel@tonic-gate 16931618Srie for (relndx = 0; relndx < relnum; relndx++, 16941618Srie rels = (void *)((char *)rels + relsize)) { 16950Sstevel@tonic-gate char section[BUFSIZ]; 16961618Srie const char *symname; 16971618Srie Word symndx, reltype; 16981618Srie Rela *rela; 16991618Srie Rel *rel; 17000Sstevel@tonic-gate 17010Sstevel@tonic-gate /* 17021618Srie * Unravel the relocation and determine the symbol with 17031618Srie * which this relocation is associated. 17040Sstevel@tonic-gate */ 17050Sstevel@tonic-gate if (type == SHT_RELA) { 17061618Srie rela = (Rela *)rels; 17071618Srie symndx = ELF_R_SYM(rela->r_info); 17081618Srie reltype = ELF_R_TYPE(rela->r_info); 17090Sstevel@tonic-gate } else { 17101618Srie rel = (Rel *)rels; 17111618Srie symndx = ELF_R_SYM(rel->r_info); 17121618Srie reltype = ELF_R_TYPE(rel->r_info); 17130Sstevel@tonic-gate } 17141618Srie 17151618Srie symname = relsymname(cache, _cache, strsec, symndx, 17161618Srie symnum, relndx, syms, section, BUFSIZ, file, 17171618Srie flags); 17181618Srie 17191618Srie /* 17201618Srie * A zero symbol index is only valid for a few 17211618Srie * relocations. 17221618Srie */ 17231618Srie if (symndx == 0) { 17241618Srie Half mach = ehdr->e_machine; 17251618Srie int badrel = 0; 17260Sstevel@tonic-gate 17271618Srie if ((mach == EM_SPARC) || 17281618Srie (mach == EM_SPARC32PLUS) || 17291618Srie (mach == EM_SPARCV9)) { 17301618Srie if ((reltype != R_SPARC_NONE) && 17311618Srie (reltype != R_SPARC_REGISTER) && 17321618Srie (reltype != R_SPARC_RELATIVE)) 17331618Srie badrel++; 17341618Srie } else if (mach == EM_386) { 17351618Srie if ((reltype != R_386_NONE) && 17361618Srie (reltype != R_386_RELATIVE)) 17371618Srie badrel++; 17381618Srie } else if (mach == EM_AMD64) { 17391618Srie if ((reltype != R_AMD64_NONE) && 17401618Srie (reltype != R_AMD64_RELATIVE)) 17411618Srie badrel++; 17421618Srie } 17431618Srie 17441618Srie if (badrel) { 17451618Srie (void) fprintf(stderr, 17461618Srie MSG_INTL(MSG_ERR_BADREL1), file, 17471976Sab196087 conv_reloc_type(mach, reltype, 0)); 17480Sstevel@tonic-gate } 17490Sstevel@tonic-gate } 17500Sstevel@tonic-gate 17511618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP, 17521618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type, 17531618Srie rels, relname, symname, 0); 17540Sstevel@tonic-gate } 17550Sstevel@tonic-gate } 17560Sstevel@tonic-gate } 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate /* 17590Sstevel@tonic-gate * Search for and process a .dynamic section. 17600Sstevel@tonic-gate */ 17610Sstevel@tonic-gate static void 17621618Srie dynamic(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 17630Sstevel@tonic-gate { 17641618Srie Word cnt; 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 17671618Srie Dyn *dyn; 17681618Srie ulong_t numdyn; 17693850Sab196087 int ndx, end_ndx; 17701618Srie Cache *_cache = &cache[cnt], *strsec; 17711618Srie Shdr *shdr = _cache->c_shdr; 17720Sstevel@tonic-gate 17730Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC) 17740Sstevel@tonic-gate continue; 17750Sstevel@tonic-gate 17760Sstevel@tonic-gate /* 17771618Srie * Verify the associated string table section. 17780Sstevel@tonic-gate */ 17791618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0) 17800Sstevel@tonic-gate continue; 17811618Srie 17823466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 17833466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 17843466Srie file, _cache->c_name); 17853466Srie continue; 17863466Srie } 17873466Srie if (_cache->c_data == NULL) 17883466Srie continue; 17893466Srie 17900Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize; 17911618Srie dyn = (Dyn *)_cache->c_data->d_buf; 17920Sstevel@tonic-gate 17931618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17941618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 17950Sstevel@tonic-gate 17961618Srie Elf_dyn_title(0); 17970Sstevel@tonic-gate 17981618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 17991618Srie const char *name; 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate /* 18020Sstevel@tonic-gate * Print the information numerically, and if possible 18030Sstevel@tonic-gate * as a string. 18040Sstevel@tonic-gate */ 18053850Sab196087 switch (dyn->d_tag) { 18063850Sab196087 case DT_NULL: 18073850Sab196087 /* 18083850Sab196087 * Special case: DT_NULLs can come in groups 18093850Sab196087 * that we prefer to reduce to a single line. 18103850Sab196087 */ 18113850Sab196087 end_ndx = ndx; 18123850Sab196087 while ((end_ndx < (numdyn - 1)) && 18134433Sab196087 ((dyn + 1)->d_tag == DT_NULL)) { 18143850Sab196087 dyn++; 18153850Sab196087 end_ndx++; 18163850Sab196087 } 18173850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 18183850Sab196087 ndx = end_ndx; 18193850Sab196087 continue; 18203850Sab196087 18213850Sab196087 /* 18223850Sab196087 * Print the information numerically, and if possible 18233850Sab196087 * as a string. 18243850Sab196087 */ 18253850Sab196087 case DT_NEEDED: 18263850Sab196087 case DT_SONAME: 18273850Sab196087 case DT_FILTER: 18283850Sab196087 case DT_AUXILIARY: 18293850Sab196087 case DT_CONFIG: 18303850Sab196087 case DT_RPATH: 18313850Sab196087 case DT_RUNPATH: 18323850Sab196087 case DT_USED: 18333850Sab196087 case DT_DEPAUDIT: 18343850Sab196087 case DT_AUDIT: 18353850Sab196087 case DT_SUNW_AUXILIARY: 18363850Sab196087 case DT_SUNW_FILTER: 18371618Srie name = string(_cache, ndx, strsec, 18381618Srie file, dyn->d_un.d_ptr); 18393850Sab196087 break; 18403850Sab196087 18413850Sab196087 case DT_FLAGS: 18422352Sab196087 name = conv_dyn_flag(dyn->d_un.d_val, 0); 18433850Sab196087 break; 18443850Sab196087 case DT_FLAGS_1: 18451618Srie name = conv_dyn_flag1(dyn->d_un.d_val); 18463850Sab196087 break; 18473850Sab196087 case DT_POSFLAG_1: 18482352Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0); 18493850Sab196087 break; 18503850Sab196087 case DT_FEATURE_1: 18512352Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0); 18523850Sab196087 break; 18533850Sab196087 case DT_DEPRECATED_SPARC_REGISTER: 18541618Srie name = MSG_INTL(MSG_STR_DEPRECATED); 18553850Sab196087 break; 18563850Sab196087 default: 18571618Srie name = MSG_ORIG(MSG_STR_EMPTY); 18583850Sab196087 break; 18593850Sab196087 } 18600Sstevel@tonic-gate 18611618Srie Elf_dyn_entry(0, dyn, ndx, name, ehdr->e_machine); 18620Sstevel@tonic-gate } 18630Sstevel@tonic-gate } 18640Sstevel@tonic-gate } 18650Sstevel@tonic-gate 18660Sstevel@tonic-gate /* 18670Sstevel@tonic-gate * Search for and process a MOVE section. 18680Sstevel@tonic-gate */ 18690Sstevel@tonic-gate static void 18704168Sab196087 move(Cache *cache, Word shnum, const char *file, uint_t flags) 18710Sstevel@tonic-gate { 18721618Srie Word cnt; 18731618Srie const char *fmt = 0; 18740Sstevel@tonic-gate 18750Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 18761618Srie Word movenum, symnum, ndx; 18771618Srie Sym *syms; 18781618Srie Cache *_cache = &cache[cnt]; 18791618Srie Shdr *shdr = _cache->c_shdr; 18801618Srie Cache *symsec, *strsec; 18811618Srie Move *move; 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move) 18840Sstevel@tonic-gate continue; 18854168Sab196087 if (!match(0, _cache->c_name, cnt)) 18860Sstevel@tonic-gate continue; 18870Sstevel@tonic-gate 18880Sstevel@tonic-gate /* 18890Sstevel@tonic-gate * Determine the move data and number. 18900Sstevel@tonic-gate */ 18910Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 18920Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 18930Sstevel@tonic-gate file, _cache->c_name); 18940Sstevel@tonic-gate continue; 18950Sstevel@tonic-gate } 18963466Srie if (_cache->c_data == NULL) 18973466Srie continue; 18983466Srie 18991618Srie move = (Move *)_cache->c_data->d_buf; 19001618Srie movenum = shdr->sh_size / shdr->sh_entsize; 19010Sstevel@tonic-gate 19020Sstevel@tonic-gate /* 19031618Srie * Get the data buffer for the associated symbol table and 19041618Srie * string table. 19050Sstevel@tonic-gate */ 19061618Srie if (stringtbl(cache, 1, cnt, shnum, file, 19071618Srie &symnum, &symsec, &strsec) == 0) 19081618Srie return; 19091618Srie 19101618Srie syms = (Sym *)symsec->c_data->d_buf; 19110Sstevel@tonic-gate 19121618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 19131618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); 19141618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); 19150Sstevel@tonic-gate 19161618Srie if (fmt == 0) 19171618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY); 19180Sstevel@tonic-gate 19191618Srie for (ndx = 0; ndx < movenum; move++, ndx++) { 19201618Srie const char *symname; 19211618Srie char index[MAXNDXSIZE], section[BUFSIZ]; 19221618Srie Word symndx, shndx; 19231618Srie Sym *sym; 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate /* 19260Sstevel@tonic-gate * Check for null entries 19270Sstevel@tonic-gate */ 19281618Srie if ((move->m_info == 0) && (move->m_value == 0) && 19291618Srie (move->m_poffset == 0) && (move->m_repeat == 0) && 19301618Srie (move->m_stride == 0)) { 19311618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY), 19321618Srie EC_XWORD(move->m_poffset), 0, 0, 0, 19331618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY)); 19340Sstevel@tonic-gate continue; 19350Sstevel@tonic-gate } 19361618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) || 19371618Srie (symndx >= symnum)) { 19380Sstevel@tonic-gate (void) fprintf(stderr, 19390Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file, 19401618Srie _cache->c_name, EC_XWORD(move->m_info)); 19411618Srie 19421618Srie (void) snprintf(index, MAXNDXSIZE, 19431618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 19441618Srie dbg_print(0, fmt, index, 19451618Srie EC_XWORD(move->m_poffset), 19461618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 19471618Srie move->m_stride, move->m_value, 19480Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN)); 19490Sstevel@tonic-gate continue; 19500Sstevel@tonic-gate } 19510Sstevel@tonic-gate 19521618Srie symname = relsymname(cache, _cache, strsec, 19531618Srie symndx, symnum, ndx, syms, section, BUFSIZ, file, 19541618Srie flags); 19551618Srie sym = (Sym *)(syms + symndx); 19560Sstevel@tonic-gate 19570Sstevel@tonic-gate /* 19580Sstevel@tonic-gate * Additional sanity check. 19590Sstevel@tonic-gate */ 19601618Srie shndx = sym->st_shndx; 19610Sstevel@tonic-gate if (!((shndx == SHN_COMMON) || 19620Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) && 19631618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) { 19640Sstevel@tonic-gate (void) fprintf(stderr, 19651618Srie MSG_INTL(MSG_ERR_BADSYM2), file, 19661618Srie _cache->c_name, demangle(symname, flags)); 19670Sstevel@tonic-gate } 19680Sstevel@tonic-gate 19691618Srie (void) snprintf(index, MAXNDXSIZE, 19701618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 19711618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset), 19721618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 19731618Srie move->m_stride, move->m_value, 19741618Srie demangle(symname, flags)); 19750Sstevel@tonic-gate } 19760Sstevel@tonic-gate } 19770Sstevel@tonic-gate } 19780Sstevel@tonic-gate 19790Sstevel@tonic-gate /* 19800Sstevel@tonic-gate * Traverse a note section analyzing each note information block. 19810Sstevel@tonic-gate * The data buffers size is used to validate references before they are made, 19820Sstevel@tonic-gate * and is decremented as each element is processed. 19830Sstevel@tonic-gate */ 19840Sstevel@tonic-gate void 19851618Srie note_entry(Cache *cache, Word *data, size_t size, const char *file) 19860Sstevel@tonic-gate { 19871618Srie size_t bsize = size; 19881618Srie 19890Sstevel@tonic-gate /* 19900Sstevel@tonic-gate * Print out a single `note' information block. 19910Sstevel@tonic-gate */ 19920Sstevel@tonic-gate while (size > 0) { 19931618Srie size_t namesz, descsz, type, pad, noteoff; 19940Sstevel@tonic-gate 19950Sstevel@tonic-gate noteoff = bsize - size; 19960Sstevel@tonic-gate /* 19970Sstevel@tonic-gate * Make sure we can at least reference the 3 initial entries 19980Sstevel@tonic-gate * (4-byte words) of the note information block. 19990Sstevel@tonic-gate */ 20001618Srie if (size >= (sizeof (Word) * 3)) 20011618Srie size -= (sizeof (Word) * 3); 20020Sstevel@tonic-gate else { 20031618Srie (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ), 20041618Srie file, cache->c_name, EC_WORD(noteoff)); 20050Sstevel@tonic-gate return; 20060Sstevel@tonic-gate } 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate /* 20090Sstevel@tonic-gate * Make sure any specified name string can be referenced. 20100Sstevel@tonic-gate */ 20110Sstevel@tonic-gate if ((namesz = *data++) != 0) { 20120Sstevel@tonic-gate if (size >= namesz) 20130Sstevel@tonic-gate size -= namesz; 20140Sstevel@tonic-gate else { 20150Sstevel@tonic-gate (void) fprintf(stderr, 20161618Srie MSG_INTL(MSG_NOTE_BADNMSZ), file, 20171618Srie cache->c_name, EC_WORD(noteoff), 20181618Srie EC_WORD(namesz)); 20190Sstevel@tonic-gate return; 20200Sstevel@tonic-gate } 20210Sstevel@tonic-gate } 20221618Srie 20230Sstevel@tonic-gate /* 20240Sstevel@tonic-gate * Make sure any specified descriptor can be referenced. 20250Sstevel@tonic-gate */ 20260Sstevel@tonic-gate if ((descsz = *data++) != 0) { 20270Sstevel@tonic-gate /* 20280Sstevel@tonic-gate * If namesz isn't a 4-byte multiple, account for any 20290Sstevel@tonic-gate * padding that must exist before the descriptor. 20300Sstevel@tonic-gate */ 20311618Srie if ((pad = (namesz & (sizeof (Word) - 1))) != 0) { 20321618Srie pad = sizeof (Word) - pad; 20330Sstevel@tonic-gate size -= pad; 20340Sstevel@tonic-gate } 20350Sstevel@tonic-gate if (size >= descsz) 20360Sstevel@tonic-gate size -= descsz; 20370Sstevel@tonic-gate else { 20380Sstevel@tonic-gate (void) fprintf(stderr, 20391618Srie MSG_INTL(MSG_NOTE_BADDESZ), file, 20401618Srie cache->c_name, EC_WORD(noteoff), 20411618Srie EC_WORD(namesz)); 20420Sstevel@tonic-gate return; 20430Sstevel@tonic-gate } 20440Sstevel@tonic-gate } 20450Sstevel@tonic-gate 20460Sstevel@tonic-gate type = *data++; 20470Sstevel@tonic-gate 20481618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 20491618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type)); 20500Sstevel@tonic-gate 20511618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz)); 20520Sstevel@tonic-gate if (namesz) { 20530Sstevel@tonic-gate char *name = (char *)data; 20540Sstevel@tonic-gate 20550Sstevel@tonic-gate /* 20560Sstevel@tonic-gate * Since the name string may have 'null' bytes 20570Sstevel@tonic-gate * in it (ia32 .string) - we just write the 20580Sstevel@tonic-gate * whole stream in a single fwrite. 20590Sstevel@tonic-gate */ 20600Sstevel@tonic-gate (void) fwrite(name, namesz, 1, stdout); 20610Sstevel@tonic-gate name = name + ((namesz + (sizeof (Word) - 1)) & 20620Sstevel@tonic-gate ~(sizeof (Word) - 1)); 20630Sstevel@tonic-gate /* LINTED */ 20640Sstevel@tonic-gate data = (Word *)name; 20651618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 20660Sstevel@tonic-gate } 20670Sstevel@tonic-gate 20680Sstevel@tonic-gate /* 20690Sstevel@tonic-gate * If multiple information blocks exist within a .note section 20700Sstevel@tonic-gate * account for any padding that must exist before the next 20710Sstevel@tonic-gate * information block. 20720Sstevel@tonic-gate */ 20731618Srie if ((pad = (descsz & (sizeof (Word) - 1))) != 0) { 20741618Srie pad = sizeof (Word) - pad; 20750Sstevel@tonic-gate if (size > pad) 20760Sstevel@tonic-gate size -= pad; 20770Sstevel@tonic-gate } 20780Sstevel@tonic-gate 20791618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz)); 20800Sstevel@tonic-gate if (descsz) { 20810Sstevel@tonic-gate int ndx, byte, word; 20821618Srie char string[58], *str = string; 20830Sstevel@tonic-gate uchar_t *desc = (uchar_t *)data; 20840Sstevel@tonic-gate 20850Sstevel@tonic-gate /* 20860Sstevel@tonic-gate * Dump descriptor bytes. 20870Sstevel@tonic-gate */ 20880Sstevel@tonic-gate for (ndx = byte = word = 0; descsz; descsz--, desc++) { 20890Sstevel@tonic-gate int tok = *desc; 20900Sstevel@tonic-gate 20910Sstevel@tonic-gate (void) snprintf(str, 58, MSG_ORIG(MSG_NOTE_TOK), 20920Sstevel@tonic-gate tok); 20930Sstevel@tonic-gate str += 3; 20940Sstevel@tonic-gate 20950Sstevel@tonic-gate if (++byte == 4) { 20960Sstevel@tonic-gate *str++ = ' ', *str++ = ' '; 20970Sstevel@tonic-gate word++; 20980Sstevel@tonic-gate byte = 0; 20990Sstevel@tonic-gate } 21000Sstevel@tonic-gate if (word == 4) { 21010Sstevel@tonic-gate *str = '\0'; 21021618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESC), 21030Sstevel@tonic-gate ndx, string); 21040Sstevel@tonic-gate word = 0; 21050Sstevel@tonic-gate ndx += 16; 21060Sstevel@tonic-gate str = string; 21070Sstevel@tonic-gate } 21080Sstevel@tonic-gate } 21090Sstevel@tonic-gate if (byte || word) { 21100Sstevel@tonic-gate *str = '\0'; 21111618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESC), 21121618Srie ndx, string); 21130Sstevel@tonic-gate } 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate desc += pad; 21160Sstevel@tonic-gate /* LINTED */ 21170Sstevel@tonic-gate data = (Word *)desc; 21180Sstevel@tonic-gate } 21190Sstevel@tonic-gate } 21200Sstevel@tonic-gate } 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate /* 21230Sstevel@tonic-gate * Search for and process a .note section. 21240Sstevel@tonic-gate */ 21250Sstevel@tonic-gate static void 21264168Sab196087 note(Cache *cache, Word shnum, const char *file) 21270Sstevel@tonic-gate { 21281618Srie Word cnt; 21290Sstevel@tonic-gate 21300Sstevel@tonic-gate /* 21310Sstevel@tonic-gate * Otherwise look for any .note sections. 21320Sstevel@tonic-gate */ 21330Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 21341618Srie Cache *_cache = &cache[cnt]; 21351618Srie Shdr *shdr = _cache->c_shdr; 21360Sstevel@tonic-gate 21370Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE) 21380Sstevel@tonic-gate continue; 21394168Sab196087 if (!match(0, _cache->c_name, cnt)) 21400Sstevel@tonic-gate continue; 21410Sstevel@tonic-gate 21420Sstevel@tonic-gate /* 21430Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're 21440Sstevel@tonic-gate * properly aligned before proceeding. 21450Sstevel@tonic-gate */ 21460Sstevel@tonic-gate if (shdr->sh_offset & (sizeof (Word) - 1)) { 21470Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 21480Sstevel@tonic-gate file, _cache->c_name); 21490Sstevel@tonic-gate continue; 21500Sstevel@tonic-gate } 21513466Srie if (_cache->c_data == NULL) 21523466Srie continue; 21530Sstevel@tonic-gate 21541618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 21551618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 21560Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf, 21570Sstevel@tonic-gate /* LINTED */ 21580Sstevel@tonic-gate (Word)_cache->c_data->d_size, file); 21590Sstevel@tonic-gate } 21600Sstevel@tonic-gate } 21610Sstevel@tonic-gate 21621618Srie /* 21631618Srie * Determine an individual hash entry. This may be the initial hash entry, 21641618Srie * or an associated chain entry. 21651618Srie */ 21661618Srie static void 21671618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx, 21681618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts, 21691618Srie uint_t flags, int chain) 21701618Srie { 21711618Srie Sym *sym; 21721618Srie const char *symname, *str; 21731618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE]; 21741618Srie ulong_t nbkt, nhash; 21751618Srie 21761618Srie if (symndx > symn) { 21771618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file, 21781618Srie EC_WORD(symndx), EC_WORD(hashndx)); 21791618Srie symname = MSG_INTL(MSG_STR_UNKNOWN); 21801618Srie } else { 21811618Srie sym = (Sym *)(syms + symndx); 21821618Srie symname = string(refsec, symndx, strsec, file, sym->st_name); 21831618Srie } 21841618Srie 21851618Srie if (chain == 0) { 21861618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 21871618Srie hashndx); 21881618Srie str = (const char *)_bucket; 21891618Srie } else 21901618Srie str = MSG_ORIG(MSG_STR_EMPTY); 21911618Srie 21921618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2), 21931618Srie EC_WORD(symndx)); 21941618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx, 21951618Srie demangle(symname, flags)); 21961618Srie 21971618Srie /* 21981618Srie * Determine if this string is in the correct bucket. 21991618Srie */ 22001618Srie nhash = elf_hash(symname); 22011618Srie nbkt = nhash % bkts; 22021618Srie 22031618Srie if (nbkt != hashndx) { 22041618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file, 22051618Srie hsecname, symname, EC_WORD(hashndx), nbkt); 22061618Srie } 22071618Srie } 22080Sstevel@tonic-gate 22090Sstevel@tonic-gate #define MAXCOUNT 500 22100Sstevel@tonic-gate 22110Sstevel@tonic-gate static void 22124168Sab196087 hash(Cache *cache, Word shnum, const char *file, uint_t flags) 22130Sstevel@tonic-gate { 22140Sstevel@tonic-gate static int count[MAXCOUNT]; 22151618Srie Word cnt; 22160Sstevel@tonic-gate ulong_t ndx, bkts; 22170Sstevel@tonic-gate char number[MAXNDXSIZE]; 22180Sstevel@tonic-gate 22190Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 22200Sstevel@tonic-gate uint_t *hash, *chain; 22210Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 22221618Srie Shdr *sshdr, *hshdr = _cache->c_shdr; 22231618Srie char *ssecname, *hsecname = _cache->c_name; 22241618Srie Sym *syms; 22251618Srie Word symn; 22260Sstevel@tonic-gate 22271618Srie if (hshdr->sh_type != SHT_HASH) 22280Sstevel@tonic-gate continue; 22290Sstevel@tonic-gate 22300Sstevel@tonic-gate /* 22310Sstevel@tonic-gate * Determine the hash table data and size. 22320Sstevel@tonic-gate */ 22331618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) { 22340Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 22351618Srie file, hsecname); 22360Sstevel@tonic-gate continue; 22370Sstevel@tonic-gate } 22383466Srie if (_cache->c_data == NULL) 22393466Srie continue; 22403466Srie 22410Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf; 22420Sstevel@tonic-gate bkts = *hash; 22430Sstevel@tonic-gate chain = hash + 2 + bkts; 22440Sstevel@tonic-gate hash += 2; 22450Sstevel@tonic-gate 22460Sstevel@tonic-gate /* 22470Sstevel@tonic-gate * Get the data buffer for the associated symbol table. 22480Sstevel@tonic-gate */ 22491618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) { 22500Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 22511618Srie file, hsecname, EC_WORD(hshdr->sh_link)); 22520Sstevel@tonic-gate continue; 22530Sstevel@tonic-gate } 22541618Srie 22551618Srie _cache = &cache[hshdr->sh_link]; 22561618Srie ssecname = _cache->c_name; 22571618Srie 22583466Srie if (_cache->c_data == NULL) 22593466Srie continue; 22603466Srie 22613466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) { 22620Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 22631618Srie file, ssecname); 22640Sstevel@tonic-gate continue; 22650Sstevel@tonic-gate } 22660Sstevel@tonic-gate 22671618Srie sshdr = _cache->c_shdr; 22681618Srie /* LINTED */ 22691618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize); 22701618Srie 22710Sstevel@tonic-gate /* 22720Sstevel@tonic-gate * Get the associated string table section. 22730Sstevel@tonic-gate */ 22741618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) { 22750Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 22761618Srie file, ssecname, EC_WORD(sshdr->sh_link)); 22770Sstevel@tonic-gate continue; 22780Sstevel@tonic-gate } 22790Sstevel@tonic-gate 22801618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 22811618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname); 22821618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO)); 22830Sstevel@tonic-gate 22840Sstevel@tonic-gate /* 22850Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate 22860Sstevel@tonic-gate * symbols. 22870Sstevel@tonic-gate */ 22880Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) { 22891618Srie Word _ndx, _cnt; 22900Sstevel@tonic-gate 22910Sstevel@tonic-gate if (*hash == 0) { 22920Sstevel@tonic-gate count[0]++; 22930Sstevel@tonic-gate continue; 22940Sstevel@tonic-gate } 22950Sstevel@tonic-gate 22961618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname, 22971618Srie ndx, *hash, symn, syms, file, bkts, flags, 0); 22980Sstevel@tonic-gate 22990Sstevel@tonic-gate /* 23000Sstevel@tonic-gate * Determine if any other symbols are chained to this 23010Sstevel@tonic-gate * bucket. 23020Sstevel@tonic-gate */ 23030Sstevel@tonic-gate _ndx = chain[*hash]; 23040Sstevel@tonic-gate _cnt = 1; 23050Sstevel@tonic-gate while (_ndx) { 23061618Srie hash_entry(_cache, &cache[sshdr->sh_link], 23071618Srie hsecname, ndx, _ndx, symn, syms, file, 23081618Srie bkts, flags, 1); 23090Sstevel@tonic-gate _ndx = chain[_ndx]; 23100Sstevel@tonic-gate _cnt++; 23110Sstevel@tonic-gate } 23120Sstevel@tonic-gate 23130Sstevel@tonic-gate if (_cnt >= MAXCOUNT) { 23140Sstevel@tonic-gate (void) fprintf(stderr, 23151324Srie MSG_INTL(MSG_HASH_OVERFLW), file, 23161618Srie _cache->c_name, EC_WORD(ndx), 23171618Srie EC_WORD(_cnt)); 23180Sstevel@tonic-gate } else 23190Sstevel@tonic-gate count[_cnt]++; 23200Sstevel@tonic-gate } 23210Sstevel@tonic-gate break; 23220Sstevel@tonic-gate } 23230Sstevel@tonic-gate 23240Sstevel@tonic-gate /* 23250Sstevel@tonic-gate * Print out the count information. 23260Sstevel@tonic-gate */ 23270Sstevel@tonic-gate bkts = cnt = 0; 23281618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 23291618Srie 23300Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) { 23311618Srie Word _cnt; 23320Sstevel@tonic-gate 23330Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0) 23340Sstevel@tonic-gate continue; 23350Sstevel@tonic-gate 23361618Srie (void) snprintf(number, MAXNDXSIZE, 23371618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt); 23381618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number, 23391618Srie EC_WORD(ndx)); 23400Sstevel@tonic-gate bkts += _cnt; 23411618Srie cnt += (Word)(ndx * _cnt); 23420Sstevel@tonic-gate } 23430Sstevel@tonic-gate if (cnt) { 23440Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 23451618Srie bkts); 23461618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number, 23471618Srie EC_WORD(cnt)); 23480Sstevel@tonic-gate } 23490Sstevel@tonic-gate } 23500Sstevel@tonic-gate 23510Sstevel@tonic-gate static void 23524168Sab196087 group(Cache *cache, Word shnum, const char *file, uint_t flags) 23530Sstevel@tonic-gate { 23541618Srie Word scnt; 23550Sstevel@tonic-gate 23561618Srie for (scnt = 1; scnt < shnum; scnt++) { 23571618Srie Cache *_cache = &cache[scnt]; 23581618Srie Shdr *shdr = _cache->c_shdr; 23591618Srie Word *grpdata, gcnt, grpcnt, symnum, unknown; 23601618Srie Cache *symsec, *strsec; 23611618Srie Sym *syms, *sym; 23621618Srie char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 23630Sstevel@tonic-gate 23640Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP) 23650Sstevel@tonic-gate continue; 23664168Sab196087 if (!match(0, _cache->c_name, scnt)) 23670Sstevel@tonic-gate continue; 23683466Srie if ((_cache->c_data == NULL) || 23693466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL)) 23700Sstevel@tonic-gate continue; 23711618Srie grpcnt = shdr->sh_size / sizeof (Word); 23721618Srie 23731618Srie /* 23741618Srie * Get the data buffer for the associated symbol table and 23751618Srie * string table. 23761618Srie */ 23771618Srie if (stringtbl(cache, 1, scnt, shnum, file, 23781618Srie &symnum, &symsec, &strsec) == 0) 23791618Srie return; 23801618Srie 23811618Srie syms = symsec->c_data->d_buf; 23821618Srie 23831618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 23841618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name); 23851618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE)); 23861618Srie 23871618Srie /* 23881618Srie * The first element of the group defines the group. The 23891618Srie * associated symbol is defined by the sh_link field. 23901618Srie */ 23911618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) { 23921618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 23931618Srie file, _cache->c_name, EC_WORD(shdr->sh_info)); 23941618Srie return; 23950Sstevel@tonic-gate } 23960Sstevel@tonic-gate 23971618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT)); 23981618Srie if (grpdata[0] & GRP_COMDAT) { 23991618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT)); 24000Sstevel@tonic-gate } 24011618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) { 24021618Srie size_t len = strlen(flgstrbuf); 24031618Srie 24041618Srie (void) snprintf(&flgstrbuf[len], 24051618Srie (MSG_GRP_COMDAT_SIZE + 10 - len), 24061618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown); 24070Sstevel@tonic-gate } 24081618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT)); 24091618Srie sym = (Sym *)(syms + shdr->sh_info); 24100Sstevel@tonic-gate 24111618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf, 24121618Srie demangle(string(_cache, 0, strsec, file, sym->st_name), 24131618Srie flags)); 24141618Srie 24151618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) { 24160Sstevel@tonic-gate char index[MAXNDXSIZE]; 24171618Srie const char *name; 24180Sstevel@tonic-gate 24190Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, 24201618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt)); 24211618Srie 24221618Srie if (grpdata[gcnt] >= shnum) 24231618Srie name = MSG_INTL(MSG_GRP_INVALSCN); 24241618Srie else 24251618Srie name = cache[grpdata[gcnt]].c_name; 24261618Srie 24271618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name, 24284433Sab196087 EC_XWORD(grpdata[gcnt])); 24290Sstevel@tonic-gate } 24300Sstevel@tonic-gate } 24310Sstevel@tonic-gate } 24320Sstevel@tonic-gate 24330Sstevel@tonic-gate static void 24341618Srie got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file, uint_t flags) 24350Sstevel@tonic-gate { 24360Sstevel@tonic-gate Cache *gotcache = 0, *symtab = 0, *_cache; 24371618Srie Addr gotbgn, gotend; 24381618Srie Shdr *gotshdr; 24391618Srie Word cnt, gotents, gotndx; 24400Sstevel@tonic-gate size_t gentsize; 24410Sstevel@tonic-gate Got_info *gottable; 24420Sstevel@tonic-gate char *gotdata; 24431618Srie Sym *gotsym; 24441618Srie Xword gotsymaddr; 24450Sstevel@tonic-gate 24460Sstevel@tonic-gate /* 24471324Srie * First, find the got. 24480Sstevel@tonic-gate */ 24490Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 24500Sstevel@tonic-gate _cache = &cache[cnt]; 24511324Srie if (strncmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT), 24521324Srie MSG_ELF_GOT_SIZE) == 0) { 24530Sstevel@tonic-gate gotcache = _cache; 24540Sstevel@tonic-gate break; 24550Sstevel@tonic-gate } 24560Sstevel@tonic-gate } 24571618Srie if (gotcache == 0) 24580Sstevel@tonic-gate return; 24591324Srie 24601324Srie /* 24611324Srie * A got section within a relocatable object is suspicious. 24621324Srie */ 24631324Srie if (ehdr->e_type == ET_REL) { 24641324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file, 24651324Srie _cache->c_name); 24661324Srie } 24671324Srie 24681618Srie gotshdr = gotcache->c_shdr; 24690Sstevel@tonic-gate if (gotshdr->sh_size == 0) { 24700Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 24710Sstevel@tonic-gate file, gotcache->c_name); 24720Sstevel@tonic-gate return; 24730Sstevel@tonic-gate } 24741618Srie 24751618Srie gotbgn = gotshdr->sh_addr; 24760Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size; 24770Sstevel@tonic-gate 24780Sstevel@tonic-gate /* 24791618Srie * Some architectures don't properly set the sh_entsize for the GOT 24801618Srie * table. If it's not set, default to a size of a pointer. 24810Sstevel@tonic-gate */ 24821618Srie if ((gentsize = gotshdr->sh_entsize) == 0) 24831618Srie gentsize = sizeof (Xword); 24841618Srie 24853466Srie if (gotcache->c_data == NULL) 24863466Srie return; 24873466Srie 24880Sstevel@tonic-gate /* LINTED */ 24891618Srie gotents = (Word)(gotshdr->sh_size / gentsize); 24900Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf; 24910Sstevel@tonic-gate 24920Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 24930Sstevel@tonic-gate int err = errno; 24941618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file, 24951618Srie strerror(err)); 24960Sstevel@tonic-gate return; 24970Sstevel@tonic-gate } 24980Sstevel@tonic-gate 24990Sstevel@tonic-gate /* 25000Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations 25010Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a 25020Sstevel@tonic-gate * .rel[a].got section we check them all. 25030Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab 25040Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 25050Sstevel@tonic-gate */ 25060Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 25071618Srie Word type, symnum; 25081618Srie Xword relndx, relnum, relsize; 25091618Srie void *rels; 25101618Srie Sym *syms; 25111618Srie Cache *symsec, *strsec; 25121618Srie Cache *_cache = &cache[cnt]; 25131618Srie Shdr *shdr; 25140Sstevel@tonic-gate 25151618Srie shdr = _cache->c_shdr; 25161618Srie type = shdr->sh_type; 25170Sstevel@tonic-gate 25181618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) { 25190Sstevel@tonic-gate symtab = _cache; 25200Sstevel@tonic-gate continue; 25210Sstevel@tonic-gate } 25221618Srie if (type == SHT_SYMTAB) { 25230Sstevel@tonic-gate symtab = _cache; 25240Sstevel@tonic-gate continue; 25250Sstevel@tonic-gate } 25261618Srie if ((type != SHT_RELA) && (type != SHT_REL)) 25270Sstevel@tonic-gate continue; 25280Sstevel@tonic-gate 25290Sstevel@tonic-gate /* 25301618Srie * Decide entry size. 25310Sstevel@tonic-gate */ 25321618Srie if (((relsize = shdr->sh_entsize) == 0) || 25331618Srie (relsize > shdr->sh_size)) { 25341618Srie if (type == SHT_RELA) 25351618Srie relsize = sizeof (Rela); 25361618Srie else 25371618Srie relsize = sizeof (Rel); 25380Sstevel@tonic-gate } 25390Sstevel@tonic-gate 25400Sstevel@tonic-gate /* 25411618Srie * Determine the number of relocations available. 25420Sstevel@tonic-gate */ 25431618Srie if (shdr->sh_size == 0) { 25441618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 25451618Srie file, _cache->c_name); 25460Sstevel@tonic-gate continue; 25470Sstevel@tonic-gate } 25483466Srie if (_cache->c_data == NULL) 25493466Srie continue; 25503466Srie 25511618Srie rels = _cache->c_data->d_buf; 25521618Srie relnum = shdr->sh_size / relsize; 25530Sstevel@tonic-gate 25541618Srie /* 25551618Srie * Get the data buffer for the associated symbol table and 25561618Srie * string table. 25571618Srie */ 25581618Srie if (stringtbl(cache, 1, cnt, shnum, file, 25591618Srie &symnum, &symsec, &strsec) == 0) 25601618Srie continue; 25611618Srie 25621618Srie syms = symsec->c_data->d_buf; 25631618Srie 25641618Srie /* 25651618Srie * Loop through the relocation entries. 25661618Srie */ 25671618Srie for (relndx = 0; relndx < relnum; relndx++, 25681618Srie rels = (void *)((char *)rels + relsize)) { 25691618Srie char section[BUFSIZ]; 25701618Srie Addr offset; 25710Sstevel@tonic-gate Got_info *gip; 25721618Srie Word symndx, reltype; 25731618Srie Rela *rela; 25741618Srie Rel *rel; 25750Sstevel@tonic-gate 25761618Srie /* 25771618Srie * Unravel the relocation. 25781618Srie */ 25791618Srie if (type == SHT_RELA) { 25801618Srie rela = (Rela *)rels; 25811618Srie symndx = ELF_R_SYM(rela->r_info); 25821618Srie reltype = ELF_R_TYPE(rela->r_info); 25831618Srie offset = rela->r_offset; 25840Sstevel@tonic-gate } else { 25851618Srie rel = (Rel *)rels; 25861618Srie symndx = ELF_R_SYM(rel->r_info); 25871618Srie reltype = ELF_R_TYPE(rel->r_info); 25881618Srie offset = rel->r_offset; 25890Sstevel@tonic-gate } 25900Sstevel@tonic-gate 25910Sstevel@tonic-gate /* 25920Sstevel@tonic-gate * Only pay attention to relocations against the GOT. 25930Sstevel@tonic-gate */ 25944146Sab196087 if ((offset < gotbgn) || (offset >= gotend)) 25950Sstevel@tonic-gate continue; 25960Sstevel@tonic-gate 25970Sstevel@tonic-gate /* LINTED */ 25981618Srie gotndx = (Word)((offset - gotbgn) / 25990Sstevel@tonic-gate gotshdr->sh_entsize); 26000Sstevel@tonic-gate gip = &gottable[gotndx]; 26011618Srie 26021618Srie if (gip->g_reltype != 0) { 26030Sstevel@tonic-gate (void) fprintf(stderr, 26040Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file, 26051618Srie EC_WORD(gotndx), EC_ADDR(offset)); 26060Sstevel@tonic-gate continue; 26070Sstevel@tonic-gate } 26080Sstevel@tonic-gate 26091618Srie if (symndx) 26101618Srie gip->g_symname = relsymname(cache, _cache, 26111618Srie strsec, symndx, symnum, relndx, syms, 26121618Srie section, BUFSIZ, file, flags); 26131618Srie gip->g_reltype = reltype; 26141618Srie gip->g_rel = rels; 26150Sstevel@tonic-gate } 26160Sstevel@tonic-gate } 26170Sstevel@tonic-gate 26181618Srie if (symlookup(MSG_ORIG(MSG_GOT_SYM), cache, shnum, &gotsym, symtab, 26191618Srie file)) 26201618Srie gotsymaddr = gotsym->st_value; 26210Sstevel@tonic-gate else 26221618Srie gotsymaddr = gotbgn; 26230Sstevel@tonic-gate 26241618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 26251618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name); 26261618Srie Elf_got_title(0); 26270Sstevel@tonic-gate 26280Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) { 26290Sstevel@tonic-gate Got_info *gip; 26300Sstevel@tonic-gate Sword gindex; 26311618Srie Addr gaddr; 26321618Srie Xword gotentry; 26330Sstevel@tonic-gate 26340Sstevel@tonic-gate gip = &gottable[gotndx]; 26350Sstevel@tonic-gate 26360Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize); 26371618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize; 26380Sstevel@tonic-gate 26391618Srie if (gentsize == sizeof (Word)) 26400Sstevel@tonic-gate /* LINTED */ 26411618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx)); 26420Sstevel@tonic-gate else 26430Sstevel@tonic-gate /* LINTED */ 26441618Srie gotentry = *((Xword *)(gotdata) + gotndx); 26450Sstevel@tonic-gate 26461618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine, 26471618Srie gip->g_reltype, gip->g_rel, gip->g_symname); 26480Sstevel@tonic-gate } 26490Sstevel@tonic-gate free(gottable); 26500Sstevel@tonic-gate } 26510Sstevel@tonic-gate 26520Sstevel@tonic-gate void 26530Sstevel@tonic-gate checksum(Elf *elf) 26540Sstevel@tonic-gate { 26551618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 26561618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf)); 26570Sstevel@tonic-gate } 26580Sstevel@tonic-gate 26594242Sab196087 /* 26604242Sab196087 * This variable is used by regular() to communicate the address of 26614242Sab196087 * the section header cache to sort_shdr_ndx_arr(). Unfortunately, 26624242Sab196087 * the qsort() interface does not include a userdata argument by which 26634242Sab196087 * such arbitrary data can be passed, so we are stuck using global data. 26644242Sab196087 */ 26654242Sab196087 static Cache *sort_shdr_ndx_arr_cache; 26664242Sab196087 26674242Sab196087 26684242Sab196087 /* 26694242Sab196087 * Used with qsort() to sort the section indices so that they can be 26704242Sab196087 * used to access the section headers in order of increasing data offset. 26714242Sab196087 * 26724242Sab196087 * entry: 26734242Sab196087 * sort_shdr_ndx_arr_cache - Contains address of 26744242Sab196087 * section header cache. 26754242Sab196087 * v1, v2 - Point at elements of sort_shdr_bits array to be compared. 26764242Sab196087 * 26774242Sab196087 * exit: 26784242Sab196087 * Returns -1 (less than), 0 (equal) or 1 (greater than). 26794242Sab196087 */ 26804242Sab196087 static int 26814242Sab196087 sort_shdr_ndx_arr(const void *v1, const void *v2) 26824242Sab196087 { 26834242Sab196087 Cache *cache1 = sort_shdr_ndx_arr_cache + *((size_t *)v1); 26844242Sab196087 Cache *cache2 = sort_shdr_ndx_arr_cache + *((size_t *)v2); 26854242Sab196087 26864242Sab196087 if (cache1->c_shdr->sh_offset < cache2->c_shdr->sh_offset) 26874242Sab196087 return (-1); 26884242Sab196087 26894242Sab196087 if (cache1->c_shdr->sh_offset > cache2->c_shdr->sh_offset) 26904242Sab196087 return (1); 26914242Sab196087 26924242Sab196087 return (0); 26934242Sab196087 } 26944242Sab196087 26954242Sab196087 2696*4665Sab196087 static int 2697*4665Sab196087 shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx, 2698*4665Sab196087 size_t shnum, Cache **cache_ret) 26990Sstevel@tonic-gate { 27000Sstevel@tonic-gate Elf_Scn *scn; 27010Sstevel@tonic-gate Elf_Data *data; 2702*4665Sab196087 size_t ndx; 2703*4665Sab196087 Shdr *nameshdr; 27040Sstevel@tonic-gate char *names = 0; 27050Sstevel@tonic-gate Cache *cache, *_cache; 27064242Sab196087 size_t *shdr_ndx_arr, shdr_ndx_arr_cnt; 27070Sstevel@tonic-gate 27080Sstevel@tonic-gate 27090Sstevel@tonic-gate /* 27100Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section 27110Sstevel@tonic-gate * name strings. 27120Sstevel@tonic-gate */ 27134156Sab196087 if (shstrndx == SHN_UNDEF) { 27144156Sab196087 /* 27154156Sab196087 * It is rare, but legal, for an object to lack a 27164156Sab196087 * header string table section. 27174156Sab196087 */ 27184156Sab196087 names = NULL; 27194156Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHSTRSEC), file); 27204156Sab196087 } else if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 27210Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 27220Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 27230Sstevel@tonic-gate EC_XWORD(shstrndx)); 27241618Srie 27250Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) { 27260Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 27270Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 27280Sstevel@tonic-gate EC_XWORD(shstrndx)); 27291618Srie 27301618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) { 27310Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 27320Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 27333862Srie EC_WORD(elf_ndxscn(scn))); 27341618Srie 27351618Srie } else if ((names = data->d_buf) == 0) 27360Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 27370Sstevel@tonic-gate 27380Sstevel@tonic-gate /* 27393862Srie * Allocate a cache to maintain a descriptor for each section. 27400Sstevel@tonic-gate */ 2741*4665Sab196087 if ((*cache_ret = cache = malloc(shnum * sizeof (Cache))) == NULL) { 27420Sstevel@tonic-gate int err = errno; 27430Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 27440Sstevel@tonic-gate file, strerror(err)); 2745*4665Sab196087 return (0); 27460Sstevel@tonic-gate } 27470Sstevel@tonic-gate 27481618Srie *cache = cache_init; 27490Sstevel@tonic-gate _cache = cache; 27500Sstevel@tonic-gate _cache++; 27510Sstevel@tonic-gate 27523862Srie /* 27534242Sab196087 * Allocate an array that will hold the section index for 27544242Sab196087 * each section that has data in the ELF file: 27554242Sab196087 * 27564242Sab196087 * - Is not a NOBITS section 27574242Sab196087 * - Data has non-zero length 27584242Sab196087 * 27594242Sab196087 * Note that shnum is an upper bound on the size required. It 27604242Sab196087 * is likely that we won't use a few of these array elements. 27614242Sab196087 * Allocating a modest amount of extra memory in this case means 27624242Sab196087 * that we can avoid an extra loop to count the number of needed 27634242Sab196087 * items, and can fill this array immediately in the first loop 27644242Sab196087 * below. 27654242Sab196087 */ 27664242Sab196087 if ((shdr_ndx_arr = malloc(shnum * sizeof (*shdr_ndx_arr))) == NULL) { 27674242Sab196087 int err = errno; 27684242Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 27694242Sab196087 file, strerror(err)); 2770*4665Sab196087 return (0); 27714242Sab196087 } 27724242Sab196087 shdr_ndx_arr_cnt = 0; 27734242Sab196087 27744242Sab196087 /* 27753862Srie * Traverse the sections of the file. This gathering of data is 27763862Srie * carried out in two passes. First, the section headers are captured 27773862Srie * and the section header names are evaluated. A verification pass is 27783862Srie * then carried out over the section information. Files have been 27793862Srie * known to exhibit overlapping (and hence erroneous) section header 27803862Srie * information. 27813862Srie * 27823862Srie * Finally, the data for each section is obtained. This processing is 27833862Srie * carried out after section verification because should any section 27843862Srie * header overlap occur, and a file needs translating (ie. xlate'ing 27853862Srie * information from a non-native architecture file), then the process 27863862Srie * of translation can corrupt the section header information. Of 27873862Srie * course, if there is any section overlap, the data related to the 27883862Srie * sections is going to be compromised. However, it is the translation 27893862Srie * of this data that has caused problems with elfdump()'s ability to 27903862Srie * extract the data. 27913862Srie */ 27924242Sab196087 for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn); 27934242Sab196087 ndx++, _cache++) { 27943862Srie char scnndxnm[100]; 27953862Srie 27964242Sab196087 _cache->c_ndx = ndx; 27973862Srie _cache->c_scn = scn; 27983862Srie 27991618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) { 28000Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 28010Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 28023862Srie EC_WORD(elf_ndxscn(scn))); 28030Sstevel@tonic-gate } 28040Sstevel@tonic-gate 28053862Srie /* 28064242Sab196087 * If this section has data in the file, include it in 28074242Sab196087 * the array of sections to check for address overlap. 28084242Sab196087 */ 28094242Sab196087 if ((_cache->c_shdr->sh_size != 0) && 28104242Sab196087 (_cache->c_shdr->sh_type != SHT_NOBITS)) 28114242Sab196087 shdr_ndx_arr[shdr_ndx_arr_cnt++] = ndx; 28124242Sab196087 28134242Sab196087 /* 28143862Srie * If a shstrtab exists, assign the section name. 28153862Srie */ 28163862Srie if (names && _cache->c_shdr) { 28173862Srie if (_cache->c_shdr->sh_name && 28183862Srie /* LINTED */ 28193862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) { 28203862Srie _cache->c_name = 28213862Srie names + _cache->c_shdr->sh_name; 28223862Srie continue; 28233862Srie } 28240Sstevel@tonic-gate 28250Sstevel@tonic-gate /* 28263862Srie * Generate an error if the section name index is zero 28273862Srie * or exceeds the shstrtab data. Fall through to 28283862Srie * fabricate a section name. 28290Sstevel@tonic-gate */ 28303862Srie if ((_cache->c_shdr->sh_name == 0) || 28310Sstevel@tonic-gate /* LINTED */ 28321618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) { 28330Sstevel@tonic-gate (void) fprintf(stderr, 28340Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file, 28354242Sab196087 EC_WORD(ndx), 28361618Srie EC_XWORD(_cache->c_shdr->sh_name)); 28370Sstevel@tonic-gate } 28383862Srie } 28393862Srie 28403862Srie /* 28413862Srie * If there exists no shstrtab data, or a section header has no 28423862Srie * name (an invalid index of 0), then compose a name for the 28433862Srie * section. 28443862Srie */ 28453862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm), 28464242Sab196087 MSG_INTL(MSG_FMT_SCNNDX), ndx); 28474242Sab196087 28484242Sab196087 if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == NULL) { 28493862Srie int err = errno; 28503862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 28513862Srie file, strerror(err)); 2852*4665Sab196087 return (0); 28533862Srie } 28543862Srie (void) strcpy(_cache->c_name, scnndxnm); 28553862Srie } 28563862Srie 28573862Srie /* 28583862Srie * Having collected all the sections, validate their address range. 28593862Srie * Cases have existed where the section information has been invalid. 28603862Srie * This can lead to all sorts of other, hard to diagnose errors, as 28613862Srie * each section is processed individually (ie. with elf_getdata()). 28623862Srie * Here, we carry out some address comparisons to catch a family of 28633862Srie * overlapping memory issues we have observed (likely, there are others 28643862Srie * that we have yet to discover). 28653862Srie * 28663862Srie * Note, should any memory overlap occur, obtaining any additional 28673862Srie * data from the file is questionable. However, it might still be 28683862Srie * possible to inspect the ELF header, Programs headers, or individual 28693862Srie * sections, so rather than bailing on an error condition, continue 28703862Srie * processing to see if any data can be salvaged. 28713862Srie */ 28724242Sab196087 if (shdr_ndx_arr_cnt > 1) { 28734242Sab196087 sort_shdr_ndx_arr_cache = cache; 28744242Sab196087 qsort(shdr_ndx_arr, shdr_ndx_arr_cnt, 28754242Sab196087 sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr); 28764242Sab196087 } 28774242Sab196087 for (ndx = 0; ndx < shdr_ndx_arr_cnt; ndx++) { 28784242Sab196087 Cache *_cache = cache + shdr_ndx_arr[ndx]; 28793862Srie Shdr *shdr = _cache->c_shdr; 28803862Srie Off bgn1, bgn = shdr->sh_offset; 28813862Srie Off end1, end = shdr->sh_offset + shdr->sh_size; 28824242Sab196087 size_t ndx1; 28834242Sab196087 28844242Sab196087 /* 28854242Sab196087 * Check the section against all following ones, reporting 28864242Sab196087 * any overlaps. Since we've sorted the sections by offset, 28874242Sab196087 * we can stop after the first comparison that fails. There 28884242Sab196087 * are no overlaps in a properly formed ELF file, in which 28894242Sab196087 * case this algorithm runs in O(n) time. This will degenerate 28904242Sab196087 * to O(n^2) for a completely broken file. Such a file is 28914242Sab196087 * (1) highly unlikely, and (2) unusable, so it is reasonable 28924242Sab196087 * for the analysis to take longer. 28934242Sab196087 */ 28944242Sab196087 for (ndx1 = ndx + 1; ndx1 < shdr_ndx_arr_cnt; ndx1++) { 28954242Sab196087 Cache *_cache1 = cache + shdr_ndx_arr[ndx1]; 28963862Srie Shdr *shdr1 = _cache1->c_shdr; 28973862Srie 28983862Srie bgn1 = shdr1->sh_offset; 28993862Srie end1 = shdr1->sh_offset + shdr1->sh_size; 29003862Srie 29013862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 29023862Srie ((bgn1 < end) && (end1 >= end))) { 29033862Srie (void) fprintf(stderr, 29043862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file, 29054242Sab196087 EC_WORD(elf_ndxscn(_cache->c_scn)), 29064242Sab196087 _cache->c_name, EC_OFF(bgn), EC_OFF(end), 29073862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)), 29084242Sab196087 _cache1->c_name, EC_OFF(bgn1), 29094242Sab196087 EC_OFF(end1)); 29104242Sab196087 } else { /* No overlap, so can stop */ 29114242Sab196087 break; 29120Sstevel@tonic-gate } 29130Sstevel@tonic-gate } 29140Sstevel@tonic-gate 29153862Srie /* 29164242Sab196087 * In addition to checking for sections overlapping 29174242Sab196087 * each other (done above), we should also make sure 29184242Sab196087 * the section doesn't overlap the section header array. 29193862Srie */ 29203862Srie bgn1 = ehdr->e_shoff; 29213862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum); 29223862Srie 29233862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 29243862Srie ((bgn1 < end) && (end1 >= end))) { 29253862Srie (void) fprintf(stderr, 29263862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1), 29273862Srie EC_OFF(end1), 29283862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 29293862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 29303862Srie } 29313862Srie } 29323862Srie 29333862Srie /* 29344242Sab196087 * Obtain the data for each section. 29353862Srie */ 29364242Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 29374242Sab196087 Cache *_cache = &cache[ndx]; 29383862Srie Elf_Scn *scn = _cache->c_scn; 29393862Srie 29400Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 29410Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 29420Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 29433862Srie EC_WORD(elf_ndxscn(scn))); 29440Sstevel@tonic-gate } 2945*4665Sab196087 } 2946*4665Sab196087 2947*4665Sab196087 return (1); 2948*4665Sab196087 } 2949*4665Sab196087 2950*4665Sab196087 2951*4665Sab196087 2952*4665Sab196087 void 2953*4665Sab196087 regular(const char *file, int fd, Elf *elf, uint_t flags, int wfd) 2954*4665Sab196087 { 2955*4665Sab196087 Elf_Scn *scn; 2956*4665Sab196087 Ehdr *ehdr; 2957*4665Sab196087 size_t ndx, shstrndx, shnum, phnum; 2958*4665Sab196087 Shdr *shdr; 2959*4665Sab196087 Cache *cache; 2960*4665Sab196087 VERSYM_STATE versym; 2961*4665Sab196087 2962*4665Sab196087 if ((ehdr = elf_getehdr(elf)) == NULL) { 2963*4665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 2964*4665Sab196087 return; 2965*4665Sab196087 } 2966*4665Sab196087 2967*4665Sab196087 if (elf_getshnum(elf, &shnum) == 0) { 2968*4665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 2969*4665Sab196087 return; 2970*4665Sab196087 } 2971*4665Sab196087 2972*4665Sab196087 if (elf_getshstrndx(elf, &shstrndx) == 0) { 2973*4665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 2974*4665Sab196087 return; 2975*4665Sab196087 } 2976*4665Sab196087 2977*4665Sab196087 if (elf_getphnum(elf, &phnum) == 0) { 2978*4665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 2979*4665Sab196087 return; 2980*4665Sab196087 } 2981*4665Sab196087 /* 2982*4665Sab196087 * If the user requested section headers derived from the 2983*4665Sab196087 * program headers (-P option) and this file doesn't have 2984*4665Sab196087 * any program headers (i.e. ET_REL), then we can't do it. 2985*4665Sab196087 */ 2986*4665Sab196087 if ((phnum == 0) && (flags & FLG_FAKESHDR)) { 2987*4665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_PNEEDSPH), file); 2988*4665Sab196087 return; 2989*4665Sab196087 } 2990*4665Sab196087 2991*4665Sab196087 2992*4665Sab196087 if ((scn = elf_getscn(elf, 0)) != NULL) { 2993*4665Sab196087 if ((shdr = elf_getshdr(scn)) == NULL) { 2994*4665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 2995*4665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 2996*4665Sab196087 return; 2997*4665Sab196087 } 2998*4665Sab196087 } else 2999*4665Sab196087 shdr = 0; 3000*4665Sab196087 3001*4665Sab196087 /* 3002*4665Sab196087 * Print the elf header. 3003*4665Sab196087 */ 3004*4665Sab196087 if (flags & FLG_EHDR) 3005*4665Sab196087 Elf_ehdr(0, ehdr, shdr); 3006*4665Sab196087 3007*4665Sab196087 /* 3008*4665Sab196087 * If the section headers or program headers have inadequate 3009*4665Sab196087 * alignment for the class of object, print a warning. libelf 3010*4665Sab196087 * can handle such files, but programs that use them can crash 3011*4665Sab196087 * when they dereference unaligned items. 3012*4665Sab196087 */ 3013*4665Sab196087 if (ehdr->e_phoff & (sizeof (Addr) - 1)) 3014*4665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADPHDRALIGN), file); 3015*4665Sab196087 if (ehdr->e_shoff & (sizeof (Addr) - 1)) 3016*4665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHDRALIGN), file); 3017*4665Sab196087 3018*4665Sab196087 /* 3019*4665Sab196087 * Print the program headers. 3020*4665Sab196087 */ 3021*4665Sab196087 if ((flags & FLG_PHDR) && (phnum != 0)) { 3022*4665Sab196087 Phdr *phdr; 3023*4665Sab196087 3024*4665Sab196087 if ((phdr = elf_getphdr(elf)) == NULL) { 3025*4665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 3026*4665Sab196087 return; 3027*4665Sab196087 } 3028*4665Sab196087 3029*4665Sab196087 for (ndx = 0; ndx < phnum; phdr++, ndx++) { 3030*4665Sab196087 if (!match(0, conv_phdr_type(ehdr->e_machine, 3031*4665Sab196087 phdr->p_type, CONV_FMT_ALTFILE), ndx)) 3032*4665Sab196087 continue; 3033*4665Sab196087 3034*4665Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 3035*4665Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx)); 3036*4665Sab196087 Elf_phdr(0, ehdr->e_machine, phdr); 3037*4665Sab196087 } 3038*4665Sab196087 } 3039*4665Sab196087 3040*4665Sab196087 /* 3041*4665Sab196087 * Decide how to proceed if there are no sections, if there's just 3042*4665Sab196087 * one section (the first section can act as an extension of the 3043*4665Sab196087 * ELF header), or if only program header information was requested. 3044*4665Sab196087 */ 3045*4665Sab196087 if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) { 3046*4665Sab196087 /* If a core file, display the note and return */ 3047*4665Sab196087 if ((ehdr->e_type == ET_CORE) && (flags & FLG_NOTE)) { 3048*4665Sab196087 note(0, shnum, file); 3049*4665Sab196087 return; 3050*4665Sab196087 } 3051*4665Sab196087 3052*4665Sab196087 /* If only program header info was requested, we're done */ 3053*4665Sab196087 if (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0) 3054*4665Sab196087 return; 30550Sstevel@tonic-gate 30560Sstevel@tonic-gate /* 3057*4665Sab196087 * Section headers are missing. Resort to synthesizing 3058*4665Sab196087 * section headers from the program headers. 30590Sstevel@tonic-gate */ 3060*4665Sab196087 if ((flags & FLG_FAKESHDR) == 0) { 3061*4665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHDR), file); 3062*4665Sab196087 flags |= FLG_FAKESHDR; 3063*4665Sab196087 } 3064*4665Sab196087 } 3065*4665Sab196087 3066*4665Sab196087 /* 3067*4665Sab196087 * Generate a cache of section headers and related information 3068*4665Sab196087 * for use by the rest of elfdump. If requested (or the file 3069*4665Sab196087 * contains no section headers), we generate a fake set of 3070*4665Sab196087 * headers from the information accessible from the program headers. 3071*4665Sab196087 * Otherwise, we use the real section headers contained in the file. 3072*4665Sab196087 */ 3073*4665Sab196087 3074*4665Sab196087 if (flags & FLG_FAKESHDR) { 3075*4665Sab196087 if (fake_shdr_cache(file, fd, elf, ehdr, &cache, &shnum) == 0) 3076*4665Sab196087 return; 3077*4665Sab196087 } else { 3078*4665Sab196087 if (shdr_cache(file, elf, ehdr, shstrndx, shnum, &cache) == 0) 3079*4665Sab196087 return; 3080*4665Sab196087 } 3081*4665Sab196087 3082*4665Sab196087 /* 3083*4665Sab196087 * If -w was specified, find and write out the section(s) data. 3084*4665Sab196087 */ 3085*4665Sab196087 if (wfd) { 3086*4665Sab196087 for (ndx = 1; ndx < shnum; ndx++) { 3087*4665Sab196087 Cache *_cache = &cache[ndx]; 3088*4665Sab196087 3089*4665Sab196087 if (match(1, _cache->c_name, ndx) && _cache->c_data) { 3090*4665Sab196087 (void) write(wfd, _cache->c_data->d_buf, 3091*4665Sab196087 _cache->c_data->d_size); 3092*4665Sab196087 } 30930Sstevel@tonic-gate } 30940Sstevel@tonic-gate } 30950Sstevel@tonic-gate 30960Sstevel@tonic-gate if (flags & FLG_SHDR) 30974168Sab196087 sections(file, cache, shnum, ehdr); 30980Sstevel@tonic-gate 30990Sstevel@tonic-gate if (flags & FLG_INTERP) 31001618Srie interp(file, cache, shnum, phnum, elf); 31010Sstevel@tonic-gate 31023875Sab196087 versions(cache, shnum, file, flags, &versym); 31030Sstevel@tonic-gate 31040Sstevel@tonic-gate if (flags & FLG_SYMBOLS) 31054168Sab196087 symbols(cache, shnum, ehdr, &versym, file, flags); 31060Sstevel@tonic-gate 31073492Sab196087 if (flags & FLG_SORT) 31084168Sab196087 sunw_sort(cache, shnum, ehdr, &versym, file, flags); 31093492Sab196087 31100Sstevel@tonic-gate if (flags & FLG_HASH) 31114168Sab196087 hash(cache, shnum, file, flags); 31120Sstevel@tonic-gate 31130Sstevel@tonic-gate if (flags & FLG_GOT) 31141618Srie got(cache, shnum, ehdr, file, flags); 31150Sstevel@tonic-gate 31160Sstevel@tonic-gate if (flags & FLG_GROUP) 31174168Sab196087 group(cache, shnum, file, flags); 31180Sstevel@tonic-gate 31190Sstevel@tonic-gate if (flags & FLG_SYMINFO) 31200Sstevel@tonic-gate syminfo(cache, shnum, file); 31210Sstevel@tonic-gate 31220Sstevel@tonic-gate if (flags & FLG_RELOC) 31234168Sab196087 reloc(cache, shnum, ehdr, file, flags); 31240Sstevel@tonic-gate 31250Sstevel@tonic-gate if (flags & FLG_DYNAMIC) 31261618Srie dynamic(cache, shnum, ehdr, file); 31270Sstevel@tonic-gate 31280Sstevel@tonic-gate if (flags & FLG_NOTE) 31294168Sab196087 note(cache, shnum, file); 31300Sstevel@tonic-gate 31310Sstevel@tonic-gate if (flags & FLG_MOVE) 31324168Sab196087 move(cache, shnum, file, flags); 31330Sstevel@tonic-gate 31340Sstevel@tonic-gate if (flags & FLG_CHECKSUM) 31350Sstevel@tonic-gate checksum(elf); 31360Sstevel@tonic-gate 31370Sstevel@tonic-gate if (flags & FLG_CAP) 31381618Srie cap(file, cache, shnum, phnum, ehdr, elf); 31390Sstevel@tonic-gate 31400Sstevel@tonic-gate if (flags & FLG_UNWIND) 31414168Sab196087 unwind(cache, shnum, phnum, ehdr, file, elf); 31420Sstevel@tonic-gate 3143*4665Sab196087 3144*4665Sab196087 /* Release the memory used to cache section headers */ 3145*4665Sab196087 if (flags & FLG_FAKESHDR) 3146*4665Sab196087 fake_shdr_cache_free(cache, shnum); 3147*4665Sab196087 else 3148*4665Sab196087 free(cache); 31490Sstevel@tonic-gate } 3150