elfdump.c revision d29b2c4438482eb00488be49a1f5d6835f455546
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Dump an elf file.
*/
#include <machdep.h>
#include <sys/elf_amd64.h>
#include <sys/elf_SPARC.h>
#include <dwarf.h>
#include <unistd.h>
#include <errno.h>
#include <strings.h>
#include <debug.h>
#include <conv.h>
#include <msg.h>
#include <_elfdump.h>
/*
* VERSYM_STATE is used to maintain information about the VERSYM section
* in the object being analyzed. It is filled in by versions(), and used
* by init_symtbl_state() when displaying symbol information.
*
* max_verndx contains the largest version index that can appear
* in a Versym entry. This can never be less than 1: In the case where
* for local symbols, and the [1] index for globals. If Solaris versioning
* rules are in effect and there is a verdef section, then the number
* of defined versions provides this number. If GNU versioning is in effect,
* then:
* - If there is no verneed section, it is the same as for
* Solaris versioning.
* - If there is a verneed section, the vna_other field of the
* Vernaux structs contain versions, and max_verndx is the
* largest such index.
*
* The value of the gnu field is based on the presence of
* a DT_VERSYM entry in the dynamic section: GNU ld produces these, and
* Solaris ld does not.
*/
typedef struct {
int gnu; /* True if object uses GNU versioning rules */
int max_verndx; /* largest versym index value */
} VERSYM_STATE;
/*
* SYMTBL_STATE is used to maintain information about a single symbol
* table section, for use by the routines that display symbol information.
*/
typedef struct {
const char *file; /* Name of file */
const char *secname; /* Name of section */
struct { /* Extended section index data */
int checked; /* TRUE if already checked for shxndx */
/* used for symbol table entries */
uint_t n; /* # items in shxndx.data */
} shxndx;
} SYMTBL_STATE;
/*
* Focal point for verifying symbol names.
*/
static const char *
{
/*
* If an error in this routine is due to a property of the string
* section, as opposed to a bad offset into the section (a property of
* the referencing section), then we will detect the same error on
* every call involving those sections. We use these static variables
* to retain the information needed to only issue each such error once.
*/
static int strsec_err; /* True if error issued */
const char *strs;
return (NULL);
/*
* We only print a diagnostic regarding a bad string table once per
* input section being processed. If the refsec has changed, reset
* our retained error state.
*/
if (last_refsec != refsec) {
strsec_err = 0;
}
/* Verify that strsec really is a string table */
if (!strsec_err) {
strsec_err = 1;
}
return (MSG_INTL(MSG_STR_UNKNOWN));
}
/*
* Is the string table offset within range of the available strings?
*/
/*
* Do we have a empty string table?
*/
if (strs == 0) {
if (!strsec_err) {
strsec_err = 1;
}
} else {
}
/*
* Return the empty string so that the calling function can
* continue it's output diagnostics.
*/
return (MSG_INTL(MSG_STR_UNKNOWN));
}
}
/*
* Relocations can reference section symbols and standard symbols. If the
* former, establish the section name.
*/
static const char *
{
return (MSG_INTL(MSG_STR_UNKNOWN));
}
/*
* If the symbol represents a section offset construct an appropriate
* string.
*/
if (flags & FLG_LONGNAME)
else
return ((const char *)secstr);
}
}
/*
* Focal point for establishing a string table section. Data such as the
* dynamic information simply points to a string table. Data such as
* relocations, reference a symbol table, which in turn is associated with a
* string table.
*/
static int
{
if (symtab) {
/*
* Validate the symbol table section.
*/
return (0);
}
return (0);
}
/*
* Obtain, and verify the symbol table data.
*/
return (0);
}
/*
* Establish the string table index.
*/
/*
* Return symbol table information.
*/
if (symnum)
if (symsec)
}
/*
* Validate the associated string table section.
*/
return (0);
}
if (strsec)
return (1);
}
/*
* Lookup a symbol and set Sym accordingly.
*/
static int
{
if (symtab == 0)
return (0);
/*
* Determine the symbol data and number.
*/
return (0);
}
return (0);
/* LINTED */
/*
* Get the associated string table section.
*/
return (0);
}
/*
* Loop through the symbol table to find a match.
*/
const char *symname;
return (1);
}
}
return (0);
}
/*
* Print section headers.
*/
static void
{
/*
* Although numerous section header entries can be zero, it's
* usually a sign of trouble if the type is zero.
*/
}
continue;
/*
* Identify any sections that are suspicious. A .got section
* shouldn't exist in a relocatable object.
*/
MSG_ELF_GOT_SIZE) == 0) {
secname);
}
}
}
}
/*
* A couple of instances of unwind data are printed as tables of 8 data items
* expressed as 0x?? integers.
*/
static void
{
char buffer[UNWINDTBLSZ];
if (cnt == 8) {
cnt = 0;
}
boff += 5;
cnt++;
}
if (cnt)
}
/*
* Obtain a specified Phdr entry.
*/
static Phdr *
{
return (0);
}
return (phdr);
}
return (0);
}
static void
{
/*
* For the moment - UNWIND is only relevant for a AMD64 object.
*/
return;
if (phnum)
/*
* AMD64 - this is a strmcp() just to find the gcc produced
* sections. Soon gcc should be setting the section type - and
* we'll not need this strcmp().
*/
MSG_SCN_FRM_SIZE) != 0) &&
MSG_SCN_FRMHDR_SIZE) != 0))
continue;
continue;
continue;
off = 0;
/*
* Is this a .eh_frame_hdr
*/
MSG_SCN_FRMHDR_SIZE) == 0)) {
ndx = 0;
}
continue;
}
/*
* Walk the Eh_frame's
*/
char *cieaugstr;
ndx = 0;
/*
* extract length in lsb format
*/
ndx += 4;
/*
* extract CIE id in lsb format
*/
ndx += 4;
/*
* A CIE record has a id of '0', otherwise this is a
* FDE entry and the 'id' is the CIE pointer.
*/
if (id == 0) {
ndx += 1;
ndx += 1;
if (cieaugstr[0])
dbg_print(0,
cieaugndx++) {
case 'z':
&ndx);
dbg_print(0,
val);
cieZflag = 1;
break;
case 'P':
ndx += 1;
dbg_print(0,
break;
case 'R':
ndx += 1;
dbg_print(0,
&dwarf_ehe_buf));
break;
case 'L':
ndx += 1;
dbg_print(0,
&dwarf_ehe_buf));
break;
default:
dbg_print(0,
break;
}
}
} else {
if (cieaugstr[0])
dbg_print(0,
if (cieZflag) {
dbg_print(0,
dbg_print(0,
}
}
}
}
}
}
/*
* this should be accompanied with a program header.
*/
static void
{
/*
*/
if (phnum) {
return;
}
break;
}
}
}
/*
*/
continue;
continue;
continue;
break;
}
return;
/*
*/
if (cshdr) {
return;
}
Elf_cap_title(0);
}
} else
/*
* If this object is an executable or shared object, then the
* program header.
*/
if (cphdr_off == 0)
}
}
/*
* Print the interpretor.
*/
static void
{
/*
* Determine if an interp header exists.
*/
if (phnum) {
}
}
if (iphdr_off == 0)
return;
/*
* Determine if an interp section exists.
*/
/*
* Scan sections to find a section which contains the PT_INTERP
* string. The target section can't be in a NOBITS section.
*/
continue;
break;
}
/*
* Print the interpreter string based on the offset defined in the
* program header, as this is the offset used by the kernel.
*/
} else
/*
* If there are any inconsistences between the program header and
* section information, flag them.
*/
}
}
/*
* Print the syminfo section.
*/
static void
{
break;
}
}
if (infocache == 0)
return;
return;
}
return;
/*
* Get the data buffer of the associated dynamic section.
*/
return;
}
return;
if (dyns == 0) {
return;
}
/*
* Get the data buffer for the associated symbol table and string table.
*/
return;
/*
* Loop through the syminfo entries.
*/
continue;
}
}
}
/*
* Print version definition section entries.
*/
static void
const char *file)
{
char index[MAXNDXSIZE];
/*
* Obtain the name and first dependency (if any).
*/
if (vcnt)
else
/*
* Print any additional dependencies.
*/
if (vcnt) {
}
}
}
}
/*
* Print version needed section entries.
*
* entry:
* vnd - Address of verneed data
* vnd_num - # of Verneed entries
* vcache - Cache of verneed section being processed
* scache - Cache of associated string table section
* file - Name of object being processed.
* versym - Information about versym section
*
* exit:
* The versions have been printed. If GNU style versioning
* is in effect, versym->max_verndx has been updated to
* contain the largest version index seen.
*/
static void
{
char index[MAXNDXSIZE];
const char *index_str;
/*
* The versym section in an object that follows Solaris versioning
* rules contains indexes into the verdef section. Symbols defined
* in other objects (UNDEF) are given a version of 0, indicating that
* they are not defined by this file, and the Verneed entries do not
* have associated version indexes. For these reasons, we do not
* display a version index for Solaris Verneed sections.
*
* The GNU versioning rules are different: Symbols defined in other
* objects receive a version index in the range above those defined
* by the Verdef section, and the vna_other field of the Vernaux
* structs inside the Verneed section contain the version index for
* that item. We therefore display the index when showing the
* contents of a GNU Verneed section. You should not expect these
* indexes to appear in sorted order --- it seems that the GNU ld
* assigns the versions as symbols are encountered during linking,
* and then the results are assembled into the Verneed section
* afterwards.
*/
} else {
/* For Solaris versioning, display a NULL string */
}
/*
* Obtain the name of the needed file and the version name
* within it that we're dependent on. Note that the count
* should be at least one, otherwise this is a pretty bogus
* entry.
*/
if (vcnt)
else
/* Format the version index value */
}
/*
* Print any additional version dependencies.
*/
if (vcnt) {
/* Format the next index value */
versym->max_verndx =
} else {
}
}
}
}
}
/*
* Compute the max_verndx value for a GNU style object with
* a Verneed section. This is only needed if version_need() is not
* called.
*
* entry:
* vnd - Address of verneed data
* vnd_num - # of Verneed entries
* versym - Information about versym section
*
* exit:
* versym->max_verndx has been updated to contain the largest
* version index seen.
*/
static void
{
/*
* Check any additional version dependencies.
*/
if (vcnt) {
}
}
}
}
/*
* Display version section information if the flags require it.
* Return version information needed by other output.
*
* entry:
* cache - Cache of all section headers
* shnum - # of sections in cache
* file - Name of file
* flags - Command line option flags
* versym - VERSYM_STATE block to be filled in.
*/
static void
{
/* Gather information about the version sections */
case SHT_DYNAMIC:
/*
* The GNU ld puts a DT_VERSYM entry in the dynamic
* section so that the runtime linker can use it to
* implement their versioning rules. They allow multiple
* incompatible functions with the same name to exist
* in different versions. The Solaris ld does not
* support this mechanism, and as such, does not
* produce DT_VERSYM. We use this fact to determine
* which ld produced this object, and how to interpret
* the version values.
*/
continue;
break;
}
break;
case SHT_SUNW_versym:
/* Record data address for later symbol processing */
continue;
}
break;
case SHT_SUNW_verdef:
case SHT_SUNW_verneed:
/*
* Ensure the data is non-NULL and the number
* of items is non-zero. Otherwise, we don't
* understand the section, and will not use it.
*/
continue;
}
continue;
}
/* Make sure the string table index is in range */
continue;
}
/*
* The section is usable. Save the cache entry.
*/
/*
* Under Solaris rules, if there is a verdef
* section, the max versym index is number
* of version definitions it supplies.
*/
} else {
}
break;
}
}
if ((flags & FLG_VERSIONS) == 0) {
/*
* If GNU versioning applies to this object, and there
* is a Verneed section, then examine it to determine
* the maximum Versym version index for this file.
*/
return;
}
/*
* Now that all the information is available, display the
* Verdef and Verneed section contents.
*/
if (verdef_cache != NULL) {
}
if (verneed_cache != NULL) {
/*
* If GNU versioning applies to this object, version_need()
* will update versym->max_verndx, and it is not
* necessary to call update_gnu_max_verndx().
*/
}
}
/*
* Initialize a symbol table state structure
*
* entry:
* state - State structure to be initialized
* cache - Cache of all section headers
* shnum - # of sections in cache
* secndx - Index of symbol table section
* ehdr - ELF header for file
* versym - Information about versym section
* file - Name of file
* flags - Command line option flags
*/
static int
{
/*
* Check the symbol data and per-item size.
*/
return (0);
}
return (0);
/* LINTED */
/*
* Check associated string table section.
*/
return (0);
}
/*
* Determine if there is a associated Versym section
* with this Symbol Table.
*/
else
return (1);
}
/*
* Determine the extended section index used for symbol tables entries.
*/
static void
{
continue;
if ((shdr->sh_entsize) &&
/* LINTED */
continue;
continue;
return;
}
}
/*
* Produce a line of output for the given symbol
*
* entry:
* state - Symbol table state
* symndx - Index of symbol within the table
* symndx_disp - Index to display. This may not be the same
* as symndx if the display is relative to the logical
* combination of the SUNW_ldynsym/dynsym tables.
* sym - Symbol to display
*/
static void
{
/*
* Symbol types for which we check that the specified
*/
static const int addr_symtype[STT_NUM] = {
0, /* STT_NOTYPE */
1, /* STT_OBJECT */
1, /* STT_FUNC */
0, /* STT_SECTION */
0, /* STT_FILE */
1, /* STT_COMMON */
0, /* STT_TLS */
};
#error "STT_NUM has grown. Update addr_symtype[]"
#endif
char index[MAXNDXSIZE];
int gnuver;
/* Ensure symbol index is in range */
return;
}
/*
* If we are using extended symbol indexes, find the
* corresponding SHN_SYMTAB_SHNDX table.
*/
/* LINTED */
tshdr = 0;
/*
* If we are using fake section headers derived from
* the program headers, then the section indexes
* in the symbols do not correspond to these headers.
* The section names are not available, so all we can
* do is to display them in numeric form.
*/
} else if ((_shxndx =
} else {
}
} else {
}
}
/*
* If versioning is available display the
* version index. If not, then use 0.
*/
/*
* Check to see if this is a defined symbol with a
* version index that is outside the valid range for
* the file. The interpretation of this depends on
* the style of versioning used by the object.
*
* Versions >= VER_NDX_LORESERVE have special meanings,
* and are exempt from this checking.
*
* GNU style version indexes use the top bit of the
* 16-bit index value (0x8000) as the "hidden bit".
* We must mask off this bit in order to compare
* the version against the maximum value.
*/
if (gnuver)
test_verndx &= ~0x8000;
(verndx < VER_NDX_LORESERVE))
} else {
verndx = 0;
gnuver = 0;
}
/*
* Error checking for TLS.
*/
if (tshdr &&
}
}
/*
* If a symbol with non-zero size has a type that
* specifies an address, then make sure the location
* it references is actually contained within the
* section. UNDEF symbols don't count in this case,
* so we ignore them.
*
* The meaning of the st_value field in a symbol
* depends on the type of object. For a relocatable
* object, it is the offset within the section.
* For sharable objects, it is the offset relative to
* the base of the object, and for other types, it is
* the virtual address. To get an offset within the
* section for non-ET_REL files, we subtract the
* base address of the section.
*/
}
}
/*
* A typical symbol table uses the sh_info field to indicate one greater
* than the symbol table index of the last local symbol, STB_LOCAL.
* Therefore, symbol indexes less than sh_info should have local
* binding. Symbol indexes greater than, or equal to sh_info, should
* value and size, as these symbols may be the result of an mcs(1)
* section deletion.
*/
if (info) {
}
}
}
/*
* Search for and process any symbol tables.
*/
void
{
continue;
continue;
continue;
/*
* Loop through the symbol tables entries.
*/
}
}
/*
* Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections.
* These sections are always associated with the .SUNW_ldynsym./.dynsym pair.
*/
static void
{
int output_cnt = 0;
continue;
continue;
/*
* If the section references a SUNW_ldynsym, then we
* expect to see the associated .dynsym immediately
* following. If it references a .dynsym, there is no
* SUNW_ldynsym. If it is any other type, then we don't
* know what to do with it.
*/
continue;
}
ldynsym_cnt = 0;
case SHT_SUNW_LDYNSYM:
continue;
/*
* We know that the dynsym follows immediately
* after the SUNW_ldynsym, and so, should be at
* (sortshdr->sh_link + 1). However, elfdump is a
* diagnostic tool, so we do the full paranoid
* search instead.
*/
break;
}
continue;
}
/* Fallthrough to process associated dynsym */
/*FALLTHROUGH*/
case SHT_DYNSYM:
continue;
break;
default:
continue;
}
/*
* Output header
*/
if (ldynsym_cnt > 0) {
/*
* The data for .SUNW_ldynsym and dynsym sections
* is supposed to be adjacent with SUNW_ldynsym coming
* first. Check, and issue a warning if it isn't so.
*/
!= dynsym_state.sym) &&
((flags & FLG_FAKESHDR) == 0))
} else {
}
/* If not first one, insert a line of whitespace */
if (output_cnt++ > 0)
/*
* SUNW_dynsymsort and SUNW_dyntlssort are arrays of
* symbol indices. Iterate over the array entries,
* dispaying the referenced symbols.
*/
if (*ndx >= ldynsym_cnt) {
} else {
}
}
}
}
/*
* Search for and process any relocation sections.
*/
static void
{
void *rels;
continue;
continue;
/*
* Decide entry size.
*/
else
}
/*
* Determine the number of relocations available.
*/
continue;
}
continue;
/*
* Get the data buffer for the associated symbol table and
* string table.
*/
continue;
/*
* Loop through the relocation entries.
*/
const char *symname;
/*
* Unravel the relocation and determine the symbol with
* which this relocation is associated.
*/
} else {
}
flags);
/*
* A zero symbol index is only valid for a few
* relocations.
*/
if (symndx == 0) {
int badrel = 0;
(mach == EM_SPARC32PLUS) ||
(mach == EM_SPARCV9)) {
if ((reltype != R_SPARC_NONE) &&
(reltype != R_SPARC_REGISTER) &&
(reltype != R_SPARC_RELATIVE))
badrel++;
if ((reltype != R_386_NONE) &&
(reltype != R_386_RELATIVE))
badrel++;
if ((reltype != R_AMD64_NONE) &&
(reltype != R_AMD64_RELATIVE))
badrel++;
}
if (badrel) {
0, &inv_buf));
}
}
}
}
}
/*
* Search for and process a .dynamic section.
*/
static void
{
continue;
/*
* Verify the associated string table section.
*/
continue;
continue;
}
continue;
Elf_dyn_title(0);
union {
} c_buf;
const char *name;
/*
* Print the information numerically, and if possible
* as a string.
*/
case DT_NULL:
/*
* Special case: DT_NULLs can come in groups
* that we prefer to reduce to a single line.
*/
dyn++;
end_ndx++;
}
continue;
/*
* Print the information numerically, and if possible
* as a string.
*/
case DT_NEEDED:
case DT_SONAME:
case DT_FILTER:
case DT_AUXILIARY:
case DT_CONFIG:
case DT_RPATH:
case DT_RUNPATH:
case DT_USED:
case DT_DEPAUDIT:
case DT_AUDIT:
case DT_SUNW_AUXILIARY:
case DT_SUNW_FILTER:
break;
case DT_FLAGS:
break;
case DT_FLAGS_1:
break;
case DT_POSFLAG_1:
break;
case DT_FEATURE_1:
break;
break;
default:
break;
}
}
}
}
/*
* Search for and process a MOVE section.
*/
static void
{
const char *fmt = 0;
continue;
continue;
/*
* Determine the move data and number.
*/
continue;
}
continue;
/*
* Get the data buffer for the associated symbol table and
* string table.
*/
return;
if (fmt == 0)
const char *symname;
/*
* Check for null entries
*/
continue;
}
continue;
}
flags);
/*
* Additional sanity check.
*/
if (!((shndx == SHN_COMMON) ||
}
}
}
}
/*
* Traverse a note section analyzing each note information block.
* The data buffers size is used to validate references before they are made,
* and is decremented as each element is processed.
*/
void
{
/*
* Print out a single `note' information block.
*/
while (size > 0) {
/*
* Make sure we can at least reference the 3 initial entries
* (4-byte words) of the note information block.
*/
else {
return;
}
/*
* Make sure any specified name string can be referenced.
*/
else {
return;
}
}
/*
* Make sure any specified descriptor can be referenced.
*/
/*
* If namesz isn't a 4-byte multiple, account for any
* padding that must exist before the descriptor.
*/
}
else {
return;
}
}
if (namesz) {
/*
* Since the name string may have 'null' bytes
* in it (ia32 .string) - we just write the
* whole stream in a single fwrite.
*/
~(sizeof (Word) - 1));
/* LINTED */
}
/*
* If multiple information blocks exist within a .note section
* account for any padding that must exist before the next
* information block.
*/
}
if (descsz) {
/*
* Dump descriptor bytes.
*/
tok);
str += 3;
if (++byte == 4) {
word++;
byte = 0;
}
if (word == 4) {
*str = '\0';
word = 0;
ndx += 16;
}
}
*str = '\0';
}
/* LINTED */
}
}
}
/*
* Search for and process a .note section.
*/
static void
{
/*
* Otherwise look for any .note sections.
*/
continue;
continue;
/*
* As these sections are often hand rolled, make sure they're
* properly aligned before proceeding.
*/
continue;
}
continue;
/* LINTED */
}
}
/*
* Determine an individual hash entry. This may be the initial hash entry,
* or an associated chain entry.
*/
static void
{
} else {
}
if (chain == 0) {
hashndx);
} else
/*
* Determine if this string is in the correct bucket.
*/
}
}
#define MAXCOUNT 500
static void
{
char number[MAXNDXSIZE];
continue;
/*
* Determine the hash table data and size.
*/
continue;
}
continue;
hash += 2;
/*
* Get the data buffer for the associated symbol table.
*/
continue;
}
continue;
continue;
}
/* LINTED */
/*
* Get the associated string table section.
*/
continue;
}
/*
* Loop through the hash buckets, printing the appropriate
* symbols.
*/
if (*hash == 0) {
count[0]++;
continue;
}
/*
* Determine if any other symbols are chained to this
* bucket.
*/
_cnt = 1;
while (_ndx) {
_cnt++;
}
} else
}
break;
}
/*
* Print out the count information.
*/
continue;
}
if (cnt) {
bkts);
}
}
static void
{
continue;
continue;
continue;
/*
* Get the data buffer for the associated symbol table and
* string table.
*/
return;
/*
* The first element of the group defines the group. The
* associated symbol is defined by the sh_link field.
*/
return;
}
if (grpdata[0] & GRP_COMDAT) {
}
}
flags));
char index[MAXNDXSIZE];
const char *name;
else
}
}
}
static void
{
char *gotdata;
/*
* First, find the got.
*/
MSG_ELF_GOT_SIZE) == 0) {
break;
}
}
if (gotcache == 0)
return;
/*
* A got section within a relocatable object is suspicious.
*/
}
return;
}
/*
* Some architectures don't properly set the sh_entsize for the GOT
* table. If it's not set, default to a size of a pointer.
*/
return;
/* LINTED */
return;
}
/*
* Now we scan through all the sections looking for any relocations
* that may be against the GOT. Since these may not be isolated to a
* .rel[a].got section we check them all.
* While scanning sections save the symbol table entry (a symtab
* overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_.
*/
void *rels;
continue;
}
if (type == SHT_SYMTAB) {
continue;
}
continue;
/*
* Decide entry size.
*/
else
}
/*
* Determine the number of relocations available.
*/
continue;
}
continue;
/*
* Get the data buffer for the associated symbol table and
* string table.
*/
continue;
/*
* Loop through the relocation entries.
*/
/*
* Unravel the relocation.
*/
} else {
}
/*
* Only pay attention to relocations against the GOT.
*/
continue;
/* LINTED */
continue;
}
if (symndx)
}
}
file))
else
gotsymaddr = gotbgn;
Elf_got_title(0);
/* LINTED */
else
/* LINTED */
}
}
void
{
}
/*
* This variable is used by regular() to communicate the address of
* the section header cache to sort_shdr_ndx_arr(). Unfortunately,
* the qsort() interface does not include a userdata argument by which
* such arbitrary data can be passed, so we are stuck using global data.
*/
static Cache *sort_shdr_ndx_arr_cache;
/*
* Used with qsort() to sort the section indices so that they can be
* used to access the section headers in order of increasing data offset.
*
* entry:
* sort_shdr_ndx_arr_cache - Contains address of
* section header cache.
* v1, v2 - Point at elements of sort_shdr_bits array to be compared.
*
* exit:
* Returns -1 (less than), 0 (equal) or 1 (greater than).
*/
static int
{
return (-1);
return (1);
return (0);
}
static int
{
char *names = 0;
/*
* Obtain the .shstrtab data buffer to provide the required section
* name strings.
*/
/*
* It is rare, but legal, for an object to lack a
* header string table section.
*/
/*
* Allocate a cache to maintain a descriptor for each section.
*/
return (0);
}
*cache = cache_init;
_cache++;
/*
* Allocate an array that will hold the section index for
* each section that has data in the ELF file:
*
* - Is not a NOBITS section
* - Data has non-zero length
*
* Note that shnum is an upper bound on the size required. It
* is likely that we won't use a few of these array elements.
* Allocating a modest amount of extra memory in this case means
* that we can avoid an extra loop to count the number of needed
* items, and can fill this array immediately in the first loop
* below.
*/
return (0);
}
shdr_ndx_arr_cnt = 0;
/*
* Traverse the sections of the file. This gathering of data is
* carried out in two passes. First, the section headers are captured
* and the section header names are evaluated. A verification pass is
* then carried out over the section information. Files have been
* known to exhibit overlapping (and hence erroneous) section header
* information.
*
* Finally, the data for each section is obtained. This processing is
* carried out after section verification because should any section
* header overlap occur, and a file needs translating (ie. xlate'ing
* information from a non-native architecture file), then the process
* of translation can corrupt the section header information. Of
* course, if there is any section overlap, the data related to the
* sections is going to be compromised. However, it is the translation
* of this data that has caused problems with elfdump()'s ability to
* extract the data.
*/
char scnndxnm[100];
}
/*
* If this section has data in the file, include it in
* the array of sections to check for address overlap.
*/
/*
* If a shstrtab exists, assign the section name.
*/
/* LINTED */
continue;
}
/*
* Generate an error if the section name index is zero
* or exceeds the shstrtab data. Fall through to
* fabricate a section name.
*/
/* LINTED */
}
}
/*
* If there exists no shstrtab data, or a section header has no
* name (an invalid index of 0), then compose a name for the
* section.
*/
return (0);
}
}
/*
* Having collected all the sections, validate their address range.
* Cases have existed where the section information has been invalid.
* This can lead to all sorts of other, hard to diagnose errors, as
* each section is processed individually (ie. with elf_getdata()).
* Here, we carry out some address comparisons to catch a family of
* overlapping memory issues we have observed (likely, there are others
* that we have yet to discover).
*
* Note, should any memory overlap occur, obtaining any additional
* data from the file is questionable. However, it might still be
* possible to inspect the ELF header, Programs headers, or individual
* sections, so rather than bailing on an error condition, continue
* processing to see if any data can be salvaged.
*/
if (shdr_ndx_arr_cnt > 1) {
sizeof (*shdr_ndx_arr), sort_shdr_ndx_arr);
}
/*
* Check the section against all following ones, reporting
* any overlaps. Since we've sorted the sections by offset,
* we can stop after the first comparison that fails. There
* are no overlaps in a properly formed ELF file, in which
* case this algorithm runs in O(n) time. This will degenerate
* to O(n^2) for a completely broken file. Such a file is
* (1) highly unlikely, and (2) unusable, so it is reasonable
* for the analysis to take longer.
*/
} else { /* No overlap, so can stop */
break;
}
}
/*
* In addition to checking for sections overlapping
* each other (done above), we should also make sure
* the section doesn't overlap the section header array.
*/
}
}
/*
* Obtain the data for each section.
*/
}
}
return (1);
}
void
{
return;
}
return;
}
return;
}
return;
}
/*
* If the user requested section headers derived from the
* program headers (-P option) and this file doesn't have
* any program headers (i.e. ET_REL), then we can't do it.
*/
return;
}
return;
}
} else
shdr = 0;
/*
* Print the elf header.
*/
/*
* If the section headers or program headers have inadequate
* alignment for the class of object, print a warning. libelf
* can handle such files, but programs that use them can crash
* when they dereference unaligned items.
*/
/*
* Print the program headers.
*/
return;
}
continue;
}
}
/*
* Decide how to proceed if there are no sections, if there's just
* one section (the first section can act as an extension of the
* ELF header), or if only program header information was requested.
*/
/* If a core file, display the note and return */
return;
}
/* If only program header info was requested, we're done */
return;
/*
* Section headers are missing. Resort to synthesizing
* section headers from the program headers.
*/
if ((flags & FLG_FAKESHDR) == 0) {
flags |= FLG_FAKESHDR;
}
}
/*
* Generate a cache of section headers and related information
* for use by the rest of elfdump. If requested (or the file
* contains no section headers), we generate a fake set of
* headers from the information accessible from the program headers.
* Otherwise, we use the real section headers contained in the file.
*/
if (flags & FLG_FAKESHDR) {
return;
} else {
return;
}
/*
* If -w was specified, find and write out the section(s) data.
*/
if (wfd) {
}
}
}
if (flags & FLG_INTERP)
if (flags & FLG_SYMBOLS)
if (flags & FLG_SYMINFO)
if (flags & FLG_DYNAMIC)
if (flags & FLG_CHECKSUM)
if (flags & FLG_UNWIND)
/* Release the memory used to cache section headers */
if (flags & FLG_FAKESHDR)
else
}