+2019-11-27  Alan Modra  <amodra@gmail.com>
+
+       PR 23652
+       * dwarf2.c (_bfd_dwarf2_stash_syms): New function.
+       (_bfd_dwarf2_find_nearest_line): Use it here, passing syms to
+       _bfd_elf_find_function.  Call _bfd_elf_find_function in cases
+       where _bfd_elf_find_nearest_line would do so.
+       * elf.c (_bfd_elf_find_nearest_line): Omit _bfd_elf_find_function
+       for dwarf2.
+       * elfxx-mips.c (_bfd_mips_elf_find_nearest_line): Similarly.  Tidy.
+       * elf32-arm.c (elf32_arm_maybe_function_sym): New function.
+       (elf_backend_maybe_function_sym): Define.
+       (arm_elf_find_function, elf32_arm_find_nearest_line): Delete.
+       (bfd_elf32_find_nearest_line): Don't define.
+       * elfnn-aarch64.c (elfNN_aarch64_maybe_function_sym): New function.
+       (elf_backend_maybe_function_sym): Define.
+       (aarch64_elf_find_function, elfNN_aarch64_find_nearest_line): Delete.
+       (bfd_elfNN_find_nearest_line): Don't define.
+
 2019-11-27  Alan Modra  <amodra@gmail.com>
 
        * elf32-sh.c (sh_reloc): Use a bfd_vma insn.
 
     }
 }
 
+/* If the dwarf2 info was found in a separate debug file, return the
+   debug file section corresponding to the section in the original file
+   and the debug file symbols.  */
+
+static void
+_bfd_dwarf2_stash_syms (struct dwarf2_debug *stash, bfd *abfd,
+                       asection **sec, asymbol ***syms)
+{
+  if (stash->bfd_ptr != abfd)
+    {
+      asection *s, *d;
+
+      if (*sec == NULL)
+       {
+         *syms = stash->syms;
+         return;
+       }
+
+      for (s = abfd->sections, d = stash->bfd_ptr->sections;
+          s != NULL && d != NULL;
+          s = s->next, d = d->next)
+       {
+         if ((d->flags & SEC_DEBUGGING) != 0)
+           break;
+         if (s == *sec
+             && strcmp (s->name, d->name) == 0)
+           {
+             *sec = d;
+             *syms = stash->syms;
+           }
+       }
+    }
+}
+
 /* Unset vmas for adjusted sections in STASH.  */
 
 static void
     }
 
  done:
-  if (function)
+  if (functionname_ptr && function && function->is_linkage)
+    *functionname_ptr = function->name;
+  else if (functionname_ptr
+          && ((found && !*functionname_ptr)
+              || (function && !function->is_linkage)))
     {
-      if (!function->is_linkage)
+      asymbol *fun;
+      asymbol **syms = symbols;
+      asection *sec = section;
+
+      if (symbols == NULL || *symbols == NULL)
+       _bfd_dwarf2_stash_syms (stash, abfd, &sec, &syms);
+      fun = _bfd_elf_find_function (abfd, syms, sec, offset,
+                                   *filename_ptr ? NULL : filename_ptr,
+                                   functionname_ptr);
+
+      if (function && !function->is_linkage)
        {
-         asymbol *fun;
          bfd_vma sec_vma;
 
-         fun = _bfd_elf_find_function (abfd, symbols, section, offset,
-                                       *filename_ptr ? NULL : filename_ptr,
-                                       functionname_ptr);
          sec_vma = section->vma;
          if (section->output_section != NULL)
            sec_vma = section->output_section->vma + section->output_offset;
             to stop a repeated search of symbols.  */
          function->is_linkage = TRUE;
        }
-      *functionname_ptr = function->name;
     }
+
   if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
     unset_sections (stash);
 
 
                                     filename_ptr, functionname_ptr,
                                     line_ptr, discriminator_ptr,
                                     dwarf_debug_sections,
-                                    &elf_tdata (abfd)->dwarf2_find_line_info)
-      || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
-                                       filename_ptr, functionname_ptr,
-                                       line_ptr))
+                                    &elf_tdata (abfd)->dwarf2_find_line_info))
+    return TRUE;
+
+  if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+                                    filename_ptr, functionname_ptr, line_ptr))
     {
       if (!*functionname_ptr)
        _bfd_elf_find_function (abfd, symbols, section, offset,
 
                                         BFD_ARM_SPECIAL_SYM_TYPE_ANY);
 }
 
