[dwarfdump] Pretty print location expressions and location lists
Summary:
Based on Fred's patch here: https://reviews.llvm.org/D6771
I can't seem to commandeer the old review, so I'm creating a new one.
With that change the locations exrpessions are pretty printed inline in the
DIE tree. The output looks like this for debug_loc entries:
DW_AT_location [DW_FORM_data4] (0x00000000
0x0000000000000001 - 0x000000000000000b: DW_OP_consts +3
0x000000000000000b - 0x0000000000000012: DW_OP_consts +7
0x0000000000000012 - 0x000000000000001b: DW_OP_reg0 RAX, DW_OP_piece 0x4
0x000000000000001b - 0x0000000000000024: DW_OP_breg5 RDI+0)
And like this for debug_loc.dwo entries:
DW_AT_location [DW_FORM_sec_offset] (0x00000000
Addr idx 2 (w/ length 190): DW_OP_consts +0, DW_OP_stack_value
Addr idx 3 (w/ length 23): DW_OP_reg0 RAX, DW_OP_piece 0x4)
Simple locations without ranges are printed inline:
DW_AT_location [DW_FORM_block1] (DW_OP_reg4 RSI, DW_OP_piece 0x4, DW_OP_bit_piece 0x20 0x0)
The debug_loc(.dwo) dumping in changed accordingly to factor the code.
Reviewers: dblaikie, aprantl, friss
Subscribers: mgorny, javed.absar, hiraditya, llvm-commits, JDevlieghere
Differential Revision: https://reviews.llvm.org/D37123
llvm-svn: 312042
diff --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
index 11f9450..620016d 100644
--- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
@@ -15,6 +15,7 @@
DWARFDebugPubTable.cpp
DWARFDebugRangeList.cpp
DWARFDie.cpp
+ DWARFExpression.cpp
DWARFFormValue.cpp
DWARFGdbIndex.cpp
DWARFTypeUnit.cpp
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index 0bd9c92..27d9db6 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -31,6 +31,7 @@
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Object/Decompressor.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
@@ -40,6 +41,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdint>
@@ -59,6 +61,12 @@
using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
+DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj,
+ std::string DWPName)
+ : DIContext(CK_DWARF), DWPName(std::move(DWPName)), DObj(std::move(DObj)) {}
+
+DWARFContext::~DWARFContext() = default;
+
static void dumpAccelSection(raw_ostream &OS, StringRef Name,
const DWARFObject &Obj,
const DWARFSection &Section,
@@ -237,12 +245,12 @@
if (DumpType == DIDT_All || DumpType == DIDT_Loc) {
OS << "\n.debug_loc contents:\n";
- getDebugLoc()->dump(OS);
+ getDebugLoc()->dump(OS, getRegisterInfo());
}
if (DumpType == DIDT_All || DumpType == DIDT_LocDwo) {
OS << "\n.debug_loc.dwo contents:\n";
- getDebugLocDWO()->dump(OS);
+ getDebugLocDWO()->dump(OS, getRegisterInfo());
}
if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
@@ -1295,3 +1303,19 @@
llvm::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian);
return llvm::make_unique<DWARFContext>(std::move(DObj), "");
}
+
+Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) {
+ // Detect the architecture from the object file. We usually don't need OS
+ // info to lookup a target and create register info.
+ Triple TT;
+ TT.setArch(Triple::ArchType(Obj.getArch()));
+ TT.setVendor(Triple::UnknownVendor);
+ TT.setOS(Triple::UnknownOS);
+ std::string TargetLookupError;
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(TT.str(), TargetLookupError);
+ if (!TargetLookupError.empty())
+ return make_error<StringError>(TargetLookupError, inconvertibleErrorCode());
+ RegInfo.reset(TheTarget->createMCRegInfo(TT.str()));
+ return Error::success();
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
index c240dd7..68bc0e5 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -11,7 +11,10 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -20,104 +23,160 @@
using namespace llvm;
-void DWARFDebugLoc::dump(raw_ostream &OS) const {
+// When directly dumping the .debug_loc without a compile unit, we have to guess
+// at the DWARF version. This only affects DW_OP_call_ref, which is a rare
+// expression that LLVM doesn't produce. Guessing the wrong version means we
+// won't be able to pretty print expressions in DWARF2 binaries produced by
+// non-LLVM tools.
+static void dumpExpression(raw_ostream &OS, ArrayRef<char> Data,
+ bool IsLittleEndian, unsigned AddressSize,
+ const MCRegisterInfo *MRI) {
+ DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()),
+ IsLittleEndian, AddressSize);
+ DWARFExpression(Extractor, AddressSize, dwarf::DWARF_VERSION).print(OS, MRI);
+}
+
+void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
+ unsigned AddressSize,
+ const MCRegisterInfo *MRI,
+ unsigned Indent) const {
+ for (const Entry &E : Entries) {
+ OS << '\n';
+ OS.indent(Indent);
+ OS << format("0x%016" PRIx64, E.Begin) << " - "
+ << format("0x%016" PRIx64, E.End) << ": ";
+
+ dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
+ }
+}
+
+void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI) const {
for (const LocationList &L : Locations) {
OS << format("0x%8.8x: ", L.Offset);
- const unsigned Indent = 12;
- for (const Entry &E : L.Entries) {
- if (&E != L.Entries.begin())
- OS.indent(Indent);
- OS << "Beginning address offset: " << format("0x%016" PRIx64, E.Begin)
- << '\n';
- OS.indent(Indent) << " Ending address offset: "
- << format("0x%016" PRIx64, E.End) << '\n';
- OS.indent(Indent) << " Location description: ";
- for (unsigned char Loc : E.Loc) {
- OS << format("%2.2x ", Loc);
- }
- OS << "\n\n";
+ L.dump(OS, IsLittleEndian, AddressSize, MRI, 12);
+ OS << "\n\n";
+ }
+}
+
+Optional<DWARFDebugLoc::LocationList>
+DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) {
+ LocationList LL;
+ LL.Offset = *Offset;
+
+ // 2.6.2 Location Lists
+ // A location list entry consists of:
+ while (true) {
+ Entry E;
+ if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) {
+ llvm::errs() << "Location list overflows the debug_loc section.\n";
+ return None;
}
+
+ // 1. A beginning address offset. ...
+ E.Begin = Data.getRelocatedAddress(Offset);
+
+ // 2. An ending address offset. ...
+ E.End = Data.getRelocatedAddress(Offset);
+
+ // The end of any given location list is marked by an end of list entry,
+ // which consists of a 0 for the beginning address offset and a 0 for the
+ // ending address offset.
+ if (E.Begin == 0 && E.End == 0)
+ return LL;
+
+ if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) {
+ llvm::errs() << "Location list overflows the debug_loc section.\n";
+ return None;
+ }
+
+ unsigned Bytes = Data.getU16(Offset);
+ if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) {
+ llvm::errs() << "Location list overflows the debug_loc section.\n";
+ return None;
+ }
+ // A single location description describing the location of the object...
+ StringRef str = Data.getData().substr(*Offset, Bytes);
+ *Offset += Bytes;
+ E.Loc.reserve(str.size());
+ std::copy(str.begin(), str.end(), std::back_inserter(E.Loc));
+ LL.Entries.push_back(std::move(E));
}
}
void DWARFDebugLoc::parse(const DWARFDataExtractor &data) {
+ IsLittleEndian = data.isLittleEndian();
+ AddressSize = data.getAddressSize();
+
uint32_t Offset = 0;
- while (data.isValidOffset(Offset+data.getAddressSize()-1)) {
- Locations.resize(Locations.size() + 1);
- LocationList &Loc = Locations.back();
- Loc.Offset = Offset;
- // 2.6.2 Location Lists
- // A location list entry consists of:
- while (true) {
- // A beginning and ending address offsets.
- Entry E;
- E.Begin = data.getRelocatedAddress(&Offset);
- E.End = data.getRelocatedAddress(&Offset);
-
- // The end of any given location list is marked by an end of list entry,
- // which consists of a 0 for the beginning address offset and a 0 for the
- // ending address offset.
- if (E.Begin == 0 && E.End == 0)
- break;
-
- unsigned Bytes = data.getU16(&Offset);
- // A single location description describing the location of the object...
- StringRef str = data.getData().substr(Offset, Bytes);
- Offset += Bytes;
- E.Loc.append(str.begin(), str.end());
- Loc.Entries.push_back(std::move(E));
- }
+ while (data.isValidOffset(Offset + data.getAddressSize() - 1)) {
+ if (auto LL = parseOneLocationList(data, &Offset))
+ Locations.push_back(std::move(*LL));
+ else
+ break;
}
if (data.isValidOffset(Offset))
errs() << "error: failed to consume entire .debug_loc section\n";
}
+Optional<DWARFDebugLocDWO::LocationList>
+DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) {
+ LocationList LL;
+ LL.Offset = *Offset;
+
+ // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
+ while (auto Kind =
+ static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) {
+ if (Kind != dwarf::DW_LLE_startx_length) {
+ llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind
+ << " not implemented\n";
+ return None;
+ }
+
+ Entry E;
+ E.Start = Data.getULEB128(Offset);
+ E.Length = Data.getU32(Offset);
+
+ unsigned Bytes = Data.getU16(Offset);
+ // A single location description describing the location of the object...
+ StringRef str = Data.getData().substr(*Offset, Bytes);
+ *Offset += Bytes;
+ E.Loc.resize(str.size());
+ std::copy(str.begin(), str.end(), E.Loc.begin());
+
+ LL.Entries.push_back(std::move(E));
+ }
+ return LL;
+}
+
void DWARFDebugLocDWO::parse(DataExtractor data) {
+ IsLittleEndian = data.isLittleEndian();
+ AddressSize = data.getAddressSize();
+
uint32_t Offset = 0;
while (data.isValidOffset(Offset)) {
- Locations.resize(Locations.size() + 1);
- LocationList &Loc = Locations.back();
- Loc.Offset = Offset;
- dwarf::LocationListEntry Kind;
- while ((Kind = static_cast<dwarf::LocationListEntry>(
- data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list) {
-
- if (Kind != dwarf::DW_LLE_startx_length) {
- errs() << "error: dumping support for LLE of kind " << (int)Kind
- << " not implemented\n";
- return;
- }
-
- Entry E;
-
- E.Start = data.getULEB128(&Offset);
- E.Length = data.getU32(&Offset);
-
- unsigned Bytes = data.getU16(&Offset);
- // A single location description describing the location of the object...
- StringRef str = data.getData().substr(Offset, Bytes);
- Offset += Bytes;
- E.Loc.resize(str.size());
- std::copy(str.begin(), str.end(), E.Loc.begin());
-
- Loc.Entries.push_back(std::move(E));
- }
+ if (auto LL = parseOneLocationList(data, &Offset))
+ Locations.push_back(std::move(*LL));
+ else
+ return;
}
}
-void DWARFDebugLocDWO::dump(raw_ostream &OS) const {
+void DWARFDebugLocDWO::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
+ unsigned AddressSize,
+ const MCRegisterInfo *MRI,
+ unsigned Indent) const {
+ for (const Entry &E : Entries) {
+ OS << '\n';
+ OS.indent(Indent);
+ OS << "Addr idx " << E.Start << " (w/ length " << E.Length << "): ";
+ dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
+ }
+}
+
+void DWARFDebugLocDWO::dump(raw_ostream &OS, const MCRegisterInfo *MRI) const {
for (const LocationList &L : Locations) {
OS << format("0x%8.8x: ", L.Offset);
- const unsigned Indent = 12;
- for (const Entry &E : L.Entries) {
- if (&E != L.Entries.begin())
- OS.indent(Indent);
- OS << "Beginning address index: " << E.Start << '\n';
- OS.indent(Indent) << " Length: " << E.Length << '\n';
- OS.indent(Indent) << " Location description: ";
- for (unsigned char Loc : E.Loc)
- OS << format("%2.2x ", Loc);
- OS << "\n\n";
- }
+ L.dump(OS, IsLittleEndian, AddressSize, MRI, /*Indent=*/12);
+ OS << "\n\n";
}
}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 9ad4b52..261a5ca 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -16,6 +16,7 @@
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "llvm/Object/ObjectFile.h"
@@ -81,6 +82,47 @@
}
}
+static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
+ DWARFUnit *U, unsigned Indent) {
+ DWARFContext &Ctx = U->getContext();
+ const DWARFObject &Obj = Ctx.getDWARFObj();
+ const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
+ if (FormValue.isFormClass(DWARFFormValue::FC_Block) ||
+ FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) {
+ ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
+ DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
+ Ctx.isLittleEndian(), 0);
+ DWARFExpression(Data, U->getVersion(), U->getAddressByteSize())
+ .print(OS, MRI);
+ return;
+ }
+
+ FormValue.dump(OS);
+ if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
+ const DWARFSection &LocSection = Obj.getLocSection();
+ const DWARFSection &LocDWOSection = Obj.getLocDWOSection();
+ uint32_t Offset = *FormValue.getAsSectionOffset();
+
+ if (!LocSection.Data.empty()) {
+ DWARFDebugLoc DebugLoc;
+ DWARFDataExtractor Data(Obj, LocSection, Ctx.isLittleEndian(),
+ Obj.getAddressSize());
+ auto LL = DebugLoc.parseOneLocationList(Data, &Offset);
+ if (LL)
+ LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent);
+ else
+ OS << "error extracting location list.";
+ } else if (!LocDWOSection.Data.empty()) {
+ DataExtractor Data(LocDWOSection.Data, Ctx.isLittleEndian(), 0);
+ auto LL = DWARFDebugLocDWO::parseOneLocationList(Data, &Offset);
+ if (LL)
+ LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent);
+ else
+ OS << "error extracting location list.";
+ }
+ }
+}
+
static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
uint32_t *OffsetPtr, dwarf::Attribute Attr,
dwarf::Form Form, unsigned Indent,
@@ -129,6 +171,9 @@
WithColor(OS, Color) << Name;
else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line)
OS << *formValue.getAsUnsignedConstant();
+ else if (Attr == DW_AT_location || Attr == DW_AT_frame_base ||
+ Attr == DW_AT_data_member_location)
+ dumpLocation(OS, formValue, U, sizeof(BaseIndent) + Indent + 4);
else
formValue.dump(OS, DumpOpts);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
new file mode 100644
index 0000000..3417fee
--- /dev/null
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -0,0 +1,272 @@
+//===-- DWARFExpression.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/Format.h"
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+namespace llvm {
+
+typedef std::vector<DWARFExpression::Operation::Description> DescVector;
+
+static DescVector getDescriptions() {
+ DescVector Descriptions;
+ typedef DWARFExpression::Operation Op;
+ typedef Op::Description Desc;
+
+ Descriptions.resize(0xff);
+ Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr);
+ Descriptions[DW_OP_deref] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1);
+ Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2);
+ Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4);
+ Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4);
+ Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8);
+ Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8);
+ Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_dup] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_drop] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_over] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_swap] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_rot] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_abs] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_and] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_div] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_minus] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_mod] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_mul] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_neg] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_not] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_or] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_plus] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_shl] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_shr] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_shra] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_xor] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_eq] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_ge] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_gt] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_le] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_lt] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_ne] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB);
+ Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_nop] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2);
+ Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4);
+ Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr);
+ Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB);
+ Descriptions[DW_OP_implicit_value] =
+ Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
+ Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ return Descriptions;
+}
+
+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());
+ return Descriptions[OpCode];
+}
+
+static uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) {
+ return (Version == 2) ? AddrSize : 4;
+}
+
+bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version,
+ uint8_t AddressSize, uint32_t Offset) {
+ Opcode = Data.getU8(&Offset);
+
+ Desc = getOpDesc(Opcode);
+ if (Desc.Version == Operation::DwarfNA)
+ return false;
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+ unsigned Signed = Size & Operation::SignBit;
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ switch (Size & ~Operation::SignBit) {
+ case Operation::Size1:
+ Operands[Operand] = Data.getU8(&Offset);
+ if (Signed)
+ Operands[Operand] = (int8_t)Operands[Operand];
+ break;
+ case Operation::Size2:
+ Operands[Operand] = Data.getU16(&Offset);
+ if (Signed)
+ Operands[Operand] = (int16_t)Operands[Operand];
+ break;
+ case Operation::Size4:
+ Operands[Operand] = Data.getU32(&Offset);
+ if (Signed)
+ Operands[Operand] = (int32_t)Operands[Operand];
+ break;
+ case Operation::Size8:
+ Operands[Operand] = Data.getU64(&Offset);
+ break;
+ case Operation::SizeAddr:
+ if (AddressSize == 8) {
+ Operands[Operand] = Data.getU64(&Offset);
+ } else {
+ assert(AddressSize == 4);
+ Operands[Operand] = Data.getU32(&Offset);
+ }
+ break;
+ case Operation::SizeRefAddr:
+ if (getRefAddrSize(AddressSize, Version) == 8) {
+ Operands[Operand] = Data.getU64(&Offset);
+ } else {
+ assert(getRefAddrSize(AddressSize, Version) == 4);
+ Operands[Operand] = Data.getU32(&Offset);
+ }
+ break;
+ case Operation::SizeLEB:
+ if (Signed)
+ Operands[Operand] = Data.getSLEB128(&Offset);
+ else
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case Operation::SizeBlock:
+ // We need a size, so this cannot be the first operand
+ if (Operand == 0)
+ return false;
+ // Store the offset of the block as the value.
+ Operands[Operand] = Offset;
+ Offset += Operands[Operand - 1];
+ break;
+ default:
+ llvm_unreachable("Unknown DWARFExpression Op size");
+ }
+ }
+
+ EndOffset = Offset;
+ return true;
+}
+
+static bool prettyPrintRegisterOp(raw_ostream &OS, uint8_t Opcode,
+ uint64_t Operands[2],
+ const MCRegisterInfo *MRI, bool isEH) {
+ if (!MRI)
+ return false;
+
+ uint64_t DwarfRegNum;
+ unsigned OpNum = 0;
+
+ if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx)
+ DwarfRegNum = Operands[OpNum++];
+ else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
+ DwarfRegNum = Opcode - DW_OP_breg0;
+ else
+ DwarfRegNum = Opcode - DW_OP_reg0;
+
+ int LLVMRegNum = MRI->getLLVMRegNum(DwarfRegNum, isEH);
+ if (LLVMRegNum >= 0) {
+ if (const char *RegName = MRI->getName(LLVMRegNum)) {
+ if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+ Opcode == DW_OP_bregx)
+ OS << format(" %s%+" PRId64, RegName, Operands[OpNum]);
+ else
+ OS << ' ' << RegName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DWARFExpression::Operation::print(raw_ostream &OS,
+ const DWARFExpression *Expr,
+ const MCRegisterInfo *RegInfo,
+ bool isEH) {
+ if (Error) {
+ OS << "decoding error.";
+ return false;
+ }
+
+ StringRef Name = OperationEncodingString(Opcode);
+ assert(!Name.empty() && "DW_OP has no name!");
+ OS << Name;
+
+ if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+ (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) ||
+ Opcode == DW_OP_bregx || Opcode == DW_OP_regx)
+ if (prettyPrintRegisterOp(OS, Opcode, Operands, RegInfo, isEH))
+ return true;
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+ unsigned Signed = Size & Operation::SignBit;
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ 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));
+ } else {
+ if (Signed)
+ OS << format(" %+" PRId64, (int64_t)Operands[Operand]);
+ else
+ OS << format(" 0x%" PRIx64, Operands[Operand]);
+ }
+ }
+ return true;
+}
+
+void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo) {
+ for (auto &Op : *this) {
+ if (!Op.print(OS, this, RegInfo, /* isEH */ false)) {
+ uint32_t FailOffset = Op.getEndOffset();
+ while (FailOffset < Data.getData().size())
+ OS << format(" %02x", Data.getU8(&FailOffset));
+ return;
+ }
+ if (Op.getEndOffset() < Data.getData().size())
+ OS << ", ";
+ }
+}
+
+} // namespace llvm
diff --git a/llvm/lib/DebugInfo/DWARF/LLVMBuild.txt b/llvm/lib/DebugInfo/DWARF/LLVMBuild.txt
index 8242a7f..a212762 100644
--- a/llvm/lib/DebugInfo/DWARF/LLVMBuild.txt
+++ b/llvm/lib/DebugInfo/DWARF/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Library
name = DebugInfoDWARF
parent = DebugInfo
-required_libraries = BinaryFormat Object Support
+required_libraries = BinaryFormat Object MC Support