Blob Blame History Raw
diff -rup binutils.orig/bfd/dwarf2.c binutils-2.36.1/bfd/dwarf2.c
--- binutils.orig/bfd/dwarf2.c	2022-04-11 12:06:47.745972052 +0100
+++ binutils-2.36.1/bfd/dwarf2.c	2022-04-11 12:58:03.964445150 +0100
@@ -1484,6 +1484,8 @@ struct funcinfo
   struct arange		arange;
   /* Where the symbol is defined.  */
   asection *		sec;
+  /* The offset of the funcinfo from the start of the unit.  */
+  bfd_uint64_t          unit_offset;
 };
 
 struct lookup_funcinfo
@@ -3304,6 +3306,15 @@ read_rangelist (struct comp_unit *unit,
     return read_rnglists (unit, arange, offset);
 }
 
+static struct funcinfo *
+lookup_func_by_offset (bfd_uint64_t offset, struct funcinfo * table)
+{
+  for (; table != NULL; table = table->prev_func)
+    if (table->unit_offset == offset)
+      return table;
+  return NULL;
+}
+
 static struct varinfo *
 lookup_var_by_offset (bfd_uint64_t offset, struct varinfo * table)
 {
@@ -3317,6 +3328,35 @@ lookup_var_by_offset (bfd_uint64_t offse
   return NULL;
 }
 
+static struct funcinfo *
+reverse_funcinfo_list (struct funcinfo * head)
+{
+  struct funcinfo * rhead;
+  struct funcinfo * temp;
+
+  for (rhead = NULL; head; head = temp)
+    {
+      temp = head->prev_func;
+      head->prev_func = rhead;
+      rhead = head;
+    }
+  return rhead;
+}
+
+static struct varinfo *
+reverse_varinfo_list (struct varinfo * head)
+{
+  struct varinfo * rhead;
+  struct varinfo * temp;
+
+  for (rhead = NULL; head; head = temp)
+    {
+      temp = head->prev_var;
+      head->prev_var = rhead;
+      rhead = head;
+    }
+  return rhead;
+}
 
 /* DWARF2 Compilation unit functions.  */
 
@@ -3334,6 +3374,8 @@ scan_unit_for_symbols (struct comp_unit
     struct funcinfo *func;
   } *nested_funcs;
   int nested_funcs_size;
+  struct funcinfo *last_func;
+  struct varinfo *last_var;
 
   /* Maintain a stack of in-scope functions and inlined functions, which we
      can use to set the caller_func field.  */
@@ -3344,16 +3386,16 @@ scan_unit_for_symbols (struct comp_unit
     return FALSE;
   nested_funcs[nesting_level].func = 0;
 
+  /* PR 27484: We must scan the DIEs twice.  The first time we look for
+     function and variable tags and accumulate them into their respective
+     tables.  The second time through we process the attributes of the
+     functions/variables and augment the table entries.  */
   while (nesting_level >= 0)
     {
       unsigned int abbrev_number, bytes_read, i;
       struct abbrev_info *abbrev;
-      struct attribute attr;
       struct funcinfo *func;
       struct varinfo *var;
-      bfd_vma low_pc = 0;
-      bfd_vma high_pc = 0;
-      bfd_boolean high_pc_relative = FALSE;
       bfd_uint64_t current_offset;
 
       /* PR 17512: file: 9f405d9d.  */
@@ -3400,6 +3442,7 @@ scan_unit_for_symbols (struct comp_unit
 	    goto fail;
 	  func->tag = abbrev->tag;
 	  func->prev_func = unit->function_table;
+	  func->unit_offset = current_offset;
 	  unit->function_table = func;
 	  unit->number_of_functions++;
 	  BFD_ASSERT (!unit->cached);
@@ -3440,6 +3483,111 @@ scan_unit_for_symbols (struct comp_unit
 
       for (i = 0; i < abbrev->num_attrs; ++i)
 	{
+	  struct attribute attr;
+
+	  info_ptr = read_attribute (&attr, &abbrev->attrs[i],
+				     unit, info_ptr, info_ptr_end);
+	  if (info_ptr == NULL)
+	    goto fail;
+	}
+
+      if (abbrev->has_children)
+	{
+	  nesting_level++;
+
+	  if (nesting_level >= nested_funcs_size)
+	    {
+	      struct nest_funcinfo *tmp;
+
+	      nested_funcs_size *= 2;
+	      tmp = (struct nest_funcinfo *)
+		bfd_realloc (nested_funcs,
+			     nested_funcs_size * sizeof (*nested_funcs));
+	      if (tmp == NULL)
+		goto fail;
+	      nested_funcs = tmp;
+	    }
+	  nested_funcs[nesting_level].func = 0;
+	}
+    }
+
+  unit->function_table = reverse_funcinfo_list (unit->function_table);
+  unit->variable_table = reverse_varinfo_list (unit->variable_table);
+
+  /* This is the second pass over the abbrevs.  */      
+  info_ptr = unit->first_child_die_ptr;
+  nesting_level = 0;
+  
+  last_func = NULL;
+  last_var = NULL;
+
+  while (nesting_level >= 0)
+    {
+      unsigned int abbrev_number, bytes_read, i;
+      struct abbrev_info *abbrev;
+      struct attribute attr;
+      struct funcinfo *func;
+      struct varinfo *var;
+      bfd_vma low_pc = 0;
+      bfd_vma high_pc = 0;
+      bfd_boolean high_pc_relative = FALSE;
+      bfd_uint64_t current_offset;
+
+      /* PR 17512: file: 9f405d9d.  */
+      if (info_ptr >= info_ptr_end)
+	goto fail;
+
+      current_offset = info_ptr - unit->info_ptr_unit;
+      abbrev_number = _bfd_safe_read_leb128 (abfd, info_ptr, &bytes_read,
+					     FALSE, info_ptr_end);
+      info_ptr += bytes_read;
+
+      if (! abbrev_number)
+	{
+	  nesting_level--;
+	  continue;
+	}
+
+      abbrev = lookup_abbrev (abbrev_number, unit->abbrevs);
+      /* This should have been handled above.  */
+      BFD_ASSERT (abbrev != NULL);
+
+      func = NULL;
+      var = NULL;
+      if (abbrev->tag == DW_TAG_subprogram
+	  || abbrev->tag == DW_TAG_entry_point
+	  || abbrev->tag == DW_TAG_inlined_subroutine)
+	{
+	  if (last_func
+	      && last_func->prev_func
+	      && last_func->prev_func->unit_offset == current_offset)
+	    func = last_func->prev_func;
+	  else
+	    func = lookup_func_by_offset (current_offset, unit->function_table);
+
+	  if (func == NULL)
+	    goto fail;
+
+	  last_func = func;
+	}
+      else if (abbrev->tag == DW_TAG_variable
+	       || abbrev->tag == DW_TAG_member)
+	{
+	  if (last_var
+	      && last_var->prev_var
+	      && last_var->prev_var->unit_offset == current_offset)
+	    var = last_var->prev_var;
+	  else
+	    var = lookup_var_by_offset (current_offset, unit->variable_table);
+
+	  if (var == NULL)
+	    goto fail;
+
+	  last_var = var;
+	}
+
+      for (i = 0; i < abbrev->num_attrs; ++i)
+	{
 	  info_ptr = read_attribute (&attr, &abbrev->attrs[i],
 				     unit, info_ptr, info_ptr_end);
 	  if (info_ptr == NULL)
@@ -3604,6 +3752,9 @@ scan_unit_for_symbols (struct comp_unit
 	    }
 	}
 
+      if (abbrev->has_children)
+	nesting_level++;
+
       if (high_pc_relative)
 	high_pc += low_pc;
 
@@ -3612,27 +3763,11 @@ scan_unit_for_symbols (struct comp_unit
 	  if (!arange_add (unit, &func->arange, low_pc, high_pc))
 	    goto fail;
 	}
-
-      if (abbrev->has_children)
-	{
-	  nesting_level++;
-
-	  if (nesting_level >= nested_funcs_size)
-	    {
-	      struct nest_funcinfo *tmp;
-
-	      nested_funcs_size *= 2;
-	      tmp = (struct nest_funcinfo *)
-		bfd_realloc (nested_funcs,
-			     nested_funcs_size * sizeof (*nested_funcs));
-	      if (tmp == NULL)
-		goto fail;
-	      nested_funcs = tmp;
-	    }
-	  nested_funcs[nesting_level].func = 0;
-	}
     }
 
+  unit->function_table = reverse_funcinfo_list (unit->function_table);
+  unit->variable_table = reverse_varinfo_list (unit->variable_table);
+
   free (nested_funcs);
   return TRUE;
 
@@ -3994,36 +4129,6 @@ comp_unit_find_line (struct comp_unit *u
 					  linenumber_ptr);
 }
 
-static struct funcinfo *
-reverse_funcinfo_list (struct funcinfo *head)
-{
-  struct funcinfo *rhead;
-  struct funcinfo *temp;
-
-  for (rhead = NULL; head; head = temp)
-    {
-      temp = head->prev_func;
-      head->prev_func = rhead;
-      rhead = head;
-    }
-  return rhead;
-}
-
-static struct varinfo *
-reverse_varinfo_list (struct varinfo *head)
-{
-  struct varinfo *rhead;
-  struct varinfo *temp;
-
-  for (rhead = NULL; head; head = temp)
-    {
-      temp = head->prev_var;
-      head->prev_var = rhead;
-      rhead = head;
-    }
-  return rhead;
-}
-
 /* Extract all interesting funcinfos and varinfos of a compilation
    unit into hash tables for faster lookup.  Returns TRUE if no
    errors were enountered; FALSE otherwise.  */