-/* This is a version of _bfd_elf_find_function() from dwarf2.c except that
-   ARM mapping symbols are ignored when looking for function names
-   and STT_ARM_TFUNC is considered to a function type.  */
+/* 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.  */
 
-static bfd_boolean
-arm_elf_find_function (bfd *        abfd,
-                      asymbol **    symbols,
-                      asection *    section,
-                      bfd_vma       offset,
-                      const char ** filename_ptr,
-                      const char ** functionname_ptr)
-{
-  const char * filename = NULL;
-  asymbol * func = NULL;
-  bfd_vma low_func = 0;
-  asymbol ** p;
-
-  if (symbols == NULL)
-    return FALSE;
-
-  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
-    return FALSE;
-
-  for (p = symbols; *p != NULL; p++)
-    {
-      elf_symbol_type *q;
+static bfd_size_type
+elf32_arm_maybe_function_sym (const asymbol *sym, asection *sec,
+                             bfd_vma *code_off)
+{
+  bfd_size_type size;
 
-      q = (elf_symbol_type *) *p;
+  if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+                    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
+      || sym->section != sec)
+    return 0;
 
-      switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
-       {
-       default:
-         break;
-       case STT_FILE:
-         filename = bfd_asymbol_name (&q->symbol);
-         break;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    switch (ELF_ST_TYPE (((elf_symbol_type *) sym)->internal_elf_sym.st_info))
+      {
        case STT_FUNC:
        case STT_ARM_TFUNC:
        case STT_NOTYPE:
-         /* Skip mapping symbols.  */
-         if ((q->symbol.flags & BSF_LOCAL)
-             && bfd_is_arm_special_symbol_name (q->symbol.name,
-                   BFD_ARM_SPECIAL_SYM_TYPE_ANY))
-           continue;
-         /* Fall through.  */
-         if (bfd_asymbol_section (&q->symbol) == section
-             && q->symbol.value >= low_func
-             && q->symbol.value <= offset)
-           {
-             func = (asymbol *) q;
-             low_func = q->symbol.value;
-           }
          break;
-       }
-    }
-
-  if (func == NULL)
-    return FALSE;
-
-  if (filename_ptr)
-    *filename_ptr = filename;
-  if (functionname_ptr)
-    *functionname_ptr = bfd_asymbol_name (func);
-
-  return TRUE;
-}
-
-
-/* Find the nearest line to a particular section and offset, for error
-   reporting.   This code is a duplicate of the code in elf.c, except
-   that it uses arm_elf_find_function.  */
-
-static bfd_boolean
-elf32_arm_find_nearest_line (bfd *         abfd,
-                            asymbol **     symbols,
-                            asection *     section,
-                            bfd_vma        offset,
-                            const char **  filename_ptr,
-                            const char **  functionname_ptr,
-                            unsigned int * line_ptr,
-                            unsigned int * discriminator_ptr)
-{
-  bfd_boolean found = FALSE;
-
-  if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset,
-                                    filename_ptr, functionname_ptr,
-                                    line_ptr, discriminator_ptr,
-                                    dwarf_debug_sections,
-                                    & elf_tdata (abfd)->dwarf2_find_line_info))
-    {
-      if (!*functionname_ptr)
-       arm_elf_find_function (abfd, symbols, section, offset,
-                              *filename_ptr ? NULL : filename_ptr,
-                              functionname_ptr);
-
-      return TRUE;
-    }
-
-  /* Skip _bfd_dwarf1_find_nearest_line since no known ARM toolchain
-     uses DWARF1.  */
-
-  if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
-                                            & found, filename_ptr,
-                                            functionname_ptr, line_ptr,
-                                            & elf_tdata (abfd)->line_info))
-    return FALSE;
-
-  if (found && (*functionname_ptr || *line_ptr))
-    return TRUE;
-
-  if (symbols == NULL)
-    return FALSE;
+       default:
+         return 0;
+      }
 
