]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/dwarf2.c
Fix the BFD library's find_nearest_line feature to produce consistent results.
[thirdparty/binutils-gdb.git] / bfd / dwarf2.c
index 4761878851362abd6d843fa6122f2d4136ac2593..8c9bd7a3026dc7c583fbb8bc7079505b24759b86 100644 (file)
@@ -1,5 +1,5 @@
 /* DWARF 2 support.
-   Copyright (C) 1994-2022 Free Software Foundation, Inc.
+   Copyright (C) 1994-2023 Free Software Foundation, Inc.
 
    Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions
    (gavin@cygnus.com).
 #include "sysdep.h"
 #include "bfd.h"
 #include "libiberty.h"
+#include "demangle.h"
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "dwarf2.h"
 #include "hashtab.h"
+#include "splay-tree.h"
 
 /* The data in the .debug_line statement prologue looks like this.  */
 
@@ -80,6 +82,7 @@ struct adjusted_section
 {
   asection *section;
   bfd_vma adj_vma;
+  bfd_vma orig_vma;
 };
 
 /* A trie to map quickly from address range to compilation unit.
@@ -152,6 +155,45 @@ static struct trie_node *alloc_trie_leaf (bfd *abfd)
   return &leaf->head;
 }
 
+struct addr_range
+{
+  bfd_byte *start;
+  bfd_byte *end;
+};
+
+/* Return true if address range do intersect.  */
+
+static bool
+addr_range_intersects (struct addr_range *r1, struct addr_range *r2)
+{
+  return (r1->start <= r2->start && r2->start < r1->end)
+    || (r1->start <= (r2->end - 1) && (r2->end - 1) < r1->end);
+}
+
+/* Compare function for splay tree of addr_ranges.  */
+
+static int
+splay_tree_compare_addr_range (splay_tree_key xa, splay_tree_key xb)
+{
+  struct addr_range *r1 = (struct addr_range *) xa;
+  struct addr_range *r2 = (struct addr_range *) xb;
+
+  if (addr_range_intersects (r1, r2) || addr_range_intersects (r2, r1))
+    return 0;
+  else if (r1->end <= r2->start)
+    return -1;
+  else
+    return 1;
+}
+
+/* Splay tree release function for keys (addr_range).  */
+
+static void
+splay_tree_free_addr_range (splay_tree_key key)
+{
+  free ((struct addr_range *)key);
+}
+
 struct dwarf2_debug_file
 {
   /* The actual bfd from which debug info was loaded.  Might be
@@ -235,6 +277,9 @@ struct dwarf2_debug_file
 
   /* Root of a trie to map addresses to compilation units.  */
   struct trie_node *trie_root;
+
+  /* Splay tree to map info_ptr address to compilation units.  */
+  splay_tree comp_unit_tree;
 };
 
 struct dwarf2_debug
@@ -646,7 +691,6 @@ read_section (bfd *abfd,
     {
       bfd_size_type amt;
       asection *msec;
-      ufile_ptr filesize;
 
       msec = bfd_get_section_by_name (abfd, section_name);
       if (msec == NULL)
@@ -662,20 +706,22 @@ read_section (bfd *abfd,
          return false;
        }
 
-      amt = bfd_get_section_limit_octets (abfd, msec);
-      filesize = bfd_get_file_size (abfd);
-      /* PR 28834: A compressed debug section could well decompress to a size
-        larger than the file, so we choose an arbitrary modifier of 10x in
-        the test below.  If this ever turns out to be insufficient, it can
-        be changed by a future update.  */
-      if (amt >= filesize * 10)
+      if ((msec->flags & SEC_HAS_CONTENTS) == 0)
+       {
+         _bfd_error_handler (_("DWARF error: section %s has no contents"),
+                             section_name);
+         bfd_set_error (bfd_error_no_contents);
+         return false;
+       }
+
+      if (_bfd_section_size_insane (abfd, msec))
        {
          /* PR 26946 */
-         _bfd_error_handler (_("DWARF error: section %s is larger than 10x its filesize! (0x%lx vs 0x%lx)"),
-                             section_name, (long) amt, (long) filesize);
-         bfd_set_error (bfd_error_bad_value);
+         _bfd_error_handler (_("DWARF error: section %s is too big"),
+                             section_name);
          return false;
        }
+      amt = bfd_get_section_limit_octets (abfd, msec);
       *section_size = amt;
       /* Paranoia - alloc one extra so that we can make sure a string
         section is NUL terminated.  */
@@ -1369,20 +1415,20 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit)
                     &file->dwarf_addr_buffer, &file->dwarf_addr_size))
     return 0;
 
-  if (_bfd_mul_overflow (idx, unit->offset_size, &offset))
+  if (_bfd_mul_overflow (idx, unit->addr_size, &offset))
     return 0;
 
   offset += unit->dwarf_addr_offset;
   if (offset < unit->dwarf_addr_offset
       || offset > file->dwarf_addr_size
-      || file->dwarf_addr_size - offset < unit->offset_size)
+      || file->dwarf_addr_size - offset < unit->addr_size)
     return 0;
 
   info_ptr = file->dwarf_addr_buffer + offset;
 
-  if (unit->offset_size == 4)
+  if (unit->addr_size == 4)
     return bfd_get_32 (unit->abfd, info_ptr);
