[llvm] r291861 - Add the ability to iterate across all attributes in a DIE.
Greg Clayton via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 12 16:13:42 PST 2017
Author: gclayton
Date: Thu Jan 12 18:13:42 2017
New Revision: 291861
URL: http://llvm.org/viewvc/llvm-project?rev=291861&view=rev
Log:
Add the ability to iterate across all attributes in a DIE.
Differential Revision: https://reviews.llvm.org/D28386
Added:
llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAttribute.h
Modified:
llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h
llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h
llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp
llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h?rev=291861&r1=291860&r2=291861&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h Thu Jan 12 18:13:42 2017
@@ -55,6 +55,7 @@ public:
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 @@ public:
}
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.
Added: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAttribute.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAttribute.h?rev=291861&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAttribute.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFAttribute.h Thu Jan 12 18:13:42 2017
@@ -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
Modified: llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h?rev=291861&r1=291860&r2=291861&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/DWARF/DWARFDie.h Thu Jan 12 18:13:42 2017
@@ -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 @@ public:
getInlinedChainForAddress(const uint64_t Address,
SmallVectorImpl<DWARFDie> &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<attribute_iterator> attributes() const;
+
class iterator;
iterator begin() const;
iterator end() const;
iterator_range<iterator> children() const;
};
+
+class DWARFDie::attribute_iterator :
+ public iterator_facade_base<attribute_iterator, std::forward_iterator_tag,
+ const DWARFAttribute> {
+ /// 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) {
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp?rev=291861&r1=291860&r2=291861&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFDie.cpp Thu Jan 12 18:13:42 2017
@@ -399,3 +399,53 @@ DWARFDie DWARFDie::getSibling() const {
return U->getSibling(Die);
return DWARFDie();
}
+
+iterator_range<DWARFDie::attribute_iterator>
+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;
+}
Modified: llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp?rev=291861&r1=291860&r2=291861&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp (original)
+++ llvm/trunk/lib/DebugInfo/DWARF/DWARFFormValue.cpp Thu Jan 12 18:13:42 2017
@@ -400,7 +400,9 @@ bool DWARFFormValue::extractValue(const
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);
Modified: llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp?rev=291861&r1=291860&r2=291861&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp (original)
+++ llvm/trunk/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp Thu Jan 12 18:13:42 2017
@@ -488,7 +488,6 @@ template <uint16_t Version, class AddrTy
// 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 @@ template <uint16_t Version, class AddrTy
// 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 @@ template <uint16_t Version, class AddrTy
// 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<uint64_t> OptU64;
@@ -1067,7 +1063,6 @@ TEST(DWARFDebugInfo, TestRelations) {
// 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 @@ TEST(DWARFDebugInfo, TestChildIterators)
// 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 @@ TEST(DWARFDebugInfo, TestEmptyChildren)
// 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 @@ TEST(DWARFDebugInfo, TestEmptyChildren)
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
More information about the llvm-commits
mailing list