elfdump.c revision 39773e466ff90ce703d7f52f3267d7e96c09c6f5
/*
* 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.
*
* Note that the value of the gnu field is a hueristic guess,
* based on the section names.
*/
typedef struct {
int num_verdef; /* # of versions defined in object */
int gnu; /* True if we think obj produced by GNU tools */
} 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,
break;
case 'L':
ndx += 1;
dbg_print(0,
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 a version needed section entries.
*/
static void
const char *file)
{
/*
* 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
/*
* Print 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
{
const char *gnu_prefix;
void *ver;
/*
* If the section names starts with the .gnu.version prefix,
* then this object was almost certainly produced by the
* GNU ld and not the native Solaris ld.
*/
/*
* If this is the version symbol table record its data
* address for later symbol processing.
*/
continue;
}
/*
* If this is a version definition section, retain # of
* version definitions for later symbol processing.
*/
if ((flags & FLG_VERSIONS) == 0)
continue;
continue;
/*
* Determine the version section data and number.
*/
continue;
}
continue;
}
/*
* Get the data buffer for the associated string table.
*/
continue;
}
}
}
}
/*
* 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];
/* 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. If so, then there are two possiblities:
*
* - Files produced by the GNU ld use the top (16th) bit
* as a "hidden symbol" marker. If we have
* detected that this object comes from GNU ld,
* then check to see if this is the case and that
* the resulting masked version is in range. If so,
* issue a warning describing it.
* - If this is not a GNU "hidden bit" issue, then
* issue a generic "out of range" error.
*/
((verndx & ~0x8000) <=
} else { /* Generic version range error */
}
}
} else {
verndx = 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.
*/
}
}
}
/*
* 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) {
}
}
}
}
}
/*
* Search for and process a .dynamic section.
*/
static void
{
continue;
/*
* Verify the associated string table section.
*/
continue;
continue;
}
continue;
Elf_dyn_title(0);
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
}