Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h @@ -55,6 +55,7 @@ DWARFAbbreviationDeclaration(); uint32_t getCode() const { return Code; } + uint8_t getCodeByteSize() const { return CodeByteSize; } dwarf::Tag getTag() const { return Tag; } bool hasChildren() const { return HasChildren; } @@ -66,9 +67,17 @@ } dwarf::Form getFormByIndex(uint32_t idx) const { - if (idx < AttributeSpecs.size()) - return AttributeSpecs[idx].Form; - return dwarf::Form(0); + assert(idx < AttributeSpecs.size()); + return AttributeSpecs[idx].Form; + } + + size_t getNumAttributes() const { + return AttributeSpecs.size(); + } + + dwarf::Attribute getAttrByIndex(uint32_t idx) const { + assert(idx < AttributeSpecs.size()); + return AttributeSpecs[idx].Attr; } /// Get the index of the specified attribute. Index: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAttribute.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAttribute.h +++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAttribute.h @@ -0,0 +1,56 @@ +//===-- DWARFAttribute.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_DEBUGINFO_DWARFATTRIBUTE_H +#define LLVM_LIB_DEBUGINFO_DWARFATTRIBUTE_H + +#include "llvm/Support/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" + +namespace llvm { + +//===----------------------------------------------------------------------===// +/// Encapsulates a DWARF attribute value and all of the data required to +/// describe the attribute value. +/// +/// This class is designed to be used by clients that want to iterate across all +/// attributes in a DWARFDie. +struct DWARFAttribute { + /// The debug info/types offset for this attribute. + uint32_t Offset; + /// The debug info/types section byte size of the data for this attribute. + uint32_t ByteSize; + /// The attribute enumeration of this attribute. + dwarf::Attribute Attr; + /// The form and value for this attribute. + DWARFFormValue Value; + + DWARFAttribute(uint32_t O, dwarf::Attribute A = dwarf::Attribute(0), + dwarf::Form F = dwarf::Form(0)) : + Offset(0), ByteSize(0), Attr(A), Value(F) {} + + bool isValid() const { + return Offset != 0 && Attr != dwarf::Attribute(0); + } + + explicit operator bool() const { + return isValid(); + } + + void clear() { + Offset = 0; + ByteSize = 0; + Attr = dwarf::Attribute(0); + Value = DWARFFormValue(); + } +}; + +} + +#endif 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 @@ -13,6 +13,7 @@ #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/DWARF/DWARFAttribute.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" namespace llvm { @@ -286,12 +287,43 @@ getInlinedChainForAddress(const uint64_t Address, SmallVectorImpl &InlinedChain) const; + /// Get an iterator range to all attributes in the current DIE only. + /// + /// \returns an iterator range for the attributes of the current DIE. + class attribute_iterator; + iterator_range attributes() const; + class iterator; iterator begin() const; iterator end() const; iterator_range children() const; }; + +class DWARFDie::attribute_iterator : + public iterator_facade_base { + /// The DWARF DIE we are extracting attributes from. + DWARFDie Die; + /// The value vended to clients via the operator*() or operator->(). + DWARFAttribute AttrValue; + /// The attribute index within the abbreviation declaration in Die. + uint32_t Index; + + /// Update the attribute index and attempt to read the attribute value. If the + /// attribute is able to be read, update AttrValue and the Index member + /// variable. If the attribute value is not able to be read, an appropriate + /// error will be set if the Err member variable is non-NULL and the iterator + /// will be set to the end value so iteration stops. + void updateForIndex(const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I); +public: + attribute_iterator() = delete; + explicit attribute_iterator(DWARFDie D, bool End); + attribute_iterator &operator++(); + explicit operator bool() const { return AttrValue.isValid(); } + const DWARFAttribute &operator*() const { return AttrValue; } + bool operator==(const attribute_iterator &X) const { return Index == X.Index; } +}; inline bool operator==(const DWARFDie &LHS, const DWARFDie &RHS) { Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -399,3 +399,53 @@ return U->getSibling(Die); return DWARFDie(); } + +iterator_range +DWARFDie::attributes() const { + return make_range(attribute_iterator(*this, false), + attribute_iterator(*this, true)); +} + +DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End) : + Die(D), AttrValue(0), Index(0) { + auto AbbrDecl = Die.getAbbreviationDeclarationPtr(); + assert(AbbrDecl && "Must have abbreviation declaration"); + if (End) { + // This is the end iterator so we set the index to the attribute count. + Index = AbbrDecl->getNumAttributes(); + } else { + // This is the begin iterator so we extract the value for this->Index. + AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize(); + updateForIndex(*AbbrDecl, 0); + } +} + +void DWARFDie::attribute_iterator::updateForIndex( + const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) { + Index = I; + // AbbrDecl must be valid befor calling this function. + auto NumAttrs = AbbrDecl.getNumAttributes(); + if (Index < NumAttrs) { + AttrValue.Attr = AbbrDecl.getAttrByIndex(Index); + // Add the previous byte size of any previous attribute value. + AttrValue.Offset += AttrValue.ByteSize; + AttrValue.Value.setForm(AbbrDecl.getFormByIndex(Index)); + uint32_t ParseOffset = AttrValue.Offset; + auto U = Die.getDwarfUnit(); + assert(U && "Die must have valid DWARF unit"); + bool b = AttrValue.Value.extractValue(U->getDebugInfoExtractor(), + &ParseOffset, U); + (void)b; + assert(b && "extractValue cannot fail on fully parsed DWARF"); + AttrValue.ByteSize = ParseOffset - AttrValue.Offset; + } else { + assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only"); + AttrValue.clear(); + } +} + +DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() { + if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr()) + updateForIndex(*AbbrDecl, Index + 1); + return *this; +} Index: llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -400,7 +400,9 @@ Value.uval = data.getULEB128(offset_ptr); break; default: - return false; + // DWARFFormValue::skipValue() will have caught this and caused all + // DWARF DIEs to fail to be parsed, so this code is not be reachable. + llvm_unreachable("unsupported form"); } } while (indirect); Index: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp =================================================================== --- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -488,7 +488,6 @@ // Get the compile unit DIE is valid. auto DieDG = U->getUnitDIE(false); EXPECT_TRUE(DieDG.isValid()); - // DieDG.dump(llvm::outs(), U, UINT32_MAX); // Verify the first child of the compile unit DIE is our subprogram. auto SubprogramDieDG = DieDG.getFirstChild(); @@ -662,11 +661,9 @@ // Get the compile unit DIE is valid. auto Unit1DieDG = U1->getUnitDIE(false); EXPECT_TRUE(Unit1DieDG.isValid()); - // Unit1DieDG.dump(llvm::outs(), UINT32_MAX); auto Unit2DieDG = U2->getUnitDIE(false); EXPECT_TRUE(Unit2DieDG.isValid()); - // Unit2DieDG.dump(llvm::outs(), UINT32_MAX); // Verify the first child of the compile unit 1 DIE is our int base type. auto CU1TypeDieDG = Unit1DieDG.getFirstChild(); @@ -887,7 +884,6 @@ // Get the compile unit DIE is valid. auto DieDG = U->getUnitDIE(false); EXPECT_TRUE(DieDG.isValid()); - // DieDG.dump(llvm::outs(), U, UINT32_MAX); uint64_t LowPC, HighPC; Optional OptU64; @@ -1067,7 +1063,6 @@ // Get the compile unit DIE is valid. auto CUDie = U->getUnitDIE(false); EXPECT_TRUE(CUDie.isValid()); - // CUDie.dump(llvm::outs(), UINT32_MAX); // The compile unit doesn't have a parent or a sibling. auto ParentDie = CUDie.getParent(); @@ -1185,7 +1180,6 @@ // 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; @@ -1255,7 +1249,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 +1256,66 @@ EXPECT_EQ(CUDie.begin(), CUDie.end()); } +TEST(DWARFDebugInfo, TestAttributeIterators) { + // Test the DWARF APIs related to iterating across all attribute values in a + // a DWARFDie. + 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(); + const uint64_t CULowPC = 0x1000; + StringRef CUPath("/tmp/main.c"); + + // Scope to allow us to re-use the same DIE names + { + auto CUDie = CU.getUnitDIE(); + // Encode an attribute value before an attribute with no data. + CUDie.addAttribute(DW_AT_name, DW_FORM_strp, CUPath.data()); + // Encode an attribute value with no data in .debug_info/types to ensure + // the iteration works correctly. + CUDie.addAttribute(DW_AT_declaration, DW_FORM_flag_present); + // Encode an attribute value after an attribute with no data. + CUDie.addAttribute(DW_AT_low_pc, DW_FORM_addr, CULowPC); + } + + 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 R = CUDie.attributes(); + auto I = R.begin(); + auto E = R.end(); + + ASSERT_NE(E, I); + EXPECT_EQ(I->Attr, DW_AT_name); + auto ActualCUPath = I->Value.getAsCString(); + EXPECT_EQ(CUPath, *ActualCUPath); + + ASSERT_NE(E, ++I); + EXPECT_EQ(I->Attr, DW_AT_declaration); + EXPECT_EQ(1ull, I->Value.getAsUnsignedConstant()); + + ASSERT_NE(E, ++I); + EXPECT_EQ(I->Attr, DW_AT_low_pc); + EXPECT_EQ(CULowPC, I->Value.getAsAddress()); + + EXPECT_EQ(E, ++I); +} + } // end anonymous namespace