Speed up the display of unwind tables by using a binary chop search to locate function symbols.

* readelf.c (find_symbol_for_address): Use a binary search to
	speed up symbol location.  Skip check for function symbol type.
	(*_unw_aux_info): Add funtab and nfuns fields contains a sorted
	list of function symbols.
	(dump_ia64_unwind): Initialise the funtab and nfuns fields and
	pass them to find_symbol_for_address.
	(dump_hppa_unwind): Likewise.
	(arm_print_vma_and_name): Pass funtab to find_symbol_for_address.
	(dump_arm_unwind): Initialise the funtab and nfuns fields.
This commit is contained in:
Dmitry Antipov
2015-02-24 13:21:10 +00:00
committed by Nick Clifton
parent cb0728165e
commit 948f632f56
2 changed files with 159 additions and 86 deletions

View File

@ -1,3 +1,15 @@
2015-02-24 Dmitry Antipov <dantipov@nvidia.com>
* readelf.c (find_symbol_for_address): Use a binary search to
speed up symbol location. Skip check for function symbol type.
(*_unw_aux_info): Add funtab and nfuns fields contains a sorted
list of function symbols.
(dump_ia64_unwind): Initialise the funtab and nfuns fields and
pass them to find_symbol_for_address.
(dump_hppa_unwind): Likewise.
(arm_print_vma_and_name): Pass funtab to find_symbol_for_address.
(dump_arm_unwind): Initialise the funtab and nfuns fields.
2015-02-24 Nick Clifton <nickc@redhat.com> 2015-02-24 Nick Clifton <nickc@redhat.com>
* objdump.c (dump_section): Extend the warning message displayed * objdump.c (dump_section): Extend the warning message displayed

View File

