Index: include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDie.h +++ include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -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 @@ 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,9 +360,62 @@ getInlinedChainForAddress(const uint64_t Address, SmallVectorImpl &InlinedChain) const; + class iterator; + + iterator begin() const; + iterator end() const; + iterator_range 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 { + 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::children() const { + return make_range(begin(), end()); +} + } // end namespace llvm #endif // LLVM_LIB_DEBUGINFO_DWARFDIE_H Index: lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDie.cpp +++ lib/DebugInfo/DWARF/DWARFDie.cpp @@ -299,11 +299,8 @@ 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 { Index: tools/dsymutil/DwarfLinker.cpp =================================================================== --- tools/dsymutil/DwarfLinker.cpp +++ tools/dsymutil/DwarfLinker.cpp @@ -1796,8 +1796,7 @@ 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 @@ 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 @@ // 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 @@ } // 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(); Index: unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -1100,5 +1100,132 @@ 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, TestNullDWARFDieIterator) { + // Test that constructing a DWARFDie::iterator with a NULL DIE ends up making + // an iterator that is the same as DWARFDie::end(). We currently can't create + // a DWARF DIE that says it has children, yet only contains a single NULL DIE + // due to how the classes in DIE.h/DIE.cpp are currently coded. To avoid + // adding code to those classes that no one wants or will use, we manually + // construct a DWARFDie::iterator with a NULL DIE to test that this would + // work. + 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 + }; + + // Scope to allow us to re-use the same DIE names + { + // Create DWARF tree that looks like: + // + // CU + // A + auto CUDie = CU.getUnitDIE(); + CUDie.addChild((dwarf::Tag)Tag::A); + } + + 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); + + DWARFDie Null = U->getUnitDIE(false).getFirstChild().getSibling(); + EXPECT_TRUE(Null.isNULL()); + + // Verify that a NULL Die that is used to create an iterator is the same as + // the DWARFDie::end() iterator. + EXPECT_EQ(DWARFDie::iterator(Null), Null.end()); +} + } // end anonymous namespace