-  if (! arm_elf_find_function (abfd, symbols, section, offset,
-                              filename_ptr, functionname_ptr))
-    return FALSE;
+  if ((sym->flags & BSF_LOCAL)
+      && bfd_is_arm_special_symbol_name (sym->name,
+                                        BFD_ARM_SPECIAL_SYM_TYPE_ANY))
+    return 0;
 
-  *line_ptr = 0;
-  return TRUE;
+  *code_off = sym->value;
+  size = 0;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+  if (size == 0)
+    size = 1;
+  return size;
 }
 
 static bfd_boolean
 #define bfd_elf32_bfd_link_hash_table_create   elf32_arm_link_hash_table_create
 #define bfd_elf32_bfd_reloc_type_lookup                elf32_arm_reloc_type_lookup
 #define bfd_elf32_bfd_reloc_name_lookup                elf32_arm_reloc_name_lookup
-#define bfd_elf32_find_nearest_line            elf32_arm_find_nearest_line
 #define bfd_elf32_find_inliner_info            elf32_arm_find_inliner_info
 #define bfd_elf32_new_section_hook             elf32_arm_new_section_hook
 #define bfd_elf32_bfd_is_target_special_symbol elf32_arm_is_target_special_symbol
 #define bfd_elf32_get_synthetic_symtab elf32_arm_get_synthetic_symtab
 
 #define elf_backend_get_symbol_type            elf32_arm_get_symbol_type
+#define elf_backend_maybe_function_sym         elf32_arm_maybe_function_sym
 #define elf_backend_gc_mark_hook               elf32_arm_gc_mark_hook
 #define elf_backend_gc_mark_extra_sections     elf32_arm_gc_mark_extra_sections
 #define elf_backend_check_relocs               elf32_arm_check_relocs
 
                                             BFD_AARCH64_SPECIAL_SYM_TYPE_ANY);
 }
 
-/* This is a version of _bfd_elf_find_function() from dwarf2.c except that
-   AArch64 mapping symbols are ignored when looking for function names.  */
+/* 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.  */
 
-static bfd_boolean
-aarch64_elf_find_function (bfd *          abfd,
-                          asymbol **     symbols,
-                          asection *     section,
-                          bfd_vma        offset,
-                          const char **  filename_ptr,
-                          const char **  functionname_ptr)
-{
-  const char *filename = NULL;
-  asymbol *func = NULL;
-  bfd_vma low_func = 0;
-  asymbol **p;
-
-  if (symbols == NULL)
-    return FALSE;
-
-  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
-    return FALSE;
-
-  for (p = symbols; *p != NULL; p++)
-    {
-      elf_symbol_type *q;
+static bfd_size_type
+elfNN_aarch64_maybe_function_sym (const asymbol *sym, asection *sec,
+                                 bfd_vma *code_off)
+{
+  bfd_size_type size;
 
-      q = (elf_symbol_type *) * p;
+  if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+                    | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0
+      || sym->section != sec)
+    return 0;
 
-      switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
-       {
-       default:
-         break;
-       case STT_FILE:
-         filename = bfd_asymbol_name (&q->symbol);
-         break;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    switch (ELF_ST_TYPE (((elf_symbol_type *) sym)->internal_elf_sym.st_info))
+      {
        case STT_FUNC:
        case STT_NOTYPE:
-         /* Skip mapping symbols.  */
-         if ((q->symbol.flags & BSF_LOCAL)
-             && (bfd_is_aarch64_special_symbol_name
-                 (q->symbol.name, BFD_AARCH64_SPECIAL_SYM_TYPE_ANY)))
-           continue;
-         /* Fall through.  */
-         if (bfd_asymbol_section (&q->symbol) == section
-             && q->symbol.value >= low_func && q->symbol.value <= offset)
-           {
-             func = (asymbol *) q;
-             low_func = q->symbol.value;
-           }
          break;
-       }
-    }
-
-  if (func == NULL)
-    return FALSE;
-
-  if (filename_ptr)
-    *filename_ptr = filename;
-  if (functionname_ptr)
-    *functionname_ptr = bfd_asymbol_name (func);
-
-  return TRUE;
-}
-
-
-/* Find the nearest line to a particular section and offset, for error
-   reporting.   This code is a duplicate of the code in elf.c, except
-   that it uses aarch64_elf_find_function.  */
-
-static bfd_boolean
-elfNN_aarch64_find_nearest_line (bfd *abfd,
-                                asymbol **symbols,
-                                asection *section,
-                                bfd_vma offset,
-                                const char **filename_ptr,
-                                const char **functionname_ptr,
-                                unsigned int *line_ptr,
-                                unsigned int *discriminator_ptr)
-{
-  bfd_boolean found = FALSE;
-
-  if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset,
-                                    filename_ptr, functionname_ptr,
-                                    line_ptr, discriminator_ptr,
-                                    dwarf_debug_sections,
-                                    &elf_tdata (abfd)->dwarf2_find_line_info))
-    {
-      if (!*functionname_ptr)
-       aarch64_elf_find_function (abfd, symbols, section, offset,
-                                  *filename_ptr ? NULL : filename_ptr,
-                                  functionname_ptr);
-
-      return TRUE;
-    }
-
-  /* Skip _bfd_dwarf1_find_nearest_line since no known AArch64
-     toolchain uses DWARF1.  */
-
-  if (!_bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
-                                           &found, filename_ptr,
-                                           functionname_ptr, line_ptr,
-                                           &elf_tdata (abfd)->line_info))
-    return FALSE;
-
-  if (found && (*functionname_ptr || *line_ptr))
-    return TRUE;
-
-  if (symbols == NULL)
-    return FALSE;
+       default:
+         return 0;
+      }
 
