mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-24 12:19:53 +00:00
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:
parent
41914406a9
commit
d1f6d693d6
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user