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;
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) {
/// 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;
#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"
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; }
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
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 {
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);
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);
}
// 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;
}
// 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();
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
return dwarfgen::DIE(this, &DU.getUnitDie());
}
+void dwarfgen::DIE::setForceChildren() {
+ Die->setForceChildren(true);
+}
+
//===----------------------------------------------------------------------===//
/// dwarfgen::Generator implementation.
//===----------------------------------------------------------------------===//
/// \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.