Index: include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDie.h +++ include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -123,8 +123,17 @@ /// \param Attr the attribute to extract. /// \returns an optional DWARFFormValue that will have the form value if the /// attribute was successfully extracted. - Optional getAttributeValue(dwarf::Attribute Attr) const; + Optional find(dwarf::Attribute Attr) const; + + /// Extract an attribute value from this DIE and recurse into any + /// DW_AT_specification or DW_AT_abstract_origin referenced DIEs. + /// + /// \param Attr the attribute to extract. + /// \returns an optional DWARFFormValue that will have the form value if the + /// attribute was successfully extracted. + Optional findRecursively(dwarf::Attribute Attr) const; + /// Extract the specified attribute from this DIE as a C string. /// /// Extract an attribute value from this DIE only. This call doesn't look Index: include/llvm/DebugInfo/DWARF/DWARFFormValue.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -164,6 +164,36 @@ void dumpString(raw_ostream &OS) const; }; +namespace dwarf { + /// Take an optional DWARFFormValue and extract a string value from it. + /// + /// \param V and optional DWARFFormValue to attempt to extract the string + /// value from. + /// \returns an optional const char * that contains a value if the form value + /// was valid and was a string. + inline Optional toString(const Optional& V) { + if (V) + return V->getAsCString(); + return None; + } + + /// Take an optional DWARFFormValue and extract a string value from it. + /// + /// \param V and optional DWARFFormValue to attempt to extract the string + /// value from. + /// \returns an const char * that is the string value for the form value + /// or Default if the value wasn't valid or wasn't a string value. + inline const char* + toString(const Optional& V, const char *Default) { + if (V) { + if (auto S = V->getAsCString()) + return *S; + } + return nullptr; + } + +} // end namespace dwarf + } #endif Index: lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDie.cpp +++ lib/DebugInfo/DWARF/DWARFDie.cpp @@ -134,7 +134,7 @@ } Optional -DWARFDie::getAttributeValue(dwarf::Attribute Attr) const { +DWARFDie::find(dwarf::Attribute Attr) const { if (!isValid()) return None; auto AbbrevDecl = getAbbreviationDeclarationPtr(); @@ -143,9 +143,24 @@ return None; } +Optional +DWARFDie::findRecursively(dwarf::Attribute Attr) const { + if (!isValid()) + return None; + if (auto Value = find(Attr)) + return Value; + if (auto Die = getAttributeValueAsReferencedDie(DW_AT_abstract_origin)) + if (auto Value = Die.find(Attr)) + return Value; + if (auto Die = getAttributeValueAsReferencedDie(DW_AT_specification)) + if (auto Value = Die.find(Attr)) + return Value; + return None; +} + const char *DWARFDie::getAttributeValueAsString(dwarf::Attribute Attr, const char *FailValue) const { - auto FormValue = getAttributeValue(Attr); + auto FormValue = find(Attr); if (!FormValue) return FailValue; Optional Result = FormValue->getAsCString(); @@ -154,35 +169,35 @@ Optional DWARFDie::getAttributeValueAsAddress(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) + if (auto FormValue = find(Attr)) return FormValue->getAsAddress(); return None; } Optional DWARFDie::getAttributeValueAsSignedConstant(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) + if (auto FormValue = find(Attr)) return FormValue->getAsSignedConstant(); return None; } Optional DWARFDie::getAttributeValueAsUnsignedConstant(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) + if (auto FormValue = find(Attr)) return FormValue->getAsUnsignedConstant(); return None; } Optional DWARFDie::getAttributeValueAsReference(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) + if (auto FormValue = find(Attr)) return FormValue->getAsReference(); return None; } Optional DWARFDie::getAttributeValueAsSectionOffset(dwarf::Attribute Attr) const { - if (auto FormValue = getAttributeValue(Attr)) + if (auto FormValue = find(Attr)) return FormValue->getAsSectionOffset(); return None; } @@ -208,7 +223,7 @@ } Optional DWARFDie::getHighPC(uint64_t LowPC) const { - if (auto FormValue = getAttributeValue(DW_AT_high_pc)) { + if (auto FormValue = find(DW_AT_high_pc)) { if (auto Address = FormValue->getAsAddress()) { // High PC is an address. return Address; Index: tools/obj2yaml/dwarf2yaml.cpp =================================================================== --- tools/obj2yaml/dwarf2yaml.cpp +++ tools/obj2yaml/dwarf2yaml.cpp @@ -126,7 +126,7 @@ DWARFYAML::FormValue NewValue; NewValue.Value = 0xDEADBEEFDEADBEEF; DWARFDie DIEWrapper(CU.get(), &DIE); - auto FormValue = DIEWrapper.getAttributeValue(AttrSpec.Attr); + auto FormValue = DIEWrapper.find(AttrSpec.Attr); if (!FormValue) return; auto Form = FormValue.getValue().getForm(); Index: unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -238,7 +238,7 @@ ArrayRef ExtractedBlockData; Optional> BlockDataOpt; - FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block); + FormValue = DieDG.find(Attr_DW_FORM_block); EXPECT_TRUE((bool)FormValue); BlockDataOpt = FormValue->getAsBlock(); EXPECT_TRUE(BlockDataOpt.hasValue()); @@ -246,7 +246,7 @@ EXPECT_EQ(ExtractedBlockData.size(), BlockSize); EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0); - FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block1); + FormValue = DieDG.find(Attr_DW_FORM_block1); EXPECT_TRUE((bool)FormValue); BlockDataOpt = FormValue->getAsBlock(); EXPECT_TRUE(BlockDataOpt.hasValue()); @@ -254,7 +254,7 @@ EXPECT_EQ(ExtractedBlockData.size(), BlockSize); EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0); - FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block2); + FormValue = DieDG.find(Attr_DW_FORM_block2); EXPECT_TRUE((bool)FormValue); BlockDataOpt = FormValue->getAsBlock(); EXPECT_TRUE(BlockDataOpt.hasValue()); @@ -262,7 +262,7 @@ EXPECT_EQ(ExtractedBlockData.size(), BlockSize); EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0); - FormValue = DieDG.getAttributeValue(Attr_DW_FORM_block4); + FormValue = DieDG.find(Attr_DW_FORM_block4); EXPECT_TRUE((bool)FormValue); BlockDataOpt = FormValue->getAsBlock(); EXPECT_TRUE(BlockDataOpt.hasValue()); @@ -1255,7 +1255,6 @@ // 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 @@ -1263,4 +1262,86 @@ EXPECT_EQ(CUDie.begin(), CUDie.end()); } +TEST(DWARFDebugInfo, TestFindRecurse) { + 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 SpecDieName("spec"); + StringRef AbsDieName("abs"); + // 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); + auto VarAbsDie = CUDie.addChild(DW_TAG_variable); + auto VarDie = CUDie.addChild(DW_TAG_variable); + FuncSpecDie.addAttribute(DW_AT_name, DW_FORM_strp, SpecDieName); + FuncDie.addAttribute(DW_AT_specification, DW_FORM_ref4, FuncSpecDie); + VarAbsDie.addAttribute(DW_AT_name, DW_FORM_strp, AbsDieName); + VarDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, VarAbsDie); + } + + 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(); + auto VarAbsDie = FuncDie.getSibling(); + auto VarDie = VarAbsDie.getSibling(); + + // Make sure we can't extract the name from the specification die when using + // DWARFDie::find() since it won't check the DW_AT_specification DIE. + EXPECT_FALSE(FuncDie.find(DW_AT_name).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(DW_AT_name); + EXPECT_TRUE(NameOpt.hasValue()); + // Test the dwarf::toString() helper function. + auto StringOpt = toString(NameOpt); + EXPECT_TRUE(StringOpt.hasValue()); + EXPECT_EQ(SpecDieName, StringOpt.getValueOr(nullptr)); + // Test the dwarf::toString() helper function with a default value specified. + EXPECT_EQ(SpecDieName, toString(NameOpt, nullptr)); + + // Make sure we can't extract the name from the abstract origin die when using + // DWARFDie::find() since it won't check the DW_AT_abstract_origin DIE. + EXPECT_FALSE(VarDie.find(DW_AT_name).hasValue()); + + // Make sure we can extract the name from the abstract origin die when using + // DWARFDie::findRecursively() since it should recurse through the + // DW_AT_abstract_origin DIE. + NameOpt = VarDie.findRecursively(DW_AT_name); + EXPECT_TRUE(NameOpt.hasValue()); + // Test the dwarf::toString() helper function. + StringOpt = toString(NameOpt); + EXPECT_TRUE(StringOpt.hasValue()); + EXPECT_EQ(AbsDieName, StringOpt.getValueOr(nullptr)); + // Test the dwarf::toString() helper function with a default value specified. + EXPECT_EQ(AbsDieName, toString(NameOpt, nullptr)); +} + } // end anonymous namespace