Add a variant of DWARFDie::find() and DWARFDie::findRecursively() that takes a llvm::ArrayRef<dwarf::Attribute>.

This allows us efficiently look for more than one attribute, something that is quite common in DWARF consumption.

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

llvm-svn: 291967
This commit is contained in:
Greg Clayton 2017-01-13 22:32:12 +00:00
parent bba17390c7
commit c109bbea57
5 changed files with 131 additions and 20 deletions

View File

@ -10,6 +10,7 @@
#ifndef LLVM_LIB_DEBUGINFO_DWARFDIE_H
#define LLVM_LIB_DEBUGINFO_DWARFDIE_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/Optional.h"
@ -125,8 +126,20 @@ public:
/// \returns an optional DWARFFormValue that will have the form value if the
/// attribute was successfully extracted.
Optional<DWARFFormValue> find(dwarf::Attribute Attr) const;
/// Extract the first value of any attribute in Attrs from this DIE.
///
/// Extract the first attribute that matches from this DIE only. This call
/// doesn't look for the attribute value in any DW_AT_specification or
/// DW_AT_abstract_origin referenced DIEs. The attributes will be searched
/// linearly in the order they are specified within Attrs.
///
/// \param Attrs an array of DWARF attribute to look for.
/// \returns an optional that has a valid DWARFFormValue for the first
/// matching attribute in Attrs, or None if none of the attributes in Attrs
/// exist in this DIE.
Optional<DWARFFormValue> find(ArrayRef<dwarf::Attribute> Attrs) const;
/// Extract an attribute value from this DIE and recurse into any
/// DW_AT_specification or DW_AT_abstract_origin referenced DIEs.
///
@ -135,6 +148,18 @@ public:
/// attribute was successfully extracted.
Optional<DWARFFormValue> findRecursively(dwarf::Attribute Attr) const;
/// Extract the first value of any attribute in Attrs from this DIE and
/// recurse into any DW_AT_specification or DW_AT_abstract_origin referenced
/// DIEs.
///
/// \param Attrs an array of DWARF attribute to look for.
/// \returns an optional that has a valid DWARFFormValue for the first
/// matching attribute in Attrs, or None if none of the attributes in Attrs
/// exist in this DIE or in any DW_AT_specification or DW_AT_abstract_origin
/// DIEs.
Optional<DWARFFormValue>
findRecursively(ArrayRef<dwarf::Attribute> Attrs) const;
/// Extract the specified attribute from this DIE as the referenced DIE.
///
/// Regardless of the reference type, return the correct DWARFDie instance if

View File

@ -158,6 +158,35 @@ DWARFDie::findRecursively(dwarf::Attribute Attr) const {
return None;
}
Optional<DWARFFormValue>
DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const {
if (!isValid())
return None;
auto AbbrevDecl = getAbbreviationDeclarationPtr();
if (AbbrevDecl) {
for (auto Attr : Attrs) {
if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U))
return Value;
}
}
return None;
}
Optional<DWARFFormValue>
DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const {
if (!isValid())
return None;
if (auto Value = find(Attrs))
return Value;
if (auto Die = getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
if (auto Value = Die.find(Attrs))
return Value;
if (auto Die = getAttributeValueAsReferencedDie(DW_AT_specification))
if (auto Value = Die.find(Attrs))
return Value;
return None;
}
DWARFDie
DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
auto SpecRef = toReference(find(Attr));
@ -171,10 +200,7 @@ DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
Optional<uint64_t>
DWARFDie::getRangesBaseAttribute() const {
auto Result = toSectionOffset(find(DW_AT_rnglists_base));
if (Result)
return Result;
return toSectionOffset(find(DW_AT_GNU_ranges_base));
return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base}));
}
Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const {
@ -256,11 +282,8 @@ DWARFDie::getName(DINameKind Kind) const {
return nullptr;
// Try to get mangled name only if it was asked for.
if (Kind == DINameKind::LinkageName) {
if (auto Name = dwarf::toString(findRecursively(DW_AT_MIPS_linkage_name),
nullptr))
return Name;
if (auto Name = dwarf::toString(findRecursively(DW_AT_linkage_name),
nullptr))
if (auto Name = dwarf::toString(findRecursively({DW_AT_MIPS_linkage_name,
DW_AT_linkage_name}), nullptr))
return Name;
}
if (auto Name = dwarf::toString(findRecursively(DW_AT_name), nullptr))

View File

@ -226,9 +226,7 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
// If CU DIE was just parsed, copy several attribute values from it.
if (!HasCUDie) {
DWARFDie UnitDie = getUnitDIE();
auto BaseAddr = toAddress(UnitDie.find(DW_AT_low_pc));
if (!BaseAddr)
BaseAddr = toAddress(UnitDie.find(DW_AT_entry_pc));
auto BaseAddr = toAddress(UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc}));
if (BaseAddr)
setBaseAddress(*BaseAddr);
AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0);

