From 98ecf5a7ed8bc31a93769bf3c86de33baca00c3f Mon Sep 17 00:00:00 2001 From: Frederic Riss Date: Fri, 6 Mar 2015 17:56:30 +0000 Subject: [PATCH] [dsymutil] Add debug_str construction support. 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 --- .../tools/dsymutil/X86/basic-linking-x86.test | 26 +++- .../dsymutil/X86/basic-lto-linking-x86.test | 25 +++- tools/dsymutil/DwarfLinker.cpp | 118 +++++++++++++++++- 3 files changed, 161 insertions(+), 8 deletions(-) diff --git a/test/tools/dsymutil/X86/basic-linking-x86.test b/test/tools/dsymutil/X86/basic-linking-x86.test index b45b104c42a..6a9352fb6b6 100644 --- a/test/tools/dsymutil/X86/basic-linking-x86.test +++ b/test/tools/dsymutil/X86/basic-linking-x86.test @@ -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 diff --git a/test/tools/dsymutil/X86/basic-lto-linking-x86.test b/test/tools/dsymutil/X86/basic-lto-linking-x86.test index a56f48cd60f..80da767870e 100644 --- a/test/tools/dsymutil/X86/basic-lto-linking-x86.test +++ b/test/tools/dsymutil/X86/basic-lto-linking-x86.test @@ -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 diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp index 628643ce7b3..b9b128c8ab8 100644 --- a/tools/dsymutil/DwarfLinker.cpp +++ b/tools/dsymutil/DwarfLinker.cpp @@ -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, 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(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 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 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 &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(); } -- 2.34.1