[llvm] r231531 - [dsymutil] Support cloning DIE reference attributes.

Frederic Riss friss at apple.com
Fri Mar 6 15:22:53 PST 2015


Author: friss
Date: Fri Mar  6 17:22:53 2015
New Revision: 231531

URL: http://llvm.org/viewvc/llvm-project?rev=231531&view=rev
Log:
[dsymutil] Support cloning DIE reference attributes.

Reference attributes are mainly handled by just creating DIEEntry
attributes for them. There is a special case for DW_FORM_ref_addr
attributes though, because the DIEEntry code needs a DwarfDebug
code to emit them (and we don't have one as we do no CodeGen).
In that case, just use DIEInteger attributes with the right form.

Modified:
    llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test
    llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test
    llvm/trunk/tools/dsymutil/DwarfLinker.cpp

Modified: llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test?rev=231531&r1=231530&r2=231531&view=diff
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test (original)
+++ llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test Fri Mar  6 17:22:53 2015
@@ -21,17 +21,20 @@ CHECK:    DW_TAG_subprogram [2] *
 CHECK:    DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000051] = "main")
 CHECK:      DW_AT_decl_line [DW_FORM_data1]	(23)
 CHECK:      DW_AT_prototyped [DW_FORM_flag]	(0x01)
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0063 => {0x00000063})
 CHECK:      DW_AT_external [DW_FORM_flag]	(0x01)
 CHECK:      DW_AT_accessibility [DW_FORM_data1]	(DW_ACCESS_public)
 CHECK:      DW_AT_frame_base [DW_FORM_block1]	(<0x01> 56 )
 CHECK:      DW_TAG_formal_parameter [3]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x00000056] = "argc")
 CHECK:        DW_AT_decl_line [DW_FORM_data1]	(23)
+CHECK:        DW_AT_type [DW_FORM_ref4]     (cu + 0x0063 => {0x00000063})
 CHECK:        DW_AT_location [DW_FORM_block1]	(<0x02> 91 78 )
 CHECK:      DW_TAG_formal_parameter [3]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x0000005b] = "argv")
 CHECK:        DW_AT_decl_file [DW_FORM_data1]	(0x01)
 CHECK:        DW_AT_decl_line [DW_FORM_data1]	(23)
+CHECK:        DW_AT_type [DW_FORM_ref4]     (cu + 0x006a => {0x0000006a})
 CHECK:        DW_AT_location [DW_FORM_block1]	(<0x02> 91 70 )
 CHECK:      NULL
 CHECK:    DW_TAG_base_type [4]
@@ -39,8 +42,11 @@ CHECK:      DW_AT_name [DW_FORM_strp]
 CHECK:      DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
 CHECK:      DW_AT_byte_size [DW_FORM_data1]	(0x04)
 CHECK:    DW_TAG_pointer_type [5]
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x006f => {0x0000006f})
 CHECK:    DW_TAG_pointer_type [5]
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0074 => {0x00000074})
 CHECK:    DW_TAG_const_type [6]
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0079 => {0x00000079})
 CHECK:    DW_TAG_base_type [4]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000064] = "char")
 CHECK:      DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
@@ -57,17 +63,22 @@ CHECK:    DW_TAG_base_type [4]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000060] = "int")
 CHECK:    DW_TAG_variable [7]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000072] = "private_int")
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0026 => {0x000000a7})
 CHECK:    DW_TAG_variable [7]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000007e] = "baz")
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0026 => {0x000000a7})
 CHECK:    DW_TAG_subprogram [2] *
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000082] = "foo")
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0026 => {0x000000a7})
 CHECK:      DW_AT_frame_base [DW_FORM_block1]	(<0x01> 56 )
 CHECK:      DW_TAG_formal_parameter [3]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x00000086] = "arg")
+CHECK:        DW_AT_type [DW_FORM_ref4]     (cu + 0x0026 => {0x000000a7})
 CHECK:        DW_AT_location [DW_FORM_block1]	(<0x02> 91 7c )
 CHECK:      NULL
 CHECK:    DW_TAG_subprogram [8]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000008a] = "inc")
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0026 => {0x000000a7})
 CHECK:      DW_AT_frame_base [DW_FORM_block1]	(<0x01> 56 )
 CHECK:    NULL
 
@@ -79,18 +90,23 @@ CHECK:    DW_AT_name [DW_FORM_strp] ( .d
 CHECK:    DW_AT_comp_dir [DW_FORM_strp]     ( .debug_str[0x00000049] = "/Inputs")
 CHECK:    DW_TAG_variable [9]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000097] = "val")
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x003c => {0x00000162})
 CHECK:    DW_TAG_volatile_type [10]
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0041 => {0x00000167})
 CHECK:    DW_TAG_base_type [4]
 CHACK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000060] = "int")
 CHECK:    DW_TAG_subprogram [2] *
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000009b] = "bar")
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0041 => {0x00000167})
 CHECK:      DW_AT_frame_base [DW_FORM_block1]	(<0x01> 56 )
 CHECK:      DW_TAG_formal_parameter [3]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x00000086] = "arg")
