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