mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-27 22:48:57 +08:00
Fix _bfd_elf_find_function so that it can cope with overlapping symbols
This commit is contained in:
104
bfd/dwarf2.c
104
bfd/dwarf2.c
@ -4681,6 +4681,7 @@ comp_unit_find_nearest_line (struct comp_unit *unit,
|
||||
|
||||
*function_ptr = NULL;
|
||||
func_p = lookup_address_in_function_table (unit, addr, function_ptr);
|
||||
|
||||
if (func_p && (*function_ptr)->tag == DW_TAG_inlined_subroutine)
|
||||
unit->stash->inliner_chain = *function_ptr;
|
||||
|
||||
@ -6134,6 +6135,60 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo)
|
||||
bfd_close (stash->alt.bfd_ptr);
|
||||
}
|
||||
|
||||
typedef struct elf_find_function_cache
|
||||
{
|
||||
asection * last_section;
|
||||
asymbol * func;
|
||||
const char * filename;
|
||||
bfd_size_type code_size;
|
||||
bfd_vma code_off;
|
||||
|
||||
} elf_find_function_cache;
|
||||
|
||||
|
||||
/* Returns TRUE if the symbol with address CODE_OFF and size CODE_SIZE
|
||||
is a better fit to match OFFSET than whatever is currenly stored in
|
||||
CACHE. */
|
||||
|
||||
static inline bool
|
||||
better_fit (elf_find_function_cache * cache,
|
||||
bfd_vma code_off,
|
||||
bfd_size_type code_size,
|
||||
bfd_vma offset)
|
||||
{
|
||||
/* If the symbol is beyond the desired offset, ignore it. */
|
||||
if (code_off > offset)
|
||||
return false;
|
||||
|
||||
/* If the symbol is further away from the desired
|
||||
offset than our current best, then ignore it. */
|
||||
if (code_off < cache->code_off)
|
||||
return false;
|
||||
|
||||
/* On the other hand, if it is closer, then use it. */
|
||||
if (code_off > cache->code_off)
|
||||
return true;
|
||||
|
||||
/* If our current best fit does not actually reach the desired
|
||||
offset... */
|
||||
if (cache->code_off + cache->code_size <= offset)
|
||||
{
|
||||
/* Then return whichever candidate covers more area. */
|
||||
return code_size > cache->code_size;
|
||||
}
|
||||
|
||||
/* If the new symbol also covers the desired offset... */
|
||||
if (code_off + code_size > offset)
|
||||
{
|
||||
/* Then choose whichever is smaller. */
|
||||
/* FIXME: Maybe prefer LOCAL over GLOBAL or something else here ? */
|
||||
return code_size < cache->code_size;
|
||||
}
|
||||
|
||||
/* Otherwise the cached symbol is better. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Find the function to a particular section and offset,
|
||||
for error reporting. */
|
||||
|
||||
@ -6145,21 +6200,14 @@ _bfd_elf_find_function (bfd *abfd,
|
||||
const char **filename_ptr,
|
||||
const char **functionname_ptr)
|
||||
{
|
||||
struct elf_find_function_cache
|
||||
{
|
||||
asection *last_section;
|
||||
asymbol *func;
|
||||
const char *filename;
|
||||
bfd_size_type func_size;
|
||||
} *cache;
|
||||
|
||||
if (symbols == NULL)
|
||||
return NULL;
|
||||
|
||||
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
|
||||
return NULL;
|
||||
|
||||
cache = elf_tdata (abfd)->elf_find_function_cache;
|
||||
elf_find_function_cache * cache = elf_tdata (abfd)->elf_find_function_cache;
|
||||
|
||||
if (cache == NULL)
|
||||
{
|
||||
cache = bfd_zalloc (abfd, sizeof (*cache));
|
||||
@ -6167,13 +6215,13 @@ _bfd_elf_find_function (bfd *abfd,
|
||||
if (cache == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cache->last_section != section
|
||||
|| cache->func == NULL
|
||||
|| offset < cache->func->value
|
||||
|| offset >= cache->func->value + cache->func_size)
|
||||
|| offset >= cache->func->value + cache->code_size)
|
||||
{
|
||||
asymbol *file;
|
||||
bfd_vma low_func;
|
||||
asymbol **p;
|
||||
/* ??? Given multiple file symbols, it is impossible to reliably
|
||||
choose the right file name for global symbols. File symbols are
|
||||
@ -6187,11 +6235,11 @@ _bfd_elf_find_function (bfd *abfd,
|
||||
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
||||
|
||||
file = NULL;
|
||||
low_func = 0;
|
||||
state = nothing_seen;
|
||||
cache->filename = NULL;
|
||||
cache->func = NULL;
|
||||
cache->func_size = 0;
|
||||
cache->code_size = 0;
|
||||
cache->code_off = 0;
|
||||
cache->last_section = section;
|
||||
|
||||
for (p = symbols; *p != NULL; p++)
|
||||
@ -6208,24 +6256,36 @@ _bfd_elf_find_function (bfd *abfd,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state == nothing_seen)
|
||||
state = symbol_seen;
|
||||
|
||||
size = bed->maybe_function_sym (sym, section, &code_off);
|
||||
if (size != 0
|
||||
&& code_off <= offset
|
||||
&& (code_off > low_func
|
||||
|| (code_off == low_func
|
||||
&& size > cache->func_size)))
|
||||
|
||||
if (size == 0)
|
||||
continue;
|
||||
|
||||
if (better_fit (cache, code_off, size, offset))
|
||||
{
|
||||
cache->func = sym;
|
||||
cache->func_size = size;
|
||||
cache->code_size = size;
|
||||
cache->code_off = code_off;
|
||||
cache->filename = NULL;
|
||||
low_func = code_off;
|
||||
|
||||
if (file != NULL
|
||||
&& ((sym->flags & BSF_LOCAL) != 0
|
||||
|| state != file_after_symbol_seen))
|
||||
cache->filename = bfd_asymbol_name (file);
|
||||
}
|
||||
if (state == nothing_seen)
|
||||
state = symbol_seen;
|
||||
/* Otherwise, if the symbol is beyond the desired offset but it
|
||||
lies within the bounds of the current best match then reduce
|
||||
the size of the current best match so that future searches
|
||||
will not not used the cached symbol by mistake. */
|
||||
else if (code_off > offset
|
||||
&& code_off > cache->code_off
|
||||
&& code_off < cache->code_off + cache->code_size)
|
||||
{
|
||||
cache->code_size = code_off - cache->code_off;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user