+CHECK:        DW_AT_type [DW_FORM_ref4]     (cu + 0x0041 => {0x00000167})
 CHECK:        DW_AT_location [DW_FORM_block1]	(<0x02> 91 78 )
 CHECK:      NULL
 CHECK:    DW_TAG_subprogram [8]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000008a] = "inc")
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0041 => {0x00000167})
 CHECK:      DW_AT_frame_base [DW_FORM_block1]	(<0x01> 56 )
 
 CHECK:    NULL

Modified: llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test?rev=231531&r1=231530&r2=231531&view=diff
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test (original)
+++ llvm/trunk/test/tools/dsymutil/X86/basic-lto-linking-x86.test Fri Mar  6 17:22:53 2015
@@ -15,14 +15,17 @@ CHECK:    DW_TAG_subprogram [2] *
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000051] = "main")
 CHECK:      DW_AT_decl_line [DW_FORM_data1]	(23)
 CHECK:      DW_AT_prototyped [DW_FORM_flag]	(0x01)
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0063 => {0x00000063})
 CHECK:      DW_AT_external [DW_FORM_flag]	(0x01)
 CHECK:      DW_AT_accessibility [DW_FORM_data1]	(DW_ACCESS_public)
 CHECK:      DW_AT_frame_base [DW_FORM_block1]	(<0x01> 56 )
 CHECK:      DW_TAG_formal_parameter [3]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x00000056] = "argc")
+CHECK:        DW_AT_type [DW_FORM_ref4]     (cu + 0x0063 => {0x00000063})
 CHECK:        DW_AT_location [DW_FORM_block1]	(<0x03> 55 93 04 )
 CHECK:      DW_TAG_formal_parameter [3]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x0000005b] = "argv")
+CHECK:        DW_AT_type [DW_FORM_ref4]     (cu + 0x006a => {0x0000006a})
 CHECK:        DW_AT_location [DW_FORM_block1]	(<0x01> 54 )
 CHECK:      NULL
 CHECK:    DW_TAG_base_type [4]
@@ -30,8 +33,11 @@ CHECK:      DW_AT_name [DW_FORM_strp]
 CHECK:      DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed)
 CHECK:      DW_AT_byte_size [DW_FORM_data1]	(0x04)
 CHECK:    DW_TAG_pointer_type [5]
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x006f => {0x0000006f})
 CHECK:    DW_TAG_pointer_type [5]
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0074 => {0x00000074})
 CHECK:    DW_TAG_const_type [6]
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x0079 => {0x00000079})
 CHECK:    DW_TAG_base_type [4]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000064] = "char")
 CHECK:      DW_AT_encoding [DW_FORM_data1]	(DW_ATE_signed_char)
@@ -46,18 +52,24 @@ CHECK:    DW_AT_name [DW_FORM_strp] ( .d
 CHECK:    DW_AT_comp_dir [DW_FORM_strp]     ( .debug_str[0x00000049] = "/Inputs")
 CHECK:    DW_TAG_variable [7]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000072] = "private_int")
+CHECK:      DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000063)
 CHECK:    DW_TAG_variable [7]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000007e] = "baz")
+CHECK:      DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000063)
 CHECK:    DW_TAG_subprogram [8] *
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000082] = "foo")
+CHECK:      DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000063)
 CHECK:      DW_AT_frame_base [DW_FORM_block1]	(<0x01> 56 )
 CHECK:      DW_TAG_formal_parameter [9]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x00000086] = "arg")
+CHECK:        DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063)
 CHECK:      DW_TAG_inlined_subroutine [10]
+CHECK:        DW_AT_abstract_origin [DW_FORM_ref4]  (cu + 0x00a7 => {0x00000128} "inc")
 CHECK:        DW_AT_call_line [DW_FORM_data1]	(20)
 CHECK:      NULL
 CHECK:    DW_TAG_subprogram [11]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000008a] = "inc")
+CHECK:      DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000063)
 CHECK:      DW_AT_inline [DW_FORM_data1]	(DW_INL_inlined)
 CHECK:    NULL
 
@@ -69,16 +81,23 @@ CHECK:    DW_AT_name [DW_FORM_strp] ( .d
 CHECK:    DW_AT_comp_dir [DW_FORM_strp]     ( .debug_str[0x00000049] = "/Inputs")
 CHECK:    DW_TAG_variable [12]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000097] = "val")