View File

@ -3184,10 +3184,8 @@ void DwarfLinker::DIECloner::copyAbbrev(
static uint64_t getDwoId(const DWARFDie &CUDie,
const DWARFUnit &Unit) {
auto DwoId = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_dwo_id));
if (DwoId)
return *DwoId;
DwoId = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_GNU_dwo_id));
auto DwoId = dwarf::toUnsigned(CUDie.find({dwarf::DW_AT_dwo_id,
dwarf::DW_AT_GNU_dwo_id}));
if (DwoId)
return *DwoId;
return 0;
@ -3196,9 +3194,9 @@ static uint64_t getDwoId(const DWARFDie &CUDie,
bool DwarfLinker::registerModuleReference(
const DWARFDie &CUDie, const DWARFUnit &Unit,
DebugMap &ModuleMap, unsigned Indent) {
std::string PCMfile = dwarf::toString(CUDie.find(dwarf::DW_AT_dwo_name), "");
if (PCMfile.empty())
PCMfile = dwarf::toString(CUDie.find(dwarf::DW_AT_GNU_dwo_name), "");
std::string PCMfile =
dwarf::toString(CUDie.find({dwarf::DW_AT_dwo_name,
dwarf::DW_AT_GNU_dwo_name}), "");
if (PCMfile.empty())
return false;

View File

@ -1476,4 +1476,71 @@ TEST(DWARFDebugInfo, TestDwarfToFunctions) {
// Test
}
TEST(DWARFDebugInfo, TestFindAttrs) {
// Test the DWARFDie::find() and DWARFDie::findRecursively() that take an
// ArrayRef<dwarf::Attribute> value to make sure they work correctly.
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();
StringRef DieMangled("_Z3fooi");
// 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();
auto FuncSpecDie = CUDie.addChild(DW_TAG_subprogram);
auto FuncDie = CUDie.addChild(DW_TAG_subprogram);
FuncSpecDie.addAttribute(DW_AT_MIPS_linkage_name, DW_FORM_strp, DieMangled);
FuncDie.addAttribute(DW_AT_specification, DW_FORM_ref4, FuncSpecDie);
}
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());
auto FuncSpecDie = CUDie.getFirstChild();
auto FuncDie = FuncSpecDie.getSibling();
// Make sure that passing in an empty attribute list behave correctly.
EXPECT_FALSE(FuncDie.find(ArrayRef<dwarf::Attribute>()).hasValue());
// Make sure that passing in a list of attribute that are not contained
// in the DIE returns nothing.
EXPECT_FALSE(FuncDie.find({DW_AT_low_pc, DW_AT_entry_pc}).hasValue());
ArrayRef<dwarf::Attribute>
Attrs = { DW_AT_linkage_name, DW_AT_MIPS_linkage_name };
// Make sure we can't extract the linkage name attributes when using
// DWARFDie::find() since it won't check the DW_AT_specification DIE.
EXPECT_FALSE(FuncDie.find(Attrs).hasValue());
// Make sure we can extract the name from the specification die when using
// DWARFDie::findRecursively() since it should recurse through the
// DW_AT_specification DIE.
auto NameOpt = FuncDie.findRecursively(Attrs);
EXPECT_TRUE(NameOpt.hasValue());
EXPECT_EQ(DieMangled, toString(NameOpt, ""));
}
} // end anonymous namespace