elfdump.c revision ba4e3c84e6b9390bbf7df80b5f1d11dec34cc525
/*
* 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 2006 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>
/*
* Focal point for verifying symbol names.
*/
static const char *
{
static int nostr;
/*
* Only print a diagnostic regarding an empty string table once per
* input section being processed.
*/
nostr = 0;
}
/*
* Is the string table offset within range of the available strings?
*/
/*
* Do we have a empty string table?
*/
if (strs == 0) {
if (nostr == 0) {
nostr++;
}
} 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);
}
/*
* 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);
}
/* 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
const char *name)
{
continue;
/*
* Although numerous section header entries can be zero, it's
* usually a sign of trouble if the name or type are zero.
*/
}
/*
* Use the empty string, rather than the fabricated
* name for the section output.
*/
}
/*
* 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;
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])
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;
break;
}
return;
/*
*/
if (cshdr) {
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.
*/
if (ishdr) {
} 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;
}
/*
* Get the data buffer of the associated dynamic section.
*/
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) {
}
}
}
}
/*
* Search for any version sections - the Versym output is possibly used by the
* symbols() printing. If VERSYM is specified - then display the version
* information.
*/
static Cache *
{
Cache *versymcache = 0;
void *ver;
/*
* If this is the version symbol table simply record its
* data address for possible use in later symbol processing.
*/
continue;
}
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;
}
}
}
return (versymcache);
}
/*
* Determine the extended section index used for symbol tables entries.
*/
static int
{
continue;
if ((shdr->sh_entsize) &&
/* LINTED */
continue;
*symnshxndx = symn;
return (0);
}
return (1);
}
/*
* Search for and process any symbol tables.
*/
void
{
int noshxndx;
continue;
continue;
/*
* Determine the symbol data and number.
*/
continue;
}
/* LINTED */
/*
* Get the associated string table section.
*/
continue;
}
/*
* Determine if there is a associated Versym section
* with this Symbol Table.
*/
else
versym = 0;
/*
* Loop through the symbol tables entries.
*/
shxndx = 0;
noshxndx = 0;
symnshxndx = 0;
const char *symname;
int verndx;
/*
* If we are using extended symbol indexes, find the
* corresponding SHN_SYMTAB_SHNDX table.
*/
/* LINTED */
tshdr = 0;
if (is_core)
if (shxndx) {
if (symcnt > symnshxndx) {
} else if ((_shxndx =
} else {
}
} else {
}
}
/*
* If versioning is available display the
* version index.
*/
if (versym)
else
verndx = 0;
/*
* Error checking for TLS.
*/
if (tshdr &&
}
}
/*
* If a symbol has size, then make sure the section it
* references is appropriate. Note, UNDEF symbols that
* have a size, have been known to exist - ignore them.
*/
}
}
}
}
/*
* Search for and process any relocation sections.
*/
static void
{
void *rels;
continue;
continue;
/*
* Decide entry size.
*/
else
}
/*
* Determine the number of relocations available.
*/
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
{
int ndx;
continue;
/*
* Verify the associated string table section.
*/
continue;
Elf_dyn_title(0);
const char *name;
/*
* Print the information numerically, and if possible
* as a string.
*/
else
}
}
}
/*
* Search for and process a MOVE section.
*/
static void
{
const char *fmt = 0;
continue;
continue;
/*
* Determine the move data and number.
*/
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;
}
/* 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;
continue;
/*
* Determine the hash table data and size.
*/
continue;
}
hash += 2;
/*
* Get the data buffer for the associated symbol table.
*/
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.
*/
/* 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;
}
/*
* 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
{
}
void
{
char *names = 0;
Cache *versymcache = 0;
return;
}
return;
}
return;
}
return;
}
return;
}
} else
shdr = 0;
/*
* Print the elf header.
*/
/*
* Print the program headers.
*/
return;
}
}
}
/*
* Return now if there are no section, if there's just one section to
* act as an extension of the ELF header, or if on section information
* was requested.
*/
return;
}
/*
* Obtain the .shstrtab data buffer to provide the required section
* name strings.
*/
/* LINTED */
(int)elf_ndxscn(scn));
/*
* Fill in the cache descriptor with information for each section.
*/
return;
}
*cache = cache_init;
_cache++;
/* LINTED */
(int)elf_ndxscn(scn));
}
/* LINTED */
else {
/*
* If there exists no shstrtab data, or a section header
* has no name (an invalid index of 0), then compose a
* name for each section.
*/
char scnndxnm[100];
cnt);
/*
* Although we have a valid shstrtab section inform the
* user if this section name index exceeds the shstrtab
* data.
*/
if (names &&
/* LINTED */
}
return;
}
}
/* LINTED */
(int)elf_ndxscn(scn));
}
/*
* Do we wish to write the section out?
*/
}
}
if (flags & FLG_INTERP)
if (flags & FLG_SYMBOLS)
if (flags & FLG_SYMINFO)
if (flags & FLG_DYNAMIC)
if (flags & FLG_CHECKSUM)
if (flags & FLG_UNWIND)
}