summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h38
-rw-r--r--llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h22
-rw-r--r--llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h23
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp10
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDie.cpp11
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp71
-rw-r--r--llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp116
7 files changed, 209 insertions, 82 deletions
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
index 57fb1f1da90..f36f470980b 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h
@@ -31,13 +31,14 @@ class DWARFDebugInfoEntry {
/// Offset within the .debug_info of the start of this entry.
uint32_t Offset;
- /// How many to add to "this" to get the sibling.
- uint32_t SiblingIdx;
+ /// The integer depth of this DIE within the compile unit DIEs where the
+ /// compile/type unit DIE has a depth of zero.
+ uint32_t Depth;
const DWARFAbbreviationDeclaration *AbbrevDecl;
public:
DWARFDebugInfoEntry()
- : Offset(0), SiblingIdx(0), AbbrevDecl(nullptr) {}
+ : Offset(0), Depth(0), AbbrevDecl(nullptr) {}
/// Extracts a debug info entry, which is a child of a given unit,
/// starting at a given offset. If DIE can't be extracted, returns false and
@@ -45,33 +46,16 @@ public:
bool extractFast(const DWARFUnit &U, uint32_t *OffsetPtr);
/// High performance extraction should use this call.
bool extractFast(const DWARFUnit &U, uint32_t *OffsetPtr,
- const DataExtractor &DebugInfoData, uint32_t UEndOffset);
+ const DataExtractor &DebugInfoData,
+ uint32_t UEndOffset,
+ uint32_t Depth);
uint32_t getOffset() const { return Offset; }
- bool hasChildren() const { return AbbrevDecl && AbbrevDecl->hasChildren(); }
-
- // We know we are kept in a vector of contiguous entries, so we know
- // our sibling will be some index after "this".
- const DWARFDebugInfoEntry *getSibling() const {
- return SiblingIdx > 0 ? this + SiblingIdx : nullptr;
- }
-
- // We know we are kept in a vector of contiguous entries, so we know
- // we don't need to store our child pointer, if we have a child it will
- // be the next entry in the list...
- const DWARFDebugInfoEntry *getFirstChild() const {
- return hasChildren() ? this + 1 : nullptr;
+ uint32_t getDepth() const { return Depth; }
+ dwarf::Tag getTag() const {
+ return AbbrevDecl ? AbbrevDecl->getTag() : dwarf::DW_TAG_null;
}
-
- void setSibling(const DWARFDebugInfoEntry *Sibling) {
- if (Sibling) {
- // We know we are kept in a vector of contiguous entries, so we know
- // our sibling will be some index after "this".
- SiblingIdx = Sibling - this;
- } else
- SiblingIdx = 0;
- }
-
+ bool hasChildren() const { return AbbrevDecl && AbbrevDecl->hasChildren(); }
const DWARFAbbreviationDeclaration *getAbbreviationDeclarationPtr() const {
return AbbrevDecl;
}
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
index 857cabab0df..f33758de6a5 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
@@ -40,6 +40,9 @@ public:
bool isValid() const { return U && Die; }
explicit operator bool() const { return isValid(); }
+ bool operator ==(const DWARFDie &RHS) const {
+ return Die == RHS.Die && U == RHS.U;
+ }
const DWARFDebugInfoEntry *getDebugInfoEntry() const { return Die; }
DWARFUnit *getDwarfUnit() const { return U; }
@@ -82,23 +85,26 @@ public:
/// Returns true if DIE represents a subprogram or an inlined subroutine.
bool isSubroutineDIE() const;
-
- /// Get the silbing of this DIE object.
+ /// Get the parent of this DIE object.
+ ///
+ /// \returns a valid DWARFDie instance if this object has a parent or an
+ /// invalid DWARFDie instance if it doesn't.
+ DWARFDie getParent() const;
+
+ /// Get the sibling of this DIE object.
///
/// \returns a valid DWARFDie instance if this object has a sibling or an
/// invalid DWARFDie instance if it doesn't.
- DWARFDie getSibling() const {
- assert(isValid() && "must check validity prior to calling");
- return DWARFDie(U, Die->getSibling());
- }
+ DWARFDie getSibling() const;
/// Get the first child of this DIE object.
///
/// \returns a valid DWARFDie instance if this object has children or an
/// invalid DWARFDie instance if it doesn't.
DWARFDie getFirstChild() const {
- assert(isValid() && "must check validity prior to calling");
- return DWARFDie(U, Die->getFirstChild());
+ if (isValid() && Die->hasChildren())
+ return DWARFDie(U, Die + 1);
+ return DWARFDie();
}
/// Dump the DIE and all of its attributes to the supplied stream.
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index 0f4a6f0438d..78bbe098b2d 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -140,6 +140,12 @@ class DWARFUnit {
const DWARFUnitIndex::Entry *IndexEntry;
+ uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) {
+ auto First = DieArray.data();
+ assert(Die >= First && Die < First + DieArray.size());
+ return Die - First;
+ }
+
protected:
virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr);
/// Size in bytes of the unit header.
@@ -251,19 +257,18 @@ public:
/// method on a DIE that isn't accessible by following
/// children/sibling links starting from this unit's getUnitDIE().
uint32_t getDIEIndex(const DWARFDie &D) {
- auto DIE = D.getDebugInfoEntry();
- assert(!DieArray.empty() && DIE >= &DieArray[0] &&
- DIE < &DieArray[0] + DieArray.size());
- return DIE - &DieArray[0];
+ return getDIEIndex(D.getDebugInfoEntry());
}
/// \brief Return the DIE object at the given index.
DWARFDie getDIEAtIndex(unsigned Index) {
- if (Index < DieArray.size())
- return DWARFDie(this, &DieArray[Index]);
- return DWARFDie();
+ assert(Index < DieArray.size());
+ return DWARFDie(this, &DieArray[Index]);
}
+ DWARFDie getParent(const DWARFDebugInfoEntry *Die);
+ DWARFDie getSibling(const DWARFDebugInfoEntry *Die);
+
/// \brief Return the DIE object for a given offset inside the
/// unit's DIE vector.
///
@@ -298,10 +303,6 @@ private:
/// extractDIEsToVector - Appends all parsed DIEs to a vector.
void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs,
std::vector<DWARFDebugInfoEntry> &DIEs) const;
- /// setDIERelations - We read in all of the DIE entries into our flat list
- /// of DIE entries and now we need to go back through all of them and set the
- /// parent, sibling and child pointers for quick DIE navigation.
- void setDIERelations();
/// clearDIEs - Clear parsed DIEs to keep memory usage low.
void clearDIEs(bool KeepCUDie);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
index 8ea65ebfdd5..9f623e4954c 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
@@ -26,13 +26,13 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U,
uint32_t *OffsetPtr) {
DataExtractor DebugInfoData = U.getDebugInfoExtractor();
const uint32_t UEndOffset = U.getNextUnitOffset();
- return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset);
+ return extractFast(U, OffsetPtr, DebugInfoData, UEndOffset, 0);
}
-bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U,
- uint32_t *OffsetPtr,
- const DataExtractor &DebugInfoData,
- uint32_t UEndOffset) {
+bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr,
+ const DataExtractor &DebugInfoData,
+ uint32_t UEndOffset, uint32_t D) {
Offset = *OffsetPtr;
+ Depth = D;
if (Offset >= UEndOffset || !DebugInfoData.isValidOffset(Offset))
return false;
uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 94777109e44..deec1633022 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -428,3 +428,14 @@ void DWARFDie::getInlinedChainForAddress(
std::reverse(InlinedChain.begin(), InlinedChain.end());
}
+DWARFDie DWARFDie::getParent() const {
+ if (isValid())
+ return U->getParent(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getSibling() const {
+ if (isValid())
+ return U->getSibling(Die);
+ return DWARFDie();
+}
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 2ddbc507ff6..63fb0d3bc36 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -158,35 +158,6 @@ Optional<uint64_t> DWARFUnit::getDWOId() {
return getUnitDIE().getAttributeValueAsUnsignedConstant(DW_AT_GNU_dwo_id);
}
-void DWARFUnit::setDIERelations() {
- if (DieArray.size() <= 1)
- return;
-
- std::vector<DWARFDebugInfoEntry *> ParentChain;
- DWARFDebugInfoEntry *SiblingChain = nullptr;
- for (auto &DIE : DieArray) {
- if (SiblingChain) {
- SiblingChain->setSibling(&DIE);
- }
- if (const DWARFAbbreviationDeclaration *AbbrDecl =
- DIE.getAbbreviationDeclarationPtr()) {
- // Normal DIE.
- if (AbbrDecl->hasChildren()) {
- ParentChain.push_back(&DIE);
- SiblingChain = nullptr;
- } else {
- SiblingChain = &DIE;
- }
- } else {
- // NULL entry terminates the sibling chain.
- SiblingChain = ParentChain.back();
- ParentChain.pop_back();
- }
- }
- assert(SiblingChain == nullptr || SiblingChain == &DieArray[0]);
- assert(ParentChain.empty());
-}
-
void DWARFUnit::extractDIEsToVector(
bool AppendCUDie, bool AppendNonCUDies,
std::vector<DWARFDebugInfoEntry> &Dies) const {
@@ -202,7 +173,8 @@ void DWARFUnit::extractDIEsToVector(
uint32_t Depth = 0;
bool IsCUDie = true;
- while (DIE.extractFast(*this, &DIEOffset, DebugInfoData, NextCUOffset)) {
+ while (DIE.extractFast(*this, &DIEOffset, DebugInfoData, NextCUOffset,
+ Depth)) {
if (IsCUDie) {
if (AppendCUDie)
Dies.push_back(DIE);
@@ -266,7 +238,6 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
// skeleton CU DIE, so that DWARF users not aware of it are not broken.
}
- setDIERelations();
return DieArray.size();
}
@@ -409,4 +380,42 @@ const DWARFUnitIndex &getDWARFUnitIndex(DWARFContext &Context,
return Context.getTUIndex();
}
+DWARFDie DWARFUnit::getParent(const DWARFDebugInfoEntry *Die) {
+ if (!Die)
+ return DWARFDie();
+ const uint32_t Depth = Die->getDepth();
+ // Unit DIEs always have a depth of zero and never have parents.
+ if (Depth == 0)
+ return DWARFDie();
+ // Depth of 1 always means parent is the compile/type unit.
+ if (Depth == 1)
+ return getUnitDIE();
+ // Look for previous DIE with a depth that is one less than the Die's depth.
+ const uint32_t ParentDepth = Depth - 1;
+ for (uint32_t I = getDIEIndex(Die) - 1; I > 0; --I) {
+ if (DieArray[I].getDepth() == ParentDepth)
+ return DWARFDie(this, &DieArray[I]);
+ }
+ return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) {
+ if (!Die)
+ return DWARFDie();
+ uint32_t Depth = Die->getDepth();
+ // Unit DIEs always have a depth of zero and never have siblings.
+ if (Depth == 0)
+ return DWARFDie();
+ // NULL DIEs don't have siblings.
+ if (Die->getAbbreviationDeclarationPtr() == nullptr)
+ return DWARFDie();
+
+ // Find the next DIE whose depth is the same as the Die's depth.
+ for (size_t I=getDIEIndex(Die)+1, EndIdx = DieArray.size(); I<EndIdx; ++I) {
+ if (DieArray[I].getDepth() == Depth)
+ return DWARFDie(this, &DieArray[I]);
+ }
+ return DWARFDie();
+}
+
} // end namespace llvm
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
index 6b9f435b2e7..e2f4bb788dd 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
@@ -967,5 +967,121 @@ TEST(DWARFDebugInfo, TestDWARF32Version4Addr8Addresses) {
TestAddresses<4, AddrType>();
}
+TEST(DWARFDebugInfo, TestRelations) {
+ // Test the DWARF APIs related to accessing the DW_AT_low_pc and
+ // DW_AT_high_pc.
+ uint16_t Version = 4;
+
+ const uint8_t AddrSize = sizeof(void *);
+ initLLVMIfNeeded();
+ Triple Triple = getHostTripleForAddrSize(AddrSize);
+ auto ExpectedDG = dwarfgen::Generator::create(Triple, Version);
+ if (HandleExpectedError(ExpectedDG))
+ return;
+ dwarfgen::Generator *DG = ExpectedDG.get().get();
+ dwarfgen::CompileUnit &CU = DG->addCompileUnit();
+
+ enum class Tag: uint16_t {
+ A = dwarf::DW_TAG_lo_user,
+ B,
+ B1,
+ B2,
+ C,
+ C1
+ };
+
+ // Scope to allow us to re-use the same DIE names
+ {
+ // Create DWARF tree that looks like:
+ //
+ // CU
+ // A
+ // B
+ // B1
+ // B2
+ // C
+ // C1
+ dwarfgen::DIE CUDie = CU.getUnitDIE();
+ CUDie.addChild((dwarf::Tag)Tag::A);
+ dwarfgen::DIE B = CUDie.addChild((dwarf::Tag)Tag::B);
+ dwarfgen::DIE C = CUDie.addChild((dwarf::Tag)Tag::C);
+ B.addChild((dwarf::Tag)Tag::B1);
+ B.addChild((dwarf::Tag)Tag::B2);
+ C.addChild((dwarf::Tag)Tag::C1);
+ }
+
+ MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
+ auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
+ EXPECT_TRUE((bool)Obj);
+ DWARFContextInMemory DwarfContext(*Obj.get());
+
+ // Verify the number of compile units is correct.
+ uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ EXPECT_EQ(NumCUs, 1u);
+ DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+
+ // Get the compile unit DIE is valid.
+ auto CUDie = U->getUnitDIE(false);
+ EXPECT_TRUE(CUDie.isValid());
+ // DieDG.dump(llvm::outs(), U, UINT32_MAX);
+
+ // The compile unit doesn't have a parent or a sibling.
+ auto ParentDie = CUDie.getParent();
+ EXPECT_FALSE(ParentDie.isValid());
+ auto SiblingDie = CUDie.getSibling();
+ EXPECT_FALSE(SiblingDie.isValid());
+
+ // Get the children of the compile unit
+ auto A = CUDie.getFirstChild();
+ auto B = A.getSibling();
+ auto C = B.getSibling();
+ auto Null = C.getSibling();
+
+ // Verify NULL Die is NULL and has no children or siblings
+ EXPECT_TRUE(Null.isNULL());
+ EXPECT_FALSE(Null.getSibling().isValid());
+ EXPECT_FALSE(Null.getFirstChild().isValid());
+
+ // Verify all children of the compile unit DIE are correct.
+ EXPECT_EQ(A.getTag(), (dwarf::Tag)Tag::A);
+ EXPECT_EQ(B.getTag(), (dwarf::Tag)Tag::B);
+ EXPECT_EQ(C.getTag(), (dwarf::Tag)Tag::C);
+
+ // Verify who has children
+ EXPECT_FALSE(A.hasChildren());
+ EXPECT_TRUE(B.hasChildren());
+
+ // Make sure the parent of all the children of the compile unit are the
+ // compile unit.
+ EXPECT_EQ(A.getParent(), CUDie);
+ EXPECT_EQ(B.getParent(), CUDie);
+ EXPECT_EQ(Null.getParent(), CUDie);
+
+ EXPECT_FALSE(A.getFirstChild().isValid());
+
+ // Verify the children of the B DIE
+ auto B1 = B.getFirstChild();
+ auto B2 = B1.getSibling();
+ EXPECT_TRUE(B2.getSibling().isNULL());
+
+ // Verify all children of the B DIE correctly valid or invalid.
+ EXPECT_EQ(B1.getTag(), (dwarf::Tag)Tag::B1);
+ EXPECT_EQ(B2.getTag(), (dwarf::Tag)Tag::B2);
+
+ // Make sure the parent of all the children of the B are the B.
+ EXPECT_EQ(B1.getParent(), B);
+ EXPECT_EQ(B2.getParent(), B);
+}
+
+TEST(DWARFDebugInfo, TestDWARFDie) {
+
+ // Make sure a default constructed DWARFDie doesn't have any parent, sibling
+ // or child;
+ DWARFDie DefaultDie;
+ EXPECT_FALSE(DefaultDie.getParent().isValid());
+ EXPECT_FALSE(DefaultDie.getFirstChild().isValid());
+ EXPECT_FALSE(DefaultDie.getSibling().isValid());
+}
+
} // end anonymous namespace
OpenPOWER on IntegriCloud