-  else if (unit->offset_size == 8)
+  else if (unit->addr_size == 8)
     return bfd_get_64 (unit->abfd, info_ptr);
   else
     return 0;
@@ -1668,31 +1714,52 @@ read_attribute (struct attribute *    attr,
   return info_ptr;
 }
 
-/* Return whether DW_AT_name will return the same as DW_AT_linkage_name
-   for a function.  */
+/* Return mangling style given LANG.  */
 
-static bool
-non_mangled (int lang)
+static int
+mangle_style (int lang)
 {
   switch (lang)
     {
+    case DW_LANG_Ada83:
+    case DW_LANG_Ada95:
+      return DMGL_GNAT;
+
+    case DW_LANG_C_plus_plus:
+    case DW_LANG_C_plus_plus_03:
+    case DW_LANG_C_plus_plus_11:
+    case DW_LANG_C_plus_plus_14:
+      return DMGL_GNU_V3;
+
+    case DW_LANG_Java:
+      return DMGL_JAVA;
+
+    case DW_LANG_D:
+      return DMGL_DLANG;
+
+    case DW_LANG_Rust:
+    case DW_LANG_Rust_old:
+      return DMGL_RUST;
+
     default:
-      return false;
+      return DMGL_AUTO;
 
     case DW_LANG_C89:
     case DW_LANG_C:
-    case DW_LANG_Ada83:
     case DW_LANG_Cobol74:
     case DW_LANG_Cobol85:
     case DW_LANG_Fortran77:
     case DW_LANG_Pascal83:
-    case DW_LANG_C99:
-    case DW_LANG_Ada95:
     case DW_LANG_PLI:
+    case DW_LANG_C99:
     case DW_LANG_UPC:
     case DW_LANG_C11:
     case DW_LANG_Mips_Assembler:
-      return true;
+    case DW_LANG_Upc:
+    case DW_LANG_HP_Basic91:
+    case DW_LANG_HP_IMacro:
+    case DW_LANG_HP_Assembler:
+      return 0;
     }
 }
 
@@ -1736,6 +1803,7 @@ struct line_info_table
   unsigned int         num_files;
   unsigned int         num_dirs;
   unsigned int         num_sequences;
+  bool                  use_dir_and_file_0;
   char *               comp_dir;
   char **              dirs;
   struct fileinfo*     files;
@@ -1766,8 +1834,6 @@ struct funcinfo
   bool is_linkage;
   const char *name;
   struct arange arange;
-  /* Where the symbol is defined.  */
-  asection *sec;
   /* The offset of the funcinfo from the start of the unit.  */
   uint64_t unit_offset;
 };
@@ -1801,11 +1867,9 @@ struct varinfo
   /* The type of this variable.  */
   int tag;
   /* The name of the variable, if it has one.  */
-  char *name;
+  const char *name;
   /* The address of the variable.  */
   bfd_vma addr;
-  /* Where the symbol is defined.  */
-  asection *sec;
   /* Is this a stack variable?  */
   bool stack;
 };
