From 603d7b305534c6a358836deff41d6beeb7f1a65d Mon Sep 17 00:00:00 2001 From: George Rimar Date: Fri, 27 Oct 2017 10:42:04 +0000 Subject: [llvm-dwarfdump] - Teach verifier to report broken DWARF expressions. Patch improves next things: * Fixes assert/crash in getOpDesc when giving it a invalid expression op code. * DWARFExpression::print() called DWARFExpression::Operation::getEndOffset() which returned and used uninitialized field EndOffset. Patch fixes that. * Teaches verifier to verify DW_AT_location and error out on broken expressions. Differential revision: https://reviews.llvm.org/D39294 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@316756 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/DebugInfo/DWARF/DWARFExpression.cpp | 10 ++++-- lib/DebugInfo/DWARF/DWARFVerifier.cpp | 64 +++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 29 deletions(-) (limited to 'lib/DebugInfo') diff --git a/lib/DebugInfo/DWARF/DWARFExpression.cpp b/lib/DebugInfo/DWARF/DWARFExpression.cpp index 3417fee14c0..16058e461f4 100644 --- a/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -104,7 +104,9 @@ static DescVector getDescriptions() { static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) { // FIXME: Make this constexpr once all compilers are smart enough to do it. static DescVector Descriptions = getDescriptions(); - assert(OpCode < Descriptions.size()); + // Handle possible corrupted or unsupported operation. + if (OpCode >= Descriptions.size()) + return {}; return Descriptions[OpCode]; } @@ -117,8 +119,10 @@ bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version, Opcode = Data.getU8(&Offset); Desc = getOpDesc(Opcode); - if (Desc.Version == Operation::DwarfNA) + if (Desc.Version == Operation::DwarfNA) { + EndOffset = Offset; return false; + } for (unsigned Operand = 0; Operand < 2; ++Operand) { unsigned Size = Desc.Op[Operand]; @@ -221,7 +225,7 @@ bool DWARFExpression::Operation::print(raw_ostream &OS, const MCRegisterInfo *RegInfo, bool isEH) { if (Error) { - OS << "decoding error."; + OS << ""; return false; } diff --git a/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/lib/DebugInfo/DWARF/DWARFVerifier.cpp index b10697c9a31..f27c849456b 100644 --- a/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -13,9 +13,11 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -377,45 +379,55 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die, unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die, DWARFAttribute &AttrValue) { - const DWARFObject &DObj = DCtx.getDWARFObj(); unsigned NumErrors = 0; + auto ReportError = [&](const Twine &TitleMsg) { + ++NumErrors; + error() << TitleMsg << '\n'; + Die.dump(OS, 0, DumpOpts); + OS << "\n"; + }; + + const DWARFObject &DObj = DCtx.getDWARFObj(); const auto Attr = AttrValue.Attr; switch (Attr) { case DW_AT_ranges: // Make sure the offset in the DW_AT_ranges attribute is valid. if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - if (*SectionOffset >= DObj.getRangeSection().Data.size()) { - ++NumErrors; - error() << "DW_AT_ranges offset is beyond .debug_ranges " - "bounds:\n"; - Die.dump(OS, 0, DumpOpts); - OS << "\n"; - } - } else { - ++NumErrors; - error() << "DIE has invalid DW_AT_ranges encoding:\n"; - Die.dump(OS, 0, DumpOpts); - OS << "\n"; + if (*SectionOffset >= DObj.getRangeSection().Data.size()) + ReportError("DW_AT_ranges offset is beyond .debug_ranges bounds:"); + break; } + ReportError("DIE has invalid DW_AT_ranges encoding:"); break; case DW_AT_stmt_list: // Make sure the offset in the DW_AT_stmt_list attribute is valid. if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) { - if (*SectionOffset >= DObj.getLineSection().Data.size()) { - ++NumErrors; - error() << "DW_AT_stmt_list offset is beyond .debug_line " - "bounds: " - << format("0x%08" PRIx64, *SectionOffset) << "\n"; - Die.dump(OS, 0, DumpOpts); - OS << "\n"; - } - } else { - ++NumErrors; - error() << "DIE has invalid DW_AT_stmt_list encoding:\n"; - Die.dump(OS, 0, DumpOpts); - OS << "\n"; + if (*SectionOffset >= DObj.getLineSection().Data.size()) + ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " + + llvm::formatv("{0:x16}", *SectionOffset)); + break; } + ReportError("DIE has invalid DW_AT_stmt_list encoding:"); break; + case DW_AT_location: { + Optional> Expr = AttrValue.Value.getAsBlock(); + if (!Expr) { + ReportError("DIE has invalid DW_AT_location encoding:"); + break; + } + + DWARFUnit *U = Die.getDwarfUnit(); + DataExtractor Data( + StringRef(reinterpret_cast(Expr->data()), Expr->size()), + DCtx.isLittleEndian(), 0); + DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize()); + bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { + return Op.isError(); + }); + if (Error) + ReportError("DIE contains invalid DWARF expression:"); + break; + } default: break; -- cgit v1.2.3