PR24623, DWARF errors

PR 24623
	* dwarf2.c (stash_comp_unit): New function, extracted from..
	(_bfd_dwarf2_find_nearest_line): ..here.
	(find_abstract_instance): Parse comp units and decode line info
	as needed.
This commit is contained in:
Alan Modra 2019-08-14 10:51:22 +09:30
parent c327a44f38
commit dfc19da6a6
2 changed files with 138 additions and 109 deletions

View File

@ -1,3 +1,11 @@
2019-08-14 Alan Modra <amodra@gmail.com>
PR 24623
* dwarf2.c (stash_comp_unit): New function, extracted from..
(_bfd_dwarf2_find_nearest_line): ..here.
(find_abstract_instance): Parse comp units and decode line info
as needed.
2019-08-14 Alan Modra <amodra@gmail.com>
* dwarf2.c (comp_unit_maybe_decode_line_info): Declare.

View File

@ -2804,6 +2804,7 @@ lookup_symbol_in_variable_table (struct comp_unit *unit,
return FALSE;
}
static struct comp_unit *stash_comp_unit (struct dwarf2_debug *);
static bfd_boolean comp_unit_maybe_decode_line_info (struct comp_unit *,
struct dwarf2_debug *);
@ -2877,12 +2878,26 @@ find_abstract_instance (struct comp_unit * unit,
if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
break;
if (u)
while (u == NULL)
{
unit = u;
info_ptr_end = unit->end_ptr;
u = stash_comp_unit (unit->stash);
if (u == NULL)
break;
if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
break;
u = NULL;
}
/* else FIXME: What do we do now ? */
if (u == NULL)
{
_bfd_error_handler
(_("DWARF error: unable to locate abstract instance DIE ref %"
PRIu64), (uint64_t) die_ref);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
unit = u;
info_ptr_end = unit->end_ptr;
}
}
else if (attr_ptr->form == DW_FORM_GNU_ref_alt)
@ -2982,6 +2997,8 @@ find_abstract_instance (struct comp_unit * unit,
}
break;
case DW_AT_decl_file:
if (!comp_unit_maybe_decode_line_info (unit, unit->stash))
return FALSE;
*filename_ptr = concat_filename (unit->line_table,
attr.u.val);
break;
@ -3334,7 +3351,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
return FALSE;
}
/* Parse a DWARF2 compilation unit starting at INFO_PTR. This
/* Parse a DWARF2 compilation unit starting at INFO_PTR. UNIT_LENGTH
includes the compilation unit header that proceeds the DIE's, but
does not include the length field that precedes each compilation
unit header. END_PTR points one past the end of this comp unit.
@ -4451,6 +4468,90 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
return TRUE;
}
/* Parse the next DWARF2 compilation unit at STASH->INFO_PTR. */
static struct comp_unit *
stash_comp_unit (struct dwarf2_debug *stash)
{
bfd_size_type length;
unsigned int offset_size;
bfd_byte *info_ptr_unit = stash->info_ptr;
if (stash->info_ptr >= stash->info_ptr_end)
return NULL;
length = read_4_bytes (stash->bfd_ptr, stash->info_ptr,
stash->info_ptr_end);
/* A 0xffffff length is the DWARF3 way of indicating
we use 64-bit offsets, instead of 32-bit offsets. */
if (length == 0xffffffff)
{
offset_size = 8;
length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4,
stash->info_ptr_end);
stash->info_ptr += 12;
}
/* A zero length is the IRIX way of indicating 64-bit offsets,
mostly because the 64-bit length will generally fit in 32
bits, and the endianness helps. */
else if (length == 0)
{
offset_size = 8;
length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4,
stash->info_ptr_end);
stash->info_ptr += 8;
}
/* In the absence of the hints above, we assume 32-bit DWARF2
offsets even for targets with 64-bit addresses, because:
a) most of the time these targets will not have generated
more than 2Gb of debug info and so will not need 64-bit
offsets,
and
b) if they do use 64-bit offsets but they are not using
the size hints that are tested for above then they are
not conforming to the DWARF3 standard anyway. */
else
{
offset_size = 4;
stash->info_ptr += 4;
}
if (length != 0
&& stash->info_ptr + length <= stash->info_ptr_end
&& stash->info_ptr + length > stash->info_ptr)
{
struct comp_unit *each = parse_comp_unit (stash, length, info_ptr_unit,
offset_size);
if (each)
{
if (stash->all_comp_units)
stash->all_comp_units->prev_unit = each;
else
stash->last_comp_unit = each;
each->next_unit = stash->all_comp_units;
stash->all_comp_units = each;
stash->info_ptr += length;
if ((bfd_size_type) (stash->info_ptr - stash->sec_info_ptr)
== stash->sec->size)
{
stash->sec = find_debug_info (stash->bfd_ptr,
stash->debug_sections,
stash->sec);
stash->sec_info_ptr = stash->info_ptr;
}
return each;
}
}
/* Don't trust any of the DWARF info after a corrupted length or
parse error. */
stash->info_ptr = stash->info_ptr_end;
return NULL;
}
/* Scan the debug information in PINFO looking for a DW_TAG_subprogram
abbrev with a DW_AT_low_pc attached to it. Then lookup that same
symbol in SYMBOLS and return the difference between the low_pc and
@ -4699,113 +4800,33 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd,
}
/* Read each remaining comp. units checking each as they are read. */
while (stash->info_ptr < stash->info_ptr_end)
while ((each = stash_comp_unit (stash)) != NULL)
{
bfd_vma length;
unsigned int offset_size;
bfd_byte *info_ptr_unit = stash->info_ptr;
length = read_4_bytes (stash->bfd_ptr, stash->info_ptr, stash->info_ptr_end);
/* A 0xffffff length is the DWARF3 way of indicating
we use 64-bit offsets, instead of 32-bit offsets. */
if (length == 0xffffffff)
{
offset_size = 8;
length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end);
stash->info_ptr += 12;
}
/* A zero length is the IRIX way of indicating 64-bit offsets,
mostly because the 64-bit length will generally fit in 32
bits, and the endianness helps. */
else if (length == 0)
{
offset_size = 8;
length = read_4_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end);
stash->info_ptr += 8;
}
/* In the absence of the hints above, we assume 32-bit DWARF2
offsets even for targets with 64-bit addresses, because:
a) most of the time these targets will not have generated
more than 2Gb of debug info and so will not need 64-bit
offsets,
and
b) if they do use 64-bit offsets but they are not using
the size hints that are tested for above then they are
not conforming to the DWARF3 standard anyway. */
/* DW_AT_low_pc and DW_AT_high_pc are optional for
compilation units. If we don't have them (i.e.,
unit->high == 0), we need to consult the line info table
to see if a compilation unit contains the given
address. */
if (do_line)
found = (((symbol->flags & BSF_FUNCTION) == 0
|| each->arange.high == 0
|| comp_unit_contains_address (each, addr))
&& comp_unit_find_line (each, symbol, addr,
filename_ptr,
linenumber_ptr,
stash));
else
{
offset_size = 4;
stash->info_ptr += 4;
}
found = ((each->arange.high == 0
|| comp_unit_contains_address (each, addr))
&& comp_unit_find_nearest_line (each, addr,
filename_ptr,
&function,
linenumber_ptr,
discriminator_ptr,
stash) != 0);
if (length > 0)
{
bfd_byte * new_ptr;
/* PR 21151 */
if (stash->info_ptr + length > stash->info_ptr_end)
return FALSE;
each = parse_comp_unit (stash, length, info_ptr_unit,
offset_size);
if (!each)
/* The dwarf information is damaged, don't trust it any
more. */
break;
new_ptr = stash->info_ptr + length;
/* PR 17512: file: 1500698c. */
if (new_ptr < stash->info_ptr)
{
/* A corrupt length value - do not trust the info any more. */
found = FALSE;
break;
}
else
stash->info_ptr = new_ptr;
if (stash->all_comp_units)
stash->all_comp_units->prev_unit = each;
else
stash->last_comp_unit = each;
each->next_unit = stash->all_comp_units;
stash->all_comp_units = each;
/* DW_AT_low_pc and DW_AT_high_pc are optional for
compilation units. If we don't have them (i.e.,
unit->high == 0), we need to consult the line info table
to see if a compilation unit contains the given
address. */
if (do_line)
found = (((symbol->flags & BSF_FUNCTION) == 0
|| each->arange.high == 0
|| comp_unit_contains_address (each, addr))
&& comp_unit_find_line (each, symbol, addr,
filename_ptr,
linenumber_ptr,
stash));
else
found = ((each->arange.high == 0
|| comp_unit_contains_address (each, addr))
&& comp_unit_find_nearest_line (each, addr,
filename_ptr,
&function,
linenumber_ptr,
discriminator_ptr,
stash) != 0);
if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
== stash->sec->size)
{
stash->sec = find_debug_info (stash->bfd_ptr, debug_sections,
stash->sec);
stash->sec_info_ptr = stash->info_ptr;
}
if (found)
goto done;
}
if (found)
break;
}
done: