DebugInfo/DWARF: Provide some (pretty half-hearted) error handling access when parsing units

This isn't the most robust error handling API, but does allow clients to
opt-in to getting Errors they can handle. I suspect the long-term
solution would be to move away from the lazy unit parsing and have an
explicit step that parses the unit and then allows access to the other
APIs that require a parsed unit.

llvm-dwarfdump could be expanded to use this (or newer/better API) to
demonstrate the benefit of it - but for now lld will use this in a
follow-up cl which ensures lld can exit non-zero on errors like this (&
provide more descriptive diagnostics including which object file the
error came from).

(error access to later errors when parsing nested DIEs would be good too
- but, again, exposing that without it being a hassle for every consumer
may be tricky)

llvm-svn: 368377
This commit is contained in:
David Blaikie 2019-08-09 01:14:33 +00:00
parent d219fa3461
commit 980f06a21f
3 changed files with 35 additions and 24 deletions

View File

@ -495,6 +495,9 @@ public:
}
virtual void dump(raw_ostream &OS, DIDumpOptions DumpOpts) = 0;
Error tryExtractDIEsIfNeeded(bool CUDieOnly);
private:
/// Size in bytes of the .debug_info data associated with this compile unit.
size_t getDebugInfoSize() const {

View File

@ -402,21 +402,26 @@ void DWARFUnit::extractDIEsToVector(
}
void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
if (Error e = tryExtractDIEsIfNeeded(CUDieOnly))
WithColor::error() << toString(std::move(e));
}
Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
if ((CUDieOnly && !DieArray.empty()) ||
DieArray.size() > 1)
return; // Already parsed.
return Error::success(); // Already parsed.
bool HasCUDie = !DieArray.empty();
extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
if (DieArray.empty())
return;
return Error::success();
// If CU DIE was just parsed, copy several attribute values from it.
if (HasCUDie)
return;
return Error::success();
DWARFDie UnitDie = getUnitDIE();
DWARFDie UnitDie(this, &DieArray[0]);
if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
Header.setDWOId(*DWOId);
if (!IsDWO) {
@ -442,13 +447,13 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
auto StringOffsetOrError =
IsDWO ? determineStringOffsetsTableContributionDWO(DA)
: determineStringOffsetsTableContribution(DA);
if (!StringOffsetOrError) {
WithColor::error() << "invalid contribution to string offsets table in "
"section .debug_str_offsets[.dwo]: "
<< toString(StringOffsetOrError.takeError()) << '\n';
} else {
StringOffsetsTableContribution = *StringOffsetOrError;
}
if (!StringOffsetOrError)
return createStringError(errc::invalid_argument,
"invalid reference to or invalid content in "
".debug_str_offsets[.dwo]: " +
toString(StringOffsetOrError.takeError()));
StringOffsetsTableContribution = *StringOffsetOrError;
}
// DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
@ -464,12 +469,14 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
// extracted lazily.
DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
isLittleEndian, 0);
if (auto TableOrError =
parseRngListTableHeader(RangesDA, RangeSectionBase))
RngListTable = TableOrError.get();
else
WithColor::error() << "parsing a range list table: "
<< toString(TableOrError.takeError()) << '\n';
auto TableOrError =
parseRngListTableHeader(RangesDA, RangeSectionBase);
if (!TableOrError)
return createStringError(errc::invalid_argument,
"parsing a range list table: " +
toString(TableOrError.takeError()));
RngListTable = TableOrError.get();
// In a split dwarf unit, there is no DW_AT_rnglists_base attribute.
// Adjust RangeSectionBase to point past the table header.
@ -480,6 +487,7 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
// Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
// skeleton CU DIE, so that DWARF users not aware of it are not broken.
return Error::success();
}
bool DWARFUnit::parseDWO() {

View File

@ -144,11 +144,11 @@ CU9_end:
.str_off_end:
# CHECK: error: invalid contribution to string offsets table in section .debug_str_offsets[.dwo]: insufficient space for 32 bit header prefix
# CHECK: error: invalid contribution to string offsets table in section .debug_str_offsets[.dwo]: insufficient space for 64 bit header prefix
# CHECK: error: invalid contribution to string offsets table in section .debug_str_offsets[.dwo]: invalid length
# CHECK: error: invalid contribution to string offsets table in section .debug_str_offsets[.dwo]: length exceeds section size
# CHECK: error: invalid contribution to string offsets table in section .debug_str_offsets[.dwo]: 32 bit contribution referenced from a 64 bit unit
# CHECK: error: invalid contribution to string offsets table in section .debug_str_offsets[.dwo]: section offset exceeds section size
# CHECK: error: invalid contribution to string offsets table in section .debug_str_offsets[.dwo]: section offset exceeds section size
# CHECK: error: invalid reference to or invalid content in .debug_str_offsets[.dwo]: insufficient space for 32 bit header prefix
# CHECK: error: invalid reference to or invalid content in .debug_str_offsets[.dwo]: insufficient space for 64 bit header prefix
# CHECK: error: invalid reference to or invalid content in .debug_str_offsets[.dwo]: invalid length
# CHECK: error: invalid reference to or invalid content in .debug_str_offsets[.dwo]: length exceeds section size
# CHECK: error: invalid reference to or invalid content in .debug_str_offsets[.dwo]: 32 bit contribution referenced from a 64 bit unit
# CHECK: error: invalid reference to or invalid content in .debug_str_offsets[.dwo]: section offset exceeds section size
# CHECK: error: invalid reference to or invalid content in .debug_str_offsets[.dwo]: section offset exceeds section size
# CHECK: error: overlapping contributions to string offsets table in section .debug_str_offsets.