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 /*
2311687SAli.Bahrami@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * Dump an elf file.
290Sstevel@tonic-gate */
309406SAli.Bahrami@Sun.COM #include <stddef.h>
311618Srie #include <sys/elf_386.h>
321618Srie #include <sys/elf_amd64.h>
331618Srie #include <sys/elf_SPARC.h>
346206Sab196087 #include <_libelf.h>
351618Srie #include <dwarf.h>
365549Srie #include <stdio.h>
370Sstevel@tonic-gate #include <unistd.h>
380Sstevel@tonic-gate #include <errno.h>
390Sstevel@tonic-gate #include <strings.h>
400Sstevel@tonic-gate #include <debug.h>
410Sstevel@tonic-gate #include <conv.h>
420Sstevel@tonic-gate #include <msg.h>
431618Srie #include <_elfdump.h>
440Sstevel@tonic-gate
453875Sab196087
463875Sab196087 /*
473875Sab196087 * VERSYM_STATE is used to maintain information about the VERSYM section
483875Sab196087 * in the object being analyzed. It is filled in by versions(), and used
493875Sab196087 * by init_symtbl_state() when displaying symbol information.
503875Sab196087 *
517682SAli.Bahrami@Sun.COM * There are three forms of symbol versioning known to us:
527682SAli.Bahrami@Sun.COM *
537682SAli.Bahrami@Sun.COM * 1) The original form, introduced with Solaris 2.5, in which
547682SAli.Bahrami@Sun.COM * the Versym contains indexes to Verdef records, and the
557682SAli.Bahrami@Sun.COM * Versym values for UNDEF symbols resolved by other objects
567682SAli.Bahrami@Sun.COM * are all set to 0.
577682SAli.Bahrami@Sun.COM * 2) The GNU form, which is backward compatible with the original
587682SAli.Bahrami@Sun.COM * Solaris form, but which adds several extensions:
597682SAli.Bahrami@Sun.COM * - The Versym also contains indexes to Verneed records, recording
607682SAli.Bahrami@Sun.COM * which object/version contributed the external symbol at
617682SAli.Bahrami@Sun.COM * link time. These indexes start with the next value following
627682SAli.Bahrami@Sun.COM * the final Verdef index. The index is written to the previously
637682SAli.Bahrami@Sun.COM * reserved vna_other field of the ELF Vernaux structure.
647682SAli.Bahrami@Sun.COM * - The top bit of the Versym value is no longer part of the index,
657682SAli.Bahrami@Sun.COM * but is used as a "hidden bit" to prevent binding to the symbol.
667682SAli.Bahrami@Sun.COM * - Multiple implementations of a given symbol, contained in varying
677682SAli.Bahrami@Sun.COM * versions are allowed, using special assembler pseudo ops,
687682SAli.Bahrami@Sun.COM * and encoded in the symbol name using '@' characters.
697682SAli.Bahrami@Sun.COM * 3) Modified Solaris form, in which we adopt the first GNU extension
707682SAli.Bahrami@Sun.COM * (Versym indexes to Verneed records), but not the others.
717682SAli.Bahrami@Sun.COM *
727682SAli.Bahrami@Sun.COM * elfdump can handle any of these cases. The presence of a DT_VERSYM
737682SAli.Bahrami@Sun.COM * dynamic element indicates a full GNU object. An object that lacks
747682SAli.Bahrami@Sun.COM * a DT_VERSYM entry, but which has non-zero vna_other fields in the Vernaux
757682SAli.Bahrami@Sun.COM * structures is a modified Solaris object. An object that has neither of
767682SAli.Bahrami@Sun.COM * these uses the original form.
777682SAli.Bahrami@Sun.COM *
784716Sab196087 * max_verndx contains the largest version index that can appear
794716Sab196087 * in a Versym entry. This can never be less than 1: In the case where
804716Sab196087 * there is no verdef/verneed sections, the [0] index is reserved
817682SAli.Bahrami@Sun.COM * for local symbols, and the [1] index for globals. If the original
827682SAli.Bahrami@Sun.COM * Solaris versioning rules are in effect and there is a verdef section,
837682SAli.Bahrami@Sun.COM * then max_verndex is the number of defined versions. If one of the
847682SAli.Bahrami@Sun.COM * other versioning forms is in effect, then:
857682SAli.Bahrami@Sun.COM * 1) If there is no verneed section, it is the same as for
867682SAli.Bahrami@Sun.COM * original Solaris versioning.
877682SAli.Bahrami@Sun.COM * 2) If there is a verneed section, the vna_other field of the
884716Sab196087 * Vernaux structs contain versions, and max_verndx is the
894716Sab196087 * largest such index.
904716Sab196087 *
917682SAli.Bahrami@Sun.COM * If gnu_full is True, the object uses the full GNU form of versioning.
927682SAli.Bahrami@Sun.COM * The value of the gnu_full field is based on the presence of
934716Sab196087 * a DT_VERSYM entry in the dynamic section: GNU ld produces these, and
944716Sab196087 * Solaris ld does not.
957682SAli.Bahrami@Sun.COM *
967682SAli.Bahrami@Sun.COM * The gnu_needed field is True if the Versym contains indexes to
977682SAli.Bahrami@Sun.COM * Verneed records, as indicated by non-zero vna_other fields in the Verneed
987682SAli.Bahrami@Sun.COM * section. If gnu_full is True, then gnu_needed will always be true.
997682SAli.Bahrami@Sun.COM * However, gnu_needed can be true without gnu_full. This is the modified
1007682SAli.Bahrami@Sun.COM * Solaris form.
1013875Sab196087 */
1023875Sab196087 typedef struct {
1033875Sab196087 Cache *cache; /* Pointer to cache entry for VERSYM */
1043875Sab196087 Versym *data; /* Pointer to versym array */
1057682SAli.Bahrami@Sun.COM int gnu_full; /* True if object uses GNU versioning rules */
1067682SAli.Bahrami@Sun.COM int gnu_needed; /* True if object uses VERSYM indexes for */
1077682SAli.Bahrami@Sun.COM /* VERNEED (subset of gnu_full) */
1084716Sab196087 int max_verndx; /* largest versym index value */
1093875Sab196087 } VERSYM_STATE;
1103875Sab196087
1113875Sab196087 /*
1123875Sab196087 * SYMTBL_STATE is used to maintain information about a single symbol
1133875Sab196087 * table section, for use by the routines that display symbol information.
1143875Sab196087 */
1153875Sab196087 typedef struct {
1163875Sab196087 const char *file; /* Name of file */
1173875Sab196087 Ehdr *ehdr; /* ELF header for file */
1183875Sab196087 Cache *cache; /* Cache of all section headers */
1199273SAli.Bahrami@Sun.COM uchar_t osabi; /* OSABI to use */
1203875Sab196087 Word shnum; /* # of sections in cache */
1213875Sab196087 Cache *seccache; /* Cache of symbol table section hdr */
1223875Sab196087 Word secndx; /* Index of symbol table section hdr */
1233875Sab196087 const char *secname; /* Name of section */
1243875Sab196087 uint_t flags; /* Command line option flags */
1253875Sab196087 struct { /* Extended section index data */
1263875Sab196087 int checked; /* TRUE if already checked for shxndx */
1273875Sab196087 Word *data; /* NULL, or extended section index */
1283875Sab196087 /* used for symbol table entries */
1293875Sab196087 uint_t n; /* # items in shxndx.data */
1303875Sab196087 } shxndx;
1313875Sab196087 VERSYM_STATE *versym; /* NULL, or associated VERSYM section */
1323875Sab196087 Sym *sym; /* Array of symbols */
1333875Sab196087 Word symn; /* # of symbols */
1343875Sab196087 } SYMTBL_STATE;
1353875Sab196087
1369406SAli.Bahrami@Sun.COM /*
1379406SAli.Bahrami@Sun.COM * A variable of this type is used to track information related to
1389406SAli.Bahrami@Sun.COM * .eh_frame and .eh_frame_hdr sections across calls to unwind_eh_frame().
1399406SAli.Bahrami@Sun.COM */
1409406SAli.Bahrami@Sun.COM typedef struct {
1419406SAli.Bahrami@Sun.COM Word frame_cnt; /* # .eh_frame sections seen */
1429406SAli.Bahrami@Sun.COM Word frame_ndx; /* Section index of 1st .eh_frame */
1439406SAli.Bahrami@Sun.COM Word hdr_cnt; /* # .eh_frame_hdr sections seen */
1449406SAli.Bahrami@Sun.COM Word hdr_ndx; /* Section index of 1st .eh_frame_hdr */
1459406SAli.Bahrami@Sun.COM uint64_t frame_ptr; /* Value of FramePtr field from first */
1469406SAli.Bahrami@Sun.COM /* .eh_frame_hdr section */
1479406SAli.Bahrami@Sun.COM uint64_t frame_base; /* Data addr of 1st .eh_frame */
1489406SAli.Bahrami@Sun.COM } gnu_eh_state_t;
1499406SAli.Bahrami@Sun.COM
1509406SAli.Bahrami@Sun.COM /*
1519406SAli.Bahrami@Sun.COM * C++ .exception_ranges entries make use of the signed ptrdiff_t
1529406SAli.Bahrami@Sun.COM * type to record self-relative pointer values. We need a type
1539406SAli.Bahrami@Sun.COM * for this that is matched to the ELFCLASS being processed.
1549406SAli.Bahrami@Sun.COM */
1559406SAli.Bahrami@Sun.COM #if defined(_ELF64)
1569406SAli.Bahrami@Sun.COM typedef int64_t PTRDIFF_T;
1579406SAli.Bahrami@Sun.COM #else
1589406SAli.Bahrami@Sun.COM typedef int32_t PTRDIFF_T;
1599406SAli.Bahrami@Sun.COM #endif
1609406SAli.Bahrami@Sun.COM
1619406SAli.Bahrami@Sun.COM /*
1629406SAli.Bahrami@Sun.COM * The Sun C++ ABI uses this struct to define each .exception_ranges
1639406SAli.Bahrami@Sun.COM * entry. From the ABI:
1649406SAli.Bahrami@Sun.COM *
1659406SAli.Bahrami@Sun.COM * The field ret_addr is a self relative pointer to the start of the address
1669406SAli.Bahrami@Sun.COM * range. The name was chosen because in the current implementation the range
1679406SAli.Bahrami@Sun.COM * typically starts at the return address for a call site.
1689406SAli.Bahrami@Sun.COM *
1699406SAli.Bahrami@Sun.COM * The field length is the difference, in bytes, between the pc of the last
1709406SAli.Bahrami@Sun.COM * instruction covered by the exception range and the first. When only a
1719406SAli.Bahrami@Sun.COM * single call site is represented without optimization, this will equal zero.
1729406SAli.Bahrami@Sun.COM *
1739406SAli.Bahrami@Sun.COM * The field handler_addr is a relative pointer which stores the difference
1749406SAli.Bahrami@Sun.COM * between the start of the exception range and the address of all code to
1759406SAli.Bahrami@Sun.COM * catch exceptions and perform the cleanup for stack unwinding.
1769406SAli.Bahrami@Sun.COM *
1779406SAli.Bahrami@Sun.COM * The field type_block is a relative pointer which stores the difference
1789406SAli.Bahrami@Sun.COM * between the start of the exception range and the address of an array used
1799406SAli.Bahrami@Sun.COM * for storing a list of the types of exceptions which can be caught within
1809406SAli.Bahrami@Sun.COM * the exception range.
1819406SAli.Bahrami@Sun.COM */
1829406SAli.Bahrami@Sun.COM typedef struct {
1839406SAli.Bahrami@Sun.COM PTRDIFF_T ret_addr;
1849406SAli.Bahrami@Sun.COM Xword length;
1859406SAli.Bahrami@Sun.COM PTRDIFF_T handler_addr;
1869406SAli.Bahrami@Sun.COM PTRDIFF_T type_block;
1879406SAli.Bahrami@Sun.COM Xword reserved;
1889406SAli.Bahrami@Sun.COM } exception_range_entry;
1893875Sab196087
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate * Focal point for verifying symbol names.
1920Sstevel@tonic-gate */
1930Sstevel@tonic-gate static const char *
string(Cache * refsec,Word ndx,Cache * strsec,const char * file,Word name)1941618Srie string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name)
1950Sstevel@tonic-gate {
1964063Sab196087 /*
1974063Sab196087 * If an error in this routine is due to a property of the string
1984063Sab196087 * section, as opposed to a bad offset into the section (a property of
1994063Sab196087 * the referencing section), then we will detect the same error on
2004063Sab196087 * every call involving those sections. We use these static variables
2014063Sab196087 * to retain the information needed to only issue each such error once.
2024063Sab196087 */
2034063Sab196087 static Cache *last_refsec; /* Last referencing section seen */
2044063Sab196087 static int strsec_err; /* True if error issued */
2054063Sab196087
2063492Sab196087 const char *strs;
2073492Sab196087 Word strn;
2080Sstevel@tonic-gate
2093466Srie if (strsec->c_data == NULL)
2103466Srie return (NULL);
2113466Srie
2123492Sab196087 strs = (char *)strsec->c_data->d_buf;
2133492Sab196087 strn = strsec->c_data->d_size;
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate /*
2164063Sab196087 * We only print a diagnostic regarding a bad string table once per
2174063Sab196087 * input section being processed. If the refsec has changed, reset
2184063Sab196087 * our retained error state.
2190Sstevel@tonic-gate */
2204063Sab196087 if (last_refsec != refsec) {
2214063Sab196087 last_refsec = refsec;
2224063Sab196087 strsec_err = 0;
2234063Sab196087 }
2244063Sab196087
2254063Sab196087 /* Verify that strsec really is a string table */
2264063Sab196087 if (strsec->c_shdr->sh_type != SHT_STRTAB) {
2274063Sab196087 if (!strsec_err) {
2284063Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOTSTRTAB),
2294063Sab196087 file, strsec->c_ndx, refsec->c_ndx);
2304063Sab196087 strsec_err = 1;
2314063Sab196087 }
2324063Sab196087 return (MSG_INTL(MSG_STR_UNKNOWN));
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate * Is the string table offset within range of the available strings?
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate if (name >= strn) {
2390Sstevel@tonic-gate /*
2400Sstevel@tonic-gate * Do we have a empty string table?
2410Sstevel@tonic-gate */
2429085SAli.Bahrami@Sun.COM if (strs == NULL) {
2434063Sab196087 if (!strsec_err) {
2440Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2450Sstevel@tonic-gate file, strsec->c_name);
2464063Sab196087 strsec_err = 1;
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate } else {
2490Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF),
2501618Srie file, refsec->c_name, EC_WORD(ndx), strsec->c_name,
2511618Srie EC_WORD(name), EC_WORD(strn - 1));
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate * Return the empty string so that the calling function can
2560Sstevel@tonic-gate * continue it's output diagnostics.
2570Sstevel@tonic-gate */
2580Sstevel@tonic-gate return (MSG_INTL(MSG_STR_UNKNOWN));
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate return (strs + name);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate /*
2641618Srie * Relocations can reference section symbols and standard symbols. If the
2651618Srie * former, establish the section name.
2661618Srie */
2671618Srie static const char *
relsymname(Cache * cache,Cache * csec,Cache * strsec,Word symndx,Word symnum,Word relndx,Sym * syms,char * secstr,size_t secsz,const char * file)2681618Srie relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum,
2697463SRod.Evans@Sun.COM Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file)
2701618Srie {
2717463SRod.Evans@Sun.COM Sym *sym;
2727463SRod.Evans@Sun.COM const char *name;
2731618Srie
2741618Srie if (symndx >= symnum) {
2751618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX),
2761618Srie file, EC_WORD(symndx), EC_WORD(relndx));
2771618Srie return (MSG_INTL(MSG_STR_UNKNOWN));
2781618Srie }
2791618Srie
2801618Srie sym = (Sym *)(syms + symndx);
2817463SRod.Evans@Sun.COM name = string(csec, symndx, strsec, file, sym->st_name);
2821618Srie
2831618Srie /*
2841618Srie * If the symbol represents a section offset construct an appropriate
2857463SRod.Evans@Sun.COM * string. Note, although section symbol table entries typically have
2867463SRod.Evans@Sun.COM * a NULL name pointer, entries do exist that point into the string
2877463SRod.Evans@Sun.COM * table to their own NULL strings.
2881618Srie */
2897463SRod.Evans@Sun.COM if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) &&
2907463SRod.Evans@Sun.COM ((sym->st_name == 0) || (*name == '\0'))) {
2917463SRod.Evans@Sun.COM (void) snprintf(secstr, secsz, MSG_INTL(MSG_STR_SECTION),
2927463SRod.Evans@Sun.COM cache[sym->st_shndx].c_name);
2931618Srie return ((const char *)secstr);
2941618Srie }
2951618Srie
2967463SRod.Evans@Sun.COM return (name);
2971618Srie }
2981618Srie
2991618Srie /*
3001618Srie * Focal point for establishing a string table section. Data such as the
3011618Srie * dynamic information simply points to a string table. Data such as
3021618Srie * relocations, reference a symbol table, which in turn is associated with a
3031618Srie * string table.
3040Sstevel@tonic-gate */
3050Sstevel@tonic-gate static int
stringtbl(Cache * cache,int symtab,Word ndx,Word shnum,const char * file,Word * symnum,Cache ** symsec,Cache ** strsec)3061618Srie stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file,
3071618Srie Word *symnum, Cache **symsec, Cache **strsec)
3081618Srie {
3091618Srie Shdr *shdr = cache[ndx].c_shdr;
3101618Srie
3111618Srie if (symtab) {
3121618Srie /*
3131618Srie * Validate the symbol table section.
3141618Srie */
3151618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
3161618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
3171618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link));
3181618Srie return (0);
3191618Srie }
3203466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
3213466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
3223466Srie file, cache[ndx].c_name);
3233466Srie return (0);
3243466Srie }
3251618Srie
3261618Srie /*
3271618Srie * Obtain, and verify the symbol table data.
3281618Srie */
3293466Srie if ((cache[ndx].c_data == NULL) ||
3303466Srie (cache[ndx].c_data->d_buf == NULL)) {
3311618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
3321618Srie file, cache[ndx].c_name);
3331618Srie return (0);
3341618Srie }
3351618Srie
3361618Srie /*
3371618Srie * Establish the string table index.
3381618Srie */
3391618Srie ndx = shdr->sh_link;
3401618Srie shdr = cache[ndx].c_shdr;
3411618Srie
3421618Srie /*
3431618Srie * Return symbol table information.
3441618Srie */
3451618Srie if (symnum)
3461618Srie *symnum = (shdr->sh_size / shdr->sh_entsize);
3471618Srie if (symsec)
3481618Srie *symsec = &cache[ndx];
3491618Srie }
3501618Srie
3511618Srie /*
3521618Srie * Validate the associated string table section.
3531618Srie */
3541618Srie if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
3551618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
3561618Srie file, cache[ndx].c_name, EC_WORD(shdr->sh_link));
3571618Srie return (0);
3581618Srie }
3591618Srie
3601618Srie if (strsec)
3611618Srie *strsec = &cache[shdr->sh_link];
3621618Srie
3631618Srie return (1);
3641618Srie }
3651618Srie
3661618Srie /*
3671618Srie * Lookup a symbol and set Sym accordingly.
36811687SAli.Bahrami@Sun.COM *
36911687SAli.Bahrami@Sun.COM * entry:
37011687SAli.Bahrami@Sun.COM * name - Name of symbol to lookup
37111687SAli.Bahrami@Sun.COM * cache - Cache of all section headers
37211687SAli.Bahrami@Sun.COM * shnum - # of sections in cache
37311687SAli.Bahrami@Sun.COM * sym - Address of pointer to receive symbol
37411687SAli.Bahrami@Sun.COM * target - NULL, or section to which the symbol must be associated.
37511687SAli.Bahrami@Sun.COM * symtab - Symbol table to search for symbol
37611687SAli.Bahrami@Sun.COM * file - Name of file
37711687SAli.Bahrami@Sun.COM *
37811687SAli.Bahrami@Sun.COM * exit:
37911687SAli.Bahrami@Sun.COM * If the symbol is found, *sym is set to reference it, and True is
38011687SAli.Bahrami@Sun.COM * returned. If target is non-NULL, the symbol must reference the given
38111687SAli.Bahrami@Sun.COM * section --- otherwise the section is not checked.
38211687SAli.Bahrami@Sun.COM *
38311687SAli.Bahrami@Sun.COM * If no symbol is found, False is returned.
3841618Srie */
3851618Srie static int
symlookup(const char * name,Cache * cache,Word shnum,Sym ** sym,Cache * target,Cache * symtab,const char * file)3861618Srie symlookup(const char *name, Cache *cache, Word shnum, Sym **sym,
38711687SAli.Bahrami@Sun.COM Cache *target, Cache *symtab, const char *file)
3880Sstevel@tonic-gate {
3891618Srie Shdr *shdr;
3901618Srie Word symn, cnt;
3911618Srie Sym *syms;
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate if (symtab == 0)
3940Sstevel@tonic-gate return (0);
3950Sstevel@tonic-gate
3961618Srie shdr = symtab->c_shdr;
3971618Srie
3980Sstevel@tonic-gate /*
3990Sstevel@tonic-gate * Determine the symbol data and number.
4000Sstevel@tonic-gate */
4010Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
4020Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
4030Sstevel@tonic-gate file, symtab->c_name);
4040Sstevel@tonic-gate return (0);
4050Sstevel@tonic-gate }
4063466Srie if (symtab->c_data == NULL)
4073466Srie return (0);
4083466Srie
4090Sstevel@tonic-gate /* LINTED */
4101618Srie symn = (Word)(shdr->sh_size / shdr->sh_entsize);
4111618Srie syms = (Sym *)symtab->c_data->d_buf;
4120Sstevel@tonic-gate
4130Sstevel@tonic-gate /*
4140Sstevel@tonic-gate * Get the associated string table section.
4150Sstevel@tonic-gate */
4160Sstevel@tonic-gate if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
4170Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
4181618Srie file, symtab->c_name, EC_WORD(shdr->sh_link));
4190Sstevel@tonic-gate return (0);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate /*
4230Sstevel@tonic-gate * Loop through the symbol table to find a match.
4240Sstevel@tonic-gate */
42511687SAli.Bahrami@Sun.COM *sym = NULL;
4261618Srie for (cnt = 0; cnt < symn; syms++, cnt++) {
4271618Srie const char *symname;
4280Sstevel@tonic-gate
4291618Srie symname = string(symtab, cnt, &cache[shdr->sh_link], file,
4301618Srie syms->st_name);
4310Sstevel@tonic-gate
43211687SAli.Bahrami@Sun.COM if (symname && (strcmp(name, symname) == 0) &&
43311687SAli.Bahrami@Sun.COM ((target == NULL) || (target->c_ndx == syms->st_shndx))) {
43411687SAli.Bahrami@Sun.COM /*
43511687SAli.Bahrami@Sun.COM * It is possible, though rare, for a local and
43611687SAli.Bahrami@Sun.COM * global symbol of the same name to exist, each
43711687SAli.Bahrami@Sun.COM * contributed by a different input object. If the
43811687SAli.Bahrami@Sun.COM * symbol just found is local, remember it, but
43911687SAli.Bahrami@Sun.COM * continue looking.
44011687SAli.Bahrami@Sun.COM */
4411618Srie *sym = syms;
44211687SAli.Bahrami@Sun.COM if (ELF_ST_BIND(syms->st_info) != STB_LOCAL)
44311687SAli.Bahrami@Sun.COM break;
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate }
44611687SAli.Bahrami@Sun.COM
44711687SAli.Bahrami@Sun.COM return (*sym != NULL);
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate * Print section headers.
4520Sstevel@tonic-gate */
4530Sstevel@tonic-gate static void
sections(const char * file,Cache * cache,Word shnum,Ehdr * ehdr,uchar_t osabi)4549273SAli.Bahrami@Sun.COM sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi)
4550Sstevel@tonic-gate {
4561618Srie size_t seccnt;
4570Sstevel@tonic-gate
4581618Srie for (seccnt = 1; seccnt < shnum; seccnt++) {
4591618Srie Cache *_cache = &cache[seccnt];
4601618Srie Shdr *shdr = _cache->c_shdr;
4611618Srie const char *secname = _cache->c_name;
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate /*
4640Sstevel@tonic-gate * Although numerous section header entries can be zero, it's
4653862Srie * usually a sign of trouble if the type is zero.
4660Sstevel@tonic-gate */
4670Sstevel@tonic-gate if (shdr->sh_type == 0) {
4680Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE),
4691618Srie file, secname, EC_WORD(shdr->sh_type));
4700Sstevel@tonic-gate }
4713862Srie
4725411Sab196087 if (!match(MATCH_F_ALL, secname, seccnt, shdr->sh_type))
4733862Srie continue;
4740Sstevel@tonic-gate
4751324Srie /*
4761324Srie * Identify any sections that are suspicious. A .got section
4771324Srie * shouldn't exist in a relocatable object.
4781324Srie */
4791324Srie if (ehdr->e_type == ET_REL) {
4801618Srie if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT),
4811324Srie MSG_ELF_GOT_SIZE) == 0) {
4821324Srie (void) fprintf(stderr,
4831618Srie MSG_INTL(MSG_GOT_UNEXPECTED), file,
4841618Srie secname);
4851324Srie }
4861324Srie }
4871324Srie
4881618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
4891618Srie dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname);
4909273SAli.Bahrami@Sun.COM Elf_shdr(0, osabi, ehdr->e_machine, shdr);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate
4941618Srie /*
4951618Srie * Obtain a specified Phdr entry.
4961618Srie */
4971618Srie static Phdr *
getphdr(Word phnum,Word * type_arr,Word type_cnt,const char * file,Elf * elf)4989085SAli.Bahrami@Sun.COM getphdr(Word phnum, Word *type_arr, Word type_cnt, const char *file, Elf *elf)
4991618Srie {
5009085SAli.Bahrami@Sun.COM Word cnt, tcnt;
5011618Srie Phdr *phdr;
5021618Srie
5031618Srie if ((phdr = elf_getphdr(elf)) == NULL) {
5041618Srie failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
5059085SAli.Bahrami@Sun.COM return (NULL);
5061618Srie }
5071618Srie
5081618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) {
5099085SAli.Bahrami@Sun.COM for (tcnt = 0; tcnt < type_cnt; tcnt++) {
5109085SAli.Bahrami@Sun.COM if (phdr->p_type == type_arr[tcnt])
5119085SAli.Bahrami@Sun.COM return (phdr);
5129085SAli.Bahrami@Sun.COM }
5131618Srie }
5149085SAli.Bahrami@Sun.COM return (NULL);
5151618Srie }
5161618Srie
5179406SAli.Bahrami@Sun.COM /*
5189406SAli.Bahrami@Sun.COM * Display the contents of GNU/amd64 .eh_frame and .eh_frame_hdr
5199406SAli.Bahrami@Sun.COM * sections.
5209406SAli.Bahrami@Sun.COM *
5219406SAli.Bahrami@Sun.COM * entry:
5229406SAli.Bahrami@Sun.COM * cache - Cache of all section headers
5239406SAli.Bahrami@Sun.COM * shndx - Index of .eh_frame or .eh_frame_hdr section to be displayed
5249406SAli.Bahrami@Sun.COM * uphdr - NULL, or unwind program header associated with
5259406SAli.Bahrami@Sun.COM * the .eh_frame_hdr section.
5269406SAli.Bahrami@Sun.COM * ehdr - ELF header for file
5279406SAli.Bahrami@Sun.COM * eh_state - Data used across calls to this routine. The
5289406SAli.Bahrami@Sun.COM * caller should zero it before the first call, and
5299406SAli.Bahrami@Sun.COM * pass it on every call.
5309406SAli.Bahrami@Sun.COM * osabi - OSABI to use in displaying information
5319406SAli.Bahrami@Sun.COM * file - Name of file
5329406SAli.Bahrami@Sun.COM * flags - Command line option flags
5339406SAli.Bahrami@Sun.COM */
5340Sstevel@tonic-gate static void
unwind_eh_frame(Cache * cache,Word shndx,Phdr * uphdr,Ehdr * ehdr,gnu_eh_state_t * eh_state,uchar_t osabi,const char * file,uint_t flags)5359406SAli.Bahrami@Sun.COM unwind_eh_frame(Cache *cache, Word shndx, Phdr *uphdr, Ehdr *ehdr,
5369406SAli.Bahrami@Sun.COM gnu_eh_state_t *eh_state, uchar_t osabi, const char *file, uint_t flags)
5370Sstevel@tonic-gate {
5389085SAli.Bahrami@Sun.COM #if defined(_ELF64)
5399085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_64
5409085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_64
5419085SAli.Bahrami@Sun.COM #else
5429085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTAB2 MSG_UNW_BINSRTAB2_32
5439085SAli.Bahrami@Sun.COM #define MSG_UNW_BINSRTABENT MSG_UNW_BINSRTABENT_32
5449085SAli.Bahrami@Sun.COM #endif
5459085SAli.Bahrami@Sun.COM
5469406SAli.Bahrami@Sun.COM Cache *_cache = &cache[shndx];
5479406SAli.Bahrami@Sun.COM Shdr *shdr = _cache->c_shdr;
5489406SAli.Bahrami@Sun.COM uchar_t *data = (uchar_t *)(_cache->c_data->d_buf);
5499406SAli.Bahrami@Sun.COM size_t datasize = _cache->c_data->d_size;
5509406SAli.Bahrami@Sun.COM Conv_dwarf_ehe_buf_t dwarf_ehe_buf;
5519406SAli.Bahrami@Sun.COM uint64_t ndx, frame_ptr, fde_cnt, tabndx;
5529406SAli.Bahrami@Sun.COM uint_t vers, frame_ptr_enc, fde_cnt_enc, table_enc;
5539406SAli.Bahrami@Sun.COM uint64_t initloc, initloc0;
5549406SAli.Bahrami@Sun.COM
5559406SAli.Bahrami@Sun.COM
5569406SAli.Bahrami@Sun.COM /*
5579406SAli.Bahrami@Sun.COM * Is this a .eh_frame_hdr?
5589406SAli.Bahrami@Sun.COM */
5599406SAli.Bahrami@Sun.COM if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) ||
5609406SAli.Bahrami@Sun.COM (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR),
5619406SAli.Bahrami@Sun.COM MSG_SCN_FRMHDR_SIZE) == 0)) {
5629406SAli.Bahrami@Sun.COM /*
5639406SAli.Bahrami@Sun.COM * There can only be a single .eh_frame_hdr.
5649406SAli.Bahrami@Sun.COM * Flag duplicates.
5659406SAli.Bahrami@Sun.COM */
5669406SAli.Bahrami@Sun.COM if (++eh_state->hdr_cnt > 1)
5679406SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_MULTEHFRMHDR),
5689406SAli.Bahrami@Sun.COM file, EC_WORD(shndx), _cache->c_name);
5699406SAli.Bahrami@Sun.COM
5709406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR));
5719406SAli.Bahrami@Sun.COM ndx = 0;
5729406SAli.Bahrami@Sun.COM
5739406SAli.Bahrami@Sun.COM vers = data[ndx++];
5749406SAli.Bahrami@Sun.COM frame_ptr_enc = data[ndx++];
5759406SAli.Bahrami@Sun.COM fde_cnt_enc = data[ndx++];
5769406SAli.Bahrami@Sun.COM table_enc = data[ndx++];
5779406SAli.Bahrami@Sun.COM
5789406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers);
5799406SAli.Bahrami@Sun.COM
5809406SAli.Bahrami@Sun.COM frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc,
5819406SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx);
5829406SAli.Bahrami@Sun.COM if (eh_state->hdr_cnt == 1) {
5839406SAli.Bahrami@Sun.COM eh_state->hdr_ndx = shndx;
5849406SAli.Bahrami@Sun.COM eh_state->frame_ptr = frame_ptr;
5859406SAli.Bahrami@Sun.COM }
5869406SAli.Bahrami@Sun.COM
5879406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC),
5889406SAli.Bahrami@Sun.COM conv_dwarf_ehe(frame_ptr_enc, &dwarf_ehe_buf),
5899406SAli.Bahrami@Sun.COM EC_XWORD(frame_ptr));
5909406SAli.Bahrami@Sun.COM
5919406SAli.Bahrami@Sun.COM fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc,
5929406SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx);
5939406SAli.Bahrami@Sun.COM
5949406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC),
5959406SAli.Bahrami@Sun.COM conv_dwarf_ehe(fde_cnt_enc, &dwarf_ehe_buf),
5969406SAli.Bahrami@Sun.COM EC_XWORD(fde_cnt));
5979406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_TABENC),
5989406SAli.Bahrami@Sun.COM conv_dwarf_ehe(table_enc, &dwarf_ehe_buf));
5999406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1));
6009406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2));
6019406SAli.Bahrami@Sun.COM
6029406SAli.Bahrami@Sun.COM for (tabndx = 0; tabndx < fde_cnt; tabndx++) {
6039406SAli.Bahrami@Sun.COM initloc = dwarf_ehe_extract(data, &ndx, table_enc,
6049406SAli.Bahrami@Sun.COM ehdr->e_ident, shdr->sh_addr, ndx);
6059406SAli.Bahrami@Sun.COM /*LINTED:E_VAR_USED_BEFORE_SET*/
6069406SAli.Bahrami@Sun.COM if ((tabndx != 0) && (initloc0 > initloc))
6079615SAli.Bahrami@Sun.COM (void) fprintf(stderr,
6089615SAli.Bahrami@Sun.COM MSG_INTL(MSG_ERR_BADSORT), file,
6099615SAli.Bahrami@Sun.COM _cache->c_name, EC_WORD(tabndx));
6109406SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT),
6119406SAli.Bahrami@Sun.COM EC_XWORD(initloc),
6129406SAli.Bahrami@Sun.COM EC_XWORD(dwarf_ehe_extract(data, &ndx,
6139406SAli.Bahrami@Sun.COM table_enc, ehdr->e_ident, shdr->sh_addr,
6149406SAli.Bahrami@Sun.COM ndx)));
6159406SAli.Bahrami@Sun.COM initloc0 = initloc;
6169406SAli.Bahrami@Sun.COM }
6179406SAli.Bahrami@Sun.COM } else { /* Display the .eh_frame section */
6189406SAli.Bahrami@Sun.COM eh_state->frame_cnt++;
6199406SAli.Bahrami@Sun.COM if (eh_state->frame_cnt == 1) {
6209406SAli.Bahrami@Sun.COM eh_state->frame_ndx = shndx;
6219406SAli.Bahrami@Sun.COM eh_state->frame_base = shdr->sh_addr;
6229406SAli.Bahrami@Sun.COM } else if ((eh_state->frame_cnt > 1) &&
6239406SAli.Bahrami@Sun.COM (ehdr->e_type != ET_REL)) {
6249406SAli.Bahrami@Sun.COM Conv_inv_buf_t inv_buf;
6259406SAli.Bahrami@Sun.COM
6269406SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_WARN_MULTEHFRM),
6279406SAli.Bahrami@Sun.COM file, EC_WORD(shndx), _cache->c_name,
6289406SAli.Bahrami@Sun.COM conv_ehdr_type(osabi, ehdr->e_type, 0, &inv_buf));
6299406SAli.Bahrami@Sun.COM }
6309406SAli.Bahrami@Sun.COM dump_eh_frame(data, datasize, shdr->sh_addr,
6319406SAli.Bahrami@Sun.COM ehdr->e_machine, ehdr->e_ident);
6329406SAli.Bahrami@Sun.COM }
6339406SAli.Bahrami@Sun.COM
6349406SAli.Bahrami@Sun.COM /*
6359406SAli.Bahrami@Sun.COM * If we've seen the .eh_frame_hdr and the first .eh_frame section,
6369406SAli.Bahrami@Sun.COM * compare the header frame_ptr to the address of the actual frame
6379406SAli.Bahrami@Sun.COM * section to ensure the link-editor got this right. Note, this
6389406SAli.Bahrami@Sun.COM * diagnostic is only produced when unwind information is explicitly
6399406SAli.Bahrami@Sun.COM * asked for, as shared objects built with an older ld(1) may reveal
6409406SAli.Bahrami@Sun.COM * this inconsistency. Although an inconsistency, it doesn't seem to
6419406SAli.Bahrami@Sun.COM * have any adverse effect on existing tools.
6429406SAli.Bahrami@Sun.COM */
6439406SAli.Bahrami@Sun.COM if (((flags & FLG_MASK_SHOW) != FLG_MASK_SHOW) &&
6449406SAli.Bahrami@Sun.COM (eh_state->hdr_cnt > 0) && (eh_state->frame_cnt > 0) &&
6459406SAli.Bahrami@Sun.COM (eh_state->frame_ptr != eh_state->frame_base))
6469406SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADEHFRMPTR),
6479406SAli.Bahrami@Sun.COM file, EC_WORD(eh_state->hdr_ndx),
6489406SAli.Bahrami@Sun.COM cache[eh_state->hdr_ndx].c_name,
6499406SAli.Bahrami@Sun.COM EC_XWORD(eh_state->frame_ptr),
6509406SAli.Bahrami@Sun.COM EC_WORD(eh_state->frame_ndx),
6519406SAli.Bahrami@Sun.COM cache[eh_state->frame_ndx].c_name,
6529406SAli.Bahrami@Sun.COM EC_XWORD(eh_state->frame_base));
6539406SAli.Bahrami@Sun.COM #undef MSG_UNW_BINSRTAB2
6549406SAli.Bahrami@Sun.COM #undef MSG_UNW_BINSRTABENT
6559406SAli.Bahrami@Sun.COM }
6569406SAli.Bahrami@Sun.COM
6579406SAli.Bahrami@Sun.COM /*
6589406SAli.Bahrami@Sun.COM * Convert a self relative pointer into an address. A self relative
6599406SAli.Bahrami@Sun.COM * pointer adds the address where the pointer resides to the offset
6609406SAli.Bahrami@Sun.COM * contained in the pointer. The benefit is that the value of the
6619406SAli.Bahrami@Sun.COM * pointer does not require relocation.
6629406SAli.Bahrami@Sun.COM *
6639406SAli.Bahrami@Sun.COM * entry:
6649406SAli.Bahrami@Sun.COM * base_addr - Address of the pointer.
6659406SAli.Bahrami@Sun.COM * delta - Offset relative to base_addr giving desired address
6669406SAli.Bahrami@Sun.COM *
6679406SAli.Bahrami@Sun.COM * exit:
6689406SAli.Bahrami@Sun.COM * The computed address is returned.
6699406SAli.Bahrami@Sun.COM *
6709406SAli.Bahrami@Sun.COM * note:
6719406SAli.Bahrami@Sun.COM * base_addr is an unsigned value, while ret_addr is signed. This routine
6729406SAli.Bahrami@Sun.COM * used explicit testing and casting to explicitly control type
6739406SAli.Bahrami@Sun.COM * conversion, and ensure that we handle the maximum possible range.
6749406SAli.Bahrami@Sun.COM */
6759406SAli.Bahrami@Sun.COM static Addr
srelptr(Addr base_addr,PTRDIFF_T delta)6769406SAli.Bahrami@Sun.COM srelptr(Addr base_addr, PTRDIFF_T delta)
6779406SAli.Bahrami@Sun.COM {
6789406SAli.Bahrami@Sun.COM if (delta < 0)
6799406SAli.Bahrami@Sun.COM return (base_addr - (Addr) (-delta));
6809406SAli.Bahrami@Sun.COM
6819406SAli.Bahrami@Sun.COM return (base_addr + (Addr) delta);
6829406SAli.Bahrami@Sun.COM }
6839406SAli.Bahrami@Sun.COM
6849406SAli.Bahrami@Sun.COM /*
6859406SAli.Bahrami@Sun.COM * Byte swap a PTRDIFF_T value.
6869406SAli.Bahrami@Sun.COM */
6879406SAli.Bahrami@Sun.COM static PTRDIFF_T
swap_ptrdiff(PTRDIFF_T value)6889406SAli.Bahrami@Sun.COM swap_ptrdiff(PTRDIFF_T value)
6899406SAli.Bahrami@Sun.COM {
6909406SAli.Bahrami@Sun.COM PTRDIFF_T r;
6919406SAli.Bahrami@Sun.COM uchar_t *dst = (uchar_t *)&r;
6929406SAli.Bahrami@Sun.COM uchar_t *src = (uchar_t *)&value;
6939406SAli.Bahrami@Sun.COM
6949406SAli.Bahrami@Sun.COM UL_ASSIGN_BSWAP_XWORD(dst, src);
6959406SAli.Bahrami@Sun.COM return (r);
6969406SAli.Bahrami@Sun.COM }
6979406SAli.Bahrami@Sun.COM
6989406SAli.Bahrami@Sun.COM /*
6999406SAli.Bahrami@Sun.COM * Display exception_range_entry items from the .exception_ranges section
7009406SAli.Bahrami@Sun.COM * of a Sun C++ object.
7019406SAli.Bahrami@Sun.COM */
7029406SAli.Bahrami@Sun.COM static void
unwind_exception_ranges(Cache * _cache,const char * file,int do_swap)7039406SAli.Bahrami@Sun.COM unwind_exception_ranges(Cache *_cache, const char *file, int do_swap)
7049406SAli.Bahrami@Sun.COM {
7059406SAli.Bahrami@Sun.COM /*
7069406SAli.Bahrami@Sun.COM * Translate a PTRDIFF_T self-relative address field of
7079406SAli.Bahrami@Sun.COM * an exception_range_entry struct into an address.
7089406SAli.Bahrami@Sun.COM *
7099406SAli.Bahrami@Sun.COM * entry:
7109406SAli.Bahrami@Sun.COM * exc_addr - Address of base of exception_range_entry struct
7119406SAli.Bahrami@Sun.COM * cur_ent - Pointer to data in the struct to be translated
7129406SAli.Bahrami@Sun.COM *
7139406SAli.Bahrami@Sun.COM * _f - Field of struct to be translated
7149406SAli.Bahrami@Sun.COM */
7159406SAli.Bahrami@Sun.COM #define SRELPTR(_f) \
7169406SAli.Bahrami@Sun.COM srelptr(exc_addr + offsetof(exception_range_entry, _f), cur_ent->_f)
7179406SAli.Bahrami@Sun.COM
7189406SAli.Bahrami@Sun.COM #if defined(_ELF64)
7199406SAli.Bahrami@Sun.COM #define MSG_EXR_TITLE MSG_EXR_TITLE_64
7209406SAli.Bahrami@Sun.COM #define MSG_EXR_ENTRY MSG_EXR_ENTRY_64
7219406SAli.Bahrami@Sun.COM #else
7229406SAli.Bahrami@Sun.COM #define MSG_EXR_TITLE MSG_EXR_TITLE_32
7239406SAli.Bahrami@Sun.COM #define MSG_EXR_ENTRY MSG_EXR_ENTRY_32
7249406SAli.Bahrami@Sun.COM #endif
7259406SAli.Bahrami@Sun.COM
7269406SAli.Bahrami@Sun.COM exception_range_entry scratch, *ent, *cur_ent = &scratch;
7279406SAli.Bahrami@Sun.COM char index[MAXNDXSIZE];
7289406SAli.Bahrami@Sun.COM Word i, nelts;
7299406SAli.Bahrami@Sun.COM Addr addr, addr0, offset = 0;
7309406SAli.Bahrami@Sun.COM Addr exc_addr = _cache->c_shdr->sh_addr;
7319406SAli.Bahrami@Sun.COM
7329406SAli.Bahrami@Sun.COM dbg_print(0, MSG_INTL(MSG_EXR_TITLE));
7339406SAli.Bahrami@Sun.COM ent = (exception_range_entry *)(_cache->c_data->d_buf);
7349406SAli.Bahrami@Sun.COM nelts = _cache->c_data->d_size / sizeof (exception_range_entry);
7359406SAli.Bahrami@Sun.COM
7369406SAli.Bahrami@Sun.COM for (i = 0; i < nelts; i++, ent++) {
7379406SAli.Bahrami@Sun.COM if (do_swap) {
7389406SAli.Bahrami@Sun.COM /*
7399406SAli.Bahrami@Sun.COM * Copy byte swapped values into the scratch buffer.
7409406SAli.Bahrami@Sun.COM * The reserved field is not used, so we skip it.
7419406SAli.Bahrami@Sun.COM */
7429406SAli.Bahrami@Sun.COM scratch.ret_addr = swap_ptrdiff(ent->ret_addr);
7439406SAli.Bahrami@Sun.COM scratch.length = BSWAP_XWORD(ent->length);
7449406SAli.Bahrami@Sun.COM scratch.handler_addr = swap_ptrdiff(ent->handler_addr);
7459406SAli.Bahrami@Sun.COM scratch.type_block = swap_ptrdiff(ent->type_block);
7469406SAli.Bahrami@Sun.COM } else {
7479406SAli.Bahrami@Sun.COM cur_ent = ent;
7489406SAli.Bahrami@Sun.COM }
7499406SAli.Bahrami@Sun.COM
7509406SAli.Bahrami@Sun.COM /*
7519406SAli.Bahrami@Sun.COM * The table is required to be sorted by the address
7529406SAli.Bahrami@Sun.COM * derived from ret_addr, to allow binary searching. Ensure
7539406SAli.Bahrami@Sun.COM * that addresses grow monotonically.
7549406SAli.Bahrami@Sun.COM */
7559406SAli.Bahrami@Sun.COM addr = SRELPTR(ret_addr);
7569406SAli.Bahrami@Sun.COM /*LINTED:E_VAR_USED_BEFORE_SET*/
7579406SAli.Bahrami@Sun.COM if ((i != 0) && (addr0 > addr))
7589615SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORT),
7599406SAli.Bahrami@Sun.COM file, _cache->c_name, EC_WORD(i));
7609406SAli.Bahrami@Sun.COM
7619406SAli.Bahrami@Sun.COM (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX),
7629406SAli.Bahrami@Sun.COM EC_XWORD(i));
7639406SAli.Bahrami@Sun.COM dbg_print(0, MSG_INTL(MSG_EXR_ENTRY), index, EC_ADDR(offset),
7649406SAli.Bahrami@Sun.COM EC_ADDR(addr), EC_ADDR(cur_ent->length),
7659406SAli.Bahrami@Sun.COM EC_ADDR(SRELPTR(handler_addr)),
7669406SAli.Bahrami@Sun.COM EC_ADDR(SRELPTR(type_block)));
7679406SAli.Bahrami@Sun.COM
7689406SAli.Bahrami@Sun.COM addr0 = addr;
7699406SAli.Bahrami@Sun.COM exc_addr += sizeof (exception_range_entry);
7709406SAli.Bahrami@Sun.COM offset += sizeof (exception_range_entry);
7719406SAli.Bahrami@Sun.COM }
7729406SAli.Bahrami@Sun.COM
7739406SAli.Bahrami@Sun.COM #undef SRELPTR
7749406SAli.Bahrami@Sun.COM #undef MSG_EXR_TITLE
7759406SAli.Bahrami@Sun.COM #undef MSG_EXR_ENTRY
7769406SAli.Bahrami@Sun.COM }
7779406SAli.Bahrami@Sun.COM
7789406SAli.Bahrami@Sun.COM /*
7799406SAli.Bahrami@Sun.COM * Display information from unwind/exception sections:
7809406SAli.Bahrami@Sun.COM *
7819406SAli.Bahrami@Sun.COM * - GNU/amd64 .eh_frame and .eh_frame_hdr
7829406SAli.Bahrami@Sun.COM * - Sun C++ .exception_ranges
7839406SAli.Bahrami@Sun.COM *
7849406SAli.Bahrami@Sun.COM */
7859406SAli.Bahrami@Sun.COM static void
unwind(Cache * cache,Word shnum,Word phnum,Ehdr * ehdr,uchar_t osabi,const char * file,Elf * elf,uint_t flags)7869406SAli.Bahrami@Sun.COM unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, uchar_t osabi,
7879406SAli.Bahrami@Sun.COM const char *file, Elf *elf, uint_t flags)
7889406SAli.Bahrami@Sun.COM {
7899085SAli.Bahrami@Sun.COM static Word phdr_types[] = { PT_SUNW_UNWIND, PT_SUNW_EH_FRAME };
7909085SAli.Bahrami@Sun.COM
7919085SAli.Bahrami@Sun.COM Word cnt;
7929085SAli.Bahrami@Sun.COM Phdr *uphdr = NULL;
7939406SAli.Bahrami@Sun.COM gnu_eh_state_t eh_state;
7941618Srie
7950Sstevel@tonic-gate /*
7969085SAli.Bahrami@Sun.COM * Historical background: .eh_frame and .eh_frame_hdr sections
7979085SAli.Bahrami@Sun.COM * come from the GNU compilers (particularly C++), and are used
7989085SAli.Bahrami@Sun.COM * under all architectures. Their format is based on DWARF. When
7999085SAli.Bahrami@Sun.COM * the amd64 ABI was defined, these sections were adopted wholesale
8009085SAli.Bahrami@Sun.COM * from the existing practice.
8019085SAli.Bahrami@Sun.COM *
8029085SAli.Bahrami@Sun.COM * When amd64 support was added to Solaris, support for these
8039085SAli.Bahrami@Sun.COM * sections was added, using the SHT_AMD64_UNWIND section type
8049085SAli.Bahrami@Sun.COM * to identify them. At first, we ignored them in objects for
8059085SAli.Bahrami@Sun.COM * non-amd64 targets, but later broadened our support to include
8069085SAli.Bahrami@Sun.COM * other architectures in order to better support gcc-generated
8079085SAli.Bahrami@Sun.COM * objects.
8089085SAli.Bahrami@Sun.COM *
8099406SAli.Bahrami@Sun.COM * .exception_ranges implement the same basic concepts, but
8109406SAli.Bahrami@Sun.COM * were invented at Sun for the Sun C++ compiler.
8119406SAli.Bahrami@Sun.COM *
8129085SAli.Bahrami@Sun.COM * We match these sections by name, rather than section type,
8139085SAli.Bahrami@Sun.COM * because they can come in as either SHT_AMD64_UNWIND, or as
8149406SAli.Bahrami@Sun.COM * SHT_PROGBITS, and because the type isn't enough to determine
81511827SRod.Evans@Sun.COM * how they should be interpreted.
8160Sstevel@tonic-gate */
8179406SAli.Bahrami@Sun.COM /* Find the program header for .eh_frame_hdr if present */
8181618Srie if (phnum)
8199085SAli.Bahrami@Sun.COM uphdr = getphdr(phnum, phdr_types,
8209085SAli.Bahrami@Sun.COM sizeof (phdr_types) / sizeof (*phdr_types), file, elf);
8210Sstevel@tonic-gate
8229406SAli.Bahrami@Sun.COM /*
8239406SAli.Bahrami@Sun.COM * eh_state is used to retain data used by unwind_eh_frame()
82411827SRod.Evans@Sun.COM * across calls.
8259406SAli.Bahrami@Sun.COM */
8269406SAli.Bahrami@Sun.COM bzero(&eh_state, sizeof (eh_state));
8279406SAli.Bahrami@Sun.COM
8280Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
8291618Srie Cache *_cache = &cache[cnt];
8301618Srie Shdr *shdr = _cache->c_shdr;
8319406SAli.Bahrami@Sun.COM int is_exrange;
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate /*
8349406SAli.Bahrami@Sun.COM * Skip sections of the wrong type. On amd64, they
8359406SAli.Bahrami@Sun.COM * can be SHT_AMD64_UNWIND. On all platforms, they
8369406SAli.Bahrami@Sun.COM * can be SHT_PROGBITS (including amd64, if using
8379406SAli.Bahrami@Sun.COM * the GNU compilers).
8389273SAli.Bahrami@Sun.COM *
8399273SAli.Bahrami@Sun.COM * Skip anything other than these two types. The name
8409273SAli.Bahrami@Sun.COM * test below will thin out the SHT_PROGBITS that don't apply.
8410Sstevel@tonic-gate */
8429273SAli.Bahrami@Sun.COM if ((shdr->sh_type != SHT_PROGBITS) &&
8439273SAli.Bahrami@Sun.COM (shdr->sh_type != SHT_AMD64_UNWIND))
8449085SAli.Bahrami@Sun.COM continue;
8459085SAli.Bahrami@Sun.COM
8469085SAli.Bahrami@Sun.COM /*
8479406SAli.Bahrami@Sun.COM * Only sections with certain well known names are of interest.
8489406SAli.Bahrami@Sun.COM * These are:
8499406SAli.Bahrami@Sun.COM *
8509406SAli.Bahrami@Sun.COM * .eh_frame - amd64/GNU-compiler unwind sections
8519406SAli.Bahrami@Sun.COM * .eh_frame_hdr - Sorted table referencing .eh_frame
8529406SAli.Bahrami@Sun.COM * .exception_ranges - Sun C++ unwind sections
8539406SAli.Bahrami@Sun.COM *
8549406SAli.Bahrami@Sun.COM * We do a prefix comparison, allowing for naming conventions
8559406SAli.Bahrami@Sun.COM * like .eh_frame.foo, hence the use of strncmp() rather than
8569406SAli.Bahrami@Sun.COM * strcmp(). This means that we only really need to test for
8579406SAli.Bahrami@Sun.COM * .eh_frame, as it's a prefix of .eh_frame_hdr.
8589085SAli.Bahrami@Sun.COM */
8599406SAli.Bahrami@Sun.COM is_exrange = strncmp(_cache->c_name,
8609406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_SCN_EXRANGE), MSG_SCN_EXRANGE_SIZE) == 0;
8619406SAli.Bahrami@Sun.COM if ((strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM),
8629406SAli.Bahrami@Sun.COM MSG_SCN_FRM_SIZE) != 0) && !is_exrange)
8630Sstevel@tonic-gate continue;
8644168Sab196087
8655411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type))
8660Sstevel@tonic-gate continue;
8670Sstevel@tonic-gate
8683466Srie if (_cache->c_data == NULL)
8693466Srie continue;
8703466Srie
8711618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
8721618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name);
8730Sstevel@tonic-gate
8749406SAli.Bahrami@Sun.COM if (is_exrange)
8759406SAli.Bahrami@Sun.COM unwind_exception_ranges(_cache, file,
8769406SAli.Bahrami@Sun.COM _elf_sys_encoding() != ehdr->e_ident[EI_DATA]);
8779406SAli.Bahrami@Sun.COM else
8789406SAli.Bahrami@Sun.COM unwind_eh_frame(cache, cnt, uphdr, ehdr, &eh_state,
8799406SAli.Bahrami@Sun.COM osabi, file, flags);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate
8830Sstevel@tonic-gate /*
88411827SRod.Evans@Sun.COM * Initialize a symbol table state structure
88511827SRod.Evans@Sun.COM *
88611827SRod.Evans@Sun.COM * entry:
88711827SRod.Evans@Sun.COM * state - State structure to be initialized
88811827SRod.Evans@Sun.COM * cache - Cache of all section headers
88911827SRod.Evans@Sun.COM * shnum - # of sections in cache
89011827SRod.Evans@Sun.COM * secndx - Index of symbol table section
89111827SRod.Evans@Sun.COM * ehdr - ELF header for file
89211827SRod.Evans@Sun.COM * versym - Information about versym section
89311827SRod.Evans@Sun.COM * file - Name of file
89411827SRod.Evans@Sun.COM * flags - Command line option flags
89511827SRod.Evans@Sun.COM */
89611827SRod.Evans@Sun.COM static int
init_symtbl_state(SYMTBL_STATE * state,Cache * cache,Word shnum,Word secndx,Ehdr * ehdr,uchar_t osabi,VERSYM_STATE * versym,const char * file,uint_t flags)89711827SRod.Evans@Sun.COM init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx,
89811827SRod.Evans@Sun.COM Ehdr *ehdr, uchar_t osabi, VERSYM_STATE *versym, const char *file,
89911827SRod.Evans@Sun.COM uint_t flags)
90011827SRod.Evans@Sun.COM {
90111827SRod.Evans@Sun.COM Shdr *shdr;
90211827SRod.Evans@Sun.COM
90311827SRod.Evans@Sun.COM state->file = file;
90411827SRod.Evans@Sun.COM state->ehdr = ehdr;
90511827SRod.Evans@Sun.COM state->cache = cache;
90611827SRod.Evans@Sun.COM state->osabi = osabi;
90711827SRod.Evans@Sun.COM state->shnum = shnum;
90811827SRod.Evans@Sun.COM state->seccache = &cache[secndx];
90911827SRod.Evans@Sun.COM state->secndx = secndx;
91011827SRod.Evans@Sun.COM state->secname = state->seccache->c_name;
91111827SRod.Evans@Sun.COM state->flags = flags;
91211827SRod.Evans@Sun.COM state->shxndx.checked = 0;
91311827SRod.Evans@Sun.COM state->shxndx.data = NULL;
91411827SRod.Evans@Sun.COM state->shxndx.n = 0;
91511827SRod.Evans@Sun.COM
91611827SRod.Evans@Sun.COM shdr = state->seccache->c_shdr;
91711827SRod.Evans@Sun.COM
91811827SRod.Evans@Sun.COM /*
91911827SRod.Evans@Sun.COM * Check the symbol data and per-item size.
92011827SRod.Evans@Sun.COM */
92111827SRod.Evans@Sun.COM if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
92211827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
92311827SRod.Evans@Sun.COM file, state->secname);
92411827SRod.Evans@Sun.COM return (0);
92511827SRod.Evans@Sun.COM }
92611827SRod.Evans@Sun.COM if (state->seccache->c_data == NULL)
92711827SRod.Evans@Sun.COM return (0);
92811827SRod.Evans@Sun.COM
92911827SRod.Evans@Sun.COM /* LINTED */
93011827SRod.Evans@Sun.COM state->symn = (Word)(shdr->sh_size / shdr->sh_entsize);
93111827SRod.Evans@Sun.COM state->sym = (Sym *)state->seccache->c_data->d_buf;
93211827SRod.Evans@Sun.COM
93311827SRod.Evans@Sun.COM /*
93411827SRod.Evans@Sun.COM * Check associated string table section.
93511827SRod.Evans@Sun.COM */
93611827SRod.Evans@Sun.COM if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
93711827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
93811827SRod.Evans@Sun.COM file, state->secname, EC_WORD(shdr->sh_link));
93911827SRod.Evans@Sun.COM return (0);
94011827SRod.Evans@Sun.COM }
94111827SRod.Evans@Sun.COM
94211827SRod.Evans@Sun.COM /*
94311827SRod.Evans@Sun.COM * Determine if there is a associated Versym section
94411827SRod.Evans@Sun.COM * with this Symbol Table.
94511827SRod.Evans@Sun.COM */
94611827SRod.Evans@Sun.COM if (versym && versym->cache &&
94711827SRod.Evans@Sun.COM (versym->cache->c_shdr->sh_link == state->secndx))
94811827SRod.Evans@Sun.COM state->versym = versym;
94911827SRod.Evans@Sun.COM else
95011827SRod.Evans@Sun.COM state->versym = NULL;
95111827SRod.Evans@Sun.COM
95211827SRod.Evans@Sun.COM
95311827SRod.Evans@Sun.COM return (1);
95411827SRod.Evans@Sun.COM }
95511827SRod.Evans@Sun.COM
95611827SRod.Evans@Sun.COM /*
95711827SRod.Evans@Sun.COM * Determine the extended section index used for symbol tables entries.
95811827SRod.Evans@Sun.COM */
95911827SRod.Evans@Sun.COM static void
symbols_getxindex(SYMTBL_STATE * state)96011827SRod.Evans@Sun.COM symbols_getxindex(SYMTBL_STATE *state)
96111827SRod.Evans@Sun.COM {
96211827SRod.Evans@Sun.COM uint_t symn;
96311827SRod.Evans@Sun.COM Word symcnt;
96411827SRod.Evans@Sun.COM
96511827SRod.Evans@Sun.COM state->shxndx.checked = 1; /* Note that we've been called */
96611827SRod.Evans@Sun.COM for (symcnt = 1; symcnt < state->shnum; symcnt++) {
96711827SRod.Evans@Sun.COM Cache *_cache = &state->cache[symcnt];
96811827SRod.Evans@Sun.COM Shdr *shdr = _cache->c_shdr;
96911827SRod.Evans@Sun.COM
97011827SRod.Evans@Sun.COM if ((shdr->sh_type != SHT_SYMTAB_SHNDX) ||
97111827SRod.Evans@Sun.COM (shdr->sh_link != state->secndx))
97211827SRod.Evans@Sun.COM continue;
97311827SRod.Evans@Sun.COM
97411827SRod.Evans@Sun.COM if ((shdr->sh_entsize) &&
97511827SRod.Evans@Sun.COM /* LINTED */
97611827SRod.Evans@Sun.COM ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0))
97711827SRod.Evans@Sun.COM continue;
97811827SRod.Evans@Sun.COM
97911827SRod.Evans@Sun.COM if (_cache->c_data == NULL)
98011827SRod.Evans@Sun.COM continue;
98111827SRod.Evans@Sun.COM
98211827SRod.Evans@Sun.COM state->shxndx.data = _cache->c_data->d_buf;
98311827SRod.Evans@Sun.COM state->shxndx.n = symn;
98411827SRod.Evans@Sun.COM return;
98511827SRod.Evans@Sun.COM }
98611827SRod.Evans@Sun.COM }
98711827SRod.Evans@Sun.COM
98811827SRod.Evans@Sun.COM /*
98911827SRod.Evans@Sun.COM * Produce a line of output for the given symbol
99011827SRod.Evans@Sun.COM *
99111827SRod.Evans@Sun.COM * entry:
99211827SRod.Evans@Sun.COM * state - Symbol table state
99311827SRod.Evans@Sun.COM * symndx - Index of symbol within the table
99411827SRod.Evans@Sun.COM * info - Value of st_info (indicates local/global range)
99511827SRod.Evans@Sun.COM * symndx_disp - Index to display. This may not be the same
99611827SRod.Evans@Sun.COM * as symndx if the display is relative to the logical
99711827SRod.Evans@Sun.COM * combination of the SUNW_ldynsym/dynsym tables.
99811827SRod.Evans@Sun.COM * sym - Symbol to display
99911827SRod.Evans@Sun.COM */
100011827SRod.Evans@Sun.COM static void
output_symbol(SYMTBL_STATE * state,Word symndx,Word info,Word disp_symndx,Sym * sym)100111827SRod.Evans@Sun.COM output_symbol(SYMTBL_STATE *state, Word symndx, Word info, Word disp_symndx,
100211827SRod.Evans@Sun.COM Sym *sym)
100311827SRod.Evans@Sun.COM {
100411827SRod.Evans@Sun.COM /*
100511827SRod.Evans@Sun.COM * Symbol types for which we check that the specified
100611827SRod.Evans@Sun.COM * address/size land inside the target section.
100711827SRod.Evans@Sun.COM */
100811827SRod.Evans@Sun.COM static const int addr_symtype[] = {
100911827SRod.Evans@Sun.COM 0, /* STT_NOTYPE */
101011827SRod.Evans@Sun.COM 1, /* STT_OBJECT */
101111827SRod.Evans@Sun.COM 1, /* STT_FUNC */
101211827SRod.Evans@Sun.COM 0, /* STT_SECTION */
101311827SRod.Evans@Sun.COM 0, /* STT_FILE */
101411827SRod.Evans@Sun.COM 1, /* STT_COMMON */
101511827SRod.Evans@Sun.COM 0, /* STT_TLS */
101611827SRod.Evans@Sun.COM 0, /* 7 */
101711827SRod.Evans@Sun.COM 0, /* 8 */
101811827SRod.Evans@Sun.COM 0, /* 9 */
101911827SRod.Evans@Sun.COM 0, /* 10 */
102011827SRod.Evans@Sun.COM 0, /* 11 */
102111827SRod.Evans@Sun.COM 0, /* 12 */
102211827SRod.Evans@Sun.COM 0, /* STT_SPARC_REGISTER */
102311827SRod.Evans@Sun.COM 0, /* 14 */
102411827SRod.Evans@Sun.COM 0, /* 15 */
102511827SRod.Evans@Sun.COM };
102611827SRod.Evans@Sun.COM #if STT_NUM != (STT_TLS + 1)
102711827SRod.Evans@Sun.COM #error "STT_NUM has grown. Update addr_symtype[]"
102811827SRod.Evans@Sun.COM #endif
102911827SRod.Evans@Sun.COM
103011827SRod.Evans@Sun.COM char index[MAXNDXSIZE];
103111827SRod.Evans@Sun.COM const char *symname, *sec;
103211827SRod.Evans@Sun.COM Versym verndx;
103311827SRod.Evans@Sun.COM int gnuver;
103411827SRod.Evans@Sun.COM uchar_t type;
103511827SRod.Evans@Sun.COM Shdr *tshdr;
103611827SRod.Evans@Sun.COM Word shndx;
103711827SRod.Evans@Sun.COM Conv_inv_buf_t inv_buf;
103811827SRod.Evans@Sun.COM
103911827SRod.Evans@Sun.COM /* Ensure symbol index is in range */
104011827SRod.Evans@Sun.COM if (symndx >= state->symn) {
104111827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYMNDX),
104211827SRod.Evans@Sun.COM state->file, state->secname, EC_WORD(symndx));
104311827SRod.Evans@Sun.COM return;
104411827SRod.Evans@Sun.COM }
104511827SRod.Evans@Sun.COM
104611827SRod.Evans@Sun.COM /*
104711827SRod.Evans@Sun.COM * If we are using extended symbol indexes, find the
104811827SRod.Evans@Sun.COM * corresponding SHN_SYMTAB_SHNDX table.
104911827SRod.Evans@Sun.COM */
105011827SRod.Evans@Sun.COM if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0))
105111827SRod.Evans@Sun.COM symbols_getxindex(state);
105211827SRod.Evans@Sun.COM
105311827SRod.Evans@Sun.COM /* LINTED */
105411827SRod.Evans@Sun.COM symname = string(state->seccache, symndx,
105511827SRod.Evans@Sun.COM &state->cache[state->seccache->c_shdr->sh_link], state->file,
105611827SRod.Evans@Sun.COM sym->st_name);
105711827SRod.Evans@Sun.COM
105811827SRod.Evans@Sun.COM tshdr = NULL;
105911827SRod.Evans@Sun.COM sec = NULL;
106011827SRod.Evans@Sun.COM
106111827SRod.Evans@Sun.COM if (state->ehdr->e_type == ET_CORE) {
106211827SRod.Evans@Sun.COM sec = (char *)MSG_INTL(MSG_STR_UNKNOWN);
106311827SRod.Evans@Sun.COM } else if (state->flags & FLG_CTL_FAKESHDR) {
106411827SRod.Evans@Sun.COM /*
106511827SRod.Evans@Sun.COM * If we are using fake section headers derived from
106611827SRod.Evans@Sun.COM * the program headers, then the section indexes
106711827SRod.Evans@Sun.COM * in the symbols do not correspond to these headers.
106811827SRod.Evans@Sun.COM * The section names are not available, so all we can
106911827SRod.Evans@Sun.COM * do is to display them in numeric form.
107011827SRod.Evans@Sun.COM */
107111827SRod.Evans@Sun.COM sec = conv_sym_shndx(state->osabi, state->ehdr->e_machine,
107211827SRod.Evans@Sun.COM sym->st_shndx, CONV_FMT_DECIMAL, &inv_buf);
107311827SRod.Evans@Sun.COM } else if ((sym->st_shndx < SHN_LORESERVE) &&
107411827SRod.Evans@Sun.COM (sym->st_shndx < state->shnum)) {
107511827SRod.Evans@Sun.COM shndx = sym->st_shndx;
107611827SRod.Evans@Sun.COM tshdr = state->cache[shndx].c_shdr;
107711827SRod.Evans@Sun.COM sec = state->cache[shndx].c_name;
107811827SRod.Evans@Sun.COM } else if (sym->st_shndx == SHN_XINDEX) {
107911827SRod.Evans@Sun.COM if (state->shxndx.data) {
108011827SRod.Evans@Sun.COM Word _shxndx;
108111827SRod.Evans@Sun.COM
108211827SRod.Evans@Sun.COM if (symndx > state->shxndx.n) {
108311827SRod.Evans@Sun.COM (void) fprintf(stderr,
108411827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYMXINDEX1),
108511827SRod.Evans@Sun.COM state->file, state->secname,
108611827SRod.Evans@Sun.COM EC_WORD(symndx));
108711827SRod.Evans@Sun.COM } else if ((_shxndx =
108811827SRod.Evans@Sun.COM state->shxndx.data[symndx]) > state->shnum) {
108911827SRod.Evans@Sun.COM (void) fprintf(stderr,
109011827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYMXINDEX2),
109111827SRod.Evans@Sun.COM state->file, state->secname,
109211827SRod.Evans@Sun.COM EC_WORD(symndx), EC_WORD(_shxndx));
109311827SRod.Evans@Sun.COM } else {
109411827SRod.Evans@Sun.COM shndx = _shxndx;
109511827SRod.Evans@Sun.COM tshdr = state->cache[shndx].c_shdr;
109611827SRod.Evans@Sun.COM sec = state->cache[shndx].c_name;
109711827SRod.Evans@Sun.COM }
109811827SRod.Evans@Sun.COM } else {
109911827SRod.Evans@Sun.COM (void) fprintf(stderr,
110011827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYMXINDEX3),
110111827SRod.Evans@Sun.COM state->file, state->secname, EC_WORD(symndx));
110211827SRod.Evans@Sun.COM }
110311827SRod.Evans@Sun.COM } else if ((sym->st_shndx < SHN_LORESERVE) &&
110411827SRod.Evans@Sun.COM (sym->st_shndx >= state->shnum)) {
110511827SRod.Evans@Sun.COM (void) fprintf(stderr,
110611827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYM5), state->file,
110711827SRod.Evans@Sun.COM state->secname, EC_WORD(symndx),
110811827SRod.Evans@Sun.COM demangle(symname, state->flags), sym->st_shndx);
110911827SRod.Evans@Sun.COM }
111011827SRod.Evans@Sun.COM
111111827SRod.Evans@Sun.COM /*
111211827SRod.Evans@Sun.COM * If versioning is available display the
111311827SRod.Evans@Sun.COM * version index. If not, then use 0.
111411827SRod.Evans@Sun.COM */
111511827SRod.Evans@Sun.COM if (state->versym) {
111611827SRod.Evans@Sun.COM Versym test_verndx;
111711827SRod.Evans@Sun.COM
111811827SRod.Evans@Sun.COM verndx = test_verndx = state->versym->data[symndx];
111911827SRod.Evans@Sun.COM gnuver = state->versym->gnu_full;
112011827SRod.Evans@Sun.COM
112111827SRod.Evans@Sun.COM /*
112211827SRod.Evans@Sun.COM * Check to see if this is a defined symbol with a
112311827SRod.Evans@Sun.COM * version index that is outside the valid range for
112411827SRod.Evans@Sun.COM * the file. The interpretation of this depends on
112511827SRod.Evans@Sun.COM * the style of versioning used by the object.
112611827SRod.Evans@Sun.COM *
112711827SRod.Evans@Sun.COM * Versions >= VER_NDX_LORESERVE have special meanings,
112811827SRod.Evans@Sun.COM * and are exempt from this checking.
112911827SRod.Evans@Sun.COM *
113011827SRod.Evans@Sun.COM * GNU style version indexes use the top bit of the
113111827SRod.Evans@Sun.COM * 16-bit index value (0x8000) as the "hidden bit".
113211827SRod.Evans@Sun.COM * We must mask off this bit in order to compare
113311827SRod.Evans@Sun.COM * the version against the maximum value.
113411827SRod.Evans@Sun.COM */
113511827SRod.Evans@Sun.COM if (gnuver)
113611827SRod.Evans@Sun.COM test_verndx &= ~0x8000;
113711827SRod.Evans@Sun.COM
113811827SRod.Evans@Sun.COM if ((test_verndx > state->versym->max_verndx) &&
113911827SRod.Evans@Sun.COM (verndx < VER_NDX_LORESERVE))
114011827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADVER),
114111827SRod.Evans@Sun.COM state->file, state->secname, EC_WORD(symndx),
114211827SRod.Evans@Sun.COM EC_HALF(test_verndx), state->versym->max_verndx);
114311827SRod.Evans@Sun.COM } else {
114411827SRod.Evans@Sun.COM verndx = 0;
114511827SRod.Evans@Sun.COM gnuver = 0;
114611827SRod.Evans@Sun.COM }
114711827SRod.Evans@Sun.COM
114811827SRod.Evans@Sun.COM /*
114911827SRod.Evans@Sun.COM * Error checking for TLS.
115011827SRod.Evans@Sun.COM */
115111827SRod.Evans@Sun.COM type = ELF_ST_TYPE(sym->st_info);
115211827SRod.Evans@Sun.COM if (type == STT_TLS) {
115311827SRod.Evans@Sun.COM if (tshdr &&
115411827SRod.Evans@Sun.COM (sym->st_shndx != SHN_UNDEF) &&
115511827SRod.Evans@Sun.COM ((tshdr->sh_flags & SHF_TLS) == 0)) {
115611827SRod.Evans@Sun.COM (void) fprintf(stderr,
115711827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYM3), state->file,
115811827SRod.Evans@Sun.COM state->secname, EC_WORD(symndx),
115911827SRod.Evans@Sun.COM demangle(symname, state->flags));
116011827SRod.Evans@Sun.COM }
116111827SRod.Evans@Sun.COM } else if ((type != STT_SECTION) && sym->st_size &&
116211827SRod.Evans@Sun.COM tshdr && (tshdr->sh_flags & SHF_TLS)) {
116311827SRod.Evans@Sun.COM (void) fprintf(stderr,
116411827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYM4), state->file,
116511827SRod.Evans@Sun.COM state->secname, EC_WORD(symndx),
116611827SRod.Evans@Sun.COM demangle(symname, state->flags));
116711827SRod.Evans@Sun.COM }
116811827SRod.Evans@Sun.COM
116911827SRod.Evans@Sun.COM /*
117011827SRod.Evans@Sun.COM * If a symbol with non-zero size has a type that
117111827SRod.Evans@Sun.COM * specifies an address, then make sure the location
117211827SRod.Evans@Sun.COM * it references is actually contained within the
117311827SRod.Evans@Sun.COM * section. UNDEF symbols don't count in this case,
117411827SRod.Evans@Sun.COM * so we ignore them.
117511827SRod.Evans@Sun.COM *
117611827SRod.Evans@Sun.COM * The meaning of the st_value field in a symbol
117711827SRod.Evans@Sun.COM * depends on the type of object. For a relocatable
117811827SRod.Evans@Sun.COM * object, it is the offset within the section.
117911827SRod.Evans@Sun.COM * For sharable objects, it is the offset relative to
118011827SRod.Evans@Sun.COM * the base of the object, and for other types, it is
118111827SRod.Evans@Sun.COM * the virtual address. To get an offset within the
118211827SRod.Evans@Sun.COM * section for non-ET_REL files, we subtract the
118311827SRod.Evans@Sun.COM * base address of the section.
118411827SRod.Evans@Sun.COM */
118511827SRod.Evans@Sun.COM if (addr_symtype[type] && (sym->st_size > 0) &&
118611827SRod.Evans@Sun.COM (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) ||
118711827SRod.Evans@Sun.COM (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) {
118811827SRod.Evans@Sun.COM Word v = sym->st_value;
118911827SRod.Evans@Sun.COM if (state->ehdr->e_type != ET_REL)
119011827SRod.Evans@Sun.COM v -= tshdr->sh_addr;
119111827SRod.Evans@Sun.COM if (((v + sym->st_size) > tshdr->sh_size)) {
119211827SRod.Evans@Sun.COM (void) fprintf(stderr,
119311827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYM6), state->file,
119411827SRod.Evans@Sun.COM state->secname, EC_WORD(symndx),
119511827SRod.Evans@Sun.COM demangle(symname, state->flags),
119611827SRod.Evans@Sun.COM EC_WORD(shndx), EC_XWORD(tshdr->sh_size),
119711827SRod.Evans@Sun.COM EC_XWORD(sym->st_value), EC_XWORD(sym->st_size));
119811827SRod.Evans@Sun.COM }
119911827SRod.Evans@Sun.COM }
120011827SRod.Evans@Sun.COM
120111827SRod.Evans@Sun.COM /*
120211827SRod.Evans@Sun.COM * A typical symbol table uses the sh_info field to indicate one greater
120311827SRod.Evans@Sun.COM * than the symbol table index of the last local symbol, STB_LOCAL.
120411827SRod.Evans@Sun.COM * Therefore, symbol indexes less than sh_info should have local
120511827SRod.Evans@Sun.COM * binding. Symbol indexes greater than, or equal to sh_info, should
120611827SRod.Evans@Sun.COM * have global binding. Note, we exclude UNDEF/NOTY symbols with zero
120711827SRod.Evans@Sun.COM * value and size, as these symbols may be the result of an mcs(1)
120811827SRod.Evans@Sun.COM * section deletion.
120911827SRod.Evans@Sun.COM */
121011827SRod.Evans@Sun.COM if (info) {
121111827SRod.Evans@Sun.COM uchar_t bind = ELF_ST_BIND(sym->st_info);
121211827SRod.Evans@Sun.COM
121311827SRod.Evans@Sun.COM if ((symndx < info) && (bind != STB_LOCAL)) {
121411827SRod.Evans@Sun.COM (void) fprintf(stderr,
121511827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYM7), state->file,
121611827SRod.Evans@Sun.COM state->secname, EC_WORD(symndx),
121711827SRod.Evans@Sun.COM demangle(symname, state->flags), EC_XWORD(info));
121811827SRod.Evans@Sun.COM
121911827SRod.Evans@Sun.COM } else if ((symndx >= info) && (bind == STB_LOCAL) &&
122011827SRod.Evans@Sun.COM ((sym->st_shndx != SHN_UNDEF) ||
122111827SRod.Evans@Sun.COM (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) ||
122211827SRod.Evans@Sun.COM (sym->st_size != 0) || (sym->st_value != 0))) {
122311827SRod.Evans@Sun.COM (void) fprintf(stderr,
122411827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_BADSYM8), state->file,
122511827SRod.Evans@Sun.COM state->secname, EC_WORD(symndx),
122611827SRod.Evans@Sun.COM demangle(symname, state->flags), EC_XWORD(info));
122711827SRod.Evans@Sun.COM }
122811827SRod.Evans@Sun.COM }
122911827SRod.Evans@Sun.COM
123011827SRod.Evans@Sun.COM (void) snprintf(index, MAXNDXSIZE,
123111827SRod.Evans@Sun.COM MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx));
123211827SRod.Evans@Sun.COM Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index, state->osabi,
123311827SRod.Evans@Sun.COM state->ehdr->e_machine, sym, verndx, gnuver, sec, symname);
123411827SRod.Evans@Sun.COM }
123511827SRod.Evans@Sun.COM
123611827SRod.Evans@Sun.COM /*
123711827SRod.Evans@Sun.COM * Process a SHT_SUNW_cap capabilities section.
123811827SRod.Evans@Sun.COM */
123911827SRod.Evans@Sun.COM static int
cap_section(const char * file,Cache * cache,Word shnum,Cache * ccache,uchar_t osabi,Ehdr * ehdr,uint_t flags)124011827SRod.Evans@Sun.COM cap_section(const char *file, Cache *cache, Word shnum, Cache *ccache,
124111827SRod.Evans@Sun.COM uchar_t osabi, Ehdr *ehdr, uint_t flags)
124211827SRod.Evans@Sun.COM {
124311827SRod.Evans@Sun.COM SYMTBL_STATE state;
124411827SRod.Evans@Sun.COM Word cnum, capnum, nulls, symcaps;
124511827SRod.Evans@Sun.COM int descapndx, objcap, title;
124611827SRod.Evans@Sun.COM Cap *cap = (Cap *)ccache->c_data->d_buf;
124711827SRod.Evans@Sun.COM Shdr *cishdr, *cshdr = ccache->c_shdr;
124811827SRod.Evans@Sun.COM Cache *cicache, *strcache;
124911827SRod.Evans@Sun.COM Capinfo *capinfo = NULL;
125011827SRod.Evans@Sun.COM Word capinfonum;
125111827SRod.Evans@Sun.COM const char *strs = NULL;
125211827SRod.Evans@Sun.COM size_t strs_size;
125311827SRod.Evans@Sun.COM
125411827SRod.Evans@Sun.COM if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) {
125511827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
125611827SRod.Evans@Sun.COM file, ccache->c_name);
125711827SRod.Evans@Sun.COM return (0);
125811827SRod.Evans@Sun.COM }
125911827SRod.Evans@Sun.COM
126011827SRod.Evans@Sun.COM /*
126111827SRod.Evans@Sun.COM * If this capabilities section is associated with symbols, then the
126211827SRod.Evans@Sun.COM * sh_link field points to the associated capabilities information
126311827SRod.Evans@Sun.COM * section. The sh_link field of the capabilities information section
126411827SRod.Evans@Sun.COM * points to the associated symbol table.
126511827SRod.Evans@Sun.COM */
126611827SRod.Evans@Sun.COM if (cshdr->sh_link) {
126711827SRod.Evans@Sun.COM Cache *scache;
126811827SRod.Evans@Sun.COM Shdr *sshdr;
126911827SRod.Evans@Sun.COM
127011827SRod.Evans@Sun.COM /*
127111827SRod.Evans@Sun.COM * Validate that the sh_link field points to a capabilities
127211827SRod.Evans@Sun.COM * information section.
127311827SRod.Evans@Sun.COM */
127411827SRod.Evans@Sun.COM if (cshdr->sh_link >= shnum) {
127511827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
127611827SRod.Evans@Sun.COM file, ccache->c_name, EC_WORD(cshdr->sh_link));
127711827SRod.Evans@Sun.COM return (0);
127811827SRod.Evans@Sun.COM }
127911827SRod.Evans@Sun.COM
128011827SRod.Evans@Sun.COM cicache = &cache[cshdr->sh_link];
128111827SRod.Evans@Sun.COM cishdr = cicache->c_shdr;
128211827SRod.Evans@Sun.COM
128311827SRod.Evans@Sun.COM if (cishdr->sh_type != SHT_SUNW_capinfo) {
128411827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_INVCAP),
128511827SRod.Evans@Sun.COM file, ccache->c_name, EC_WORD(cshdr->sh_link));
128611827SRod.Evans@Sun.COM return (0);
128711827SRod.Evans@Sun.COM }
128811827SRod.Evans@Sun.COM
128911827SRod.Evans@Sun.COM capinfo = cicache->c_data->d_buf;
129011827SRod.Evans@Sun.COM capinfonum = (Word)(cishdr->sh_size / cishdr->sh_entsize);
129111827SRod.Evans@Sun.COM
129211827SRod.Evans@Sun.COM /*
129311827SRod.Evans@Sun.COM * Validate that the sh_link field of the capabilities
129411827SRod.Evans@Sun.COM * information section points to a valid symbol table.
129511827SRod.Evans@Sun.COM */
129611827SRod.Evans@Sun.COM if ((cishdr->sh_link == 0) || (cishdr->sh_link >= shnum)) {
129711827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
129811827SRod.Evans@Sun.COM file, cicache->c_name, EC_WORD(cishdr->sh_link));
129911827SRod.Evans@Sun.COM return (0);
130011827SRod.Evans@Sun.COM }
130111827SRod.Evans@Sun.COM scache = &cache[cishdr->sh_link];
130211827SRod.Evans@Sun.COM sshdr = scache->c_shdr;
130311827SRod.Evans@Sun.COM
130411827SRod.Evans@Sun.COM if ((sshdr->sh_type != SHT_SYMTAB) &&
130511827SRod.Evans@Sun.COM (sshdr->sh_type != SHT_DYNSYM)) {
130611827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_INVCAPINFO1),
130711827SRod.Evans@Sun.COM file, cicache->c_name, EC_WORD(cishdr->sh_link));
130811827SRod.Evans@Sun.COM return (0);
130911827SRod.Evans@Sun.COM }
131011827SRod.Evans@Sun.COM
131111827SRod.Evans@Sun.COM if (!init_symtbl_state(&state, cache, shnum,
131211827SRod.Evans@Sun.COM cishdr->sh_link, ehdr, osabi, NULL, file, flags))
131311827SRod.Evans@Sun.COM return (0);
131411827SRod.Evans@Sun.COM }
131511827SRod.Evans@Sun.COM
131611827SRod.Evans@Sun.COM /*
131711827SRod.Evans@Sun.COM * If this capabilities section contains capability string entries,
131811827SRod.Evans@Sun.COM * then determine the associated string table. Capabilities entries
131911827SRod.Evans@Sun.COM * that define names require that the capability section indicate
132011827SRod.Evans@Sun.COM * which string table to use via sh_info.
132111827SRod.Evans@Sun.COM */
132211827SRod.Evans@Sun.COM if (cshdr->sh_info) {
132311827SRod.Evans@Sun.COM Shdr *strshdr;
132411827SRod.Evans@Sun.COM
132511827SRod.Evans@Sun.COM /*
132611827SRod.Evans@Sun.COM * Validate that the sh_info field points to a string table.
132711827SRod.Evans@Sun.COM */
132811827SRod.Evans@Sun.COM if (cshdr->sh_info >= shnum) {
132911827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
133011827SRod.Evans@Sun.COM file, ccache->c_name, EC_WORD(cshdr->sh_info));
133111827SRod.Evans@Sun.COM return (0);
133211827SRod.Evans@Sun.COM }
133311827SRod.Evans@Sun.COM
133411827SRod.Evans@Sun.COM strcache = &cache[cshdr->sh_info];
133511827SRod.Evans@Sun.COM strshdr = strcache->c_shdr;
133611827SRod.Evans@Sun.COM
133711827SRod.Evans@Sun.COM if (strshdr->sh_type != SHT_STRTAB) {
133811827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_INVCAP),
133911827SRod.Evans@Sun.COM file, ccache->c_name, EC_WORD(cshdr->sh_info));
134011827SRod.Evans@Sun.COM return (0);
134111827SRod.Evans@Sun.COM }
134211827SRod.Evans@Sun.COM strs = (const char *)strcache->c_data->d_buf;
134311827SRod.Evans@Sun.COM strs_size = strcache->c_data->d_size;
134411827SRod.Evans@Sun.COM }
134511827SRod.Evans@Sun.COM
134611827SRod.Evans@Sun.COM dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
134711827SRod.Evans@Sun.COM dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name);
134811827SRod.Evans@Sun.COM
134911827SRod.Evans@Sun.COM capnum = (Word)(cshdr->sh_size / cshdr->sh_entsize);
135011827SRod.Evans@Sun.COM
135111827SRod.Evans@Sun.COM nulls = symcaps = 0;
135211827SRod.Evans@Sun.COM objcap = title = 1;
135311827SRod.Evans@Sun.COM descapndx = -1;
135411827SRod.Evans@Sun.COM
135511827SRod.Evans@Sun.COM /*
135611827SRod.Evans@Sun.COM * Traverse the capabilities section printing each capability group.
135711827SRod.Evans@Sun.COM * The first capabilities group defines any object capabilities. Any
135811827SRod.Evans@Sun.COM * following groups define symbol capabilities. In the case where no
135911827SRod.Evans@Sun.COM * object capabilities exist, but symbol capabilities do, a single
136011827SRod.Evans@Sun.COM * CA_SUNW_NULL terminator for the object capabilities exists.
136111827SRod.Evans@Sun.COM */
136211827SRod.Evans@Sun.COM for (cnum = 0; cnum < capnum; cap++, cnum++) {
136311827SRod.Evans@Sun.COM if (cap->c_tag == CA_SUNW_NULL) {
136411827SRod.Evans@Sun.COM /*
136511827SRod.Evans@Sun.COM * A CA_SUNW_NULL tag terminates a capabilities group.
136611827SRod.Evans@Sun.COM * If the first capabilities tag is CA_SUNW_NULL, then
136711827SRod.Evans@Sun.COM * no object capabilities exist.
136811827SRod.Evans@Sun.COM */
136911827SRod.Evans@Sun.COM if ((nulls++ == 0) && (cnum == 0))
137011827SRod.Evans@Sun.COM objcap = 0;
137111827SRod.Evans@Sun.COM title = 1;
137211827SRod.Evans@Sun.COM } else {
137311827SRod.Evans@Sun.COM if (title) {
137411827SRod.Evans@Sun.COM if (nulls == 0) {
137511827SRod.Evans@Sun.COM /*
137611827SRod.Evans@Sun.COM * If this capabilities group represents
137711827SRod.Evans@Sun.COM * the object capabilities (i.e., no
137811827SRod.Evans@Sun.COM * CA_SUNW_NULL tag has been processed
137911827SRod.Evans@Sun.COM * yet), then display an object
138011827SRod.Evans@Sun.COM * capabilities title.
138111827SRod.Evans@Sun.COM */
138211827SRod.Evans@Sun.COM dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
138311827SRod.Evans@Sun.COM dbg_print(0,
138411827SRod.Evans@Sun.COM MSG_INTL(MSG_OBJ_CAP_TITLE));
138511827SRod.Evans@Sun.COM } else {
138611827SRod.Evans@Sun.COM /*
138711827SRod.Evans@Sun.COM * If this is a symbols capabilities
138811827SRod.Evans@Sun.COM * group (i.e., a CA_SUNW_NULL tag has
138911827SRod.Evans@Sun.COM * already be found that terminates
139011827SRod.Evans@Sun.COM * the object capabilities group), then
139111827SRod.Evans@Sun.COM * display a symbol capabilities title,
139211827SRod.Evans@Sun.COM * and retain this capabilities index
139311827SRod.Evans@Sun.COM * for later processing.
139411827SRod.Evans@Sun.COM */
139511827SRod.Evans@Sun.COM dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
139611827SRod.Evans@Sun.COM dbg_print(0,
139711827SRod.Evans@Sun.COM MSG_INTL(MSG_SYM_CAP_TITLE));
139811827SRod.Evans@Sun.COM descapndx = cnum;
139911827SRod.Evans@Sun.COM }
140011827SRod.Evans@Sun.COM Elf_cap_title(0);
140111827SRod.Evans@Sun.COM title = 0;
140211827SRod.Evans@Sun.COM }
140311827SRod.Evans@Sun.COM
140411827SRod.Evans@Sun.COM /*
140511827SRod.Evans@Sun.COM * Print the capabilities data.
140611827SRod.Evans@Sun.COM *
140711827SRod.Evans@Sun.COM * Note that CA_SUNW_PLAT, CA_SUNW_MACH and CA_SUNW_ID
140811827SRod.Evans@Sun.COM * entries require a string table, which should have
140911827SRod.Evans@Sun.COM * already been established.
141011827SRod.Evans@Sun.COM */
141111827SRod.Evans@Sun.COM if ((strs == NULL) && ((cap->c_tag == CA_SUNW_PLAT) ||
141211827SRod.Evans@Sun.COM (cap->c_tag == CA_SUNW_MACH) ||
141311827SRod.Evans@Sun.COM (cap->c_tag == CA_SUNW_ID))) {
141411827SRod.Evans@Sun.COM (void) fprintf(stderr,
141511827SRod.Evans@Sun.COM MSG_INTL(MSG_WARN_INVCAP4), file,
141611827SRod.Evans@Sun.COM EC_WORD(elf_ndxscn(ccache->c_scn)),
141711827SRod.Evans@Sun.COM ccache->c_name, EC_WORD(cshdr->sh_info));
141811827SRod.Evans@Sun.COM }
141911827SRod.Evans@Sun.COM Elf_cap_entry(0, cap, cnum, strs, strs_size,
142011827SRod.Evans@Sun.COM ehdr->e_machine);
142111827SRod.Evans@Sun.COM }
142211827SRod.Evans@Sun.COM
142311827SRod.Evans@Sun.COM /*
142411827SRod.Evans@Sun.COM * If this CA_SUNW_NULL tag terminates a symbol capabilities
142511827SRod.Evans@Sun.COM * group, determine the associated symbols.
142611827SRod.Evans@Sun.COM */
142711827SRod.Evans@Sun.COM if ((cap->c_tag == CA_SUNW_NULL) && (nulls > 1) &&
142811827SRod.Evans@Sun.COM (descapndx != -1)) {
142911827SRod.Evans@Sun.COM Capinfo *cip;
143011827SRod.Evans@Sun.COM Word inum;
143111827SRod.Evans@Sun.COM
143211827SRod.Evans@Sun.COM symcaps++;
143311827SRod.Evans@Sun.COM
143411827SRod.Evans@Sun.COM /*
143511827SRod.Evans@Sun.COM * Make sure we've discovered a SHT_SUNW_capinfo table.
143611827SRod.Evans@Sun.COM */
143711827SRod.Evans@Sun.COM if ((cip = capinfo) == NULL) {
143811827SRod.Evans@Sun.COM (void) fprintf(stderr,
143911827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_INVCAP), file,
144011827SRod.Evans@Sun.COM ccache->c_name, EC_WORD(cshdr->sh_link));
144111827SRod.Evans@Sun.COM return (0);
144211827SRod.Evans@Sun.COM }
144311827SRod.Evans@Sun.COM
144411827SRod.Evans@Sun.COM /*
144511827SRod.Evans@Sun.COM * Determine what symbols reference this capabilities
144611827SRod.Evans@Sun.COM * group.
144711827SRod.Evans@Sun.COM */
144811827SRod.Evans@Sun.COM dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
144911827SRod.Evans@Sun.COM dbg_print(0, MSG_INTL(MSG_CAPINFO_ENTRIES));
145011827SRod.Evans@Sun.COM Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
145111827SRod.Evans@Sun.COM
145211827SRod.Evans@Sun.COM for (inum = 1, cip++; inum < capinfonum;
145311827SRod.Evans@Sun.COM inum++, cip++) {
145411827SRod.Evans@Sun.COM Word gndx = (Word)ELF_C_GROUP(*cip);
145511827SRod.Evans@Sun.COM
145611827SRod.Evans@Sun.COM if (gndx && (gndx == descapndx)) {
145711827SRod.Evans@Sun.COM output_symbol(&state, inum, 0,
145811827SRod.Evans@Sun.COM inum, state.sym + inum);
145911827SRod.Evans@Sun.COM }
146011827SRod.Evans@Sun.COM }
146111827SRod.Evans@Sun.COM descapndx = -1;
146211827SRod.Evans@Sun.COM continue;
146311827SRod.Evans@Sun.COM }
146411827SRod.Evans@Sun.COM
146511827SRod.Evans@Sun.COM /*
146611827SRod.Evans@Sun.COM * An SF1_SUNW_ADDR32 software capability tag in a 32-bit
146711827SRod.Evans@Sun.COM * object is suspicious as it has no effect.
146811827SRod.Evans@Sun.COM */
146911827SRod.Evans@Sun.COM if ((cap->c_tag == CA_SUNW_SF_1) &&
147011827SRod.Evans@Sun.COM (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
147111827SRod.Evans@Sun.COM (cap->c_un.c_val & SF1_SUNW_ADDR32)) {
147211827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_WARN_INADDR32SF1),
147311827SRod.Evans@Sun.COM file, ccache->c_name);
147411827SRod.Evans@Sun.COM }
147511827SRod.Evans@Sun.COM }
147611827SRod.Evans@Sun.COM
147711827SRod.Evans@Sun.COM /*
147811827SRod.Evans@Sun.COM * If this is a dynamic object, with symbol capabilities, then a
147911827SRod.Evans@Sun.COM * .SUNW_capchain section should exist. This section contains a chain
148011827SRod.Evans@Sun.COM * of symbol indexes for each capabilities family. This is the list
148111827SRod.Evans@Sun.COM * that is searched by ld.so.1 to determine the best capabilities
148211827SRod.Evans@Sun.COM * candidate.
148311827SRod.Evans@Sun.COM *
148411827SRod.Evans@Sun.COM * Note, more than one capabilities lead symbol can point to the same
148511827SRod.Evans@Sun.COM * family chain. For example, a weak/global pair of symbols can both
148611827SRod.Evans@Sun.COM * represent the same family of capabilities symbols. Therefore, to
148711827SRod.Evans@Sun.COM * display all possible families we traverse the capabilities
148811827SRod.Evans@Sun.COM * information section looking for CAPINFO_SUNW_GLOB lead symbols.
148911827SRod.Evans@Sun.COM * From these we determine the associated capabilities chain to inspect.
149011827SRod.Evans@Sun.COM */
149111827SRod.Evans@Sun.COM if (symcaps &&
149211827SRod.Evans@Sun.COM ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) {
149311827SRod.Evans@Sun.COM Capinfo *cip;
149411827SRod.Evans@Sun.COM Capchain *chain;
149511827SRod.Evans@Sun.COM Cache *chcache;
149611827SRod.Evans@Sun.COM Shdr *chshdr;
149711827SRod.Evans@Sun.COM Word chainnum, inum;
149811827SRod.Evans@Sun.COM
149911827SRod.Evans@Sun.COM /*
150011827SRod.Evans@Sun.COM * Validate that the sh_info field of the capabilities
150111827SRod.Evans@Sun.COM * information section points to a capabilities chain section.
150211827SRod.Evans@Sun.COM */
150311827SRod.Evans@Sun.COM if (cishdr->sh_info >= shnum) {
150411827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
150511827SRod.Evans@Sun.COM file, cicache->c_name, EC_WORD(cishdr->sh_info));
150611827SRod.Evans@Sun.COM return (0);
150711827SRod.Evans@Sun.COM }
150811827SRod.Evans@Sun.COM
150911827SRod.Evans@Sun.COM chcache = &cache[cishdr->sh_info];
151011827SRod.Evans@Sun.COM chshdr = chcache->c_shdr;
151111827SRod.Evans@Sun.COM
151211827SRod.Evans@Sun.COM if (chshdr->sh_type != SHT_SUNW_capchain) {
151311827SRod.Evans@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_INVCAPINFO2),
151411827SRod.Evans@Sun.COM file, cicache->c_name, EC_WORD(cishdr->sh_info));
151511827SRod.Evans@Sun.COM return (0);
151611827SRod.Evans@Sun.COM }
151711827SRod.Evans@Sun.COM
151811827SRod.Evans@Sun.COM chainnum = (Word)(chshdr->sh_size / chshdr->sh_entsize);
151911827SRod.Evans@Sun.COM chain = (Capchain *)chcache->c_data->d_buf;
152011827SRod.Evans@Sun.COM
152111827SRod.Evans@Sun.COM dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
152211827SRod.Evans@Sun.COM dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAPCHAIN), chcache->c_name);
152311827SRod.Evans@Sun.COM
152411827SRod.Evans@Sun.COM /*
152511827SRod.Evans@Sun.COM * Traverse the capabilities information section looking for
152611827SRod.Evans@Sun.COM * CAPINFO_SUNW_GLOB lead capabilities symbols.
152711827SRod.Evans@Sun.COM */
152811827SRod.Evans@Sun.COM cip = capinfo;
152911827SRod.Evans@Sun.COM for (inum = 1, cip++; inum < capinfonum; inum++, cip++) {
153011827SRod.Evans@Sun.COM const char *name;
153111827SRod.Evans@Sun.COM Sym *sym;
153211827SRod.Evans@Sun.COM Word sndx, cndx;
153311827SRod.Evans@Sun.COM Word gndx = (Word)ELF_C_GROUP(*cip);
153411827SRod.Evans@Sun.COM
153511827SRod.Evans@Sun.COM if ((gndx == 0) || (gndx != CAPINFO_SUNW_GLOB))
153611827SRod.Evans@Sun.COM continue;
153711827SRod.Evans@Sun.COM
153811827SRod.Evans@Sun.COM /*
153911827SRod.Evans@Sun.COM * Determine the symbol that is associated with this
154011827SRod.Evans@Sun.COM * capability information entry, and use this to
154111827SRod.Evans@Sun.COM * identify this capability family.
154211827SRod.Evans@Sun.COM */
154311827SRod.Evans@Sun.COM sym = (Sym *)(state.sym + inum);
154411827SRod.Evans@Sun.COM name = string(cicache, inum, strcache, file,
154511827SRod.Evans@Sun.COM sym->st_name);
154611827SRod.Evans@Sun.COM
154711827SRod.Evans@Sun.COM dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
154811827SRod.Evans@Sun.COM dbg_print(0, MSG_INTL(MSG_CAPCHAIN_TITLE), name);
154911827SRod.Evans@Sun.COM dbg_print(0, MSG_INTL(MSG_CAPCHAIN_ENTRY));
155011827SRod.Evans@Sun.COM
155111827SRod.Evans@Sun.COM cndx = (Word)ELF_C_SYM(*cip);
155211827SRod.Evans@Sun.COM
155311827SRod.Evans@Sun.COM /*
155411827SRod.Evans@Sun.COM * Traverse this families chain and identify each
155511827SRod.Evans@Sun.COM * family member.
155611827SRod.Evans@Sun.COM */
155711827SRod.Evans@Sun.COM for (;;) {
155811827SRod.Evans@Sun.COM char _chain[MAXNDXSIZE], _symndx[MAXNDXSIZE];
155911827SRod.Evans@Sun.COM
156011827SRod.Evans@Sun.COM if (cndx >= chainnum) {
156111827SRod.Evans@Sun.COM (void) fprintf(stderr,
156211827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_INVCAPINFO3), file,
156311827SRod.Evans@Sun.COM cicache->c_name, EC_WORD(inum),
156411827SRod.Evans@Sun.COM EC_WORD(cndx));
156511827SRod.Evans@Sun.COM break;
156611827SRod.Evans@Sun.COM }
156711827SRod.Evans@Sun.COM if ((sndx = chain[cndx]) == 0)
156811827SRod.Evans@Sun.COM break;
156911827SRod.Evans@Sun.COM
157011827SRod.Evans@Sun.COM /*
157111827SRod.Evans@Sun.COM * Determine this entries symbol reference.
157211827SRod.Evans@Sun.COM */
157311827SRod.Evans@Sun.COM if (sndx > state.symn) {
157411827SRod.Evans@Sun.COM (void) fprintf(stderr,
157511827SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_CHBADSYMNDX), file,
157611827SRod.Evans@Sun.COM EC_WORD(sndx), chcache->c_name,
157711827SRod.Evans@Sun.COM EC_WORD(cndx));
157811827SRod.Evans@Sun.COM name = MSG_INTL(MSG_STR_UNKNOWN);
157911827SRod.Evans@Sun.COM } else {
158011827SRod.Evans@Sun.COM sym = (Sym *)(state.sym + sndx);
158111827SRod.Evans@Sun.COM name = string(chcache, sndx,
158211827SRod.Evans@Sun.COM strcache, file, sym->st_name);
158311827SRod.Evans@Sun.COM }
158411827SRod.Evans@Sun.COM
158511827SRod.Evans@Sun.COM /*
158611827SRod.Evans@Sun.COM * Display the family member.
158711827SRod.Evans@Sun.COM */
158811827SRod.Evans@Sun.COM (void) snprintf(_chain, MAXNDXSIZE,
158911827SRod.Evans@Sun.COM MSG_ORIG(MSG_FMT_INTEGER), cndx);
159011827SRod.Evans@Sun.COM (void) snprintf(_symndx, MAXNDXSIZE,
159111827SRod.Evans@Sun.COM MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(sndx));
159211827SRod.Evans@Sun.COM dbg_print(0, MSG_ORIG(MSG_FMT_CHAIN_INFO),
159311827SRod.Evans@Sun.COM _chain, _symndx, demangle(name, flags));
159411827SRod.Evans@Sun.COM
159511827SRod.Evans@Sun.COM cndx++;
159611827SRod.Evans@Sun.COM }
159711827SRod.Evans@Sun.COM }
159811827SRod.Evans@Sun.COM }
159911827SRod.Evans@Sun.COM return (objcap);
160011827SRod.Evans@Sun.COM }
160111827SRod.Evans@Sun.COM
160211827SRod.Evans@Sun.COM /*
160311827SRod.Evans@Sun.COM * Print the capabilities.
160411827SRod.Evans@Sun.COM *
160511827SRod.Evans@Sun.COM * A .SUNW_cap section can contain one or more, CA_SUNW_NULL terminated,
160611827SRod.Evans@Sun.COM * capabilities groups. The first group defines the object capabilities.
160711827SRod.Evans@Sun.COM * This group defines the minimum capability requirements of the entire
160811827SRod.Evans@Sun.COM * object file. If this is a dynamic object, this group should be associated
160911827SRod.Evans@Sun.COM * with a PT_SUNWCAP program header.
161011827SRod.Evans@Sun.COM *
161111827SRod.Evans@Sun.COM * Additional capabilities groups define the association of individual symbols
161211827SRod.Evans@Sun.COM * to specific capabilities.
16130Sstevel@tonic-gate */
16140Sstevel@tonic-gate static void
cap(const char * file,Cache * cache,Word shnum,Word phnum,Ehdr * ehdr,uchar_t osabi,Elf * elf,uint_t flags)16151618Srie cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr,
161611827SRod.Evans@Sun.COM uchar_t osabi, Elf *elf, uint_t flags)
16170Sstevel@tonic-gate {
16181618Srie Word cnt;
16197833SRod.Evans@Sun.COM Shdr *cshdr = NULL;
16203466Srie Cache *ccache;
16211618Srie Off cphdr_off = 0;
16221618Srie Xword cphdr_sz;
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate /*
162511827SRod.Evans@Sun.COM * Determine if a global capabilities header exists.
16260Sstevel@tonic-gate */
16271618Srie if (phnum) {
16281618Srie Phdr *phdr;
16290Sstevel@tonic-gate
16301618Srie if ((phdr = elf_getphdr(elf)) == NULL) {
16310Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
16320Sstevel@tonic-gate return;
16330Sstevel@tonic-gate }
16340Sstevel@tonic-gate
16351618Srie for (cnt = 0; cnt < phnum; phdr++, cnt++) {
16361618Srie if (phdr->p_type == PT_SUNWCAP) {
16371618Srie cphdr_off = phdr->p_offset;
16381618Srie cphdr_sz = phdr->p_filesz;
16391618Srie break;
16401618Srie }
16410Sstevel@tonic-gate }
16420Sstevel@tonic-gate }
16430Sstevel@tonic-gate
16440Sstevel@tonic-gate /*
164511827SRod.Evans@Sun.COM * Determine if a capabilities section exists.
16460Sstevel@tonic-gate */
16470Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
16481618Srie Cache *_cache = &cache[cnt];
16491618Srie Shdr *shdr = _cache->c_shdr;
16500Sstevel@tonic-gate
165111827SRod.Evans@Sun.COM /*
165211827SRod.Evans@Sun.COM * Process any capabilities information.
165311827SRod.Evans@Sun.COM */
165411827SRod.Evans@Sun.COM if (shdr->sh_type == SHT_SUNW_cap) {
165511827SRod.Evans@Sun.COM if (cap_section(file, cache, shnum, _cache, osabi,
165611827SRod.Evans@Sun.COM ehdr, flags)) {
165711827SRod.Evans@Sun.COM /*
165811827SRod.Evans@Sun.COM * If this section defined an object capability
165911827SRod.Evans@Sun.COM * group, retain the section information for
166011827SRod.Evans@Sun.COM * program header validation.
166111827SRod.Evans@Sun.COM */
166211827SRod.Evans@Sun.COM ccache = _cache;
166311827SRod.Evans@Sun.COM cshdr = shdr;
166411827SRod.Evans@Sun.COM }
16650Sstevel@tonic-gate continue;
166611827SRod.Evans@Sun.COM }
16670Sstevel@tonic-gate }
16680Sstevel@tonic-gate
16697833SRod.Evans@Sun.COM if ((cshdr == NULL) && (cphdr_off == 0))
16700Sstevel@tonic-gate return;
16710Sstevel@tonic-gate
167211827SRod.Evans@Sun.COM if (cphdr_off && (cshdr == NULL))
16730Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file);
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate /*
167611827SRod.Evans@Sun.COM * If this object is an executable or shared object, and it provided
167711827SRod.Evans@Sun.COM * an object capabilities group, then the group should have an
167811827SRod.Evans@Sun.COM * accompanying PT_SUNWCAP program header.
16790Sstevel@tonic-gate */
16800Sstevel@tonic-gate if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) {
168111827SRod.Evans@Sun.COM if (cphdr_off == 0) {
16820Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2),
168311827SRod.Evans@Sun.COM file, EC_WORD(elf_ndxscn(ccache->c_scn)),
168411827SRod.Evans@Sun.COM ccache->c_name);
168511827SRod.Evans@Sun.COM } else if ((cphdr_off != cshdr->sh_offset) ||
168611827SRod.Evans@Sun.COM (cphdr_sz != cshdr->sh_size)) {
16870Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3),
168811827SRod.Evans@Sun.COM file, EC_WORD(elf_ndxscn(ccache->c_scn)),
168911827SRod.Evans@Sun.COM ccache->c_name);
169011827SRod.Evans@Sun.COM }
16910Sstevel@tonic-gate }
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate /*
16950Sstevel@tonic-gate * Print the interpretor.
16960Sstevel@tonic-gate */
16970Sstevel@tonic-gate static void
interp(const char * file,Cache * cache,Word shnum,Word phnum,Elf * elf)16981618Srie interp(const char *file, Cache *cache, Word shnum, Word phnum, Elf *elf)
16990Sstevel@tonic-gate {
17009085SAli.Bahrami@Sun.COM static Word phdr_types[] = { PT_INTERP };
17019085SAli.Bahrami@Sun.COM
17029085SAli.Bahrami@Sun.COM
17031618Srie Word cnt;
17049085SAli.Bahrami@Sun.COM Shdr *ishdr = NULL;
17051618Srie Cache *icache;
17061618Srie Off iphdr_off = 0;
17071618Srie Xword iphdr_fsz;
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate /*
17100Sstevel@tonic-gate * Determine if an interp header exists.
17110Sstevel@tonic-gate */
17121618Srie if (phnum) {
17131618Srie Phdr *phdr;
17140Sstevel@tonic-gate
17159085SAli.Bahrami@Sun.COM phdr = getphdr(phnum, phdr_types,
17169085SAli.Bahrami@Sun.COM sizeof (phdr_types) / sizeof (*phdr_types), file, elf);
17179085SAli.Bahrami@Sun.COM if (phdr != NULL) {
17181618Srie iphdr_off = phdr->p_offset;
17191618Srie iphdr_fsz = phdr->p_filesz;
17200Sstevel@tonic-gate }
17210Sstevel@tonic-gate }
17220Sstevel@tonic-gate
17230Sstevel@tonic-gate if (iphdr_off == 0)
17240Sstevel@tonic-gate return;
17250Sstevel@tonic-gate
17260Sstevel@tonic-gate /*
17270Sstevel@tonic-gate * Determine if an interp section exists.
17280Sstevel@tonic-gate */
17290Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
17301618Srie Cache *_cache = &cache[cnt];
17311618Srie Shdr *shdr = _cache->c_shdr;
17320Sstevel@tonic-gate
17330Sstevel@tonic-gate /*
17340Sstevel@tonic-gate * Scan sections to find a section which contains the PT_INTERP
17350Sstevel@tonic-gate * string. The target section can't be in a NOBITS section.
17360Sstevel@tonic-gate */
17370Sstevel@tonic-gate if ((shdr->sh_type == SHT_NOBITS) ||
17380Sstevel@tonic-gate (iphdr_off < shdr->sh_offset) ||
17391618Srie (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size))
17400Sstevel@tonic-gate continue;
17410Sstevel@tonic-gate
17420Sstevel@tonic-gate icache = _cache;
17430Sstevel@tonic-gate ishdr = shdr;
17440Sstevel@tonic-gate break;
17450Sstevel@tonic-gate }
17460Sstevel@tonic-gate
17470Sstevel@tonic-gate /*
17480Sstevel@tonic-gate * Print the interpreter string based on the offset defined in the
17490Sstevel@tonic-gate * program header, as this is the offset used by the kernel.
17500Sstevel@tonic-gate */
17513466Srie if (ishdr && icache->c_data) {
17521618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
17531618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name);
17541618Srie dbg_print(0, MSG_ORIG(MSG_FMT_INDENT),
17550Sstevel@tonic-gate (char *)icache->c_data->d_buf +
17560Sstevel@tonic-gate (iphdr_off - ishdr->sh_offset));
17570Sstevel@tonic-gate } else
17580Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file);
17590Sstevel@tonic-gate
17600Sstevel@tonic-gate /*
17610Sstevel@tonic-gate * If there are any inconsistences between the program header and
17620Sstevel@tonic-gate * section information, flag them.
17630Sstevel@tonic-gate */
17640Sstevel@tonic-gate if (ishdr && ((iphdr_off != ishdr->sh_offset) ||
17651618Srie (iphdr_fsz != ishdr->sh_size))) {
17660Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file,
17670Sstevel@tonic-gate icache->c_name);
17680Sstevel@tonic-gate }
17690Sstevel@tonic-gate }
17700Sstevel@tonic-gate
17710Sstevel@tonic-gate /*
17720Sstevel@tonic-gate * Print the syminfo section.
17730Sstevel@tonic-gate */
17740Sstevel@tonic-gate static void
syminfo(Cache * cache,Word shnum,Ehdr * ehdr,uchar_t osabi,const char * file)1775*11993SAli.Bahrami@Sun.COM syminfo(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, const char *file)
17760Sstevel@tonic-gate {
17771618Srie Shdr *infoshdr;
17781618Srie Syminfo *info;
17791618Srie Sym *syms;
17801618Srie Dyn *dyns;
1781*11993SAli.Bahrami@Sun.COM Word infonum, cnt, ndx, symnum, dynnum;
1782*11993SAli.Bahrami@Sun.COM Cache *infocache = NULL, *dyncache = NULL, *symsec, *strsec;
1783*11993SAli.Bahrami@Sun.COM Boolean *dynerr;
17840Sstevel@tonic-gate
17850Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
17861618Srie if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) {
17871618Srie infocache = &cache[cnt];
17880Sstevel@tonic-gate break;
17890Sstevel@tonic-gate }
17900Sstevel@tonic-gate }
17919085SAli.Bahrami@Sun.COM if (infocache == NULL)
17920Sstevel@tonic-gate return;
17930Sstevel@tonic-gate
17941618Srie infoshdr = infocache->c_shdr;
17951618Srie if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) {
17960Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
17971618Srie file, infocache->c_name);
17980Sstevel@tonic-gate return;
17990Sstevel@tonic-gate }
18003466Srie if (infocache->c_data == NULL)
18013466Srie return;
18023466Srie
18031618Srie infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize);
18041618Srie info = (Syminfo *)infocache->c_data->d_buf;
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate /*
1807*11993SAli.Bahrami@Sun.COM * If there is no associated dynamic section, determine if one
1808*11993SAli.Bahrami@Sun.COM * is needed, and if so issue a warning. If there is an
1809*11993SAli.Bahrami@Sun.COM * associated dynamic section, validate it and get the data buffer
1810*11993SAli.Bahrami@Sun.COM * for it.
18110Sstevel@tonic-gate */
1812*11993SAli.Bahrami@Sun.COM dyns = NULL;
1813*11993SAli.Bahrami@Sun.COM dynnum = 0;
1814*11993SAli.Bahrami@Sun.COM if (infoshdr->sh_info == 0) {
1815*11993SAli.Bahrami@Sun.COM Syminfo *_info = info + 1;
1816*11993SAli.Bahrami@Sun.COM
1817*11993SAli.Bahrami@Sun.COM for (ndx = 1; ndx < infonum; ndx++, _info++) {
1818*11993SAli.Bahrami@Sun.COM if ((_info->si_flags == 0) && (_info->si_boundto == 0))
1819*11993SAli.Bahrami@Sun.COM continue;
1820*11993SAli.Bahrami@Sun.COM
1821*11993SAli.Bahrami@Sun.COM if (_info->si_boundto < SYMINFO_BT_LOWRESERVE)
1822*11993SAli.Bahrami@Sun.COM (void) fprintf(stderr,
1823*11993SAli.Bahrami@Sun.COM MSG_INTL(MSG_ERR_BADSHINFO), file,
1824*11993SAli.Bahrami@Sun.COM infocache->c_name,
1825*11993SAli.Bahrami@Sun.COM EC_WORD(infoshdr->sh_info));
1826*11993SAli.Bahrami@Sun.COM }
1827*11993SAli.Bahrami@Sun.COM } else if ((infoshdr->sh_info >= shnum) ||
1828*11993SAli.Bahrami@Sun.COM (cache[infoshdr->sh_info].c_shdr->sh_type != SHT_DYNAMIC)) {
18290Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
18301618Srie file, infocache->c_name, EC_WORD(infoshdr->sh_info));
1831*11993SAli.Bahrami@Sun.COM } else {
1832*11993SAli.Bahrami@Sun.COM dyncache = &cache[infoshdr->sh_info];
1833*11993SAli.Bahrami@Sun.COM if ((dyncache->c_data == NULL) ||
1834*11993SAli.Bahrami@Sun.COM ((dyns = dyncache->c_data->d_buf) == NULL)) {
1835*11993SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1836*11993SAli.Bahrami@Sun.COM file, dyncache->c_name);
1837*11993SAli.Bahrami@Sun.COM }
1838*11993SAli.Bahrami@Sun.COM if (dyns != NULL) {
1839*11993SAli.Bahrami@Sun.COM dynnum = dyncache->c_shdr->sh_size /
1840*11993SAli.Bahrami@Sun.COM dyncache->c_shdr->sh_entsize;
1841*11993SAli.Bahrami@Sun.COM
1842*11993SAli.Bahrami@Sun.COM /*
1843*11993SAli.Bahrami@Sun.COM * We validate the type of dynamic elements referenced
1844*11993SAli.Bahrami@Sun.COM * from the syminfo. This array is used report any
1845*11993SAli.Bahrami@Sun.COM * bad dynamic entries.
1846*11993SAli.Bahrami@Sun.COM */
1847*11993SAli.Bahrami@Sun.COM if ((dynerr = calloc(dynnum, sizeof (*dynerr))) ==
1848*11993SAli.Bahrami@Sun.COM NULL) {
1849*11993SAli.Bahrami@Sun.COM int err = errno;
1850*11993SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
1851*11993SAli.Bahrami@Sun.COM file, strerror(err));
1852*11993SAli.Bahrami@Sun.COM return;
1853*11993SAli.Bahrami@Sun.COM }
1854*11993SAli.Bahrami@Sun.COM }
18550Sstevel@tonic-gate }
18560Sstevel@tonic-gate
18570Sstevel@tonic-gate /*
18581618Srie * Get the data buffer for the associated symbol table and string table.
18590Sstevel@tonic-gate */
18601618Srie if (stringtbl(cache, 1, cnt, shnum, file,
18611618Srie &symnum, &symsec, &strsec) == 0)
18620Sstevel@tonic-gate return;
18630Sstevel@tonic-gate
18641618Srie syms = symsec->c_data->d_buf;
18650Sstevel@tonic-gate
18661618Srie /*
18671618Srie * Loop through the syminfo entries.
18681618Srie */
18691618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
18701618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name);
18711618Srie Elf_syminfo_title(0);
18720Sstevel@tonic-gate
18731618Srie for (ndx = 1, info++; ndx < infonum; ndx++, info++) {
18741618Srie Sym *sym;
1875*11993SAli.Bahrami@Sun.COM const char *needed, *name;
1876*11993SAli.Bahrami@Sun.COM Word expect_dt;
1877*11993SAli.Bahrami@Sun.COM Word boundto = info->si_boundto;
1878*11993SAli.Bahrami@Sun.COM
1879*11993SAli.Bahrami@Sun.COM if ((info->si_flags == 0) && (boundto == 0))
18800Sstevel@tonic-gate continue;
18810Sstevel@tonic-gate
18821618Srie sym = &syms[ndx];
18831618Srie name = string(infocache, ndx, strsec, file, sym->st_name);
18840Sstevel@tonic-gate
1885*11993SAli.Bahrami@Sun.COM /* Is si_boundto set to one of the reserved values? */
1886*11993SAli.Bahrami@Sun.COM if (boundto >= SYMINFO_BT_LOWRESERVE) {
1887*11993SAli.Bahrami@Sun.COM Elf_syminfo_entry(0, ndx, info, name, NULL);
1888*11993SAli.Bahrami@Sun.COM continue;
1889*11993SAli.Bahrami@Sun.COM }
1890*11993SAli.Bahrami@Sun.COM
1891*11993SAli.Bahrami@Sun.COM /*
1892*11993SAli.Bahrami@Sun.COM * si_boundto is referencing a dynamic section. If we don't
1893*11993SAli.Bahrami@Sun.COM * have one, an error was already issued above, so it suffices
1894*11993SAli.Bahrami@Sun.COM * to display an empty string. If we are out of bounds, then
1895*11993SAli.Bahrami@Sun.COM * report that and then display an empty string.
1896*11993SAli.Bahrami@Sun.COM */
1897*11993SAli.Bahrami@Sun.COM if ((dyns == NULL) || (boundto >= dynnum)) {
1898*11993SAli.Bahrami@Sun.COM if (dyns != NULL)
1899*11993SAli.Bahrami@Sun.COM (void) fprintf(stderr,
1900*11993SAli.Bahrami@Sun.COM MSG_INTL(MSG_ERR_BADSIDYNNDX), file,
1901*11993SAli.Bahrami@Sun.COM infocache->c_ndx, infocache->c_name,
1902*11993SAli.Bahrami@Sun.COM EC_WORD(ndx), EC_WORD(dynnum - 1),
1903*11993SAli.Bahrami@Sun.COM EC_WORD(boundto));
1904*11993SAli.Bahrami@Sun.COM Elf_syminfo_entry(0, ndx, info, name,
1905*11993SAli.Bahrami@Sun.COM MSG_ORIG(MSG_STR_EMPTY));
1906*11993SAli.Bahrami@Sun.COM continue;
1907*11993SAli.Bahrami@Sun.COM }
1908*11993SAli.Bahrami@Sun.COM
1909*11993SAli.Bahrami@Sun.COM /*
1910*11993SAli.Bahrami@Sun.COM * The si_boundto reference expects a specific dynamic element
1911*11993SAli.Bahrami@Sun.COM * type at the given index. The dynamic element is always a
1912*11993SAli.Bahrami@Sun.COM * string that gives an object name. The specific type depends
1913*11993SAli.Bahrami@Sun.COM * on the si_flags present. Ensure that we've got the right
1914*11993SAli.Bahrami@Sun.COM * type.
1915*11993SAli.Bahrami@Sun.COM */
1916*11993SAli.Bahrami@Sun.COM if (info->si_flags & SYMINFO_FLG_FILTER)
1917*11993SAli.Bahrami@Sun.COM expect_dt = DT_SUNW_FILTER;
1918*11993SAli.Bahrami@Sun.COM else if (info->si_flags & SYMINFO_FLG_AUXILIARY)
1919*11993SAli.Bahrami@Sun.COM expect_dt = DT_SUNW_AUXILIARY;
1920*11993SAli.Bahrami@Sun.COM else if (info->si_flags & (SYMINFO_FLG_DIRECT |
1921*11993SAli.Bahrami@Sun.COM SYMINFO_FLG_LAZYLOAD | SYMINFO_FLG_DIRECTBIND))
1922*11993SAli.Bahrami@Sun.COM expect_dt = DT_NEEDED;
1923*11993SAli.Bahrami@Sun.COM else
1924*11993SAli.Bahrami@Sun.COM expect_dt = DT_NULL; /* means we ignore the type */
1925*11993SAli.Bahrami@Sun.COM
1926*11993SAli.Bahrami@Sun.COM if ((dyns[boundto].d_tag != expect_dt) &&
1927*11993SAli.Bahrami@Sun.COM (expect_dt != DT_NULL)) {
1928*11993SAli.Bahrami@Sun.COM Conv_inv_buf_t buf1, buf2;
1929*11993SAli.Bahrami@Sun.COM
1930*11993SAli.Bahrami@Sun.COM /* Only complain about each dynamic element once */
1931*11993SAli.Bahrami@Sun.COM if (!dynerr[boundto]) {
1932*11993SAli.Bahrami@Sun.COM (void) fprintf(stderr,
1933*11993SAli.Bahrami@Sun.COM MSG_INTL(MSG_ERR_BADSIDYNTAG),
1934*11993SAli.Bahrami@Sun.COM file, infocache->c_ndx, infocache->c_name,
1935*11993SAli.Bahrami@Sun.COM EC_WORD(ndx), dyncache->c_ndx,
1936*11993SAli.Bahrami@Sun.COM dyncache->c_name, EC_WORD(boundto),
1937*11993SAli.Bahrami@Sun.COM conv_dyn_tag(expect_dt, osabi,
1938*11993SAli.Bahrami@Sun.COM ehdr->e_machine, CONV_FMT_ALT_CF, &buf1),
1939*11993SAli.Bahrami@Sun.COM conv_dyn_tag(dyns[boundto].d_tag, osabi,
1940*11993SAli.Bahrami@Sun.COM ehdr->e_machine, CONV_FMT_ALT_CF, &buf2));
1941*11993SAli.Bahrami@Sun.COM dynerr[boundto] = TRUE;
1942*11993SAli.Bahrami@Sun.COM }
1943*11993SAli.Bahrami@Sun.COM }
1944*11993SAli.Bahrami@Sun.COM
1945*11993SAli.Bahrami@Sun.COM /*
1946*11993SAli.Bahrami@Sun.COM * Whether or not the DT item we're pointing at is
1947*11993SAli.Bahrami@Sun.COM * of the right type, if it's a type we recognize as
1948*11993SAli.Bahrami@Sun.COM * providing a string, go ahead and show it. Otherwise
1949*11993SAli.Bahrami@Sun.COM * an empty string.
1950*11993SAli.Bahrami@Sun.COM */
1951*11993SAli.Bahrami@Sun.COM switch (dyns[boundto].d_tag) {
1952*11993SAli.Bahrami@Sun.COM case DT_NEEDED:
1953*11993SAli.Bahrami@Sun.COM case DT_SONAME:
1954*11993SAli.Bahrami@Sun.COM case DT_RPATH:
1955*11993SAli.Bahrami@Sun.COM case DT_RUNPATH:
1956*11993SAli.Bahrami@Sun.COM case DT_CONFIG:
1957*11993SAli.Bahrami@Sun.COM case DT_DEPAUDIT:
1958*11993SAli.Bahrami@Sun.COM case DT_USED:
1959*11993SAli.Bahrami@Sun.COM case DT_AUDIT:
1960*11993SAli.Bahrami@Sun.COM case DT_SUNW_AUXILIARY:
1961*11993SAli.Bahrami@Sun.COM case DT_SUNW_FILTER:
1962*11993SAli.Bahrami@Sun.COM case DT_FILTER:
1963*11993SAli.Bahrami@Sun.COM case DT_AUXILIARY:
1964*11993SAli.Bahrami@Sun.COM needed = string(infocache, boundto,
1965*11993SAli.Bahrami@Sun.COM strsec, file, dyns[boundto].d_un.d_val);
1966*11993SAli.Bahrami@Sun.COM break;
1967*11993SAli.Bahrami@Sun.COM default:
1968*11993SAli.Bahrami@Sun.COM needed = MSG_ORIG(MSG_STR_EMPTY);
19690Sstevel@tonic-gate }
19701618Srie Elf_syminfo_entry(0, ndx, info, name, needed);
19710Sstevel@tonic-gate }
1972*11993SAli.Bahrami@Sun.COM if (dyns != NULL)
1973*11993SAli.Bahrami@Sun.COM free(dynerr);
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate
19760Sstevel@tonic-gate /*
19770Sstevel@tonic-gate * Print version definition section entries.
19780Sstevel@tonic-gate */
19790Sstevel@tonic-gate static void
version_def(Verdef * vdf,Word vdf_num,Cache * vcache,Cache * scache,const char * file)19804716Sab196087 version_def(Verdef *vdf, Word vdf_num, Cache *vcache, Cache *scache,
19810Sstevel@tonic-gate const char *file)
19820Sstevel@tonic-gate {
19831618Srie Word cnt;
19841618Srie char index[MAXNDXSIZE];
19850Sstevel@tonic-gate
19861618Srie Elf_ver_def_title(0);
19870Sstevel@tonic-gate
19884716Sab196087 for (cnt = 1; cnt <= vdf_num; cnt++,
19891618Srie vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
19907682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf;
19917682SAli.Bahrami@Sun.COM const char *name, *dep;
19927682SAli.Bahrami@Sun.COM Half vcnt = vdf->vd_cnt - 1;
19937682SAli.Bahrami@Sun.COM Half ndx = vdf->vd_ndx;
19947682SAli.Bahrami@Sun.COM Verdaux *vdap = (Verdaux *)((uintptr_t)vdf + vdf->vd_aux);
19950Sstevel@tonic-gate
19960Sstevel@tonic-gate /*
19970Sstevel@tonic-gate * Obtain the name and first dependency (if any).
19980Sstevel@tonic-gate */
19990Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vdap->vda_name);
20001618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next);
20010Sstevel@tonic-gate if (vcnt)
20020Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vdap->vda_name);
20030Sstevel@tonic-gate else
20040Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY);
20050Sstevel@tonic-gate
20060Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX),
20070Sstevel@tonic-gate EC_XWORD(ndx));
20081618Srie Elf_ver_line_1(0, index, name, dep,
20097682SAli.Bahrami@Sun.COM conv_ver_flags(vdf->vd_flags, 0, &ver_flags_buf));
20100Sstevel@tonic-gate
20110Sstevel@tonic-gate /*
20120Sstevel@tonic-gate * Print any additional dependencies.
20130Sstevel@tonic-gate */
20140Sstevel@tonic-gate if (vcnt) {
20151618Srie vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next);
20160Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--,
20171618Srie vdap = (Verdaux *)((uintptr_t)vdap +
20180Sstevel@tonic-gate vdap->vda_next)) {
20190Sstevel@tonic-gate dep = string(vcache, cnt, scache, file,
20200Sstevel@tonic-gate vdap->vda_name);
20211618Srie Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep);
20220Sstevel@tonic-gate }
20230Sstevel@tonic-gate }
20240Sstevel@tonic-gate }
20250Sstevel@tonic-gate }
20260Sstevel@tonic-gate
20270Sstevel@tonic-gate /*
20284716Sab196087 * Print version needed section entries.
20294716Sab196087 *
20304716Sab196087 * entry:
20314716Sab196087 * vnd - Address of verneed data
20324716Sab196087 * vnd_num - # of Verneed entries
20334716Sab196087 * vcache - Cache of verneed section being processed
20344716Sab196087 * scache - Cache of associated string table section
20354716Sab196087 * file - Name of object being processed.
20364716Sab196087 * versym - Information about versym section
20374716Sab196087 *
20384716Sab196087 * exit:
20394716Sab196087 * The versions have been printed. If GNU style versioning
20404716Sab196087 * is in effect, versym->max_verndx has been updated to
20414716Sab196087 * contain the largest version index seen.
20427682SAli.Bahrami@Sun.COM *
20437682SAli.Bahrami@Sun.COM * note:
20447682SAli.Bahrami@Sun.COM * The versym section of an object that follows the original
20457682SAli.Bahrami@Sun.COM * Solaris versioning rules only contains indexes into the verdef
20467682SAli.Bahrami@Sun.COM * section. Symbols defined in other objects (UNDEF) are given
20477682SAli.Bahrami@Sun.COM * a version of 0, indicating that they are not defined by
20487682SAli.Bahrami@Sun.COM * this file, and the Verneed entries do not have associated version
20497682SAli.Bahrami@Sun.COM * indexes. For these reasons, we do not display a version index
20507682SAli.Bahrami@Sun.COM * for original-style Verneed sections.
20517682SAli.Bahrami@Sun.COM *
20527682SAli.Bahrami@Sun.COM * The GNU versioning extensions alter this: Symbols defined in other
20537682SAli.Bahrami@Sun.COM * objects receive a version index in the range above those defined
20547682SAli.Bahrami@Sun.COM * by the Verdef section, and the vna_other field of the Vernaux
20557682SAli.Bahrami@Sun.COM * structs inside the Verneed section contain the version index for
20567682SAli.Bahrami@Sun.COM * that item. We therefore display the index when showing the
20577682SAli.Bahrami@Sun.COM * contents of a GNU style Verneed section. You should not
20587682SAli.Bahrami@Sun.COM * necessarily expect these indexes to appear in sorted
20597682SAli.Bahrami@Sun.COM * order --- it seems that the GNU ld assigns the versions as
20607682SAli.Bahrami@Sun.COM * symbols are encountered during linking, and then the results
20617682SAli.Bahrami@Sun.COM * are assembled into the Verneed section afterwards.
20620Sstevel@tonic-gate */
20630Sstevel@tonic-gate static void
version_need(Verneed * vnd,Word vnd_num,Cache * vcache,Cache * scache,const char * file,VERSYM_STATE * versym)20644716Sab196087 version_need(Verneed *vnd, Word vnd_num, Cache *vcache, Cache *scache,
20654716Sab196087 const char *file, VERSYM_STATE *versym)
20660Sstevel@tonic-gate {
20674716Sab196087 Word cnt;
20684716Sab196087 char index[MAXNDXSIZE];
20694716Sab196087 const char *index_str;
20704716Sab196087
20717682SAli.Bahrami@Sun.COM Elf_ver_need_title(0, versym->gnu_needed);
20724716Sab196087
20734716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++,
20741618Srie vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
20757682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf;
20767682SAli.Bahrami@Sun.COM const char *name, *dep;
20777682SAli.Bahrami@Sun.COM Half vcnt = vnd->vn_cnt;
20784433Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux);
20790Sstevel@tonic-gate
20800Sstevel@tonic-gate /*
20810Sstevel@tonic-gate * Obtain the name of the needed file and the version name
20820Sstevel@tonic-gate * within it that we're dependent on. Note that the count
20830Sstevel@tonic-gate * should be at least one, otherwise this is a pretty bogus
20840Sstevel@tonic-gate * entry.
20850Sstevel@tonic-gate */
20860Sstevel@tonic-gate name = string(vcache, cnt, scache, file, vnd->vn_file);
20870Sstevel@tonic-gate if (vcnt)
20880Sstevel@tonic-gate dep = string(vcache, cnt, scache, file, vnap->vna_name);
20890Sstevel@tonic-gate else
20900Sstevel@tonic-gate dep = MSG_INTL(MSG_STR_NULL);
20910Sstevel@tonic-gate
20927682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0) { /* Traditional form */
20937682SAli.Bahrami@Sun.COM index_str = MSG_ORIG(MSG_STR_EMPTY);
20947682SAli.Bahrami@Sun.COM } else { /* GNU form */
20957682SAli.Bahrami@Sun.COM index_str = index;
20964716Sab196087 /* Format the version index value */
20974716Sab196087 (void) snprintf(index, MAXNDXSIZE,
20984716Sab196087 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(vnap->vna_other));
20994716Sab196087 if (vnap->vna_other > versym->max_verndx)
21004716Sab196087 versym->max_verndx = vnap->vna_other;
21014716Sab196087 }
21024716Sab196087 Elf_ver_line_1(0, index_str, name, dep,
21037682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags, 0, &ver_flags_buf));
21040Sstevel@tonic-gate
21050Sstevel@tonic-gate /*
21060Sstevel@tonic-gate * Print any additional version dependencies.
21070Sstevel@tonic-gate */
21080Sstevel@tonic-gate if (vcnt) {
21091618Srie vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next);
21100Sstevel@tonic-gate for (vcnt--; vcnt; vcnt--,
21111618Srie vnap = (Vernaux *)((uintptr_t)vnap +
21120Sstevel@tonic-gate vnap->vna_next)) {
21130Sstevel@tonic-gate dep = string(vcache, cnt, scache, file,
21140Sstevel@tonic-gate vnap->vna_name);
21157682SAli.Bahrami@Sun.COM if (vnap->vna_other > 0) {
21164716Sab196087 /* Format the next index value */
21174716Sab196087 (void) snprintf(index, MAXNDXSIZE,
21184716Sab196087 MSG_ORIG(MSG_FMT_INDEX),
21194716Sab196087 EC_XWORD(vnap->vna_other));
21207682SAli.Bahrami@Sun.COM Elf_ver_line_1(0, index,
21214716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep,
21227682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags,
21237682SAli.Bahrami@Sun.COM 0, &ver_flags_buf));
21244716Sab196087 if (vnap->vna_other >
21254716Sab196087 versym->max_verndx)
21264716Sab196087 versym->max_verndx =
21274716Sab196087 vnap->vna_other;
21284716Sab196087 } else {
21294716Sab196087 Elf_ver_line_3(0,
21304716Sab196087 MSG_ORIG(MSG_STR_EMPTY), dep,
21317682SAli.Bahrami@Sun.COM conv_ver_flags(vnap->vna_flags,
21327682SAli.Bahrami@Sun.COM 0, &ver_flags_buf));
21334716Sab196087 }
21344716Sab196087 }
21354716Sab196087 }
21364716Sab196087 }
21374716Sab196087 }
21384716Sab196087
21394716Sab196087 /*
21407682SAli.Bahrami@Sun.COM * Examine the Verneed section for information related to GNU
21417682SAli.Bahrami@Sun.COM * style Versym indexing:
21427682SAli.Bahrami@Sun.COM * - A non-zero vna_other field indicates that Versym indexes can
21437682SAli.Bahrami@Sun.COM * reference Verneed records.
21447682SAli.Bahrami@Sun.COM * - If the object uses GNU style Versym indexing, the
21457682SAli.Bahrami@Sun.COM * maximum index value is needed to detect bad Versym entries.
21464716Sab196087 *
21474716Sab196087 * entry:
21484716Sab196087 * vnd - Address of verneed data
21494716Sab196087 * vnd_num - # of Verneed entries
21504716Sab196087 * versym - Information about versym section
21514716Sab196087 *
21524716Sab196087 * exit:
21537682SAli.Bahrami@Sun.COM * If a non-zero vna_other field is seen, versym->gnu_needed is set.
21547682SAli.Bahrami@Sun.COM *
21554716Sab196087 * versym->max_verndx has been updated to contain the largest
21564716Sab196087 * version index seen.
21574716Sab196087 */
21584716Sab196087 static void
update_gnu_verndx(Verneed * vnd,Word vnd_num,VERSYM_STATE * versym)21597682SAli.Bahrami@Sun.COM update_gnu_verndx(Verneed *vnd, Word vnd_num, VERSYM_STATE *versym)
21604716Sab196087 {
21614716Sab196087 Word cnt;
21624716Sab196087
21634716Sab196087 for (cnt = 1; cnt <= vnd_num; cnt++,
21644716Sab196087 vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
21654716Sab196087 Half vcnt = vnd->vn_cnt;
21664716Sab196087 Vernaux *vnap = (Vernaux *)((uintptr_t)vnd + vnd->vn_aux);
21674716Sab196087
21687682SAli.Bahrami@Sun.COM /*
21697682SAli.Bahrami@Sun.COM * A non-zero value of vna_other indicates that this
21707682SAli.Bahrami@Sun.COM * object references VERNEED items from the VERSYM
21717682SAli.Bahrami@Sun.COM * array.
21727682SAli.Bahrami@Sun.COM */
21737682SAli.Bahrami@Sun.COM if (vnap->vna_other != 0) {
21747682SAli.Bahrami@Sun.COM versym->gnu_needed = 1;
21757682SAli.Bahrami@Sun.COM if (vnap->vna_other > versym->max_verndx)
21767682SAli.Bahrami@Sun.COM versym->max_verndx = vnap->vna_other;
21777682SAli.Bahrami@Sun.COM }
21784716Sab196087
21794716Sab196087 /*
21804716Sab196087 * Check any additional version dependencies.
21814716Sab196087 */
21824716Sab196087 if (vcnt) {
21834716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next);
21844716Sab196087 for (vcnt--; vcnt; vcnt--,
21854716Sab196087 vnap = (Vernaux *)((uintptr_t)vnap +
21864716Sab196087 vnap->vna_next)) {
21877682SAli.Bahrami@Sun.COM if (vnap->vna_other == 0)
21887682SAli.Bahrami@Sun.COM continue;
21897682SAli.Bahrami@Sun.COM
21907682SAli.Bahrami@Sun.COM versym->gnu_needed = 1;
21914716Sab196087 if (vnap->vna_other > versym->max_verndx)
21924716Sab196087 versym->max_verndx = vnap->vna_other;
21930Sstevel@tonic-gate }
21940Sstevel@tonic-gate }
21950Sstevel@tonic-gate }
21960Sstevel@tonic-gate }
21970Sstevel@tonic-gate
21980Sstevel@tonic-gate /*
21993875Sab196087 * Display version section information if the flags require it.
22003875Sab196087 * Return version information needed by other output.
22013875Sab196087 *
22023875Sab196087 * entry:
22033875Sab196087 * cache - Cache of all section headers
22043875Sab196087 * shnum - # of sections in cache
22053875Sab196087 * file - Name of file
22063875Sab196087 * flags - Command line option flags
22073875Sab196087 * versym - VERSYM_STATE block to be filled in.
22080Sstevel@tonic-gate */
22093875Sab196087 static void
versions(Cache * cache,Word shnum,const char * file,uint_t flags,VERSYM_STATE * versym)22103875Sab196087 versions(Cache *cache, Word shnum, const char *file, uint_t flags,
22113875Sab196087 VERSYM_STATE *versym)
22120Sstevel@tonic-gate {
22130Sstevel@tonic-gate GElf_Word cnt;
22144716Sab196087 Cache *verdef_cache = NULL, *verneed_cache = NULL;
22154716Sab196087
22164716Sab196087
22174716Sab196087 /* Gather information about the version sections */
22183875Sab196087 bzero(versym, sizeof (*versym));
22194716Sab196087 versym->max_verndx = 1;
22200Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
22211618Srie Cache *_cache = &cache[cnt];
22221618Srie Shdr *shdr = _cache->c_shdr;
22234716Sab196087 Dyn *dyn;
22244716Sab196087 ulong_t numdyn;
22254716Sab196087
22264716Sab196087 switch (shdr->sh_type) {
22274716Sab196087 case SHT_DYNAMIC:
22284716Sab196087 /*
22294716Sab196087 * The GNU ld puts a DT_VERSYM entry in the dynamic
22304716Sab196087 * section so that the runtime linker can use it to
22314716Sab196087 * implement their versioning rules. They allow multiple
22324716Sab196087 * incompatible functions with the same name to exist
22334716Sab196087 * in different versions. The Solaris ld does not
22344716Sab196087 * support this mechanism, and as such, does not
22354716Sab196087 * produce DT_VERSYM. We use this fact to determine
22364716Sab196087 * which ld produced this object, and how to interpret
22374716Sab196087 * the version values.
22384716Sab196087 */
22394716Sab196087 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0) ||
22404716Sab196087 (_cache->c_data == NULL))
22414716Sab196087 continue;
22424716Sab196087 numdyn = shdr->sh_size / shdr->sh_entsize;
22434716Sab196087 dyn = (Dyn *)_cache->c_data->d_buf;
22444716Sab196087 for (; numdyn-- > 0; dyn++)
22454716Sab196087 if (dyn->d_tag == DT_VERSYM) {
22467682SAli.Bahrami@Sun.COM versym->gnu_full =
22477682SAli.Bahrami@Sun.COM versym->gnu_needed = 1;
22484716Sab196087 break;
22494716Sab196087 }
22504716Sab196087 break;
22514716Sab196087
22524716Sab196087 case SHT_SUNW_versym:
22534716Sab196087 /* Record data address for later symbol processing */
22544716Sab196087 if (_cache->c_data != NULL) {
22554716Sab196087 versym->cache = _cache;
22564716Sab196087 versym->data = _cache->c_data->d_buf;
22574716Sab196087 continue;
22584716Sab196087 }
22594716Sab196087 break;
22604716Sab196087
22614716Sab196087 case SHT_SUNW_verdef:
22624716Sab196087 case SHT_SUNW_verneed:
22634716Sab196087 /*
22644716Sab196087 * Ensure the data is non-NULL and the number
22654716Sab196087 * of items is non-zero. Otherwise, we don't
22664716Sab196087 * understand the section, and will not use it.
22674716Sab196087 */
22684716Sab196087 if ((_cache->c_data == NULL) ||
22694716Sab196087 (_cache->c_data->d_buf == NULL)) {
22704716Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
22714716Sab196087 file, _cache->c_name);
22724716Sab196087 continue;
22734716Sab196087 }
22744716Sab196087 if (shdr->sh_info == 0) {
22754716Sab196087 (void) fprintf(stderr,
22764716Sab196087 MSG_INTL(MSG_ERR_BADSHINFO),
22774716Sab196087 file, _cache->c_name,
22784716Sab196087 EC_WORD(shdr->sh_info));
22794716Sab196087 continue;
22804716Sab196087 }
22814716Sab196087
22824716Sab196087 /* Make sure the string table index is in range */
22834716Sab196087 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
22844716Sab196087 (void) fprintf(stderr,
22854716Sab196087 MSG_INTL(MSG_ERR_BADSHLINK), file,
22864716Sab196087 _cache->c_name, EC_WORD(shdr->sh_link));
22874716Sab196087 continue;
22884716Sab196087 }
22894716Sab196087
22904716Sab196087 /*
22914716Sab196087 * The section is usable. Save the cache entry.
22924716Sab196087 */
22934716Sab196087 if (shdr->sh_type == SHT_SUNW_verdef) {
22944716Sab196087 verdef_cache = _cache;
22954716Sab196087 /*
22964716Sab196087 * Under Solaris rules, if there is a verdef
22974716Sab196087 * section, the max versym index is number
22984716Sab196087 * of version definitions it supplies.
22994716Sab196087 */
23004716Sab196087 versym->max_verndx = shdr->sh_info;
23014716Sab196087 } else {
23024716Sab196087 verneed_cache = _cache;
23034716Sab196087 }
23044716Sab196087 break;
23054716Sab196087 }
23064716Sab196087 }
23074716Sab196087
23087682SAli.Bahrami@Sun.COM /*
23097682SAli.Bahrami@Sun.COM * If there is a Verneed section, examine it for information
23107682SAli.Bahrami@Sun.COM * related to GNU style versioning.
23117682SAli.Bahrami@Sun.COM */
23127682SAli.Bahrami@Sun.COM if (verneed_cache != NULL)
23137682SAli.Bahrami@Sun.COM update_gnu_verndx((Verneed *)verneed_cache->c_data->d_buf,
23147682SAli.Bahrami@Sun.COM verneed_cache->c_shdr->sh_info, versym);
23154716Sab196087
23164716Sab196087 /*
23174716Sab196087 * Now that all the information is available, display the
23187682SAli.Bahrami@Sun.COM * Verdef and Verneed section contents, if requested.
23194716Sab196087 */
23207682SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_VERSIONS) == 0)
23217682SAli.Bahrami@Sun.COM return;
23224716Sab196087 if (verdef_cache != NULL) {
23234716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
23244716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF),
23254716Sab196087 verdef_cache->c_name);
23264716Sab196087 version_def((Verdef *)verdef_cache->c_data->d_buf,
23274716Sab196087 verdef_cache->c_shdr->sh_info, verdef_cache,
23284716Sab196087 &cache[verdef_cache->c_shdr->sh_link], file);
23294716Sab196087 }
23304716Sab196087 if (verneed_cache != NULL) {
23314716Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
23324716Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED),
23334716Sab196087 verneed_cache->c_name);
23340Sstevel@tonic-gate /*
23354716Sab196087 * If GNU versioning applies to this object, version_need()
23364716Sab196087 * will update versym->max_verndx, and it is not
23377682SAli.Bahrami@Sun.COM * necessary to call update_gnu_verndx().
23380Sstevel@tonic-gate */
23394716Sab196087 version_need((Verneed *)verneed_cache->c_data->d_buf,
23404716Sab196087 verneed_cache->c_shdr->sh_info, verneed_cache,
23414716Sab196087 &cache[verneed_cache->c_shdr->sh_link], file, versym);
23420Sstevel@tonic-gate }
23430Sstevel@tonic-gate }
23440Sstevel@tonic-gate
23450Sstevel@tonic-gate /*
23463492Sab196087 * Search for and process any symbol tables.
23473492Sab196087 */
23483492Sab196087 void
symbols(Cache * cache,Word shnum,Ehdr * ehdr,uchar_t osabi,VERSYM_STATE * versym,const char * file,uint_t flags)23499273SAli.Bahrami@Sun.COM symbols(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi,
23509273SAli.Bahrami@Sun.COM VERSYM_STATE *versym, const char *file, uint_t flags)
23513492Sab196087 {
23523492Sab196087 SYMTBL_STATE state;
23533492Sab196087 Cache *_cache;
23543492Sab196087 Word secndx;
23553492Sab196087
23563492Sab196087 for (secndx = 1; secndx < shnum; secndx++) {
23573492Sab196087 Word symcnt;
23583492Sab196087 Shdr *shdr;
23593492Sab196087
23603492Sab196087 _cache = &cache[secndx];
23613492Sab196087 shdr = _cache->c_shdr;
23620Sstevel@tonic-gate
23630Sstevel@tonic-gate if ((shdr->sh_type != SHT_SYMTAB) &&
23642766Sab196087 (shdr->sh_type != SHT_DYNSYM) &&
23659273SAli.Bahrami@Sun.COM ((shdr->sh_type != SHT_SUNW_LDYNSYM) ||
23669273SAli.Bahrami@Sun.COM (osabi != ELFOSABI_SOLARIS)))
23670Sstevel@tonic-gate continue;
23685411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, secndx, shdr->sh_type))
23693466Srie continue;
23703466Srie
23713492Sab196087 if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr,
23729273SAli.Bahrami@Sun.COM osabi, versym, file, flags))
23730Sstevel@tonic-gate continue;
23740Sstevel@tonic-gate /*
23750Sstevel@tonic-gate * Loop through the symbol tables entries.
23760Sstevel@tonic-gate */
23771618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
23783492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname);
23791618Srie Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
23800Sstevel@tonic-gate
23813492Sab196087 for (symcnt = 0; symcnt < state.symn; symcnt++)
23824832Srie output_symbol(&state, symcnt, shdr->sh_info, symcnt,
23833492Sab196087 state.sym + symcnt);
23843492Sab196087 }
23853492Sab196087 }
23860Sstevel@tonic-gate
23873492Sab196087 /*
23883492Sab196087 * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections.
23893492Sab196087 * These sections are always associated with the .SUNW_ldynsym./.dynsym pair.
23903492Sab196087 */
23913492Sab196087 static void
sunw_sort(Cache * cache,Word shnum,Ehdr * ehdr,uchar_t osabi,VERSYM_STATE * versym,const char * file,uint_t flags)23929273SAli.Bahrami@Sun.COM sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi,
23939273SAli.Bahrami@Sun.COM VERSYM_STATE *versym, const char *file, uint_t flags)
23943492Sab196087 {
23953492Sab196087 SYMTBL_STATE ldynsym_state, dynsym_state;
23963492Sab196087 Cache *sortcache, *symcache;
23973492Sab196087 Shdr *sortshdr, *symshdr;
23983492Sab196087 Word sortsecndx, symsecndx;
23993492Sab196087 Word ldynsym_cnt;
24003492Sab196087 Word *ndx;
24013492Sab196087 Word ndxn;
24023492Sab196087 int output_cnt = 0;
24034734Sab196087 Conv_inv_buf_t inv_buf;
24040Sstevel@tonic-gate
24053492Sab196087 for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) {
24060Sstevel@tonic-gate
24073492Sab196087 sortcache = &cache[sortsecndx];
24083492Sab196087 sortshdr = sortcache->c_shdr;
24090Sstevel@tonic-gate
24103492Sab196087 if ((sortshdr->sh_type != SHT_SUNW_symsort) &&
24113492Sab196087 (sortshdr->sh_type != SHT_SUNW_tlssort))
24123492Sab196087 continue;
24135411Sab196087 if (!match(MATCH_F_ALL, sortcache->c_name, sortsecndx,
24145411Sab196087 sortshdr->sh_type))
24153492Sab196087 continue;
24160Sstevel@tonic-gate
24173492Sab196087 /*
24183492Sab196087 * If the section references a SUNW_ldynsym, then we
24193492Sab196087 * expect to see the associated .dynsym immediately
24203492Sab196087 * following. If it references a .dynsym, there is no
24213492Sab196087 * SUNW_ldynsym. If it is any other type, then we don't
24223492Sab196087 * know what to do with it.
24233492Sab196087 */
24243492Sab196087 if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) {
24253492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
24263492Sab196087 file, sortcache->c_name,
24273492Sab196087 EC_WORD(sortshdr->sh_link));
24283492Sab196087 continue;
24293492Sab196087 }
24303492Sab196087 symcache = &cache[sortshdr->sh_link];
24313492Sab196087 symshdr = symcache->c_shdr;
24323492Sab196087 symsecndx = sortshdr->sh_link;
24333492Sab196087 ldynsym_cnt = 0;
24343492Sab196087 switch (symshdr->sh_type) {
24353492Sab196087 case SHT_SUNW_LDYNSYM:
24363492Sab196087 if (!init_symtbl_state(&ldynsym_state, cache, shnum,
24379273SAli.Bahrami@Sun.COM symsecndx, ehdr, osabi, versym, file, flags))
24383492Sab196087 continue;
24393492Sab196087 ldynsym_cnt = ldynsym_state.symn;
24400Sstevel@tonic-gate /*
24413492Sab196087 * We know that the dynsym follows immediately
24423492Sab196087 * after the SUNW_ldynsym, and so, should be at
24433492Sab196087 * (sortshdr->sh_link + 1). However, elfdump is a
24443492Sab196087 * diagnostic tool, so we do the full paranoid
24453492Sab196087 * search instead.
24460Sstevel@tonic-gate */
24473492Sab196087 for (symsecndx = 1; symsecndx < shnum; symsecndx++) {
24483492Sab196087 symcache = &cache[symsecndx];
24493492Sab196087 symshdr = symcache->c_shdr;
24503492Sab196087 if (symshdr->sh_type == SHT_DYNSYM)
24513492Sab196087 break;
24523492Sab196087 }
24533492Sab196087 if (symsecndx >= shnum) { /* Dynsym not found! */
24540Sstevel@tonic-gate (void) fprintf(stderr,
24553492Sab196087 MSG_INTL(MSG_ERR_NODYNSYM),
24563492Sab196087 file, sortcache->c_name);
24573492Sab196087 continue;
24580Sstevel@tonic-gate }
24593492Sab196087 /* Fallthrough to process associated dynsym */
24607463SRod.Evans@Sun.COM /* FALLTHROUGH */
24613492Sab196087 case SHT_DYNSYM:
24623492Sab196087 if (!init_symtbl_state(&dynsym_state, cache, shnum,
24639273SAli.Bahrami@Sun.COM symsecndx, ehdr, osabi, versym, file, flags))
24643492Sab196087 continue;
24653492Sab196087 break;
24663492Sab196087 default:
24673492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC),
24689273SAli.Bahrami@Sun.COM file, sortcache->c_name,
24699273SAli.Bahrami@Sun.COM conv_sec_type(osabi, ehdr->e_machine,
24709273SAli.Bahrami@Sun.COM symshdr->sh_type, 0, &inv_buf));
24713492Sab196087 continue;
24723492Sab196087 }
24730Sstevel@tonic-gate
24743492Sab196087 /*
24753492Sab196087 * Output header
24763492Sab196087 */
24773492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
24783492Sab196087 if (ldynsym_cnt > 0) {
24793492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2),
24803492Sab196087 sortcache->c_name, ldynsym_state.secname,
24813492Sab196087 dynsym_state.secname);
24820Sstevel@tonic-gate /*
24833492Sab196087 * The data for .SUNW_ldynsym and dynsym sections
24843492Sab196087 * is supposed to be adjacent with SUNW_ldynsym coming
24853492Sab196087 * first. Check, and issue a warning if it isn't so.
24860Sstevel@tonic-gate */
24874665Sab196087 if (((ldynsym_state.sym + ldynsym_state.symn)
24884665Sab196087 != dynsym_state.sym) &&
24895411Sab196087 ((flags & FLG_CTL_FAKESHDR) == 0))
24903492Sab196087 (void) fprintf(stderr,
24913492Sab196087 MSG_INTL(MSG_ERR_LDYNNOTADJ), file,
24923492Sab196087 ldynsym_state.secname,
24933492Sab196087 dynsym_state.secname);
24943492Sab196087 } else {
24953492Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1),
24963492Sab196087 sortcache->c_name, dynsym_state.secname);
24973492Sab196087 }
24983492Sab196087 Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
24993492Sab196087
250011827SRod.Evans@Sun.COM /* If not first one, insert a line of white space */
25013492Sab196087 if (output_cnt++ > 0)
25023492Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
25033118Sab196087
25043492Sab196087 /*
25053492Sab196087 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of
25063492Sab196087 * symbol indices. Iterate over the array entries,
25073492Sab196087 * dispaying the referenced symbols.
25083492Sab196087 */
25093492Sab196087 ndxn = sortshdr->sh_size / sortshdr->sh_entsize;
25103492Sab196087 ndx = (Word *)sortcache->c_data->d_buf;
25113492Sab196087 for (; ndxn-- > 0; ndx++) {
25123492Sab196087 if (*ndx >= ldynsym_cnt) {
25133492Sab196087 Word sec_ndx = *ndx - ldynsym_cnt;
25143492Sab196087
25154832Srie output_symbol(&dynsym_state, sec_ndx, 0,
25163492Sab196087 *ndx, dynsym_state.sym + sec_ndx);
25173492Sab196087 } else {
25184832Srie output_symbol(&ldynsym_state, *ndx, 0,
25193492Sab196087 *ndx, ldynsym_state.sym + *ndx);
25200Sstevel@tonic-gate }
25210Sstevel@tonic-gate }
25220Sstevel@tonic-gate }
25230Sstevel@tonic-gate }
25240Sstevel@tonic-gate
25250Sstevel@tonic-gate /*
25260Sstevel@tonic-gate * Search for and process any relocation sections.
25270Sstevel@tonic-gate */
25280Sstevel@tonic-gate static void
reloc(Cache * cache,Word shnum,Ehdr * ehdr,const char * file)25297463SRod.Evans@Sun.COM reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *file)
25300Sstevel@tonic-gate {
25311618Srie Word cnt;
25320Sstevel@tonic-gate
25330Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
25341618Srie Word type, symnum;
25351618Srie Xword relndx, relnum, relsize;
25361618Srie void *rels;
25371618Srie Sym *syms;
25381618Srie Cache *symsec, *strsec;
25390Sstevel@tonic-gate Cache *_cache = &cache[cnt];
25401618Srie Shdr *shdr = _cache->c_shdr;
25411618Srie char *relname = _cache->c_name;
25424734Sab196087 Conv_inv_buf_t inv_buf;
25430Sstevel@tonic-gate
25440Sstevel@tonic-gate if (((type = shdr->sh_type) != SHT_RELA) &&
25450Sstevel@tonic-gate (type != SHT_REL))
25460Sstevel@tonic-gate continue;
25475411Sab196087 if (!match(MATCH_F_ALL, relname, cnt, type))
25480Sstevel@tonic-gate continue;
25490Sstevel@tonic-gate
25500Sstevel@tonic-gate /*
25511618Srie * Decide entry size.
25520Sstevel@tonic-gate */
25531618Srie if (((relsize = shdr->sh_entsize) == 0) ||
25541618Srie (relsize > shdr->sh_size)) {
25550Sstevel@tonic-gate if (type == SHT_RELA)
25561618Srie relsize = sizeof (Rela);
25570Sstevel@tonic-gate else
25581618Srie relsize = sizeof (Rel);
25590Sstevel@tonic-gate }
25600Sstevel@tonic-gate
25610Sstevel@tonic-gate /*
25620Sstevel@tonic-gate * Determine the number of relocations available.
25630Sstevel@tonic-gate */
25640Sstevel@tonic-gate if (shdr->sh_size == 0) {
25650Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
25661618Srie file, relname);
25670Sstevel@tonic-gate continue;
25680Sstevel@tonic-gate }
25693466Srie if (_cache->c_data == NULL)
25703466Srie continue;
25713466Srie
25721618Srie rels = _cache->c_data->d_buf;
25731618Srie relnum = shdr->sh_size / relsize;
25740Sstevel@tonic-gate
25750Sstevel@tonic-gate /*
25761618Srie * Get the data buffer for the associated symbol table and
25771618Srie * string table.
25780Sstevel@tonic-gate */
25791618Srie if (stringtbl(cache, 1, cnt, shnum, file,
25801618Srie &symnum, &symsec, &strsec) == 0)
25810Sstevel@tonic-gate continue;
25821618Srie
25831618Srie syms = symsec->c_data->d_buf;
25840Sstevel@tonic-gate
25850Sstevel@tonic-gate /*
25860Sstevel@tonic-gate * Loop through the relocation entries.
25870Sstevel@tonic-gate */
25881618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
25891618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name);
25901618Srie Elf_reloc_title(0, ELF_DBG_ELFDUMP, type);
25910Sstevel@tonic-gate
25921618Srie for (relndx = 0; relndx < relnum; relndx++,
25931618Srie rels = (void *)((char *)rels + relsize)) {
25946206Sab196087 Half mach = ehdr->e_machine;
25950Sstevel@tonic-gate char section[BUFSIZ];
25961618Srie const char *symname;
25971618Srie Word symndx, reltype;
25981618Srie Rela *rela;
25991618Srie Rel *rel;
26000Sstevel@tonic-gate
26010Sstevel@tonic-gate /*
26021618Srie * Unravel the relocation and determine the symbol with
26031618Srie * which this relocation is associated.
26040Sstevel@tonic-gate */
26050Sstevel@tonic-gate if (type == SHT_RELA) {
26061618Srie rela = (Rela *)rels;
26071618Srie symndx = ELF_R_SYM(rela->r_info);
26086206Sab196087 reltype = ELF_R_TYPE(rela->r_info, mach);
26090Sstevel@tonic-gate } else {
26101618Srie rel = (Rel *)rels;
26111618Srie symndx = ELF_R_SYM(rel->r_info);
26126206Sab196087 reltype = ELF_R_TYPE(rel->r_info, mach);
26130Sstevel@tonic-gate }
26141618Srie
26151618Srie symname = relsymname(cache, _cache, strsec, symndx,
26167463SRod.Evans@Sun.COM symnum, relndx, syms, section, BUFSIZ, file);
26171618Srie
26181618Srie /*
26191618Srie * A zero symbol index is only valid for a few
26201618Srie * relocations.
26211618Srie */
26221618Srie if (symndx == 0) {
26231618Srie int badrel = 0;
26240Sstevel@tonic-gate
26251618Srie if ((mach == EM_SPARC) ||
26261618Srie (mach == EM_SPARC32PLUS) ||
26271618Srie (mach == EM_SPARCV9)) {
26281618Srie if ((reltype != R_SPARC_NONE) &&
26291618Srie (reltype != R_SPARC_REGISTER) &&
26301618Srie (reltype != R_SPARC_RELATIVE))
26311618Srie badrel++;
26321618Srie } else if (mach == EM_386) {
26331618Srie if ((reltype != R_386_NONE) &&
26341618Srie (reltype != R_386_RELATIVE))
26351618Srie badrel++;
26361618Srie } else if (mach == EM_AMD64) {
26371618Srie if ((reltype != R_AMD64_NONE) &&
26381618Srie (reltype != R_AMD64_RELATIVE))
26391618Srie badrel++;
26401618Srie }
26411618Srie
26421618Srie if (badrel) {
26431618Srie (void) fprintf(stderr,
26441618Srie MSG_INTL(MSG_ERR_BADREL1), file,
26454734Sab196087 conv_reloc_type(mach, reltype,
26464734Sab196087 0, &inv_buf));
26470Sstevel@tonic-gate }
26480Sstevel@tonic-gate }
26490Sstevel@tonic-gate
26501618Srie Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP,
26511618Srie MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type,
26521618Srie rels, relname, symname, 0);
26530Sstevel@tonic-gate }
26540Sstevel@tonic-gate }
26550Sstevel@tonic-gate }
26560Sstevel@tonic-gate
26575230Sab196087
26585230Sab196087 /*
26595230Sab196087 * This value controls which test dyn_test() performs.
26605230Sab196087 */
26615230Sab196087 typedef enum { DYN_TEST_ADDR, DYN_TEST_SIZE, DYN_TEST_ENTSIZE } dyn_test_t;
26625230Sab196087
26635230Sab196087 /*
26645230Sab196087 * Used by dynamic() to compare the value of a dynamic element against
26655230Sab196087 * the starting address of the section it references.
26665230Sab196087 *
26675230Sab196087 * entry:
26685230Sab196087 * test_type - Specify which dyn item is being tested.
26695230Sab196087 * sh_type - SHT_* type value for required section.
26705230Sab196087 * sec_cache - Cache entry for section, or NULL if the object lacks
26715230Sab196087 * a section of this type.
26725230Sab196087 * dyn - Dyn entry to be tested
26735230Sab196087 * dynsec_cnt - # of dynamic section being examined. The first
26745230Sab196087 * dynamic section is 1, the next is 2, and so on...
26755230Sab196087 * ehdr - ELF header for file
26765230Sab196087 * file - Name of file
26775230Sab196087 */
26785230Sab196087 static void
dyn_test(dyn_test_t test_type,Word sh_type,Cache * sec_cache,Dyn * dyn,Word dynsec_cnt,Ehdr * ehdr,uchar_t osabi,const char * file)26795230Sab196087 dyn_test(dyn_test_t test_type, Word sh_type, Cache *sec_cache, Dyn *dyn,
26809273SAli.Bahrami@Sun.COM Word dynsec_cnt, Ehdr *ehdr, uchar_t osabi, const char *file)
26815230Sab196087 {
26825230Sab196087 Conv_inv_buf_t buf1, buf2;
26835230Sab196087
26845230Sab196087 /*
26855230Sab196087 * These tests are based around the implicit assumption that
26865230Sab196087 * there is only one dynamic section in an object, and also only
26875230Sab196087 * one of the sections it references. We have therefore gathered
26885230Sab196087 * all of the necessary information to test this in a single pass
26895230Sab196087 * over the section headers, which is very efficient. We are not
26905230Sab196087 * aware of any case where more than one dynamic section would
26915230Sab196087 * be meaningful in an ELF object, so this is a reasonable solution.
26925230Sab196087 *
26935230Sab196087 * To test multiple dynamic sections correctly would be more
26945230Sab196087 * expensive in code and time. We would have to build a data structure
26955230Sab196087 * containing all the dynamic elements. Then, we would use the address
26965230Sab196087 * to locate the section it references and ensure the section is of
26975230Sab196087 * the right type and that the address in the dynamic element is
26985230Sab196087 * to the start of the section. Then, we could check the size and
26995230Sab196087 * entsize values against those same sections. This is O(n^2), and
27005230Sab196087 * also complicated.
27015230Sab196087 *
27025230Sab196087 * In the highly unlikely case that there is more than one dynamic
27035230Sab196087 * section, we only test the first one, and simply allow the values
27045230Sab196087 * of the subsequent one to be displayed unchallenged.
27055230Sab196087 */
27065230Sab196087 if (dynsec_cnt != 1)
27075230Sab196087 return;
27085230Sab196087
27095230Sab196087 /*
27105230Sab196087 * A DT_ item that references a section address should always find
27115230Sab196087 * the section in the file.
27125230Sab196087 */
27135230Sab196087 if (sec_cache == NULL) {
27146299Sab196087 const char *name;
27156299Sab196087
27166299Sab196087 /*
27176299Sab196087 * Supply section names instead of section types for
27186299Sab196087 * things that reference progbits so that the error
27196299Sab196087 * message will make more sense.
27206299Sab196087 */
27216299Sab196087 switch (dyn->d_tag) {
27226299Sab196087 case DT_INIT:
27236299Sab196087 name = MSG_ORIG(MSG_ELF_INIT);
27246299Sab196087 break;
27256299Sab196087 case DT_FINI:
27266299Sab196087 name = MSG_ORIG(MSG_ELF_FINI);
27276299Sab196087 break;
27286299Sab196087 default:
27299273SAli.Bahrami@Sun.COM name = conv_sec_type(osabi, ehdr->e_machine,
27309273SAli.Bahrami@Sun.COM sh_type, 0, &buf1);
27316299Sab196087 break;
27326299Sab196087 }
27335230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNNOBCKSEC), file,
27349273SAli.Bahrami@Sun.COM name, conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine,
273511957SAli.Bahrami@Sun.COM CONV_FMT_ALT_CF, &buf2));
27365230Sab196087 return;
27375230Sab196087 }
27385230Sab196087
27395230Sab196087
27405230Sab196087 switch (test_type) {
27415230Sab196087 case DYN_TEST_ADDR:
27425230Sab196087 /* The section address should match the DT_ item value */
27435230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_addr)
27445230Sab196087 (void) fprintf(stderr,
27455230Sab196087 MSG_INTL(MSG_ERR_DYNBADADDR), file,
27469273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine,
274711957SAli.Bahrami@Sun.COM CONV_FMT_ALT_CF, &buf1), EC_ADDR(dyn->d_un.d_val),
27489273SAli.Bahrami@Sun.COM sec_cache->c_ndx, sec_cache->c_name,
27495230Sab196087 EC_ADDR(sec_cache->c_shdr->sh_addr));
27505230Sab196087 break;
27515230Sab196087
27525230Sab196087 case DYN_TEST_SIZE:
27535230Sab196087 /* The section size should match the DT_ item value */
27545230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_size)
27555230Sab196087 (void) fprintf(stderr,
27565230Sab196087 MSG_INTL(MSG_ERR_DYNBADSIZE), file,
27579273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine,
275811957SAli.Bahrami@Sun.COM CONV_FMT_ALT_CF, &buf1), EC_XWORD(dyn->d_un.d_val),
27595230Sab196087 sec_cache->c_ndx, sec_cache->c_name,
27605230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_size));
27615230Sab196087 break;
27625230Sab196087
27635230Sab196087 case DYN_TEST_ENTSIZE:
27645230Sab196087 /* The sh_entsize value should match the DT_ item value */
27655230Sab196087 if (dyn->d_un.d_val != sec_cache->c_shdr->sh_entsize)
27665230Sab196087 (void) fprintf(stderr,
27675230Sab196087 MSG_INTL(MSG_ERR_DYNBADENTSIZE), file,
27689273SAli.Bahrami@Sun.COM conv_dyn_tag(dyn->d_tag, osabi, ehdr->e_machine,
276911957SAli.Bahrami@Sun.COM CONV_FMT_ALT_CF, &buf1), EC_XWORD(dyn->d_un.d_val),
27705230Sab196087 sec_cache->c_ndx, sec_cache->c_name,
27715230Sab196087 EC_XWORD(sec_cache->c_shdr->sh_entsize));
27725230Sab196087 break;
27735230Sab196087 }
27745230Sab196087 }
27755230Sab196087
27760Sstevel@tonic-gate /*
27776299Sab196087 * There are some DT_ entries that have corresponding symbols
27786299Sab196087 * (e.g. DT_INIT and _init). It is expected that these items will
27796299Sab196087 * both have the same value if both are present. This routine
27806299Sab196087 * examines the well known symbol tables for such symbols and
27816299Sab196087 * issues warnings for any that don't match.
27826299Sab196087 *
27836299Sab196087 * entry:
27846299Sab196087 * dyn - Dyn entry to be tested
27856299Sab196087 * symname - Name of symbol that corresponds to dyn
27866299Sab196087 * symtab_cache, dynsym_cache, ldynsym_cache - Symbol tables to check
278711687SAli.Bahrami@Sun.COM * target_cache - Section the symname section is expected to be
278811687SAli.Bahrami@Sun.COM * associated with.
27896299Sab196087 * cache - Cache of all section headers
27906299Sab196087 * shnum - # of sections in cache
27916299Sab196087 * ehdr - ELF header for file
279211687SAli.Bahrami@Sun.COM * osabi - OSABI to apply when interpreting object
27936299Sab196087 * file - Name of file
27946299Sab196087 */
27956299Sab196087 static void
dyn_symtest(Dyn * dyn,const char * symname,Cache * symtab_cache,Cache * dynsym_cache,Cache * ldynsym_cache,Cache * target_cache,Cache * cache,Word shnum,Ehdr * ehdr,uchar_t osabi,const char * file)27966299Sab196087 dyn_symtest(Dyn *dyn, const char *symname, Cache *symtab_cache,
279711687SAli.Bahrami@Sun.COM Cache *dynsym_cache, Cache *ldynsym_cache, Cache *target_cache,
279811687SAli.Bahrami@Sun.COM Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, const char *file)
27996299Sab196087 {
28006299Sab196087 Conv_inv_buf_t buf;
28016299Sab196087 int i;
28026299Sab196087 Sym *sym;
28036299Sab196087 Cache *_cache;
28046299Sab196087
28056299Sab196087 for (i = 0; i < 3; i++) {
28066299Sab196087 switch (i) {
28076299Sab196087 case 0:
28086299Sab196087 _cache = symtab_cache;
28096299Sab196087 break;
28106299Sab196087 case 1:
28116299Sab196087 _cache = dynsym_cache;
28126299Sab196087 break;
28136299Sab196087 case 2:
28146299Sab196087 _cache = ldynsym_cache;
28156299Sab196087 break;
28166299Sab196087 }
28176299Sab196087
28186299Sab196087 if ((_cache != NULL) &&
281911687SAli.Bahrami@Sun.COM symlookup(symname, cache, shnum, &sym, target_cache,
282011687SAli.Bahrami@Sun.COM _cache, file) && (sym->st_value != dyn->d_un.d_val))
28216299Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_DYNSYMVAL),
28229273SAli.Bahrami@Sun.COM file, _cache->c_name, conv_dyn_tag(dyn->d_tag,
282311957SAli.Bahrami@Sun.COM osabi, ehdr->e_machine, CONV_FMT_ALT_CF, &buf),
28246299Sab196087 symname, EC_ADDR(sym->st_value));
28256299Sab196087 }
28266299Sab196087 }
28276299Sab196087
28286299Sab196087 /*
28290Sstevel@tonic-gate * Search for and process a .dynamic section.
28300Sstevel@tonic-gate */
28310Sstevel@tonic-gate static void
dynamic(Cache * cache,Word shnum,Ehdr * ehdr,uchar_t osabi,const char * file)28329273SAli.Bahrami@Sun.COM dynamic(Cache *cache, Word shnum, Ehdr *ehdr, uchar_t osabi, const char *file)
28330Sstevel@tonic-gate {
28345230Sab196087 struct {
28356299Sab196087 Cache *symtab;
28365230Sab196087 Cache *dynstr;
28375230Sab196087 Cache *dynsym;
28385230Sab196087 Cache *hash;
28395230Sab196087 Cache *fini;
28405230Sab196087 Cache *fini_array;
28415230Sab196087 Cache *init;
28425230Sab196087 Cache *init_array;
28435230Sab196087 Cache *preinit_array;
28445230Sab196087 Cache *rel;
28455230Sab196087 Cache *rela;
28465230Sab196087 Cache *sunw_cap;
284711827SRod.Evans@Sun.COM Cache *sunw_capinfo;
284811827SRod.Evans@Sun.COM Cache *sunw_capchain;
28495230Sab196087 Cache *sunw_ldynsym;
28505230Sab196087 Cache *sunw_move;
28515230Sab196087 Cache *sunw_syminfo;
28525230Sab196087 Cache *sunw_symsort;
28535230Sab196087 Cache *sunw_tlssort;
28545230Sab196087 Cache *sunw_verdef;
28555230Sab196087 Cache *sunw_verneed;
28565230Sab196087 Cache *sunw_versym;
28575230Sab196087 } sec;
28585230Sab196087 Word dynsec_ndx;
28595230Sab196087 Word dynsec_num;
28605230Sab196087 int dynsec_cnt;
28611618Srie Word cnt;
28629273SAli.Bahrami@Sun.COM int osabi_solaris = osabi == ELFOSABI_SOLARIS;
28630Sstevel@tonic-gate
28645230Sab196087 /*
28655230Sab196087 * Make a pass over all the sections, gathering section information
28665230Sab196087 * we'll need below.
28675230Sab196087 */
28685230Sab196087 dynsec_num = 0;
28695230Sab196087 bzero(&sec, sizeof (sec));
28700Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
28715230Sab196087 Cache *_cache = &cache[cnt];
28725230Sab196087
28735230Sab196087 switch (_cache->c_shdr->sh_type) {
28745230Sab196087 case SHT_DYNAMIC:
28755230Sab196087 if (dynsec_num == 0) {
28765230Sab196087 dynsec_ndx = cnt;
28775230Sab196087
28785230Sab196087 /* Does it have a valid string table? */
28795230Sab196087 (void) stringtbl(cache, 0, cnt, shnum, file,
28805230Sab196087 0, 0, &sec.dynstr);
28815230Sab196087 }
28825230Sab196087 dynsec_num++;
28835230Sab196087 break;
28845230Sab196087
28855230Sab196087
28865230Sab196087 case SHT_PROGBITS:
28875230Sab196087 /*
28885230Sab196087 * We want to detect the .init and .fini sections,
28895230Sab196087 * if present. These are SHT_PROGBITS, so all we
28905230Sab196087 * have to go on is the section name. Normally comparing
28915230Sab196087 * names is a bad idea, but there are some special
28925230Sab196087 * names (i.e. .init/.fini/.interp) that are very
28935230Sab196087 * difficult to use in any other context, and for
28945230Sab196087 * these symbols, we do the heuristic match.
28955230Sab196087 */
28965230Sab196087 if (strcmp(_cache->c_name,
28975230Sab196087 MSG_ORIG(MSG_ELF_INIT)) == 0) {
28985230Sab196087 if (sec.init == NULL)
28995230Sab196087 sec.init = _cache;
29005230Sab196087 } else if (strcmp(_cache->c_name,
29015230Sab196087 MSG_ORIG(MSG_ELF_FINI)) == 0) {
29025230Sab196087 if (sec.fini == NULL)
29035230Sab196087 sec.fini = _cache;
29045230Sab196087 }
29055230Sab196087 break;
29065230Sab196087
29075230Sab196087 case SHT_REL:
29085230Sab196087 /*
29095230Sab196087 * We want the SHT_REL section with the lowest
29105230Sab196087 * offset. The linker gathers them together,
29115230Sab196087 * and puts the address of the first one
29125230Sab196087 * into the DT_REL dynamic element.
29135230Sab196087 */
29145230Sab196087 if ((sec.rel == NULL) ||
29155230Sab196087 (_cache->c_shdr->sh_offset <
29165230Sab196087 sec.rel->c_shdr->sh_offset))
29175230Sab196087 sec.rel = _cache;
29185230Sab196087 break;
29195230Sab196087
29205230Sab196087 case SHT_RELA:
29215230Sab196087 /* RELA is handled just like RELA above */
29225230Sab196087 if ((sec.rela == NULL) ||
29235230Sab196087 (_cache->c_shdr->sh_offset <
29245230Sab196087 sec.rela->c_shdr->sh_offset))
29255230Sab196087 sec.rela = _cache;
29265230Sab196087 break;
29275230Sab196087
29285230Sab196087 /*
29295230Sab196087 * The GRAB macro is used for the simple case in which
29305230Sab196087 * we simply grab the first section of the desired type.
29315230Sab196087 */
29325230Sab196087 #define GRAB(_sec_type, _sec_field) \
29335230Sab196087 case _sec_type: \
29345230Sab196087 if (sec._sec_field == NULL) \
29355230Sab196087 sec._sec_field = _cache; \
29365230Sab196087 break
29376299Sab196087 GRAB(SHT_SYMTAB, symtab);
29385230Sab196087 GRAB(SHT_DYNSYM, dynsym);
29395230Sab196087 GRAB(SHT_FINI_ARRAY, fini_array);
29405230Sab196087 GRAB(SHT_HASH, hash);
29415230Sab196087 GRAB(SHT_INIT_ARRAY, init_array);
29425230Sab196087 GRAB(SHT_SUNW_move, sunw_move);
29435230Sab196087 GRAB(SHT_PREINIT_ARRAY, preinit_array);
29445230Sab196087 GRAB(SHT_SUNW_cap, sunw_cap);
294511827SRod.Evans@Sun.COM GRAB(SHT_SUNW_capinfo, sunw_capinfo);
294611827SRod.Evans@Sun.COM GRAB(SHT_SUNW_capchain, sunw_capchain);
29475230Sab196087 GRAB(SHT_SUNW_LDYNSYM, sunw_ldynsym);
29485230Sab196087 GRAB(SHT_SUNW_syminfo, sunw_syminfo);
29495230Sab196087 GRAB(SHT_SUNW_symsort, sunw_symsort);
29505230Sab196087 GRAB(SHT_SUNW_tlssort, sunw_tlssort);
29515230Sab196087 GRAB(SHT_SUNW_verdef, sunw_verdef);
29525230Sab196087 GRAB(SHT_SUNW_verneed, sunw_verneed);
29535230Sab196087 GRAB(SHT_SUNW_versym, sunw_versym);
29545230Sab196087 #undef GRAB
29555230Sab196087 }
29565230Sab196087 }
29575230Sab196087
29585230Sab196087 /*
29595230Sab196087 * If no dynamic section, return immediately. If more than one
29605230Sab196087 * dynamic section, then something odd is going on and an error
29615230Sab196087 * is in order, but then continue on and display them all.
29625230Sab196087 */
29635230Sab196087 if (dynsec_num == 0)
29645230Sab196087 return;
29655230Sab196087 if (dynsec_num > 1)
29665230Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MULTDYN),
29675230Sab196087 file, EC_WORD(dynsec_num));
29685230Sab196087
29695230Sab196087
29705230Sab196087 dynsec_cnt = 0;
29715230Sab196087 for (cnt = dynsec_ndx; (cnt < shnum) && (dynsec_cnt < dynsec_num);
29725230Sab196087 cnt++) {
29731618Srie Dyn *dyn;
29741618Srie ulong_t numdyn;
29753850Sab196087 int ndx, end_ndx;
29761618Srie Cache *_cache = &cache[cnt], *strsec;
29771618Srie Shdr *shdr = _cache->c_shdr;
29785230Sab196087 int dumped = 0;
29790Sstevel@tonic-gate
29800Sstevel@tonic-gate if (shdr->sh_type != SHT_DYNAMIC)
29810Sstevel@tonic-gate continue;
29825230Sab196087 dynsec_cnt++;
29830Sstevel@tonic-gate
29840Sstevel@tonic-gate /*
29851618Srie * Verify the associated string table section.
29860Sstevel@tonic-gate */
29871618Srie if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0)
29880Sstevel@tonic-gate continue;
29891618Srie
29903466Srie if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
29913466Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
29923466Srie file, _cache->c_name);
29933466Srie continue;
29943466Srie }
29953466Srie if (_cache->c_data == NULL)
29963466Srie continue;
29973466Srie
29980Sstevel@tonic-gate numdyn = shdr->sh_size / shdr->sh_entsize;
29991618Srie dyn = (Dyn *)_cache->c_data->d_buf;
30000Sstevel@tonic-gate
30015230Sab196087 /*
30025230Sab196087 * We expect the REL/RELA entries to reference the reloc
30035230Sab196087 * section with the lowest address. However, this is
30045230Sab196087 * not true for dumped objects. Detect if this object has
30055230Sab196087 * been dumped so that we can skip the reloc address test
30065230Sab196087 * in that case.
30075230Sab196087 */
30085230Sab196087 for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
30095230Sab196087 if (dyn->d_tag == DT_FLAGS_1) {
30105230Sab196087 dumped = (dyn->d_un.d_val & DF_1_CONFALT) != 0;
30115230Sab196087 break;
30125230Sab196087 }
30135230Sab196087 }
30145230Sab196087 dyn = (Dyn *)_cache->c_data->d_buf;
30155230Sab196087
30161618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
30171618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name);
30180Sstevel@tonic-gate
30191618Srie Elf_dyn_title(0);
30200Sstevel@tonic-gate
30211618Srie for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
30224734Sab196087 union {
30236206Sab196087 Conv_inv_buf_t inv;
30244734Sab196087 Conv_dyn_flag_buf_t flag;
30254734Sab196087 Conv_dyn_flag1_buf_t flag1;
30264734Sab196087 Conv_dyn_posflag1_buf_t posflag1;
30274734Sab196087 Conv_dyn_feature1_buf_t feature1;
30284734Sab196087 } c_buf;
30295230Sab196087 const char *name = NULL;
30300Sstevel@tonic-gate
30310Sstevel@tonic-gate /*
30320Sstevel@tonic-gate * Print the information numerically, and if possible
30335230Sab196087 * as a string. If a string is available, name is
30345230Sab196087 * set to reference it.
30355230Sab196087 *
30365230Sab196087 * Also, take this opportunity to sanity check
30375230Sab196087 * the values of DT elements. In the code above,
30385230Sab196087 * we gathered information on sections that are
30395230Sab196087 * referenced by the dynamic section. Here, we
30405230Sab196087 * compare the attributes of those sections to
30415230Sab196087 * the DT_ items that reference them and report
30425230Sab196087 * on inconsistencies.
30435230Sab196087 *
30445230Sab196087 * Things not currently tested that could be improved
30455230Sab196087 * in later revisions include:
30465230Sab196087 * - We don't check PLT or GOT related items
30475230Sab196087 * - We don't handle computing the lengths of
30485230Sab196087 * relocation arrays. To handle this
30495230Sab196087 * requires examining data that spans
30505230Sab196087 * across sections, in a contiguous span
30515230Sab196087 * within a single segment.
30525230Sab196087 * - DT_VERDEFNUM and DT_VERNEEDNUM can't be
30535230Sab196087 * verified without parsing the sections.
30545230Sab196087 * - We don't handle DT_SUNW_SYMSZ, which would
30555230Sab196087 * be the sum of the lengths of .dynsym and
30565230Sab196087 * .SUNW_ldynsym
30575230Sab196087 * - DT_SUNW_STRPAD can't be verified other than
30585230Sab196087 * to check that it's not larger than
30595230Sab196087 * the string table.
30605230Sab196087 * - Some items come in "all or none" clusters
30615230Sab196087 * that give an address, element size,
30625230Sab196087 * and data length in bytes. We don't
30635230Sab196087 * verify that there are no missing items
30645230Sab196087 * in such groups.
30650Sstevel@tonic-gate */
30663850Sab196087 switch (dyn->d_tag) {
30673850Sab196087 case DT_NULL:
30683850Sab196087 /*
30693850Sab196087 * Special case: DT_NULLs can come in groups
30703850Sab196087 * that we prefer to reduce to a single line.
30713850Sab196087 */
30723850Sab196087 end_ndx = ndx;
30733850Sab196087 while ((end_ndx < (numdyn - 1)) &&
30744433Sab196087 ((dyn + 1)->d_tag == DT_NULL)) {
30753850Sab196087 dyn++;
30763850Sab196087 end_ndx++;
30773850Sab196087 }
30783850Sab196087 Elf_dyn_null_entry(0, dyn, ndx, end_ndx);
30793850Sab196087 ndx = end_ndx;
30803850Sab196087 continue;
30813850Sab196087
30823850Sab196087 /*
30835230Sab196087 * String items all reference the dynstr. The string()
30845230Sab196087 * function does the necessary sanity checking.
30853850Sab196087 */
30863850Sab196087 case DT_NEEDED:
30873850Sab196087 case DT_SONAME:
30883850Sab196087 case DT_FILTER:
30893850Sab196087 case DT_AUXILIARY:
30903850Sab196087 case DT_CONFIG:
30913850Sab196087 case DT_RPATH:
30923850Sab196087 case DT_RUNPATH:
30933850Sab196087 case DT_USED:
30943850Sab196087 case DT_DEPAUDIT:
30953850Sab196087 case DT_AUDIT:
30969273SAli.Bahrami@Sun.COM name = string(_cache, ndx, strsec,
30979273SAli.Bahrami@Sun.COM file, dyn->d_un.d_ptr);
30989273SAli.Bahrami@Sun.COM break;
30999273SAli.Bahrami@Sun.COM
31003850Sab196087 case DT_SUNW_AUXILIARY:
31013850Sab196087 case DT_SUNW_FILTER:
31029273SAli.Bahrami@Sun.COM if (osabi_solaris)
31039273SAli.Bahrami@Sun.COM name = string(_cache, ndx, strsec,
31049273SAli.Bahrami@Sun.COM file, dyn->d_un.d_ptr);
31053850Sab196087 break;
31063850Sab196087
31073850Sab196087 case DT_FLAGS:
31084734Sab196087 name = conv_dyn_flag(dyn->d_un.d_val,
31094734Sab196087 0, &c_buf.flag);
31103850Sab196087 break;
31113850Sab196087 case DT_FLAGS_1:
31125088Sab196087 name = conv_dyn_flag1(dyn->d_un.d_val, 0,
31134734Sab196087 &c_buf.flag1);
31143850Sab196087 break;
31153850Sab196087 case DT_POSFLAG_1:
31164734Sab196087 name = conv_dyn_posflag1(dyn->d_un.d_val, 0,
31174734Sab196087 &c_buf.posflag1);
31183850Sab196087 break;
31193850Sab196087 case DT_FEATURE_1:
31204734Sab196087 name = conv_dyn_feature1(dyn->d_un.d_val, 0,
31214734Sab196087 &c_buf.feature1);
31223850Sab196087 break;
31233850Sab196087 case DT_DEPRECATED_SPARC_REGISTER:
31241618Srie name = MSG_INTL(MSG_STR_DEPRECATED);
31253850Sab196087 break;
31265230Sab196087
31276206Sab196087 case DT_SUNW_LDMACH:
31289273SAli.Bahrami@Sun.COM if (!osabi_solaris)
31299273SAli.Bahrami@Sun.COM break;
31309273SAli.Bahrami@Sun.COM name = conv_ehdr_mach((Half)dyn->d_un.d_val,
31319273SAli.Bahrami@Sun.COM 0, &c_buf.inv);
31326206Sab196087 break;
31336206Sab196087
31345230Sab196087 /*
31355230Sab196087 * Cases below this point are strictly sanity checking,
31365230Sab196087 * and do not generate a name string. The TEST_ macros
313711827SRod.Evans@Sun.COM * are used to hide the boiler plate arguments neeeded
31385230Sab196087 * by dyn_test().
31395230Sab196087 */
31405230Sab196087 #define TEST_ADDR(_sh_type, _sec_field) \
31415230Sab196087 dyn_test(DYN_TEST_ADDR, _sh_type, \
31429273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \
31439273SAli.Bahrami@Sun.COM osabi, file)
31445230Sab196087 #define TEST_SIZE(_sh_type, _sec_field) \
31455230Sab196087 dyn_test(DYN_TEST_SIZE, _sh_type, \
31469273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \
31479273SAli.Bahrami@Sun.COM osabi, file)
31485230Sab196087 #define TEST_ENTSIZE(_sh_type, _sec_field) \
31495230Sab196087 dyn_test(DYN_TEST_ENTSIZE, _sh_type, \
31509273SAli.Bahrami@Sun.COM sec._sec_field, dyn, dynsec_cnt, ehdr, \
31519273SAli.Bahrami@Sun.COM osabi, file)
31525230Sab196087
31535230Sab196087 case DT_FINI:
31546299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_FINI),
31556299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym,
315611687SAli.Bahrami@Sun.COM sec.fini, cache, shnum, ehdr, osabi, file);
31575230Sab196087 TEST_ADDR(SHT_PROGBITS, fini);
31585230Sab196087 break;
31595230Sab196087
31605230Sab196087 case DT_FINI_ARRAY:
31615230Sab196087 TEST_ADDR(SHT_FINI_ARRAY, fini_array);
31625230Sab196087 break;
31635230Sab196087
31645230Sab196087 case DT_FINI_ARRAYSZ:
31655230Sab196087 TEST_SIZE(SHT_FINI_ARRAY, fini_array);
31665230Sab196087 break;
31675230Sab196087
31685230Sab196087 case DT_HASH:
31695230Sab196087 TEST_ADDR(SHT_HASH, hash);
31705230Sab196087 break;
31715230Sab196087
31725230Sab196087 case DT_INIT:
31736299Sab196087 dyn_symtest(dyn, MSG_ORIG(MSG_SYM_INIT),
31746299Sab196087 sec.symtab, sec.dynsym, sec.sunw_ldynsym,
317511687SAli.Bahrami@Sun.COM sec.init, cache, shnum, ehdr, osabi, file);
31765230Sab196087 TEST_ADDR(SHT_PROGBITS, init);
31775230Sab196087 break;
31785230Sab196087
31795230Sab196087 case DT_INIT_ARRAY:
31805230Sab196087 TEST_ADDR(SHT_INIT_ARRAY, init_array);
31815230Sab196087 break;
31825230Sab196087
31835230Sab196087 case DT_INIT_ARRAYSZ:
31845230Sab196087 TEST_SIZE(SHT_INIT_ARRAY, init_array);
31855230Sab196087 break;
31865230Sab196087
31875230Sab196087 case DT_MOVEENT:
31885230Sab196087 TEST_ENTSIZE(SHT_SUNW_move, sunw_move);
31895230Sab196087 break;
31905230Sab196087
31915230Sab196087 case DT_MOVESZ:
31925230Sab196087 TEST_SIZE(SHT_SUNW_move, sunw_move);
31935230Sab196087 break;
31945230Sab196087
31955230Sab196087 case DT_MOVETAB:
31965230Sab196087 TEST_ADDR(SHT_SUNW_move, sunw_move);
31975230Sab196087 break;
31985230Sab196087
31995230Sab196087 case DT_PREINIT_ARRAY:
32005230Sab196087 TEST_ADDR(SHT_PREINIT_ARRAY, preinit_array);
32015230Sab196087 break;
32025230Sab196087
32035230Sab196087 case DT_PREINIT_ARRAYSZ:
32045230Sab196087 TEST_SIZE(SHT_PREINIT_ARRAY, preinit_array);
32055230Sab196087 break;
32065230Sab196087
32075230Sab196087 case DT_REL:
32085230Sab196087 if (!dumped)
32095230Sab196087 TEST_ADDR(SHT_REL, rel);
32105230Sab196087 break;
32115230Sab196087
32125230Sab196087 case DT_RELENT:
32135230Sab196087 TEST_ENTSIZE(SHT_REL, rel);
32145230Sab196087 break;
32155230Sab196087
32165230Sab196087 case DT_RELA:
32175230Sab196087 if (!dumped)
32185230Sab196087 TEST_ADDR(SHT_RELA, rela);
32195230Sab196087 break;
32205230Sab196087
32215230Sab196087 case DT_RELAENT:
32225230Sab196087 TEST_ENTSIZE(SHT_RELA, rela);
32235230Sab196087 break;
32245230Sab196087
32255230Sab196087 case DT_STRTAB:
32265230Sab196087 TEST_ADDR(SHT_STRTAB, dynstr);
32273850Sab196087 break;
32285230Sab196087
32295230Sab196087 case DT_STRSZ:
32305230Sab196087 TEST_SIZE(SHT_STRTAB, dynstr);
32315230Sab196087 break;
32325230Sab196087
32335230Sab196087 case DT_SUNW_CAP:
323411957SAli.Bahrami@Sun.COM if (osabi_solaris)
323511957SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_cap, sunw_cap);
32365230Sab196087 break;
32375230Sab196087
323811827SRod.Evans@Sun.COM case DT_SUNW_CAPINFO:
323911957SAli.Bahrami@Sun.COM if (osabi_solaris)
324011957SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_capinfo,
324111957SAli.Bahrami@Sun.COM sunw_capinfo);
324211827SRod.Evans@Sun.COM break;
324311827SRod.Evans@Sun.COM
324411827SRod.Evans@Sun.COM case DT_SUNW_CAPCHAIN:
324511957SAli.Bahrami@Sun.COM if (osabi_solaris)
324611957SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_capchain,
324711957SAli.Bahrami@Sun.COM sunw_capchain);
324811827SRod.Evans@Sun.COM break;
324911827SRod.Evans@Sun.COM
32505230Sab196087 case DT_SUNW_SYMTAB:
32515230Sab196087 TEST_ADDR(SHT_SUNW_LDYNSYM, sunw_ldynsym);
32525230Sab196087 break;
32535230Sab196087
32545230Sab196087 case DT_SYMENT:
32555230Sab196087 TEST_ENTSIZE(SHT_DYNSYM, dynsym);
32565230Sab196087 break;
32575230Sab196087
32585230Sab196087 case DT_SYMINENT:
32595230Sab196087 TEST_ENTSIZE(SHT_SUNW_syminfo, sunw_syminfo);
32605230Sab196087 break;
32615230Sab196087
32625230Sab196087 case DT_SYMINFO:
32635230Sab196087 TEST_ADDR(SHT_SUNW_syminfo, sunw_syminfo);
32645230Sab196087 break;
32655230Sab196087
32665230Sab196087 case DT_SYMINSZ:
32675230Sab196087 TEST_SIZE(SHT_SUNW_syminfo, sunw_syminfo);
32685230Sab196087 break;
32695230Sab196087
32705230Sab196087 case DT_SYMTAB:
32715230Sab196087 TEST_ADDR(SHT_DYNSYM, dynsym);
32725230Sab196087 break;
32735230Sab196087
32745230Sab196087 case DT_SUNW_SORTENT:
32755230Sab196087 /*
32765230Sab196087 * This entry is related to both the symsort and
32775230Sab196087 * tlssort sections.
32785230Sab196087 */
32799273SAli.Bahrami@Sun.COM if (osabi_solaris) {
32805230Sab196087 int test_tls =
32815230Sab196087 (sec.sunw_tlssort != NULL);
32825230Sab196087 int test_sym =
32835230Sab196087 (sec.sunw_symsort != NULL) ||
32845230Sab196087 !test_tls;
32855230Sab196087 if (test_sym)
32865230Sab196087 TEST_ENTSIZE(SHT_SUNW_symsort,
32875230Sab196087 sunw_symsort);
32885230Sab196087 if (test_tls)
32895230Sab196087 TEST_ENTSIZE(SHT_SUNW_tlssort,
32905230Sab196087 sunw_tlssort);
32915230Sab196087 }
32925230Sab196087 break;
32935230Sab196087
32945230Sab196087
32955230Sab196087 case DT_SUNW_SYMSORT:
32969273SAli.Bahrami@Sun.COM if (osabi_solaris)
32979273SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_symsort,
32989273SAli.Bahrami@Sun.COM sunw_symsort);
32995230Sab196087 break;
33005230Sab196087
33015230Sab196087 case DT_SUNW_SYMSORTSZ:
33029273SAli.Bahrami@Sun.COM if (osabi_solaris)
33039273SAli.Bahrami@Sun.COM TEST_SIZE(SHT_SUNW_symsort,
33049273SAli.Bahrami@Sun.COM sunw_symsort);
33055230Sab196087 break;
33065230Sab196087
33075230Sab196087 case DT_SUNW_TLSSORT:
33089273SAli.Bahrami@Sun.COM if (osabi_solaris)
33099273SAli.Bahrami@Sun.COM TEST_ADDR(SHT_SUNW_tlssort,
33109273SAli.Bahrami@Sun.COM sunw_tlssort);
33115230Sab196087 break;
33125230Sab196087
33135230Sab196087 case DT_SUNW_TLSSORTSZ:
33149273SAli.Bahrami@Sun.COM if (osabi_solaris)
33159273SAli.Bahrami@Sun.COM TEST_SIZE(SHT_SUNW_tlssort,
33169273SAli.Bahrami@Sun.COM sunw_tlssort);
33175230Sab196087 break;
33185230Sab196087
33195230Sab196087 case DT_VERDEF:
33205230Sab196087 TEST_ADDR(SHT_SUNW_verdef, sunw_verdef);
33215230Sab196087 break;
33225230Sab196087
33235230Sab196087 case DT_VERNEED:
33245230Sab196087 TEST_ADDR(SHT_SUNW_verneed, sunw_verneed);
33255230Sab196087 break;
33265230Sab196087
33275230Sab196087 case DT_VERSYM:
33285230Sab196087 TEST_ADDR(SHT_SUNW_versym, sunw_versym);
33295230Sab196087 break;
33305230Sab196087 #undef TEST_ADDR
33315230Sab196087 #undef TEST_SIZE
33325230Sab196087 #undef TEST_ENTSIZE
33333850Sab196087 }
33340Sstevel@tonic-gate
33355230Sab196087 if (name == NULL)
33365230Sab196087 name = MSG_ORIG(MSG_STR_EMPTY);
33379273SAli.Bahrami@Sun.COM Elf_dyn_entry(0, dyn, ndx, name,
33389273SAli.Bahrami@Sun.COM osabi, ehdr->e_machine);
33390Sstevel@tonic-gate }
33400Sstevel@tonic-gate }
33410Sstevel@tonic-gate }
33420Sstevel@tonic-gate
33430Sstevel@tonic-gate /*
33440Sstevel@tonic-gate * Search for and process a MOVE section.
33450Sstevel@tonic-gate */
33460Sstevel@tonic-gate static void
move(Cache * cache,Word shnum,const char * file,uint_t flags)33474168Sab196087 move(Cache *cache, Word shnum, const char *file, uint_t flags)
33480Sstevel@tonic-gate {
33491618Srie Word cnt;
33509085SAli.Bahrami@Sun.COM const char *fmt = NULL;
33510Sstevel@tonic-gate
33520Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
33531618Srie Word movenum, symnum, ndx;
33541618Srie Sym *syms;
33551618Srie Cache *_cache = &cache[cnt];
33561618Srie Shdr *shdr = _cache->c_shdr;
33571618Srie Cache *symsec, *strsec;
33581618Srie Move *move;
33590Sstevel@tonic-gate
33600Sstevel@tonic-gate if (shdr->sh_type != SHT_SUNW_move)
33610Sstevel@tonic-gate continue;
33625411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type))
33630Sstevel@tonic-gate continue;
33640Sstevel@tonic-gate
33650Sstevel@tonic-gate /*
33660Sstevel@tonic-gate * Determine the move data and number.
33670Sstevel@tonic-gate */
33680Sstevel@tonic-gate if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
33690Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
33700Sstevel@tonic-gate file, _cache->c_name);
33710Sstevel@tonic-gate continue;
33720Sstevel@tonic-gate }
33733466Srie if (_cache->c_data == NULL)
33743466Srie continue;
33753466Srie
33761618Srie move = (Move *)_cache->c_data->d_buf;
33771618Srie movenum = shdr->sh_size / shdr->sh_entsize;
33780Sstevel@tonic-gate
33790Sstevel@tonic-gate /*
33801618Srie * Get the data buffer for the associated symbol table and
33811618Srie * string table.
33820Sstevel@tonic-gate */
33831618Srie if (stringtbl(cache, 1, cnt, shnum, file,
33841618Srie &symnum, &symsec, &strsec) == 0)
33851618Srie return;
33861618Srie
33871618Srie syms = (Sym *)symsec->c_data->d_buf;
33880Sstevel@tonic-gate
33891618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
33901618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name);
33911618Srie dbg_print(0, MSG_INTL(MSG_MOVE_TITLE));
33920Sstevel@tonic-gate
33939085SAli.Bahrami@Sun.COM if (fmt == NULL)
33941618Srie fmt = MSG_INTL(MSG_MOVE_ENTRY);
33950Sstevel@tonic-gate
33961618Srie for (ndx = 0; ndx < movenum; move++, ndx++) {
33971618Srie const char *symname;
33981618Srie char index[MAXNDXSIZE], section[BUFSIZ];
33991618Srie Word symndx, shndx;
34001618Srie Sym *sym;
34010Sstevel@tonic-gate
34020Sstevel@tonic-gate /*
34030Sstevel@tonic-gate * Check for null entries
34040Sstevel@tonic-gate */
34051618Srie if ((move->m_info == 0) && (move->m_value == 0) &&
34061618Srie (move->m_poffset == 0) && (move->m_repeat == 0) &&
34071618Srie (move->m_stride == 0)) {
34081618Srie dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY),
34091618Srie EC_XWORD(move->m_poffset), 0, 0, 0,
34101618Srie EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY));
34110Sstevel@tonic-gate continue;
34120Sstevel@tonic-gate }
34131618Srie if (((symndx = ELF_M_SYM(move->m_info)) == 0) ||
34141618Srie (symndx >= symnum)) {
34150Sstevel@tonic-gate (void) fprintf(stderr,
34160Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADMINFO), file,
34171618Srie _cache->c_name, EC_XWORD(move->m_info));
34181618Srie
34191618Srie (void) snprintf(index, MAXNDXSIZE,
34201618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx));
34211618Srie dbg_print(0, fmt, index,
34221618Srie EC_XWORD(move->m_poffset),
34231618Srie ELF_M_SIZE(move->m_info), move->m_repeat,
34241618Srie move->m_stride, move->m_value,
34250Sstevel@tonic-gate MSG_INTL(MSG_STR_UNKNOWN));
34260Sstevel@tonic-gate continue;
34270Sstevel@tonic-gate }
34280Sstevel@tonic-gate
34291618Srie symname = relsymname(cache, _cache, strsec,
34307463SRod.Evans@Sun.COM symndx, symnum, ndx, syms, section, BUFSIZ, file);
34311618Srie sym = (Sym *)(syms + symndx);
34320Sstevel@tonic-gate
34330Sstevel@tonic-gate /*
34340Sstevel@tonic-gate * Additional sanity check.
34350Sstevel@tonic-gate */
34361618Srie shndx = sym->st_shndx;
34370Sstevel@tonic-gate if (!((shndx == SHN_COMMON) ||
34380Sstevel@tonic-gate (((shndx >= 1) && (shndx <= shnum)) &&
34391618Srie (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) {
34400Sstevel@tonic-gate (void) fprintf(stderr,
34411618Srie MSG_INTL(MSG_ERR_BADSYM2), file,
34426206Sab196087 _cache->c_name, EC_WORD(symndx),
34436206Sab196087 demangle(symname, flags));
34440Sstevel@tonic-gate }
34450Sstevel@tonic-gate
34461618Srie (void) snprintf(index, MAXNDXSIZE,
34471618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx));
34481618Srie dbg_print(0, fmt, index, EC_XWORD(move->m_poffset),
34491618Srie ELF_M_SIZE(move->m_info), move->m_repeat,
34501618Srie move->m_stride, move->m_value,
34511618Srie demangle(symname, flags));
34520Sstevel@tonic-gate }
34530Sstevel@tonic-gate }
34540Sstevel@tonic-gate }
34550Sstevel@tonic-gate
34560Sstevel@tonic-gate /*
34579273SAli.Bahrami@Sun.COM * parse_note_t is used to track the state used by parse_note_entry()
34589273SAli.Bahrami@Sun.COM * between calls, and also to return the results of each call.
34599273SAli.Bahrami@Sun.COM */
34609273SAli.Bahrami@Sun.COM typedef struct {
34619273SAli.Bahrami@Sun.COM /* pns_ fields track progress through the data */
34629273SAli.Bahrami@Sun.COM const char *pns_file; /* File name */
34639273SAli.Bahrami@Sun.COM Cache *pns_cache; /* Note section cache entry */
34649273SAli.Bahrami@Sun.COM size_t pns_size; /* # unprocessed data bytes */
34659273SAli.Bahrami@Sun.COM Word *pns_data; /* # to next unused data byte */
34669273SAli.Bahrami@Sun.COM
34679273SAli.Bahrami@Sun.COM /* pn_ fields return the results for a single call */
34689273SAli.Bahrami@Sun.COM Word pn_namesz; /* Value of note namesz field */
34699273SAli.Bahrami@Sun.COM Word pn_descsz; /* Value of note descsz field */
34709273SAli.Bahrami@Sun.COM Word pn_type; /* Value of note type field */
34719273SAli.Bahrami@Sun.COM const char *pn_name; /* if (namesz > 0) ptr to name bytes */
34729273SAli.Bahrami@Sun.COM const char *pn_desc; /* if (descsx > 0) ptr to data bytes */
34739273SAli.Bahrami@Sun.COM } parse_note_t;
34749273SAli.Bahrami@Sun.COM
34759273SAli.Bahrami@Sun.COM /*
34769273SAli.Bahrami@Sun.COM * Extract the various sub-parts of a note entry, and advance the
34779273SAli.Bahrami@Sun.COM * data pointer past it.
34789273SAli.Bahrami@Sun.COM *
34799273SAli.Bahrami@Sun.COM * entry:
34809273SAli.Bahrami@Sun.COM * The state pns_ fields contain current values for the Note section
34819273SAli.Bahrami@Sun.COM *
34829273SAli.Bahrami@Sun.COM * exit:
34839273SAli.Bahrami@Sun.COM * On success, True (1) is returned, the state pns_ fields have been
34849273SAli.Bahrami@Sun.COM * advanced to point at the start of the next entry, and the information
34859273SAli.Bahrami@Sun.COM * for the recovered note entry is found in the state pn_ fields.
34869273SAli.Bahrami@Sun.COM *
34879273SAli.Bahrami@Sun.COM * On failure, False (0) is returned. The values contained in state
34889273SAli.Bahrami@Sun.COM * are undefined.
34899273SAli.Bahrami@Sun.COM */
34909273SAli.Bahrami@Sun.COM static int
parse_note_entry(parse_note_t * state)34919273SAli.Bahrami@Sun.COM parse_note_entry(parse_note_t *state)
34929273SAli.Bahrami@Sun.COM {
34939273SAli.Bahrami@Sun.COM size_t pad, noteoff;
34949273SAli.Bahrami@Sun.COM
34959273SAli.Bahrami@Sun.COM noteoff = (Word)state->pns_cache->c_data->d_size - state->pns_size;
34969273SAli.Bahrami@Sun.COM /*
34979273SAli.Bahrami@Sun.COM * Make sure we can at least reference the 3 initial entries
34989273SAli.Bahrami@Sun.COM * (4-byte words) of the note information block.
34999273SAli.Bahrami@Sun.COM */
35009273SAli.Bahrami@Sun.COM if (state->pns_size >= (sizeof (Word) * 3)) {
35019273SAli.Bahrami@Sun.COM state->pns_size -= (sizeof (Word) * 3);
35029273SAli.Bahrami@Sun.COM } else {
35039273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ),
35049273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name,
35059273SAli.Bahrami@Sun.COM EC_WORD(noteoff));
35069273SAli.Bahrami@Sun.COM return (0);
35079273SAli.Bahrami@Sun.COM }
35089273SAli.Bahrami@Sun.COM
35099273SAli.Bahrami@Sun.COM /*
35109273SAli.Bahrami@Sun.COM * Make sure any specified name string can be referenced.
35119273SAli.Bahrami@Sun.COM */
35129273SAli.Bahrami@Sun.COM if ((state->pn_namesz = *state->pns_data++) != 0) {
35139273SAli.Bahrami@Sun.COM if (state->pns_size >= state->pn_namesz) {
35149273SAli.Bahrami@Sun.COM state->pns_size -= state->pn_namesz;
35159273SAli.Bahrami@Sun.COM } else {
35169273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADNMSZ),
35179273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name,
35189273SAli.Bahrami@Sun.COM EC_WORD(noteoff), EC_WORD(state->pn_namesz));
35199273SAli.Bahrami@Sun.COM return (0);
35209273SAli.Bahrami@Sun.COM }
35219273SAli.Bahrami@Sun.COM }
35229273SAli.Bahrami@Sun.COM
35239273SAli.Bahrami@Sun.COM /*
35249273SAli.Bahrami@Sun.COM * Make sure any specified descriptor can be referenced.
35259273SAli.Bahrami@Sun.COM */
35269273SAli.Bahrami@Sun.COM if ((state->pn_descsz = *state->pns_data++) != 0) {
35279273SAli.Bahrami@Sun.COM /*
35289273SAli.Bahrami@Sun.COM * If namesz isn't a 4-byte multiple, account for any
35299273SAli.Bahrami@Sun.COM * padding that must exist before the descriptor.
35309273SAli.Bahrami@Sun.COM */
35319273SAli.Bahrami@Sun.COM if ((pad = (state->pn_namesz & (sizeof (Word) - 1))) != 0) {
35329273SAli.Bahrami@Sun.COM pad = sizeof (Word) - pad;
35339273SAli.Bahrami@Sun.COM state->pns_size -= pad;
35349273SAli.Bahrami@Sun.COM }
35359273SAli.Bahrami@Sun.COM if (state->pns_size >= state->pn_descsz) {
35369273SAli.Bahrami@Sun.COM state->pns_size -= state->pn_descsz;
35379273SAli.Bahrami@Sun.COM } else {
35389273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDESZ),
35399273SAli.Bahrami@Sun.COM state->pns_file, state->pns_cache->c_name,
35409273SAli.Bahrami@Sun.COM EC_WORD(noteoff), EC_WORD(state->pn_namesz));
35419273SAli.Bahrami@Sun.COM return (0);
35429273SAli.Bahrami@Sun.COM }
35439273SAli.Bahrami@Sun.COM }
35449273SAli.Bahrami@Sun.COM
35459273SAli.Bahrami@Sun.COM state->pn_type = *state->pns_data++;
35469273SAli.Bahrami@Sun.COM
35479273SAli.Bahrami@Sun.COM /* Name */
35489273SAli.Bahrami@Sun.COM if (state->pn_namesz) {
35499273SAli.Bahrami@Sun.COM state->pn_name = (char *)state->pns_data;
35509273SAli.Bahrami@Sun.COM pad = (state->pn_namesz +
35519273SAli.Bahrami@Sun.COM (sizeof (Word) - 1)) & ~(sizeof (Word) - 1);
35529273SAli.Bahrami@Sun.COM /* LINTED */
35539273SAli.Bahrami@Sun.COM state->pns_data = (Word *)(state->pn_name + pad);
35549273SAli.Bahrami@Sun.COM }
35559273SAli.Bahrami@Sun.COM
35569273SAli.Bahrami@Sun.COM /*
35579273SAli.Bahrami@Sun.COM * If multiple information blocks exist within a .note section
35589273SAli.Bahrami@Sun.COM * account for any padding that must exist before the next
35599273SAli.Bahrami@Sun.COM * information block.
35609273SAli.Bahrami@Sun.COM */
35619273SAli.Bahrami@Sun.COM if ((pad = (state->pn_descsz & (sizeof (Word) - 1))) != 0) {
35629273SAli.Bahrami@Sun.COM pad = sizeof (Word) - pad;
35639273SAli.Bahrami@Sun.COM if (state->pns_size > pad)
35649273SAli.Bahrami@Sun.COM state->pns_size -= pad;
35659273SAli.Bahrami@Sun.COM }
35669273SAli.Bahrami@Sun.COM
35679273SAli.Bahrami@Sun.COM /* Data */
35689273SAli.Bahrami@Sun.COM if (state->pn_descsz) {
35699273SAli.Bahrami@Sun.COM state->pn_desc = (const char *)state->pns_data;
35709273SAli.Bahrami@Sun.COM /* LINTED */
35719273SAli.Bahrami@Sun.COM state->pns_data = (Word *)(state->pn_desc +
35729273SAli.Bahrami@Sun.COM state->pn_descsz + pad);
35739273SAli.Bahrami@Sun.COM }
35749273SAli.Bahrami@Sun.COM
35759273SAli.Bahrami@Sun.COM return (1);
35769273SAli.Bahrami@Sun.COM }
35779273SAli.Bahrami@Sun.COM
35789273SAli.Bahrami@Sun.COM /*
35796635Sab196087 * Callback function for use with conv_str_to_c_literal() below.
35806635Sab196087 */
35816635Sab196087 /*ARGSUSED2*/
35826635Sab196087 static void
c_literal_cb(const void * ptr,size_t size,void * uvalue)35836635Sab196087 c_literal_cb(const void *ptr, size_t size, void *uvalue)
35846635Sab196087 {
35856635Sab196087 (void) fwrite(ptr, size, 1, stdout);
35866635Sab196087 }
35876635Sab196087
35886635Sab196087 /*
35890Sstevel@tonic-gate * Traverse a note section analyzing each note information block.
35900Sstevel@tonic-gate * The data buffers size is used to validate references before they are made,
35910Sstevel@tonic-gate * and is decremented as each element is processed.
35920Sstevel@tonic-gate */
35930Sstevel@tonic-gate void
note_entry(Cache * cache,Word * data,size_t size,Ehdr * ehdr,const char * file)35946635Sab196087 note_entry(Cache *cache, Word *data, size_t size, Ehdr *ehdr, const char *file)
35950Sstevel@tonic-gate {
35966635Sab196087 int cnt = 0;
35976635Sab196087 int is_corenote;
35986635Sab196087 int do_swap;
35996635Sab196087 Conv_inv_buf_t inv_buf;
36009273SAli.Bahrami@Sun.COM parse_note_t pnstate;
36019273SAli.Bahrami@Sun.COM
36029273SAli.Bahrami@Sun.COM pnstate.pns_file = file;
36039273SAli.Bahrami@Sun.COM pnstate.pns_cache = cache;
36049273SAli.Bahrami@Sun.COM pnstate.pns_size = size;
36059273SAli.Bahrami@Sun.COM pnstate.pns_data = data;
36069273SAli.Bahrami@Sun.COM do_swap = _elf_sys_encoding() != ehdr->e_ident[EI_DATA];
36071618Srie
36080Sstevel@tonic-gate /*
36090Sstevel@tonic-gate * Print out a single `note' information block.
36100Sstevel@tonic-gate */
36119273SAli.Bahrami@Sun.COM while (pnstate.pns_size > 0) {
36129273SAli.Bahrami@Sun.COM
36139273SAli.Bahrami@Sun.COM if (parse_note_entry(&pnstate) == 0)
36140Sstevel@tonic-gate return;
36150Sstevel@tonic-gate
36166635Sab196087 /*
36176635Sab196087 * Is this a Solaris core note? Such notes all have
36186635Sab196087 * the name "CORE".
36196635Sab196087 */
36206635Sab196087 is_corenote = (ehdr->e_type == ET_CORE) &&
36219273SAli.Bahrami@Sun.COM (pnstate.pn_namesz == (MSG_STR_CORE_SIZE + 1)) &&
36229273SAli.Bahrami@Sun.COM (strncmp(MSG_ORIG(MSG_STR_CORE), pnstate.pn_name,
36236635Sab196087 MSG_STR_CORE_SIZE + 1) == 0);
36246635Sab196087
36251618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
36266635Sab196087 dbg_print(0, MSG_INTL(MSG_FMT_NOTEENTNDX), EC_WORD(cnt));
36276635Sab196087 cnt++;
36289273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ),
36299273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_namesz));
36309273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ),
36319273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_descsz));
36326635Sab196087
36336635Sab196087 if (is_corenote)
36346635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE_STR),
36359273SAli.Bahrami@Sun.COM conv_cnote_type(pnstate.pn_type, 0, &inv_buf));
36366635Sab196087 else
36379273SAli.Bahrami@Sun.COM dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE),
36389273SAli.Bahrami@Sun.COM EC_WORD(pnstate.pn_type));
36399273SAli.Bahrami@Sun.COM if (pnstate.pn_namesz) {
36406635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_NAME));
36410Sstevel@tonic-gate /*
36426635Sab196087 * The name string can contain embedded 'null'
36436635Sab196087 * bytes and/or unprintable characters. Also,
36446635Sab196087 * the final NULL is documented in the ELF ABI
36456635Sab196087 * as being included in the namesz. So, display
36466635Sab196087 * the name using C literal string notation, and
36476635Sab196087 * include the terminating NULL in the output.
36486635Sab196087 * We don't show surrounding double quotes, as
36496635Sab196087 * that implies the termination that we are showing
36506635Sab196087 * explicitly.
36510Sstevel@tonic-gate */
36526635Sab196087 (void) fwrite(MSG_ORIG(MSG_STR_8SP),
36536635Sab196087 MSG_STR_8SP_SIZE, 1, stdout);
36549273SAli.Bahrami@Sun.COM conv_str_to_c_literal(pnstate.pn_name,
36559273SAli.Bahrami@Sun.COM pnstate.pn_namesz, c_literal_cb, NULL);
36561618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
36570Sstevel@tonic-gate }
36580Sstevel@tonic-gate
36599273SAli.Bahrami@Sun.COM if (pnstate.pn_descsz) {
36606635Sab196087 int hexdump = 1;
36610Sstevel@tonic-gate
36620Sstevel@tonic-gate /*
36636635Sab196087 * If this is a core note, let the corenote()
36646635Sab196087 * function handle it.
36650Sstevel@tonic-gate */
36666635Sab196087 if (is_corenote) {
36676635Sab196087 /* We only issue the bad arch error once */
36686635Sab196087 static int badnote_done = 0;
36696635Sab196087 corenote_ret_t corenote_ret;
36706635Sab196087
36716635Sab196087 corenote_ret = corenote(ehdr->e_machine,
36729273SAli.Bahrami@Sun.COM do_swap, pnstate.pn_type, pnstate.pn_desc,
36739273SAli.Bahrami@Sun.COM pnstate.pn_descsz);
36746635Sab196087 switch (corenote_ret) {
36756635Sab196087 case CORENOTE_R_OK:
36766635Sab196087 hexdump = 0;
36776635Sab196087 break;
36786635Sab196087 case CORENOTE_R_BADDATA:
36796635Sab196087 (void) fprintf(stderr,
36806635Sab196087 MSG_INTL(MSG_NOTE_BADCOREDATA),
36816635Sab196087 file);
36826635Sab196087 break;
36836635Sab196087 case CORENOTE_R_BADARCH:
36846635Sab196087 if (badnote_done)
36856635Sab196087 break;
36866635Sab196087 (void) fprintf(stderr,
36876635Sab196087 MSG_INTL(MSG_NOTE_BADCOREARCH),
36886635Sab196087 file,
36896635Sab196087 conv_ehdr_mach(ehdr->e_machine,
36906635Sab196087 0, &inv_buf));
36916635Sab196087 break;
36920Sstevel@tonic-gate }
36930Sstevel@tonic-gate }
36946635Sab196087
36956635Sab196087 /*
36966635Sab196087 * The default thing when we don't understand
36976635Sab196087 * the note data is to display it as hex bytes.
36986635Sab196087 */
36996635Sab196087 if (hexdump) {
37006635Sab196087 dbg_print(0, MSG_ORIG(MSG_NOTE_DESC));
37019273SAli.Bahrami@Sun.COM dump_hex_bytes(pnstate.pn_desc,
37029273SAli.Bahrami@Sun.COM pnstate.pn_descsz, 8, 4, 4);
37030Sstevel@tonic-gate }
37040Sstevel@tonic-gate }
37050Sstevel@tonic-gate }
37060Sstevel@tonic-gate }
37070Sstevel@tonic-gate
37080Sstevel@tonic-gate /*
37096635Sab196087 * Search for and process .note sections.
37106635Sab196087 *
37116635Sab196087 * Returns the number of note sections seen.
37120Sstevel@tonic-gate */
37136635Sab196087 static Word
note(Cache * cache,Word shnum,Ehdr * ehdr,const char * file)37146635Sab196087 note(Cache *cache, Word shnum, Ehdr *ehdr, const char *file)
37150Sstevel@tonic-gate {
37166635Sab196087 Word cnt, note_cnt = 0;
37170Sstevel@tonic-gate
37180Sstevel@tonic-gate /*
37190Sstevel@tonic-gate * Otherwise look for any .note sections.
37200Sstevel@tonic-gate */
37210Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
37221618Srie Cache *_cache = &cache[cnt];
37231618Srie Shdr *shdr = _cache->c_shdr;
37240Sstevel@tonic-gate
37250Sstevel@tonic-gate if (shdr->sh_type != SHT_NOTE)
37260Sstevel@tonic-gate continue;
37276635Sab196087 note_cnt++;
37285411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, cnt, shdr->sh_type))
37290Sstevel@tonic-gate continue;
37300Sstevel@tonic-gate
37310Sstevel@tonic-gate /*
37320Sstevel@tonic-gate * As these sections are often hand rolled, make sure they're
37335230Sab196087 * properly aligned before proceeding, and issue an error
37345230Sab196087 * as necessary.
37355230Sab196087 *
37365230Sab196087 * Note that we will continue on to display the note even
37375230Sab196087 * if it has bad alignment. We can do this safely, because
37385230Sab196087 * libelf knows the alignment required for SHT_NOTE, and
37395230Sab196087 * takes steps to deliver a properly aligned buffer to us
37405230Sab196087 * even if the actual file is misaligned.
37410Sstevel@tonic-gate */
37425230Sab196087 if (shdr->sh_offset & (sizeof (Word) - 1))
37430Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN),
37440Sstevel@tonic-gate file, _cache->c_name);
37455230Sab196087
37463466Srie if (_cache->c_data == NULL)
37473466Srie continue;
37480Sstevel@tonic-gate
37491618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
37501618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name);
37510Sstevel@tonic-gate note_entry(_cache, (Word *)_cache->c_data->d_buf,
37520Sstevel@tonic-gate /* LINTED */
37536635Sab196087 (Word)_cache->c_data->d_size, ehdr, file);
37540Sstevel@tonic-gate }
37556635Sab196087
37566635Sab196087 return (note_cnt);
37570Sstevel@tonic-gate }
37580Sstevel@tonic-gate
37591618Srie /*
37609273SAli.Bahrami@Sun.COM * The Linux Standard Base defines a special note named .note.ABI-tag
37619273SAli.Bahrami@Sun.COM * that is used to maintain Linux ABI information. Presence of this section
37629273SAli.Bahrami@Sun.COM * is a strong indication that the object should be considered to be
37639273SAli.Bahrami@Sun.COM * ELFOSABI_LINUX.
37649273SAli.Bahrami@Sun.COM *
37659273SAli.Bahrami@Sun.COM * This function returns True (1) if such a note is seen, and False (0)
37669273SAli.Bahrami@Sun.COM * otherwise.
37679273SAli.Bahrami@Sun.COM */
37689273SAli.Bahrami@Sun.COM static int
has_linux_abi_note(Cache * cache,Word shnum,const char * file)37699273SAli.Bahrami@Sun.COM has_linux_abi_note(Cache *cache, Word shnum, const char *file)
37709273SAli.Bahrami@Sun.COM {
37719273SAli.Bahrami@Sun.COM Word cnt;
37729273SAli.Bahrami@Sun.COM
37739273SAli.Bahrami@Sun.COM for (cnt = 1; cnt < shnum; cnt++) {
37749273SAli.Bahrami@Sun.COM parse_note_t pnstate;
37759273SAli.Bahrami@Sun.COM Cache *_cache = &cache[cnt];
37769273SAli.Bahrami@Sun.COM Shdr *shdr = _cache->c_shdr;
37779273SAli.Bahrami@Sun.COM
37789273SAli.Bahrami@Sun.COM /*
37799273SAli.Bahrami@Sun.COM * Section must be SHT_NOTE, must have the name
37809273SAli.Bahrami@Sun.COM * .note.ABI-tag, and must have data.
37819273SAli.Bahrami@Sun.COM */
37829273SAli.Bahrami@Sun.COM if ((shdr->sh_type != SHT_NOTE) ||
37839273SAli.Bahrami@Sun.COM (strcmp(MSG_ORIG(MSG_STR_NOTEABITAG),
37849273SAli.Bahrami@Sun.COM _cache->c_name) != 0) || (_cache->c_data == NULL))
37859273SAli.Bahrami@Sun.COM continue;
37869273SAli.Bahrami@Sun.COM
37879273SAli.Bahrami@Sun.COM pnstate.pns_file = file;
37889273SAli.Bahrami@Sun.COM pnstate.pns_cache = _cache;
37899273SAli.Bahrami@Sun.COM pnstate.pns_size = _cache->c_data->d_size;
37909273SAli.Bahrami@Sun.COM pnstate.pns_data = (Word *)_cache->c_data->d_buf;
37919273SAli.Bahrami@Sun.COM
37929273SAli.Bahrami@Sun.COM while (pnstate.pns_size > 0) {
37939273SAli.Bahrami@Sun.COM Word *w;
37949273SAli.Bahrami@Sun.COM
37959273SAli.Bahrami@Sun.COM if (parse_note_entry(&pnstate) == 0)
37969273SAli.Bahrami@Sun.COM break;
37979273SAli.Bahrami@Sun.COM
37989273SAli.Bahrami@Sun.COM /*
37999273SAli.Bahrami@Sun.COM * The type must be 1, and the name must be "GNU".
38009273SAli.Bahrami@Sun.COM * The descsz must be at least 16 bytes.
38019273SAli.Bahrami@Sun.COM */
38029273SAli.Bahrami@Sun.COM if ((pnstate.pn_type != 1) ||
38039273SAli.Bahrami@Sun.COM (pnstate.pn_namesz != (MSG_STR_GNU_SIZE + 1)) ||
38049273SAli.Bahrami@Sun.COM (strncmp(MSG_ORIG(MSG_STR_GNU), pnstate.pn_name,
38059273SAli.Bahrami@Sun.COM MSG_STR_CORE_SIZE + 1) != 0) ||
38069273SAli.Bahrami@Sun.COM (pnstate.pn_descsz < 16))
38079273SAli.Bahrami@Sun.COM continue;
38089273SAli.Bahrami@Sun.COM
38099273SAli.Bahrami@Sun.COM /*
38109273SAli.Bahrami@Sun.COM * desc contains 4 32-bit fields. Field 0 must be 0,
38119273SAli.Bahrami@Sun.COM * indicating Linux. The second, third, and fourth
38129273SAli.Bahrami@Sun.COM * fields represent the earliest Linux kernel
38139273SAli.Bahrami@Sun.COM * version compatible with this object.
38149273SAli.Bahrami@Sun.COM */
38159273SAli.Bahrami@Sun.COM /*LINTED*/
38169273SAli.Bahrami@Sun.COM w = (Word *) pnstate.pn_desc;
38179273SAli.Bahrami@Sun.COM if (*w == 0)
38189273SAli.Bahrami@Sun.COM return (1);
38199273SAli.Bahrami@Sun.COM }
38209273SAli.Bahrami@Sun.COM }
38219273SAli.Bahrami@Sun.COM
38229273SAli.Bahrami@Sun.COM return (0);
38239273SAli.Bahrami@Sun.COM }
38249273SAli.Bahrami@Sun.COM
38259273SAli.Bahrami@Sun.COM /*
38261618Srie * Determine an individual hash entry. This may be the initial hash entry,
38271618Srie * or an associated chain entry.
38281618Srie */
38291618Srie static void
hash_entry(Cache * refsec,Cache * strsec,const char * hsecname,Word hashndx,Word symndx,Word symn,Sym * syms,const char * file,ulong_t bkts,uint_t flags,int chain)38301618Srie hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx,
38311618Srie Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts,
38321618Srie uint_t flags, int chain)
38331618Srie {
38341618Srie Sym *sym;
38351618Srie const char *symname, *str;
38361618Srie char _bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE];
38371618Srie ulong_t nbkt, nhash;
38381618Srie
38391618Srie if (symndx > symn) {
38401618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file,
38411618Srie EC_WORD(symndx), EC_WORD(hashndx));
38421618Srie symname = MSG_INTL(MSG_STR_UNKNOWN);
38431618Srie } else {
38441618Srie sym = (Sym *)(syms + symndx);
38451618Srie symname = string(refsec, symndx, strsec, file, sym->st_name);
38461618Srie }
38471618Srie
38481618Srie if (chain == 0) {
38491618Srie (void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER),
38501618Srie hashndx);
38511618Srie str = (const char *)_bucket;
38521618Srie } else
38531618Srie str = MSG_ORIG(MSG_STR_EMPTY);
38541618Srie
38551618Srie (void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2),
38561618Srie EC_WORD(symndx));
38571618Srie dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx,
38581618Srie demangle(symname, flags));
38591618Srie
38601618Srie /*
38611618Srie * Determine if this string is in the correct bucket.
38621618Srie */
38631618Srie nhash = elf_hash(symname);
38641618Srie nbkt = nhash % bkts;
38651618Srie
38661618Srie if (nbkt != hashndx) {
38671618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file,
38681618Srie hsecname, symname, EC_WORD(hashndx), nbkt);
38691618Srie }
38701618Srie }
38710Sstevel@tonic-gate
38720Sstevel@tonic-gate #define MAXCOUNT 500
38730Sstevel@tonic-gate
38740Sstevel@tonic-gate static void
hash(Cache * cache,Word shnum,const char * file,uint_t flags)38754168Sab196087 hash(Cache *cache, Word shnum, const char *file, uint_t flags)
38760Sstevel@tonic-gate {
38770Sstevel@tonic-gate static int count[MAXCOUNT];
38781618Srie Word cnt;
38790Sstevel@tonic-gate ulong_t ndx, bkts;
38800Sstevel@tonic-gate char number[MAXNDXSIZE];
38810Sstevel@tonic-gate
38820Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
38830Sstevel@tonic-gate uint_t *hash, *chain;
38840Sstevel@tonic-gate Cache *_cache = &cache[cnt];
38851618Srie Shdr *sshdr, *hshdr = _cache->c_shdr;
38861618Srie char *ssecname, *hsecname = _cache->c_name;
38871618Srie Sym *syms;
38881618Srie Word symn;
38890Sstevel@tonic-gate
38901618Srie if (hshdr->sh_type != SHT_HASH)
38910Sstevel@tonic-gate continue;
38920Sstevel@tonic-gate
38930Sstevel@tonic-gate /*
38940Sstevel@tonic-gate * Determine the hash table data and size.
38950Sstevel@tonic-gate */
38961618Srie if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) {
38970Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
38981618Srie file, hsecname);
38990Sstevel@tonic-gate continue;
39000Sstevel@tonic-gate }
39013466Srie if (_cache->c_data == NULL)
39023466Srie continue;
39033466Srie
39040Sstevel@tonic-gate hash = (uint_t *)_cache->c_data->d_buf;
39050Sstevel@tonic-gate bkts = *hash;
39060Sstevel@tonic-gate chain = hash + 2 + bkts;
39070Sstevel@tonic-gate hash += 2;
39080Sstevel@tonic-gate
39090Sstevel@tonic-gate /*
39100Sstevel@tonic-gate * Get the data buffer for the associated symbol table.
39110Sstevel@tonic-gate */
39121618Srie if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) {
39130Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
39141618Srie file, hsecname, EC_WORD(hshdr->sh_link));
39150Sstevel@tonic-gate continue;
39160Sstevel@tonic-gate }
39171618Srie
39181618Srie _cache = &cache[hshdr->sh_link];
39191618Srie ssecname = _cache->c_name;
39201618Srie
39213466Srie if (_cache->c_data == NULL)
39223466Srie continue;
39233466Srie
39243466Srie if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) {
39250Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
39261618Srie file, ssecname);
39270Sstevel@tonic-gate continue;
39280Sstevel@tonic-gate }
39290Sstevel@tonic-gate
39301618Srie sshdr = _cache->c_shdr;
39311618Srie /* LINTED */
39321618Srie symn = (Word)(sshdr->sh_size / sshdr->sh_entsize);
39331618Srie
39340Sstevel@tonic-gate /*
39350Sstevel@tonic-gate * Get the associated string table section.
39360Sstevel@tonic-gate */
39371618Srie if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) {
39380Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
39391618Srie file, ssecname, EC_WORD(sshdr->sh_link));
39400Sstevel@tonic-gate continue;
39410Sstevel@tonic-gate }
39420Sstevel@tonic-gate
39431618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
39441618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname);
39451618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO));
39460Sstevel@tonic-gate
39470Sstevel@tonic-gate /*
39480Sstevel@tonic-gate * Loop through the hash buckets, printing the appropriate
39490Sstevel@tonic-gate * symbols.
39500Sstevel@tonic-gate */
39510Sstevel@tonic-gate for (ndx = 0; ndx < bkts; ndx++, hash++) {
39521618Srie Word _ndx, _cnt;
39530Sstevel@tonic-gate
39540Sstevel@tonic-gate if (*hash == 0) {
39550Sstevel@tonic-gate count[0]++;
39560Sstevel@tonic-gate continue;
39570Sstevel@tonic-gate }
39580Sstevel@tonic-gate
39591618Srie hash_entry(_cache, &cache[sshdr->sh_link], hsecname,
39601618Srie ndx, *hash, symn, syms, file, bkts, flags, 0);
39610Sstevel@tonic-gate
39620Sstevel@tonic-gate /*
39630Sstevel@tonic-gate * Determine if any other symbols are chained to this
39640Sstevel@tonic-gate * bucket.
39650Sstevel@tonic-gate */
39660Sstevel@tonic-gate _ndx = chain[*hash];
39670Sstevel@tonic-gate _cnt = 1;
39680Sstevel@tonic-gate while (_ndx) {
39691618Srie hash_entry(_cache, &cache[sshdr->sh_link],
39701618Srie hsecname, ndx, _ndx, symn, syms, file,
39711618Srie bkts, flags, 1);
39720Sstevel@tonic-gate _ndx = chain[_ndx];
39730Sstevel@tonic-gate _cnt++;
39740Sstevel@tonic-gate }
39750Sstevel@tonic-gate
39760Sstevel@tonic-gate if (_cnt >= MAXCOUNT) {
39770Sstevel@tonic-gate (void) fprintf(stderr,
39781324Srie MSG_INTL(MSG_HASH_OVERFLW), file,
39791618Srie _cache->c_name, EC_WORD(ndx),
39801618Srie EC_WORD(_cnt));
39810Sstevel@tonic-gate } else
39820Sstevel@tonic-gate count[_cnt]++;
39830Sstevel@tonic-gate }
39840Sstevel@tonic-gate break;
39850Sstevel@tonic-gate }
39860Sstevel@tonic-gate
39870Sstevel@tonic-gate /*
39880Sstevel@tonic-gate * Print out the count information.
39890Sstevel@tonic-gate */
39900Sstevel@tonic-gate bkts = cnt = 0;
39911618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
39921618Srie
39930Sstevel@tonic-gate for (ndx = 0; ndx < MAXCOUNT; ndx++) {
39941618Srie Word _cnt;
39950Sstevel@tonic-gate
39960Sstevel@tonic-gate if ((_cnt = count[ndx]) == 0)
39970Sstevel@tonic-gate continue;
39980Sstevel@tonic-gate
39991618Srie (void) snprintf(number, MAXNDXSIZE,
40001618Srie MSG_ORIG(MSG_FMT_INTEGER), _cnt);
40011618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number,
40021618Srie EC_WORD(ndx));
40030Sstevel@tonic-gate bkts += _cnt;
40041618Srie cnt += (Word)(ndx * _cnt);
40050Sstevel@tonic-gate }
40060Sstevel@tonic-gate if (cnt) {
40070Sstevel@tonic-gate (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER),
40081618Srie bkts);
40091618Srie dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number,
40101618Srie EC_WORD(cnt));
40110Sstevel@tonic-gate }
40120Sstevel@tonic-gate }
40130Sstevel@tonic-gate
40140Sstevel@tonic-gate static void
group(Cache * cache,Word shnum,const char * file,uint_t flags)40154168Sab196087 group(Cache *cache, Word shnum, const char *file, uint_t flags)
40160Sstevel@tonic-gate {
40171618Srie Word scnt;
40180Sstevel@tonic-gate
40191618Srie for (scnt = 1; scnt < shnum; scnt++) {
402011227SAli.Bahrami@Sun.COM Cache *_cache = &cache[scnt];
402111227SAli.Bahrami@Sun.COM Shdr *shdr = _cache->c_shdr;
402211227SAli.Bahrami@Sun.COM Word *grpdata, gcnt, grpcnt, symnum, unknown;
402311227SAli.Bahrami@Sun.COM Cache *symsec, *strsec;
402411227SAli.Bahrami@Sun.COM Sym *syms, *sym;
402511227SAli.Bahrami@Sun.COM char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10];
402611227SAli.Bahrami@Sun.COM const char *grpnam;
40270Sstevel@tonic-gate
40280Sstevel@tonic-gate if (shdr->sh_type != SHT_GROUP)
40290Sstevel@tonic-gate continue;
40305411Sab196087 if (!match(MATCH_F_ALL, _cache->c_name, scnt, shdr->sh_type))
40310Sstevel@tonic-gate continue;
40323466Srie if ((_cache->c_data == NULL) ||
40333466Srie ((grpdata = (Word *)_cache->c_data->d_buf) == NULL))
40340Sstevel@tonic-gate continue;
40351618Srie grpcnt = shdr->sh_size / sizeof (Word);
40361618Srie
40371618Srie /*
40381618Srie * Get the data buffer for the associated symbol table and
40391618Srie * string table.
40401618Srie */
40411618Srie if (stringtbl(cache, 1, scnt, shnum, file,
40421618Srie &symnum, &symsec, &strsec) == 0)
40431618Srie return;
40441618Srie
40451618Srie syms = symsec->c_data->d_buf;
40461618Srie
40471618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
40481618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name);
40491618Srie dbg_print(0, MSG_INTL(MSG_GRP_TITLE));
40501618Srie
40511618Srie /*
40521618Srie * The first element of the group defines the group. The
40531618Srie * associated symbol is defined by the sh_link field.
40541618Srie */
40551618Srie if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) {
40561618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
40571618Srie file, _cache->c_name, EC_WORD(shdr->sh_info));
40581618Srie return;
40590Sstevel@tonic-gate }
40600Sstevel@tonic-gate
40611618Srie (void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT));
40621618Srie if (grpdata[0] & GRP_COMDAT) {
40631618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT));
40640Sstevel@tonic-gate }
40651618Srie if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) {
40661618Srie size_t len = strlen(flgstrbuf);
40671618Srie
40681618Srie (void) snprintf(&flgstrbuf[len],
40691618Srie (MSG_GRP_COMDAT_SIZE + 10 - len),
40701618Srie MSG_ORIG(MSG_GRP_UNKNOWN), unknown);
40710Sstevel@tonic-gate }
40721618Srie (void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT));
40731618Srie sym = (Sym *)(syms + shdr->sh_info);
40740Sstevel@tonic-gate
407511227SAli.Bahrami@Sun.COM /*
407611227SAli.Bahrami@Sun.COM * The GNU assembler can use section symbols as the signature
407711227SAli.Bahrami@Sun.COM * symbol as described by this comment in the gold linker
407811227SAli.Bahrami@Sun.COM * (found via google):
407911227SAli.Bahrami@Sun.COM *
408011227SAli.Bahrami@Sun.COM * It seems that some versions of gas will create a
408111227SAli.Bahrami@Sun.COM * section group associated with a section symbol, and
408211227SAli.Bahrami@Sun.COM * then fail to give a name to the section symbol. In
408311227SAli.Bahrami@Sun.COM * such a case, use the name of the section.
408411227SAli.Bahrami@Sun.COM *
408511227SAli.Bahrami@Sun.COM * In order to support such objects, we do the same.
408611227SAli.Bahrami@Sun.COM */
408711227SAli.Bahrami@Sun.COM grpnam = string(_cache, 0, strsec, file, sym->st_name);
408811227SAli.Bahrami@Sun.COM if (((sym->st_name == 0) || (*grpnam == '\0')) &&
408911227SAli.Bahrami@Sun.COM (ELF_ST_TYPE(sym->st_info) == STT_SECTION))
409011227SAli.Bahrami@Sun.COM grpnam = cache[sym->st_shndx].c_name;
409111227SAli.Bahrami@Sun.COM
40921618Srie dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf,
409311227SAli.Bahrami@Sun.COM demangle(grpnam, flags));
40941618Srie
40951618Srie for (gcnt = 1; gcnt < grpcnt; gcnt++) {
40960Sstevel@tonic-gate char index[MAXNDXSIZE];
40971618Srie const char *name;
40980Sstevel@tonic-gate
40990Sstevel@tonic-gate (void) snprintf(index, MAXNDXSIZE,
41001618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt));
41011618Srie
41021618Srie if (grpdata[gcnt] >= shnum)
41031618Srie name = MSG_INTL(MSG_GRP_INVALSCN);
41041618Srie else
41051618Srie name = cache[grpdata[gcnt]].c_name;
41061618Srie
41071618Srie (void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name,
41084433Sab196087 EC_XWORD(grpdata[gcnt]));
41090Sstevel@tonic-gate }
41100Sstevel@tonic-gate }
41110Sstevel@tonic-gate }
41120Sstevel@tonic-gate
41130Sstevel@tonic-gate static void
got(Cache * cache,Word shnum,Ehdr * ehdr,const char * file)41147463SRod.Evans@Sun.COM got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file)
41150Sstevel@tonic-gate {
41165230Sab196087 Cache *gotcache = NULL, *symtab = NULL;
41171618Srie Addr gotbgn, gotend;
41181618Srie Shdr *gotshdr;
41191618Srie Word cnt, gotents, gotndx;
41200Sstevel@tonic-gate size_t gentsize;
41210Sstevel@tonic-gate Got_info *gottable;
41220Sstevel@tonic-gate char *gotdata;
41231618Srie Sym *gotsym;
41241618Srie Xword gotsymaddr;
41256206Sab196087 uint_t sys_encoding;
41260Sstevel@tonic-gate
41270Sstevel@tonic-gate /*
41281324Srie * First, find the got.
41290Sstevel@tonic-gate */
41300Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
41315230Sab196087 if (strncmp(cache[cnt].c_name, MSG_ORIG(MSG_ELF_GOT),
41321324Srie MSG_ELF_GOT_SIZE) == 0) {
41335230Sab196087 gotcache = &cache[cnt];
41340Sstevel@tonic-gate break;
41350Sstevel@tonic-gate }
41360Sstevel@tonic-gate }
41375230Sab196087 if (gotcache == NULL)
41380Sstevel@tonic-gate return;
41391324Srie
41401324Srie /*
41411324Srie * A got section within a relocatable object is suspicious.
41421324Srie */
41431324Srie if (ehdr->e_type == ET_REL) {
41441324Srie (void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file,
41455230Sab196087 gotcache->c_name);
41461324Srie }
41471324Srie
41481618Srie gotshdr = gotcache->c_shdr;
41490Sstevel@tonic-gate if (gotshdr->sh_size == 0) {
41500Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
41510Sstevel@tonic-gate file, gotcache->c_name);
41520Sstevel@tonic-gate return;
41530Sstevel@tonic-gate }
41541618Srie
41551618Srie gotbgn = gotshdr->sh_addr;
41560Sstevel@tonic-gate gotend = gotbgn + gotshdr->sh_size;
41570Sstevel@tonic-gate
41580Sstevel@tonic-gate /*
41591618Srie * Some architectures don't properly set the sh_entsize for the GOT
41601618Srie * table. If it's not set, default to a size of a pointer.
41610Sstevel@tonic-gate */
41621618Srie if ((gentsize = gotshdr->sh_entsize) == 0)
41631618Srie gentsize = sizeof (Xword);
41641618Srie
41653466Srie if (gotcache->c_data == NULL)
41663466Srie return;
41673466Srie
41680Sstevel@tonic-gate /* LINTED */
41691618Srie gotents = (Word)(gotshdr->sh_size / gentsize);
41700Sstevel@tonic-gate gotdata = gotcache->c_data->d_buf;
41710Sstevel@tonic-gate
41720Sstevel@tonic-gate if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) {
41730Sstevel@tonic-gate int err = errno;
41741618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file,
41751618Srie strerror(err));
41760Sstevel@tonic-gate return;
41770Sstevel@tonic-gate }
41780Sstevel@tonic-gate
41790Sstevel@tonic-gate /*
41800Sstevel@tonic-gate * Now we scan through all the sections looking for any relocations
41810Sstevel@tonic-gate * that may be against the GOT. Since these may not be isolated to a
41820Sstevel@tonic-gate * .rel[a].got section we check them all.
41830Sstevel@tonic-gate * While scanning sections save the symbol table entry (a symtab
41840Sstevel@tonic-gate * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_.
41850Sstevel@tonic-gate */
41860Sstevel@tonic-gate for (cnt = 1; cnt < shnum; cnt++) {
41871618Srie Word type, symnum;
41881618Srie Xword relndx, relnum, relsize;
41891618Srie void *rels;
41901618Srie Sym *syms;
41911618Srie Cache *symsec, *strsec;
41921618Srie Cache *_cache = &cache[cnt];
41931618Srie Shdr *shdr;
41940Sstevel@tonic-gate
41951618Srie shdr = _cache->c_shdr;
41961618Srie type = shdr->sh_type;
41970Sstevel@tonic-gate
41981618Srie if ((symtab == 0) && (type == SHT_DYNSYM)) {
41990Sstevel@tonic-gate symtab = _cache;
42000Sstevel@tonic-gate continue;
42010Sstevel@tonic-gate }
42021618Srie if (type == SHT_SYMTAB) {
42030Sstevel@tonic-gate symtab = _cache;
42040Sstevel@tonic-gate continue;
42050Sstevel@tonic-gate }
42061618Srie if ((type != SHT_RELA) && (type != SHT_REL))
42070Sstevel@tonic-gate continue;
42080Sstevel@tonic-gate
42090Sstevel@tonic-gate /*
42101618Srie * Decide entry size.
42110Sstevel@tonic-gate */
42121618Srie if (((relsize = shdr->sh_entsize) == 0) ||
42131618Srie (relsize > shdr->sh_size)) {
42141618Srie if (type == SHT_RELA)
42151618Srie relsize = sizeof (Rela);
42161618Srie else
42171618Srie relsize = sizeof (Rel);
42180Sstevel@tonic-gate }
42190Sstevel@tonic-gate
42200Sstevel@tonic-gate /*
42211618Srie * Determine the number of relocations available.
42220Sstevel@tonic-gate */
42231618Srie if (shdr->sh_size == 0) {
42241618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
42251618Srie file, _cache->c_name);
42260Sstevel@tonic-gate continue;
42270Sstevel@tonic-gate }
42283466Srie if (_cache->c_data == NULL)
42293466Srie continue;
42303466Srie
42311618Srie rels = _cache->c_data->d_buf;
42321618Srie relnum = shdr->sh_size / relsize;
42330Sstevel@tonic-gate
42341618Srie /*
42351618Srie * Get the data buffer for the associated symbol table and
42361618Srie * string table.
42371618Srie */
42381618Srie if (stringtbl(cache, 1, cnt, shnum, file,
42391618Srie &symnum, &symsec, &strsec) == 0)
42401618Srie continue;
42411618Srie
42421618Srie syms = symsec->c_data->d_buf;
42431618Srie
42441618Srie /*
42451618Srie * Loop through the relocation entries.
42461618Srie */
42471618Srie for (relndx = 0; relndx < relnum; relndx++,
42481618Srie rels = (void *)((char *)rels + relsize)) {
42491618Srie char section[BUFSIZ];
42501618Srie Addr offset;
42510Sstevel@tonic-gate Got_info *gip;
42521618Srie Word symndx, reltype;
42531618Srie Rela *rela;
42541618Srie Rel *rel;
42550Sstevel@tonic-gate
42561618Srie /*
42571618Srie * Unravel the relocation.
42581618Srie */
42591618Srie if (type == SHT_RELA) {
42601618Srie rela = (Rela *)rels;
42611618Srie symndx = ELF_R_SYM(rela->r_info);
42626206Sab196087 reltype = ELF_R_TYPE(rela->r_info,
42636206Sab196087 ehdr->e_machine);
42641618Srie offset = rela->r_offset;
42650Sstevel@tonic-gate } else {
42661618Srie rel = (Rel *)rels;
42671618Srie symndx = ELF_R_SYM(rel->r_info);
42686206Sab196087 reltype = ELF_R_TYPE(rel->r_info,
42696206Sab196087 ehdr->e_machine);
42701618Srie offset = rel->r_offset;
42710Sstevel@tonic-gate }
42720Sstevel@tonic-gate
42730Sstevel@tonic-gate /*
42740Sstevel@tonic-gate * Only pay attention to relocations against the GOT.
42750Sstevel@tonic-gate */
42764146Sab196087 if ((offset < gotbgn) || (offset >= gotend))
42770Sstevel@tonic-gate continue;
42780Sstevel@tonic-gate
42790Sstevel@tonic-gate /* LINTED */
42801618Srie gotndx = (Word)((offset - gotbgn) /
42810Sstevel@tonic-gate gotshdr->sh_entsize);
42820Sstevel@tonic-gate gip = &gottable[gotndx];
42831618Srie
42841618Srie if (gip->g_reltype != 0) {
42850Sstevel@tonic-gate (void) fprintf(stderr,
42860Sstevel@tonic-gate MSG_INTL(MSG_GOT_MULTIPLE), file,
42871618Srie EC_WORD(gotndx), EC_ADDR(offset));
42880Sstevel@tonic-gate continue;
42890Sstevel@tonic-gate }
42900Sstevel@tonic-gate
42911618Srie if (symndx)
42921618Srie gip->g_symname = relsymname(cache, _cache,
42931618Srie strsec, symndx, symnum, relndx, syms,
42947463SRod.Evans@Sun.COM section, BUFSIZ, file);
42951618Srie gip->g_reltype = reltype;
42961618Srie gip->g_rel = rels;
42970Sstevel@tonic-gate }
42980Sstevel@tonic-gate }
42990Sstevel@tonic-gate
430011687SAli.Bahrami@Sun.COM if (symlookup(MSG_ORIG(MSG_SYM_GOT), cache, shnum, &gotsym, NULL,
430111687SAli.Bahrami@Sun.COM symtab, file))
43021618Srie gotsymaddr = gotsym->st_value;
43030Sstevel@tonic-gate else
43041618Srie gotsymaddr = gotbgn;
43050Sstevel@tonic-gate
43061618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
43071618Srie dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name);
43081618Srie Elf_got_title(0);
43090Sstevel@tonic-gate
43106206Sab196087 sys_encoding = _elf_sys_encoding();
43110Sstevel@tonic-gate for (gotndx = 0; gotndx < gotents; gotndx++) {
43120Sstevel@tonic-gate Got_info *gip;
43130Sstevel@tonic-gate Sword gindex;
43141618Srie Addr gaddr;
43151618Srie Xword gotentry;
43160Sstevel@tonic-gate
43170Sstevel@tonic-gate gip = &gottable[gotndx];
43180Sstevel@tonic-gate
43190Sstevel@tonic-gate gaddr = gotbgn + (gotndx * gentsize);
43201618Srie gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize;
43210Sstevel@tonic-gate
43221618Srie if (gentsize == sizeof (Word))
43230Sstevel@tonic-gate /* LINTED */
43241618Srie gotentry = (Xword)(*((Word *)(gotdata) + gotndx));
43250Sstevel@tonic-gate else
43260Sstevel@tonic-gate /* LINTED */
43271618Srie gotentry = *((Xword *)(gotdata) + gotndx);
43280Sstevel@tonic-gate
43291618Srie Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine,
43306206Sab196087 ehdr->e_ident[EI_DATA], sys_encoding,
43311618Srie gip->g_reltype, gip->g_rel, gip->g_symname);
43320Sstevel@tonic-gate }
43330Sstevel@tonic-gate free(gottable);
43340Sstevel@tonic-gate }
43350Sstevel@tonic-gate
43360Sstevel@tonic-gate void
checksum(Elf * elf)43370Sstevel@tonic-gate checksum(Elf *elf)
43380Sstevel@tonic-gate {
43391618Srie dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
43401618Srie dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf));
43410Sstevel@tonic-gate }
43420Sstevel@tonic-gate
43434242Sab196087 /*
43444242Sab196087 * This variable is used by regular() to communicate the address of
43454242Sab196087 * the section header cache to sort_shdr_ndx_arr(). Unfortunately,
43464242Sab196087 * the qsort() interface does not include a userdata argument by which
43474242Sab196087 * such arbitrary data can be passed, so we are stuck using global data.
43484242Sab196087 */
43494242Sab196087 static Cache *sort_shdr_ndx_arr_cache;
43504242Sab196087
43514242Sab196087
43524242Sab196087 /*
43534242Sab196087 * Used with qsort() to sort the section indices so that they can be
43544242Sab196087 * used to access the section headers in order of increasing data offset.
43554242Sab196087 *
43564242Sab196087 * entry:
43574242Sab196087 * sort_shdr_ndx_arr_cache - Contains address of
43584242Sab196087 * section header cache.
43594242Sab196087 * v1, v2 - Point at elements of sort_shdr_bits array to be compared.
43604242Sab196087 *
43614242Sab196087 * exit:
43624242Sab196087 * Returns -1 (less than), 0 (equal) or 1 (greater than).
43634242Sab196087 */
43644242Sab196087 static int
sort_shdr_ndx_arr(const void * v1,const void * v2)43654242Sab196087 sort_shdr_ndx_arr(const void *v1, const void *v2)
43664242Sab196087 {
43674242Sab196087 Cache *cache1 = sort_shdr_ndx_arr_cache + *((size_t *)v1);
43684242Sab196087 Cache *cache2 = sort_shdr_ndx_arr_cache + *((size_t *)v2);
43694242Sab196087
43704242Sab196087 if (cache1->c_shdr->sh_offset < cache2->c_shdr->sh_offset)
43714242Sab196087 return (-1);
43724242Sab196087
43734242Sab196087 if (cache1->c_shdr->sh_offset > cache2->c_shdr->sh_offset)
43744242Sab196087 return (1);
43754242Sab196087
43764242Sab196087 return (0);
43774242Sab196087 }
43784242Sab196087
43794242Sab196087
43804665Sab196087 static int
shdr_cache(const char * file,Elf * elf,Ehdr * ehdr,size_t shstrndx,size_t shnum,Cache ** cache_ret,Word flags)43814665Sab196087 shdr_cache(const char *file, Elf *elf, Ehdr *ehdr, size_t shstrndx,
43827463SRod.Evans@Sun.COM size_t shnum, Cache **cache_ret, Word flags)
43830Sstevel@tonic-gate {
43840Sstevel@tonic-gate Elf_Scn *scn;
43850Sstevel@tonic-gate Elf_Data *data;
43864665Sab196087 size_t ndx;
43874665Sab196087 Shdr *nameshdr;
43889085SAli.Bahrami@Sun.COM char *names = NULL;
43890Sstevel@tonic-gate Cache *cache, *_cache;
43904242Sab196087 size_t *shdr_ndx_arr, shdr_ndx_arr_cnt;
43910Sstevel@tonic-gate
43920Sstevel@tonic-gate
43930Sstevel@tonic-gate /*
43940Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required section
43950Sstevel@tonic-gate * name strings.
43960Sstevel@tonic-gate */
43974156Sab196087 if (shstrndx == SHN_UNDEF) {
43984156Sab196087 /*
43994156Sab196087 * It is rare, but legal, for an object to lack a
44004156Sab196087 * header string table section.
44014156Sab196087 */
44024156Sab196087 names = NULL;
44034156Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHSTRSEC), file);
44044156Sab196087 } else if ((scn = elf_getscn(elf, shstrndx)) == NULL) {
44050Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSCN));
44060Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR),
44070Sstevel@tonic-gate EC_XWORD(shstrndx));
44081618Srie
44090Sstevel@tonic-gate } else if ((data = elf_getdata(scn, NULL)) == NULL) {
44100Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA));
44110Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA),
44120Sstevel@tonic-gate EC_XWORD(shstrndx));
44131618Srie
44141618Srie } else if ((nameshdr = elf_getshdr(scn)) == NULL) {
44150Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
44160Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN),
44173862Srie EC_WORD(elf_ndxscn(scn)));
44181618Srie
44199085SAli.Bahrami@Sun.COM } else if ((names = data->d_buf) == NULL)
44200Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file);
44210Sstevel@tonic-gate
44220Sstevel@tonic-gate /*
44233862Srie * Allocate a cache to maintain a descriptor for each section.
44240Sstevel@tonic-gate */
44254665Sab196087 if ((*cache_ret = cache = malloc(shnum * sizeof (Cache))) == NULL) {
44260Sstevel@tonic-gate int err = errno;
44270Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
44280Sstevel@tonic-gate file, strerror(err));
44294665Sab196087 return (0);
44300Sstevel@tonic-gate }
44310Sstevel@tonic-gate
44321618Srie *cache = cache_init;
44330Sstevel@tonic-gate _cache = cache;
44340Sstevel@tonic-gate _cache++;
44350Sstevel@tonic-gate
44363862Srie /*
44374242Sab196087 * Allocate an array that will hold the section index for
44384242Sab196087 * each section that has data in the ELF file:
44394242Sab196087 *
44404242Sab196087 * - Is not a NOBITS section
44414242Sab196087 * - Data has non-zero length
44424242Sab196087 *
44434242Sab196087 * Note that shnum is an upper bound on the size required. It
44444242Sab196087 * is likely that we won't use a few of these array elements.
44454242Sab196087 * Allocating a modest amount of extra memory in this case means
44464242Sab196087 * that we can avoid an extra loop to count the number of needed
44474242Sab196087 * items, and can fill this array immediately in the first loop
44484242Sab196087 * below.
44494242Sab196087 */
44504242Sab196087 if ((shdr_ndx_arr = malloc(shnum * sizeof (*shdr_ndx_arr))) == NULL) {
44514242Sab196087 int err = errno;
44524242Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
44534242Sab196087 file, strerror(err));
44544665Sab196087 return (0);
44554242Sab196087 }
44564242Sab196087 shdr_ndx_arr_cnt = 0;
44574242Sab196087
44584242Sab196087 /*
44593862Srie * Traverse the sections of the file. This gathering of data is
44603862Srie * carried out in two passes. First, the section headers are captured
44613862Srie * and the section header names are evaluated. A verification pass is
44623862Srie * then carried out over the section information. Files have been
44633862Srie * known to exhibit overlapping (and hence erroneous) section header
44643862Srie * information.
44653862Srie *
44663862Srie * Finally, the data for each section is obtained. This processing is
44673862Srie * carried out after section verification because should any section
44683862Srie * header overlap occur, and a file needs translating (ie. xlate'ing
44693862Srie * information from a non-native architecture file), then the process
44703862Srie * of translation can corrupt the section header information. Of
44713862Srie * course, if there is any section overlap, the data related to the
44723862Srie * sections is going to be compromised. However, it is the translation
44733862Srie * of this data that has caused problems with elfdump()'s ability to
44743862Srie * extract the data.
44753862Srie */
44764242Sab196087 for (ndx = 1, scn = NULL; scn = elf_nextscn(elf, scn);
44774242Sab196087 ndx++, _cache++) {
44783862Srie char scnndxnm[100];
44793862Srie
44804242Sab196087 _cache->c_ndx = ndx;
44813862Srie _cache->c_scn = scn;
44823862Srie
44831618Srie if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) {
44840Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
44850Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN),
44863862Srie EC_WORD(elf_ndxscn(scn)));
44870Sstevel@tonic-gate }
44880Sstevel@tonic-gate
44893862Srie /*
44904242Sab196087 * If this section has data in the file, include it in
44914242Sab196087 * the array of sections to check for address overlap.
44924242Sab196087 */
44934242Sab196087 if ((_cache->c_shdr->sh_size != 0) &&
44944242Sab196087 (_cache->c_shdr->sh_type != SHT_NOBITS))
44954242Sab196087 shdr_ndx_arr[shdr_ndx_arr_cnt++] = ndx;
44964242Sab196087
44974242Sab196087 /*
44983862Srie * If a shstrtab exists, assign the section name.
44993862Srie */
45003862Srie if (names && _cache->c_shdr) {
45013862Srie if (_cache->c_shdr->sh_name &&
45023862Srie /* LINTED */
45033862Srie (nameshdr->sh_size > _cache->c_shdr->sh_name)) {
45047463SRod.Evans@Sun.COM const char *symname;
45057463SRod.Evans@Sun.COM char *secname;
45067463SRod.Evans@Sun.COM
45077463SRod.Evans@Sun.COM secname = names + _cache->c_shdr->sh_name;
45087463SRod.Evans@Sun.COM
45097463SRod.Evans@Sun.COM /*
45107463SRod.Evans@Sun.COM * A SUN naming convention employs a "%" within
45117463SRod.Evans@Sun.COM * a section name to indicate a section/symbol
45127463SRod.Evans@Sun.COM * name. This originated from the compilers
45137463SRod.Evans@Sun.COM * -xF option, that places functions into their
45147463SRod.Evans@Sun.COM * own sections. This convention (which has no
45157463SRod.Evans@Sun.COM * formal standard) has also been followed for
45167463SRod.Evans@Sun.COM * COMDAT sections. To demangle the symbol
45177463SRod.Evans@Sun.COM * name, the name must be separated from the
45187463SRod.Evans@Sun.COM * section name.
45197463SRod.Evans@Sun.COM */
45207463SRod.Evans@Sun.COM if (((flags & FLG_CTL_DEMANGLE) == 0) ||
45217463SRod.Evans@Sun.COM ((symname = strchr(secname, '%')) == NULL))
45227463SRod.Evans@Sun.COM _cache->c_name = secname;
45237463SRod.Evans@Sun.COM else {
45247463SRod.Evans@Sun.COM size_t secsz = ++symname - secname;
45257463SRod.Evans@Sun.COM size_t strsz;
45267463SRod.Evans@Sun.COM
45277463SRod.Evans@Sun.COM symname = demangle(symname, flags);
45287463SRod.Evans@Sun.COM strsz = secsz + strlen(symname) + 1;
45297463SRod.Evans@Sun.COM
45307463SRod.Evans@Sun.COM if ((_cache->c_name =
45317463SRod.Evans@Sun.COM malloc(strsz)) == NULL) {
45327463SRod.Evans@Sun.COM int err = errno;
45337463SRod.Evans@Sun.COM (void) fprintf(stderr,
45347463SRod.Evans@Sun.COM MSG_INTL(MSG_ERR_MALLOC),
45357463SRod.Evans@Sun.COM file, strerror(err));
45367463SRod.Evans@Sun.COM return (0);
45377463SRod.Evans@Sun.COM }
45387463SRod.Evans@Sun.COM (void) snprintf(_cache->c_name, strsz,
45397463SRod.Evans@Sun.COM MSG_ORIG(MSG_FMT_SECSYM),
45407463SRod.Evans@Sun.COM EC_WORD(secsz), secname, symname);
45417463SRod.Evans@Sun.COM }
45429085SAli.Bahrami@Sun.COM
45433862Srie continue;
45443862Srie }
45450Sstevel@tonic-gate
45460Sstevel@tonic-gate /*
45473862Srie * Generate an error if the section name index is zero
45483862Srie * or exceeds the shstrtab data. Fall through to
45493862Srie * fabricate a section name.
45500Sstevel@tonic-gate */
45513862Srie if ((_cache->c_shdr->sh_name == 0) ||
45520Sstevel@tonic-gate /* LINTED */
45531618Srie (nameshdr->sh_size <= _cache->c_shdr->sh_name)) {
45540Sstevel@tonic-gate (void) fprintf(stderr,
45550Sstevel@tonic-gate MSG_INTL(MSG_ERR_BADSHNAME), file,
45564242Sab196087 EC_WORD(ndx),
45571618Srie EC_XWORD(_cache->c_shdr->sh_name));
45580Sstevel@tonic-gate }
45593862Srie }
45603862Srie
45613862Srie /*
45623862Srie * If there exists no shstrtab data, or a section header has no
45633862Srie * name (an invalid index of 0), then compose a name for the
45643862Srie * section.
45653862Srie */
45663862Srie (void) snprintf(scnndxnm, sizeof (scnndxnm),
45674242Sab196087 MSG_INTL(MSG_FMT_SCNNDX), ndx);
45684242Sab196087
45694242Sab196087 if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == NULL) {
45703862Srie int err = errno;
45713862Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
45723862Srie file, strerror(err));
45734665Sab196087 return (0);
45743862Srie }
45753862Srie (void) strcpy(_cache->c_name, scnndxnm);
45763862Srie }
45773862Srie
45783862Srie /*
45793862Srie * Having collected all the sections, validate their address range.
45803862Srie * Cases have existed where the section information has been invalid.
45813862Srie * This can lead to all sorts of other, hard to diagnose errors, as
45823862Srie * each section is processed individually (ie. with elf_getdata()).
45833862Srie * Here, we carry out some address comparisons to catch a family of
45843862Srie * overlapping memory issues we have observed (likely, there are others
45853862Srie * that we have yet to discover).
45863862Srie *
45873862Srie * Note, should any memory overlap occur, obtaining any additional
45883862Srie * data from the file is questionable. However, it might still be
45893862Srie * possible to inspect the ELF header, Programs headers, or individual
45903862Srie * sections, so rather than bailing on an error condition, continue
45913862Srie * processing to see if any data can be salvaged.
45923862Srie */
45934242Sab196087 if (shdr_ndx_arr_cnt > 1) {
45944242Sab196087 sort_shdr_ndx_arr_cache = cache;
45954242Sab196087 qsort(shdr_ndx_arr, shdr_ndx_arr_cnt,
45964242Sab196087 sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr);
45974242Sab196087 }
45984242Sab196087 for (ndx = 0; ndx < shdr_ndx_arr_cnt; ndx++) {
45994242Sab196087 Cache *_cache = cache + shdr_ndx_arr[ndx];
46003862Srie Shdr *shdr = _cache->c_shdr;
46013862Srie Off bgn1, bgn = shdr->sh_offset;
46023862Srie Off end1, end = shdr->sh_offset + shdr->sh_size;
46034242Sab196087 size_t ndx1;
46044242Sab196087
46054242Sab196087 /*
46064242Sab196087 * Check the section against all following ones, reporting
46074242Sab196087 * any overlaps. Since we've sorted the sections by offset,
46084242Sab196087 * we can stop after the first comparison that fails. There
46094242Sab196087 * are no overlaps in a properly formed ELF file, in which
46104242Sab196087 * case this algorithm runs in O(n) time. This will degenerate
46114242Sab196087 * to O(n^2) for a completely broken file. Such a file is
46124242Sab196087 * (1) highly unlikely, and (2) unusable, so it is reasonable
46134242Sab196087 * for the analysis to take longer.
46144242Sab196087 */
46154242Sab196087 for (ndx1 = ndx + 1; ndx1 < shdr_ndx_arr_cnt; ndx1++) {
46164242Sab196087 Cache *_cache1 = cache + shdr_ndx_arr[ndx1];
46173862Srie Shdr *shdr1 = _cache1->c_shdr;
46183862Srie
46193862Srie bgn1 = shdr1->sh_offset;
46203862Srie end1 = shdr1->sh_offset + shdr1->sh_size;
46213862Srie
46223862Srie if (((bgn1 <= bgn) && (end1 > bgn)) ||
46233862Srie ((bgn1 < end) && (end1 >= end))) {
46243862Srie (void) fprintf(stderr,
46253862Srie MSG_INTL(MSG_ERR_SECMEMOVER), file,
46264242Sab196087 EC_WORD(elf_ndxscn(_cache->c_scn)),
46274242Sab196087 _cache->c_name, EC_OFF(bgn), EC_OFF(end),
46283862Srie EC_WORD(elf_ndxscn(_cache1->c_scn)),
46294242Sab196087 _cache1->c_name, EC_OFF(bgn1),
46304242Sab196087 EC_OFF(end1));
46314242Sab196087 } else { /* No overlap, so can stop */
46324242Sab196087 break;
46330Sstevel@tonic-gate }
46340Sstevel@tonic-gate }
46350Sstevel@tonic-gate
46363862Srie /*
46374242Sab196087 * In addition to checking for sections overlapping
46384242Sab196087 * each other (done above), we should also make sure
46394242Sab196087 * the section doesn't overlap the section header array.
46403862Srie */
46413862Srie bgn1 = ehdr->e_shoff;
46423862Srie end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum);
46433862Srie
46443862Srie if (((bgn1 <= bgn) && (end1 > bgn)) ||
46453862Srie ((bgn1 < end) && (end1 >= end))) {
46463862Srie (void) fprintf(stderr,
46473862Srie MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1),
46483862Srie EC_OFF(end1),
46493862Srie EC_WORD(elf_ndxscn(_cache->c_scn)),
46503862Srie _cache->c_name, EC_OFF(bgn), EC_OFF(end));
46513862Srie }
46523862Srie }
46533862Srie
46543862Srie /*
46554242Sab196087 * Obtain the data for each section.
46563862Srie */
46574242Sab196087 for (ndx = 1; ndx < shnum; ndx++) {
46584242Sab196087 Cache *_cache = &cache[ndx];
46593862Srie Elf_Scn *scn = _cache->c_scn;
46603862Srie
46610Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) {
46620Sstevel@tonic-gate failure(file, MSG_ORIG(MSG_ELF_GETDATA));
46630Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA),
46643862Srie EC_WORD(elf_ndxscn(scn)));
46650Sstevel@tonic-gate }
46668747SAli.Bahrami@Sun.COM
46678747SAli.Bahrami@Sun.COM /*
46688747SAli.Bahrami@Sun.COM * If a string table, verify that it has NULL first and
46698747SAli.Bahrami@Sun.COM * final bytes.
46708747SAli.Bahrami@Sun.COM */
46718747SAli.Bahrami@Sun.COM if ((_cache->c_shdr->sh_type == SHT_STRTAB) &&
46728747SAli.Bahrami@Sun.COM (_cache->c_data->d_buf != NULL) &&
46738747SAli.Bahrami@Sun.COM (_cache->c_data->d_size > 0)) {
46748747SAli.Bahrami@Sun.COM const char *s = _cache->c_data->d_buf;
46758747SAli.Bahrami@Sun.COM
46768747SAli.Bahrami@Sun.COM if ((*s != '\0') ||
46778747SAli.Bahrami@Sun.COM (*(s + _cache->c_data->d_size - 1) != '\0'))
46788747SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALSTR),
46798747SAli.Bahrami@Sun.COM file, _cache->c_name);
46808747SAli.Bahrami@Sun.COM }
46814665Sab196087 }
46824665Sab196087
46834665Sab196087 return (1);
46844665Sab196087 }
46854665Sab196087
46864665Sab196087
46874665Sab196087
46889273SAli.Bahrami@Sun.COM /*
46899273SAli.Bahrami@Sun.COM * Generate a cache of section headers and related information
46909273SAli.Bahrami@Sun.COM * for use by the rest of elfdump. If requested (or the file
46919273SAli.Bahrami@Sun.COM * contains no section headers), we generate a fake set of
46929273SAli.Bahrami@Sun.COM * headers from the information accessible from the program headers.
46939273SAli.Bahrami@Sun.COM * Otherwise, we use the real section headers contained in the file.
46949273SAli.Bahrami@Sun.COM */
46959273SAli.Bahrami@Sun.COM static int
create_cache(const char * file,int fd,Elf * elf,Ehdr * ehdr,Cache ** cache,size_t shstrndx,size_t * shnum,uint_t * flags)46969273SAli.Bahrami@Sun.COM create_cache(const char *file, int fd, Elf *elf, Ehdr *ehdr, Cache **cache,
46979273SAli.Bahrami@Sun.COM size_t shstrndx, size_t *shnum, uint_t *flags)
46989273SAli.Bahrami@Sun.COM {
46999273SAli.Bahrami@Sun.COM /*
47009273SAli.Bahrami@Sun.COM * If there are no section headers, then resort to synthesizing
47019273SAli.Bahrami@Sun.COM * section headers from the program headers. This is normally
47029273SAli.Bahrami@Sun.COM * only done by explicit request, but in this case there's no
47039273SAli.Bahrami@Sun.COM * reason not to go ahead, since the alternative is simply to quit.
47049273SAli.Bahrami@Sun.COM */
47059273SAli.Bahrami@Sun.COM if ((*shnum <= 1) && ((*flags & FLG_CTL_FAKESHDR) == 0)) {
47069273SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_ERR_NOSHDR), file);
47079273SAli.Bahrami@Sun.COM *flags |= FLG_CTL_FAKESHDR;
47089273SAli.Bahrami@Sun.COM }
47099273SAli.Bahrami@Sun.COM
47109273SAli.Bahrami@Sun.COM if (*flags & FLG_CTL_FAKESHDR) {
47119273SAli.Bahrami@Sun.COM if (fake_shdr_cache(file, fd, elf, ehdr, cache, shnum) == 0)
47129273SAli.Bahrami@Sun.COM return (0);
47139273SAli.Bahrami@Sun.COM } else {
47149273SAli.Bahrami@Sun.COM if (shdr_cache(file, elf, ehdr, shstrndx, *shnum,
47159273SAli.Bahrami@Sun.COM cache, *flags) == 0)
47169273SAli.Bahrami@Sun.COM return (0);
47179273SAli.Bahrami@Sun.COM }
47189273SAli.Bahrami@Sun.COM
47199273SAli.Bahrami@Sun.COM return (1);
47209273SAli.Bahrami@Sun.COM }
47219273SAli.Bahrami@Sun.COM
47225411Sab196087 int
regular(const char * file,int fd,Elf * elf,uint_t flags,const char * wname,int wfd,uchar_t osabi)47235411Sab196087 regular(const char *file, int fd, Elf *elf, uint_t flags,
47249273SAli.Bahrami@Sun.COM const char *wname, int wfd, uchar_t osabi)
47254665Sab196087 {
47269273SAli.Bahrami@Sun.COM enum { CACHE_NEEDED, CACHE_OK, CACHE_FAIL} cache_state = CACHE_NEEDED;
47274665Sab196087 Elf_Scn *scn;
47284665Sab196087 Ehdr *ehdr;
47294665Sab196087 size_t ndx, shstrndx, shnum, phnum;
47304665Sab196087 Shdr *shdr;
47314665Sab196087 Cache *cache;
47324665Sab196087 VERSYM_STATE versym;
47335411Sab196087 int ret = 0;
47345411Sab196087 int addr_align;
47354665Sab196087
47364665Sab196087 if ((ehdr = elf_getehdr(elf)) == NULL) {
47374665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETEHDR));
47385411Sab196087 return (ret);
47394665Sab196087 }
47404665Sab196087
47419900SAli.Bahrami@Sun.COM if (elf_getshdrnum(elf, &shnum) == -1) {
47429900SAli.Bahrami@Sun.COM failure(file, MSG_ORIG(MSG_ELF_GETSHDRNUM));
47435411Sab196087 return (ret);
47444665Sab196087 }
47454665Sab196087
47469900SAli.Bahrami@Sun.COM if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
47479900SAli.Bahrami@Sun.COM failure(file, MSG_ORIG(MSG_ELF_GETSHDRSTRNDX));
47485411Sab196087 return (ret);
47494665Sab196087 }
47504665Sab196087
47519900SAli.Bahrami@Sun.COM if (elf_getphdrnum(elf, &phnum) == -1) {
47529900SAli.Bahrami@Sun.COM failure(file, MSG_ORIG(MSG_ELF_GETPHDRNUM));
47535411Sab196087 return (ret);
47544665Sab196087 }
47554665Sab196087 /*
47564665Sab196087 * If the user requested section headers derived from the
47574665Sab196087 * program headers (-P option) and this file doesn't have
47584665Sab196087 * any program headers (i.e. ET_REL), then we can't do it.
47594665Sab196087 */
47605411Sab196087 if ((phnum == 0) && (flags & FLG_CTL_FAKESHDR)) {
47614665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_PNEEDSPH), file);
47625411Sab196087 return (ret);
47634665Sab196087 }
47644665Sab196087
47654665Sab196087
47664665Sab196087 if ((scn = elf_getscn(elf, 0)) != NULL) {
47674665Sab196087 if ((shdr = elf_getshdr(scn)) == NULL) {
47684665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
47694665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0);
47705411Sab196087 return (ret);
47714665Sab196087 }
47724665Sab196087 } else
47739085SAli.Bahrami@Sun.COM shdr = NULL;
47744665Sab196087
47754665Sab196087 /*
47764665Sab196087 * Print the elf header.
47774665Sab196087 */
47785411Sab196087 if (flags & FLG_SHOW_EHDR)
47794665Sab196087 Elf_ehdr(0, ehdr, shdr);
47804665Sab196087
47814665Sab196087 /*
47824665Sab196087 * If the section headers or program headers have inadequate
47834665Sab196087 * alignment for the class of object, print a warning. libelf
47844665Sab196087 * can handle such files, but programs that use them can crash
47854665Sab196087 * when they dereference unaligned items.
47865411Sab196087 *
47875411Sab196087 * Note that the AMD64 ABI, although it is a 64-bit architecture,
47885411Sab196087 * allows access to data types smaller than 128-bits to be on
47895411Sab196087 * word alignment.
47904665Sab196087 */
47915411Sab196087 if (ehdr->e_machine == EM_AMD64)
47925411Sab196087 addr_align = sizeof (Word);
47935411Sab196087 else
47945411Sab196087 addr_align = sizeof (Addr);
47955411Sab196087
47965411Sab196087 if (ehdr->e_phoff & (addr_align - 1))
47974665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADPHDRALIGN), file);
47985411Sab196087 if (ehdr->e_shoff & (addr_align - 1))
47994665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHDRALIGN), file);
48004665Sab196087
48019273SAli.Bahrami@Sun.COM
48029273SAli.Bahrami@Sun.COM /*
48039273SAli.Bahrami@Sun.COM * Determine the Operating System ABI (osabi) we will use to
48049273SAli.Bahrami@Sun.COM * interpret the object.
48059273SAli.Bahrami@Sun.COM */
48069273SAli.Bahrami@Sun.COM if (flags & FLG_CTL_OSABI) {
48079273SAli.Bahrami@Sun.COM /*
48089273SAli.Bahrami@Sun.COM * If the user explicitly specifies '-O none', we need
48099273SAli.Bahrami@Sun.COM * to display a completely generic view of the file.
48109273SAli.Bahrami@Sun.COM * However, libconv is written to assume that ELFOSABI_NONE
48119273SAli.Bahrami@Sun.COM * is equivalent to ELFOSABI_SOLARIS. To get the desired
48129273SAli.Bahrami@Sun.COM * effect, we use an osabi that libconv has no knowledge of.
48139273SAli.Bahrami@Sun.COM */
48149273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE)
48159273SAli.Bahrami@Sun.COM osabi = ELFOSABI_UNKNOWN4;
48169273SAli.Bahrami@Sun.COM } else {
48179273SAli.Bahrami@Sun.COM /* Determine osabi from file */
48189273SAli.Bahrami@Sun.COM osabi = ehdr->e_ident[EI_OSABI];
48199273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE) {
48209273SAli.Bahrami@Sun.COM /*
48219273SAli.Bahrami@Sun.COM * Chicken/Egg scenario:
48229273SAli.Bahrami@Sun.COM *
48239273SAli.Bahrami@Sun.COM * Ideally, we wait to create the section header cache
48249273SAli.Bahrami@Sun.COM * until after the program headers are printed. If we
48259273SAli.Bahrami@Sun.COM * only output program headers, we can skip building
48269273SAli.Bahrami@Sun.COM * the cache entirely.
48279273SAli.Bahrami@Sun.COM *
48289273SAli.Bahrami@Sun.COM * Proper interpretation of program headers requires
48299273SAli.Bahrami@Sun.COM * the osabi, which is supposed to be in the ELF header.
48309273SAli.Bahrami@Sun.COM * However, many systems (Solaris and Linux included)
48319273SAli.Bahrami@Sun.COM * have a history of setting the osabi to the generic
48329273SAli.Bahrami@Sun.COM * SysV ABI (ELFOSABI_NONE). We assume ELFOSABI_SOLARIS
48339273SAli.Bahrami@Sun.COM * in such cases, but would like to check the object
48349273SAli.Bahrami@Sun.COM * to see if it has a Linux .note.ABI-tag section,
48359273SAli.Bahrami@Sun.COM * which implies ELFOSABI_LINUX. This requires a
48369273SAli.Bahrami@Sun.COM * section header cache.
48379273SAli.Bahrami@Sun.COM *
48389273SAli.Bahrami@Sun.COM * To break the cycle, we create section headers now
48399273SAli.Bahrami@Sun.COM * if osabi is ELFOSABI_NONE, and later otherwise.
48409273SAli.Bahrami@Sun.COM * If it succeeds, we use them, if not, we defer
48419273SAli.Bahrami@Sun.COM * exiting until after the program headers are out.
48429273SAli.Bahrami@Sun.COM */
48439273SAli.Bahrami@Sun.COM if (create_cache(file, fd, elf, ehdr, &cache,
48449273SAli.Bahrami@Sun.COM shstrndx, &shnum, &flags) == 0) {
48459273SAli.Bahrami@Sun.COM cache_state = CACHE_FAIL;
48469273SAli.Bahrami@Sun.COM } else {
48479273SAli.Bahrami@Sun.COM cache_state = CACHE_OK;
48489273SAli.Bahrami@Sun.COM if (has_linux_abi_note(cache, shnum, file)) {
48499273SAli.Bahrami@Sun.COM Conv_inv_buf_t ibuf1, ibuf2;
48509273SAli.Bahrami@Sun.COM
48519273SAli.Bahrami@Sun.COM (void) fprintf(stderr,
48529273SAli.Bahrami@Sun.COM MSG_INTL(MSG_INFO_LINUXOSABI), file,
48539273SAli.Bahrami@Sun.COM conv_ehdr_osabi(osabi, 0, &ibuf1),
48549273SAli.Bahrami@Sun.COM conv_ehdr_osabi(ELFOSABI_LINUX,
48559273SAli.Bahrami@Sun.COM 0, &ibuf2));
48569273SAli.Bahrami@Sun.COM osabi = ELFOSABI_LINUX;
48579273SAli.Bahrami@Sun.COM }
48589273SAli.Bahrami@Sun.COM }
48599273SAli.Bahrami@Sun.COM }
48609273SAli.Bahrami@Sun.COM /*
48619273SAli.Bahrami@Sun.COM * We treat ELFOSABI_NONE identically to ELFOSABI_SOLARIS.
48629273SAli.Bahrami@Sun.COM * Mapping NONE to SOLARIS simplifies the required test.
48639273SAli.Bahrami@Sun.COM */
48649273SAli.Bahrami@Sun.COM if (osabi == ELFOSABI_NONE)
48659273SAli.Bahrami@Sun.COM osabi = ELFOSABI_SOLARIS;
48669273SAli.Bahrami@Sun.COM }
48679273SAli.Bahrami@Sun.COM
48684665Sab196087 /*
48694665Sab196087 * Print the program headers.
48704665Sab196087 */
48715411Sab196087 if ((flags & FLG_SHOW_PHDR) && (phnum != 0)) {
48725411Sab196087 Phdr *phdr;
48734665Sab196087
48744665Sab196087 if ((phdr = elf_getphdr(elf)) == NULL) {
48754665Sab196087 failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
48765411Sab196087 return (ret);
48774665Sab196087 }
48784665Sab196087
48794665Sab196087 for (ndx = 0; ndx < phnum; phdr++, ndx++) {
48805411Sab196087 if (!match(MATCH_F_PHDR| MATCH_F_NDX | MATCH_F_TYPE,
48815411Sab196087 NULL, ndx, phdr->p_type))
48824665Sab196087 continue;
48834665Sab196087
48844665Sab196087 dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
48854665Sab196087 dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx));
48869273SAli.Bahrami@Sun.COM Elf_phdr(0, osabi, ehdr->e_machine, phdr);
48874665Sab196087 }
48884665Sab196087 }
48894665Sab196087
48904665Sab196087 /*
48915411Sab196087 * If we have flag bits set that explicitly require a show or calc
48925411Sab196087 * operation, but none of them require the section headers, then
48935411Sab196087 * we are done and can return now.
48944665Sab196087 */
48955411Sab196087 if (((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) != 0) &&
48965411Sab196087 ((flags & (FLG_MASK_SHOW_SHDR | FLG_MASK_CALC_SHDR)) == 0))
48975411Sab196087 return (ret);
48985411Sab196087
48995411Sab196087 /*
49005411Sab196087 * Everything from this point on requires section headers.
49015411Sab196087 * If we have no section headers, there is no reason to continue.
49029273SAli.Bahrami@Sun.COM *
49039273SAli.Bahrami@Sun.COM * If we tried above to create the section header cache and failed,
49049273SAli.Bahrami@Sun.COM * it is time to exit. Otherwise, create it if needed.
49055411Sab196087 */
49069273SAli.Bahrami@Sun.COM switch (cache_state) {
49079273SAli.Bahrami@Sun.COM case CACHE_NEEDED:
49089273SAli.Bahrami@Sun.COM if (create_cache(file, fd, elf, ehdr, &cache, shstrndx,
49099273SAli.Bahrami@Sun.COM &shnum, &flags) == 0)
49109273SAli.Bahrami@Sun.COM return (ret);
49119273SAli.Bahrami@Sun.COM break;
49129273SAli.Bahrami@Sun.COM case CACHE_FAIL:
49139273SAli.Bahrami@Sun.COM return (ret);
49149273SAli.Bahrami@Sun.COM }
49155411Sab196087 if (shnum <= 1)
49165411Sab196087 goto done;
49175411Sab196087
49185411Sab196087 /*
49194665Sab196087 * If -w was specified, find and write out the section(s) data.
49204665Sab196087 */
49214665Sab196087 if (wfd) {
49224665Sab196087 for (ndx = 1; ndx < shnum; ndx++) {
49234665Sab196087 Cache *_cache = &cache[ndx];
49244665Sab196087
49255411Sab196087 if (match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name,
49265411Sab196087 ndx, _cache->c_shdr->sh_type) &&
49275411Sab196087 _cache->c_data && _cache->c_data->d_buf) {
49285411Sab196087 if (write(wfd, _cache->c_data->d_buf,
49295411Sab196087 _cache->c_data->d_size) !=
49305411Sab196087 _cache->c_data->d_size) {
49315411Sab196087 int err = errno;
49325411Sab196087 (void) fprintf(stderr,
49335411Sab196087 MSG_INTL(MSG_ERR_WRITE), wname,
49345411Sab196087 strerror(err));
49355411Sab196087 /*
49365411Sab196087 * Return an exit status of 1, because
49375411Sab196087 * the failure is not related to the
49385411Sab196087 * ELF file, but by system resources.
49395411Sab196087 */
49405411Sab196087 ret = 1;
49415411Sab196087 goto done;
49425411Sab196087 }
49434665Sab196087 }
49440Sstevel@tonic-gate }
49450Sstevel@tonic-gate }
49460Sstevel@tonic-gate
49475411Sab196087 /*
49485411Sab196087 * If we have no flag bits set that explicitly require a show or calc
49495411Sab196087 * operation, but match options (-I, -N, -T) were used, then run
49505411Sab196087 * through the section headers and see if we can't deduce show flags
49515411Sab196087 * from the match options given.
49525411Sab196087 *
49535411Sab196087 * We don't do this if -w was specified, because (-I, -N, -T) used
49545411Sab196087 * with -w in lieu of some other option is supposed to be quiet.
49555411Sab196087 */
49565411Sab196087 if ((wfd == 0) && (flags & FLG_CTL_MATCH) &&
49575411Sab196087 ((flags & (FLG_MASK_SHOW | FLG_MASK_CALC)) == 0)) {
49585411Sab196087 for (ndx = 1; ndx < shnum; ndx++) {
49595411Sab196087 Cache *_cache = &cache[ndx];
49605411Sab196087
49615411Sab196087 if (!match(MATCH_F_STRICT | MATCH_F_ALL, _cache->c_name,
49625411Sab196087 ndx, _cache->c_shdr->sh_type))
49635411Sab196087 continue;
49645411Sab196087
49655411Sab196087 switch (_cache->c_shdr->sh_type) {
49665411Sab196087 case SHT_PROGBITS:
49675411Sab196087 /*
49685411Sab196087 * Heuristic time: It is usually bad form
49699085SAli.Bahrami@Sun.COM * to assume the meaning/format of a PROGBITS
49709085SAli.Bahrami@Sun.COM * section based on its name. However, there
49719406SAli.Bahrami@Sun.COM * are ABI mandated exceptions. Check for
49729406SAli.Bahrami@Sun.COM * these special names.
49735411Sab196087 */
49749406SAli.Bahrami@Sun.COM
49759406SAli.Bahrami@Sun.COM /* The ELF ABI specifies .interp and .got */
49769406SAli.Bahrami@Sun.COM if (strcmp(_cache->c_name,
49779406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_ELF_INTERP)) == 0) {
49789406SAli.Bahrami@Sun.COM flags |= FLG_SHOW_INTERP;
49799406SAli.Bahrami@Sun.COM break;
49809406SAli.Bahrami@Sun.COM }
49815411Sab196087 if (strcmp(_cache->c_name,
49829406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_ELF_GOT)) == 0) {
49835411Sab196087 flags |= FLG_SHOW_GOT;
49849406SAli.Bahrami@Sun.COM break;
49859406SAli.Bahrami@Sun.COM }
49869406SAli.Bahrami@Sun.COM /*
49879406SAli.Bahrami@Sun.COM * The GNU compilers, and amd64 ABI, define
49889406SAli.Bahrami@Sun.COM * .eh_frame and .eh_frame_hdr. The Sun
49899406SAli.Bahrami@Sun.COM * C++ ABI defines .exception_ranges.
49909406SAli.Bahrami@Sun.COM */
49919406SAli.Bahrami@Sun.COM if ((strncmp(_cache->c_name,
49929085SAli.Bahrami@Sun.COM MSG_ORIG(MSG_SCN_FRM),
49939406SAli.Bahrami@Sun.COM MSG_SCN_FRM_SIZE) == 0) ||
49949406SAli.Bahrami@Sun.COM (strncmp(_cache->c_name,
49959406SAli.Bahrami@Sun.COM MSG_ORIG(MSG_SCN_EXRANGE),
49969406SAli.Bahrami@Sun.COM MSG_SCN_EXRANGE_SIZE) == 0)) {
49979085SAli.Bahrami@Sun.COM flags |= FLG_SHOW_UNWIND;
49989406SAli.Bahrami@Sun.COM break;
49999406SAli.Bahrami@Sun.COM }
50005411Sab196087 break;
50015411Sab196087
50025411Sab196087 case SHT_SYMTAB:
50035411Sab196087 case SHT_DYNSYM:
50045411Sab196087 case SHT_SUNW_LDYNSYM:
50055411Sab196087 case SHT_SUNW_versym:
50065411Sab196087 case SHT_SYMTAB_SHNDX:
50075411Sab196087 flags |= FLG_SHOW_SYMBOLS;
50085411Sab196087 break;
50095411Sab196087
50105411Sab196087 case SHT_RELA:
50115411Sab196087 case SHT_REL:
50125411Sab196087 flags |= FLG_SHOW_RELOC;
50135411Sab196087 break;
50145411Sab196087
50155411Sab196087 case SHT_HASH:
50165411Sab196087 flags |= FLG_SHOW_HASH;
50175411Sab196087 break;
50185411Sab196087
50195411Sab196087 case SHT_DYNAMIC:
50205411Sab196087 flags |= FLG_SHOW_DYNAMIC;
50215411Sab196087 break;
50225411Sab196087
50235411Sab196087 case SHT_NOTE:
50245411Sab196087 flags |= FLG_SHOW_NOTE;
50255411Sab196087 break;
50265411Sab196087
50275411Sab196087 case SHT_GROUP:
50285411Sab196087 flags |= FLG_SHOW_GROUP;
50295411Sab196087 break;
50305411Sab196087
50315411Sab196087 case SHT_SUNW_symsort:
50325411Sab196087 case SHT_SUNW_tlssort:
50335411Sab196087 flags |= FLG_SHOW_SORT;
50345411Sab196087 break;
50355411Sab196087
50365411Sab196087 case SHT_SUNW_cap:
50375411Sab196087 flags |= FLG_SHOW_CAP;
50385411Sab196087 break;
50395411Sab196087
50405411Sab196087 case SHT_SUNW_move:
50415411Sab196087 flags |= FLG_SHOW_MOVE;
50425411Sab196087 break;
50435411Sab196087
50445411Sab196087 case SHT_SUNW_syminfo:
50455411Sab196087 flags |= FLG_SHOW_SYMINFO;
50465411Sab196087 break;
50475411Sab196087
50485411Sab196087 case SHT_SUNW_verdef:
50495411Sab196087 case SHT_SUNW_verneed:
50505411Sab196087 flags |= FLG_SHOW_VERSIONS;
50515411Sab196087 break;
50525411Sab196087
50535411Sab196087 case SHT_AMD64_UNWIND:
50545411Sab196087 flags |= FLG_SHOW_UNWIND;
50555411Sab196087 break;
50565411Sab196087 }
50575411Sab196087 }
50585411Sab196087 }
50595411Sab196087
50605411Sab196087
50615411Sab196087 if (flags & FLG_SHOW_SHDR)
50629273SAli.Bahrami@Sun.COM sections(file, cache, shnum, ehdr, osabi);
50630Sstevel@tonic-gate
50645411Sab196087 if (flags & FLG_SHOW_INTERP)
50651618Srie interp(file, cache, shnum, phnum, elf);
50660Sstevel@tonic-gate
50679273SAli.Bahrami@Sun.COM if ((osabi == ELFOSABI_SOLARIS) || (osabi == ELFOSABI_LINUX))
50689273SAli.Bahrami@Sun.COM versions(cache, shnum, file, flags, &versym);
50690Sstevel@tonic-gate
50705411Sab196087 if (flags & FLG_SHOW_SYMBOLS)
50719273SAli.Bahrami@Sun.COM symbols(cache, shnum, ehdr, osabi, &versym, file, flags);
50729273SAli.Bahrami@Sun.COM
50739273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_SORT) && (osabi == ELFOSABI_SOLARIS))
50749273SAli.Bahrami@Sun.COM sunw_sort(cache, shnum, ehdr, osabi, &versym, file, flags);
50753492Sab196087
50765411Sab196087 if (flags & FLG_SHOW_HASH)
50774168Sab196087 hash(cache, shnum, file, flags);
50780Sstevel@tonic-gate
50795411Sab196087 if (flags & FLG_SHOW_GOT)
50807463SRod.Evans@Sun.COM got(cache, shnum, ehdr, file);
50810Sstevel@tonic-gate
50825411Sab196087 if (flags & FLG_SHOW_GROUP)
50834168Sab196087 group(cache, shnum, file, flags);
50840Sstevel@tonic-gate
50855411Sab196087 if (flags & FLG_SHOW_SYMINFO)
5086*11993SAli.Bahrami@Sun.COM syminfo(cache, shnum, ehdr, osabi, file);
50870Sstevel@tonic-gate
50885411Sab196087 if (flags & FLG_SHOW_RELOC)
50897463SRod.Evans@Sun.COM reloc(cache, shnum, ehdr, file);
50900Sstevel@tonic-gate
50915411Sab196087 if (flags & FLG_SHOW_DYNAMIC)
50929273SAli.Bahrami@Sun.COM dynamic(cache, shnum, ehdr, osabi, file);
50930Sstevel@tonic-gate
50946635Sab196087 if (flags & FLG_SHOW_NOTE) {
50956635Sab196087 Word note_cnt;
50966635Sab196087 size_t note_shnum;
50976635Sab196087 Cache *note_cache;
50986635Sab196087
50996635Sab196087 note_cnt = note(cache, shnum, ehdr, file);
51006635Sab196087
51016635Sab196087 /*
51026635Sab196087 * Solaris core files have section headers, but these
51036635Sab196087 * headers do not include SHT_NOTE sections that reference
51046635Sab196087 * the core note sections. This means that note() won't
51056635Sab196087 * find the core notes. Fake section headers (-P option)
51066635Sab196087 * recover these sections, but it is inconvenient to require
51076635Sab196087 * users to specify -P in this situation. If the following
51086635Sab196087 * are all true:
51096635Sab196087 *
51106635Sab196087 * - No note sections were found
51116635Sab196087 * - This is a core file
51126635Sab196087 * - We are not already using fake section headers
51136635Sab196087 *
51146635Sab196087 * then we will automatically generate fake section headers
51156635Sab196087 * and then process them in a second call to note().
51166635Sab196087 */
51176635Sab196087 if ((note_cnt == 0) && (ehdr->e_type == ET_CORE) &&
51186635Sab196087 !(flags & FLG_CTL_FAKESHDR) &&
51196635Sab196087 (fake_shdr_cache(file, fd, elf, ehdr,
51206635Sab196087 ¬e_cache, ¬e_shnum) != 0)) {
51216635Sab196087 (void) note(note_cache, note_shnum, ehdr, file);
51226635Sab196087 fake_shdr_cache_free(note_cache, note_shnum);
51236635Sab196087 }
51246635Sab196087 }
51250Sstevel@tonic-gate
51269273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_MOVE) && (osabi == ELFOSABI_SOLARIS))
51274168Sab196087 move(cache, shnum, file, flags);
51280Sstevel@tonic-gate
51295411Sab196087 if (flags & FLG_CALC_CHECKSUM)
51300Sstevel@tonic-gate checksum(elf);
51310Sstevel@tonic-gate
51329273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_CAP) && (osabi == ELFOSABI_SOLARIS))
513311827SRod.Evans@Sun.COM cap(file, cache, shnum, phnum, ehdr, osabi, elf, flags);
51340Sstevel@tonic-gate
51359273SAli.Bahrami@Sun.COM if ((flags & FLG_SHOW_UNWIND) &&
51369273SAli.Bahrami@Sun.COM ((osabi == ELFOSABI_SOLARIS) || (osabi == ELFOSABI_LINUX)))
51379273SAli.Bahrami@Sun.COM unwind(cache, shnum, phnum, ehdr, osabi, file, elf, flags);
51380Sstevel@tonic-gate
51394665Sab196087
51404665Sab196087 /* Release the memory used to cache section headers */
51415411Sab196087 done:
51425411Sab196087 if (flags & FLG_CTL_FAKESHDR)
51434665Sab196087 fake_shdr_cache_free(cache, shnum);
51444665Sab196087 else
51454665Sab196087 free(cache);
51465411Sab196087
51475411Sab196087 return (ret);
51480Sstevel@tonic-gate }
5149