SmallVector<Entry, 2> Entries;
/// Dump this list on OS.
void dump(raw_ostream &OS, bool IsLittleEndian, unsigned AddressSize,
- const MCRegisterInfo *MRI, uint64_t BaseAddress,
+ const MCRegisterInfo *MRI, DWARFUnit *U, uint64_t BaseAddress,
unsigned Indent) const;
};
SizeAddr = 5,
SizeRefAddr = 6,
SizeBlock = 7, ///< Preceding operand contains block size
- SignBit = 0x8,
+ BaseTypeRef = 8,
+ SignBit = 0x80,
SignedSize1 = SignBit | Size1,
SignedSize2 = SignBit | Size2,
SignedSize4 = SignBit | Size4,
DwarfNA, ///< Serves as a marker for unused entries
Dwarf2 = 2,
Dwarf3,
- Dwarf4
+ Dwarf4,
+ Dwarf5
};
/// Description of the encoding of one expression Op.
bool extract(DataExtractor Data, uint16_t Version, uint8_t AddressSize,
uint32_t Offset);
bool isError() { return Error; }
- bool print(raw_ostream &OS, const DWARFExpression *U,
- const MCRegisterInfo *RegInfo, bool isEH);
+ bool print(raw_ostream &OS, const DWARFExpression *Expr,
+ const MCRegisterInfo *RegInfo, DWARFUnit *U, bool isEH);
+ bool verify(DWARFUnit *U);
};
/// An iterator to go through the expression operations.
iterator begin() const { return iterator(this, 0); }
iterator end() const { return iterator(this, Data.getData().size()); }
- void print(raw_ostream &OS, const MCRegisterInfo *RegInfo,
+ void print(raw_ostream &OS, const MCRegisterInfo *RegInfo, DWARFUnit *U,
bool IsEH = false) const;
+ bool verify(DWARFUnit *U);
+
private:
DataExtractor Data;
uint16_t Version;
case OT_Expression:
assert(Instr.Expression && "missing DWARFExpression object");
OS << " ";
- Instr.Expression->print(OS, MRI, IsEH);
+ Instr.Expression->print(OS, MRI, nullptr, IsEH);
break;
}
}
// non-LLVM tools.
static void dumpExpression(raw_ostream &OS, ArrayRef<char> Data,
bool IsLittleEndian, unsigned AddressSize,
- const MCRegisterInfo *MRI) {
+ const MCRegisterInfo *MRI, DWARFUnit *U) {
DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()),
IsLittleEndian, AddressSize);
- DWARFExpression(Extractor, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI);
+ DWARFExpression(Extractor, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI, U);
}
void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
unsigned AddressSize,
const MCRegisterInfo *MRI,
+ DWARFUnit *U,
uint64_t BaseAddress,
unsigned Indent) const {
for (const Entry &E : Entries) {
BaseAddress + E.End);
OS << ": ";
- dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
+ dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U);
}
}
Optional<uint64_t> Offset) const {
auto DumpLocationList = [&](const LocationList &L) {
OS << format("0x%8.8x: ", L.Offset);
- L.dump(OS, IsLittleEndian, AddressSize, MRI, 0, 12);
+ L.dump(OS, IsLittleEndian, AddressSize, MRI, nullptr, 0, 12);
OS << "\n\n";
};
llvm_unreachable("unreachable locations list kind");
}
- dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
+ dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, nullptr);
}
}
DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
Ctx.isLittleEndian(), 0);
DWARFExpression(Data, U->getVersion(), U->getAddressByteSize())
- .print(OS, MRI);
+ .print(OS, MRI, U);
return;
}
uint64_t BaseAddr = 0;
if (Optional<SectionedAddress> BA = U->getBaseAddress())
BaseAddr = BA->Address;
- LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, BaseAddr,
- Indent);
+ LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, U,
+ BaseAddr, Indent);
} else
OS << "error extracting location list.";
return;
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Format.h"
Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+
+ Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
+
return Descriptions;
}
else
Operands[Operand] = Data.getULEB128(&Offset);
break;
+ case Operation::BaseTypeRef:
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
case Operation::SizeBlock:
// We need a size, so this cannot be the first operand
if (Operand == 0)
bool DWARFExpression::Operation::print(raw_ostream &OS,
const DWARFExpression *Expr,
const MCRegisterInfo *RegInfo,
+ DWARFUnit *U,
bool isEH) {
if (Error) {
OS << "<decoding error>";
if (Size == Operation::SizeNA)
break;
- if (Size == Operation::SizeBlock) {
+ if (Size == Operation::BaseTypeRef && U) {
+ auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
+ if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
+ OS << format(" (0x%08x)", U->getOffset() + Operands[Operand]);
+ if (auto Name = Die.find(dwarf::DW_AT_name))
+ OS << " \"" << Name->getAsCString() << "\"";
+ } else {
+ OS << format(" <invalid base_type ref: 0x%" PRIx64 ">",
+ Operands[Operand]);
+ }
+ } else if (Size == Operation::SizeBlock) {
uint32_t Offset = Operands[Operand];
for (unsigned i = 0; i < Operands[Operand - 1]; ++i)
OS << format(" 0x%02x", Expr->Data.getU8(&Offset));
}
void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo,
- bool IsEH) const {
+ DWARFUnit *U, bool IsEH) const {
for (auto &Op : *this) {
- if (!Op.print(OS, this, RegInfo, IsEH)) {
+ if (!Op.print(OS, this, RegInfo, U, IsEH)) {
uint32_t FailOffset = Op.getEndOffset();
while (FailOffset < Data.getData().size())
OS << format(" %02x", Data.getU8(&FailOffset));
}
}
+bool DWARFExpression::Operation::verify(DWARFUnit *U) {
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ if (Size == Operation::BaseTypeRef) {
+ auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
+ if (!Die || Die.getTag() != dwarf::DW_TAG_base_type) {
+ Error = true;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool DWARFExpression::verify(DWARFUnit *U) {
+ for (auto &Op : *this)
+ if (!Op.verify(U))
+ return false;
+
+ return true;
+}
+
} // namespace llvm
bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
return Op.isError();
});
- if (Error)
+ if (Error || !Expression.verify(U))
ReportError("DIE contains invalid DWARF expression:");
};
if (Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock()) {
--- /dev/null
+# RUN: llvm-mc %s -filetype obj -triple x86_64-pc-linux -o %t.o
+# RUN: llvm-dwarfdump %t.o | FileCheck %s
+# RUN: not llvm-dwarfdump -verify %t.o
+
+# CHECK: DW_AT_location (DW_OP_addr 0x{{[0-9a-f]+}}, DW_OP_convert <invalid base_type ref: 0x{{[0-9a-f]+}}>, DW_OP_convert (0x{{[0-9a-f]+}}) "DW_ATE_signed_32")
+
+ .text
+ .file "dbg.g.c"
+ .file 1 "/tmp/dbg.g.c"
+ .type global,@object # @global
+ .data
+ .globl global
+ .p2align 2
+global:
+ .long 255 # 0xff
+ .size global, 4
+
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 9.0.0 (trunk 354265) (llvm/trunk 354264)" # string offset=0
+.Linfo_string1:
+ .asciz "dbg.g.c" # string offset=55
+.Linfo_string2:
+ .asciz "/tmp" # string offset=63
+.Linfo_string3:
+ .asciz "global" # string offset=68
+.Linfo_string4:
+ .asciz "int" # string offset=75
+.Linfo_string5:
+ .asciz "DW_ATE_signed_32" # string offset=79
+.Linfo_string6:
+ .asciz "DW_ATE_signed_8" # string offset=96
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 14 # DW_FORM_strp
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 14 # DW_FORM_strp
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 4 # DWARF version number
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 8 # Address Size (in bytes)
+ .byte 1 # Abbrev [1] 0xb:0x48 DW_TAG_compile_unit
+ .long .Linfo_string0 # DW_AT_producer
+ .short 12 # DW_AT_language
+ .long .Linfo_string1 # DW_AT_name
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .long .Linfo_string2 # DW_AT_comp_dir
+ .byte 2 # Abbrev [2] 0x1e:0x7 DW_TAG_base_type
+ .long .Linfo_string6 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 1 # DW_AT_byte_size
+ .byte 2 # Abbrev [2] 0x25:0x7 DW_TAG_base_type
+ .long .Linfo_string5 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 3 # Abbrev [3] 0x2c:0x1f DW_TAG_variable
+ .long .Linfo_string3 # DW_AT_name
+ .long 75 # DW_AT_type
+ # DW_AT_external
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .byte 19 # DW_AT_location
+ .byte 3
+ .quad global
+ .byte 168
+ .asciz "\235\200\200" ### This offset is off by one to test the invalid base_type ref printout
+ .byte 168
+ .asciz "\245\200\200"
+ .byte 2 # Abbrev [2] 0x4b:0x7 DW_TAG_base_type
+ .long .Linfo_string4 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_macinfo,"",@progbits
+ .byte 0 # End Of Macro List Mark
+
+ .ident "clang version 9.0.0 (trunk 354265) (llvm/trunk 354264)"
+ .section ".note.GNU-stack","",@progbits
+ .section .debug_line,"",@progbits
+.Lline_table_start0: