aboutsummaryrefslogtreecommitdiff
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.cpp26
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp803
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFAddressRange.cpp29
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp7
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp267
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp69
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp13
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp2
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp550
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp387
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp25
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp5
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp2
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp25
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp205
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp165
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp5
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp210
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp109
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp21
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp671
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp643
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp43
-rw-r--r--contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h52
24 files changed, 2870 insertions, 1464 deletions
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
index f593953c62ff..adada672af00 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -16,6 +16,7 @@
#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>
@@ -96,8 +97,7 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data,
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 =
- DWARFFormValue::getFixedByteSize(F, DWARFFormParams()))) {
+ if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
if (FixedAttributeSize)
FixedAttributeSize->NumBytes += *ByteSize;
break;
@@ -127,26 +127,11 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data,
}
void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
- auto tagString = TagString(getTag());
OS << '[' << getCode() << "] ";
- if (!tagString.empty())
- OS << tagString;
- else
- OS << format("DW_TAG_Unknown_%x", getTag());
+ OS << formatv("{0}", getTag());
OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
for (const AttributeSpec &Spec : AttributeSpecs) {
- OS << '\t';
- auto attrString = AttributeString(Spec.Attr);
- if (!attrString.empty())
- OS << attrString;
- else
- OS << format("DW_AT_Unknown_%x", Spec.Attr);
- OS << '\t';
- auto formString = FormEncodingString(Spec.Form);
- if (!formString.empty())
- OS << formString;
- else
- OS << format("DW_FORM_Unknown_%x", Spec.Form);
+ OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
if (Spec.isImplicitConst())
OS << '\t' << Spec.getImplicitConstValue();
OS << '\n';
@@ -217,8 +202,7 @@ Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
if (ByteSize.HasByteSize)
return ByteSize.ByteSize;
Optional<int64_t> S;
- auto FixedByteSize =
- DWARFFormValue::getFixedByteSize(Form, U.getFormParams());
+ auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
if (FixedByteSize)
S = *FixedByteSize;
return S;
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 6a6b7fc6fc20..4582e036f9fc 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -13,7 +13,10 @@
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DJB.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>
@@ -21,7 +24,24 @@
using namespace llvm;
-llvm::Error DWARFAcceleratorTable::extract() {
+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.
@@ -32,8 +52,8 @@ llvm::Error DWARFAcceleratorTable::extract() {
Hdr.Magic = AccelSection.getU32(&Offset);
Hdr.Version = AccelSection.getU16(&Offset);
Hdr.HashFunction = AccelSection.getU16(&Offset);
- Hdr.NumBuckets = AccelSection.getU32(&Offset);
- Hdr.NumHashes = AccelSection.getU32(&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
@@ -41,7 +61,7 @@ llvm::Error DWARFAcceleratorTable::extract() {
// 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.NumBuckets * 4 + Hdr.NumHashes * 8 - 1))
+ Hdr.BucketCount * 4 + Hdr.HashCount * 8 - 1))
return make_error<StringError>(
"Section too small: cannot read buckets and hashes.",
inconvertibleErrorCode());
@@ -59,20 +79,20 @@ llvm::Error DWARFAcceleratorTable::extract() {
return Error::success();
}
-uint32_t DWARFAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; }
-uint32_t DWARFAcceleratorTable::getNumHashes() { return Hdr.NumHashes; }
-uint32_t DWARFAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
-uint32_t DWARFAcceleratorTable::getHeaderDataLength() {
+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<DWARFAcceleratorTable::HeaderData::AtomType,
- DWARFAcceleratorTable::HeaderData::Form>>
-DWARFAcceleratorTable::getAtomsDesc() {
+ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,
+ AppleAcceleratorTable::HeaderData::Form>>
+AppleAcceleratorTable::getAtomsDesc() {
return HdrData.Atoms;
}
-bool DWARFAcceleratorTable::validateForms() {
+bool AppleAcceleratorTable::validateForms() {
for (auto Atom : getAtomsDesc()) {
DWARFFormValue FormValue(Atom.second);
switch (Atom.first) {
@@ -92,10 +112,10 @@ bool DWARFAcceleratorTable::validateForms() {
}
std::pair<uint32_t, dwarf::Tag>
-DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
+AppleAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
dwarf::Tag DieTag = dwarf::DW_TAG_null;
- DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+ dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
for (auto Atom : getAtomsDesc()) {
DWARFFormValue FormValue(Atom.second);
@@ -114,144 +134,219 @@ DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
return {DieOffset, DieTag};
}
-LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const {
+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;
- // Dump the header.
- OS << "Magic = " << format("0x%08x", Hdr.Magic) << '\n'
- << "Version = " << format("0x%04x", Hdr.Version) << '\n'
- << "Hash function = " << format("0x%08x", Hdr.HashFunction) << '\n'
- << "Bucket count = " << Hdr.NumBuckets << '\n'
- << "Hashes count = " << Hdr.NumHashes << '\n'
- << "HeaderData length = " << Hdr.HeaderDataLength << '\n'
- << "DIE offset base = " << HdrData.DIEOffsetBase << '\n'
- << "Number of atoms = " << HdrData.Atoms.size() << '\n';
-
- unsigned i = 0;
+ 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;
- for (const auto &Atom: HdrData.Atoms) {
- OS << format("Atom[%d] Type: ", i++);
- auto TypeString = dwarf::AtomTypeString(Atom.first);
- if (!TypeString.empty())
- OS << TypeString;
- else
- OS << format("DW_ATOM_Unknown_0x%x", Atom.first);
- OS << " Form: ";
- auto FormString = dwarf::FormEncodingString(Atom.second);
- if (!FormString.empty())
- OS << FormString;
- else
- OS << format("DW_FORM_Unknown_0x%x", Atom.second);
- OS << '\n';
- AtomForms.push_back(DWARFFormValue(Atom.second));
+ {
+ 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.NumBuckets * 4;
- unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
- DWARFFormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+ unsigned HashesBase = Offset + Hdr.BucketCount * 4;
+ unsigned OffsetsBase = HashesBase + Hdr.HashCount * 4;
- for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) {
+ for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) {
unsigned Index = AccelSection.getU32(&Offset);
- OS << format("Bucket[%d]\n", Bucket);
+ ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
if (Index == UINT32_MAX) {
- OS << " EMPTY\n";
+ W.printString("EMPTY");
continue;
}
- for (unsigned HashIdx = Index; HashIdx < Hdr.NumHashes; ++HashIdx) {
+ 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.NumBuckets != Bucket)
+ if (Hash % Hdr.BucketCount != Bucket)
break;
unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
- OS << format(" Hash = 0x%08x Offset = 0x%08x\n", Hash, DataOffset);
+ ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str());
if (!AccelSection.isValidOffset(DataOffset)) {
- OS << " Invalid section offset\n";
+ W.printString("Invalid section offset");
continue;
}
- while (AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
- unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
- if (!StringOffset)
- break;
- OS << format(" Name: %08x \"%s\"\n", StringOffset,
- StringSection.getCStr(&StringOffset));
- unsigned NumData = AccelSection.getU32(&DataOffset);
- for (unsigned Data = 0; Data < NumData; ++Data) {
- OS << format(" Data[%d] => ", Data);
- unsigned i = 0;
- for (auto &Atom : AtomForms) {
- OS << format("{Atom[%d]: ", i++);
- if (Atom.extractValue(AccelSection, &DataOffset, FormParams))
- Atom.dump(OS);
- else
- OS << "Error extracting the value";
- OS << "} ";
- }
- OS << '\n';
- }
- }
+ while (dumpName(W, AtomForms, &DataOffset))
+ /*empty*/;
}
}
}
-DWARFAcceleratorTable::ValueIterator::ValueIterator(
- const DWARFAcceleratorTable &AccelTable, unsigned Offset)
- : AccelTable(&AccelTable), DataOffset(Offset) {
+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;
- for (const auto &Atom : AccelTable.HdrData.Atoms)
- AtomForms.push_back(DWARFFormValue(Atom.second));
-
// Read the first entry.
NumData = AccelTable.AccelSection.getU32(&DataOffset);
Next();
}
-void DWARFAcceleratorTable::ValueIterator::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;
}
- DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0,
- dwarf::DwarfFormat::DWARF32};
- for (auto &Atom : AtomForms)
- Atom.extractValue(AccelSection, &DataOffset, FormParams);
+ Current.extract(*AccelTable, &DataOffset);
++Data;
}
-iterator_range<DWARFAcceleratorTable::ValueIterator>
-DWARFAcceleratorTable::equal_range(StringRef Key) const {
+iterator_range<AppleAcceleratorTable::ValueIterator>
+AppleAcceleratorTable::equal_range(StringRef Key) const {
if (!IsValid)
return make_range(ValueIterator(), ValueIterator());
// Find the bucket.
- unsigned HashValue = dwarf::djbHash(Key);
- unsigned Bucket = HashValue % Hdr.NumBuckets;
+ unsigned HashValue = djbHash(Key);
+ unsigned Bucket = HashValue % Hdr.BucketCount;
unsigned BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
- unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4;
- unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 4;
+ 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.NumHashes; ++HashIdx) {
+ 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.NumBuckets != Bucket)
+ if (Hash % Hdr.BucketCount != Bucket)
// We are already in the next bucket.
break;
@@ -266,3 +361,529 @@ DWARFAcceleratorTable::equal_range(StringRef Key) const {
}
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 make_error<StringError>("Section too small: cannot read header.",
+ inconvertibleErrorCode());
+
+ 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 make_error<StringError>(
+ "Section too small: cannot read header augmentation.",
+ inconvertibleErrorCode());
+ 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 make_error<StringError>("Incorrectly terminated abbreviation table.",
+ inconvertibleErrorCode());
+ }
+
+ 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 make_error<StringError>("Incorrectly terminated abbreviation table.",
+ inconvertibleErrorCode());
+ }
+
+ 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 make_error<StringError>(
+ "Section too small: cannot read abbreviations.",
+ inconvertibleErrorCode());
+
+ 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 make_error<StringError>("Duplicate abbreviation code.",
+ inconvertibleErrorCode());
+ }
+ }
+}
+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 make_error<StringError>("Incorrectly terminated entry list.",
+ inconvertibleErrorCode());
+
+ 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 make_error<StringError>("Invalid abbreviation.",
+ inconvertibleErrorCode());
+
+ 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 make_error<StringError>("Error extracting index attribute values.",
+ inconvertibleErrorCode());
+ }
+ 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
index 43b235621d18..00a23b3898fa 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
@@ -22,9 +22,10 @@ void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
if (getVersion() >= 5)
OS << " unit_type = " << dwarf::UnitTypeString(getUnitType());
OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset())
- << " addr_size = " << format("0x%02x", getAddressByteSize())
- << " (next unit at " << format("0x%08x", getNextUnitOffset())
- << ")\n";
+ << " 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);
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index eb23ca8229a3..da13c5047f77 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -25,6 +25,7 @@
#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"
@@ -43,9 +44,11 @@
#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>
@@ -82,7 +85,8 @@ static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) {
OS << "UUID: ";
memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID));
OS.write_uuid(UUID);
- OS << ' ' << MachO->getFileFormatName();
+ Triple T = MachO->getArchTriple();
+ OS << " (" << T.getArchName() << ')';
OS << ' ' << MachO->getFileName() << '\n';
}
}
@@ -106,12 +110,12 @@ collectContributionData(DWARFContext::cu_iterator_range CUs,
// Sort the contributions so that any invalid ones are placed at
// the start of the contributions vector. This way they are reported
// first.
- std::sort(Contributions.begin(), Contributions.end(),
- [](const Optional<StrOffsetsContributionDescriptor> &L,
- const Optional<StrOffsetsContributionDescriptor> &R) {
- if (L && R) return L->Base < R->Base;
- return R.hasValue();
- });
+ llvm::sort(Contributions.begin(), Contributions.end(),
+ [](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
@@ -169,7 +173,11 @@ static void dumpDWARFv5StringOffsetsSection(
OS << (ContributionHeader - Offset) << "\n";
}
OS << format("0x%8.8x: ", (uint32_t)ContributionHeader);
- OS << "Contribution size = " << Contribution->Size
+ // 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";
@@ -241,26 +249,26 @@ static void dumpStringOffsetsSection(
}
}
-// 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.
-typedef std::map<uint64_t, DWARFUnit *> LineToUnitMap;
-
-static LineToUnitMap
-buildLineToUnitMap(DWARFContext::cu_iterator_range CUs,
- DWARFContext::tu_section_iterator_range TUSections) {
- 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 &TUS : TUSections)
- 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;
+// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
+static void dumpRnglistsSection(raw_ostream &OS,
+ DWARFDataExtractor &rnglistData,
+ 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, DumpOpts);
+ }
+ }
}
void DWARFContext::dump(
@@ -347,11 +355,11 @@ void DWARFContext::dump(
if (shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
DObj->getDebugFrameSection()))
- getDebugFrame()->dump(OS, DumpOffset);
+ getDebugFrame()->dump(OS, getRegisterInfo(), DumpOffset);
if (shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
DObj->getEHFrameSection()))
- getEHFrame()->dump(OS, DumpOffset);
+ getEHFrame()->dump(OS, getRegisterInfo(), DumpOffset);
if (DumpType & DIDT_DebugMacro) {
if (Explicit || !getDebugMacro()->empty()) {
@@ -369,63 +377,39 @@ void DWARFContext::dump(
set.dump(OS);
}
- if (shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine,
- DObj->getLineSection().Data)) {
- LineToUnitMap LineToUnit =
- buildLineToUnitMap(compile_units(), type_unit_sections());
- unsigned Offset = 0;
- DWARFDataExtractor LineData(*DObj, DObj->getLineSection(), isLittleEndian(),
- 0);
- while (Offset < LineData.getData().size()) {
- DWARFUnit *U = nullptr;
- auto It = LineToUnit.find(Offset);
- if (It != LineToUnit.end())
- U = It->second;
- LineData.setAddressSize(U ? U->getAddressByteSize() : 0);
- DWARFDebugLine::LineTable LineTable;
- if (DumpOffset && Offset != *DumpOffset) {
- // Find the size of this part of the line table section and skip it.
- unsigned OldOffset = Offset;
- LineTable.Prologue.parse(LineData, &Offset, U);
- Offset = OldOffset + LineTable.Prologue.TotalLength +
- LineTable.Prologue.sizeofTotalLength();
+ auto DumpLineSection = [&](DWARFDebugLine::SectionParser Parser,
+ DIDumpOptions DumpOpts) {
+ while (!Parser.done()) {
+ if (DumpOffset && Parser.getOffset() != *DumpOffset) {
+ Parser.skip();
continue;
}
- // Verbose dumping is done during parsing and not on the intermediate
- // representation.
- OS << "debug_line[" << format("0x%8.8x", Offset) << "]\n";
- unsigned OldOffset = Offset;
+ OS << "debug_line[" << format("0x%8.8x", Parser.getOffset()) << "]\n";
if (DumpOpts.Verbose) {
- LineTable.parse(LineData, &Offset, U, &OS);
+ Parser.parseNext(DWARFDebugLine::warn, DWARFDebugLine::warn, &OS);
} else {
- LineTable.parse(LineData, &Offset, U);
- LineTable.dump(OS);
+ DWARFDebugLine::LineTable LineTable = Parser.parseNext();
+ LineTable.dump(OS, DumpOpts);
}
- // Check for unparseable prologue, to avoid infinite loops.
- if (OldOffset == Offset)
- break;
}
+ };
+
+ if (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_unit_sections());
+ DumpLineSection(Parser, DumpOpts);
}
if (shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine,
DObj->getLineDWOSection().Data)) {
- LineToUnitMap LineToUnit =
- buildLineToUnitMap(dwo_compile_units(), dwo_type_unit_sections());
- unsigned Offset = 0;
DWARFDataExtractor LineData(*DObj, DObj->getLineDWOSection(),
isLittleEndian(), 0);
- while (Offset < LineData.getData().size()) {
- DWARFUnit *U = nullptr;
- auto It = LineToUnit.find(Offset);
- if (It != LineToUnit.end())
- U = It->second;
- DWARFDebugLine::LineTable LineTable;
- unsigned OldOffset = Offset;
- if (!LineTable.Prologue.parse(LineData, &Offset, U))
- break;
- if (!DumpOffset || OldOffset == *DumpOffset)
- LineTable.dump(OS);
- }
+ DWARFDebugLine::SectionParser Parser(LineData, *this, dwo_compile_units(),
+ dwo_type_unit_sections());
+ DumpLineSection(Parser, DumpOpts);
}
if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex,
@@ -458,6 +442,18 @@ void DWARFContext::dump(
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_ranges", DIDT_ID_DebugRanges,
DObj->getRangeSection().Data)) {
@@ -475,8 +471,27 @@ void DWARFContext::dump(
isLittleEndian(), savedAddressByteSize);
uint32_t offset = 0;
DWARFDebugRangeList rangeList;
- while (rangeList.extract(rangesData, &offset))
+ while (rangesData.isValidOffset(offset)) {
+ if (Error E = rangeList.extract(rangesData, &offset)) {
+ WithColor::error() << toString(std::move(E)) << '\n';
+ break;
+ }
rangeList.dump(OS);
+ }
+ }
+
+ if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
+ DObj->getRnglistsSection().Data)) {
+ DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(),
+ isLittleEndian(), 0);
+ dumpRnglistsSection(OS, RnglistData, DumpOpts);
+ }
+
+ if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists,
+ DObj->getRnglistsDWOSection().Data)) {
+ DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
+ isLittleEndian(), 0);
+ dumpRnglistsSection(OS, RnglistData, DumpOpts);
}
if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
@@ -534,6 +549,9 @@ void DWARFContext::dump(
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) {
@@ -549,9 +567,19 @@ DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
// 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())
+ 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 DWOCU.get();
+ }
return nullptr;
}
@@ -633,7 +661,7 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() {
return Loc.get();
Loc.reset(new DWARFDebugLoc);
- // assume all compile units have the same address byte size
+ // Assume all compile units have the same address byte size.
if (getNumCompileUnits()) {
DWARFDataExtractor LocData(*DObj, DObj->getLocSection(), isLittleEndian(),
getCompileUnitAtIndex(0)->getAddressByteSize());
@@ -646,9 +674,13 @@ const DWARFDebugLocDWO *DWARFContext::getDebugLocDWO() {
if (LocDWO)
return LocDWO.get();
- DataExtractor LocData(DObj->getLocDWOSection().Data, isLittleEndian(), 0);
LocDWO.reset(new DWARFDebugLocDWO());
- LocDWO->parse(LocData);
+ // Assume all compile units have the same address byte size.
+ if (getNumCompileUnits()) {
+ DataExtractor LocData(DObj->getLocDWOSection().Data, isLittleEndian(),
+ getCompileUnitAtIndex(0)->getAddressByteSize());
+ LocDWO->parse(LocData);
+ }
return LocDWO.get();
}
@@ -674,8 +706,8 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
// 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
- DataExtractor debugFrameData(DObj->getDebugFrameSection(), isLittleEndian(),
- DObj->getAddressSize());
+ DWARFDataExtractor debugFrameData(DObj->getDebugFrameSection(),
+ isLittleEndian(), DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
@@ -685,8 +717,8 @@ const DWARFDebugFrame *DWARFContext::getEHFrame() {
if (EHFrame)
return EHFrame.get();
- DataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(),
- DObj->getAddressSize());
+ DWARFDataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(),
+ DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
@@ -702,43 +734,59 @@ const DWARFDebugMacro *DWARFContext::getDebugMacro() {
return Macro.get();
}
-static DWARFAcceleratorTable &
-getAccelTable(std::unique_ptr<DWARFAcceleratorTable> &Cache,
- const DWARFObject &Obj, const DWARFSection &Section,
- StringRef StringSection, bool IsLittleEndian) {
+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 DWARFAcceleratorTable(AccelSection, StrData));
+ Cache.reset(new T(AccelSection, StrData));
if (Error E = Cache->extract())
llvm::consumeError(std::move(E));
return *Cache;
}
-const DWARFAcceleratorTable &DWARFContext::getAppleNames() {
+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 DWARFAcceleratorTable &DWARFContext::getAppleTypes() {
+const AppleAcceleratorTable &DWARFContext::getAppleTypes() {
return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(),
DObj->getStringSection(), isLittleEndian());
}
-const DWARFAcceleratorTable &DWARFContext::getAppleNamespaces() {
+const AppleAcceleratorTable &DWARFContext::getAppleNamespaces() {
return getAccelTable(AppleNamespaces, *DObj,
DObj->getAppleNamespacesSection(),
DObj->getStringSection(), isLittleEndian());
}
-const DWARFAcceleratorTable &DWARFContext::getAppleObjC() {
+const AppleAcceleratorTable &DWARFContext::getAppleObjC() {
return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(),
DObj->getStringSection(), isLittleEndian());
}
-const DWARFLineTable *
+const DWARFDebugLine::LineTable *
DWARFContext::getLineTableForUnit(DWARFUnit *U) {
+ Expected<const DWARFDebugLine::LineTable *> ExpectedLineTable =
+ getLineTableForUnit(U, DWARFDebugLine::warn);
+ if (!ExpectedLineTable) {
+ DWARFDebugLine::warn(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);
@@ -762,7 +810,8 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) {
// We have to parse it first.
DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(),
U->getAddressByteSize());
- return Line->getOrParseLineTable(lineData, stmtOffset, U);
+ return Line->getOrParseLineTable(lineData, stmtOffset, *this, U,
+ RecoverableErrorCallback);
}
void DWARFContext::parseCompileUnits() {
@@ -1119,7 +1168,7 @@ static bool isRelocScattered(const object::ObjectFile &Obj,
}
ErrorPolicy DWARFContext::defaultErrorHandler(Error E) {
- errs() << "error: " + toString(std::move(E)) << '\n';
+ WithColor::error() << toString(std::move(E)) << '\n';
return ErrorPolicy::Continue;
}
@@ -1145,17 +1194,20 @@ class DWARFObjInMemory final : public DWARFObject {
DWARFSectionMap LocSection;
DWARFSectionMap LineSection;
DWARFSectionMap RangeSection;
+ DWARFSectionMap RnglistsSection;
DWARFSectionMap StringOffsetSection;
DWARFSectionMap InfoDWOSection;
DWARFSectionMap LineDWOSection;
DWARFSectionMap LocDWOSection;
DWARFSectionMap StringOffsetDWOSection;
DWARFSectionMap RangeDWOSection;
+ DWARFSectionMap RnglistsDWOSection;
DWARFSectionMap AddrSection;
DWARFSectionMap AppleNamesSection;
DWARFSectionMap AppleTypesSection;
DWARFSectionMap AppleNamespacesSection;
DWARFSectionMap AppleObjCSection;
+ DWARFSectionMap DebugNamesSection;
DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
return StringSwitch<DWARFSectionMap *>(Name)
@@ -1164,9 +1216,12 @@ class DWARFObjInMemory final : public DWARFObject {
.Case("debug_line", &LineSection)
.Case("debug_str_offsets", &StringOffsetSection)
.Case("debug_ranges", &RangeSection)
+ .Case("debug_rnglists", &RnglistsSection)
.Case("debug_info.dwo", &InfoDWOSection)
.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)
@@ -1192,8 +1247,11 @@ class DWARFObjInMemory final : public DWARFObject {
StringRef CUIndexSection;
StringRef GdbIndexSection;
StringRef TUIndexSection;
+ StringRef LineStringSection;
- SmallVector<SmallString<32>, 4> UncompressedSections;
+ // 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))
@@ -1214,6 +1272,7 @@ class DWARFObjInMemory final : public DWARFObject {
.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);
}
@@ -1230,11 +1289,11 @@ class DWARFObjInMemory final : public DWARFObject {
if (!Decompressor)
return Decompressor.takeError();
- SmallString<32> Out;
+ SmallString<0> Out;
if (auto Err = Decompressor->resizeAndDecompress(Out))
return Err;
- UncompressedSections.emplace_back(std::move(Out));
+ UncompressedSections.push_back(std::move(Out));
Data = UncompressedSections.back();
return Error::success();
@@ -1423,6 +1482,9 @@ public:
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; }
@@ -1432,6 +1494,7 @@ public:
const DWARFSection &getStringOffsetSection() const override {
return StringOffsetSection;
}
+ StringRef getLineStringSection() const override { return LineStringSection; }
// Sections for DWARF5 split dwarf proposal.
const DWARFSection &getInfoDWOSection() const override {
@@ -1451,6 +1514,9 @@ public:
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; }
StringRef getPubNamesSection() const override { return PubNamesSection; }
StringRef getPubTypesSection() const override { return PubTypesSection; }
@@ -1472,6 +1538,9 @@ public:
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; }
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
index 861dd313fb09..03e317461396 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
using namespace llvm;
@@ -25,3 +26,71 @@ uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off,
*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/DWARFDebugArangeSet.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
index ed5d726ae4e2..b9ef6905912a 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
@@ -17,6 +17,13 @@
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));
@@ -98,10 +105,8 @@ void DWARFDebugArangeSet::dump(raw_ostream &OS) const {
<< format("cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n",
HeaderData.CuOffset, HeaderData.AddrSize, HeaderData.SegSize);
- const uint32_t hex_width = HeaderData.AddrSize * 2;
for (const auto &Desc : ArangeDescriptors) {
- OS << format("[0x%*.*" PRIx64 " -", hex_width, hex_width, Desc.Address)
- << format(" 0x%*.*" PRIx64 ")\n",
- hex_width, hex_width, Desc.getEndAddress());
+ 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
index a3ecb15e3661..19bfcaed2021 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
@@ -80,7 +80,7 @@ void DWARFDebugAranges::appendRange(uint32_t CUOffset, uint64_t LowPC,
void DWARFDebugAranges::construct() {
std::multiset<uint32_t> ValidCUs; // Maintain the set of CUs describing
// a current address range.
- std::sort(Endpoints.begin(), Endpoints.end());
+ llvm::sort(Endpoints.begin(), Endpoints.end());
uint64_t PrevAddress = -1ULL;
for (const auto &E : Endpoints) {
if (PrevAddress < E.Address && !ValidCUs.empty()) {
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index 3312da67804b..73333395f4c1 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -8,10 +8,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
@@ -31,87 +29,13 @@
using namespace llvm;
using namespace dwarf;
-/// \brief Abstract frame entry defining the common interface concrete
-/// entries implement.
-class llvm::FrameEntry {
-public:
- enum FrameKind {FK_CIE, FK_FDE};
-
- FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length)
- : Kind(K), Offset(Offset), Length(Length) {}
-
- virtual ~FrameEntry() = default;
-
- FrameKind getKind() const { return Kind; }
- virtual uint64_t getOffset() const { return Offset; }
-
- /// Parse and store a sequence of CFI instructions from Data,
- /// starting at *Offset and ending at EndOffset. If everything
- /// goes well, *Offset should be equal to EndOffset when this method
- /// returns. Otherwise, an error occurred.
- virtual void parseInstructions(DataExtractor Data, uint32_t *Offset,
- uint32_t EndOffset);
-
- /// Dump the entry header to the given output stream.
- virtual void dumpHeader(raw_ostream &OS) const = 0;
-
- /// Dump the entry's instructions to the given output stream.
- virtual void dumpInstructions(raw_ostream &OS) const;
-
- /// Dump the entire entry to the given output stream.
- void dump(raw_ostream &OS) const {
- dumpHeader(OS);
- dumpInstructions(OS);
- OS << "\n";
- }
-
-protected:
- const FrameKind Kind;
-
- /// \brief Offset of this entry in the section.
- uint64_t Offset;
-
- /// \brief Entry length as specified in DWARF.
- uint64_t Length;
-
- /// An entry may contain CFI instructions. An instruction consists of an
- /// opcode and an optional sequence of operands.
- using Operands = std::vector<uint64_t>;
- struct Instruction {
- Instruction(uint8_t Opcode)
- : Opcode(Opcode)
- {}
-
- uint8_t Opcode;
- Operands Ops;
- };
-
- std::vector<Instruction> Instructions;
-
- /// Convenience methods to add a new instruction with the given opcode and
- /// operands to the Instructions vector.
- void addInstruction(uint8_t Opcode) {
- Instructions.push_back(Instruction(Opcode));
- }
-
- void addInstruction(uint8_t Opcode, uint64_t Operand1) {
- Instructions.push_back(Instruction(Opcode));
- Instructions.back().Ops.push_back(Operand1);
- }
-
- void addInstruction(uint8_t Opcode, uint64_t Operand1, uint64_t Operand2) {
- Instructions.push_back(Instruction(Opcode));
- Instructions.back().Ops.push_back(Operand1);
- Instructions.back().Ops.push_back(Operand2);
- }
-};
// 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;
-void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
- uint32_t EndOffset) {
+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.
@@ -122,67 +46,73 @@ void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
// bits of the opcode itself.
uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
switch (Primary) {
- default: llvm_unreachable("Impossible primary CFI opcode");
- case DW_CFA_advance_loc:
- case DW_CFA_restore:
- addInstruction(Primary, Op1);
- break;
- case DW_CFA_offset:
- addInstruction(Primary, Op1, Data.getULEB128(Offset));
- break;
+ default:
+ return make_error<StringError>(
+ "Invalid primary CFI opcode",
+ std::make_error_code(std::errc::illegal_byte_sequence));
+ 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: llvm_unreachable("Invalid extended CFI 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;
+ default:
+ return make_error<StringError>(
+ "Invalid extended CFI opcode",
+ std::make_error_code(std::errc::illegal_byte_sequence));
+ 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:
@@ -194,162 +124,49 @@ void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
addInstruction(Opcode, op1, op2);
break;
}
- case DW_CFA_def_cfa_expression:
- // FIXME: Parse the actual instruction.
- *Offset += Data.getULEB128(Offset);
+ 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: {
- // FIXME: Parse the actual instruction.
- Data.getULEB128(Offset);
- *Offset += Data.getULEB128(Offset);
+ 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 {
-/// \brief DWARF Common Information Entry (CIE)
-class CIE : public FrameEntry {
-public:
- // CIEs (and FDEs) are simply container classes, so the only sensible way to
- // create them is by providing the full parsed contents in the constructor.
- CIE(uint64_t Offset, uint64_t Length, uint8_t Version,
- SmallString<8> Augmentation, uint8_t AddressSize,
- uint8_t SegmentDescriptorSize, uint64_t CodeAlignmentFactor,
- int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
- SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
- uint32_t LSDAPointerEncoding)
- : FrameEntry(FK_CIE, Offset, Length), Version(Version),
- Augmentation(std::move(Augmentation)), AddressSize(AddressSize),
- SegmentDescriptorSize(SegmentDescriptorSize),
- CodeAlignmentFactor(CodeAlignmentFactor),
- DataAlignmentFactor(DataAlignmentFactor),
- ReturnAddressRegister(ReturnAddressRegister),
- AugmentationData(std::move(AugmentationData)),
- FDEPointerEncoding(FDEPointerEncoding),
- LSDAPointerEncoding(LSDAPointerEncoding) {}
-
- ~CIE() override = default;
-
- StringRef getAugmentationString() const { return Augmentation; }
- uint64_t getCodeAlignmentFactor() const { return CodeAlignmentFactor; }
- int64_t getDataAlignmentFactor() const { return DataAlignmentFactor; }
-
- uint32_t getFDEPointerEncoding() const {
- return FDEPointerEncoding;
- }
-
- uint32_t getLSDAPointerEncoding() const {
- return LSDAPointerEncoding;
- }
-
- void dumpHeader(raw_ostream &OS) const override {
- 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 (!AugmentationData.empty()) {
- OS << " Augmentation data: ";
- for (uint8_t Byte : AugmentationData)
- OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
- OS << "\n";
- }
- OS << "\n";
- }
-
- static bool classof(const FrameEntry *FE) {
- return FE->getKind() == FK_CIE;
- }
-
-private:
- /// The following fields are defined in section 6.4.1 of the DWARF standard v4
- uint8_t Version;
- SmallString<8> Augmentation;
- uint8_t AddressSize;
- uint8_t SegmentDescriptorSize;
- uint64_t CodeAlignmentFactor;
- int64_t DataAlignmentFactor;
- uint64_t ReturnAddressRegister;
-
- // The following are used when the CIE represents an EH frame entry.
- SmallString<8> AugmentationData;
- uint32_t FDEPointerEncoding;
- uint32_t LSDAPointerEncoding;
-};
-
-/// \brief DWARF Frame Description Entry (FDE)
-class FDE : public FrameEntry {
-public:
- // Each FDE has a CIE it's "linked to". Our FDE contains is constructed with
- // an offset to the CIE (provided by parsing the FDE header). The CIE itself
- // is obtained lazily once it's actually required.
- FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset,
- uint64_t InitialLocation, uint64_t AddressRange,
- CIE *Cie)
- : FrameEntry(FK_FDE, Offset, Length), LinkedCIEOffset(LinkedCIEOffset),
- InitialLocation(InitialLocation), AddressRange(AddressRange),
- LinkedCIE(Cie) {}
-
- ~FDE() override = default;
-
- CIE *getLinkedCIE() const { return LinkedCIE; }
-
- void dumpHeader(raw_ostream &OS) const override {
- 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);
- }
-
- static bool classof(const FrameEntry *FE) {
- return FE->getKind() == FK_FDE;
- }
-
-private:
- /// The following fields are defined in section 6.4.1 of the DWARF standard v3
- uint64_t LinkedCIEOffset;
- uint64_t InitialLocation;
- uint64_t AddressRange;
- CIE *LinkedCIE;
-};
-
-/// \brief Types of operands to CF instructions.
-enum OperandType {
- OT_Unset,
- OT_None,
- OT_Address,
- OT_Offset,
- OT_FactoredCodeOffset,
- OT_SignedFactDataOffset,
- OT_UnsignedFactDataOffset,
- OT_Register,
- OT_Expression
-};
} // end anonymous namespace
-/// \brief Initialize the array describing the types of operands.
-static ArrayRef<OperandType[2]> getOperandTypes() {
+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 { \
@@ -396,15 +213,13 @@ static ArrayRef<OperandType[2]> getOperandTypes() {
return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
}
-static ArrayRef<OperandType[2]> OpTypes = getOperandTypes();
-
-/// \brief Print \p Opcode's operand number \p OperandIdx which has
-/// value \p Operand.
-static void printOperand(raw_ostream &OS, uint8_t Opcode, unsigned OperandIdx,
- uint64_t Operand, uint64_t CodeAlignmentFactor,
- int64_t DataAlignmentFactor) {
+/// 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);
- OperandType Type = OpTypes[Opcode][OperandIdx];
+ uint8_t Opcode = Instr.Opcode;
+ OperandType Type = getOperandTypes()[Opcode][OperandIdx];
switch (Type) {
case OT_Unset: {
@@ -449,36 +264,68 @@ static void printOperand(raw_ostream &OS, uint8_t Opcode, unsigned OperandIdx,
OS << format(" reg%" PRId64, Operand);
break;
case OT_Expression:
- OS << " expression";
+ assert(Instr.Expression && "missing DWARFExpression object");
+ OS << " ";
+ Instr.Expression->print(OS, MRI, IsEH);
break;
}
}
-void FrameEntry::dumpInstructions(raw_ostream &OS) const {
- uint64_t CodeAlignmentFactor = 0;
- int64_t DataAlignmentFactor = 0;
- const CIE *Cie = dyn_cast<CIE>(this);
-
- if (!Cie)
- Cie = cast<FDE>(this)->getLinkedCIE();
- if (Cie) {
- CodeAlignmentFactor = Cie->getCodeAlignmentFactor();
- DataAlignmentFactor = Cie->getDataAlignmentFactor();
- }
-
+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 << " " << CallFrameString(Opcode) << ":";
+ OS.indent(2 * IndentLevel);
+ OS << CallFrameString(Opcode) << ":";
for (unsigned i = 0; i < Instr.Ops.size(); ++i)
- printOperand(OS, Opcode, i, Instr.Ops[i], CodeAlignmentFactor,
- DataAlignmentFactor);
+ printOperand(OS, MRI, IsEH, Instr, i, Instr.Ops[i]);
OS << '\n';
}
}
-DWARFDebugFrame::DWARFDebugFrame(bool IsEH) : IsEH(IsEH) {}
+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(bool IsEH, uint64_t EHFrameAddress)
+ : IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
DWARFDebugFrame::~DWARFDebugFrame() = default;
@@ -492,40 +339,6 @@ static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
errs() << "\n";
}
-static unsigned getSizeForEncoding(const DataExtractor &Data,
- unsigned symbolEncoding) {
- unsigned format = symbolEncoding & 0x0f;
- switch (format) {
- default: llvm_unreachable("Unknown Encoding");
- case DW_EH_PE_absptr:
- case DW_EH_PE_signed:
- return Data.getAddressSize();
- case DW_EH_PE_udata2:
- case DW_EH_PE_sdata2:
- return 2;
- case DW_EH_PE_udata4:
- case DW_EH_PE_sdata4:
- return 4;
- case DW_EH_PE_udata8:
- case DW_EH_PE_sdata8:
- return 8;
- }
-}
-
-static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset,
- unsigned Encoding) {
- switch (getSizeForEncoding(Data, Encoding)) {
- case 2:
- return Data.getU16(&Offset);
- case 4:
- return Data.getU32(&Offset);
- case 8:
- return Data.getU64(&Offset);
- default:
- llvm_unreachable("Illegal data size");
- }
-}
-
// 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
@@ -539,7 +352,7 @@ static void LLVM_ATTRIBUTE_NORETURN ReportError(uint32_t StartOffset,
report_fatal_error(Str);
}
-void DWARFDebugFrame::parse(DataExtractor Data) {
+void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
uint32_t Offset = 0;
DenseMap<uint32_t, CIE *> CIEs;
@@ -569,9 +382,8 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
// 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));
+ bool IsCIE =
+ ((IsDWARF64 && Id == DW64_CIE_ID) || Id == DW_CIE_ID || (IsEH && !Id));
if (IsCIE) {
uint8_t Version = Data.getU8(&Offset);
@@ -587,12 +399,11 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
// Parse the augmentation data for EH CIEs
StringRef AugmentationData("");
- uint32_t FDEPointerEncoding = DW_EH_PE_omit;
+ 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<uint32_t> PersonalityEncoding;
- Optional<uint64_t> Personality;
-
Optional<uint64_t> AugmentationLength;
uint32_t StartAugmentationOffset;
uint32_t EndAugmentationOffset;
@@ -611,12 +422,17 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
ReportError(StartOffset,
"Duplicate personality in entry at %lx");
PersonalityEncoding = Data.getU8(&Offset);
- Personality = readPointer(Data, Offset, *PersonalityEncoding);
+ 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,
@@ -639,14 +455,11 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
}
}
- auto Cie = llvm::make_unique<CIE>(StartOffset, Length, Version,
- AugmentationString, AddressSize,
- SegmentDescriptorSize,
- CodeAlignmentFactor,
- DataAlignmentFactor,
- ReturnAddressRegister,
- AugmentationData, FDEPointerEncoding,
- LSDAPointerEncoding);
+ auto Cie = llvm::make_unique<CIE>(
+ StartOffset, Length, Version, AugmentationString, AddressSize,
+ SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor,
+ ReturnAddressRegister, AugmentationData, FDEPointerEncoding,
+ LSDAPointerEncoding, Personality, PersonalityEncoding);
CIEs[StartOffset] = Cie.get();
Entries.emplace_back(std::move(Cie));
} else {
@@ -654,6 +467,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
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) {
@@ -662,10 +476,15 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
ReportError(StartOffset,
"Parsing FDE data at %lx failed due to missing CIE");
- InitialLocation = readPointer(Data, Offset,
- Cie->getFDEPointerEncoding());
- AddressRange = readPointer(Data, Offset,
- Cie->getFDEPointerEncoding());
+ 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()) {
@@ -676,8 +495,11 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
Offset + static_cast<uint32_t>(AugmentationLength);
// Decode the LSDA if the CIE augmentation string said we should.
- if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit)
- readPointer(Data, Offset, Cie->getLSDAPointerEncoding());
+ 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");
@@ -689,10 +511,13 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
InitialLocation, AddressRange,
- Cie));
+ Cie, LSDAAddress));
}
- Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset);
+ 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");
@@ -709,14 +534,15 @@ FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
return nullptr;
}
-void DWARFDebugFrame::dump(raw_ostream &OS, Optional<uint64_t> Offset) const {
+void DWARFDebugFrame::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ Optional<uint64_t> Offset) const {
if (Offset) {
if (auto *Entry = getEntryAtOffset(*Offset))
- Entry->dump(OS);
+ Entry->dump(OS, MRI, IsEH);
return;
}
OS << "\n";
for (const auto &Entry : Entries)
- Entry->dump(OS);
+ Entry->dump(OS, MRI, IsEH);
}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index e5ef4eaceebe..53a8e193ef56 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#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"
@@ -16,6 +17,7 @@
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.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>
@@ -40,6 +42,28 @@ 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() {
@@ -47,14 +71,15 @@ void DWARFDebugLine::Prologue::clear() {
SegSelectorSize = 0;
MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0;
OpcodeBase = 0;
- FormParams = DWARFFormParams({0, 0, DWARF32});
- HasMD5 = false;
+ FormParams = dwarf::FormParams({0, 0, DWARF32});
+ ContentTypes = ContentTypeTracker();
StandardOpcodeLengths.clear();
IncludeDirectories.clear();
FileNames.clear();
}
-void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
+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());
@@ -73,29 +98,37 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
OS << format("standard_opcode_lengths[%s] = %u\n",
LNStandardString(I + 1).data(), StandardOpcodeLengths[I]);
- if (!IncludeDirectories.empty())
- for (uint32_t I = 0; I != IncludeDirectories.size(); ++I)
- OS << format("include_directories[%3u] = '", I + 1)
- << IncludeDirectories[I] << "'\n";
+ 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()) {
- if (HasMD5)
- OS << " Dir MD5 Checksum File Name\n"
- << " ---- -------------------------------- -----------"
- "---------------\n";
- else
- OS << " Dir Mod Time File Len File Name\n"
- << " ---- ---------- ---------- -----------"
- "----------------\n";
+ // 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] %4" PRIu64 " ", I + 1, FileEntry.DirIdx);
- if (HasMD5)
- OS << FileEntry.Checksum.digest();
- else
- OS << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64, FileEntry.ModTime,
- FileEntry.Length);
- OS << ' ' << FileEntry.Name << '\n';
+ 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';
+ }
}
}
}
@@ -104,13 +137,16 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
static void
parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
uint32_t *OffsetPtr, uint64_t EndPrologueOffset,
- std::vector<StringRef> &IncludeDirectories,
+ DWARFDebugLine::ContentTypeTracker &ContentTypes,
+ std::vector<DWARFFormValue> &IncludeDirectories,
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
while (*OffsetPtr < EndPrologueOffset) {
StringRef S = DebugLineData.getCStrRef(OffsetPtr);
if (S.empty())
break;
- IncludeDirectories.push_back(S);
+ DWARFFormValue Dir(dwarf::DW_FORM_string);
+ Dir.setPValue(S.data());
+ IncludeDirectories.push_back(Dir);
}
while (*OffsetPtr < EndPrologueOffset) {
@@ -118,20 +154,25 @@ parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
if (Name.empty())
break;
DWARFDebugLine::FileNameEntry FileEntry;
- FileEntry.Name = Name;
+ 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, bool *HasMD5) {
+parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t
+ *OffsetPtr, uint64_t EndPrologueOffset, DWARFDebugLine::ContentTypeTracker
+ *ContentTypes) {
ContentDescriptors Descriptors;
int FormatCount = DebugLineData.getU8(OffsetPtr);
bool HasPath = false;
@@ -144,8 +185,8 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr));
if (Descriptor.Type == dwarf::DW_LNCT_path)
HasPath = true;
- else if (Descriptor.Type == dwarf::DW_LNCT_MD5 && HasMD5)
- *HasMD5 = true;
+ if (ContentTypes)
+ ContentTypes->trackContentType(Descriptor.Type);
Descriptors.push_back(Descriptor);
}
return HasPath ? Descriptors : ContentDescriptors();
@@ -154,8 +195,10 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
static bool
parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
uint32_t *OffsetPtr, uint64_t EndPrologueOffset,
- const DWARFFormParams &FormParams, const DWARFUnit *U,
- bool &HasMD5, std::vector<StringRef> &IncludeDirectories,
+ 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 =
@@ -172,9 +215,9 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
DWARFFormValue Value(Descriptor.Form);
switch (Descriptor.Type) {
case DW_LNCT_path:
- if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U))
+ if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
return false;
- IncludeDirectories.push_back(Value.getAsCString().getValue());
+ IncludeDirectories.push_back(Value);
break;
default:
if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams))
@@ -185,7 +228,8 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
// Get the file entry description.
ContentDescriptors FileDescriptors =
- parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, &HasMD5);
+ parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset,
+ &ContentTypes);
if (FileDescriptors.empty())
return false;
@@ -197,11 +241,14 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
DWARFDebugLine::FileNameEntry FileEntry;
for (auto Descriptor : FileDescriptors) {
DWARFFormValue Value(Descriptor.Form);
- if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U))
+ if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
return false;
switch (Descriptor.Type) {
case DW_LNCT_path:
- FileEntry.Name = Value.getAsCString().getValue();
+ FileEntry.Name = Value;
+ break;
+ case DW_LNCT_LLVM_source:
+ FileEntry.Source = Value;
break;
case DW_LNCT_directory_index:
FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue();
@@ -226,8 +273,28 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
return true;
}
-bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
- uint32_t *OffsetPtr, const DWARFUnit *U) {
+template <typename... Ts>
+static std::string formatErrorString(char const *Fmt, const Ts &... Vals) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ return Stream.str();
+}
+
+template <typename... Ts>
+static Error createError(char const *Fmt, const Ts &... Vals) {
+ return make_error<StringError>(formatErrorString(Fmt, Vals...),
+ inconvertibleErrorCode());
+}
+
+static Error createError(char const *Msg) {
+ return make_error<StringError>(Msg, inconvertibleErrorCode());
+}
+
+Error DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
+ uint32_t *OffsetPtr,
+ const DWARFContext &Ctx,
+ const DWARFUnit *U) {
const uint64_t PrologueOffset = *OffsetPtr;
clear();
@@ -236,11 +303,16 @@ bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
FormParams.Format = dwarf::DWARF64;
TotalLength = DebugLineData.getU64(OffsetPtr);
} else if (TotalLength >= 0xffffff00) {
- return false;
+ return createError(
+ "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 false;
+ return createError("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);
@@ -268,27 +340,24 @@ bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
if (getVersion() >= 5) {
if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
- getFormParams(), U, HasMD5, IncludeDirectories,
- FileNames)) {
- fprintf(stderr,
- "warning: parsing line table prologue at 0x%8.8" PRIx64
- " found an invalid directory or file table description at"
- " 0x%8.8" PRIx64 "\n", PrologueOffset, (uint64_t)*OffsetPtr);
- return false;
+ FormParams, Ctx, U, ContentTypes,
+ IncludeDirectories, FileNames)) {
+ return createError(
+ "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,
- IncludeDirectories, FileNames);
-
- if (*OffsetPtr != EndPrologueOffset) {
- fprintf(stderr,
- "warning: 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 "\n",
- PrologueOffset, EndPrologueOffset, (uint64_t)*OffsetPtr);
- return false;
- }
- return true;
+ ContentTypes, IncludeDirectories, FileNames);
+
+ if (*OffsetPtr != EndPrologueOffset)
+ return createError("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); }
@@ -340,8 +409,9 @@ void DWARFDebugLine::Sequence::reset() {
DWARFDebugLine::LineTable::LineTable() { clear(); }
-void DWARFDebugLine::LineTable::dump(raw_ostream &OS) const {
- Prologue.dump(OS);
+void DWARFDebugLine::LineTable::dump(raw_ostream &OS,
+ DIDumpOptions DumpOptions) const {
+ Prologue.dump(OS, DumpOptions);
OS << '\n';
if (!Rows.empty()) {
@@ -396,34 +466,45 @@ DWARFDebugLine::getLineTable(uint32_t Offset) const {
return nullptr;
}
-const DWARFDebugLine::LineTable *
-DWARFDebugLine::getOrParseLineTable(DWARFDataExtractor &DebugLineData,
- uint32_t Offset, const DWARFUnit *U) {
+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 createError("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 (!LT->parse(DebugLineData, &Offset, U))
- return nullptr;
+ if (Error Err =
+ LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorCallback))
+ return std::move(Err);
+ return LT;
}
return LT;
}
-bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData,
- uint32_t *OffsetPtr, const DWARFUnit *U,
- raw_ostream *OS) {
+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();
- if (!Prologue.parse(DebugLineData, OffsetPtr, U)) {
- // Restore our offset and return false to indicate failure!
- *OffsetPtr = DebugLineOffset;
- return false;
+ 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 (OS)
- Prologue.dump(*OS);
+ if (PrologueErr)
+ return PrologueErr;
const uint32_t EndOffset =
DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength();
@@ -493,8 +574,12 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData,
// from the size of the operand.
if (DebugLineData.getAddressSize() == 0)
DebugLineData.setAddressSize(Len - 1);
- else
- assert(DebugLineData.getAddressSize() == Len - 1);
+ else if (DebugLineData.getAddressSize() != Len - 1) {
+ return createError("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);
@@ -523,14 +608,15 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData,
// the file register of the state machine.
{
FileNameEntry FileEntry;
- FileEntry.Name = DebugLineData.getCStr(OffsetPtr);
+ 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 << " (" << FileEntry.Name.str()
- << ", dir=" << FileEntry.DirIdx << ", mod_time="
+ *OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time="
<< format("(0x%16.16" PRIx64 ")", FileEntry.ModTime)
<< ", length=" << FileEntry.Length << ")";
}
@@ -553,14 +639,10 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData,
}
// Make sure the stated and parsed lengths are the same.
// Otherwise we have an unparseable line-number program.
- if (*OffsetPtr - ExtOffset != Len) {
- fprintf(stderr, "Unexpected line op length at offset 0x%8.8" PRIx32
- " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx32 "\n",
- ExtOffset, Len, *OffsetPtr - ExtOffset);
- // Skip the rest of the line-number program.
- *OffsetPtr = EndOffset;
- return false;
- }
+ if (*OffsetPtr - ExtOffset != Len)
+ return createError("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);
@@ -763,14 +845,13 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData,
*OS << "\n";
}
- if (!State.Sequence.Empty) {
- fprintf(stderr, "warning: last sequence in debug line table is not"
- "terminated!\n");
- }
+ if (!State.Sequence.Empty)
+ RecoverableErrorCallback(
+ createError("last sequence in debug line table is not terminated!"));
// Sort all sequences so that address lookup will work faster.
if (!Sequences.empty()) {
- std::sort(Sequences.begin(), Sequences.end(), Sequence::orderByLowPC);
+ llvm::sort(Sequences.begin(), Sequences.end(), 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.
@@ -779,7 +860,7 @@ bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData,
// rudimentary sequences for address ranges [0x0, 0xsomething).
}
- return EndOffset;
+ return Error::success();
}
uint32_t
@@ -887,6 +968,24 @@ 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,
@@ -894,9 +993,9 @@ bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex))
return false;
const FileNameEntry &Entry = Prologue.FileNames[FileIndex - 1];
- StringRef FileName = Entry.Name;
+ StringRef FileName = Entry.Name.getAsCString().getValue();
if (Kind != FileLineInfoKind::AbsoluteFilePath ||
- sys::path::is_absolute(FileName)) {
+ isPathAbsoluteOnWindowsOrPosix(FileName)) {
Result = FileName;
return true;
}
@@ -907,13 +1006,15 @@ bool DWARFDebugLine::LineTable::getFileNameByIndex(uint64_t FileIndex,
// Be defensive about the contents of Entry.
if (IncludeDirIndex > 0 &&
IncludeDirIndex <= Prologue.IncludeDirectories.size())
- IncludeDir = Prologue.IncludeDirectories[IncludeDirIndex - 1];
+ 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 &&
- sys::path::is_relative(IncludeDir))
+ !isPathAbsoluteOnWindowsOrPosix(IncludeDir))
sys::path::append(FilePath, CompDir);
// sys::path::append skips empty strings.
@@ -936,5 +1037,97 @@ bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
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 TUSections) {
+ 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 &TUS : TUSections)
+ 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;
+ }
+}
+
+void DWARFDebugLine::warn(Error Err) {
+ handleAllErrors(std::move(Err), [](ErrorInfoBase &Info) {
+ WithColor::warning() << Info.message() << '\n';
+ });
+}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
index 58f88536f317..617b914ecce9 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -16,6 +16,7 @@
#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>
@@ -33,18 +34,22 @@ static void dumpExpression(raw_ostream &OS, ArrayRef<char> Data,
const MCRegisterInfo *MRI) {
DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()),
IsLittleEndian, AddressSize);
- DWARFExpression(Extractor, AddressSize, dwarf::DWARF_VERSION).print(OS, MRI);
+ 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%016" PRIx64, E.Begin) << " - "
- << format("0x%016" PRIx64, E.End) << ": ";
+ 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);
}
@@ -64,7 +69,7 @@ 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, 12);
+ L.dump(OS, IsLittleEndian, AddressSize, MRI, 0, 12);
OS << "\n\n";
};
@@ -89,7 +94,7 @@ DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) {
while (true) {
Entry E;
if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) {
- llvm::errs() << "Location list overflows the debug_loc section.\n";
+ WithColor::error() << "location list overflows the debug_loc section.\n";
return None;
}
@@ -106,13 +111,13 @@ DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) {
return LL;
if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) {
- llvm::errs() << "Location list overflows the debug_loc section.\n";
+ WithColor::error() << "location list overflows the debug_loc section.\n";
return None;
}
unsigned Bytes = Data.getU16(Offset);
if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) {
- llvm::errs() << "Location list overflows the debug_loc section.\n";
+ WithColor::error() << "location list overflows the debug_loc section.\n";
return None;
}
// A single location description describing the location of the object...
@@ -136,7 +141,7 @@ void DWARFDebugLoc::parse(const DWARFDataExtractor &data) {
break;
}
if (data.isValidOffset(Offset))
- errs() << "error: failed to consume entire .debug_loc section\n";
+ WithColor::error() << "failed to consume entire .debug_loc section\n";
}
Optional<DWARFDebugLocDWO::LocationList>
@@ -148,8 +153,8 @@ DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) {
while (auto Kind =
static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) {
if (Kind != dwarf::DW_LLE_startx_length) {
- llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind
- << " not implemented\n";
+ WithColor::error() << "dumping support for LLE of kind " << (int)Kind
+ << " not implemented\n";
return None;
}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
index 1b77be6192dd..6d789c3027a5 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
@@ -8,14 +8,13 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
-#include "SyntaxHighlighting.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;
-using namespace syntax;
void DWARFDebugMacro::dump(raw_ostream &OS) const {
unsigned IndLevel = 0;
@@ -29,7 +28,7 @@ void DWARFDebugMacro::dump(raw_ostream &OS) const {
OS << " ";
IndLevel += (E.Type == DW_MACINFO_start_file);
- WithColor(OS, syntax::Macro).get() << MacinfoString(E.Type);
+ WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type);
switch (E.Type) {
default:
// Got a corrupted ".debug_macinfo" section (invalid macinfo type).
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
index 956a91e9c4d6..de8b6e543fab 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
@@ -37,7 +37,7 @@ DWARFDebugPubTable::DWARFDebugPubTable(StringRef Data, bool LittleEndian,
if (DieRef == 0)
break;
uint8_t IndexEntryValue = GnuStyle ? PubNames.getU8(&Offset) : 0;
- const char *Name = PubNames.getCStr(&Offset);
+ StringRef Name = PubNames.getCStrRef(&Offset);
SetData.Entries.push_back(
{DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name});
}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
index f0b7ec2751de..a565718debd0 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
@@ -13,13 +13,16 @@
#include "llvm/Support/raw_ostream.h"
#include <cinttypes>
#include <cstdint>
-#include <utility>
using namespace llvm;
-raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) {
- return OS << format("[0x%16.16" PRIx64 ", 0x%16.16" PRIx64 ")", R.LowPC,
- R.HighPC);
+// FIXME: There are several versions of this. Consolidate them.
+template <typename... Ts>
+static Error createError(char const *Fmt, const Ts &... Vals) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
}
void DWARFDebugRangeList::clear() {
@@ -28,14 +31,15 @@ void DWARFDebugRangeList::clear() {
Entries.clear();
}
-bool DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
- uint32_t *offset_ptr) {
+Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
+ uint32_t *offset_ptr) {
clear();
if (!data.isValidOffset(*offset_ptr))
- return false;
+ return createError("invalid range list offset 0x%" PRIx32, *offset_ptr);
+
AddressSize = data.getAddressSize();
if (AddressSize != 4 && AddressSize != 8)
- return false;
+ return createError("invalid address size: %d", AddressSize);
Offset = *offset_ptr;
while (true) {
RangeListEntry Entry;
@@ -49,13 +53,14 @@ bool DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
// Check that both values were extracted correctly.
if (*offset_ptr != prev_offset + 2 * AddressSize) {
clear();
- return false;
+ return createError("invalid range list entry at offset 0x%" PRIx32,
+ prev_offset);
}
if (Entry.isEndOfListEntry())
break;
Entries.push_back(Entry);
}
- return true;
+ return Error::success();
}
void DWARFDebugRangeList::dump(raw_ostream &OS) const {
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
new file mode 100644
index 000000000000..b19c808a8fb3
--- /dev/null
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
@@ -0,0 +1,205 @@
+//===- 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/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+template <typename... Ts>
+static Error createError(char const *Fmt, const Ts &... Vals) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
+}
+
+namespace llvm { // workaround for gcc bug
+template <>
+Error DWARFListType<RangeListEntry>::createError(const char *Fmt, const char *s,
+ uint32_t Val) {
+ return ::createError(Fmt, s, Val);
+}
+}
+
+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:
+ return createError("unsupported rnglists encoding DW_RLE_base_addressx "
+ "at offset 0x%" PRIx32,
+ *OffsetPtr - 1);
+ case dwarf::DW_RLE_startx_endx:
+ return createError("unsupported rnglists encoding DW_RLE_startx_endx at "
+ "offset 0x%" PRIx32,
+ *OffsetPtr - 1);
+ case dwarf::DW_RLE_startx_length:
+ return createError("unsupported rnglists encoding DW_RLE_startx_length "
+ "at offset 0x%" PRIx32,
+ *OffsetPtr - 1);
+ case dwarf::DW_RLE_offset_pair: {
+ uint32_t PreviousOffset = *OffsetPtr - 1;
+ Value0 = Data.getULEB128(OffsetPtr);
+ Value1 = Data.getULEB128(OffsetPtr);
+ if (End < *OffsetPtr)
+ return createError("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 createError("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 createError("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 createError("read past end of table when reading "
+ "DW_RLE_start_length encoding at offset 0x%" PRIx32,
+ PreviousOffset);
+ break;
+ }
+ default:
+ return createError("unknown rnglists encoding 0x%" PRIx32
+ " at offset 0x%" PRIx32,
+ uint32_t(Encoding), *OffsetPtr - 1);
+ }
+
+ EntryKind = Encoding;
+ return Error::success();
+}
+
+DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
+ llvm::Optional<BaseAddress> BaseAddr) 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_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;
+ 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) 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_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;
+ 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
index 91f0f8501f0c..904ceab7b286 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -8,9 +8,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
-#include "SyntaxHighlighting.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"
@@ -22,7 +22,9 @@
#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>
@@ -34,7 +36,6 @@
using namespace llvm;
using namespace dwarf;
using namespace object;
-using namespace syntax;
static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) {
OS << " (";
@@ -62,13 +63,11 @@ static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS,
if (DumpOpts.Verbose)
SectionNames = Obj.getSectionNames();
- for (size_t I = 0; I < Ranges.size(); ++I) {
- const DWARFAddressRange &R = Ranges[I];
+ for (const DWARFAddressRange &R : Ranges) {
OS << '\n';
OS.indent(Indent);
- OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")", AddressSize * 2,
- R.LowPC, AddressSize * 2, R.HighPC);
+ R.dump(OS, AddressSize);
if (SectionNames.empty() || R.SectionIndex == -1ULL)
continue;
@@ -103,15 +102,18 @@ static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
const DWARFSection &LocSection = Obj.getLocSection();
const DWARFSection &LocDWOSection = Obj.getLocDWOSection();
uint32_t Offset = *FormValue.getAsSectionOffset();
-
if (!LocSection.Data.empty()) {
DWARFDebugLoc DebugLoc;
DWARFDataExtractor Data(Obj, LocSection, Ctx.isLittleEndian(),
Obj.getAddressSize());
auto LL = DebugLoc.parseOneLocationList(Data, &Offset);
- if (LL)
- LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent);
- else
+ if (LL) {
+ uint64_t BaseAddr = 0;
+ if (Optional<BaseAddress> BA = U->getBaseAddress())
+ BaseAddr = BA->Address;
+ LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, BaseAddr,
+ Indent);
+ } else
OS << "error extracting location list.";
} else if (!LocDWOSection.Data.empty()) {
DataExtractor Data(LocDWOSection.Data, Ctx.isLittleEndian(), 0);
@@ -191,19 +193,10 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
const char BaseIndent[] = " ";
OS << BaseIndent;
OS.indent(Indent + 2);
- auto attrString = AttributeString(Attr);
- if (!attrString.empty())
- WithColor(OS, syntax::Attribute) << attrString;
- else
- WithColor(OS, syntax::Attribute).get() << format("DW_AT_Unknown_%x", Attr);
+ WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr);
- if (DumpOpts.Verbose || DumpOpts.ShowForm) {
- auto formString = FormEncodingString(Form);
- if (!formString.empty())
- OS << " [" << formString << ']';
- else
- OS << format(" [DW_FORM_Unknown_%x]", Form);
- }
+ if (DumpOpts.Verbose || DumpOpts.ShowForm)
+ OS << formatv(" [{0}]", Form);
DWARFUnit *U = Die.getDwarfUnit();
DWARFFormValue formValue(Form);
@@ -216,9 +209,9 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
StringRef Name;
std::string File;
- auto Color = syntax::Enumerator;
+ auto Color = HighlightColor::Enumerator;
if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) {
- Color = syntax::String;
+ Color = HighlightColor::String;
if (const auto *LT = U->getContext().getLineTableForUnit(U))
if (LT->getFileNameByIndex(
formValue.getAsUnsignedConstant().getValue(),
@@ -267,8 +260,22 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
dumpApplePropertyAttribute(OS, *OptVal);
} else if (Attr == DW_AT_ranges) {
const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj();
- dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(),
- sizeof(BaseIndent) + Indent + 4, DumpOpts);
+ // For DW_FORM_rnglistx we need to dump the offset separately, since
+ // we have only dumped the index so far.
+ Optional<DWARFFormValue> Value = Die.find(DW_AT_ranges);
+ if (Value && Value->getForm() == DW_FORM_rnglistx)
+ if (auto RangeListOffset =
+ U->getRnglistOffset(*Value->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";
@@ -306,18 +313,37 @@ DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const {
Optional<DWARFFormValue>
DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const {
- if (!isValid())
- return None;
- if (auto Value = find(Attrs))
- return Value;
- if (auto Die = getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) {
- if (auto Value = Die.findRecursively(Attrs))
- return Value;
- }
- if (auto Die = getAttributeValueAsReferencedDie(DW_AT_specification)) {
- if (auto Value = Die.findRecursively(Attrs))
+ 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;
}
@@ -363,20 +389,19 @@ bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC,
return false;
}
-DWARFAddressRangesVector DWARFDie::getAddressRanges() const {
+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 {{LowPC, HighPC, Index}};
-
- // Multiple ranges from .debug_ranges section.
- auto RangesOffset = toSectionOffset(find(DW_AT_ranges));
- if (RangesOffset) {
- DWARFDebugRangeList RangeList;
- if (U->extractRangeList(*RangesOffset, RangeList))
- return RangeList.getAbsoluteRanges(U->getBaseAddress());
+ 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();
}
@@ -386,8 +411,11 @@ void DWARFDie::collectChildrenAddressRanges(
if (isNULL())
return;
if (isSubprogramDIE()) {
- const auto &DIERanges = getAddressRanges();
- Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end());
+ if (auto DIERangesOrError = getAddressRanges())
+ Ranges.insert(Ranges.end(), DIERangesOrError.get().begin(),
+ DIERangesOrError.get().end());
+ else
+ llvm::consumeError(DIERangesOrError.takeError());
}
for (auto Child : children())
@@ -395,10 +423,15 @@ void DWARFDie::collectChildrenAddressRanges(
}
bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
- for (const auto &R : getAddressRanges()) {
+ 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;
}
@@ -454,25 +487,23 @@ void DWARFDie::dump(raw_ostream &OS, unsigned Indent,
const uint32_t Offset = getOffset();
uint32_t offset = Offset;
if (DumpOpts.ShowParents) {
- DumpOpts.ShowParents = false;
- Indent = dumpParentChain(getParent(), OS, Indent, DumpOpts);
+ 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, syntax::Address).get() << format("\n0x%8.8x: ", Offset);
+ WithColor(OS, HighlightColor::Address).get()
+ << format("\n0x%8.8x: ", Offset);
if (abbrCode) {
auto AbbrevDecl = getAbbreviationDeclarationPtr();
if (AbbrevDecl) {
- auto tagString = TagString(getTag());
- if (!tagString.empty())
- WithColor(OS, syntax::Tag).get().indent(Indent) << tagString;
- else
- WithColor(OS, syntax::Tag).get().indent(Indent)
- << format("DW_TAG_Unknown_%x", getTag());
-
+ WithColor(OS, HighlightColor::Tag).get().indent(Indent)
+ << formatv("{0}", getTag());
if (DumpOpts.Verbose)
OS << format(" [%u] %c", abbrCode,
AbbrevDecl->hasChildren() ? '*' : ' ');
@@ -493,8 +524,10 @@ void DWARFDie::dump(raw_ostream &OS, unsigned Indent,
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, DumpOpts);
+ child.dump(OS, Indent + 2, ChildDumpOpts);
child = child.getSibling();
}
}
@@ -522,12 +555,24 @@ DWARFDie DWARFDie::getSibling() const {
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));
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index c704c2901aef..a9ea26c476ca 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -258,9 +258,10 @@ bool DWARFExpression::Operation::print(raw_ostream &OS,
return true;
}
-void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo) {
+void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo,
+ bool IsEH) const {
for (auto &Op : *this) {
- if (!Op.print(OS, this, RegInfo, /* isEH */ false)) {
+ if (!Op.print(OS, this, RegInfo, IsEH)) {
uint32_t FailOffset = Op.getEndOffset();
while (FailOffset < Data.getData().size())
OS << format(" %02x", Data.getU8(&FailOffset));
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
index 44886de2e3d5..1aa43c6b6517 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
-#include "SyntaxHighlighting.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
@@ -19,6 +18,7 @@
#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>
@@ -26,9 +26,8 @@
using namespace llvm;
using namespace dwarf;
-using namespace syntax;
-static const DWARFFormValue::FormClass DWARF4FormClasses[] = {
+static const DWARFFormValue::FormClass DWARF5FormClasses[] = {
DWARFFormValue::FC_Unknown, // 0x0
DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr
DWARFFormValue::FC_Unknown, // 0x02 unused
@@ -57,96 +56,31 @@ static const DWARFFormValue::FormClass DWARF4FormClasses[] = {
DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset
DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc
DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present
-};
-
-Optional<uint8_t>
-DWARFFormValue::getFixedByteSize(dwarf::Form Form,
- const DWARFFormParams Params) {
- switch (Form) {
- case DW_FORM_addr:
- assert(Params.Version && Params.AddrSize && "Invalid Params for form");
- return Params.AddrSize;
-
- case DW_FORM_block: // ULEB128 length L followed by L bytes.
- case DW_FORM_block1: // 1 byte length L followed by L bytes.
- case DW_FORM_block2: // 2 byte length L followed by L bytes.
- case DW_FORM_block4: // 4 byte length L followed by L bytes.
- case DW_FORM_string: // C-string with null terminator.
- case DW_FORM_sdata: // SLEB128.
- case DW_FORM_udata: // ULEB128.
- case DW_FORM_ref_udata: // ULEB128.
- case DW_FORM_indirect: // ULEB128.
- case DW_FORM_exprloc: // ULEB128 length L followed by L bytes.
- case DW_FORM_strx: // ULEB128.
- case DW_FORM_addrx: // ULEB128.
- case DW_FORM_loclistx: // ULEB128.
- case DW_FORM_rnglistx: // ULEB128.
- case DW_FORM_GNU_addr_index: // ULEB128.
- case DW_FORM_GNU_str_index: // ULEB128.
- return None;
-
- case DW_FORM_ref_addr:
- assert(Params.Version && Params.AddrSize && "Invalid Params for form");
- return Params.getRefAddrByteSize();
-
- case DW_FORM_flag:
- case DW_FORM_data1:
- case DW_FORM_ref1:
- case DW_FORM_strx1:
- case DW_FORM_addrx1:
- return 1;
-
- case DW_FORM_data2:
- case DW_FORM_ref2:
- case DW_FORM_strx2:
- case DW_FORM_addrx2:
- return 2;
-
- case DW_FORM_strx3:
- return 3;
-
- case DW_FORM_data4:
- case DW_FORM_ref4:
- case DW_FORM_ref_sup4:
- case DW_FORM_strx4:
- case DW_FORM_addrx4:
- return 4;
-
- 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:
- assert(Params.Version && Params.AddrSize && "Invalid Params for form");
- return Params.getDwarfOffsetByteSize();
-
- case DW_FORM_data8:
- case DW_FORM_ref8:
- case DW_FORM_ref_sig8:
- case DW_FORM_ref_sup8:
- return 8;
-
- case DW_FORM_flag_present:
- return 0;
+ 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
- case DW_FORM_data16:
- return 16;
-
- case DW_FORM_implicit_const:
- // The implicit value is stored in the abbreviation as a SLEB128, and
- // there no data in debug info.
- return 0;
-
- default:
- llvm_unreachable("Handle this form in this switch statement");
- }
- return None;
-}
+};
bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
uint32_t *OffsetPtr,
- const DWARFFormParams Params) {
+ const dwarf::FormParams Params) {
bool Indirect = false;
do {
switch (Form) {
@@ -208,7 +142,7 @@ bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
case DW_FORM_GNU_ref_alt:
case DW_FORM_GNU_strp_alt:
if (Optional<uint8_t> FixedSize =
- DWARFFormValue::getFixedByteSize(Form, Params)) {
+ dwarf::getFixedFormByteSize(Form, Params)) {
*OffsetPtr += *FixedSize;
return true;
}
@@ -243,42 +177,38 @@ bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
}
bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
- // First, check DWARF4 form classes.
- if (Form < makeArrayRef(DWARF4FormClasses).size() &&
- DWARF4FormClasses[Form] == FC)
+ // First, check DWARF5 form classes.
+ if (Form < makeArrayRef(DWARF5FormClasses).size() &&
+ DWARF5FormClasses[Form] == FC)
return true;
- // Check more forms from DWARF4 and DWARF5 proposals.
+ // Check more forms from extensions and proposals.
switch (Form) {
- case DW_FORM_ref_sig8:
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:
- case DW_FORM_strx:
- case DW_FORM_strx1:
- case DW_FORM_strx2:
- case DW_FORM_strx3:
- case DW_FORM_strx4:
return (FC == FC_String);
- case DW_FORM_implicit_const:
- return (FC == FC_Constant);
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_strp since this is .debug_str section
- // offset.
+ // 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_strp || Form == DW_FORM_line_strp) &&
FC == FC_SectionOffset;
}
bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
- uint32_t *OffsetPtr, DWARFFormParams FP,
+ 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;
@@ -350,6 +280,7 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
break;
case DW_FORM_udata:
case DW_FORM_ref_udata:
+ case DW_FORM_rnglistx:
Value.uval = Data.getULEB128(OffsetPtr);
break;
case DW_FORM_string:
@@ -402,8 +333,9 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
uint64_t UValue = Value.uval;
bool CURelativeOffset = false;
- raw_ostream &AddrOS =
- DumpOpts.ShowAddresses ? WithColor(OS, syntax::Address).get() : nulls();
+ raw_ostream &AddrOS = DumpOpts.ShowAddresses
+ ? WithColor(OS, HighlightColor::Address).get()
+ : nulls();
switch (Form) {
case DW_FORM_addr:
AddrOS << format("0x%016" PRIx64, UValue);
@@ -494,6 +426,11 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
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:
@@ -514,23 +451,28 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
break;
case DW_FORM_ref1:
CURelativeOffset = true;
- AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue);
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue);
break;
case DW_FORM_ref2:
CURelativeOffset = true;
- AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue);
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue);
break;
case DW_FORM_ref4:
CURelativeOffset = true;
- AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue);
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue);
break;
case DW_FORM_ref8:
CURelativeOffset = true;
- AddrOS << format("cu + 0x%8.8" PRIx64, UValue);
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%8.8" PRIx64, UValue);
break;
case DW_FORM_ref_udata:
CURelativeOffset = true;
- AddrOS << format("cu + 0x%" PRIx64, UValue);
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%" PRIx64, UValue);
break;
case DW_FORM_GNU_ref_alt:
AddrOS << format("<alt 0x%" PRIx64 ">", UValue);
@@ -542,6 +484,10 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
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);
@@ -552,21 +498,23 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
break;
}
- if (CURelativeOffset && DumpOpts.Verbose) {
- OS << " => {";
- WithColor(OS, syntax::Address).get()
+ if (CURelativeOffset) {
+ if (DumpOpts.Verbose)
+ OS << " => {";
+ WithColor(OS, HighlightColor::Address).get()
<< format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0));
- OS << "}";
+ if (DumpOpts.Verbose)
+ OS << "}";
}
}
void DWARFFormValue::dumpString(raw_ostream &OS) const {
Optional<const char *> DbgStr = getAsCString();
if (DbgStr.hasValue()) {
- raw_ostream &COS = WithColor(OS, syntax::String);
- COS << '"';
- COS.write_escaped(DbgStr.getValue());
- COS << '"';
+ auto COS = WithColor(OS, HighlightColor::String);
+ COS.get() << '"';
+ COS.get().write_escaped(DbgStr.getValue());
+ COS.get() << '"';
}
}
@@ -576,20 +524,32 @@ Optional<const char *> DWARFFormValue::getAsCString() const {
if (Form == DW_FORM_string)
return Value.cstr;
// FIXME: Add support for DW_FORM_GNU_strp_alt
- if (Form == DW_FORM_GNU_strp_alt || U == nullptr)
+ 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) {
uint64_t StrOffset;
- if (!U->getStringOffsetSectionItem(Offset, StrOffset))
+ if (!U || !U->getStringOffsetSectionItem(Offset, StrOffset))
return None;
Offset = StrOffset;
}
- if (const char *Str = U->getStringExtractor().getCStr(&Offset)) {
- return Str;
+ // 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;
}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp
new file mode 100644
index 000000000000..559afc7559bd
--- /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/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+template <typename... Ts>
+static Error createError(char const *Fmt, const Ts &... Vals) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
+}
+
+Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
+ uint32_t *OffsetPtr) {
+ HeaderOffset = *OffsetPtr;
+ // Read and verify the length field.
+ if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, sizeof(uint32_t)))
+ return createError("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 createError("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 createError("%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 createError("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 createError("unrecognised %s table version %" PRIu16
+ " in table at offset 0x%" PRIx32,
+ SectionName.data(), HeaderData.Version, HeaderOffset);
+ if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
+ return createError("%s table at offset 0x%" PRIx32
+ " has unsupported address size %hhu",
+ SectionName.data(), HeaderOffset, HeaderData.AddrSize);
+ if (HeaderData.SegSize != 0)
+ return createError("%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 createError(
+ "%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
index 206c12fa403f..00be75e1a94d 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
@@ -18,26 +18,13 @@
using namespace llvm;
-bool DWARFTypeUnit::extractImpl(DataExtractor debug_info,
- uint32_t *offset_ptr) {
- if (!DWARFUnit::extractImpl(debug_info, offset_ptr))
- return false;
- TypeHash = debug_info.getU64(offset_ptr);
- TypeOffset = debug_info.getU32(offset_ptr);
- // TypeOffset is relative to the beginning of the header,
- // so we have to account for the leading length field.
- // FIXME: The size of the length field is 12 in DWARF64.
- unsigned SizeOfLength = 4;
- return TypeOffset < getLength() + SizeOfLength;
-}
-
void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
- DWARFDie TD = getDIEForOffset(TypeOffset + getOffset());
+ DWARFDie TD = getDIEForOffset(getTypeOffset() + getOffset());
const char *Name = TD.getName(DINameKind::ShortName);
if (DumpOpts.SummarizeTypes) {
OS << "name = '" << Name << "'"
- << " type_signature = " << format("0x%016" PRIx64, TypeHash)
+ << " type_signature = " << format("0x%016" PRIx64, getTypeHash())
<< " length = " << format("0x%08x", getLength()) << '\n';
return;
}
@@ -50,8 +37,8 @@ void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
OS << " abbr_offset = " << format("0x%04x", getAbbreviations()->getOffset())
<< " addr_size = " << format("0x%02x", getAddressByteSize())
<< " name = '" << Name << "'"
- << " type_signature = " << format("0x%016" PRIx64, TypeHash)
- << " type_offset = " << format("0x%04x", TypeOffset)
+ << " 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))
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index df55d7debf92..3b408857d29f 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -8,17 +8,18 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.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/Support/DataExtractor.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/WithColor.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -32,7 +33,7 @@ using namespace dwarf;
void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) {
const DWARFObject &D = C.getDWARFObj();
- parseImpl(C, Section, C.getDebugAbbrev(), &D.getRangeSection(),
+ parseImpl(C, D, Section, C.getDebugAbbrev(), &D.getRangeSection(),
D.getStringSection(), D.getStringOffsetSection(),
&D.getAddrSection(), D.getLineSection(), D.isLittleEndian(), false,
false);
@@ -41,22 +42,22 @@ void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) {
void DWARFUnitSectionBase::parseDWO(DWARFContext &C,
const DWARFSection &DWOSection, bool Lazy) {
const DWARFObject &D = C.getDWARFObj();
- parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), &D.getRangeDWOSection(),
+ parseImpl(C, D, DWOSection, C.getDebugAbbrevDWO(), &D.getRangeDWOSection(),
D.getStringDWOSection(), D.getStringOffsetDWOSection(),
&D.getAddrSection(), D.getLineDWOSection(), C.isLittleEndian(),
true, Lazy);
}
DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
+ const DWARFUnitHeader &Header,
const DWARFDebugAbbrev *DA, const DWARFSection *RS,
StringRef SS, const DWARFSection &SOS,
const DWARFSection *AOS, const DWARFSection &LS, bool LE,
- bool IsDWO, const DWARFUnitSectionBase &UnitSection,
- const DWARFUnitIndex::Entry *IndexEntry)
- : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS),
- LineSection(LS), StringSection(SS), StringOffsetSection(SOS),
- AddrOffsetSection(AOS), isLittleEndian(LE), isDWO(IsDWO),
- UnitSection(UnitSection), IndexEntry(IndexEntry) {
+ bool IsDWO, const DWARFUnitSectionBase &UnitSection)
+ : Context(DC), InfoSection(Section), Header(Header), Abbrev(DA),
+ RangeSection(RS), LineSection(LS), StringSection(SS),
+ StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE),
+ isDWO(IsDWO), UnitSection(UnitSection) {
clear();
}
@@ -92,9 +93,16 @@ bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index,
return true;
}
-bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
+bool DWARFUnitHeader::extract(DWARFContext &Context,
+ const DWARFDataExtractor &debug_info,
+ uint32_t *offset_ptr,
+ DWARFSectionKind SectionKind,
+ const DWARFUnitIndex *Index) {
+ Offset = *offset_ptr;
+ IndexEntry = Index ? Index->getFromOffset(*offset_ptr) : nullptr;
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) {
@@ -102,8 +110,14 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
FormParams.AddrSize = debug_info.getU8(offset_ptr);
AbbrOffset = debug_info.getU32(offset_ptr);
} else {
- AbbrOffset = debug_info.getU32(offset_ptr);
+ 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)
@@ -116,12 +130,27 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
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)
+ if (!LengthOK || !VersionOK || !AddrSizeOK || !TypeOffsetOK)
return false;
// Keep track of the highest DWARF version we encounter across all units.
@@ -129,24 +158,31 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
return true;
}
-bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) {
- clear();
-
- Offset = *offset_ptr;
-
- if (debug_info.isValidOffset(*offset_ptr)) {
- if (extractImpl(debug_info, offset_ptr))
- return true;
-
- // reset the offset to where we tried to parse from if anything went wrong
- *offset_ptr = Offset;
+// 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) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(
+ "Did not detect a valid range list table with base = 0x%x", Offset);
+ return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
+ }
+ Offset -= 12U;
}
-
- return false;
+ llvm::DWARFDebugRnglistTable Table;
+ if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
+ return std::move(E);
+ return Table;
}
-bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
- DWARFDebugRangeList &RangeList) const {
+Error DWARFUnit::extractRangeList(uint32_t RangeListOffset,
+ DWARFDebugRangeList &RangeList) const {
// Require that compile unit is extracted.
assert(!DieArray.empty());
DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
@@ -156,10 +192,7 @@ bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
}
void DWARFUnit::clear() {
- Offset = 0;
- Length = 0;
Abbrevs = nullptr;
- FormParams = DWARFFormParams({0, 0, DWARF32});
BaseAddr.reset();
RangeSectionBase = 0;
AddrOffsetSectionBase = 0;
@@ -171,10 +204,6 @@ const char *DWARFUnit::getCompilationDir() {
return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr);
}
-Optional<uint64_t> DWARFUnit::getDWOId() {
- return toUnsigned(getUnitDIE().find(DW_AT_GNU_dwo_id));
-}
-
void DWARFUnit::extractDIEsToVector(
bool AppendCUDie, bool AppendNonCUDies,
std::vector<DWARFDebugInfoEntry> &Dies) const {
@@ -183,7 +212,7 @@ void DWARFUnit::extractDIEsToVector(
// Set the offset to that of the first DIE and calculate the start of the
// next compilation unit header.
- uint32_t DIEOffset = Offset + getHeaderSize();
+ uint32_t DIEOffset = getOffset() + getHeaderSize();
uint32_t NextCUOffset = getNextUnitOffset();
DWARFDebugInfoEntry DIE;
DWARFDataExtractor DebugInfoData = getDebugInfoExtractor();
@@ -224,8 +253,9 @@ void DWARFUnit::extractDIEsToVector(
// should always terminate at or before the start of the next compilation
// unit header).
if (DIEOffset > NextCUOffset)
- fprintf(stderr, "warning: DWARF compile unit extends beyond its "
- "bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), DIEOffset);
+ 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) {
@@ -242,10 +272,8 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
// If CU DIE was just parsed, copy several attribute values from it.
if (!HasCUDie) {
DWARFDie UnitDie = getUnitDIE();
- Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc});
- if (Optional<uint64_t> Addr = toAddress(PC))
- setBaseAddress({*Addr, PC->getSectionIndex()});
-
+ if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
+ Header.setDWOId(*DWOId);
if (!isDWO) {
assert(AddrOffsetSectionBase == 0);
assert(RangeSectionBase == 0);
@@ -263,6 +291,7 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
// which may differ from the unit's format.
uint64_t StringOffsetsContributionBase =
isDWO ? 0 : toSectionOffset(UnitDie.find(DW_AT_str_offsets_base), 0);
+ auto IndexEntry = Header.getIndexEntry();
if (IndexEntry)
if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS))
StringOffsetsContributionBase += C->Offset;
@@ -277,6 +306,34 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
StringOffsetsTableContribution = determineStringOffsetsTableContribution(
DA, StringOffsetsContributionBase);
+ // 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.
}
@@ -315,8 +372,23 @@ bool DWARFUnit::parseDWO() {
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);
- auto DWORangesBase = UnitDie.getRangesBaseAttribute();
- DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
+ 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;
}
@@ -327,16 +399,56 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
}
}
+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());
+ return RangeListOrError.takeError();
+ }
+
+ return make_error<StringError>("missing or invalid range list table",
+ inconvertibleErrorCode());
+}
+
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromIndex(uint32_t Index) {
+ if (auto Offset = getRnglistOffset(Index))
+ return findRnglistFromOffset(*Offset + RangeSectionBase);
+
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ if (RngListTable)
+ Stream << format("invalid range list table index %d", Index);
+ else
+ Stream << "missing or invalid range list table";
+ return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
+}
+
void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
DWARFDie UnitDie = getUnitDIE();
if (!UnitDie)
return;
// First, check if unit DIE describes address ranges for the whole unit.
- const auto &CUDIERanges = UnitDie.getAddressRanges();
- if (!CUDIERanges.empty()) {
- CURanges.insert(CURanges.end(), CUDIERanges.begin(), CUDIERanges.end());
- return;
- }
+ auto CUDIERangesOrError = UnitDie.getAddressRanges();
+ if (CUDIERangesOrError) {
+ if (!CUDIERangesOrError.get().empty()) {
+ CURanges.insert(CURanges.end(), CUDIERangesOrError.get().begin(),
+ CUDIERangesOrError.get().end());
+ return;
+ }
+ } else
+ WithColor::error() << "decoding address ranges: "
+ << toString(CUDIERangesOrError.takeError()) << '\n';
// This function is usually called if there in no .debug_aranges section
// in order to produce a compile unit level set of address ranges that
@@ -360,378 +472,49 @@ void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
clearDIEs(true);
}
-// Populates a map from PC addresses to subprogram DIEs.
-//
-// This routine tries to look at the smallest amount of the debug info it can
-// to locate the DIEs. This is because many subprograms will never end up being
-// read or needed at all. We want to be as lazy as possible.
-void DWARFUnit::buildSubprogramDIEAddrMap() {
- assert(SubprogramDIEAddrMap.empty() && "Must only build this map once!");
- SmallVector<DWARFDie, 16> Worklist;
- Worklist.push_back(getUnitDIE());
- do {
- DWARFDie Die = Worklist.pop_back_val();
-
- // Queue up child DIEs to recurse through.
- // FIXME: This causes us to read a lot more debug info than we really need.
- // We should look at pruning out DIEs which cannot transitively hold
- // separate subprograms.
- for (DWARFDie Child : Die.children())
- Worklist.push_back(Child);
-
- // If handling a non-subprogram DIE, nothing else to do.
- if (!Die.isSubprogramDIE())
- continue;
-
- // For subprogram DIEs, store them, and insert relevant markers into the
- // address map. We don't care about overlap at all here as DWARF doesn't
- // meaningfully support that, so we simply will insert a range with no DIE
- // starting from the high PC. In the event there are overlaps, sorting
- // these may truncate things in surprising ways but still will allow
- // lookups to proceed.
- int DIEIndex = SubprogramDIEAddrInfos.size();
- SubprogramDIEAddrInfos.push_back({Die, (uint64_t)-1, {}});
- for (const auto &R : Die.getAddressRanges()) {
- // Ignore 0-sized ranges.
- if (R.LowPC == R.HighPC)
- continue;
-
- SubprogramDIEAddrMap.push_back({R.LowPC, DIEIndex});
- SubprogramDIEAddrMap.push_back({R.HighPC, -1});
-
- if (R.LowPC < SubprogramDIEAddrInfos.back().SubprogramBasePC)
- SubprogramDIEAddrInfos.back().SubprogramBasePC = R.LowPC;
- }
- } while (!Worklist.empty());
-
- if (SubprogramDIEAddrMap.empty()) {
- // If we found no ranges, create a no-op map so that lookups remain simple
- // but never find anything.
- SubprogramDIEAddrMap.push_back({0, -1});
- return;
- }
-
- // Next, sort the ranges and remove both exact duplicates and runs with the
- // same DIE index. We order the ranges so that non-empty ranges are
- // preferred. Because there may be ties, we also need to use stable sort.
- std::stable_sort(SubprogramDIEAddrMap.begin(), SubprogramDIEAddrMap.end(),
- [](const std::pair<uint64_t, int64_t> &LHS,
- const std::pair<uint64_t, int64_t> &RHS) {
- if (LHS.first < RHS.first)
- return true;
- if (LHS.first > RHS.first)
- return false;
-
- // For ranges that start at the same address, keep the one
- // with a DIE.
- if (LHS.second != -1 && RHS.second == -1)
- return true;
-
- return false;
- });
- SubprogramDIEAddrMap.erase(
- std::unique(SubprogramDIEAddrMap.begin(), SubprogramDIEAddrMap.end(),
- [](const std::pair<uint64_t, int64_t> &LHS,
- const std::pair<uint64_t, int64_t> &RHS) {
- // If the start addresses are exactly the same, we can
- // remove all but the first one as it is the only one that
- // will be found and used.
- //
- // If the DIE indices are the same, we can "merge" the
- // ranges by eliminating the second.
- return LHS.first == RHS.first || LHS.second == RHS.second;
- }),
- SubprogramDIEAddrMap.end());
-
- assert(SubprogramDIEAddrMap.back().second == -1 &&
- "The last interval must not have a DIE as each DIE's address range is "
- "bounded.");
-}
-
-// Build the second level of mapping from PC to DIE, specifically one that maps
-// a PC *within* a particular DWARF subprogram into a precise, maximally nested
-// inlined subroutine DIE (if any exists). We build a separate map for each
-// subprogram because many subprograms will never get queried for an address
-// and this allows us to be significantly lazier in reading the DWARF itself.
-void DWARFUnit::buildInlinedSubroutineDIEAddrMap(
- SubprogramDIEAddrInfo &SPInfo) {
- auto &AddrMap = SPInfo.InlinedSubroutineDIEAddrMap;
- uint64_t BasePC = SPInfo.SubprogramBasePC;
-
- auto SubroutineAddrMapSorter = [](const std::pair<int, int> &LHS,
- const std::pair<int, int> &RHS) {
- if (LHS.first < RHS.first)
- return true;
- if (LHS.first > RHS.first)
- return false;
-
- // For ranges that start at the same address, keep the
- // non-empty one.
- if (LHS.second != -1 && RHS.second == -1)
- return true;
-
- return false;
- };
- auto SubroutineAddrMapUniquer = [](const std::pair<int, int> &LHS,
- const std::pair<int, int> &RHS) {
- // If the start addresses are exactly the same, we can
- // remove all but the first one as it is the only one that
- // will be found and used.
- //
- // If the DIE indices are the same, we can "merge" the
- // ranges by eliminating the second.
- return LHS.first == RHS.first || LHS.second == RHS.second;
- };
-
- struct DieAndParentIntervalRange {
- DWARFDie Die;
- int ParentIntervalsBeginIdx, ParentIntervalsEndIdx;
- };
-
- SmallVector<DieAndParentIntervalRange, 16> Worklist;
- auto EnqueueChildDIEs = [&](const DWARFDie &Die, int ParentIntervalsBeginIdx,
- int ParentIntervalsEndIdx) {
- for (DWARFDie Child : Die.children())
- Worklist.push_back(
- {Child, ParentIntervalsBeginIdx, ParentIntervalsEndIdx});
- };
- EnqueueChildDIEs(SPInfo.SubprogramDIE, 0, 0);
- while (!Worklist.empty()) {
- DWARFDie Die = Worklist.back().Die;
- int ParentIntervalsBeginIdx = Worklist.back().ParentIntervalsBeginIdx;
- int ParentIntervalsEndIdx = Worklist.back().ParentIntervalsEndIdx;
- Worklist.pop_back();
-
- // If we encounter a nested subprogram, simply ignore it. We map to
- // (disjoint) subprograms before arriving here and we don't want to examine
- // any inlined subroutines of an unrelated subpragram.
- if (Die.getTag() == DW_TAG_subprogram)
- continue;
-
- // For non-subroutines, just recurse to keep searching for inlined
- // subroutines.
- if (Die.getTag() != DW_TAG_inlined_subroutine) {
- EnqueueChildDIEs(Die, ParentIntervalsBeginIdx, ParentIntervalsEndIdx);
- continue;
- }
-
- // Capture the inlined subroutine DIE that we will reference from the map.
- int DIEIndex = InlinedSubroutineDIEs.size();
- InlinedSubroutineDIEs.push_back(Die);
-
- int DieIntervalsBeginIdx = AddrMap.size();
- // First collect the PC ranges for this DIE into our subroutine interval
- // map.
- for (auto R : Die.getAddressRanges()) {
- // Clamp the PCs to be above the base.
- R.LowPC = std::max(R.LowPC, BasePC);
- R.HighPC = std::max(R.HighPC, BasePC);
- // Compute relative PCs from the subprogram base and drop down to an
- // unsigned 32-bit int to represent them within the data structure. This
- // lets us cover a 4gb single subprogram. Because subprograms may be
- // partitioned into distant parts of a binary (think hot/cold
- // partitioning) we want to preserve as much as we can here without
- // burning extra memory. Past that, we will simply truncate and lose the
- // ability to map those PCs to a DIE more precise than the subprogram.
- const uint32_t MaxRelativePC = std::numeric_limits<uint32_t>::max();
- uint32_t RelativeLowPC = (R.LowPC - BasePC) > (uint64_t)MaxRelativePC
- ? MaxRelativePC
- : (uint32_t)(R.LowPC - BasePC);
- uint32_t RelativeHighPC = (R.HighPC - BasePC) > (uint64_t)MaxRelativePC
- ? MaxRelativePC
- : (uint32_t)(R.HighPC - BasePC);
- // Ignore empty or bogus ranges.
- if (RelativeLowPC >= RelativeHighPC)
- continue;
- AddrMap.push_back({RelativeLowPC, DIEIndex});
- AddrMap.push_back({RelativeHighPC, -1});
- }
-
- // If there are no address ranges, there is nothing to do to map into them
- // and there cannot be any child subroutine DIEs with address ranges of
- // interest as those would all be required to nest within this DIE's
- // non-existent ranges, so we can immediately continue to the next DIE in
- // the worklist.
- if (DieIntervalsBeginIdx == (int)AddrMap.size())
- continue;
-
- // The PCs from this DIE should never overlap, so we can easily sort them
- // here.
- std::sort(AddrMap.begin() + DieIntervalsBeginIdx, AddrMap.end(),
- SubroutineAddrMapSorter);
- // Remove any dead ranges. These should only come from "empty" ranges that
- // were clobbered by some other range.
- AddrMap.erase(std::unique(AddrMap.begin() + DieIntervalsBeginIdx,
- AddrMap.end(), SubroutineAddrMapUniquer),
- AddrMap.end());
-
- // Compute the end index of this DIE's addr map intervals.
- int DieIntervalsEndIdx = AddrMap.size();
-
- assert(DieIntervalsBeginIdx != DieIntervalsEndIdx &&
- "Must not have an empty map for this layer!");
- assert(AddrMap.back().second == -1 && "Must end with an empty range!");
- assert(std::is_sorted(AddrMap.begin() + DieIntervalsBeginIdx, AddrMap.end(),
- less_first()) &&
- "Failed to sort this DIE's interals!");
-
- // If we have any parent intervals, walk the newly added ranges and find
- // the parent ranges they were inserted into. Both of these are sorted and
- // neither has any overlaps. We need to append new ranges to split up any
- // parent ranges these new ranges would overlap when we merge them.
- if (ParentIntervalsBeginIdx != ParentIntervalsEndIdx) {
- int ParentIntervalIdx = ParentIntervalsBeginIdx;
- for (int i = DieIntervalsBeginIdx, e = DieIntervalsEndIdx - 1; i < e;
- ++i) {
- const uint32_t IntervalStart = AddrMap[i].first;
- const uint32_t IntervalEnd = AddrMap[i + 1].first;
- const int IntervalDieIdx = AddrMap[i].second;
- if (IntervalDieIdx == -1) {
- // For empty intervals, nothing is required. This is a bit surprising
- // however. If the prior interval overlaps a parent interval and this
- // would be necessary to mark the end, we will synthesize a new end
- // that switches back to the parent DIE below. And this interval will
- // get dropped in favor of one with a DIE attached. However, we'll
- // still include this and so worst-case, it will still end the prior
- // interval.
- continue;
- }
-
- // We are walking the new ranges in order, so search forward from the
- // last point for a parent range that might overlap.
- auto ParentIntervalsRange =
- make_range(AddrMap.begin() + ParentIntervalIdx,
- AddrMap.begin() + ParentIntervalsEndIdx);
- assert(std::is_sorted(ParentIntervalsRange.begin(),
- ParentIntervalsRange.end(), less_first()) &&
- "Unsorted parent intervals can't be searched!");
- auto PI = std::upper_bound(
- ParentIntervalsRange.begin(), ParentIntervalsRange.end(),
- IntervalStart,
- [](uint32_t LHS, const std::pair<uint32_t, int32_t> &RHS) {
- return LHS < RHS.first;
- });
- if (PI == ParentIntervalsRange.begin() ||
- PI == ParentIntervalsRange.end())
- continue;
-
- ParentIntervalIdx = PI - AddrMap.begin();
- int32_t &ParentIntervalDieIdx = std::prev(PI)->second;
- uint32_t &ParentIntervalStart = std::prev(PI)->first;
- const uint32_t ParentIntervalEnd = PI->first;
-
- // If the new range starts exactly at the position of the parent range,
- // we need to adjust the parent range. Note that these collisions can
- // only happen with the original parent range because we will merge any
- // adjacent ranges in the child.
- if (IntervalStart == ParentIntervalStart) {
- // If there will be a tail, just shift the start of the parent
- // forward. Note that this cannot change the parent ordering.
- if (IntervalEnd < ParentIntervalEnd) {
- ParentIntervalStart = IntervalEnd;
- continue;
- }
- // Otherwise, mark this as becoming empty so we'll remove it and
- // prefer the child range.
- ParentIntervalDieIdx = -1;
+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;
}
-
- // Finally, if the parent interval will need to remain as a prefix to
- // this one, insert a new interval to cover any tail.
- if (IntervalEnd < ParentIntervalEnd)
- AddrMap.push_back({IntervalEnd, ParentIntervalDieIdx});
+ AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die);
}
- }
-
- // Note that we don't need to re-sort even this DIE's address map intervals
- // after this. All of the newly added intervals actually fill in *gaps* in
- // this DIE's address map, and we know that children won't need to lookup
- // into those gaps.
-
- // Recurse through its children, giving them the interval map range of this
- // DIE to use as their parent intervals.
- EnqueueChildDIEs(Die, DieIntervalsBeginIdx, DieIntervalsEndIdx);
- }
-
- if (AddrMap.empty()) {
- AddrMap.push_back({0, -1});
- return;
+ } else
+ llvm::consumeError(DIERangesOrError.takeError());
}
-
- // Now that we've added all of the intervals needed, we need to resort and
- // unique them. Most notably, this will remove all the empty ranges that had
- // a parent range covering, etc. We only expect a single non-empty interval
- // at any given start point, so we just use std::sort. This could potentially
- // produce non-deterministic maps for invalid DWARF.
- std::sort(AddrMap.begin(), AddrMap.end(), SubroutineAddrMapSorter);
- AddrMap.erase(
- std::unique(AddrMap.begin(), AddrMap.end(), SubroutineAddrMapUniquer),
- AddrMap.end());
+ // 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);
-
- // We use a two-level mapping structure to locate subroutines for a given PC
- // address.
- //
- // First, we map the address to a subprogram. This can be done more cheaply
- // because subprograms cannot nest within each other. It also allows us to
- // avoid detailed examination of many subprograms, instead only focusing on
- // the ones which we end up actively querying.
- if (SubprogramDIEAddrMap.empty())
- buildSubprogramDIEAddrMap();
-
- assert(!SubprogramDIEAddrMap.empty() &&
- "We must always end up with a non-empty map!");
-
- auto I = std::upper_bound(
- SubprogramDIEAddrMap.begin(), SubprogramDIEAddrMap.end(), Address,
- [](uint64_t LHS, const std::pair<uint64_t, int64_t> &RHS) {
- return LHS < RHS.first;
- });
- // If we find the beginning, then the address is before the first subprogram.
- if (I == SubprogramDIEAddrMap.begin())
+ if (AddrDieMap.empty())
+ updateAddressDieMap(getUnitDIE());
+ auto R = AddrDieMap.upper_bound(Address);
+ if (R == AddrDieMap.begin())
return DWARFDie();
- // Back up to the interval containing the address and see if it
- // has a DIE associated with it.
- --I;
- if (I->second == -1)
+ // upper_bound's previous item contains Address.
+ --R;
+ if (Address >= R->second.first)
return DWARFDie();
-
- auto &SPInfo = SubprogramDIEAddrInfos[I->second];
-
- // Now that we have the subprogram for this address, we do the second level
- // mapping by building a map within a subprogram's PC range to any specific
- // inlined subroutine.
- if (SPInfo.InlinedSubroutineDIEAddrMap.empty())
- buildInlinedSubroutineDIEAddrMap(SPInfo);
-
- // We lookup within the inlined subroutine using a subprogram-relative
- // address.
- assert(Address >= SPInfo.SubprogramBasePC &&
- "Address isn't above the start of the subprogram!");
- uint32_t RelativeAddr = ((Address - SPInfo.SubprogramBasePC) >
- (uint64_t)std::numeric_limits<uint32_t>::max())
- ? std::numeric_limits<uint32_t>::max()
- : (uint32_t)(Address - SPInfo.SubprogramBasePC);
-
- auto J =
- std::upper_bound(SPInfo.InlinedSubroutineDIEAddrMap.begin(),
- SPInfo.InlinedSubroutineDIEAddrMap.end(), RelativeAddr,
- [](uint32_t LHS, const std::pair<uint32_t, int32_t> &RHS) {
- return LHS < RHS.first;
- });
- // If we find the beginning, the address is before any inlined subroutine so
- // return the subprogram DIE.
- if (J == SPInfo.InlinedSubroutineDIEAddrMap.begin())
- return SPInfo.SubprogramDIE;
- // Back up `J` and return the inlined subroutine if we have one or the
- // subprogram if we don't.
- --J;
- return J->second == -1 ? SPInfo.SubprogramDIE
- : InlinedSubroutineDIEs[J->second];
+ return R->second.second;
}
void
@@ -745,11 +528,15 @@ DWARFUnit::getInlinedChainForAddress(uint64_t Address,
DWARFDie SubroutineDIE =
(DWO ? DWO.get() : this)->getSubroutineForAddress(Address);
- while (SubroutineDIE) {
- if (SubroutineDIE.isSubroutineDIE())
+ 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,
@@ -799,6 +586,25 @@ DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) {
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();
@@ -810,12 +616,39 @@ DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) {
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(AbbrOffset);
+ Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset());
return Abbrevs;
}
+llvm::Optional<BaseAddress> DWARFUnit::getBaseAddress() {
+ if (BaseAddr)
+ return BaseAddr;
+
+ DWARFDie UnitDie = getUnitDIE();
+ Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc});
+ if (Optional<uint64_t> Addr = toAddress(PC))
+ BaseAddr = {*Addr, PC->getSectionIndex()};
+
+ return BaseAddr;
+}
+
Optional<StrOffsetsContributionDescriptor>
StrOffsetsContributionDescriptor::validateContributionSize(
DWARFDataExtractor &DA) {
@@ -843,7 +676,9 @@ parseDWARF64StringOffsetsTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
uint64_t Size = DA.getU64(&Offset);
uint8_t Version = DA.getU16(&Offset);
(void)DA.getU16(&Offset); // padding
- return StrOffsetsContributionDescriptor(Offset, Size, Version, DWARF64);
+ // 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 StrOffsetsContributionDescriptor(Offset, Size - 4, Version, DWARF64);
//return Optional<StrOffsetsContributionDescriptor>(Descriptor);
}
@@ -858,7 +693,10 @@ parseDWARF32StringOffsetsTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
return Optional<StrOffsetsContributionDescriptor>();
uint8_t Version = DA.getU16(&Offset);
(void)DA.getU16(&Offset); // padding
- return StrOffsetsContributionDescriptor(Offset, ContributionSize, Version, DWARF32);
+ // 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 StrOffsetsContributionDescriptor(Offset, ContributionSize - 4, Version,
+ DWARF32);
//return Optional<StrOffsetsContributionDescriptor>(Descriptor);
}
@@ -891,6 +729,7 @@ DWARFUnit::determineStringOffsetsTableContributionDWO(DWARFDataExtractor &DA,
// index table (in a package file). In a .dwo file it is simply
// the length of the string offsets section.
uint64_t Size = 0;
+ auto IndexEntry = Header.getIndexEntry();
if (!IndexEntry)
Size = StringOffsetSection.Data.size();
else if (const auto *C = IndexEntry->getOffset(DW_SECT_STR_OFFSETS))
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 3d473698b463..82d52c467bc0 100644
--- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#include "SyntaxHighlighting.h"
#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"
@@ -16,8 +16,9 @@
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
-#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/Support/DJB.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <set>
@@ -26,7 +27,6 @@
using namespace llvm;
using namespace dwarf;
using namespace object;
-using namespace syntax;
DWARFVerifier::DieRangeInfo::address_range_iterator
DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
@@ -171,7 +171,7 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
return Success;
}
-bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit, uint8_t UnitType) {
+bool DWARFVerifier::verifyUnitContents(DWARFUnit &Unit, uint8_t UnitType) {
uint32_t NumUnitErrors = 0;
unsigned NumDies = Unit.getNumDIEs();
for (unsigned I = 0; I < NumDies; ++I) {
@@ -274,16 +274,17 @@ bool DWARFVerifier::handleDebugInfo() {
if (isUnitDWARF64)
break;
} else {
+ DWARFUnitHeader Header;
+ Header.extract(DCtx, DebugInfoData, &OffsetStart);
std::unique_ptr<DWARFUnit> Unit;
switch (UnitType) {
case dwarf::DW_UT_type:
case dwarf::DW_UT_split_type: {
Unit.reset(new DWARFTypeUnit(
- DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
+ DCtx, DObj.getInfoSection(), Header, DCtx.getDebugAbbrev(),
&DObj.getRangeSection(), DObj.getStringSection(),
DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
- DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection,
- nullptr));
+ DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection));
break;
}
case dwarf::DW_UT_skeleton:
@@ -294,16 +295,14 @@ bool DWARFVerifier::handleDebugInfo() {
// verifying a compile unit in DWARF v4.
case 0: {
Unit.reset(new DWARFCompileUnit(
- DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
+ DCtx, DObj.getInfoSection(), Header, DCtx.getDebugAbbrev(),
&DObj.getRangeSection(), DObj.getStringSection(),
DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
- DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection,
- nullptr));
+ DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection));
break;
}
default: { llvm_unreachable("Invalid UnitType."); }
}
- Unit->extract(DebugInfoData, &OffsetStart);
if (!verifyUnitContents(*Unit, UnitType))
++NumDebugInfoErrors;
}
@@ -325,8 +324,15 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
if (!Die.isValid())
return NumErrors;
- DWARFAddressRangesVector Ranges = Die.getAddressRanges();
+ 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);
@@ -363,10 +369,9 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
ParentRI.Die.getTag() == DW_TAG_subprogram);
if (ShouldBeContained && !ParentRI.contains(RI)) {
++NumErrors;
- error() << "DIE address ranges are not "
- "contained in its parent's ranges:";
- Die.dump(OS, 0);
+ error() << "DIE address ranges are not contained in its parent's ranges:";
ParentRI.Die.dump(OS, 0);
+ Die.dump(OS, 2);
OS << "\n";
}
@@ -410,22 +415,27 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
ReportError("DIE has invalid DW_AT_stmt_list encoding:");
break;
case DW_AT_location: {
- Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock();
- if (!Expr) {
- ReportError("DIE has invalid DW_AT_location encoding:");
- break;
+ 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()});
}
-
- DWARFUnit *U = Die.getDwarfUnit();
- DataExtractor Data(
- StringRef(reinterpret_cast<const char *>(Expr->data()), Expr->size()),
- DCtx.isLittleEndian(), 0);
- DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
- bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
- return Op.isError();
- });
- if (Error)
- ReportError("DIE contains invalid DWARF expression:");
break;
}
@@ -669,13 +679,13 @@ bool DWARFVerifier::handleDebugLine() {
return NumDebugLineErrors == 0;
}
-unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection,
- DataExtractor *StrData,
- const char *SectionName) {
+unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
+ DataExtractor *StrData,
+ const char *SectionName) {
unsigned NumErrors = 0;
DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
DCtx.isLittleEndian(), 0);
- DWARFAcceleratorTable AccelTable(AccelSectionData, *StrData);
+ AppleAcceleratorTable AccelTable(AccelSectionData, *StrData);
OS << "Verifying " << SectionName << "...\n";
@@ -773,33 +783,572 @@ unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection,
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) {
+ 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 (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 EntryNames = getNames(Die);
+ 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 unit has a name but it shouldn't be indexed.
+ case DW_TAG_compile_unit:
+ 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<DWARFCompileUnit> &CU : DCtx.compile_units()) {
+ if (const DWARFDebugNames::NameIndex *NI =
+ AccelTable.getCUNameIndex(CU->getOffset())) {
+ for (const DWARFDebugInfoEntry &Die : CU->dies())
+ NumErrors += verifyNameIndexCompleteness(DWARFDie(CU.get(), &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 +=
- verifyAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names");
+ verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData, ".apple_names");
if (!D.getAppleTypesSection().Data.empty())
NumErrors +=
- verifyAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");
+ verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");
if (!D.getAppleNamespacesSection().Data.empty())
- NumErrors += verifyAccelTable(&D.getAppleNamespacesSection(), &StrData,
+ NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData,
".apple_namespaces");
if (!D.getAppleObjCSection().Data.empty())
NumErrors +=
- verifyAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc");
+ 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(OS, syntax::Error).get() << "error: ";
-}
+raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); }
-raw_ostream &DWARFVerifier::warn() const {
- return WithColor(OS, syntax::Warning).get() << "warning: ";
-}
+raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); }
-raw_ostream &DWARFVerifier::note() const {
- return WithColor(OS, syntax::Note).get() << "note: ";
-}
+raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); }
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp
deleted file mode 100644
index 65d66fc8f514..000000000000
--- a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//===- SyntaxHighlighting.cpp ---------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SyntaxHighlighting.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm;
-using namespace dwarf;
-using namespace syntax;
-
-static cl::opt<cl::boolOrDefault>
- UseColor("color",
- cl::desc("use colored syntax highlighting (default=autodetect)"),
- cl::init(cl::BOU_UNSET));
-
-WithColor::WithColor(raw_ostream &OS, enum HighlightColor Type) : OS(OS) {
- // Detect color from terminal type unless the user passed the --color option.
- if (UseColor == cl::BOU_UNSET ? OS.has_colors() : UseColor == cl::BOU_TRUE) {
- switch (Type) {
- case Address: OS.changeColor(raw_ostream::YELLOW); break;
- case String: OS.changeColor(raw_ostream::GREEN); break;
- case Tag: OS.changeColor(raw_ostream::BLUE); break;
- case Attribute: OS.changeColor(raw_ostream::CYAN); break;
- case Enumerator: OS.changeColor(raw_ostream::MAGENTA); break;
- case Macro: OS.changeColor(raw_ostream::RED); break;
- case Error: OS.changeColor(raw_ostream::RED, true); break;
- case Warning: OS.changeColor(raw_ostream::MAGENTA, true); break;
- case Note: OS.changeColor(raw_ostream::BLACK, true); break;
- }
- }
-}
-
-WithColor::~WithColor() {
- if (UseColor == cl::BOU_UNSET ? OS.has_colors() : UseColor == cl::BOU_TRUE)
- OS.resetColor();
-}
diff --git a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h b/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h
deleted file mode 100644
index 686cf2c77608..000000000000
--- a/contrib/llvm/lib/DebugInfo/DWARF/SyntaxHighlighting.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//===- SyntaxHighlighting.h -------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H
-#define LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H
-
-namespace llvm {
-
-class raw_ostream;
-
-namespace dwarf {
-namespace syntax {
-
-// Symbolic names for various syntax elements.
-enum HighlightColor {
- Address,
- String,
- Tag,
- Attribute,
- Enumerator,
- Macro,
- Error,
- Warning,
- Note
-};
-
-/// An RAII object that temporarily switches an output stream to a
-/// specific color.
-class WithColor {
- raw_ostream &OS;
-
-public:
- /// To be used like this: WithColor(OS, syntax::String) << "text";
- WithColor(raw_ostream &OS, enum HighlightColor Type);
- ~WithColor();
-
- raw_ostream &get() { return OS; }
- operator raw_ostream &() { return OS; }
-};
-
-} // end namespace syntax
-} // end namespace dwarf
-
-} // end namespace llvm
-
-#endif // LLVM_LIB_DEBUGINFO_SYNTAXHIGHLIGHTING_H