PR binutils/13897
[deliverable/binutils-gdb.git] / bfd / elf.c
index 7a06fb4a746ae3da5819c173ab4da2d25faa034b..ac7be2c5ec135fcafd1fb76ccb98eee4616b99f5 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -7407,59 +7407,74 @@ elf_find_function (bfd *abfd,
                   const char **filename_ptr,
                   const char **functionname_ptr)
 {
-  const char *filename;
-  asymbol *func, *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
-     local symbols, and thus all file symbols must sort before any
-     global symbols.  The ELF spec may be interpreted to say that a
-     file symbol must sort before other local symbols, but currently
-     ld -r doesn't do this.  So, for ld -r output, it is possible to
-     make a better choice of file name for local symbols by ignoring
-     file symbols appearing after a given local symbol.  */
-  enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+  static asection *last_section;
+  static asymbol *func;
+  static const char *filename;
+  static bfd_size_type func_size;
 
   if (symbols == NULL)
     return FALSE;
 
-  filename = NULL;
-  func = NULL;
-  file = NULL;
-  low_func = 0;
-  state = nothing_seen;
-
-  for (p = symbols; *p != NULL; p++)
-    {
-      asymbol *sym = *p;
-      asection *code_sec;
-      bfd_vma code_off;
-
-      if ((sym->flags & BSF_FILE) != 0)
-       {
-         file = sym;
-         if (state == symbol_seen)
-           state = file_after_symbol_seen;
-         continue;
-       }
+  if (last_section != section
+      || func == NULL
+      || offset < func->value
+      || offset >= func->value + func_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
+        local symbols, and thus all file symbols must sort before any
+        global symbols.  The ELF spec may be interpreted to say that a
+        file symbol must sort before other local symbols, but currently
+        ld -r doesn't do this.  So, for ld -r output, it is possible to
+        make a better choice of file name for local symbols by ignoring
+        file symbols appearing after a given local symbol.  */
+      enum { nothing_seen, symbol_seen, file_after_symbol_seen } state;
+      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+      filename = NULL;
+      func = NULL;
+      file = NULL;
+      low_func = 0;
+      state = nothing_seen;
+      func_size = 0;
+      last_section = section;
+
+      for (p = symbols; *p != NULL; p++)
+       {
+         asymbol *sym = *p;
+         bfd_vma code_off;
+         bfd_size_type size;
+
+         if ((sym->flags & BSF_FILE) != 0)
+           {
+             file = sym;
+             if (state == symbol_seen)
+               state = file_after_symbol_seen;
+             continue;
+           }
 
-      if (bed->maybe_function_sym (sym, &code_sec, &code_off)
-         && code_sec == section
-         && code_off >= low_func
-         && code_off <= offset)
-       {
-         func = sym;
-         low_func = code_off;
-         filename = NULL;
-         if (file != NULL
-             && ((sym->flags & BSF_LOCAL) != 0
-                 || state != file_after_symbol_seen))
-           filename = bfd_asymbol_name (file);
+         size = bed->maybe_function_sym (sym, section, &code_off);
+         if (size != 0
+             && code_off <= offset
+             && (code_off > low_func
+                 || (code_off == low_func
+                     && size > func_size)))
+           {
+             func = sym;
+             func_size = size;
+             low_func = code_off;
+             filename = NULL;
+             if (file != NULL
+                 && ((sym->flags & BSF_LOCAL) != 0
+                     || state != file_after_symbol_seen))
+               filename = bfd_asymbol_name (file);
+           }
+         if (state == nothing_seen)
+           state = symbol_seen;
        }
-      if (state == nothing_seen)
-       state = symbol_seen;
     }
 
   if (func == NULL)
@@ -9714,18 +9729,26 @@ _bfd_elf_is_function_type (unsigned int type)
          || type == STT_GNU_IFUNC);
 }
 
-/* Return TRUE iff the ELF symbol SYM might be a function.  Set *CODE_SEC
-   and *CODE_OFF to the function's entry point.  */
+/* If the ELF symbol SYM might be a function in SEC, return the
+   function size and set *CODE_OFF to the function's entry point,
+   otherwise return zero.  */
 
-bfd_boolean
-_bfd_elf_maybe_function_sym (const asymbol *sym,
-                            asection **code_sec, bfd_vma *code_off)
+bfd_size_type
+_bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+                            bfd_vma *code_off)
 {
+  bfd_size_type size;
+
   if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
-                    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
-    return FALSE;
+                    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
+      || sym->section != sec)
+    return 0;
 
-  *code_sec = sym->section;
   *code_off = sym->value;
-  return TRUE;
+  size = 0;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+  if (size == 0)
+    size = 1;
+  return size;
 }
This page took 0.030768 seconds and 4 git commands to generate.