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> 2019-08-14 Alan Modra <amodra@gmail.com>
* dwarf2.c (comp_unit_maybe_decode_line_info): Declare. * 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; return FALSE;
} }
static struct comp_unit *stash_comp_unit (struct dwarf2_debug *);
static bfd_boolean comp_unit_maybe_decode_line_info (struct comp_unit *, static bfd_boolean comp_unit_maybe_decode_line_info (struct comp_unit *,
struct dwarf2_debug *); 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) if (info_ptr >= u->info_ptr_unit && info_ptr < u->end_ptr)
break; break;
if (u) while (u == NULL)
{ {
unit = u; u = stash_comp_unit (unit->stash);
info_ptr_end = unit->end_ptr; 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) else if (attr_ptr->form == DW_FORM_GNU_ref_alt)
@ -2982,6 +2997,8 @@ find_abstract_instance (struct comp_unit * unit,
} }
break; break;
case DW_AT_decl_file: case DW_AT_decl_file:
if (!comp_unit_maybe_decode_line_info (unit, unit->stash))
return FALSE;
*filename_ptr = concat_filename (unit->line_table, *filename_ptr = concat_filename (unit->line_table,
attr.u.val); attr.u.val);
break; break;
@ -3334,7 +3351,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
return FALSE; 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 includes the compilation unit header that proceeds the DIE's, but
does not include the length field that precedes each compilation does not include the length field that precedes each compilation
unit header. END_PTR points one past the end of this comp unit. 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; 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 /* 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 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 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. */ /* 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; /* DW_AT_low_pc and DW_AT_high_pc are optional for
unsigned int offset_size; compilation units. If we don't have them (i.e.,
bfd_byte *info_ptr_unit = stash->info_ptr; unit->high == 0), we need to consult the line info table
to see if a compilation unit contains the given
length = read_4_bytes (stash->bfd_ptr, stash->info_ptr, stash->info_ptr_end); address. */
/* A 0xffffff length is the DWARF3 way of indicating if (do_line)
we use 64-bit offsets, instead of 32-bit offsets. */ found = (((symbol->flags & BSF_FUNCTION) == 0
if (length == 0xffffffff) || each->arange.high == 0
{ || comp_unit_contains_address (each, addr))
offset_size = 8; && comp_unit_find_line (each, symbol, addr,
length = read_8_bytes (stash->bfd_ptr, stash->info_ptr + 4, stash->info_ptr_end); filename_ptr,
stash->info_ptr += 12; linenumber_ptr,
} stash));
/* 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 else
{ found = ((each->arange.high == 0
offset_size = 4; || comp_unit_contains_address (each, addr))
stash->info_ptr += 4; && comp_unit_find_nearest_line (each, addr,
} filename_ptr,
&function,
linenumber_ptr,
discriminator_ptr,
stash) != 0);
if (length > 0) if (found)
{ break;
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;
}
} }
done: done: