[dsymutil] Add debug_str construction support.
authorFrederic Riss <friss@apple.com>
Fri, 6 Mar 2015 17:56:30 +0000 (17:56 +0000)
committerFrederic Riss <friss@apple.com>
Fri, 6 Mar 2015 17:56:30 +0000 (17:56 +0000)
With this comes the ability to correctly clone string attributes in DIEs.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231493 91177308-0d34-0410-b5e6-96231b3b80d8

test/tools/dsymutil/X86/basic-linking-x86.test
test/tools/dsymutil/X86/basic-lto-linking-x86.test
tools/dsymutil/DwarfLinker.cpp

index b45b104c42a44d840826a283464bd783d03939a3..6a9352fb6b6131193961b97a689d67341b9e379b 100644 (file)
@@ -13,29 +13,36 @@ CHECK: debug_info contents
 CHECK:  Compile Unit:
 
 CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]     ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
 CHECK:    DW_AT_language [DW_FORM_data2]       (DW_LANG_C99)
+CHECK:    DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000040] = "basic1.c")
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]     ( .debug_str[0x00000049] = "/Inputs")
 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_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_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_location [DW_FORM_block1]  (<0x02> 91 70 )
 CHECK:      NULL
 CHECK:    DW_TAG_base_type [4]
-CHECK:      DW_AT_name [DW_FORM_strp]  ( .debug_str[0x00000000] = )
+CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000060] = "int")
 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_TAG_pointer_type [5]
 CHECK:    DW_TAG_const_type [6]
 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)
 CHECK:      DW_AT_byte_size [DW_FORM_data1]    (0x01)
 CHECK:    NULL
@@ -43,30 +50,47 @@ CHECK:    NULL
 CHECK:  Compile Unit:
 
 CHECK:  DW_TAG_compile_unit [1] *
+CHECK:   DW_AT_producer [DW_FORM_strp]     ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
+CHECK:   DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000069] = "basic2.c")
+CHECK:   DW_AT_comp_dir [DW_FORM_strp]     ( .debug_str[0x00000049] = "/Inputs")
 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_TAG_variable [7]
+CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000007e] = "baz")
 CHECK:    DW_TAG_subprogram [2] *
+CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000082] = "foo")
 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_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_frame_base [DW_FORM_block1]  (<0x01> 56 )
 CHECK:    NULL
 
 CHECK:  Compile Unit:
 
 CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]     ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
+CHECK:    DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008e] = "basic3.c")
+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_TAG_volatile_type [10]
 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_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_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_frame_base [DW_FORM_block1]  (<0x01> 56 )
 
 CHECK:    NULL
index a56f48cd60f7f0690c4ea690a29de2b7d708dfb4..80da767870eff65e0a59c20fb1803a93dc5dd54d 100644 (file)
@@ -7,25 +7,33 @@ CHECK: debug_info contents
 CHECK:  Compile Unit:
 
 CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]     ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
 CHECK:    DW_AT_language [DW_FORM_data2]       (DW_LANG_C99)
+CHECK:    DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000040] = "basic1.c")
+CHECK:    DW_AT_comp_dir [DW_FORM_strp]     ( .debug_str[0x00000049] = "/Inputs")
 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_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_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_location [DW_FORM_block1]  (<0x01> 54 )
 CHECK:      NULL
-CHECK:    DW_TAG_base_type [4
+CHECK:    DW_TAG_base_type [4]
+CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000060] = "int")
 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_TAG_pointer_type [5]
 CHECK:    DW_TAG_const_type [6]
 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)
 CHECK:      DW_AT_byte_size [DW_FORM_data1]    (0x01)
 CHECK:    NULL
@@ -33,29 +41,44 @@ CHECK:    NULL
 CHECK:  Compile Unit:
 
 CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]     ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
+CHECK:    DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000069] = "basic2.c")
+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_TAG_variable [7]
+CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000007e] = "baz")
 CHECK:    DW_TAG_subprogram [8] *
+CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x00000082] = "foo")
 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_TAG_inlined_subroutine [10]
 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_inline [DW_FORM_data1]       (DW_INL_inlined)
 CHECK:    NULL
 
 CHECK:  Compile Unit:
 
 CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer [DW_FORM_strp]     ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
+CHECK:    DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008e] = "basic3.c")
+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_TAG_volatile_type [13]
 CHECK:    DW_TAG_subprogram [8] *
+CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000009b] = "bar")
 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_TAG_lexical_block [14] *
 CHECK:        DW_TAG_inlined_subroutine [15]
 CHECK:        NULL
 CHECK:      NULL
 CHECK:    DW_TAG_subprogram [11]
+CHECK:      DW_AT_name [DW_FORM_strp]       ( .debug_str[0x0000008a] = "inc")
 CHECK:    NULL
index 628643ce7b362202111260b2e7285187575e5c78..b9b128c8ab81fc53e02ece110661ee9ce761ca82 100644 (file)
@@ -108,6 +108,91 @@ uint64_t CompileUnit::computeOffsets(uint64_t DebugInfoSize) {
   return NextUnitOffset;
 }
 
+/// \brief A string table that doesn't need relocations.
+///
+/// We are doing a final link, no need for a string table that
+/// has relocation entries for every reference to it. This class
+/// provides this ablitity by just associating offsets with
+/// strings.
+class NonRelocatableStringpool {
+public:
+  /// \brief Entries are stored into the StringMap and simply linked
+  /// together through the second element of this pair in order to
+  /// keep track of insertion order.
+  typedef StringMap<std::pair<uint32_t, StringMapEntryBase *>, BumpPtrAllocator>
+      MapTy;
+
+  NonRelocatableStringpool()
+      : CurrentEndOffset(0), Sentinel(0), Last(&Sentinel) {
+    // Legacy dsymutil puts an empty string at the start of the line
+    // table.
+    getStringOffset("");
+  }
+
+  /// \brief Get the offset of string \p S in the string table. This
+  /// can insert a new element or return the offset of a preexisitng
+  /// one.
+  uint32_t getStringOffset(StringRef S);
+
+  /// \brief Get permanent storage for \p S (but do not necessarily
+  /// emit \p S in the output section).
+  /// \returns The StringRef that points to permanent storage to use
+  /// in place of \p S.
+  StringRef internString(StringRef S);
+
+  // \brief Return the first entry of the string table.
+  const MapTy::MapEntryTy *getFirstEntry() const {
+    return getNextEntry(&Sentinel);
+  }
+
+  // \brief Get the entry following \p E in the string table or null
+  // if \p E was the last entry.
+  const MapTy::MapEntryTy *getNextEntry(const MapTy::MapEntryTy *E) const {
+    return static_cast<const MapTy::MapEntryTy *>(E->getValue().second);
+  }
+
+  uint64_t getSize() { return CurrentEndOffset; }
+
+private:
+  MapTy Strings;
+  uint32_t CurrentEndOffset;
+  MapTy::MapEntryTy Sentinel, *Last;
+};
+
+/// \brief Get the offset of string \p S in the string table. This
+/// can insert a new element or return the offset of a preexisitng
+/// one.
+uint32_t NonRelocatableStringpool::getStringOffset(StringRef S) {
+  if (S.empty() && !Strings.empty())
+    return 0;
+
+  std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr);
+  MapTy::iterator It;
+  bool Inserted;
+
+  // A non-empty string can't be at offset 0, so if we have an entry
+  // with a 0 offset, it must be a previously interned string.
+  std::tie(It, Inserted) = Strings.insert(std::make_pair(S, Entry));
+  if (Inserted || It->getValue().first == 0) {
+    // Set offset and chain at the end of the entries list.
+    It->getValue().first = CurrentEndOffset;
+    CurrentEndOffset += S.size() + 1; // +1 for the '\0'.
+    Last->getValue().second = &*It;
+    Last = &*It;
+  }
+  return It->getValue().first;
+};
+
+/// \brief Put \p S into the StringMap so that it gets permanent
+/// storage, but do not actually link it in the chain of elements
+/// that go into the output section. A latter call to
+/// getStringOffset() with the same string will chain it though.
+StringRef NonRelocatableStringpool::internString(StringRef S) {
+  std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr);
+  auto InsertResult = Strings.insert(std::make_pair(S, Entry));
+  return InsertResult.first->getKey();
+};
+
 /// \brief The Dwarf streaming logic
 ///
 /// All interactions with the MC layer that is used to build the debug
