[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