From c109bbea57c2df9edb983177ec1c998bd946d23a Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Fri, 13 Jan 2017 22:32:12 +0000 Subject: [PATCH] Add a variant of DWARFDie::find() and DWARFDie::findRecursively() that takes a llvm::ArrayRef. 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 --- llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h | 27 +++++++- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 41 +++++++++--- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 4 +- llvm/tools/dsymutil/DwarfLinker.cpp | 12 ++-- .../DebugInfo/DWARF/DWARFDebugInfoTest.cpp | 67 +++++++++++++++++++ 5 files changed, 131 insertions(+), 20 deletions(-) diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h index 39c4d87f45e1..07651dd872ab 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -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 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 find(ArrayRef 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 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 + findRecursively(ArrayRef Attrs) const; + /// Extract the specified attribute from this DIE as the referenced DIE. /// /// Regardless of the reference type, return the correct DWARFDie instance if diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index 11fb726f4338..9a05ae8d38ac 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -158,6 +158,35 @@ DWARFDie::findRecursively(dwarf::Attribute Attr) const { return None; } +Optional +DWARFDie::find(ArrayRef 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 +DWARFDie::findRecursively(ArrayRef 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 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 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)) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index e0dcd9b20b2a..84dc904f9b82 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -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); diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 8b1a2d129733..a4033ce30897 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -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; diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp index 72d885645026..5c9febd18905 100644 --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -1476,4 +1476,71 @@ TEST(DWARFDebugInfo, TestDwarfToFunctions) { // Test } +TEST(DWARFDebugInfo, TestFindAttrs) { + // Test the DWARFDie::find() and DWARFDie::findRecursively() that take an + // ArrayRef 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()).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 + 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