-  if (!aarch64_elf_find_function (abfd, symbols, section, offset,
-                                 filename_ptr, functionname_ptr))
-    return FALSE;
+  if ((sym->flags & BSF_LOCAL)
+      && bfd_is_aarch64_special_symbol_name (sym->name,
+                                            BFD_AARCH64_SPECIAL_SYM_TYPE_ANY))
+    return 0;
 
-  *line_ptr = 0;
-  return TRUE;
+  *code_off = sym->value;
+  size = 0;
+  if (!(sym->flags & BSF_SYNTHETIC))
+    size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+  if (size == 0)
+    size = 1;
+  return size;
 }
 
 static bfd_boolean
 #define bfd_elfNN_find_inliner_info            \
   elfNN_aarch64_find_inliner_info
 
-#define bfd_elfNN_find_nearest_line            \
-  elfNN_aarch64_find_nearest_line
-
 #define bfd_elfNN_get_synthetic_symtab         \
   elfNN_aarch64_get_synthetic_symtab
 
 #define elf_backend_output_arch_local_syms     \
   elfNN_aarch64_output_arch_local_syms
 
+#define elf_backend_maybe_function_sym         \
+  elfNN_aarch64_maybe_function_sym
+
 #define elf_backend_plt_sym_val                        \
   elfNN_aarch64_plt_sym_val
 
 
                                     filename_ptr, functionname_ptr,
                                     line_ptr, discriminator_ptr,
                                     dwarf_debug_sections,
-                                    &elf_tdata (abfd)->dwarf2_find_line_info)
-      || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
-                                       filename_ptr, functionname_ptr,
-                                       line_ptr))
-    {
-      /* PR 22789: If the function name or filename was not found through
-        the debug information, then try an ordinary lookup instead.  */
-      if ((functionname_ptr != NULL && *functionname_ptr == NULL)
-         || (filename_ptr != NULL && *filename_ptr == NULL))
-       {
-         /* Do not override already discovered names.  */
-         if (functionname_ptr != NULL && *functionname_ptr != NULL)
-           functionname_ptr = NULL;
-
-         if (filename_ptr != NULL && *filename_ptr != NULL)
-           filename_ptr = NULL;
-
-         _bfd_elf_find_function (abfd, symbols, section, offset,
-                                 filename_ptr, functionname_ptr);
-       }
+                                    &elf_tdata (abfd)->dwarf2_find_line_info))
+    return TRUE;
 
+  if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+                                    filename_ptr, functionname_ptr,
+                                    line_ptr))
+    {
+      if (!*functionname_ptr)
+       _bfd_elf_find_function (abfd, symbols, section, offset,
+                               *filename_ptr ? NULL : filename_ptr,
+                               functionname_ptr);
       return TRUE;
     }