Fix N^2 behavior in _bfd_dwarf2_find_symbol_bias

A customer reported a case where addr2line was very slow.  We tracked
this down to some N^2 behavior in _bfd_dwarf2_find_symbol_bias in the
unusual case where no function can be found.

This patch fixes the bug, and reduces the runtime for a particular
request from 127 seconds to 1 second.

bfd/ChangeLog
2019-08-19  Tom Tromey  <tromey@adacore.com>

	* dwarf2.c (_bfd_dwarf2_find_symbol_bias): Create hash table
	holding symbols.
This commit is contained in:
Tom Tromey 2019-08-15 07:33:20 -06:00
parent d292364e95
commit 3eb185c97d
2 changed files with 51 additions and 10 deletions

View File

@ -1,3 +1,8 @@
2019-08-19 Tom Tromey <tromey@adacore.com>
* dwarf2.c (_bfd_dwarf2_find_symbol_bias): Create hash table
holding symbols.
2019-08-19 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (struct ppc64_elf_obj_tdata): Rename has_gotrel

View File

@ -35,6 +35,7 @@
#include "libbfd.h"
#include "elf-bfd.h"
#include "dwarf2.h"
#include "hashtab.h"
/* The data in the .debug_line statement prologue looks like this. */
@ -4552,6 +4553,25 @@ stash_comp_unit (struct dwarf2_debug *stash)
return NULL;
}
/* Hash function for an asymbol. */
static hashval_t
hash_asymbol (const void *sym)
{
const asymbol *asym = sym;
return htab_hash_string (asym->name);
}
/* Equality function for asymbols. */
static int
eq_asymbol (const void *a, const void *b)
{
const asymbol *sa = a;
const asymbol *sb = b;
return strcmp (sa->name, sb->name) == 0;
}
/* Scan the debug information in PINFO looking for a DW_TAG_subprogram
abbrev with a DW_AT_low_pc attached to it. Then lookup that same
symbol in SYMBOLS and return the difference between the low_pc and
@ -4562,12 +4582,28 @@ _bfd_dwarf2_find_symbol_bias (asymbol ** symbols, void ** pinfo)
{
struct dwarf2_debug *stash;
struct comp_unit * unit;
htab_t sym_hash;
bfd_signed_vma result = 0;
asymbol ** psym;
stash = (struct dwarf2_debug *) *pinfo;
if (stash == NULL || symbols == NULL)
return 0;
sym_hash = htab_create_alloc (10, hash_asymbol, eq_asymbol,
NULL, xcalloc, free);
for (psym = symbols; * psym != NULL; psym++)
{
asymbol * sym = * psym;
if (sym->flags & BSF_FUNCTION && sym->section != NULL)
{
void **slot = htab_find_slot (sym_hash, sym, INSERT);
*slot = sym;
}
}
for (unit = stash->all_comp_units; unit; unit = unit->next_unit)
{
struct funcinfo * func;
@ -4577,24 +4613,24 @@ _bfd_dwarf2_find_symbol_bias (asymbol ** symbols, void ** pinfo)
for (func = unit->function_table; func != NULL; func = func->prev_func)
if (func->name && func->arange.low)
{
asymbol ** psym;
asymbol search, *sym;
/* FIXME: Do we need to scan the aranges looking for the lowest pc value ? */
for (psym = symbols; * psym != NULL; psym++)
search.name = func->name;
sym = htab_find (sym_hash, &search);
if (sym != NULL)
{
asymbol * sym = * psym;
if (sym->flags & BSF_FUNCTION
&& sym->section != NULL
&& strcmp (sym->name, func->name) == 0)
return ((bfd_signed_vma) func->arange.low) -
((bfd_signed_vma) (sym->value + sym->section->vma));
result = ((bfd_signed_vma) func->arange.low) -
((bfd_signed_vma) (sym->value + sym->section->vma));
goto done;
}
}
}
return 0;
done:
htab_delete (sym_hash);
return result;
}
/* Find the source code location of SYMBOL. If SYMBOL is NULL