summaryrefslogtreecommitdiff
path: root/contrib/llvm/lib/DebugInfo/DWARF
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/DebugInfo/DWARF')
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp216
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp887
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp29
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp37
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp1693
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp96
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp139
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp198
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp112
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp134
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp556
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp70
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp1114
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp279
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp101
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp70
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp96
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp248
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp712
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp276
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp679
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp200
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp109
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp48
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp844
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp202
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp1514
27 files changed, 10659 insertions, 0 deletions
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
new file mode 100644
index 000000000000..f49ab40fad9a
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -0,0 +1,216 @@
+//===- DWARFAbbreviationDeclaration.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/DWARFAbbreviationDeclaration.h"
+
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFAbbreviationDeclaration::clear() {
+ Code = 0;
+ Tag = DW_TAG_null;
+ CodeByteSize = 0;
+ HasChildren = false;
+ AttributeSpecs.clear();
+ FixedAttributeSize.reset();
+}
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
+ clear();
+}
+
+bool
+DWARFAbbreviationDeclaration::extract(DataExtractor Data,
+ uint32_t* OffsetPtr) {
+ clear();
+ const uint32_t Offset = *OffsetPtr;
+ Code = Data.getULEB128(OffsetPtr);
+ if (Code == 0) {
+ return false;
+ }
+ CodeByteSize = *OffsetPtr - Offset;
+ Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr));
+ if (Tag == DW_TAG_null) {
+ clear();
+ return false;
+ }
+ uint8_t ChildrenByte = Data.getU8(OffsetPtr);
+ HasChildren = (ChildrenByte == DW_CHILDREN_yes);
+ // Assign a value to our optional FixedAttributeSize member variable. If
+ // this member variable still has a value after the while loop below, then
+ // all attribute data in this abbreviation declaration has a fixed byte size.
+ FixedAttributeSize = FixedSizeInfo();
+
+ // Read all of the abbreviation attributes and forms.
+ while (true) {
+ auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
+ auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
+ if (A && F) {
+ bool IsImplicitConst = (F == DW_FORM_implicit_const);
+ if (IsImplicitConst) {
+ int64_t V = Data.getSLEB128(OffsetPtr);
+ AttributeSpecs.push_back(AttributeSpec(A, F, V));
+ continue;
+ }
+ Optional<uint8_t> ByteSize;
+ // If this abbrevation still has a fixed byte size, then update the
+ // FixedAttributeSize as needed.
+ switch (F) {
+ case DW_FORM_addr:
+ if (FixedAttributeSize)
+ ++FixedAttributeSize->NumAddrs;
+ break;
+
+ case DW_FORM_ref_addr:
+ if (FixedAttributeSize)
+ ++FixedAttributeSize->NumRefAddrs;
+ break;
+
+ case DW_FORM_strp:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
+ case DW_FORM_line_strp:
+ case DW_FORM_sec_offset:
+ case DW_FORM_strp_sup:
+ if (FixedAttributeSize)
+ ++FixedAttributeSize->NumDwarfOffsets;
+ break;
+
+ default:
+ // The form has a byte size that doesn't depend on Params.
+ // If it's a fixed size, keep track of it.
+ if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
+ if (FixedAttributeSize)
+ FixedAttributeSize->NumBytes += *ByteSize;
+ break;
+ }
+ // Indicate we no longer have a fixed byte size for this
+ // abbreviation by clearing the FixedAttributeSize optional value
+ // so it doesn't have a value.
+ FixedAttributeSize.reset();
+ break;
+ }
+ // Record this attribute and its fixed size if it has one.
+ AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));
+ } else if (A == 0 && F == 0) {
+ // We successfully reached the end of this abbreviation declaration
+ // since both attribute and form are zero.
+ break;
+ } else {
+ // Attribute and form pairs must either both be non-zero, in which case
+ // they are added to the abbreviation declaration, or both be zero to
+ // terminate the abbrevation declaration. In this case only one was
+ // zero which is an error.
+ clear();
+ return false;
+ }
+ }
+ return true;
+}
+
+void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
+ OS << '[' << getCode() << "] ";
+ OS << formatv("{0}", getTag());
+ OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
+ for (const AttributeSpec &Spec : AttributeSpecs) {
+ OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
+ if (Spec.isImplicitConst())
+ OS << '\t' << Spec.getImplicitConstValue();
+ OS << '\n';
+ }
+ OS << '\n';
+}
+
+Optional<uint32_t>
+DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
+ for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
+ if (AttributeSpecs[i].Attr == Attr)
+ return i;
+ }
+ return None;
+}
+
+Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue(
+ const uint32_t DIEOffset, const dwarf::Attribute Attr,
+ const DWARFUnit &U) const {
+ Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
+ if (!MatchAttrIndex)
+ return None;
+
+ auto DebugInfoData = U.getDebugInfoExtractor();
+
+ // Add the byte size of ULEB that for the abbrev Code so we can start
+ // skipping the attribute data.
+ uint32_t Offset = DIEOffset + CodeByteSize;
+ uint32_t AttrIndex = 0;
+ for (const auto &Spec : AttributeSpecs) {
+ if (*MatchAttrIndex == AttrIndex) {
+ // We have arrived at the attribute to extract, extract if from Offset.
+ DWARFFormValue FormValue(Spec.Form);
+ if (Spec.isImplicitConst()) {
+ FormValue.setSValue(Spec.getImplicitConstValue());
+ return FormValue;
+ }
+ if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
+ return FormValue;
+ }
+ // March Offset along until we get to the attribute we want.
+ if (auto FixedSize = Spec.getByteSize(U))
+ Offset += *FixedSize;
+ else
+ DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset,
+ U.getFormParams());
+ ++AttrIndex;
+ }
+ return None;
+}
+
+size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
+ const DWARFUnit &U) const {
+ size_t ByteSize = NumBytes;
+ if (NumAddrs)
+ ByteSize += NumAddrs * U.getAddressByteSize();
+ if (NumRefAddrs)
+ ByteSize += NumRefAddrs * U.getRefAddrByteSize();
+ if (NumDwarfOffsets)
+ ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
+ return ByteSize;
+}
+
+Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
+ const DWARFUnit &U) const {
+ if (isImplicitConst())
+ return 0;
+ if (ByteSize.HasByteSize)
+ return ByteSize.ByteSize;
+ Optional<int64_t> S;
+ auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
+ if (FixedByteSize)
+ S = *FixedByteSize;
+ return S;
+}
+
+Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
+ const DWARFUnit &U) const {
+ if (FixedAttributeSize)
+ return FixedAttributeSize->getByteSize(U);
+ return None;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
new file mode 100644
index 000000000000..54daf34ff253
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -0,0 +1,887 @@
+//===- DWARFAcceleratorTable.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/DWARFAcceleratorTable.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+
+namespace {
+struct Atom {
+ unsigned Value;
+};
+
+static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) {
+ StringRef Str = dwarf::AtomTypeString(A.Value);
+ if (!Str.empty())
+ return OS << Str;
+ return OS << "DW_ATOM_unknown_" << format("%x", A.Value);
+}
+} // namespace
+
+static Atom formatAtom(unsigned Atom) { return {Atom}; }
+
+DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;
+
+llvm::Error AppleAcceleratorTable::extract() {
+ uint32_t Offset = 0;
+
+ // Check that we can at least read the header.
+ if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4))
+ return createStringError(errc::illegal_byte_sequence,
+ "Section too small: cannot read header.");
+
+ Hdr.Magic = AccelSection.getU32(&Offset);
+ Hdr.Version = AccelSection.getU16(&Offset);
+ Hdr.HashFunction = AccelSection.getU16(&Offset);
+ Hdr.BucketCount = AccelSection.getU32(&Offset);
+ Hdr.HashCount = AccelSection.getU32(&Offset);
+ Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
+
+ // Check that we can read all the hashes and offsets from the
+ // section (see SourceLevelDebugging.rst for the structure of the index).
+ // We need to substract one because we're checking for an *offset* which is
+ // equal to the size for an empty table and hence pointer after the section.
+ if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
+ Hdr.BucketCount * 4 + Hdr.HashCount * 8 - 1))
+ return createStringError(
+ errc::illegal_byte_sequence,
+ "Section too small: cannot read buckets and hashes.");
+
+ HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
+ uint32_t NumAtoms = AccelSection.getU32(&Offset);
+
+ for (unsigned i = 0; i < NumAtoms; ++i) {
+ uint16_t AtomType = AccelSection.getU16(&Offset);
+ auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));
+ HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
+ }
+
+ IsValid = true;
+ return Error::success();
+}
+
+uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.BucketCount; }
+uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.HashCount; }
+uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
+uint32_t AppleAcceleratorTable::getHeaderDataLength() {
+ return Hdr.HeaderDataLength;
+}
+
+ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,
+ AppleAcceleratorTable::HeaderData::Form>>
+AppleAcceleratorTable::getAtomsDesc() {
+ return HdrData.Atoms;
+}
+
+bool AppleAcceleratorTable::validateForms() {
+ for (auto Atom : getAtomsDesc()) {
+ DWARFFormValue FormValue(Atom.second);
+ switch (Atom.first) {
+ case dwarf::DW_ATOM_die_offset:
+ case dwarf::DW_ATOM_die_tag:
+ case dwarf::DW_ATOM_type_flags:
+ if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
+ !FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
+ FormValue.getForm() == dwarf::DW_FORM_sdata)
+ return false;
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+std::pair<uint32_t, dwarf::Tag>
+AppleAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
+ uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
+ dwarf::Tag DieTag = dwarf::DW_TAG_null;
+ dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+
+ for (auto Atom : getAtomsDesc()) {
+ DWARFFormValue FormValue(Atom.second);
+ FormValue.extractValue(AccelSection, &HashDataOffset, FormParams);
+ switch (Atom.first) {
+ case dwarf::DW_ATOM_die_offset:
+ DieOffset = *FormValue.getAsUnsignedConstant();
+ break;
+ case dwarf::DW_ATOM_die_tag:
+ DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
+ break;
+ default:
+ break;
+ }
+ }
+ return {DieOffset, DieTag};
+}
+
+void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const {
+ DictScope HeaderScope(W, "Header");
+ W.printHex("Magic", Magic);
+ W.printHex("Version", Version);
+ W.printHex("Hash function", HashFunction);
+ W.printNumber("Bucket count", BucketCount);
+ W.printNumber("Hashes count", HashCount);
+ W.printNumber("HeaderData length", HeaderDataLength);
+}
+
+Optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset(
+ Optional<DWARFFormValue> Value) const {
+ if (!Value)
+ return None;
+
+ switch (Value->getForm()) {
+ case dwarf::DW_FORM_ref1:
+ case dwarf::DW_FORM_ref2:
+ case dwarf::DW_FORM_ref4:
+ case dwarf::DW_FORM_ref8:
+ case dwarf::DW_FORM_ref_udata:
+ return Value->getRawUValue() + DIEOffsetBase;
+ default:
+ return Value->getAsSectionOffset();
+ }
+}
+
+bool AppleAcceleratorTable::dumpName(ScopedPrinter &W,
+ SmallVectorImpl<DWARFFormValue> &AtomForms,
+ uint32_t *DataOffset) const {
+ dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+ uint32_t NameOffset = *DataOffset;
+ if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) {
+ W.printString("Incorrectly terminated list.");
+ return false;
+ }
+ unsigned StringOffset = AccelSection.getRelocatedValue(4, DataOffset);
+ if (!StringOffset)
+ return false; // End of list
+
+ DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str());
+ W.startLine() << format("String: 0x%08x", StringOffset);
+ W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n";
+
+ unsigned NumData = AccelSection.getU32(DataOffset);
+ for (unsigned Data = 0; Data < NumData; ++Data) {
+ ListScope DataScope(W, ("Data " + Twine(Data)).str());
+ unsigned i = 0;
+ for (auto &Atom : AtomForms) {
+ W.startLine() << format("Atom[%d]: ", i);
+ if (Atom.extractValue(AccelSection, DataOffset, FormParams)) {
+ Atom.dump(W.getOStream());
+ if (Optional<uint64_t> Val = Atom.getAsUnsignedConstant()) {
+ StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val);
+ if (!Str.empty())
+ W.getOStream() << " (" << Str << ")";
+ }
+ } else
+ W.getOStream() << "Error extracting the value";
+ W.getOStream() << "\n";
+ i++;
+ }
+ }
+ return true; // more entries follow
+}
+
+LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
+ if (!IsValid)
+ return;
+
+ ScopedPrinter W(OS);
+
+ Hdr.dump(W);
+
+ W.printNumber("DIE offset base", HdrData.DIEOffsetBase);
+ W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size()));
+ SmallVector<DWARFFormValue, 3> AtomForms;
+ {
+ ListScope AtomsScope(W, "Atoms");
+ unsigned i = 0;
+ for (const auto &Atom : HdrData.Atoms) {
+ DictScope AtomScope(W, ("Atom " + Twine(i++)).str());
+ W.startLine() << "Type: " << formatAtom(Atom.first) << '\n';
+ W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n';
+ AtomForms.push_back(DWARFFormValue(Atom.second));
+ }
+ }
+
+ // Now go through the actual tables and dump them.
+ uint32_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
+ unsigned HashesBase = Offset + Hdr.BucketCount * 4;
+ unsigned OffsetsBase = HashesBase + Hdr.HashCount * 4;
+
+ for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) {
+ unsigned Index = AccelSection.getU32(&Offset);
+
+ ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
+ if (Index == UINT32_MAX) {
+ W.printString("EMPTY");
+ continue;
+ }
+
+ for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
+ unsigned HashOffset = HashesBase + HashIdx*4;
+ unsigned OffsetsOffset = OffsetsBase + HashIdx*4;
+ uint32_t Hash = AccelSection.getU32(&HashOffset);
+
+ if (Hash % Hdr.BucketCount != Bucket)
+ break;
+
+ unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
+ ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str());
+ if (!AccelSection.isValidOffset(DataOffset)) {
+ W.printString("Invalid section offset");
+ continue;
+ }
+ while (dumpName(W, AtomForms, &DataOffset))
+ /*empty*/;
+ }
+ }
+}
+
+AppleAcceleratorTable::Entry::Entry(
+ const AppleAcceleratorTable::HeaderData &HdrData)
+ : HdrData(&HdrData) {
+ Values.reserve(HdrData.Atoms.size());
+ for (const auto &Atom : HdrData.Atoms)
+ Values.push_back(DWARFFormValue(Atom.second));
+}
+
+void AppleAcceleratorTable::Entry::extract(
+ const AppleAcceleratorTable &AccelTable, uint32_t *Offset) {
+
+ dwarf::FormParams FormParams = {AccelTable.Hdr.Version, 0,
+ dwarf::DwarfFormat::DWARF32};
+ for (auto &Atom : Values)
+ Atom.extractValue(AccelTable.AccelSection, Offset, FormParams);
+}
+
+Optional<DWARFFormValue>
+AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const {
+ assert(HdrData && "Dereferencing end iterator?");
+ assert(HdrData->Atoms.size() == Values.size());
+ for (const auto &Tuple : zip_first(HdrData->Atoms, Values)) {
+ if (std::get<0>(Tuple).first == Atom)
+ return std::get<1>(Tuple);
+ }
+ return None;
+}
+
+Optional<uint64_t> AppleAcceleratorTable::Entry::getDIESectionOffset() const {
+ return HdrData->extractOffset(lookup(dwarf::DW_ATOM_die_offset));
+}
+
+Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const {
+ return HdrData->extractOffset(lookup(dwarf::DW_ATOM_cu_offset));
+}
+
+Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const {
+ Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag);
+ if (!Tag)
+ return None;
+ if (Optional<uint64_t> Value = Tag->getAsUnsignedConstant())
+ return dwarf::Tag(*Value);
+ return None;
+}
+
+AppleAcceleratorTable::ValueIterator::ValueIterator(
+ const AppleAcceleratorTable &AccelTable, unsigned Offset)
+ : AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) {
+ if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
+ return;
+
+ // Read the first entry.
+ NumData = AccelTable.AccelSection.getU32(&DataOffset);
+ Next();
+}
+
+void AppleAcceleratorTable::ValueIterator::Next() {
+ assert(NumData > 0 && "attempted to increment iterator past the end");
+ auto &AccelSection = AccelTable->AccelSection;
+ if (Data >= NumData ||
+ !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
+ NumData = 0;
+ DataOffset = 0;
+ return;
+ }
+ Current.extract(*AccelTable, &DataOffset);
+ ++Data;
+}
+
+iterator_range<AppleAcceleratorTable::ValueIterator>
+AppleAcceleratorTable::equal_range(StringRef Key) const {
+ if (!IsValid)
+ return make_range(ValueIterator(), ValueIterator());
+
+ // Find the bucket.
+ unsigned HashValue = djbHash(Key);
+ unsigned Bucket = HashValue % Hdr.BucketCount;
+ unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
+ unsigned HashesBase = BucketBase + Hdr.BucketCount * 4;
+ unsigned OffsetsBase = HashesBase + Hdr.HashCount * 4;
+
+ unsigned BucketOffset = BucketBase + Bucket * 4;
+ unsigned Index = AccelSection.getU32(&BucketOffset);
+
+ // Search through all hashes in the bucket.
+ for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
+ unsigned HashOffset = HashesBase + HashIdx * 4;
+ unsigned OffsetsOffset = OffsetsBase + HashIdx * 4;
+ uint32_t Hash = AccelSection.getU32(&HashOffset);
+
+ if (Hash % Hdr.BucketCount != Bucket)
+ // We are already in the next bucket.
+ break;
+
+ unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
+ unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
+ if (!StringOffset)
+ break;
+
+ // Finally, compare the key.
+ if (Key == StringSection.getCStr(&StringOffset))
+ return make_range({*this, DataOffset}, ValueIterator());
+ }
+ return make_range(ValueIterator(), ValueIterator());
+}
+
+void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {
+ DictScope HeaderScope(W, "Header");
+ W.printHex("Length", UnitLength);
+ W.printNumber("Version", Version);
+ W.printHex("Padding", Padding);
+ W.printNumber("CU count", CompUnitCount);
+ W.printNumber("Local TU count", LocalTypeUnitCount);
+ W.printNumber("Foreign TU count", ForeignTypeUnitCount);
+ W.printNumber("Bucket count", BucketCount);
+ W.printNumber("Name count", NameCount);
+ W.printHex("Abbreviations table size", AbbrevTableSize);
+ W.startLine() << "Augmentation: '" << AugmentationString << "'\n";
+}
+
+llvm::Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,
+ uint32_t *Offset) {
+ // Check that we can read the fixed-size part.
+ if (!AS.isValidOffset(*Offset + sizeof(HeaderPOD) - 1))
+ return createStringError(errc::illegal_byte_sequence,
+ "Section too small: cannot read header.");
+
+ UnitLength = AS.getU32(Offset);
+ Version = AS.getU16(Offset);
+ Padding = AS.getU16(Offset);
+ CompUnitCount = AS.getU32(Offset);
+ LocalTypeUnitCount = AS.getU32(Offset);
+ ForeignTypeUnitCount = AS.getU32(Offset);
+ BucketCount = AS.getU32(Offset);
+ NameCount = AS.getU32(Offset);
+ AbbrevTableSize = AS.getU32(Offset);
+ AugmentationStringSize = alignTo(AS.getU32(Offset), 4);
+
+ if (!AS.isValidOffsetForDataOfSize(*Offset, AugmentationStringSize))
+ return createStringError(
+ errc::illegal_byte_sequence,
+ "Section too small: cannot read header augmentation.");
+ AugmentationString.resize(AugmentationStringSize);
+ AS.getU8(Offset, reinterpret_cast<uint8_t *>(AugmentationString.data()),
+ AugmentationStringSize);
+ return Error::success();
+}
+
+void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const {
+ DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str());
+ W.startLine() << formatv("Tag: {0}\n", Tag);
+
+ for (const auto &Attr : Attributes)
+ W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form);
+}
+
+static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() {
+ return {dwarf::Index(0), dwarf::Form(0)};
+}
+
+static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) {
+ return AE == sentinelAttrEnc();
+}
+
+static DWARFDebugNames::Abbrev sentinelAbbrev() {
+ return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {});
+}
+
+static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) {
+ return Abbr.Code == 0;
+}
+
+DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {
+ return sentinelAbbrev();
+}
+
+DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() {
+ return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {});
+}
+
+Expected<DWARFDebugNames::AttributeEncoding>
+DWARFDebugNames::NameIndex::extractAttributeEncoding(uint32_t *Offset) {
+ if (*Offset >= EntriesBase) {
+ return createStringError(errc::illegal_byte_sequence,
+ "Incorrectly terminated abbreviation table.");
+ }
+
+ uint32_t Index = Section.AccelSection.getULEB128(Offset);
+ uint32_t Form = Section.AccelSection.getULEB128(Offset);
+ return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form));
+}
+
+Expected<std::vector<DWARFDebugNames::AttributeEncoding>>
+DWARFDebugNames::NameIndex::extractAttributeEncodings(uint32_t *Offset) {
+ std::vector<AttributeEncoding> Result;
+ for (;;) {
+ auto AttrEncOr = extractAttributeEncoding(Offset);
+ if (!AttrEncOr)
+ return AttrEncOr.takeError();
+ if (isSentinel(*AttrEncOr))
+ return std::move(Result);
+
+ Result.emplace_back(*AttrEncOr);
+ }
+}
+
+Expected<DWARFDebugNames::Abbrev>
+DWARFDebugNames::NameIndex::extractAbbrev(uint32_t *Offset) {
+ if (*Offset >= EntriesBase) {
+ return createStringError(errc::illegal_byte_sequence,
+ "Incorrectly terminated abbreviation table.");
+ }
+
+ uint32_t Code = Section.AccelSection.getULEB128(Offset);
+ if (Code == 0)
+ return sentinelAbbrev();
+
+ uint32_t Tag = Section.AccelSection.getULEB128(Offset);
+ auto AttrEncOr = extractAttributeEncodings(Offset);
+ if (!AttrEncOr)
+ return AttrEncOr.takeError();
+ return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr));
+}
+
+Error DWARFDebugNames::NameIndex::extract() {
+ const DWARFDataExtractor &AS = Section.AccelSection;
+ uint32_t Offset = Base;
+ if (Error E = Hdr.extract(AS, &Offset))
+ return E;
+
+ CUsBase = Offset;
+ Offset += Hdr.CompUnitCount * 4;
+ Offset += Hdr.LocalTypeUnitCount * 4;
+ Offset += Hdr.ForeignTypeUnitCount * 8;
+ BucketsBase = Offset;
+ Offset += Hdr.BucketCount * 4;
+ HashesBase = Offset;
+ if (Hdr.BucketCount > 0)
+ Offset += Hdr.NameCount * 4;
+ StringOffsetsBase = Offset;
+ Offset += Hdr.NameCount * 4;
+ EntryOffsetsBase = Offset;
+ Offset += Hdr.NameCount * 4;
+
+ if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize))
+ return createStringError(errc::illegal_byte_sequence,
+ "Section too small: cannot read abbreviations.");
+
+ EntriesBase = Offset + Hdr.AbbrevTableSize;
+
+ for (;;) {
+ auto AbbrevOr = extractAbbrev(&Offset);
+ if (!AbbrevOr)
+ return AbbrevOr.takeError();
+ if (isSentinel(*AbbrevOr))
+ return Error::success();
+
+ if (!Abbrevs.insert(std::move(*AbbrevOr)).second)
+ return createStringError(errc::invalid_argument,
+ "Duplicate abbreviation code.");
+ }
+}
+DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr)
+ : NameIdx(&NameIdx), Abbr(&Abbr) {
+ // This merely creates form values. It is up to the caller
+ // (NameIndex::getEntry) to populate them.
+ Values.reserve(Abbr.Attributes.size());
+ for (const auto &Attr : Abbr.Attributes)
+ Values.emplace_back(Attr.Form);
+}
+
+Optional<DWARFFormValue>
+DWARFDebugNames::Entry::lookup(dwarf::Index Index) const {
+ assert(Abbr->Attributes.size() == Values.size());
+ for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) {
+ if (std::get<0>(Tuple).Index == Index)
+ return std::get<1>(Tuple);
+ }
+ return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const {
+ if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset))
+ return Off->getAsReferenceUVal();
+ return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
+ if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
+ return Off->getAsUnsignedConstant();
+ // In a per-CU index, the entries without a DW_IDX_compile_unit attribute
+ // implicitly refer to the single CU.
+ if (NameIdx->getCUCount() == 1)
+ return 0;
+ return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
+ Optional<uint64_t> Index = getCUIndex();
+ if (!Index || *Index >= NameIdx->getCUCount())
+ return None;
+ return NameIdx->getCUOffset(*Index);
+}
+
+void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
+ W.printHex("Abbrev", Abbr->Code);
+ W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);
+ assert(Abbr->Attributes.size() == Values.size());
+ for (const auto &Tuple : zip_first(Abbr->Attributes, Values)) {
+ W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index);
+ std::get<1>(Tuple).dump(W.getOStream());
+ W.getOStream() << '\n';
+ }
+}
+
+char DWARFDebugNames::SentinelError::ID;
+std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const {
+ return inconvertibleErrorCode();
+}
+
+uint32_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const {
+ assert(CU < Hdr.CompUnitCount);
+ uint32_t Offset = CUsBase + 4 * CU;
+ return Section.AccelSection.getRelocatedValue(4, &Offset);
+}
+
+uint32_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const {
+ assert(TU < Hdr.LocalTypeUnitCount);
+ uint32_t Offset = CUsBase + Hdr.CompUnitCount * 4;
+ return Section.AccelSection.getRelocatedValue(4, &Offset);
+}
+
+uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const {
+ assert(TU < Hdr.ForeignTypeUnitCount);
+ uint32_t Offset = CUsBase + (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) * 4;
+ return Section.AccelSection.getU64(&Offset);
+}
+
+Expected<DWARFDebugNames::Entry>
+DWARFDebugNames::NameIndex::getEntry(uint32_t *Offset) const {
+ const DWARFDataExtractor &AS = Section.AccelSection;
+ if (!AS.isValidOffset(*Offset))
+ return createStringError(errc::illegal_byte_sequence,
+ "Incorrectly terminated entry list.");
+
+ uint32_t AbbrevCode = AS.getULEB128(Offset);
+ if (AbbrevCode == 0)
+ return make_error<SentinelError>();
+
+ const auto AbbrevIt = Abbrevs.find_as(AbbrevCode);
+ if (AbbrevIt == Abbrevs.end())
+ return createStringError(errc::invalid_argument, "Invalid abbreviation.");
+
+ Entry E(*this, *AbbrevIt);
+
+ dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+ for (auto &Value : E.Values) {
+ if (!Value.extractValue(AS, Offset, FormParams))
+ return createStringError(errc::io_error,
+ "Error extracting index attribute values.");
+ }
+ return std::move(E);
+}
+
+DWARFDebugNames::NameTableEntry
+DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const {
+ assert(0 < Index && Index <= Hdr.NameCount);
+ uint32_t StringOffsetOffset = StringOffsetsBase + 4 * (Index - 1);
+ uint32_t EntryOffsetOffset = EntryOffsetsBase + 4 * (Index - 1);
+ const DWARFDataExtractor &AS = Section.AccelSection;
+
+ uint32_t StringOffset = AS.getRelocatedValue(4, &StringOffsetOffset);
+ uint32_t EntryOffset = AS.getU32(&EntryOffsetOffset);
+ EntryOffset += EntriesBase;
+ return {Section.StringSection, Index, StringOffset, EntryOffset};
+}
+
+uint32_t
+DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const {
+ assert(Bucket < Hdr.BucketCount);
+ uint32_t BucketOffset = BucketsBase + 4 * Bucket;
+ return Section.AccelSection.getU32(&BucketOffset);
+}
+
+uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const {
+ assert(0 < Index && Index <= Hdr.NameCount);
+ uint32_t HashOffset = HashesBase + 4 * (Index - 1);
+ return Section.AccelSection.getU32(&HashOffset);
+}
+
+// Returns true if we should continue scanning for entries, false if this is the
+// last (sentinel) entry). In case of a parsing error we also return false, as
+// it's not possible to recover this entry list (but the other lists may still
+// parse OK).
+bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,
+ uint32_t *Offset) const {
+ uint32_t EntryId = *Offset;
+ auto EntryOr = getEntry(Offset);
+ if (!EntryOr) {
+ handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},
+ [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
+ return false;
+ }
+
+ DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str());
+ EntryOr->dump(W);
+ return true;
+}
+
+void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W,
+ const NameTableEntry &NTE,
+ Optional<uint32_t> Hash) const {
+ DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str());
+ if (Hash)
+ W.printHex("Hash", *Hash);
+
+ W.startLine() << format("String: 0x%08x", NTE.getStringOffset());
+ W.getOStream() << " \"" << NTE.getString() << "\"\n";
+
+ uint32_t EntryOffset = NTE.getEntryOffset();
+ while (dumpEntry(W, &EntryOffset))
+ /*empty*/;
+}
+
+void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const {
+ ListScope CUScope(W, "Compilation Unit offsets");
+ for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU)
+ W.startLine() << format("CU[%u]: 0x%08x\n", CU, getCUOffset(CU));
+}
+
+void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const {
+ if (Hdr.LocalTypeUnitCount == 0)
+ return;
+
+ ListScope TUScope(W, "Local Type Unit offsets");
+ for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU)
+ W.startLine() << format("LocalTU[%u]: 0x%08x\n", TU, getLocalTUOffset(TU));
+}
+
+void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const {
+ if (Hdr.ForeignTypeUnitCount == 0)
+ return;
+
+ ListScope TUScope(W, "Foreign Type Unit signatures");
+ for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) {
+ W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU,
+ getForeignTUSignature(TU));
+ }
+}
+
+void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const {
+ ListScope AbbrevsScope(W, "Abbreviations");
+ for (const auto &Abbr : Abbrevs)
+ Abbr.dump(W);
+}
+
+void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W,
+ uint32_t Bucket) const {
+ ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
+ uint32_t Index = getBucketArrayEntry(Bucket);
+ if (Index == 0) {
+ W.printString("EMPTY");
+ return;
+ }
+ if (Index > Hdr.NameCount) {
+ W.printString("Name index is invalid");
+ return;
+ }
+
+ for (; Index <= Hdr.NameCount; ++Index) {
+ uint32_t Hash = getHashArrayEntry(Index);
+ if (Hash % Hdr.BucketCount != Bucket)
+ break;
+
+ dumpName(W, getNameTableEntry(Index), Hash);
+ }
+}
+
+LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const {
+ DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str());
+ Hdr.dump(W);
+ dumpCUs(W);
+ dumpLocalTUs(W);
+ dumpForeignTUs(W);
+ dumpAbbreviations(W);
+
+ if (Hdr.BucketCount > 0) {
+ for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket)
+ dumpBucket(W, Bucket);
+ return;
+ }
+
+ W.startLine() << "Hash table not present\n";
+ for (NameTableEntry NTE : *this)
+ dumpName(W, NTE, None);
+}
+
+llvm::Error DWARFDebugNames::extract() {
+ uint32_t Offset = 0;
+ while (AccelSection.isValidOffset(Offset)) {
+ NameIndex Next(*this, Offset);
+ if (llvm::Error E = Next.extract())
+ return E;
+ Offset = Next.getNextUnitOffset();
+ NameIndices.push_back(std::move(Next));
+ }
+ return Error::success();
+}
+
+iterator_range<DWARFDebugNames::ValueIterator>
+DWARFDebugNames::NameIndex::equal_range(StringRef Key) const {
+ return make_range(ValueIterator(*this, Key), ValueIterator());
+}
+
+LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const {
+ ScopedPrinter W(OS);
+ for (const NameIndex &NI : NameIndices)
+ NI.dump(W);
+}
+
+Optional<uint32_t>
+DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() {
+ const Header &Hdr = CurrentIndex->Hdr;
+ if (Hdr.BucketCount == 0) {
+ // No Hash Table, We need to search through all names in the Name Index.
+ for (NameTableEntry NTE : *CurrentIndex) {
+ if (NTE.getString() == Key)
+ return NTE.getEntryOffset();
+ }
+ return None;
+ }
+
+ // The Name Index has a Hash Table, so use that to speed up the search.
+ // Compute the Key Hash, if it has not been done already.
+ if (!Hash)
+ Hash = caseFoldingDjbHash(Key);
+ uint32_t Bucket = *Hash % Hdr.BucketCount;
+ uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket);
+ if (Index == 0)
+ return None; // Empty bucket
+
+ for (; Index <= Hdr.NameCount; ++Index) {
+ uint32_t Hash = CurrentIndex->getHashArrayEntry(Index);
+ if (Hash % Hdr.BucketCount != Bucket)
+ return None; // End of bucket
+
+ NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index);
+ if (NTE.getString() == Key)
+ return NTE.getEntryOffset();
+ }
+ return None;
+}
+
+bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() {
+ auto EntryOr = CurrentIndex->getEntry(&DataOffset);
+ if (!EntryOr) {
+ consumeError(EntryOr.takeError());
+ return false;
+ }
+ CurrentEntry = std::move(*EntryOr);
+ return true;
+}
+
+bool DWARFDebugNames::ValueIterator::findInCurrentIndex() {
+ Optional<uint32_t> Offset = findEntryOffsetInCurrentIndex();
+ if (!Offset)
+ return false;
+ DataOffset = *Offset;
+ return getEntryAtCurrentOffset();
+}
+
+void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() {
+ for (const NameIndex *End = CurrentIndex->Section.NameIndices.end();
+ CurrentIndex != End; ++CurrentIndex) {
+ if (findInCurrentIndex())
+ return;
+ }
+ setEnd();
+}
+
+void DWARFDebugNames::ValueIterator::next() {
+ assert(CurrentIndex && "Incrementing an end() iterator?");
+
+ // First try the next entry in the current Index.
+ if (getEntryAtCurrentOffset())
+ return;
+
+ // If we're a local iterator or we have reached the last Index, we're done.
+ if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) {
+ setEnd();
+ return;
+ }
+
+ // Otherwise, try the next index.
+ ++CurrentIndex;
+ searchFromStartOfCurrentIndex();
+}
+
+DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable,
+ StringRef Key)
+ : CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false), Key(Key) {
+ searchFromStartOfCurrentIndex();
+}
+
+DWARFDebugNames::ValueIterator::ValueIterator(
+ const DWARFDebugNames::NameIndex &NI, StringRef Key)
+ : CurrentIndex(&NI), IsLocal(true), Key(Key) {
+ if (!findInCurrentIndex())
+ setEnd();
+}
+
+iterator_range<DWARFDebugNames::ValueIterator>
+DWARFDebugNames::equal_range(StringRef Key) const {
+ if (NameIndices.empty())
+ return make_range(ValueIterator(), ValueIterator());
+ return make_range(ValueIterator(*this, Key), ValueIterator());
+}
+
+const DWARFDebugNames::NameIndex *
+DWARFDebugNames::getCUNameIndex(uint32_t CUOffset) {
+ if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) {
+ for (const auto &NI : *this) {
+ for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU)
+ CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI);
+ }
+ }
+ return CUToNameIndex.lookup(CUOffset);
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp
new file mode 100644
index 000000000000..86c8d19c02f4
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp
@@ -0,0 +1,29 @@
+//===- DWARFDebugAranges.cpp ------------------------------------*- C++ -*-===//
+//
+// 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/DWARFAddressRange.h"
+
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize,
+ DIDumpOptions DumpOpts) const {
+
+ OS << (DumpOpts.DisplayRawContents ? " " : "[");
+ OS << format("0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, LowPC)
+ << format("0x%*.*" PRIx64, AddressSize * 2, AddressSize * 2, HighPC);
+ OS << (DumpOpts.DisplayRawContents ? "" : ")");
+}
+
+raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) {
+ R.dump(OS, /* AddressSize */ 8);
+ return OS;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
new file mode 100644
index 000000000000..00a23b3898fa
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
@@ -0,0 +1,37 @@
+//===-- DWARFCompileUnit.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/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
+ OS << format("0x%08x", getOffset()) << ": Compile Unit:"
+ << " length = " << format("0x%08x", getLength())
+ << " version = " << format("0x%04x", getVersion());
+ if (getVersion() >= 5)
+ OS << " unit_type = " << dwarf::UnitTypeString(getUnitType());
+ OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset())
+ << " addr_size = " << format("0x%02x", getAddressByteSize());
+ if (getVersion() >= 5 && getUnitType() != dwarf::DW_UT_compile)
+ OS << " DWO_id = " << format("0x%016" PRIx64, *getDWOId());
+ OS << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n";
+
+ if (DWARFDie CUDie = getUnitDIE(false))
+ CUDie.dump(OS, 0, DumpOpts);
+ else
+ OS << "<compile unit can't be parsed!>\n\n";
+}
+
+// VTable anchor.
+DWARFCompileUnit::~DWARFCompileUnit() = default;
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
new file mode 100644
index 000000000000..e6620ee3dd1d
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -0,0 +1,1693 @@
+//===- DWARFContext.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/DWARFContext.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h"
+#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"
+#include "llvm/Object/RelocVisitor.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdint>
+#include <deque>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+#define DEBUG_TYPE "dwarf"
+
+using DWARFLineTable = DWARFDebugLine::LineTable;
+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;
+
+/// Dump the UUID load command.
+static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) {
+ auto *MachO = dyn_cast<MachOObjectFile>(&Obj);
+ if (!MachO)
+ return;
+ for (auto LC : MachO->load_commands()) {
+ raw_ostream::uuid_t UUID;
+ if (LC.C.cmd == MachO::LC_UUID) {
+ if (LC.C.cmdsize < sizeof(UUID) + sizeof(LC.C)) {
+ OS << "error: UUID load command is too short.\n";
+ return;
+ }
+ OS << "UUID: ";
+ memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID));
+ OS.write_uuid(UUID);
+ Triple T = MachO->getArchTriple();
+ OS << " (" << T.getArchName() << ')';
+ OS << ' ' << MachO->getFileName() << '\n';
+ }
+ }
+}
+
+using ContributionCollection =
+ std::vector<Optional<StrOffsetsContributionDescriptor>>;
+
+// Collect all the contributions to the string offsets table from all units,
+// sort them by their starting offsets and remove duplicates.
+static ContributionCollection
+collectContributionData(DWARFContext::unit_iterator_range Units) {
+ ContributionCollection Contributions;
+ for (const auto &U : Units)
+ Contributions.push_back(U->getStringOffsetsTableContribution());
+ // Sort the contributions so that any invalid ones are placed at
+ // the start of the contributions vector. This way they are reported
+ // first.
+ llvm::sort(Contributions,
+ [](const Optional<StrOffsetsContributionDescriptor> &L,
+ const Optional<StrOffsetsContributionDescriptor> &R) {
+ if (L && R)
+ return L->Base < R->Base;
+ return R.hasValue();
+ });
+
+ // Uniquify contributions, as it is possible that units (specifically
+ // type units in dwo or dwp files) share contributions. We don't want
+ // to report them more than once.
+ Contributions.erase(
+ std::unique(Contributions.begin(), Contributions.end(),
+ [](const Optional<StrOffsetsContributionDescriptor> &L,
+ const Optional<StrOffsetsContributionDescriptor> &R) {
+ if (L && R)
+ return L->Base == R->Base && L->Size == R->Size;
+ return false;
+ }),
+ Contributions.end());
+ return Contributions;
+}
+
+static void dumpDWARFv5StringOffsetsSection(
+ raw_ostream &OS, StringRef SectionName, const DWARFObject &Obj,
+ const DWARFSection &StringOffsetsSection, StringRef StringSection,
+ DWARFContext::unit_iterator_range Units, bool LittleEndian) {
+ auto Contributions = collectContributionData(Units);
+ DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0);
+ DataExtractor StrData(StringSection, LittleEndian, 0);
+ uint64_t SectionSize = StringOffsetsSection.Data.size();
+ uint32_t Offset = 0;
+ for (auto &Contribution : Contributions) {
+ // Report an ill-formed contribution.
+ if (!Contribution) {
+ OS << "error: invalid contribution to string offsets table in section ."
+ << SectionName << ".\n";
+ return;
+ }
+
+ dwarf::DwarfFormat Format = Contribution->getFormat();
+ uint16_t Version = Contribution->getVersion();
+ uint64_t ContributionHeader = Contribution->Base;
+ // In DWARF v5 there is a contribution header that immediately precedes
+ // the string offsets base (the location we have previously retrieved from
+ // the CU DIE's DW_AT_str_offsets attribute). The header is located either
+ // 8 or 16 bytes before the base, depending on the contribution's format.
+ if (Version >= 5)
+ ContributionHeader -= Format == DWARF32 ? 8 : 16;
+
+ // Detect overlapping contributions.
+ if (Offset > ContributionHeader) {
+ OS << "error: overlapping contributions to string offsets table in "
+ "section ."
+ << SectionName << ".\n";
+ return;
+ }
+ // Report a gap in the table.
+ if (Offset < ContributionHeader) {
+ OS << format("0x%8.8x: Gap, length = ", Offset);
+ OS << (ContributionHeader - Offset) << "\n";
+ }
+ OS << format("0x%8.8x: ", (uint32_t)ContributionHeader);
+ // In DWARF v5 the contribution size in the descriptor does not equal
+ // the originally encoded length (it does not contain the length of the
+ // version field and the padding, a total of 4 bytes). Add them back in
+ // for reporting.
+ OS << "Contribution size = " << (Contribution->Size + (Version < 5 ? 0 : 4))
+ << ", Format = " << (Format == DWARF32 ? "DWARF32" : "DWARF64")
+ << ", Version = " << Version << "\n";
+
+ Offset = Contribution->Base;
+ unsigned EntrySize = Contribution->getDwarfOffsetByteSize();
+ while (Offset - Contribution->Base < Contribution->Size) {
+ OS << format("0x%8.8x: ", Offset);
+ // FIXME: We can only extract strings if the offset fits in 32 bits.
+ uint64_t StringOffset =
+ StrOffsetExt.getRelocatedValue(EntrySize, &Offset);
+ // Extract the string if we can and display it. Otherwise just report
+ // the offset.
+ if (StringOffset <= std::numeric_limits<uint32_t>::max()) {
+ uint32_t StringOffset32 = (uint32_t)StringOffset;
+ OS << format("%8.8x ", StringOffset32);
+ const char *S = StrData.getCStr(&StringOffset32);
+ if (S)
+ OS << format("\"%s\"", S);
+ } else
+ OS << format("%16.16" PRIx64 " ", StringOffset);
+ OS << "\n";
+ }
+ }
+ // Report a gap at the end of the table.
+ if (Offset < SectionSize) {
+ OS << format("0x%8.8x: Gap, length = ", Offset);
+ OS << (SectionSize - Offset) << "\n";
+ }
+}
+
+// Dump a DWARF string offsets section. This may be a DWARF v5 formatted
+// string offsets section, where each compile or type unit contributes a
+// number of entries (string offsets), with each contribution preceded by
+// a header containing size and version number. Alternatively, it may be a
+// monolithic series of string offsets, as generated by the pre-DWARF v5
+// implementation of split DWARF.
+static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName,
+ const DWARFObject &Obj,
+ const DWARFSection &StringOffsetsSection,
+ StringRef StringSection,
+ DWARFContext::unit_iterator_range Units,
+ bool LittleEndian, unsigned MaxVersion) {
+ // If we have at least one (compile or type) unit with DWARF v5 or greater,
+ // we assume that the section is formatted like a DWARF v5 string offsets
+ // section.
+ if (MaxVersion >= 5)
+ dumpDWARFv5StringOffsetsSection(OS, SectionName, Obj, StringOffsetsSection,
+ StringSection, Units, LittleEndian);
+ else {
+ DataExtractor strOffsetExt(StringOffsetsSection.Data, LittleEndian, 0);
+ uint32_t offset = 0;
+ uint64_t size = StringOffsetsSection.Data.size();
+ // Ensure that size is a multiple of the size of an entry.
+ if (size & ((uint64_t)(sizeof(uint32_t) - 1))) {
+ OS << "error: size of ." << SectionName << " is not a multiple of "
+ << sizeof(uint32_t) << ".\n";
+ size &= -(uint64_t)sizeof(uint32_t);
+ }
+ DataExtractor StrData(StringSection, LittleEndian, 0);
+ while (offset < size) {
+ OS << format("0x%8.8x: ", offset);
+ uint32_t StringOffset = strOffsetExt.getU32(&offset);
+ OS << format("%8.8x ", StringOffset);
+ const char *S = StrData.getCStr(&StringOffset);
+ if (S)
+ OS << format("\"%s\"", S);
+ OS << "\n";
+ }
+ }
+}
+
+// Dump the .debug_addr section.
+static void dumpAddrSection(raw_ostream &OS, DWARFDataExtractor &AddrData,
+ DIDumpOptions DumpOpts, uint16_t Version,
+ uint8_t AddrSize) {
+ uint32_t Offset = 0;
+ while (AddrData.isValidOffset(Offset)) {
+ DWARFDebugAddrTable AddrTable;
+ uint32_t TableOffset = Offset;
+ if (Error Err = AddrTable.extract(AddrData, &Offset, Version, AddrSize,
+ DWARFContext::dumpWarning)) {
+ WithColor::error() << toString(std::move(Err)) << '\n';
+ // Keep going after an error, if we can, assuming that the length field
+ // could be read. If it couldn't, stop reading the section.
+ if (!AddrTable.hasValidLength())
+ break;
+ uint64_t Length = AddrTable.getLength();
+ Offset = TableOffset + Length;
+ } else {
+ AddrTable.dump(OS, DumpOpts);
+ }
+ }
+}
+
+// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
+static void
+dumpRnglistsSection(raw_ostream &OS, DWARFDataExtractor &rnglistData,
+ llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
+ LookupPooledAddress,
+ DIDumpOptions DumpOpts) {
+ uint32_t Offset = 0;
+ while (rnglistData.isValidOffset(Offset)) {
+ llvm::DWARFDebugRnglistTable Rnglists;
+ uint32_t TableOffset = Offset;
+ if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
+ WithColor::error() << toString(std::move(Err)) << '\n';
+ uint64_t Length = Rnglists.length();
+ // Keep going after an error, if we can, assuming that the length field
+ // could be read. If it couldn't, stop reading the section.
+ if (Length == 0)
+ break;
+ Offset = TableOffset + Length;
+ } else {
+ Rnglists.dump(OS, LookupPooledAddress, DumpOpts);
+ }
+ }
+}
+
+static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
+ DWARFDataExtractor Data,
+ const MCRegisterInfo *MRI,
+ Optional<uint64_t> DumpOffset) {
+ uint32_t Offset = 0;
+ DWARFDebugLoclists Loclists;
+
+ DWARFListTableHeader Header(".debug_loclists", "locations");
+ if (Error E = Header.extract(Data, &Offset)) {
+ WithColor::error() << toString(std::move(E)) << '\n';
+ return;
+ }
+
+ Header.dump(OS, DumpOpts);
+ DataExtractor LocData(Data.getData().drop_front(Offset),
+ Data.isLittleEndian(), Header.getAddrSize());
+
+ Loclists.parse(LocData, Header.getVersion());
+ Loclists.dump(OS, 0, MRI, DumpOffset);
+}
+
+void DWARFContext::dump(
+ raw_ostream &OS, DIDumpOptions DumpOpts,
+ std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
+
+ uint64_t DumpType = DumpOpts.DumpType;
+
+ StringRef Extension = sys::path::extension(DObj->getFileName());
+ bool IsDWO = (Extension == ".dwo") || (Extension == ".dwp");
+
+ // Print UUID header.
+ const auto *ObjFile = DObj->getFile();
+ if (DumpType & DIDT_UUID)
+ dumpUUID(OS, *ObjFile);
+
+ // Print a header for each explicitly-requested section.
+ // Otherwise just print one for non-empty sections.
+ // Only print empty .dwo section headers when dumping a .dwo file.
+ bool Explicit = DumpType != DIDT_All && !IsDWO;
+ bool ExplicitDWO = Explicit && IsDWO;
+ auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID,
+ StringRef Section) -> Optional<uint64_t> * {
+ unsigned Mask = 1U << ID;
+ bool Should = (DumpType & Mask) && (Explicit || !Section.empty());
+ if (!Should)
+ return nullptr;
+ OS << "\n" << Name << " contents:\n";
+ return &DumpOffsets[ID];
+ };
+
+ // Dump individual sections.
+ if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev,
+ DObj->getAbbrevSection()))
+ getDebugAbbrev()->dump(OS);
+ if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev,
+ DObj->getAbbrevDWOSection()))
+ getDebugAbbrevDWO()->dump(OS);
+
+ auto dumpDebugInfo = [&](const char *Name, unit_iterator_range Units) {
+ OS << '\n' << Name << " contents:\n";
+ if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugInfo])
+ for (const auto &U : Units)
+ U->getDIEForOffset(DumpOffset.getValue())
+ .dump(OS, 0, DumpOpts.noImplicitRecursion());
+ else
+ for (const auto &U : Units)
+ U->dump(OS, DumpOpts);
+ };
+ if ((DumpType & DIDT_DebugInfo)) {
+ if (Explicit || getNumCompileUnits())
+ dumpDebugInfo(".debug_info", info_section_units());
+ if (ExplicitDWO || getNumDWOCompileUnits())
+ dumpDebugInfo(".debug_info.dwo", dwo_info_section_units());
+ }
+
+ auto dumpDebugType = [&](const char *Name, unit_iterator_range Units) {
+ OS << '\n' << Name << " contents:\n";
+ for (const auto &U : Units)
+ if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugTypes])
+ U->getDIEForOffset(*DumpOffset)
+ .dump(OS, 0, DumpOpts.noImplicitRecursion());
+ else
+ U->dump(OS, DumpOpts);
+ };
+ if ((DumpType & DIDT_DebugTypes)) {
+ if (Explicit || getNumTypeUnits())
+ dumpDebugType(".debug_types", types_section_units());
+ if (ExplicitDWO || getNumDWOTypeUnits())
+ dumpDebugType(".debug_types.dwo", dwo_types_section_units());
+ }
+
+ if (const auto *Off = shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc,
+ DObj->getLocSection().Data)) {
+ getDebugLoc()->dump(OS, getRegisterInfo(), *Off);
+ }
+ if (const auto *Off =
+ shouldDump(Explicit, ".debug_loclists", DIDT_ID_DebugLoclists,
+ DObj->getLoclistsSection().Data)) {
+ DWARFDataExtractor Data(*DObj, DObj->getLoclistsSection(), isLittleEndian(),
+ 0);
+ dumpLoclistsSection(OS, DumpOpts, Data, getRegisterInfo(), *Off);
+ }
+ if (const auto *Off =
+ shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc,
+ DObj->getLocDWOSection().Data)) {
+ getDebugLocDWO()->dump(OS, 0, getRegisterInfo(), *Off);
+ }
+
+ if (const auto *Off = shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
+ DObj->getDebugFrameSection()))
+ getDebugFrame()->dump(OS, getRegisterInfo(), *Off);
+
+ if (const auto *Off = shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
+ DObj->getEHFrameSection()))
+ getEHFrame()->dump(OS, getRegisterInfo(), *Off);
+
+ if (DumpType & DIDT_DebugMacro) {
+ if (Explicit || !getDebugMacro()->empty()) {
+ OS << "\n.debug_macinfo contents:\n";
+ getDebugMacro()->dump(OS);
+ }
+ }
+
+ if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges,
+ DObj->getARangeSection())) {
+ uint32_t offset = 0;
+ DataExtractor arangesData(DObj->getARangeSection(), isLittleEndian(), 0);
+ DWARFDebugArangeSet set;
+ while (set.extract(arangesData, &offset))
+ set.dump(OS);
+ }
+
+ auto DumpLineSection = [&](DWARFDebugLine::SectionParser Parser,
+ DIDumpOptions DumpOpts,
+ Optional<uint64_t> DumpOffset) {
+ while (!Parser.done()) {
+ if (DumpOffset && Parser.getOffset() != *DumpOffset) {
+ Parser.skip(dumpWarning);
+ continue;
+ }
+ OS << "debug_line[" << format("0x%8.8x", Parser.getOffset()) << "]\n";
+ if (DumpOpts.Verbose) {
+ Parser.parseNext(dumpWarning, dumpWarning, &OS);
+ } else {
+ DWARFDebugLine::LineTable LineTable =
+ Parser.parseNext(dumpWarning, dumpWarning);
+ LineTable.dump(OS, DumpOpts);
+ }
+ }
+ };
+
+ if (const auto *Off = shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine,
+ DObj->getLineSection().Data)) {
+ DWARFDataExtractor LineData(*DObj, DObj->getLineSection(), isLittleEndian(),
+ 0);
+ DWARFDebugLine::SectionParser Parser(LineData, *this, compile_units(),
+ type_units());
+ DumpLineSection(Parser, DumpOpts, *Off);
+ }
+
+ if (const auto *Off =
+ shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine,
+ DObj->getLineDWOSection().Data)) {
+ DWARFDataExtractor LineData(*DObj, DObj->getLineDWOSection(),
+ isLittleEndian(), 0);
+ DWARFDebugLine::SectionParser Parser(LineData, *this, dwo_compile_units(),
+ dwo_type_units());
+ DumpLineSection(Parser, DumpOpts, *Off);
+ }
+
+ if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex,
+ DObj->getCUIndexSection())) {
+ getCUIndex().dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex,
+ DObj->getTUIndexSection())) {
+ getTUIndex().dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr,
+ DObj->getStringSection())) {
+ DataExtractor strData(DObj->getStringSection(), isLittleEndian(), 0);
+ uint32_t offset = 0;
+ uint32_t strOffset = 0;
+ while (const char *s = strData.getCStr(&offset)) {
+ OS << format("0x%8.8x: \"%s\"\n", strOffset, s);
+ strOffset = offset;
+ }
+ }
+ if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr,
+ DObj->getStringDWOSection())) {
+ DataExtractor strDWOData(DObj->getStringDWOSection(), isLittleEndian(), 0);
+ uint32_t offset = 0;
+ uint32_t strDWOOffset = 0;
+ while (const char *s = strDWOData.getCStr(&offset)) {
+ OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s);
+ strDWOOffset = offset;
+ }
+ }
+ if (shouldDump(Explicit, ".debug_line_str", DIDT_ID_DebugLineStr,
+ DObj->getLineStringSection())) {
+ DataExtractor strData(DObj->getLineStringSection(), isLittleEndian(), 0);
+ uint32_t offset = 0;
+ uint32_t strOffset = 0;
+ while (const char *s = strData.getCStr(&offset)) {
+ OS << format("0x%8.8x: \"", strOffset);
+ OS.write_escaped(s);
+ OS << "\"\n";
+ strOffset = offset;
+ }
+ }
+
+ if (shouldDump(Explicit, ".debug_addr", DIDT_ID_DebugAddr,
+ DObj->getAddrSection().Data)) {
+ DWARFDataExtractor AddrData(*DObj, DObj->getAddrSection(),
+ isLittleEndian(), 0);
+ dumpAddrSection(OS, AddrData, DumpOpts, getMaxVersion(), getCUAddrSize());
+ }
+
+ if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges,
+ DObj->getRangeSection().Data)) {
+ uint8_t savedAddressByteSize = getCUAddrSize();
+ DWARFDataExtractor rangesData(*DObj, DObj->getRangeSection(),
+ isLittleEndian(), savedAddressByteSize);
+ uint32_t offset = 0;
+ DWARFDebugRangeList rangeList;
+ while (rangesData.isValidOffset(offset)) {
+ if (Error E = rangeList.extract(rangesData, &offset)) {
+ WithColor::error() << toString(std::move(E)) << '\n';
+ break;
+ }
+ rangeList.dump(OS);
+ }
+ }
+
+ auto LookupPooledAddress = [&](uint32_t Index) -> Optional<SectionedAddress> {
+ const auto &CUs = compile_units();
+ auto I = CUs.begin();
+ if (I == CUs.end())
+ return None;
+ return (*I)->getAddrOffsetSectionItem(Index);
+ };
+
+ if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
+ DObj->getRnglistsSection().Data)) {
+ DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(),
+ isLittleEndian(), 0);
+ dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
+ }
+
+ if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists,
+ DObj->getRnglistsDWOSection().Data)) {
+ DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
+ isLittleEndian(), 0);
+ dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
+ }
+
+ if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
+ DObj->getPubNamesSection().Data))
+ DWARFDebugPubTable(*DObj, DObj->getPubNamesSection(), isLittleEndian(), false)
+ .dump(OS);
+
+ if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes,
+ DObj->getPubTypesSection().Data))
+ DWARFDebugPubTable(*DObj, DObj->getPubTypesSection(), isLittleEndian(), false)
+ .dump(OS);
+
+ if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames,
+ DObj->getGnuPubNamesSection().Data))
+ DWARFDebugPubTable(*DObj, DObj->getGnuPubNamesSection(), isLittleEndian(),
+ true /* GnuStyle */)
+ .dump(OS);
+
+ if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes,
+ DObj->getGnuPubTypesSection().Data))
+ DWARFDebugPubTable(*DObj, DObj->getGnuPubTypesSection(), isLittleEndian(),
+ true /* GnuStyle */)
+ .dump(OS);
+
+ if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets,
+ DObj->getStringOffsetSection().Data))
+ dumpStringOffsetsSection(OS, "debug_str_offsets", *DObj,
+ DObj->getStringOffsetSection(),
+ DObj->getStringSection(), normal_units(),
+ isLittleEndian(), getMaxVersion());
+ if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets,
+ DObj->getStringOffsetDWOSection().Data))
+ dumpStringOffsetsSection(OS, "debug_str_offsets.dwo", *DObj,
+ DObj->getStringOffsetDWOSection(),
+ DObj->getStringDWOSection(), dwo_units(),
+ isLittleEndian(), getMaxDWOVersion());
+
+ if (shouldDump(Explicit, ".gdb_index", DIDT_ID_GdbIndex,
+ DObj->getGdbIndexSection())) {
+ getGdbIndex().dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames,
+ DObj->getAppleNamesSection().Data))
+ getAppleNames().dump(OS);
+
+ if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes,
+ DObj->getAppleTypesSection().Data))
+ getAppleTypes().dump(OS);
+
+ if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces,
+ DObj->getAppleNamespacesSection().Data))
+ getAppleNamespaces().dump(OS);
+
+ if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC,
+ DObj->getAppleObjCSection().Data))
+ getAppleObjC().dump(OS);
+ if (shouldDump(Explicit, ".debug_names", DIDT_ID_DebugNames,
+ DObj->getDebugNamesSection().Data))
+ getDebugNames().dump(OS);
+}
+
+DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
+ parseDWOUnits(LazyParse);
+
+ if (const auto &CUI = getCUIndex()) {
+ if (const auto *R = CUI.getFromHash(Hash))
+ return dyn_cast_or_null<DWARFCompileUnit>(
+ DWOUnits.getUnitForIndexEntry(*R));
+ return nullptr;
+ }
+
+ // If there's no index, just search through the CUs in the DWO - there's
+ // probably only one unless this is something like LTO - though an in-process
+ // built/cached lookup table could be used in that case to improve repeated
+ // lookups of different CUs in the DWO.
+ for (const auto &DWOCU : dwo_compile_units()) {
+ // Might not have parsed DWO ID yet.
+ if (!DWOCU->getDWOId()) {
+ if (Optional<uint64_t> DWOId =
+ toUnsigned(DWOCU->getUnitDIE().find(DW_AT_GNU_dwo_id)))
+ DWOCU->setDWOId(*DWOId);
+ else
+ // No DWO ID?
+ continue;
+ }
+ if (DWOCU->getDWOId() == Hash)
+ return dyn_cast<DWARFCompileUnit>(DWOCU.get());
+ }
+ return nullptr;
+}
+
+DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) {
+ parseNormalUnits();
+ if (auto *CU = NormalUnits.getUnitForOffset(Offset))
+ return CU->getDIEForOffset(Offset);
+ return DWARFDie();
+}
+
+bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
+ bool Success = true;
+ DWARFVerifier verifier(OS, *this, DumpOpts);
+
+ Success &= verifier.handleDebugAbbrev();
+ if (DumpOpts.DumpType & DIDT_DebugInfo)
+ Success &= verifier.handleDebugInfo();
+ if (DumpOpts.DumpType & DIDT_DebugLine)
+ Success &= verifier.handleDebugLine();
+ Success &= verifier.handleAccelTables();
+ return Success;
+}
+
+const DWARFUnitIndex &DWARFContext::getCUIndex() {
+ if (CUIndex)
+ return *CUIndex;
+
+ DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0);
+
+ CUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_INFO);
+ CUIndex->parse(CUIndexData);
+ return *CUIndex;
+}
+
+const DWARFUnitIndex &DWARFContext::getTUIndex() {
+ if (TUIndex)
+ return *TUIndex;
+
+ DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0);
+
+ TUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_TYPES);
+ TUIndex->parse(TUIndexData);
+ return *TUIndex;
+}
+
+DWARFGdbIndex &DWARFContext::getGdbIndex() {
+ if (GdbIndex)
+ return *GdbIndex;
+
+ DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0);
+ GdbIndex = llvm::make_unique<DWARFGdbIndex>();
+ GdbIndex->parse(GdbIndexData);
+ return *GdbIndex;
+}
+
+const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
+ if (Abbrev)
+ return Abbrev.get();
+
+ DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0);
+
+ Abbrev.reset(new DWARFDebugAbbrev());
+ Abbrev->extract(abbrData);
+ return Abbrev.get();
+}
+
+const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() {
+ if (AbbrevDWO)
+ return AbbrevDWO.get();
+
+ DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0);
+ AbbrevDWO.reset(new DWARFDebugAbbrev());
+ AbbrevDWO->extract(abbrData);
+ return AbbrevDWO.get();
+}
+
+const DWARFDebugLoc *DWARFContext::getDebugLoc() {
+ if (Loc)
+ return Loc.get();
+
+ Loc.reset(new DWARFDebugLoc);
+ // Assume all units have the same address byte size.
+ if (getNumCompileUnits()) {
+ DWARFDataExtractor LocData(*DObj, DObj->getLocSection(), isLittleEndian(),
+ getUnitAtIndex(0)->getAddressByteSize());
+ Loc->parse(LocData);
+ }
+ return Loc.get();
+}
+
+const DWARFDebugLoclists *DWARFContext::getDebugLocDWO() {
+ if (LocDWO)
+ return LocDWO.get();
+
+ LocDWO.reset(new DWARFDebugLoclists());
+ // Assume all compile units have the same address byte size.
+ // FIXME: We don't need AddressSize for split DWARF since relocatable
+ // addresses cannot appear there. At the moment DWARFExpression requires it.
+ DataExtractor LocData(DObj->getLocDWOSection().Data, isLittleEndian(), 4);
+ // Use version 4. DWO does not support the DWARF v5 .debug_loclists yet and
+ // that means we are parsing the new style .debug_loc (pre-standatized version
+ // of the .debug_loclists).
+ LocDWO->parse(LocData, 4 /* Version */);
+ return LocDWO.get();
+}
+
+const DWARFDebugAranges *DWARFContext::getDebugAranges() {
+ if (Aranges)
+ return Aranges.get();
+
+ Aranges.reset(new DWARFDebugAranges());
+ Aranges->generate(this);
+ return Aranges.get();
+}
+
+const DWARFDebugFrame *DWARFContext::getDebugFrame() {
+ if (DebugFrame)
+ return DebugFrame.get();
+
+ // There's a "bug" in the DWARFv3 standard with respect to the target address
+ // size within debug frame sections. While DWARF is supposed to be independent
+ // of its container, FDEs have fields with size being "target address size",
+ // which isn't specified in DWARF in general. It's only specified for CUs, but
+ // .eh_frame can appear without a .debug_info section. Follow the example of
+ // other tools (libdwarf) and extract this from the container (ObjectFile
+ // provides this information). This problem is fixed in DWARFv4
+ // See this dwarf-discuss discussion for more details:
+ // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
+ DWARFDataExtractor debugFrameData(DObj->getDebugFrameSection(),
+ isLittleEndian(), DObj->getAddressSize());
+ DebugFrame.reset(new DWARFDebugFrame(getArch(), false /* IsEH */));
+ DebugFrame->parse(debugFrameData);
+ return DebugFrame.get();
+}
+
+const DWARFDebugFrame *DWARFContext::getEHFrame() {
+ if (EHFrame)
+ return EHFrame.get();
+
+ DWARFDataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(),
+ DObj->getAddressSize());
+ DebugFrame.reset(new DWARFDebugFrame(getArch(), true /* IsEH */));
+ DebugFrame->parse(debugFrameData);
+ return DebugFrame.get();
+}
+
+const DWARFDebugMacro *DWARFContext::getDebugMacro() {
+ if (Macro)
+ return Macro.get();
+
+ DataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), 0);
+ Macro.reset(new DWARFDebugMacro());
+ Macro->parse(MacinfoData);
+ return Macro.get();
+}
+
+template <typename T>
+static T &getAccelTable(std::unique_ptr<T> &Cache, const DWARFObject &Obj,
+ const DWARFSection &Section, StringRef StringSection,
+ bool IsLittleEndian) {
+ if (Cache)
+ return *Cache;
+ DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0);
+ DataExtractor StrData(StringSection, IsLittleEndian, 0);
+ Cache.reset(new T(AccelSection, StrData));
+ if (Error E = Cache->extract())
+ llvm::consumeError(std::move(E));
+ return *Cache;
+}
+
+const DWARFDebugNames &DWARFContext::getDebugNames() {
+ return getAccelTable(Names, *DObj, DObj->getDebugNamesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleNames() {
+ return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleTypes() {
+ return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleNamespaces() {
+ return getAccelTable(AppleNamespaces, *DObj,
+ DObj->getAppleNamespacesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleObjC() {
+ return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const DWARFDebugLine::LineTable *
+DWARFContext::getLineTableForUnit(DWARFUnit *U) {
+ Expected<const DWARFDebugLine::LineTable *> ExpectedLineTable =
+ getLineTableForUnit(U, dumpWarning);
+ if (!ExpectedLineTable) {
+ dumpWarning(ExpectedLineTable.takeError());
+ return nullptr;
+ }
+ return *ExpectedLineTable;
+}
+
+Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit(
+ DWARFUnit *U, std::function<void(Error)> RecoverableErrorCallback) {
+ if (!Line)
+ Line.reset(new DWARFDebugLine);
+
+ auto UnitDIE = U->getUnitDIE();
+ if (!UnitDIE)
+ return nullptr;
+
+ auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list));
+ if (!Offset)
+ return nullptr; // No line table for this compile unit.
+
+ uint32_t stmtOffset = *Offset + U->getLineTableOffset();
+ // See if the line table is cached.
+ if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset))
+ return lt;
+
+ // Make sure the offset is good before we try to parse.
+ if (stmtOffset >= U->getLineSection().Data.size())
+ return nullptr;
+
+ // We have to parse it first.
+ DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(),
+ U->getAddressByteSize());
+ return Line->getOrParseLineTable(lineData, stmtOffset, *this, U,
+ RecoverableErrorCallback);
+}
+
+void DWARFContext::parseNormalUnits() {
+ if (!NormalUnits.empty())
+ return;
+ DObj->forEachInfoSections([&](const DWARFSection &S) {
+ NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO);
+ });
+ NormalUnits.finishedInfoUnits();
+ DObj->forEachTypesSections([&](const DWARFSection &S) {
+ NormalUnits.addUnitsForSection(*this, S, DW_SECT_TYPES);
+ });
+}
+
+void DWARFContext::parseDWOUnits(bool Lazy) {
+ if (!DWOUnits.empty())
+ return;
+ DObj->forEachInfoDWOSections([&](const DWARFSection &S) {
+ DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy);
+ });
+ DWOUnits.finishedInfoUnits();
+ DObj->forEachTypesDWOSections([&](const DWARFSection &S) {
+ DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_TYPES, Lazy);
+ });
+}
+
+DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint32_t Offset) {
+ parseNormalUnits();
+ return dyn_cast_or_null<DWARFCompileUnit>(
+ NormalUnits.getUnitForOffset(Offset));
+}
+
+DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) {
+ // First, get the offset of the compile unit.
+ uint32_t CUOffset = getDebugAranges()->findAddress(Address);
+ // Retrieve the compile unit.
+ return getCompileUnitForOffset(CUOffset);
+}
+
+DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) {
+ DIEsForAddress Result;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return Result;
+
+ Result.CompileUnit = CU;
+ Result.FunctionDIE = CU->getSubroutineForAddress(Address);
+
+ std::vector<DWARFDie> Worklist;
+ Worklist.push_back(Result.FunctionDIE);
+ while (!Worklist.empty()) {
+ DWARFDie DIE = Worklist.back();
+ Worklist.pop_back();
+
+ if (DIE.getTag() == DW_TAG_lexical_block &&
+ DIE.addressRangeContainsAddress(Address)) {
+ Result.BlockDIE = DIE;
+ break;
+ }
+
+ for (auto Child : DIE)
+ Worklist.push_back(Child);
+ }
+
+ return Result;
+}
+
+static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU,
+ uint64_t Address,
+ FunctionNameKind Kind,
+ std::string &FunctionName,
+ uint32_t &StartLine) {
+ // The address may correspond to instruction in some inlined function,
+ // so we have to build the chain of inlined functions and take the
+ // name of the topmost function in it.
+ SmallVector<DWARFDie, 4> InlinedChain;
+ CU->getInlinedChainForAddress(Address, InlinedChain);
+ if (InlinedChain.empty())
+ return false;
+
+ const DWARFDie &DIE = InlinedChain[0];
+ bool FoundResult = false;
+ const char *Name = nullptr;
+ if (Kind != FunctionNameKind::None && (Name = DIE.getSubroutineName(Kind))) {
+ FunctionName = Name;
+ FoundResult = true;
+ }
+ if (auto DeclLineResult = DIE.getDeclLine()) {
+ StartLine = DeclLineResult;
+ FoundResult = true;
+ }
+
+ return FoundResult;
+}
+
+DILineInfo DWARFContext::getLineInfoForAddress(uint64_t Address,
+ DILineInfoSpecifier Spec) {
+ DILineInfo Result;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return Result;
+ getFunctionNameAndStartLineForAddress(CU, Address, Spec.FNKind,
+ Result.FunctionName,
+ Result.StartLine);
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ if (const DWARFLineTable *LineTable = getLineTableForUnit(CU))
+ LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(),
+ Spec.FLIKind, Result);
+ }
+ return Result;
+}
+
+DILineInfoTable
+DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size,
+ DILineInfoSpecifier Spec) {
+ DILineInfoTable Lines;
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return Lines;
+
+ std::string FunctionName = "<invalid>";
+ uint32_t StartLine = 0;
+ getFunctionNameAndStartLineForAddress(CU, Address, Spec.FNKind, FunctionName,
+ StartLine);
+
+ // If the Specifier says we don't need FileLineInfo, just
+ // return the top-most function at the starting address.
+ if (Spec.FLIKind == FileLineInfoKind::None) {
+ DILineInfo Result;
+ Result.FunctionName = FunctionName;
+ Result.StartLine = StartLine;
+ Lines.push_back(std::make_pair(Address, Result));
+ return Lines;
+ }
+
+ const DWARFLineTable *LineTable = getLineTableForUnit(CU);
+
+ // Get the index of row we're looking for in the line table.
+ std::vector<uint32_t> RowVector;
+ if (!LineTable->lookupAddressRange(Address, Size, RowVector))
+ return Lines;
+
+ for (uint32_t RowIndex : RowVector) {
+ // Take file number and line/column from the row.
+ const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex];
+ DILineInfo Result;
+ LineTable->getFileNameByIndex(Row.File, CU->getCompilationDir(),
+ Spec.FLIKind, Result.FileName);
+ Result.FunctionName = FunctionName;
+ Result.Line = Row.Line;
+ Result.Column = Row.Column;
+ Result.StartLine = StartLine;
+ Lines.push_back(std::make_pair(Row.Address, Result));
+ }
+
+ return Lines;
+}
+
+DIInliningInfo
+DWARFContext::getInliningInfoForAddress(uint64_t Address,
+ DILineInfoSpecifier Spec) {
+ DIInliningInfo InliningInfo;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return InliningInfo;
+
+ const DWARFLineTable *LineTable = nullptr;
+ SmallVector<DWARFDie, 4> InlinedChain;
+ CU->getInlinedChainForAddress(Address, InlinedChain);
+ if (InlinedChain.size() == 0) {
+ // If there is no DIE for address (e.g. it is in unavailable .dwo file),
+ // try to at least get file/line info from symbol table.
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ DILineInfo Frame;
+ LineTable = getLineTableForUnit(CU);
+ if (LineTable &&
+ LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(),
+ Spec.FLIKind, Frame))
+ InliningInfo.addFrame(Frame);
+ }
+ return InliningInfo;
+ }
+
+ uint32_t CallFile = 0, CallLine = 0, CallColumn = 0, CallDiscriminator = 0;
+ for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) {
+ DWARFDie &FunctionDIE = InlinedChain[i];
+ DILineInfo Frame;
+ // Get function name if necessary.
+ if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind))
+ Frame.FunctionName = Name;
+ if (auto DeclLineResult = FunctionDIE.getDeclLine())
+ Frame.StartLine = DeclLineResult;
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ if (i == 0) {
+ // For the topmost frame, initialize the line table of this
+ // compile unit and fetch file/line info from it.
+ LineTable = getLineTableForUnit(CU);
+ // For the topmost routine, get file/line info from line table.
+ if (LineTable)
+ LineTable->getFileLineInfoForAddress(Address, CU->getCompilationDir(),
+ Spec.FLIKind, Frame);
+ } else {
+ // Otherwise, use call file, call line and call column from
+ // previous DIE in inlined chain.
+ if (LineTable)
+ LineTable->getFileNameByIndex(CallFile, CU->getCompilationDir(),
+ Spec.FLIKind, Frame.FileName);
+ Frame.Line = CallLine;
+ Frame.Column = CallColumn;
+ Frame.Discriminator = CallDiscriminator;
+ }
+ // Get call file/line/column of a current DIE.
+ if (i + 1 < n) {
+ FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn,
+ CallDiscriminator);
+ }
+ }
+ InliningInfo.addFrame(Frame);
+ }
+ return InliningInfo;
+}
+
+std::shared_ptr<DWARFContext>
+DWARFContext::getDWOContext(StringRef AbsolutePath) {
+ if (auto S = DWP.lock()) {
+ DWARFContext *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath];
+
+ if (auto S = Entry->lock()) {
+ DWARFContext *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ Expected<OwningBinary<ObjectFile>> Obj = [&] {
+ if (!CheckedForDWP) {
+ SmallString<128> DWPName;
+ auto Obj = object::ObjectFile::createObjectFile(
+ this->DWPName.empty()
+ ? (DObj->getFileName() + ".dwp").toStringRef(DWPName)
+ : StringRef(this->DWPName));
+ if (Obj) {
+ Entry = &DWP;
+ return Obj;
+ } else {
+ CheckedForDWP = true;
+ // TODO: Should this error be handled (maybe in a high verbosity mode)
+ // before falling back to .dwo files?
+ consumeError(Obj.takeError());
+ }
+ }
+
+ return object::ObjectFile::createObjectFile(AbsolutePath);
+ }();
+
+ if (!Obj) {
+ // TODO: Actually report errors helpfully.
+ consumeError(Obj.takeError());
+ return nullptr;
+ }
+
+ auto S = std::make_shared<DWOFile>();
+ S->File = std::move(Obj.get());
+ S->Context = DWARFContext::create(*S->File.getBinary());
+ *Entry = S;
+ auto *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+}
+
+static Error createError(const Twine &Reason, llvm::Error E) {
+ return make_error<StringError>(Reason + toString(std::move(E)),
+ inconvertibleErrorCode());
+}
+
+/// SymInfo contains information about symbol: it's address
+/// and section index which is -1LL for absolute symbols.
+struct SymInfo {
+ uint64_t Address;
+ uint64_t SectionIndex;
+};
+
+/// Returns the address of symbol relocation used against and a section index.
+/// Used for futher relocations computation. Symbol's section load address is
+static Expected<SymInfo> getSymbolInfo(const object::ObjectFile &Obj,
+ const RelocationRef &Reloc,
+ const LoadedObjectInfo *L,
+ std::map<SymbolRef, SymInfo> &Cache) {
+ SymInfo Ret = {0, (uint64_t)-1LL};
+ object::section_iterator RSec = Obj.section_end();
+ object::symbol_iterator Sym = Reloc.getSymbol();
+
+ std::map<SymbolRef, SymInfo>::iterator CacheIt = Cache.end();
+ // First calculate the address of the symbol or section as it appears
+ // in the object file
+ if (Sym != Obj.symbol_end()) {
+ bool New;
+ std::tie(CacheIt, New) = Cache.insert({*Sym, {0, 0}});
+ if (!New)
+ return CacheIt->second;
+
+ Expected<uint64_t> SymAddrOrErr = Sym->getAddress();
+ if (!SymAddrOrErr)
+ return createError("failed to compute symbol address: ",
+ SymAddrOrErr.takeError());
+
+ // Also remember what section this symbol is in for later
+ auto SectOrErr = Sym->getSection();
+ if (!SectOrErr)
+ return createError("failed to get symbol section: ",
+ SectOrErr.takeError());
+
+ RSec = *SectOrErr;
+ Ret.Address = *SymAddrOrErr;
+ } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) {
+ RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl());
+ Ret.Address = RSec->getAddress();
+ }
+
+ if (RSec != Obj.section_end())
+ Ret.SectionIndex = RSec->getIndex();
+
+ // If we are given load addresses for the sections, we need to adjust:
+ // SymAddr = (Address of Symbol Or Section in File) -
+ // (Address of Section in File) +
+ // (Load Address of Section)
+ // RSec is now either the section being targeted or the section
+ // containing the symbol being targeted. In either case,
+ // we need to perform the same computation.
+ if (L && RSec != Obj.section_end())
+ if (uint64_t SectionLoadAddress = L->getSectionLoadAddress(*RSec))
+ Ret.Address += SectionLoadAddress - RSec->getAddress();
+
+ if (CacheIt != Cache.end())
+ CacheIt->second = Ret;
+
+ return Ret;
+}
+
+static bool isRelocScattered(const object::ObjectFile &Obj,
+ const RelocationRef &Reloc) {
+ const MachOObjectFile *MachObj = dyn_cast<MachOObjectFile>(&Obj);
+ if (!MachObj)
+ return false;
+ // MachO also has relocations that point to sections and
+ // scattered relocations.
+ auto RelocInfo = MachObj->getRelocation(Reloc.getRawDataRefImpl());
+ return MachObj->isRelocationScattered(RelocInfo);
+}
+
+ErrorPolicy DWARFContext::defaultErrorHandler(Error E) {
+ WithColor::error() << toString(std::move(E)) << '\n';
+ return ErrorPolicy::Continue;
+}
+
+namespace {
+struct DWARFSectionMap final : public DWARFSection {
+ RelocAddrMap Relocs;
+};
+
+class DWARFObjInMemory final : public DWARFObject {
+ bool IsLittleEndian;
+ uint8_t AddressSize;
+ StringRef FileName;
+ const object::ObjectFile *Obj = nullptr;
+ std::vector<SectionName> SectionNames;
+
+ using InfoSectionMap = MapVector<object::SectionRef, DWARFSectionMap,
+ std::map<object::SectionRef, unsigned>>;
+
+ InfoSectionMap InfoSections;
+ InfoSectionMap TypesSections;
+ InfoSectionMap InfoDWOSections;
+ InfoSectionMap TypesDWOSections;
+
+ DWARFSectionMap LocSection;
+ DWARFSectionMap LocListsSection;
+ DWARFSectionMap LineSection;
+ DWARFSectionMap RangeSection;
+ DWARFSectionMap RnglistsSection;
+ DWARFSectionMap StringOffsetSection;
+ DWARFSectionMap LineDWOSection;
+ DWARFSectionMap LocDWOSection;
+ DWARFSectionMap StringOffsetDWOSection;
+ DWARFSectionMap RangeDWOSection;
+ DWARFSectionMap RnglistsDWOSection;
+ DWARFSectionMap AddrSection;
+ DWARFSectionMap AppleNamesSection;
+ DWARFSectionMap AppleTypesSection;
+ DWARFSectionMap AppleNamespacesSection;
+ DWARFSectionMap AppleObjCSection;
+ DWARFSectionMap DebugNamesSection;
+ DWARFSectionMap PubNamesSection;
+ DWARFSectionMap PubTypesSection;
+ DWARFSectionMap GnuPubNamesSection;
+ DWARFSectionMap GnuPubTypesSection;
+
+ DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
+ return StringSwitch<DWARFSectionMap *>(Name)
+ .Case("debug_loc", &LocSection)
+ .Case("debug_loclists", &LocListsSection)
+ .Case("debug_line", &LineSection)
+ .Case("debug_str_offsets", &StringOffsetSection)
+ .Case("debug_ranges", &RangeSection)
+ .Case("debug_rnglists", &RnglistsSection)
+ .Case("debug_loc.dwo", &LocDWOSection)
+ .Case("debug_line.dwo", &LineDWOSection)
+ .Case("debug_names", &DebugNamesSection)
+ .Case("debug_rnglists.dwo", &RnglistsDWOSection)
+ .Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
+ .Case("debug_addr", &AddrSection)
+ .Case("apple_names", &AppleNamesSection)
+ .Case("debug_pubnames", &PubNamesSection)
+ .Case("debug_pubtypes", &PubTypesSection)
+ .Case("debug_gnu_pubnames", &GnuPubNamesSection)
+ .Case("debug_gnu_pubtypes", &GnuPubTypesSection)
+ .Case("apple_types", &AppleTypesSection)
+ .Case("apple_namespaces", &AppleNamespacesSection)
+ .Case("apple_namespac", &AppleNamespacesSection)
+ .Case("apple_objc", &AppleObjCSection)
+ .Default(nullptr);
+ }
+
+ StringRef AbbrevSection;
+ StringRef ARangeSection;
+ StringRef DebugFrameSection;
+ StringRef EHFrameSection;
+ StringRef StringSection;
+ StringRef MacinfoSection;
+ StringRef AbbrevDWOSection;
+ StringRef StringDWOSection;
+ StringRef CUIndexSection;
+ StringRef GdbIndexSection;
+ StringRef TUIndexSection;
+ StringRef LineStringSection;
+
+ // A deque holding section data whose iterators are not invalidated when
+ // new decompressed sections are inserted at the end.
+ std::deque<SmallString<0>> UncompressedSections;
+
+ StringRef *mapSectionToMember(StringRef Name) {
+ if (DWARFSection *Sec = mapNameToDWARFSection(Name))
+ return &Sec->Data;
+ return StringSwitch<StringRef *>(Name)
+ .Case("debug_abbrev", &AbbrevSection)
+ .Case("debug_aranges", &ARangeSection)
+ .Case("debug_frame", &DebugFrameSection)
+ .Case("eh_frame", &EHFrameSection)
+ .Case("debug_str", &StringSection)
+ .Case("debug_macinfo", &MacinfoSection)
+ .Case("debug_abbrev.dwo", &AbbrevDWOSection)
+ .Case("debug_str.dwo", &StringDWOSection)
+ .Case("debug_cu_index", &CUIndexSection)
+ .Case("debug_tu_index", &TUIndexSection)
+ .Case("gdb_index", &GdbIndexSection)
+ .Case("debug_line_str", &LineStringSection)
+ // Any more debug info sections go here.
+ .Default(nullptr);
+ }
+
+ /// If Sec is compressed section, decompresses and updates its contents
+ /// provided by Data. Otherwise leaves it unchanged.
+ Error maybeDecompress(const object::SectionRef &Sec, StringRef Name,
+ StringRef &Data) {
+ if (!Decompressor::isCompressed(Sec))
+ return Error::success();
+
+ Expected<Decompressor> Decompressor =
+ Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8);
+ if (!Decompressor)
+ return Decompressor.takeError();
+
+ SmallString<0> Out;
+ if (auto Err = Decompressor->resizeAndDecompress(Out))
+ return Err;
+
+ UncompressedSections.push_back(std::move(Out));
+ Data = UncompressedSections.back();
+
+ return Error::success();
+ }
+
+public:
+ DWARFObjInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+ uint8_t AddrSize, bool IsLittleEndian)
+ : IsLittleEndian(IsLittleEndian) {
+ for (const auto &SecIt : Sections) {
+ if (StringRef *SectionData = mapSectionToMember(SecIt.first()))
+ *SectionData = SecIt.second->getBuffer();
+ else if (SecIt.first() == "debug_info")
+ // Find debug_info and debug_types data by section rather than name as
+ // there are multiple, comdat grouped, of these sections.
+ InfoSections[SectionRef()].Data = SecIt.second->getBuffer();
+ else if (SecIt.first() == "debug_info.dwo")
+ InfoDWOSections[SectionRef()].Data = SecIt.second->getBuffer();
+ else if (SecIt.first() == "debug_types")
+ TypesSections[SectionRef()].Data = SecIt.second->getBuffer();
+ else if (SecIt.first() == "debug_types.dwo")
+ TypesDWOSections[SectionRef()].Data = SecIt.second->getBuffer();
+ }
+ }
+ DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+ function_ref<ErrorPolicy(Error)> HandleError)
+ : IsLittleEndian(Obj.isLittleEndian()),
+ AddressSize(Obj.getBytesInAddress()), FileName(Obj.getFileName()),
+ Obj(&Obj) {
+
+ StringMap<unsigned> SectionAmountMap;
+ for (const SectionRef &Section : Obj.sections()) {
+ StringRef Name;
+ Section.getName(Name);
+ ++SectionAmountMap[Name];
+ SectionNames.push_back({ Name, true });
+
+ // Skip BSS and Virtual sections, they aren't interesting.
+ if (Section.isBSS() || Section.isVirtual())
+ continue;
+
+ // Skip sections stripped by dsymutil.
+ if (Section.isStripped())
+ continue;
+
+ StringRef Data;
+ section_iterator RelocatedSection = Section.getRelocatedSection();
+ // Try to obtain an already relocated version of this section.
+ // Else use the unrelocated section from the object file. We'll have to
+ // apply relocations ourselves later.
+ if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data))
+ Section.getContents(Data);
+
+ if (auto Err = maybeDecompress(Section, Name, Data)) {
+ ErrorPolicy EP = HandleError(createError(
+ "failed to decompress '" + Name + "', ", std::move(Err)));
+ if (EP == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
+
+ // Compressed sections names in GNU style starts from ".z",
+ // at this point section is decompressed and we drop compression prefix.
+ Name = Name.substr(
+ Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.
+
+ // Map platform specific debug section names to DWARF standard section
+ // names.
+ Name = Obj.mapDebugSectionName(Name);
+
+ if (StringRef *SectionData = mapSectionToMember(Name)) {
+ *SectionData = Data;
+ if (Name == "debug_ranges") {
+ // FIXME: Use the other dwo range section when we emit it.
+ RangeDWOSection.Data = Data;
+ }
+ } else if (Name == "debug_info") {
+ // Find debug_info and debug_types data by section rather than name as
+ // there are multiple, comdat grouped, of these sections.
+ InfoSections[Section].Data = Data;
+ } else if (Name == "debug_info.dwo") {
+ InfoDWOSections[Section].Data = Data;
+ } else if (Name == "debug_types") {
+ TypesSections[Section].Data = Data;
+ } else if (Name == "debug_types.dwo") {
+ TypesDWOSections[Section].Data = Data;
+ }
+
+ if (RelocatedSection == Obj.section_end())
+ continue;
+
+ StringRef RelSecName;
+ StringRef RelSecData;
+ RelocatedSection->getName(RelSecName);
+
+ // If the section we're relocating was relocated already by the JIT,
+ // then we used the relocated version above, so we do not need to process
+ // relocations for it now.
+ if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData))
+ continue;
+
+ // In Mach-o files, the relocations do not need to be applied if
+ // there is no load offset to apply. The value read at the
+ // relocation point already factors in the section address
+ // (actually applying the relocations will produce wrong results
+ // as the section address will be added twice).
+ if (!L && isa<MachOObjectFile>(&Obj))
+ continue;
+
+ RelSecName = RelSecName.substr(
+ RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes.
+
+ // TODO: Add support for relocations in other sections as needed.
+ // Record relocations for the debug_info and debug_line sections.
+ DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName);
+ RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr;
+ if (!Map) {
+ // Find debug_info and debug_types relocs by section rather than name
+ // as there are multiple, comdat grouped, of these sections.
+ if (RelSecName == "debug_info")
+ Map = &static_cast<DWARFSectionMap &>(InfoSections[*RelocatedSection])
+ .Relocs;
+ else if (RelSecName == "debug_info.dwo")
+ Map = &static_cast<DWARFSectionMap &>(
+ InfoDWOSections[*RelocatedSection])
+ .Relocs;
+ else if (RelSecName == "debug_types")
+ Map =
+ &static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection])
+ .Relocs;
+ else if (RelSecName == "debug_types.dwo")
+ Map = &static_cast<DWARFSectionMap &>(
+ TypesDWOSections[*RelocatedSection])
+ .Relocs;
+ else
+ continue;
+ }
+
+ if (Section.relocation_begin() == Section.relocation_end())
+ continue;
+
+ // Symbol to [address, section index] cache mapping.
+ std::map<SymbolRef, SymInfo> AddrCache;
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ // FIXME: it's not clear how to correctly handle scattered
+ // relocations.
+ if (isRelocScattered(Obj, Reloc))
+ continue;
+
+ Expected<SymInfo> SymInfoOrErr =
+ getSymbolInfo(Obj, Reloc, L, AddrCache);
+ if (!SymInfoOrErr) {
+ if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
+
+ object::RelocVisitor V(Obj);
+ uint64_t Val = V.visit(Reloc.getType(), Reloc, SymInfoOrErr->Address);
+ if (V.error()) {
+ SmallString<32> Type;
+ Reloc.getTypeName(Type);
+ ErrorPolicy EP = HandleError(
+ createError("failed to compute relocation: " + Type + ", ",
+ errorCodeToError(object_error::parse_failed)));
+ if (EP == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
+ RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val};
+ Map->insert({Reloc.getOffset(), Rel});
+ }
+ }
+
+ for (SectionName &S : SectionNames)
+ if (SectionAmountMap[S.Name] > 1)
+ S.IsNameUnique = false;
+ }
+
+ Optional<RelocAddrEntry> find(const DWARFSection &S,
+ uint64_t Pos) const override {
+ auto &Sec = static_cast<const DWARFSectionMap &>(S);
+ RelocAddrMap::const_iterator AI = Sec.Relocs.find(Pos);
+ if (AI == Sec.Relocs.end())
+ return None;
+ return AI->second;
+ }
+
+ const object::ObjectFile *getFile() const override { return Obj; }
+
+ ArrayRef<SectionName> getSectionNames() const override {
+ return SectionNames;
+ }
+
+ bool isLittleEndian() const override { return IsLittleEndian; }
+ StringRef getAbbrevDWOSection() const override { return AbbrevDWOSection; }
+ const DWARFSection &getLineDWOSection() const override {
+ return LineDWOSection;
+ }
+ const DWARFSection &getLocDWOSection() const override {
+ return LocDWOSection;
+ }
+ StringRef getStringDWOSection() const override { return StringDWOSection; }
+ const DWARFSection &getStringOffsetDWOSection() const override {
+ return StringOffsetDWOSection;
+ }
+ const DWARFSection &getRangeDWOSection() const override {
+ return RangeDWOSection;
+ }
+ const DWARFSection &getRnglistsDWOSection() const override {
+ return RnglistsDWOSection;
+ }
+ const DWARFSection &getAddrSection() const override { return AddrSection; }
+ StringRef getCUIndexSection() const override { return CUIndexSection; }
+ StringRef getGdbIndexSection() const override { return GdbIndexSection; }
+ StringRef getTUIndexSection() const override { return TUIndexSection; }
+
+ // DWARF v5
+ const DWARFSection &getStringOffsetSection() const override {
+ return StringOffsetSection;
+ }
+ StringRef getLineStringSection() const override { return LineStringSection; }
+
+ // Sections for DWARF5 split dwarf proposal.
+ void forEachInfoDWOSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : InfoDWOSections)
+ F(P.second);
+ }
+ void forEachTypesDWOSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : TypesDWOSections)
+ F(P.second);
+ }
+
+ StringRef getAbbrevSection() const override { return AbbrevSection; }
+ const DWARFSection &getLocSection() const override { return LocSection; }
+ const DWARFSection &getLoclistsSection() const override { return LocListsSection; }
+ StringRef getARangeSection() const override { return ARangeSection; }
+ StringRef getDebugFrameSection() const override { return DebugFrameSection; }
+ StringRef getEHFrameSection() const override { return EHFrameSection; }
+ const DWARFSection &getLineSection() const override { return LineSection; }
+ StringRef getStringSection() const override { return StringSection; }
+ const DWARFSection &getRangeSection() const override { return RangeSection; }
+ const DWARFSection &getRnglistsSection() const override {
+ return RnglistsSection;
+ }
+ StringRef getMacinfoSection() const override { return MacinfoSection; }
+ const DWARFSection &getPubNamesSection() const override { return PubNamesSection; }
+ const DWARFSection &getPubTypesSection() const override { return PubTypesSection; }
+ const DWARFSection &getGnuPubNamesSection() const override {
+ return GnuPubNamesSection;
+ }
+ const DWARFSection &getGnuPubTypesSection() const override {
+ return GnuPubTypesSection;
+ }
+ const DWARFSection &getAppleNamesSection() const override {
+ return AppleNamesSection;
+ }
+ const DWARFSection &getAppleTypesSection() const override {
+ return AppleTypesSection;
+ }
+ const DWARFSection &getAppleNamespacesSection() const override {
+ return AppleNamespacesSection;
+ }
+ const DWARFSection &getAppleObjCSection() const override {
+ return AppleObjCSection;
+ }
+ const DWARFSection &getDebugNamesSection() const override {
+ return DebugNamesSection;
+ }
+
+ StringRef getFileName() const override { return FileName; }
+ uint8_t getAddressSize() const override { return AddressSize; }
+ void forEachInfoSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : InfoSections)
+ F(P.second);
+ }
+ void forEachTypesSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : TypesSections)
+ F(P.second);
+ }
+};
+} // namespace
+
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+ function_ref<ErrorPolicy(Error)> HandleError,
+ std::string DWPName) {
+ auto DObj = llvm::make_unique<DWARFObjInMemory>(Obj, L, HandleError);
+ return llvm::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName));
+}
+
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+ uint8_t AddrSize, bool isLittleEndian) {
+ auto DObj =
+ 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 createStringError(errc::invalid_argument,
+ TargetLookupError.c_str());
+ RegInfo.reset(TheTarget->createMCRegInfo(TT.str()));
+ return Error::success();
+}
+
+uint8_t DWARFContext::getCUAddrSize() {
+ // In theory, different compile units may have different address byte
+ // sizes, but for simplicity we just use the address byte size of the
+ // last compile unit. In practice the address size field is repeated across
+ // various DWARF headers (at least in version 5) to make it easier to dump
+ // them independently, not to enable varying the address size.
+ uint8_t Addr = 0;
+ for (const auto &CU : compile_units()) {
+ Addr = CU->getAddressByteSize();
+ break;
+ }
+ return Addr;
+}
+
+void DWARFContext::dumpWarning(Error Warning) {
+ handleAllErrors(std::move(Warning), [](ErrorInfoBase &Info) {
+ WithColor::warning() << Info.message() << '\n';
+ });
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
new file mode 100644
index 000000000000..03e317461396
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
@@ -0,0 +1,96 @@
+//===- DWARFDataExtractor.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/DWARFDataExtractor.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+
+using namespace llvm;
+
+uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off,
+ uint64_t *SecNdx) const {
+ if (SecNdx)
+ *SecNdx = -1ULL;
+ if (!Section)
+ return getUnsigned(Off, Size);
+ Optional<RelocAddrEntry> Rel = Obj->find(*Section, *Off);
+ if (!Rel)
+ return getUnsigned(Off, Size);
+ if (SecNdx)
+ *SecNdx = Rel->SectionIndex;
+ return getUnsigned(Off, Size) + Rel->Value;
+}
+
+Optional<uint64_t>
+DWARFDataExtractor::getEncodedPointer(uint32_t *Offset, uint8_t Encoding,
+ uint64_t PCRelOffset) const {
+ if (Encoding == dwarf::DW_EH_PE_omit)
+ return None;
+
+ uint64_t Result = 0;
+ uint32_t OldOffset = *Offset;
+ // First get value
+ switch (Encoding & 0x0F) {
+ case dwarf::DW_EH_PE_absptr:
+ switch (getAddressSize()) {
+ case 2:
+ case 4:
+ case 8:
+ Result = getUnsigned(Offset, getAddressSize());
+ break;
+ default:
+ return None;
+ }
+ break;
+ case dwarf::DW_EH_PE_uleb128:
+ Result = getULEB128(Offset);
+ break;
+ case dwarf::DW_EH_PE_sleb128:
+ Result = getSLEB128(Offset);
+ break;
+ case dwarf::DW_EH_PE_udata2:
+ Result = getUnsigned(Offset, 2);
+ break;
+ case dwarf::DW_EH_PE_udata4:
+ Result = getUnsigned(Offset, 4);
+ break;
+ case dwarf::DW_EH_PE_udata8:
+ Result = getUnsigned(Offset, 8);
+ break;
+ case dwarf::DW_EH_PE_sdata2:
+ Result = getSigned(Offset, 2);
+ break;
+ case dwarf::DW_EH_PE_sdata4:
+ Result = getSigned(Offset, 4);
+ break;
+ case dwarf::DW_EH_PE_sdata8:
+ Result = getSigned(Offset, 8);
+ break;
+ default:
+ return None;
+ }
+ // Then add relative offset, if required
+ switch (Encoding & 0x70) {
+ case dwarf::DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case dwarf::DW_EH_PE_pcrel:
+ Result += PCRelOffset;
+ break;
+ case dwarf::DW_EH_PE_datarel:
+ case dwarf::DW_EH_PE_textrel:
+ case dwarf::DW_EH_PE_funcrel:
+ case dwarf::DW_EH_PE_aligned:
+ default:
+ *Offset = OldOffset;
+ return None;
+ }
+
+ return Result;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
new file mode 100644
index 000000000000..4830c36a8ee7
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
@@ -0,0 +1,139 @@
+//===- DWARFDebugAbbrev.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/DWARFDebugAbbrev.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() {
+ clear();
+}
+
+void DWARFAbbreviationDeclarationSet::clear() {
+ Offset = 0;
+ FirstAbbrCode = 0;
+ Decls.clear();
+}
+
+bool DWARFAbbreviationDeclarationSet::extract(DataExtractor Data,
+ uint32_t *OffsetPtr) {
+ clear();
+ const uint32_t BeginOffset = *OffsetPtr;
+ Offset = BeginOffset;
+ DWARFAbbreviationDeclaration AbbrDecl;
+ uint32_t PrevAbbrCode = 0;
+ while (AbbrDecl.extract(Data, OffsetPtr)) {
+ if (FirstAbbrCode == 0) {
+ FirstAbbrCode = AbbrDecl.getCode();
+ } else {
+ if (PrevAbbrCode + 1 != AbbrDecl.getCode()) {
+ // Codes are not consecutive, can't do O(1) lookups.
+ FirstAbbrCode = UINT32_MAX;
+ }
+ }
+ PrevAbbrCode = AbbrDecl.getCode();
+ Decls.push_back(std::move(AbbrDecl));
+ }
+ return BeginOffset != *OffsetPtr;
+}
+
+void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const {
+ for (const auto &Decl : Decls)
+ Decl.dump(OS);
+}
+
+const DWARFAbbreviationDeclaration *
+DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration(
+ uint32_t AbbrCode) const {
+ if (FirstAbbrCode == UINT32_MAX) {
+ for (const auto &Decl : Decls) {
+ if (Decl.getCode() == AbbrCode)
+ return &Decl;
+ }
+ return nullptr;
+ }
+ if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size())
+ return nullptr;
+ return &Decls[AbbrCode - FirstAbbrCode];
+}
+
+DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); }
+
+void DWARFDebugAbbrev::clear() {
+ AbbrDeclSets.clear();
+ PrevAbbrOffsetPos = AbbrDeclSets.end();
+}
+
+void DWARFDebugAbbrev::extract(DataExtractor Data) {
+ clear();
+ this->Data = Data;
+}
+
+void DWARFDebugAbbrev::parse() const {
+ if (!Data)
+ return;
+ uint32_t Offset = 0;
+ DWARFAbbreviationDeclarationSet AbbrDecls;
+ auto I = AbbrDeclSets.begin();
+ while (Data->isValidOffset(Offset)) {
+ while (I != AbbrDeclSets.end() && I->first < Offset)
+ ++I;
+ uint32_t CUAbbrOffset = Offset;
+ if (!AbbrDecls.extract(*Data, &Offset))
+ break;
+ AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls)));
+ }
+ Data = None;
+}
+
+void DWARFDebugAbbrev::dump(raw_ostream &OS) const {
+ parse();
+
+ if (AbbrDeclSets.empty()) {
+ OS << "< EMPTY >\n";
+ return;
+ }
+
+ for (const auto &I : AbbrDeclSets) {
+ OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first);
+ I.second.dump(OS);
+ }
+}
+
+const DWARFAbbreviationDeclarationSet*
+DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const {
+ const auto End = AbbrDeclSets.end();
+ if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) {
+ return &(PrevAbbrOffsetPos->second);
+ }
+
+ const auto Pos = AbbrDeclSets.find(CUAbbrOffset);
+ if (Pos != End) {
+ PrevAbbrOffsetPos = Pos;
+ return &(Pos->second);
+ }
+
+ if (Data && CUAbbrOffset < Data->getData().size()) {
+ uint32_t Offset = CUAbbrOffset;
+ DWARFAbbreviationDeclarationSet AbbrDecls;
+ if (!AbbrDecls.extract(*Data, &Offset))
+ return nullptr;
+ PrevAbbrOffsetPos =
+ AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls)))
+ .first;
+ return &PrevAbbrOffsetPos->second;
+ }
+
+ return nullptr;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp
new file mode 100644
index 000000000000..22759bfac26c
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp
@@ -0,0 +1,198 @@
+//===- DWARFDebugAddr.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/DWARFDebugAddr.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+
+using namespace llvm;
+
+void DWARFDebugAddrTable::clear() {
+ HeaderData = {};
+ Addrs.clear();
+ invalidateLength();
+}
+
+Error DWARFDebugAddrTable::extract(DWARFDataExtractor Data,
+ uint32_t *OffsetPtr,
+ uint16_t Version,
+ uint8_t AddrSize,
+ std::function<void(Error)> WarnCallback) {
+ clear();
+ HeaderOffset = *OffsetPtr;
+ // Read and verify the length field.
+ if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
+ return createStringError(errc::invalid_argument,
+ "section is not large enough to contain a "
+ ".debug_addr table length at offset 0x%"
+ PRIx32, *OffsetPtr);
+ uint16_t UnitVersion;
+ if (Version == 0) {
+ WarnCallback(createStringError(errc::invalid_argument,
+ "DWARF version is not defined in CU,"
+ " assuming version 5"));
+ UnitVersion = 5;
+ } else {
+ UnitVersion = Version;
+ }
+ // TODO: Add support for DWARF64.
+ Format = dwarf::DwarfFormat::DWARF32;
+ if (UnitVersion >= 5) {
+ HeaderData.Length = Data.getU32(OffsetPtr);
+ if (HeaderData.Length == 0xffffffffu) {
+ invalidateLength();
+ return createStringError(errc::not_supported,
+ "DWARF64 is not supported in .debug_addr at offset 0x%" PRIx32,
+ HeaderOffset);
+ }
+ if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header)) {
+ uint32_t TmpLength = getLength();
+ invalidateLength();
+ return createStringError(errc::invalid_argument,
+ ".debug_addr table at offset 0x%" PRIx32
+ " has too small length (0x%" PRIx32
+ ") to contain a complete header",
+ HeaderOffset, TmpLength);
+ }
+ uint32_t End = HeaderOffset + getLength();
+ if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset)) {
+ uint32_t TmpLength = getLength();
+ invalidateLength();
+ return createStringError(errc::invalid_argument,
+ "section is not large enough to contain a .debug_addr table "
+ "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
+ TmpLength, HeaderOffset);
+ }
+
+ HeaderData.Version = Data.getU16(OffsetPtr);
+ HeaderData.AddrSize = Data.getU8(OffsetPtr);
+ HeaderData.SegSize = Data.getU8(OffsetPtr);
+ DataSize = getDataSize();
+ } else {
+ HeaderData.Version = UnitVersion;
+ HeaderData.AddrSize = AddrSize;
+ // TODO: Support for non-zero SegSize.
+ HeaderData.SegSize = 0;
+ DataSize = Data.size();
+ }
+
+ // Perform basic validation of the remaining header fields.
+
+ // We support DWARF version 5 for now as well as pre-DWARF5
+ // implementations of .debug_addr table, which doesn't contain a header
+ // and consists only of a series of addresses.
+ if (HeaderData.Version > 5) {
+ return createStringError(errc::not_supported, "version %" PRIu16
+ " of .debug_addr section at offset 0x%" PRIx32 " is not supported",
+ HeaderData.Version, HeaderOffset);
+ }
+ // FIXME: For now we just treat version mismatch as an error,
+ // however the correct way to associate a .debug_addr table
+ // with a .debug_info table is to look at the DW_AT_addr_base
+ // attribute in the info table.
+ if (HeaderData.Version != UnitVersion)
+ return createStringError(errc::invalid_argument,
+ ".debug_addr table at offset 0x%" PRIx32
+ " has version %" PRIu16
+ " which is different from the version suggested"
+ " by the DWARF unit header: %" PRIu16,
+ HeaderOffset, HeaderData.Version, UnitVersion);
+ if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
+ return createStringError(errc::not_supported,
+ ".debug_addr table at offset 0x%" PRIx32
+ " has unsupported address size %" PRIu8,
+ HeaderOffset, HeaderData.AddrSize);
+ if (HeaderData.AddrSize != AddrSize && AddrSize != 0)
+ return createStringError(errc::invalid_argument,
+ ".debug_addr table at offset 0x%" PRIx32
+ " has address size %" PRIu8
+ " which is different from CU address size %" PRIu8,
+ HeaderOffset, HeaderData.AddrSize, AddrSize);
+
+ // TODO: add support for non-zero segment selector size.
+ if (HeaderData.SegSize != 0)
+ return createStringError(errc::not_supported,
+ ".debug_addr table at offset 0x%" PRIx32
+ " has unsupported segment selector size %" PRIu8,
+ HeaderOffset, HeaderData.SegSize);
+ if (DataSize % HeaderData.AddrSize != 0) {
+ invalidateLength();
+ return createStringError(errc::invalid_argument,
+ ".debug_addr table at offset 0x%" PRIx32
+ " contains data of size %" PRIu32
+ " which is not a multiple of addr size %" PRIu8,
+ HeaderOffset, DataSize, HeaderData.AddrSize);
+ }
+ Data.setAddressSize(HeaderData.AddrSize);
+ uint32_t AddrCount = DataSize / HeaderData.AddrSize;
+ for (uint32_t I = 0; I < AddrCount; ++I)
+ if (HeaderData.AddrSize == 4)
+ Addrs.push_back(Data.getU32(OffsetPtr));
+ else
+ Addrs.push_back(Data.getU64(OffsetPtr));
+ return Error::success();
+}
+
+void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+ if (DumpOpts.Verbose)
+ OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
+ OS << format("Addr Section: length = 0x%8.8" PRIx32
+ ", version = 0x%4.4" PRIx16 ", "
+ "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8 "\n",
+ HeaderData.Length, HeaderData.Version, HeaderData.AddrSize,
+ HeaderData.SegSize);
+
+ static const char *Fmt32 = "0x%8.8" PRIx64;
+ static const char *Fmt64 = "0x%16.16" PRIx64;
+ std::string AddrFmt = "\n";
+ std::string AddrFmtVerbose = " => ";
+ if (HeaderData.AddrSize == 4) {
+ AddrFmt.append(Fmt32);
+ AddrFmtVerbose.append(Fmt32);
+ }
+ else {
+ AddrFmt.append(Fmt64);
+ AddrFmtVerbose.append(Fmt64);
+ }
+
+ if (Addrs.size() > 0) {
+ OS << "Addrs: [";
+ for (uint64_t Addr : Addrs) {
+ OS << format(AddrFmt.c_str(), Addr);
+ if (DumpOpts.Verbose)
+ OS << format(AddrFmtVerbose.c_str(),
+ Addr + HeaderOffset + sizeof(HeaderData));
+ }
+ OS << "\n]\n";
+ }
+}
+
+Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
+ if (Index < Addrs.size())
+ return Addrs[Index];
+ return createStringError(errc::invalid_argument,
+ "Index %" PRIu32 " is out of range of the "
+ ".debug_addr table at offset 0x%" PRIx32,
+ Index, HeaderOffset);
+}
+
+uint32_t DWARFDebugAddrTable::getLength() const {
+ if (HeaderData.Length == 0)
+ return 0;
+ // TODO: DWARF64 support.
+ return HeaderData.Length + sizeof(uint32_t);
+}
+
+uint32_t DWARFDebugAddrTable::getDataSize() const {
+ if (DataSize != 0)
+ return DataSize;
+ if (getLength() == 0)
+ return 0;
+ return getLength() - getHeaderSize();
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
new file mode 100644
index 000000000000..b9ef6905912a
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
@@ -0,0 +1,112 @@
+//===- DWARFDebugArangeSet.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/DWARFDebugArangeSet.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+
+void DWARFDebugArangeSet::Descriptor::dump(raw_ostream &OS,
+ uint32_t AddressSize) const {
+ OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, Address)
+ << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2,
+ getEndAddress());
+}
+
+void DWARFDebugArangeSet::clear() {
+ Offset = -1U;
+ std::memset(&HeaderData, 0, sizeof(Header));
+ ArangeDescriptors.clear();
+}
+
+bool
+DWARFDebugArangeSet::extract(DataExtractor data, uint32_t *offset_ptr) {
+ if (data.isValidOffset(*offset_ptr)) {
+ ArangeDescriptors.clear();
+ Offset = *offset_ptr;
+
+ // 7.20 Address Range Table
+ //
+ // Each set of entries in the table of address ranges contained in
+ // the .debug_aranges section begins with a header consisting of: a
+ // 4-byte length containing the length of the set of entries for this
+ // compilation unit, not including the length field itself; a 2-byte
+ // version identifier containing the value 2 for DWARF Version 2; a
+ // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer
+ // containing the size in bytes of an address (or the offset portion of
+ // an address for segmented addressing) on the target system; and a
+ // 1-byte unsigned integer containing the size in bytes of a segment
+ // descriptor on the target system. This header is followed by a series
+ // of tuples. Each tuple consists of an address and a length, each in
+ // the size appropriate for an address on the target architecture.
+ HeaderData.Length = data.getU32(offset_ptr);
+ HeaderData.Version = data.getU16(offset_ptr);
+ HeaderData.CuOffset = data.getU32(offset_ptr);
+ HeaderData.AddrSize = data.getU8(offset_ptr);
+ HeaderData.SegSize = data.getU8(offset_ptr);
+
+ // Perform basic validation of the header fields.
+ if (!data.isValidOffsetForDataOfSize(Offset, HeaderData.Length) ||
+ (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)) {
+ clear();
+ return false;
+ }
+
+ // The first tuple following the header in each set begins at an offset
+ // that is a multiple of the size of a single tuple (that is, twice the
+ // size of an address). The header is padded, if necessary, to the
+ // appropriate boundary.
+ const uint32_t header_size = *offset_ptr - Offset;
+ const uint32_t tuple_size = HeaderData.AddrSize * 2;
+ uint32_t first_tuple_offset = 0;
+ while (first_tuple_offset < header_size)
+ first_tuple_offset += tuple_size;
+
+ *offset_ptr = Offset + first_tuple_offset;
+
+ Descriptor arangeDescriptor;
+
+ static_assert(sizeof(arangeDescriptor.Address) ==
+ sizeof(arangeDescriptor.Length),
+ "Different datatypes for addresses and sizes!");
+ assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize);
+
+ while (data.isValidOffset(*offset_ptr)) {
+ arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
+ arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
+
+ // Each set of tuples is terminated by a 0 for the address and 0
+ // for the length.
+ if (arangeDescriptor.Address || arangeDescriptor.Length)
+ ArangeDescriptors.push_back(arangeDescriptor);
+ else
+ break; // We are done if we get a zero address and length
+ }
+
+ return !ArangeDescriptors.empty();
+ }
+ return false;
+}
+
+void DWARFDebugArangeSet::dump(raw_ostream &OS) const {
+ OS << format("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, ",
+ HeaderData.Length, HeaderData.Version)
+ << format("cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n",
+ HeaderData.CuOffset, HeaderData.AddrSize, HeaderData.SegSize);
+
+ for (const auto &Desc : ArangeDescriptors) {
+ Desc.dump(OS, HeaderData.AddrSize);
+ OS << '\n';
+ }
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
new file mode 100644
index 000000000000..e8c5dec821b4
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
@@ -0,0 +1,134 @@
+//===- DWARFDebugAranges.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/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/WithColor.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <set>
+#include <vector>
+
+using namespace llvm;
+
+void DWARFDebugAranges::extract(DataExtractor DebugArangesData) {
+ if (!DebugArangesData.isValidOffset(0))
+ return;
+ uint32_t Offset = 0;
+ DWARFDebugArangeSet Set;
+
+ while (Set.extract(DebugArangesData, &Offset)) {
+ uint32_t CUOffset = Set.getCompileUnitDIEOffset();
+ for (const auto &Desc : Set.descriptors()) {
+ uint64_t LowPC = Desc.Address;
+ uint64_t HighPC = Desc.getEndAddress();
+ appendRange(CUOffset, LowPC, HighPC);
+ }
+ ParsedCUOffsets.insert(CUOffset);
+ }
+}
+
+void DWARFDebugAranges::generate(DWARFContext *CTX) {
+ clear();
+ if (!CTX)
+ return;
+
+ // Extract aranges from .debug_aranges section.
+ DataExtractor ArangesData(CTX->getDWARFObj().getARangeSection(),
+ CTX->isLittleEndian(), 0);
+ extract(ArangesData);
+
+ // Generate aranges from DIEs: even if .debug_aranges section is present,
+ // it may describe only a small subset of compilation units, so we need to
+ // manually build aranges for the rest of them.
+ for (const auto &CU : CTX->compile_units()) {
+ uint32_t CUOffset = CU->getOffset();
+ if (ParsedCUOffsets.insert(CUOffset).second) {
+ Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges();
+ if (!CURanges)
+ WithColor::error() << toString(CURanges.takeError()) << '\n';
+ else
+ for (const auto &R : *CURanges)
+ appendRange(CUOffset, R.LowPC, R.HighPC);
+ }
+ }
+
+ construct();
+}
+
+void DWARFDebugAranges::clear() {
+ Endpoints.clear();
+ Aranges.clear();
+ ParsedCUOffsets.clear();
+}
+
+void DWARFDebugAranges::appendRange(uint32_t CUOffset, uint64_t LowPC,
+ uint64_t HighPC) {
+ if (LowPC >= HighPC)
+ return;
+ Endpoints.emplace_back(LowPC, CUOffset, true);
+ Endpoints.emplace_back(HighPC, CUOffset, false);
+}
+
+void DWARFDebugAranges::construct() {
+ std::multiset<uint32_t> ValidCUs; // Maintain the set of CUs describing
+ // a current address range.
+ llvm::sort(Endpoints);
+ uint64_t PrevAddress = -1ULL;
+ for (const auto &E : Endpoints) {
+ if (PrevAddress < E.Address && !ValidCUs.empty()) {
+ // If the address range between two endpoints is described by some
+ // CU, first try to extend the last range in Aranges. If we can't
+ // do it, start a new range.
+ if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress &&
+ ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) {
+ Aranges.back().setHighPC(E.Address);
+ } else {
+ Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin());
+ }
+ }
+ // Update the set of valid CUs.
+ if (E.IsRangeStart) {
+ ValidCUs.insert(E.CUOffset);
+ } else {
+ auto CUPos = ValidCUs.find(E.CUOffset);
+ assert(CUPos != ValidCUs.end());
+ ValidCUs.erase(CUPos);
+ }
+ PrevAddress = E.Address;
+ }
+ assert(ValidCUs.empty());
+
+ // Endpoints are not needed now.
+ Endpoints.clear();
+ Endpoints.shrink_to_fit();
+}
+
+uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const {
+ if (!Aranges.empty()) {
+ Range range(Address);
+ RangeCollIterator begin = Aranges.begin();
+ RangeCollIterator end = Aranges.end();
+ RangeCollIterator pos =
+ std::lower_bound(begin, end, range);
+
+ if (pos != end && pos->containsAddress(Address)) {
+ return pos->CUOffset;
+ } else if (pos != begin) {
+ --pos;
+ if (pos->containsAddress(Address))
+ return pos->CUOffset;
+ }
+ }
+ return -1U;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
new file mode 100644
index 000000000000..ba55ffc28174
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -0,0 +1,556 @@
+//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===//
+//
+// 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/DWARFDebugFrame.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+
+// See DWARF standard v3, section 7.23
+const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
+const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
+
+Error CFIProgram::parse(DataExtractor Data, uint32_t *Offset,
+ uint32_t EndOffset) {
+ while (*Offset < EndOffset) {
+ uint8_t Opcode = Data.getU8(Offset);
+ // Some instructions have a primary opcode encoded in the top bits.
+ uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK;
+
+ if (Primary) {
+ // If it's a primary opcode, the first operand is encoded in the bottom
+ // bits of the opcode itself.
+ uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
+ switch (Primary) {
+ default:
+ return createStringError(errc::illegal_byte_sequence,
+ "Invalid primary CFI opcode 0x%" PRIx8,
+ Primary);
+ case DW_CFA_advance_loc:
+ case DW_CFA_restore:
+ addInstruction(Primary, Op1);
+ break;
+ case DW_CFA_offset:
+ addInstruction(Primary, Op1, Data.getULEB128(Offset));
+ break;
+ }
+ } else {
+ // Extended opcode - its value is Opcode itself.
+ switch (Opcode) {
+ default:
+ return createStringError(errc::illegal_byte_sequence,
+ "Invalid extended CFI opcode 0x%" PRIx8,
+ Opcode);
+ case DW_CFA_nop:
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ case DW_CFA_GNU_window_save:
+ // No operands
+ addInstruction(Opcode);
+ break;
+ case DW_CFA_set_loc:
+ // Operands: Address
+ addInstruction(Opcode, Data.getAddress(Offset));
+ break;
+ case DW_CFA_advance_loc1:
+ // Operands: 1-byte delta
+ addInstruction(Opcode, Data.getU8(Offset));
+ break;
+ case DW_CFA_advance_loc2:
+ // Operands: 2-byte delta
+ addInstruction(Opcode, Data.getU16(Offset));
+ break;
+ case DW_CFA_advance_loc4:
+ // Operands: 4-byte delta
+ addInstruction(Opcode, Data.getU32(Offset));
+ break;
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_GNU_args_size:
+ // Operands: ULEB128
+ addInstruction(Opcode, Data.getULEB128(Offset));
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ // Operands: SLEB128
+ addInstruction(Opcode, Data.getSLEB128(Offset));
+ break;
+ case DW_CFA_offset_extended:
+ case DW_CFA_register:
+ case DW_CFA_def_cfa:
+ case DW_CFA_val_offset: {
+ // Operands: ULEB128, ULEB128
+ // Note: We can not embed getULEB128 directly into function
+ // argument list. getULEB128 changes Offset and order of evaluation
+ // for arguments is unspecified.
+ auto op1 = Data.getULEB128(Offset);
+ auto op2 = Data.getULEB128(Offset);
+ addInstruction(Opcode, op1, op2);
+ break;
+ }
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_val_offset_sf: {
+ // Operands: ULEB128, SLEB128
+ // Note: see comment for the previous case
+ auto op1 = Data.getULEB128(Offset);
+ auto op2 = (uint64_t)Data.getSLEB128(Offset);
+ addInstruction(Opcode, op1, op2);
+ break;
+ }
+ case DW_CFA_def_cfa_expression: {
+ uint32_t ExprLength = Data.getULEB128(Offset);
+ addInstruction(Opcode, 0);
+ DataExtractor Extractor(
+ Data.getData().slice(*Offset, *Offset + ExprLength),
+ Data.isLittleEndian(), Data.getAddressSize());
+ Instructions.back().Expression = DWARFExpression(
+ Extractor, Data.getAddressSize(), dwarf::DWARF_VERSION);
+ *Offset += ExprLength;
+ break;
+ }
+ case DW_CFA_expression:
+ case DW_CFA_val_expression: {
+ auto RegNum = Data.getULEB128(Offset);
+ auto BlockLength = Data.getULEB128(Offset);
+ addInstruction(Opcode, RegNum, 0);
+ DataExtractor Extractor(
+ Data.getData().slice(*Offset, *Offset + BlockLength),
+ Data.isLittleEndian(), Data.getAddressSize());
+ Instructions.back().Expression = DWARFExpression(
+ Extractor, Data.getAddressSize(), dwarf::DWARF_VERSION);
+ *Offset += BlockLength;
+ break;
+ }
+ }
+ }
+ }
+
+ return Error::success();
+}
+
+namespace {
+
+
+} // end anonymous namespace
+
+ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
+ static OperandType OpTypes[DW_CFA_restore+1][2];
+ static bool Initialized = false;
+ if (Initialized) {
+ return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+ }
+ Initialized = true;
+
+#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
+ do { \
+ OpTypes[OP][0] = OPTYPE0; \
+ OpTypes[OP][1] = OPTYPE1; \
+ } while (false)
+#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
+#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
+
+ DECLARE_OP1(DW_CFA_set_loc, OT_Address);
+ DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset);
+ DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
+ DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
+ DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
+ DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
+ DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
+ DECLARE_OP1(DW_CFA_undefined, OT_Register);
+ DECLARE_OP1(DW_CFA_same_value, OT_Register);
+ DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register);
+ DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression);
+ DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression);
+ DECLARE_OP1(DW_CFA_restore, OT_Register);
+ DECLARE_OP1(DW_CFA_restore_extended, OT_Register);
+ DECLARE_OP0(DW_CFA_remember_state);
+ DECLARE_OP0(DW_CFA_restore_state);
+ DECLARE_OP0(DW_CFA_GNU_window_save);
+ DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
+ DECLARE_OP0(DW_CFA_nop);
+
+#undef DECLARE_OP0
+#undef DECLARE_OP1
+#undef DECLARE_OP2
+
+ return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+}
+
+/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
+void CFIProgram::printOperand(raw_ostream &OS, const MCRegisterInfo *MRI,
+ bool IsEH, const Instruction &Instr,
+ unsigned OperandIdx, uint64_t Operand) const {
+ assert(OperandIdx < 2);
+ uint8_t Opcode = Instr.Opcode;
+ OperandType Type = getOperandTypes()[Opcode][OperandIdx];
+
+ switch (Type) {
+ case OT_Unset: {
+ OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
+ auto OpcodeName = CallFrameString(Opcode, Arch);
+ if (!OpcodeName.empty())
+ OS << " " << OpcodeName;
+ else
+ OS << format(" Opcode %x", Opcode);
+ break;
+ }
+ case OT_None:
+ break;
+ case OT_Address:
+ OS << format(" %" PRIx64, Operand);
+ break;
+ case OT_Offset:
+ // The offsets are all encoded in a unsigned form, but in practice
+ // consumers use them signed. It's most certainly legacy due to
+ // the lack of signed variants in the first Dwarf standards.
+ OS << format(" %+" PRId64, int64_t(Operand));
+ break;
+ case OT_FactoredCodeOffset: // Always Unsigned
+ if (CodeAlignmentFactor)
+ OS << format(" %" PRId64, Operand * CodeAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*code_alignment_factor" , Operand);
+ break;
+ case OT_SignedFactDataOffset:
+ if (DataAlignmentFactor)
+ OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand));
+ break;
+ case OT_UnsignedFactDataOffset:
+ if (DataAlignmentFactor)
+ OS << format(" %" PRId64, Operand * DataAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*data_alignment_factor" , Operand);
+ break;
+ case OT_Register:
+ OS << format(" reg%" PRId64, Operand);
+ break;
+ case OT_Expression:
+ assert(Instr.Expression && "missing DWARFExpression object");
+ OS << " ";
+ Instr.Expression->print(OS, MRI, IsEH);
+ break;
+ }
+}
+
+void CFIProgram::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+ unsigned IndentLevel) const {
+ for (const auto &Instr : Instructions) {
+ uint8_t Opcode = Instr.Opcode;
+ if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
+ Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
+ OS.indent(2 * IndentLevel);
+ OS << CallFrameString(Opcode, Arch) << ":";
+ for (unsigned i = 0; i < Instr.Ops.size(); ++i)
+ printOperand(OS, MRI, IsEH, Instr, i, Instr.Ops[i]);
+ OS << '\n';
+ }
+}
+
+void CIE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
+ OS << format("%08x %08x %08x CIE", (uint32_t)Offset, (uint32_t)Length,
+ DW_CIE_ID)
+ << "\n";
+ OS << format(" Version: %d\n", Version);
+ OS << " Augmentation: \"" << Augmentation << "\"\n";
+ if (Version >= 4) {
+ OS << format(" Address size: %u\n", (uint32_t)AddressSize);
+ OS << format(" Segment desc size: %u\n",
+ (uint32_t)SegmentDescriptorSize);
+ }
+ OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor);
+ OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor);
+ OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister);
+ if (Personality)
+ OS << format(" Personality Address: %08x\n", *Personality);
+ if (!AugmentationData.empty()) {
+ OS << " Augmentation data: ";
+ for (uint8_t Byte : AugmentationData)
+ OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
+ OS << "\n";
+ }
+ OS << "\n";
+ CFIs.dump(OS, MRI, IsEH);
+ OS << "\n";
+}
+
+void FDE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
+ OS << format("%08x %08x %08x FDE ", (uint32_t)Offset, (uint32_t)Length,
+ (int32_t)LinkedCIEOffset);
+ OS << format("cie=%08x pc=%08x...%08x\n", (int32_t)LinkedCIEOffset,
+ (uint32_t)InitialLocation,
+ (uint32_t)InitialLocation + (uint32_t)AddressRange);
+ if (LSDAAddress)
+ OS << format(" LSDA Address: %08x\n", *LSDAAddress);
+ CFIs.dump(OS, MRI, IsEH);
+ OS << "\n";
+}
+
+DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
+ bool IsEH, uint64_t EHFrameAddress)
+ : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
+
+DWARFDebugFrame::~DWARFDebugFrame() = default;
+
+static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
+ uint32_t Offset, int Length) {
+ errs() << "DUMP: ";
+ for (int i = 0; i < Length; ++i) {
+ uint8_t c = Data.getU8(&Offset);
+ errs().write_hex(c); errs() << " ";
+ }
+ errs() << "\n";
+}
+
+// This is a workaround for old compilers which do not allow
+// noreturn attribute usage in lambdas. Once the support for those
+// compilers are phased out, we can remove this and return back to
+// a ReportError lambda: [StartOffset](const char *ErrorMsg).
+static void LLVM_ATTRIBUTE_NORETURN ReportError(uint32_t StartOffset,
+ const char *ErrorMsg) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ OS << format(ErrorMsg, StartOffset);
+ OS.flush();
+ report_fatal_error(Str);
+}
+
+void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
+ uint32_t Offset = 0;
+ DenseMap<uint32_t, CIE *> CIEs;
+
+ while (Data.isValidOffset(Offset)) {
+ uint32_t StartOffset = Offset;
+
+ bool IsDWARF64 = false;
+ uint64_t Length = Data.getU32(&Offset);
+ uint64_t Id;
+
+ if (Length == UINT32_MAX) {
+ // DWARF-64 is distinguished by the first 32 bits of the initial length
+ // field being 0xffffffff. Then, the next 64 bits are the actual entry
+ // length.
+ IsDWARF64 = true;
+ Length = Data.getU64(&Offset);
+ }
+
+ // At this point, Offset points to the next field after Length.
+ // Length is the structure size excluding itself. Compute an offset one
+ // past the end of the structure (needed to know how many instructions to
+ // read).
+ // TODO: For honest DWARF64 support, DataExtractor will have to treat
+ // offset_ptr as uint64_t*
+ uint32_t StartStructureOffset = Offset;
+ uint32_t EndStructureOffset = Offset + static_cast<uint32_t>(Length);
+
+ // The Id field's size depends on the DWARF format
+ Id = Data.getUnsigned(&Offset, (IsDWARF64 && !IsEH) ? 8 : 4);
+ bool IsCIE =
+ ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID || (IsEH && !Id));
+
+ if (IsCIE) {
+ uint8_t Version = Data.getU8(&Offset);
+ const char *Augmentation = Data.getCStr(&Offset);
+ StringRef AugmentationString(Augmentation ? Augmentation : "");
+ uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
+ Data.getU8(&Offset);
+ Data.setAddressSize(AddressSize);
+ uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
+ uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
+ int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
+ uint64_t ReturnAddressRegister =
+ Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);
+
+ // Parse the augmentation data for EH CIEs
+ StringRef AugmentationData("");
+ uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
+ uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
+ Optional<uint64_t> Personality;
+ Optional<uint32_t> PersonalityEncoding;
+ if (IsEH) {
+ Optional<uint64_t> AugmentationLength;
+ uint32_t StartAugmentationOffset;
+ uint32_t EndAugmentationOffset;
+
+ // Walk the augmentation string to get all the augmentation data.
+ for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
+ switch (AugmentationString[i]) {
+ default:
+ ReportError(StartOffset,
+ "Unknown augmentation character in entry at %lx");
+ case 'L':
+ LSDAPointerEncoding = Data.getU8(&Offset);
+ break;
+ case 'P': {
+ if (Personality)
+ ReportError(StartOffset,
+ "Duplicate personality in entry at %lx");
+ PersonalityEncoding = Data.getU8(&Offset);
+ Personality = Data.getEncodedPointer(
+ &Offset, *PersonalityEncoding,
+ EHFrameAddress ? EHFrameAddress + Offset : 0);
+ break;
+ }
+ case 'R':
+ FDEPointerEncoding = Data.getU8(&Offset);
+ break;
+ case 'S':
+ // Current frame is a signal trampoline.
+ break;
+ case 'z':
+ if (i)
+ ReportError(StartOffset,
+ "'z' must be the first character at %lx");
+ // Parse the augmentation length first. We only parse it if
+ // the string contains a 'z'.
+ AugmentationLength = Data.getULEB128(&Offset);
+ StartAugmentationOffset = Offset;
+ EndAugmentationOffset = Offset +
+ static_cast<uint32_t>(*AugmentationLength);
+ break;
+ case 'B':
+ // B-Key is used for signing functions associated with this
+ // augmentation string
+ break;
+ }
+ }
+
+ if (AugmentationLength.hasValue()) {
+ if (Offset != EndAugmentationOffset)
+ ReportError(StartOffset, "Parsing augmentation data at %lx failed");
+
+ AugmentationData = Data.getData().slice(StartAugmentationOffset,
+ EndAugmentationOffset);
+ }
+ }
+
+ auto Cie = llvm::make_unique<CIE>(
+ StartOffset, Length, Version, AugmentationString, AddressSize,
+ SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor,
+ ReturnAddressRegister, AugmentationData, FDEPointerEncoding,
+ LSDAPointerEncoding, Personality, PersonalityEncoding, Arch);
+ CIEs[StartOffset] = Cie.get();
+ Entries.emplace_back(std::move(Cie));
+ } else {
+ // FDE
+ uint64_t CIEPointer = Id;
+ uint64_t InitialLocation = 0;
+ uint64_t AddressRange = 0;
+ Optional<uint64_t> LSDAAddress;
+ CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
+
+ if (IsEH) {
+ // The address size is encoded in the CIE we reference.
+ if (!Cie)
+ ReportError(StartOffset,
+ "Parsing FDE data at %lx failed due to missing CIE");
+
+ if (auto Val = Data.getEncodedPointer(
+ &Offset, Cie->getFDEPointerEncoding(),
+ EHFrameAddress ? EHFrameAddress + Offset : 0)) {
+ InitialLocation = *Val;
+ }
+ if (auto Val = Data.getEncodedPointer(
+ &Offset, Cie->getFDEPointerEncoding(), 0)) {
+ AddressRange = *Val;
+ }
+
+ StringRef AugmentationString = Cie->getAugmentationString();
+ if (!AugmentationString.empty()) {
+ // Parse the augmentation length and data for this FDE.
+ uint64_t AugmentationLength = Data.getULEB128(&Offset);
+
+ uint32_t EndAugmentationOffset =
+ Offset + static_cast<uint32_t>(AugmentationLength);
+
+ // Decode the LSDA if the CIE augmentation string said we should.
+ if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) {
+ LSDAAddress = Data.getEncodedPointer(
+ &Offset, Cie->getLSDAPointerEncoding(),
+ EHFrameAddress ? Offset + EHFrameAddress : 0);
+ }
+
+ if (Offset != EndAugmentationOffset)
+ ReportError(StartOffset, "Parsing augmentation data at %lx failed");
+ }
+ } else {
+ InitialLocation = Data.getAddress(&Offset);
+ AddressRange = Data.getAddress(&Offset);
+ }
+
+ Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
+ InitialLocation, AddressRange,
+ Cie, LSDAAddress, Arch));
+ }
+
+ if (Error E =
+ Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset)) {
+ report_fatal_error(toString(std::move(E)));
+ }
+
+ if (Offset != EndStructureOffset)
+ ReportError(StartOffset, "Parsing entry instructions at %lx failed");
+ }
+}
+
+FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
+ auto It =
+ std::lower_bound(Entries.begin(), Entries.end(), Offset,
+ [](const std::unique_ptr<FrameEntry> &E,
+ uint64_t Offset) { return E->getOffset() < Offset; });
+ if (It != Entries.end() && (*It)->getOffset() == Offset)
+ return It->get();
+ return nullptr;
+}
+
+void DWARFDebugFrame::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ Optional<uint64_t> Offset) const {
+ if (Offset) {
+ if (auto *Entry = getEntryAtOffset(*Offset))
+ Entry->dump(OS, MRI, IsEH);
+ return;
+ }
+
+ OS << "\n";
+ for (const auto &Entry : Entries)
+ Entry->dump(OS, MRI, IsEH);
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 000000000000..976bc4651ae6
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,70 @@
+//===- DWARFDebugInfoEntry.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/DWARFDebugInfoEntry.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U,
+ uint32_t *OffsetPtr) {
+ DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
+ const uint32_t UEndOffset = U.getNextUnitOffset();
+ return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset, 0);
+}
+
+bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr,
+ const DWARFDataExtractor &DebugInfoData,
+ uint32_t UEndOffset, uint32_t D) {
+ Offset = *OffsetPtr;
+ Depth = D;
+ if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset))
+ return false;
+ uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
+ if (0 == AbbrCode) {
+ // NULL debug tag entry.
+ AbbrevDecl = nullptr;
+ return true;
+ }
+ AbbrevDecl = U.getAbbreviations()->getAbbreviationDeclaration(AbbrCode);
+ if (nullptr == AbbrevDecl) {
+ // Restore the original offset.
+ *OffsetPtr = Offset;
+ return false;
+ }
+ // See if all attributes in this DIE have fixed byte sizes. If so, we can
+ // just add this size to the offset to skip to the next DIE.
+ if (Optional<size_t> FixedSize = AbbrevDecl->getFixedAttributesByteSize(U)) {
+ *OffsetPtr += *FixedSize;
+ return true;
+ }
+
+ // Skip all data in the .debug_info for the attributes
+ for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+ // Check if this attribute has a fixed byte size.
+ if (auto FixedSize = AttrSpec.getByteSize(U)) {
+ // Attribute byte size if fixed, just add the size to the offset.
+ *OffsetPtr += *FixedSize;
+ } else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData,
+ OffsetPtr, U.getFormParams())) {
+ // We failed to skip this attribute's value, restore the original offset
+ // and return the failure status.
+ *OffsetPtr = Offset;
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
new file mode 100644
index 000000000000..1d621ff244f3
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -0,0 +1,1114 @@
+//===- DWARFDebugLine.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/DWARFDebugLine.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <cstdio>
+#include <utility>
+
+using namespace llvm;
+using namespace dwarf;
+
+using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
+
+namespace {
+
+struct ContentDescriptor {
+ dwarf::LineNumberEntryFormat Type;
+ dwarf::Form Form;
+};
+
+using ContentDescriptors = SmallVector<ContentDescriptor, 4>;
+
+} // end anonmyous namespace
+
+void DWARFDebugLine::ContentTypeTracker::trackContentType(
+ dwarf::LineNumberEntryFormat ContentType) {
+ switch (ContentType) {
+ case dwarf::DW_LNCT_timestamp:
+ HasModTime = true;
+ break;
+ case dwarf::DW_LNCT_size:
+ HasLength = true;
+ break;
+ case dwarf::DW_LNCT_MD5:
+ HasMD5 = true;
+ break;
+ case dwarf::DW_LNCT_LLVM_source:
+ HasSource = true;
+ break;
+ default:
+ // We only care about values we consider optional, and new values may be
+ // added in the vendor extension range, so we do not match exhaustively.
+ break;
+ }
+}
+
+DWARFDebugLine::Prologue::Prologue() { clear(); }
+
+void DWARFDebugLine::Prologue::clear() {
+ TotalLength = PrologueLength = 0;
+ SegSelectorSize = 0;
+ MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0;
+ OpcodeBase = 0;
+ FormParams = dwarf::FormParams({0, 0, DWARF32});
+ ContentTypes = ContentTypeTracker();
+ StandardOpcodeLengths.clear();
+ IncludeDirectories.clear();
+ FileNames.clear();
+}
+
+void DWARFDebugLine::Prologue::dump(raw_ostream &OS,
+ DIDumpOptions DumpOptions) const {
+ OS << "Line table prologue:\n"
+ << format(" total_length: 0x%8.8" PRIx64 "\n", TotalLength)
+ << format(" version: %u\n", getVersion());
+ if (getVersion() >= 5)
+ OS << format(" address_size: %u\n", getAddressSize())
+ << format(" seg_select_size: %u\n", SegSelectorSize);
+ OS << format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength)
+ << format(" min_inst_length: %u\n", MinInstLength)
+ << format(getVersion() >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst)
+ << format(" default_is_stmt: %u\n", DefaultIsStmt)
+ << format(" line_base: %i\n", LineBase)
+ << format(" line_range: %u\n", LineRange)
+ << format(" opcode_base: %u\n", OpcodeBase);
+
+ for (uint32_t I = 0; I != StandardOpcodeLengths.size(); ++I)
+ OS << format("standard_opcode_lengths[%s] = %u\n",
+ LNStandardString(I + 1).data(), StandardOpcodeLengths[I]);
+
+ if (!IncludeDirectories.empty()) {
+ // DWARF v5 starts directory indexes at 0.
+ uint32_t DirBase = getVersion() >= 5 ? 0 : 1;
+ for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) {
+ OS << format("include_directories[%3u] = ", I + DirBase);
+ IncludeDirectories[I].dump(OS, DumpOptions);
+ OS << '\n';
+ }
+ }
+
+ if (!FileNames.empty()) {
+ // DWARF v5 starts file indexes at 0.
+ uint32_t FileBase = getVersion() >= 5 ? 0 : 1;
+ for (uint32_t I = 0; I != FileNames.size(); ++I) {
+ const FileNameEntry &FileEntry = FileNames[I];
+ OS << format("file_names[%3u]:\n", I + FileBase);
+ OS << " name: ";
+ FileEntry.Name.dump(OS, DumpOptions);
+ OS << '\n'
+ << format(" dir_index: %" PRIu64 "\n", FileEntry.DirIdx);
+ if (ContentTypes.HasMD5)
+ OS << " md5_checksum: " << FileEntry.Checksum.digest() << '\n';
+ if (ContentTypes.HasModTime)
+ OS << format(" mod_time: 0x%8.8" PRIx64 "\n", FileEntry.ModTime);
+ if (ContentTypes.HasLength)
+ OS << format(" length: 0x%8.8" PRIx64 "\n", FileEntry.Length);
+ if (ContentTypes.HasSource) {
+ OS << " source: ";
+ FileEntry.Source.dump(OS, DumpOptions);
+ OS << '\n';
+ }
+ }
+ }
+}
+
+// Parse v2-v4 directory and file tables.
+static void
+parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
+ uint32_t *OffsetPtr, uint64_t EndPrologueOffset,
+ DWARFDebugLine::ContentTypeTracker &ContentTypes,
+ std::vector<DWARFFormValue> &IncludeDirectories,
+ std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
+ while (*OffsetPtr < EndPrologueOffset) {
+ StringRef S = DebugLineData.getCStrRef(OffsetPtr);
+ if (S.empty())
+ break;
+ DWARFFormValue Dir(dwarf::DW_FORM_string);
+ Dir.setPValue(S.data());
+ IncludeDirectories.push_back(Dir);
+ }
+
+ while (*OffsetPtr < EndPrologueOffset) {
+ StringRef Name = DebugLineData.getCStrRef(OffsetPtr);
+ if (Name.empty())
+ break;
+ DWARFDebugLine::FileNameEntry FileEntry;
+ FileEntry.Name.setForm(dwarf::DW_FORM_string);
+ FileEntry.Name.setPValue(Name.data());
+ FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
+ FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
+ FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
+ FileNames.push_back(FileEntry);
+ }
+
+ ContentTypes.HasModTime = true;
+ ContentTypes.HasLength = true;
+}
+
+// Parse v5 directory/file entry content descriptions.
+// Returns the descriptors, or an empty vector if we did not find a path or
+// ran off the end of the prologue.
+static ContentDescriptors
+parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t
+ *OffsetPtr, uint64_t EndPrologueOffset, DWARFDebugLine::ContentTypeTracker
+ *ContentTypes) {
+ ContentDescriptors Descriptors;
+ int FormatCount = DebugLineData.getU8(OffsetPtr);
+ bool HasPath = false;
+ for (int I = 0; I != FormatCount; ++I) {
+ if (*OffsetPtr >= EndPrologueOffset)
+ return ContentDescriptors();
+ ContentDescriptor Descriptor;
+ Descriptor.Type =
+ dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr));
+ Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr));
+ if (Descriptor.Type == dwarf::DW_LNCT_path)
+ HasPath = true;
+ if (ContentTypes)
+ ContentTypes->trackContentType(Descriptor.Type);
+ Descriptors.push_back(Descriptor);
+ }
+ return HasPath ? Descriptors : ContentDescriptors();
+}
+
+static bool
+parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
+ uint32_t *OffsetPtr, uint64_t EndPrologueOffset,
+ const dwarf::FormParams &FormParams,
+ const DWARFContext &Ctx, const DWARFUnit *U,
+ DWARFDebugLine::ContentTypeTracker &ContentTypes,
+ std::vector<DWARFFormValue> &IncludeDirectories,
+ std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
+ // Get the directory entry description.
+ ContentDescriptors DirDescriptors =
+ parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, nullptr);
+ if (DirDescriptors.empty())
+ return false;
+
+ // Get the directory entries, according to the format described above.
+ int DirEntryCount = DebugLineData.getU8(OffsetPtr);
+ for (int I = 0; I != DirEntryCount; ++I) {
+ if (*OffsetPtr >= EndPrologueOffset)
+ return false;
+ for (auto Descriptor : DirDescriptors) {
+ DWARFFormValue Value(Descriptor.Form);
+ switch (Descriptor.Type) {
+ case DW_LNCT_path:
+ if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
+ return false;
+ IncludeDirectories.push_back(Value);
+ break;
+ default:
+ if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams))
+ return false;
+ }
+ }
+ }
+
+ // Get the file entry description.
+ ContentDescriptors FileDescriptors =
+ parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset,
+ &ContentTypes);
+ if (FileDescriptors.empty())
+ return false;
+
+ // Get the file entries, according to the format described above.
+ int FileEntryCount = DebugLineData.getU8(OffsetPtr);
+ for (int I = 0; I != FileEntryCount; ++I) {
+ if (*OffsetPtr >= EndPrologueOffset)
+ return false;
+ DWARFDebugLine::FileNameEntry FileEntry;
+ for (auto Descriptor : FileDescriptors) {
+ DWARFFormValue Value(Descriptor.Form);
+ if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
+ return false;
+ switch (Descriptor.Type) {
+ case DW_LNCT_path:
+ FileEntry.Name = Value;
+ break;
+ case DW_LNCT_LLVM_source:
+ FileEntry.Source = Value;
+ break;
+ case DW_LNCT_directory_index:
+ FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue();
+ break;
+ case DW_LNCT_timestamp:
+ FileEntry.ModTime = Value.getAsUnsignedConstant().getValue();
+ break;
+ case DW_LNCT_size:
+ FileEntry.Length = Value.getAsUnsignedConstant().getValue();
+ break;
+ case DW_LNCT_MD5:
+ assert(Value.getAsBlock().getValue().size() == 16);
+ std::uninitialized_copy_n(Value.getAsBlock().getValue().begin(), 16,
+ FileEntry.Checksum.Bytes.begin());
+ break;
+ default:
+ break;
+ }
+ }
+ FileNames.push_back(FileEntry);
+ }
+ return true;
+}
+
+Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
+ uint32_t *OffsetPtr,
+ const DWARFContext &Ctx,
+ const DWARFUnit *U) {
+ const uint64_t PrologueOffset = *OffsetPtr;
+
+ clear();
+ TotalLength = DebugLineData.getU32(OffsetPtr);
+ if (TotalLength == UINT32_MAX) {
+ FormParams.Format = dwarf::DWARF64;
+ TotalLength = DebugLineData.getU64(OffsetPtr);
+ } else if (TotalLength >= 0xffffff00) {
+ return createStringError(errc::invalid_argument,
+ "parsing line table prologue at offset 0x%8.8" PRIx64
+ " unsupported reserved unit length found of value 0x%8.8" PRIx64,
+ PrologueOffset, TotalLength);
+ }
+ FormParams.Version = DebugLineData.getU16(OffsetPtr);
+ if (getVersion() < 2)
+ return createStringError(errc::not_supported,
+ "parsing line table prologue at offset 0x%8.8" PRIx64
+ " found unsupported version 0x%2.2" PRIx16,
+ PrologueOffset, getVersion());
+
+ if (getVersion() >= 5) {
+ FormParams.AddrSize = DebugLineData.getU8(OffsetPtr);
+ assert((DebugLineData.getAddressSize() == 0 ||
+ DebugLineData.getAddressSize() == getAddressSize()) &&
+ "Line table header and data extractor disagree");
+ SegSelectorSize = DebugLineData.getU8(OffsetPtr);
+ }
+
+ PrologueLength = DebugLineData.getUnsigned(OffsetPtr, sizeofPrologueLength());
+ const uint64_t EndPrologueOffset = PrologueLength + *OffsetPtr;
+ MinInstLength = DebugLineData.getU8(OffsetPtr);
+ if (getVersion() >= 4)
+ MaxOpsPerInst = DebugLineData.getU8(OffsetPtr);
+ DefaultIsStmt = DebugLineData.getU8(OffsetPtr);
+ LineBase = DebugLineData.getU8(OffsetPtr);
+ LineRange = DebugLineData.getU8(OffsetPtr);
+ OpcodeBase = DebugLineData.getU8(OffsetPtr);
+
+ StandardOpcodeLengths.reserve(OpcodeBase - 1);
+ for (uint32_t I = 1; I < OpcodeBase; ++I) {
+ uint8_t OpLen = DebugLineData.getU8(OffsetPtr);
+ StandardOpcodeLengths.push_back(OpLen);
+ }
+
+ if (getVersion() >= 5) {
+ if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
+ FormParams, Ctx, U, ContentTypes,
+ IncludeDirectories, FileNames)) {
+ return createStringError(errc::invalid_argument,
+ "parsing line table prologue at 0x%8.8" PRIx64
+ " found an invalid directory or file table description at"
+ " 0x%8.8" PRIx64,
+ PrologueOffset, (uint64_t)*OffsetPtr);
+ }
+ } else
+ parseV2DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
+ ContentTypes, IncludeDirectories, FileNames);
+
+ if (*OffsetPtr != EndPrologueOffset)
+ return createStringError(errc::invalid_argument,
+ "parsing line table prologue at 0x%8.8" PRIx64
+ " should have ended at 0x%8.8" PRIx64
+ " but it ended at 0x%8.8" PRIx64,
+ PrologueOffset, EndPrologueOffset, (uint64_t)*OffsetPtr);
+ return Error::success();
+}
+
+DWARFDebugLine::Row::Row(bool DefaultIsStmt) { reset(DefaultIsStmt); }
+
+void DWARFDebugLine::Row::postAppend() {
+ BasicBlock = false;
+ PrologueEnd = false;
+ EpilogueBegin = false;
+}
+
+void DWARFDebugLine::Row::reset(bool DefaultIsStmt) {
+ Address = 0;
+ Line = 1;
+ Column = 0;
+ File = 1;
+ Isa = 0;
+ Discriminator = 0;
+ IsStmt = DefaultIsStmt;
+ BasicBlock = false;
+ EndSequence = false;
+ PrologueEnd = false;
+ EpilogueBegin = false;
+}
+
+void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS) {
+ OS << "Address Line Column File ISA Discriminator Flags\n"
+ << "------------------ ------ ------ ------ --- ------------- "
+ "-------------\n";
+}
+
+void DWARFDebugLine::Row::dump(raw_ostream &OS) const {
+ OS << format("0x%16.16" PRIx64 " %6u %6u", Address, Line, Column)
+ << format(" %6u %3u %13u ", File, Isa, Discriminator)
+ << (IsStmt ? " is_stmt" : "") << (BasicBlock ? " basic_block" : "")
+ << (PrologueEnd ? " prologue_end" : "")
+ << (EpilogueBegin ? " epilogue_begin" : "")
+ << (EndSequence ? " end_sequence" : "") << '\n';
+}
+
+DWARFDebugLine::Sequence::Sequence() { reset(); }
+
+void DWARFDebugLine::Sequence::reset() {
+ LowPC = 0;
+ HighPC = 0;
+ FirstRowIndex = 0;
+ LastRowIndex = 0;
+ Empty = true;
+}
+
+DWARFDebugLine::LineTable::LineTable() { clear(); }
+
+void DWARFDebugLine::LineTable::dump(raw_ostream &OS,
+ DIDumpOptions DumpOptions) const {
+ Prologue.dump(OS, DumpOptions);
+ OS << '\n';
+
+ if (!Rows.empty()) {
+ Row::dumpTableHeader(OS);
+ for (const Row &R : Rows) {
+ R.dump(OS);
+ }
+ }
+}
+
+void DWARFDebugLine::LineTable::clear() {
+ Prologue.clear();
+ Rows.clear();
+ Sequences.clear();
+}
+
+DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT)
+ : LineTable(LT) {
+ resetRowAndSequence();
+}
+
+void DWARFDebugLine::ParsingState::resetRowAndSequence() {
+ Row.reset(LineTable->Prologue.DefaultIsStmt);
+ Sequence.reset();
+}
+
+void DWARFDebugLine::ParsingState::appendRowToMatrix(uint32_t Offset) {
+ if (Sequence.Empty) {
+ // Record the beginning of instruction sequence.
+ Sequence.Empty = false;
+ Sequence.LowPC = Row.Address;
+ Sequence.FirstRowIndex = RowNumber;
+ }
+ ++RowNumber;
+ LineTable->appendRow(Row);
+ if (Row.EndSequence) {
+ // Record the end of instruction sequence.
+ Sequence.HighPC = Row.Address;
+ Sequence.LastRowIndex = RowNumber;
+ if (Sequence.isValid())
+ LineTable->appendSequence(Sequence);
+ Sequence.reset();
+ }
+ Row.postAppend();
+}
+
+const DWARFDebugLine::LineTable *
+DWARFDebugLine::getLineTable(uint32_t Offset) const {
+ LineTableConstIter Pos = LineTableMap.find(Offset);
+ if (Pos != LineTableMap.end())
+ return &Pos->second;
+ return nullptr;
+}
+
+Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
+ DWARFDataExtractor &DebugLineData, uint32_t Offset, const DWARFContext &Ctx,
+ const DWARFUnit *U, std::function<void(Error)> RecoverableErrorCallback) {
+ if (!DebugLineData.isValidOffset(Offset))
+ return createStringError(errc::invalid_argument, "offset 0x%8.8" PRIx32
+ " is not a valid debug line section offset",
+ Offset);
+
+ std::pair<LineTableIter, bool> Pos =
+ LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable()));
+ LineTable *LT = &Pos.first->second;
+ if (Pos.second) {
+ if (Error Err =
+ LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorCallback))
+ return std::move(Err);
+ return LT;
+ }
+ return LT;
+}
+
+Error DWARFDebugLine::LineTable::parse(
+ DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
+ const DWARFContext &Ctx, const DWARFUnit *U,
+ std::function<void(Error)> RecoverableErrorCallback, raw_ostream *OS) {
+ const uint32_t DebugLineOffset = *OffsetPtr;
+
+ clear();
+
+ Error PrologueErr = Prologue.parse(DebugLineData, OffsetPtr, Ctx, U);
+
+ if (OS) {
+ // The presence of OS signals verbose dumping.
+ DIDumpOptions DumpOptions;
+ DumpOptions.Verbose = true;
+ Prologue.dump(*OS, DumpOptions);
+ }
+
+ if (PrologueErr)
+ return PrologueErr;
+
+ const uint32_t EndOffset =
+ DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength();
+
+ // See if we should tell the data extractor the address size.
+ if (DebugLineData.getAddressSize() == 0)
+ DebugLineData.setAddressSize(Prologue.getAddressSize());
+ else
+ assert(Prologue.getAddressSize() == 0 ||
+ Prologue.getAddressSize() == DebugLineData.getAddressSize());
+
+ ParsingState State(this);
+
+ while (*OffsetPtr < EndOffset) {
+ if (OS)
+ *OS << format("0x%08.08" PRIx32 ": ", *OffsetPtr);
+
+ uint8_t Opcode = DebugLineData.getU8(OffsetPtr);
+
+ if (OS)
+ *OS << format("%02.02" PRIx8 " ", Opcode);
+
+ if (Opcode == 0) {
+ // Extended Opcodes always start with a zero opcode followed by
+ // a uleb128 length so you can skip ones you don't know about
+ uint64_t Len = DebugLineData.getULEB128(OffsetPtr);
+ uint32_t ExtOffset = *OffsetPtr;
+
+ // Tolerate zero-length; assume length is correct and soldier on.
+ if (Len == 0) {
+ if (OS)
+ *OS << "Badly formed extended line op (length 0)\n";
+ continue;
+ }
+
+ uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr);
+ if (OS)
+ *OS << LNExtendedString(SubOpcode);
+ switch (SubOpcode) {
+ case DW_LNE_end_sequence:
+ // Set the end_sequence register of the state machine to true and
+ // append a row to the matrix using the current values of the
+ // state-machine registers. Then reset the registers to the initial
+ // values specified above. Every statement program sequence must end
+ // with a DW_LNE_end_sequence instruction which creates a row whose
+ // address is that of the byte after the last target machine instruction
+ // of the sequence.
+ State.Row.EndSequence = true;
+ State.appendRowToMatrix(*OffsetPtr);
+ if (OS) {
+ *OS << "\n";
+ OS->indent(12);
+ State.Row.dump(*OS);
+ }
+ State.resetRowAndSequence();
+ break;
+
+ case DW_LNE_set_address:
+ // Takes a single relocatable address as an operand. The size of the
+ // operand is the size appropriate to hold an address on the target
+ // machine. Set the address register to the value given by the
+ // relocatable address. All of the other statement program opcodes
+ // that affect the address register add a delta to it. This instruction
+ // stores a relocatable value into it instead.
+ //
+ // Make sure the extractor knows the address size. If not, infer it
+ // from the size of the operand.
+ if (DebugLineData.getAddressSize() == 0)
+ DebugLineData.setAddressSize(Len - 1);
+ else if (DebugLineData.getAddressSize() != Len - 1) {
+ return createStringError(errc::invalid_argument,
+ "mismatching address size at offset 0x%8.8" PRIx32
+ " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64,
+ ExtOffset, DebugLineData.getAddressSize(),
+ Len - 1);
+ }
+ State.Row.Address = DebugLineData.getRelocatedAddress(OffsetPtr);
+ if (OS)
+ *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address);
+ break;
+
+ case DW_LNE_define_file:
+ // Takes 4 arguments. The first is a null terminated string containing
+ // a source file name. The second is an unsigned LEB128 number
+ // representing the directory index of the directory in which the file
+ // was found. The third is an unsigned LEB128 number representing the
+ // time of last modification of the file. The fourth is an unsigned
+ // LEB128 number representing the length in bytes of the file. The time
+ // and length fields may contain LEB128(0) if the information is not
+ // available.
+ //
+ // The directory index represents an entry in the include_directories
+ // section of the statement program prologue. The index is LEB128(0)
+ // if the file was found in the current directory of the compilation,
+ // LEB128(1) if it was found in the first directory in the
+ // include_directories section, and so on. The directory index is
+ // ignored for file names that represent full path names.
+ //
+ // The files are numbered, starting at 1, in the order in which they
+ // appear; the names in the prologue come before names defined by
+ // the DW_LNE_define_file instruction. These numbers are used in the
+ // the file register of the state machine.
+ {
+ FileNameEntry FileEntry;
+ const char *Name = DebugLineData.getCStr(OffsetPtr);
+ FileEntry.Name.setForm(dwarf::DW_FORM_string);
+ FileEntry.Name.setPValue(Name);
+ FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr);
+ FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr);
+ FileEntry.Length = DebugLineData.getULEB128(OffsetPtr);
+ Prologue.FileNames.push_back(FileEntry);
+ if (OS)
+ *OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time="
+ << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime)
+ << ", length=" << FileEntry.Length << ")";
+ }
+ break;
+
+ case DW_LNE_set_discriminator:
+ State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.Discriminator << ")";
+ break;
+
+ default:
+ if (OS)
+ *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode)
+ << format(" length %" PRIx64, Len);
+ // Len doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that.
+ (*OffsetPtr) += Len - 1;
+ break;
+ }
+ // Make sure the stated and parsed lengths are the same.
+ // Otherwise we have an unparseable line-number program.
+ if (*OffsetPtr - ExtOffset != Len)
+ return createStringError(errc::illegal_byte_sequence,
+ "unexpected line op length at offset 0x%8.8" PRIx32
+ " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx32,
+ ExtOffset, Len, *OffsetPtr - ExtOffset);
+ } else if (Opcode < Prologue.OpcodeBase) {
+ if (OS)
+ *OS << LNStandardString(Opcode);
+ switch (Opcode) {
+ // Standard Opcodes
+ case DW_LNS_copy:
+ // Takes no arguments. Append a row to the matrix using the
+ // current values of the state-machine registers. Then set
+ // the basic_block register to false.
+ State.appendRowToMatrix(*OffsetPtr);
+ if (OS) {
+ *OS << "\n";
+ OS->indent(12);
+ State.Row.dump(*OS);
+ *OS << "\n";
+ }
+ break;
+
+ case DW_LNS_advance_pc:
+ // Takes a single unsigned LEB128 operand, multiplies it by the
+ // min_inst_length field of the prologue, and adds the
+ // result to the address register of the state machine.
+ {
+ uint64_t AddrOffset =
+ DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength;
+ State.Row.Address += AddrOffset;
+ if (OS)
+ *OS << " (" << AddrOffset << ")";
+ }
+ break;
+
+ case DW_LNS_advance_line:
+ // Takes a single signed LEB128 operand and adds that value to
+ // the line register of the state machine.
+ State.Row.Line += DebugLineData.getSLEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.Line << ")";
+ break;
+
+ case DW_LNS_set_file:
+ // Takes a single unsigned LEB128 operand and stores it in the file
+ // register of the state machine.
+ State.Row.File = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.File << ")";
+ break;
+
+ case DW_LNS_set_column:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ State.Row.Column = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.Column << ")";
+ break;
+
+ case DW_LNS_negate_stmt:
+ // Takes no arguments. Set the is_stmt register of the state
+ // machine to the logical negation of its current value.
+ State.Row.IsStmt = !State.Row.IsStmt;
+ break;
+
+ case DW_LNS_set_basic_block:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ State.Row.BasicBlock = true;
+ break;
+
+ case DW_LNS_const_add_pc:
+ // Takes no arguments. Add to the address register of the state
+ // machine the address increment value corresponding to special
+ // opcode 255. The motivation for DW_LNS_const_add_pc is this:
+ // when the statement program needs to advance the address by a
+ // small amount, it can use a single special opcode, which occupies
+ // a single byte. When it needs to advance the address by up to
+ // twice the range of the last special opcode, it can use
+ // DW_LNS_const_add_pc followed by a special opcode, for a total
+ // of two bytes. Only if it needs to advance the address by more
+ // than twice that range will it need to use both DW_LNS_advance_pc
+ // and a special opcode, requiring three or more bytes.
+ {
+ uint8_t AdjustOpcode = 255 - Prologue.OpcodeBase;
+ uint64_t AddrOffset =
+ (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength;
+ State.Row.Address += AddrOffset;
+ if (OS)
+ *OS
+ << format(" (0x%16.16" PRIx64 ")", AddrOffset);
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ // Takes a single uhalf operand. Add to the address register of
+ // the state machine the value of the (unencoded) operand. This
+ // is the only extended opcode that takes an argument that is not
+ // a variable length number. The motivation for DW_LNS_fixed_advance_pc
+ // is this: existing assemblers cannot emit DW_LNS_advance_pc or
+ // special opcodes because they cannot encode LEB128 numbers or
+ // judge when the computation of a special opcode overflows and
+ // requires the use of DW_LNS_advance_pc. Such assemblers, however,
+ // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
+ {
+ uint16_t PCOffset = DebugLineData.getU16(OffsetPtr);
+ State.Row.Address += PCOffset;
+ if (OS)
+ *OS
+ << format(" (0x%16.16" PRIx64 ")", PCOffset);
+ }
+ break;
+
+ case DW_LNS_set_prologue_end:
+ // Takes no arguments. Set the prologue_end register of the
+ // state machine to true
+ State.Row.PrologueEnd = true;
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ State.Row.EpilogueBegin = true;
+ break;
+
+ case DW_LNS_set_isa:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ State.Row.Isa = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.Isa << ")";
+ break;
+
+ default:
+ // Handle any unknown standard opcodes here. We know the lengths
+ // of such opcodes because they are specified in the prologue
+ // as a multiple of LEB128 operands for each opcode.
+ {
+ assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size());
+ uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1];
+ for (uint8_t I = 0; I < OpcodeLength; ++I) {
+ uint64_t Value = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << format("Skipping ULEB128 value: 0x%16.16" PRIx64 ")\n",
+ Value);
+ }
+ }
+ break;
+ }
+ } else {
+ // Special Opcodes
+
+ // A special opcode value is chosen based on the amount that needs
+ // to be added to the line and address registers. The maximum line
+ // increment for a special opcode is the value of the line_base
+ // field in the header, plus the value of the line_range field,
+ // minus 1 (line base + line range - 1). If the desired line
+ // increment is greater than the maximum line increment, a standard
+ // opcode must be used instead of a special opcode. The "address
+ // advance" is calculated by dividing the desired address increment
+ // by the minimum_instruction_length field from the header. The
+ // special opcode is then calculated using the following formula:
+ //
+ // opcode = (desired line increment - line_base) +
+ // (line_range * address advance) + opcode_base
+ //
+ // If the resulting opcode is greater than 255, a standard opcode
+ // must be used instead.
+ //
+ // To decode a special opcode, subtract the opcode_base from the
+ // opcode itself to give the adjusted opcode. The amount to
+ // increment the address register is the result of the adjusted
+ // opcode divided by the line_range multiplied by the
+ // minimum_instruction_length field from the header. That is:
+ //
+ // address increment = (adjusted opcode / line_range) *
+ // minimum_instruction_length
+ //
+ // The amount to increment the line register is the line_base plus
+ // the result of the adjusted opcode modulo the line_range. That is:
+ //
+ // line increment = line_base + (adjusted opcode % line_range)
+
+ uint8_t AdjustOpcode = Opcode - Prologue.OpcodeBase;
+ uint64_t AddrOffset =
+ (AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength;
+ int32_t LineOffset =
+ Prologue.LineBase + (AdjustOpcode % Prologue.LineRange);
+ State.Row.Line += LineOffset;
+ State.Row.Address += AddrOffset;
+
+ if (OS) {
+ *OS << "address += " << ((uint32_t)AdjustOpcode)
+ << ", line += " << LineOffset << "\n";
+ OS->indent(12);
+ State.Row.dump(*OS);
+ }
+
+ State.appendRowToMatrix(*OffsetPtr);
+ // Reset discriminator to 0.
+ State.Row.Discriminator = 0;
+ }
+ if(OS)
+ *OS << "\n";
+ }
+
+ if (!State.Sequence.Empty)
+ RecoverableErrorCallback(
+ createStringError(errc::illegal_byte_sequence,
+ "last sequence in debug line table is not terminated!"));
+
+ // Sort all sequences so that address lookup will work faster.
+ if (!Sequences.empty()) {
+ llvm::sort(Sequences, Sequence::orderByLowPC);
+ // Note: actually, instruction address ranges of sequences should not
+ // overlap (in shared objects and executables). If they do, the address
+ // lookup would still work, though, but result would be ambiguous.
+ // We don't report warning in this case. For example,
+ // sometimes .so compiled from multiple object files contains a few
+ // rudimentary sequences for address ranges [0x0, 0xsomething).
+ }
+
+ return Error::success();
+}
+
+uint32_t
+DWARFDebugLine::LineTable::findRowInSeq(const DWARFDebugLine::Sequence &Seq,
+ uint64_t Address) const {
+ if (!Seq.containsPC(Address))
+ return UnknownRowIndex;
+ // Search for instruction address in the rows describing the sequence.
+ // Rows are stored in a vector, so we may use arithmetical operations with
+ // iterators.
+ DWARFDebugLine::Row Row;
+ Row.Address = Address;
+ RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex;
+ RowIter LastRow = Rows.begin() + Seq.LastRowIndex;
+ LineTable::RowIter RowPos = std::lower_bound(
+ FirstRow, LastRow, Row, DWARFDebugLine::Row::orderByAddress);
+ if (RowPos == LastRow) {
+ return Seq.LastRowIndex - 1;
+ }
+ uint32_t Index = Seq.FirstRowIndex + (RowPos - FirstRow);
+ if (RowPos->Address > Address) {
+ if (RowPos == FirstRow)
+ return UnknownRowIndex;
+ else
+ Index--;
+ }
+ return Index;
+}
+
+uint32_t DWARFDebugLine::LineTable::lookupAddress(uint64_t Address) const {
+ if (Sequences.empty())
+ return UnknownRowIndex;
+ // First, find an instruction sequence containing the given address.
+ DWARFDebugLine::Sequence Sequence;
+ Sequence.LowPC = Address;
+ SequenceIter FirstSeq = Sequences.begin();
+ SequenceIter LastSeq = Sequences.end();
+ SequenceIter SeqPos = std::lower_bound(
+ FirstSeq, LastSeq, Sequence, DWARFDebugLine::Sequence::orderByLowPC);
+ DWARFDebugLine::Sequence FoundSeq;
+ if (SeqPos == LastSeq) {
+ FoundSeq = Sequences.back();
+ } else if (SeqPos->LowPC == Address) {
+ FoundSeq = *SeqPos;
+ } else {
+ if (SeqPos == FirstSeq)
+ return UnknownRowIndex;
+ FoundSeq = *(SeqPos - 1);
+ }
+ return findRowInSeq(FoundSeq, Address);
+}
+
+bool DWARFDebugLine::LineTable::lookupAddressRange(
+ uint64_t Address, uint64_t Size, std::vector<uint32_t> &Result) const {
+ if (Sequences.empty())
+ return false;
+ uint64_t EndAddr = Address + Size;
+ // First, find an instruction sequence containing the given address.
+ DWARFDebugLine::Sequence Sequence;
+ Sequence.LowPC = Address;
+ SequenceIter FirstSeq = Sequences.begin();
+ SequenceIter LastSeq = Sequences.end();
+ SequenceIter SeqPos = std::lower_bound(
+ FirstSeq, LastSeq, Sequence, DWARFDebugLine::Sequence::orderByLowPC);
+ if (SeqPos == LastSeq || SeqPos->LowPC != Address) {
+ if (SeqPos == FirstSeq)
+ return false;
+ SeqPos--;
+ }
+ if (!SeqPos->containsPC(Address))
+ return false;
+
+ SequenceIter StartPos = SeqPos;
+
+ // Add the rows from the first sequence to the vector, starting with the
+ // index we just calculated
+
+ while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) {
+ const DWARFDebugLine::Sequence &CurSeq = *SeqPos;
+ // For the first sequence, we need to find which row in the sequence is the
+ // first in our range.
+ uint32_t FirstRowIndex = CurSeq.FirstRowIndex;
+ if (SeqPos == StartPos)
+ FirstRowIndex = findRowInSeq(CurSeq, Address);
+
+ // Figure out the last row in the range.
+ uint32_t LastRowIndex = findRowInSeq(CurSeq, EndAddr - 1);
+ if (LastRowIndex == UnknownRowIndex)
+ LastRowIndex = CurSeq.LastRowIndex - 1;
+
+ assert(FirstRowIndex != UnknownRowIndex);
+ assert(LastRowIndex != UnknownRowIndex);
+
+ for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) {
+ Result.push_back(I);
+ }
+
+ ++SeqPos;
+ }
+
+ return true;
+}
+
+bool DWARFDebugLine::LineTable::hasFileAtIndex(uint64_t FileIndex) const {
+ return FileIndex != 0 && FileIndex <= Prologue.FileNames.size();
+}
+
+Optional<StringRef> DWARFDebugLine::LineTable::getSourceByIndex(uint64_t FileIndex,
+ FileLineInfoKind Kind) const {
+ if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex))
+ return None;
+ const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1];
+ if (Optional<const char *> source = Entry.Source.getAsCString())
+ return StringRef(*source);
+ return None;
+}
+
+static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) {
+ // Debug info can contain paths from any OS, not necessarily
+ // an OS we're currently running on. Moreover different compilation units can
+ // be compiled on different operating systems and linked together later.
+ return sys::path::is_absolute(Path, sys::path::Style::posix) ||
+ sys::path::is_absolute(Path, sys::path::Style::windows);
+}
+
+bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
+ const char *CompDir,
+ FileLineInfoKind Kind,
+ std::string &Result) const {
+ if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex))
+ return false;
+ const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1];
+ StringRef FileName = Entry.Name.getAsCString().getValue();
+ if (Kind != FileLineInfoKind::AbsoluteFilePath ||
+ isPathAbsoluteOnWindowsOrPosix(FileName)) {
+ Result = FileName;
+ return true;
+ }
+
+ SmallString<16> FilePath;
+ uint64_t IncludeDirIndex = Entry.DirIdx;
+ StringRef IncludeDir;
+ // Be defensive about the contents of Entry.
+ if (IncludeDirIndex > 0 &&
+ IncludeDirIndex <= Prologue.IncludeDirectories.size())
+ IncludeDir = Prologue.IncludeDirectories[IncludeDirIndex - 1]
+ .getAsCString()
+ .getValue();
+
+ // We may still need to append compilation directory of compile unit.
+ // We know that FileName is not absolute, the only way to have an
+ // absolute path at this point would be if IncludeDir is absolute.
+ if (CompDir && Kind == FileLineInfoKind::AbsoluteFilePath &&
+ !isPathAbsoluteOnWindowsOrPosix(IncludeDir))
+ sys::path::append(FilePath, CompDir);
+
+ // sys::path::append skips empty strings.
+ sys::path::append(FilePath, IncludeDir, FileName);
+ Result = FilePath.str();
+ return true;
+}
+
+bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
+ uint64_t Address, const char *CompDir, FileLineInfoKind Kind,
+ DILineInfo &Result) const {
+ // Get the index of row we're looking for in the line table.
+ uint32_t RowIndex = lookupAddress(Address);
+ if (RowIndex == -1U)
+ return false;
+ // Take file number and line/column from the row.
+ const auto &Row = Rows[RowIndex];
+ if (!getFileNameByIndex(Row.File, CompDir, Kind, Result.FileName))
+ return false;
+ Result.Line = Row.Line;
+ Result.Column = Row.Column;
+ Result.Discriminator = Row.Discriminator;
+ Result.Source = getSourceByIndex(Row.File, Kind);
+ return true;
+}
+
+// We want to supply the Unit associated with a .debug_line[.dwo] table when
+// we dump it, if possible, but still dump the table even if there isn't a Unit.
+// Therefore, collect up handles on all the Units that point into the
+// line-table section.
+static DWARFDebugLine::SectionParser::LineToUnitMap
+buildLineToUnitMap(DWARFDebugLine::SectionParser::cu_range CUs,
+ DWARFDebugLine::SectionParser::tu_range TUs) {
+ DWARFDebugLine::SectionParser::LineToUnitMap LineToUnit;
+ for (const auto &CU : CUs)
+ if (auto CUDIE = CU->getUnitDIE())
+ if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list)))
+ LineToUnit.insert(std::make_pair(*StmtOffset, &*CU));
+ for (const auto &TU : TUs)
+ if (auto TUDIE = TU->getUnitDIE())
+ if (auto StmtOffset = toSectionOffset(TUDIE.find(DW_AT_stmt_list)))
+ LineToUnit.insert(std::make_pair(*StmtOffset, &*TU));
+ return LineToUnit;
+}
+
+DWARFDebugLine::SectionParser::SectionParser(DWARFDataExtractor &Data,
+ const DWARFContext &C,
+ cu_range CUs, tu_range TUs)
+ : DebugLineData(Data), Context(C) {
+ LineToUnit = buildLineToUnitMap(CUs, TUs);
+ if (!DebugLineData.isValidOffset(Offset))
+ Done = true;
+}
+
+bool DWARFDebugLine::Prologue::totalLengthIsValid() const {
+ return TotalLength == 0xffffffff || TotalLength < 0xffffff00;
+}
+
+DWARFDebugLine::LineTable DWARFDebugLine::SectionParser::parseNext(
+ function_ref<void(Error)> RecoverableErrorCallback,
+ function_ref<void(Error)> UnrecoverableErrorCallback, raw_ostream *OS) {
+ assert(DebugLineData.isValidOffset(Offset) &&
+ "parsing should have terminated");
+ DWARFUnit *U = prepareToParse(Offset);
+ uint32_t OldOffset = Offset;
+ LineTable LT;
+ if (Error Err = LT.parse(DebugLineData, &Offset, Context, U,
+ RecoverableErrorCallback, OS))
+ UnrecoverableErrorCallback(std::move(Err));
+ moveToNextTable(OldOffset, LT.Prologue);
+ return LT;
+}
+
+void DWARFDebugLine::SectionParser::skip(
+ function_ref<void(Error)> ErrorCallback) {
+ assert(DebugLineData.isValidOffset(Offset) &&
+ "parsing should have terminated");
+ DWARFUnit *U = prepareToParse(Offset);
+ uint32_t OldOffset = Offset;
+ LineTable LT;
+ if (Error Err = LT.Prologue.parse(DebugLineData, &Offset, Context, U))
+ ErrorCallback(std::move(Err));
+ moveToNextTable(OldOffset, LT.Prologue);
+}
+
+DWARFUnit *DWARFDebugLine::SectionParser::prepareToParse(uint32_t Offset) {
+ DWARFUnit *U = nullptr;
+ auto It = LineToUnit.find(Offset);
+ if (It != LineToUnit.end())
+ U = It->second;
+ DebugLineData.setAddressSize(U ? U->getAddressByteSize() : 0);
+ return U;
+}
+
+void DWARFDebugLine::SectionParser::moveToNextTable(uint32_t OldOffset,
+ const Prologue &P) {
+ // If the length field is not valid, we don't know where the next table is, so
+ // cannot continue to parse. Mark the parser as done, and leave the Offset
+ // value as it currently is. This will be the end of the bad length field.
+ if (!P.totalLengthIsValid()) {
+ Done = true;
+ return;
+ }
+
+ Offset = OldOffset + P.TotalLength + P.sizeofTotalLength();
+ if (!DebugLineData.isValidOffset(Offset)) {
+ Done = true;
+ }
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
new file mode 100644
index 000000000000..94df6946f3ae
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -0,0 +1,279 @@
+//===- DWARFDebugLoc.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/DWARFDebugLoc.h"
+#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/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+// 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, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI);
+}
+
+void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
+ unsigned AddressSize,
+ const MCRegisterInfo *MRI,
+ uint64_t BaseAddress,
+ unsigned Indent) const {
+ for (const Entry &E : Entries) {
+ OS << '\n';
+ OS.indent(Indent);
+ OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2,
+ BaseAddress + E.Begin);
+ OS << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2,
+ BaseAddress + E.End);
+ OS << ": ";
+
+ dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
+ }
+}
+
+DWARFDebugLoc::LocationList const *
+DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const {
+ auto It = std::lower_bound(
+ Locations.begin(), Locations.end(), Offset,
+ [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; });
+ if (It != Locations.end() && It->Offset == Offset)
+ return &(*It);
+ return nullptr;
+}
+
+void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ 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);
+ OS << "\n\n";
+ };
+
+ if (Offset) {
+ if (auto *L = getLocationListAtOffset(*Offset))
+ DumpLocationList(*L);
+ return;
+ }
+
+ for (const LocationList &L : Locations) {
+ DumpLocationList(L);
+ }
+}
+
+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())) {
+ WithColor::error() << "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)) {
+ WithColor::error() << "location list overflows the debug_loc section.\n";
+ return None;
+ }
+
+ unsigned Bytes = Data.getU16(Offset);
+ if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) {
+ WithColor::error() << "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());
+ llvm::copy(str, 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)) {
+ if (auto LL = parseOneLocationList(data, &Offset))
+ Locations.push_back(std::move(*LL));
+ else
+ break;
+ }
+ if (data.isValidOffset(Offset))
+ WithColor::error() << "failed to consume entire .debug_loc section\n";
+}
+
+Optional<DWARFDebugLoclists::LocationList>
+DWARFDebugLoclists::parseOneLocationList(DataExtractor Data, unsigned *Offset,
+ unsigned Version) {
+ 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))) {
+
+ Entry E;
+ E.Kind = Kind;
+ switch (Kind) {
+ case dwarf::DW_LLE_startx_length:
+ E.Value0 = Data.getULEB128(Offset);
+ // Pre-DWARF 5 has different interpretation of the length field. We have
+ // to support both pre- and standartized styles for the compatibility.
+ if (Version < 5)
+ E.Value1 = Data.getU32(Offset);
+ else
+ E.Value1 = Data.getULEB128(Offset);
+ break;
+ case dwarf::DW_LLE_start_length:
+ E.Value0 = Data.getAddress(Offset);
+ E.Value1 = Data.getULEB128(Offset);
+ break;
+ case dwarf::DW_LLE_offset_pair:
+ E.Value0 = Data.getULEB128(Offset);
+ E.Value1 = Data.getULEB128(Offset);
+ break;
+ case dwarf::DW_LLE_base_address:
+ E.Value0 = Data.getAddress(Offset);
+ break;
+ default:
+ WithColor::error() << "dumping support for LLE of kind " << (int)Kind
+ << " not implemented\n";
+ return None;
+ }
+
+ if (Kind != dwarf::DW_LLE_base_address) {
+ unsigned Bytes =
+ Version >= 5 ? Data.getULEB128(Offset) : 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());
+ llvm::copy(str, E.Loc.begin());
+ }
+
+ LL.Entries.push_back(std::move(E));
+ }
+ return LL;
+}
+
+void DWARFDebugLoclists::parse(DataExtractor data, unsigned Version) {
+ IsLittleEndian = data.isLittleEndian();
+ AddressSize = data.getAddressSize();
+
+ uint32_t Offset = 0;
+ while (data.isValidOffset(Offset)) {
+ if (auto LL = parseOneLocationList(data, &Offset, Version))
+ Locations.push_back(std::move(*LL));
+ else
+ return;
+ }
+}
+
+DWARFDebugLoclists::LocationList const *
+DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset) const {
+ auto It = std::lower_bound(
+ Locations.begin(), Locations.end(), Offset,
+ [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; });
+ if (It != Locations.end() && It->Offset == Offset)
+ return &(*It);
+ return nullptr;
+}
+
+void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr,
+ bool IsLittleEndian,
+ unsigned AddressSize,
+ const MCRegisterInfo *MRI,
+ unsigned Indent) const {
+ for (const Entry &E : Entries) {
+ switch (E.Kind) {
+ case dwarf::DW_LLE_startx_length:
+ OS << '\n';
+ OS.indent(Indent);
+ OS << "Addr idx " << E.Value0 << " (w/ length " << E.Value1 << "): ";
+ break;
+ case dwarf::DW_LLE_start_length:
+ OS << '\n';
+ OS.indent(Indent);
+ OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2,
+ AddressSize * 2, E.Value0, AddressSize * 2, AddressSize * 2,
+ E.Value0 + E.Value1);
+ break;
+ case dwarf::DW_LLE_offset_pair:
+ OS << '\n';
+ OS.indent(Indent);
+ OS << format("[0x%*.*" PRIx64 ", 0x%*.*" PRIx64 "): ", AddressSize * 2,
+ AddressSize * 2, BaseAddr + E.Value0, AddressSize * 2,
+ AddressSize * 2, BaseAddr + E.Value1);
+ break;
+ case dwarf::DW_LLE_base_address:
+ BaseAddr = E.Value0;
+ break;
+ default:
+ llvm_unreachable("unreachable locations list kind");
+ }
+
+ dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
+ }
+}
+
+void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr,
+ const MCRegisterInfo *MRI,
+ Optional<uint64_t> Offset) const {
+ auto DumpLocationList = [&](const LocationList &L) {
+ OS << format("0x%8.8x: ", L.Offset);
+ L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, /*Indent=*/12);
+ OS << "\n\n";
+ };
+
+ if (Offset) {
+ if (auto *L = getLocationListAtOffset(*Offset))
+ DumpLocationList(*L);
+ return;
+ }
+
+ for (const LocationList &L : Locations) {
+ DumpLocationList(L);
+ }
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
new file mode 100644
index 000000000000..6d789c3027a5
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
@@ -0,0 +1,101 @@
+//===- DWARFDebugMacro.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/DWARFDebugMacro.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFDebugMacro::dump(raw_ostream &OS) const {
+ unsigned IndLevel = 0;
+ for (const Entry &E : Macros) {
+ // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,
+ // this check handles the case of corrupted ".debug_macinfo" section.
+ if (IndLevel > 0)
+ IndLevel -= (E.Type == DW_MACINFO_end_file);
+ // Print indentation.
+ for (unsigned I = 0; I < IndLevel; I++)
+ OS << " ";
+ IndLevel += (E.Type == DW_MACINFO_start_file);
+
+ WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type);
+ switch (E.Type) {
+ default:
+ // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ OS << " - lineno: " << E.Line;
+ OS << " macro: " << E.MacroStr;
+ break;
+ case DW_MACINFO_start_file:
+ OS << " - lineno: " << E.Line;
+ OS << " filenum: " << E.File;
+ break;
+ case DW_MACINFO_end_file:
+ break;
+ case DW_MACINFO_vendor_ext:
+ OS << " - constant: " << E.ExtConstant;
+ OS << " string: " << E.ExtStr;
+ break;
+ }
+ OS << "\n";
+ }
+}
+
+void DWARFDebugMacro::parse(DataExtractor data) {
+ uint32_t Offset = 0;
+ while (data.isValidOffset(Offset)) {
+ // A macro list entry consists of:
+ Entry E;
+ // 1. Macinfo type
+ E.Type = data.getULEB128(&Offset);
+
+ if (E.Type == 0) {
+ // Reached end of ".debug_macinfo" section.
+ return;
+ }
+
+ switch (E.Type) {
+ default:
+ // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
+ // Push the corrupted entry to the list and halt parsing.
+ E.Type = DW_MACINFO_invalid;
+ Macros.push_back(E);
+ return;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ // 2. Source line
+ E.Line = data.getULEB128(&Offset);
+ // 3. Macro string
+ E.MacroStr = data.getCStr(&Offset);
+ break;
+ case DW_MACINFO_start_file:
+ // 2. Source line
+ E.Line = data.getULEB128(&Offset);
+ // 3. Source file id
+ E.File = data.getULEB128(&Offset);
+ break;
+ case DW_MACINFO_end_file:
+ break;
+ case DW_MACINFO_vendor_ext:
+ // 2. Vendor extension constant
+ E.ExtConstant = data.getULEB128(&Offset);
+ // 3. Vendor extension string
+ E.ExtStr = data.getCStr(&Offset);
+ break;
+ }
+
+ Macros.push_back(E);
+ }
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
new file mode 100644
index 000000000000..abd1ad59a9c1
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
@@ -0,0 +1,70 @@
+//===- DWARFDebugPubTable.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/DWARFDebugPubTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+DWARFDebugPubTable::DWARFDebugPubTable(const DWARFObject &Obj,
+ const DWARFSection &Sec,
+ bool LittleEndian, bool GnuStyle)
+ : GnuStyle(GnuStyle) {
+ DWARFDataExtractor PubNames(Obj, Sec, LittleEndian, 0);
+ uint32_t Offset = 0;
+ while (PubNames.isValidOffset(Offset)) {
+ Sets.push_back({});
+ Set &SetData = Sets.back();
+
+ SetData.Length = PubNames.getU32(&Offset);
+ SetData.Version = PubNames.getU16(&Offset);
+ SetData.Offset = PubNames.getRelocatedValue(4, &Offset);
+ SetData.Size = PubNames.getU32(&Offset);
+
+ while (Offset < Sec.Data.size()) {
+ uint32_t DieRef = PubNames.getU32(&Offset);
+ if (DieRef == 0)
+ break;
+ uint8_t IndexEntryValue = GnuStyle ? PubNames.getU8(&Offset) : 0;
+ StringRef Name = PubNames.getCStrRef(&Offset);
+ SetData.Entries.push_back(
+ {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name});
+ }
+ }
+}
+
+void DWARFDebugPubTable::dump(raw_ostream &OS) const {
+ for (const Set &S : Sets) {
+ OS << "length = " << format("0x%08x", S.Length);
+ OS << " version = " << format("0x%04x", S.Version);
+ OS << " unit_offset = " << format("0x%08x", S.Offset);
+ OS << " unit_size = " << format("0x%08x", S.Size) << '\n';
+ OS << (GnuStyle ? "Offset Linkage Kind Name\n"
+ : "Offset Name\n");
+
+ for (const Entry &E : S.Entries) {
+ OS << format("0x%8.8x ", E.SecOffset);
+ if (GnuStyle) {
+ StringRef EntryLinkage =
+ GDBIndexEntryLinkageString(E.Descriptor.Linkage);
+ StringRef EntryKind = dwarf::GDBIndexEntryKindString(E.Descriptor.Kind);
+ OS << format("%-8s", EntryLinkage.data()) << ' '
+ << format("%-8s", EntryKind.data()) << ' ';
+ }
+ OS << '\"' << E.Name << "\"\n";
+ }
+ }
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
new file mode 100644
index 000000000000..dfb913000a46
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
@@ -0,0 +1,96 @@
+//===- DWARFDebugRangesList.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/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+void DWARFDebugRangeList::clear() {
+ Offset = -1U;
+ AddressSize = 0;
+ Entries.clear();
+}
+
+Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
+ uint32_t *offset_ptr) {
+ clear();
+ if (!data.isValidOffset(*offset_ptr))
+ return createStringError(errc::invalid_argument,
+ "invalid range list offset 0x%" PRIx32, *offset_ptr);
+
+ AddressSize = data.getAddressSize();
+ if (AddressSize != 4 && AddressSize != 8)
+ return createStringError(errc::invalid_argument,
+ "invalid address size: %" PRIu8, AddressSize);
+ Offset = *offset_ptr;
+ while (true) {
+ RangeListEntry Entry;
+ Entry.SectionIndex = -1ULL;
+
+ uint32_t prev_offset = *offset_ptr;
+ Entry.StartAddress = data.getRelocatedAddress(offset_ptr);
+ Entry.EndAddress =
+ data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex);
+
+ // Check that both values were extracted correctly.
+ if (*offset_ptr != prev_offset + 2 * AddressSize) {
+ clear();
+ return createStringError(errc::invalid_argument,
+ "invalid range list entry at offset 0x%" PRIx32,
+ prev_offset);
+ }
+ if (Entry.isEndOfListEntry())
+ break;
+ Entries.push_back(Entry);
+ }
+ return Error::success();
+}
+
+void DWARFDebugRangeList::dump(raw_ostream &OS) const {
+ for (const RangeListEntry &RLE : Entries) {
+ const char *format_str = (AddressSize == 4
+ ? "%08x %08" PRIx64 " %08" PRIx64 "\n"
+ : "%08x %016" PRIx64 " %016" PRIx64 "\n");
+ OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress);
+ }
+ OS << format("%08x <End of list>\n", Offset);
+}
+
+DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
+ llvm::Optional<SectionedAddress> BaseAddr) const {
+ DWARFAddressRangesVector Res;
+ for (const RangeListEntry &RLE : Entries) {
+ if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
+ BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
+ continue;
+ }
+
+ DWARFAddressRange E;
+ E.LowPC = RLE.StartAddress;
+ E.HighPC = RLE.EndAddress;
+ E.SectionIndex = RLE.SectionIndex;
+ // Base address of a range list entry is determined by the closest preceding
+ // base address selection entry in the same range list. It defaults to the
+ // base address of the compilation unit if there is no such entry.
+ if (BaseAddr) {
+ E.LowPC += BaseAddr->Address;
+ E.HighPC += BaseAddr->Address;
+ if (E.SectionIndex == -1ULL)
+ E.SectionIndex = BaseAddr->SectionIndex;
+ }
+ Res.push_back(E);
+ }
+ return Res;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
new file mode 100644
index 000000000000..60c6eb30857f
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
@@ -0,0 +1,248 @@
+//===- DWARFDebugRnglists.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/DWARFDebugRnglists.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+Error RangeListEntry::extract(DWARFDataExtractor Data, uint32_t End,
+ uint32_t *OffsetPtr) {
+ Offset = *OffsetPtr;
+ SectionIndex = -1ULL;
+ // The caller should guarantee that we have at least 1 byte available, so
+ // we just assert instead of revalidate.
+ assert(*OffsetPtr < End &&
+ "not enough space to extract a rangelist encoding");
+ uint8_t Encoding = Data.getU8(OffsetPtr);
+
+ switch (Encoding) {
+ case dwarf::DW_RLE_end_of_list:
+ Value0 = Value1 = 0;
+ break;
+ // TODO: Support other encodings.
+ case dwarf::DW_RLE_base_addressx: {
+ uint32_t PreviousOffset = *OffsetPtr - 1;
+ Value0 = Data.getULEB128(OffsetPtr);
+ if (End < *OffsetPtr)
+ return createStringError(
+ errc::invalid_argument,
+ "read past end of table when reading "
+ "DW_RLE_base_addressx encoding at offset 0x%" PRIx32,
+ PreviousOffset);
+ break;
+ }
+ case dwarf::DW_RLE_startx_endx:
+ return createStringError(errc::not_supported,
+ "unsupported rnglists encoding DW_RLE_startx_endx at "
+ "offset 0x%" PRIx32,
+ *OffsetPtr - 1);
+ case dwarf::DW_RLE_startx_length: {
+ uint32_t PreviousOffset = *OffsetPtr - 1;
+ Value0 = Data.getULEB128(OffsetPtr);
+ Value1 = Data.getULEB128(OffsetPtr);
+ if (End < *OffsetPtr)
+ return createStringError(
+ errc::invalid_argument,
+ "read past end of table when reading "
+ "DW_RLE_startx_length encoding at offset 0x%" PRIx32,
+ PreviousOffset);
+ break;
+ }
+ case dwarf::DW_RLE_offset_pair: {
+ uint32_t PreviousOffset = *OffsetPtr - 1;
+ Value0 = Data.getULEB128(OffsetPtr);
+ Value1 = Data.getULEB128(OffsetPtr);
+ if (End < *OffsetPtr)
+ return createStringError(errc::invalid_argument,
+ "read past end of table when reading "
+ "DW_RLE_offset_pair encoding at offset 0x%" PRIx32,
+ PreviousOffset);
+ break;
+ }
+ case dwarf::DW_RLE_base_address: {
+ if ((End - *OffsetPtr) < Data.getAddressSize())
+ return createStringError(errc::invalid_argument,
+ "insufficient space remaining in table for "
+ "DW_RLE_base_address encoding at offset 0x%" PRIx32,
+ *OffsetPtr - 1);
+ Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+ break;
+ }
+ case dwarf::DW_RLE_start_end: {
+ if ((End - *OffsetPtr) < unsigned(Data.getAddressSize() * 2))
+ return createStringError(errc::invalid_argument,
+ "insufficient space remaining in table for "
+ "DW_RLE_start_end encoding "
+ "at offset 0x%" PRIx32,
+ *OffsetPtr - 1);
+ Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+ Value1 = Data.getRelocatedAddress(OffsetPtr);
+ break;
+ }
+ case dwarf::DW_RLE_start_length: {
+ uint32_t PreviousOffset = *OffsetPtr - 1;
+ Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
+ Value1 = Data.getULEB128(OffsetPtr);
+ if (End < *OffsetPtr)
+ return createStringError(errc::invalid_argument,
+ "read past end of table when reading "
+ "DW_RLE_start_length encoding at offset 0x%" PRIx32,
+ PreviousOffset);
+ break;
+ }
+ default:
+ return createStringError(errc::not_supported,
+ "unknown rnglists encoding 0x%" PRIx32
+ " at offset 0x%" PRIx32,
+ uint32_t(Encoding), *OffsetPtr - 1);
+ }
+
+ EntryKind = Encoding;
+ return Error::success();
+}
+
+DWARFAddressRangesVector
+DWARFDebugRnglist::getAbsoluteRanges(llvm::Optional<SectionedAddress> BaseAddr,
+ DWARFUnit &U) const {
+ DWARFAddressRangesVector Res;
+ for (const RangeListEntry &RLE : Entries) {
+ if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
+ break;
+ if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
+ BaseAddr = U.getAddrOffsetSectionItem(RLE.Value0);
+ if (!BaseAddr)
+ BaseAddr = {RLE.Value0, -1ULL};
+ continue;
+ }
+ if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
+ BaseAddr = {RLE.Value0, RLE.SectionIndex};
+ continue;
+ }
+
+ DWARFAddressRange E;
+ E.SectionIndex = RLE.SectionIndex;
+ if (BaseAddr && E.SectionIndex == -1ULL)
+ E.SectionIndex = BaseAddr->SectionIndex;
+
+ switch (RLE.EntryKind) {
+ case dwarf::DW_RLE_offset_pair:
+ E.LowPC = RLE.Value0;
+ E.HighPC = RLE.Value1;
+ if (BaseAddr) {
+ E.LowPC += BaseAddr->Address;
+ E.HighPC += BaseAddr->Address;
+ }
+ break;
+ case dwarf::DW_RLE_start_end:
+ E.LowPC = RLE.Value0;
+ E.HighPC = RLE.Value1;
+ break;
+ case dwarf::DW_RLE_start_length:
+ E.LowPC = RLE.Value0;
+ E.HighPC = E.LowPC + RLE.Value1;
+ break;
+ case dwarf::DW_RLE_startx_length: {
+ auto Start = U.getAddrOffsetSectionItem(RLE.Value0);
+ if (!Start)
+ Start = {0, -1ULL};
+ E.SectionIndex = Start->SectionIndex;
+ E.LowPC = Start->Address;
+ E.HighPC = E.LowPC + RLE.Value1;
+ break;
+ }
+ default:
+ // Unsupported encodings should have been reported during extraction,
+ // so we should not run into any here.
+ llvm_unreachable("Unsupported range list encoding");
+ }
+ Res.push_back(E);
+ }
+ return Res;
+}
+
+void RangeListEntry::dump(
+ raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
+ uint64_t &CurrentBase, DIDumpOptions DumpOpts,
+ llvm::function_ref<Optional<SectionedAddress>(uint32_t)>
+ LookupPooledAddress) const {
+ auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
+ uint8_t AddrSize, DIDumpOptions DumpOpts) {
+ if (DumpOpts.Verbose) {
+ DumpOpts.DisplayRawContents = true;
+ DWARFAddressRange(Entry.Value0, Entry.Value1)
+ .dump(OS, AddrSize, DumpOpts);
+ OS << " => ";
+ }
+ };
+
+ if (DumpOpts.Verbose) {
+ // Print the section offset in verbose mode.
+ OS << format("0x%8.8" PRIx32 ":", Offset);
+ auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
+ // Unsupported encodings should have been reported during parsing.
+ assert(!EncodingString.empty() && "Unknown range entry encoding");
+ OS << format(" [%s%*c", EncodingString.data(),
+ MaxEncodingStringLength - EncodingString.size() + 1, ']');
+ if (EntryKind != dwarf::DW_RLE_end_of_list)
+ OS << ": ";
+ }
+
+ switch (EntryKind) {
+ case dwarf::DW_RLE_end_of_list:
+ OS << (DumpOpts.Verbose ? "" : "<End of list>");
+ break;
+ // case dwarf::DW_RLE_base_addressx:
+ case dwarf::DW_RLE_base_addressx: {
+ if (auto SA = LookupPooledAddress(Value0))
+ CurrentBase = SA->Address;
+ else
+ CurrentBase = Value0;
+ if (!DumpOpts.Verbose)
+ return;
+ OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
+ break;
+ }
+ case dwarf::DW_RLE_base_address:
+ // In non-verbose mode we do not print anything for this entry.
+ CurrentBase = Value0;
+ if (!DumpOpts.Verbose)
+ return;
+ OS << format(" 0x%*.*" PRIx64, AddrSize * 2, AddrSize * 2, Value0);
+ break;
+ case dwarf::DW_RLE_start_length:
+ PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+ DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
+ break;
+ case dwarf::DW_RLE_offset_pair:
+ PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+ DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
+ .dump(OS, AddrSize, DumpOpts);
+ break;
+ case dwarf::DW_RLE_start_end:
+ DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
+ break;
+ case dwarf::DW_RLE_startx_length: {
+ PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+ uint64_t Start = 0;
+ if (auto SA = LookupPooledAddress(Value0))
+ Start = SA->Address;
+ DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
+ break;
+ } break;
+ default:
+ llvm_unreachable("Unsupported range list encoding");
+ }
+ OS << "\n";
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
new file mode 100644
index 000000000000..81ef0c8c7aec
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -0,0 +1,712 @@
+//===- DWARFDie.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/DWARFDie.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#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"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <string>
+#include <utility>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) {
+ OS << " (";
+ do {
+ uint64_t Shift = countTrailingZeros(Val);
+ assert(Shift < 64 && "undefined behavior");
+ uint64_t Bit = 1ULL << Shift;
+ auto PropName = ApplePropertyString(Bit);
+ if (!PropName.empty())
+ OS << PropName;
+ else
+ OS << format("DW_APPLE_PROPERTY_0x%" PRIx64, Bit);
+ if (!(Val ^= Bit))
+ break;
+ OS << ", ";
+ } while (true);
+ OS << ")";
+}
+
+static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS,
+ const DWARFAddressRangesVector &Ranges,
+ unsigned AddressSize, unsigned Indent,
+ const DIDumpOptions &DumpOpts) {
+ if (!DumpOpts.ShowAddresses)
+ return;
+
+ ArrayRef<SectionName> SectionNames;
+ if (DumpOpts.Verbose)
+ SectionNames = Obj.getSectionNames();
+
+ for (const DWARFAddressRange &R : Ranges) {
+ OS << '\n';
+ OS.indent(Indent);
+ R.dump(OS, AddressSize);
+
+ DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, R.SectionIndex);
+ }
+}
+
+static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
+ DWARFUnit *U, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ 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, DumpOpts);
+ if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
+ uint32_t Offset = *FormValue.getAsSectionOffset();
+ if (!U->isDWOUnit() && !U->getLocSection()->Data.empty()) {
+ DWARFDebugLoc DebugLoc;
+ DWARFDataExtractor Data(Obj, *U->getLocSection(), Ctx.isLittleEndian(),
+ Obj.getAddressSize());
+ auto LL = DebugLoc.parseOneLocationList(Data, &Offset);
+ if (LL) {
+ uint64_t BaseAddr = 0;
+ if (Optional<SectionedAddress> BA = U->getBaseAddress())
+ BaseAddr = BA->Address;
+ LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, BaseAddr,
+ Indent);
+ } else
+ OS << "error extracting location list.";
+ return;
+ }
+
+ bool UseLocLists = !U->isDWOUnit();
+ StringRef LoclistsSectionData =
+ UseLocLists ? Obj.getLoclistsSection().Data : U->getLocSectionData();
+
+ if (!LoclistsSectionData.empty()) {
+ DataExtractor Data(LoclistsSectionData, Ctx.isLittleEndian(),
+ Obj.getAddressSize());
+
+ // Old-style location list were used in DWARF v4 (.debug_loc.dwo section).
+ // Modern locations list (.debug_loclists) are used starting from v5.
+ // Ideally we should take the version from the .debug_loclists section
+ // header, but using CU's version for simplicity.
+ auto LL = DWARFDebugLoclists::parseOneLocationList(
+ Data, &Offset, UseLocLists ? U->getVersion() : 4);
+
+ uint64_t BaseAddr = 0;
+ if (Optional<SectionedAddress> BA = U->getBaseAddress())
+ BaseAddr = BA->Address;
+
+ if (LL)
+ LL->dump(OS, BaseAddr, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI,
+ Indent);
+ else
+ OS << "error extracting location list.";
+ }
+ }
+}
+
+/// Dump the name encoded in the type tag.
+static void dumpTypeTagName(raw_ostream &OS, dwarf::Tag T) {
+ StringRef TagStr = TagString(T);
+ if (!TagStr.startswith("DW_TAG_") || !TagStr.endswith("_type"))
+ return;
+ OS << TagStr.substr(7, TagStr.size() - 12) << " ";
+}
+
+static void dumpArrayType(raw_ostream &OS, const DWARFDie &D) {
+ Optional<uint64_t> Bound;
+ for (const DWARFDie &C : D.children())
+ if (C.getTag() == DW_TAG_subrange_type) {
+ Optional<uint64_t> LB;
+ Optional<uint64_t> Count;
+ Optional<uint64_t> UB;
+ Optional<unsigned> DefaultLB;
+ if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
+ LB = L->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
+ Count = CountV->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
+ UB = UpperV->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> LV =
+ D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
+ if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
+ if ((DefaultLB =
+ LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
+ if (LB && *LB == *DefaultLB)
+ LB = None;
+ if (!LB && !Count && !UB)
+ OS << "[]";
+ else if (!LB && (Count || UB) && DefaultLB)
+ OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
+ else {
+ OS << "[[";
+ if (LB)
+ OS << *LB;
+ else
+ OS << '?';
+ OS << ", ";
+ if (Count)
+ if (LB)
+ OS << *LB + *Count;
+ else
+ OS << "? + " << *Count;
+ else if (UB)
+ OS << *UB + 1;
+ else
+ OS << '?';
+ OS << ")]";
+ }
+ }
+}
+
+/// Recursively dump the DIE type name when applicable.
+static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) {
+ if (!D.isValid())
+ return;
+
+ if (const char *Name = D.getName(DINameKind::LinkageName)) {
+ OS << Name;
+ return;
+ }
+
+ // FIXME: We should have pretty printers per language. Currently we print
+ // everything as if it was C++ and fall back to the TAG type name.
+ const dwarf::Tag T = D.getTag();
+ switch (T) {
+ case DW_TAG_array_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_subroutine_type:
+ break;
+ default:
+ dumpTypeTagName(OS, T);
+ }
+
+ // Follow the DW_AT_type if possible.
+ DWARFDie TypeDie = D.getAttributeValueAsReferencedDie(DW_AT_type);
+ dumpTypeName(OS, TypeDie);
+
+ switch (T) {
+ case DW_TAG_subroutine_type: {
+ if (!TypeDie)
+ OS << "void";
+ OS << '(';
+ bool First = true;
+ for (const DWARFDie &C : D.children()) {
+ if (C.getTag() == DW_TAG_formal_parameter) {
+ if (!First)
+ OS << ", ";
+ First = false;
+ dumpTypeName(OS, C.getAttributeValueAsReferencedDie(DW_AT_type));
+ }
+ }
+ OS << ')';
+ break;
+ }
+ case DW_TAG_array_type: {
+ dumpArrayType(OS, D);
+ break;
+ }
+ case DW_TAG_pointer_type:
+ OS << '*';
+ break;
+ case DW_TAG_ptr_to_member_type:
+ if (DWARFDie Cont =
+ D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) {
+ dumpTypeName(OS << ' ', Cont);
+ OS << "::";
+ }
+ OS << '*';
+ break;
+ case DW_TAG_reference_type:
+ OS << '&';
+ break;
+ case DW_TAG_rvalue_reference_type:
+ OS << "&&";
+ break;
+ default:
+ break;
+ }
+}
+
+static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
+ uint32_t *OffsetPtr, dwarf::Attribute Attr,
+ dwarf::Form Form, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ if (!Die.isValid())
+ return;
+ const char BaseIndent[] = " ";
+ OS << BaseIndent;
+ OS.indent(Indent + 2);
+ WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr);
+
+ if (DumpOpts.Verbose || DumpOpts.ShowForm)
+ OS << formatv(" [{0}]", Form);
+
+ DWARFUnit *U = Die.getDwarfUnit();
+ DWARFFormValue formValue(Form);
+
+ if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr,
+ U->getFormParams(), U))
+ return;
+
+ OS << "\t(";
+
+ StringRef Name;
+ std::string File;
+ auto Color = HighlightColor::Enumerator;
+ if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) {
+ Color = HighlightColor::String;
+ if (const auto *LT = U->getContext().getLineTableForUnit(U))
+ if (LT->getFileNameByIndex(
+ formValue.getAsUnsignedConstant().getValue(),
+ U->getCompilationDir(),
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) {
+ File = '"' + File + '"';
+ Name = File;
+ }
+ } else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant())
+ Name = AttributeValueString(Attr, *Val);
+
+ if (!Name.empty())
+ WithColor(OS, Color) << Name;
+ else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line)
+ OS << *formValue.getAsUnsignedConstant();
+ else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose &&
+ formValue.getAsUnsignedConstant()) {
+ if (DumpOpts.ShowAddresses) {
+ // Print the actual address rather than the offset.
+ uint64_t LowPC, HighPC, Index;
+ if (Die.getLowAndHighPC(LowPC, HighPC, Index))
+ OS << format("0x%016" PRIx64, HighPC);
+ else
+ formValue.dump(OS, DumpOpts);
+ }
+ } else if (Attr == DW_AT_location || Attr == DW_AT_frame_base ||
+ Attr == DW_AT_data_member_location ||
+ Attr == DW_AT_GNU_call_site_value)
+ dumpLocation(OS, formValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts);
+ else
+ formValue.dump(OS, DumpOpts);
+
+ std::string Space = DumpOpts.ShowAddresses ? " " : "";
+
+ // We have dumped the attribute raw value. For some attributes
+ // having both the raw value and the pretty-printed value is
+ // interesting. These attributes are handled below.
+ if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) {
+ if (const char *Name =
+ Die.getAttributeValueAsReferencedDie(formValue).getName(
+ DINameKind::LinkageName))
+ OS << Space << "\"" << Name << '\"';
+ } else if (Attr == DW_AT_type) {
+ OS << Space << "\"";
+ dumpTypeName(OS, Die.getAttributeValueAsReferencedDie(formValue));
+ OS << '"';
+ } else if (Attr == DW_AT_APPLE_property_attribute) {
+ if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant())
+ dumpApplePropertyAttribute(OS, *OptVal);
+ } else if (Attr == DW_AT_ranges) {
+ const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj();
+ // For DW_FORM_rnglistx we need to dump the offset separately, since
+ // we have only dumped the index so far.
+ if (formValue.getForm() == DW_FORM_rnglistx)
+ if (auto RangeListOffset =
+ U->getRnglistOffset(*formValue.getAsSectionOffset())) {
+ DWARFFormValue FV(dwarf::DW_FORM_sec_offset);
+ FV.setUValue(*RangeListOffset);
+ FV.dump(OS, DumpOpts);
+ }
+ if (auto RangesOrError = Die.getAddressRanges())
+ dumpRanges(Obj, OS, RangesOrError.get(), U->getAddressByteSize(),
+ sizeof(BaseIndent) + Indent + 4, DumpOpts);
+ else
+ WithColor::error() << "decoding address ranges: "
+ << toString(RangesOrError.takeError()) << '\n';
+ }
+
+ OS << ")\n";
+}
+
+bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; }
+
+bool DWARFDie::isSubroutineDIE() const {
+ auto Tag = getTag();
+ return Tag == DW_TAG_subprogram || Tag == DW_TAG_inlined_subroutine;
+}
+
+Optional<DWARFFormValue> DWARFDie::find(dwarf::Attribute Attr) const {
+ if (!isValid())
+ return None;
+ auto AbbrevDecl = getAbbreviationDeclarationPtr();
+ if (AbbrevDecl)
+ return AbbrevDecl->getAttributeValue(getOffset(), Attr, *U);
+ return None;
+}
+
+Optional<DWARFFormValue>
+DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const {
+ if (!isValid())
+ return None;
+ auto AbbrevDecl = getAbbreviationDeclarationPtr();
+ if (AbbrevDecl) {
+ for (auto Attr : Attrs) {
+ if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U))
+ return Value;
+ }
+ }
+ return None;
+}
+
+Optional<DWARFFormValue>
+DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const {
+ std::vector<DWARFDie> Worklist;
+ Worklist.push_back(*this);
+
+ // Keep track if DIEs already seen to prevent infinite recursion.
+ // Empirically we rarely see a depth of more than 3 when dealing with valid
+ // DWARF. This corresponds to following the DW_AT_abstract_origin and
+ // DW_AT_specification just once.
+ SmallSet<DWARFDie, 3> Seen;
+
+ while (!Worklist.empty()) {
+ DWARFDie Die = Worklist.back();
+ Worklist.pop_back();
+
+ if (!Die.isValid())
+ continue;
+
+ if (Seen.count(Die))
+ continue;
+
+ Seen.insert(Die);
+
+ if (auto Value = Die.find(Attrs))
+ return Value;
+
+ if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
+ Worklist.push_back(D);
+
+ if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification))
+ Worklist.push_back(D);
+ }
+
+ return None;
+}
+
+DWARFDie
+DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
+ if (Optional<DWARFFormValue> F = find(Attr))
+ return getAttributeValueAsReferencedDie(*F);
+ return DWARFDie();
+}
+
+DWARFDie
+DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const {
+ if (auto SpecRef = toReference(V)) {
+ if (auto SpecUnit = U->getUnitVector().getUnitForOffset(*SpecRef))
+ return SpecUnit->getDIEForOffset(*SpecRef);
+ }
+ return DWARFDie();
+}
+
+Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const {
+ return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base}));
+}
+
+Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const {
+ if (auto FormValue = find(DW_AT_high_pc)) {
+ if (auto Address = FormValue->getAsAddress()) {
+ // High PC is an address.
+ return Address;
+ }
+ if (auto Offset = FormValue->getAsUnsignedConstant()) {
+ // High PC is an offset from LowPC.
+ return LowPC + *Offset;
+ }
+ }
+ return None;
+}
+
+bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC,
+ uint64_t &SectionIndex) const {
+ auto F = find(DW_AT_low_pc);
+ auto LowPcAddr = toSectionedAddress(F);
+ if (!LowPcAddr)
+ return false;
+ if (auto HighPcAddr = getHighPC(LowPcAddr->Address)) {
+ LowPC = LowPcAddr->Address;
+ HighPC = *HighPcAddr;
+ SectionIndex = LowPcAddr->SectionIndex;
+ return true;
+ }
+ return false;
+}
+
+Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const {
+ if (isNULL())
+ return DWARFAddressRangesVector();
+ // Single range specified by low/high PC.
+ uint64_t LowPC, HighPC, Index;
+ if (getLowAndHighPC(LowPC, HighPC, Index))
+ return DWARFAddressRangesVector{{LowPC, HighPC, Index}};
+
+ Optional<DWARFFormValue> Value = find(DW_AT_ranges);
+ if (Value) {
+ if (Value->getForm() == DW_FORM_rnglistx)
+ return U->findRnglistFromIndex(*Value->getAsSectionOffset());
+ return U->findRnglistFromOffset(*Value->getAsSectionOffset());
+ }
+ return DWARFAddressRangesVector();
+}
+
+void DWARFDie::collectChildrenAddressRanges(
+ DWARFAddressRangesVector &Ranges) const {
+ if (isNULL())
+ return;
+ if (isSubprogramDIE()) {
+ if (auto DIERangesOrError = getAddressRanges())
+ Ranges.insert(Ranges.end(), DIERangesOrError.get().begin(),
+ DIERangesOrError.get().end());
+ else
+ llvm::consumeError(DIERangesOrError.takeError());
+ }
+
+ for (auto Child : children())
+ Child.collectChildrenAddressRanges(Ranges);
+}
+
+bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
+ auto RangesOrError = getAddressRanges();
+ if (!RangesOrError) {
+ llvm::consumeError(RangesOrError.takeError());
+ return false;
+ }
+
+ for (const auto &R : RangesOrError.get())
+ if (R.LowPC <= Address && Address < R.HighPC)
+ return true;
+ return false;
+}
+
+const char *DWARFDie::getSubroutineName(DINameKind Kind) const {
+ if (!isSubroutineDIE())
+ return nullptr;
+ return getName(Kind);
+}
+
+const char *DWARFDie::getName(DINameKind Kind) const {
+ if (!isValid() || Kind == DINameKind::None)
+ return nullptr;
+ // Try to get mangled name only if it was asked for.
+ if (Kind == DINameKind::LinkageName) {
+ if (auto Name = dwarf::toString(
+ findRecursively({DW_AT_MIPS_linkage_name, DW_AT_linkage_name}),
+ nullptr))
+ return Name;
+ }
+ if (auto Name = dwarf::toString(findRecursively(DW_AT_name), nullptr))
+ return Name;
+ return nullptr;
+}
+
+uint64_t DWARFDie::getDeclLine() const {
+ return toUnsigned(findRecursively(DW_AT_decl_line), 0);
+}
+
+void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
+ uint32_t &CallColumn,
+ uint32_t &CallDiscriminator) const {
+ CallFile = toUnsigned(find(DW_AT_call_file), 0);
+ CallLine = toUnsigned(find(DW_AT_call_line), 0);
+ CallColumn = toUnsigned(find(DW_AT_call_column), 0);
+ CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0);
+}
+
+/// Helper to dump a DIE with all of its parents, but no siblings.
+static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ if (!Die)
+ return Indent;
+ Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts);
+ Die.dump(OS, Indent, DumpOpts);
+ return Indent + 2;
+}
+
+void DWARFDie::dump(raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts) const {
+ if (!isValid())
+ return;
+ DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor();
+ const uint32_t Offset = getOffset();
+ uint32_t offset = Offset;
+ if (DumpOpts.ShowParents) {
+ DIDumpOptions ParentDumpOpts = DumpOpts;
+ ParentDumpOpts.ShowParents = false;
+ ParentDumpOpts.ShowChildren = false;
+ Indent = dumpParentChain(getParent(), OS, Indent, ParentDumpOpts);
+ }
+
+ if (debug_info_data.isValidOffset(offset)) {
+ uint32_t abbrCode = debug_info_data.getULEB128(&offset);
+ if (DumpOpts.ShowAddresses)
+ WithColor(OS, HighlightColor::Address).get()
+ << format("\n0x%8.8x: ", Offset);
+
+ if (abbrCode) {
+ auto AbbrevDecl = getAbbreviationDeclarationPtr();
+ if (AbbrevDecl) {
+ WithColor(OS, HighlightColor::Tag).get().indent(Indent)
+ << formatv("{0}", getTag());
+ if (DumpOpts.Verbose)
+ OS << format(" [%u] %c", abbrCode,
+ AbbrevDecl->hasChildren() ? '*' : ' ');
+ OS << '\n';
+
+ // Dump all data in the DIE for the attributes.
+ for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+ if (AttrSpec.Form == DW_FORM_implicit_const) {
+ // We are dumping .debug_info section ,
+ // implicit_const attribute values are not really stored here,
+ // but in .debug_abbrev section. So we just skip such attrs.
+ continue;
+ }
+ dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form,
+ Indent, DumpOpts);
+ }
+
+ DWARFDie child = getFirstChild();
+ if (DumpOpts.ShowChildren && DumpOpts.RecurseDepth > 0 && child) {
+ DumpOpts.RecurseDepth--;
+ DIDumpOptions ChildDumpOpts = DumpOpts;
+ ChildDumpOpts.ShowParents = false;
+ while (child) {
+ child.dump(OS, Indent + 2, ChildDumpOpts);
+ child = child.getSibling();
+ }
+ }
+ } else {
+ OS << "Abbreviation code not found in 'debug_abbrev' class for code: "
+ << abbrCode << '\n';
+ }
+ } else {
+ OS.indent(Indent) << "NULL\n";
+ }
+ }
+}
+
+LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(llvm::errs(), 0); }
+
+DWARFDie DWARFDie::getParent() const {
+ if (isValid())
+ return U->getParent(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getSibling() const {
+ if (isValid())
+ return U->getSibling(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getPreviousSibling() const {
+ if (isValid())
+ return U->getPreviousSibling(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getFirstChild() const {
+ if (isValid())
+ return U->getFirstChild(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getLastChild() const {
+ if (isValid())
+ return U->getLastChild(Die);
+ return DWARFDie();
+}
+
+iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const {
+ return make_range(attribute_iterator(*this, false),
+ attribute_iterator(*this, true));
+}
+
+DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End)
+ : Die(D), AttrValue(0), Index(0) {
+ auto AbbrDecl = Die.getAbbreviationDeclarationPtr();
+ assert(AbbrDecl && "Must have abbreviation declaration");
+ if (End) {
+ // This is the end iterator so we set the index to the attribute count.
+ Index = AbbrDecl->getNumAttributes();
+ } else {
+ // This is the begin iterator so we extract the value for this->Index.
+ AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize();
+ updateForIndex(*AbbrDecl, 0);
+ }
+}
+
+void DWARFDie::attribute_iterator::updateForIndex(
+ const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) {
+ Index = I;
+ // AbbrDecl must be valid before calling this function.
+ auto NumAttrs = AbbrDecl.getNumAttributes();
+ if (Index < NumAttrs) {
+ AttrValue.Attr = AbbrDecl.getAttrByIndex(Index);
+ // Add the previous byte size of any previous attribute value.
+ AttrValue.Offset += AttrValue.ByteSize;
+ AttrValue.Value.setForm(AbbrDecl.getFormByIndex(Index));
+ uint32_t ParseOffset = AttrValue.Offset;
+ auto U = Die.getDwarfUnit();
+ assert(U && "Die must have valid DWARF unit");
+ bool b = AttrValue.Value.extractValue(U->getDebugInfoExtractor(),
+ &ParseOffset, U->getFormParams(), U);
+ (void)b;
+ assert(b && "extractValue cannot fail on fully parsed DWARF");
+ AttrValue.ByteSize = ParseOffset - AttrValue.Offset;
+ } else {
+ assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only");
+ AttrValue.clear();
+ }
+}
+
+DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() {
+ if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr())
+ updateForIndex(*AbbrDecl, Index + 1);
+ return *this;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
new file mode 100644
index 000000000000..2df4456053fb
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -0,0 +1,276 @@
+//===-- 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/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_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);
+ 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();
+ // Handle possible corrupted or unsupported operation.
+ if (OpCode >= Descriptions.size())
+ return {};
+ 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) {
+ EndOffset = Offset;
+ 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,
+ bool IsEH) const {
+ for (auto &Op : *this) {
+ if (!Op.print(OS, this, RegInfo, IsEH)) {
+ 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/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
new file mode 100644
index 000000000000..7719fea63120
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -0,0 +1,679 @@
+//===- DWARFFormValue.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/DWARFFormValue.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+#include <limits>
+
+using namespace llvm;
+using namespace dwarf;
+
+static const DWARFFormValue::FormClass DWARF5FormClasses[] = {
+ DWARFFormValue::FC_Unknown, // 0x0
+ DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr
+ DWARFFormValue::FC_Unknown, // 0x02 unused
+ DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2
+ DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4
+ DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2
+ // --- These can be FC_SectionOffset in DWARF3 and below:
+ DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4
+ DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8
+ // ---
+ DWARFFormValue::FC_String, // 0x08 DW_FORM_string
+ DWARFFormValue::FC_Block, // 0x09 DW_FORM_block
+ DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1
+ DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1
+ DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag
+ DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata
+ DWARFFormValue::FC_String, // 0x0e DW_FORM_strp
+ DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata
+ DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr
+ DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1
+ DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2
+ DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4
+ DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8
+ DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata
+ DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect
+ DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset
+ DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc
+ DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present
+ DWARFFormValue::FC_String, // 0x1a DW_FORM_strx
+ DWARFFormValue::FC_Address, // 0x1b DW_FORM_addrx
+ DWARFFormValue::FC_Reference, // 0x1c DW_FORM_ref_sup4
+ DWARFFormValue::FC_String, // 0x1d DW_FORM_strp_sup
+ DWARFFormValue::FC_Constant, // 0x1e DW_FORM_data16
+ DWARFFormValue::FC_String, // 0x1f DW_FORM_line_strp
+ DWARFFormValue::FC_Reference, // 0x20 DW_FORM_ref_sig8
+ DWARFFormValue::FC_Constant, // 0x21 DW_FORM_implicit_const
+ DWARFFormValue::FC_SectionOffset, // 0x22 DW_FORM_loclistx
+ DWARFFormValue::FC_SectionOffset, // 0x23 DW_FORM_rnglistx
+ DWARFFormValue::FC_Reference, // 0x24 DW_FORM_ref_sup8
+ DWARFFormValue::FC_String, // 0x25 DW_FORM_strx1
+ DWARFFormValue::FC_String, // 0x26 DW_FORM_strx2
+ DWARFFormValue::FC_String, // 0x27 DW_FORM_strx3
+ DWARFFormValue::FC_String, // 0x28 DW_FORM_strx4
+ DWARFFormValue::FC_Address, // 0x29 DW_FORM_addrx1
+ DWARFFormValue::FC_Address, // 0x2a DW_FORM_addrx2
+ DWARFFormValue::FC_Address, // 0x2b DW_FORM_addrx3
+ DWARFFormValue::FC_Address, // 0x2c DW_FORM_addrx4
+
+};
+
+bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
+ uint32_t *OffsetPtr,
+ const dwarf::FormParams Params) {
+ bool Indirect = false;
+ do {
+ switch (Form) {
+ // Blocks of inlined data that have a length field and the data bytes
+ // inlined in the .debug_info.
+ case DW_FORM_exprloc:
+ case DW_FORM_block: {
+ uint64_t size = DebugInfoData.getULEB128(OffsetPtr);
+ *OffsetPtr += size;
+ return true;
+ }
+ case DW_FORM_block1: {
+ uint8_t size = DebugInfoData.getU8(OffsetPtr);
+ *OffsetPtr += size;
+ return true;
+ }
+ case DW_FORM_block2: {
+ uint16_t size = DebugInfoData.getU16(OffsetPtr);
+ *OffsetPtr += size;
+ return true;
+ }
+ case DW_FORM_block4: {
+ uint32_t size = DebugInfoData.getU32(OffsetPtr);
+ *OffsetPtr += size;
+ return true;
+ }
+
+ // Inlined NULL terminated C-strings.
+ case DW_FORM_string:
+ DebugInfoData.getCStr(OffsetPtr);
+ return true;
+
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr:
+ case DW_FORM_flag_present:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_data16:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_ref_sup4:
+ case DW_FORM_ref_sup8:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx4:
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx4:
+ case DW_FORM_sec_offset:
+ case DW_FORM_strp:
+ case DW_FORM_strp_sup:
+ case DW_FORM_line_strp:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
+ if (Optional<uint8_t> FixedSize =
+ dwarf::getFixedFormByteSize(Form, Params)) {
+ *OffsetPtr += *FixedSize;
+ return true;
+ }
+ return false;
+
+ // signed or unsigned LEB 128 values.
+ case DW_FORM_sdata:
+ DebugInfoData.getSLEB128(OffsetPtr);
+ return true;
+
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_strx:
+ case DW_FORM_addrx:
+ case DW_FORM_loclistx:
+ case DW_FORM_rnglistx:
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_GNU_str_index:
+ DebugInfoData.getULEB128(OffsetPtr);
+ return true;
+
+ case DW_FORM_indirect:
+ Indirect = true;
+ Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr));
+ break;
+
+ default:
+ return false;
+ }
+ } while (Indirect);
+ return true;
+}
+
+bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
+ // First, check DWARF5 form classes.
+ if (Form < makeArrayRef(DWARF5FormClasses).size() &&
+ DWARF5FormClasses[Form] == FC)
+ return true;
+ // Check more forms from extensions and proposals.
+ switch (Form) {
+ case DW_FORM_GNU_ref_alt:
+ return (FC == FC_Reference);
+ case DW_FORM_GNU_addr_index:
+ return (FC == FC_Address);
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_strp_alt:
+ return (FC == FC_String);
+ default:
+ break;
+ }
+ // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section offset.
+ // Don't check for DWARF version here, as some producers may still do this
+ // by mistake. Also accept DW_FORM_[line_]strp since these are
+ // .debug_[line_]str section offsets.
+ return (Form == DW_FORM_data4 || Form == DW_FORM_data8 ||
+ Form == DW_FORM_strp || Form == DW_FORM_line_strp) &&
+ FC == FC_SectionOffset;
+}
+
+bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
+ uint32_t *OffsetPtr, dwarf::FormParams FP,
+ const DWARFContext *Ctx,
+ const DWARFUnit *CU) {
+ if (!Ctx && CU)
+ Ctx = &CU->getContext();
+ C = Ctx;
+ U = CU;
+ bool Indirect = false;
+ bool IsBlock = false;
+ Value.data = nullptr;
+ // Read the value for the form into value and follow and DW_FORM_indirect
+ // instances we run into
+ do {
+ Indirect = false;
+ switch (Form) {
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr: {
+ uint16_t Size =
+ (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize();
+ Value.uval = Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex);
+ break;
+ }
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ Value.uval = Data.getULEB128(OffsetPtr);
+ IsBlock = true;
+ break;
+ case DW_FORM_block1:
+ Value.uval = Data.getU8(OffsetPtr);
+ IsBlock = true;
+ break;
+ case DW_FORM_block2:
+ Value.uval = Data.getU16(OffsetPtr);
+ IsBlock = true;
+ break;
+ case DW_FORM_block4:
+ Value.uval = Data.getU32(OffsetPtr);
+ IsBlock = true;
+ break;
+ case DW_FORM_data1:
+ case DW_FORM_ref1:
+ case DW_FORM_flag:
+ case DW_FORM_strx1:
+ case DW_FORM_addrx1:
+ Value.uval = Data.getU8(OffsetPtr);
+ break;
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ case DW_FORM_strx2:
+ case DW_FORM_addrx2:
+ Value.uval = Data.getU16(OffsetPtr);
+ break;
+ case DW_FORM_strx3:
+ Value.uval = Data.getU24(OffsetPtr);
+ break;
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ case DW_FORM_ref_sup4:
+ case DW_FORM_strx4:
+ case DW_FORM_addrx4:
+ Value.uval = Data.getRelocatedValue(4, OffsetPtr);
+ break;
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sup8:
+ Value.uval = Data.getU64(OffsetPtr);
+ break;
+ case DW_FORM_data16:
+ // Treat this like a 16-byte block.
+ Value.uval = 16;
+ IsBlock = true;
+ break;
+ case DW_FORM_sdata:
+ Value.sval = Data.getSLEB128(OffsetPtr);
+ break;
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_rnglistx:
+ Value.uval = Data.getULEB128(OffsetPtr);
+ break;
+ case DW_FORM_string:
+ Value.cstr = Data.getCStr(OffsetPtr);
+ break;
+ case DW_FORM_indirect:
+ Form = static_cast<dwarf::Form>(Data.getULEB128(OffsetPtr));
+ Indirect = true;
+ break;
+ case DW_FORM_strp:
+ case DW_FORM_sec_offset:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
+ case DW_FORM_line_strp:
+ case DW_FORM_strp_sup: {
+ Value.uval =
+ Data.getRelocatedValue(FP.getDwarfOffsetByteSize(), OffsetPtr);
+ break;
+ }
+ case DW_FORM_flag_present:
+ Value.uval = 1;
+ break;
+ case DW_FORM_ref_sig8:
+ Value.uval = Data.getU64(OffsetPtr);
+ break;
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_addrx:
+ case DW_FORM_strx:
+ Value.uval = Data.getULEB128(OffsetPtr);
+ break;
+ default:
+ // DWARFFormValue::skipValue() will have caught this and caused all
+ // DWARF DIEs to fail to be parsed, so this code is not be reachable.
+ llvm_unreachable("unsupported form");
+ }
+ } while (Indirect);
+
+ if (IsBlock) {
+ StringRef Str = Data.getData().substr(*OffsetPtr, Value.uval);
+ Value.data = nullptr;
+ if (!Str.empty()) {
+ Value.data = reinterpret_cast<const uint8_t *>(Str.data());
+ *OffsetPtr += Value.uval;
+ }
+ }
+
+ return true;
+}
+
+void DWARFFormValue::dumpSectionedAddress(raw_ostream &OS,
+ DIDumpOptions DumpOpts,
+ SectionedAddress SA) const {
+ OS << format("0x%016" PRIx64, SA.Address);
+ dumpAddressSection(U->getContext().getDWARFObj(), OS, DumpOpts,
+ SA.SectionIndex);
+}
+
+void DWARFFormValue::dumpAddressSection(const DWARFObject &Obj, raw_ostream &OS,
+ DIDumpOptions DumpOpts,
+ uint64_t SectionIndex) {
+ if (!DumpOpts.Verbose || SectionIndex == -1ULL)
+ return;
+ ArrayRef<SectionName> SectionNames = Obj.getSectionNames();
+ const auto &SecRef = SectionNames[SectionIndex];
+
+ OS << " \"" << SecRef.Name << '\"';
+
+ // Print section index if name is not unique.
+ if (!SecRef.IsNameUnique)
+ OS << format(" [%" PRIu64 "]", SectionIndex);
+}
+
+void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+ uint64_t UValue = Value.uval;
+ bool CURelativeOffset = false;
+ raw_ostream &AddrOS = DumpOpts.ShowAddresses
+ ? WithColor(OS, HighlightColor::Address).get()
+ : nulls();
+ switch (Form) {
+ case DW_FORM_addr:
+ dumpSectionedAddress(AddrOS, DumpOpts, {Value.uval, Value.SectionIndex});
+ break;
+ case DW_FORM_addrx:
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx3:
+ case DW_FORM_addrx4:
+ case DW_FORM_GNU_addr_index: {
+ Optional<SectionedAddress> A = U->getAddrOffsetSectionItem(UValue);
+ if (!A || DumpOpts.Verbose)
+ AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue);
+ if (U == nullptr)
+ OS << "<invalid dwarf unit>";
+ else if (A)
+ dumpSectionedAddress(AddrOS, DumpOpts, *A);
+ else
+ OS << "<no .debug_addr section>";
+ break;
+ }
+ case DW_FORM_flag_present:
+ OS << "true";
+ break;
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ OS << format("0x%02x", (uint8_t)UValue);
+ break;
+ case DW_FORM_data2:
+ OS << format("0x%04x", (uint16_t)UValue);
+ break;
+ case DW_FORM_data4:
+ OS << format("0x%08x", (uint32_t)UValue);
+ break;
+ case DW_FORM_ref_sig8:
+ AddrOS << format("0x%016" PRIx64, UValue);
+ break;
+ case DW_FORM_data8:
+ OS << format("0x%016" PRIx64, UValue);
+ break;
+ case DW_FORM_data16:
+ OS << format_bytes(ArrayRef<uint8_t>(Value.data, 16), None, 16, 16);
+ break;
+ case DW_FORM_string:
+ OS << '"';
+ OS.write_escaped(Value.cstr);
+ OS << '"';
+ break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (UValue > 0) {
+ switch (Form) {
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ AddrOS << format("<0x%" PRIx64 "> ", UValue);
+ break;
+ case DW_FORM_block1:
+ AddrOS << format("<0x%2.2x> ", (uint8_t)UValue);
+ break;
+ case DW_FORM_block2:
+ AddrOS << format("<0x%4.4x> ", (uint16_t)UValue);
+ break;
+ case DW_FORM_block4:
+ AddrOS << format("<0x%8.8x> ", (uint32_t)UValue);
+ break;
+ default:
+ break;
+ }
+
+ const uint8_t *DataPtr = Value.data;
+ if (DataPtr) {
+ // UValue contains size of block
+ const uint8_t *EndDataPtr = DataPtr + UValue;
+ while (DataPtr < EndDataPtr) {
+ AddrOS << format("%2.2x ", *DataPtr);
+ ++DataPtr;
+ }
+ } else
+ OS << "NULL";
+ }
+ break;
+
+ case DW_FORM_sdata:
+ OS << Value.sval;
+ break;
+ case DW_FORM_udata:
+ OS << Value.uval;
+ break;
+ case DW_FORM_strp:
+ if (DumpOpts.Verbose)
+ OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue);
+ dumpString(OS);
+ break;
+ case DW_FORM_line_strp:
+ if (DumpOpts.Verbose)
+ OS << format(" .debug_line_str[0x%8.8x] = ", (uint32_t)UValue);
+ dumpString(OS);
+ break;
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4:
+ case DW_FORM_GNU_str_index:
+ if (DumpOpts.Verbose)
+ OS << format("indexed (%8.8x) string = ", (uint32_t)UValue);
+ dumpString(OS);
+ break;
+ case DW_FORM_GNU_strp_alt:
+ if (DumpOpts.Verbose)
+ OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue);
+ dumpString(OS);
+ break;
+ case DW_FORM_ref_addr:
+ AddrOS << format("0x%016" PRIx64, UValue);
+ break;
+ case DW_FORM_ref1:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue);
+ break;
+ case DW_FORM_ref2:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue);
+ break;
+ case DW_FORM_ref4:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue);
+ break;
+ case DW_FORM_ref8:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%8.8" PRIx64, UValue);
+ break;
+ case DW_FORM_ref_udata:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%" PRIx64, UValue);
+ break;
+ case DW_FORM_GNU_ref_alt:
+ AddrOS << format("<alt 0x%" PRIx64 ">", UValue);
+ break;
+
+ // All DW_FORM_indirect attributes should be resolved prior to calling
+ // this function
+ case DW_FORM_indirect:
+ OS << "DW_FORM_indirect";
+ break;
+
+ case DW_FORM_rnglistx:
+ OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
+ break;
+
+ // Should be formatted to 64-bit for DWARF64.
+ case DW_FORM_sec_offset:
+ AddrOS << format("0x%08x", (uint32_t)UValue);
+ break;
+
+ default:
+ OS << format("DW_FORM(0x%4.4x)", Form);
+ break;
+ }
+
+ if (CURelativeOffset) {
+ if (DumpOpts.Verbose)
+ OS << " => {";
+ if (DumpOpts.ShowAddresses)
+ WithColor(OS, HighlightColor::Address).get()
+ << format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0));
+ if (DumpOpts.Verbose)
+ OS << "}";
+ }
+}
+
+void DWARFFormValue::dumpString(raw_ostream &OS) const {
+ Optional<const char *> DbgStr = getAsCString();
+ if (DbgStr.hasValue()) {
+ auto COS = WithColor(OS, HighlightColor::String);
+ COS.get() << '"';
+ COS.get().write_escaped(DbgStr.getValue());
+ COS.get() << '"';
+ }
+}
+
+Optional<const char *> DWARFFormValue::getAsCString() const {
+ if (!isFormClass(FC_String))
+ return None;
+ if (Form == DW_FORM_string)
+ return Value.cstr;
+ // FIXME: Add support for DW_FORM_GNU_strp_alt
+ if (Form == DW_FORM_GNU_strp_alt || C == nullptr)
+ return None;
+ uint32_t Offset = Value.uval;
+ if (Form == DW_FORM_line_strp) {
+ // .debug_line_str is tracked in the Context.
+ if (const char *Str = C->getLineStringExtractor().getCStr(&Offset))
+ return Str;
+ return None;
+ }
+ if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx ||
+ Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 ||
+ Form == DW_FORM_strx4) {
+ if (!U)
+ return None;
+ Optional<uint64_t> StrOffset = U->getStringOffsetSectionItem(Offset);
+ if (!StrOffset)
+ return None;
+ Offset = *StrOffset;
+ }
+ // Prefer the Unit's string extractor, because for .dwo it will point to
+ // .debug_str.dwo, while the Context's extractor always uses .debug_str.
+ if (U) {
+ if (const char *Str = U->getStringExtractor().getCStr(&Offset))
+ return Str;
+ return None;
+ }
+ if (const char *Str = C->getStringExtractor().getCStr(&Offset))
+ return Str;
+ return None;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsAddress() const {
+ if (auto SA = getAsSectionedAddress())
+ return SA->Address;
+ return None;
+}
+Optional<SectionedAddress> DWARFFormValue::getAsSectionedAddress() const {
+ if (!isFormClass(FC_Address))
+ return None;
+ if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx) {
+ uint32_t Index = Value.uval;
+ if (!U)
+ return None;
+ Optional<SectionedAddress> SA = U->getAddrOffsetSectionItem(Index);
+ if (!SA)
+ return None;
+ return SA;
+ }
+ return {{Value.uval, Value.SectionIndex}};
+}
+
+Optional<uint64_t> DWARFFormValue::getAsReference() const {
+ if (!isFormClass(FC_Reference))
+ return None;
+ switch (Form) {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ if (!U)
+ return None;
+ return Value.uval + U->getOffset();
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_GNU_ref_alt:
+ return Value.uval;
+ default:
+ return None;
+ }
+}
+
+Optional<uint64_t> DWARFFormValue::getAsSectionOffset() const {
+ if (!isFormClass(FC_SectionOffset))
+ return None;
+ return Value.uval;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const {
+ if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) ||
+ Form == DW_FORM_sdata)
+ return None;
+ return Value.uval;
+}
+
+Optional<int64_t> DWARFFormValue::getAsSignedConstant() const {
+ if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) ||
+ (Form == DW_FORM_udata &&
+ uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval))
+ return None;
+ switch (Form) {
+ case DW_FORM_data4:
+ return int32_t(Value.uval);
+ case DW_FORM_data2:
+ return int16_t(Value.uval);
+ case DW_FORM_data1:
+ return int8_t(Value.uval);
+ case DW_FORM_sdata:
+ case DW_FORM_data8:
+ default:
+ return Value.sval;
+ }
+}
+
+Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const {
+ if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc) &&
+ Form != DW_FORM_data16)
+ return None;
+ return makeArrayRef(Value.data, Value.uval);
+}
+
+Optional<uint64_t> DWARFFormValue::getAsCStringOffset() const {
+ if (!isFormClass(FC_String) && Form == DW_FORM_string)
+ return None;
+ return Value.uval;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsReferenceUVal() const {
+ if (!isFormClass(FC_Reference))
+ return None;
+ return Value.uval;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp
new file mode 100644
index 000000000000..1abd931e3b8b
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp
@@ -0,0 +1,200 @@
+//===- DWARFGdbIndex.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/DWARFGdbIndex.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+
+// .gdb_index section format reference:
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html
+
+void DWARFGdbIndex::dumpCUList(raw_ostream &OS) const {
+ OS << format("\n CU list offset = 0x%x, has %" PRId64 " entries:",
+ CuListOffset, (uint64_t)CuList.size())
+ << '\n';
+ uint32_t I = 0;
+ for (const CompUnitEntry &CU : CuList)
+ OS << format(" %d: Offset = 0x%llx, Length = 0x%llx\n", I++, CU.Offset,
+ CU.Length);
+}
+
+void DWARFGdbIndex::dumpTUList(raw_ostream &OS) const {
+ OS << formatv("\n Types CU list offset = {0:x}, has {1} entries:\n",
+ TuListOffset, TuList.size());
+ uint32_t I = 0;
+ for (const TypeUnitEntry &TU : TuList)
+ OS << formatv(" {0}: offset = {1:x8}, type_offset = {2:x8}, "
+ "type_signature = {3:x16}\n",
+ I++, TU.Offset, TU.TypeOffset, TU.TypeSignature);
+}
+
+void DWARFGdbIndex::dumpAddressArea(raw_ostream &OS) const {
+ OS << format("\n Address area offset = 0x%x, has %" PRId64 " entries:",
+ AddressAreaOffset, (uint64_t)AddressArea.size())
+ << '\n';
+ for (const AddressEntry &Addr : AddressArea)
+ OS << format(
+ " Low/High address = [0x%llx, 0x%llx) (Size: 0x%llx), CU id = %d\n",
+ Addr.LowAddress, Addr.HighAddress, Addr.HighAddress - Addr.LowAddress,
+ Addr.CuIndex);
+}
+
+void DWARFGdbIndex::dumpSymbolTable(raw_ostream &OS) const {
+ OS << format("\n Symbol table offset = 0x%x, size = %" PRId64
+ ", filled slots:",
+ SymbolTableOffset, (uint64_t)SymbolTable.size())
+ << '\n';
+ uint32_t I = -1;
+ for (const SymTableEntry &E : SymbolTable) {
+ ++I;
+ if (!E.NameOffset && !E.VecOffset)
+ continue;
+
+ OS << format(" %d: Name offset = 0x%x, CU vector offset = 0x%x\n", I,
+ E.NameOffset, E.VecOffset);
+
+ StringRef Name = ConstantPoolStrings.substr(
+ ConstantPoolOffset - StringPoolOffset + E.NameOffset);
+
+ auto CuVector = std::find_if(
+ ConstantPoolVectors.begin(), ConstantPoolVectors.end(),
+ [&](const std::pair<uint32_t, SmallVector<uint32_t, 0>> &V) {
+ return V.first == E.VecOffset;
+ });
+ assert(CuVector != ConstantPoolVectors.end() && "Invalid symbol table");
+ uint32_t CuVectorId = CuVector - ConstantPoolVectors.begin();
+ OS << format(" String name: %s, CU vector index: %d\n", Name.data(),
+ CuVectorId);
+ }
+}
+
+void DWARFGdbIndex::dumpConstantPool(raw_ostream &OS) const {
+ OS << format("\n Constant pool offset = 0x%x, has %" PRId64 " CU vectors:",
+ ConstantPoolOffset, (uint64_t)ConstantPoolVectors.size());
+ uint32_t I = 0;
+ for (const auto &V : ConstantPoolVectors) {
+ OS << format("\n %d(0x%x): ", I++, V.first);
+ for (uint32_t Val : V.second)
+ OS << format("0x%x ", Val);
+ }
+ OS << '\n';
+}
+
+void DWARFGdbIndex::dump(raw_ostream &OS) {
+ if (HasError) {
+ OS << "\n<error parsing>\n";
+ return;
+ }
+
+ if (HasContent) {
+ OS << " Version = " << Version << '\n';
+ dumpCUList(OS);
+ dumpTUList(OS);
+ dumpAddressArea(OS);
+ dumpSymbolTable(OS);
+ dumpConstantPool(OS);
+ }
+}
+
+bool DWARFGdbIndex::parseImpl(DataExtractor Data) {
+ uint32_t Offset = 0;
+
+ // Only version 7 is supported at this moment.
+ Version = Data.getU32(&Offset);
+ if (Version != 7)
+ return false;
+
+ CuListOffset = Data.getU32(&Offset);
+ uint32_t CuTypesOffset = Data.getU32(&Offset);
+ AddressAreaOffset = Data.getU32(&Offset);
+ SymbolTableOffset = Data.getU32(&Offset);
+ ConstantPoolOffset = Data.getU32(&Offset);
+
+ if (Offset != CuListOffset)
+ return false;
+
+ uint32_t CuListSize = (CuTypesOffset - CuListOffset) / 16;
+ CuList.reserve(CuListSize);
+ for (uint32_t i = 0; i < CuListSize; ++i) {
+ uint64_t CuOffset = Data.getU64(&Offset);
+ uint64_t CuLength = Data.getU64(&Offset);
+ CuList.push_back({CuOffset, CuLength});
+ }
+
+ // CU Types are no longer needed as DWARF skeleton type units never made it
+ // into the standard.
+ uint32_t TuListSize = (AddressAreaOffset - CuTypesOffset) / 24;
+ TuList.resize(TuListSize);
+ for (uint32_t I = 0; I < TuListSize; ++I) {
+ uint64_t CuOffset = Data.getU64(&Offset);
+ uint64_t TypeOffset = Data.getU64(&Offset);
+ uint64_t Signature = Data.getU64(&Offset);
+ TuList[I] = {CuOffset, TypeOffset, Signature};
+ }
+
+ uint32_t AddressAreaSize = (SymbolTableOffset - AddressAreaOffset) / 20;
+ AddressArea.reserve(AddressAreaSize);
+ for (uint32_t i = 0; i < AddressAreaSize; ++i) {
+ uint64_t LowAddress = Data.getU64(&Offset);
+ uint64_t HighAddress = Data.getU64(&Offset);
+ uint32_t CuIndex = Data.getU32(&Offset);
+ AddressArea.push_back({LowAddress, HighAddress, CuIndex});
+ }
+
+ // The symbol table. This is an open addressed hash table. The size of the
+ // hash table is always a power of 2.
+ // Each slot in the hash table consists of a pair of offset_type values. The
+ // first value is the offset of the symbol's name in the constant pool. The
+ // second value is the offset of the CU vector in the constant pool.
+ // If both values are 0, then this slot in the hash table is empty. This is ok
+ // because while 0 is a valid constant pool index, it cannot be a valid index
+ // for both a string and a CU vector.
+ uint32_t SymTableSize = (ConstantPoolOffset - SymbolTableOffset) / 8;
+ SymbolTable.reserve(SymTableSize);
+ uint32_t CuVectorsTotal = 0;
+ for (uint32_t i = 0; i < SymTableSize; ++i) {
+ uint32_t NameOffset = Data.getU32(&Offset);
+ uint32_t CuVecOffset = Data.getU32(&Offset);
+ SymbolTable.push_back({NameOffset, CuVecOffset});
+ if (NameOffset || CuVecOffset)
+ ++CuVectorsTotal;
+ }
+
+ // The constant pool. CU vectors are stored first, followed by strings.
+ // The first value is the number of CU indices in the vector. Each subsequent
+ // value is the index and symbol attributes of a CU in the CU list.
+ for (uint32_t i = 0; i < CuVectorsTotal; ++i) {
+ ConstantPoolVectors.emplace_back(0, SmallVector<uint32_t, 0>());
+ auto &Vec = ConstantPoolVectors.back();
+ Vec.first = Offset - ConstantPoolOffset;
+
+ uint32_t Num = Data.getU32(&Offset);
+ for (uint32_t j = 0; j < Num; ++j)
+ Vec.second.push_back(Data.getU32(&Offset));
+ }
+
+ ConstantPoolStrings = Data.getData().drop_front(Offset);
+ StringPoolOffset = Offset;
+ return true;
+}
+
+void DWARFGdbIndex::parse(DataExtractor Data) {
+ HasContent = !Data.getData().empty();
+ HasError = HasContent && !parseImpl(Data);
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
new file mode 100644
index 000000000000..462c036d73ad
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
@@ -0,0 +1,109 @@
+//===- DWARFListTable.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/DWARFListTable.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
+ uint32_t *OffsetPtr) {
+ HeaderOffset = *OffsetPtr;
+ // Read and verify the length field.
+ if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
+ return createStringError(errc::invalid_argument,
+ "section is not large enough to contain a "
+ "%s table length at offset 0x%" PRIx32,
+ SectionName.data(), *OffsetPtr);
+ // TODO: Add support for DWARF64.
+ HeaderData.Length = Data.getU32(OffsetPtr);
+ if (HeaderData.Length == 0xffffffffu)
+ return createStringError(errc::not_supported,
+ "DWARF64 is not supported in %s at offset 0x%" PRIx32,
+ SectionName.data(), HeaderOffset);
+ Format = dwarf::DwarfFormat::DWARF32;
+ if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
+ return createStringError(errc::invalid_argument,
+ "%s table at offset 0x%" PRIx32
+ " has too small length (0x%" PRIx32
+ ") to contain a complete header",
+ SectionName.data(), HeaderOffset, length());
+ uint32_t End = HeaderOffset + length();
+ if (!Data.isValidOffsetForDataOfSize(HeaderOffset, End - HeaderOffset))
+ return createStringError(errc::invalid_argument,
+ "section is not large enough to contain a %s table "
+ "of length 0x%" PRIx32 " at offset 0x%" PRIx32,
+ SectionName.data(), length(), HeaderOffset);
+
+ HeaderData.Version = Data.getU16(OffsetPtr);
+ HeaderData.AddrSize = Data.getU8(OffsetPtr);
+ HeaderData.SegSize = Data.getU8(OffsetPtr);
+ HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
+
+ // Perform basic validation of the remaining header fields.
+ if (HeaderData.Version != 5)
+ return createStringError(errc::invalid_argument,
+ "unrecognised %s table version %" PRIu16
+ " in table at offset 0x%" PRIx32,
+ SectionName.data(), HeaderData.Version, HeaderOffset);
+ if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
+ return createStringError(errc::not_supported,
+ "%s table at offset 0x%" PRIx32
+ " has unsupported address size %" PRIu8,
+ SectionName.data(), HeaderOffset, HeaderData.AddrSize);
+ if (HeaderData.SegSize != 0)
+ return createStringError(errc::not_supported,
+ "%s table at offset 0x%" PRIx32
+ " has unsupported segment selector size %" PRIu8,
+ SectionName.data(), HeaderOffset, HeaderData.SegSize);
+ if (End < HeaderOffset + sizeof(HeaderData) +
+ HeaderData.OffsetEntryCount * sizeof(uint32_t))
+ return createStringError(errc::invalid_argument,
+ "%s table at offset 0x%" PRIx32 " has more offset entries (%" PRIu32
+ ") than there is space for",
+ SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount);
+ Data.setAddressSize(HeaderData.AddrSize);
+ for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I)
+ Offsets.push_back(Data.getU32(OffsetPtr));
+ return Error::success();
+}
+
+void DWARFListTableHeader::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+ if (DumpOpts.Verbose)
+ OS << format("0x%8.8" PRIx32 ": ", HeaderOffset);
+ OS << format(
+ "%s list header: length = 0x%8.8" PRIx32 ", version = 0x%4.4" PRIx16 ", "
+ "addr_size = 0x%2.2" PRIx8 ", seg_size = 0x%2.2" PRIx8
+ ", offset_entry_count = "
+ "0x%8.8" PRIx32 "\n",
+ ListTypeString.data(), HeaderData.Length, HeaderData.Version,
+ HeaderData.AddrSize, HeaderData.SegSize, HeaderData.OffsetEntryCount);
+
+ if (HeaderData.OffsetEntryCount > 0) {
+ OS << "offsets: [";
+ for (const auto &Off : Offsets) {
+ OS << format("\n0x%8.8" PRIx32, Off);
+ if (DumpOpts.Verbose)
+ OS << format(" => 0x%8.8" PRIx32,
+ Off + HeaderOffset + sizeof(HeaderData));
+ }
+ OS << "\n]\n";
+ }
+}
+
+uint32_t DWARFListTableHeader::length() const {
+ if (HeaderData.Length == 0)
+ return 0;
+ // TODO: DWARF64 support.
+ return HeaderData.Length + sizeof(uint32_t);
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
new file mode 100644
index 000000000000..00be75e1a94d
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
@@ -0,0 +1,48 @@
+//===- DWARFTypeUnit.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/DWARFTypeUnit.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+
+using namespace llvm;
+
+void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
+ DWARFDie TD = getDIEForOffset(getTypeOffset() + getOffset());
+ const char *Name = TD.getName(DINameKind::ShortName);
+
+ if (DumpOpts.SummarizeTypes) {
+ OS << "name = '" << Name << "'"
+ << " type_signature = " << format("0x%016" PRIx64, getTypeHash())
+ << " length = " << format("0x%08x", getLength()) << '\n';
+ return;
+ }
+
+ OS << format("0x%08x", getOffset()) << ": Type Unit:"
+ << " length = " << format("0x%08x", getLength())
+ << " version = " << format("0x%04x", getVersion());
+ if (getVersion() >= 5)
+ OS << " unit_type = " << dwarf::UnitTypeString(getUnitType());
+ OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset())
+ << " addr_size = " << format("0x%02x", getAddressByteSize())
+ << " name = '" << Name << "'"
+ << " type_signature = " << format("0x%016" PRIx64, getTypeHash())
+ << " type_offset = " << format("0x%04x", getTypeOffset())
+ << " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n";
+
+ if (DWARFDie TU = getUnitDIE(false))
+ TU.dump(OS, 0, DumpOpts);
+ else
+ OS << "<type unit can't be parsed!>\n\n";
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
new file mode 100644
index 000000000000..80234665bdeb
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -0,0 +1,844 @@
+//===- DWARFUnit.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/DWARFUnit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFUnitVector::addUnitsForSection(DWARFContext &C,
+ const DWARFSection &Section,
+ DWARFSectionKind SectionKind) {
+ const DWARFObject &D = C.getDWARFObj();
+ addUnitsImpl(C, D, Section, C.getDebugAbbrev(), &D.getRangeSection(),
+ &D.getLocSection(), D.getStringSection(),
+ D.getStringOffsetSection(), &D.getAddrSection(),
+ D.getLineSection(), D.isLittleEndian(), false, false,
+ SectionKind);
+}
+
+void DWARFUnitVector::addUnitsForDWOSection(DWARFContext &C,
+ const DWARFSection &DWOSection,
+ DWARFSectionKind SectionKind,
+ bool Lazy) {
+ const DWARFObject &D = C.getDWARFObj();
+ addUnitsImpl(C, D, DWOSection, C.getDebugAbbrevDWO(), &D.getRangeDWOSection(),
+ &D.getLocDWOSection(), D.getStringDWOSection(),
+ D.getStringOffsetDWOSection(), &D.getAddrSection(),
+ D.getLineDWOSection(), C.isLittleEndian(), true, Lazy,
+ SectionKind);
+}
+
+void DWARFUnitVector::addUnitsImpl(
+ DWARFContext &Context, const DWARFObject &Obj, const DWARFSection &Section,
+ const DWARFDebugAbbrev *DA, const DWARFSection *RS,
+ const DWARFSection *LocSection, StringRef SS, const DWARFSection &SOS,
+ const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO,
+ bool Lazy, DWARFSectionKind SectionKind) {
+ DWARFDataExtractor Data(Obj, Section, LE, 0);
+ // Lazy initialization of Parser, now that we have all section info.
+ if (!Parser) {
+ Parser = [=, &Context, &Obj, &Section, &SOS,
+ &LS](uint32_t Offset, DWARFSectionKind SectionKind,
+ const DWARFSection *CurSection,
+ const DWARFUnitIndex::Entry *IndexEntry)
+ -> std::unique_ptr<DWARFUnit> {
+ const DWARFSection &InfoSection = CurSection ? *CurSection : Section;
+ DWARFDataExtractor Data(Obj, InfoSection, LE, 0);
+ if (!Data.isValidOffset(Offset))
+ return nullptr;
+ const DWARFUnitIndex *Index = nullptr;
+ if (IsDWO)
+ Index = &getDWARFUnitIndex(Context, SectionKind);
+ DWARFUnitHeader Header;
+ if (!Header.extract(Context, Data, &Offset, SectionKind, Index,
+ IndexEntry))
+ return nullptr;
+ std::unique_ptr<DWARFUnit> U;
+ if (Header.isTypeUnit())
+ U = llvm::make_unique<DWARFTypeUnit>(Context, InfoSection, Header, DA,
+ RS, LocSection, SS, SOS, AOS, LS,
+ LE, IsDWO, *this);
+ else
+ U = llvm::make_unique<DWARFCompileUnit>(Context, InfoSection, Header,
+ DA, RS, LocSection, SS, SOS,
+ AOS, LS, LE, IsDWO, *this);
+ return U;
+ };
+ }
+ if (Lazy)
+ return;
+ // Find a reasonable insertion point within the vector. We skip over
+ // (a) units from a different section, (b) units from the same section
+ // but with lower offset-within-section. This keeps units in order
+ // within a section, although not necessarily within the object file,
+ // even if we do lazy parsing.
+ auto I = this->begin();
+ uint32_t Offset = 0;
+ while (Data.isValidOffset(Offset)) {
+ if (I != this->end() &&
+ (&(*I)->getInfoSection() != &Section || (*I)->getOffset() == Offset)) {
+ ++I;
+ continue;
+ }
+ auto U = Parser(Offset, SectionKind, &Section, nullptr);
+ // If parsing failed, we're done with this section.
+ if (!U)
+ break;
+ Offset = U->getNextUnitOffset();
+ I = std::next(this->insert(I, std::move(U)));
+ }
+}
+
+DWARFUnit *DWARFUnitVector::addUnit(std::unique_ptr<DWARFUnit> Unit) {
+ auto I = std::upper_bound(begin(), end(), Unit,
+ [](const std::unique_ptr<DWARFUnit> &LHS,
+ const std::unique_ptr<DWARFUnit> &RHS) {
+ return LHS->getOffset() < RHS->getOffset();
+ });
+ return this->insert(I, std::move(Unit))->get();
+}
+
+DWARFUnit *DWARFUnitVector::getUnitForOffset(uint32_t Offset) const {
+ auto end = begin() + getNumInfoUnits();
+ auto *CU =
+ std::upper_bound(begin(), end, Offset,
+ [](uint32_t LHS, const std::unique_ptr<DWARFUnit> &RHS) {
+ return LHS < RHS->getNextUnitOffset();
+ });
+ if (CU != end && (*CU)->getOffset() <= Offset)
+ return CU->get();
+ return nullptr;
+}
+
+DWARFUnit *
+DWARFUnitVector::getUnitForIndexEntry(const DWARFUnitIndex::Entry &E) {
+ const auto *CUOff = E.getOffset(DW_SECT_INFO);
+ if (!CUOff)
+ return nullptr;
+
+ auto Offset = CUOff->Offset;
+ auto end = begin() + getNumInfoUnits();
+
+ auto *CU =
+ std::upper_bound(begin(), end, CUOff->Offset,
+ [](uint32_t LHS, const std::unique_ptr<DWARFUnit> &RHS) {
+ return LHS < RHS->getNextUnitOffset();
+ });
+ if (CU != end && (*CU)->getOffset() <= Offset)
+ return CU->get();
+
+ if (!Parser)
+ return nullptr;
+
+ auto U = Parser(Offset, DW_SECT_INFO, nullptr, &E);
+ if (!U)
+ U = nullptr;
+
+ auto *NewCU = U.get();
+ this->insert(CU, std::move(U));
+ ++NumInfoUnits;
+ return NewCU;
+}
+
+DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
+ const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA,
+ const DWARFSection *RS, const DWARFSection *LocSection,
+ StringRef SS, const DWARFSection &SOS,
+ const DWARFSection *AOS, const DWARFSection &LS, bool LE,
+ bool IsDWO, const DWARFUnitVector &UnitVector)
+ : Context(DC), InfoSection(Section), Header(Header), Abbrev(DA),
+ RangeSection(RS), LocSection(LocSection), LineSection(LS),
+ StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS),
+ isLittleEndian(LE), IsDWO(IsDWO), UnitVector(UnitVector) {
+ clear();
+ // For split DWARF we only need to keep track of the location list section's
+ // data (no relocations), and if we are reading a package file, we need to
+ // adjust the location list data based on the index entries.
+ if (IsDWO) {
+ LocSectionData = LocSection->Data;
+ if (auto *IndexEntry = Header.getIndexEntry())
+ if (const auto *C = IndexEntry->getOffset(DW_SECT_LOC))
+ LocSectionData = LocSectionData.substr(C->Offset, C->Length);
+ }
+}
+
+DWARFUnit::~DWARFUnit() = default;
+
+DWARFDataExtractor DWARFUnit::getDebugInfoExtractor() const {
+ return DWARFDataExtractor(Context.getDWARFObj(), InfoSection, isLittleEndian,
+ getAddressByteSize());
+}
+
+Optional<SectionedAddress>
+DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const {
+ if (IsDWO) {
+ auto R = Context.info_section_units();
+ auto I = R.begin();
+ // Surprising if a DWO file has more than one skeleton unit in it - this
+ // probably shouldn't be valid, but if a use case is found, here's where to
+ // support it (probably have to linearly search for the matching skeleton CU
+ // here)
+ if (I != R.end() && std::next(I) == R.end())
+ return (*I)->getAddrOffsetSectionItem(Index);
+ }
+ uint32_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize();
+ if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize())
+ return None;
+ DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection,
+ isLittleEndian, getAddressByteSize());
+ uint64_t Section;
+ uint64_t Address = DA.getRelocatedAddress(&Offset, &Section);
+ return {{Address, Section}};
+}
+
+Optional<uint64_t> DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const {
+ if (!StringOffsetsTableContribution)
+ return None;
+ unsigned ItemSize = getDwarfStringOffsetsByteSize();
+ uint32_t Offset = getStringOffsetsBase() + Index * ItemSize;
+ if (StringOffsetSection.Data.size() < Offset + ItemSize)
+ return None;
+ DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
+ isLittleEndian, 0);
+ return DA.getRelocatedValue(ItemSize, &Offset);
+}
+
+bool DWARFUnitHeader::extract(DWARFContext &Context,
+ const DWARFDataExtractor &debug_info,
+ uint32_t *offset_ptr,
+ DWARFSectionKind SectionKind,
+ const DWARFUnitIndex *Index,
+ const DWARFUnitIndex::Entry *Entry) {
+ Offset = *offset_ptr;
+ IndexEntry = Entry;
+ if (!IndexEntry && Index)
+ IndexEntry = Index->getFromOffset(*offset_ptr);
+ Length = debug_info.getU32(offset_ptr);
+ // FIXME: Support DWARF64.
+ unsigned SizeOfLength = 4;
+ FormParams.Format = DWARF32;
+ FormParams.Version = debug_info.getU16(offset_ptr);
+ if (FormParams.Version >= 5) {
+ UnitType = debug_info.getU8(offset_ptr);
+ FormParams.AddrSize = debug_info.getU8(offset_ptr);
+ AbbrOffset = debug_info.getU32(offset_ptr);
+ } else {
+ AbbrOffset = debug_info.getRelocatedValue(4, offset_ptr);
+ FormParams.AddrSize = debug_info.getU8(offset_ptr);
+ // Fake a unit type based on the section type. This isn't perfect,
+ // but distinguishing compile and type units is generally enough.
+ if (SectionKind == DW_SECT_TYPES)
+ UnitType = DW_UT_type;
+ else
+ UnitType = DW_UT_compile;
+ }
+ if (IndexEntry) {
+ if (AbbrOffset)
+ return false;
+ auto *UnitContrib = IndexEntry->getOffset();
+ if (!UnitContrib || UnitContrib->Length != (Length + 4))
+ return false;
+ auto *AbbrEntry = IndexEntry->getOffset(DW_SECT_ABBREV);
+ if (!AbbrEntry)
+ return false;
+ AbbrOffset = AbbrEntry->Offset;
+ }
+ if (isTypeUnit()) {
+ TypeHash = debug_info.getU64(offset_ptr);
+ TypeOffset = debug_info.getU32(offset_ptr);
+ } else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton)
+ DWOId = debug_info.getU64(offset_ptr);
+
+ // Header fields all parsed, capture the size of this unit header.
+ assert(*offset_ptr - Offset <= 255 && "unexpected header size");
+ Size = uint8_t(*offset_ptr - Offset);
+
+ // Type offset is unit-relative; should be after the header and before
+ // the end of the current unit.
+ bool TypeOffsetOK =
+ !isTypeUnit()
+ ? true
+ : TypeOffset >= Size && TypeOffset < getLength() + SizeOfLength;
+ bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1);
+ bool VersionOK = DWARFContext::isSupportedVersion(getVersion());
+ bool AddrSizeOK = getAddressByteSize() == 4 || getAddressByteSize() == 8;
+
+ if (!LengthOK || !VersionOK || !AddrSizeOK || !TypeOffsetOK)
+ return false;
+
+ // Keep track of the highest DWARF version we encounter across all units.
+ Context.setMaxVersionIfGreater(getVersion());
+ return true;
+}
+
+// Parse the rangelist table header, including the optional array of offsets
+// following it (DWARF v5 and later).
+static Expected<DWARFDebugRnglistTable>
+parseRngListTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
+ // TODO: Support DWARF64
+ // We are expected to be called with Offset 0 or pointing just past the table
+ // header, which is 12 bytes long for DWARF32.
+ if (Offset > 0) {
+ if (Offset < 12U)
+ return createStringError(errc::invalid_argument, "Did not detect a valid"
+ " range list table with base = 0x%" PRIu32,
+ Offset);
+ Offset -= 12U;
+ }
+ llvm::DWARFDebugRnglistTable Table;
+ if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
+ return std::move(E);
+ return Table;
+}
+
+Error DWARFUnit::extractRangeList(uint32_t RangeListOffset,
+ DWARFDebugRangeList &RangeList) const {
+ // Require that compile unit is extracted.
+ assert(!DieArray.empty());
+ DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, getAddressByteSize());
+ uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
+ return RangeList.extract(RangesData, &ActualRangeListOffset);
+}
+
+void DWARFUnit::clear() {
+ Abbrevs = nullptr;
+ BaseAddr.reset();
+ RangeSectionBase = 0;
+ AddrOffsetSectionBase = 0;
+ clearDIEs(false);
+ DWO.reset();
+}
+
+const char *DWARFUnit::getCompilationDir() {
+ return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr);
+}
+
+void DWARFUnit::extractDIEsToVector(
+ bool AppendCUDie, bool AppendNonCUDies,
+ std::vector<DWARFDebugInfoEntry> &Dies) const {
+ if (!AppendCUDie && !AppendNonCUDies)
+ return;
+
+ // Set the offset to that of the first DIE and calculate the start of the
+ // next compilation unit header.
+ uint32_t DIEOffset = getOffset() + getHeaderSize();
+ uint32_t NextCUOffset = getNextUnitOffset();
+ DWARFDebugInfoEntry DIE;
+ DWARFDataExtractor DebugInfoData = getDebugInfoExtractor();
+ uint32_t Depth = 0;
+ bool IsCUDie = true;
+
+ while (DIE.extractFast(*this, &DIEOffset, DebugInfoData, NextCUOffset,
+ Depth)) {
+ if (IsCUDie) {
+ if (AppendCUDie)
+ Dies.push_back(DIE);
+ if (!AppendNonCUDies)
+ break;
+ // The average bytes per DIE entry has been seen to be
+ // around 14-20 so let's pre-reserve the needed memory for
+ // our DIE entries accordingly.
+ Dies.reserve(Dies.size() + getDebugInfoSize() / 14);
+ IsCUDie = false;
+ } else {
+ Dies.push_back(DIE);
+ }
+
+ if (const DWARFAbbreviationDeclaration *AbbrDecl =
+ DIE.getAbbreviationDeclarationPtr()) {
+ // Normal DIE
+ if (AbbrDecl->hasChildren())
+ ++Depth;
+ } else {
+ // NULL DIE.
+ if (Depth > 0)
+ --Depth;
+ if (Depth == 0)
+ break; // We are done with this compile unit!
+ }
+ }
+
+ // Give a little bit of info if we encounter corrupt DWARF (our offset
+ // should always terminate at or before the start of the next compilation
+ // unit header).
+ if (DIEOffset > NextCUOffset)
+ WithColor::warning() << format("DWARF compile unit extends beyond its "
+ "bounds cu 0x%8.8x at 0x%8.8x\n",
+ getOffset(), DIEOffset);
+}
+
+size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
+ if ((CUDieOnly && !DieArray.empty()) ||
+ DieArray.size() > 1)
+ return 0; // Already parsed.
+
+ bool HasCUDie = !DieArray.empty();
+ extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+
+ if (DieArray.empty())
+ return 0;
+
+ // If CU DIE was just parsed, copy several attribute values from it.
+ if (!HasCUDie) {
+ DWARFDie UnitDie = getUnitDIE();
+ if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
+ Header.setDWOId(*DWOId);
+ if (!IsDWO) {
+ assert(AddrOffsetSectionBase == 0);
+ assert(RangeSectionBase == 0);
+ AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base), 0);
+ if (!AddrOffsetSectionBase)
+ AddrOffsetSectionBase =
+ toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0);
+ RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
+ }
+
+ // In general, in DWARF v5 and beyond we derive the start of the unit's
+ // contribution to the string offsets table from the unit DIE's
+ // DW_AT_str_offsets_base attribute. Split DWARF units do not use this
+ // attribute, so we assume that there is a contribution to the string
+ // offsets table starting at offset 0 of the debug_str_offsets.dwo section.
+ // In both cases we need to determine the format of the contribution,
+ // which may differ from the unit's format.
+ DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
+ isLittleEndian, 0);
+ if (IsDWO)
+ StringOffsetsTableContribution =
+ determineStringOffsetsTableContributionDWO(DA);
+ else if (getVersion() >= 5)
+ StringOffsetsTableContribution =
+ determineStringOffsetsTableContribution(DA);
+
+ // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
+ // describe address ranges.
+ if (getVersion() >= 5) {
+ if (IsDWO)
+ setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
+ else
+ setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
+ toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0));
+ if (RangeSection->Data.size()) {
+ // Parse the range list table header. Individual range lists are
+ // extracted lazily.
+ DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, 0);
+ if (auto TableOrError =
+ parseRngListTableHeader(RangesDA, RangeSectionBase))
+ RngListTable = TableOrError.get();
+ else
+ WithColor::error() << "parsing a range list table: "
+ << toString(TableOrError.takeError())
+ << '\n';
+
+ // In a split dwarf unit, there is no DW_AT_rnglists_base attribute.
+ // Adjust RangeSectionBase to point past the table header.
+ if (IsDWO && RngListTable)
+ RangeSectionBase = RngListTable->getHeaderSize();
+ }
+ }
+
+ // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
+ // skeleton CU DIE, so that DWARF users not aware of it are not broken.
+ }
+
+ return DieArray.size();
+}
+
+bool DWARFUnit::parseDWO() {
+ if (IsDWO)
+ return false;
+ if (DWO.get())
+ return false;
+ DWARFDie UnitDie = getUnitDIE();
+ if (!UnitDie)
+ return false;
+ auto DWOFileName = dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name));
+ if (!DWOFileName)
+ return false;
+ auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir));
+ SmallString<16> AbsolutePath;
+ if (sys::path::is_relative(*DWOFileName) && CompilationDir &&
+ *CompilationDir) {
+ sys::path::append(AbsolutePath, *CompilationDir);
+ }
+ sys::path::append(AbsolutePath, *DWOFileName);
+ auto DWOId = getDWOId();
+ if (!DWOId)
+ return false;
+ auto DWOContext = Context.getDWOContext(AbsolutePath);
+ if (!DWOContext)
+ return false;
+
+ DWARFCompileUnit *DWOCU = DWOContext->getDWOCompileUnitForHash(*DWOId);
+ if (!DWOCU)
+ return false;
+ DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU);
+ // Share .debug_addr and .debug_ranges section with compile unit in .dwo
+ DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
+ if (getVersion() >= 5) {
+ DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
+ DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, 0);
+ if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase))
+ DWO->RngListTable = TableOrError.get();
+ else
+ WithColor::error() << "parsing a range list table: "
+ << toString(TableOrError.takeError())
+ << '\n';
+ if (DWO->RngListTable)
+ DWO->RangeSectionBase = DWO->RngListTable->getHeaderSize();
+ } else {
+ auto DWORangesBase = UnitDie.getRangesBaseAttribute();
+ DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
+ }
+
+ return true;
+}
+
+void DWARFUnit::clearDIEs(bool KeepCUDie) {
+ if (DieArray.size() > (unsigned)KeepCUDie) {
+ DieArray.resize((unsigned)KeepCUDie);
+ DieArray.shrink_to_fit();
+ }
+}
+
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromOffset(uint32_t Offset) {
+ if (getVersion() <= 4) {
+ DWARFDebugRangeList RangeList;
+ if (Error E = extractRangeList(Offset, RangeList))
+ return std::move(E);
+ return RangeList.getAbsoluteRanges(getBaseAddress());
+ }
+ if (RngListTable) {
+ DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, RngListTable->getAddrSize());
+ auto RangeListOrError = RngListTable->findList(RangesData, Offset);
+ if (RangeListOrError)
+ return RangeListOrError.get().getAbsoluteRanges(getBaseAddress(), *this);
+ return RangeListOrError.takeError();
+ }
+
+ return createStringError(errc::invalid_argument,
+ "missing or invalid range list table");
+}
+
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromIndex(uint32_t Index) {
+ if (auto Offset = getRnglistOffset(Index))
+ return findRnglistFromOffset(*Offset + RangeSectionBase);
+
+ if (RngListTable)
+ return createStringError(errc::invalid_argument,
+ "invalid range list table index %d", Index);
+ else
+ return createStringError(errc::invalid_argument,
+ "missing or invalid range list table");
+}
+
+Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() {
+ DWARFDie UnitDie = getUnitDIE();
+ if (!UnitDie)
+ return createStringError(errc::invalid_argument, "No unit DIE");
+
+ // First, check if unit DIE describes address ranges for the whole unit.
+ auto CUDIERangesOrError = UnitDie.getAddressRanges();
+ if (!CUDIERangesOrError)
+ return createStringError(errc::invalid_argument,
+ "decoding address ranges: %s",
+ toString(CUDIERangesOrError.takeError()).c_str());
+ return *CUDIERangesOrError;
+}
+
+void DWARFUnit::updateAddressDieMap(DWARFDie Die) {
+ if (Die.isSubroutineDIE()) {
+ auto DIERangesOrError = Die.getAddressRanges();
+ if (DIERangesOrError) {
+ for (const auto &R : DIERangesOrError.get()) {
+ // Ignore 0-sized ranges.
+ if (R.LowPC == R.HighPC)
+ continue;
+ auto B = AddrDieMap.upper_bound(R.LowPC);
+ if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) {
+ // The range is a sub-range of existing ranges, we need to split the
+ // existing range.
+ if (R.HighPC < B->second.first)
+ AddrDieMap[R.HighPC] = B->second;
+ if (R.LowPC > B->first)
+ AddrDieMap[B->first].first = R.LowPC;
+ }
+ AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die);
+ }
+ } else
+ llvm::consumeError(DIERangesOrError.takeError());
+ }
+ // Parent DIEs are added to the AddrDieMap prior to the Children DIEs to
+ // simplify the logic to update AddrDieMap. The child's range will always
+ // be equal or smaller than the parent's range. With this assumption, when
+ // adding one range into the map, it will at most split a range into 3
+ // sub-ranges.
+ for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling())
+ updateAddressDieMap(Child);
+}
+
+DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) {
+ extractDIEsIfNeeded(false);
+ if (AddrDieMap.empty())
+ updateAddressDieMap(getUnitDIE());
+ auto R = AddrDieMap.upper_bound(Address);
+ if (R == AddrDieMap.begin())
+ return DWARFDie();
+ // upper_bound's previous item contains Address.
+ --R;
+ if (Address >= R->second.first)
+ return DWARFDie();
+ return R->second.second;
+}
+
+void
+DWARFUnit::getInlinedChainForAddress(uint64_t Address,
+ SmallVectorImpl<DWARFDie> &InlinedChain) {
+ assert(InlinedChain.empty());
+ // Try to look for subprogram DIEs in the DWO file.
+ parseDWO();
+ // First, find the subroutine that contains the given address (the leaf
+ // of inlined chain).
+ DWARFDie SubroutineDIE =
+ (DWO ? DWO.get() : this)->getSubroutineForAddress(Address);
+
+ if (!SubroutineDIE)
+ return;
+
+ while (!SubroutineDIE.isSubprogramDIE()) {
+ if (SubroutineDIE.getTag() == DW_TAG_inlined_subroutine)
+ InlinedChain.push_back(SubroutineDIE);
+ SubroutineDIE = SubroutineDIE.getParent();
+ }
+ InlinedChain.push_back(SubroutineDIE);
+}
+
+const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context,
+ DWARFSectionKind Kind) {
+ if (Kind == DW_SECT_INFO)
+ return Context.getCUIndex();
+ assert(Kind == DW_SECT_TYPES);
+ return Context.getTUIndex();
+}
+
+DWARFDie DWARFUnit::getParent(const DWARFDebugInfoEntry *Die) {
+ if (!Die)
+ return DWARFDie();
+ const uint32_t Depth = Die->getDepth();
+ // Unit DIEs always have a depth of zero and never have parents.
+ if (Depth == 0)
+ return DWARFDie();
+ // Depth of 1 always means parent is the compile/type unit.
+ if (Depth == 1)
+ return getUnitDIE();
+ // Look for previous DIE with a depth that is one less than the Die's depth.
+ const uint32_t ParentDepth = Depth - 1;
+ for (uint32_t I = getDIEIndex(Die) - 1; I > 0; --I) {
+ if (DieArray[I].getDepth() == ParentDepth)
+ return DWARFDie(this, &DieArray[I]);
+ }
+ return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) {
+ if (!Die)
+ return DWARFDie();
+ uint32_t Depth = Die->getDepth();
+ // Unit DIEs always have a depth of zero and never have siblings.
+ if (Depth == 0)
+ return DWARFDie();
+ // NULL DIEs don't have siblings.
+ if (Die->getAbbreviationDeclarationPtr() == nullptr)
+ return DWARFDie();
+
+ // Find the next DIE whose depth is the same as the Die's depth.
+ for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx;
+ ++I) {
+ if (DieArray[I].getDepth() == Depth)
+ return DWARFDie(this, &DieArray[I]);
+ }
+ return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getPreviousSibling(const DWARFDebugInfoEntry *Die) {
+ if (!Die)
+ return DWARFDie();
+ uint32_t Depth = Die->getDepth();
+ // Unit DIEs always have a depth of zero and never have siblings.
+ if (Depth == 0)
+ return DWARFDie();
+
+ // Find the previous DIE whose depth is the same as the Die's depth.
+ for (size_t I = getDIEIndex(Die); I > 0;) {
+ --I;
+ if (DieArray[I].getDepth() == Depth - 1)
+ return DWARFDie();
+ if (DieArray[I].getDepth() == Depth)
+ return DWARFDie(this, &DieArray[I]);
+ }
+ return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) {
+ if (!Die->hasChildren())
+ return DWARFDie();
+
+ // We do not want access out of bounds when parsing corrupted debug data.
+ size_t I = getDIEIndex(Die) + 1;
+ if (I >= DieArray.size())
+ return DWARFDie();
+ return DWARFDie(this, &DieArray[I]);
+}
+
+DWARFDie DWARFUnit::getLastChild(const DWARFDebugInfoEntry *Die) {
+ if (!Die->hasChildren())
+ return DWARFDie();
+
+ uint32_t Depth = Die->getDepth();
+ for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx;
+ ++I) {
+ if (DieArray[I].getDepth() == Depth + 1 &&
+ DieArray[I].getTag() == dwarf::DW_TAG_null)
+ return DWARFDie(this, &DieArray[I]);
+ assert(DieArray[I].getDepth() > Depth && "Not processing children?");
+ }
+ return DWARFDie();
+}
+
+const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
+ if (!Abbrevs)
+ Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset());
+ return Abbrevs;
+}
+
+llvm::Optional<SectionedAddress> DWARFUnit::getBaseAddress() {
+ if (BaseAddr)
+ return BaseAddr;
+
+ DWARFDie UnitDie = getUnitDIE();
+ Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc});
+ BaseAddr = toSectionedAddress(PC);
+ return BaseAddr;
+}
+
+Optional<StrOffsetsContributionDescriptor>
+StrOffsetsContributionDescriptor::validateContributionSize(
+ DWARFDataExtractor &DA) {
+ uint8_t EntrySize = getDwarfOffsetByteSize();
+ // In order to ensure that we don't read a partial record at the end of
+ // the section we validate for a multiple of the entry size.
+ uint64_t ValidationSize = alignTo(Size, EntrySize);
+ // Guard against overflow.
+ if (ValidationSize >= Size)
+ if (DA.isValidOffsetForDataOfSize((uint32_t)Base, ValidationSize))
+ return *this;
+ return None;
+}
+
+// Look for a DWARF64-formatted contribution to the string offsets table
+// starting at a given offset and record it in a descriptor.
+static Optional<StrOffsetsContributionDescriptor>
+parseDWARF64StringOffsetsTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
+ if (!DA.isValidOffsetForDataOfSize(Offset, 16))
+ return None;
+
+ if (DA.getU32(&Offset) != 0xffffffff)
+ return None;
+
+ uint64_t Size = DA.getU64(&Offset);
+ uint8_t Version = DA.getU16(&Offset);
+ (void)DA.getU16(&Offset); // padding
+ // The encoded length includes the 2-byte version field and the 2-byte
+ // padding, so we need to subtract them out when we populate the descriptor.
+ return {{Offset, Size - 4, Version, DWARF64}};
+}
+
+// Look for a DWARF32-formatted contribution to the string offsets table
+// starting at a given offset and record it in a descriptor.
+static Optional<StrOffsetsContributionDescriptor>
+parseDWARF32StringOffsetsTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
+ if (!DA.isValidOffsetForDataOfSize(Offset, 8))
+ return None;
+ uint32_t ContributionSize = DA.getU32(&Offset);
+ if (ContributionSize >= 0xfffffff0)
+ return None;
+ uint8_t Version = DA.getU16(&Offset);
+ (void)DA.getU16(&Offset); // padding
+ // The encoded length includes the 2-byte version field and the 2-byte
+ // padding, so we need to subtract them out when we populate the descriptor.
+ return {{Offset, ContributionSize - 4, Version, DWARF32}};
+}
+
+Optional<StrOffsetsContributionDescriptor>
+DWARFUnit::determineStringOffsetsTableContribution(DWARFDataExtractor &DA) {
+ auto Offset = toSectionOffset(getUnitDIE().find(DW_AT_str_offsets_base), 0);
+ Optional<StrOffsetsContributionDescriptor> Descriptor;
+ // Attempt to find a DWARF64 contribution 16 bytes before the base.
+ if (Offset >= 16)
+ Descriptor =
+ parseDWARF64StringOffsetsTableHeader(DA, (uint32_t)Offset - 16);
+ // Try to find a DWARF32 contribution 8 bytes before the base.
+ if (!Descriptor && Offset >= 8)
+ Descriptor = parseDWARF32StringOffsetsTableHeader(DA, (uint32_t)Offset - 8);
+ return Descriptor ? Descriptor->validateContributionSize(DA) : Descriptor;
+}
+
+Optional<StrOffsetsContributionDescriptor>
+DWARFUnit::determineStringOffsetsTableContributionDWO(DWARFDataExtractor & DA) {
+ uint64_t Offset = 0;
+ auto IndexEntry = Header.getIndexEntry();
+ const auto *C =
+ IndexEntry ? IndexEntry->getOffset(DW_SECT_STR_OFFSETS) : nullptr;
+ if (C)
+ Offset = C->Offset;
+ if (getVersion() >= 5) {
+ // Look for a valid contribution at the given offset.
+ auto Descriptor =
+ parseDWARF64StringOffsetsTableHeader(DA, (uint32_t)Offset);
+ if (!Descriptor)
+ Descriptor = parseDWARF32StringOffsetsTableHeader(DA, (uint32_t)Offset);
+ return Descriptor ? Descriptor->validateContributionSize(DA) : Descriptor;
+ }
+ // Prior to DWARF v5, we derive the contribution size from the
+ // index table (in a package file). In a .dwo file it is simply
+ // the length of the string offsets section.
+ if (!IndexEntry)
+ return {{0, StringOffsetSection.Data.size(), 4, DWARF32}};
+ if (C)
+ return {{C->Offset, C->Length, 4, DWARF32}};
+ return None;
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
new file mode 100644
index 000000000000..84b6c4b81817
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
@@ -0,0 +1,202 @@
+//===- DWARFUnitIndex.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/DWARFUnitIndex.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+bool DWARFUnitIndex::Header::parse(DataExtractor IndexData,
+ uint32_t *OffsetPtr) {
+ if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16))
+ return false;
+ Version = IndexData.getU32(OffsetPtr);
+ NumColumns = IndexData.getU32(OffsetPtr);
+ NumUnits = IndexData.getU32(OffsetPtr);
+ NumBuckets = IndexData.getU32(OffsetPtr);
+ return Version <= 2;
+}
+
+void DWARFUnitIndex::Header::dump(raw_ostream &OS) const {
+ OS << format("version = %u slots = %u\n\n", Version, NumBuckets);
+}
+
+bool DWARFUnitIndex::parse(DataExtractor IndexData) {
+ bool b = parseImpl(IndexData);
+ if (!b) {
+ // Make sure we don't try to dump anything
+ Header.NumBuckets = 0;
+ // Release any partially initialized data.
+ ColumnKinds.reset();
+ Rows.reset();
+ }
+ return b;
+}
+
+bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {
+ uint32_t Offset = 0;
+ if (!Header.parse(IndexData, &Offset))
+ return false;
+
+ if (!IndexData.isValidOffsetForDataOfSize(
+ Offset, Header.NumBuckets * (8 + 4) +
+ (2 * Header.NumUnits + 1) * 4 * Header.NumColumns))
+ return false;
+
+ Rows = llvm::make_unique<Entry[]>(Header.NumBuckets);
+ auto Contribs =
+ llvm::make_unique<Entry::SectionContribution *[]>(Header.NumUnits);
+ ColumnKinds = llvm::make_unique<DWARFSectionKind[]>(Header.NumColumns);
+
+ // Read Hash Table of Signatures
+ for (unsigned i = 0; i != Header.NumBuckets; ++i)
+ Rows[i].Signature = IndexData.getU64(&Offset);
+
+ // Read Parallel Table of Indexes
+ for (unsigned i = 0; i != Header.NumBuckets; ++i) {
+ auto Index = IndexData.getU32(&Offset);
+ if (!Index)
+ continue;
+ Rows[i].Index = this;
+ Rows[i].Contributions =
+ llvm::make_unique<Entry::SectionContribution[]>(Header.NumColumns);
+ Contribs[Index - 1] = Rows[i].Contributions.get();
+ }
+
+ // Read the Column Headers
+ for (unsigned i = 0; i != Header.NumColumns; ++i) {
+ ColumnKinds[i] = static_cast<DWARFSectionKind>(IndexData.getU32(&Offset));
+ if (ColumnKinds[i] == InfoColumnKind) {
+ if (InfoColumn != -1)
+ return false;
+ InfoColumn = i;
+ }
+ }
+
+ if (InfoColumn == -1)
+ return false;
+
+ // Read Table of Section Offsets
+ for (unsigned i = 0; i != Header.NumUnits; ++i) {
+ auto *Contrib = Contribs[i];
+ for (unsigned i = 0; i != Header.NumColumns; ++i)
+ Contrib[i].Offset = IndexData.getU32(&Offset);
+ }
+
+ // Read Table of Section Sizes
+ for (unsigned i = 0; i != Header.NumUnits; ++i) {
+ auto *Contrib = Contribs[i];
+ for (unsigned i = 0; i != Header.NumColumns; ++i)
+ Contrib[i].Length = IndexData.getU32(&Offset);
+ }
+
+ return true;
+}
+
+StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) {
+#define CASE(DS) \
+ case DW_SECT_##DS: \
+ return #DS;
+ switch (DS) {
+ CASE(INFO);
+ CASE(TYPES);
+ CASE(ABBREV);
+ CASE(LINE);
+ CASE(LOC);
+ CASE(STR_OFFSETS);
+ CASE(MACINFO);
+ CASE(MACRO);
+ }
+ llvm_unreachable("unknown DWARFSectionKind");
+}
+
+void DWARFUnitIndex::dump(raw_ostream &OS) const {
+ if (!*this)
+ return;
+
+ Header.dump(OS);
+ OS << "Index Signature ";
+ for (unsigned i = 0; i != Header.NumColumns; ++i)
+ OS << ' ' << left_justify(getColumnHeader(ColumnKinds[i]), 24);
+ OS << "\n----- ------------------";
+ for (unsigned i = 0; i != Header.NumColumns; ++i)
+ OS << " ------------------------";
+ OS << '\n';
+ for (unsigned i = 0; i != Header.NumBuckets; ++i) {
+ auto &Row = Rows[i];
+ if (auto *Contribs = Row.Contributions.get()) {
+ OS << format("%5u 0x%016" PRIx64 " ", i + 1, Row.Signature);
+ for (unsigned i = 0; i != Header.NumColumns; ++i) {
+ auto &Contrib = Contribs[i];
+ OS << format("[0x%08x, 0x%08x) ", Contrib.Offset,
+ Contrib.Offset + Contrib.Length);
+ }
+ OS << '\n';
+ }
+ }
+}
+
+const DWARFUnitIndex::Entry::SectionContribution *
+DWARFUnitIndex::Entry::getOffset(DWARFSectionKind Sec) const {
+ uint32_t i = 0;
+ for (; i != Index->Header.NumColumns; ++i)
+ if (Index->ColumnKinds[i] == Sec)
+ return &Contributions[i];
+ return nullptr;
+}
+
+const DWARFUnitIndex::Entry::SectionContribution *
+DWARFUnitIndex::Entry::getOffset() const {
+ return &Contributions[Index->InfoColumn];
+}
+
+const DWARFUnitIndex::Entry *
+DWARFUnitIndex::getFromOffset(uint32_t Offset) const {
+ if (OffsetLookup.empty()) {
+ for (uint32_t i = 0; i != Header.NumBuckets; ++i)
+ if (Rows[i].Contributions)
+ OffsetLookup.push_back(&Rows[i]);
+ llvm::sort(OffsetLookup, [&](Entry *E1, Entry *E2) {
+ return E1->Contributions[InfoColumn].Offset <
+ E2->Contributions[InfoColumn].Offset;
+ });
+ }
+ auto I =
+ llvm::upper_bound(OffsetLookup, Offset, [&](uint32_t Offset, Entry *E2) {
+ return Offset < E2->Contributions[InfoColumn].Offset;
+ });
+ if (I == OffsetLookup.begin())
+ return nullptr;
+ --I;
+ const auto *E = *I;
+ const auto &InfoContrib = E->Contributions[InfoColumn];
+ if ((InfoContrib.Offset + InfoContrib.Length) <= Offset)
+ return nullptr;
+ return E;
+}
+
+const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const {
+ uint64_t Mask = Header.NumBuckets - 1;
+
+ auto H = S & Mask;
+ auto HP = ((S >> 32) & Mask) | 1;
+ while (Rows[H].getSignature() != S && Rows[H].getSignature() != 0)
+ H = (H + HP) & Mask;
+
+ if (Rows[H].getSignature() != S)
+ return nullptr;
+
+ return &Rows[H];
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
new file mode 100644
index 000000000000..f8370178b627
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -0,0 +1,1514 @@
+//===- DWARFVerifier.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/DWARFVerifier.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#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/Support/DJB.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+#include <set>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+DWARFVerifier::DieRangeInfo::address_range_iterator
+DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
+ auto Begin = Ranges.begin();
+ auto End = Ranges.end();
+ auto Pos = std::lower_bound(Begin, End, R);
+
+ if (Pos != End) {
+ if (Pos->intersects(R))
+ return Pos;
+ if (Pos != Begin) {
+ auto Iter = Pos - 1;
+ if (Iter->intersects(R))
+ return Iter;
+ }
+ }
+
+ Ranges.insert(Pos, R);
+ return Ranges.end();
+}
+
+DWARFVerifier::DieRangeInfo::die_range_info_iterator
+DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) {
+ auto End = Children.end();
+ auto Iter = Children.begin();
+ while (Iter != End) {
+ if (Iter->intersects(RI))
+ return Iter;
+ ++Iter;
+ }
+ Children.insert(RI);
+ return Children.end();
+}
+
+bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const {
+ // Both list of ranges are sorted so we can make this fast.
+
+ if (Ranges.empty() || RHS.Ranges.empty())
+ return false;
+
+ // Since the ranges are sorted we can advance where we start searching with
+ // this object's ranges as we traverse RHS.Ranges.
+ auto End = Ranges.end();
+ auto Iter = findRange(RHS.Ranges.front());
+
+ // Now linearly walk the ranges in this object and see if they contain each
+ // ranges from RHS.Ranges.
+ for (const auto &R : RHS.Ranges) {
+ while (Iter != End) {
+ if (Iter->contains(R))
+ break;
+ ++Iter;
+ }
+ if (Iter == End)
+ return false;
+ }
+ return true;
+}
+
+bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const {
+ if (Ranges.empty() || RHS.Ranges.empty())
+ return false;
+
+ auto End = Ranges.end();
+ auto Iter = findRange(RHS.Ranges.front());
+ for (const auto &R : RHS.Ranges) {
+ if (Iter == End)
+ return false;
+ if (R.HighPC <= Iter->LowPC)
+ continue;
+ while (Iter != End) {
+ if (Iter->intersects(R))
+ return true;
+ ++Iter;
+ }
+ }
+
+ return false;
+}
+
+bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
+ uint32_t *Offset, unsigned UnitIndex,
+ uint8_t &UnitType, bool &isUnitDWARF64) {
+ uint32_t AbbrOffset, Length;
+ uint8_t AddrSize = 0;
+ uint16_t Version;
+ bool Success = true;
+
+ bool ValidLength = false;
+ bool ValidVersion = false;
+ bool ValidAddrSize = false;
+ bool ValidType = true;
+ bool ValidAbbrevOffset = true;
+
+ uint32_t OffsetStart = *Offset;
+ Length = DebugInfoData.getU32(Offset);
+ if (Length == UINT32_MAX) {
+ isUnitDWARF64 = true;
+ OS << format(
+ "Unit[%d] is in 64-bit DWARF format; cannot verify from this point.\n",
+ UnitIndex);
+ return false;
+ }
+ Version = DebugInfoData.getU16(Offset);
+
+ if (Version >= 5) {
+ UnitType = DebugInfoData.getU8(Offset);
+ AddrSize = DebugInfoData.getU8(Offset);
+ AbbrOffset = DebugInfoData.getU32(Offset);
+ ValidType = dwarf::isUnitType(UnitType);
+ } else {
+ UnitType = 0;
+ AbbrOffset = DebugInfoData.getU32(Offset);
+ AddrSize = DebugInfoData.getU8(Offset);
+ }
+
+ if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
+ ValidAbbrevOffset = false;
+
+ ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
+ ValidVersion = DWARFContext::isSupportedVersion(Version);
+ ValidAddrSize = AddrSize == 4 || AddrSize == 8;
+ if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
+ !ValidType) {
+ Success = false;
+ error() << format("Units[%d] - start offset: 0x%08x \n", UnitIndex,
+ OffsetStart);
+ if (!ValidLength)
+ note() << "The length for this unit is too "
+ "large for the .debug_info provided.\n";
+ if (!ValidVersion)
+ note() << "The 16 bit unit header version is not valid.\n";
+ if (!ValidType)
+ note() << "The unit type encoding is not valid.\n";
+ if (!ValidAbbrevOffset)
+ note() << "The offset into the .debug_abbrev section is "
+ "not valid.\n";
+ if (!ValidAddrSize)
+ note() << "The address size is unsupported.\n";
+ }
+ *Offset = OffsetStart + Length + 4;
+ return Success;
+}
+
+unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit) {
+ unsigned NumUnitErrors = 0;
+ unsigned NumDies = Unit.getNumDIEs();
+ for (unsigned I = 0; I < NumDies; ++I) {
+ auto Die = Unit.getDIEAtIndex(I);
+
+ if (Die.getTag() == DW_TAG_null)
+ continue;
+
+ bool HasTypeAttr = false;
+ for (auto AttrValue : Die.attributes()) {
+ NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
+ NumUnitErrors += verifyDebugInfoForm(Die, AttrValue);
+ HasTypeAttr |= (AttrValue.Attr == DW_AT_type);
+ }
+
+ if (!HasTypeAttr && (Die.getTag() == DW_TAG_formal_parameter ||
+ Die.getTag() == DW_TAG_variable ||
+ Die.getTag() == DW_TAG_array_type)) {
+ error() << "DIE with tag " << TagString(Die.getTag())
+ << " is missing type attribute:\n";
+ dump(Die) << '\n';
+ NumUnitErrors++;
+ }
+ NumUnitErrors += verifyDebugInfoCallSite(Die);
+ }
+
+ DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
+ if (!Die) {
+ error() << "Compilation unit without DIE.\n";
+ NumUnitErrors++;
+ return NumUnitErrors;
+ }
+
+ if (!dwarf::isUnitType(Die.getTag())) {
+ error() << "Compilation unit root DIE is not a unit DIE: "
+ << dwarf::TagString(Die.getTag()) << ".\n";
+ NumUnitErrors++;
+ }
+
+ uint8_t UnitType = Unit.getUnitType();
+ if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) {
+ error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType)
+ << ") and root DIE (" << dwarf::TagString(Die.getTag())
+ << ") do not match.\n";
+ NumUnitErrors++;
+ }
+
+ DieRangeInfo RI;
+ NumUnitErrors += verifyDieRanges(Die, RI);
+
+ return NumUnitErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) {
+ if (Die.getTag() != DW_TAG_call_site)
+ return 0;
+
+ DWARFDie Curr = Die.getParent();
+ for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()) {
+ if (Curr.getTag() == DW_TAG_inlined_subroutine) {
+ error() << "Call site entry nested within inlined subroutine:";
+ Curr.dump(OS);
+ return 1;
+ }
+ }
+
+ if (!Curr.isValid()) {
+ error() << "Call site entry not nested within a valid subprogram:";
+ Die.dump(OS);
+ return 1;
+ }
+
+ Optional<DWARFFormValue> CallAttr =
+ Curr.find({DW_AT_call_all_calls, DW_AT_call_all_source_calls,
+ DW_AT_call_all_tail_calls});
+ if (!CallAttr) {
+ error() << "Subprogram with call site entry has no DW_AT_call attribute:";
+ Curr.dump(OS);
+ Die.dump(OS, /*indent*/ 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
+ unsigned NumErrors = 0;
+ if (Abbrev) {
+ const DWARFAbbreviationDeclarationSet *AbbrDecls =
+ Abbrev->getAbbreviationDeclarationSet(0);
+ for (auto AbbrDecl : *AbbrDecls) {
+ SmallDenseSet<uint16_t> AttributeSet;
+ for (auto Attribute : AbbrDecl.attributes()) {
+ auto Result = AttributeSet.insert(Attribute.Attr);
+ if (!Result.second) {
+ error() << "Abbreviation declaration contains multiple "
+ << AttributeString(Attribute.Attr) << " attributes.\n";
+ AbbrDecl.dump(OS);
+ ++NumErrors;
+ }
+ }
+ }
+ }
+ return NumErrors;
+}
+
+bool DWARFVerifier::handleDebugAbbrev() {
+ OS << "Verifying .debug_abbrev...\n";
+
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ bool noDebugAbbrev = DObj.getAbbrevSection().empty();
+ bool noDebugAbbrevDWO = DObj.getAbbrevDWOSection().empty();
+
+ if (noDebugAbbrev && noDebugAbbrevDWO) {
+ return true;
+ }
+
+ unsigned NumErrors = 0;
+ if (!noDebugAbbrev)
+ NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
+
+ if (!noDebugAbbrevDWO)
+ NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
+ return NumErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S,
+ DWARFSectionKind SectionKind) {
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);
+ unsigned NumDebugInfoErrors = 0;
+ uint32_t OffsetStart = 0, Offset = 0, UnitIdx = 0;
+ uint8_t UnitType = 0;
+ bool isUnitDWARF64 = false;
+ bool isHeaderChainValid = true;
+ bool hasDIE = DebugInfoData.isValidOffset(Offset);
+ DWARFUnitVector TypeUnitVector;
+ DWARFUnitVector CompileUnitVector;
+ while (hasDIE) {
+ OffsetStart = Offset;
+ if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,
+ isUnitDWARF64)) {
+ isHeaderChainValid = false;
+ if (isUnitDWARF64)
+ break;
+ } else {
+ DWARFUnitHeader Header;
+ Header.extract(DCtx, DebugInfoData, &OffsetStart, SectionKind);
+ DWARFUnit *Unit;
+ switch (UnitType) {
+ case dwarf::DW_UT_type:
+ case dwarf::DW_UT_split_type: {
+ Unit = TypeUnitVector.addUnit(llvm::make_unique<DWARFTypeUnit>(
+ DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangeSection(),
+ &DObj.getLocSection(), DObj.getStringSection(),
+ DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
+ DObj.getLineSection(), DCtx.isLittleEndian(), false,
+ TypeUnitVector));
+ break;
+ }
+ case dwarf::DW_UT_skeleton:
+ case dwarf::DW_UT_split_compile:
+ case dwarf::DW_UT_compile:
+ case dwarf::DW_UT_partial:
+ // UnitType = 0 means that we are verifying a compile unit in DWARF v4.
+ case 0: {
+ Unit = CompileUnitVector.addUnit(llvm::make_unique<DWARFCompileUnit>(
+ DCtx, S, Header, DCtx.getDebugAbbrev(), &DObj.getRangeSection(),
+ &DObj.getLocSection(), DObj.getStringSection(),
+ DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
+ DObj.getLineSection(), DCtx.isLittleEndian(), false,
+ CompileUnitVector));
+ break;
+ }
+ default: { llvm_unreachable("Invalid UnitType."); }
+ }
+ NumDebugInfoErrors += verifyUnitContents(*Unit);
+ }
+ hasDIE = DebugInfoData.isValidOffset(Offset);
+ ++UnitIdx;
+ }
+ if (UnitIdx == 0 && !hasDIE) {
+ warn() << "Section is empty.\n";
+ isHeaderChainValid = true;
+ }
+ if (!isHeaderChainValid)
+ ++NumDebugInfoErrors;
+ NumDebugInfoErrors += verifyDebugInfoReferences();
+ return NumDebugInfoErrors;
+}
+
+bool DWARFVerifier::handleDebugInfo() {
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ unsigned NumErrors = 0;
+
+ OS << "Verifying .debug_info Unit Header Chain...\n";
+ DObj.forEachInfoSections([&](const DWARFSection &S) {
+ NumErrors += verifyUnitSection(S, DW_SECT_INFO);
+ });
+
+ OS << "Verifying .debug_types Unit Header Chain...\n";
+ DObj.forEachTypesSections([&](const DWARFSection &S) {
+ NumErrors += verifyUnitSection(S, DW_SECT_TYPES);
+ });
+ return NumErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
+ DieRangeInfo &ParentRI) {
+ unsigned NumErrors = 0;
+
+ if (!Die.isValid())
+ return NumErrors;
+
+ auto RangesOrError = Die.getAddressRanges();
+ if (!RangesOrError) {
+ // FIXME: Report the error.
+ ++NumErrors;
+ llvm::consumeError(RangesOrError.takeError());
+ return NumErrors;
+ }
+
+ DWARFAddressRangesVector Ranges = RangesOrError.get();
+ // Build RI for this DIE and check that ranges within this DIE do not
+ // overlap.
+ DieRangeInfo RI(Die);
+
+ // TODO support object files better
+ //
+ // Some object file formats (i.e. non-MachO) support COMDAT. ELF in
+ // particular does so by placing each function into a section. The DWARF data
+ // for the function at that point uses a section relative DW_FORM_addrp for
+ // the DW_AT_low_pc and a DW_FORM_data4 for the offset as the DW_AT_high_pc.
+ // In such a case, when the Die is the CU, the ranges will overlap, and we
+ // will flag valid conflicting ranges as invalid.
+ //
+ // For such targets, we should read the ranges from the CU and partition them
+ // by the section id. The ranges within a particular section should be
+ // disjoint, although the ranges across sections may overlap. We would map
+ // the child die to the entity that it references and the section with which
+ // it is associated. The child would then be checked against the range
+ // information for the associated section.
+ //
+ // For now, simply elide the range verification for the CU DIEs if we are
+ // processing an object file.
+
+ if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) {
+ for (auto Range : Ranges) {
+ if (!Range.valid()) {
+ ++NumErrors;
+ error() << "Invalid address range " << Range << "\n";
+ continue;
+ }
+
+ // Verify that ranges don't intersect.
+ const auto IntersectingRange = RI.insert(Range);
+ if (IntersectingRange != RI.Ranges.end()) {
+ ++NumErrors;
+ error() << "DIE has overlapping address ranges: " << Range << " and "
+ << *IntersectingRange << "\n";
+ break;
+ }
+ }
+ }
+
+ // Verify that children don't intersect.
+ const auto IntersectingChild = ParentRI.insert(RI);
+ if (IntersectingChild != ParentRI.Children.end()) {
+ ++NumErrors;
+ error() << "DIEs have overlapping address ranges:";
+ dump(Die);
+ dump(IntersectingChild->Die) << '\n';
+ }
+
+ // Verify that ranges are contained within their parent.
+ bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() &&
+ !(Die.getTag() == DW_TAG_subprogram &&
+ ParentRI.Die.getTag() == DW_TAG_subprogram);
+ if (ShouldBeContained && !ParentRI.contains(RI)) {
+ ++NumErrors;
+ error() << "DIE address ranges are not contained in its parent's ranges:";
+ dump(ParentRI.Die);
+ dump(Die, 2) << '\n';
+ }
+
+ // Recursively check children.
+ for (DWARFDie Child : Die)
+ NumErrors += verifyDieRanges(Child, RI);
+
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
+ DWARFAttribute &AttrValue) {
+ unsigned NumErrors = 0;
+ auto ReportError = [&](const Twine &TitleMsg) {
+ ++NumErrors;
+ error() << TitleMsg << '\n';
+ dump(Die) << '\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())
+ 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())
+ ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " +
+ llvm::formatv("{0:x8}", *SectionOffset));
+ break;
+ }
+ ReportError("DIE has invalid DW_AT_stmt_list encoding:");
+ break;
+ case DW_AT_location: {
+ auto VerifyLocationExpr = [&](StringRef D) {
+ DWARFUnit *U = Die.getDwarfUnit();
+ DataExtractor Data(D, 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:");
+ };
+ if (Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock()) {
+ // Verify inlined location.
+ VerifyLocationExpr(llvm::toStringRef(*Expr));
+ } else if (auto LocOffset = AttrValue.Value.getAsSectionOffset()) {
+ // Verify location list.
+ if (auto DebugLoc = DCtx.getDebugLoc())
+ if (auto LocList = DebugLoc->getLocationListAtOffset(*LocOffset))
+ for (const auto &Entry : LocList->Entries)
+ VerifyLocationExpr({Entry.Loc.data(), Entry.Loc.size()});
+ }
+ break;
+ }
+ case DW_AT_specification:
+ case DW_AT_abstract_origin: {
+ if (auto ReferencedDie = Die.getAttributeValueAsReferencedDie(Attr)) {
+ auto DieTag = Die.getTag();
+ auto RefTag = ReferencedDie.getTag();
+ if (DieTag == RefTag)
+ break;
+ if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
+ break;
+ if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
+ break;
+ ReportError("DIE with tag " + TagString(DieTag) + " has " +
+ AttributeString(Attr) +
+ " that points to DIE with "
+ "incompatible tag " +
+ TagString(RefTag));
+ }
+ break;
+ }
+ case DW_AT_type: {
+ DWARFDie TypeDie = Die.getAttributeValueAsReferencedDie(DW_AT_type);
+ if (TypeDie && !isType(TypeDie.getTag())) {
+ ReportError("DIE has " + AttributeString(Attr) +
+ " with incompatible tag " + TagString(TypeDie.getTag()));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
+ DWARFAttribute &AttrValue) {
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ auto DieCU = Die.getDwarfUnit();
+ unsigned NumErrors = 0;
+ const auto Form = AttrValue.Value.getForm();
+ switch (Form) {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata: {
+ // Verify all CU relative references are valid CU offsets.
+ Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
+ assert(RefVal);
+ if (RefVal) {
+ auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
+ auto CUOffset = AttrValue.Value.getRawUValue();
+ if (CUOffset >= CUSize) {
+ ++NumErrors;
+ error() << FormEncodingString(Form) << " CU offset "
+ << format("0x%08" PRIx64, CUOffset)
+ << " is invalid (must be less than CU size of "
+ << format("0x%08" PRIx32, CUSize) << "):\n";
+ Die.dump(OS, 0, DumpOpts);
+ dump(Die) << '\n';
+ } else {
+ // Valid reference, but we will verify it points to an actual
+ // DIE later.
+ ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
+ }
+ }
+ break;
+ }
+ case DW_FORM_ref_addr: {
+ // Verify all absolute DIE references have valid offsets in the
+ // .debug_info section.
+ Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
+ assert(RefVal);
+ if (RefVal) {
+ if (*RefVal >= DieCU->getInfoSection().Data.size()) {
+ ++NumErrors;
+ error() << "DW_FORM_ref_addr offset beyond .debug_info "
+ "bounds:\n";
+ dump(Die) << '\n';
+ } else {
+ // Valid reference, but we will verify it points to an actual
+ // DIE later.
+ ReferenceToDIEOffsets[*RefVal].insert(Die.getOffset());
+ }
+ }
+ break;
+ }
+ case DW_FORM_strp: {
+ auto SecOffset = AttrValue.Value.getAsSectionOffset();
+ assert(SecOffset); // DW_FORM_strp is a section offset.
+ if (SecOffset && *SecOffset >= DObj.getStringSection().size()) {
+ ++NumErrors;
+ error() << "DW_FORM_strp offset beyond .debug_str bounds:\n";
+ dump(Die) << '\n';
+ }
+ break;
+ }
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4: {
+ auto Index = AttrValue.Value.getRawUValue();
+ auto DieCU = Die.getDwarfUnit();
+ // Check that we have a valid DWARF v5 string offsets table.
+ if (!DieCU->getStringOffsetsTableContribution()) {
+ ++NumErrors;
+ error() << FormEncodingString(Form)
+ << " used without a valid string offsets table:\n";
+ dump(Die) << '\n';
+ break;
+ }
+ // Check that the index is within the bounds of the section.
+ unsigned ItemSize = DieCU->getDwarfStringOffsetsByteSize();
+ // Use a 64-bit type to calculate the offset to guard against overflow.
+ uint64_t Offset =
+ (uint64_t)DieCU->getStringOffsetsBase() + Index * ItemSize;
+ if (DObj.getStringOffsetSection().Data.size() < Offset + ItemSize) {
+ ++NumErrors;
+ error() << FormEncodingString(Form) << " uses index "
+ << format("%" PRIu64, Index) << ", which is too large:\n";
+ dump(Die) << '\n';
+ break;
+ }
+ // Check that the string offset is valid.
+ uint64_t StringOffset = *DieCU->getStringOffsetSectionItem(Index);
+ if (StringOffset >= DObj.getStringSection().size()) {
+ ++NumErrors;
+ error() << FormEncodingString(Form) << " uses index "
+ << format("%" PRIu64, Index)
+ << ", but the referenced string"
+ " offset is beyond .debug_str bounds:\n";
+ dump(Die) << '\n';
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoReferences() {
+ // Take all references and make sure they point to an actual DIE by
+ // getting the DIE by offset and emitting an error
+ OS << "Verifying .debug_info references...\n";
+ unsigned NumErrors = 0;
+ for (auto Pair : ReferenceToDIEOffsets) {
+ auto Die = DCtx.getDIEForOffset(Pair.first);
+ if (Die)
+ continue;
+ ++NumErrors;
+ error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
+ << ". Offset is in between DIEs:\n";
+ for (auto Offset : Pair.second)
+ dump(DCtx.getDIEForOffset(Offset)) << '\n';
+ OS << "\n";
+ }
+ return NumErrors;
+}
+
+void DWARFVerifier::verifyDebugLineStmtOffsets() {
+ std::map<uint64_t, DWARFDie> StmtListToDie;
+ for (const auto &CU : DCtx.compile_units()) {
+ auto Die = CU->getUnitDIE();
+ // Get the attribute value as a section offset. No need to produce an
+ // error here if the encoding isn't correct because we validate this in
+ // the .debug_info verifier.
+ auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
+ if (!StmtSectionOffset)
+ continue;
+ const uint32_t LineTableOffset = *StmtSectionOffset;
+ auto LineTable = DCtx.getLineTableForUnit(CU.get());
+ if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
+ if (!LineTable) {
+ ++NumDebugLineErrors;
+ error() << ".debug_line[" << format("0x%08" PRIx32, LineTableOffset)
+ << "] was not able to be parsed for CU:\n";
+ dump(Die) << '\n';
+ continue;
+ }
+ } else {
+ // Make sure we don't get a valid line table back if the offset is wrong.
+ assert(LineTable == nullptr);
+ // Skip this line table as it isn't valid. No need to create an error
+ // here because we validate this in the .debug_info verifier.
+ continue;
+ }
+ auto Iter = StmtListToDie.find(LineTableOffset);
+ if (Iter != StmtListToDie.end()) {
+ ++NumDebugLineErrors;
+ error() << "two compile unit DIEs, "
+ << format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
+ << format("0x%08" PRIx32, Die.getOffset())
+ << ", have the same DW_AT_stmt_list section offset:\n";
+ dump(Iter->second);
+ dump(Die) << '\n';
+ // Already verified this line table before, no need to do it again.
+ continue;
+ }
+ StmtListToDie[LineTableOffset] = Die;
+ }
+}
+
+void DWARFVerifier::verifyDebugLineRows() {
+ for (const auto &CU : DCtx.compile_units()) {
+ auto Die = CU->getUnitDIE();
+ auto LineTable = DCtx.getLineTableForUnit(CU.get());
+ // If there is no line table we will have created an error in the
+ // .debug_info verifier or in verifyDebugLineStmtOffsets().
+ if (!LineTable)
+ continue;
+
+ // Verify prologue.
+ uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
+ uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
+ uint32_t FileIndex = 1;
+ StringMap<uint16_t> FullPathMap;
+ for (const auto &FileName : LineTable->Prologue.FileNames) {
+ // Verify directory index.
+ if (FileName.DirIdx > MaxDirIndex) {
+ ++NumDebugLineErrors;
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "].prologue.file_names[" << FileIndex
+ << "].dir_idx contains an invalid index: " << FileName.DirIdx
+ << "\n";
+ }
+
+ // Check file paths for duplicates.
+ std::string FullPath;
+ const bool HasFullPath = LineTable->getFileNameByIndex(
+ FileIndex, CU->getCompilationDir(),
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
+ assert(HasFullPath && "Invalid index?");
+ (void)HasFullPath;
+ auto It = FullPathMap.find(FullPath);
+ if (It == FullPathMap.end())
+ FullPathMap[FullPath] = FileIndex;
+ else if (It->second != FileIndex) {
+ warn() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "].prologue.file_names[" << FileIndex
+ << "] is a duplicate of file_names[" << It->second << "]\n";
+ }
+
+ FileIndex++;
+ }
+
+ // Verify rows.
+ uint64_t PrevAddress = 0;
+ uint32_t RowIndex = 0;
+ for (const auto &Row : LineTable->Rows) {
+ // Verify row address.
+ if (Row.Address < PrevAddress) {
+ ++NumDebugLineErrors;
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "] row[" << RowIndex
+ << "] decreases in address from previous row:\n";
+
+ DWARFDebugLine::Row::dumpTableHeader(OS);
+ if (RowIndex > 0)
+ LineTable->Rows[RowIndex - 1].dump(OS);
+ Row.dump(OS);
+ OS << '\n';
+ }
+
+ // Verify file index.
+ if (Row.File > MaxFileIndex) {
+ ++NumDebugLineErrors;
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "][" << RowIndex << "] has invalid file index " << Row.File
+ << " (valid values are [1," << MaxFileIndex << "]):\n";
+ DWARFDebugLine::Row::dumpTableHeader(OS);
+ Row.dump(OS);
+ OS << '\n';
+ }
+ if (Row.EndSequence)
+ PrevAddress = 0;
+ else
+ PrevAddress = Row.Address;
+ ++RowIndex;
+ }
+ }
+}
+
+DWARFVerifier::DWARFVerifier(raw_ostream &S, DWARFContext &D,
+ DIDumpOptions DumpOpts)
+ : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false),
+ IsMachOObject(false) {
+ if (const auto *F = DCtx.getDWARFObj().getFile()) {
+ IsObjectFile = F->isRelocatableObject();
+ IsMachOObject = F->isMachO();
+ }
+}
+
+bool DWARFVerifier::handleDebugLine() {
+ NumDebugLineErrors = 0;
+ OS << "Verifying .debug_line...\n";
+ verifyDebugLineStmtOffsets();
+ verifyDebugLineRows();
+ return NumDebugLineErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
+ DataExtractor *StrData,
+ const char *SectionName) {
+ unsigned NumErrors = 0;
+ DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
+ DCtx.isLittleEndian(), 0);
+ AppleAcceleratorTable AccelTable(AccelSectionData, *StrData);
+
+ OS << "Verifying " << SectionName << "...\n";
+
+ // Verify that the fixed part of the header is not too short.
+ if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
+ error() << "Section is too small to fit a section header.\n";
+ return 1;
+ }
+
+ // Verify that the section is not too short.
+ if (Error E = AccelTable.extract()) {
+ error() << toString(std::move(E)) << '\n';
+ return 1;
+ }
+
+ // Verify that all buckets have a valid hash index or are empty.
+ uint32_t NumBuckets = AccelTable.getNumBuckets();
+ uint32_t NumHashes = AccelTable.getNumHashes();
+
+ uint32_t BucketsOffset =
+ AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
+ uint32_t HashesBase = BucketsOffset + NumBuckets * 4;
+ uint32_t OffsetsBase = HashesBase + NumHashes * 4;
+ for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
+ uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
+ if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
+ error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
+ HashIdx);
+ ++NumErrors;
+ }
+ }
+ uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
+ if (NumAtoms == 0) {
+ error() << "No atoms: failed to read HashData.\n";
+ return 1;
+ }
+ if (!AccelTable.validateForms()) {
+ error() << "Unsupported form: failed to read HashData.\n";
+ return 1;
+ }
+
+ for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
+ uint32_t HashOffset = HashesBase + 4 * HashIdx;
+ uint32_t DataOffset = OffsetsBase + 4 * HashIdx;
+ uint32_t Hash = AccelSectionData.getU32(&HashOffset);
+ uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
+ if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
+ sizeof(uint64_t))) {
+ error() << format("Hash[%d] has invalid HashData offset: 0x%08x.\n",
+ HashIdx, HashDataOffset);
+ ++NumErrors;
+ }
+
+ uint32_t StrpOffset;
+ uint32_t StringOffset;
+ uint32_t StringCount = 0;
+ unsigned Offset;
+ unsigned Tag;
+ while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
+ const uint32_t NumHashDataObjects =
+ AccelSectionData.getU32(&HashDataOffset);
+ for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
+ ++HashDataIdx) {
+ std::tie(Offset, Tag) = AccelTable.readAtoms(HashDataOffset);
+ auto Die = DCtx.getDIEForOffset(Offset);
+ if (!Die) {
+ const uint32_t BucketIdx =
+ NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
+ StringOffset = StrpOffset;
+ const char *Name = StrData->getCStr(&StringOffset);
+ if (!Name)
+ Name = "<NULL>";
+
+ error() << format(
+ "%s Bucket[%d] Hash[%d] = 0x%08x "
+ "Str[%u] = 0x%08x "
+ "DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n",
+ SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
+ HashDataIdx, Offset, Name);
+
+ ++NumErrors;
+ continue;
+ }
+ if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
+ error() << "Tag " << dwarf::TagString(Tag)
+ << " in accelerator table does not match Tag "
+ << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx
+ << "].\n";
+ ++NumErrors;
+ }
+ }
+ ++StringCount;
+ }
+ }
+ return NumErrors;
+}
+
+unsigned
+DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) {
+ // A map from CU offset to the (first) Name Index offset which claims to index
+ // this CU.
+ DenseMap<uint32_t, uint32_t> CUMap;
+ const uint32_t NotIndexed = std::numeric_limits<uint32_t>::max();
+
+ CUMap.reserve(DCtx.getNumCompileUnits());
+ for (const auto &CU : DCtx.compile_units())
+ CUMap[CU->getOffset()] = NotIndexed;
+
+ unsigned NumErrors = 0;
+ for (const DWARFDebugNames::NameIndex &NI : AccelTable) {
+ if (NI.getCUCount() == 0) {
+ error() << formatv("Name Index @ {0:x} does not index any CU\n",
+ NI.getUnitOffset());
+ ++NumErrors;
+ continue;
+ }
+ for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) {
+ uint32_t Offset = NI.getCUOffset(CU);
+ auto Iter = CUMap.find(Offset);
+
+ if (Iter == CUMap.end()) {
+ error() << formatv(
+ "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
+ NI.getUnitOffset(), Offset);
+ ++NumErrors;
+ continue;
+ }
+
+ if (Iter->second != NotIndexed) {
+ error() << formatv("Name Index @ {0:x} references a CU @ {1:x}, but "
+ "this CU is already indexed by Name Index @ {2:x}\n",
+ NI.getUnitOffset(), Offset, Iter->second);
+ continue;
+ }
+ Iter->second = NI.getUnitOffset();
+ }
+ }
+
+ for (const auto &KV : CUMap) {
+ if (KV.second == NotIndexed)
+ warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first);
+ }
+
+ return NumErrors;
+}
+
+unsigned
+DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
+ const DataExtractor &StrData) {
+ struct BucketInfo {
+ uint32_t Bucket;
+ uint32_t Index;
+
+ constexpr BucketInfo(uint32_t Bucket, uint32_t Index)
+ : Bucket(Bucket), Index(Index) {}
+ bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; };
+ };
+
+ uint32_t NumErrors = 0;
+ if (NI.getBucketCount() == 0) {
+ warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n",
+ NI.getUnitOffset());
+ return NumErrors;
+ }
+
+ // Build up a list of (Bucket, Index) pairs. We use this later to verify that
+ // each Name is reachable from the appropriate bucket.
+ std::vector<BucketInfo> BucketStarts;
+ BucketStarts.reserve(NI.getBucketCount() + 1);
+ for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) {
+ uint32_t Index = NI.getBucketArrayEntry(Bucket);
+ if (Index > NI.getNameCount()) {
+ error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid "
+ "value {2}. Valid range is [0, {3}].\n",
+ Bucket, NI.getUnitOffset(), Index, NI.getNameCount());
+ ++NumErrors;
+ continue;
+ }
+ if (Index > 0)
+ BucketStarts.emplace_back(Bucket, Index);
+ }
+
+ // If there were any buckets with invalid values, skip further checks as they
+ // will likely produce many errors which will only confuse the actual root
+ // problem.
+ if (NumErrors > 0)
+ return NumErrors;
+
+ // Sort the list in the order of increasing "Index" entries.
+ array_pod_sort(BucketStarts.begin(), BucketStarts.end());
+
+ // Insert a sentinel entry at the end, so we can check that the end of the
+ // table is covered in the loop below.
+ BucketStarts.emplace_back(NI.getBucketCount(), NI.getNameCount() + 1);
+
+ // Loop invariant: NextUncovered is the (1-based) index of the first Name
+ // which is not reachable by any of the buckets we processed so far (and
+ // hasn't been reported as uncovered).
+ uint32_t NextUncovered = 1;
+ for (const BucketInfo &B : BucketStarts) {
+ // Under normal circumstances B.Index be equal to NextUncovered, but it can
+ // be less if a bucket points to names which are already known to be in some
+ // bucket we processed earlier. In that case, we won't trigger this error,
+ // but report the mismatched hash value error instead. (We know the hash
+ // will not match because we have already verified that the name's hash
+ // puts it into the previous bucket.)
+ if (B.Index > NextUncovered) {
+ error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] "
+ "are not covered by the hash table.\n",
+ NI.getUnitOffset(), NextUncovered, B.Index - 1);
+ ++NumErrors;
+ }
+ uint32_t Idx = B.Index;
+
+ // The rest of the checks apply only to non-sentinel entries.
+ if (B.Bucket == NI.getBucketCount())
+ break;
+
+ // This triggers if a non-empty bucket points to a name with a mismatched
+ // hash. Clients are likely to interpret this as an empty bucket, because a
+ // mismatched hash signals the end of a bucket, but if this is indeed an
+ // empty bucket, the producer should have signalled this by marking the
+ // bucket as empty.
+ uint32_t FirstHash = NI.getHashArrayEntry(Idx);
+ if (FirstHash % NI.getBucketCount() != B.Bucket) {
+ error() << formatv(
+ "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
+ "mismatched hash value {2:x} (belonging to bucket {3}).\n",
+ NI.getUnitOffset(), B.Bucket, FirstHash,
+ FirstHash % NI.getBucketCount());
+ ++NumErrors;
+ }
+
+ // This find the end of this bucket and also verifies that all the hashes in
+ // this bucket are correct by comparing the stored hashes to the ones we
+ // compute ourselves.
+ while (Idx <= NI.getNameCount()) {
+ uint32_t Hash = NI.getHashArrayEntry(Idx);
+ if (Hash % NI.getBucketCount() != B.Bucket)
+ break;
+
+ const char *Str = NI.getNameTableEntry(Idx).getString();
+ if (caseFoldingDjbHash(Str) != Hash) {
+ error() << formatv("Name Index @ {0:x}: String ({1}) at index {2} "
+ "hashes to {3:x}, but "
+ "the Name Index hash is {4:x}\n",
+ NI.getUnitOffset(), Str, Idx,
+ caseFoldingDjbHash(Str), Hash);
+ ++NumErrors;
+ }
+
+ ++Idx;
+ }
+ NextUncovered = std::max(NextUncovered, Idx);
+ }
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyNameIndexAttribute(
+ const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr,
+ DWARFDebugNames::AttributeEncoding AttrEnc) {
+ StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form);
+ if (FormName.empty()) {
+ error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
+ "unknown form: {3}.\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
+ AttrEnc.Form);
+ return 1;
+ }
+
+ if (AttrEnc.Index == DW_IDX_type_hash) {
+ if (AttrEnc.Form != dwarf::DW_FORM_data8) {
+ error() << formatv(
+ "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
+ "uses an unexpected form {2} (should be {3}).\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8);
+ return 1;
+ }
+ }
+
+ // A list of known index attributes and their expected form classes.
+ // DW_IDX_type_hash is handled specially in the check above, as it has a
+ // specific form (not just a form class) we should expect.
+ struct FormClassTable {
+ dwarf::Index Index;
+ DWARFFormValue::FormClass Class;
+ StringLiteral ClassName;
+ };
+ static constexpr FormClassTable Table[] = {
+ {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}},
+ {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}},
+ {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}},
+ {dwarf::DW_IDX_parent, DWARFFormValue::FC_Constant, {"constant"}},
+ };
+
+ ArrayRef<FormClassTable> TableRef(Table);
+ auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) {
+ return T.Index == AttrEnc.Index;
+ });
+ if (Iter == TableRef.end()) {
+ warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an "
+ "unknown index attribute: {2}.\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Index);
+ return 0;
+ }
+
+ if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) {
+ error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
+ "unexpected form {3} (expected form class {4}).\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
+ AttrEnc.Form, Iter->ClassName);
+ return 1;
+ }
+ return 0;
+}
+
+unsigned
+DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
+ if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) {
+ warn() << formatv("Name Index @ {0:x}: Verifying indexes of type units is "
+ "not currently supported.\n",
+ NI.getUnitOffset());
+ return 0;
+ }
+
+ unsigned NumErrors = 0;
+ for (const auto &Abbrev : NI.getAbbrevs()) {
+ StringRef TagName = dwarf::TagString(Abbrev.Tag);
+ if (TagName.empty()) {
+ warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an "
+ "unknown tag: {2}.\n",
+ NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag);
+ }
+ SmallSet<unsigned, 5> Attributes;
+ for (const auto &AttrEnc : Abbrev.Attributes) {
+ if (!Attributes.insert(AttrEnc.Index).second) {
+ error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains "
+ "multiple {2} attributes.\n",
+ NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index);
+ ++NumErrors;
+ continue;
+ }
+ NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
+ }
+
+ if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit)) {
+ error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units "
+ "and abbreviation {1:x} has no {2} attribute.\n",
+ NI.getUnitOffset(), Abbrev.Code,
+ dwarf::DW_IDX_compile_unit);
+ ++NumErrors;
+ }
+ if (!Attributes.count(dwarf::DW_IDX_die_offset)) {
+ error() << formatv(
+ "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
+ NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset);
+ ++NumErrors;
+ }
+ }
+ return NumErrors;
+}
+
+static SmallVector<StringRef, 2> getNames(const DWARFDie &DIE,
+ bool IncludeLinkageName = true) {
+ SmallVector<StringRef, 2> Result;
+ if (const char *Str = DIE.getName(DINameKind::ShortName))
+ Result.emplace_back(Str);
+ else if (DIE.getTag() == dwarf::DW_TAG_namespace)
+ Result.emplace_back("(anonymous namespace)");
+
+ if (IncludeLinkageName) {
+ if (const char *Str = DIE.getName(DINameKind::LinkageName)) {
+ if (Result.empty() || Result[0] != Str)
+ Result.emplace_back(Str);
+ }
+ }
+
+ return Result;
+}
+
+unsigned DWARFVerifier::verifyNameIndexEntries(
+ const DWARFDebugNames::NameIndex &NI,
+ const DWARFDebugNames::NameTableEntry &NTE) {
+ // Verifying type unit indexes not supported.
+ if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0)
+ return 0;
+
+ const char *CStr = NTE.getString();
+ if (!CStr) {
+ error() << formatv(
+ "Name Index @ {0:x}: Unable to get string associated with name {1}.\n",
+ NI.getUnitOffset(), NTE.getIndex());
+ return 1;
+ }
+ StringRef Str(CStr);
+
+ unsigned NumErrors = 0;
+ unsigned NumEntries = 0;
+ uint32_t EntryID = NTE.getEntryOffset();
+ uint32_t NextEntryID = EntryID;
+ Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID);
+ for (; EntryOr; ++NumEntries, EntryID = NextEntryID,
+ EntryOr = NI.getEntry(&NextEntryID)) {
+ uint32_t CUIndex = *EntryOr->getCUIndex();
+ if (CUIndex > NI.getCUCount()) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
+ "invalid CU index ({2}).\n",
+ NI.getUnitOffset(), EntryID, CUIndex);
+ ++NumErrors;
+ continue;
+ }
+ uint32_t CUOffset = NI.getCUOffset(CUIndex);
+ uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset();
+ DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset);
+ if (!DIE) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "
+ "non-existing DIE @ {2:x}.\n",
+ NI.getUnitOffset(), EntryID, DIEOffset);
+ ++NumErrors;
+ continue;
+ }
+ if (DIE.getDwarfUnit()->getOffset() != CUOffset) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
+ "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
+ NI.getUnitOffset(), EntryID, DIEOffset, CUOffset,
+ DIE.getDwarfUnit()->getOffset());
+ ++NumErrors;
+ }
+ if (DIE.getTag() != EntryOr->tag()) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
+ "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
+ NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(),
+ DIE.getTag());
+ ++NumErrors;
+ }
+
+ auto EntryNames = getNames(DIE);
+ if (!is_contained(EntryNames, Str)) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
+ "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
+ NI.getUnitOffset(), EntryID, DIEOffset, Str,
+ make_range(EntryNames.begin(), EntryNames.end()));
+ ++NumErrors;
+ }
+ }
+ handleAllErrors(EntryOr.takeError(),
+ [&](const DWARFDebugNames::SentinelError &) {
+ if (NumEntries > 0)
+ return;
+ error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is "
+ "not associated with any entries.\n",
+ NI.getUnitOffset(), NTE.getIndex(), Str);
+ ++NumErrors;
+ },
+ [&](const ErrorInfoBase &Info) {
+ error()
+ << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n",
+ NI.getUnitOffset(), NTE.getIndex(), Str,
+ Info.message());
+ ++NumErrors;
+ });
+ return NumErrors;
+}
+
+static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) {
+ Optional<DWARFFormValue> Location = Die.findRecursively(DW_AT_location);
+ if (!Location)
+ return false;
+
+ auto ContainsInterestingOperators = [&](StringRef D) {
+ DWARFUnit *U = Die.getDwarfUnit();
+ DataExtractor Data(D, DCtx.isLittleEndian(), U->getAddressByteSize());
+ DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
+ return any_of(Expression, [](DWARFExpression::Operation &Op) {
+ return !Op.isError() && (Op.getCode() == DW_OP_addr ||
+ Op.getCode() == DW_OP_form_tls_address ||
+ Op.getCode() == DW_OP_GNU_push_tls_address);
+ });
+ };
+
+ if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) {
+ // Inlined location.
+ if (ContainsInterestingOperators(toStringRef(*Expr)))
+ return true;
+ } else if (Optional<uint64_t> Offset = Location->getAsSectionOffset()) {
+ // Location list.
+ if (const DWARFDebugLoc *DebugLoc = DCtx.getDebugLoc()) {
+ if (const DWARFDebugLoc::LocationList *LocList =
+ DebugLoc->getLocationListAtOffset(*Offset)) {
+ if (any_of(LocList->Entries, [&](const DWARFDebugLoc::Entry &E) {
+ return ContainsInterestingOperators({E.Loc.data(), E.Loc.size()});
+ }))
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+unsigned DWARFVerifier::verifyNameIndexCompleteness(
+ const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) {
+
+ // First check, if the Die should be indexed. The code follows the DWARF v5
+ // wording as closely as possible.
+
+ // "All non-defining declarations (that is, debugging information entries
+ // with a DW_AT_declaration attribute) are excluded."
+ if (Die.find(DW_AT_declaration))
+ return 0;
+
+ // "DW_TAG_namespace debugging information entries without a DW_AT_name
+ // attribute are included with the name “(anonymous namespace)”.
+ // All other debugging information entries without a DW_AT_name attribute
+ // are excluded."
+ // "If a subprogram or inlined subroutine is included, and has a
+ // DW_AT_linkage_name attribute, there will be an additional index entry for
+ // the linkage name."
+ auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram ||
+ Die.getTag() == DW_TAG_inlined_subroutine;
+ auto EntryNames = getNames(Die, IncludeLinkageName);
+ if (EntryNames.empty())
+ return 0;
+
+ // We deviate from the specification here, which says:
+ // "The name index must contain an entry for each debugging information entry
+ // that defines a named subprogram, label, variable, type, or namespace,
+ // subject to ..."
+ // Instead whitelisting all TAGs representing a "type" or a "subprogram", to
+ // make sure we catch any missing items, we instead blacklist all TAGs that we
+ // know shouldn't be indexed.
+ switch (Die.getTag()) {
+ // Compile units and modules have names but shouldn't be indexed.
+ case DW_TAG_compile_unit:
+ case DW_TAG_module:
+ return 0;
+
+ // Function and template parameters are not globally visible, so we shouldn't
+ // index them.
+ case DW_TAG_formal_parameter:
+ case DW_TAG_template_value_parameter:
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_GNU_template_parameter_pack:
+ case DW_TAG_GNU_template_template_param:
+ return 0;
+
+ // Object members aren't globally visible.
+ case DW_TAG_member:
+ return 0;
+
+ // According to a strict reading of the specification, enumerators should not
+ // be indexed (and LLVM currently does not do that). However, this causes
+ // problems for the debuggers, so we may need to reconsider this.
+ case DW_TAG_enumerator:
+ return 0;
+
+ // Imported declarations should not be indexed according to the specification
+ // and LLVM currently does not do that.
+ case DW_TAG_imported_declaration:
+ return 0;
+
+ // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging
+ // information entries without an address attribute (DW_AT_low_pc,
+ // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded."
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_label:
+ if (Die.findRecursively(
+ {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
+ break;
+ return 0;
+
+ // "DW_TAG_variable debugging information entries with a DW_AT_location
+ // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are
+ // included; otherwise, they are excluded."
+ //
+ // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list.
+ case DW_TAG_variable:
+ if (isVariableIndexable(Die, DCtx))
+ break;
+ return 0;
+
+ default:
+ break;
+ }
+
+ // Now we know that our Die should be present in the Index. Let's check if
+ // that's the case.
+ unsigned NumErrors = 0;
+ uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset();
+ for (StringRef Name : EntryNames) {
+ if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) {
+ return E.getDIEUnitOffset() == DieUnitOffset;
+ })) {
+ error() << formatv("Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
+ "name {3} missing.\n",
+ NI.getUnitOffset(), Die.getOffset(), Die.getTag(),
+ Name);
+ ++NumErrors;
+ }
+ }
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
+ const DataExtractor &StrData) {
+ unsigned NumErrors = 0;
+ DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
+ DCtx.isLittleEndian(), 0);
+ DWARFDebugNames AccelTable(AccelSectionData, StrData);
+
+ OS << "Verifying .debug_names...\n";
+
+ // This verifies that we can read individual name indices and their
+ // abbreviation tables.
+ if (Error E = AccelTable.extract()) {
+ error() << toString(std::move(E)) << '\n';
+ return 1;
+ }
+
+ NumErrors += verifyDebugNamesCULists(AccelTable);
+ for (const auto &NI : AccelTable)
+ NumErrors += verifyNameIndexBuckets(NI, StrData);
+ for (const auto &NI : AccelTable)
+ NumErrors += verifyNameIndexAbbrevs(NI);
+
+ // Don't attempt Entry validation if any of the previous checks found errors
+ if (NumErrors > 0)
+ return NumErrors;
+ for (const auto &NI : AccelTable)
+ for (DWARFDebugNames::NameTableEntry NTE : NI)
+ NumErrors += verifyNameIndexEntries(NI, NTE);
+
+ if (NumErrors > 0)
+ return NumErrors;
+
+ for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units()) {
+ if (const DWARFDebugNames::NameIndex *NI =
+ AccelTable.getCUNameIndex(U->getOffset())) {
+ auto *CU = cast<DWARFCompileUnit>(U.get());
+ for (const DWARFDebugInfoEntry &Die : CU->dies())
+ NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI);
+ }
+ }
+ return NumErrors;
+}
+
+bool DWARFVerifier::handleAccelTables() {
+ const DWARFObject &D = DCtx.getDWARFObj();
+ DataExtractor StrData(D.getStringSection(), DCtx.isLittleEndian(), 0);
+ unsigned NumErrors = 0;
+ if (!D.getAppleNamesSection().Data.empty())
+ NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData,
+ ".apple_names");
+ if (!D.getAppleTypesSection().Data.empty())
+ NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData,
+ ".apple_types");
+ if (!D.getAppleNamespacesSection().Data.empty())
+ NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData,
+ ".apple_namespaces");
+ if (!D.getAppleObjCSection().Data.empty())
+ NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData,
+ ".apple_objc");
+
+ if (!D.getDebugNamesSection().Data.empty())
+ NumErrors += verifyDebugNames(D.getDebugNamesSection(), StrData);
+ return NumErrors == 0;
+}
+
+raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); }
+
+raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); }
+
+raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); }
+
+raw_ostream &DWARFVerifier::dump(const DWARFDie &Die, unsigned indent) const {
+ Die.dump(OS, indent, DumpOpts);
+ return OS;
+}