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" @@ -43,6 +45,9 @@ bool operator ==(const DWARFDie &RHS) const { return Die == RHS.Die && U == RHS.U; } + 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 +366,32 @@ getInlinedChainForAddress(const uint64_t Address, SmallVectorImpl &InlinedChain) const; + class iterator; + + iterator begin() const; + iterator end() const; + iterator_range children() const; + }; +class DWARFDie::iterator : public iterator_facade_base { + DWARFDie Die; +public: + iterator() : Die() {} + explicit iterator(const DWARFDie &D) : Die(D) {} + iterator &operator++() { + Die = Die.getSibling(); + return *this; + } + explicit operator bool() const { return Die.isValid(); } + DWARFDie operator*() const { return Die; } + bool operator==(const iterator &X) const { return Die == X.Die; } + bool operator!=(const iterator &X) const { return Die != X.Die; } +}; + } // 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 { @@ -384,12 +381,9 @@ Indent); } - DWARFDie child = getFirstChild(); - if (RecurseDepth > 0 && child) { - while (child) { - child.dump(OS, RecurseDepth-1, Indent+2); - child = child.getSibling(); - } + if (RecurseDepth > 0) { + for (auto Child : children()) + Child.dump(OS, RecurseDepth-1, Indent+2); } } else { OS << "Abbreviation code not found in 'debug_abbrev' class for code: " @@ -439,3 +433,15 @@ return U->getSibling(Die); return DWARFDie(); } + +DWARFDie::iterator DWARFDie::begin() const { + return iterator(getFirstChild()); +} + +DWARFDie::iterator DWARFDie::end() const { + return iterator(); +} + +llvm::iterator_range DWARFDie::children() const { + return make_range(begin(), end()); +} Index: tools/dsymutil/DwarfLinker.cpp =================================================================== --- tools/dsymutil/DwarfLinker.cpp +++ tools/dsymutil/DwarfLinker.cpp @@ -1796,10 +1796,12 @@ Info.Prune = InImportedModule; if (DIE.hasChildren()) - for (auto Child = DIE.getFirstChild(); Child && !Child.isNULL(); - Child = Child.getSibling()) + for (auto Child: DIE.children()) { + if (Child.isNULL()) + break; Info.Prune &= analyzeContextInfo(Child, MyIdx, CU, CurrentDeclContext, StringPool, Contexts, InImportedModule); + } // Prune this DIE if it is either a forward declaration inside a // DW_TAG_module or a DW_TAG_module that contains nothing but @@ -2294,9 +2296,11 @@ if (!Die.hasChildren() || (Flags & TF_ParentWalk)) return; - for (auto Child = Die.getFirstChild(); Child && !Child.isNULL(); - Child = Child.getSibling()) + for (auto Child: Die.children()) { + if (Child.isNULL()) + break; lookForDIEsToKeep(RelocMgr, Child, DMO, CU, Flags); + } } /// \brief Assign an abbreviation numer to \p Abbrev. @@ -2814,8 +2818,9 @@ // 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()) { + if (Child.isNULL()) + break; unsigned Idx = U.getDIEIndex(Child); if (Unit.getInfo(Idx).Keep) { HasChildren = true; @@ -2840,8 +2845,9 @@ } // Recursively clone children. - for (auto Child = InputDIE.getFirstChild(); Child && !Child.isNULL(); - Child = Child.getSibling()) { + for (auto Child: InputDIE.children()) { + if (Child.isNULL()) + break; 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,140 @@ 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, + B1, + B2, + C, + C1, + D + }; + + // Scope to allow us to re-use the same DIE names + { + // Create DWARF tree that looks like: + // + // CU + // A + // B + // B1 + // B2 + // C + // C1 + // D + auto CUDie = CU.getUnitDIE(); + CUDie.addChild((dwarf::Tag)Tag::A); + auto B = CUDie.addChild((dwarf::Tag)Tag::B); + auto C = CUDie.addChild((dwarf::Tag)Tag::C); + CUDie.addChild((dwarf::Tag)Tag::D); + 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()); + // CUDie.dump(llvm::outs(), UINT32_MAX); + uint32_t Index; + DWARFDie A; + DWARFDie B; + DWARFDie C; + DWARFDie D; + DWARFDie Null; + + // 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; + case 2: C = Die; break; + case 3: D = Die; break; + case 4: Null = Die; break; + } + } + + EXPECT_EQ(A.getTag(), (dwarf::Tag)Tag::A); + EXPECT_EQ(B.getTag(), (dwarf::Tag)Tag::B); + EXPECT_EQ(C.getTag(), (dwarf::Tag)Tag::C); + EXPECT_EQ(D.getTag(), (dwarf::Tag)Tag::D); + EXPECT_TRUE(Null.isNULL()); + // Verify that A has no children by verifying that the begin and end contain + // invalid DIEs and also that the iterators are equal. + auto begin = A.begin(); + auto end = A.end(); + EXPECT_FALSE((*begin).isValid()); + EXPECT_FALSE((*end).isValid()); + EXPECT_EQ(begin, end); + + // Verify B's children. + DWARFDie B1; + DWARFDie B2; + Index = 0; + for (auto Die : B.children()) { + switch (Index++) { + case 0: B1 = Die; break; + case 1: B2 = Die; break; + case 2: Null = Die; break; + } + } + EXPECT_EQ(B1.getTag(), (dwarf::Tag)Tag::B1); + EXPECT_EQ(B2.getTag(), (dwarf::Tag)Tag::B2); + EXPECT_TRUE(Null.isNULL()); + + // Verify C's children. + DWARFDie C1; + Index = 0; + for (auto Die : C.children()) { + switch (Index++) { + case 0: C1 = Die; break; + case 1: Null = Die; break; + } + } + EXPECT_EQ(C1.getTag(), (dwarf::Tag)Tag::C1); + EXPECT_TRUE(Null.isNULL()); + + // Verify that a NULL DIE has no children. + begin = Null.begin(); + end = Null.end(); + EXPECT_FALSE((*begin).isValid()); + EXPECT_FALSE((*end).isValid()); + EXPECT_EQ(begin, end); + + // Verify that an invalid DIE has no children. + DWARFDie Invalid; + begin = Invalid.begin(); + end = Invalid.end(); + EXPECT_FALSE((*begin).isValid()); + EXPECT_FALSE((*end).isValid()); + EXPECT_EQ(begin, end); +} + } // end anonymous namespace