Index: lib/DebugInfo/DWARF/DWARFExpression.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFExpression.cpp +++ lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -104,7 +104,9 @@ 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 @@ 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 @@ const MCRegisterInfo *RegInfo, bool isEH) { if (Error) { - OS << "decoding error."; + OS << "decoding error"; return false; } Index: lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ 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::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; Index: test/tools/llvm-dwarfdump/X86/verify_broken_exprloc.s =================================================================== --- test/tools/llvm-dwarfdump/X86/verify_broken_exprloc.s +++ test/tools/llvm-dwarfdump/X86/verify_broken_exprloc.s @@ -0,0 +1,52 @@ +# RUN: llvm-mc %s -filetype obj -triple i686-pc-linux -o %t + +## Check we don't crash when parsing invalid expression opcode. +# RUN: llvm-dwarfdump %t | FileCheck %s +# CHECK: DW_TAG_GNU_call_site_parameter +# CHECK-NEXT: DW_AT_location (decoding error) + +## Check verifier reports an error. +# RUN: not llvm-dwarfdump -verify %t 2>&1 | FileCheck %s --check-prefix=VERIFY +# VERIFY: DIE contains invalid DWARF expression: +# VERIFY: DW_TAG_GNU_call_site_parameter +# VERIFY-NEXT: DW_AT_location (decoding error) + +.section .debug_info,"",@progbits + .long 0x12 + .value 0x4 + .long 0 + .byte 0x4 + + .uleb128 0x1 # DW_TAG_compile_unit [1] + .long 0 + .byte 0x0 + + .uleb128 0x2 # DW_TAG_GNU_call_site_parameter [2] + .uleb128 0x1 # Expression size. + .byte 0xff # Broken expression. + + .byte 0 # End mark. + .byte 0 # End mark. + +.section .debug_abbrev,"",@progbits + .uleb128 0x1 # ID [1] + .uleb128 0x11 # DW_TAG_compile_unit, DW_CHILDREN_yes + .byte 0x1 + .uleb128 0x25 # DW_AT_producer, DW_FORM_strp + .uleb128 0xe + .uleb128 0x13 # DW_AT_language, DW_FORM_data1 + .uleb128 0xb + .byte 0 + .byte 0 + + .uleb128 0x2 # ID [2] + .uleb128 0x410a # DW_TAG_GNU_call_site_parameter, DW_CHILDREN_no + .byte 0 + .uleb128 0x2 # DW_AT_location, DW_FORM_exprloc + .uleb128 0x18 + .byte 0 + .byte 0 + .byte 0 + +.section .debug_str,"MS",@progbits,1 +.string "test"