+CHECK:      DW_AT_type [DW_FORM_ref4]       (cu + 0x003c => {0x00000176})
 CHECK:    DW_TAG_volatile_type [13]
+CHECK:      DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000063)
 CHECK:    DW_TAG_subprogram [8] *
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000009b] = "bar")
+CHECK:      DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000063)
 CHECK:      DW_AT_frame_base [DW_FORM_block1]	(<0x01> 56 )
 CHECK:      DW_TAG_formal_parameter [9]
 CHECK:        DW_AT_name [DW_FORM_strp]     ( .debug_str[0x00000086] = "arg")
+CHECK:        DW_AT_type [DW_FORM_ref_addr] (0x0000000000000063)
 CHECK:      DW_TAG_lexical_block [14] *
 CHECK:        DW_TAG_inlined_subroutine [15]
+CHECK:          DW_AT_abstract_origin [DW_FORM_ref4]        (cu + 0x009a => {0x000001d4} "inc")
+
 CHECK:        NULL
 CHECK:      NULL
 CHECK:    DW_TAG_subprogram [11]
 CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000008a] = "inc")
+CHECK:      DW_AT_type [DW_FORM_ref_addr]   (0x0000000000000063)
 CHECK:    NULL

Modified: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=231531&r1=231530&r2=231531&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Fri Mar  6 17:22:53 2015
@@ -55,6 +55,7 @@ public:
   /// \brief Information gathered about a DIE in the object file.
   struct DIEInfo {
     uint64_t Address;   ///< Linked address of the described entity.
+    DIE *Clone;         ///< Cloned version of that DIE.
     uint32_t ParentIdx; ///< The index of this DIE's parent.
     bool Keep;          ///< Is the DIE part of the linked output?
     bool InDebugMap;    ///< Was this DIE's entity found in the map?
@@ -89,6 +90,14 @@ public:
   /// debug_info section size).
   uint64_t computeNextUnitOffset();
 
+  /// \brief Keep track of a forward reference to DIE \p Die by
+  /// \p Attr. The attribute should be fixed up later to point to the
+  /// absolute offset of \p Die in the debug_info section.
+  void noteForwardReference(DIE *Die, DIEInteger *Attr);
+
+  /// \brief Apply all fixups recored by noteForwardReference().
+  void fixupForwardReferences();
+
 private:
   DWARFUnit &OrigUnit;
   std::vector<DIEInfo> Info;  ///< DIE info indexed by DIE index.
@@ -96,6 +105,14 @@ private:
 
   uint64_t StartOffset;
   uint64_t NextUnitOffset;
+
+  /// \brief A list of attributes to fixup with the absolute offset of
+  /// a DIE in the debug_info section.
+  ///
+  /// The offsets for the attributes in this array couldn't be set while
+  /// cloning because for forward refences the target DIE's offset isn't
+  /// known you emit the reference attribute.
+  std::vector<std::pair<DIE *, DIEInteger *>> ForwardDIEReferences;
 };
 
 uint64_t CompileUnit::computeNextUnitOffset() {
@@ -108,6 +125,17 @@ uint64_t CompileUnit::computeNextUnitOff
   return NextUnitOffset;
 }
 
+/// \brief Keep track of a forward reference to \p Die.
+void CompileUnit::noteForwardReference(DIE *Die, DIEInteger *Attr) {
+  ForwardDIEReferences.emplace_back(Die, Attr);
+}
+
+/// \brief Apply all fixups recorded by noteForwardReference().
+void CompileUnit::fixupForwardReferences() {
+  for (const auto &Ref : ForwardDIEReferences)
+    Ref.second->setValue(Ref.first->getOffset() + getStartOffset());
+}
+
 /// \brief A string table that doesn't need relocations.
 ///
 /// We are doing a final link, no need for a string table that
@@ -518,8 +546,11 @@ private:
                                 const DWARFFormValue &Val, const DWARFUnit &U);
 
   /// \brief Helper for cloneDIE.
-  unsigned cloneDieReferenceAttribute(DIE &Die, AttributeSpec AttrSpec,
-                                      unsigned AttrSize);
+  unsigned
+  cloneDieReferenceAttribute(DIE &Die,
+                             const DWARFDebugInfoEntryMinimal &InputDIE,
+                             AttributeSpec AttrSpec, unsigned AttrSize,
+                             const DWARFFormValue &Val, const DWARFUnit &U);
 
   /// \brief Helper for cloneDIE.
   unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec,
@@ -1059,12 +1090,60 @@ unsigned DwarfLinker::cloneStringAttribu
 /// \brief Clone an attribute referencing another DIE and add
 /// it to \p Die.
 /// \returns the size of the new attribute.
