[llvm] r291194 - Add iterator support to DWARFDie to allow child DIE iteration.
Greg Clayton via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 5 15:47:37 PST 2017
Author: gclayton
Date: Thu Jan 5 17:47:37 2017
New Revision: 291194
URL: http://llvm.org/viewvc/llvm-project?rev=291194&view=rev
Log:
Add iterator support to DWARFDie to allow child DIE iteration.
Differential Revision: https://reviews.llvm.org/D28303
Modified:
llvm/trunk/include/llvm/CodeGen/DIE.h
llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h
llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
llvm/trunk/tools/dsymutil/DwarfLinker.cpp
llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.h
Modified: llvm/trunk/include/llvm/CodeGen/DIE.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/DIE.h?rev=291194&r1=291193&r2=291194&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/DIE.h (original)
+++ llvm/trunk/include/llvm/CodeGen/DIE.h Thu Jan 5 17:47:37 2017
@@ -651,6 +651,9 @@ class DIE : IntrusiveBackListNode, publi
unsigned AbbrevNumber = ~0u;
/// Dwarf tag code.
dwarf::Tag Tag = (dwarf::Tag)0;
+ /// Set to true to force a DIE to emit an abbreviation that says it has
+ /// children even when it doesn't. This is used for unit testing purposes.
+ bool ForceChildren;
/// Children DIEs.
IntrusiveBackList<DIE> Children;
@@ -659,7 +662,8 @@ class DIE : IntrusiveBackListNode, publi
PointerUnion<DIE *, DIEUnit *> Owner;
DIE() = delete;
- explicit DIE(dwarf::Tag Tag) : Offset(0), Size(0), Tag(Tag) {}
+ explicit DIE(dwarf::Tag Tag) : Offset(0), Size(0), Tag(Tag),
+ ForceChildren(false) {}
public:
static DIE *get(BumpPtrAllocator &Alloc, dwarf::Tag Tag) {
@@ -677,7 +681,8 @@ public:
/// Get the compile/type unit relative offset of this DIE.
unsigned getOffset() const { return Offset; }
unsigned getSize() const { return Size; }
- bool hasChildren() const { return !Children.empty(); }
+ bool hasChildren() const { return ForceChildren || !Children.empty(); }
+ void setForceChildren(bool B) { ForceChildren = B; }
typedef IntrusiveBackList<DIE>::iterator child_iterator;
typedef IntrusiveBackList<DIE>::const_iterator const_child_iterator;
Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h?rev=291194&r1=291193&r2=291194&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h Thu Jan 5 17:47:37 2017
@@ -10,6 +10,8 @@
#ifndef LLVM_LIB_DEBUGINFO_DWARFDIE_H
#define LLVM_LIB_DEBUGINFO_DWARFDIE_H
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/Optional.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
@@ -40,9 +42,6 @@ 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; }
@@ -361,8 +360,61 @@ public:
getInlinedChainForAddress(const uint64_t Address,
SmallVectorImpl<DWARFDie> &InlinedChain) const;
+ class iterator;
+
+ iterator begin() const;
+ iterator end() const;
+ iterator_range<iterator> children() const;
+};
+
+
+inline bool operator==(const DWARFDie &LHS, const DWARFDie &RHS) {
+ return LHS.getDebugInfoEntry() == RHS.getDebugInfoEntry() &&
+ LHS.getDwarfUnit() == RHS.getDwarfUnit();
+}
+
+inline bool operator!=(const DWARFDie &LHS, const DWARFDie &RHS) {
+ return !(LHS == RHS);
+}
+
+class DWARFDie::iterator : public iterator_facade_base<iterator,
+ std::forward_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;
+ }
+ explicit operator bool() const { return Die.isValid(); }
+ const DWARFDie &operator*() const { return Die; }
+ bool operator==(const iterator &X) const { return Die == X.Die; }
};
+// These inline functions must follow the DWARFDie::iterator definition above
+// as they use functions from that class.
+inline DWARFDie::iterator DWARFDie::begin() const {
+ return iterator(getFirstChild());
+}
+
+inline DWARFDie::iterator DWARFDie::end() const {
+ return iterator();
+}
+
+inline iterator_range<DWARFDie::iterator> DWARFDie::children() const {
+ return make_range(begin(), end());
+}
} // end namespace llvm
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp?rev=291194&r1=291193&r2=291194&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp Thu Jan 5 17:47:37 2017
@@ -299,11 +299,8 @@ DWARFDie::collectChildrenAddressRanges(D
Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end());
}
- DWARFDie Child = getFirstChild();
- while (Child) {
+ for (auto Child: children())
Child.collectChildrenAddressRanges(Ranges);
- Child = Child.getSibling();
- }
}
bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
Modified: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=291194&r1=291193&r2=291194&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Thu Jan 5 17:47:37 2017
@@ -1796,8 +1796,7 @@ static bool analyzeContextInfo(const DWA
Info.Prune = InImportedModule;
if (DIE.hasChildren())
- for (auto Child = DIE.getFirstChild(); Child && !Child.isNULL();
- Child = Child.getSibling())
+ for (auto Child: DIE.children())
Info.Prune &= analyzeContextInfo(Child, MyIdx, CU, CurrentDeclContext,
StringPool, Contexts, InImportedModule);
@@ -2294,8 +2293,7 @@ void DwarfLinker::lookForDIEsToKeep(Relo
if (!Die.hasChildren() || (Flags & TF_ParentWalk))
return;
- for (auto Child = Die.getFirstChild(); Child && !Child.isNULL();
- Child = Child.getSibling())
+ for (auto Child: Die.children())
lookForDIEsToKeep(RelocMgr, Child, DMO, CU, Flags);
}
@@ -2814,8 +2812,7 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
// Determine whether there are any children that we want to keep.
bool HasChildren = false;
- for (auto Child = InputDIE.getFirstChild(); Child && !Child.isNULL();
- Child = Child.getSibling()) {
+ for (auto Child: InputDIE.children()) {
unsigned Idx = U.getDIEIndex(Child);
if (Unit.getInfo(Idx).Keep) {
HasChildren = true;
@@ -2840,8 +2837,7 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
}
// Recursively clone children.
- for (auto Child = InputDIE.getFirstChild(); Child && !Child.isNULL();
- Child = Child.getSibling()) {
+ for (auto Child: InputDIE.children()) {
if (DIE *Clone = cloneDIE(Child, Unit, PCOffset, OutOffset, Flags)) {
Die->addChild(Clone);
OutOffset = Clone->getOffset() + Clone->getSize();
Modified: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp?rev=291194&r1=291193&r2=291194&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp (original)
+++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp Thu Jan 5 17:47:37 2017
@@ -1100,5 +1100,126 @@ TEST(DWARFDebugInfo, TestDWARFDie) {
EXPECT_FALSE(DefaultDie.getSibling().isValid());
}
+TEST(DWARFDebugInfo, TestChildIterators) {
+ // Test the DWARF APIs related to iterating across the children of a DIE using
+ // the DWARFDie::iterator class.
+ 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,
+ };
+
+ // Scope to allow us to re-use the same DIE names
+ {
+ // Create DWARF tree that looks like:
+ //
+ // CU
+ // A
+ // B
+ auto CUDie = CU.getUnitDIE();
+ CUDie.addChild((dwarf::Tag)Tag::A);
+ CUDie.addChild((dwarf::Tag)Tag::B);
+ }
+
+ 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());
+ // CUDie.dump(llvm::outs(), UINT32_MAX);
+ uint32_t Index;
+ DWARFDie A;
+ DWARFDie B;
+
+ // Verify the compile unit DIE's children.
+ Index = 0;
+ for (auto Die : CUDie.children()) {
+ switch (Index++) {
+ case 0: A = Die; break;
+ case 1: B = Die; break;
+ }
+ }
+
+ EXPECT_EQ(A.getTag(), (dwarf::Tag)Tag::A);
+ EXPECT_EQ(B.getTag(), (dwarf::Tag)Tag::B);
+
+ // Verify that A has no children by verifying that the begin and end contain
+ // invalid DIEs and also that the iterators are equal.
+ EXPECT_EQ(A.begin(), A.end());
+}
+
+TEST(DWARFDebugInfo, TestChildIteratorsOnInvalidDie) {
+ // Verify that an invalid DIE has no children.
+ DWARFDie Invalid;
+ auto begin = Invalid.begin();
+ auto end = Invalid.end();
+ EXPECT_FALSE(begin->isValid());
+ EXPECT_FALSE(end->isValid());
+ EXPECT_EQ(begin, end);
+}
+
+
+TEST(DWARFDebugInfo, TestEmptyChildren) {
+ // Test a DIE that says it has children in the abbreviation, but actually
+ // doesn't have any attributes, will not return anything during iteration.
+ // We do this by making sure the begin and end iterators are equal.
+ 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();
+
+ // Scope to allow us to re-use the same DIE names
+ {
+ // Create a compile unit DIE that has an abbreviation that says it has
+ // children, but doesn't have any actual attributes. This helps us test
+ // a DIE that has only one child: a NULL DIE.
+ auto CUDie = CU.getUnitDIE();
+ CUDie.setForceChildren();
+ }
+
+ 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());
+ CUDie.dump(llvm::outs(), UINT32_MAX);
+
+ // Verify that the CU Die that says it has children, but doesn't, actually
+ // has begin and end iterators that are equal. We want to make sure we don't
+ // see the Null DIEs during iteration.
+ EXPECT_EQ(CUDie.begin(), CUDie.end());
+}
} // end anonymous namespace
Modified: llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp?rev=291194&r1=291193&r2=291194&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp (original)
+++ llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.cpp Thu Jan 5 17:47:37 2017
@@ -108,6 +108,10 @@ dwarfgen::DIE dwarfgen::CompileUnit::get
return dwarfgen::DIE(this, &DU.getUnitDie());
}
+void dwarfgen::DIE::setForceChildren() {
+ Die->setForceChildren(true);
+}
+
//===----------------------------------------------------------------------===//
/// dwarfgen::Generator implementation.
//===----------------------------------------------------------------------===//
Modified: llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.h?rev=291194&r1=291193&r2=291194&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.h (original)
+++ llvm/trunk/unittests/DebugInfo/DWARF/DwarfGenerator.h Thu Jan 5 17:47:37 2017
@@ -129,6 +129,9 @@ public:
/// \returns the newly created DIE object that is now a child owned by this
/// object.
dwarfgen::DIE addChild(dwarf::Tag Tag);
+
+ /// Force a DIE to say it has children even when it doesn't.
+ void setForceChildren();
};
/// A DWARF compile unit used to generate DWARF compile/type units.
More information about the llvm-commits
mailing list