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. */