Index: llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -104,12 +104,24 @@ /// invalid DWARFDie instance if it doesn't. DWARFDie getSibling() const; + /// Get the previous 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 getPreviousSibling() 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; + /// Get the last child of this DIE object. + /// + /// \returns a valid null DWARFDie instance if this object has children or an + /// invalid DWARFDie instance if it doesn't. + DWARFDie getLastChild() const; + /// Dump the DIE and all of its attributes to the supplied stream. /// /// \param OS the stream to use for output. @@ -288,6 +300,7 @@ explicit attribute_iterator(DWARFDie D, bool End); attribute_iterator &operator++(); + attribute_iterator &operator--(); explicit operator bool() const { return AttrValue.isValid(); } const DWARFAttribute &operator*() const { return AttrValue; } bool operator==(const attribute_iterator &X) const { return Index == X.Index; } @@ -306,26 +319,23 @@ return LHS.getOffset() < RHS.getOffset(); } -class DWARFDie::iterator : public iterator_facade_base { +class DWARFDie::iterator + : public iterator_facade_base { DWARFDie Die; - void skipNull() { - if (Die && Die.isNULL()) - Die = DWARFDie(); - } public: iterator() = default; explicit iterator(DWARFDie D) : Die(D) { - // If we start out with only a Null DIE then invalidate. - skipNull(); } iterator &operator++() { Die = Die.getSibling(); - // Don't include the NULL die when iterating. - skipNull(); + return *this; + } + + iterator &operator--() { + Die = Die.getPreviousSibling(); return *this; } @@ -341,7 +351,7 @@ } inline DWARFDie::iterator DWARFDie::end() const { - return iterator(); + return iterator(getLastChild()); } inline iterator_range DWARFDie::children() const { Index: llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -508,7 +508,9 @@ DWARFDie getParent(const DWARFDebugInfoEntry *Die); DWARFDie getSibling(const DWARFDebugInfoEntry *Die); + DWARFDie getPreviousSibling(const DWARFDebugInfoEntry *Die); DWARFDie getFirstChild(const DWARFDebugInfoEntry *Die); + DWARFDie getLastChild(const DWARFDebugInfoEntry *Die); /// Return the DIE object for a given offset inside the /// unit's DIE vector. Index: llvm/lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -555,12 +555,24 @@ return DWARFDie(); } +DWARFDie DWARFDie::getPreviousSibling() const { + if (isValid()) + return U->getPreviousSibling(Die); + return DWARFDie(); +} + DWARFDie DWARFDie::getFirstChild() const { if (isValid()) return U->getFirstChild(Die); return DWARFDie(); } +DWARFDie DWARFDie::getLastChild() const { + if (isValid()) + return U->getLastChild(Die); + return DWARFDie(); +} + iterator_range DWARFDie::attributes() const { return make_range(attribute_iterator(*this, false), attribute_iterator(*this, true)); Index: llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -584,6 +584,24 @@ return DWARFDie(); } +DWARFDie DWARFUnit::getPreviousSibling(const DWARFDebugInfoEntry *Die) { + if (!Die) + return DWARFDie(); + uint32_t Depth = Die->getDepth(); + // Unit DIEs always have a depth of zero and never have siblings. + if (Depth == 0) + return DWARFDie(); + + // Find the previous DIE whose depth is the same as the Die's depth. + for (size_t I = getDIEIndex(Die) - 1; I >= 0; --I) { + if (DieArray[I].getDepth() == Depth - 1) + return DWARFDie(); + if (DieArray[I].getDepth() == Depth) + return DWARFDie(this, &DieArray[I]); + } + return DWARFDie(); +} + DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) { if (!Die->hasChildren()) return DWARFDie(); @@ -595,6 +613,20 @@ return DWARFDie(this, &DieArray[I]); } +DWARFDie DWARFUnit::getLastChild(const DWARFDebugInfoEntry *Die) { + if (!Die->hasChildren()) + return DWARFDie(); + + uint32_t Depth = Die->getDepth(); + for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx; + ++I) { + if (DieArray[I].getDepth() == Depth + 1 && + DieArray[I].getTag() == dwarf::DW_TAG_null) + return DWARFDie(this, &DieArray[I]); + } + return DWARFDie(); +} + const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const { if (!Abbrevs) Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset()); Index: llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -490,6 +490,11 @@ EXPECT_TRUE(!NullDieDG.getSibling().isValid()); EXPECT_TRUE(!NullDieDG.getFirstChild().isValid()); } + + // Verify the previous sibling of our subprogram is our integer base type. + IntDieDG = NullDieDG.getPreviousSibling(); + EXPECT_TRUE(IntDieDG.isValid()); + EXPECT_EQ(IntDieDG.getTag(), DW_TAG_base_type); } TEST(DWARFDebugInfo, TestDWARF32Version2Addr4Children) { @@ -1072,6 +1077,27 @@ // Make sure the parent of all the children of the B are the B. EXPECT_EQ(C1.getParent(), C); EXPECT_EQ(C2.getParent(), C); + + // Make sure bidirectional iterator works as expected. + auto Begin = A.begin(); + auto End = A.end(); + auto It = A.begin(); + + EXPECT_EQ(It, Begin); + EXPECT_EQ(*It, B); + ++It; + EXPECT_EQ(*It, C); + ++It; + EXPECT_EQ(*It, D); + ++It; + EXPECT_EQ(It, End); + --It; + EXPECT_EQ(*It, D); + --It; + EXPECT_EQ(*It, C); + --It; + EXPECT_EQ(*It, B); + EXPECT_EQ(It, Begin); } TEST(DWARFDebugInfo, TestDWARFDie) {