Line 1... |
Line 1... |
/* readelf.c -- display contents of an ELF format file
|
/* readelf.c -- display contents of an ELF format file
|
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
2008, 2009, 2010, 2011
|
2008, 2009, 2010, 2011, 2012
|
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
|
|
Originally developed by Eric Youngdale <eric@andante.jic.com>
|
Originally developed by Eric Youngdale <eric@andante.jic.com>
|
Modifications by Nick Clifton <nickc@redhat.com>
|
Modifications by Nick Clifton <nickc@redhat.com>
|
|
|
Line 40... |
Line 40... |
|
|
There is also the case that readelf can provide more information about an
|
There is also the case that readelf can provide more information about an
|
ELF file than is provided by objdump. In particular it can display DWARF
|
ELF file than is provided by objdump. In particular it can display DWARF
|
debugging information which (at the moment) objdump cannot. */
|
debugging information which (at the moment) objdump cannot. */
|
|
|
#include "config.h"
|
|
#include "sysdep.h"
|
#include "sysdep.h"
|
#include <assert.h>
|
#include <assert.h>
|
#include <sys/stat.h>
|
|
#include <time.h>
|
#include <time.h>
|
#ifdef HAVE_ZLIB_H
|
#ifdef HAVE_ZLIB_H
|
#include <zlib.h>
|
#include <zlib.h>
|
#endif
|
#endif
|
|
|
Line 3192... |
Line 3190... |
-n --notes Display the core notes (if present)\n\
|
-n --notes Display the core notes (if present)\n\
|
-r --relocs Display the relocations (if present)\n\
|
-r --relocs Display the relocations (if present)\n\
|
-u --unwind Display the unwind info (if present)\n\
|
-u --unwind Display the unwind info (if present)\n\
|
-d --dynamic Display the dynamic section (if present)\n\
|
-d --dynamic Display the dynamic section (if present)\n\
|
-V --version-info Display the version sections (if present)\n\
|
-V --version-info Display the version sections (if present)\n\
|
-A --arch-specific Display architecture specific information (if any).\n\
|
-A --arch-specific Display architecture specific information (if any)\n\
|
-c --archive-index Display the symbol/file index in an archive\n\
|
-c --archive-index Display the symbol/file index in an archive\n\
|
-D --use-dynamic Use the dynamic section info when displaying symbols\n\
|
-D --use-dynamic Use the dynamic section info when displaying symbols\n\
|
-x --hex-dump=<number|name>\n\
|
-x --hex-dump=<number|name>\n\
|
Dump the contents of section <number|name> as bytes\n\
|
Dump the contents of section <number|name> as bytes\n\
|
-p --string-dump=<number|name>\n\
|
-p --string-dump=<number|name>\n\
|
Line 4966... |
Line 4964... |
}
|
}
|
|
|
if (section_headers == NULL)
|
if (section_headers == NULL)
|
{
|
{
|
error (_("Section headers are not available!\n"));
|
error (_("Section headers are not available!\n"));
|
abort ();
|
/* PR 13622: This can happen with a corrupt ELF header. */
|
|
return 0;
|
}
|
}
|
|
|
section_headers_groups = (struct group **) calloc (elf_header.e_shnum,
|
section_headers_groups = (struct group **) calloc (elf_header.e_shnum,
|
sizeof (struct group *));
|
sizeof (struct group *));
|
|
|
Line 5600... |
Line 5599... |
dist = addr.offset - value;
|
dist = addr.offset - value;
|
if (!dist)
|
if (!dist)
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
if (best)
|
if (best)
|
{
|
{
|
*symname = (best->st_name >= strtab_size
|
*symname = (best->st_name >= strtab_size
|
? _("<corrupt>") : strtab + best->st_name);
|
? _("<corrupt>") : strtab + best->st_name);
|
*offset = dist;
|
*offset = dist;
|
return;
|
return;
|
}
|
}
|
|
|
*symname = NULL;
|
*symname = NULL;
|
*offset = addr.offset;
|
*offset = addr.offset;
|
}
|
}
|
|
|
static void
|
static void
|
Line 5784... |
Line 5785... |
|
|
aux->table_len = size / (3 * eh_addr_size);
|
aux->table_len = size / (3 * eh_addr_size);
|
return 1;
|
return 1;
|
}
|
}
|
|
|
static int
|
static void
|
ia64_process_unwind (FILE * file)
|
ia64_process_unwind (FILE * file)
|
{
|
{
|
Elf_Internal_Shdr * sec;
|
Elf_Internal_Shdr * sec;
|
Elf_Internal_Shdr * unwsec = NULL;
|
Elf_Internal_Shdr * unwsec = NULL;
|
Elf_Internal_Shdr * strsec;
|
Elf_Internal_Shdr * strsec;
|
Line 5921... |
Line 5922... |
|
|
if (aux.symtab)
|
if (aux.symtab)
|
free (aux.symtab);
|
free (aux.symtab);
|
if (aux.strtab)
|
if (aux.strtab)
|
free ((char *) aux.strtab);
|
free ((char *) aux.strtab);
|
|
|
return 1;
|
|
}
|
}
|
|
|
struct hppa_unw_table_entry
|
struct hppa_unw_table_entry
|
{
|
{
|
struct absaddr start;
|
struct absaddr start;
|
Line 6194... |
Line 6193... |
aux->table_len = nentries;
|
aux->table_len = nentries;
|
|
|
return 1;
|
return 1;
|
}
|
}
|
|
|
static int
|
static void
|
hppa_process_unwind (FILE * file)
|
hppa_process_unwind (FILE * file)
|
{
|
{
|
struct hppa_unw_aux_info aux;
|
struct hppa_unw_aux_info aux;
|
Elf_Internal_Shdr * unwsec = NULL;
|
Elf_Internal_Shdr * unwsec = NULL;
|
Elf_Internal_Shdr * strsec;
|
Elf_Internal_Shdr * strsec;
|
Elf_Internal_Shdr * sec;
|
Elf_Internal_Shdr * sec;
|
unsigned long i;
|
unsigned long i;
|
|
|
memset (& aux, 0, sizeof (aux));
|
|
|
|
if (string_table == NULL)
|
if (string_table == NULL)
|
return 1;
|
return;
|
|
|
|
memset (& aux, 0, sizeof (aux));
|
|
|
for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
|
for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
|
{
|
{
|
if (sec->sh_type == SHT_SYMTAB
|
if (sec->sh_type == SHT_SYMTAB
|
&& sec->sh_link < elf_header.e_shnum)
|
&& sec->sh_link < elf_header.e_shnum)
|
Line 6254... |
Line 6253... |
|
|
if (aux.symtab)
|
if (aux.symtab)
|
free (aux.symtab);
|
free (aux.symtab);
|
if (aux.strtab)
|
if (aux.strtab)
|
free ((char *) aux.strtab);
|
free ((char *) aux.strtab);
|
|
|
return 1;
|
|
}
|
}
|
|
|
struct arm_section
|
struct arm_section
|
{
|
{
|
unsigned char *data;
|
unsigned char * data; /* The unwind data. */
|
|
Elf_Internal_Shdr * sec; /* The cached unwind section header. */
|
Elf_Internal_Shdr *sec;
|
Elf_Internal_Rela * rela; /* The cached relocations for this section. */
|
Elf_Internal_Rela *rela;
|
unsigned long nrelas; /* The number of relocations. */
|
unsigned long nrelas;
|
unsigned int rel_type; /* REL or RELA ? */
|
unsigned int rel_type;
|
Elf_Internal_Rela * next_rela; /* Cyclic pointer to the next reloc to process. */
|
|
|
Elf_Internal_Rela *next_rela;
|
|
};
|
};
|
|
|
struct arm_unw_aux_info
|
struct arm_unw_aux_info
|
{
|
{
|
FILE *file;
|
FILE * file; /* The file containing the unwind sections. */
|
|
Elf_Internal_Sym * symtab; /* The file's symbol table. */
|
Elf_Internal_Sym *symtab; /* The symbol table. */
|
|
unsigned long nsyms; /* Number of symbols. */
|
unsigned long nsyms; /* Number of symbols. */
|
char *strtab; /* The string table. */
|
char * strtab; /* The file's string table. */
|
unsigned long strtab_size; /* Size of string table. */
|
unsigned long strtab_size; /* Size of string table. */
|
};
|
};
|
|
|
static const char *
|
static const char *
|
arm_print_vma_and_name (struct arm_unw_aux_info *aux,
|
arm_print_vma_and_name (struct arm_unw_aux_info *aux,
|
Line 6319... |
Line 6313... |
|
|
if (arm_sec->rela != NULL)
|
if (arm_sec->rela != NULL)
|
free (arm_sec->rela);
|
free (arm_sec->rela);
|
}
|
}
|
|
|
static int
|
/* 1) If SEC does not match the one cached in ARM_SEC, then free the current
|
arm_section_get_word (struct arm_unw_aux_info *aux,
|
cached section and install SEC instead.
|
|
2) Locate the 32-bit word at WORD_OFFSET in unwind section SEC
|
|
and return its valued in * WORDP, relocating if necessary.
|
|
3) Update the NEXT_RELA field in ARM_SEC and store the section index and
|
|
relocation's offset in ADDR.
|
|
4) If SYM_NAME is non-NULL and a relocation was applied, record the offset
|
|
into the string table of the symbol associated with the reloc. If no
|
|
reloc was applied store -1 there.
|
|
5) Return TRUE upon success, FALSE otherwise. */
|
|
|
|
static bfd_boolean
|
|
get_unwind_section_word (struct arm_unw_aux_info * aux,
|
struct arm_section *arm_sec,
|
struct arm_section *arm_sec,
|
Elf_Internal_Shdr *sec, bfd_vma word_offset,
|
Elf_Internal_Shdr * sec,
|
unsigned int *wordp, struct absaddr *addr)
|
bfd_vma word_offset,
|
|
unsigned int * wordp,
|
|
struct absaddr * addr,
|
|
bfd_vma * sym_name)
|
{
|
{
|
Elf_Internal_Rela *rp;
|
Elf_Internal_Rela *rp;
|
Elf_Internal_Sym *sym;
|
Elf_Internal_Sym *sym;
|
const char * relname;
|
const char * relname;
|
unsigned int word;
|
unsigned int word;
|
bfd_boolean wrapped;
|
bfd_boolean wrapped;
|
|
|
addr->section = SHN_UNDEF;
|
addr->section = SHN_UNDEF;
|
addr->offset = 0;
|
addr->offset = 0;
|
|
|
|
if (sym_name != NULL)
|
|
*sym_name = (bfd_vma) -1;
|
|
|
|
/* If necessary, update the section cache. */
|
if (sec != arm_sec->sec)
|
if (sec != arm_sec->sec)
|
{
|
{
|
Elf_Internal_Shdr *relsec;
|
Elf_Internal_Shdr *relsec;
|
|
|
arm_free_section (arm_sec);
|
arm_free_section (arm_sec);
|
Line 6354... |
Line 6366... |
{
|
{
|
if (relsec->sh_info >= elf_header.e_shnum
|
if (relsec->sh_info >= elf_header.e_shnum
|
|| section_headers + relsec->sh_info != sec)
|
|| section_headers + relsec->sh_info != sec)
|
continue;
|
continue;
|
|
|
|
arm_sec->rel_type = relsec->sh_type;
|
if (relsec->sh_type == SHT_REL)
|
if (relsec->sh_type == SHT_REL)
|
{
|
{
|
if (!slurp_rel_relocs (aux->file, relsec->sh_offset,
|
if (!slurp_rel_relocs (aux->file, relsec->sh_offset,
|
relsec->sh_size,
|
relsec->sh_size,
|
& arm_sec->rela, & arm_sec->nrelas))
|
& arm_sec->rela, & arm_sec->nrelas))
|
return 0;
|
return FALSE;
|
break;
|
break;
|
}
|
}
|
else if (relsec->sh_type == SHT_RELA)
|
else if (relsec->sh_type == SHT_RELA)
|
{
|
{
|
if (!slurp_rela_relocs (aux->file, relsec->sh_offset,
|
if (!slurp_rela_relocs (aux->file, relsec->sh_offset,
|
relsec->sh_size,
|
relsec->sh_size,
|
& arm_sec->rela, & arm_sec->nrelas))
|
& arm_sec->rela, & arm_sec->nrelas))
|
return 0;
|
return FALSE;
|
break;
|
break;
|
}
|
}
|
|
else
|
|
warn (_("unexpected relocation type (%d) for section %d"),
|
|
relsec->sh_type, relsec->sh_info);
|
}
|
}
|
|
|
arm_sec->next_rela = arm_sec->rela;
|
arm_sec->next_rela = arm_sec->rela;
|
}
|
}
|
|
|
|
/* If there is no unwind data we can do nothing. */
|
if (arm_sec->data == NULL)
|
if (arm_sec->data == NULL)
|
return 0;
|
return FALSE;
|
|
|
|
/* Get the word at the required offset. */
|
word = byte_get (arm_sec->data + word_offset, 4);
|
word = byte_get (arm_sec->data + word_offset, 4);
|
|
|
|
/* Look through the relocs to find the one that applies to the provided offset. */
|
wrapped = FALSE;
|
wrapped = FALSE;
|
for (rp = arm_sec->next_rela; rp != arm_sec->rela + arm_sec->nrelas; rp++)
|
for (rp = arm_sec->next_rela; rp != arm_sec->rela + arm_sec->nrelas; rp++)
|
{
|
{
|
bfd_vma prelval, offset;
|
bfd_vma prelval, offset;
|
|
|
Line 6403... |
Line 6422... |
}
|
}
|
|
|
if (rp->r_offset < word_offset)
|
if (rp->r_offset < word_offset)
|
continue;
|
continue;
|
|
|
switch (elf_header.e_machine)
|
sym = aux->symtab + ELF32_R_SYM (rp->r_info);
|
|
|
|
if (arm_sec->rel_type == SHT_REL)
|
{
|
{
|
case EM_ARM:
|
offset = word & 0x7fffffff;
|
relname = elf_arm_reloc_type (ELF32_R_TYPE (rp->r_info));
|
if (offset & 0x40000000)
|
break;
|
offset |= ~ (bfd_vma) 0x7fffffff;
|
|
}
|
|
else if (arm_sec->rel_type == SHT_RELA)
|
|
offset = rp->r_addend;
|
|
else
|
|
abort ();
|
|
|
case EM_TI_C6000:
|
offset += sym->st_value;
|
relname = elf_tic6x_reloc_type (ELF32_R_TYPE (rp->r_info));
|
prelval = offset - (arm_sec->sec->sh_addr + rp->r_offset);
|
break;
|
|
|
|
default:
|
/* Check that we are processing the expected reloc type. */
|
abort();
|
if (elf_header.e_machine == EM_ARM)
|
}
|
{
|
|
relname = elf_arm_reloc_type (ELF32_R_TYPE (rp->r_info));
|
|
|
if (streq (relname, "R_ARM_NONE")
|
if (streq (relname, "R_ARM_NONE"))
|
|| streq (relname, "R_C6000_NONE"))
|
|
continue;
|
continue;
|
|
|
if (!(streq (relname, "R_ARM_PREL31")
|
if (! streq (relname, "R_ARM_PREL31"))
|
|| streq (relname, "R_C6000_PREL31")))
|
|
{
|
{
|
warn (_("Skipping unexpected relocation type %s\n"), relname);
|
warn (_("Skipping unexpected relocation type %s\n"), relname);
|
continue;
|
continue;
|
}
|
}
|
|
}
|
|
else if (elf_header.e_machine == EM_TI_C6000)
|
|
{
|
|
relname = elf_tic6x_reloc_type (ELF32_R_TYPE (rp->r_info));
|
|
|
sym = aux->symtab + ELF32_R_SYM (rp->r_info);
|
if (streq (relname, "R_C6000_NONE"))
|
|
continue;
|
|
|
if (arm_sec->rel_type == SHT_REL)
|
if (! streq (relname, "R_C6000_PREL31"))
|
{
|
{
|
offset = word & 0x7fffffff;
|
warn (_("Skipping unexpected relocation type %s\n"), relname);
|
if (offset & 0x40000000)
|
continue;
|
offset |= ~ (bfd_vma) 0x7fffffff;
|
|
}
|
}
|
else
|
|
offset = rp->r_addend;
|
|
|
|
offset += sym->st_value;
|
|
prelval = offset - (arm_sec->sec->sh_addr + rp->r_offset);
|
|
|
|
if (streq (relname, "R_C6000_PREL31"))
|
|
prelval >>= 1;
|
prelval >>= 1;
|
|
}
|
|
else
|
|
/* This function currently only supports ARM and TI unwinders. */
|
|
abort ();
|
|
|
word = (word & ~ (bfd_vma) 0x7fffffff) | (prelval & 0x7fffffff);
|
word = (word & ~ (bfd_vma) 0x7fffffff) | (prelval & 0x7fffffff);
|
addr->section = sym->st_shndx;
|
addr->section = sym->st_shndx;
|
addr->offset = offset;
|
addr->offset = offset;
|
|
if (sym_name)
|
|
* sym_name = sym->st_name;
|
break;
|
break;
|
}
|
}
|
|
|
*wordp = word;
|
*wordp = word;
|
arm_sec->next_rela = rp;
|
arm_sec->next_rela = rp;
|
|
|
return 1;
|
return TRUE;
|
}
|
}
|
|
|
static const char *tic6x_unwind_regnames[16] = {
|
static const char *tic6x_unwind_regnames[16] =
|
|
{
|
"A15", "B15", "B14", "B13", "B12", "B11", "B10", "B3",
|
"A15", "B15", "B14", "B13", "B12", "B11", "B10", "B3",
|
"A14", "A13", "A12", "A11", "A10",
|
"A14", "A13", "A12", "A11", "A10",
|
"[invalid reg 13]", "[invalid reg 14]", "[invalid reg 15]"};
|
"[invalid reg 13]", "[invalid reg 14]", "[invalid reg 15]"
|
|
};
|
|
|
static void
|
static void
|
decode_tic6x_unwind_regmask (unsigned int mask)
|
decode_tic6x_unwind_regmask (unsigned int mask)
|
{
|
{
|
int i;
|
int i;
|
Line 6482... |
Line 6512... |
|
|
#define ADVANCE \
|
#define ADVANCE \
|
if (remaining == 0 && more_words) \
|
if (remaining == 0 && more_words) \
|
{ \
|
{ \
|
data_offset += 4; \
|
data_offset += 4; \
|
if (!arm_section_get_word (aux, data_arm_sec, data_sec, \
|
if (! get_unwind_section_word (aux, data_arm_sec, data_sec, \
|
data_offset, &word, &addr)) \
|
data_offset, & word, & addr, NULL)) \
|
return; \
|
return; \
|
remaining = 4; \
|
remaining = 4; \
|
more_words--; \
|
more_words--; \
|
} \
|
} \
|
|
|
Line 6587... |
Line 6617... |
printf (", ");
|
printf (", ");
|
printf ("r%d", i);
|
printf ("r%d", i);
|
}
|
}
|
if (op & 0x08)
|
if (op & 0x08)
|
{
|
{
|
if (first)
|
if (!first)
|
printf (", ");
|
printf (", ");
|
printf ("r14");
|
printf ("r14");
|
}
|
}
|
printf ("}");
|
printf ("}");
|
}
|
}
|
Line 6762... |
Line 6792... |
{
|
{
|
unsigned int reg;
|
unsigned int reg;
|
unsigned int nregs;
|
unsigned int nregs;
|
unsigned int i;
|
unsigned int i;
|
const char *name;
|
const char *name;
|
struct {
|
struct
|
|
{
|
unsigned int offset;
|
unsigned int offset;
|
unsigned int reg;
|
unsigned int reg;
|
} regpos[16];
|
} regpos[16];
|
|
|
/* Scan entire instruction first so that GET_OP output is not
|
/* Scan entire instruction first so that GET_OP output is not
|
Line 6819... |
Line 6850... |
else if (op == 0xd2)
|
else if (op == 0xd2)
|
{
|
{
|
unsigned char buf[9];
|
unsigned char buf[9];
|
unsigned int i, len;
|
unsigned int i, len;
|
unsigned long offset;
|
unsigned long offset;
|
|
|
for (i = 0; i < sizeof (buf); i++)
|
for (i = 0; i < sizeof (buf); i++)
|
{
|
{
|
GET_OP (buf[i]);
|
GET_OP (buf[i]);
|
if ((buf[i] & 0x80) == 0)
|
if ((buf[i] & 0x80) == 0)
|
break;
|
break;
|
Line 6847... |
Line 6879... |
putchar ('\n');
|
putchar ('\n');
|
}
|
}
|
}
|
}
|
|
|
static bfd_vma
|
static bfd_vma
|
expand_prel31 (bfd_vma word, bfd_vma where)
|
arm_expand_prel31 (bfd_vma word, bfd_vma where)
|
{
|
{
|
bfd_vma offset;
|
bfd_vma offset;
|
|
|
offset = word & 0x7fffffff;
|
offset = word & 0x7fffffff;
|
if (offset & 0x40000000)
|
if (offset & 0x40000000)
|
Line 6863... |
Line 6895... |
return offset + where;
|
return offset + where;
|
}
|
}
|
|
|
static void
|
static void
|
decode_arm_unwind (struct arm_unw_aux_info *aux,
|
decode_arm_unwind (struct arm_unw_aux_info *aux,
|
unsigned int word, unsigned int remaining,
|
unsigned int word,
|
bfd_vma data_offset, Elf_Internal_Shdr *data_sec,
|
unsigned int remaining,
|
|
bfd_vma data_offset,
|
|
Elf_Internal_Shdr * data_sec,
|
struct arm_section *data_arm_sec)
|
struct arm_section *data_arm_sec)
|
{
|
{
|
int per_index;
|
int per_index;
|
unsigned int more_words = 0;
|
unsigned int more_words = 0;
|
struct absaddr addr;
|
struct absaddr addr;
|
|
bfd_vma sym_name = (bfd_vma) -1;
|
|
|
if (remaining == 0)
|
if (remaining == 0)
|
{
|
{
|
/* Fetch the first word. */
|
/* Fetch the first word.
|
if (!arm_section_get_word (aux, data_arm_sec, data_sec, data_offset,
|
Note - when decoding an object file the address extracted
|
&word, &addr))
|
here will always be 0. So we also pass in the sym_name
|
|
parameter so that we can find the symbol associated with
|
|
the personality routine. */
|
|
if (! get_unwind_section_word (aux, data_arm_sec, data_sec, data_offset,
|
|
& word, & addr, & sym_name))
|
return;
|
return;
|
|
|
remaining = 4;
|
remaining = 4;
|
}
|
}
|
|
|
if ((word & 0x80000000) == 0)
|
if ((word & 0x80000000) == 0)
|
{
|
{
|
/* Expand prel31 for personality routine. */
|
/* Expand prel31 for personality routine. */
|
bfd_vma fn;
|
bfd_vma fn;
|
const char *procname;
|
const char *procname;
|
|
|
fn = expand_prel31 (word, data_sec->sh_addr + data_offset);
|
fn = arm_expand_prel31 (word, data_sec->sh_addr + data_offset);
|
printf (_(" Personality routine: "));
|
printf (_(" Personality routine: "));
|
|
if (fn == 0
|
|
&& addr.section == SHN_UNDEF && addr.offset == 0
|
|
&& sym_name != (bfd_vma) -1 && sym_name < aux->strtab_size)
|
|
{
|
|
procname = aux->strtab + sym_name;
|
|
print_vma (fn, PREFIX_HEX);
|
|
if (procname)
|
|
{
|
|
fputs (" <", stdout);
|
|
fputs (procname, stdout);
|
|
fputc ('>', stdout);
|
|
}
|
|
}
|
|
else
|
procname = arm_print_vma_and_name (aux, fn, addr);
|
procname = arm_print_vma_and_name (aux, fn, addr);
|
fputc ('\n', stdout);
|
fputc ('\n', stdout);
|
|
|
/* The GCC personality routines use the standard compact
|
/* The GCC personality routines use the standard compact
|
encoding, starting with one byte giving the number of
|
encoding, starting with one byte giving the number of
|
Line 6918... |
Line 6972... |
else
|
else
|
return;
|
return;
|
}
|
}
|
else
|
else
|
{
|
{
|
|
/* ARM EHABI Section 6.3:
|
|
|
|
An exception-handling table entry for the compact model looks like:
|
|
|
|
31 30-28 27-24 23-0
|
|
-- ----- ----- ----
|
|
1 0 index Data for personalityRoutine[index] */
|
|
|
|
if (elf_header.e_machine == EM_ARM
|
|
&& (word & 0x70000000))
|
|
warn (_("Corrupt ARM compact model table entry: %x \n"), word);
|
|
|
per_index = (word >> 24) & 0x7f;
|
per_index = (word >> 24) & 0x7f;
|
printf (_(" Compact model %d\n"), per_index);
|
printf (_(" Compact model index: %d\n"), per_index);
|
if (per_index == 0)
|
if (per_index == 0)
|
{
|
{
|
more_words = 0;
|
more_words = 0;
|
word <<= 8;
|
word <<= 8;
|
remaining--;
|
remaining--;
|
Line 6944... |
Line 7009... |
{
|
{
|
decode_arm_unwind_bytecode (aux, word, remaining, more_words,
|
decode_arm_unwind_bytecode (aux, word, remaining, more_words,
|
data_offset, data_sec, data_arm_sec);
|
data_offset, data_sec, data_arm_sec);
|
}
|
}
|
else
|
else
|
printf (" [reserved]\n");
|
{
|
|
warn (_("Unknown ARM compact model index encountered\n"));
|
|
printf (_(" [reserved]\n"));
|
|
}
|
break;
|
break;
|
|
|
case EM_TI_C6000:
|
case EM_TI_C6000:
|
if (per_index < 3)
|
if (per_index < 3)
|
{
|
{
|
Line 6968... |
Line 7036... |
putchar ('\n');
|
putchar ('\n');
|
printf (_(" Return register: %s\n"),
|
printf (_(" Return register: %s\n"),
|
tic6x_unwind_regnames[word & 0xf]);
|
tic6x_unwind_regnames[word & 0xf]);
|
}
|
}
|
else
|
else
|
printf (" [reserved]\n");
|
printf (_(" [reserved (%d)]\n"), per_index);
|
break;
|
break;
|
|
|
default:
|
default:
|
abort ();
|
error (_("Unsupported architecture type %d encountered when decoding unwind table"),
|
|
elf_header.e_machine);
|
}
|
}
|
|
|
/* Decode the descriptors. Not implemented. */
|
/* Decode the descriptors. Not implemented. */
|
}
|
}
|
|
|
Line 6996... |
Line 7065... |
struct absaddr fn_addr, entry_addr;
|
struct absaddr fn_addr, entry_addr;
|
bfd_vma fn;
|
bfd_vma fn;
|
|
|
fputc ('\n', stdout);
|
fputc ('\n', stdout);
|
|
|
if (!arm_section_get_word (aux, &exidx_arm_sec, exidx_sec,
|
if (! get_unwind_section_word (aux, & exidx_arm_sec, exidx_sec,
|
8 * i, &exidx_fn, &fn_addr)
|
8 * i, & exidx_fn, & fn_addr, NULL)
|
|| !arm_section_get_word (aux, &exidx_arm_sec, exidx_sec,
|
|| ! get_unwind_section_word (aux, & exidx_arm_sec, exidx_sec,
|
8 * i + 4, &exidx_entry, &entry_addr))
|
8 * i + 4, & exidx_entry, & entry_addr, NULL))
|
{
|
{
|
arm_free_section (&exidx_arm_sec);
|
arm_free_section (&exidx_arm_sec);
|
arm_free_section (&extab_arm_sec);
|
arm_free_section (&extab_arm_sec);
|
return;
|
return;
|
}
|
}
|
|
|
fn = expand_prel31 (exidx_fn, exidx_sec->sh_addr + 8 * i);
|
/* ARM EHABI, Section 5:
|
|
An index table entry consists of 2 words.
|
|
The first word contains a prel31 offset to the start of a function, with bit 31 clear. */
|
|
if (exidx_fn & 0x80000000)
|
|
warn (_("corrupt index table entry: %x\n"), exidx_fn);
|
|
|
|
fn = arm_expand_prel31 (exidx_fn, exidx_sec->sh_addr + 8 * i);
|
|
|
arm_print_vma_and_name (aux, fn, entry_addr);
|
arm_print_vma_and_name (aux, fn, fn_addr);
|
fputs (": ", stdout);
|
fputs (": ", stdout);
|
|
|
if (exidx_entry == 1)
|
if (exidx_entry == 1)
|
{
|
{
|
print_vma (exidx_entry, PREFIX_HEX);
|
print_vma (exidx_entry, PREFIX_HEX);
|
Line 7028... |
Line 7103... |
{
|
{
|
bfd_vma table, table_offset = 0;
|
bfd_vma table, table_offset = 0;
|
Elf_Internal_Shdr *table_sec;
|
Elf_Internal_Shdr *table_sec;
|
|
|
fputs ("@", stdout);
|
fputs ("@", stdout);
|
table = expand_prel31 (exidx_entry, exidx_sec->sh_addr + 8 * i + 4);
|
table = arm_expand_prel31 (exidx_entry, exidx_sec->sh_addr + 8 * i + 4);
|
print_vma (table, PREFIX_HEX);
|
print_vma (table, PREFIX_HEX);
|
printf ("\n");
|
printf ("\n");
|
|
|
/* Locate the matching .ARM.extab. */
|
/* Locate the matching .ARM.extab. */
|
if (entry_addr.section != SHN_UNDEF
|
if (entry_addr.section != SHN_UNDEF
|
Line 7063... |
Line 7138... |
arm_free_section (&exidx_arm_sec);
|
arm_free_section (&exidx_arm_sec);
|
arm_free_section (&extab_arm_sec);
|
arm_free_section (&extab_arm_sec);
|
}
|
}
|
|
|
/* Used for both ARM and C6X unwinding tables. */
|
/* Used for both ARM and C6X unwinding tables. */
|
static int
|
|
|
static void
|
arm_process_unwind (FILE *file)
|
arm_process_unwind (FILE *file)
|
{
|
{
|
struct arm_unw_aux_info aux;
|
struct arm_unw_aux_info aux;
|
Elf_Internal_Shdr *unwsec = NULL;
|
Elf_Internal_Shdr *unwsec = NULL;
|
Elf_Internal_Shdr *strsec;
|
Elf_Internal_Shdr *strsec;
|
Elf_Internal_Shdr *sec;
|
Elf_Internal_Shdr *sec;
|
unsigned long i;
|
unsigned long i;
|
unsigned int sec_type;
|
unsigned int sec_type;
|
|
|
memset (& aux, 0, sizeof (aux));
|
|
aux.file = file;
|
|
|
|
switch (elf_header.e_machine)
|
switch (elf_header.e_machine)
|
{
|
{
|
case EM_ARM:
|
case EM_ARM:
|
sec_type = SHT_ARM_EXIDX;
|
sec_type = SHT_ARM_EXIDX;
|
break;
|
break;
|
Line 7087... |
Line 7160... |
case EM_TI_C6000:
|
case EM_TI_C6000:
|
sec_type = SHT_C6000_UNWIND;
|
sec_type = SHT_C6000_UNWIND;
|
break;
|
break;
|
|
|
default:
|
default:
|
abort();
|
error (_("Unsupported architecture type %d encountered when processing unwind table"),
|
|
elf_header.e_machine);
|
|
return;
|
}
|
}
|
|
|
if (string_table == NULL)
|
if (string_table == NULL)
|
return 1;
|
return;
|
|
|
|
memset (& aux, 0, sizeof (aux));
|
|
aux.file = file;
|
|
|
for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
|
for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
|
{
|
{
|
if (sec->sh_type == SHT_SYMTAB && sec->sh_link < elf_header.e_shnum)
|
if (sec->sh_type == SHT_SYMTAB && sec->sh_link < elf_header.e_shnum)
|
{
|
{
|
Line 7109... |
Line 7187... |
}
|
}
|
else if (sec->sh_type == sec_type)
|
else if (sec->sh_type == sec_type)
|
unwsec = sec;
|
unwsec = sec;
|
}
|
}
|
|
|
if (!unwsec)
|
if (unwsec == NULL)
|
printf (_("\nThere are no unwind sections in this file.\n"));
|
printf (_("\nThere are no unwind sections in this file.\n"));
|
|
else
|
for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
|
for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
|
{
|
{
|
if (sec->sh_type == sec_type)
|
if (sec->sh_type == sec_type)
|
{
|
{
|
printf (_("\nUnwind table index '%s' at offset 0x%lx contains %lu entries:\n"),
|
printf (_("\nUnwind table index '%s' at offset 0x%lx contains %lu entries:\n"),
|
Line 7129... |
Line 7207... |
|
|
if (aux.symtab)
|
if (aux.symtab)
|
free (aux.symtab);
|
free (aux.symtab);
|
if (aux.strtab)
|
if (aux.strtab)
|
free ((char *) aux.strtab);
|
free ((char *) aux.strtab);
|
|
|
return 1;
|
|
}
|
}
|
|
|
static int
|
static void
|
process_unwind (FILE * file)
|
process_unwind (FILE * file)
|
{
|
{
|
struct unwind_handler
|
struct unwind_handler
|
{
|
{
|
int machtype;
|
int machtype;
|
int (* handler)(FILE *);
|
void (* handler)(FILE *);
|
} handlers[] =
|
} handlers[] =
|
{
|
{
|
{ EM_ARM, arm_process_unwind },
|
{ EM_ARM, arm_process_unwind },
|
{ EM_IA_64, ia64_process_unwind },
|
{ EM_IA_64, ia64_process_unwind },
|
{ EM_PARISC, hppa_process_unwind },
|
{ EM_PARISC, hppa_process_unwind },
|
Line 7151... |
Line 7227... |
{ 0, 0 }
|
{ 0, 0 }
|
};
|
};
|
int i;
|
int i;
|
|
|
if (!do_unwind)
|
if (!do_unwind)
|
return 1;
|
return;
|
|
|
for (i = 0; handlers[i].handler != NULL; i++)
|
for (i = 0; handlers[i].handler != NULL; i++)
|
if (elf_header.e_machine == handlers[i].machtype)
|
if (elf_header.e_machine == handlers[i].machtype)
|
return handlers[i].handler (file);
|
return handlers[i].handler (file);
|
|
|
printf (_("\nThere are no unwind sections in this file.\n"));
|
printf (_("\nThe decoding of unwind sections for machine type %s is not currently supported.\n"),
|
return 1;
|
get_machine_name (elf_header.e_machine));
|
}
|
}
|
|
|
static void
|
static void
|
dynamic_section_mips_val (Elf_Internal_Dyn * entry)
|
dynamic_section_mips_val (Elf_Internal_Dyn * entry)
|
{
|
{
|
switch (entry->d_tag)
|
switch (entry->d_tag)
|
{
|
{
|
case DT_MIPS_FLAGS:
|
case DT_MIPS_FLAGS:
|
if (entry->d_un.d_val == 0)
|
if (entry->d_un.d_val == 0)
|
printf (_("NONE\n"));
|
printf (_("NONE"));
|
else
|
else
|
{
|
{
|
static const char * opts[] =
|
static const char * opts[] =
|
{
|
{
|
"QUICKSTART", "NOTPOT", "NO_LIBRARY_REPLACEMENT",
|
"QUICKSTART", "NOTPOT", "NO_LIBRARY_REPLACEMENT",
|
Line 7188... |
Line 7264... |
if (entry->d_un.d_val & (1 << cnt))
|
if (entry->d_un.d_val & (1 << cnt))
|
{
|
{
|
printf ("%s%s", first ? "" : " ", opts[cnt]);
|
printf ("%s%s", first ? "" : " ", opts[cnt]);
|
first = 0;
|
first = 0;
|
}
|
}
|
puts ("");
|
|
}
|
}
|
break;
|
break;
|
|
|
case DT_MIPS_IVERSION:
|
case DT_MIPS_IVERSION:
|
if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
|
if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
|
printf (_("Interface Version: %s\n"), GET_DYNAMIC_NAME (entry->d_un.d_val));
|
printf (_("Interface Version: %s"), GET_DYNAMIC_NAME (entry->d_un.d_val));
|
else
|
else
|
printf (_("<corrupt: %ld>\n"), (long) entry->d_un.d_ptr);
|
printf (_("<corrupt: %" BFD_VMA_FMT "d>"), entry->d_un.d_ptr);
|
break;
|
break;
|
|
|
case DT_MIPS_TIME_STAMP:
|
case DT_MIPS_TIME_STAMP:
|
{
|
{
|
char timebuf[20];
|
char timebuf[20];
|
Line 7209... |
Line 7284... |
time_t atime = entry->d_un.d_val;
|
time_t atime = entry->d_un.d_val;
|
tmp = gmtime (&atime);
|
tmp = gmtime (&atime);
|
snprintf (timebuf, sizeof (timebuf), "%04u-%02u-%02uT%02u:%02u:%02u",
|
snprintf (timebuf, sizeof (timebuf), "%04u-%02u-%02uT%02u:%02u:%02u",
|
tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
|
tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
|
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
printf (_("Time Stamp: %s\n"), timebuf);
|
printf (_("Time Stamp: %s"), timebuf);
|
}
|
}
|
break;
|
break;
|
|
|
case DT_MIPS_RLD_VERSION:
|
case DT_MIPS_RLD_VERSION:
|
case DT_MIPS_LOCAL_GOTNO:
|
case DT_MIPS_LOCAL_GOTNO:
|
Line 7226... |
Line 7301... |
case DT_MIPS_DELTA_INSTANCE_NO:
|
case DT_MIPS_DELTA_INSTANCE_NO:
|
case DT_MIPS_DELTA_RELOC_NO:
|
case DT_MIPS_DELTA_RELOC_NO:
|
case DT_MIPS_DELTA_SYM_NO:
|
case DT_MIPS_DELTA_SYM_NO:
|
case DT_MIPS_DELTA_CLASSSYM_NO:
|
case DT_MIPS_DELTA_CLASSSYM_NO:
|
case DT_MIPS_COMPACT_SIZE:
|
case DT_MIPS_COMPACT_SIZE:
|
printf ("%ld\n", (long) entry->d_un.d_ptr);
|
print_vma (entry->d_un.d_ptr, DEC);
|
break;
|
break;
|
|
|
default:
|
default:
|
printf ("%#lx\n", (unsigned long) entry->d_un.d_ptr);
|
print_vma (entry->d_un.d_ptr, PREFIX_HEX);
|
}
|
}
|
|
putchar ('\n');
|
}
|
}
|
|
|
static void
|
static void
|
dynamic_section_parisc_val (Elf_Internal_Dyn * entry)
|
dynamic_section_parisc_val (Elf_Internal_Dyn * entry)
|
{
|
{
|
Line 8684... |
Line 8760... |
return "HP_STUB";
|
return "HP_STUB";
|
}
|
}
|
|
|
if (type == STT_GNU_IFUNC
|
if (type == STT_GNU_IFUNC
|
&& (elf_header.e_ident[EI_OSABI] == ELFOSABI_GNU
|
&& (elf_header.e_ident[EI_OSABI] == ELFOSABI_GNU
|
|
|| elf_header.e_ident[EI_OSABI] == ELFOSABI_FREEBSD
|
/* GNU is still using the default value 0. */
|
/* GNU is still using the default value 0. */
|
|| elf_header.e_ident[EI_OSABI] == ELFOSABI_NONE))
|
|| elf_header.e_ident[EI_OSABI] == ELFOSABI_NONE))
|
return "IFUNC";
|
return "IFUNC";
|
|
|
snprintf (buff, sizeof (buff), _("<OS specific>: %d"), type);
|
snprintf (buff, sizeof (buff), _("<OS specific>: %d"), type);
|
Line 12924... |
Line 13001... |
}
|
}
|
|
|
external = next;
|
external = next;
|
|
|
/* Prevent out-of-bounds indexing. */
|
/* Prevent out-of-bounds indexing. */
|
if (inote.namedata + inote.namesz >= (char *) pnotes + length
|
if (inote.namedata + inote.namesz > (char *) pnotes + length
|
|| inote.namedata + inote.namesz < inote.namedata)
|
|| inote.namedata + inote.namesz < inote.namedata)
|
{
|
{
|
warn (_("corrupt note found at offset %lx into core notes\n"),
|
warn (_("corrupt note found at offset %lx into core notes\n"),
|
(unsigned long) ((char *) external - (char *) pnotes));
|
(unsigned long) ((char *) external - (char *) pnotes));
|
warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"),
|
warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"),
|
Line 12938... |
Line 13015... |
|
|
/* Verify that name is null terminated. It appears that at least
|
/* Verify that name is null terminated. It appears that at least
|
one version of Linux (RedHat 6.0) generates corefiles that don't
|
one version of Linux (RedHat 6.0) generates corefiles that don't
|
comply with the ELF spec by failing to include the null byte in
|
comply with the ELF spec by failing to include the null byte in
|
namesz. */
|
namesz. */
|
if (inote.namedata[inote.namesz] != '\0')
|
if (inote.namedata[inote.namesz - 1] != '\0')
|
{
|
{
|
temp = (char *) malloc (inote.namesz + 1);
|
temp = (char *) malloc (inote.namesz + 1);
|
|
|
if (temp == NULL)
|
if (temp == NULL)
|
{
|
{
|
Line 13001... |
Line 13078... |
Elf_Internal_Shdr * section;
|
Elf_Internal_Shdr * section;
|
unsigned long i;
|
unsigned long i;
|
int res = 1;
|
int res = 1;
|
|
|
for (i = 0, section = section_headers;
|
for (i = 0, section = section_headers;
|
i < elf_header.e_shnum;
|
i < elf_header.e_shnum && section != NULL;
|
i++, section++)
|
i++, section++)
|
if (section->sh_type == SHT_NOTE)
|
if (section->sh_type == SHT_NOTE)
|
res &= process_corefile_note_segment (file,
|
res &= process_corefile_note_segment (file,
|
(bfd_vma) section->sh_offset,
|
(bfd_vma) section->sh_offset,
|
(bfd_vma) section->sh_size);
|
(bfd_vma) section->sh_size);
|