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>
* objdump.c (dump_section): Extend the warning message displayed

View File

@ -6439,10 +6439,6 @@ process_relocs (FILE * file)
return 1;
}
/* Process the unwind section. */
#include "unwind-ia64.h"
/* An absolute address consists of a section and an offset. If the
section is NULL, the offset itself is the address, otherwise, the
address equals to LOAD_ADDRESS(section) + offset. */
@ -6458,27 +6454,8 @@ struct absaddr
? section_headers [(a).section].sh_addr + (a).offset \
: (a).offset)
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. */
char * strtab; /* The string table. */
unsigned long strtab_size; /* Size of string table. */
};
/* Find the nearest symbol at or below ADDR. Returns the symbol
name, if found, and the offset from the symbol to ADDR. */
static void
find_symbol_for_address (Elf_Internal_Sym * symtab,
@ -6491,19 +6468,24 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
{
bfd_vma dist = 0x100000;
Elf_Internal_Sym * sym;
Elf_Internal_Sym * beg;
Elf_Internal_Sym * end;
Elf_Internal_Sym * best = NULL;
unsigned long i;
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);
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC
&& sym->st_name != 0
if (sym->st_name != 0
&& (addr.section == SHN_UNDEF || addr.section == sym->st_shndx)
&& addr.offset >= value
&& addr.offset - value < dist)
@ -6513,6 +6495,11 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
if (!dist)
break;
}
if (addr.offset < value)
end = sym;
else
beg = sym + 1;
}
if (best)
@ -6527,12 +6514,56 @@ find_symbol_for_address (Elf_Internal_Sym * symtab,
*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
dump_ia64_unwind (struct ia64_unw_aux_info * aux)
{
struct ia64_unw_table_entry * tp;
unsigned long j, nfuns;
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)
{
bfd_vma stamp;
@ -6542,7 +6573,7 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux)
const unsigned char * end;
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);
fputs ("\n<", stdout);
@ -6598,6 +6629,8 @@ dump_ia64_unwind (struct ia64_unw_aux_info * aux)
for (dp = head + 8; dp < end;)
dp = unw_decode (dp, in_body, & in_body);
}
free (aux->funtab);
}
static bfd_boolean
@ -6936,6 +6969,8 @@ struct hppa_unw_aux_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. */
};
@ -6944,13 +6979,21 @@ static void
dump_hppa_unwind (struct hppa_unw_aux_info * aux)
{
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)
{
bfd_vma offset;
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);
@ -7004,6 +7047,8 @@ dump_hppa_unwind (struct hppa_unw_aux_info * aux)
}
printf ("\n");
free (aux->funtab);
}
static int
@ -7240,6 +7285,8 @@ struct arm_unw_aux_info
FILE * file; /* The file containing the unwind sections. */
Elf_Internal_Sym * symtab; /* The file's symbol table. */
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. */
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)
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,
&sym_offset);
@ -7550,9 +7597,11 @@ decode_tic6x_unwind_regmask (unsigned int mask)
static void
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,
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 absaddr addr;
@ -7761,9 +7810,11 @@ decode_arm_unwind_bytecode (struct arm_unw_aux_info *aux,
static void
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,
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 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;
unsigned int i, exidx_len;
unsigned long j, nfuns;
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;
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++)
{
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,
8 * i + 4, & exidx_entry, & entry_addr, NULL))
{
free (aux->funtab);
arm_free_section (& exidx_arm_sec);
arm_free_section (& extab_arm_sec);
return;
@ -8158,6 +8218,7 @@ dump_arm_unwind (struct arm_unw_aux_info *aux, Elf_Internal_Shdr *exidx_sec)
printf ("\n");
free (aux->funtab);
arm_free_section (&exidx_arm_sec);
arm_free_section (&extab_arm_sec);
}