@ -6439,10 +6439,6 @@ process_relocs (FILE * file)
return 1; return 1;
} }
/* Process the unwind section. */
#include "unwind-ia64.h"
/* An absolute address consists of a section and an offset. If the /* An absolute address consists of a section and an offset. If the
section is NULL, the offset itself is the address, otherwise, the section is NULL, the offset itself is the address, otherwise, the
address equals to LOAD_ADDRESS(section) + offset. */ address equals to LOAD_ADDRESS(section) + offset. */
@ -6458,27 +6454,8 @@ struct absaddr
? section_headers [(a).section].sh_addr + (a).offset \ ? section_headers [(a).section].sh_addr + (a).offset \
: (a).offset) : (a).offset)
struct ia64_unw_table_entry /* Find the nearest symbol at or below ADDR. Returns the symbol
{ name, if found, and the offset from the symbol to ADDR. */
struct absaddr start;
struct absaddr end;
struct absaddr info;
};
struct ia64_unw_aux_info
{
struct ia64_unw_table_entry *table; /* Unwind table. */
unsigned long table_len; /* Length of unwind table. */
unsigned char * info; /* Unwind info. */
unsigned long info_size; /* Size of unwind info. */
bfd_vma info_addr; /* starting address of unwind info. */
bfd_vma seg_base; /* Starting address of segment. */
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 void static void
find_symbol_for_address (Elf_Internal_Sym * symtab, find_symbol_for_address (Elf_Internal_Sym * symtab,
@ -6491,19 +6468,24 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
{ {
bfd_vma dist = 0x100000; bfd_vma dist = 0x100000;
Elf_Internal_Sym * sym; Elf_Internal_Sym * sym;
Elf_Internal_Sym * beg;
Elf_Internal_Sym * end;
Elf_Internal_Sym * best = NULL; Elf_Internal_Sym * best = NULL;
unsigned long i;
REMOVE_ARCH_BITS (addr.offset); REMOVE_ARCH_BITS (addr.offset);
beg = symtab;
end = symtab + nsyms;
for (i = 0, sym = symtab; i < nsyms; ++i, ++sym) while (beg < end)
{ {
bfd_vma value = sym->st_value; bfd_vma value;
sym = beg + (end - beg) / 2;
value = sym->st_value;
REMOVE_ARCH_BITS (value); REMOVE_ARCH_BITS (value);
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC if (sym->st_name != 0
&& sym->st_name != 0
&& (addr.section == SHN_UNDEF || addr.section == sym->st_shndx) && (addr.section == SHN_UNDEF || addr.section == sym->st_shndx)
&& addr.offset >= value && addr.offset >= value
&& addr.offset - value < dist) && addr.offset - value < dist)
@ -6513,6 +6495,11 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
if (!dist) if (!dist)
break; break;
} }
if (addr.offset < value)
end = sym;
else
beg = sym + 1;
} }
if (best) if (best)
@ -6527,12 +6514,56 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
*offset = addr.offset; *offset = addr.offset;
} }
static int
symcmp (const void *p, const void *q)
{
Elf_Internal_Sym *sp = (Elf_Internal_Sym *) p;
Elf_Internal_Sym *sq = (Elf_Internal_Sym *) q;
return sp->st_value > sq->st_value ? 1 : (sp->st_value < sq->st_value ? -1 : 0);
}
/* Process the unwind section. */
#include "unwind-ia64.h"
struct ia64_unw_table_entry
{
struct absaddr start;
struct absaddr end;
struct absaddr info;
};
struct ia64_unw_aux_info
{
struct ia64_unw_table_entry *table; /* Unwind table. */
unsigned long table_len; /* Length of unwind table. */
unsigned char * info; /* Unwind info. */
unsigned long info_size; /* Size of unwind info. */
bfd_vma info_addr; /* Starting address of unwind info. */
bfd_vma seg_base; /* Starting address of segment. */
Elf_Internal_Sym * symtab; /* The symbol table. */
unsigned long nsyms; /* Number of symbols. */
Elf_Internal_Sym * funtab; /* Sorted table of STT_FUNC symbols. */
unsigned long nfuns; /* Number of entries in funtab. */
char * strtab; /* The string table. */
unsigned long strtab_size; /* Size of string table. */
};
static void static void
dump_ia64_unwind (struct ia64_unw_aux_info * aux) dump_ia64_unwind (struct ia64_unw_aux_info * aux)
{ {
struct ia64_unw_table_entry * tp; struct ia64_unw_table_entry * tp;
unsigned long j, nfuns;
int in_body; int in_body;
aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym));
for (nfuns = 0, j = 0; j < aux->nsyms; j++)
if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC)
aux->funtab[nfuns++] = aux->symtab[j];
aux->nfuns = nfuns;
qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp);
for (tp = aux->table; tp < aux->table + aux->table_len; ++tp) for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
{ {
bfd_vma stamp; bfd_vma stamp;
@ -6542,7 +6573,7 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux)
const unsigned char * end; const unsigned char * end;
const char * procname; const char * procname;
find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab,
aux->strtab_size, tp->start, &procname, &offset); aux->strtab_size, tp->start, &procname, &offset);
fputs ("\n<", stdout); fputs ("\n<", stdout);
@ -6598,6 +6629,8 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux)
for (dp = head + 8; dp < end;) for (dp = head + 8; dp < end;)
dp = unw_decode (dp, in_body, & in_body); dp = unw_decode (dp, in_body, & in_body);
} }
free (aux->funtab);
} }
static bfd_boolean static bfd_boolean
@ -6936,6 +6969,8 @@ struct hppa_unw_aux_info
bfd_vma seg_base; /* Starting address of segment. */ bfd_vma seg_base; /* Starting address of segment. */
Elf_Internal_Sym * symtab; /* The symbol table. */ Elf_Internal_Sym * symtab; /* The symbol table. */
unsigned long nsyms; /* Number of symbols. */ unsigned long nsyms; /* Number of symbols. */
Elf_Internal_Sym * funtab; /* Sorted table of STT_FUNC symbols. */
unsigned long nfuns; /* Number of entries in funtab. */
char * strtab; /* The string table. */ char * strtab; /* The string table. */
unsigned long strtab_size; /* Size of string table. */ unsigned long strtab_size; /* Size of string table. */
}; };
@ -6944,13 +6979,21 @@ static void
dump_hppa_unwind (struct hppa_unw_aux_info * aux) dump_hppa_unwind (struct hppa_unw_aux_info * aux)
{ {
struct hppa_unw_table_entry * tp; struct hppa_unw_table_entry * tp;
unsigned long j, nfuns;
aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym));
for (nfuns = 0, j = 0; j < aux->nsyms; j++)
if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC)
aux->funtab[nfuns++] = aux->symtab[j];
aux->nfuns = nfuns;
qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp);
for (tp = aux->table; tp < aux->table + aux->table_len; ++tp) for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
{ {
bfd_vma offset; bfd_vma offset;
const char * procname; const char * procname;
find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab,
aux->strtab_size, tp->start, &procname, aux->strtab_size, tp->start, &procname,
&offset); &offset);
@ -7004,6 +7047,8 @@ dump_hppa_unwind (struct hppa_unw_aux_info * aux)
} }
printf ("\n"); printf ("\n");
free (aux->funtab);
} }
static int static int
@ -7240,6 +7285,8 @@ struct arm_unw_aux_info
FILE * file; /* The file containing the unwind sections. */ FILE * file; /* The file containing the unwind sections. */
Elf_Internal_Sym * symtab; /* The file's symbol table. */ Elf_Internal_Sym * symtab; /* The file's symbol table. */
unsigned long nsyms; /* Number of symbols. */ unsigned long nsyms; /* Number of symbols. */
Elf_Internal_Sym * funtab; /* Sorted table of STT_FUNC symbols. */
unsigned long nfuns; /* Number of these symbols. */
char * strtab; /* The file's 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. */
}; };
@ -7254,7 +7301,7 @@ arm_print_vma_and_name (struct arm_unw_aux_info *aux,
if (addr.section == SHN_UNDEF) if (addr.section == SHN_UNDEF)
addr.offset = fn; addr.offset = fn;
find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, find_symbol_for_address (aux->funtab, aux->nfuns, aux->strtab,
aux->strtab_size, addr, &procname, aux->strtab_size, addr, &procname,
&sym_offset); &sym_offset);
@ -7550,9 +7597,11 @@ decode_tic6x_unwind_regmask (unsigned int mask)
static void static void
decode_arm_unwind_bytecode (struct arm_unw_aux_info * aux, decode_arm_unwind_bytecode (struct arm_unw_aux_info * aux,
unsigned int word, unsigned int remaining, unsigned int word,
unsigned int remaining,
unsigned int more_words, unsigned int more_words,
bfd_vma data_offset, Elf_Internal_Shdr *data_sec, bfd_vma data_offset,
Elf_Internal_Shdr * data_sec,
struct arm_section * data_arm_sec) struct arm_section * data_arm_sec)
{ {
struct absaddr addr; struct absaddr addr;
@ -7761,9 +7810,11 @@ decode_arm_unwind_bytecode (struct arm_unw_aux_info *aux,
static void static void
decode_tic6x_unwind_bytecode (struct arm_unw_aux_info * aux, decode_tic6x_unwind_bytecode (struct arm_unw_aux_info * aux,
unsigned int word, unsigned int remaining, unsigned int word,
unsigned int remaining,
unsigned int more_words, unsigned int more_words,
bfd_vma data_offset, Elf_Internal_Shdr *data_sec, bfd_vma data_offset,
Elf_Internal_Shdr * data_sec,
struct arm_section * data_arm_sec) struct arm_section * data_arm_sec)
{ {
struct absaddr addr; struct absaddr addr;
@ -8077,11 +8128,19 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
{ {
struct arm_section exidx_arm_sec, extab_arm_sec; struct arm_section exidx_arm_sec, extab_arm_sec;
unsigned int i, exidx_len; unsigned int i, exidx_len;
unsigned long j, nfuns;
memset (&exidx_arm_sec, 0, sizeof (exidx_arm_sec)); memset (&exidx_arm_sec, 0, sizeof (exidx_arm_sec));
memset (&extab_arm_sec, 0, sizeof (extab_arm_sec)); memset (&extab_arm_sec, 0, sizeof (extab_arm_sec));
exidx_len = exidx_sec->sh_size / 8; exidx_len = exidx_sec->sh_size / 8;
aux->funtab = xmalloc (aux->nsyms * sizeof (Elf_Internal_Sym));
for (nfuns = 0, j = 0; j < aux->nsyms; j++)
if (aux->symtab[j].st_value && ELF_ST_TYPE (aux->symtab[j].st_info) == STT_FUNC)
aux->funtab[nfuns++] = aux->symtab[j];
aux->nfuns = nfuns;
qsort (aux->funtab, aux->nfuns, sizeof (Elf_Internal_Sym), symcmp);
for (i = 0; i < exidx_len; i++) for (i = 0; i < exidx_len; i++)
{ {
unsigned int exidx_fn, exidx_entry; unsigned int exidx_fn, exidx_entry;
@ -8095,6 +8154,7 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
|| ! get_unwind_section_word (aux, & exidx_arm_sec, exidx_sec, || ! get_unwind_section_word (aux, & exidx_arm_sec, exidx_sec,
8 * i + 4, & exidx_entry, & entry_addr, NULL)) 8 * i + 4, & exidx_entry, & entry_addr, NULL))
{ {
free (aux->funtab);
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;
@ -8158,6 +8218,7 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
printf ("\n"); printf ("\n");
free (aux->funtab);
arm_free_section (&exidx_arm_sec); arm_free_section (&exidx_arm_sec);
arm_free_section (&extab_arm_sec); arm_free_section (&extab_arm_sec);
} }