@@ -1956,16 +2020,30 @@ concat_filename (struct line_info_table *table, unsigned int file)
 {
   char *filename;
 
-  if (table == NULL || file - 1 >= table->num_files)
+  /* Pre DWARF-5 entry 0 in the directory and filename tables was not used.
+     So in order to save space in the tables used here the info for, eg
+     directory 1 is stored in slot 0 of the directory table, directory 2
+     in slot 1 and so on.
+
+     Starting with DWARF-5 the 0'th entry is used so there is a one to one
+     mapping between DWARF slots and internal table entries.  */
+  if (! table->use_dir_and_file_0)
+    {
+      /* Pre DWARF-5, FILE == 0 means unknown.  */
+      if (file == 0)
+       return strdup ("<unknown>");
+      -- file;
+    }
+
+  if (table == NULL || file >= table->num_files)
     {
-      /* FILE == 0 means unknown.  */
-      if (file)
-       _bfd_error_handler
-         (_("DWARF error: mangled line number section (bad file number)"));
+      _bfd_error_handler
+       (_("DWARF error: mangled line number section (bad file number)"));
       return strdup ("<unknown>");
     }
 
-  filename = table->files[file - 1].name;
+  filename = table->files[file].name;
+
   if (filename == NULL)
     return strdup ("<unknown>");
 
@@ -1975,13 +2053,16 @@ concat_filename (struct line_info_table *table, unsigned int file)
       char *subdir_name = NULL;
       char *name;
       size_t len;
+      unsigned int dir = table->files[file].dir;
 
-      if (table->files[file - 1].dir
-         /* PR 17512: file: 0317e960.  */
-         && table->files[file - 1].dir <= table->num_dirs
-         /* PR 17512: file: 7f3d2e4b.  */
-         && table->dirs != NULL)
-       subdir_name = table->dirs[table->files[file - 1].dir - 1];
+      if (!table->use_dir_and_file_0)
+       --dir;
+      /* Wrapping from 0 to -1u above gives the intended result with
+        the test below of leaving subdir_name NULL for pre-DWARF5 dir
+        of 0.  */
+      /* PR 17512: file: 0317e960, file: 7f3d2e4b.  */
+      if (dir < table->num_dirs)
+       subdir_name = table->dirs[dir];
 
       if (!subdir_name || !IS_ABSOLUTE_PATH (subdir_name))
        dir_name = table->comp_dir;
@@ -2022,10 +2103,12 @@ concat_filename (struct line_info_table *table, unsigned int file)
 
 /* Check whether [low1, high1) can be combined with [low2, high2),
    i.e., they touch or overlap.  */
-static bool ranges_overlap (bfd_vma low1,
-                           bfd_vma high1,
-                           bfd_vma low2,
-                           bfd_vma high2)
+
+static bool
+ranges_overlap (bfd_vma low1,
+               bfd_vma high1,
+               bfd_vma low2,
+               bfd_vma high2)
 {
   if (low1 == low2 || high1 == high2)
     return true;
@@ -2052,15 +2135,16 @@ static bool ranges_overlap (bfd_vma low1,
 /* Insert an address range in the trie mapping addresses to compilation units.
    Will return the new trie node (usually the same as is being sent in, but
    in case of a leaf-to-interior conversion, or expansion of a leaf, it may be
-   different), or NULL on failure.
- */
-static struct trie_node *insert_arange_in_trie(bfd *abfd,
-                                              struct trie_node *trie,
-                                              bfd_vma trie_pc,
-                                              unsigned int trie_pc_bits,
-                                              struct comp_unit *unit,
-                                              bfd_vma low_pc,
-                                              bfd_vma high_pc)
+   different), or NULL on failure.  */
+
+static struct trie_node *
+insert_arange_in_trie (bfd *abfd,
+                      struct trie_node *trie,
+                      bfd_vma trie_pc,
+                      unsigned int trie_pc_bits,
+                      struct comp_unit *unit,
+                      bfd_vma low_pc,
+                      bfd_vma high_pc)
 {
   bfd_vma clamped_low_pc, clamped_high_pc;
   int ch, from_ch, to_ch;
@@ -2198,7 +2282,6 @@ static struct trie_node *insert_arange_in_trie(bfd *abfd,
     return trie;
 }
 
-
 static bool
 arange_add (struct comp_unit *unit, struct arange *first_arange,
            struct trie_node **trie_root, bfd_vma low_pc, bfd_vma high_pc)
@@ -2584,10 +2667,8 @@ read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp,
            }
        }
 
-      /* Skip the first "zero entry", which is the compilation dir/file.  */
-      if (datai != 0)
-       if (!callback (table, fe.name, fe.dir, fe.time, fe.size))
-         return false;
+      if (!callback (table, fe.name, fe.dir, fe.time, fe.size))
+       return false;
     }
 
   *bufp = buf;
@@ -2764,6 +2845,7 @@ decode_line_info (struct comp_unit *unit)
       if (!read_formatted_entries (unit, &line_ptr, line_end, table,
                                   line_info_add_file_name))
        goto fail;
+      table->use_dir_and_file_0 = true;
     }
   else
     {
@@ -2786,6 +2868,7 @@ decode_line_info (struct comp_unit *unit)
          if (!line_info_add_file_name (table, cur_file, dir, xtime, size))
            goto fail;
        }
+      table->use_dir_and_file_0 = false;
     }
 
   /* Read the statement sequences until there's nothing left.  */
@@ -2794,7 +2877,7 @@ decode_line_info (struct comp_unit *unit)
       /* State machine registers.  */
       bfd_vma address = 0;
       unsigned char op_index = 0;
-      char * filename = table->num_files ? concat_filename (table, 1) : NULL;
+      char * filename = NULL;
       unsigned int line = 1;
       unsigned int column = 0;
       unsigned int discriminator = 0;
@@ -2809,6 +2892,14 @@ decode_line_info (struct comp_unit *unit)
       bfd_vma low_pc  = (bfd_vma) -1;
       bfd_vma high_pc = 0;
 