@@ -160,6 +245,9 @@ public:
   /// \brief Emit the abbreviation table \p Abbrevs to the
   /// debug_abbrev section.
   void emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs);
+
+  /// \brief Emit the string table described by \p Pool.
+  void emitStrings(const NonRelocatableStringpool &Pool);
 };
 
 bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
@@ -278,6 +366,15 @@ void DwarfStreamer::emitDIE(DIE &Die) {
   Asm->emitDwarfDIE(Die);
 }
 
+/// \brief Emit the debug_str section stored in \p Pool.
+void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
+  Asm->OutStreamer.SwitchSection(MOFI->getDwarfStrSection());
+  for (auto *Entry = Pool.getFirstEntry(); Entry;
+       Entry = Pool.getNextEntry(Entry))
+    Asm->OutStreamer.EmitBytes(
+        StringRef(Entry->getKey().data(), Entry->getKey().size() + 1));
+}
+
 /// \brief The core of the Dwarf linking logic.
 ///
 /// The link of the dwarf information from the object files will be
@@ -417,7 +514,8 @@ private:
                           const AttributeSpec AttrSpec, unsigned AttrSize);
 
   /// \brief Helper for cloneDIE.
-  unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec);
+  unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
+                                const DWARFFormValue &Val, const DWARFUnit &U);
 
   /// \brief Helper for cloneDIE.
   unsigned cloneDieReferenceAttribute(DIE &Die, AttributeSpec AttrSpec,
@@ -478,6 +576,9 @@ private:
 
   /// The debug map object curently under consideration.
   DebugMapObject *CurrentDebugObject;
+
+  /// \brief The Dwarf string pool
+  NonRelocatableStringpool StringPool;
 };
 
 /// \brief Similar to DWARFUnitSection::getUnitForOffset(), but
@@ -944,11 +1045,14 @@ void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) {
 /// \brief Clone a string attribute described by \p AttrSpec and add
 /// it to \p Die.
 /// \returns the size of the new attribute.
-unsigned DwarfLinker::cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec) {
+unsigned DwarfLinker::cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
+                                           const DWARFFormValue &Val,
+                                           const DWARFUnit &U) {
   // Switch everything to out of line strings.
-  // FIXME: Construct the actual string table.
+  const char *String = *Val.getAsCString(&U);
+  unsigned Offset = StringPool.getStringOffset(String);
   Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
-               new (DIEAlloc) DIEInteger(0));
+               new (DIEAlloc) DIEInteger(Offset));
   return 4;
 }
 
@@ -1040,7 +1144,7 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die,
   switch (AttrSpec.Form) {
   case dwarf::DW_FORM_strp:
   case dwarf::DW_FORM_string:
-    return cloneStringAttribute(Die, AttrSpec);
+    return cloneStringAttribute(Die, AttrSpec, Val, U);
   case dwarf::DW_FORM_ref_addr:
   case dwarf::DW_FORM_ref1:
   case dwarf::DW_FORM_ref2:
@@ -1223,8 +1327,10 @@ bool DwarfLinker::link(const DebugMap &Map) {
   }
 
   // Emit everything that's global.
-  if (!Options.NoOutput)
+  if (!Options.NoOutput) {
     Streamer->emitAbbrevs(Abbreviations);
+    Streamer->emitStrings(StringPool);
+  }
 
   return Options.NoOutput ? true : Streamer->finish();
 }