* NEWS: Document .ARM.exidx / .ARM.extab support.
* dwarf.c (read_leb128): Make non-static. * dwarf.h (read_leb128): Declare. * readelf.c (REMOVE_ARCH_BITS): Define. (find_section_by_address): New. (read_uleb128): Move higher. Use read_leb128 from dwarf.c. (find_symbol_for_address): Handle the Thumb bit for ARM, by using REMOVE_ARCH_BITS. (struct arm_section, struct arm_unw_aux_info, arm_print_vma_and_name) (arm_free_section, arm_section_get_word, decode_arm_unwind) (dump_arm_unwind, arm_process_unwind): New. (process_unwind): Handle ARM.
This commit is contained in:
parent
1ba53b71ca
commit
0b6ae52290
@ -1,3 +1,19 @@
|
||||
2010-03-02 Daniel Jacobowitz <dan@codesourcery.com>
|
||||
|
||||
* NEWS: Document .ARM.exidx / .ARM.extab support.
|
||||
|
||||
* dwarf.c (read_leb128): Make non-static.
|
||||
* dwarf.h (read_leb128): Declare.
|
||||
* readelf.c (REMOVE_ARCH_BITS): Define.
|
||||
(find_section_by_address): New.
|
||||
(read_uleb128): Move higher. Use read_leb128 from dwarf.c.
|
||||
(find_symbol_for_address): Handle the Thumb bit for ARM, by
|
||||
using REMOVE_ARCH_BITS.
|
||||
(struct arm_section, struct arm_unw_aux_info, arm_print_vma_and_name)
|
||||
(arm_free_section, arm_section_get_word, decode_arm_unwind)
|
||||
(dump_arm_unwind, arm_process_unwind): New.
|
||||
(process_unwind): Handle ARM.
|
||||
|
||||
2010-02-26 Jie Zhang <jie@codesourcery.com>
|
||||
|
||||
* MAINTAINERS: Update my email address.
|
||||
|
@ -1,5 +1,8 @@
|
||||
-*- text -*-
|
||||
|
||||
* Readelf can now display ARM unwind tables (.ARM.exidx / .ARM.extab) using
|
||||
the -u / --unwind option.
|
||||
|
||||
* Add --dyn-syms to readelf to dump dynamic symbol table.
|
||||
|
||||
* A new tool - elfedit - has been added to directly manipulate ELF format
|
||||
|
@ -227,7 +227,7 @@ print_dwarf_vma (dwarf_vma val, unsigned byte_size)
|
||||
fputs (buff + (byte_size == 4 ? 8 : 0), stdout);
|
||||
}
|
||||
|
||||
static unsigned long int
|
||||
unsigned long int
|
||||
read_leb128 (unsigned char *data, unsigned int *length_return, int sign)
|
||||
{
|
||||
unsigned long int result = 0;
|
||||
|
@ -133,3 +133,6 @@ void *xcrealloc (void *, size_t, size_t);
|
||||
|
||||
void error (const char *, ...) ATTRIBUTE_PRINTF_1;
|
||||
void warn (const char *, ...) ATTRIBUTE_PRINTF_1;
|
||||
|
||||
unsigned long int read_leb128 (unsigned char *data,
|
||||
unsigned int *length_return, int sign);
|
||||
|
@ -285,6 +285,11 @@ static void (* byte_put) (unsigned char *, bfd_vma, int);
|
||||
#define streq(a,b) (strcmp ((a), (b)) == 0)
|
||||
#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
|
||||
#define const_strneq(a,b) (strncmp ((a), (b), sizeof (b) - 1) == 0)
|
||||
|
||||
#define REMOVE_ARCH_BITS(ADDR) do { \
|
||||
if (elf_header.e_machine == EM_ARM) \
|
||||
(ADDR) &= ~1; \
|
||||
} while (0)
|
||||
|
||||
static void *
|
||||
get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb,
|
||||
@ -544,6 +549,33 @@ find_section (const char * name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return a pointer to a section containing ADDR, or NULL if no such
|
||||
section exists. */
|
||||
|
||||
static Elf_Internal_Shdr *
|
||||
find_section_by_address (bfd_vma addr)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < elf_header.e_shnum; i++)
|
||||
{
|
||||
Elf_Internal_Shdr *sec = section_headers + i;
|
||||
if (addr >= sec->sh_addr && addr < sec->sh_addr + sec->sh_size)
|
||||
return sec;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read an unsigned LEB128 encoded value from p. Set *PLEN to the number of
|
||||
bytes read. */
|
||||
|
||||
static unsigned long
|
||||
read_uleb128 (unsigned char *data, unsigned int *length_return)
|
||||
{
|
||||
return read_leb128 (data, length_return, 0);
|
||||
}
|
||||
|
||||
/* Guess the relocation size commonly used by the specific machines. */
|
||||
|
||||
static int
|
||||
@ -5089,16 +5121,22 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
|
||||
Elf_Internal_Sym * best = NULL;
|
||||
unsigned long i;
|
||||
|
||||
REMOVE_ARCH_BITS (addr.offset);
|
||||
|
||||
for (i = 0, sym = symtab; i < nsyms; ++i, ++sym)
|
||||
{
|
||||
bfd_vma value = sym->st_value;
|
||||
|
||||
REMOVE_ARCH_BITS (value);
|
||||
|
||||
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC
|
||||
&& sym->st_name != 0
|
||||
&& (addr.section == SHN_UNDEF || addr.section == sym->st_shndx)
|
||||
&& addr.offset >= sym->st_value
|
||||
&& addr.offset - sym->st_value < dist)
|
||||
&& addr.offset >= value
|
||||
&& addr.offset - value < dist)
|
||||
{
|
||||
best = sym;
|
||||
dist = addr.offset - sym->st_value;
|
||||
dist = addr.offset - value;
|
||||
if (!dist)
|
||||
break;
|
||||
}
|
||||
@ -5761,6 +5799,579 @@ hppa_process_unwind (FILE * file)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct arm_section
|
||||
{
|
||||
unsigned char *data;
|
||||
|
||||
Elf_Internal_Shdr *sec;
|
||||
Elf_Internal_Rela *rela;
|
||||
unsigned long nrelas;
|
||||
unsigned int rel_type;
|
||||
|
||||
Elf_Internal_Rela *next_rela;
|
||||
};
|
||||
|
||||
struct arm_unw_aux_info
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
Elf_Internal_Sym *symtab; /* The symbol table. */
|
||||
unsigned long nsyms; /* Number of symbols. */
|
||||
char *strtab; /* The string table. */
|
||||
unsigned long strtab_size; /* Size of string table. */
|
||||
};
|
||||
|
||||
static const char *
|
||||
arm_print_vma_and_name (struct arm_unw_aux_info *aux,
|
||||
bfd_vma fn, struct absaddr addr)
|
||||
{
|
||||
const char *procname;
|
||||
bfd_vma sym_offset;
|
||||
|
||||
if (addr.section == SHN_UNDEF)
|
||||
addr.offset = fn;
|
||||
|
||||
find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
|
||||
aux->strtab_size, addr, &procname,
|
||||
&sym_offset);
|
||||
|
||||
print_vma (fn, PREFIX_HEX);
|
||||
|
||||
if (procname)
|
||||
{
|
||||
fputs (" <", stdout);
|
||||
fputs (procname, stdout);
|
||||
|
||||
if (sym_offset)
|
||||
printf ("+0x%lx", (unsigned long) sym_offset);
|
||||
fputc ('>', stdout);
|
||||
}
|
||||
|
||||
return procname;
|
||||
}
|
||||
|
||||
static void
|
||||
arm_free_section (struct arm_section *arm_sec)
|
||||
{
|
||||
if (arm_sec->data != NULL)
|
||||
free (arm_sec->data);
|
||||
|
||||
if (arm_sec->rela != NULL)
|
||||
free (arm_sec->rela);
|
||||
}
|
||||
|
||||
static int
|
||||
arm_section_get_word (struct arm_unw_aux_info *aux,
|
||||
struct arm_section *arm_sec,
|
||||
Elf_Internal_Shdr *sec, bfd_vma word_offset,
|
||||
unsigned int *wordp, struct absaddr *addr)
|
||||
{
|
||||
Elf_Internal_Rela *rp;
|
||||
Elf_Internal_Sym *sym;
|
||||
const char * relname;
|
||||
unsigned int word;
|
||||
bfd_boolean wrapped;
|
||||
|
||||
addr->section = SHN_UNDEF;
|
||||
addr->offset = 0;
|
||||
|
||||
if (sec != arm_sec->sec)
|
||||
{
|
||||
Elf_Internal_Shdr *relsec;
|
||||
|
||||
arm_free_section (arm_sec);
|
||||
|
||||
arm_sec->sec = sec;
|
||||
arm_sec->data = get_data (NULL, aux->file, sec->sh_offset, 1,
|
||||
sec->sh_size, _("unwind data"));
|
||||
|
||||
arm_sec->rela = NULL;
|
||||
arm_sec->nrelas = 0;
|
||||
|
||||
for (relsec = section_headers;
|
||||
relsec < section_headers + elf_header.e_shnum;
|
||||
++relsec)
|
||||
{
|
||||
if (relsec->sh_info >= elf_header.e_shnum
|
||||
|| section_headers + relsec->sh_info != sec)
|
||||
continue;
|
||||
|
||||
if (relsec->sh_type == SHT_REL)
|
||||
{
|
||||
if (!slurp_rel_relocs (aux->file, relsec->sh_offset,
|
||||
relsec->sh_size,
|
||||
& arm_sec->rela, & arm_sec->nrelas))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
else if (relsec->sh_type == SHT_RELA)
|
||||
{
|
||||
if (!slurp_rela_relocs (aux->file, relsec->sh_offset,
|
||||
relsec->sh_size,
|
||||
& arm_sec->rela, & arm_sec->nrelas))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
arm_sec->next_rela = arm_sec->rela;
|
||||
}
|
||||
|
||||
if (arm_sec->data == NULL)
|
||||
return 0;
|
||||
|
||||
word = byte_get (arm_sec->data + word_offset, 4);
|
||||
|
||||
wrapped = FALSE;
|
||||
for (rp = arm_sec->next_rela; rp != arm_sec->rela + arm_sec->nrelas; rp++)
|
||||
{
|
||||
bfd_vma prelval, offset;
|
||||
|
||||
if (rp->r_offset > word_offset && !wrapped)
|
||||
{
|
||||
rp = arm_sec->rela;
|
||||
wrapped = TRUE;
|
||||
}
|
||||
if (rp->r_offset > word_offset)
|
||||
break;
|
||||
|
||||
if (rp->r_offset & 3)
|
||||
{
|
||||
warn (_("Skipping unexpected relocation at offset 0x%lx\n"),
|
||||
(unsigned long) rp->r_offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rp->r_offset < word_offset)
|
||||
continue;
|
||||
|
||||
relname = elf_arm_reloc_type (ELF32_R_TYPE (rp->r_info));
|
||||
|
||||
if (streq (relname, "R_ARM_NONE"))
|
||||
continue;
|
||||
|
||||
if (! streq (relname, "R_ARM_PREL31"))
|
||||
{
|
||||
warn (_("Skipping unexpected relocation type %s\n"), relname);
|
||||
continue;
|
||||
}
|
||||
|
||||
sym = aux->symtab + ELF32_R_SYM (rp->r_info);
|
||||
|
||||
if (arm_sec->rel_type == SHT_REL)
|
||||
{
|
||||
offset = word & 0x7fffffff;
|
||||
if (offset & 0x40000000)
|
||||
offset |= ~ (bfd_vma) 0x7fffffff;
|
||||
}
|
||||
else
|
||||
offset = rp->r_addend;
|
||||
|
||||
offset += sym->st_value;
|
||||
prelval = offset - (arm_sec->sec->sh_addr + rp->r_offset);
|
||||
|
||||
word = (word & ~ (bfd_vma) 0x7fffffff) | (prelval & 0x7fffffff);
|
||||
addr->section = sym->st_shndx;
|
||||
addr->offset = offset;
|
||||
break;
|
||||
}
|
||||
|
||||
*wordp = word;
|
||||
arm_sec->next_rela = rp;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
decode_arm_unwind (struct arm_unw_aux_info *aux,
|
||||
unsigned int word, unsigned int remaining,
|
||||
bfd_vma data_offset, Elf_Internal_Shdr *data_sec,
|
||||
struct arm_section *data_arm_sec)
|
||||
{
|
||||
int per_index;
|
||||
unsigned int more_words;
|
||||
struct absaddr addr;
|
||||
|
||||
#define ADVANCE \
|
||||
if (remaining == 0 && more_words) \
|
||||
{ \
|
||||
data_offset += 4; \
|
||||
if (!arm_section_get_word (aux, data_arm_sec, data_sec, \
|
||||
data_offset, &word, &addr)) \
|
||||
return; \
|
||||
remaining = 4; \
|
||||
more_words--; \
|
||||
} \
|
||||
|
||||
#define GET_OP(OP) \
|
||||
ADVANCE; \
|
||||
if (remaining) \
|
||||
{ \
|
||||
remaining--; \
|
||||
(OP) = word >> 24; \
|
||||
word <<= 8; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
printf ("[Truncated opcode]\n"); \
|
||||
return; \
|
||||
} \
|
||||
printf (_("0x%02x "), OP)
|
||||
|
||||
if (remaining == 0)
|
||||
{
|
||||
/* Fetch the first word. */
|
||||
if (!arm_section_get_word (aux, data_arm_sec, data_sec, data_offset,
|
||||
&word, &addr))
|
||||
return;
|
||||
remaining = 4;
|
||||
}
|
||||
|
||||
if ((word & 0x80000000) == 0)
|
||||
{
|
||||
/* Expand prel31 for personality routine. */
|
||||
bfd_vma fn;
|
||||
const char *procname;
|
||||
|
||||
fn = word;
|
||||
if (fn & 0x40000000)
|
||||
fn |= ~ (bfd_vma) 0x7fffffff;
|
||||
fn = fn + data_sec->sh_addr + data_offset;
|
||||
|
||||
printf (_(" Personality routine: "));
|
||||
procname = arm_print_vma_and_name (aux, fn, addr);
|
||||
fputc ('\n', stdout);
|
||||
|
||||
/* The GCC personality routines use the standard compact
|
||||
encoding, starting with one byte giving the number of
|
||||
words. */
|
||||
if (procname != NULL
|
||||
&& (const_strneq (procname, "__gcc_personality_v0")
|
||||
|| const_strneq (procname, "__gxx_personality_v0")
|
||||
|| const_strneq (procname, "__gcj_personality_v0")
|
||||
|| const_strneq (procname, "__gnu_objc_personality_v0")))
|
||||
{
|
||||
remaining = 0;
|
||||
more_words = 1;
|
||||
ADVANCE;
|
||||
if (!remaining)
|
||||
{
|
||||
printf (_(" [Truncated data]\n"));
|
||||
return;
|
||||
}
|
||||
more_words = word >> 24;
|
||||
word <<= 8;
|
||||
remaining--;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
per_index = (word >> 24) & 0x7f;
|
||||
if (per_index != 0 && per_index != 1 && per_index != 2)
|
||||
{
|
||||
printf (_(" [reserved compact index %d]\n"), per_index);
|
||||
return;
|
||||
}
|
||||
|
||||
printf (_(" Compact model %d\n"), per_index);
|
||||
if (per_index == 0)
|
||||
{
|
||||
more_words = 0;
|
||||
word <<= 8;
|
||||
remaining--;
|
||||
}
|
||||
else
|
||||
{
|
||||
more_words = (word >> 16) & 0xff;
|
||||
word <<= 16;
|
||||
remaining -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode the unwinding instructions. */
|
||||
while (1)
|
||||
{
|
||||
unsigned int op, op2;
|
||||
|
||||
ADVANCE;
|
||||
if (remaining == 0)
|
||||
break;
|
||||
remaining--;
|
||||
op = word >> 24;
|
||||
word <<= 8;
|
||||
|
||||
printf (_(" 0x%02x "), op);
|
||||
|
||||
if ((op & 0xc0) == 0x00)
|
||||
{
|
||||
int offset = ((op & 0x3f) << 2) + 4;
|
||||
printf (_(" vsp = vsp + %d"), offset);
|
||||
}
|
||||
else if ((op & 0xc0) == 0x40)
|
||||
{
|
||||
int offset = ((op & 0x3f) << 2) + 4;
|
||||
printf (_(" vsp = vsp - %d"), offset);
|
||||
}
|
||||
else if ((op & 0xf0) == 0x80)
|
||||
{
|
||||
GET_OP (op2);
|
||||
if (op == 0x80 && op2 == 0)
|
||||
printf (_("Refuse to unwind"));
|
||||
else
|
||||
{
|
||||
unsigned int mask = ((op & 0x0f) << 8) | op2;
|
||||
int first = 1;
|
||||
int i;
|
||||
printf ("pop {");
|
||||
for (i = 0; i < 12; i++)
|
||||
if (mask & (1 << i))
|
||||
{
|
||||
if (first)
|
||||
first = 0;
|
||||
else
|
||||
printf (", ");
|
||||
printf ("r%d", 4 + i);
|
||||
}
|
||||
printf ("}");
|
||||
}
|
||||
}
|
||||
else if ((op & 0xf0) == 0x90)
|
||||
{
|
||||
if (op == 0x9d || op == 0x9f)
|
||||
printf (_(" [Reserved]"));
|
||||
else
|
||||
printf (_(" vsp = r%d"), op & 0x0f);
|
||||
}
|
||||
else if ((op & 0xf0) == 0xa0)
|
||||
{
|
||||
int end = 4 + (op & 0x07);
|
||||
int first = 1;
|
||||
int i;
|
||||
printf (" pop {");
|
||||
for (i = 4; i <= end; i++)
|
||||
{
|
||||
if (first)
|
||||
first = 0;
|
||||
else
|
||||
printf (", ");
|
||||
printf ("r%d", i);
|
||||
}
|
||||
if (op & 0x08)
|
||||
{
|
||||
if (first)
|
||||
printf (", ");
|
||||
printf ("r14");
|
||||
}
|
||||
printf ("}");
|
||||
}
|
||||
else if (op == 0xb0)
|
||||
printf (_(" finish"));
|
||||
else if (op == 0xb1)
|
||||
{
|
||||
GET_OP (op2);
|
||||
if (op2 == 0 || (op2 & 0xf0) != 0)
|
||||
printf (_("[Spare]"));
|
||||
else
|
||||
{
|
||||
unsigned int mask = op2 & 0x0f;
|
||||
int first = 1;
|
||||
int i;
|
||||
printf ("pop {");
|
||||
for (i = 0; i < 12; i++)
|
||||
if (mask & (1 << i))
|
||||
{
|
||||
if (first)
|
||||
first = 0;
|
||||
else
|
||||
printf (", ");
|
||||
printf ("r%d", i);
|
||||
}
|
||||
printf ("}");
|
||||
}
|
||||
}
|
||||
else if (op == 0xb2)
|
||||
{
|
||||
unsigned char buf[5];
|
||||
unsigned int i, len;
|
||||
unsigned long offset;
|
||||
for (i = 0; i < 9; i++)
|
||||
{
|
||||
GET_OP (buf[i]);
|
||||
if ((buf[i] & 0x80) == 0)
|
||||
break;
|
||||
}
|
||||
assert (i < sizeof (buf));
|
||||
offset = read_uleb128 (buf, &len);
|
||||
assert (len == i + 1);
|
||||
offset = offset * 4 + 0x204;
|
||||
printf (_("vsp = vsp + %ld"), offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (op == 0xb3 || op == 0xc6 || op == 0xc7 || op == 0xc8 || op == 0xc9)
|
||||
{
|
||||
GET_OP (op2);
|
||||
printf (_("[unsupported two-byte opcode]"));
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (_(" [unsupported opcode]"));
|
||||
}
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
/* Decode the descriptors. Not implemented. */
|
||||
}
|
||||
|
||||
static void
|
||||
dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
|
||||
{
|
||||
struct arm_section exidx_arm_sec, extab_arm_sec;
|
||||
unsigned int i, exidx_len;
|
||||
|
||||
memset (&exidx_arm_sec, 0, sizeof (exidx_arm_sec));
|
||||
memset (&extab_arm_sec, 0, sizeof (extab_arm_sec));
|
||||
exidx_len = exidx_sec->sh_size / 8;
|
||||
|
||||
for (i = 0; i < exidx_len; i++)
|
||||
{
|
||||
unsigned int exidx_fn, exidx_entry;
|
||||
struct absaddr fn_addr, entry_addr;
|
||||
bfd_vma fn;
|
||||
|
||||
fputc ('\n', stdout);
|
||||
|
||||
if (!arm_section_get_word (aux, &exidx_arm_sec, exidx_sec,
|
||||
8 * i, &exidx_fn, &fn_addr)
|
||||
|| !arm_section_get_word (aux, &exidx_arm_sec, exidx_sec,
|
||||
8 * i + 4, &exidx_entry, &entry_addr))
|
||||
{
|
||||
arm_free_section (&exidx_arm_sec);
|
||||
arm_free_section (&extab_arm_sec);
|
||||
return;
|
||||
}
|
||||
|
||||
fn = exidx_fn & 0x7fffffff;
|
||||
if (fn & 0x40000000)
|
||||
fn |= ~ (bfd_vma) 0x7fffffff;
|
||||
fn = fn + exidx_sec->sh_addr + 8 * i;
|
||||
|
||||
arm_print_vma_and_name (aux, fn, entry_addr);
|
||||
fputs (": ", stdout);
|
||||
|
||||
if (exidx_entry == 1)
|
||||
{
|
||||
print_vma (exidx_entry, PREFIX_HEX);
|
||||
fputs (" [cantunwind]\n", stdout);
|
||||
}
|
||||
else if (exidx_entry & 0x80000000)
|
||||
{
|
||||
print_vma (exidx_entry, PREFIX_HEX);
|
||||
fputc ('\n', stdout);
|
||||
decode_arm_unwind (aux, exidx_entry, 4, 0, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
bfd_vma table, table_offset;
|
||||
Elf_Internal_Shdr *table_sec;
|
||||
|
||||
fputs ("@", stdout);
|
||||
table = exidx_entry;
|
||||
if (table & 0x40000000)
|
||||
table |= ~ (bfd_vma) 0x7fffffff;
|
||||
table = table + exidx_sec->sh_addr + 8 * i + 4;
|
||||
print_vma (table, PREFIX_HEX);
|
||||
printf ("\n");
|
||||
|
||||
/* Locate the matching .ARM.extab. */
|
||||
if (entry_addr.section != SHN_UNDEF
|
||||
&& entry_addr.section < elf_header.e_shnum)
|
||||
{
|
||||
table_sec = section_headers + entry_addr.section;
|
||||
table_offset = entry_addr.offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
table_sec = find_section_by_address (table);
|
||||
if (table_sec != NULL)
|
||||
table_offset = table - table_sec->sh_addr;
|
||||
}
|
||||
if (table_sec == NULL)
|
||||
{
|
||||
warn (_("Could not locate .ARM.extab section containing 0x%lx.\n"),
|
||||
(unsigned long) table);
|
||||
continue;
|
||||
}
|
||||
decode_arm_unwind (aux, 0, 0, table_offset, table_sec,
|
||||
&extab_arm_sec);
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\n");
|
||||
|
||||
arm_free_section (&exidx_arm_sec);
|
||||
arm_free_section (&extab_arm_sec);
|
||||
}
|
||||
|
||||
static int
|
||||
arm_process_unwind (FILE *file)
|
||||
{
|
||||
struct arm_unw_aux_info aux;
|
||||
Elf_Internal_Shdr *unwsec = NULL;
|
||||
Elf_Internal_Shdr *strsec;
|
||||
Elf_Internal_Shdr *sec;
|
||||
unsigned long i;
|
||||
|
||||
memset (& aux, 0, sizeof (aux));
|
||||
aux.file = file;
|
||||
|
||||
if (string_table == NULL)
|
||||
return 1;
|
||||
|
||||
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)
|
||||
{
|
||||
aux.nsyms = sec->sh_size / sec->sh_entsize;
|
||||
aux.symtab = GET_ELF_SYMBOLS (file, sec);
|
||||
|
||||
strsec = section_headers + sec->sh_link;
|
||||
aux.strtab = get_data (NULL, file, strsec->sh_offset,
|
||||
1, strsec->sh_size, _("string table"));
|
||||
aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
|
||||
}
|
||||
else if (sec->sh_type == SHT_ARM_EXIDX)
|
||||
unwsec = sec;
|
||||
}
|
||||
|
||||
if (!unwsec)
|
||||
printf (_("\nThere are no unwind sections in this file.\n"));
|
||||
|
||||
for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
|
||||
{
|
||||
if (sec->sh_type == SHT_ARM_EXIDX)
|
||||
{
|
||||
printf (_("\nUnwind table index '%s' at offset 0x%lx contains %lu entries:\n"),
|
||||
SECTION_NAME (sec),
|
||||
(unsigned long) sec->sh_offset,
|
||||
(unsigned long) (sec->sh_size / (2 * eh_addr_size)));
|
||||
|
||||
dump_arm_unwind (&aux, sec);
|
||||
}
|
||||
}
|
||||
|
||||
if (aux.symtab)
|
||||
free (aux.symtab);
|
||||
if (aux.strtab)
|
||||
free ((char *) aux.strtab);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
process_unwind (FILE * file)
|
||||
{
|
||||
@ -5770,6 +6381,7 @@ process_unwind (FILE * file)
|
||||
int (* handler)(FILE *);
|
||||
} handlers[] =
|
||||
{
|
||||
{ EM_ARM, arm_process_unwind },
|
||||
{ EM_IA_64, ia64_process_unwind },
|
||||
{ EM_PARISC, hppa_process_unwind },
|
||||
{ 0, 0 }
|
||||
@ -9177,33 +9789,6 @@ static arm_attr_public_tag arm_attr_public_tags[] =
|
||||
};
|
||||
#undef LOOKUP
|
||||
|
||||
/* Read an unsigned LEB128 encoded value from p. Set *PLEN to the number of
|
||||
bytes read. */
|
||||
|
||||
static unsigned int
|
||||
read_uleb128 (unsigned char * p, unsigned int * plen)
|
||||
{
|
||||
unsigned char c;
|
||||
unsigned int val;
|
||||
int shift;
|
||||
int len;
|
||||
|
||||
val = 0;
|
||||
shift = 0;
|
||||
len = 0;
|
||||
do
|
||||
{
|
||||
c = *(p++);
|
||||
len++;
|
||||
val |= ((unsigned int)c & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
while (c & 0x80);
|
||||
|
||||
*plen = len;
|
||||
return val;
|
||||
}
|
||||
|
||||
static unsigned char *
|
||||
display_arm_attribute (unsigned char * p)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user