Skip to content

Commit

Permalink
[llvm-dwarfdump] - Teach verifier to report broken DWARF expressions.
Browse files Browse the repository at this point in the history
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

llvm-svn: 316756
  • Loading branch information
George Rimar committed Oct 27, 2017
1 parent 7f92294 commit 144e4c5
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 29 deletions.
10 changes: 7 additions & 3 deletions llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}

Expand All @@ -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];
Expand Down Expand Up @@ -221,7 +225,7 @@ bool DWARFExpression::Operation::print(raw_ostream &OS,
const MCRegisterInfo *RegInfo,
bool isEH) {
if (Error) {
OS << "decoding error.";
OS << "<decoding error>";
return false;
}

Expand Down
64 changes: 38 additions & 26 deletions llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <map>
#include <set>
Expand Down Expand Up @@ -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<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock();
if (!Expr) {
ReportError("DIE has invalid DW_AT_location encoding:");
break;
}

DWARFUnit *U = Die.getDwarfUnit();
DataExtractor Data(
StringRef(reinterpret_cast<const char *>(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;
Expand Down
52 changes: 52 additions & 0 deletions llvm/test/tools/llvm-dwarfdump/X86/verify_broken_exprloc.s
Original file line number Diff line number Diff line change
@@ -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"

0 comments on commit 144e4c5

Please sign in to comment.