aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2021-03-02 16:08:23 +0000
committerNick Clifton <nickc@redhat.com>2021-03-02 16:08:23 +0000
commitca8f6bc629cb27792ce449e7253c74a3f6f75fda (patch)
treee299aa4b18780df60bdf9bde1d685276b7be0167
parent211bcd013331fcaefa9bb31b6145ae0df13a3363 (diff)
downloadgdb-ca8f6bc629cb27792ce449e7253c74a3f6f75fda.zip
gdb-ca8f6bc629cb27792ce449e7253c74a3f6f75fda.tar.gz
gdb-ca8f6bc629cb27792ce449e7253c74a3f6f75fda.tar.bz2
Fix the BFD library's parsing of DIEs where specification attributes can refer to variables that are defined later on.
PR 27484 * dwarf2.c (scan_unit_for_symbols): Scan twice, once to accumulate function and variable tags and a second time to resolve their attributes.
-rw-r--r--bfd/ChangeLog7
-rw-r--r--bfd/dwarf2.c133
2 files changed, 114 insertions, 26 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index c56cfc4..a056a14 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2021-03-02 Nick Clifton <nickc@redhat.com>
+
+ PR 27484
+ * dwarf2.c (scan_unit_for_symbols): Scan twice, once to accumulate
+ function and variable tags and a second time to resolve their
+ attributes.
+
2021-03-02 Nick Alcock <nick.alcock@oracle.com>
* elf-strtab.c (_bfd_elf_strtab_str): Skip strings with zero refcount.
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index 240138d..c0fb956 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -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, struct arange *arange,
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)
{
@@ -3330,7 +3341,8 @@ scan_unit_for_symbols (struct comp_unit *unit)
bfd_byte *info_ptr = unit->first_child_die_ptr;
bfd_byte *info_ptr_end = unit->end_ptr;
int nesting_level = 0;
- struct nest_funcinfo {
+ struct nest_funcinfo
+ {
struct funcinfo *func;
} *nested_funcs;
int nested_funcs_size;
@@ -3344,16 +3356,16 @@ scan_unit_for_symbols (struct comp_unit *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. */
@@ -3365,7 +3377,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
FALSE, info_ptr_end);
info_ptr += bytes_read;
- if (! abbrev_number)
+ if (abbrev_number == 0)
{
nesting_level--;
continue;
@@ -3400,6 +3412,7 @@ scan_unit_for_symbols (struct comp_unit *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);
@@ -3420,6 +3433,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
|| abbrev->tag == DW_TAG_member)
{
size_t amt = sizeof (struct varinfo);
+
var = (struct varinfo *) bfd_zalloc (abfd, amt);
if (var == NULL)
goto fail;
@@ -3440,6 +3454,89 @@ scan_unit_for_symbols (struct comp_unit *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;
+ }
+ }
+
+ /* This is the second pass over the abbrevs. */
+ info_ptr = unit->first_child_die_ptr;
+ nesting_level = 0;
+
+ 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)
+ {
+ func = lookup_func_by_offset (current_offset, unit->function_table);
+ if (func == NULL)
+ goto fail;
+ }
+ else if (abbrev->tag == DW_TAG_variable
+ || abbrev->tag == DW_TAG_member)
+ {
+ var = lookup_var_by_offset (current_offset, unit->variable_table);
+ if (var == NULL)
+ goto fail;
+ }
+
+ 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)
@@ -3532,7 +3629,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
{
_bfd_error_handler (_("DWARF error: could not find "
"variable specification "
- "at offset %lx"),
+ "at offset 0x%lx"),
(unsigned long) attr.u.val);
break;
}
@@ -3604,6 +3701,9 @@ scan_unit_for_symbols (struct comp_unit *unit)
}
}
+ if (abbrev->has_children)
+ nesting_level++;
+
if (high_pc_relative)
high_pc += low_pc;
@@ -3612,25 +3712,6 @@ scan_unit_for_symbols (struct comp_unit *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;
- }
}
free (nested_funcs);