/// 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.
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; }
return LHS.getOffset() < RHS.getOffset();
}
-class DWARFDie::iterator : public iterator_facade_base<iterator,
- std::forward_iterator_tag,
- const DWARFDie> {
+class DWARFDie::iterator
+ : public iterator_facade_base<iterator, std::bidirectional_iterator_tag,
+ const DWARFDie> {
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;
}
}
inline DWARFDie::iterator DWARFDie::end() const {
- return iterator();
+ return iterator(getLastChild());
}
inline iterator_range<DWARFDie::iterator> DWARFDie::children() const {
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.
return DWARFDie();
}
+DWARFDie DWARFDie::getPreviousSibling() const {
+ if (isValid())
+ return U->getPreviousSibling(Die);
+ return DWARFDie();
+}
+
DWARFDie DWARFDie::getFirstChild() const {
if (isValid())
return U->getFirstChild(Die);
return DWARFDie();
}
+DWARFDie DWARFDie::getLastChild() const {
+ if (isValid())
+ return U->getLastChild(Die);
+ return DWARFDie();
+}
+
iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const {
return make_range(attribute_iterator(*this, false),
attribute_iterator(*this, true));
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();
return DWARFDie(this, &DieArray[I]);
}
+DWARFDie DWARFUnit::getLastChild(const DWARFDebugInfoEntry *Die) {
+ if (!Die->hasChildren())
+ return DWARFDie();
+
+ uint32_t Depth = Die->getDepth();
+ for (size_t I = getDIEIndex(Die) + 1, EndIdx = DieArray.size(); I < EndIdx;
+ ++I) {
+ if (DieArray[I].getDepth() == Depth + 1 &&
+ DieArray[I].getTag() == dwarf::DW_TAG_null)
+ return DWARFDie(this, &DieArray[I]);
+ assert(DieArray[I].getDepth() > Depth && "Not processing children?");
+ }
+ return DWARFDie();
+}
+
const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
if (!Abbrevs)
Abbrevs = Abbrev->getAbbreviationDeclarationSet(Header.getAbbrOffset());
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) {
// 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) {