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;
|
*function_ptr = NULL;
|
||||||
func_p = lookup_address_in_function_table (unit, addr, function_ptr);
|
func_p = lookup_address_in_function_table (unit, addr, function_ptr);
|
||||||
|
|
||||||
if (func_p && (*function_ptr)->tag == DW_TAG_inlined_subroutine)
|
if (func_p && (*function_ptr)->tag == DW_TAG_inlined_subroutine)
|
||||||
unit->stash->inliner_chain = *function_ptr;
|
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);
|
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,
|
/* Find the function to a particular section and offset,
|
||||||
for error reporting. */
|
for error reporting. */
|
||||||
|
|
||||||
@ -6145,21 +6200,14 @@ _bfd_elf_find_function (bfd *abfd,
|
|||||||
const char **filename_ptr,
|
const char **filename_ptr,
|
||||||
const char **functionname_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)
|
if (symbols == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
|
if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
|
||||||
return NULL;
|
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)
|
if (cache == NULL)
|
||||||
{
|
{
|
||||||
cache = bfd_zalloc (abfd, sizeof (*cache));
|
cache = bfd_zalloc (abfd, sizeof (*cache));
|
||||||
@ -6167,13 +6215,13 @@ _bfd_elf_find_function (bfd *abfd,
|
|||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cache->last_section != section
|
if (cache->last_section != section
|
||||||
|| cache->func == NULL
|
|| cache->func == NULL
|
||||||
|| offset < cache->func->value
|
|| offset < cache->func->value
|
||||||
|| offset >= cache->func->value + cache->func_size)
|
|| offset >= cache->func->value + cache->code_size)
|
||||||
{
|
{
|
||||||
asymbol *file;
|
asymbol *file;
|
||||||
bfd_vma low_func;
|
|
||||||
asymbol **p;
|
asymbol **p;
|
||||||
/* ??? Given multiple file symbols, it is impossible to reliably
|
/* ??? Given multiple file symbols, it is impossible to reliably
|
||||||
choose the right file name for global symbols. File symbols are
|
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);
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
||||||
|
|
||||||
file = NULL;
|
file = NULL;
|
||||||
low_func = 0;
|
|
||||||
state = nothing_seen;
|
state = nothing_seen;
|
||||||
cache->filename = NULL;
|
cache->filename = NULL;
|
||||||
cache->func = NULL;
|
cache->func = NULL;
|
||||||
cache->func_size = 0;
|
cache->code_size = 0;
|
||||||
|
cache->code_off = 0;
|
||||||
cache->last_section = section;
|
cache->last_section = section;
|
||||||
|
|
||||||
for (p = symbols; *p != NULL; p++)
|
for (p = symbols; *p != NULL; p++)
|
||||||
@ -6208,24 +6256,36 @@ _bfd_elf_find_function (bfd *abfd,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state == nothing_seen)
|
||||||
|
state = symbol_seen;
|
||||||
|
|
||||||
size = bed->maybe_function_sym (sym, section, &code_off);
|
size = bed->maybe_function_sym (sym, section, &code_off);
|
||||||
if (size != 0
|
|
||||||
&& code_off <= offset
|
if (size == 0)
|
||||||
&& (code_off > low_func
|
continue;
|
||||||
|| (code_off == low_func
|
|
||||||
&& size > cache->func_size)))
|
if (better_fit (cache, code_off, size, offset))
|
||||||
{
|
{
|
||||||
cache->func = sym;
|
cache->func = sym;
|
||||||
cache->func_size = size;
|
cache->code_size = size;
|
||||||
|
cache->code_off = code_off;
|
||||||
cache->filename = NULL;
|
cache->filename = NULL;
|
||||||
low_func = code_off;
|
|
||||||
if (file != NULL
|
if (file != NULL
|
||||||
&& ((sym->flags & BSF_LOCAL) != 0
|
&& ((sym->flags & BSF_LOCAL) != 0
|
||||||
|| state != file_after_symbol_seen))
|
|| state != file_after_symbol_seen))
|
||||||
cache->filename = bfd_asymbol_name (file);
|
cache->filename = bfd_asymbol_name (file);
|
||||||
}
|
}
|
||||||
if (state == nothing_seen)
|
/* Otherwise, if the symbol is beyond the desired offset but it
|
||||||
state = symbol_seen;
|
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