summaryrefslogtreecommitdiff
path: root/lib/DebugInfo/DWARF
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo/DWARF')
-rw-r--r--lib/DebugInfo/DWARF/CMakeLists.txt1
-rw-r--r--lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp23
-rw-r--r--lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp104
-rw-r--r--lib/DebugInfo/DWARF/DWARFCompileUnit.cpp2
-rw-r--r--lib/DebugInfo/DWARF/DWARFContext.cpp1091
-rw-r--r--lib/DebugInfo/DWARF/DWARFDataExtractor.cpp13
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp32
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugAranges.cpp7
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugFrame.cpp52
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugLine.cpp189
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugLoc.cpp253
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp3
-rw-r--r--lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp44
-rw-r--r--lib/DebugInfo/DWARF/DWARFDie.cpp299
-rw-r--r--lib/DebugInfo/DWARF/DWARFExpression.cpp274
-rw-r--r--lib/DebugInfo/DWARF/DWARFFormValue.cpp65
-rw-r--r--lib/DebugInfo/DWARF/DWARFTypeUnit.cpp6
-rw-r--r--lib/DebugInfo/DWARF/DWARFUnit.cpp92
-rw-r--r--lib/DebugInfo/DWARF/DWARFUnitIndex.cpp23
-rw-r--r--lib/DebugInfo/DWARF/DWARFVerifier.cpp564
-rw-r--r--lib/DebugInfo/DWARF/LLVMBuild.txt2
-rw-r--r--lib/DebugInfo/DWARF/SyntaxHighlighting.cpp15
-rw-r--r--lib/DebugInfo/DWARF/SyntaxHighlighting.h16
23 files changed, 2351 insertions, 819 deletions
diff --git a/lib/DebugInfo/DWARF/CMakeLists.txt b/lib/DebugInfo/DWARF/CMakeLists.txt
index 11f94509e8fa..620016d76fb6 100644
--- a/lib/DebugInfo/DWARF/CMakeLists.txt
+++ b/lib/DebugInfo/DWARF/CMakeLists.txt
@@ -15,6 +15,7 @@ add_llvm_library(LLVMDebugInfoDWARF
DWARFDebugPubTable.cpp
DWARFDebugRangeList.cpp
DWARFDie.cpp
+ DWARFExpression.cpp
DWARFFormValue.cpp
DWARFGdbIndex.cpp
DWARFTypeUnit.cpp
diff --git a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
index bb475a669efb..f593953c62ff 100644
--- a/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
+++ b/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -63,13 +63,13 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data,
auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
if (A && F) {
- Optional<int64_t> V;
bool IsImplicitConst = (F == DW_FORM_implicit_const);
if (IsImplicitConst) {
- V = Data.getSLEB128(OffsetPtr);
+ int64_t V = Data.getSLEB128(OffsetPtr);
AttributeSpecs.push_back(AttributeSpec(A, F, V));
continue;
}
+ Optional<uint8_t> ByteSize;
// If this abbrevation still has a fixed byte size, then update the
// FixedAttributeSize as needed.
switch (F) {
@@ -96,11 +96,10 @@ 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 (auto Size =
- DWARFFormValue::getFixedByteSize(F, DWARFFormParams())) {
- V = *Size;
+ if ((ByteSize =
+ DWARFFormValue::getFixedByteSize(F, DWARFFormParams()))) {
if (FixedAttributeSize)
- FixedAttributeSize->NumBytes += *V;
+ FixedAttributeSize->NumBytes += *ByteSize;
break;
}
// Indicate we no longer have a fixed byte size for this
@@ -110,7 +109,7 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data,
break;
}
// Record this attribute and its fixed size if it has one.
- AttributeSpecs.push_back(AttributeSpec(A, F, V));
+ AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));
} else if (A == 0 && F == 0) {
// We successfully reached the end of this abbreviation declaration
// since both attribute and form are zero.
@@ -149,7 +148,7 @@ void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
else
OS << format("DW_FORM_Unknown_%x", Spec.Form);
if (Spec.isImplicitConst())
- OS << '\t' << *Spec.ByteSizeOrValue;
+ OS << '\t' << Spec.getImplicitConstValue();
OS << '\n';
}
OS << '\n';
@@ -182,10 +181,10 @@ Optional<DWARFFormValue> DWARFAbbreviationDeclaration::getAttributeValue(
// We have arrived at the attribute to extract, extract if from Offset.
DWARFFormValue FormValue(Spec.Form);
if (Spec.isImplicitConst()) {
- FormValue.setSValue(*Spec.ByteSizeOrValue);
+ FormValue.setSValue(Spec.getImplicitConstValue());
return FormValue;
}
- if (FormValue.extractValue(DebugInfoData, &Offset, &U))
+ if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
return FormValue;
}
// March Offset along until we get to the attribute we want.
@@ -215,8 +214,8 @@ Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
const DWARFUnit &U) const {
if (isImplicitConst())
return 0;
- if (ByteSizeOrValue)
- return ByteSizeOrValue;
+ if (ByteSize.HasByteSize)
+ return ByteSize.ByteSize;
Optional<int64_t> S;
auto FixedByteSize =
DWARFFormValue::getFixedByteSize(Form, U.getFormParams());
diff --git a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
index 9ae7c9a07f76..17f29737bf93 100644
--- a/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+++ b/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -11,8 +11,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/BinaryFormat/Dwarf.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
-#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
@@ -23,12 +21,13 @@
using namespace llvm;
-bool DWARFAcceleratorTable::extract() {
+llvm::Error DWARFAcceleratorTable::extract() {
uint32_t Offset = 0;
// Check that we can at least read the header.
if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength)+4))
- return false;
+ return make_error<StringError>("Section too small: cannot read header.",
+ inconvertibleErrorCode());
Hdr.Magic = AccelSection.getU32(&Offset);
Hdr.Version = AccelSection.getU16(&Offset);
@@ -39,9 +38,13 @@ bool DWARFAcceleratorTable::extract() {
// Check that we can read all the hashes and offsets from the
// section (see SourceLevelDebugging.rst for the structure of the index).
+ // We need to substract one because we're checking for an *offset* which is
+ // equal to the size for an empty table and hence pointer after the section.
if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
- Hdr.NumBuckets*4 + Hdr.NumHashes*8))
- return false;
+ Hdr.NumBuckets * 4 + Hdr.NumHashes * 8 - 1))
+ return make_error<StringError>(
+ "Section too small: cannot read buckets and hashes.",
+ inconvertibleErrorCode());
HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
uint32_t NumAtoms = AccelSection.getU32(&Offset);
@@ -52,7 +55,8 @@ bool DWARFAcceleratorTable::extract() {
HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
}
- return true;
+ IsValid = true;
+ return Error::success();
}
uint32_t DWARFAcceleratorTable::getNumBuckets() { return Hdr.NumBuckets; }
@@ -73,6 +77,8 @@ bool DWARFAcceleratorTable::validateForms() {
DWARFFormValue FormValue(Atom.second);
switch (Atom.first) {
case dwarf::DW_ATOM_die_offset:
+ case dwarf::DW_ATOM_die_tag:
+ case dwarf::DW_ATOM_type_flags:
if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
!FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
FormValue.getForm() == dwarf::DW_FORM_sdata)
@@ -84,24 +90,33 @@ bool DWARFAcceleratorTable::validateForms() {
return true;
}
-uint32_t DWARFAcceleratorTable::readAtoms(uint32_t &HashDataOffset) {
+std::pair<uint32_t, dwarf::Tag>
+DWARFAcceleratorTable::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};
for (auto Atom : getAtomsDesc()) {
DWARFFormValue FormValue(Atom.second);
- FormValue.extractValue(AccelSection, &HashDataOffset, NULL);
+ FormValue.extractValue(AccelSection, &HashDataOffset, FormParams);
switch (Atom.first) {
case dwarf::DW_ATOM_die_offset:
DieOffset = *FormValue.getAsUnsignedConstant();
break;
+ case dwarf::DW_ATOM_die_tag:
+ DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
+ break;
default:
break;
}
}
- return DieOffset;
+ return {DieOffset, DieTag};
}
LLVM_DUMP_METHOD void DWARFAcceleratorTable::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'
@@ -135,6 +150,7 @@ LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const {
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};
for (unsigned Bucket = 0; Bucket < Hdr.NumBuckets; ++Bucket) {
unsigned Index = AccelSection.getU32(&Offset);
@@ -171,7 +187,7 @@ LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const {
unsigned i = 0;
for (auto &Atom : AtomForms) {
OS << format("{Atom[%d]: ", i++);
- if (Atom.extractValue(AccelSection, &DataOffset, nullptr))
+ if (Atom.extractValue(AccelSection, &DataOffset, FormParams))
Atom.dump(OS);
else
OS << "Error extracting the value";
@@ -183,3 +199,69 @@ LLVM_DUMP_METHOD void DWARFAcceleratorTable::dump(raw_ostream &OS) const {
}
}
}
+
+DWARFAcceleratorTable::ValueIterator::ValueIterator(
+ const DWARFAcceleratorTable &AccelTable, unsigned Offset)
+ : AccelTable(&AccelTable), 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() {
+ assert(NumData > 0 && "attempted to increment iterator past the end");
+ auto &AccelSection = AccelTable->AccelSection;
+ if (Data >= NumData ||
+ !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
+ NumData = 0;
+ return;
+ }
+ DWARFFormParams FormParams = {AccelTable->Hdr.Version, 0,
+ dwarf::DwarfFormat::DWARF32};
+ for (auto &Atom : AtomForms)
+ Atom.extractValue(AccelSection, &DataOffset, FormParams);
+ ++Data;
+}
+
+iterator_range<DWARFAcceleratorTable::ValueIterator>
+DWARFAcceleratorTable::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 BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
+ unsigned HashesBase = BucketBase + Hdr.NumBuckets * 4;
+ unsigned OffsetsBase = HashesBase + Hdr.NumHashes * 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) {
+ unsigned HashOffset = HashesBase + HashIdx * 4;
+ unsigned OffsetsOffset = OffsetsBase + HashIdx * 4;
+ uint32_t Hash = AccelSection.getU32(&HashOffset);
+
+ if (Hash % Hdr.NumBuckets != Bucket)
+ // We are already in the next bucket.
+ break;
+
+ unsigned DataOffset = AccelSection.getU32(&OffsetsOffset);
+ unsigned StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
+ if (!StringOffset)
+ break;
+
+ // Finally, compare the key.
+ if (Key == StringSection.getCStr(&StringOffset))
+ return make_range({*this, DataOffset}, ValueIterator());
+ }
+ return make_range(ValueIterator(), ValueIterator());
+}
diff --git a/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
index 358e9bf43d00..43b235621d18 100644
--- a/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
+++ b/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
@@ -27,7 +27,7 @@ void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
<< ")\n";
if (DWARFDie CUDie = getUnitDIE(false))
- CUDie.dump(OS, -1U, 0, DumpOpts);
+ CUDie.dump(OS, 0, DumpOpts);
else
OS << "<compile unit can't be parsed!>\n\n";
}
diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp
index dd3235244e24..a5defa90eb35 100644
--- a/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -31,6 +31,7 @@
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Object/Decompressor.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
@@ -40,12 +41,13 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdint>
#include <map>
#include <string>
-#include <tuple>
#include <utility>
#include <vector>
@@ -59,23 +61,39 @@ using DWARFLineTable = DWARFDebugLine::LineTable;
using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
-static void dumpAccelSection(raw_ostream &OS, StringRef Name,
- const DWARFSection& Section, StringRef StringSection,
- bool LittleEndian) {
- DWARFDataExtractor AccelSection(Section, LittleEndian, 0);
- DataExtractor StrData(StringSection, LittleEndian, 0);
- OS << "\n." << Name << " contents:\n";
- DWARFAcceleratorTable Accel(AccelSection, StrData);
- if (!Accel.extract())
+DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj,
+ std::string DWPName)
+ : DIContext(CK_DWARF), DWPName(std::move(DWPName)), DObj(std::move(DObj)) {}
+
+DWARFContext::~DWARFContext() = default;
+
+/// Dump the UUID load command.
+static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) {
+ auto *MachO = dyn_cast<MachOObjectFile>(&Obj);
+ if (!MachO)
return;
- Accel.dump(OS);
+ for (auto LC : MachO->load_commands()) {
+ raw_ostream::uuid_t UUID;
+ if (LC.C.cmd == MachO::LC_UUID) {
+ if (LC.C.cmdsize < sizeof(UUID) + sizeof(LC.C)) {
+ OS << "error: UUID load command is too short.\n";
+ return;
+ }
+ OS << "UUID: ";
+ memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID));
+ OS.write_uuid(UUID);
+ OS << ' ' << MachO->getFileFormatName();
+ OS << ' ' << MachO->getFileName() << '\n';
+ }
+ }
}
static void
dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName,
+ const DWARFObject &Obj,
const DWARFSection &StringOffsetsSection,
StringRef StringSection, bool LittleEndian) {
- DWARFDataExtractor StrOffsetExt(StringOffsetsSection, LittleEndian, 0);
+ DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0);
uint32_t Offset = 0;
uint64_t SectionSize = StringOffsetsSection.Data.size();
@@ -153,17 +171,15 @@ dumpDWARFv5StringOffsetsSection(raw_ostream &OS, StringRef SectionName,
// monolithic series of string offsets, as generated by the pre-DWARF v5
// implementation of split DWARF.
static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName,
+ const DWARFObject &Obj,
const DWARFSection &StringOffsetsSection,
StringRef StringSection, bool LittleEndian,
unsigned MaxVersion) {
- if (StringOffsetsSection.Data.empty())
- return;
- OS << "\n." << SectionName << " contents:\n";
// If we have at least one (compile or type) unit with DWARF v5 or greater,
// we assume that the section is formatted like a DWARF v5 string offsets
// section.
if (MaxVersion >= 5)
- dumpDWARFv5StringOffsetsSection(OS, SectionName, StringOffsetsSection,
+ dumpDWARFv5StringOffsetsSection(OS, SectionName, Obj, StringOffsetsSection,
StringSection, LittleEndian);
else {
DataExtractor strOffsetExt(StringOffsetsSection.Data, LittleEndian, 0);
@@ -188,140 +204,217 @@ static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName,
}
}
-void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
- DIDumpType DumpType = DumpOpts.DumpType;
- bool DumpEH = DumpOpts.DumpEH;
- bool SummarizeTypes = DumpOpts.SummarizeTypes;
+// 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;
- if (DumpType == DIDT_All || DumpType == DIDT_Abbrev) {
- OS << ".debug_abbrev contents:\n";
- getDebugAbbrev()->dump(OS);
- }
+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;
+}
- if (DumpType == DIDT_All || DumpType == DIDT_AbbrevDwo)
- if (const DWARFDebugAbbrev *D = getDebugAbbrevDWO()) {
- OS << "\n.debug_abbrev.dwo contents:\n";
- D->dump(OS);
- }
+void DWARFContext::dump(
+ raw_ostream &OS, DIDumpOptions DumpOpts,
+ std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
- if (DumpType == DIDT_All || DumpType == DIDT_Info) {
- OS << "\n.debug_info contents:\n";
- for (const auto &CU : compile_units())
- CU->dump(OS, DumpOpts);
- }
+ Optional<uint64_t> DumpOffset;
+ uint64_t DumpType = DumpOpts.DumpType;
- if ((DumpType == DIDT_All || DumpType == DIDT_InfoDwo) &&
- getNumDWOCompileUnits()) {
- OS << "\n.debug_info.dwo contents:\n";
- for (const auto &DWOCU : dwo_compile_units())
- DWOCU->dump(OS, DumpOpts);
- }
+ StringRef Extension = sys::path::extension(DObj->getFileName());
+ bool IsDWO = (Extension == ".dwo") || (Extension == ".dwp");
+
+ // Print UUID header.
+ const auto *ObjFile = DObj->getFile();
+ if (DumpType & DIDT_UUID)
+ dumpUUID(OS, *ObjFile);
+
+ // Print a header for each explicitly-requested section.
+ // Otherwise just print one for non-empty sections.
+ // Only print empty .dwo section headers when dumping a .dwo file.
+ bool Explicit = DumpType != DIDT_All && !IsDWO;
+ bool ExplicitDWO = Explicit && IsDWO;
+ auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID,
+ StringRef Section) {
+ DumpOffset = DumpOffsets[ID];
+ unsigned Mask = 1U << ID;
+ bool Should = (DumpType & Mask) && (Explicit || !Section.empty());
+ if (Should)
+ OS << "\n" << Name << " contents:\n";
+ return Should;
+ };
+
+ // Dump individual sections.
+ if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev,
+ DObj->getAbbrevSection()))
+ getDebugAbbrev()->dump(OS);
+ if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev,
+ DObj->getAbbrevDWOSection()))
+ getDebugAbbrevDWO()->dump(OS);
+
+ auto dumpDebugInfo = [&](bool IsExplicit, const char *Name,
+ DWARFSection Section, cu_iterator_range CUs) {
+ if (shouldDump(IsExplicit, Name, DIDT_ID_DebugInfo, Section.Data)) {
+ if (DumpOffset)
+ getDIEForOffset(DumpOffset.getValue())
+ .dump(OS, 0, DumpOpts.noImplicitRecursion());
+ else
+ for (const auto &CU : CUs)
+ CU->dump(OS, DumpOpts);
+ }
+ };
+ dumpDebugInfo(Explicit, ".debug_info", DObj->getInfoSection(),
+ compile_units());
+ dumpDebugInfo(ExplicitDWO, ".debug_info.dwo", DObj->getInfoDWOSection(),
+ dwo_compile_units());
- if ((DumpType == DIDT_All || DumpType == DIDT_Types) && getNumTypeUnits()) {
- OS << "\n.debug_types contents:\n";
- for (const auto &TUS : type_unit_sections())
+ auto dumpDebugType = [&](const char *Name,
+ tu_section_iterator_range TUSections) {
+ OS << '\n' << Name << " contents:\n";
+ DumpOffset = DumpOffsets[DIDT_ID_DebugTypes];
+ for (const auto &TUS : TUSections)
for (const auto &TU : TUS)
- TU->dump(OS, SummarizeTypes);
+ if (DumpOffset)
+ TU->getDIEForOffset(*DumpOffset)
+ .dump(OS, 0, DumpOpts.noImplicitRecursion());
+ else
+ TU->dump(OS, DumpOpts);
+ };
+ if ((DumpType & DIDT_DebugTypes)) {
+ if (Explicit || getNumTypeUnits())
+ dumpDebugType(".debug_types", type_unit_sections());
+ if (ExplicitDWO || getNumDWOTypeUnits())
+ dumpDebugType(".debug_types.dwo", dwo_type_unit_sections());
}
- if ((DumpType == DIDT_All || DumpType == DIDT_TypesDwo) &&
- getNumDWOTypeUnits()) {
- OS << "\n.debug_types.dwo contents:\n";
- for (const auto &DWOTUS : dwo_type_unit_sections())
- for (const auto &DWOTU : DWOTUS)
- DWOTU->dump(OS, SummarizeTypes);
+ if (shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc,
+ DObj->getLocSection().Data)) {
+ getDebugLoc()->dump(OS, getRegisterInfo(), DumpOffset);
}
-
- if (DumpType == DIDT_All || DumpType == DIDT_Loc) {
- OS << "\n.debug_loc contents:\n";
- getDebugLoc()->dump(OS);
+ if (shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc,
+ DObj->getLocDWOSection().Data)) {
+ getDebugLocDWO()->dump(OS, getRegisterInfo(), DumpOffset);
}
- if (DumpType == DIDT_All || DumpType == DIDT_LocDwo) {
- OS << "\n.debug_loc.dwo contents:\n";
- getDebugLocDWO()->dump(OS);
- }
+ if (shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
+ DObj->getDebugFrameSection()))
+ getDebugFrame()->dump(OS, DumpOffset);
- if (DumpType == DIDT_All || DumpType == DIDT_Frames) {
- OS << "\n.debug_frame contents:\n";
- getDebugFrame()->dump(OS);
- if (DumpEH) {
- OS << "\n.eh_frame contents:\n";
- getEHFrame()->dump(OS);
- }
- }
+ if (shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
+ DObj->getEHFrameSection()))
+ getEHFrame()->dump(OS, DumpOffset);
- if (DumpType == DIDT_All || DumpType == DIDT_Macro) {
- OS << "\n.debug_macinfo contents:\n";
- getDebugMacro()->dump(OS);
+ if (DumpType & DIDT_DebugMacro) {
+ if (Explicit || !getDebugMacro()->empty()) {
+ OS << "\n.debug_macinfo contents:\n";
+ getDebugMacro()->dump(OS);
+ }
}
- uint32_t offset = 0;
- if (DumpType == DIDT_All || DumpType == DIDT_Aranges) {
- OS << "\n.debug_aranges contents:\n";
- DataExtractor arangesData(getARangeSection(), isLittleEndian(), 0);
+ if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges,
+ DObj->getARangeSection())) {
+ uint32_t offset = 0;
+ DataExtractor arangesData(DObj->getARangeSection(), isLittleEndian(), 0);
DWARFDebugArangeSet set;
while (set.extract(arangesData, &offset))
set.dump(OS);
}
- uint8_t savedAddressByteSize = 0;
- if (DumpType == DIDT_All || DumpType == DIDT_Line) {
- OS << "\n.debug_line contents:\n";
- for (const auto &CU : compile_units()) {
- savedAddressByteSize = CU->getAddressByteSize();
- auto CUDIE = CU->getUnitDIE();
- if (!CUDIE)
+ 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();
continue;
- if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list))) {
- DWARFDataExtractor lineData(getLineSection(), isLittleEndian(),
- savedAddressByteSize);
- DWARFDebugLine::LineTable LineTable;
- uint32_t Offset = *StmtOffset;
- LineTable.parse(lineData, &Offset);
+ }
+ // Verbose dumping is done during parsing and not on the intermediate
+ // representation.
+ OS << "debug_line[" << format("0x%8.8x", Offset) << "]\n";
+ unsigned OldOffset = Offset;
+ if (DumpOpts.Verbose) {
+ LineTable.parse(LineData, &Offset, U, &OS);
+ } else {
+ LineTable.parse(LineData, &Offset, U);
LineTable.dump(OS);
}
+ // Check for unparseable prologue, to avoid infinite loops.
+ if (OldOffset == Offset)
+ break;
}
}
- if (DumpType == DIDT_All || DumpType == DIDT_CUIndex) {
- OS << "\n.debug_cu_index contents:\n";
- getCUIndex().dump(OS);
+ 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);
+ }
}
- if (DumpType == DIDT_All || DumpType == DIDT_TUIndex) {
- OS << "\n.debug_tu_index contents:\n";
- getTUIndex().dump(OS);
+ if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex,
+ DObj->getCUIndexSection())) {
+ getCUIndex().dump(OS);
}
- if (DumpType == DIDT_All || DumpType == DIDT_LineDwo) {
- OS << "\n.debug_line.dwo contents:\n";
- unsigned stmtOffset = 0;
- DWARFDataExtractor lineData(getLineDWOSection(), isLittleEndian(),
- savedAddressByteSize);
- DWARFDebugLine::LineTable LineTable;
- while (LineTable.Prologue.parse(lineData, &stmtOffset)) {
- LineTable.dump(OS);
- LineTable.clear();
- }
+ if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex,
+ DObj->getTUIndexSection())) {
+ getTUIndex().dump(OS);
}
- if (DumpType == DIDT_All || DumpType == DIDT_Str) {
- OS << "\n.debug_str contents:\n";
- DataExtractor strData(getStringSection(), isLittleEndian(), 0);
- offset = 0;
+ if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr,
+ DObj->getStringSection())) {
+ DataExtractor strData(DObj->getStringSection(), isLittleEndian(), 0);
+ uint32_t offset = 0;
uint32_t strOffset = 0;
while (const char *s = strData.getCStr(&offset)) {
OS << format("0x%8.8x: \"%s\"\n", strOffset, s);
strOffset = offset;
}
}
-
- if ((DumpType == DIDT_All || DumpType == DIDT_StrDwo) &&
- !getStringDWOSection().empty()) {
- OS << "\n.debug_str.dwo contents:\n";
- DataExtractor strDWOData(getStringDWOSection(), isLittleEndian(), 0);
- offset = 0;
+ if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr,
+ DObj->getStringDWOSection())) {
+ DataExtractor strDWOData(DObj->getStringDWOSection(), isLittleEndian(), 0);
+ uint32_t offset = 0;
uint32_t strDWOOffset = 0;
while (const char *s = strDWOData.getCStr(&offset)) {
OS << format("0x%8.8x: \"%s\"\n", strDWOOffset, s);
@@ -329,75 +422,94 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
}
}
- if (DumpType == DIDT_All || DumpType == DIDT_Ranges) {
- OS << "\n.debug_ranges contents:\n";
+ if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges,
+ DObj->getRangeSection().Data)) {
// In fact, different compile units may have different address byte
- // sizes, but for simplicity we just use the address byte size of the last
- // compile unit (there is no easy and fast way to associate address range
- // list and the compile unit it describes).
- DWARFDataExtractor rangesData(getRangeSection(), isLittleEndian(),
- savedAddressByteSize);
- offset = 0;
+ // sizes, but for simplicity we just use the address byte size of the
+ // last compile unit (there is no easy and fast way to associate address
+ // range list and the compile unit it describes).
+ // FIXME: savedAddressByteSize seems sketchy.
+ uint8_t savedAddressByteSize = 0;
+ for (const auto &CU : compile_units()) {
+ savedAddressByteSize = CU->getAddressByteSize();
+ break;
+ }
+ DWARFDataExtractor rangesData(*DObj, DObj->getRangeSection(),
+ isLittleEndian(), savedAddressByteSize);
+ uint32_t offset = 0;
DWARFDebugRangeList rangeList;
while (rangeList.extract(rangesData, &offset))
rangeList.dump(OS);
}
- if (DumpType == DIDT_All || DumpType == DIDT_Pubnames)
- DWARFDebugPubTable(getPubNamesSection(), isLittleEndian(), false)
- .dump("debug_pubnames", OS);
+ if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
+ DObj->getPubNamesSection()))
+ DWARFDebugPubTable(DObj->getPubNamesSection(), isLittleEndian(), false)
+ .dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_Pubtypes)
- DWARFDebugPubTable(getPubTypesSection(), isLittleEndian(), false)
- .dump("debug_pubtypes", OS);
+ if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes,
+ DObj->getPubTypesSection()))
+ DWARFDebugPubTable(DObj->getPubTypesSection(), isLittleEndian(), false)
+ .dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_GnuPubnames)
- DWARFDebugPubTable(getGnuPubNamesSection(), isLittleEndian(),
+ if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames,
+ DObj->getGnuPubNamesSection()))
+ DWARFDebugPubTable(DObj->getGnuPubNamesSection(), isLittleEndian(),
true /* GnuStyle */)
- .dump("debug_gnu_pubnames", OS);
+ .dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_GnuPubtypes)
- DWARFDebugPubTable(getGnuPubTypesSection(), isLittleEndian(),
+ if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes,
+ DObj->getGnuPubTypesSection()))
+ DWARFDebugPubTable(DObj->getGnuPubTypesSection(), isLittleEndian(),
true /* GnuStyle */)
- .dump("debug_gnu_pubtypes", OS);
-
- if (DumpType == DIDT_All || DumpType == DIDT_StrOffsets)
- dumpStringOffsetsSection(OS, "debug_str_offsets", getStringOffsetSection(),
- getStringSection(), isLittleEndian(),
- getMaxVersion());
+ .dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_StrOffsetsDwo) {
- dumpStringOffsetsSection(OS, "debug_str_offsets.dwo",
- getStringOffsetDWOSection(), getStringDWOSection(),
- isLittleEndian(), getMaxVersion());
- }
+ if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets,
+ DObj->getStringOffsetSection().Data))
+ dumpStringOffsetsSection(
+ OS, "debug_str_offsets", *DObj, DObj->getStringOffsetSection(),
+ DObj->getStringSection(), isLittleEndian(), getMaxVersion());
+ if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets,
+ DObj->getStringOffsetDWOSection().Data))
+ dumpStringOffsetsSection(
+ OS, "debug_str_offsets.dwo", *DObj, DObj->getStringOffsetDWOSection(),
+ DObj->getStringDWOSection(), isLittleEndian(), getMaxVersion());
- if ((DumpType == DIDT_All || DumpType == DIDT_GdbIndex) &&
- !getGdbIndexSection().empty()) {
- OS << "\n.gnu_index contents:\n";
+ if (shouldDump(Explicit, ".gnu_index", DIDT_ID_GdbIndex,
+ DObj->getGdbIndexSection())) {
getGdbIndex().dump(OS);
}
- if (DumpType == DIDT_All || DumpType == DIDT_AppleNames)
- dumpAccelSection(OS, "apple_names", getAppleNamesSection(),
- getStringSection(), isLittleEndian());
+ if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames,
+ DObj->getAppleNamesSection().Data))
+ getAppleNames().dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_AppleTypes)
- dumpAccelSection(OS, "apple_types", getAppleTypesSection(),
- getStringSection(), isLittleEndian());
+ if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes,
+ DObj->getAppleTypesSection().Data))
+ getAppleTypes().dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_AppleNamespaces)
- dumpAccelSection(OS, "apple_namespaces", getAppleNamespacesSection(),
- getStringSection(), isLittleEndian());
+ if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces,
+ DObj->getAppleNamespacesSection().Data))
+ getAppleNamespaces().dump(OS);
- if (DumpType == DIDT_All || DumpType == DIDT_AppleObjC)
- dumpAccelSection(OS, "apple_objc", getAppleObjCSection(),
- getStringSection(), isLittleEndian());
+ if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC,
+ DObj->getAppleObjCSection().Data))
+ getAppleObjC().dump(OS);
}
DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
- // FIXME: Improve this for the case where this DWO file is really a DWP file
- // with an index - use the index for lookup instead of a linear search.
+ DWOCUs.parseDWO(*this, DObj->getInfoDWOSection(), true);
+
+ if (const auto &CUI = getCUIndex()) {
+ if (const auto *R = CUI.getFromHash(Hash))
+ return DWOCUs.getUnitForIndexEntry(*R);
+ return nullptr;
+ }
+
+ // If there's no index, just search through the CUs in the DWO - there's
+ // probably only one unless this is something like LTO - though an in-process
+ // built/cached lookup table could be used in that case to improve repeated
+ // lookups of different CUs in the DWO.
for (const auto &DWOCU : dwo_compile_units())
if (DWOCU->getDWOId() == Hash)
return DWOCU.get();
@@ -411,21 +523,16 @@ DWARFDie DWARFContext::getDIEForOffset(uint32_t Offset) {
return DWARFDie();
}
-bool DWARFContext::verify(raw_ostream &OS, DIDumpType DumpType) {
+bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
bool Success = true;
- DWARFVerifier verifier(OS, *this);
- if (DumpType == DIDT_All || DumpType == DIDT_Info) {
- if (!verifier.handleDebugInfo())
- Success = false;
- }
- if (DumpType == DIDT_All || DumpType == DIDT_Line) {
- if (!verifier.handleDebugLine())
- Success = false;
- }
- if (DumpType == DIDT_All || DumpType == DIDT_AppleNames) {
- if (!verifier.handleAppleNames())
- Success = false;
- }
+ DWARFVerifier verifier(OS, *this, DumpOpts);
+
+ Success &= verifier.handleDebugAbbrev();
+ if (DumpOpts.DumpType & DIDT_DebugInfo)
+ Success &= verifier.handleDebugInfo();
+ if (DumpOpts.DumpType & DIDT_DebugLine)
+ Success &= verifier.handleDebugLine();
+ Success &= verifier.handleAccelTables();
return Success;
}
@@ -433,7 +540,7 @@ const DWARFUnitIndex &DWARFContext::getCUIndex() {
if (CUIndex)
return *CUIndex;
- DataExtractor CUIndexData(getCUIndexSection(), isLittleEndian(), 0);
+ DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0);
CUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_INFO);
CUIndex->parse(CUIndexData);
@@ -444,7 +551,7 @@ const DWARFUnitIndex &DWARFContext::getTUIndex() {
if (TUIndex)
return *TUIndex;
- DataExtractor TUIndexData(getTUIndexSection(), isLittleEndian(), 0);
+ DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0);
TUIndex = llvm::make_unique<DWARFUnitIndex>(DW_SECT_TYPES);
TUIndex->parse(TUIndexData);
@@ -455,7 +562,7 @@ DWARFGdbIndex &DWARFContext::getGdbIndex() {
if (GdbIndex)
return *GdbIndex;
- DataExtractor GdbIndexData(getGdbIndexSection(), true /*LE*/, 0);
+ DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0);
GdbIndex = llvm::make_unique<DWARFGdbIndex>();
GdbIndex->parse(GdbIndexData);
return *GdbIndex;
@@ -465,7 +572,7 @@ const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
if (Abbrev)
return Abbrev.get();
- DataExtractor abbrData(getAbbrevSection(), isLittleEndian(), 0);
+ DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0);
Abbrev.reset(new DWARFDebugAbbrev());
Abbrev->extract(abbrData);
@@ -476,7 +583,7 @@ const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() {
if (AbbrevDWO)
return AbbrevDWO.get();
- DataExtractor abbrData(getAbbrevDWOSection(), isLittleEndian(), 0);
+ DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0);
AbbrevDWO.reset(new DWARFDebugAbbrev());
AbbrevDWO->extract(abbrData);
return AbbrevDWO.get();
@@ -489,7 +596,7 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() {
Loc.reset(new DWARFDebugLoc);
// assume all compile units have the same address byte size
if (getNumCompileUnits()) {
- DWARFDataExtractor LocData(getLocSection(), isLittleEndian(),
+ DWARFDataExtractor LocData(*DObj, DObj->getLocSection(), isLittleEndian(),
getCompileUnitAtIndex(0)->getAddressByteSize());
Loc->parse(LocData);
}
@@ -500,7 +607,7 @@ const DWARFDebugLocDWO *DWARFContext::getDebugLocDWO() {
if (LocDWO)
return LocDWO.get();
- DataExtractor LocData(getLocDWOSection().Data, isLittleEndian(), 0);
+ DataExtractor LocData(DObj->getLocDWOSection().Data, isLittleEndian(), 0);
LocDWO.reset(new DWARFDebugLocDWO());
LocDWO->parse(LocData);
return LocDWO.get();
@@ -528,8 +635,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(getDebugFrameSection(), isLittleEndian(),
- getAddressSize());
+ DataExtractor debugFrameData(DObj->getDebugFrameSection(), isLittleEndian(),
+ DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
@@ -539,8 +646,8 @@ const DWARFDebugFrame *DWARFContext::getEHFrame() {
if (EHFrame)
return EHFrame.get();
- DataExtractor debugFrameData(getEHFrameSection(), isLittleEndian(),
- getAddressSize());
+ DataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(),
+ DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
@@ -550,12 +657,47 @@ const DWARFDebugMacro *DWARFContext::getDebugMacro() {
if (Macro)
return Macro.get();
- DataExtractor MacinfoData(getMacinfoSection(), isLittleEndian(), 0);
+ DataExtractor MacinfoData(DObj->getMacinfoSection(), isLittleEndian(), 0);
Macro.reset(new DWARFDebugMacro());
Macro->parse(MacinfoData);
return Macro.get();
}
+static DWARFAcceleratorTable &
+getAccelTable(std::unique_ptr<DWARFAcceleratorTable> &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));
+ if (Error E = Cache->extract())
+ llvm::consumeError(std::move(E));
+ return *Cache;
+}
+
+const DWARFAcceleratorTable &DWARFContext::getAppleNames() {
+ return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const DWARFAcceleratorTable &DWARFContext::getAppleTypes() {
+ return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const DWARFAcceleratorTable &DWARFContext::getAppleNamespaces() {
+ return getAccelTable(AppleNamespaces, *DObj,
+ DObj->getAppleNamespacesSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
+const DWARFAcceleratorTable &DWARFContext::getAppleObjC() {
+ return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(),
+ DObj->getStringSection(), isLittleEndian());
+}
+
const DWARFLineTable *
DWARFContext::getLineTableForUnit(DWARFUnit *U) {
if (!Line)
@@ -576,35 +718,35 @@ DWARFContext::getLineTableForUnit(DWARFUnit *U) {
// Make sure the offset is good before we try to parse.
if (stmtOffset >= U->getLineSection().Data.size())
- return nullptr;
+ return nullptr;
// We have to parse it first.
- DWARFDataExtractor lineData(U->getLineSection(), isLittleEndian(),
+ DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(),
U->getAddressByteSize());
- return Line->getOrParseLineTable(lineData, stmtOffset);
+ return Line->getOrParseLineTable(lineData, stmtOffset, U);
}
void DWARFContext::parseCompileUnits() {
- CUs.parse(*this, getInfoSection());
+ CUs.parse(*this, DObj->getInfoSection());
}
void DWARFContext::parseTypeUnits() {
if (!TUs.empty())
return;
- forEachTypesSections([&](const DWARFSection &S) {
+ DObj->forEachTypesSections([&](const DWARFSection &S) {
TUs.emplace_back();
TUs.back().parse(*this, S);
});
}
void DWARFContext::parseDWOCompileUnits() {
- DWOCUs.parseDWO(*this, getInfoDWOSection());
+ DWOCUs.parseDWO(*this, DObj->getInfoDWOSection());
}
void DWARFContext::parseDWOTypeUnits() {
if (!DWOTUs.empty())
return;
- forEachTypesDWOSections([&](const DWARFSection &S) {
+ DObj->forEachTypesDWOSections([&](const DWARFSection &S) {
DWOTUs.emplace_back();
DWOTUs.back().parseDWO(*this, S);
});
@@ -622,6 +764,35 @@ DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) {
return getCompileUnitForOffset(CUOffset);
}
+DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) {
+ DIEsForAddress Result;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return Result;
+
+ Result.CompileUnit = CU;
+ Result.FunctionDIE = CU->getSubroutineForAddress(Address);
+
+ std::vector<DWARFDie> Worklist;
+ Worklist.push_back(Result.FunctionDIE);
+ while (!Worklist.empty()) {
+ DWARFDie DIE = Worklist.back();
+ Worklist.pop_back();
+
+ if (DIE.getTag() == DW_TAG_lexical_block &&
+ DIE.addressRangeContainsAddress(Address)) {
+ Result.BlockDIE = DIE;
+ break;
+ }
+
+ for (auto Child : DIE)
+ Worklist.push_back(Child);
+ }
+
+ return Result;
+}
+
static bool getFunctionNameAndStartLineForAddress(DWARFCompileUnit *CU,
uint64_t Address,
FunctionNameKind Kind,
@@ -793,11 +964,13 @@ DWARFContext::getDWOContext(StringRef AbsolutePath) {
return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
}
- SmallString<128> DWPName;
Expected<OwningBinary<ObjectFile>> Obj = [&] {
if (!CheckedForDWP) {
- (getFileName() + ".dwp").toVector(DWPName);
- auto Obj = object::ObjectFile::createObjectFile(DWPName);
+ SmallString<128> DWPName;
+ auto Obj = object::ObjectFile::createObjectFile(
+ this->DWPName.empty()
+ ? (DObj->getFileName() + ".dwp").toStringRef(DWPName)
+ : StringRef(this->DWPName));
if (Obj) {
Entry = &DWP;
return Obj;
@@ -820,7 +993,7 @@ DWARFContext::getDWOContext(StringRef AbsolutePath) {
auto S = std::make_shared<DWOFile>();
S->File = std::move(Obj.get());
- S->Context = llvm::make_unique<DWARFContextInMemory>(*S->File.getBinary());
+ S->Context = DWARFContext::create(*S->File.getBinary());
*Entry = S;
auto *Ctxt = S->Context.get();
return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
@@ -906,208 +1079,400 @@ static bool isRelocScattered(const object::ObjectFile &Obj,
return MachObj->isRelocationScattered(RelocInfo);
}
-Error DWARFContextInMemory::maybeDecompress(const SectionRef &Sec,
- StringRef Name, StringRef &Data) {
- if (!Decompressor::isCompressed(Sec))
- return Error::success();
+ErrorPolicy DWARFContext::defaultErrorHandler(Error E) {
+ errs() << "error: " + toString(std::move(E)) << '\n';
+ return ErrorPolicy::Continue;
+}
- Expected<Decompressor> Decompressor =
- Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8);
- if (!Decompressor)
- return Decompressor.takeError();
+namespace {
+struct DWARFSectionMap final : public DWARFSection {
+ RelocAddrMap Relocs;
+};
- SmallString<32> Out;
- if (auto Err = Decompressor->resizeAndDecompress(Out))
- return Err;
+class DWARFObjInMemory final : public DWARFObject {
+ bool IsLittleEndian;
+ uint8_t AddressSize;
+ StringRef FileName;
+ const object::ObjectFile *Obj = nullptr;
+ std::vector<SectionName> SectionNames;
- UncompressedSections.emplace_back(std::move(Out));
- Data = UncompressedSections.back();
+ using TypeSectionMap = MapVector<object::SectionRef, DWARFSectionMap,
+ std::map<object::SectionRef, unsigned>>;
- return Error::success();
-}
+ TypeSectionMap TypesSections;
+ TypeSectionMap TypesDWOSections;
-ErrorPolicy DWARFContextInMemory::defaultErrorHandler(Error E) {
- errs() << "error: " + toString(std::move(E)) << '\n';
- return ErrorPolicy::Continue;
-}
+ DWARFSectionMap InfoSection;
+ DWARFSectionMap LocSection;
+ DWARFSectionMap LineSection;
+ DWARFSectionMap RangeSection;
+ DWARFSectionMap StringOffsetSection;
+ DWARFSectionMap InfoDWOSection;
+ DWARFSectionMap LineDWOSection;
+ DWARFSectionMap LocDWOSection;
+ DWARFSectionMap StringOffsetDWOSection;
+ DWARFSectionMap RangeDWOSection;
+ DWARFSectionMap AddrSection;
+ DWARFSectionMap AppleNamesSection;
+ DWARFSectionMap AppleTypesSection;
+ DWARFSectionMap AppleNamespacesSection;
+ DWARFSectionMap AppleObjCSection;
-DWARFContextInMemory::DWARFContextInMemory(
- const object::ObjectFile &Obj, const LoadedObjectInfo *L,
- function_ref<ErrorPolicy(Error)> HandleError)
- : FileName(Obj.getFileName()), IsLittleEndian(Obj.isLittleEndian()),
- AddressSize(Obj.getBytesInAddress()) {
- for (const SectionRef &Section : Obj.sections()) {
- StringRef Name;
- Section.getName(Name);
- // Skip BSS and Virtual sections, they aren't interesting.
- if (Section.isBSS() || Section.isVirtual())
- continue;
+ DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
+ return StringSwitch<DWARFSectionMap *>(Name)
+ .Case("debug_info", &InfoSection)
+ .Case("debug_loc", &LocSection)
+ .Case("debug_line", &LineSection)
+ .Case("debug_str_offsets", &StringOffsetSection)
+ .Case("debug_ranges", &RangeSection)
+ .Case("debug_info.dwo", &InfoDWOSection)
+ .Case("debug_loc.dwo", &LocDWOSection)
+ .Case("debug_line.dwo", &LineDWOSection)
+ .Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
+ .Case("debug_addr", &AddrSection)
+ .Case("apple_names", &AppleNamesSection)
+ .Case("apple_types", &AppleTypesSection)
+ .Case("apple_namespaces", &AppleNamespacesSection)
+ .Case("apple_namespac", &AppleNamespacesSection)
+ .Case("apple_objc", &AppleObjCSection)
+ .Default(nullptr);
+ }
- StringRef Data;
- section_iterator RelocatedSection = Section.getRelocatedSection();
- // Try to obtain an already relocated version of this section.
- // Else use the unrelocated section from the object file. We'll have to
- // apply relocations ourselves later.
- if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data))
- Section.getContents(Data);
+ StringRef AbbrevSection;
+ StringRef ARangeSection;
+ StringRef DebugFrameSection;
+ StringRef EHFrameSection;
+ StringRef StringSection;
+ StringRef MacinfoSection;
+ StringRef PubNamesSection;
+ StringRef PubTypesSection;
+ StringRef GnuPubNamesSection;
+ StringRef AbbrevDWOSection;
+ StringRef StringDWOSection;
+ StringRef GnuPubTypesSection;
+ StringRef CUIndexSection;
+ StringRef GdbIndexSection;
+ StringRef TUIndexSection;
- if (auto Err = maybeDecompress(Section, Name, Data)) {
- ErrorPolicy EP = HandleError(
- createError("failed to decompress '" + Name + "', ", std::move(Err)));
- if (EP == ErrorPolicy::Halt)
- return;
- continue;
- }
+ SmallVector<SmallString<32>, 4> UncompressedSections;
- // Compressed sections names in GNU style starts from ".z",
- // at this point section is decompressed and we drop compression prefix.
- Name = Name.substr(
- Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.
+ StringRef *mapSectionToMember(StringRef Name) {
+ if (DWARFSection *Sec = mapNameToDWARFSection(Name))
+ return &Sec->Data;
+ return StringSwitch<StringRef *>(Name)
+ .Case("debug_abbrev", &AbbrevSection)
+ .Case("debug_aranges", &ARangeSection)
+ .Case("debug_frame", &DebugFrameSection)
+ .Case("eh_frame", &EHFrameSection)
+ .Case("debug_str", &StringSection)
+ .Case("debug_macinfo", &MacinfoSection)
+ .Case("debug_pubnames", &PubNamesSection)
+ .Case("debug_pubtypes", &PubTypesSection)
+ .Case("debug_gnu_pubnames", &GnuPubNamesSection)
+ .Case("debug_gnu_pubtypes", &GnuPubTypesSection)
+ .Case("debug_abbrev.dwo", &AbbrevDWOSection)
+ .Case("debug_str.dwo", &StringDWOSection)
+ .Case("debug_cu_index", &CUIndexSection)
+ .Case("debug_tu_index", &TUIndexSection)
+ .Case("gdb_index", &GdbIndexSection)
+ // Any more debug info sections go here.
+ .Default(nullptr);
+ }
- // Map platform specific debug section names to DWARF standard section
- // names.
- Name = Obj.mapDebugSectionName(Name);
+ /// If Sec is compressed section, decompresses and updates its contents
+ /// provided by Data. Otherwise leaves it unchanged.
+ Error maybeDecompress(const object::SectionRef &Sec, StringRef Name,
+ StringRef &Data) {
+ if (!Decompressor::isCompressed(Sec))
+ return Error::success();
- if (StringRef *SectionData = mapSectionToMember(Name)) {
- *SectionData = Data;
- if (Name == "debug_ranges") {
- // FIXME: Use the other dwo range section when we emit it.
- RangeDWOSection.Data = Data;
- }
- } else if (Name == "debug_types") {
- // Find debug_types data by section rather than name as there are
- // multiple, comdat grouped, debug_types sections.
- TypesSections[Section].Data = Data;
- } else if (Name == "debug_types.dwo") {
- TypesDWOSections[Section].Data = Data;
+ Expected<Decompressor> Decompressor =
+ Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8);
+ if (!Decompressor)
+ return Decompressor.takeError();
+
+ SmallString<32> Out;
+ if (auto Err = Decompressor->resizeAndDecompress(Out))
+ return Err;
+
+ UncompressedSections.emplace_back(std::move(Out));
+ Data = UncompressedSections.back();
+
+ return Error::success();
+ }
+
+public:
+ DWARFObjInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+ uint8_t AddrSize, bool IsLittleEndian)
+ : IsLittleEndian(IsLittleEndian) {
+ for (const auto &SecIt : Sections) {
+ if (StringRef *SectionData = mapSectionToMember(SecIt.first()))
+ *SectionData = SecIt.second->getBuffer();
}
+ }
+ DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+ function_ref<ErrorPolicy(Error)> HandleError)
+ : IsLittleEndian(Obj.isLittleEndian()),
+ AddressSize(Obj.getBytesInAddress()), FileName(Obj.getFileName()),
+ Obj(&Obj) {
+
+ StringMap<unsigned> SectionAmountMap;
+ for (const SectionRef &Section : Obj.sections()) {
+ StringRef Name;
+ Section.getName(Name);
+ ++SectionAmountMap[Name];
+ SectionNames.push_back({ Name, true });
+
+ // Skip BSS and Virtual sections, they aren't interesting.
+ if (Section.isBSS() || Section.isVirtual())
+ continue;
- if (RelocatedSection == Obj.section_end())
- continue;
+ // Skip sections stripped by dsymutil.
+ if (Section.isStripped())
+ continue;
- StringRef RelSecName;
- StringRef RelSecData;
- RelocatedSection->getName(RelSecName);
+ StringRef Data;
+ section_iterator RelocatedSection = Section.getRelocatedSection();
+ // Try to obtain an already relocated version of this section.
+ // Else use the unrelocated section from the object file. We'll have to
+ // apply relocations ourselves later.
+ if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data))
+ Section.getContents(Data);
- // If the section we're relocating was relocated already by the JIT,
- // then we used the relocated version above, so we do not need to process
- // relocations for it now.
- if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData))
- continue;
+ if (auto Err = maybeDecompress(Section, Name, Data)) {
+ ErrorPolicy EP = HandleError(createError(
+ "failed to decompress '" + Name + "', ", std::move(Err)));
+ if (EP == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
- // In Mach-o files, the relocations do not need to be applied if
- // there is no load offset to apply. The value read at the
- // relocation point already factors in the section address
- // (actually applying the relocations will produce wrong results
- // as the section address will be added twice).
- if (!L && isa<MachOObjectFile>(&Obj))
- continue;
+ // Compressed sections names in GNU style starts from ".z",
+ // at this point section is decompressed and we drop compression prefix.
+ Name = Name.substr(
+ Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.
- RelSecName = RelSecName.substr(
- RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes.
+ // Map platform specific debug section names to DWARF standard section
+ // names.
+ Name = Obj.mapDebugSectionName(Name);
- // TODO: Add support for relocations in other sections as needed.
- // Record relocations for the debug_info and debug_line sections.
- DWARFSection *Sec = mapNameToDWARFSection(RelSecName);
- RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr;
- if (!Map) {
- // Find debug_types relocs by section rather than name as there are
- // multiple, comdat grouped, debug_types sections.
- if (RelSecName == "debug_types")
- Map = &TypesSections[*RelocatedSection].Relocs;
- else if (RelSecName == "debug_types.dwo")
- Map = &TypesDWOSections[*RelocatedSection].Relocs;
- else
+ if (StringRef *SectionData = mapSectionToMember(Name)) {
+ *SectionData = Data;
+ if (Name == "debug_ranges") {
+ // FIXME: Use the other dwo range section when we emit it.
+ RangeDWOSection.Data = Data;
+ }
+ } else if (Name == "debug_types") {
+ // Find debug_types data by section rather than name as there are
+ // multiple, comdat grouped, debug_types sections.
+ TypesSections[Section].Data = Data;
+ } else if (Name == "debug_types.dwo") {
+ TypesDWOSections[Section].Data = Data;
+ }
+
+ if (RelocatedSection == Obj.section_end())
continue;
- }
- if (Section.relocation_begin() == Section.relocation_end())
- continue;
+ StringRef RelSecName;
+ StringRef RelSecData;
+ RelocatedSection->getName(RelSecName);
- // Symbol to [address, section index] cache mapping.
- std::map<SymbolRef, SymInfo> AddrCache;
- for (const RelocationRef &Reloc : Section.relocations()) {
- // FIXME: it's not clear how to correctly handle scattered
- // relocations.
- if (isRelocScattered(Obj, Reloc))
+ // If the section we're relocating was relocated already by the JIT,
+ // then we used the relocated version above, so we do not need to process
+ // relocations for it now.
+ if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData))
continue;
- Expected<SymInfo> SymInfoOrErr = getSymbolInfo(Obj, Reloc, L, AddrCache);
- if (!SymInfoOrErr) {
- if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt)
- return;
+ // In Mach-o files, the relocations do not need to be applied if
+ // there is no load offset to apply. The value read at the
+ // relocation point already factors in the section address
+ // (actually applying the relocations will produce wrong results
+ // as the section address will be added twice).
+ if (!L && isa<MachOObjectFile>(&Obj))
continue;
+
+ RelSecName = RelSecName.substr(
+ RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes.
+
+ // TODO: Add support for relocations in other sections as needed.
+ // Record relocations for the debug_info and debug_line sections.
+ DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName);
+ RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr;
+ if (!Map) {
+ // Find debug_types relocs by section rather than name as there are
+ // multiple, comdat grouped, debug_types sections.
+ if (RelSecName == "debug_types")
+ Map =
+ &static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection])
+ .Relocs;
+ else if (RelSecName == "debug_types.dwo")
+ Map = &static_cast<DWARFSectionMap &>(
+ TypesDWOSections[*RelocatedSection])
+ .Relocs;
+ else
+ continue;
}
- object::RelocVisitor V(Obj);
- uint64_t Val = V.visit(Reloc.getType(), Reloc, SymInfoOrErr->Address);
- if (V.error()) {
- SmallString<32> Type;
- Reloc.getTypeName(Type);
- ErrorPolicy EP = HandleError(
- createError("failed to compute relocation: " + Type + ", ",
- errorCodeToError(object_error::parse_failed)));
- if (EP == ErrorPolicy::Halt)
- return;
+ if (Section.relocation_begin() == Section.relocation_end())
continue;
+
+ // Symbol to [address, section index] cache mapping.
+ std::map<SymbolRef, SymInfo> AddrCache;
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ // FIXME: it's not clear how to correctly handle scattered
+ // relocations.
+ if (isRelocScattered(Obj, Reloc))
+ continue;
+
+ Expected<SymInfo> SymInfoOrErr =
+ getSymbolInfo(Obj, Reloc, L, AddrCache);
+ if (!SymInfoOrErr) {
+ if (HandleError(SymInfoOrErr.takeError()) == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
+
+ object::RelocVisitor V(Obj);
+ uint64_t Val = V.visit(Reloc.getType(), Reloc, SymInfoOrErr->Address);
+ if (V.error()) {
+ SmallString<32> Type;
+ Reloc.getTypeName(Type);
+ ErrorPolicy EP = HandleError(
+ createError("failed to compute relocation: " + Type + ", ",
+ errorCodeToError(object_error::parse_failed)));
+ if (EP == ErrorPolicy::Halt)
+ return;
+ continue;
+ }
+ RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val};
+ Map->insert({Reloc.getOffset(), Rel});
}
- RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val};
- Map->insert({Reloc.getOffset(), Rel});
}
+
+ for (SectionName &S : SectionNames)
+ if (SectionAmountMap[S.Name] > 1)
+ S.IsNameUnique = false;
}
-}
-DWARFContextInMemory::DWARFContextInMemory(
- const StringMap<std::unique_ptr<MemoryBuffer>> &Sections, uint8_t AddrSize,
- bool isLittleEndian)
- : IsLittleEndian(isLittleEndian), AddressSize(AddrSize) {
- for (const auto &SecIt : Sections) {
- if (StringRef *SectionData = mapSectionToMember(SecIt.first()))
- *SectionData = SecIt.second->getBuffer();
+ Optional<RelocAddrEntry> find(const DWARFSection &S,
+ uint64_t Pos) const override {
+ auto &Sec = static_cast<const DWARFSectionMap &>(S);
+ RelocAddrMap::const_iterator AI = Sec.Relocs.find(Pos);
+ if (AI == Sec.Relocs.end())
+ return None;
+ return AI->second;
+ }
+
+ const object::ObjectFile *getFile() const override { return Obj; }
+
+ ArrayRef<SectionName> getSectionNames() const override {
+ return SectionNames;
}
-}
-DWARFSection *DWARFContextInMemory::mapNameToDWARFSection(StringRef Name) {
- return StringSwitch<DWARFSection *>(Name)
- .Case("debug_info", &InfoSection)
- .Case("debug_loc", &LocSection)
- .Case("debug_line", &LineSection)
- .Case("debug_str_offsets", &StringOffsetSection)
- .Case("debug_ranges", &RangeSection)
- .Case("debug_info.dwo", &InfoDWOSection)
- .Case("debug_loc.dwo", &LocDWOSection)
- .Case("debug_line.dwo", &LineDWOSection)
- .Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
- .Case("debug_addr", &AddrSection)
- .Case("apple_names", &AppleNamesSection)
- .Case("apple_types", &AppleTypesSection)
- .Case("apple_namespaces", &AppleNamespacesSection)
- .Case("apple_namespac", &AppleNamespacesSection)
- .Case("apple_objc", &AppleObjCSection)
- .Default(nullptr);
+ bool isLittleEndian() const override { return IsLittleEndian; }
+ StringRef getAbbrevDWOSection() const override { return AbbrevDWOSection; }
+ const DWARFSection &getLineDWOSection() const override {
+ return LineDWOSection;
+ }
+ const DWARFSection &getLocDWOSection() const override {
+ return LocDWOSection;
+ }
+ StringRef getStringDWOSection() const override { return StringDWOSection; }
+ const DWARFSection &getStringOffsetDWOSection() const override {
+ return StringOffsetDWOSection;
+ }
+ const DWARFSection &getRangeDWOSection() const override {
+ return RangeDWOSection;
+ }
+ const DWARFSection &getAddrSection() const override { return AddrSection; }
+ StringRef getCUIndexSection() const override { return CUIndexSection; }
+ StringRef getGdbIndexSection() const override { return GdbIndexSection; }
+ StringRef getTUIndexSection() const override { return TUIndexSection; }
+
+ // DWARF v5
+ const DWARFSection &getStringOffsetSection() const override {
+ return StringOffsetSection;
+ }
+
+ // Sections for DWARF5 split dwarf proposal.
+ const DWARFSection &getInfoDWOSection() const override {
+ return InfoDWOSection;
+ }
+ void forEachTypesDWOSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : TypesDWOSections)
+ F(P.second);
+ }
+
+ StringRef getAbbrevSection() const override { return AbbrevSection; }
+ const DWARFSection &getLocSection() const override { return LocSection; }
+ StringRef getARangeSection() const override { return ARangeSection; }
+ StringRef getDebugFrameSection() const override { return DebugFrameSection; }
+ StringRef getEHFrameSection() const override { return EHFrameSection; }
+ const DWARFSection &getLineSection() const override { return LineSection; }
+ StringRef getStringSection() const override { return StringSection; }
+ const DWARFSection &getRangeSection() const override { return RangeSection; }
+ StringRef getMacinfoSection() const override { return MacinfoSection; }
+ StringRef getPubNamesSection() const override { return PubNamesSection; }
+ StringRef getPubTypesSection() const override { return PubTypesSection; }
+ StringRef getGnuPubNamesSection() const override {
+ return GnuPubNamesSection;
+ }
+ StringRef getGnuPubTypesSection() const override {
+ return GnuPubTypesSection;
+ }
+ const DWARFSection &getAppleNamesSection() const override {
+ return AppleNamesSection;
+ }
+ const DWARFSection &getAppleTypesSection() const override {
+ return AppleTypesSection;
+ }
+ const DWARFSection &getAppleNamespacesSection() const override {
+ return AppleNamespacesSection;
+ }
+ const DWARFSection &getAppleObjCSection() const override {
+ return AppleObjCSection;
+ }
+
+ StringRef getFileName() const override { return FileName; }
+ uint8_t getAddressSize() const override { return AddressSize; }
+ const DWARFSection &getInfoSection() const override { return InfoSection; }
+ void forEachTypesSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : TypesSections)
+ F(P.second);
+ }
+};
+} // namespace
+
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+ function_ref<ErrorPolicy(Error)> HandleError,
+ std::string DWPName) {
+ auto DObj = llvm::make_unique<DWARFObjInMemory>(Obj, L, HandleError);
+ return llvm::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName));
}
-StringRef *DWARFContextInMemory::mapSectionToMember(StringRef Name) {
- if (DWARFSection *Sec = mapNameToDWARFSection(Name))
- return &Sec->Data;
- return StringSwitch<StringRef *>(Name)
- .Case("debug_abbrev", &AbbrevSection)
- .Case("debug_aranges", &ARangeSection)
- .Case("debug_frame", &DebugFrameSection)
- .Case("eh_frame", &EHFrameSection)
- .Case("debug_str", &StringSection)
- .Case("debug_macinfo", &MacinfoSection)
- .Case("debug_pubnames", &PubNamesSection)
- .Case("debug_pubtypes", &PubTypesSection)
- .Case("debug_gnu_pubnames", &GnuPubNamesSection)
- .Case("debug_gnu_pubtypes", &GnuPubTypesSection)
- .Case("debug_abbrev.dwo", &AbbrevDWOSection)
- .Case("debug_str.dwo", &StringDWOSection)
- .Case("debug_cu_index", &CUIndexSection)
- .Case("debug_tu_index", &TUIndexSection)
- .Case("gdb_index", &GdbIndexSection)
- // Any more debug info sections go here.
- .Default(nullptr);
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+ uint8_t AddrSize, bool isLittleEndian) {
+ auto DObj =
+ llvm::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian);
+ return llvm::make_unique<DWARFContext>(std::move(DObj), "");
}
-void DWARFContextInMemory::anchor() {}
+Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) {
+ // Detect the architecture from the object file. We usually don't need OS
+ // info to lookup a target and create register info.
+ Triple TT;
+ TT.setArch(Triple::ArchType(Obj.getArch()));
+ TT.setVendor(Triple::UnknownVendor);
+ TT.setOS(Triple::UnknownOS);
+ std::string TargetLookupError;
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(TT.str(), TargetLookupError);
+ if (!TargetLookupError.empty())
+ return make_error<StringError>(TargetLookupError, inconvertibleErrorCode());
+ RegInfo.reset(TheTarget->createMCRegInfo(TT.str()));
+ return Error::success();
+}
diff --git a/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
index 001097e56c71..861dd313fb09 100644
--- a/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
@@ -8,17 +8,20 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
using namespace llvm;
uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off,
uint64_t *SecNdx) const {
- if (!RelocMap)
+ if (SecNdx)
+ *SecNdx = -1ULL;
+ if (!Section)
return getUnsigned(Off, Size);
- RelocAddrMap::const_iterator AI = RelocMap->find(*Off);
- if (AI == RelocMap->end())
+ Optional<RelocAddrEntry> Rel = Obj->find(*Section, *Off);
+ if (!Rel)
return getUnsigned(Off, Size);
if (SecNdx)
- *SecNdx = AI->second.SectionIndex;
- return getUnsigned(Off, Size) + AI->second.Value;
+ *SecNdx = Rel->SectionIndex;
+ return getUnsigned(Off, Size) + Rel->Value;
}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
index 76dd2e4c21bc..4830c36a8ee7 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
@@ -68,9 +68,7 @@ DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration(
return &Decls[AbbrCode - FirstAbbrCode];
}
-DWARFDebugAbbrev::DWARFDebugAbbrev() {
- clear();
-}
+DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); }
void DWARFDebugAbbrev::clear() {
AbbrDeclSets.clear();
@@ -79,18 +77,29 @@ void DWARFDebugAbbrev::clear() {
void DWARFDebugAbbrev::extract(DataExtractor Data) {
clear();
+ this->Data = Data;
+}
+void DWARFDebugAbbrev::parse() const {
+ if (!Data)
+ return;
uint32_t Offset = 0;
DWARFAbbreviationDeclarationSet AbbrDecls;
- while (Data.isValidOffset(Offset)) {
+ auto I = AbbrDeclSets.begin();
+ while (Data->isValidOffset(Offset)) {
+ while (I != AbbrDeclSets.end() && I->first < Offset)
+ ++I;
uint32_t CUAbbrOffset = Offset;
- if (!AbbrDecls.extract(Data, &Offset))
+ if (!AbbrDecls.extract(*Data, &Offset))
break;
- AbbrDeclSets[CUAbbrOffset] = std::move(AbbrDecls);
+ AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls)));
}
+ Data = None;
}
void DWARFDebugAbbrev::dump(raw_ostream &OS) const {
+ parse();
+
if (AbbrDeclSets.empty()) {
OS << "< EMPTY >\n";
return;
@@ -115,5 +124,16 @@ DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const {
return &(Pos->second);
}
+ if (Data && CUAbbrOffset < Data->getData().size()) {
+ uint32_t Offset = CUAbbrOffset;
+ DWARFAbbreviationDeclarationSet AbbrDecls;
+ if (!AbbrDecls.extract(*Data, &Offset))
+ return nullptr;
+ PrevAbbrOffsetPos =
+ AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls)))
+ .first;
+ return &PrevAbbrOffsetPos->second;
+ }
+
return nullptr;
}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
index 6601393d7459..a3ecb15e3661 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
@@ -43,7 +43,8 @@ void DWARFDebugAranges::generate(DWARFContext *CTX) {
return;
// Extract aranges from .debug_aranges section.
- DataExtractor ArangesData(CTX->getARangeSection(), CTX->isLittleEndian(), 0);
+ DataExtractor ArangesData(CTX->getDWARFObj().getARangeSection(),
+ CTX->isLittleEndian(), 0);
extract(ArangesData);
// Generate aranges from DIEs: even if .debug_aranges section is present,
@@ -106,8 +107,8 @@ void DWARFDebugAranges::construct() {
assert(ValidCUs.empty());
// Endpoints are not needed now.
- std::vector<RangeEndpoint> EmptyEndpoints;
- EmptyEndpoints.swap(Endpoints);
+ Endpoints.clear();
+ Endpoints.shrink_to_fit();
}
uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const {
diff --git a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index 475cf25b781b..3312da67804b 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -11,7 +11,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -46,19 +45,26 @@ public:
FrameKind getKind() const { return Kind; }
virtual uint64_t getOffset() const { return Offset; }
- /// \brief Parse and store a sequence of CFI instructions from Data,
+ /// 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);
- /// \brief Dump the entry header to the given output stream.
+ /// Dump the entry header to the given output stream.
virtual void dumpHeader(raw_ostream &OS) const = 0;
- /// \brief Dump the entry's instructions to the given output stream.
+ /// 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;
@@ -157,6 +163,7 @@ void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
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;
@@ -188,10 +195,16 @@ void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
break;
}
case DW_CFA_def_cfa_expression:
+ // FIXME: Parse the actual instruction.
+ *Offset += Data.getULEB128(Offset);
+ break;
case DW_CFA_expression:
- case DW_CFA_val_expression:
- // TODO: implement this
- report_fatal_error("Values with expressions not implemented yet!");
+ case DW_CFA_val_expression: {
+ // FIXME: Parse the actual instruction.
+ Data.getULEB128(Offset);
+ *Offset += Data.getULEB128(Offset);
+ break;
+ }
}
}
}
@@ -686,11 +699,24 @@ void DWARFDebugFrame::parse(DataExtractor Data) {
}
}
-void DWARFDebugFrame::dump(raw_ostream &OS) const {
- OS << "\n";
- for (const auto &Entry : Entries) {
- Entry->dumpHeader(OS);
- Entry->dumpInstructions(OS);
- OS << "\n";
+FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
+ auto It =
+ std::lower_bound(Entries.begin(), Entries.end(), Offset,
+ [](const std::unique_ptr<FrameEntry> &E,
+ uint64_t Offset) { return E->getOffset() < Offset; });
+ if (It != Entries.end() && (*It)->getOffset() == Offset)
+ return It->get();
+ return nullptr;
+}
+
+void DWARFDebugFrame::dump(raw_ostream &OS, Optional<uint64_t> Offset) const {
+ if (Offset) {
+ if (auto *Entry = getEntryAtOffset(*Offset))
+ Entry->dump(OS);
+ return;
}
+
+ OS << "\n";
+ for (const auto &Entry : Entries)
+ Entry->dump(OS);
}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 7d180564e9f7..e5ef4eaceebe 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -12,7 +12,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/Support/Format.h"
@@ -49,6 +48,7 @@ void DWARFDebugLine::Prologue::clear() {
MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0;
OpcodeBase = 0;
FormParams = DWARFFormParams({0, 0, DWARF32});
+ HasMD5 = false;
StandardOpcodeLengths.clear();
IncludeDirectories.clear();
FileNames.clear();
@@ -79,15 +79,23 @@ void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const {
<< IncludeDirectories[I] << "'\n";
if (!FileNames.empty()) {
- OS << " Dir Mod Time File Len File Name\n"
- << " ---- ---------- ---------- -----------"
- "----------------\n";
+ if (HasMD5)
+ OS << " Dir MD5 Checksum File Name\n"
+ << " ---- -------------------------------- -----------"
+ "---------------\n";
+ else
+ OS << " Dir Mod Time File Len File Name\n"
+ << " ---- ---------- ---------- -----------"
+ "----------------\n";
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)
- << format("0x%8.8" PRIx64 " 0x%8.8" PRIx64 " ", FileEntry.ModTime,
- FileEntry.Length)
- << FileEntry.Name << '\n';
+ 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';
}
}
}
@@ -123,7 +131,7 @@ parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
// ran off the end of the prologue.
static ContentDescriptors
parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
- uint64_t EndPrologueOffset) {
+ uint64_t EndPrologueOffset, bool *HasMD5) {
ContentDescriptors Descriptors;
int FormatCount = DebugLineData.getU8(OffsetPtr);
bool HasPath = false;
@@ -136,6 +144,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;
Descriptors.push_back(Descriptor);
}
return HasPath ? Descriptors : ContentDescriptors();
@@ -144,12 +154,12 @@ parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint32_t *OffsetPtr,
static bool
parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
uint32_t *OffsetPtr, uint64_t EndPrologueOffset,
- const DWARFFormParams &FormParams,
- std::vector<StringRef> &IncludeDirectories,
+ const DWARFFormParams &FormParams, const DWARFUnit *U,
+ bool &HasMD5, std::vector<StringRef> &IncludeDirectories,
std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
// Get the directory entry description.
ContentDescriptors DirDescriptors =
- parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset);
+ parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, nullptr);
if (DirDescriptors.empty())
return false;
@@ -162,7 +172,7 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
DWARFFormValue Value(Descriptor.Form);
switch (Descriptor.Type) {
case DW_LNCT_path:
- if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr))
+ if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U))
return false;
IncludeDirectories.push_back(Value.getAsCString().getValue());
break;
@@ -175,7 +185,7 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
// Get the file entry description.
ContentDescriptors FileDescriptors =
- parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset);
+ parseV5EntryFormat(DebugLineData, OffsetPtr, EndPrologueOffset, &HasMD5);
if (FileDescriptors.empty())
return false;
@@ -187,7 +197,7 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
DWARFDebugLine::FileNameEntry FileEntry;
for (auto Descriptor : FileDescriptors) {
DWARFFormValue Value(Descriptor.Form);
- if (!Value.extractValue(DebugLineData, OffsetPtr, nullptr))
+ if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, U))
return false;
switch (Descriptor.Type) {
case DW_LNCT_path:
@@ -202,7 +212,11 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
case DW_LNCT_size:
FileEntry.Length = Value.getAsUnsignedConstant().getValue();
break;
- // FIXME: Add MD5
+ case DW_LNCT_MD5:
+ assert(Value.getAsBlock().getValue().size() == 16);
+ std::uninitialized_copy_n(Value.getAsBlock().getValue().begin(), 16,
+ FileEntry.Checksum.Bytes.begin());
+ break;
default:
break;
}
@@ -213,7 +227,7 @@ parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
}
bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
- uint32_t *OffsetPtr) {
+ uint32_t *OffsetPtr, const DWARFUnit *U) {
const uint64_t PrologueOffset = *OffsetPtr;
clear();
@@ -230,7 +244,8 @@ bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
if (getVersion() >= 5) {
FormParams.AddrSize = DebugLineData.getU8(OffsetPtr);
- assert(getAddressSize() == DebugLineData.getAddressSize() &&
+ assert((DebugLineData.getAddressSize() == 0 ||
+ DebugLineData.getAddressSize() == getAddressSize()) &&
"Line table header and data extractor disagree");
SegSelectorSize = DebugLineData.getU8(OffsetPtr);
}
@@ -253,7 +268,8 @@ bool DWARFDebugLine::Prologue::parse(const DWARFDataExtractor &DebugLineData,
if (getVersion() >= 5) {
if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset,
- getFormParams(), IncludeDirectories, FileNames)) {
+ 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"
@@ -381,46 +397,71 @@ DWARFDebugLine::getLineTable(uint32_t Offset) const {
}
const DWARFDebugLine::LineTable *
-DWARFDebugLine::getOrParseLineTable(const DWARFDataExtractor &DebugLineData,
- uint32_t Offset) {
+DWARFDebugLine::getOrParseLineTable(DWARFDataExtractor &DebugLineData,
+ uint32_t Offset, const DWARFUnit *U) {
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))
+ if (!LT->parse(DebugLineData, &Offset, U))
return nullptr;
}
return LT;
}
-bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
- uint32_t *OffsetPtr) {
+bool DWARFDebugLine::LineTable::parse(DWARFDataExtractor &DebugLineData,
+ uint32_t *OffsetPtr, const DWARFUnit *U,
+ raw_ostream *OS) {
const uint32_t DebugLineOffset = *OffsetPtr;
clear();
- if (!Prologue.parse(DebugLineData, OffsetPtr)) {
+ if (!Prologue.parse(DebugLineData, OffsetPtr, U)) {
// Restore our offset and return false to indicate failure!
*OffsetPtr = DebugLineOffset;
return false;
}
+ if (OS)
+ Prologue.dump(*OS);
+
const uint32_t EndOffset =
DebugLineOffset + Prologue.TotalLength + Prologue.sizeofTotalLength();
+ // See if we should tell the data extractor the address size.
+ if (DebugLineData.getAddressSize() == 0)
+ DebugLineData.setAddressSize(Prologue.getAddressSize());
+ else
+ assert(Prologue.getAddressSize() == 0 ||
+ Prologue.getAddressSize() == DebugLineData.getAddressSize());
+
ParsingState State(this);
while (*OffsetPtr < EndOffset) {
+ if (OS)
+ *OS << format("0x%08.08" PRIx32 ": ", *OffsetPtr);
+
uint8_t Opcode = DebugLineData.getU8(OffsetPtr);
+ if (OS)
+ *OS << format("%02.02" PRIx8 " ", Opcode);
+
if (Opcode == 0) {
// Extended Opcodes always start with a zero opcode followed by
// a uleb128 length so you can skip ones you don't know about
- uint32_t ExtOffset = *OffsetPtr;
uint64_t Len = DebugLineData.getULEB128(OffsetPtr);
- uint32_t ArgSize = Len - (*OffsetPtr - ExtOffset);
+ uint32_t ExtOffset = *OffsetPtr;
+
+ // Tolerate zero-length; assume length is correct and soldier on.
+ if (Len == 0) {
+ if (OS)
+ *OS << "Badly formed extended line op (length 0)\n";
+ continue;
+ }
uint8_t SubOpcode = DebugLineData.getU8(OffsetPtr);
+ if (OS)
+ *OS << LNExtendedString(SubOpcode);
switch (SubOpcode) {
case DW_LNE_end_sequence:
// Set the end_sequence register of the state machine to true and
@@ -432,6 +473,11 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
// of the sequence.
State.Row.EndSequence = true;
State.appendRowToMatrix(*OffsetPtr);
+ if (OS) {
+ *OS << "\n";
+ OS->indent(12);
+ State.Row.dump(*OS);
+ }
State.resetRowAndSequence();
break;
@@ -442,7 +488,16 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
// relocatable address. All of the other statement program opcodes
// that affect the address register add a delta to it. This instruction
// stores a relocatable value into it instead.
+ //
+ // Make sure the extractor knows the address size. If not, infer it
+ // from the size of the operand.
+ if (DebugLineData.getAddressSize() == 0)
+ DebugLineData.setAddressSize(Len - 1);
+ else
+ assert(DebugLineData.getAddressSize() == Len - 1);
State.Row.Address = DebugLineData.getRelocatedAddress(OffsetPtr);
+ if (OS)
+ *OS << format(" (0x%16.16" PRIx64 ")", State.Row.Address);
break;
case DW_LNE_define_file:
@@ -473,20 +528,42 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
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="
+ << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime)
+ << ", length=" << FileEntry.Length << ")";
}
break;
case DW_LNE_set_discriminator:
State.Row.Discriminator = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.Discriminator << ")";
break;
default:
- // Length doesn't include the zero opcode byte or the length itself, but
- // it does include the sub_opcode, so we have to adjust for that below
- (*OffsetPtr) += ArgSize;
+ if (OS)
+ *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode)
+ << format(" length %" PRIx64, Len);
+ // Len doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that.
+ (*OffsetPtr) += Len - 1;
break;
}
+ // Make sure the stated and parsed lengths are the same.
+ // Otherwise we have an unparseable line-number program.
+ if (*OffsetPtr - ExtOffset != Len) {
+ 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;
+ }
} else if (Opcode < Prologue.OpcodeBase) {
+ if (OS)
+ *OS << LNStandardString(Opcode);
switch (Opcode) {
// Standard Opcodes
case DW_LNS_copy:
@@ -494,32 +571,49 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
// current values of the state-machine registers. Then set
// the basic_block register to false.
State.appendRowToMatrix(*OffsetPtr);
+ if (OS) {
+ *OS << "\n";
+ OS->indent(12);
+ State.Row.dump(*OS);
+ *OS << "\n";
+ }
break;
case DW_LNS_advance_pc:
// Takes a single unsigned LEB128 operand, multiplies it by the
// min_inst_length field of the prologue, and adds the
// result to the address register of the state machine.
- State.Row.Address +=
- DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength;
+ {
+ uint64_t AddrOffset =
+ DebugLineData.getULEB128(OffsetPtr) * Prologue.MinInstLength;
+ State.Row.Address += AddrOffset;
+ if (OS)
+ *OS << " (" << AddrOffset << ")";
+ }
break;
case DW_LNS_advance_line:
// Takes a single signed LEB128 operand and adds that value to
// the line register of the state machine.
State.Row.Line += DebugLineData.getSLEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.Line << ")";
break;
case DW_LNS_set_file:
// Takes a single unsigned LEB128 operand and stores it in the file
// register of the state machine.
State.Row.File = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.File << ")";
break;
case DW_LNS_set_column:
// Takes a single unsigned LEB128 operand and stores it in the
// column register of the state machine.
State.Row.Column = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.Column << ")";
break;
case DW_LNS_negate_stmt:
@@ -551,6 +645,9 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
uint64_t AddrOffset =
(AdjustOpcode / Prologue.LineRange) * Prologue.MinInstLength;
State.Row.Address += AddrOffset;
+ if (OS)
+ *OS
+ << format(" (0x%16.16" PRIx64 ")", AddrOffset);
}
break;
@@ -564,7 +661,13 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
// judge when the computation of a special opcode overflows and
// requires the use of DW_LNS_advance_pc. Such assemblers, however,
// can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
- State.Row.Address += DebugLineData.getU16(OffsetPtr);
+ {
+ uint16_t PCOffset = DebugLineData.getU16(OffsetPtr);
+ State.Row.Address += PCOffset;
+ if (OS)
+ *OS
+ << format(" (0x%16.16" PRIx64 ")", PCOffset);
+ }
break;
case DW_LNS_set_prologue_end:
@@ -583,6 +686,8 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
// Takes a single unsigned LEB128 operand and stores it in the
// column register of the state machine.
State.Row.Isa = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << " (" << State.Row.Isa << ")";
break;
default:
@@ -592,8 +697,12 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
{
assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size());
uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1];
- for (uint8_t I = 0; I < OpcodeLength; ++I)
- DebugLineData.getULEB128(OffsetPtr);
+ for (uint8_t I = 0; I < OpcodeLength; ++I) {
+ uint64_t Value = DebugLineData.getULEB128(OffsetPtr);
+ if (OS)
+ *OS << format("Skipping ULEB128 value: 0x%16.16" PRIx64 ")\n",
+ Value);
+ }
}
break;
}
@@ -638,10 +747,20 @@ bool DWARFDebugLine::LineTable::parse(const DWARFDataExtractor &DebugLineData,
Prologue.LineBase + (AdjustOpcode % Prologue.LineRange);
State.Row.Line += LineOffset;
State.Row.Address += AddrOffset;
+
+ if (OS) {
+ *OS << "address += " << ((uint32_t)AdjustOpcode)
+ << ", line += " << LineOffset << "\n";
+ OS->indent(12);
+ State.Row.dump(*OS);
+ }
+
State.appendRowToMatrix(*OffsetPtr);
// Reset discriminator to 0.
State.Row.Discriminator = 0;
}
+ if(OS)
+ *OS << "\n";
}
if (!State.Sequence.Empty) {
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
index c240dd7406d9..58f88536f317 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -11,7 +11,10 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -20,104 +23,202 @@
using namespace llvm;
-void DWARFDebugLoc::dump(raw_ostream &OS) const {
- for (const LocationList &L : Locations) {
+// When directly dumping the .debug_loc without a compile unit, we have to guess
+// at the DWARF version. This only affects DW_OP_call_ref, which is a rare
+// expression that LLVM doesn't produce. Guessing the wrong version means we
+// won't be able to pretty print expressions in DWARF2 binaries produced by
+// non-LLVM tools.
+static void dumpExpression(raw_ostream &OS, ArrayRef<char> Data,
+ bool IsLittleEndian, unsigned AddressSize,
+ const MCRegisterInfo *MRI) {
+ DWARFDataExtractor Extractor(StringRef(Data.data(), Data.size()),
+ IsLittleEndian, AddressSize);
+ DWARFExpression(Extractor, AddressSize, dwarf::DWARF_VERSION).print(OS, MRI);
+}
+
+void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
+ unsigned AddressSize,
+ const MCRegisterInfo *MRI,
+ unsigned Indent) const {
+ for (const Entry &E : Entries) {
+ OS << '\n';
+ OS.indent(Indent);
+ OS << format("0x%016" PRIx64, E.Begin) << " - "
+ << format("0x%016" PRIx64, E.End) << ": ";
+
+ dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
+ }
+}
+
+DWARFDebugLoc::LocationList const *
+DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const {
+ auto It = std::lower_bound(
+ Locations.begin(), Locations.end(), Offset,
+ [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; });
+ if (It != Locations.end() && It->Offset == Offset)
+ return &(*It);
+ return nullptr;
+}
+
+void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ Optional<uint64_t> Offset) const {
+ auto DumpLocationList = [&](const LocationList &L) {
OS << format("0x%8.8x: ", L.Offset);
- const unsigned Indent = 12;
- for (const Entry &E : L.Entries) {
- if (&E != L.Entries.begin())
- OS.indent(Indent);
- OS << "Beginning address offset: " << format("0x%016" PRIx64, E.Begin)
- << '\n';
- OS.indent(Indent) << " Ending address offset: "
- << format("0x%016" PRIx64, E.End) << '\n';
- OS.indent(Indent) << " Location description: ";
- for (unsigned char Loc : E.Loc) {
- OS << format("%2.2x ", Loc);
- }
- OS << "\n\n";
+ L.dump(OS, IsLittleEndian, AddressSize, MRI, 12);
+ OS << "\n\n";
+ };
+
+ if (Offset) {
+ if (auto *L = getLocationListAtOffset(*Offset))
+ DumpLocationList(*L);
+ return;
+ }
+
+ for (const LocationList &L : Locations) {
+ DumpLocationList(L);
+ }
+}
+
+Optional<DWARFDebugLoc::LocationList>
+DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) {
+ LocationList LL;
+ LL.Offset = *Offset;
+
+ // 2.6.2 Location Lists
+ // A location list entry consists of:
+ while (true) {
+ Entry E;
+ if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) {
+ llvm::errs() << "Location list overflows the debug_loc section.\n";
+ return None;
+ }
+
+ // 1. A beginning address offset. ...
+ E.Begin = Data.getRelocatedAddress(Offset);
+
+ // 2. An ending address offset. ...
+ E.End = Data.getRelocatedAddress(Offset);
+
+ // The end of any given location list is marked by an end of list entry,
+ // which consists of a 0 for the beginning address offset and a 0 for the
+ // ending address offset.
+ if (E.Begin == 0 && E.End == 0)
+ return LL;
+
+ if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) {
+ llvm::errs() << "Location list overflows the debug_loc section.\n";
+ return None;
+ }
+
+ unsigned Bytes = Data.getU16(Offset);
+ if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) {
+ llvm::errs() << "Location list overflows the debug_loc section.\n";
+ return None;
}
+ // A single location description describing the location of the object...
+ StringRef str = Data.getData().substr(*Offset, Bytes);
+ *Offset += Bytes;
+ E.Loc.reserve(str.size());
+ std::copy(str.begin(), str.end(), std::back_inserter(E.Loc));
+ LL.Entries.push_back(std::move(E));
}
}
void DWARFDebugLoc::parse(const DWARFDataExtractor &data) {
+ IsLittleEndian = data.isLittleEndian();
+ AddressSize = data.getAddressSize();
+
uint32_t Offset = 0;
- while (data.isValidOffset(Offset+data.getAddressSize()-1)) {
- Locations.resize(Locations.size() + 1);
- LocationList &Loc = Locations.back();
- Loc.Offset = Offset;
- // 2.6.2 Location Lists
- // A location list entry consists of:
- while (true) {
- // A beginning and ending address offsets.
- Entry E;
- E.Begin = data.getRelocatedAddress(&Offset);
- E.End = data.getRelocatedAddress(&Offset);
+ while (data.isValidOffset(Offset + data.getAddressSize() - 1)) {
+ if (auto LL = parseOneLocationList(data, &Offset))
+ Locations.push_back(std::move(*LL));
+ else
+ break;
+ }
+ if (data.isValidOffset(Offset))
+ errs() << "error: failed to consume entire .debug_loc section\n";
+}
- // The end of any given location list is marked by an end of list entry,
- // which consists of a 0 for the beginning address offset and a 0 for the
- // ending address offset.
- if (E.Begin == 0 && E.End == 0)
- break;
+Optional<DWARFDebugLocDWO::LocationList>
+DWARFDebugLocDWO::parseOneLocationList(DataExtractor Data, unsigned *Offset) {
+ LocationList LL;
+ LL.Offset = *Offset;
- unsigned Bytes = data.getU16(&Offset);
- // A single location description describing the location of the object...
- StringRef str = data.getData().substr(Offset, Bytes);
- Offset += Bytes;
- E.Loc.append(str.begin(), str.end());
- Loc.Entries.push_back(std::move(E));
+ // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list.
+ while (auto Kind =
+ static_cast<dwarf::LocationListEntry>(Data.getU8(Offset))) {
+ if (Kind != dwarf::DW_LLE_startx_length) {
+ llvm::errs() << "error: dumping support for LLE of kind " << (int)Kind
+ << " not implemented\n";
+ return None;
}
+
+ Entry E;
+ E.Start = Data.getULEB128(Offset);
+ E.Length = Data.getU32(Offset);
+
+ unsigned Bytes = Data.getU16(Offset);
+ // A single location description describing the location of the object...
+ StringRef str = Data.getData().substr(*Offset, Bytes);
+ *Offset += Bytes;
+ E.Loc.resize(str.size());
+ std::copy(str.begin(), str.end(), E.Loc.begin());
+
+ LL.Entries.push_back(std::move(E));
}
- if (data.isValidOffset(Offset))
- errs() << "error: failed to consume entire .debug_loc section\n";
+ return LL;
}
void DWARFDebugLocDWO::parse(DataExtractor data) {
+ IsLittleEndian = data.isLittleEndian();
+ AddressSize = data.getAddressSize();
+
uint32_t Offset = 0;
while (data.isValidOffset(Offset)) {
- Locations.resize(Locations.size() + 1);
- LocationList &Loc = Locations.back();
- Loc.Offset = Offset;
- dwarf::LocationListEntry Kind;
- while ((Kind = static_cast<dwarf::LocationListEntry>(
- data.getU8(&Offset))) != dwarf::DW_LLE_end_of_list) {
-
- if (Kind != dwarf::DW_LLE_startx_length) {
- errs() << "error: dumping support for LLE of kind " << (int)Kind
- << " not implemented\n";
- return;
- }
+ if (auto LL = parseOneLocationList(data, &Offset))
+ Locations.push_back(std::move(*LL));
+ else
+ return;
+ }
+}
- Entry E;
+DWARFDebugLocDWO::LocationList const *
+DWARFDebugLocDWO::getLocationListAtOffset(uint64_t Offset) const {
+ auto It = std::lower_bound(
+ Locations.begin(), Locations.end(), Offset,
+ [](const LocationList &L, uint64_t Offset) { return L.Offset < Offset; });
+ if (It != Locations.end() && It->Offset == Offset)
+ return &(*It);
+ return nullptr;
+}
- E.Start = data.getULEB128(&Offset);
- E.Length = data.getU32(&Offset);
+void DWARFDebugLocDWO::LocationList::dump(raw_ostream &OS, bool IsLittleEndian,
+ unsigned AddressSize,
+ const MCRegisterInfo *MRI,
+ unsigned Indent) const {
+ for (const Entry &E : Entries) {
+ OS << '\n';
+ OS.indent(Indent);
+ OS << "Addr idx " << E.Start << " (w/ length " << E.Length << "): ";
+ dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI);
+ }
+}
- unsigned Bytes = data.getU16(&Offset);
- // A single location description describing the location of the object...
- StringRef str = data.getData().substr(Offset, Bytes);
- Offset += Bytes;
- E.Loc.resize(str.size());
- std::copy(str.begin(), str.end(), E.Loc.begin());
+void DWARFDebugLocDWO::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, /*Indent=*/12);
+ OS << "\n\n";
+ };
- Loc.Entries.push_back(std::move(E));
- }
+ if (Offset) {
+ if (auto *L = getLocationListAtOffset(*Offset))
+ DumpLocationList(*L);
+ return;
}
-}
-void DWARFDebugLocDWO::dump(raw_ostream &OS) const {
for (const LocationList &L : Locations) {
- OS << format("0x%8.8x: ", L.Offset);
- const unsigned Indent = 12;
- for (const Entry &E : L.Entries) {
- if (&E != L.Entries.begin())
- OS.indent(Indent);
- OS << "Beginning address index: " << E.Start << '\n';
- OS.indent(Indent) << " Length: " << E.Length << '\n';
- OS.indent(Indent) << " Location description: ";
- for (unsigned char Loc : E.Loc)
- OS << format("%2.2x ", Loc);
- OS << "\n\n";
- }
+ DumpLocationList(L);
}
}
diff --git a/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
index 5a4e39f3c2af..956a91e9c4d6 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
@@ -44,8 +44,7 @@ DWARFDebugPubTable::DWARFDebugPubTable(StringRef Data, bool LittleEndian,
}
}
-void DWARFDebugPubTable::dump(StringRef Name, raw_ostream &OS) const {
- OS << "\n." << Name << " contents:\n";
+void DWARFDebugPubTable::dump(raw_ostream &OS) const {
for (const Set &S : Sets) {
OS << "length = " << format("0x%08x", S.Length);
OS << " version = " << format("0x%04x", S.Version);
diff --git a/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
index 0b6ae86fd94b..f0b7ec2751de 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
@@ -17,6 +17,11 @@
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);
+}
+
void DWARFDebugRangeList::clear() {
Offset = -1U;
AddressSize = 0;
@@ -33,20 +38,22 @@ bool DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
return false;
Offset = *offset_ptr;
while (true) {
- RangeListEntry entry;
+ RangeListEntry Entry;
+ Entry.SectionIndex = -1ULL;
+
uint32_t prev_offset = *offset_ptr;
- entry.StartAddress =
- data.getRelocatedAddress(offset_ptr, &entry.SectionIndex);
- entry.EndAddress = data.getRelocatedAddress(offset_ptr);
+ Entry.StartAddress = data.getRelocatedAddress(offset_ptr);
+ Entry.EndAddress =
+ data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex);
// Check that both values were extracted correctly.
if (*offset_ptr != prev_offset + 2 * AddressSize) {
clear();
return false;
}
- if (entry.isEndOfListEntry())
+ if (Entry.isEndOfListEntry())
break;
- Entries.push_back(entry);
+ Entries.push_back(Entry);
}
return true;
}
@@ -61,16 +68,29 @@ void DWARFDebugRangeList::dump(raw_ostream &OS) const {
OS << format("%08x <End of list>\n", Offset);
}
-DWARFAddressRangesVector
-DWARFDebugRangeList::getAbsoluteRanges(uint64_t BaseAddress) const {
+DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
+ llvm::Optional<BaseAddress> BaseAddr) const {
DWARFAddressRangesVector Res;
for (const RangeListEntry &RLE : Entries) {
if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
- BaseAddress = RLE.EndAddress;
- } else {
- Res.push_back({BaseAddress + RLE.StartAddress,
- BaseAddress + RLE.EndAddress, RLE.SectionIndex});
+ BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
+ continue;
+ }
+
+ DWARFAddressRange E;
+ E.LowPC = RLE.StartAddress;
+ E.HighPC = RLE.EndAddress;
+ E.SectionIndex = RLE.SectionIndex;
+ // Base address of a range list entry is determined by the closest preceding
+ // base address selection entry in the same range list. It defaults to the
+ // base address of the compilation unit if there is no such entry.
+ if (BaseAddr) {
+ E.LowPC += BaseAddr->Address;
+ E.HighPC += BaseAddr->Address;
+ if (E.SectionIndex == -1ULL)
+ E.SectionIndex = BaseAddr->SectionIndex;
}
+ Res.push_back(E);
}
return Res;
}
diff --git a/lib/DebugInfo/DWARF/DWARFDie.cpp b/lib/DebugInfo/DWARF/DWARFDie.cpp
index 111f0bbd4444..91f0f8501f0c 100644
--- a/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -16,8 +16,10 @@
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
@@ -31,6 +33,7 @@
using namespace llvm;
using namespace dwarf;
+using namespace object;
using namespace syntax;
static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) {
@@ -51,17 +54,131 @@ static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) {
OS << ")";
}
-static void dumpRanges(raw_ostream &OS, const DWARFAddressRangesVector& Ranges,
- unsigned AddressSize, unsigned Indent) {
- if (Ranges.empty())
- return;
-
- for (const auto &Range: Ranges) {
+static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS,
+ const DWARFAddressRangesVector &Ranges,
+ unsigned AddressSize, unsigned Indent,
+ const DIDumpOptions &DumpOpts) {
+ ArrayRef<SectionName> SectionNames;
+ if (DumpOpts.Verbose)
+ SectionNames = Obj.getSectionNames();
+
+ for (size_t I = 0; I < Ranges.size(); ++I) {
+ const DWARFAddressRange &R = Ranges[I];
+
OS << '\n';
OS.indent(Indent);
- OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")",
- AddressSize*2, Range.LowPC,
- AddressSize*2, Range.HighPC);
+ OS << format("[0x%0*" PRIx64 " - 0x%0*" PRIx64 ")", AddressSize * 2,
+ R.LowPC, AddressSize * 2, R.HighPC);
+
+ if (SectionNames.empty() || R.SectionIndex == -1ULL)
+ continue;
+
+ StringRef Name = SectionNames[R.SectionIndex].Name;
+ OS << " \"" << Name << '\"';
+
+ // Print section index if name is not unique.
+ if (!SectionNames[R.SectionIndex].IsNameUnique)
+ OS << format(" [%" PRIu64 "]", R.SectionIndex);
+ }
+}
+
+static void dumpLocation(raw_ostream &OS, DWARFFormValue &FormValue,
+ DWARFUnit *U, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ DWARFContext &Ctx = U->getContext();
+ const DWARFObject &Obj = Ctx.getDWARFObj();
+ const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
+ if (FormValue.isFormClass(DWARFFormValue::FC_Block) ||
+ FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) {
+ ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
+ DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
+ Ctx.isLittleEndian(), 0);
+ DWARFExpression(Data, U->getVersion(), U->getAddressByteSize())
+ .print(OS, MRI);
+ return;
+ }
+
+ FormValue.dump(OS, DumpOpts);
+ if (FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
+ const DWARFSection &LocSection = Obj.getLocSection();
+ const DWARFSection &LocDWOSection = Obj.getLocDWOSection();
+ uint32_t Offset = *FormValue.getAsSectionOffset();
+
+ if (!LocSection.Data.empty()) {
+ DWARFDebugLoc DebugLoc;
+ DWARFDataExtractor Data(Obj, LocSection, Ctx.isLittleEndian(),
+ Obj.getAddressSize());
+ auto LL = DebugLoc.parseOneLocationList(Data, &Offset);
+ if (LL)
+ LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent);
+ else
+ OS << "error extracting location list.";
+ } else if (!LocDWOSection.Data.empty()) {
+ DataExtractor Data(LocDWOSection.Data, Ctx.isLittleEndian(), 0);
+ auto LL = DWARFDebugLocDWO::parseOneLocationList(Data, &Offset);
+ if (LL)
+ LL->dump(OS, Ctx.isLittleEndian(), Obj.getAddressSize(), MRI, Indent);
+ else
+ OS << "error extracting location list.";
+ }
+ }
+}
+
+/// Dump the name encoded in the type tag.
+static void dumpTypeTagName(raw_ostream &OS, dwarf::Tag T) {
+ StringRef TagStr = TagString(T);
+ if (!TagStr.startswith("DW_TAG_") || !TagStr.endswith("_type"))
+ return;
+ OS << TagStr.substr(7, TagStr.size() - 12) << " ";
+}
+
+/// Recursively dump the DIE type name when applicable.
+static void dumpTypeName(raw_ostream &OS, const DWARFDie &Die) {
+ DWARFDie D = Die.getAttributeValueAsReferencedDie(DW_AT_type);
+
+ if (!D.isValid())
+ return;
+
+ if (const char *Name = D.getName(DINameKind::LinkageName)) {
+ OS << Name;
+ return;
+ }
+
+ // FIXME: We should have pretty printers per language. Currently we print
+ // everything as if it was C++ and fall back to the TAG type name.
+ const dwarf::Tag T = D.getTag();
+ switch (T) {
+ case DW_TAG_array_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ break;
+ default:
+ dumpTypeTagName(OS, T);
+ }
+
+ // Follow the DW_AT_type if possible.
+ dumpTypeName(OS, D);
+
+ switch (T) {
+ case DW_TAG_array_type:
+ OS << "[]";
+ break;
+ case DW_TAG_pointer_type:
+ OS << '*';
+ break;
+ case DW_TAG_ptr_to_member_type:
+ OS << '*';
+ break;
+ case DW_TAG_reference_type:
+ OS << '&';
+ break;
+ case DW_TAG_rvalue_reference_type:
+ OS << "&&";
+ break;
+ default:
+ break;
}
}
@@ -73,14 +190,14 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
return;
const char BaseIndent[] = " ";
OS << BaseIndent;
- OS.indent(Indent+2);
+ 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);
- if (!DumpOpts.Brief) {
+ if (DumpOpts.Verbose || DumpOpts.ShowForm) {
auto formString = FormEncodingString(Form);
if (!formString.empty())
OS << " [" << formString << ']';
@@ -90,60 +207,81 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
DWARFUnit *U = Die.getDwarfUnit();
DWARFFormValue formValue(Form);
-
- if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr, U))
+
+ if (!formValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr,
+ U->getFormParams(), U))
return;
-
+
OS << "\t(";
-
+
StringRef Name;
std::string File;
auto Color = syntax::Enumerator;
if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) {
Color = syntax::String;
if (const auto *LT = U->getContext().getLineTableForUnit(U))
- if (LT->getFileNameByIndex(formValue.getAsUnsignedConstant().getValue(), U->getCompilationDir(), DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) {
+ if (LT->getFileNameByIndex(
+ formValue.getAsUnsignedConstant().getValue(),
+ U->getCompilationDir(),
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) {
File = '"' + File + '"';
Name = File;
}
} else if (Optional<uint64_t> Val = formValue.getAsUnsignedConstant())
Name = AttributeValueString(Attr, *Val);
-
+
if (!Name.empty())
WithColor(OS, Color) << Name;
else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line)
OS << *formValue.getAsUnsignedConstant();
+ else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose &&
+ formValue.getAsUnsignedConstant()) {
+ if (DumpOpts.ShowAddresses) {
+ // Print the actual address rather than the offset.
+ uint64_t LowPC, HighPC, Index;
+ if (Die.getLowAndHighPC(LowPC, HighPC, Index))
+ OS << format("0x%016" PRIx64, HighPC);
+ else
+ formValue.dump(OS, DumpOpts);
+ }
+ } else if (Attr == DW_AT_location || Attr == DW_AT_frame_base ||
+ Attr == DW_AT_data_member_location ||
+ Attr == DW_AT_GNU_call_site_value)
+ dumpLocation(OS, formValue, U, sizeof(BaseIndent) + Indent + 4, DumpOpts);
else
- formValue.dump(OS);
-
+ formValue.dump(OS, DumpOpts);
+
// We have dumped the attribute raw value. For some attributes
// having both the raw value and the pretty-printed value is
// interesting. These attributes are handled below.
if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) {
- if (const char *Name = Die.getAttributeValueAsReferencedDie(Attr).getName(DINameKind::LinkageName))
- OS << " \"" << Name << '\"';
+ if (const char *Name = Die.getAttributeValueAsReferencedDie(Attr).getName(
+ DINameKind::LinkageName))
+ OS << " \"" << Name << '\"';
+ } else if (Attr == DW_AT_type) {
+ OS << " \"";
+ dumpTypeName(OS, Die);
+ OS << '"';
} else if (Attr == DW_AT_APPLE_property_attribute) {
if (Optional<uint64_t> OptVal = formValue.getAsUnsignedConstant())
dumpApplePropertyAttribute(OS, *OptVal);
} else if (Attr == DW_AT_ranges) {
- dumpRanges(OS, Die.getAddressRanges(), U->getAddressByteSize(),
- sizeof(BaseIndent)+Indent+4);
+ const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj();
+ dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(),
+ sizeof(BaseIndent) + Indent + 4, DumpOpts);
}
-
+
OS << ")\n";
}
-bool DWARFDie::isSubprogramDIE() const {
- return getTag() == DW_TAG_subprogram;
-}
+bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; }
bool DWARFDie::isSubroutineDIE() const {
auto Tag = getTag();
return Tag == DW_TAG_subprogram || Tag == DW_TAG_inlined_subroutine;
}
-Optional<DWARFFormValue>
-DWARFDie::find(dwarf::Attribute Attr) const {
+Optional<DWARFFormValue> DWARFDie::find(dwarf::Attribute Attr) const {
if (!isValid())
return None;
auto AbbrevDecl = getAbbreviationDeclarationPtr();
@@ -170,33 +308,29 @@ Optional<DWARFFormValue>
DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const {
if (!isValid())
return None;
- auto Die = *this;
- if (auto Value = Die.find(Attrs))
- return Value;
- if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
- Die = D;
- if (auto Value = Die.find(Attrs))
- return Value;
- if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification))
- Die = D;
- if (auto Value = Die.find(Attrs))
+ 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))
+ return Value;
+ }
return None;
}
DWARFDie
DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
- auto SpecRef = toReference(find(Attr));
- if (SpecRef) {
- auto SpecUnit = U->getUnitSection().getUnitForOffset(*SpecRef);
- if (SpecUnit)
+ if (auto SpecRef = toReference(find(Attr))) {
+ if (auto SpecUnit = U->getUnitSection().getUnitForOffset(*SpecRef))
return SpecUnit->getDIEForOffset(*SpecRef);
}
return DWARFDie();
}
-Optional<uint64_t>
-DWARFDie::getRangesBaseAttribute() const {
+Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const {
return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base}));
}
@@ -229,8 +363,7 @@ bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC,
return false;
}
-DWARFAddressRangesVector
-DWARFDie::getAddressRanges() const {
+DWARFAddressRangesVector DWARFDie::getAddressRanges() const {
if (isNULL())
return DWARFAddressRangesVector();
// Single range specified by low/high PC.
@@ -248,8 +381,8 @@ DWARFDie::getAddressRanges() const {
return DWARFAddressRangesVector();
}
-void
-DWARFDie::collectChildrenAddressRanges(DWARFAddressRangesVector& Ranges) const {
+void DWARFDie::collectChildrenAddressRanges(
+ DWARFAddressRangesVector &Ranges) const {
if (isNULL())
return;
if (isSubprogramDIE()) {
@@ -257,33 +390,32 @@ DWARFDie::collectChildrenAddressRanges(DWARFAddressRangesVector& Ranges) const {
Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end());
}
- for (auto Child: children())
+ for (auto Child : children())
Child.collectChildrenAddressRanges(Ranges);
}
bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
- for (const auto& R : getAddressRanges()) {
+ for (const auto &R : getAddressRanges()) {
if (R.LowPC <= Address && Address < R.HighPC)
return true;
}
return false;
}
-const char *
-DWARFDie::getSubroutineName(DINameKind Kind) const {
+const char *DWARFDie::getSubroutineName(DINameKind Kind) const {
if (!isSubroutineDIE())
return nullptr;
return getName(Kind);
}
-const char *
-DWARFDie::getName(DINameKind Kind) const {
+const char *DWARFDie::getName(DINameKind Kind) const {
if (!isValid() || Kind == DINameKind::None)
return nullptr;
// Try to get mangled name only if it was asked for.
if (Kind == DINameKind::LinkageName) {
- if (auto Name = dwarf::toString(findRecursively({DW_AT_MIPS_linkage_name,
- DW_AT_linkage_name}), nullptr))
+ if (auto Name = dwarf::toString(
+ findRecursively({DW_AT_MIPS_linkage_name, DW_AT_linkage_name}),
+ nullptr))
return Name;
}
if (auto Name = dwarf::toString(findRecursively(DW_AT_name), nullptr))
@@ -304,18 +436,33 @@ void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0);
}
-void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent,
+/// Helper to dump a DIE with all of its parents, but no siblings.
+static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ if (!Die)
+ return Indent;
+ Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts);
+ Die.dump(OS, Indent, DumpOpts);
+ return Indent + 2;
+}
+
+void DWARFDie::dump(raw_ostream &OS, unsigned Indent,
DIDumpOptions DumpOpts) const {
if (!isValid())
return;
DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor();
const uint32_t Offset = getOffset();
uint32_t offset = Offset;
-
+ if (DumpOpts.ShowParents) {
+ DumpOpts.ShowParents = false;
+ Indent = dumpParentChain(getParent(), OS, Indent, DumpOpts);
+ }
+
if (debug_info_data.isValidOffset(offset)) {
uint32_t abbrCode = debug_info_data.getULEB128(&offset);
- WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset);
-
+ if (DumpOpts.ShowAddresses)
+ WithColor(OS, syntax::Address).get() << format("\n0x%8.8x: ", Offset);
+
if (abbrCode) {
auto AbbrevDecl = getAbbreviationDeclarationPtr();
if (AbbrevDecl) {
@@ -324,9 +471,9 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent,
WithColor(OS, syntax::Tag).get().indent(Indent) << tagString;
else
WithColor(OS, syntax::Tag).get().indent(Indent)
- << format("DW_TAG_Unknown_%x", getTag());
+ << format("DW_TAG_Unknown_%x", getTag());
- if (!DumpOpts.Brief)
+ if (DumpOpts.Verbose)
OS << format(" [%u] %c", abbrCode,
AbbrevDecl->hasChildren() ? '*' : ' ');
OS << '\n';
@@ -342,17 +489,18 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent,
dumpAttribute(OS, *this, &offset, AttrSpec.Attr, AttrSpec.Form,
Indent, DumpOpts);
}
-
+
DWARFDie child = getFirstChild();
- if (RecurseDepth > 0 && child) {
+ if (DumpOpts.ShowChildren && DumpOpts.RecurseDepth > 0 && child) {
+ DumpOpts.RecurseDepth--;
while (child) {
- child.dump(OS, RecurseDepth-1, Indent+2, DumpOpts);
+ child.dump(OS, Indent + 2, DumpOpts);
child = child.getSibling();
}
}
} else {
OS << "Abbreviation code not found in 'debug_abbrev' class for code: "
- << abbrCode << '\n';
+ << abbrCode << '\n';
}
} else {
OS.indent(Indent) << "NULL\n";
@@ -360,6 +508,8 @@ void DWARFDie::dump(raw_ostream &OS, unsigned RecurseDepth, unsigned Indent,
}
}
+LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(llvm::errs(), 0); }
+
DWARFDie DWARFDie::getParent() const {
if (isValid())
return U->getParent(Die);
@@ -372,14 +522,19 @@ DWARFDie DWARFDie::getSibling() const {
return DWARFDie();
}
-iterator_range<DWARFDie::attribute_iterator>
-DWARFDie::attributes() const {
+DWARFDie DWARFDie::getFirstChild() const {
+ if (isValid())
+ return U->getFirstChild(Die);
+ return DWARFDie();
+}
+
+iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const {
return make_range(attribute_iterator(*this, false),
attribute_iterator(*this, true));
}
-DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) :
- Die(D), AttrValue(0), Index(0) {
+DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End)
+ : Die(D), AttrValue(0), Index(0) {
auto AbbrDecl = Die.getAbbreviationDeclarationPtr();
assert(AbbrDecl && "Must have abbreviation declaration");
if (End) {
@@ -406,7 +561,7 @@ void DWARFDie::attribute_iterator::updateForIndex(
auto U = Die.getDwarfUnit();
assert(U && "Die must have valid DWARF unit");
bool b = AttrValue.Value.extractValue(U->getDebugInfoExtractor(),
- &ParseOffset, U);
+ &ParseOffset, U->getFormParams(), U);
(void)b;
assert(b && "extractValue cannot fail on fully parsed DWARF");
AttrValue.ByteSize = ParseOffset - AttrValue.Offset;
diff --git a/lib/DebugInfo/DWARF/DWARFExpression.cpp b/lib/DebugInfo/DWARF/DWARFExpression.cpp
new file mode 100644
index 000000000000..c704c2901aef
--- /dev/null
+++ b/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -0,0 +1,274 @@
+//===-- DWARFExpression.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/Format.h"
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+namespace llvm {
+
+typedef std::vector<DWARFExpression::Operation::Description> DescVector;
+
+static DescVector getDescriptions() {
+ DescVector Descriptions;
+ typedef DWARFExpression::Operation Op;
+ typedef Op::Description Desc;
+
+ Descriptions.resize(0xff);
+ Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr);
+ Descriptions[DW_OP_deref] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1);
+ Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2);
+ Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4);
+ Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4);
+ Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8);
+ Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8);
+ Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_dup] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_drop] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_over] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_swap] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_rot] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_abs] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_and] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_div] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_minus] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_mod] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_mul] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_neg] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_not] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_or] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_plus] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_shl] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_shr] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_shra] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_xor] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_eq] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_ge] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_gt] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_le] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_lt] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_ne] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB);
+ Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_nop] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2);
+ Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4);
+ Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr);
+ Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB);
+ Descriptions[DW_OP_implicit_value] =
+ Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
+ Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ return Descriptions;
+}
+
+static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) {
+ // FIXME: Make this constexpr once all compilers are smart enough to do it.
+ static DescVector Descriptions = getDescriptions();
+ // Handle possible corrupted or unsupported operation.
+ if (OpCode >= Descriptions.size())
+ return {};
+ return Descriptions[OpCode];
+}
+
+static uint8_t getRefAddrSize(uint8_t AddrSize, uint16_t Version) {
+ return (Version == 2) ? AddrSize : 4;
+}
+
+bool DWARFExpression::Operation::extract(DataExtractor Data, uint16_t Version,
+ uint8_t AddressSize, uint32_t Offset) {
+ Opcode = Data.getU8(&Offset);
+
+ Desc = getOpDesc(Opcode);
+ if (Desc.Version == Operation::DwarfNA) {
+ EndOffset = Offset;
+ return false;
+ }
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+ unsigned Signed = Size & Operation::SignBit;
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ switch (Size & ~Operation::SignBit) {
+ case Operation::Size1:
+ Operands[Operand] = Data.getU8(&Offset);
+ if (Signed)
+ Operands[Operand] = (int8_t)Operands[Operand];
+ break;
+ case Operation::Size2:
+ Operands[Operand] = Data.getU16(&Offset);
+ if (Signed)
+ Operands[Operand] = (int16_t)Operands[Operand];
+ break;
+ case Operation::Size4:
+ Operands[Operand] = Data.getU32(&Offset);
+ if (Signed)
+ Operands[Operand] = (int32_t)Operands[Operand];
+ break;
+ case Operation::Size8:
+ Operands[Operand] = Data.getU64(&Offset);
+ break;
+ case Operation::SizeAddr:
+ if (AddressSize == 8) {
+ Operands[Operand] = Data.getU64(&Offset);
+ } else {
+ assert(AddressSize == 4);
+ Operands[Operand] = Data.getU32(&Offset);
+ }
+ break;
+ case Operation::SizeRefAddr:
+ if (getRefAddrSize(AddressSize, Version) == 8) {
+ Operands[Operand] = Data.getU64(&Offset);
+ } else {
+ assert(getRefAddrSize(AddressSize, Version) == 4);
+ Operands[Operand] = Data.getU32(&Offset);
+ }
+ break;
+ case Operation::SizeLEB:
+ if (Signed)
+ Operands[Operand] = Data.getSLEB128(&Offset);
+ else
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case Operation::SizeBlock:
+ // We need a size, so this cannot be the first operand
+ if (Operand == 0)
+ return false;
+ // Store the offset of the block as the value.
+ Operands[Operand] = Offset;
+ Offset += Operands[Operand - 1];
+ break;
+ default:
+ llvm_unreachable("Unknown DWARFExpression Op size");
+ }
+ }
+
+ EndOffset = Offset;
+ return true;
+}
+
+static bool prettyPrintRegisterOp(raw_ostream &OS, uint8_t Opcode,
+ uint64_t Operands[2],
+ const MCRegisterInfo *MRI, bool isEH) {
+ if (!MRI)
+ return false;
+
+ uint64_t DwarfRegNum;
+ unsigned OpNum = 0;
+
+ if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx)
+ DwarfRegNum = Operands[OpNum++];
+ else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
+ DwarfRegNum = Opcode - DW_OP_breg0;
+ else
+ DwarfRegNum = Opcode - DW_OP_reg0;
+
+ int LLVMRegNum = MRI->getLLVMRegNum(DwarfRegNum, isEH);
+ if (LLVMRegNum >= 0) {
+ if (const char *RegName = MRI->getName(LLVMRegNum)) {
+ if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+ Opcode == DW_OP_bregx)
+ OS << format(" %s%+" PRId64, RegName, Operands[OpNum]);
+ else
+ OS << ' ' << RegName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DWARFExpression::Operation::print(raw_ostream &OS,
+ const DWARFExpression *Expr,
+ const MCRegisterInfo *RegInfo,
+ bool isEH) {
+ if (Error) {
+ OS << "<decoding error>";
+ return false;
+ }
+
+ StringRef Name = OperationEncodingString(Opcode);
+ assert(!Name.empty() && "DW_OP has no name!");
+ OS << Name;
+
+ if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+ (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) ||
+ Opcode == DW_OP_bregx || Opcode == DW_OP_regx)
+ if (prettyPrintRegisterOp(OS, Opcode, Operands, RegInfo, isEH))
+ return true;
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+ unsigned Signed = Size & Operation::SignBit;
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ if (Size == Operation::SizeBlock) {
+ uint32_t Offset = Operands[Operand];
+ for (unsigned i = 0; i < Operands[Operand - 1]; ++i)
+ OS << format(" 0x%02x", Expr->Data.getU8(&Offset));
+ } else {
+ if (Signed)
+ OS << format(" %+" PRId64, (int64_t)Operands[Operand]);
+ else
+ OS << format(" 0x%" PRIx64, Operands[Operand]);
+ }
+ }
+ return true;
+}
+
+void DWARFExpression::print(raw_ostream &OS, const MCRegisterInfo *RegInfo) {
+ for (auto &Op : *this) {
+ if (!Op.print(OS, this, RegInfo, /* isEH */ false)) {
+ uint32_t FailOffset = Op.getEndOffset();
+ while (FailOffset < Data.getData().size())
+ OS << format(" %02x", Data.getU8(&FailOffset));
+ return;
+ }
+ if (Op.getEndOffset() < Data.getData().size())
+ OS << ", ";
+ }
+}
+
+} // namespace llvm
diff --git a/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/lib/DebugInfo/DWARF/DWARFFormValue.cpp
index 83a7792e1244..44886de2e3d5 100644
--- a/lib/DebugInfo/DWARF/DWARFFormValue.cpp
+++ b/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -186,6 +186,7 @@ bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
case DW_FORM_data2:
case DW_FORM_data4:
case DW_FORM_data8:
+ case DW_FORM_data16:
case DW_FORM_flag:
case DW_FORM_ref1:
case DW_FORM_ref2:
@@ -276,7 +277,8 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
}
bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
- uint32_t *OffsetPtr, const DWARFUnit *CU) {
+ uint32_t *OffsetPtr, DWARFFormParams FP,
+ const DWARFUnit *CU) {
U = CU;
bool Indirect = false;
bool IsBlock = false;
@@ -288,10 +290,8 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
switch (Form) {
case DW_FORM_addr:
case DW_FORM_ref_addr: {
- if (!U)
- return false;
- uint16_t Size = (Form == DW_FORM_addr) ? U->getAddressByteSize()
- : U->getRefAddrByteSize();
+ uint16_t Size =
+ (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize();
Value.uval = Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex);
break;
}
@@ -340,6 +340,11 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
case DW_FORM_ref_sup8:
Value.uval = Data.getU64(OffsetPtr);
break;
+ case DW_FORM_data16:
+ // Treat this like a 16-byte block.
+ Value.uval = 16;
+ IsBlock = true;
+ break;
case DW_FORM_sdata:
Value.sval = Data.getSLEB128(OffsetPtr);
break;
@@ -360,10 +365,8 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
case DW_FORM_GNU_strp_alt:
case DW_FORM_line_strp:
case DW_FORM_strp_sup: {
- if (!U)
- return false;
Value.uval =
- Data.getRelocatedValue(U->getDwarfOffsetByteSize(), OffsetPtr);
+ Data.getRelocatedValue(FP.getDwarfOffsetByteSize(), OffsetPtr);
break;
}
case DW_FORM_flag_present:
@@ -396,21 +399,22 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
return true;
}
-void DWARFFormValue::dump(raw_ostream &OS) const {
+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();
switch (Form) {
case DW_FORM_addr:
- OS << format("0x%016" PRIx64, UValue);
+ AddrOS << format("0x%016" PRIx64, UValue);
break;
case DW_FORM_GNU_addr_index: {
- OS << format(" indexed (%8.8x) address = ", (uint32_t)UValue);
+ AddrOS << format(" indexed (%8.8x) address = ", (uint32_t)UValue);
uint64_t Address;
if (U == nullptr)
OS << "<invalid dwarf unit>";
else if (U->getAddrOffsetSectionItem(UValue, Address))
- OS << format("0x%016" PRIx64, Address);
+ AddrOS << format("0x%016" PRIx64, Address);
else
OS << "<no .debug_addr section>";
break;
@@ -429,9 +433,14 @@ void DWARFFormValue::dump(raw_ostream &OS) const {
OS << format("0x%08x", (uint32_t)UValue);
break;
case DW_FORM_ref_sig8:
+ AddrOS << format("0x%016" PRIx64, UValue);
+ break;
case DW_FORM_data8:
OS << format("0x%016" PRIx64, UValue);
break;
+ case DW_FORM_data16:
+ OS << format_bytes(ArrayRef<uint8_t>(Value.data, 16), None, 16, 16);
+ break;
case DW_FORM_string:
OS << '"';
OS.write_escaped(Value.cstr);
@@ -481,7 +490,8 @@ void DWARFFormValue::dump(raw_ostream &OS) const {
OS << Value.uval;
break;
case DW_FORM_strp:
- OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue);
+ if (DumpOpts.Verbose)
+ OS << format(" .debug_str[0x%8.8x] = ", (uint32_t)UValue);
dumpString(OS);
break;
case DW_FORM_strx:
@@ -490,38 +500,40 @@ void DWARFFormValue::dump(raw_ostream &OS) const {
case DW_FORM_strx3:
case DW_FORM_strx4:
case DW_FORM_GNU_str_index:
- OS << format(" indexed (%8.8x) string = ", (uint32_t)UValue);
+ if (DumpOpts.Verbose)
+ OS << format(" indexed (%8.8x) string = ", (uint32_t)UValue);
dumpString(OS);
break;
case DW_FORM_GNU_strp_alt:
- OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue);
+ if (DumpOpts.Verbose)
+ OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue);
dumpString(OS);
break;
case DW_FORM_ref_addr:
- OS << format("0x%016" PRIx64, UValue);
+ AddrOS << format("0x%016" PRIx64, UValue);
break;
case DW_FORM_ref1:
CURelativeOffset = true;
- OS << format("cu + 0x%2.2x", (uint8_t)UValue);
+ AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue);
break;
case DW_FORM_ref2:
CURelativeOffset = true;
- OS << format("cu + 0x%4.4x", (uint16_t)UValue);
+ AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue);
break;
case DW_FORM_ref4:
CURelativeOffset = true;
- OS << format("cu + 0x%4.4x", (uint32_t)UValue);
+ AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue);
break;
case DW_FORM_ref8:
CURelativeOffset = true;
- OS << format("cu + 0x%8.8" PRIx64, UValue);
+ AddrOS << format("cu + 0x%8.8" PRIx64, UValue);
break;
case DW_FORM_ref_udata:
CURelativeOffset = true;
- OS << format("cu + 0x%" PRIx64, UValue);
+ AddrOS << format("cu + 0x%" PRIx64, UValue);
break;
case DW_FORM_GNU_ref_alt:
- OS << format("<alt 0x%" PRIx64 ">", UValue);
+ AddrOS << format("<alt 0x%" PRIx64 ">", UValue);
break;
// All DW_FORM_indirect attributes should be resolved prior to calling
@@ -532,7 +544,7 @@ void DWARFFormValue::dump(raw_ostream &OS) const {
// Should be formatted to 64-bit for DWARF64.
case DW_FORM_sec_offset:
- OS << format("0x%08x", (uint32_t)UValue);
+ AddrOS << format("0x%08x", (uint32_t)UValue);
break;
default:
@@ -540,7 +552,7 @@ void DWARFFormValue::dump(raw_ostream &OS) const {
break;
}
- if (CURelativeOffset) {
+ if (CURelativeOffset && DumpOpts.Verbose) {
OS << " => {";
WithColor(OS, syntax::Address).get()
<< format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0));
@@ -648,7 +660,8 @@ Optional<int64_t> DWARFFormValue::getAsSignedConstant() const {
}
Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const {
- if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc))
+ if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc) &&
+ Form != DW_FORM_data16)
return None;
return makeArrayRef(Value.data, Value.uval);
}
diff --git a/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
index fd1684d33a16..206c12fa403f 100644
--- a/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
+++ b/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
@@ -31,11 +31,11 @@ bool DWARFTypeUnit::extractImpl(DataExtractor debug_info,
return TypeOffset < getLength() + SizeOfLength;
}
-void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) {
+void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
DWARFDie TD = getDIEForOffset(TypeOffset + getOffset());
const char *Name = TD.getName(DINameKind::ShortName);
- if (SummarizeTypes) {
+ if (DumpOpts.SummarizeTypes) {
OS << "name = '" << Name << "'"
<< " type_signature = " << format("0x%016" PRIx64, TypeHash)
<< " length = " << format("0x%08x", getLength()) << '\n';
@@ -55,7 +55,7 @@ void DWARFTypeUnit::dump(raw_ostream &OS, bool SummarizeTypes) {
<< " (next unit at " << format("0x%08x", getNextUnitOffset()) << ")\n";
if (DWARFDie TU = getUnitDIE(false))
- TU.dump(OS, -1U);
+ TU.dump(OS, 0, DumpOpts);
else
OS << "<type unit can't be parsed!>\n\n";
}
diff --git a/lib/DebugInfo/DWARF/DWARFUnit.cpp b/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 043bdb874f43..c3d8ff2cbc29 100644
--- a/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -30,18 +30,20 @@ using namespace llvm;
using namespace dwarf;
void DWARFUnitSectionBase::parse(DWARFContext &C, const DWARFSection &Section) {
- parseImpl(C, Section, C.getDebugAbbrev(), &C.getRangeSection(),
- C.getStringSection(), C.getStringOffsetSection(),
- &C.getAddrSection(), C.getLineSection(), C.isLittleEndian(), false);
+ const DWARFObject &D = C.getDWARFObj();
+ parseImpl(C, Section, C.getDebugAbbrev(), &D.getRangeSection(),
+ D.getStringSection(), D.getStringOffsetSection(),
+ &D.getAddrSection(), D.getLineSection(), D.isLittleEndian(), false,
+ false);
}
void DWARFUnitSectionBase::parseDWO(DWARFContext &C,
- const DWARFSection &DWOSection,
- DWARFUnitIndex *Index) {
- parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), &C.getRangeDWOSection(),
- C.getStringDWOSection(), C.getStringOffsetDWOSection(),
- &C.getAddrSection(), C.getLineDWOSection(), C.isLittleEndian(),
- true);
+ const DWARFSection &DWOSection, bool Lazy) {
+ const DWARFObject &D = C.getDWARFObj();
+ parseImpl(C, DWOSection, C.getDebugAbbrevDWO(), &D.getRangeDWOSection(),
+ D.getStringDWOSection(), D.getStringOffsetDWOSection(),
+ &D.getAddrSection(), D.getLineDWOSection(), C.isLittleEndian(),
+ true, Lazy);
}
DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
@@ -59,13 +61,18 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
DWARFUnit::~DWARFUnit() = default;
+DWARFDataExtractor DWARFUnit::getDebugInfoExtractor() const {
+ return DWARFDataExtractor(Context.getDWARFObj(), InfoSection, isLittleEndian,
+ getAddressByteSize());
+}
+
bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index,
uint64_t &Result) const {
uint32_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize();
if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize())
return false;
- DWARFDataExtractor DA(*AddrOffsetSection, isLittleEndian,
- getAddressByteSize());
+ DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection,
+ isLittleEndian, getAddressByteSize());
Result = DA.getRelocatedAddress(&Offset);
return true;
}
@@ -76,7 +83,8 @@ bool DWARFUnit::getStringOffsetSectionItem(uint32_t Index,
uint32_t Offset = StringOffsetSectionBase + Index * ItemSize;
if (StringOffsetSection.Data.size() < Offset + ItemSize)
return false;
- DWARFDataExtractor DA(StringOffsetSection, isLittleEndian, 0);
+ DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
+ isLittleEndian, 0);
Result = DA.getRelocatedValue(ItemSize, &Offset);
return true;
}
@@ -86,7 +94,6 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
// FIXME: Support DWARF64.
FormParams.Format = DWARF32;
FormParams.Version = debug_info.getU16(offset_ptr);
- uint64_t AbbrOffset;
if (FormParams.Version >= 5) {
UnitType = debug_info.getU8(offset_ptr);
FormParams.AddrSize = debug_info.getU8(offset_ptr);
@@ -116,9 +123,7 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) {
// Keep track of the highest DWARF version we encounter across all units.
Context.setMaxVersionIfGreater(getVersion());
-
- Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset);
- return Abbrevs != nullptr;
+ return true;
}
bool DWARFUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) {
@@ -141,8 +146,8 @@ bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
DWARFDebugRangeList &RangeList) const {
// Require that compile unit is extracted.
assert(!DieArray.empty());
- DWARFDataExtractor RangesData(*RangeSection, isLittleEndian,
- getAddressByteSize());
+ DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, getAddressByteSize());
uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
return RangeList.extract(RangesData, &ActualRangeListOffset);
}
@@ -152,7 +157,7 @@ void DWARFUnit::clear() {
Length = 0;
Abbrevs = nullptr;
FormParams = DWARFFormParams({0, 0, DWARF32});
- BaseAddr = 0;
+ BaseAddr.reset();
RangeSectionBase = 0;
AddrOffsetSectionBase = 0;
clearDIEs(false);
@@ -234,11 +239,17 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
// If CU DIE was just parsed, copy several attribute values from it.
if (!HasCUDie) {
DWARFDie UnitDie = getUnitDIE();
- auto BaseAddr = toAddress(UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc}));
- if (BaseAddr)
- setBaseAddress(*BaseAddr);
- AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0);
- RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
+ 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 (!isDWO) {
+ assert(AddrOffsetSectionBase == 0);
+ assert(RangeSectionBase == 0);
+ AddrOffsetSectionBase =
+ toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0);
+ RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
+ }
// In general, we derive the offset of the unit's contibution to the
// debug_str_offsets{.dwo} section from the unit DIE's
@@ -295,18 +306,8 @@ bool DWARFUnit::parseDWO() {
void DWARFUnit::clearDIEs(bool KeepCUDie) {
if (DieArray.size() > (unsigned)KeepCUDie) {
- // std::vectors never get any smaller when resized to a smaller size,
- // or when clear() or erase() are called, the size will report that it
- // is smaller, but the memory allocated remains intact (call capacity()
- // to see this). So we need to create a temporary vector and swap the
- // contents which will cause just the internal pointers to be swapped
- // so that when temporary vector goes out of scope, it will destroy the
- // contents.
- std::vector<DWARFDebugInfoEntry> TmpArray;
- DieArray.swap(TmpArray);
- // Save at least the compile unit DIE
- if (KeepCUDie)
- DieArray.push_back(TmpArray.front());
+ DieArray.resize((unsigned)KeepCUDie);
+ DieArray.shrink_to_fit();
}
}
@@ -439,7 +440,7 @@ DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) {
// NULL DIEs don't have siblings.
if (Die->getAbbreviationDeclarationPtr() == nullptr)
return DWARFDie();
-
+
// Find the next DIE whose depth is the same as the Die's depth.
for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx;
++I) {
@@ -448,3 +449,20 @@ DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) {
}
return DWARFDie();
}
+
+DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) {
+ if (!Die->hasChildren())
+ return DWARFDie();
+
+ // We do not want access out of bounds when parsing corrupted debug data.
+ size_t I = getDIEIndex(Die) + 1;
+ if (I >= DieArray.size())
+ return DWARFDie();
+ return DWARFDie(this, &DieArray[I]);
+}
+
+const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
+ if (!Abbrevs)
+ Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset);
+ return Abbrevs;
+}
diff --git a/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
index 59b3d0ca55a6..17f17572a309 100644
--- a/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
+++ b/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
@@ -123,7 +123,7 @@ StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) {
}
void DWARFUnitIndex::dump(raw_ostream &OS) const {
- if (!Header.NumBuckets)
+ if (!*this)
return;
Header.dump(OS);
@@ -165,8 +165,25 @@ DWARFUnitIndex::Entry::getOffset() const {
const DWARFUnitIndex::Entry *
DWARFUnitIndex::getFromOffset(uint32_t Offset) const {
for (uint32_t i = 0; i != Header.NumBuckets; ++i)
- if (const auto &Contribs = Rows[i].Contributions)
- if (Contribs[InfoColumn].Offset == Offset)
+ if (const auto &Contribs = Rows[i].Contributions) {
+ const auto &InfoContrib = Contribs[InfoColumn];
+ if (InfoContrib.Offset <= Offset &&
+ Offset < (InfoContrib.Offset + InfoContrib.Length))
return &Rows[i];
+ }
return nullptr;
}
+
+const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const {
+ uint64_t Mask = Header.NumBuckets - 1;
+
+ auto H = S & Mask;
+ auto HP = ((S >> 32) & Mask) | 1;
+ while (Rows[H].getSignature() != S && Rows[H].getSignature() != 0)
+ H = (H + HP) & Mask;
+
+ if (Rows[H].getSignature() != S)
+ return nullptr;
+
+ return &Rows[H];
+}
diff --git a/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index 4de46bea301e..3d473698b463 100644
--- a/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -7,14 +7,17 @@
//
//===----------------------------------------------------------------------===//
+#include "SyntaxHighlighting.h"
#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/DebugInfo/DWARF/DWARFSection.h"
#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
#include <set>
@@ -23,6 +26,86 @@
using namespace llvm;
using namespace dwarf;
using namespace object;
+using namespace syntax;
+
+DWARFVerifier::DieRangeInfo::address_range_iterator
+DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
+ auto Begin = Ranges.begin();
+ auto End = Ranges.end();
+ auto Pos = std::lower_bound(Begin, End, R);
+
+ if (Pos != End) {
+ if (Pos->intersects(R))
+ return Pos;
+ if (Pos != Begin) {
+ auto Iter = Pos - 1;
+ if (Iter->intersects(R))
+ return Iter;
+ }
+ }
+
+ Ranges.insert(Pos, R);
+ return Ranges.end();
+}
+
+DWARFVerifier::DieRangeInfo::die_range_info_iterator
+DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) {
+ auto End = Children.end();
+ auto Iter = Children.begin();
+ while (Iter != End) {
+ if (Iter->intersects(RI))
+ return Iter;
+ ++Iter;
+ }
+ Children.insert(RI);
+ return Children.end();
+}
+
+bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const {
+ // Both list of ranges are sorted so we can make this fast.
+
+ if (Ranges.empty() || RHS.Ranges.empty())
+ return false;
+
+ // Since the ranges are sorted we can advance where we start searching with
+ // this object's ranges as we traverse RHS.Ranges.
+ auto End = Ranges.end();
+ auto Iter = findRange(RHS.Ranges.front());
+
+ // Now linearly walk the ranges in this object and see if they contain each
+ // ranges from RHS.Ranges.
+ for (const auto &R : RHS.Ranges) {
+ while (Iter != End) {
+ if (Iter->contains(R))
+ break;
+ ++Iter;
+ }
+ if (Iter == End)
+ return false;
+ }
+ return true;
+}
+
+bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const {
+ if (Ranges.empty() || RHS.Ranges.empty())
+ return false;
+
+ auto End = Ranges.end();
+ auto Iter = findRange(RHS.Ranges.front());
+ for (const auto &R : RHS.Ranges) {
+ if(Iter == End)
+ return false;
+ if (R.HighPC <= Iter->LowPC)
+ continue;
+ while (Iter != End) {
+ if (Iter->intersects(R))
+ return true;
+ ++Iter;
+ }
+ }
+
+ return false;
+}
bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
uint32_t *Offset, unsigned UnitIndex,
@@ -53,7 +136,7 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
UnitType = DebugInfoData.getU8(Offset);
AddrSize = DebugInfoData.getU8(Offset);
AbbrOffset = DebugInfoData.getU32(Offset);
- ValidType = DWARFUnit::isValidUnitType(UnitType);
+ ValidType = dwarf::isUnitType(UnitType);
} else {
UnitType = 0;
AbbrOffset = DebugInfoData.getU32(Offset);
@@ -69,25 +152,26 @@ bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
!ValidType) {
Success = false;
- OS << format("Units[%d] - start offset: 0x%08x \n", UnitIndex, OffsetStart);
+ error() << format("Units[%d] - start offset: 0x%08x \n", UnitIndex,
+ OffsetStart);
if (!ValidLength)
- OS << "\tError: The length for this unit is too "
+ note() << "The length for this unit is too "
"large for the .debug_info provided.\n";
if (!ValidVersion)
- OS << "\tError: The 16 bit unit header version is not valid.\n";
+ note() << "The 16 bit unit header version is not valid.\n";
if (!ValidType)
- OS << "\tError: The unit type encoding is not valid.\n";
+ note() << "The unit type encoding is not valid.\n";
if (!ValidAbbrevOffset)
- OS << "\tError: The offset into the .debug_abbrev section is "
+ note() << "The offset into the .debug_abbrev section is "
"not valid.\n";
if (!ValidAddrSize)
- OS << "\tError: The address size is unsupported.\n";
+ note() << "The address size is unsupported.\n";
}
*Offset = OffsetStart + Length + 4;
return Success;
}
-bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) {
+bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit, uint8_t UnitType) {
uint32_t NumUnitErrors = 0;
unsigned NumDies = Unit.getNumDIEs();
for (unsigned I = 0; I < NumDies; ++I) {
@@ -99,20 +183,89 @@ bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit) {
NumUnitErrors += verifyDebugInfoForm(Die, AttrValue);
}
}
+
+ DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
+ if (!Die) {
+ error() << "Compilation unit without DIE.\n";
+ NumUnitErrors++;
+ return NumUnitErrors == 0;
+ }
+
+ if (!dwarf::isUnitType(Die.getTag())) {
+ error() << "Compilation unit root DIE is not a unit DIE: "
+ << dwarf::TagString(Die.getTag()) << ".\n";
+ NumUnitErrors++;
+ }
+
+ if (UnitType != 0 &&
+ !DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) {
+ error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType)
+ << ") and root DIE (" << dwarf::TagString(Die.getTag())
+ << ") do not match.\n";
+ NumUnitErrors++;
+ }
+
+ DieRangeInfo RI;
+ NumUnitErrors += verifyDieRanges(Die, RI);
+
return NumUnitErrors == 0;
}
+unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
+ unsigned NumErrors = 0;
+ if (Abbrev) {
+ const DWARFAbbreviationDeclarationSet *AbbrDecls =
+ Abbrev->getAbbreviationDeclarationSet(0);
+ for (auto AbbrDecl : *AbbrDecls) {
+ SmallDenseSet<uint16_t> AttributeSet;
+ for (auto Attribute : AbbrDecl.attributes()) {
+ auto Result = AttributeSet.insert(Attribute.Attr);
+ if (!Result.second) {
+ error() << "Abbreviation declaration contains multiple "
+ << AttributeString(Attribute.Attr) << " attributes.\n";
+ AbbrDecl.dump(OS);
+ ++NumErrors;
+ }
+ }
+ }
+ }
+ return NumErrors;
+}
+
+bool DWARFVerifier::handleDebugAbbrev() {
+ OS << "Verifying .debug_abbrev...\n";
+
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ bool noDebugAbbrev = DObj.getAbbrevSection().empty();
+ bool noDebugAbbrevDWO = DObj.getAbbrevDWOSection().empty();
+
+ if (noDebugAbbrev && noDebugAbbrevDWO) {
+ return true;
+ }
+
+ unsigned NumErrors = 0;
+ if (!noDebugAbbrev)
+ NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
+
+ if (!noDebugAbbrevDWO)
+ NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
+ return NumErrors == 0;
+}
+
bool DWARFVerifier::handleDebugInfo() {
OS << "Verifying .debug_info Unit Header Chain...\n";
- DWARFDataExtractor DebugInfoData(DCtx.getInfoSection(), DCtx.isLittleEndian(),
- 0);
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ DWARFDataExtractor DebugInfoData(DObj, DObj.getInfoSection(),
+ DCtx.isLittleEndian(), 0);
uint32_t NumDebugInfoErrors = 0;
uint32_t OffsetStart = 0, Offset = 0, UnitIdx = 0;
uint8_t UnitType = 0;
bool isUnitDWARF64 = false;
bool isHeaderChainValid = true;
bool hasDIE = DebugInfoData.isValidOffset(Offset);
+ DWARFUnitSection<DWARFTypeUnit> TUSection{};
+ DWARFUnitSection<DWARFCompileUnit> CUSection{};
while (hasDIE) {
OffsetStart = Offset;
if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,
@@ -125,12 +278,11 @@ bool DWARFVerifier::handleDebugInfo() {
switch (UnitType) {
case dwarf::DW_UT_type:
case dwarf::DW_UT_split_type: {
- DWARFUnitSection<DWARFTypeUnit> TUSection{};
Unit.reset(new DWARFTypeUnit(
- DCtx, DCtx.getInfoSection(), DCtx.getDebugAbbrev(),
- &DCtx.getRangeSection(), DCtx.getStringSection(),
- DCtx.getStringOffsetSection(), &DCtx.getAppleObjCSection(),
- DCtx.getLineSection(), DCtx.isLittleEndian(), false, TUSection,
+ DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
+ &DObj.getRangeSection(), DObj.getStringSection(),
+ DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
+ DObj.getLineSection(), DCtx.isLittleEndian(), false, TUSection,
nullptr));
break;
}
@@ -141,72 +293,141 @@ bool DWARFVerifier::handleDebugInfo() {
// UnitType = 0 means that we are
// verifying a compile unit in DWARF v4.
case 0: {
- DWARFUnitSection<DWARFCompileUnit> CUSection{};
Unit.reset(new DWARFCompileUnit(
- DCtx, DCtx.getInfoSection(), DCtx.getDebugAbbrev(),
- &DCtx.getRangeSection(), DCtx.getStringSection(),
- DCtx.getStringOffsetSection(), &DCtx.getAppleObjCSection(),
- DCtx.getLineSection(), DCtx.isLittleEndian(), false, CUSection,
+ DCtx, DObj.getInfoSection(), DCtx.getDebugAbbrev(),
+ &DObj.getRangeSection(), DObj.getStringSection(),
+ DObj.getStringOffsetSection(), &DObj.getAppleObjCSection(),
+ DObj.getLineSection(), DCtx.isLittleEndian(), false, CUSection,
nullptr));
break;
}
default: { llvm_unreachable("Invalid UnitType."); }
}
Unit->extract(DebugInfoData, &OffsetStart);
- if (!verifyUnitContents(*Unit))
+ if (!verifyUnitContents(*Unit, UnitType))
++NumDebugInfoErrors;
}
hasDIE = DebugInfoData.isValidOffset(Offset);
++UnitIdx;
}
if (UnitIdx == 0 && !hasDIE) {
- OS << "Warning: .debug_info is empty.\n";
+ warn() << ".debug_info is empty.\n";
isHeaderChainValid = true;
}
NumDebugInfoErrors += verifyDebugInfoReferences();
return (isHeaderChainValid && NumDebugInfoErrors == 0);
}
+unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
+ DieRangeInfo &ParentRI) {
+ unsigned NumErrors = 0;
+
+ if (!Die.isValid())
+ return NumErrors;
+
+ DWARFAddressRangesVector Ranges = Die.getAddressRanges();
+
+ // Build RI for this DIE and check that ranges within this DIE do not
+ // overlap.
+ DieRangeInfo RI(Die);
+ for (auto Range : Ranges) {
+ if (!Range.valid()) {
+ ++NumErrors;
+ error() << "Invalid address range " << Range << "\n";
+ continue;
+ }
+
+ // Verify that ranges don't intersect.
+ const auto IntersectingRange = RI.insert(Range);
+ if (IntersectingRange != RI.Ranges.end()) {
+ ++NumErrors;
+ error() << "DIE has overlapping address ranges: " << Range << " and "
+ << *IntersectingRange << "\n";
+ break;
+ }
+ }
+
+ // Verify that children don't intersect.
+ const auto IntersectingChild = ParentRI.insert(RI);
+ if (IntersectingChild != ParentRI.Children.end()) {
+ ++NumErrors;
+ error() << "DIEs have overlapping address ranges:";
+ Die.dump(OS, 0);
+ IntersectingChild->Die.dump(OS, 0);
+ OS << "\n";
+ }
+
+ // Verify that ranges are contained within their parent.
+ bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() &&
+ !(Die.getTag() == DW_TAG_subprogram &&
+ ParentRI.Die.getTag() == DW_TAG_subprogram);
+ if (ShouldBeContained && !ParentRI.contains(RI)) {
+ ++NumErrors;
+ error() << "DIE address ranges are not "
+ "contained in its parent's ranges:";
+ Die.dump(OS, 0);
+ ParentRI.Die.dump(OS, 0);
+ OS << "\n";
+ }
+
+ // Recursively check children.
+ for (DWARFDie Child : Die)
+ NumErrors += verifyDieRanges(Child, RI);
+
+ return NumErrors;
+}
+
unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
DWARFAttribute &AttrValue) {
unsigned NumErrors = 0;
+ auto ReportError = [&](const Twine &TitleMsg) {
+ ++NumErrors;
+ error() << TitleMsg << '\n';
+ Die.dump(OS, 0, DumpOpts);
+ OS << "\n";
+ };
+
+ const DWARFObject &DObj = DCtx.getDWARFObj();
const auto Attr = AttrValue.Attr;
switch (Attr) {
case DW_AT_ranges:
// Make sure the offset in the DW_AT_ranges attribute is valid.
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
- if (*SectionOffset >= DCtx.getRangeSection().Data.size()) {
- ++NumErrors;
- OS << "error: DW_AT_ranges offset is beyond .debug_ranges "
- "bounds:\n";
- Die.dump(OS, 0);
- OS << "\n";
- }
- } else {
- ++NumErrors;
- OS << "error: DIE has invalid DW_AT_ranges encoding:\n";
- Die.dump(OS, 0);
- OS << "\n";
+ if (*SectionOffset >= DObj.getRangeSection().Data.size())
+ ReportError("DW_AT_ranges offset is beyond .debug_ranges bounds:");
+ break;
}
+ ReportError("DIE has invalid DW_AT_ranges encoding:");
break;
case DW_AT_stmt_list:
// Make sure the offset in the DW_AT_stmt_list attribute is valid.
if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
- if (*SectionOffset >= DCtx.getLineSection().Data.size()) {
- ++NumErrors;
- OS << "error: DW_AT_stmt_list offset is beyond .debug_line "
- "bounds: "
- << format("0x%08" PRIx64, *SectionOffset) << "\n";
- Die.dump(OS, 0);
- OS << "\n";
- }
- } else {
- ++NumErrors;
- OS << "error: DIE has invalid DW_AT_stmt_list encoding:\n";
- Die.dump(OS, 0);
- OS << "\n";
+ if (*SectionOffset >= DObj.getLineSection().Data.size())
+ ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " +
+ llvm::formatv("{0:x8}", *SectionOffset));
+ break;
}
+ ReportError("DIE has invalid DW_AT_stmt_list encoding:");
+ break;
+ case DW_AT_location: {
+ Optional<ArrayRef<uint8_t>> Expr = AttrValue.Value.getAsBlock();
+ if (!Expr) {
+ ReportError("DIE has invalid DW_AT_location encoding:");
+ break;
+ }
+
+ DWARFUnit *U = Die.getDwarfUnit();
+ DataExtractor Data(
+ StringRef(reinterpret_cast<const char *>(Expr->data()), Expr->size()),
+ DCtx.isLittleEndian(), 0);
+ DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
+ bool Error = llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
+ return Op.isError();
+ });
+ if (Error)
+ ReportError("DIE contains invalid DWARF expression:");
break;
+ }
default:
break;
@@ -216,6 +437,7 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
DWARFAttribute &AttrValue) {
+ const DWARFObject &DObj = DCtx.getDWARFObj();
unsigned NumErrors = 0;
const auto Form = AttrValue.Value.getForm();
switch (Form) {
@@ -233,11 +455,11 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
auto CUOffset = AttrValue.Value.getRawUValue();
if (CUOffset >= CUSize) {
++NumErrors;
- OS << "error: " << FormEncodingString(Form) << " CU offset "
- << format("0x%08" PRIx64, CUOffset)
- << " is invalid (must be less than CU size of "
- << format("0x%08" PRIx32, CUSize) << "):\n";
- Die.dump(OS, 0);
+ error() << FormEncodingString(Form) << " CU offset "
+ << format("0x%08" PRIx64, CUOffset)
+ << " is invalid (must be less than CU size of "
+ << format("0x%08" PRIx32, CUSize) << "):\n";
+ Die.dump(OS, 0, DumpOpts);
OS << "\n";
} else {
// Valid reference, but we will verify it points to an actual
@@ -253,11 +475,11 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
assert(RefVal);
if (RefVal) {
- if (*RefVal >= DCtx.getInfoSection().Data.size()) {
+ if (*RefVal >= DObj.getInfoSection().Data.size()) {
++NumErrors;
- OS << "error: DW_FORM_ref_addr offset beyond .debug_info "
- "bounds:\n";
- Die.dump(OS, 0);
+ error() << "DW_FORM_ref_addr offset beyond .debug_info "
+ "bounds:\n";
+ Die.dump(OS, 0, DumpOpts);
OS << "\n";
} else {
// Valid reference, but we will verify it points to an actual
@@ -270,10 +492,10 @@ unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
case DW_FORM_strp: {
auto SecOffset = AttrValue.Value.getAsSectionOffset();
assert(SecOffset); // DW_FORM_strp is a section offset.
- if (SecOffset && *SecOffset >= DCtx.getStringSection().size()) {
+ if (SecOffset && *SecOffset >= DObj.getStringSection().size()) {
++NumErrors;
- OS << "error: DW_FORM_strp offset beyond .debug_str bounds:\n";
- Die.dump(OS, 0);
+ error() << "DW_FORM_strp offset beyond .debug_str bounds:\n";
+ Die.dump(OS, 0, DumpOpts);
OS << "\n";
}
break;
@@ -294,11 +516,11 @@ unsigned DWARFVerifier::verifyDebugInfoReferences() {
if (Die)
continue;
++NumErrors;
- OS << "error: invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
- << ". Offset is in between DIEs:\n";
+ error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
+ << ". Offset is in between DIEs:\n";
for (auto Offset : Pair.second) {
auto ReferencingDie = DCtx.getDIEForOffset(Offset);
- ReferencingDie.dump(OS, 0);
+ ReferencingDie.dump(OS, 0, DumpOpts);
OS << "\n";
}
OS << "\n";
@@ -318,12 +540,12 @@ void DWARFVerifier::verifyDebugLineStmtOffsets() {
continue;
const uint32_t LineTableOffset = *StmtSectionOffset;
auto LineTable = DCtx.getLineTableForUnit(CU.get());
- if (LineTableOffset < DCtx.getLineSection().Data.size()) {
+ if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
if (!LineTable) {
++NumDebugLineErrors;
- OS << "error: .debug_line[" << format("0x%08" PRIx32, LineTableOffset)
- << "] was not able to be parsed for CU:\n";
- Die.dump(OS, 0);
+ error() << ".debug_line[" << format("0x%08" PRIx32, LineTableOffset)
+ << "] was not able to be parsed for CU:\n";
+ Die.dump(OS, 0, DumpOpts);
OS << '\n';
continue;
}
@@ -337,12 +559,12 @@ void DWARFVerifier::verifyDebugLineStmtOffsets() {
auto Iter = StmtListToDie.find(LineTableOffset);
if (Iter != StmtListToDie.end()) {
++NumDebugLineErrors;
- OS << "error: two compile unit DIEs, "
- << format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
- << format("0x%08" PRIx32, Die.getOffset())
- << ", have the same DW_AT_stmt_list section offset:\n";
- Iter->second.dump(OS, 0);
- Die.dump(OS, 0);
+ error() << "two compile unit DIEs, "
+ << format("0x%08" PRIx32, Iter->second.getOffset()) << " and "
+ << format("0x%08" PRIx32, Die.getOffset())
+ << ", have the same DW_AT_stmt_list section offset:\n";
+ Iter->second.dump(OS, 0, DumpOpts);
+ Die.dump(OS, 0, DumpOpts);
OS << '\n';
// Already verified this line table before, no need to do it again.
continue;
@@ -359,17 +581,57 @@ void DWARFVerifier::verifyDebugLineRows() {
// .debug_info verifier or in verifyDebugLineStmtOffsets().
if (!LineTable)
continue;
+
+ // Verify prologue.
uint32_t MaxFileIndex = LineTable->Prologue.FileNames.size();
+ uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
+ uint32_t FileIndex = 1;
+ StringMap<uint16_t> FullPathMap;
+ for (const auto &FileName : LineTable->Prologue.FileNames) {
+ // Verify directory index.
+ if (FileName.DirIdx > MaxDirIndex) {
+ ++NumDebugLineErrors;
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "].prologue.file_names[" << FileIndex
+ << "].dir_idx contains an invalid index: " << FileName.DirIdx
+ << "\n";
+ }
+
+ // Check file paths for duplicates.
+ std::string FullPath;
+ const bool HasFullPath = LineTable->getFileNameByIndex(
+ FileIndex, CU->getCompilationDir(),
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
+ assert(HasFullPath && "Invalid index?");
+ (void)HasFullPath;
+ auto It = FullPathMap.find(FullPath);
+ if (It == FullPathMap.end())
+ FullPathMap[FullPath] = FileIndex;
+ else if (It->second != FileIndex) {
+ warn() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "].prologue.file_names[" << FileIndex
+ << "] is a duplicate of file_names[" << It->second << "]\n";
+ }
+
+ FileIndex++;
+ }
+
+ // Verify rows.
uint64_t PrevAddress = 0;
uint32_t RowIndex = 0;
for (const auto &Row : LineTable->Rows) {
+ // Verify row address.
if (Row.Address < PrevAddress) {
++NumDebugLineErrors;
- OS << "error: .debug_line["
- << format("0x%08" PRIx64,
- *toSectionOffset(Die.find(DW_AT_stmt_list)))
- << "] row[" << RowIndex
- << "] decreases in address from previous row:\n";
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "] row[" << RowIndex
+ << "] decreases in address from previous row:\n";
DWARFDebugLine::Row::dumpTableHeader(OS);
if (RowIndex > 0)
@@ -378,13 +640,14 @@ void DWARFVerifier::verifyDebugLineRows() {
OS << '\n';
}
+ // Verify file index.
if (Row.File > MaxFileIndex) {
++NumDebugLineErrors;
- OS << "error: .debug_line["
- << format("0x%08" PRIx64,
- *toSectionOffset(Die.find(DW_AT_stmt_list)))
- << "][" << RowIndex << "] has invalid file index " << Row.File
- << " (valid values are [1," << MaxFileIndex << "]):\n";
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "][" << RowIndex << "] has invalid file index " << Row.File
+ << " (valid values are [1," << MaxFileIndex << "]):\n";
DWARFDebugLine::Row::dumpTableHeader(OS);
Row.dump(OS);
OS << '\n';
@@ -406,94 +669,137 @@ bool DWARFVerifier::handleDebugLine() {
return NumDebugLineErrors == 0;
}
-bool DWARFVerifier::handleAppleNames() {
- NumAppleNamesErrors = 0;
+unsigned DWARFVerifier::verifyAccelTable(const DWARFSection *AccelSection,
+ DataExtractor *StrData,
+ const char *SectionName) {
+ unsigned NumErrors = 0;
+ DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
+ DCtx.isLittleEndian(), 0);
+ DWARFAcceleratorTable AccelTable(AccelSectionData, *StrData);
- DWARFDataExtractor AppleNamesSection(DCtx.getAppleNamesSection(),
- DCtx.isLittleEndian(), 0);
- DataExtractor StrData(DCtx.getStringSection(), DCtx.isLittleEndian(), 0);
- DWARFAcceleratorTable AppleNames(AppleNamesSection, StrData);
+ OS << "Verifying " << SectionName << "...\n";
- if (!AppleNames.extract()) {
- return true;
+ // Verify that the fixed part of the header is not too short.
+ if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
+ error() << "Section is too small to fit a section header.\n";
+ return 1;
}
- OS << "Verifying .apple_names...\n";
+ // Verify that the section is not too short.
+ if (Error E = AccelTable.extract()) {
+ error() << toString(std::move(E)) << '\n';
+ return 1;
+ }
// Verify that all buckets have a valid hash index or are empty.
- uint32_t NumBuckets = AppleNames.getNumBuckets();
- uint32_t NumHashes = AppleNames.getNumHashes();
+ uint32_t NumBuckets = AccelTable.getNumBuckets();
+ uint32_t NumHashes = AccelTable.getNumHashes();
uint32_t BucketsOffset =
- AppleNames.getSizeHdr() + AppleNames.getHeaderDataLength();
+ AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
uint32_t HashesBase = BucketsOffset + NumBuckets * 4;
uint32_t OffsetsBase = HashesBase + NumHashes * 4;
-
for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
- uint32_t HashIdx = AppleNamesSection.getU32(&BucketsOffset);
+ uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
- OS << format("error: Bucket[%d] has invalid hash index: %u\n", BucketIdx,
- HashIdx);
- ++NumAppleNamesErrors;
+ error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
+ HashIdx);
+ ++NumErrors;
}
}
-
- uint32_t NumAtoms = AppleNames.getAtomsDesc().size();
+ uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
if (NumAtoms == 0) {
- OS << "error: no atoms; failed to read HashData\n";
- ++NumAppleNamesErrors;
- return false;
+ error() << "No atoms: failed to read HashData.\n";
+ return 1;
}
-
- if (!AppleNames.validateForms()) {
- OS << "error: unsupported form; failed to read HashData\n";
- ++NumAppleNamesErrors;
- return false;
+ if (!AccelTable.validateForms()) {
+ error() << "Unsupported form: failed to read HashData.\n";
+ return 1;
}
for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
uint32_t HashOffset = HashesBase + 4 * HashIdx;
uint32_t DataOffset = OffsetsBase + 4 * HashIdx;
- uint32_t Hash = AppleNamesSection.getU32(&HashOffset);
- uint32_t HashDataOffset = AppleNamesSection.getU32(&DataOffset);
- if (!AppleNamesSection.isValidOffsetForDataOfSize(HashDataOffset,
- sizeof(uint64_t))) {
- OS << format("error: Hash[%d] has invalid HashData offset: 0x%08x\n",
- HashIdx, HashDataOffset);
- ++NumAppleNamesErrors;
+ uint32_t Hash = AccelSectionData.getU32(&HashOffset);
+ uint32_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
+ if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
+ sizeof(uint64_t))) {
+ error() << format("Hash[%d] has invalid HashData offset: 0x%08x.\n",
+ HashIdx, HashDataOffset);
+ ++NumErrors;
}
uint32_t StrpOffset;
uint32_t StringOffset;
uint32_t StringCount = 0;
- uint32_t DieOffset = dwarf::DW_INVALID_OFFSET;
-
- while ((StrpOffset = AppleNamesSection.getU32(&HashDataOffset)) != 0) {
+ unsigned Offset;
+ unsigned Tag;
+ while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
const uint32_t NumHashDataObjects =
- AppleNamesSection.getU32(&HashDataOffset);
+ AccelSectionData.getU32(&HashDataOffset);
for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
++HashDataIdx) {
- DieOffset = AppleNames.readAtoms(HashDataOffset);
- if (!DCtx.getDIEForOffset(DieOffset)) {
+ std::tie(Offset, Tag) = AccelTable.readAtoms(HashDataOffset);
+ auto Die = DCtx.getDIEForOffset(Offset);
+ if (!Die) {
const uint32_t BucketIdx =
NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
StringOffset = StrpOffset;
- const char *Name = StrData.getCStr(&StringOffset);
+ const char *Name = StrData->getCStr(&StringOffset);
if (!Name)
Name = "<NULL>";
- OS << format(
- "error: .apple_names Bucket[%d] Hash[%d] = 0x%08x "
+ error() << format(
+ "%s Bucket[%d] Hash[%d] = 0x%08x "
"Str[%u] = 0x%08x "
"DIE[%d] = 0x%08x is not a valid DIE offset for \"%s\".\n",
- BucketIdx, HashIdx, Hash, StringCount, StrpOffset, HashDataIdx,
- DieOffset, Name);
+ SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
+ HashDataIdx, Offset, Name);
- ++NumAppleNamesErrors;
+ ++NumErrors;
+ continue;
+ }
+ if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
+ error() << "Tag " << dwarf::TagString(Tag)
+ << " in accelerator table does not match Tag "
+ << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx
+ << "].\n";
+ ++NumErrors;
}
}
++StringCount;
}
}
- return NumAppleNamesErrors == 0;
+ 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");
+ if (!D.getAppleTypesSection().Data.empty())
+ NumErrors +=
+ verifyAccelTable(&D.getAppleTypesSection(), &StrData, ".apple_types");
+ if (!D.getAppleNamespacesSection().Data.empty())
+ NumErrors += verifyAccelTable(&D.getAppleNamespacesSection(), &StrData,
+ ".apple_namespaces");
+ if (!D.getAppleObjCSection().Data.empty())
+ NumErrors +=
+ verifyAccelTable(&D.getAppleObjCSection(), &StrData, ".apple_objc");
+ return NumErrors == 0;
+}
+
+raw_ostream &DWARFVerifier::error() const {
+ return WithColor(OS, syntax::Error).get() << "error: ";
+}
+
+raw_ostream &DWARFVerifier::warn() const {
+ return WithColor(OS, syntax::Warning).get() << "warning: ";
+}
+
+raw_ostream &DWARFVerifier::note() const {
+ return WithColor(OS, syntax::Note).get() << "note: ";
}
diff --git a/lib/DebugInfo/DWARF/LLVMBuild.txt b/lib/DebugInfo/DWARF/LLVMBuild.txt
index 8242a7f2e7f7..a21276244ea7 100644
--- a/lib/DebugInfo/DWARF/LLVMBuild.txt
+++ b/lib/DebugInfo/DWARF/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Library
name = DebugInfoDWARF
parent = DebugInfo
-required_libraries = BinaryFormat Object Support
+required_libraries = BinaryFormat Object MC Support
diff --git a/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp b/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp
index d4f44e446954..65d66fc8f514 100644
--- a/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp
+++ b/lib/DebugInfo/DWARF/SyntaxHighlighting.cpp
@@ -24,12 +24,15 @@ 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 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;
}
}
}
diff --git a/lib/DebugInfo/DWARF/SyntaxHighlighting.h b/lib/DebugInfo/DWARF/SyntaxHighlighting.h
index 277de973dbf0..686cf2c77608 100644
--- a/lib/DebugInfo/DWARF/SyntaxHighlighting.h
+++ b/lib/DebugInfo/DWARF/SyntaxHighlighting.h
@@ -18,7 +18,17 @@ namespace dwarf {
namespace syntax {
// Symbolic names for various syntax elements.
-enum HighlightColor { Address, String, Tag, Attribute, Enumerator, Macro };
+enum HighlightColor {
+ Address,
+ String,
+ Tag,
+ Attribute,
+ Enumerator,
+ Macro,
+ Error,
+ Warning,
+ Note
+};
/// An RAII object that temporarily switches an output stream to a
/// specific color.
@@ -30,8 +40,8 @@ public:
WithColor(raw_ostream &OS, enum HighlightColor Type);
~WithColor();
- raw_ostream& get() { return OS; }
- operator raw_ostream& () { return OS; }
+ raw_ostream &get() { return OS; }
+ operator raw_ostream &() { return OS; }
};
} // end namespace syntax