+      if (table->num_files)
+       {
+         if (table->use_dir_and_file_0)
+           filename = concat_filename (table, 0);
+         else
+           filename = concat_filename (table, 1);
+       }
+
       /* Decode the table.  */
       while (!end_sequence && line_ptr < line_end)
        {
@@ -3197,7 +3288,7 @@ lookup_address_in_function_table (struct comp_unit *unit,
   struct lookup_funcinfo* lookup_funcinfo = NULL;
   struct funcinfo* funcinfo = NULL;
   struct funcinfo* best_fit = NULL;
-  bfd_vma best_fit_len = 0;
+  bfd_vma best_fit_len = (bfd_vma) -1;
   bfd_size_type low, high, mid, first;
   struct arange *arange;
 
@@ -3243,8 +3334,7 @@ lookup_address_in_function_table (struct comp_unit *unit,
          if (addr < arange->low || addr >= arange->high)
            continue;
 
-         if (!best_fit
-             || arange->high - arange->low < best_fit_len
+         if (arange->high - arange->low < best_fit_len
              /* The following comparison is designed to return the same
                 match as the previous algorithm for routines which have the
                 same best fit length.  */
@@ -3276,44 +3366,33 @@ lookup_symbol_in_function_table (struct comp_unit *unit,
                                 const char **filename_ptr,
                                 unsigned int *linenumber_ptr)
 {
-  struct funcinfo* each_func;
+  struct funcinfo* each;
   struct funcinfo* best_fit = NULL;
-  bfd_vma best_fit_len = 0;
+  bfd_vma best_fit_len = (bfd_vma) -1;
   struct arange *arange;
   const char *name = bfd_asymbol_name (sym);
-  asection *sec = bfd_asymbol_section (sym);
 
-  for (each_func = unit->function_table;
-       each_func;
-       each_func = each_func->prev_func)
-    {
-      for (arange = &each_func->arange;
-          arange;
-          arange = arange->next)
+  for (each = unit->function_table; each; each = each->prev_func)
+    for (arange = &each->arange; arange; arange = arange->next)
+      if (addr >= arange->low
+         && addr < arange->high
+         && arange->high - arange->low < best_fit_len
+         && each->file
+         && each->name
+         && strstr (name, each->name) != NULL)
        {
-         if ((!each_func->sec || each_func->sec == sec)
-             && addr >= arange->low
-             && addr < arange->high
-             && each_func->name
-             && strcmp (name, each_func->name) == 0
-             && (!best_fit
-                 || arange->high - arange->low < best_fit_len))
-           {
-             best_fit = each_func;
-             best_fit_len = arange->high - arange->low;
-           }
+         best_fit = each;
+         best_fit_len = arange->high - arange->low;
        }
-    }
 
   if (best_fit)
     {
-      best_fit->sec = sec;
       *filename_ptr = best_fit->file;
       *linenumber_ptr = best_fit->line;
       return true;
     }
-  else
-    return false;
+
+  return false;
 }
 
 /* Variable table functions.  */
@@ -3328,22 +3407,19 @@ lookup_symbol_in_variable_table (struct comp_unit *unit,
                                 const char **filename_ptr,
                                 unsigned int *linenumber_ptr)
 {
-  const char *name = bfd_asymbol_name (sym);
-  asection *sec = bfd_asymbol_section (sym);
   struct varinfo* each;
+  const char *name = bfd_asymbol_name (sym);
 
   for (each = unit->variable_table; each; each = each->prev_var)
-    if (! each->stack
+    if (each->addr == addr
+       && !each->stack
        && each->file != NULL
        && each->name != NULL
-       && each->addr == addr
-       && (!each->sec || each->sec == sec)
-       && strcmp (name, each->name) == 0)
+       && strstr (name, each->name) != NULL)
       break;
 
   if (each)
     {
-      each->sec = sec;
       *filename_ptr = each->file;
       *linenumber_ptr = each->line;
       return true;
@@ -3372,7 +3448,6 @@ find_abstract_instance (struct comp_unit *unit,
   struct abbrev_info *abbrev;
   uint64_t die_ref = attr_ptr->u.val;
   struct attribute attr;
-  const char *name = NULL;
 
   if (recur_count == 100)
     {
@@ -3447,16 +3522,12 @@ find_abstract_instance (struct comp_unit *unit,
       else
        {
          /* Check other CUs to see if they contain the abbrev.  */
-         struct comp_unit *u;
-
-         for (u = unit->prev_unit; u != NULL; u = u->prev_unit)
-           if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
-             break;
-
-         if (u == NULL)
-           for (u = unit->next_unit; u != NULL; u = u->next_unit)
-             if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
-               break;
+         struct comp_unit *u = NULL;
+         struct addr_range range = { info_ptr, info_ptr };
+         splay_tree_node v = splay_tree_lookup (unit->file->comp_unit_tree,
+                                                (splay_tree_key)&range);
+         if (v != NULL)
+           u = (struct comp_unit *)v->value;
 
          if (attr_ptr->form == DW_FORM_ref_addr)
            while (u == NULL)
@@ -3537,17 +3608,17 @@ find_abstract_instance (struct comp_unit *unit,
                case DW_AT_name:
                  /* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
                     over DW_AT_name.  */
-                 if (name == NULL && is_str_form (&attr))
+                 if (*pname == NULL && is_str_form (&attr))
                    {
-                     name = attr.u.str;
-                     if (non_mangled (unit->lang))
+                     *pname = attr.u.str;
+                     if (mangle_style (unit->lang) == 0)
                        *is_linkage = true;
                    }
                  break;
                case DW_AT_specification:
                  if (is_int_form (&attr)
                      && !find_abstract_instance (unit, &attr, recur_count + 1,
-                                                 &name, is_linkage,
+                                                 pname, is_linkage,
                                                  filename_ptr, linenumber_ptr))
                    return false;
                  break;
@@ -3557,7 +3628,7 @@ find_abstract_instance (struct comp_unit *unit,
                     non-string forms into these attributes.  */
                  if (is_str_form (&attr))
                    {
-                     name = attr.u.str;
+                     *pname = attr.u.str;
                      *is_linkage = true;
                    }
                  break;
@@ -3565,8 +3636,11 @@ find_abstract_instance (struct comp_unit *unit,
                  if (!comp_unit_maybe_decode_line_info (unit))
                    return false;
                  if (is_int_form (&attr))
-                   *filename_ptr = concat_filename (unit->line_table,
-                                                    attr.u.val);
+                   {
+                     free (*filename_ptr);
+                     *filename_ptr = concat_filename (unit->line_table,
+                                                      attr.u.val);
+                   }
                  break;
                case DW_AT_decl_line:
                  if (is_int_form (&attr))
@@ -3578,7 +3652,6 @@ find_abstract_instance (struct comp_unit *unit,
            }
        }
     }
-  *pname = name;
   return true;
 }
 
@@ -4036,7 +4109,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
                  if (func->name == NULL && is_str_form (&attr))
                    {
                      func->name = attr.u.str;
-                     if (non_mangled (unit->lang))
+                     if (mangle_style (unit->lang) == 0)
                        func->is_linkage = true;
                    }
                  break;
@@ -4074,8 +4147,11 @@ scan_unit_for_symbols (struct comp_unit *unit)
 
                case DW_AT_decl_file:
                  if (is_int_form (&attr))
-                   func->file = concat_filename (unit->line_table,
-                                                 attr.u.val);
+                   {
+                     free (func->file);
+                     func->file = concat_filename (unit->line_table,
+                                                   attr.u.val);
+                   }
                  break;
 
                case DW_AT_decl_line:
@@ -4094,11 +4170,12 @@ scan_unit_for_symbols (struct comp_unit *unit)
                case DW_AT_specification:
                  if (is_int_form (&attr) && attr.u.val)
                    {
-                     struct varinfo * spec_var;
-
-                     spec_var = lookup_var_by_offset (attr.u.val,
-                                                      unit->variable_table);
-                     if (spec_var == NULL)
+                     bool is_linkage;
+                     if (!find_abstract_instance (unit, &attr, 0,
+                                                  &var->name,
+                                                  &is_linkage,
+                                                  &var->file,
+                                                  &var->line))
                        {
                          _bfd_error_handler (_("DWARF error: could not find "
                                                "variable specification "
@@ -4106,15 +4183,6 @@ scan_unit_for_symbols (struct comp_unit *unit)
                                              (unsigned long) attr.u.val);
                          break;
                        }
-
-                     if (var->name == NULL)
-                       var->name = spec_var->name;
-                     if (var->file == NULL && spec_var->file != NULL)
-                       var->file = strdup (spec_var->file);
-                     if (var->line == 0)
-                       var->line = spec_var->line;
-                     if (var->sec == NULL)
-                       var->sec = spec_var->sec;
                    }
                  break;
 
@@ -4125,8 +4193,11 @@ scan_unit_for_symbols (struct comp_unit *unit)
 
                case DW_AT_decl_file:
                  if (is_int_form (&attr))
-                   var->file = concat_filename (unit->line_table,
-                                                attr.u.val);
+                   {
+                     free (var->file);
+                     var->file = concat_filename (unit->line_table,
+                                                  attr.u.val);
+                   }
                  break;
 
                case DW_AT_decl_line:
@@ -4347,13 +4418,23 @@ parse_comp_unit (struct dwarf2_debug *stash,
   if (version < 5)
     addr_size = read_1_byte (abfd, &info_ptr, end_ptr);
 
-  if (unit_type == DW_UT_type)
+  switch (unit_type)
     {
+    case DW_UT_type:
       /* Skip type signature.  */
       info_ptr += 8;
 
       /* Skip type offset.  */
       info_ptr += offset_size;
+      break;
+
+    case DW_UT_skeleton:
+      /* Skip DWO_id field.  */
+      info_ptr += 8;
+      break;
+
+    default:
+      break;
     }
 
   if (addr_size > sizeof (bfd_vma))
@@ -4562,21 +4643,20 @@ parse_comp_unit (struct dwarf2_debug *stash,
    really contains the given address.  */
 
 static bool
-comp_unit_contains_address (struct comp_unit *unit, bfd_vma addr)
+comp_unit_may_contain_address (struct comp_unit *unit, bfd_vma addr)
 {
   struct arange *arange;
 
   if (unit->error)
     return false;
 
-  arange = &unit->arange;
-  do
-    {
-      if (addr >= arange->low && addr < arange->high)
-       return true;
-      arange = arange->next;
-    }
-  while (arange);
+  if (unit->arange.high == 0 /* No ranges have been computed yet.  */
+      || unit->line_table == NULL) /* The line info table has not been loaded.  */
+    return true;
+
+  for (arange = &unit->arange; arange != NULL; arange = arange->next)
+    if (addr >= arange->low && addr < arange->high)
+      return true;
 
   return false;
 }
@@ -4764,16 +4844,19 @@ find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections,
     {
       look = debug_sections[debug_info].uncompressed_name;
       msec = bfd_get_section_by_name (abfd, look);
-      if (msec != NULL)
+      /* Testing SEC_HAS_CONTENTS is an anti-fuzzer measure.  Of
+        course debug sections always have contents.  */
+      if (msec != NULL && (msec->flags & SEC_HAS_CONTENTS) != 0)
        return msec;
 
       look = debug_sections[debug_info].compressed_name;
       msec = bfd_get_section_by_name (abfd, look);
-      if (msec != NULL)
+      if (msec != NULL && (msec->flags & SEC_HAS_CONTENTS) != 0)
         return msec;
 
       for (msec = abfd->sections; msec != NULL; msec = msec->next)
-       if (startswith (msec->name, GNU_LINKONCE_INFO))
+       if ((msec->flags & SEC_HAS_CONTENTS) != 0
+           && startswith (msec->name, GNU_LINKONCE_INFO))
          return msec;
 
       return NULL;
@@ -4781,6 +4864,9 @@ find_debug_info (bfd *abfd, const struct dwarf_debug_section *debug_sections,
 
   for (msec = after_sec->next; msec != NULL; msec = msec->next)
     {
+      if ((msec->flags & SEC_HAS_CONTENTS) == 0)
+       continue;
+
       look = debug_sections[debug_info].uncompressed_name;
       if (strcmp (msec->name, look) == 0)
        return msec;
@@ -4866,7 +4952,7 @@ unset_sections (struct dwarf2_debug *stash)
   i = stash->adjusted_section_count;
   p = stash->adjusted_sections;
   for (; i > 0; i--, p++)
-    p->section->vma = 0;
+    p->section->vma = p->orig_vma;
 }
 
 /* Set VMAs for allocated and .debug_info sections in ORIG_BFD, a
@@ -4907,10 +4993,9 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash)
        {
          int is_debug_info;
 
-         if ((sect->output_section != NULL
-              && sect->output_section != sect
-              && (sect->flags & SEC_DEBUGGING) == 0)
-             || sect->vma != 0)
+         if (sect->output_section != NULL
+             && sect->output_section != sect
+             && (sect->flags & SEC_DEBUGGING) == 0)
            continue;
 
          is_debug_info = (strcmp (sect->name, debug_info_name) == 0
@@ -4951,10 +5036,9 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash)
              bfd_size_type sz;
              int is_debug_info;
 
-             if ((sect->output_section != NULL
-                  && sect->output_section != sect
-                  && (sect->flags & SEC_DEBUGGING) == 0)
-                 || sect->vma != 0)
+             if (sect->output_section != NULL
+                 && sect->output_section != sect
+                 && (sect->flags & SEC_DEBUGGING) == 0)
                continue;
 
              is_debug_info = (strcmp (sect->name, debug_info_name) == 0
@@ -4966,24 +5050,17 @@ place_sections (bfd *orig_bfd, struct dwarf2_debug *stash)
 
              sz = sect->rawsize ? sect->rawsize : sect->size;
 
-             if (is_debug_info)
-               {
-                 BFD_ASSERT (sect->alignment_power == 0);
-                 sect->vma = last_dwarf;
-                 last_dwarf += sz;
-               }
-             else
-               {
-                 /* Align the new address to the current section
-                    alignment.  */
-                 last_vma = ((last_vma
-                              + ~(-((bfd_vma) 1 << sect->alignment_power)))
-                             & (-((bfd_vma) 1 << sect->alignment_power)));
-                 sect->vma = last_vma;
-                 last_vma += sz;
-               }
-
              p->section = sect;
+             p->orig_vma = sect->vma;
+
+             bfd_vma *v = is_debug_info ? &last_dwarf : &last_vma;
+             /* Align the new address to the current section
+                alignment.  */
+             bfd_vma mask = -(bfd_vma) 1 << sect->alignment_power;
+             *v = (*v + ~mask) & mask;
+             sect->vma = *v;
+             *v += sz;
+
              p->adj_vma = sect->vma;
              p++;
            }
@@ -5014,11 +5091,10 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table,
 {
   struct funcinfo* each_func;
   struct funcinfo* best_fit = NULL;
-  bfd_vma best_fit_len = 0;
+  bfd_vma best_fit_len = (bfd_vma) -1;
   struct info_list_node *node;
   struct arange *arange;
   const char *name = bfd_asymbol_name (sym);
-  asection *sec = bfd_asymbol_section (sym);
 
   for (node = lookup_info_hash_table (hash_table, name);
        node;
@@ -5029,11 +5105,9 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table,
           arange;
           arange = arange->next)
        {
-         if ((!each_func->sec || each_func->sec == sec)
-             && addr >= arange->low
+         if (addr >= arange->low
              && addr < arange->high
-             && (!best_fit
-                 || arange->high - arange->low < best_fit_len))
+             && arange->high - arange->low < best_fit_len)
            {
              best_fit = each_func;
              best_fit_len = arange->high - arange->low;
@@ -5043,7 +5117,6 @@ info_hash_lookup_funcinfo (struct info_hash_table *hash_table,
 
   if (best_fit)
     {
-      best_fit->sec = sec;
       *filename_ptr = best_fit->file;
       *linenumber_ptr = best_fit->line;
       return true;
@@ -5065,20 +5138,17 @@ info_hash_lookup_varinfo (struct info_hash_table *hash_table,
                          const char **filename_ptr,
                          unsigned int *linenumber_ptr)
 {
-  const char *name = bfd_asymbol_name (sym);
-  asection *sec = bfd_asymbol_section (sym);
   struct varinfo* each;
   struct info_list_node *node;
+  const char *name = bfd_asymbol_name (sym);
 
   for (node = lookup_info_hash_table (hash_table, name);
        node;
        node = node->next)
     {
       each = (struct varinfo *) node->info;
-      if (each->addr == addr
-         && (!each->sec || each->sec == sec))
+      if (each->addr == addr)
        {
-         each->sec = sec;
          *filename_ptr = each->file;
          *linenumber_ptr = each->line;
          return true;
@@ -5300,7 +5370,6 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
                              void **pinfo,
                              bool do_place)
 {
-  size_t amt = sizeof (struct dwarf2_debug);
   bfd_size_type total_size;
   asection *msec;
   struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo;
@@ -5312,7 +5381,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
        {
          /* Check that we did previously find some debug information
             before attempting to make use of it.  */
-         if (stash->f.bfd_ptr != NULL)
+         if (stash->f.dwarf_info_size != 0)
            {
              if (do_place && !place_sections (abfd, stash))
                return false;
@@ -5322,13 +5391,14 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
          return false;
        }
       _bfd_dwarf2_cleanup_debug_info (abfd, pinfo);
-      memset (stash, 0, amt);
+      memset (stash, 0, sizeof (*stash));
     }
   else
     {
-      stash = (struct dwarf2_debug *) bfd_zalloc (abfd, amt);
+      stash = (struct dwarf2_debug *) bfd_zalloc (abfd, sizeof (*stash));
       if (! stash)
        return false;
+      *pinfo = stash;
     }
   stash->orig_bfd = abfd;
   stash->debug_sections = debug_sections;
@@ -5354,8 +5424,6 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
   if (!stash->alt.trie_root)
     return false;
 
-  *pinfo = stash;
-
   if (debug_bfd == NULL)
     debug_bfd = abfd;
 
@@ -5404,14 +5472,11 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
 
   /* There can be more than one DWARF2 info section in a BFD these
      days.  First handle the easy case when there's only one.  If
-     there's more than one, try case two: none of the sections is
-     compressed.  In that case, read them all in and produce one
-     large stash.  We do this in two passes - in the first pass we
+     there's more than one, try case two: read them all in and produce
+     one large stash.  We do this in two passes - in the first pass we
      just accumulate the section sizes, and in the second pass we
      read in the section's contents.  (The allows us to avoid
-     reallocing the data as we add sections to the stash.)  If
-     some or all sections are compressed, then do things the slow
-     way, with a bunch of reallocs.  */
+     reallocing the data as we add sections to the stash.)  */
 
   if (! find_debug_info (debug_bfd, debug_sections, msec))
     {
@@ -5420,7 +5485,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
       if (! read_section (debug_bfd, &stash->debug_sections[debug_info],
                          symbols, 0,
                          &stash->f.dwarf_info_buffer, &total_size))
-       return false;
+       goto restore_vma;
     }
   else
     {
@@ -5429,19 +5494,20 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
           msec;
           msec = find_debug_info (debug_bfd, debug_sections, msec))
        {
+         if (_bfd_section_size_insane (debug_bfd, msec))
+           goto restore_vma;
          /* Catch PR25070 testcase overflowing size calculation here.  */
-         if (total_size + msec->size < total_size
-             || total_size + msec->size < msec->size)
+         if (total_size + msec->size < total_size)
            {
              bfd_set_error (bfd_error_no_memory);
-             return false;
+             goto restore_vma;
            }
          total_size += msec->size;
        }
 
       stash->f.dwarf_info_buffer = (bfd_byte *) bfd_malloc (total_size);
       if (stash->f.dwarf_info_buffer == NULL)
-       return false;
+       goto restore_vma;
 
       total_size = 0;
       for (msec = find_debug_info (debug_bfd, debug_sections, NULL);
@@ -5457,7 +5523,7 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
          if (!(bfd_simple_get_relocated_section_contents
                (debug_bfd, msec, stash->f.dwarf_info_buffer + total_size,
                 symbols)))
-           return false;
+           goto restore_vma;
 
          total_size += size;
        }
@@ -5466,6 +5532,10 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
   stash->f.info_ptr = stash->f.dwarf_info_buffer;
   stash->f.dwarf_info_size = total_size;
   return true;
+
+ restore_vma:
+  unset_sections (stash);
+  return false;
 }
 
 /* Parse the next DWARF2 compilation unit at FILE->INFO_PTR.  */
@@ -5517,6 +5587,22 @@ stash_comp_unit (struct dwarf2_debug *stash, struct dwarf2_debug_file *file)
                                                info_ptr_unit, offset_size);
       if (each)
        {
+         if (file->comp_unit_tree == NULL)
+           file->comp_unit_tree
+             = splay_tree_new (splay_tree_compare_addr_range,
+                               splay_tree_free_addr_range, NULL);
+
+         struct addr_range *r
+           = (struct addr_range *)bfd_malloc (sizeof (struct addr_range));
+         r->start = each->info_ptr_unit;
+         r->end = each->end_ptr;
+         splay_tree_node v = splay_tree_lookup (file->comp_unit_tree,
+                                                (splay_tree_key)r);
+         if (v != NULL || r->end <= r->start)
+           abort ();
+         splay_tree_insert (file->comp_unit_tree, (splay_tree_key)r,
+                            (splay_tree_value)each);
+
          if (file->all_comp_units)
            file->all_comp_units->prev_unit = each;
          else
@@ -5622,18 +5708,7 @@ _bfd_dwarf2_find_symbol_bias (asymbol ** symbols, void ** pinfo)
   return result;
 }
 
-/* Find the source code location of SYMBOL.  If SYMBOL is NULL
-   then find the nearest source code location corresponding to
-   the address SECTION + OFFSET.
-   Returns 1 if the line is found without error and fills in
-   FILENAME_PTR and LINENUMBER_PTR.  In the case where SYMBOL was
-   NULL the FUNCTIONNAME_PTR is also filled in.
-   Returns 2 if partial information from _bfd_elf_find_function is
-   returned (function and maybe file) by looking at symbols.  DWARF2
-   info is present but not regarding the requested code location.
-   Returns 0 otherwise.
-   SYMBOLS contains the symbol table for ABFD.
-   DEBUG_SECTIONS contains the name of the dwarf debug sections.  */
+/* See _bfd_dwarf2_find_nearest_line_with_alt.  */
 
 int
 _bfd_dwarf2_find_nearest_line (bfd *abfd,
@@ -5647,6 +5722,43 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
                               unsigned int *discriminator_ptr,
                               const struct dwarf_debug_section *debug_sections,
                               void **pinfo)
+{
+  return _bfd_dwarf2_find_nearest_line_with_alt
+    (abfd, NULL, symbols, symbol, section, offset, filename_ptr,
+     functionname_ptr, linenumber_ptr, discriminator_ptr, debug_sections,
+     pinfo);
+}
+
+/* Find the source code location of SYMBOL.  If SYMBOL is NULL
+   then find the nearest source code location corresponding to
+   the address SECTION + OFFSET.
+   Returns 1 if the line is found without error and fills in
+   FILENAME_PTR and LINENUMBER_PTR.  In the case where SYMBOL was
+   NULL the FUNCTIONNAME_PTR is also filled in.
+   Returns 2 if partial information from _bfd_elf_find_function is
+   returned (function and maybe file) by looking at symbols.  DWARF2
+   info is present but not regarding the requested code location.
+   Returns 0 otherwise.
+   SYMBOLS contains the symbol table for ABFD.
+   DEBUG_SECTIONS contains the name of the dwarf debug sections.
+   If ALT_FILENAME is given, attempt to open the file and use it
+   as the .gnu_debugaltlink file. Otherwise this file will be
+   searched for when needed.  */
+
+int
+_bfd_dwarf2_find_nearest_line_with_alt
+  (bfd *abfd,
+   const char *alt_filename,
+   asymbol **symbols,
+   asymbol *symbol,
+   asection *section,
+   bfd_vma offset,
+   const char **filename_ptr,
+   const char **functionname_ptr,
+   unsigned int *linenumber_ptr,
+   unsigned int *discriminator_ptr,
+   const struct dwarf_debug_section *debug_sections,
+   void **pinfo)
 {
   /* Read each compilation unit from the section .debug_info, and check
      to see if it contains the address we are searching for.  If yes,
@@ -5678,6 +5790,23 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
 
   stash = (struct dwarf2_debug *) *pinfo;
 
+  if (stash->alt.bfd_ptr == NULL && alt_filename != NULL)
+    {
+      bfd *alt_bfd = bfd_openr (alt_filename, NULL);
+
+      if (alt_bfd == NULL)
+       /* bfd_openr will have set the bfd_error.  */
+       return false;
+      if (!bfd_check_format (alt_bfd, bfd_object))
+       {
+         bfd_set_error (bfd_error_wrong_format);
+         bfd_close (alt_bfd);
+         return false;
+       }
+
+      stash->alt.bfd_ptr = alt_bfd;
+    }
+
   do_line = symbol != NULL;
   if (do_line)
     {
@@ -5751,25 +5880,22 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
 
       if (stash->info_hash_status == STASH_INFO_HASH_ON)
        {
-         found = stash_find_line_fast (stash, symbol, addr, filename_ptr,
-                                       linenumber_ptr);
+         found = stash_find_line_fast (stash, symbol, addr,
+                                       filename_ptr, linenumber_ptr);
          if (found)
            goto done;
        }
-      else
-       {
-         /* Check the previously read comp. units first.  */
-         for (each = stash->f.all_comp_units; each; each = each->next_unit)
-           if ((symbol->flags & BSF_FUNCTION) == 0
-               || each->arange.high == 0
-               || comp_unit_contains_address (each, addr))
-             {
-               found = comp_unit_find_line (each, symbol, addr, filename_ptr,
-                                            linenumber_ptr);
-               if (found)
-                 goto done;
-             }
-       }
+
+      /* Check the previously read comp. units first.  */
+      for (each = stash->f.all_comp_units; each; each = each->next_unit)
+       if ((symbol->flags & BSF_FUNCTION) == 0
+           || comp_unit_may_contain_address (each, addr))
+         {
+           found = comp_unit_find_line (each, symbol, addr, filename_ptr,
+                                        linenumber_ptr);
+           if (found)
+             goto done;
+         }
     }
   else
     {
@@ -5845,13 +5971,11 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
         address.  */
       if (do_line)
        found = (((symbol->flags & BSF_FUNCTION) == 0
-                 || each->arange.high == 0
-                 || comp_unit_contains_address (each, addr))
+                 || comp_unit_may_contain_address (each, addr))
                 && comp_unit_find_line (each, symbol, addr,
                                         filename_ptr, linenumber_ptr));
       else
-       found = ((each->arange.high == 0
-                 || comp_unit_contains_address (each, addr))
+       found = (comp_unit_may_contain_address (each, addr)
                 && comp_unit_find_nearest_line (each, addr,
                                                 filename_ptr,
                                                 &function,
@@ -5902,8 +6026,7 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
        }
     }
 
-  if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
-    unset_sections (stash);
+  unset_sections (stash);
 
   return found;
 }
@@ -5990,6 +6113,8 @@ _bfd_dwarf2_cleanup_debug_info (bfd *abfd, void **pinfo)
          free (file->line_table->dirs);
        }
       htab_delete (file->abbrev_offsets);
+      if (file->comp_unit_tree != NULL)
+       splay_tree_delete (file->comp_unit_tree);
 
       free (file->dwarf_line_str_buffer);
       free (file->dwarf_str_buffer);