Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h +++ llvm/trunk/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 @@ /// \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 @@ /// 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 Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -158,6 +158,35 @@ 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 @@ 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 @@ 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)) Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -226,9 +226,7 @@ // 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); Index: llvm/trunk/tools/dsymutil/DwarfLinker.cpp =================================================================== --- llvm/trunk/tools/dsymutil/DwarfLinker.cpp +++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp @@ -3184,10 +3184,8 @@ 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 @@ 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; Index: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -1476,4 +1476,71 @@ // 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