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 44*3875Sab196087 45*3875Sab196087 46*3875Sab196087 /* 47*3875Sab196087 * VERSYM_STATE is used to maintain information about the VERSYM section 48*3875Sab196087 * in the object being analyzed. It is filled in by versions(), and used 49*3875Sab196087 * by init_symtbl_state() when displaying symbol information. 50*3875Sab196087 * 51*3875Sab196087 * Note that the value of the gnu field is a hueristic guess, 52*3875Sab196087 * based on the section names. 53*3875Sab196087 */ 54*3875Sab196087 typedef struct { 55*3875Sab196087 Cache *cache; /* Pointer to cache entry for VERSYM */ 56*3875Sab196087 Versym *data; /* Pointer to versym array */ 57*3875Sab196087 int num_verdef; /* # of versions defined in object */ 58*3875Sab196087 int gnu; /* True if we think obj produced by GNU tools */ 59*3875Sab196087 } VERSYM_STATE; 60*3875Sab196087 61*3875Sab196087 /* 62*3875Sab196087 * SYMTBL_STATE is used to maintain information about a single symbol 63*3875Sab196087 * table section, for use by the routines that display symbol information. 64*3875Sab196087 */ 65*3875Sab196087 typedef struct { 66*3875Sab196087 const char *file; /* Name of file */ 67*3875Sab196087 Ehdr *ehdr; /* ELF header for file */ 68*3875Sab196087 Cache *cache; /* Cache of all section headers */ 69*3875Sab196087 Word shnum; /* # of sections in cache */ 70*3875Sab196087 Cache *seccache; /* Cache of symbol table section hdr */ 71*3875Sab196087 Word secndx; /* Index of symbol table section hdr */ 72*3875Sab196087 const char *secname; /* Name of section */ 73*3875Sab196087 uint_t flags; /* Command line option flags */ 74*3875Sab196087 struct { /* Extended section index data */ 75*3875Sab196087 int checked; /* TRUE if already checked for shxndx */ 76*3875Sab196087 Word *data; /* NULL, or extended section index */ 77*3875Sab196087 /* used for symbol table entries */ 78*3875Sab196087 uint_t n; /* # items in shxndx.data */ 79*3875Sab196087 } shxndx; 80*3875Sab196087 VERSYM_STATE *versym; /* NULL, or associated VERSYM section */ 81*3875Sab196087 Sym *sym; /* Array of symbols */ 82*3875Sab196087 Word symn; /* # of symbols */ 83*3875Sab196087 } SYMTBL_STATE; 84*3875Sab196087 85*3875Sab196087 86*3875Sab196087 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 { 930Sstevel@tonic-gate static Cache *osec = 0; 940Sstevel@tonic-gate static int nostr; 953492Sab196087 const char *strs; 963492Sab196087 Word strn; 970Sstevel@tonic-gate 983466Srie if (strsec->c_data == NULL) 993466Srie return (NULL); 1003466Srie 1013492Sab196087 strs = (char *)strsec->c_data->d_buf; 1023492Sab196087 strn = strsec->c_data->d_size; 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate /* 1051618Srie * Only print a diagnostic regarding an empty string table once per 1060Sstevel@tonic-gate * input section being processed. 1070Sstevel@tonic-gate */ 1080Sstevel@tonic-gate if (osec != refsec) { 1090Sstevel@tonic-gate osec = refsec; 1100Sstevel@tonic-gate nostr = 0; 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * Is the string table offset within range of the available strings? 1150Sstevel@tonic-gate */ 1160Sstevel@tonic-gate if (name >= strn) { 1170Sstevel@tonic-gate /* 1180Sstevel@tonic-gate * Do we have a empty string table? 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate if (strs == 0) { 1210Sstevel@tonic-gate if (nostr == 0) { 1220Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1230Sstevel@tonic-gate file, strsec->c_name); 1240Sstevel@tonic-gate nostr++; 1250Sstevel@tonic-gate } 1260Sstevel@tonic-gate } else { 1270Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF), 1281618Srie file, refsec->c_name, EC_WORD(ndx), strsec->c_name, 1291618Srie EC_WORD(name), EC_WORD(strn - 1)); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate /* 1330Sstevel@tonic-gate * Return the empty string so that the calling function can 1340Sstevel@tonic-gate * continue it's output diagnostics. 1350Sstevel@tonic-gate */ 1360Sstevel@tonic-gate return (MSG_INTL(MSG_STR_UNKNOWN)); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate return (strs + name); 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* 1421618Srie * Relocations can reference section symbols and standard symbols. If the 1431618Srie * former, establish the section name. 1441618Srie */ 1451618Srie static const char * 1461618Srie relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum, 1471618Srie Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file, 1481618Srie uint_t flags) 1491618Srie { 1501618Srie Sym *sym; 1511618Srie 1521618Srie if (symndx >= symnum) { 1531618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX), 1541618Srie file, EC_WORD(symndx), EC_WORD(relndx)); 1551618Srie return (MSG_INTL(MSG_STR_UNKNOWN)); 1561618Srie } 1571618Srie 1581618Srie sym = (Sym *)(syms + symndx); 1591618Srie 1601618Srie /* 1611618Srie * If the symbol represents a section offset construct an appropriate 1621618Srie * string. 1631618Srie */ 1641618Srie if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) && (sym->st_name == 0)) { 1651618Srie if (flags & FLG_LONGNAME) 1661618Srie (void) snprintf(secstr, secsz, 1671618Srie MSG_INTL(MSG_STR_L_SECTION), 1681618Srie cache[sym->st_shndx].c_name); 1691618Srie else 1701618Srie (void) snprintf(secstr, secsz, 1711618Srie MSG_INTL(MSG_STR_SECTION), 1721618Srie cache[sym->st_shndx].c_name); 1731618Srie return ((const char *)secstr); 1741618Srie } 1751618Srie 1761618Srie return (string(csec, symndx, strsec, file, sym->st_name)); 1771618Srie } 1781618Srie 1791618Srie /* 1801618Srie * Focal point for establishing a string table section. Data such as the 1811618Srie * dynamic information simply points to a string table. Data such as 1821618Srie * relocations, reference a symbol table, which in turn is associated with a 1831618Srie * string table. 1840Sstevel@tonic-gate */ 1850Sstevel@tonic-gate static int 1861618Srie stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file, 1871618Srie Word *symnum, Cache **symsec, Cache **strsec) 1881618Srie { 1891618Srie Shdr *shdr = cache[ndx].c_shdr; 1901618Srie 1911618Srie if (symtab) { 1921618Srie /* 1931618Srie * Validate the symbol table section. 1941618Srie */ 1951618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1961618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 1971618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 1981618Srie return (0); 1991618Srie } 2003466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2013466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2023466Srie file, cache[ndx].c_name); 2033466Srie return (0); 2043466Srie } 2051618Srie 2061618Srie /* 2071618Srie * Obtain, and verify the symbol table data. 2081618Srie */ 2093466Srie if ((cache[ndx].c_data == NULL) || 2103466Srie (cache[ndx].c_data->d_buf == NULL)) { 2111618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2121618Srie file, cache[ndx].c_name); 2131618Srie return (0); 2141618Srie } 2151618Srie 2161618Srie /* 2171618Srie * Establish the string table index. 2181618Srie */ 2191618Srie ndx = shdr->sh_link; 2201618Srie shdr = cache[ndx].c_shdr; 2211618Srie 2221618Srie /* 2231618Srie * Return symbol table information. 2241618Srie */ 2251618Srie if (symnum) 2261618Srie *symnum = (shdr->sh_size / shdr->sh_entsize); 2271618Srie if (symsec) 2281618Srie *symsec = &cache[ndx]; 2291618Srie } 2301618Srie 2311618Srie /* 2321618Srie * Validate the associated string table section. 2331618Srie */ 2341618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2351618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2361618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link)); 2371618Srie return (0); 2381618Srie } 2391618Srie 2401618Srie if (strsec) 2411618Srie *strsec = &cache[shdr->sh_link]; 2421618Srie 2431618Srie return (1); 2441618Srie } 2451618Srie 2461618Srie /* 2471618Srie * Lookup a symbol and set Sym accordingly. 2481618Srie */ 2491618Srie static int 2501618Srie symlookup(const char *name, Cache *cache, Word shnum, Sym **sym, 2510Sstevel@tonic-gate Cache *symtab, const char *file) 2520Sstevel@tonic-gate { 2531618Srie Shdr *shdr; 2541618Srie Word symn, cnt; 2551618Srie Sym *syms; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate if (symtab == 0) 2580Sstevel@tonic-gate return (0); 2590Sstevel@tonic-gate 2601618Srie shdr = symtab->c_shdr; 2611618Srie 2620Sstevel@tonic-gate /* 2630Sstevel@tonic-gate * Determine the symbol data and number. 2640Sstevel@tonic-gate */ 2650Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2660Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2670Sstevel@tonic-gate file, symtab->c_name); 2680Sstevel@tonic-gate return (0); 2690Sstevel@tonic-gate } 2703466Srie if (symtab->c_data == NULL) 2713466Srie return (0); 2723466Srie 2730Sstevel@tonic-gate /* LINTED */ 2741618Srie symn = (Word)(shdr->sh_size / shdr->sh_entsize); 2751618Srie syms = (Sym *)symtab->c_data->d_buf; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* 2780Sstevel@tonic-gate * Get the associated string table section. 2790Sstevel@tonic-gate */ 2800Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2810Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2821618Srie file, symtab->c_name, EC_WORD(shdr->sh_link)); 2830Sstevel@tonic-gate return (0); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate /* 2870Sstevel@tonic-gate * Loop through the symbol table to find a match. 2880Sstevel@tonic-gate */ 2891618Srie for (cnt = 0; cnt < symn; syms++, cnt++) { 2901618Srie const char *symname; 2910Sstevel@tonic-gate 2921618Srie symname = string(symtab, cnt, &cache[shdr->sh_link], file, 2931618Srie syms->st_name); 2940Sstevel@tonic-gate 2951618Srie if (symname && (strcmp(name, symname) == 0)) { 2961618Srie *sym = syms; 2970Sstevel@tonic-gate return (1); 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate } 3000Sstevel@tonic-gate return (0); 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate /* 3040Sstevel@tonic-gate * Print section headers. 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate static void 3071618Srie sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr, 3081618Srie const char *name) 3090Sstevel@tonic-gate { 3101618Srie size_t seccnt; 3110Sstevel@tonic-gate 3121618Srie for (seccnt = 1; seccnt < shnum; seccnt++) { 3131618Srie Cache *_cache = &cache[seccnt]; 3141618Srie Shdr *shdr = _cache->c_shdr; 3151618Srie const char *secname = _cache->c_name; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * Although numerous section header entries can be zero, it's 3193862Srie * usually a sign of trouble if the type is zero. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate if (shdr->sh_type == 0) { 3220Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE), 3231618Srie file, secname, EC_WORD(shdr->sh_type)); 3240Sstevel@tonic-gate } 3253862Srie 3263862Srie if (name && strcmp(name, secname)) 3273862Srie continue; 3280Sstevel@tonic-gate 3291324Srie /* 3301324Srie * Identify any sections that are suspicious. A .got section 3311324Srie * shouldn't exist in a relocatable object. 3321324Srie */ 3331324Srie if (ehdr->e_type == ET_REL) { 3341618Srie if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT), 3351324Srie MSG_ELF_GOT_SIZE) == 0) { 3361324Srie (void) fprintf(stderr, 3371618Srie MSG_INTL(MSG_GOT_UNEXPECTED), file, 3381618Srie secname); 3391324Srie } 3401324Srie } 3411324Srie 3421618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 3431618Srie dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname); 3441618Srie Elf_shdr(0, ehdr->e_machine, shdr); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate 3481618Srie /* 3491618Srie * A couple of instances of unwind data are printed as tables of 8 data items 3501618Srie * expressed as 0x?? integers. 3511618Srie */ 3521618Srie #define UNWINDTBLSZ 10 + (8 * 5) + 1 3531618Srie 3541618Srie static void 3551618Srie unwindtbl(uint64_t *ndx, uint_t len, uchar_t *data, uint64_t doff, 3561618Srie const char *msg, const char *pre, size_t plen) 3571618Srie { 3581618Srie char buffer[UNWINDTBLSZ]; 3591618Srie uint_t boff = plen, cnt = 0; 3601618Srie 3611618Srie dbg_print(0, msg); 3621618Srie (void) strncpy(buffer, pre, UNWINDTBLSZ); 3631618Srie 3641618Srie while (*ndx < (len + 4)) { 3651618Srie if (cnt == 8) { 3661618Srie dbg_print(0, buffer); 3671618Srie boff = plen; 3681618Srie cnt = 0; 3691618Srie } 3701618Srie (void) snprintf(&buffer[boff], UNWINDTBLSZ - boff, 3711618Srie MSG_ORIG(MSG_UNW_TBLENTRY), data[doff + (*ndx)++]); 3721618Srie boff += 5; 3731618Srie cnt++; 3741618Srie } 3751618Srie if (cnt) 3761618Srie dbg_print(0, buffer); 3771618Srie } 3781618Srie 3791618Srie /* 3801618Srie * Obtain a specified Phdr entry. 3811618Srie */ 3821618Srie static Phdr * 3831618Srie getphdr(Word phnum, Word type, const char *file, Elf *elf) 3841618Srie { 3851618Srie Word cnt; 3861618Srie Phdr *phdr; 3871618Srie 3881618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 3891618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 3901618Srie return (0); 3911618Srie } 3921618Srie 3931618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 3941618Srie if (phdr->p_type == type) 3951618Srie return (phdr); 3961618Srie } 3971618Srie return (0); 3981618Srie } 3991618Srie 4000Sstevel@tonic-gate static void 4011618Srie unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *name, 4021618Srie const char *file, Elf *elf) 4030Sstevel@tonic-gate { 4041618Srie Word cnt; 4051618Srie Phdr *uphdr = 0; 4061618Srie 4070Sstevel@tonic-gate /* 4081618Srie * For the moment - UNWIND is only relevant for a AMD64 object. 4090Sstevel@tonic-gate */ 4100Sstevel@tonic-gate if (ehdr->e_machine != EM_AMD64) 4111618Srie return; 4120Sstevel@tonic-gate 4131618Srie if (phnum) 4141618Srie uphdr = getphdr(phnum, PT_SUNW_UNWIND, file, elf); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 4171618Srie Cache *_cache = &cache[cnt]; 4181618Srie Shdr *shdr = _cache->c_shdr; 4191618Srie uchar_t *data; 4200Sstevel@tonic-gate size_t datasize; 4211618Srie uint64_t off, ndx, frame_ptr, fde_cnt, tabndx; 4221618Srie uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate /* 4251618Srie * AMD64 - this is a strmcp() just to find the gcc produced 4261618Srie * sections. Soon gcc should be setting the section type - and 4271618Srie * we'll not need this strcmp(). 4280Sstevel@tonic-gate */ 4290Sstevel@tonic-gate if ((shdr->sh_type != SHT_AMD64_UNWIND) && 4300Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 4310Sstevel@tonic-gate MSG_SCN_FRM_SIZE) != 0) && 4320Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4330Sstevel@tonic-gate MSG_SCN_FRMHDR_SIZE) != 0)) 4340Sstevel@tonic-gate continue; 4350Sstevel@tonic-gate if (name && strcmp(name, _cache->c_name)) 4360Sstevel@tonic-gate continue; 4370Sstevel@tonic-gate 4383466Srie if (_cache->c_data == NULL) 4393466Srie continue; 4403466Srie 4411618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 4421618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 4430Sstevel@tonic-gate 4441618Srie data = (uchar_t *)(_cache->c_data->d_buf); 4450Sstevel@tonic-gate datasize = _cache->c_data->d_size; 4460Sstevel@tonic-gate off = 0; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate /* 4490Sstevel@tonic-gate * Is this a .eh_frame_hdr 4500Sstevel@tonic-gate */ 4511618Srie if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) || 4520Sstevel@tonic-gate (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 4531618Srie MSG_SCN_FRMHDR_SIZE) == 0)) { 4541618Srie 4551618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR)); 4561618Srie ndx = 0; 4570Sstevel@tonic-gate 4581618Srie vers = data[ndx++]; 4591618Srie frame_ptr_enc = data[ndx++]; 4601618Srie fde_cnt_enc = data[ndx++]; 4611618Srie table_enc = data[ndx++]; 4620Sstevel@tonic-gate 4631618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers); 4640Sstevel@tonic-gate 4651618Srie frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc, 4661618Srie ehdr->e_ident, shdr->sh_addr + ndx); 4670Sstevel@tonic-gate 4681618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC), 4691618Srie conv_dwarf_ehe(frame_ptr_enc), EC_XWORD(frame_ptr)); 4701618Srie 4711618Srie fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc, 4721618Srie ehdr->e_ident, shdr->sh_addr + ndx); 4730Sstevel@tonic-gate 4741618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC), 4751618Srie conv_dwarf_ehe(fde_cnt_enc), EC_XWORD(fde_cnt)); 4761618Srie dbg_print(0, MSG_ORIG(MSG_UNW_TABENC), 4771618Srie conv_dwarf_ehe(table_enc)); 4781618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1)); 4791618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2)); 4800Sstevel@tonic-gate 4811618Srie for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 4821618Srie dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT), 4831618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 4841618Srie table_enc, ehdr->e_ident, shdr->sh_addr)), 4851618Srie EC_XWORD(dwarf_ehe_extract(data, &ndx, 4861618Srie table_enc, ehdr->e_ident, shdr->sh_addr))); 4871618Srie } 4881618Srie continue; 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate /* 4920Sstevel@tonic-gate * Walk the Eh_frame's 4930Sstevel@tonic-gate */ 4940Sstevel@tonic-gate while (off < datasize) { 4950Sstevel@tonic-gate uint_t cieid, cielength, cieversion, 4960Sstevel@tonic-gate cieretaddr; 4971618Srie int cieRflag, cieLflag, ciePflag, cieZflag; 4981618Srie uint_t cieaugndx, length, id; 4990Sstevel@tonic-gate uint64_t ciecalign, ciedalign; 5000Sstevel@tonic-gate char *cieaugstr; 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate ndx = 0; 5030Sstevel@tonic-gate /* 5040Sstevel@tonic-gate * extract length in lsb format 5050Sstevel@tonic-gate */ 5060Sstevel@tonic-gate length = LSB32EXTRACT(data + off + ndx); 5070Sstevel@tonic-gate ndx += 4; 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate /* 5100Sstevel@tonic-gate * extract CIE id in lsb format 5110Sstevel@tonic-gate */ 5120Sstevel@tonic-gate id = LSB32EXTRACT(data + off + ndx); 5130Sstevel@tonic-gate ndx += 4; 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate /* 5161618Srie * A CIE record has a id of '0', otherwise this is a 5171618Srie * FDE entry and the 'id' is the CIE pointer. 5180Sstevel@tonic-gate */ 5190Sstevel@tonic-gate if (id == 0) { 5200Sstevel@tonic-gate uint64_t persVal; 5211618Srie 5220Sstevel@tonic-gate cielength = length; 5230Sstevel@tonic-gate cieid = id; 5241618Srie cieLflag = ciePflag = cieRflag = cieZflag = 0; 5250Sstevel@tonic-gate 5261618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIE), 5271618Srie EC_XWORD(shdr->sh_addr + off)); 5281618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH), 5291618Srie cielength, cieid); 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate cieversion = data[off + ndx]; 5320Sstevel@tonic-gate ndx += 1; 5330Sstevel@tonic-gate cieaugstr = (char *)(&data[off + ndx]); 5340Sstevel@tonic-gate ndx += strlen(cieaugstr) + 1; 5351618Srie 5361618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS), 5371618Srie cieversion, cieaugstr); 5381618Srie 5390Sstevel@tonic-gate ciecalign = uleb_extract(&data[off], &ndx); 5400Sstevel@tonic-gate ciedalign = sleb_extract(&data[off], &ndx); 5410Sstevel@tonic-gate cieretaddr = data[off + ndx]; 5420Sstevel@tonic-gate ndx += 1; 5431618Srie 5441618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN), 5451618Srie EC_XWORD(ciecalign), EC_XWORD(ciedalign), 5461618Srie cieretaddr); 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate if (cieaugstr[0]) 5491618Srie dbg_print(0, MSG_ORIG(MSG_UNW_CIEAUXVAL)); 5501618Srie 5510Sstevel@tonic-gate for (cieaugndx = 0; cieaugstr[cieaugndx]; 5520Sstevel@tonic-gate cieaugndx++) { 5530Sstevel@tonic-gate uint_t val; 5541618Srie 5550Sstevel@tonic-gate switch (cieaugstr[cieaugndx]) { 5560Sstevel@tonic-gate case 'z': 5570Sstevel@tonic-gate val = uleb_extract(&data[off], 5580Sstevel@tonic-gate &ndx); 5591618Srie dbg_print(0, 5600Sstevel@tonic-gate MSG_ORIG(MSG_UNW_CIEAUXSIZE), 5610Sstevel@tonic-gate val); 5620Sstevel@tonic-gate cieZflag = 1; 5630Sstevel@tonic-gate break; 5640Sstevel@tonic-gate case 'P': 5650Sstevel@tonic-gate ciePflag = data[off + ndx]; 5660Sstevel@tonic-gate ndx += 1; 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate persVal = dwarf_ehe_extract( 5690Sstevel@tonic-gate &data[off], 5700Sstevel@tonic-gate &ndx, ciePflag, ehdr->e_ident, 5710Sstevel@tonic-gate shdr->sh_addr + off + ndx); 5721618Srie dbg_print(0, 5730Sstevel@tonic-gate MSG_ORIG(MSG_UNW_CIEAUXPERS), 5740Sstevel@tonic-gate ciePflag, 5751618Srie conv_dwarf_ehe(ciePflag), 5760Sstevel@tonic-gate EC_XWORD(persVal)); 5770Sstevel@tonic-gate break; 5780Sstevel@tonic-gate case 'R': 5790Sstevel@tonic-gate val = data[off + ndx]; 5800Sstevel@tonic-gate ndx += 1; 5811618Srie dbg_print(0, 5820Sstevel@tonic-gate MSG_ORIG(MSG_UNW_CIEAUXCENC), 5831618Srie val, conv_dwarf_ehe(val)); 5840Sstevel@tonic-gate cieRflag = val; 5850Sstevel@tonic-gate break; 5860Sstevel@tonic-gate case 'L': 5870Sstevel@tonic-gate val = data[off + ndx]; 5880Sstevel@tonic-gate ndx += 1; 5891618Srie dbg_print(0, 5900Sstevel@tonic-gate MSG_ORIG(MSG_UNW_CIEAUXLSDA), 5911618Srie val, conv_dwarf_ehe(val)); 5920Sstevel@tonic-gate cieLflag = val; 5930Sstevel@tonic-gate break; 5940Sstevel@tonic-gate default: 5951618Srie dbg_print(0, 5960Sstevel@tonic-gate MSG_ORIG(MSG_UNW_CIEAUXUNEC), 5970Sstevel@tonic-gate cieaugstr[cieaugndx]); 5980Sstevel@tonic-gate break; 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate } 6011618Srie if ((cielength + 4) > ndx) 6021618Srie unwindtbl(&ndx, cielength, data, off, 6031618Srie MSG_ORIG(MSG_UNW_CIECFI), 6041618Srie MSG_ORIG(MSG_UNW_CIEPRE), 6051618Srie MSG_UNW_CIEPRE_SIZE); 6060Sstevel@tonic-gate off += cielength + 4; 6071618Srie 6080Sstevel@tonic-gate } else { 6090Sstevel@tonic-gate uint_t fdelength = length; 6100Sstevel@tonic-gate int fdecieptr = id; 6110Sstevel@tonic-gate uint64_t fdeinitloc, fdeaddrrange; 6120Sstevel@tonic-gate 6131618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDE), 6141618Srie EC_XWORD(shdr->sh_addr + off)); 6151618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH), 6160Sstevel@tonic-gate fdelength, fdecieptr); 6171618Srie 6180Sstevel@tonic-gate fdeinitloc = dwarf_ehe_extract(&data[off], 6190Sstevel@tonic-gate &ndx, cieRflag, ehdr->e_ident, 6200Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6210Sstevel@tonic-gate fdeaddrrange = dwarf_ehe_extract(&data[off], 6220Sstevel@tonic-gate &ndx, (cieRflag & ~DW_EH_PE_pcrel), 6230Sstevel@tonic-gate ehdr->e_ident, 6240Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6251618Srie 6261618Srie dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC), 6271618Srie EC_XWORD(fdeinitloc), 6281618Srie EC_XWORD(fdeaddrrange)); 6291618Srie 6300Sstevel@tonic-gate if (cieaugstr[0]) 6311618Srie dbg_print(0, 6321618Srie MSG_ORIG(MSG_UNW_FDEAUXVAL)); 6330Sstevel@tonic-gate if (cieZflag) { 6340Sstevel@tonic-gate uint64_t val; 6350Sstevel@tonic-gate val = uleb_extract(&data[off], &ndx); 6361618Srie dbg_print(0, 6371618Srie MSG_ORIG(MSG_UNW_FDEAUXSIZE), 6381618Srie EC_XWORD(val)); 6390Sstevel@tonic-gate if (val & cieLflag) { 6400Sstevel@tonic-gate fdeinitloc = dwarf_ehe_extract( 6410Sstevel@tonic-gate &data[off], &ndx, cieLflag, 6420Sstevel@tonic-gate ehdr->e_ident, 6430Sstevel@tonic-gate shdr->sh_addr + off + ndx); 6441618Srie dbg_print(0, 6450Sstevel@tonic-gate MSG_ORIG(MSG_UNW_FDEAUXLSDA), 6461618Srie EC_XWORD(val)); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate } 6491618Srie if ((fdelength + 4) > ndx) 6501618Srie unwindtbl(&ndx, fdelength, data, off, 6511618Srie MSG_ORIG(MSG_UNW_FDECFI), 6521618Srie MSG_ORIG(MSG_UNW_FDEPRE), 6531618Srie MSG_UNW_FDEPRE_SIZE); 6540Sstevel@tonic-gate off += fdelength + 4; 6550Sstevel@tonic-gate } 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate /* 6610Sstevel@tonic-gate * Print the hardware/software capabilities. For executables and shared objects 6620Sstevel@tonic-gate * this should be accompanied with a program header. 6630Sstevel@tonic-gate */ 6640Sstevel@tonic-gate static void 6651618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, 6661618Srie Elf *elf) 6670Sstevel@tonic-gate { 6681618Srie Word cnt; 6693466Srie Shdr *cshdr = 0; 6703466Srie Cache *ccache; 6711618Srie Off cphdr_off = 0; 6721618Srie Xword cphdr_sz; 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate /* 6750Sstevel@tonic-gate * Determine if a hardware/software capabilities header exists. 6760Sstevel@tonic-gate */ 6771618Srie if (phnum) { 6781618Srie Phdr *phdr; 6790Sstevel@tonic-gate 6801618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 6810Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 6820Sstevel@tonic-gate return; 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate 6851618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 6861618Srie if (phdr->p_type == PT_SUNWCAP) { 6871618Srie cphdr_off = phdr->p_offset; 6881618Srie cphdr_sz = phdr->p_filesz; 6891618Srie break; 6901618Srie } 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate /* 6950Sstevel@tonic-gate * Determine if a hardware/software capabilities section exists. 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 6981618Srie Cache *_cache = &cache[cnt]; 6991618Srie Shdr *shdr = _cache->c_shdr; 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_cap) 7020Sstevel@tonic-gate continue; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 7050Sstevel@tonic-gate (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 7060Sstevel@tonic-gate continue; 7070Sstevel@tonic-gate 7083466Srie if (_cache->c_data == NULL) 7093466Srie continue; 7103466Srie 7110Sstevel@tonic-gate ccache = _cache; 7120Sstevel@tonic-gate cshdr = shdr; 7130Sstevel@tonic-gate break; 7140Sstevel@tonic-gate } 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate if ((cshdr == 0) && (cphdr_off == 0)) 7170Sstevel@tonic-gate return; 7180Sstevel@tonic-gate 7193466Srie if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) { 7203466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 7213466Srie file, ccache->c_name); 7223466Srie return; 7233466Srie } 7243466Srie 7250Sstevel@tonic-gate /* 7260Sstevel@tonic-gate * Print the hardware/software capabilities section. 7270Sstevel@tonic-gate */ 7280Sstevel@tonic-gate if (cshdr) { 7291618Srie Word ndx, capn; 7303492Sab196087 Cap *cap = (Cap *)ccache->c_data->d_buf; 7310Sstevel@tonic-gate 7321618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 7331618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 7340Sstevel@tonic-gate 7351618Srie Elf_cap_title(0); 7361618Srie 7371618Srie capn = (Word)(cshdr->sh_size / cshdr->sh_entsize); 7380Sstevel@tonic-gate 7391618Srie for (ndx = 0; ndx < capn; cap++, ndx++) { 7401618Srie if (cap->c_tag != CA_SUNW_NULL) 7411618Srie Elf_cap_entry(0, cap, ndx, ehdr->e_machine); 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate } else 7440Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate /* 7470Sstevel@tonic-gate * If this object is an executable or shared object, then the 7480Sstevel@tonic-gate * hardware/software capabilities section should have an accompanying 7490Sstevel@tonic-gate * program header. 7500Sstevel@tonic-gate */ 7510Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 7520Sstevel@tonic-gate if (cphdr_off == 0) 7530Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 7540Sstevel@tonic-gate file, ccache->c_name); 7550Sstevel@tonic-gate else if ((cphdr_off != cshdr->sh_offset) || 7560Sstevel@tonic-gate (cphdr_sz != cshdr->sh_size)) 7570Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 7580Sstevel@tonic-gate file, ccache->c_name); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate /* 7630Sstevel@tonic-gate * Print the interpretor. 7640Sstevel@tonic-gate */ 7650Sstevel@tonic-gate static void 7661618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf) 7670Sstevel@tonic-gate { 7681618Srie Word cnt; 7691618Srie Shdr *ishdr = 0; 7701618Srie Cache *icache; 7711618Srie Off iphdr_off = 0; 7721618Srie Xword iphdr_fsz; 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate /* 7750Sstevel@tonic-gate * Determine if an interp header exists. 7760Sstevel@tonic-gate */ 7771618Srie if (phnum) { 7781618Srie Phdr *phdr; 7790Sstevel@tonic-gate 7801618Srie if ((phdr = getphdr(phnum, PT_INTERP, file, elf)) != 0) { 7811618Srie iphdr_off = phdr->p_offset; 7821618Srie iphdr_fsz = phdr->p_filesz; 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate if (iphdr_off == 0) 7870Sstevel@tonic-gate return; 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate /* 7900Sstevel@tonic-gate * Determine if an interp section exists. 7910Sstevel@tonic-gate */ 7920Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 7931618Srie Cache *_cache = &cache[cnt]; 7941618Srie Shdr *shdr = _cache->c_shdr; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate /* 7970Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP 7980Sstevel@tonic-gate * string. The target section can't be in a NOBITS section. 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) || 8010Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) || 8021618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size)) 8030Sstevel@tonic-gate continue; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate icache = _cache; 8060Sstevel@tonic-gate ishdr = shdr; 8070Sstevel@tonic-gate break; 8080Sstevel@tonic-gate } 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate /* 8110Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the 8120Sstevel@tonic-gate * program header, as this is the offset used by the kernel. 8130Sstevel@tonic-gate */ 8143466Srie if (ishdr && icache->c_data) { 8151618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8161618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 8171618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT), 8180Sstevel@tonic-gate (char *)icache->c_data->d_buf + 8190Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset)); 8200Sstevel@tonic-gate } else 8210Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * If there are any inconsistences between the program header and 8250Sstevel@tonic-gate * section information, flag them. 8260Sstevel@tonic-gate */ 8270Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) || 8281618Srie (iphdr_fsz != ishdr->sh_size))) { 8290Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 8300Sstevel@tonic-gate icache->c_name); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate /* 8350Sstevel@tonic-gate * Print the syminfo section. 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate static void 8381618Srie syminfo(Cache *cache, Word shnum, const char *file) 8390Sstevel@tonic-gate { 8401618Srie Shdr *infoshdr; 8411618Srie Syminfo *info; 8421618Srie Sym *syms; 8431618Srie Dyn *dyns; 8441618Srie Word infonum, cnt, ndx, symnum; 8451618Srie Cache *infocache = 0, *symsec, *strsec; 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 8481618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) { 8491618Srie infocache = &cache[cnt]; 8500Sstevel@tonic-gate break; 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate } 8531618Srie if (infocache == 0) 8540Sstevel@tonic-gate return; 8550Sstevel@tonic-gate 8561618Srie infoshdr = infocache->c_shdr; 8571618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) { 8580Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8591618Srie file, infocache->c_name); 8600Sstevel@tonic-gate return; 8610Sstevel@tonic-gate } 8623466Srie if (infocache->c_data == NULL) 8633466Srie return; 8643466Srie 8651618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize); 8661618Srie info = (Syminfo *)infocache->c_data->d_buf; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate /* 8690Sstevel@tonic-gate * Get the data buffer of the associated dynamic section. 8700Sstevel@tonic-gate */ 8711618Srie if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) { 8720Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 8731618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info)); 8740Sstevel@tonic-gate return; 8750Sstevel@tonic-gate } 8763466Srie if (cache[infoshdr->sh_info].c_data == NULL) 8773466Srie return; 8783466Srie 8791618Srie dyns = cache[infoshdr->sh_info].c_data->d_buf; 8801618Srie if (dyns == 0) { 8810Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 8821618Srie file, cache[infoshdr->sh_info].c_name); 8830Sstevel@tonic-gate return; 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate /* 8871618Srie * Get the data buffer for the associated symbol table and string table. 8880Sstevel@tonic-gate */ 8891618Srie if (stringtbl(cache, 1, cnt, shnum, file, 8901618Srie &symnum, &symsec, &strsec) == 0) 8910Sstevel@tonic-gate return; 8920Sstevel@tonic-gate 8931618Srie syms = symsec->c_data->d_buf; 8940Sstevel@tonic-gate 8951618Srie /* 8961618Srie * Loop through the syminfo entries. 8971618Srie */ 8981618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 8991618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name); 9001618Srie Elf_syminfo_title(0); 9010Sstevel@tonic-gate 9021618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) { 9031618Srie Sym *sym; 9041618Srie const char *needed = 0, *name; 9051618Srie 9061618Srie if ((info->si_flags == 0) && (info->si_boundto == 0)) 9070Sstevel@tonic-gate continue; 9080Sstevel@tonic-gate 9091618Srie sym = &syms[ndx]; 9101618Srie name = string(infocache, ndx, strsec, file, sym->st_name); 9110Sstevel@tonic-gate 9121618Srie if (info->si_boundto < SYMINFO_BT_LOWRESERVE) { 9131618Srie Dyn *dyn = &dyns[info->si_boundto]; 9141618Srie 9151618Srie needed = string(infocache, info->si_boundto, 9161618Srie strsec, file, dyn->d_un.d_val); 9170Sstevel@tonic-gate } 9181618Srie Elf_syminfo_entry(0, ndx, info, name, needed); 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate } 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate /* 9230Sstevel@tonic-gate * Print version definition section entries. 9240Sstevel@tonic-gate */ 9250Sstevel@tonic-gate static void 9261618Srie version_def(Verdef *vdf, Word shnum, Cache *vcache, Cache *scache, 9270Sstevel@tonic-gate const char *file) 9280Sstevel@tonic-gate { 9291618Srie Word cnt; 9301618Srie char index[MAXNDXSIZE]; 9310Sstevel@tonic-gate 9321618Srie Elf_ver_def_title(0); 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate for (cnt = 1; cnt <= shnum; cnt++, 9351618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 9360Sstevel@tonic-gate const char *name, *dep; 9371618Srie Half vcnt = vdf->vd_cnt - 1; 9381618Srie Half ndx = vdf->vd_ndx; 9391618Srie Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + 9401618Srie vdf->vd_aux); 9410Sstevel@tonic-gate 9420Sstevel@tonic-gate /* 9430Sstevel@tonic-gate * Obtain the name and first dependency (if any). 9440Sstevel@tonic-gate */ 9450Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name); 9461618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9470Sstevel@tonic-gate if (vcnt) 9480Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name); 9490Sstevel@tonic-gate else 9500Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 9530Sstevel@tonic-gate EC_XWORD(ndx)); 9541618Srie Elf_ver_line_1(0, index, name, dep, 9551618Srie conv_ver_flags(vdf->vd_flags)); 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate /* 9580Sstevel@tonic-gate * Print any additional dependencies. 9590Sstevel@tonic-gate */ 9600Sstevel@tonic-gate if (vcnt) { 9611618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next); 9620Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 9631618Srie vdap = (Verdaux *)((uintptr_t)vdap + 9640Sstevel@tonic-gate vdap->vda_next)) { 9650Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 9660Sstevel@tonic-gate vdap->vda_name); 9671618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep); 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate /* 9740Sstevel@tonic-gate * Print a version needed section entries. 9750Sstevel@tonic-gate */ 9760Sstevel@tonic-gate static void 9771618Srie version_need(Verneed *vnd, Word shnum, Cache *vcache, Cache *scache, 9780Sstevel@tonic-gate const char *file) 9790Sstevel@tonic-gate { 9801618Srie Word cnt; 9810Sstevel@tonic-gate 9821618Srie Elf_ver_need_title(0); 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate for (cnt = 1; cnt <= shnum; cnt++, 9851618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 9860Sstevel@tonic-gate const char *name, *dep; 9871618Srie Half vcnt = vnd->vn_cnt; 9881618Srie Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + 9891618Srie vnd->vn_aux); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate /* 9920Sstevel@tonic-gate * Obtain the name of the needed file and the version name 9930Sstevel@tonic-gate * within it that we're dependent on. Note that the count 9940Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus 9950Sstevel@tonic-gate * entry. 9960Sstevel@tonic-gate */ 9970Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file); 9980Sstevel@tonic-gate if (vcnt) 9990Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name); 10000Sstevel@tonic-gate else 10010Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL); 10020Sstevel@tonic-gate 10031618Srie Elf_ver_line_1(0, MSG_ORIG(MSG_STR_EMPTY), name, dep, 10041618Srie conv_ver_flags(vnap->vna_flags)); 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate /* 10070Sstevel@tonic-gate * Print any additional version dependencies. 10080Sstevel@tonic-gate */ 10090Sstevel@tonic-gate if (vcnt) { 10101618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next); 10110Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--, 10121618Srie vnap = (Vernaux *)((uintptr_t)vnap + 10130Sstevel@tonic-gate vnap->vna_next)) { 10140Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, 10150Sstevel@tonic-gate vnap->vna_name); 10161618Srie Elf_ver_line_3(0, MSG_ORIG(MSG_STR_EMPTY), dep, 10171618Srie conv_ver_flags(vnap->vna_flags)); 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate } 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate } 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate /* 1024*3875Sab196087 * Display version section information if the flags require it. 1025*3875Sab196087 * Return version information needed by other output. 1026*3875Sab196087 * 1027*3875Sab196087 * entry: 1028*3875Sab196087 * cache - Cache of all section headers 1029*3875Sab196087 * shnum - # of sections in cache 1030*3875Sab196087 * file - Name of file 1031*3875Sab196087 * flags - Command line option flags 1032*3875Sab196087 * versym - VERSYM_STATE block to be filled in. 10330Sstevel@tonic-gate */ 1034*3875Sab196087 static void 1035*3875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags, 1036*3875Sab196087 VERSYM_STATE *versym) 10370Sstevel@tonic-gate { 10380Sstevel@tonic-gate GElf_Word cnt; 1039*3875Sab196087 const char *gnu_prefix; 1040*3875Sab196087 size_t gnu_prefix_len; 1041*3875Sab196087 1042*3875Sab196087 bzero(versym, sizeof (*versym)); 1043*3875Sab196087 gnu_prefix = MSG_ORIG(MSG_GNU_VERNAMPREFIX); 1044*3875Sab196087 gnu_prefix_len = strlen(gnu_prefix); 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 10471618Srie void *ver; 10480Sstevel@tonic-gate uint_t num; 10491618Srie Cache *_cache = &cache[cnt]; 10501618Srie Shdr *shdr = _cache->c_shdr; 10511618Srie const char *secname = _cache->c_name; 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate /* 1054*3875Sab196087 * If the section names starts with the .gnu.version prefix, 1055*3875Sab196087 * then this object was almost certainly produced by the 1056*3875Sab196087 * GNU ld and not the native Solaris ld. 10570Sstevel@tonic-gate */ 1058*3875Sab196087 if (strncmp(gnu_prefix, secname, gnu_prefix_len) == 0) 1059*3875Sab196087 versym->gnu = 1; 1060*3875Sab196087 1061*3875Sab196087 /* 1062*3875Sab196087 * If this is the version symbol table record its data 1063*3875Sab196087 * address for later symbol processing. 1064*3875Sab196087 */ 1065*3875Sab196087 if ((shdr->sh_type == SHT_SUNW_versym) && 1066*3875Sab196087 (_cache->c_data != NULL)) { 1067*3875Sab196087 versym->cache = _cache; 1068*3875Sab196087 versym->data = _cache->c_data->d_buf; 10690Sstevel@tonic-gate continue; 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate 1072*3875Sab196087 /* 1073*3875Sab196087 * If this is a version definition section, retain # of 1074*3875Sab196087 * version definitions for later symbol processing. 1075*3875Sab196087 */ 1076*3875Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) 1077*3875Sab196087 versym->num_verdef = shdr->sh_info; 1078*3875Sab196087 10790Sstevel@tonic-gate if ((flags & FLG_VERSIONS) == 0) 10800Sstevel@tonic-gate continue; 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate if ((shdr->sh_type != SHT_SUNW_verdef) && 10830Sstevel@tonic-gate (shdr->sh_type != SHT_SUNW_verneed)) 10840Sstevel@tonic-gate continue; 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate /* 10870Sstevel@tonic-gate * Determine the version section data and number. 10880Sstevel@tonic-gate */ 10893466Srie if ((_cache->c_data == NULL) || 10903466Srie ((ver = (void *)_cache->c_data->d_buf) == NULL)) { 10910Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 10921618Srie file, secname); 10930Sstevel@tonic-gate continue; 10940Sstevel@tonic-gate } 10950Sstevel@tonic-gate if ((num = shdr->sh_info) == 0) { 10960Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 10971618Srie file, secname, EC_WORD(shdr->sh_info)); 10980Sstevel@tonic-gate continue; 10990Sstevel@tonic-gate } 11000Sstevel@tonic-gate 11010Sstevel@tonic-gate /* 11020Sstevel@tonic-gate * Get the data buffer for the associated string table. 11030Sstevel@tonic-gate */ 11040Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 11050Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 11061618Srie file, secname, EC_WORD(shdr->sh_link)); 11070Sstevel@tonic-gate continue; 11080Sstevel@tonic-gate } 11090Sstevel@tonic-gate 11101618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 11110Sstevel@tonic-gate if (shdr->sh_type == SHT_SUNW_verdef) { 11121618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), secname); 11131618Srie version_def((Verdef *)ver, num, _cache, 11140Sstevel@tonic-gate &cache[shdr->sh_link], file); 11150Sstevel@tonic-gate } else if (shdr->sh_type == SHT_SUNW_verneed) { 11161618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), secname); 11171618Srie version_need((Verneed *)ver, num, _cache, 11180Sstevel@tonic-gate &cache[shdr->sh_link], file); 11190Sstevel@tonic-gate } 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate /* 11243492Sab196087 * Initialize a symbol table state structure 11253492Sab196087 * 11263492Sab196087 * entry: 11273492Sab196087 * state - State structure to be initialized 11283492Sab196087 * cache - Cache of all section headers 11293492Sab196087 * shnum - # of sections in cache 11303492Sab196087 * secndx - Index of symbol table section 11313492Sab196087 * ehdr - ELF header for file 1132*3875Sab196087 * versym - Information about versym section 11333492Sab196087 * file - Name of file 11343492Sab196087 * flags - Command line option flags 11351618Srie */ 11361618Srie static int 11373492Sab196087 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx, 1138*3875Sab196087 Ehdr *ehdr, VERSYM_STATE *versym, const char *file, uint_t flags) 11393492Sab196087 { 11403492Sab196087 Shdr *shdr; 11413492Sab196087 11423492Sab196087 state->file = file; 11433492Sab196087 state->ehdr = ehdr; 11443492Sab196087 state->cache = cache; 11453492Sab196087 state->shnum = shnum; 11463492Sab196087 state->seccache = &cache[secndx]; 11473492Sab196087 state->secndx = secndx; 11483492Sab196087 state->secname = state->seccache->c_name; 11493492Sab196087 state->flags = flags; 11503492Sab196087 state->shxndx.checked = 0; 11513492Sab196087 state->shxndx.data = NULL; 11523492Sab196087 state->shxndx.n = 0; 11533492Sab196087 11543492Sab196087 shdr = state->seccache->c_shdr; 11553492Sab196087 11563492Sab196087 /* 11573492Sab196087 * Check the symbol data and per-item size. 11583492Sab196087 */ 11593492Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 11603492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 11613492Sab196087 file, state->secname); 11623492Sab196087 return (0); 11633492Sab196087 } 11643492Sab196087 if (state->seccache->c_data == NULL) 11653492Sab196087 return (0); 11663492Sab196087 11673492Sab196087 /* LINTED */ 11683492Sab196087 state->symn = (Word)(shdr->sh_size / shdr->sh_entsize); 11693492Sab196087 state->sym = (Sym *)state->seccache->c_data->d_buf; 11703492Sab196087 11713492Sab196087 /* 11723492Sab196087 * Check associated string table section. 11733492Sab196087 */ 11743492Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 11753492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 11763492Sab196087 file, state->secname, EC_WORD(shdr->sh_link)); 11773492Sab196087 return (0); 11783492Sab196087 } 11793492Sab196087 11803492Sab196087 /* 11813492Sab196087 * Determine if there is a associated Versym section 11823492Sab196087 * with this Symbol Table. 11833492Sab196087 */ 1184*3875Sab196087 if (versym->cache && 1185*3875Sab196087 (versym->cache->c_shdr->sh_link == state->secndx)) 1186*3875Sab196087 state->versym = versym; 11873492Sab196087 else 11883492Sab196087 state->versym = NULL; 11893492Sab196087 11903492Sab196087 11913492Sab196087 return (1); 11923492Sab196087 } 11933492Sab196087 11943492Sab196087 /* 11953492Sab196087 * Determine the extended section index used for symbol tables entries. 11963492Sab196087 */ 11973492Sab196087 static void 11983492Sab196087 symbols_getxindex(SYMTBL_STATE * state) 11991618Srie { 12001618Srie uint_t symn; 12011618Srie Word symcnt; 12021618Srie 12033492Sab196087 state->shxndx.checked = 1; /* Note that we've been called */ 12043492Sab196087 for (symcnt = 1; symcnt < state->shnum; symcnt++) { 12053492Sab196087 Cache *_cache = &state->cache[symcnt]; 12061618Srie Shdr *shdr = _cache->c_shdr; 12071618Srie 12081618Srie if ((shdr->sh_type != SHT_SYMTAB_SHNDX) || 12093492Sab196087 (shdr->sh_link != state->secndx)) 12101618Srie continue; 12111618Srie 12121618Srie if ((shdr->sh_entsize) && 12131618Srie /* LINTED */ 12141618Srie ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0)) 12151618Srie continue; 12161618Srie 12173466Srie if (_cache->c_data == NULL) 12183466Srie continue; 12193466Srie 12203492Sab196087 state->shxndx.data = _cache->c_data->d_buf; 12213492Sab196087 state->shxndx.n = symn; 12223492Sab196087 return; 12231618Srie } 12241618Srie } 12251618Srie 12261618Srie /* 12273492Sab196087 * Produce a line of output for the given symbol 12283492Sab196087 * 12293492Sab196087 * entry: 1230*3875Sab196087 * state - Symbol table state 12313492Sab196087 * symndx - Index of symbol within the table 12323492Sab196087 * symndx_disp - Index to display. This may not be the same 12333492Sab196087 * as symndx if the display is relative to the logical 12343492Sab196087 * combination of the SUNW_ldynsym/dynsym tables. 12353492Sab196087 * sym - Symbol to display 12360Sstevel@tonic-gate */ 12373492Sab196087 static void 12383492Sab196087 output_symbol(SYMTBL_STATE *state, Word symndx, Word disp_symndx, Sym *sym) 12390Sstevel@tonic-gate { 12403118Sab196087 /* 12413118Sab196087 * Symbol types for which we check that the specified 12423118Sab196087 * address/size land inside the target section. 12433118Sab196087 */ 12443492Sab196087 static const int addr_symtype[STT_NUM] = { 12453118Sab196087 0, /* STT_NOTYPE */ 12463118Sab196087 1, /* STT_OBJECT */ 12473118Sab196087 1, /* STT_FUNC */ 12483118Sab196087 0, /* STT_SECTION */ 12493118Sab196087 0, /* STT_FILE */ 12503118Sab196087 1, /* STT_COMMON */ 12513118Sab196087 0, /* STT_TLS */ 12523118Sab196087 }; 12533118Sab196087 #if STT_NUM != (STT_TLS + 1) 12543492Sab196087 #error "STT_NUM has grown. Update addr_symtype[]" 12553118Sab196087 #endif 12563118Sab196087 12573492Sab196087 char index[MAXNDXSIZE], *sec; 12583492Sab196087 const char *symname; 1259*3875Sab196087 Versym verndx; 12603492Sab196087 uchar_t type; 12613492Sab196087 Shdr *tshdr; 12623492Sab196087 Word shndx; 12633492Sab196087 12643492Sab196087 /* Ensure symbol index is in range */ 12653492Sab196087 if (symndx >= state->symn) { 12663492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX), 12673492Sab196087 state->file, state->secname, EC_WORD(symndx)); 12683492Sab196087 return; 12693492Sab196087 } 12703492Sab196087 12713492Sab196087 /* 12723492Sab196087 * If we are using extended symbol indexes, find the 12733492Sab196087 * corresponding SHN_SYMTAB_SHNDX table. 12743492Sab196087 */ 12753492Sab196087 if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0)) 12763492Sab196087 symbols_getxindex(state); 12773492Sab196087 12783492Sab196087 /* LINTED */ 12793492Sab196087 symname = string(state->seccache, symndx, 12803492Sab196087 &state->cache[state->seccache->c_shdr->sh_link], state->file, 12813492Sab196087 sym->st_name); 12823492Sab196087 12833492Sab196087 tshdr = 0; 12843492Sab196087 sec = NULL; 12853492Sab196087 12863492Sab196087 if ((state->ehdr->e_type == ET_CORE)) 12873492Sab196087 sec = (char *)MSG_INTL(MSG_STR_UNKNOWN); 12883492Sab196087 else if ((sym->st_shndx < SHN_LORESERVE) && 12893492Sab196087 (sym->st_shndx < state->shnum)) { 12903492Sab196087 shndx = sym->st_shndx; 12913492Sab196087 tshdr = state->cache[shndx].c_shdr; 12923492Sab196087 sec = state->cache[shndx].c_name; 12933492Sab196087 } else if (sym->st_shndx == SHN_XINDEX) { 12943492Sab196087 if (state->shxndx.data) { 12953492Sab196087 Word _shxndx; 12963492Sab196087 12973492Sab196087 if (symndx > state->shxndx.n) { 12983492Sab196087 (void) fprintf(stderr, 12993492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 13003492Sab196087 state->file, state->secname, EC_WORD(symndx)); 13013492Sab196087 } else if ((_shxndx = 13023492Sab196087 state->shxndx.data[symndx]) > state->shnum) { 13033492Sab196087 (void) fprintf(stderr, 13043492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 13053492Sab196087 state->file, state->secname, EC_WORD(symndx), 13063492Sab196087 EC_WORD(_shxndx)); 13073492Sab196087 } else { 13083492Sab196087 shndx = _shxndx; 13093492Sab196087 tshdr = state->cache[shndx].c_shdr; 13103492Sab196087 sec = state->cache[shndx].c_name; 13113492Sab196087 } 13123492Sab196087 } else { 13133492Sab196087 (void) fprintf(stderr, 13143492Sab196087 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 13153492Sab196087 state->file, state->secname, EC_WORD(symndx)); 13163492Sab196087 } 13173492Sab196087 } else if ((sym->st_shndx < SHN_LORESERVE) && 13183492Sab196087 (sym->st_shndx >= state->shnum)) { 13193492Sab196087 (void) fprintf(stderr, 13203492Sab196087 MSG_INTL(MSG_ERR_BADSYM5), state->file, 13213492Sab196087 state->secname, demangle(symname, state->flags), 13223492Sab196087 sym->st_shndx); 13233492Sab196087 } 13240Sstevel@tonic-gate 13253492Sab196087 /* 13263492Sab196087 * If versioning is available display the 1327*3875Sab196087 * version index. If not, then use 0. 13283492Sab196087 */ 1329*3875Sab196087 if (state->versym) { 1330*3875Sab196087 verndx = state->versym->data[symndx]; 1331*3875Sab196087 1332*3875Sab196087 /* 1333*3875Sab196087 * Check to see if this is a defined symbol with a 1334*3875Sab196087 * version index that is outside the valid range for 1335*3875Sab196087 * the file. If so, then there are two possiblities: 1336*3875Sab196087 * 1337*3875Sab196087 * - Files produced by the GNU ld use the top (16th) bit 1338*3875Sab196087 * as a "hidden symbol" marker. If we have 1339*3875Sab196087 * detected that this object comes from GNU ld, 1340*3875Sab196087 * then check to see if this is the case and that 1341*3875Sab196087 * the resulting masked version is in range. If so, 1342*3875Sab196087 * issue a warning describing it. 1343*3875Sab196087 * - If this is not a GNU "hidden bit" issue, then 1344*3875Sab196087 * issue a generic "out of range" error. 1345*3875Sab196087 */ 1346*3875Sab196087 if (VERNDX_INVALID(sym->st_shndx, state->versym->num_verdef, 1347*3875Sab196087 state->versym->data, verndx)) { 1348*3875Sab196087 if (state->versym->gnu && (verndx & 0x8000) && 1349*3875Sab196087 ((verndx & ~0x8000) <= 1350*3875Sab196087 state->versym->num_verdef)) { 1351*3875Sab196087 (void) fprintf(stderr, 1352*3875Sab196087 MSG_INTL(MSG_WARN_GNUVER), state->file, 1353*3875Sab196087 state->secname, EC_WORD(symndx), 1354*3875Sab196087 EC_HALF(verndx & ~0x8000)); 1355*3875Sab196087 } else { /* Generic version range error */ 1356*3875Sab196087 (void) fprintf(stderr, 1357*3875Sab196087 MSG_INTL(MSG_ERR_BADVER), state->file, 1358*3875Sab196087 state->secname, EC_WORD(symndx), 1359*3875Sab196087 EC_HALF(verndx), state->versym->num_verdef); 1360*3875Sab196087 } 1361*3875Sab196087 } 1362*3875Sab196087 } else { 13633492Sab196087 verndx = 0; 1364*3875Sab196087 } 13653492Sab196087 13663492Sab196087 /* 13673492Sab196087 * Error checking for TLS. 13683492Sab196087 */ 13693492Sab196087 type = ELF_ST_TYPE(sym->st_info); 13703492Sab196087 if (type == STT_TLS) { 13713492Sab196087 if (tshdr && 13723492Sab196087 (sym->st_shndx != SHN_UNDEF) && 13733492Sab196087 ((tshdr->sh_flags & SHF_TLS) == 0)) { 13743492Sab196087 (void) fprintf(stderr, 13753492Sab196087 MSG_INTL(MSG_ERR_BADSYM3), state->file, 13763492Sab196087 state->secname, demangle(symname, state->flags)); 13773492Sab196087 } 13783492Sab196087 } else if ((type != STT_SECTION) && sym->st_size && 13793492Sab196087 tshdr && (tshdr->sh_flags & SHF_TLS)) { 13803492Sab196087 (void) fprintf(stderr, 13813492Sab196087 MSG_INTL(MSG_ERR_BADSYM4), state->file, 13823492Sab196087 state->secname, demangle(symname, state->flags)); 13833492Sab196087 } 13843492Sab196087 13853492Sab196087 /* 13863492Sab196087 * If a symbol with non-zero size has a type that 13873492Sab196087 * specifies an address, then make sure the location 13883492Sab196087 * it references is actually contained within the 13893492Sab196087 * section. UNDEF symbols don't count in this case, 13903492Sab196087 * so we ignore them. 13913492Sab196087 * 13923492Sab196087 * The meaning of the st_value field in a symbol 13933492Sab196087 * depends on the type of object. For a relocatable 13943492Sab196087 * object, it is the offset within the section. 13953492Sab196087 * For sharable objects, it is the offset relative to 13963492Sab196087 * the base of the object, and for other types, it is 13973492Sab196087 * the virtual address. To get an offset within the 13983492Sab196087 * section for non-ET_REL files, we subtract the 13993492Sab196087 * base address of the section. 14003492Sab196087 */ 14013492Sab196087 if (addr_symtype[type] && (sym->st_size > 0) && 14023492Sab196087 (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) || 14033492Sab196087 (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) { 14043492Sab196087 Word v = sym->st_value; 14053492Sab196087 if (state->ehdr->e_type != ET_REL) 14063492Sab196087 v -= tshdr->sh_addr; 14073492Sab196087 if (((v + sym->st_size) > tshdr->sh_size)) { 14083492Sab196087 (void) fprintf(stderr, 14093492Sab196087 MSG_INTL(MSG_ERR_BADSYM6), state->file, 14103492Sab196087 state->secname, demangle(symname, state->flags), 14113492Sab196087 EC_WORD(shndx), EC_XWORD(tshdr->sh_size), 14123492Sab196087 EC_XWORD(sym->st_value), EC_XWORD(sym->st_size)); 14133492Sab196087 } 14143492Sab196087 } 14153492Sab196087 14163492Sab196087 (void) snprintf(index, MAXNDXSIZE, 14173492Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx)); 14183492Sab196087 Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, 14193492Sab196087 state->ehdr->e_machine, sym, verndx, sec, symname); 14203492Sab196087 } 14213492Sab196087 14223492Sab196087 /* 14233492Sab196087 * Search for and process any symbol tables. 14243492Sab196087 */ 14253492Sab196087 void 14263492Sab196087 symbols(Cache *cache, Word shnum, Ehdr *ehdr, const char *name, 1427*3875Sab196087 VERSYM_STATE *versym, const char *file, uint_t flags) 14283492Sab196087 { 14293492Sab196087 SYMTBL_STATE state; 14303492Sab196087 Cache *_cache; 14313492Sab196087 Word secndx; 14323492Sab196087 14333492Sab196087 for (secndx = 1; secndx < shnum; secndx++) { 14343492Sab196087 Word symcnt; 14353492Sab196087 Shdr *shdr; 14363492Sab196087 14373492Sab196087 _cache = &cache[secndx]; 14383492Sab196087 shdr = _cache->c_shdr; 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) && 14412766Sab196087 (shdr->sh_type != SHT_DYNSYM) && 14422766Sab196087 (shdr->sh_type != SHT_SUNW_LDYNSYM)) 14430Sstevel@tonic-gate continue; 14443492Sab196087 if (name && strcmp(name, _cache->c_name)) 14453466Srie continue; 14463466Srie 14473492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr, 1448*3875Sab196087 versym, file, flags)) 14490Sstevel@tonic-gate continue; 14500Sstevel@tonic-gate /* 14510Sstevel@tonic-gate * Loop through the symbol tables entries. 14520Sstevel@tonic-gate */ 14531618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 14543492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname); 14551618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 14560Sstevel@tonic-gate 14573492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++) 14583492Sab196087 output_symbol(&state, symcnt, symcnt, 14593492Sab196087 state.sym + symcnt); 14603492Sab196087 } 14613492Sab196087 } 14620Sstevel@tonic-gate 14633492Sab196087 /* 14643492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections. 14653492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair. 14663492Sab196087 */ 14673492Sab196087 static void 14683492Sab196087 sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, const char *name, 1469*3875Sab196087 VERSYM_STATE *versym, const char *file, uint_t flags) 14703492Sab196087 { 14713492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state; 14723492Sab196087 Cache *sortcache, *symcache; 14733492Sab196087 Shdr *sortshdr, *symshdr; 14743492Sab196087 Word sortsecndx, symsecndx; 14753492Sab196087 Word ldynsym_cnt; 14763492Sab196087 Word *ndx; 14773492Sab196087 Word ndxn; 14783492Sab196087 int output_cnt = 0; 14790Sstevel@tonic-gate 14803492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) { 14810Sstevel@tonic-gate 14823492Sab196087 sortcache = &cache[sortsecndx]; 14833492Sab196087 sortshdr = sortcache->c_shdr; 14840Sstevel@tonic-gate 14853492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) && 14863492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort)) 14873492Sab196087 continue; 14883492Sab196087 if (name && strcmp(name, sortcache->c_name)) 14893492Sab196087 continue; 14900Sstevel@tonic-gate 14913492Sab196087 /* 14923492Sab196087 * If the section references a SUNW_ldynsym, then we 14933492Sab196087 * expect to see the associated .dynsym immediately 14943492Sab196087 * following. If it references a .dynsym, there is no 14953492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't 14963492Sab196087 * know what to do with it. 14973492Sab196087 */ 14983492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) { 14993492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 15003492Sab196087 file, sortcache->c_name, 15013492Sab196087 EC_WORD(sortshdr->sh_link)); 15023492Sab196087 continue; 15033492Sab196087 } 15043492Sab196087 symcache = &cache[sortshdr->sh_link]; 15053492Sab196087 symshdr = symcache->c_shdr; 15063492Sab196087 symsecndx = sortshdr->sh_link; 15073492Sab196087 ldynsym_cnt = 0; 15083492Sab196087 switch (symshdr->sh_type) { 15093492Sab196087 case SHT_SUNW_LDYNSYM: 15103492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum, 1511*3875Sab196087 symsecndx, ehdr, versym, file, flags)) 15123492Sab196087 continue; 15133492Sab196087 ldynsym_cnt = ldynsym_state.symn; 15140Sstevel@tonic-gate /* 15153492Sab196087 * We know that the dynsym follows immediately 15163492Sab196087 * after the SUNW_ldynsym, and so, should be at 15173492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a 15183492Sab196087 * diagnostic tool, so we do the full paranoid 15193492Sab196087 * search instead. 15200Sstevel@tonic-gate */ 15213492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) { 15223492Sab196087 symcache = &cache[symsecndx]; 15233492Sab196087 symshdr = symcache->c_shdr; 15243492Sab196087 if (symshdr->sh_type == SHT_DYNSYM) 15253492Sab196087 break; 15263492Sab196087 } 15273492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */ 15280Sstevel@tonic-gate (void) fprintf(stderr, 15293492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM), 15303492Sab196087 file, sortcache->c_name); 15313492Sab196087 continue; 15320Sstevel@tonic-gate } 15333492Sab196087 /* Fallthrough to process associated dynsym */ 15343492Sab196087 /*FALLTHROUGH*/ 15353492Sab196087 case SHT_DYNSYM: 15363492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum, 1537*3875Sab196087 symsecndx, ehdr, versym, file, flags)) 15383492Sab196087 continue; 15393492Sab196087 break; 15403492Sab196087 default: 15413492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC), 15423492Sab196087 file, sortcache->c_name, conv_sec_type( 15433492Sab196087 ehdr->e_machine, symshdr->sh_type, 0)); 15443492Sab196087 continue; 15453492Sab196087 } 15460Sstevel@tonic-gate 15473492Sab196087 /* 15483492Sab196087 * Output header 15493492Sab196087 */ 15503492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 15513492Sab196087 if (ldynsym_cnt > 0) { 15523492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2), 15533492Sab196087 sortcache->c_name, ldynsym_state.secname, 15543492Sab196087 dynsym_state.secname); 15550Sstevel@tonic-gate /* 15563492Sab196087 * The data for .SUNW_ldynsym and dynsym sections 15573492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming 15583492Sab196087 * first. Check, and issue a warning if it isn't so. 15590Sstevel@tonic-gate */ 15603492Sab196087 if ((ldynsym_state.sym + ldynsym_state.symn) 15613492Sab196087 != dynsym_state.sym) 15623492Sab196087 (void) fprintf(stderr, 15633492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file, 15643492Sab196087 ldynsym_state.secname, 15653492Sab196087 dynsym_state.secname); 15663492Sab196087 } else { 15673492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1), 15683492Sab196087 sortcache->c_name, dynsym_state.secname); 15693492Sab196087 } 15703492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 15713492Sab196087 15723492Sab196087 /* If not first one, insert a line of whitespace */ 15733492Sab196087 if (output_cnt++ > 0) 15743492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 15753118Sab196087 15763492Sab196087 /* 15773492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of 15783492Sab196087 * symbol indices. Iterate over the array entries, 15793492Sab196087 * dispaying the referenced symbols. 15803492Sab196087 */ 15813492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize; 15823492Sab196087 ndx = (Word *)sortcache->c_data->d_buf; 15833492Sab196087 for (; ndxn-- > 0; ndx++) { 15843492Sab196087 if (*ndx >= ldynsym_cnt) { 15853492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt; 15863492Sab196087 15873492Sab196087 output_symbol(&dynsym_state, sec_ndx, 15883492Sab196087 *ndx, dynsym_state.sym + sec_ndx); 15893492Sab196087 } else { 15903492Sab196087 output_symbol(&ldynsym_state, *ndx, 15913492Sab196087 *ndx, ldynsym_state.sym + *ndx); 15920Sstevel@tonic-gate } 15930Sstevel@tonic-gate } 15940Sstevel@tonic-gate } 15950Sstevel@tonic-gate } 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate /* 15980Sstevel@tonic-gate * Search for and process any relocation sections. 15990Sstevel@tonic-gate */ 16000Sstevel@tonic-gate static void 16011618Srie reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *name, const char *file, 16021618Srie uint_t flags) 16030Sstevel@tonic-gate { 16041618Srie Word cnt; 16050Sstevel@tonic-gate 16060Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 16071618Srie Word type, symnum; 16081618Srie Xword relndx, relnum, relsize; 16091618Srie void *rels; 16101618Srie Sym *syms; 16111618Srie Cache *symsec, *strsec; 16120Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 16131618Srie Shdr *shdr = _cache->c_shdr; 16141618Srie char *relname = _cache->c_name; 16150Sstevel@tonic-gate 16160Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) && 16170Sstevel@tonic-gate (type != SHT_REL)) 16180Sstevel@tonic-gate continue; 16191618Srie if (name && strcmp(name, relname)) 16200Sstevel@tonic-gate continue; 16210Sstevel@tonic-gate 16220Sstevel@tonic-gate /* 16231618Srie * Decide entry size. 16240Sstevel@tonic-gate */ 16251618Srie if (((relsize = shdr->sh_entsize) == 0) || 16261618Srie (relsize > shdr->sh_size)) { 16270Sstevel@tonic-gate if (type == SHT_RELA) 16281618Srie relsize = sizeof (Rela); 16290Sstevel@tonic-gate else 16301618Srie relsize = sizeof (Rel); 16310Sstevel@tonic-gate } 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate /* 16340Sstevel@tonic-gate * Determine the number of relocations available. 16350Sstevel@tonic-gate */ 16360Sstevel@tonic-gate if (shdr->sh_size == 0) { 16370Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 16381618Srie file, relname); 16390Sstevel@tonic-gate continue; 16400Sstevel@tonic-gate } 16413466Srie if (_cache->c_data == NULL) 16423466Srie continue; 16433466Srie 16441618Srie rels = _cache->c_data->d_buf; 16451618Srie relnum = shdr->sh_size / relsize; 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate /* 16481618Srie * Get the data buffer for the associated symbol table and 16491618Srie * string table. 16500Sstevel@tonic-gate */ 16511618Srie if (stringtbl(cache, 1, cnt, shnum, file, 16521618Srie &symnum, &symsec, &strsec) == 0) 16530Sstevel@tonic-gate continue; 16541618Srie 16551618Srie syms = symsec->c_data->d_buf; 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate /* 16580Sstevel@tonic-gate * Loop through the relocation entries. 16590Sstevel@tonic-gate */ 16601618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 16611618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 16621618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type); 16630Sstevel@tonic-gate 16641618Srie for (relndx = 0; relndx < relnum; relndx++, 16651618Srie rels = (void *)((char *)rels + relsize)) { 16660Sstevel@tonic-gate char section[BUFSIZ]; 16671618Srie const char *symname; 16681618Srie Word symndx, reltype; 16691618Srie Rela *rela; 16701618Srie Rel *rel; 16710Sstevel@tonic-gate 16720Sstevel@tonic-gate /* 16731618Srie * Unravel the relocation and determine the symbol with 16741618Srie * which this relocation is associated. 16750Sstevel@tonic-gate */ 16760Sstevel@tonic-gate if (type == SHT_RELA) { 16771618Srie rela = (Rela *)rels; 16781618Srie symndx = ELF_R_SYM(rela->r_info); 16791618Srie reltype = ELF_R_TYPE(rela->r_info); 16800Sstevel@tonic-gate } else { 16811618Srie rel = (Rel *)rels; 16821618Srie symndx = ELF_R_SYM(rel->r_info); 16831618Srie reltype = ELF_R_TYPE(rel->r_info); 16840Sstevel@tonic-gate } 16851618Srie 16861618Srie symname = relsymname(cache, _cache, strsec, symndx, 16871618Srie symnum, relndx, syms, section, BUFSIZ, file, 16881618Srie flags); 16891618Srie 16901618Srie /* 16911618Srie * A zero symbol index is only valid for a few 16921618Srie * relocations. 16931618Srie */ 16941618Srie if (symndx == 0) { 16951618Srie Half mach = ehdr->e_machine; 16961618Srie int badrel = 0; 16970Sstevel@tonic-gate 16981618Srie if ((mach == EM_SPARC) || 16991618Srie (mach == EM_SPARC32PLUS) || 17001618Srie (mach == EM_SPARCV9)) { 17011618Srie if ((reltype != R_SPARC_NONE) && 17021618Srie (reltype != R_SPARC_REGISTER) && 17031618Srie (reltype != R_SPARC_RELATIVE)) 17041618Srie badrel++; 17051618Srie } else if (mach == EM_386) { 17061618Srie if ((reltype != R_386_NONE) && 17071618Srie (reltype != R_386_RELATIVE)) 17081618Srie badrel++; 17091618Srie } else if (mach == EM_AMD64) { 17101618Srie if ((reltype != R_AMD64_NONE) && 17111618Srie (reltype != R_AMD64_RELATIVE)) 17121618Srie badrel++; 17131618Srie } 17141618Srie 17151618Srie if (badrel) { 17161618Srie (void) fprintf(stderr, 17171618Srie MSG_INTL(MSG_ERR_BADREL1), file, 17181976Sab196087 conv_reloc_type(mach, reltype, 0)); 17190Sstevel@tonic-gate } 17200Sstevel@tonic-gate } 17210Sstevel@tonic-gate 17221618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP, 17231618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type, 17241618Srie rels, relname, symname, 0); 17250Sstevel@tonic-gate } 17260Sstevel@tonic-gate } 17270Sstevel@tonic-gate } 17280Sstevel@tonic-gate 17290Sstevel@tonic-gate /* 17300Sstevel@tonic-gate * Search for and process a .dynamic section. 17310Sstevel@tonic-gate */ 17320Sstevel@tonic-gate static void 17331618Srie dynamic(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 17340Sstevel@tonic-gate { 17351618Srie Word cnt; 17360Sstevel@tonic-gate 17370Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 17381618Srie Dyn *dyn; 17391618Srie ulong_t numdyn; 17403850Sab196087 int ndx, end_ndx; 17411618Srie Cache *_cache = &cache[cnt], *strsec; 17421618Srie Shdr *shdr = _cache->c_shdr; 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC) 17450Sstevel@tonic-gate continue; 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate /* 17481618Srie * Verify the associated string table section. 17490Sstevel@tonic-gate */ 17501618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0) 17510Sstevel@tonic-gate continue; 17521618Srie 17533466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 17543466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 17553466Srie file, _cache->c_name); 17563466Srie continue; 17573466Srie } 17583466Srie if (_cache->c_data == NULL) 17593466Srie continue; 17603466Srie 17610Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize; 17621618Srie dyn = (Dyn *)_cache->c_data->d_buf; 17630Sstevel@tonic-gate 17641618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 17651618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 17660Sstevel@tonic-gate 17671618Srie Elf_dyn_title(0); 17680Sstevel@tonic-gate 17691618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 17701618Srie const char *name; 17710Sstevel@tonic-gate 17720Sstevel@tonic-gate /* 17730Sstevel@tonic-gate * Print the information numerically, and if possible 17740Sstevel@tonic-gate * as a string. 17750Sstevel@tonic-gate */ 17763850Sab196087 switch (dyn->d_tag) { 17773850Sab196087 case DT_NULL: 17783850Sab196087 /* 17793850Sab196087 * Special case: DT_NULLs can come in groups 17803850Sab196087 * that we prefer to reduce to a single line. 17813850Sab196087 */ 17823850Sab196087 end_ndx = ndx; 17833850Sab196087 while ((end_ndx < (numdyn - 1)) && 17843850Sab196087 ((dyn + 1)->d_tag == DT_NULL)) { 17853850Sab196087 dyn++; 17863850Sab196087 end_ndx++; 17873850Sab196087 } 17883850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 17893850Sab196087 ndx = end_ndx; 17903850Sab196087 continue; 17913850Sab196087 17923850Sab196087 /* 17933850Sab196087 * Print the information numerically, and if possible 17943850Sab196087 * as a string. 17953850Sab196087 */ 17963850Sab196087 case DT_NEEDED: 17973850Sab196087 case DT_SONAME: 17983850Sab196087 case DT_FILTER: 17993850Sab196087 case DT_AUXILIARY: 18003850Sab196087 case DT_CONFIG: 18013850Sab196087 case DT_RPATH: 18023850Sab196087 case DT_RUNPATH: 18033850Sab196087 case DT_USED: 18043850Sab196087 case DT_DEPAUDIT: 18053850Sab196087 case DT_AUDIT: 18063850Sab196087 case DT_SUNW_AUXILIARY: 18073850Sab196087 case DT_SUNW_FILTER: 18081618Srie name = string(_cache, ndx, strsec, 18091618Srie file, dyn->d_un.d_ptr); 18103850Sab196087 break; 18113850Sab196087 18123850Sab196087 case DT_FLAGS: 18132352Sab196087 name = conv_dyn_flag(dyn->d_un.d_val, 0); 18143850Sab196087 break; 18153850Sab196087 case DT_FLAGS_1: 18161618Srie name = conv_dyn_flag1(dyn->d_un.d_val); 18173850Sab196087 break; 18183850Sab196087 case DT_POSFLAG_1: 18192352Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0); 18203850Sab196087 break; 18213850Sab196087 case DT_FEATURE_1: 18222352Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0); 18233850Sab196087 break; 18243850Sab196087 case DT_DEPRECATED_SPARC_REGISTER: 18251618Srie name = MSG_INTL(MSG_STR_DEPRECATED); 18263850Sab196087 break; 18273850Sab196087 default: 18281618Srie name = MSG_ORIG(MSG_STR_EMPTY); 18293850Sab196087 break; 18303850Sab196087 } 18310Sstevel@tonic-gate 18321618Srie Elf_dyn_entry(0, dyn, ndx, name, ehdr->e_machine); 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate } 18350Sstevel@tonic-gate } 18360Sstevel@tonic-gate 18370Sstevel@tonic-gate /* 18380Sstevel@tonic-gate * Search for and process a MOVE section. 18390Sstevel@tonic-gate */ 18400Sstevel@tonic-gate static void 18411618Srie move(Cache *cache, Word shnum, const char *name, const char *file, uint_t flags) 18420Sstevel@tonic-gate { 18431618Srie Word cnt; 18441618Srie const char *fmt = 0; 18450Sstevel@tonic-gate 18460Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 18471618Srie Word movenum, symnum, ndx; 18481618Srie Sym *syms; 18491618Srie Cache *_cache = &cache[cnt]; 18501618Srie Shdr *shdr = _cache->c_shdr; 18511618Srie Cache *symsec, *strsec; 18521618Srie Move *move; 18530Sstevel@tonic-gate 18540Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move) 18550Sstevel@tonic-gate continue; 18560Sstevel@tonic-gate if (name && strcmp(name, _cache->c_name)) 18570Sstevel@tonic-gate continue; 18580Sstevel@tonic-gate 18590Sstevel@tonic-gate /* 18600Sstevel@tonic-gate * Determine the move data and number. 18610Sstevel@tonic-gate */ 18620Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 18630Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 18640Sstevel@tonic-gate file, _cache->c_name); 18650Sstevel@tonic-gate continue; 18660Sstevel@tonic-gate } 18673466Srie if (_cache->c_data == NULL) 18683466Srie continue; 18693466Srie 18701618Srie move = (Move *)_cache->c_data->d_buf; 18711618Srie movenum = shdr->sh_size / shdr->sh_entsize; 18720Sstevel@tonic-gate 18730Sstevel@tonic-gate /* 18741618Srie * Get the data buffer for the associated symbol table and 18751618Srie * string table. 18760Sstevel@tonic-gate */ 18771618Srie if (stringtbl(cache, 1, cnt, shnum, file, 18781618Srie &symnum, &symsec, &strsec) == 0) 18791618Srie return; 18801618Srie 18811618Srie syms = (Sym *)symsec->c_data->d_buf; 18820Sstevel@tonic-gate 18831618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 18841618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name); 18851618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE)); 18860Sstevel@tonic-gate 18871618Srie if (fmt == 0) 18881618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY); 18890Sstevel@tonic-gate 18901618Srie for (ndx = 0; ndx < movenum; move++, ndx++) { 18911618Srie const char *symname; 18921618Srie char index[MAXNDXSIZE], section[BUFSIZ]; 18931618Srie Word symndx, shndx; 18941618Srie Sym *sym; 18950Sstevel@tonic-gate 18960Sstevel@tonic-gate /* 18970Sstevel@tonic-gate * Check for null entries 18980Sstevel@tonic-gate */ 18991618Srie if ((move->m_info == 0) && (move->m_value == 0) && 19001618Srie (move->m_poffset == 0) && (move->m_repeat == 0) && 19011618Srie (move->m_stride == 0)) { 19021618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY), 19031618Srie EC_XWORD(move->m_poffset), 0, 0, 0, 19041618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY)); 19050Sstevel@tonic-gate continue; 19060Sstevel@tonic-gate } 19071618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) || 19081618Srie (symndx >= symnum)) { 19090Sstevel@tonic-gate (void) fprintf(stderr, 19100Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file, 19111618Srie _cache->c_name, EC_XWORD(move->m_info)); 19121618Srie 19131618Srie (void) snprintf(index, MAXNDXSIZE, 19141618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 19151618Srie dbg_print(0, fmt, index, 19161618Srie EC_XWORD(move->m_poffset), 19171618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 19181618Srie move->m_stride, move->m_value, 19190Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN)); 19200Sstevel@tonic-gate continue; 19210Sstevel@tonic-gate } 19220Sstevel@tonic-gate 19231618Srie symname = relsymname(cache, _cache, strsec, 19241618Srie symndx, symnum, ndx, syms, section, BUFSIZ, file, 19251618Srie flags); 19261618Srie sym = (Sym *)(syms + symndx); 19270Sstevel@tonic-gate 19280Sstevel@tonic-gate /* 19290Sstevel@tonic-gate * Additional sanity check. 19300Sstevel@tonic-gate */ 19311618Srie shndx = sym->st_shndx; 19320Sstevel@tonic-gate if (!((shndx == SHN_COMMON) || 19330Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) && 19341618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) { 19350Sstevel@tonic-gate (void) fprintf(stderr, 19361618Srie MSG_INTL(MSG_ERR_BADSYM2), file, 19371618Srie _cache->c_name, demangle(symname, flags)); 19380Sstevel@tonic-gate } 19390Sstevel@tonic-gate 19401618Srie (void) snprintf(index, MAXNDXSIZE, 19411618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx)); 19421618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset), 19431618Srie ELF_M_SIZE(move->m_info), move->m_repeat, 19441618Srie move->m_stride, move->m_value, 19451618Srie demangle(symname, flags)); 19460Sstevel@tonic-gate } 19470Sstevel@tonic-gate } 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate /* 19510Sstevel@tonic-gate * Traverse a note section analyzing each note information block. 19520Sstevel@tonic-gate * The data buffers size is used to validate references before they are made, 19530Sstevel@tonic-gate * and is decremented as each element is processed. 19540Sstevel@tonic-gate */ 19550Sstevel@tonic-gate void 19561618Srie note_entry(Cache *cache, Word *data, size_t size, const char *file) 19570Sstevel@tonic-gate { 19581618Srie size_t bsize = size; 19591618Srie 19600Sstevel@tonic-gate /* 19610Sstevel@tonic-gate * Print out a single `note' information block. 19620Sstevel@tonic-gate */ 19630Sstevel@tonic-gate while (size > 0) { 19641618Srie size_t namesz, descsz, type, pad, noteoff; 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate noteoff = bsize - size; 19670Sstevel@tonic-gate /* 19680Sstevel@tonic-gate * Make sure we can at least reference the 3 initial entries 19690Sstevel@tonic-gate * (4-byte words) of the note information block. 19700Sstevel@tonic-gate */ 19711618Srie if (size >= (sizeof (Word) * 3)) 19721618Srie size -= (sizeof (Word) * 3); 19730Sstevel@tonic-gate else { 19741618Srie (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ), 19751618Srie file, cache->c_name, EC_WORD(noteoff)); 19760Sstevel@tonic-gate return; 19770Sstevel@tonic-gate } 19780Sstevel@tonic-gate 19790Sstevel@tonic-gate /* 19800Sstevel@tonic-gate * Make sure any specified name string can be referenced. 19810Sstevel@tonic-gate */ 19820Sstevel@tonic-gate if ((namesz = *data++) != 0) { 19830Sstevel@tonic-gate if (size >= namesz) 19840Sstevel@tonic-gate size -= namesz; 19850Sstevel@tonic-gate else { 19860Sstevel@tonic-gate (void) fprintf(stderr, 19871618Srie MSG_INTL(MSG_NOTE_BADNMSZ), file, 19881618Srie cache->c_name, EC_WORD(noteoff), 19891618Srie EC_WORD(namesz)); 19900Sstevel@tonic-gate return; 19910Sstevel@tonic-gate } 19920Sstevel@tonic-gate } 19931618Srie 19940Sstevel@tonic-gate /* 19950Sstevel@tonic-gate * Make sure any specified descriptor can be referenced. 19960Sstevel@tonic-gate */ 19970Sstevel@tonic-gate if ((descsz = *data++) != 0) { 19980Sstevel@tonic-gate /* 19990Sstevel@tonic-gate * If namesz isn't a 4-byte multiple, account for any 20000Sstevel@tonic-gate * padding that must exist before the descriptor. 20010Sstevel@tonic-gate */ 20021618Srie if ((pad = (namesz & (sizeof (Word) - 1))) != 0) { 20031618Srie pad = sizeof (Word) - pad; 20040Sstevel@tonic-gate size -= pad; 20050Sstevel@tonic-gate } 20060Sstevel@tonic-gate if (size >= descsz) 20070Sstevel@tonic-gate size -= descsz; 20080Sstevel@tonic-gate else { 20090Sstevel@tonic-gate (void) fprintf(stderr, 20101618Srie MSG_INTL(MSG_NOTE_BADDESZ), file, 20111618Srie cache->c_name, EC_WORD(noteoff), 20121618Srie EC_WORD(namesz)); 20130Sstevel@tonic-gate return; 20140Sstevel@tonic-gate } 20150Sstevel@tonic-gate } 20160Sstevel@tonic-gate 20170Sstevel@tonic-gate type = *data++; 20180Sstevel@tonic-gate 20191618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 20201618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type)); 20210Sstevel@tonic-gate 20221618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz)); 20230Sstevel@tonic-gate if (namesz) { 20240Sstevel@tonic-gate char *name = (char *)data; 20250Sstevel@tonic-gate 20260Sstevel@tonic-gate /* 20270Sstevel@tonic-gate * Since the name string may have 'null' bytes 20280Sstevel@tonic-gate * in it (ia32 .string) - we just write the 20290Sstevel@tonic-gate * whole stream in a single fwrite. 20300Sstevel@tonic-gate */ 20310Sstevel@tonic-gate (void) fwrite(name, namesz, 1, stdout); 20320Sstevel@tonic-gate name = name + ((namesz + (sizeof (Word) - 1)) & 20330Sstevel@tonic-gate ~(sizeof (Word) - 1)); 20340Sstevel@tonic-gate /* LINTED */ 20350Sstevel@tonic-gate data = (Word *)name; 20361618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 20370Sstevel@tonic-gate } 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate /* 20400Sstevel@tonic-gate * If multiple information blocks exist within a .note section 20410Sstevel@tonic-gate * account for any padding that must exist before the next 20420Sstevel@tonic-gate * information block. 20430Sstevel@tonic-gate */ 20441618Srie if ((pad = (descsz & (sizeof (Word) - 1))) != 0) { 20451618Srie pad = sizeof (Word) - pad; 20460Sstevel@tonic-gate if (size > pad) 20470Sstevel@tonic-gate size -= pad; 20480Sstevel@tonic-gate } 20490Sstevel@tonic-gate 20501618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz)); 20510Sstevel@tonic-gate if (descsz) { 20520Sstevel@tonic-gate int ndx, byte, word; 20531618Srie char string[58], *str = string; 20540Sstevel@tonic-gate uchar_t *desc = (uchar_t *)data; 20550Sstevel@tonic-gate 20560Sstevel@tonic-gate /* 20570Sstevel@tonic-gate * Dump descriptor bytes. 20580Sstevel@tonic-gate */ 20590Sstevel@tonic-gate for (ndx = byte = word = 0; descsz; descsz--, desc++) { 20600Sstevel@tonic-gate int tok = *desc; 20610Sstevel@tonic-gate 20620Sstevel@tonic-gate (void) snprintf(str, 58, MSG_ORIG(MSG_NOTE_TOK), 20630Sstevel@tonic-gate tok); 20640Sstevel@tonic-gate str += 3; 20650Sstevel@tonic-gate 20660Sstevel@tonic-gate if (++byte == 4) { 20670Sstevel@tonic-gate *str++ = ' ', *str++ = ' '; 20680Sstevel@tonic-gate word++; 20690Sstevel@tonic-gate byte = 0; 20700Sstevel@tonic-gate } 20710Sstevel@tonic-gate if (word == 4) { 20720Sstevel@tonic-gate *str = '\0'; 20731618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESC), 20740Sstevel@tonic-gate ndx, string); 20750Sstevel@tonic-gate word = 0; 20760Sstevel@tonic-gate ndx += 16; 20770Sstevel@tonic-gate str = string; 20780Sstevel@tonic-gate } 20790Sstevel@tonic-gate } 20800Sstevel@tonic-gate if (byte || word) { 20810Sstevel@tonic-gate *str = '\0'; 20821618Srie dbg_print(0, MSG_ORIG(MSG_NOTE_DESC), 20831618Srie ndx, string); 20840Sstevel@tonic-gate } 20850Sstevel@tonic-gate 20860Sstevel@tonic-gate desc += pad; 20870Sstevel@tonic-gate /* LINTED */ 20880Sstevel@tonic-gate data = (Word *)desc; 20890Sstevel@tonic-gate } 20900Sstevel@tonic-gate } 20910Sstevel@tonic-gate } 20920Sstevel@tonic-gate 20930Sstevel@tonic-gate /* 20940Sstevel@tonic-gate * Search for and process a .note section. 20950Sstevel@tonic-gate */ 20960Sstevel@tonic-gate static void 20971618Srie note(Cache *cache, Word shnum, const char *name, const char *file) 20980Sstevel@tonic-gate { 20991618Srie Word cnt; 21000Sstevel@tonic-gate 21010Sstevel@tonic-gate /* 21020Sstevel@tonic-gate * Otherwise look for any .note sections. 21030Sstevel@tonic-gate */ 21040Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 21051618Srie Cache *_cache = &cache[cnt]; 21061618Srie Shdr *shdr = _cache->c_shdr; 21070Sstevel@tonic-gate 21080Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE) 21090Sstevel@tonic-gate continue; 21100Sstevel@tonic-gate if (name && strcmp(name, _cache->c_name)) 21110Sstevel@tonic-gate continue; 21120Sstevel@tonic-gate 21130Sstevel@tonic-gate /* 21140Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're 21150Sstevel@tonic-gate * properly aligned before proceeding. 21160Sstevel@tonic-gate */ 21170Sstevel@tonic-gate if (shdr->sh_offset & (sizeof (Word) - 1)) { 21180Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 21190Sstevel@tonic-gate file, _cache->c_name); 21200Sstevel@tonic-gate continue; 21210Sstevel@tonic-gate } 21223466Srie if (_cache->c_data == NULL) 21233466Srie continue; 21240Sstevel@tonic-gate 21251618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 21261618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 21270Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf, 21280Sstevel@tonic-gate /* LINTED */ 21290Sstevel@tonic-gate (Word)_cache->c_data->d_size, file); 21300Sstevel@tonic-gate } 21310Sstevel@tonic-gate } 21320Sstevel@tonic-gate 21331618Srie /* 21341618Srie * Determine an individual hash entry. This may be the initial hash entry, 21351618Srie * or an associated chain entry. 21361618Srie */ 21371618Srie static void 21381618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx, 21391618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts, 21401618Srie uint_t flags, int chain) 21411618Srie { 21421618Srie Sym *sym; 21431618Srie const char *symname, *str; 21441618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE]; 21451618Srie ulong_t nbkt, nhash; 21461618Srie 21471618Srie if (symndx > symn) { 21481618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file, 21491618Srie EC_WORD(symndx), EC_WORD(hashndx)); 21501618Srie symname = MSG_INTL(MSG_STR_UNKNOWN); 21511618Srie } else { 21521618Srie sym = (Sym *)(syms + symndx); 21531618Srie symname = string(refsec, symndx, strsec, file, sym->st_name); 21541618Srie } 21551618Srie 21561618Srie if (chain == 0) { 21571618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 21581618Srie hashndx); 21591618Srie str = (const char *)_bucket; 21601618Srie } else 21611618Srie str = MSG_ORIG(MSG_STR_EMPTY); 21621618Srie 21631618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2), 21641618Srie EC_WORD(symndx)); 21651618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx, 21661618Srie demangle(symname, flags)); 21671618Srie 21681618Srie /* 21691618Srie * Determine if this string is in the correct bucket. 21701618Srie */ 21711618Srie nhash = elf_hash(symname); 21721618Srie nbkt = nhash % bkts; 21731618Srie 21741618Srie if (nbkt != hashndx) { 21751618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file, 21761618Srie hsecname, symname, EC_WORD(hashndx), nbkt); 21771618Srie } 21781618Srie } 21790Sstevel@tonic-gate 21800Sstevel@tonic-gate #define MAXCOUNT 500 21810Sstevel@tonic-gate 21820Sstevel@tonic-gate static void 21831618Srie hash(Cache *cache, Word shnum, const char *name, const char *file, uint_t flags) 21840Sstevel@tonic-gate { 21850Sstevel@tonic-gate static int count[MAXCOUNT]; 21861618Srie Word cnt; 21870Sstevel@tonic-gate ulong_t ndx, bkts; 21880Sstevel@tonic-gate char number[MAXNDXSIZE]; 21890Sstevel@tonic-gate 21900Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 21910Sstevel@tonic-gate uint_t *hash, *chain; 21920Sstevel@tonic-gate Cache *_cache = &cache[cnt]; 21931618Srie Shdr *sshdr, *hshdr = _cache->c_shdr; 21941618Srie char *ssecname, *hsecname = _cache->c_name; 21951618Srie Sym *syms; 21961618Srie Word symn; 21970Sstevel@tonic-gate 21981618Srie if (hshdr->sh_type != SHT_HASH) 21990Sstevel@tonic-gate continue; 22001618Srie if (name && strcmp(name, hsecname)) 22010Sstevel@tonic-gate continue; 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate /* 22040Sstevel@tonic-gate * Determine the hash table data and size. 22050Sstevel@tonic-gate */ 22061618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) { 22070Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 22081618Srie file, hsecname); 22090Sstevel@tonic-gate continue; 22100Sstevel@tonic-gate } 22113466Srie if (_cache->c_data == NULL) 22123466Srie continue; 22133466Srie 22140Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf; 22150Sstevel@tonic-gate bkts = *hash; 22160Sstevel@tonic-gate chain = hash + 2 + bkts; 22170Sstevel@tonic-gate hash += 2; 22180Sstevel@tonic-gate 22190Sstevel@tonic-gate /* 22200Sstevel@tonic-gate * Get the data buffer for the associated symbol table. 22210Sstevel@tonic-gate */ 22221618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) { 22230Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 22241618Srie file, hsecname, EC_WORD(hshdr->sh_link)); 22250Sstevel@tonic-gate continue; 22260Sstevel@tonic-gate } 22271618Srie 22281618Srie _cache = &cache[hshdr->sh_link]; 22291618Srie ssecname = _cache->c_name; 22301618Srie 22313466Srie if (_cache->c_data == NULL) 22323466Srie continue; 22333466Srie 22343466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) { 22350Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 22361618Srie file, ssecname); 22370Sstevel@tonic-gate continue; 22380Sstevel@tonic-gate } 22390Sstevel@tonic-gate 22401618Srie sshdr = _cache->c_shdr; 22411618Srie /* LINTED */ 22421618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize); 22431618Srie 22440Sstevel@tonic-gate /* 22450Sstevel@tonic-gate * Get the associated string table section. 22460Sstevel@tonic-gate */ 22471618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) { 22480Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 22491618Srie file, ssecname, EC_WORD(sshdr->sh_link)); 22500Sstevel@tonic-gate continue; 22510Sstevel@tonic-gate } 22520Sstevel@tonic-gate 22531618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 22541618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname); 22551618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO)); 22560Sstevel@tonic-gate 22570Sstevel@tonic-gate /* 22580Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate 22590Sstevel@tonic-gate * symbols. 22600Sstevel@tonic-gate */ 22610Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) { 22621618Srie Word _ndx, _cnt; 22630Sstevel@tonic-gate 22640Sstevel@tonic-gate if (*hash == 0) { 22650Sstevel@tonic-gate count[0]++; 22660Sstevel@tonic-gate continue; 22670Sstevel@tonic-gate } 22680Sstevel@tonic-gate 22691618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname, 22701618Srie ndx, *hash, symn, syms, file, bkts, flags, 0); 22710Sstevel@tonic-gate 22720Sstevel@tonic-gate /* 22730Sstevel@tonic-gate * Determine if any other symbols are chained to this 22740Sstevel@tonic-gate * bucket. 22750Sstevel@tonic-gate */ 22760Sstevel@tonic-gate _ndx = chain[*hash]; 22770Sstevel@tonic-gate _cnt = 1; 22780Sstevel@tonic-gate while (_ndx) { 22791618Srie hash_entry(_cache, &cache[sshdr->sh_link], 22801618Srie hsecname, ndx, _ndx, symn, syms, file, 22811618Srie bkts, flags, 1); 22820Sstevel@tonic-gate _ndx = chain[_ndx]; 22830Sstevel@tonic-gate _cnt++; 22840Sstevel@tonic-gate } 22850Sstevel@tonic-gate 22860Sstevel@tonic-gate if (_cnt >= MAXCOUNT) { 22870Sstevel@tonic-gate (void) fprintf(stderr, 22881324Srie MSG_INTL(MSG_HASH_OVERFLW), file, 22891618Srie _cache->c_name, EC_WORD(ndx), 22901618Srie EC_WORD(_cnt)); 22910Sstevel@tonic-gate } else 22920Sstevel@tonic-gate count[_cnt]++; 22930Sstevel@tonic-gate } 22940Sstevel@tonic-gate break; 22950Sstevel@tonic-gate } 22960Sstevel@tonic-gate 22970Sstevel@tonic-gate /* 22980Sstevel@tonic-gate * Print out the count information. 22990Sstevel@tonic-gate */ 23000Sstevel@tonic-gate bkts = cnt = 0; 23011618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 23021618Srie 23030Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) { 23041618Srie Word _cnt; 23050Sstevel@tonic-gate 23060Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0) 23070Sstevel@tonic-gate continue; 23080Sstevel@tonic-gate 23091618Srie (void) snprintf(number, MAXNDXSIZE, 23101618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt); 23111618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number, 23121618Srie EC_WORD(ndx)); 23130Sstevel@tonic-gate bkts += _cnt; 23141618Srie cnt += (Word)(ndx * _cnt); 23150Sstevel@tonic-gate } 23160Sstevel@tonic-gate if (cnt) { 23170Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 23181618Srie bkts); 23191618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number, 23201618Srie EC_WORD(cnt)); 23210Sstevel@tonic-gate } 23220Sstevel@tonic-gate } 23230Sstevel@tonic-gate 23240Sstevel@tonic-gate static void 23251618Srie group(Cache *cache, Word shnum, const char *name, const char *file, 23261618Srie uint_t flags) 23270Sstevel@tonic-gate { 23281618Srie Word scnt; 23290Sstevel@tonic-gate 23301618Srie for (scnt = 1; scnt < shnum; scnt++) { 23311618Srie Cache *_cache = &cache[scnt]; 23321618Srie Shdr *shdr = _cache->c_shdr; 23331618Srie Word *grpdata, gcnt, grpcnt, symnum, unknown; 23341618Srie Cache *symsec, *strsec; 23351618Srie Sym *syms, *sym; 23361618Srie char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 23370Sstevel@tonic-gate 23380Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP) 23390Sstevel@tonic-gate continue; 23400Sstevel@tonic-gate if (name && strcmp(name, _cache->c_name)) 23410Sstevel@tonic-gate continue; 23423466Srie if ((_cache->c_data == NULL) || 23433466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL)) 23440Sstevel@tonic-gate continue; 23451618Srie grpcnt = shdr->sh_size / sizeof (Word); 23461618Srie 23471618Srie /* 23481618Srie * Get the data buffer for the associated symbol table and 23491618Srie * string table. 23501618Srie */ 23511618Srie if (stringtbl(cache, 1, scnt, shnum, file, 23521618Srie &symnum, &symsec, &strsec) == 0) 23531618Srie return; 23541618Srie 23551618Srie syms = symsec->c_data->d_buf; 23561618Srie 23571618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 23581618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name); 23591618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE)); 23601618Srie 23611618Srie /* 23621618Srie * The first element of the group defines the group. The 23631618Srie * associated symbol is defined by the sh_link field. 23641618Srie */ 23651618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) { 23661618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 23671618Srie file, _cache->c_name, EC_WORD(shdr->sh_info)); 23681618Srie return; 23690Sstevel@tonic-gate } 23700Sstevel@tonic-gate 23711618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT)); 23721618Srie if (grpdata[0] & GRP_COMDAT) { 23731618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT)); 23740Sstevel@tonic-gate } 23751618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) { 23761618Srie size_t len = strlen(flgstrbuf); 23771618Srie 23781618Srie (void) snprintf(&flgstrbuf[len], 23791618Srie (MSG_GRP_COMDAT_SIZE + 10 - len), 23801618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown); 23810Sstevel@tonic-gate } 23821618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT)); 23831618Srie sym = (Sym *)(syms + shdr->sh_info); 23840Sstevel@tonic-gate 23851618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf, 23861618Srie demangle(string(_cache, 0, strsec, file, sym->st_name), 23871618Srie flags)); 23881618Srie 23891618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) { 23900Sstevel@tonic-gate char index[MAXNDXSIZE]; 23911618Srie const char *name; 23920Sstevel@tonic-gate 23930Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, 23941618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt)); 23951618Srie 23961618Srie if (grpdata[gcnt] >= shnum) 23971618Srie name = MSG_INTL(MSG_GRP_INVALSCN); 23981618Srie else 23991618Srie name = cache[grpdata[gcnt]].c_name; 24001618Srie 24011618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name, 24021618Srie EC_XWORD(grpdata[gcnt])); 24030Sstevel@tonic-gate } 24040Sstevel@tonic-gate } 24050Sstevel@tonic-gate } 24060Sstevel@tonic-gate 24070Sstevel@tonic-gate static void 24081618Srie got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file, uint_t flags) 24090Sstevel@tonic-gate { 24100Sstevel@tonic-gate Cache *gotcache = 0, *symtab = 0, *_cache; 24111618Srie Addr gotbgn, gotend; 24121618Srie Shdr *gotshdr; 24131618Srie Word cnt, gotents, gotndx; 24140Sstevel@tonic-gate size_t gentsize; 24150Sstevel@tonic-gate Got_info *gottable; 24160Sstevel@tonic-gate char *gotdata; 24171618Srie Sym *gotsym; 24181618Srie Xword gotsymaddr; 24190Sstevel@tonic-gate 24200Sstevel@tonic-gate /* 24211324Srie * First, find the got. 24220Sstevel@tonic-gate */ 24230Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 24240Sstevel@tonic-gate _cache = &cache[cnt]; 24251324Srie if (strncmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT), 24261324Srie MSG_ELF_GOT_SIZE) == 0) { 24270Sstevel@tonic-gate gotcache = _cache; 24280Sstevel@tonic-gate break; 24290Sstevel@tonic-gate } 24300Sstevel@tonic-gate } 24311618Srie if (gotcache == 0) 24320Sstevel@tonic-gate return; 24331324Srie 24341324Srie /* 24351324Srie * A got section within a relocatable object is suspicious. 24361324Srie */ 24371324Srie if (ehdr->e_type == ET_REL) { 24381324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file, 24391324Srie _cache->c_name); 24401324Srie } 24411324Srie 24421618Srie gotshdr = gotcache->c_shdr; 24430Sstevel@tonic-gate if (gotshdr->sh_size == 0) { 24440Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 24450Sstevel@tonic-gate file, gotcache->c_name); 24460Sstevel@tonic-gate return; 24470Sstevel@tonic-gate } 24481618Srie 24491618Srie gotbgn = gotshdr->sh_addr; 24500Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size; 24510Sstevel@tonic-gate 24520Sstevel@tonic-gate /* 24531618Srie * Some architectures don't properly set the sh_entsize for the GOT 24541618Srie * table. If it's not set, default to a size of a pointer. 24550Sstevel@tonic-gate */ 24561618Srie if ((gentsize = gotshdr->sh_entsize) == 0) 24571618Srie gentsize = sizeof (Xword); 24581618Srie 24593466Srie if (gotcache->c_data == NULL) 24603466Srie return; 24613466Srie 24620Sstevel@tonic-gate /* LINTED */ 24631618Srie gotents = (Word)(gotshdr->sh_size / gentsize); 24640Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf; 24650Sstevel@tonic-gate 24660Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 24670Sstevel@tonic-gate int err = errno; 24681618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file, 24691618Srie strerror(err)); 24700Sstevel@tonic-gate return; 24710Sstevel@tonic-gate } 24720Sstevel@tonic-gate 24730Sstevel@tonic-gate /* 24740Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations 24750Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a 24760Sstevel@tonic-gate * .rel[a].got section we check them all. 24770Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab 24780Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 24790Sstevel@tonic-gate */ 24800Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) { 24811618Srie Word type, symnum; 24821618Srie Xword relndx, relnum, relsize; 24831618Srie void *rels; 24841618Srie Sym *syms; 24851618Srie Cache *symsec, *strsec; 24861618Srie Cache *_cache = &cache[cnt]; 24871618Srie Shdr *shdr; 24880Sstevel@tonic-gate 24891618Srie shdr = _cache->c_shdr; 24901618Srie type = shdr->sh_type; 24910Sstevel@tonic-gate 24921618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) { 24930Sstevel@tonic-gate symtab = _cache; 24940Sstevel@tonic-gate continue; 24950Sstevel@tonic-gate } 24961618Srie if (type == SHT_SYMTAB) { 24970Sstevel@tonic-gate symtab = _cache; 24980Sstevel@tonic-gate continue; 24990Sstevel@tonic-gate } 25001618Srie if ((type != SHT_RELA) && (type != SHT_REL)) 25010Sstevel@tonic-gate continue; 25020Sstevel@tonic-gate 25030Sstevel@tonic-gate /* 25041618Srie * Decide entry size. 25050Sstevel@tonic-gate */ 25061618Srie if (((relsize = shdr->sh_entsize) == 0) || 25071618Srie (relsize > shdr->sh_size)) { 25081618Srie if (type == SHT_RELA) 25091618Srie relsize = sizeof (Rela); 25101618Srie else 25111618Srie relsize = sizeof (Rel); 25120Sstevel@tonic-gate } 25130Sstevel@tonic-gate 25140Sstevel@tonic-gate /* 25151618Srie * Determine the number of relocations available. 25160Sstevel@tonic-gate */ 25171618Srie if (shdr->sh_size == 0) { 25181618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 25191618Srie file, _cache->c_name); 25200Sstevel@tonic-gate continue; 25210Sstevel@tonic-gate } 25223466Srie if (_cache->c_data == NULL) 25233466Srie continue; 25243466Srie 25251618Srie rels = _cache->c_data->d_buf; 25261618Srie relnum = shdr->sh_size / relsize; 25270Sstevel@tonic-gate 25281618Srie /* 25291618Srie * Get the data buffer for the associated symbol table and 25301618Srie * string table. 25311618Srie */ 25321618Srie if (stringtbl(cache, 1, cnt, shnum, file, 25331618Srie &symnum, &symsec, &strsec) == 0) 25341618Srie continue; 25351618Srie 25361618Srie syms = symsec->c_data->d_buf; 25371618Srie 25381618Srie /* 25391618Srie * Loop through the relocation entries. 25401618Srie */ 25411618Srie for (relndx = 0; relndx < relnum; relndx++, 25421618Srie rels = (void *)((char *)rels + relsize)) { 25431618Srie char section[BUFSIZ]; 25441618Srie Addr offset; 25450Sstevel@tonic-gate Got_info *gip; 25461618Srie Word symndx, reltype; 25471618Srie Rela *rela; 25481618Srie Rel *rel; 25490Sstevel@tonic-gate 25501618Srie /* 25511618Srie * Unravel the relocation. 25521618Srie */ 25531618Srie if (type == SHT_RELA) { 25541618Srie rela = (Rela *)rels; 25551618Srie symndx = ELF_R_SYM(rela->r_info); 25561618Srie reltype = ELF_R_TYPE(rela->r_info); 25571618Srie offset = rela->r_offset; 25580Sstevel@tonic-gate } else { 25591618Srie rel = (Rel *)rels; 25601618Srie symndx = ELF_R_SYM(rel->r_info); 25611618Srie reltype = ELF_R_TYPE(rel->r_info); 25621618Srie offset = rel->r_offset; 25630Sstevel@tonic-gate } 25640Sstevel@tonic-gate 25650Sstevel@tonic-gate /* 25660Sstevel@tonic-gate * Only pay attention to relocations against the GOT. 25670Sstevel@tonic-gate */ 25680Sstevel@tonic-gate if ((offset < gotbgn) || (offset > gotend)) 25690Sstevel@tonic-gate continue; 25700Sstevel@tonic-gate 25710Sstevel@tonic-gate /* LINTED */ 25721618Srie gotndx = (Word)((offset - gotbgn) / 25730Sstevel@tonic-gate gotshdr->sh_entsize); 25740Sstevel@tonic-gate gip = &gottable[gotndx]; 25751618Srie 25761618Srie if (gip->g_reltype != 0) { 25770Sstevel@tonic-gate (void) fprintf(stderr, 25780Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file, 25791618Srie EC_WORD(gotndx), EC_ADDR(offset)); 25800Sstevel@tonic-gate continue; 25810Sstevel@tonic-gate } 25820Sstevel@tonic-gate 25831618Srie if (symndx) 25841618Srie gip->g_symname = relsymname(cache, _cache, 25851618Srie strsec, symndx, symnum, relndx, syms, 25861618Srie section, BUFSIZ, file, flags); 25871618Srie gip->g_reltype = reltype; 25881618Srie gip->g_rel = rels; 25890Sstevel@tonic-gate } 25900Sstevel@tonic-gate } 25910Sstevel@tonic-gate 25921618Srie if (symlookup(MSG_ORIG(MSG_GOT_SYM), cache, shnum, &gotsym, symtab, 25931618Srie file)) 25941618Srie gotsymaddr = gotsym->st_value; 25950Sstevel@tonic-gate else 25961618Srie gotsymaddr = gotbgn; 25970Sstevel@tonic-gate 25981618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 25991618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name); 26001618Srie Elf_got_title(0); 26010Sstevel@tonic-gate 26020Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) { 26030Sstevel@tonic-gate Got_info *gip; 26040Sstevel@tonic-gate Sword gindex; 26051618Srie Addr gaddr; 26061618Srie Xword gotentry; 26070Sstevel@tonic-gate 26080Sstevel@tonic-gate gip = &gottable[gotndx]; 26090Sstevel@tonic-gate 26100Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize); 26111618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize; 26120Sstevel@tonic-gate 26131618Srie if (gentsize == sizeof (Word)) 26140Sstevel@tonic-gate /* LINTED */ 26151618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx)); 26160Sstevel@tonic-gate else 26170Sstevel@tonic-gate /* LINTED */ 26181618Srie gotentry = *((Xword *)(gotdata) + gotndx); 26190Sstevel@tonic-gate 26201618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine, 26211618Srie gip->g_reltype, gip->g_rel, gip->g_symname); 26220Sstevel@tonic-gate } 26230Sstevel@tonic-gate free(gottable); 26240Sstevel@tonic-gate } 26250Sstevel@tonic-gate 26260Sstevel@tonic-gate void 26270Sstevel@tonic-gate checksum(Elf *elf) 26280Sstevel@tonic-gate { 26291618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 26301618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf)); 26310Sstevel@tonic-gate } 26320Sstevel@tonic-gate 26331618Srie void 26341618Srie regular(const char *file, Elf *elf, uint_t flags, char *Nname, int wfd) 26350Sstevel@tonic-gate { 26363862Srie /* 26373862Srie * Program header names that we can test for. 26383862Srie */ 26393862Srie static const char *pnames[PT_NUM] = { 26403862Srie MSG_ORIG(MSG_PT_NULL), MSG_ORIG(MSG_PT_LOAD), 26413862Srie MSG_ORIG(MSG_PT_DYNAMIC), MSG_ORIG(MSG_PT_INTERP), 26423862Srie MSG_ORIG(MSG_PT_NOTE), MSG_ORIG(MSG_PT_SHLIB), 26433862Srie MSG_ORIG(MSG_PT_PHDR), MSG_ORIG(MSG_PT_TLS) 26443862Srie }; 26453862Srie #if PT_NUM != (PT_TLS + 1) 26463862Srie #error "P_NUM has grown. Update addr_symtype[]" 26473862Srie #endif 26483862Srie 26490Sstevel@tonic-gate Elf_Scn *scn; 26501618Srie Ehdr *ehdr; 26510Sstevel@tonic-gate Elf_Data *data; 26521618Srie size_t cnt, shstrndx, shnum, phnum; 26531618Srie Shdr *nameshdr, *shdr; 26540Sstevel@tonic-gate char *names = 0; 26550Sstevel@tonic-gate Cache *cache, *_cache; 2656*3875Sab196087 VERSYM_STATE versym; 26570Sstevel@tonic-gate 26581618Srie if ((ehdr = elf_getehdr(elf)) == NULL) { 26590Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 26600Sstevel@tonic-gate return; 26610Sstevel@tonic-gate } 26620Sstevel@tonic-gate 26631618Srie if (elf_getshnum(elf, &shnum) == 0) { 26640Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 26650Sstevel@tonic-gate return; 26660Sstevel@tonic-gate } 26670Sstevel@tonic-gate 2668942Sahl if (elf_getshstrndx(elf, &shstrndx) == 0) { 26690Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 26700Sstevel@tonic-gate return; 26710Sstevel@tonic-gate } 2672942Sahl 26731618Srie if (elf_getphnum(elf, &phnum) == 0) { 2674942Sahl failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 2675942Sahl return; 2676942Sahl } 2677942Sahl 26780Sstevel@tonic-gate if ((scn = elf_getscn(elf, 0)) != NULL) { 26791618Srie if ((shdr = elf_getshdr(scn)) == NULL) { 26800Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 26810Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 26820Sstevel@tonic-gate return; 26830Sstevel@tonic-gate } 26840Sstevel@tonic-gate } else 26851618Srie shdr = 0; 26860Sstevel@tonic-gate 26870Sstevel@tonic-gate /* 26880Sstevel@tonic-gate * Print the elf header. 26890Sstevel@tonic-gate */ 26900Sstevel@tonic-gate if (flags & FLG_EHDR) 26911618Srie Elf_ehdr(0, ehdr, shdr); 26920Sstevel@tonic-gate 26930Sstevel@tonic-gate /* 26940Sstevel@tonic-gate * Print the program headers. 26950Sstevel@tonic-gate */ 26961618Srie if ((flags & FLG_PHDR) && (phnum != 0)) { 26971618Srie Phdr *phdr; 26980Sstevel@tonic-gate 26991618Srie if ((phdr = elf_getphdr(elf)) == NULL) { 27001618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 27011618Srie return; 27021618Srie } 27030Sstevel@tonic-gate 27041618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) { 27053862Srie 27063862Srie if (Nname && ((phdr->p_type >= PT_NUM) || 27073862Srie (strcmp(Nname, pnames[phdr->p_type]) != 0))) 27083862Srie continue; 27093862Srie 27101618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); 27111618Srie dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(cnt)); 27121618Srie Elf_phdr(0, ehdr->e_machine, phdr); 27130Sstevel@tonic-gate } 27140Sstevel@tonic-gate } 27150Sstevel@tonic-gate 27160Sstevel@tonic-gate /* 2717942Sahl * Return now if there are no section, if there's just one section to 2718942Sahl * act as an extension of the ELF header, or if on section information 2719942Sahl * was requested. 27200Sstevel@tonic-gate */ 2721942Sahl if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) { 27221618Srie if ((ehdr->e_type == ET_CORE) && (flags & FLG_NOTE)) 27230Sstevel@tonic-gate note(0, shnum, 0, file); 27240Sstevel@tonic-gate return; 27250Sstevel@tonic-gate } 27260Sstevel@tonic-gate 27270Sstevel@tonic-gate /* 27280Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section 27290Sstevel@tonic-gate * name strings. 27300Sstevel@tonic-gate */ 27310Sstevel@tonic-gate if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 27320Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 27330Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 27340Sstevel@tonic-gate EC_XWORD(shstrndx)); 27351618Srie 27360Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) { 27370Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 27380Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 27390Sstevel@tonic-gate EC_XWORD(shstrndx)); 27401618Srie 27411618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) { 27420Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 27430Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 27443862Srie EC_WORD(elf_ndxscn(scn))); 27451618Srie 27461618Srie } else if ((names = data->d_buf) == 0) 27470Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 27480Sstevel@tonic-gate 27490Sstevel@tonic-gate /* 27503862Srie * Allocate a cache to maintain a descriptor for each section. 27510Sstevel@tonic-gate */ 27520Sstevel@tonic-gate if ((cache = malloc(shnum * sizeof (Cache))) == 0) { 27530Sstevel@tonic-gate int err = errno; 27540Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 27550Sstevel@tonic-gate file, strerror(err)); 27560Sstevel@tonic-gate return; 27570Sstevel@tonic-gate } 27580Sstevel@tonic-gate 27591618Srie *cache = cache_init; 27600Sstevel@tonic-gate _cache = cache; 27610Sstevel@tonic-gate _cache++; 27620Sstevel@tonic-gate 27633862Srie /* 27643862Srie * Traverse the sections of the file. This gathering of data is 27653862Srie * carried out in two passes. First, the section headers are captured 27663862Srie * and the section header names are evaluated. A verification pass is 27673862Srie * then carried out over the section information. Files have been 27683862Srie * known to exhibit overlapping (and hence erroneous) section header 27693862Srie * information. 27703862Srie * 27713862Srie * Finally, the data for each section is obtained. This processing is 27723862Srie * carried out after section verification because should any section 27733862Srie * header overlap occur, and a file needs translating (ie. xlate'ing 27743862Srie * information from a non-native architecture file), then the process 27753862Srie * of translation can corrupt the section header information. Of 27763862Srie * course, if there is any section overlap, the data related to the 27773862Srie * sections is going to be compromised. However, it is the translation 27783862Srie * of this data that has caused problems with elfdump()'s ability to 27793862Srie * extract the data. 27803862Srie */ 27810Sstevel@tonic-gate for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn); 27820Sstevel@tonic-gate cnt++, _cache++) { 27833862Srie char scnndxnm[100]; 27843862Srie 27853862Srie _cache->c_scn = scn; 27863862Srie 27871618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) { 27880Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 27890Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 27903862Srie EC_WORD(elf_ndxscn(scn))); 27910Sstevel@tonic-gate } 27920Sstevel@tonic-gate 27933862Srie /* 27943862Srie * If a shstrtab exists, assign the section name. 27953862Srie */ 27963862Srie if (names && _cache->c_shdr) { 27973862Srie if (_cache->c_shdr->sh_name && 27983862Srie /* LINTED */ 27993862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) { 28003862Srie _cache->c_name = 28013862Srie names + _cache->c_shdr->sh_name; 28023862Srie continue; 28033862Srie } 28040Sstevel@tonic-gate 28050Sstevel@tonic-gate /* 28063862Srie * Generate an error if the section name index is zero 28073862Srie * or exceeds the shstrtab data. Fall through to 28083862Srie * fabricate a section name. 28090Sstevel@tonic-gate */ 28103862Srie if ((_cache->c_shdr->sh_name == 0) || 28110Sstevel@tonic-gate /* LINTED */ 28121618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) { 28130Sstevel@tonic-gate (void) fprintf(stderr, 28140Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file, 28153862Srie EC_WORD(cnt), 28161618Srie EC_XWORD(_cache->c_shdr->sh_name)); 28170Sstevel@tonic-gate } 28183862Srie } 28193862Srie 28203862Srie /* 28213862Srie * If there exists no shstrtab data, or a section header has no 28223862Srie * name (an invalid index of 0), then compose a name for the 28233862Srie * section. 28243862Srie */ 28253862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm), 28263862Srie MSG_INTL(MSG_FMT_SCNNDX), cnt); 28273862Srie 28283862Srie if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == 0) { 28293862Srie int err = errno; 28303862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 28313862Srie file, strerror(err)); 28323862Srie return; 28333862Srie } 28343862Srie (void) strcpy(_cache->c_name, scnndxnm); 28353862Srie } 28363862Srie 28373862Srie /* 28383862Srie * Having collected all the sections, validate their address range. 28393862Srie * Cases have existed where the section information has been invalid. 28403862Srie * This can lead to all sorts of other, hard to diagnose errors, as 28413862Srie * each section is processed individually (ie. with elf_getdata()). 28423862Srie * Here, we carry out some address comparisons to catch a family of 28433862Srie * overlapping memory issues we have observed (likely, there are others 28443862Srie * that we have yet to discover). 28453862Srie * 28463862Srie * Note, should any memory overlap occur, obtaining any additional 28473862Srie * data from the file is questionable. However, it might still be 28483862Srie * possible to inspect the ELF header, Programs headers, or individual 28493862Srie * sections, so rather than bailing on an error condition, continue 28503862Srie * processing to see if any data can be salvaged. 28513862Srie */ 28523862Srie for (cnt = 1; cnt < shnum; cnt++) { 28533862Srie Cache *_cache = &cache[cnt]; 28543862Srie Shdr *shdr = _cache->c_shdr; 28553862Srie Off bgn1, bgn = shdr->sh_offset; 28563862Srie Off end1, end = shdr->sh_offset + shdr->sh_size; 28573862Srie int cnt1; 28583862Srie 28593862Srie if ((shdr->sh_size == 0) || (shdr->sh_type == SHT_NOBITS)) 28603862Srie continue; 28613862Srie 28623862Srie for (cnt1 = 1; cnt1 < shnum; cnt1++) { 28633862Srie Cache *_cache1 = &cache[cnt1]; 28643862Srie Shdr *shdr1 = _cache1->c_shdr; 28653862Srie 28663862Srie bgn1 = shdr1->sh_offset; 28673862Srie end1 = shdr1->sh_offset + shdr1->sh_size; 28683862Srie 28693862Srie if ((cnt1 == cnt) || (shdr->sh_size == 0) || 28703862Srie (shdr1->sh_type == SHT_NOBITS)) 28713862Srie continue; 28723862Srie 28733862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 28743862Srie ((bgn1 < end) && (end1 >= end))) { 28753862Srie (void) fprintf(stderr, 28763862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file, 28773862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)), 28783862Srie _cache1->c_name, EC_OFF(bgn1), EC_OFF(end1), 28793862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 28803862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 28810Sstevel@tonic-gate } 28820Sstevel@tonic-gate } 28830Sstevel@tonic-gate 28843862Srie /* 28853862Srie * And finally, make sure this section doesn't overlap the 28863862Srie * section header itself. 28873862Srie */ 28883862Srie bgn1 = ehdr->e_shoff; 28893862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum); 28903862Srie 28913862Srie if (((bgn1 <= bgn) && (end1 > bgn)) || 28923862Srie ((bgn1 < end) && (end1 >= end))) { 28933862Srie (void) fprintf(stderr, 28943862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1), 28953862Srie EC_OFF(end1), 28963862Srie EC_WORD(elf_ndxscn(_cache->c_scn)), 28973862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end)); 28983862Srie } 28993862Srie } 29003862Srie 29013862Srie /* 29023862Srie * Finally, obtain the data for each section. 29033862Srie */ 29043862Srie for (cnt = 1; cnt < shnum; cnt++) { 29053862Srie Cache *_cache = &cache[cnt]; 29063862Srie Elf_Scn *scn = _cache->c_scn; 29073862Srie 29080Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 29090Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 29100Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 29113862Srie EC_WORD(elf_ndxscn(scn))); 29120Sstevel@tonic-gate } 29130Sstevel@tonic-gate 29140Sstevel@tonic-gate /* 29150Sstevel@tonic-gate * Do we wish to write the section out? 29160Sstevel@tonic-gate */ 29173466Srie if (wfd && Nname && (strcmp(Nname, _cache->c_name) == 0) && 29183466Srie _cache->c_data) { 29190Sstevel@tonic-gate (void) write(wfd, _cache->c_data->d_buf, 29200Sstevel@tonic-gate _cache->c_data->d_size); 29210Sstevel@tonic-gate } 29220Sstevel@tonic-gate } 29230Sstevel@tonic-gate 29240Sstevel@tonic-gate if (flags & FLG_SHDR) 29251618Srie sections(file, cache, shnum, ehdr, Nname); 29260Sstevel@tonic-gate 29270Sstevel@tonic-gate if (flags & FLG_INTERP) 29281618Srie interp(file, cache, shnum, phnum, elf); 29290Sstevel@tonic-gate 2930*3875Sab196087 versions(cache, shnum, file, flags, &versym); 29310Sstevel@tonic-gate 29320Sstevel@tonic-gate if (flags & FLG_SYMBOLS) 2933*3875Sab196087 symbols(cache, shnum, ehdr, Nname, &versym, file, flags); 29340Sstevel@tonic-gate 29353492Sab196087 if (flags & FLG_SORT) 2936*3875Sab196087 sunw_sort(cache, shnum, ehdr, Nname, &versym, file, flags); 29373492Sab196087 29380Sstevel@tonic-gate if (flags & FLG_HASH) 29390Sstevel@tonic-gate hash(cache, shnum, Nname, file, flags); 29400Sstevel@tonic-gate 29410Sstevel@tonic-gate if (flags & FLG_GOT) 29421618Srie got(cache, shnum, ehdr, file, flags); 29430Sstevel@tonic-gate 29440Sstevel@tonic-gate if (flags & FLG_GROUP) 29450Sstevel@tonic-gate group(cache, shnum, Nname, file, flags); 29460Sstevel@tonic-gate 29470Sstevel@tonic-gate if (flags & FLG_SYMINFO) 29480Sstevel@tonic-gate syminfo(cache, shnum, file); 29490Sstevel@tonic-gate 29500Sstevel@tonic-gate if (flags & FLG_RELOC) 29511618Srie reloc(cache, shnum, ehdr, Nname, file, flags); 29520Sstevel@tonic-gate 29530Sstevel@tonic-gate if (flags & FLG_DYNAMIC) 29541618Srie dynamic(cache, shnum, ehdr, file); 29550Sstevel@tonic-gate 29560Sstevel@tonic-gate if (flags & FLG_NOTE) 29570Sstevel@tonic-gate note(cache, shnum, Nname, file); 29580Sstevel@tonic-gate 29590Sstevel@tonic-gate if (flags & FLG_MOVE) 29600Sstevel@tonic-gate move(cache, shnum, Nname, file, flags); 29610Sstevel@tonic-gate 29620Sstevel@tonic-gate if (flags & FLG_CHECKSUM) 29630Sstevel@tonic-gate checksum(elf); 29640Sstevel@tonic-gate 29650Sstevel@tonic-gate if (flags & FLG_CAP) 29661618Srie cap(file, cache, shnum, phnum, ehdr, elf); 29670Sstevel@tonic-gate 29680Sstevel@tonic-gate if (flags & FLG_UNWIND) 29691618Srie unwind(cache, shnum, phnum, ehdr, Nname, file, elf); 29700Sstevel@tonic-gate 29710Sstevel@tonic-gate free(cache); 29720Sstevel@tonic-gate } 2973