Add iterator support to DWARFDie to allow child DIE iteration.

Differential Revision: https://reviews.llvm.org/D28303



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291194 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Greg Clayton 2017-01-05 23:47:37 +00:00
parent 41914406a9
commit d1f6d693d6
7 changed files with 195 additions and 17 deletions

View File

@ -651,6 +651,9 @@ class DIE : IntrusiveBackListNode, public DIEValueList {
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, public DIEValueList {
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;

View File

@ -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

View File

@ -299,11 +299,8 @@ DWARFDie::collectChildrenAddressRanges(DWARFAddressRangesVector& Ranges) const {
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 {

View File

@ -1796,8 +1796,7 @@ static bool analyzeContextInfo(const DWARFDie &DIE,
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(RelocationManager &RelocMgr,
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();

View File

@ -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

View File

@ -108,6 +108,10 @@ dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() {
return dwarfgen::DIE(this, &DU.getUnitDie());
}
void dwarfgen::DIE::setForceChildren() {
Die->setForceChildren(true);
}
//===----------------------------------------------------------------------===//
/// dwarfgen::Generator implementation.
//===----------------------------------------------------------------------===//

View File

@ -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.