-unsigned DwarfLinker::cloneDieReferenceAttribute(DIE &Die,
-                                                 AttributeSpec AttrSpec,
-                                                 unsigned AttrSize) {
-  // FIXME: Handle DIE references.
+unsigned DwarfLinker::cloneDieReferenceAttribute(
+    DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE,
+    AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val,
+    const DWARFUnit &U) {
+  uint32_t Ref = *Val.getAsReference(&U);
+  DIE *NewRefDie = nullptr;
+  CompileUnit *RefUnit = nullptr;
+  const DWARFDebugInfoEntryMinimal *RefDie = nullptr;
+
+  if (!(RefUnit = getUnitForOffset(Ref)) ||
+      !(RefDie = RefUnit->getOrigUnit().getDIEForOffset(Ref))) {
+    const char *AttributeString = dwarf::AttributeString(AttrSpec.Attr);
+    if (!AttributeString)
+      AttributeString = "DW_AT_???";
+    reportWarning(Twine("Missing DIE for ref in attribute ") + AttributeString +
+                      ". Dropping.",
+                  &U, &InputDIE);
+    return 0;
+  }
+
+  unsigned Idx = RefUnit->getOrigUnit().getDIEIndex(RefDie);
+  CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(Idx);
+  if (!RefInfo.Clone) {
+    assert(Ref > InputDIE.getOffset());
+    // We haven't cloned this DIE yet. Just create an empty one and
+    // store it. It'll get really cloned when we process it.
+    RefInfo.Clone = new DIE(dwarf::Tag(RefDie->getTag()));
+  }
+  NewRefDie = RefInfo.Clone;
+
+  if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) {
+    // We cannot currently rely on a DIEEntry to emit ref_addr
+    // references, because the implementation calls back to DwarfDebug
+    // to find the unit offset. (We don't have a DwarfDebug)
+    // FIXME: we should be able to design DIEEntry reliance on
+    // DwarfDebug away.
+    DIEInteger *Attr;
+    if (Ref < InputDIE.getOffset()) {
+      // We must have already cloned that DIE.
+      uint32_t NewRefOffset =
+          RefUnit->getStartOffset() + NewRefDie->getOffset();
+      Attr = new (DIEAlloc) DIEInteger(NewRefOffset);
+    } else {
+      // A forward reference. Note and fixup later.
+      Attr = new (DIEAlloc) DIEInteger(0xBADDEF);
+      RefUnit->noteForwardReference(NewRefDie, Attr);
+    }
+    Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_ref_addr,
+                 Attr);
+    return AttrSize;
+  }
+
   Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form),
-               new (DIEAlloc) DIEInteger(0));
+               new (DIEAlloc) DIEEntry(*NewRefDie));
   return AttrSize;
 }
 
@@ -1150,7 +1229,8 @@ unsigned DwarfLinker::cloneAttribute(DIE
   case dwarf::DW_FORM_ref2:
   case dwarf::DW_FORM_ref4:
   case dwarf::DW_FORM_ref8:
-    return cloneDieReferenceAttribute(Die, AttrSpec, AttrSize);
+    return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val,
+                                      U);
   case dwarf::DW_FORM_block:
   case dwarf::DW_FORM_block1:
   case dwarf::DW_FORM_block2:
@@ -1187,14 +1267,19 @@ DIE *DwarfLinker::cloneDIE(const DWARFDe
                            CompileUnit &Unit, uint32_t OutOffset) {
   DWARFUnit &U = Unit.getOrigUnit();
   unsigned Idx = U.getDIEIndex(&InputDIE);
+  CompileUnit::DIEInfo &Info = Unit.getInfo(Idx);
 
   // Should the DIE appear in the output?
   if (!Unit.getInfo(Idx).Keep)
     return nullptr;
 
   uint32_t Offset = InputDIE.getOffset();
-
-  DIE *Die = new DIE(static_cast<dwarf::Tag>(InputDIE.getTag()));
+  // The DIE might have been already created by a forward reference
+  // (see cloneDieReferenceAttribute()).
+  DIE *Die = Info.Clone;
+  if (!Die)
+    Die = Info.Clone = new DIE(dwarf::Tag(InputDIE.getTag()));
+  assert(Die->getTag() == InputDIE.getTag());
   Die->setOffset(OutOffset);
 
   // Extract and clone every attribute.
@@ -1317,6 +1402,7 @@ bool DwarfLinker::link(const DebugMap &M
     // Emit all the compile unit's debug information.
     if (!ValidRelocs.empty() && !Options.NoOutput)
       for (auto &CurrentUnit : Units) {
+        CurrentUnit.fixupForwardReferences();
         Streamer->emitCompileUnitHeader(CurrentUnit);
         if (!CurrentUnit.getOutputUnitDIE())
           continue;





More information about the llvm-commits mailing list