[llvm] 788e6ff - [DWARFLinker][DWARFv5] Add support for .debug_line_str table.

Alexey Lapshin via llvm-commits llvm-commits at lists.llvm.org
Tue May 16 08:00:33 PDT 2023


Author: Alexey Lapshin
Date: 2023-05-16T16:56:14+02:00
New Revision: 788e6ff4e5e6414c6707e91e95829f1d7c76b1aa

URL: https://github.com/llvm/llvm-project/commit/788e6ff4e5e6414c6707e91e95829f1d7c76b1aa
DIFF: https://github.com/llvm/llvm-project/commit/788e6ff4e5e6414c6707e91e95829f1d7c76b1aa.diff

LOG: [DWARFLinker][DWARFv5] Add support for .debug_line_str table.

This patch adds support for DWARFv5 .debug_line_str table.
It replaces code generating line table. Instead of copying original
table and patching certain places this patch implements full line table
generation.

Differential Revision: https://reviews.llvm.org/D150554

Added: 
    llvm/test/tools/dsymutil/Inputs/dwarf5-linetable.o
    llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-line-str.test

Modified: 
    llvm/include/llvm/DWARFLinker/DWARFLinker.h
    llvm/include/llvm/DWARFLinker/DWARFStreamer.h
    llvm/lib/DWARFLinker/DWARFLinker.cpp
    llvm/lib/DWARFLinker/DWARFStreamer.cpp
    llvm/test/tools/dsymutil/X86/dwarf5-linetable.test

Removed: 
    llvm/test/tools/dsymutil/Inputs/dwarf5.o


################################################################################
diff  --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
index a090ea43f1d33..4d519479fab6e 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h
@@ -25,7 +25,6 @@ class DWARFExpression;
 class DWARFUnit;
 class DataExtractor;
 class DeclContextTree;
-struct MCDwarfLineTableParams;
 template <typename T> class SmallVectorImpl;
 
 enum class DwarfLinkerClient { Dsymutil, LLD, General };
@@ -100,9 +99,12 @@ class DwarfEmitter {
   emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs,
               unsigned DwarfVersion) = 0;
 
-  /// Emit the string table described by \p Pool.
+  /// Emit the string table described by \p Pool into .debug_str table.
   virtual void emitStrings(const NonRelocatableStringpool &Pool) = 0;
 
+  /// Emit the string table described by \p Pool into .debug_line_str table.
+  virtual void emitLineStrings(const NonRelocatableStringpool &Pool) = 0;
+
   /// Emit DWARF debug names.
   virtual void
   emitDebugNames(AccelTable<DWARF5AccelTableStaticData> &Table) = 0;
@@ -154,16 +156,11 @@ class DwarfEmitter {
   emitDwarfDebugArangesTable(const CompileUnit &Unit,
                              const AddressRanges &LinkedRanges) = 0;
 
-  /// Copy the .debug_line over to the updated binary while unobfuscating the
-  /// file names and directories.
-  virtual void translateLineTable(DataExtractor LineData, uint64_t Offset) = 0;
-
-  /// Emit the line table described in \p Rows into the .debug_line section.
-  virtual void emitLineTableForUnit(MCDwarfLineTableParams Params,
-                                    StringRef PrologueBytes,
-                                    unsigned MinInstLength,
-                                    std::vector<DWARFDebugLine::Row> &Rows,
-                                    unsigned AdddressSize) = 0;
+  /// Emit specified \p LineTable into .debug_line table.
+  virtual void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable,
+                                    const CompileUnit &Unit,
+                                    OffsetsStringPool &DebugStrPool,
+                                    OffsetsStringPool &DebugLineStrPool) = 0;
 
   /// Emit the .debug_pubnames contribution for \p Unit.
   virtual void emitPubNamesForUnit(const CompileUnit &Unit) = 0;
@@ -559,7 +556,8 @@ class DWARFLinker {
   /// Clone specified Clang module unit \p Unit.
   Error cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
                         DeclContextTree &ODRContexts,
-                        OffsetsStringPool &OffsetsStringPool,
+                        OffsetsStringPool &DebugStrPool,
+                        OffsetsStringPool &DebugLineStrPool,
                         unsigned Indent = 0);
 
   /// Mark the passed DIE as well as all the ones it depends on as kept.
@@ -605,6 +603,8 @@ class DWARFLinker {
     DWARFLinker &Linker;
     DwarfEmitter *Emitter;
     DWARFFile &ObjFile;
+    OffsetsStringPool &DebugStrPool;
+    OffsetsStringPool &DebugLineStrPool;
 
     /// Allocator used for all the DIEValue objects.
     BumpPtrAllocator &DIEAlloc;
@@ -621,8 +621,10 @@ class DWARFLinker {
     DIECloner(DWARFLinker &Linker, DwarfEmitter *Emitter, DWARFFile &ObjFile,
               BumpPtrAllocator &DIEAlloc,
               std::vector<std::unique_ptr<CompileUnit>> &CompileUnits,
-              bool Update)
+              bool Update, OffsetsStringPool &DebugStrPool,
+              OffsetsStringPool &DebugLineStrPool)
         : Linker(Linker), Emitter(Emitter), ObjFile(ObjFile),
+          DebugStrPool(DebugStrPool), DebugLineStrPool(DebugLineStrPool),
           DIEAlloc(DIEAlloc), CompileUnits(CompileUnits), Update(Update) {}
 
     /// Recursively clone \p InputDIE into an tree of DIE objects
@@ -637,17 +639,14 @@ class DWARFLinker {
     /// \param Die the output DIE to use, pass NULL to create one.
     /// \returns the root of the cloned tree or null if nothing was selected.
     DIE *cloneDIE(const DWARFDie &InputDIE, const DWARFFile &File,
-                  CompileUnit &U, OffsetsStringPool &StringPool,
-                  int64_t PCOffset, uint32_t OutOffset, unsigned Flags,
-                  bool IsLittleEndian, DIE *Die = nullptr);
+                  CompileUnit &U, int64_t PCOffset, uint32_t OutOffset,
+                  unsigned Flags, bool IsLittleEndian, DIE *Die = nullptr);
 
     /// Construct the output DIE tree by cloning the DIEs we
     /// chose to keep above. If there are no valid relocs, then there's
     /// nothing to clone/emit.
     uint64_t cloneAllCompileUnits(DWARFContext &DwarfContext,
-                                  const DWARFFile &File,
-                                  OffsetsStringPool &StringPool,
-                                  bool IsLittleEndian);
+                                  const DWARFFile &File, bool IsLittleEndian);
 
   private:
     using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec;
@@ -680,7 +679,6 @@ class DWARFLinker {
     /// Helper for cloneDIE.
     unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE,
                             const DWARFFile &File, CompileUnit &U,
-                            OffsetsStringPool &StringPool,
                             const DWARFFormValue &Val,
                             const AttributeSpec AttrSpec, unsigned AttrSize,
                             AttributesInfo &AttrInfo, bool IsLittleEndian);
@@ -690,7 +688,6 @@ class DWARFLinker {
     /// \returns the size of the new attribute.
     unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
                                   const DWARFFormValue &Val, const DWARFUnit &U,
-                                  OffsetsStringPool &StringPool,
                                   AttributesInfo &Info);
 
     /// Clone an attribute referencing another DIE and add
@@ -750,6 +747,11 @@ class DWARFLinker {
                             OffsetsStringPool &StringPool, bool SkipPubSection);
 
     void rememberUnitForMacroOffset(CompileUnit &Unit);
+
+    /// Clone and emit the line table for the specified \p Unit.
+    /// Translate directories and file names if necessary.
+    /// Relocate address ranges.
+    void generateLineTableForUnit(CompileUnit &Unit);
   };
 
   /// Assign an abbreviation number to \p Abbrev
@@ -767,12 +769,6 @@ class DWARFLinker {
   void generateUnitLocations(CompileUnit &Unit, const DWARFFile &File,
                              ExpressionHandlerRef ExprHandler) const;
 
-  /// Extract the line tables from the original dwarf, extract the relevant
-  /// parts according to the linked function ranges and emit the result in the
-  /// .debug_line section.
-  void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf,
-                             const DWARFFile &File);
-
   /// Emit the accelerator entries for \p Unit.
   void emitAcceleratorEntriesForUnit(CompileUnit &Unit);
 

diff  --git a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
index c96dd4007c23f..f7dbdd2196a61 100644
--- a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
+++ b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h
@@ -82,9 +82,12 @@ class DwarfStreamer : public DwarfEmitter {
   /// Emit contents of section SecName From Obj.
   void emitSectionContents(StringRef SecData, StringRef SecName) override;
 
-  /// Emit the string table described by \p Pool.
+  /// Emit the string table described by \p Pool into .debug_str table.
   void emitStrings(const NonRelocatableStringpool &Pool) override;
 
+  /// Emit the string table described by \p Pool into .debug_line_str table.
+  void emitLineStrings(const NonRelocatableStringpool &Pool) override;
+
   /// Emit the swift_ast section stored in \p Buffer.
   void emitSwiftAST(StringRef Buffer);
 
@@ -128,15 +131,11 @@ class DwarfStreamer : public DwarfEmitter {
     return RngListsSectionSize;
   }
 
-  /// Emit the line table described in \p Rows into the debug_line section.
-  void emitLineTableForUnit(MCDwarfLineTableParams Params,
-                            StringRef PrologueBytes, unsigned MinInstLength,
-                            std::vector<DWARFDebugLine::Row> &Rows,
-                            unsigned AdddressSize) override;
-
-  /// Copy the debug_line over to the updated binary while unobfuscating the
-  /// file names and directories.
-  void translateLineTable(DataExtractor LineData, uint64_t Offset) override;
+  /// Emit .debug_line table entry for specified \p LineTable
+  void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable,
+                            const CompileUnit &Unit,
+                            OffsetsStringPool &DebugStrPool,
+                            OffsetsStringPool &DebugLineStrPool) override;
 
   uint64_t getLineSectionSize() const override { return LineSectionSize; }
 
@@ -231,6 +230,32 @@ class DwarfStreamer : public DwarfEmitter {
       const DWARFLocationExpressionsVector &LinkedLocationExpression,
       PatchLocation Patch);
 
+  /// \defgroup Line table emission
+  /// @{
+  void emitLineTablePrologue(const DWARFDebugLine::Prologue &P,
+                             OffsetsStringPool &DebugStrPool,
+                             OffsetsStringPool &DebugLineStrPool);
+  void emitLineTableString(const DWARFDebugLine::Prologue &P,
+                           const DWARFFormValue &String,
+                           OffsetsStringPool &DebugStrPool,
+                           OffsetsStringPool &DebugLineStrPool);
+  void emitLineTableProloguePayload(const DWARFDebugLine::Prologue &P,
+                                    OffsetsStringPool &DebugStrPool,
+                                    OffsetsStringPool &DebugLineStrPool);
+  void emitLineTablePrologueV2IncludeAndFileTable(
+      const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+      OffsetsStringPool &DebugLineStrPool);
+  void emitLineTablePrologueV5IncludeAndFileTable(
+      const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+      OffsetsStringPool &DebugLineStrPool);
+  void emitLineTableRows(const DWARFDebugLine::LineTable &LineTable,
+                         MCSymbol *LineEndSym, unsigned AddressByteSize);
+  void emitIntOffset(uint64_t Offset, dwarf::DwarfFormat Format,
+                     uint64_t &SectionSize);
+  void emitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo,
+                           dwarf::DwarfFormat Format, uint64_t &SectionSize);
+  /// @}
+
   /// \defgroup MCObjects MC layer objects constructed by the streamer
   /// @{
   std::unique_ptr<MCRegisterInfo> MRI;

diff  --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp
index 3c6495a12a9bb..3307f5384158f 100644
--- a/llvm/lib/DWARFLinker/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp
@@ -948,24 +948,33 @@ void DWARFLinker::assignAbbrev(DIEAbbrev &Abbrev) {
   }
 }
 
-unsigned DWARFLinker::DIECloner::cloneStringAttribute(
-    DIE &Die, AttributeSpec AttrSpec, const DWARFFormValue &Val,
-    const DWARFUnit &, OffsetsStringPool &StringPool, AttributesInfo &Info) {
+unsigned DWARFLinker::DIECloner::cloneStringAttribute(DIE &Die,
+                                                      AttributeSpec AttrSpec,
+                                                      const DWARFFormValue &Val,
+                                                      const DWARFUnit &,
+                                                      AttributesInfo &Info) {
   std::optional<const char *> String = dwarf::toString(Val);
   if (!String)
     return 0;
 
-  // Switch everything to out of line strings.
-  auto StringEntry = StringPool.getEntry(*String);
+  DwarfStringPoolEntryRef StringEntry;
+  if (AttrSpec.Form == dwarf::DW_FORM_line_strp) {
+    StringEntry = DebugLineStrPool.getEntry(*String);
+  } else {
+    StringEntry = DebugStrPool.getEntry(*String);
+
+    // Update attributes info.
+    if (AttrSpec.Attr == dwarf::DW_AT_name)
+      Info.Name = StringEntry;
+    else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||
+             AttrSpec.Attr == dwarf::DW_AT_linkage_name)
+      Info.MangledName = StringEntry;
 
-  // Update attributes info.
-  if (AttrSpec.Attr == dwarf::DW_AT_name)
-    Info.Name = StringEntry;
-  else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||
-           AttrSpec.Attr == dwarf::DW_AT_linkage_name)
-    Info.MangledName = StringEntry;
+    // Switch everything to out of line strings.
+    AttrSpec.Form = dwarf::DW_FORM_strp;
+  }
 
-  Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
+  Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), AttrSpec.Form,
                DIEInteger(StringEntry.getOffset()));
 
   return 4;
@@ -1373,20 +1382,20 @@ unsigned DWARFLinker::DIECloner::cloneScalarAttribute(
 /// \returns the size of the cloned attribute.
 unsigned DWARFLinker::DIECloner::cloneAttribute(
     DIE &Die, const DWARFDie &InputDIE, const DWARFFile &File,
-    CompileUnit &Unit, OffsetsStringPool &StringPool, const DWARFFormValue &Val,
-    const AttributeSpec AttrSpec, unsigned AttrSize, AttributesInfo &Info,
-    bool IsLittleEndian) {
+    CompileUnit &Unit, const DWARFFormValue &Val, const AttributeSpec AttrSpec,
+    unsigned AttrSize, AttributesInfo &Info, bool IsLittleEndian) {
   const DWARFUnit &U = Unit.getOrigUnit();
 
   switch (AttrSpec.Form) {
   case dwarf::DW_FORM_strp:
+  case dwarf::DW_FORM_line_strp:
   case dwarf::DW_FORM_string:
   case dwarf::DW_FORM_strx:
   case dwarf::DW_FORM_strx1:
   case dwarf::DW_FORM_strx2:
   case dwarf::DW_FORM_strx3:
   case dwarf::DW_FORM_strx4:
-    return cloneStringAttribute(Die, AttrSpec, Val, U, StringPool, Info);
+    return cloneStringAttribute(Die, AttrSpec, Val, U, Info);
   case dwarf::DW_FORM_ref_addr:
   case dwarf::DW_FORM_ref1:
   case dwarf::DW_FORM_ref2:
@@ -1524,7 +1533,6 @@ static bool shouldSkipAttribute(
 
 DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
                                       const DWARFFile &File, CompileUnit &Unit,
-                                      OffsetsStringPool &StringPool,
                                       int64_t PCOffset, uint32_t OutOffset,
                                       unsigned Flags, bool IsLittleEndian,
                                       DIE *Die) {
@@ -1614,8 +1622,8 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
     Val.extractValue(Data, &Offset, U.getFormParams(), &U);
     AttrSize = Offset - AttrSize;
 
-    OutOffset += cloneAttribute(*Die, InputDIE, File, Unit, StringPool, Val,
-                                AttrSpec, AttrSize, AttrInfo, IsLittleEndian);
+    OutOffset += cloneAttribute(*Die, InputDIE, File, Unit, Val, AttrSpec,
+                                AttrSize, AttrInfo, IsLittleEndian);
   }
 
   // Look for accelerator entries.
@@ -1625,7 +1633,7 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
   // accelerator tables too. For now stick with dsymutil's behavior.
   if ((Info.InDebugMap || AttrInfo.HasLowPc || AttrInfo.HasRanges) &&
       Tag != dwarf::DW_TAG_compile_unit &&
-      getDIENames(InputDIE, AttrInfo, StringPool,
+      getDIENames(InputDIE, AttrInfo, DebugStrPool,
                   Tag != dwarf::DW_TAG_inlined_subroutine)) {
     if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
       Unit.addNameAccelerator(Die, AttrInfo.MangledName,
@@ -1638,17 +1646,17 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
                               Tag == dwarf::DW_TAG_inlined_subroutine);
     }
     if (AttrInfo.Name && isObjCSelector(AttrInfo.Name.getString()))
-      addObjCAccelerator(Unit, Die, AttrInfo.Name, StringPool,
+      addObjCAccelerator(Unit, Die, AttrInfo.Name, DebugStrPool,
                          /* SkipPubSection =*/true);
 
   } else if (Tag == dwarf::DW_TAG_namespace) {
     if (!AttrInfo.Name)
-      AttrInfo.Name = StringPool.getEntry("(anonymous namespace)");
+      AttrInfo.Name = DebugStrPool.getEntry("(anonymous namespace)");
     Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
   } else if (Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {
     Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
   } else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration &&
-             getDIENames(InputDIE, AttrInfo, StringPool) && AttrInfo.Name &&
+             getDIENames(InputDIE, AttrInfo, DebugStrPool) && AttrInfo.Name &&
              AttrInfo.Name.getString()[0]) {
     uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit, File);
     uint64_t RuntimeLang =
@@ -1691,8 +1699,8 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
 
   // Recursively clone children.
   for (auto Child : InputDIE.children()) {
-    if (DIE *Clone = cloneDIE(Child, File, Unit, StringPool, PCOffset,
-                              OutOffset, Flags, IsLittleEndian)) {
+    if (DIE *Clone = cloneDIE(Child, File, Unit, PCOffset, OutOffset, Flags,
+                              IsLittleEndian)) {
       Die->addChild(Clone);
       OutOffset = Clone->getOffset() + Clone->getSize();
     }
@@ -1850,7 +1858,7 @@ static void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
 
   // FIXME: this only removes the unneeded end_sequence if the
   // sequences have been inserted in order. Using a global sort like
-  // described in patchLineTableForUnit() and delaying the end_sequene
+  // described in generateLineTableForUnit() and delaying the end_sequene
   // elimination to emitLineTableForUnit() we can get rid of all of them.
   if (InsertPoint != Rows.end() && InsertPoint->Address == Front &&
       InsertPoint->EndSequence) {
@@ -1873,142 +1881,6 @@ static void patchStmtList(DIE &Die, DIEInteger Offset) {
   llvm_unreachable("Didn't find DW_AT_stmt_list in cloned DIE!");
 }
 
-/// Extract the line table for \p Unit from \p OrigDwarf, and
-/// recreate a relocated version of these for the address ranges that
-/// are present in the binary.
-void DWARFLinker::patchLineTableForUnit(CompileUnit &Unit,
-                                        DWARFContext &OrigDwarf,
-                                        const DWARFFile &File) {
-  DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
-  auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list));
-  if (!StmtList)
-    return;
-
-  // Update the cloned DW_AT_stmt_list with the correct debug_line offset.
-  if (auto *OutputDIE = Unit.getOutputUnitDIE())
-    patchStmtList(*OutputDIE,
-                  DIEInteger(TheDwarfEmitter->getLineSectionSize()));
-
-  RangesTy &Ranges = File.Addresses->getValidAddressRanges();
-
-  // Parse the original line info for the unit.
-  DWARFDebugLine::LineTable LineTable;
-  uint64_t StmtOffset = *StmtList;
-  DWARFDataExtractor LineExtractor(
-      OrigDwarf.getDWARFObj(), OrigDwarf.getDWARFObj().getLineSection(),
-      OrigDwarf.isLittleEndian(), Unit.getOrigUnit().getAddressByteSize());
-  if (needToTranslateStrings())
-    return TheDwarfEmitter->translateLineTable(LineExtractor, StmtOffset);
-
-  if (Error Err =
-          LineTable.parse(LineExtractor, &StmtOffset, OrigDwarf,
-                          &Unit.getOrigUnit(), OrigDwarf.getWarningHandler()))
-    OrigDwarf.getWarningHandler()(std::move(Err));
-
-  // This vector is the output line table.
-  std::vector<DWARFDebugLine::Row> NewRows;
-  NewRows.reserve(LineTable.Rows.size());
-
-  // Current sequence of rows being extracted, before being inserted
-  // in NewRows.
-  std::vector<DWARFDebugLine::Row> Seq;
-  const auto &FunctionRanges = Unit.getFunctionRanges();
-  std::optional<AddressRangeValuePair> CurrRange;
-
-  // FIXME: This logic is meant to generate exactly the same output as
-  // Darwin's classic dsymutil. There is a nicer way to implement this
-  // by simply putting all the relocated line info in NewRows and simply
-  // sorting NewRows before passing it to emitLineTableForUnit. This
-  // should be correct as sequences for a function should stay
-  // together in the sorted output. There are a few corner cases that
-  // look suspicious though, and that required to implement the logic
-  // this way. Revisit that once initial validation is finished.
-
-  // Iterate over the object file line info and extract the sequences
-  // that correspond to linked functions.
-  for (auto &Row : LineTable.Rows) {
-    // Check whether we stepped out of the range. The range is
-    // half-open, but consider accept the end address of the range if
-    // it is marked as end_sequence in the input (because in that
-    // case, the relocation offset is accurate and that entry won't
-    // serve as the start of another function).
-    if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address) ||
-        (Row.Address.Address == CurrRange->Range.end() && !Row.EndSequence)) {
-      // We just stepped out of a known range. Insert a end_sequence
-      // corresponding to the end of the range.
-      uint64_t StopAddress =
-          CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
-      CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
-      if (!CurrRange) {
-        if (StopAddress != -1ULL) {
-          // Try harder by looking in the Address ranges map.
-          // There are corner cases where this finds a
-          // valid entry. It's unclear if this is right or wrong, but
-          // for now do as dsymutil.
-          // FIXME: Understand exactly what cases this addresses and
-          // potentially remove it along with the Ranges map.
-          if (std::optional<AddressRangeValuePair> Range =
-                  Ranges.getRangeThatContains(Row.Address.Address))
-            StopAddress = Row.Address.Address + (*Range).Value;
-        }
-      }
-      if (StopAddress != -1ULL && !Seq.empty()) {
-        // Insert end sequence row with the computed end address, but
-        // the same line as the previous one.
-        auto NextLine = Seq.back();
-        NextLine.Address.Address = StopAddress;
-        NextLine.EndSequence = 1;
-        NextLine.PrologueEnd = 0;
-        NextLine.BasicBlock = 0;
-        NextLine.EpilogueBegin = 0;
-        Seq.push_back(NextLine);
-        insertLineSequence(Seq, NewRows);
-      }
-
-      if (!CurrRange)
-        continue;
-    }
-
-    // Ignore empty sequences.
-    if (Row.EndSequence && Seq.empty())
-      continue;
-
-    // Relocate row address and add it to the current sequence.
-    Row.Address.Address += CurrRange->Value;
-    Seq.emplace_back(Row);
-
-    if (Row.EndSequence)
-      insertLineSequence(Seq, NewRows);
-  }
-
-  // Finished extracting, now emit the line tables.
-  // FIXME: LLVM hard-codes its prologue values. We just copy the
-  // prologue over and that works because we act as both producer and
-  // consumer. It would be nicer to have a real configurable line
-  // table emitter.
-  if (LineTable.Prologue.getVersion() < 2 ||
-      LineTable.Prologue.getVersion() > 5 ||
-      LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT ||
-      LineTable.Prologue.OpcodeBase > 13)
-    reportWarning("line table parameters mismatch. Cannot emit.", File);
-  else {
-    uint32_t PrologueEnd = *StmtList + 10 + LineTable.Prologue.PrologueLength;
-    // DWARF v5 has an extra 2 bytes of information before the header_length
-    // field.
-    if (LineTable.Prologue.getVersion() == 5)
-      PrologueEnd += 2;
-    StringRef LineData = OrigDwarf.getDWARFObj().getLineSection().Data;
-    MCDwarfLineTableParams Params;
-    Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
-    Params.DWARF2LineBase = LineTable.Prologue.LineBase;
-    Params.DWARF2LineRange = LineTable.Prologue.LineRange;
-    TheDwarfEmitter->emitLineTableForUnit(
-        Params, LineData.slice(*StmtList + 4, PrologueEnd),
-        LineTable.Prologue.MinInstLength, NewRows,
-        Unit.getOrigUnit().getAddressByteSize());
-  }
-}
-
 void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
   DWARFUnit &OrigUnit = Unit.getOrigUnit();
   DWARFDie OrigUnitDie = OrigUnit.getUnitDIE();
@@ -2026,6 +1898,123 @@ void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
   }
 }
 
+void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
+  if (LLVM_UNLIKELY(Linker.Options.NoOutput))
+    return;
+
+  // Check whether DW_AT_stmt_list attribute is presented.
+  DWARFDie CUDie = Unit.getOrigUnit().getUnitDIE();
+  auto StmtList = dwarf::toSectionOffset(CUDie.find(dwarf::DW_AT_stmt_list));
+  if (!StmtList)
+    return;
+
+  // Update the cloned DW_AT_stmt_list with the correct debug_line offset.
+  if (auto *OutputDIE = Unit.getOutputUnitDIE())
+    patchStmtList(*OutputDIE, DIEInteger(Emitter->getLineSectionSize()));
+
+  if (const DWARFDebugLine::LineTable *LT =
+          ObjFile.Dwarf->getLineTableForUnit(&Unit.getOrigUnit())) {
+
+    DWARFDebugLine::LineTable LineTable;
+
+    // Set Line Table header.
+    LineTable.Prologue = LT->Prologue;
+
+    // Set Line Table Rows.
+    if (Linker.Options.Update) {
+      LineTable.Rows = LT->Rows;
+
+      LineTable.Sequences = LT->Sequences;
+    } else {
+      RangesTy &Ranges = ObjFile.Addresses->getValidAddressRanges();
+
+      // This vector is the output line table.
+      std::vector<DWARFDebugLine::Row> NewRows;
+      NewRows.reserve(LT->Rows.size());
+
+      // Current sequence of rows being extracted, before being inserted
+      // in NewRows.
+      std::vector<DWARFDebugLine::Row> Seq;
+
+      const auto &FunctionRanges = Unit.getFunctionRanges();
+      std::optional<AddressRangeValuePair> CurrRange;
+
+      // FIXME: This logic is meant to generate exactly the same output as
+      // Darwin's classic dsymutil. There is a nicer way to implement this
+      // by simply putting all the relocated line info in NewRows and simply
+      // sorting NewRows before passing it to emitLineTableForUnit. This
+      // should be correct as sequences for a function should stay
+      // together in the sorted output. There are a few corner cases that
+      // look suspicious though, and that required to implement the logic
+      // this way. Revisit that once initial validation is finished.
+
+      // Iterate over the object file line info and extract the sequences
+      // that correspond to linked functions.
+      for (DWARFDebugLine::Row Row : LT->Rows) {
+        // Check whether we stepped out of the range. The range is
+        // half-open, but consider accept the end address of the range if
+        // it is marked as end_sequence in the input (because in that
+        // case, the relocation offset is accurate and that entry won't
+        // serve as the start of another function).
+        if (!CurrRange || !CurrRange->Range.contains(Row.Address.Address) ||
+            (Row.Address.Address == CurrRange->Range.end() &&
+             !Row.EndSequence)) {
+          // We just stepped out of a known range. Insert a end_sequence
+          // corresponding to the end of the range.
+          uint64_t StopAddress =
+              CurrRange ? CurrRange->Range.end() + CurrRange->Value : -1ULL;
+          CurrRange = FunctionRanges.getRangeThatContains(Row.Address.Address);
+          if (!CurrRange) {
+            if (StopAddress != -1ULL) {
+              // Try harder by looking in the Address ranges map.
+              // There are corner cases where this finds a
+              // valid entry. It's unclear if this is right or wrong, but
+              // for now do as dsymutil.
+              // FIXME: Understand exactly what cases this addresses and
+              // potentially remove it along with the Ranges map.
+              if (std::optional<AddressRangeValuePair> Range =
+                      Ranges.getRangeThatContains(Row.Address.Address))
+                StopAddress = Row.Address.Address + (*Range).Value;
+            }
+          }
+          if (StopAddress != -1ULL && !Seq.empty()) {
+            // Insert end sequence row with the computed end address, but
+            // the same line as the previous one.
+            auto NextLine = Seq.back();
+            NextLine.Address.Address = StopAddress;
+            NextLine.EndSequence = 1;
+            NextLine.PrologueEnd = 0;
+            NextLine.BasicBlock = 0;
+            NextLine.EpilogueBegin = 0;
+            Seq.push_back(NextLine);
+            insertLineSequence(Seq, NewRows);
+          }
+
+          if (!CurrRange)
+            continue;
+        }
+
+        // Ignore empty sequences.
+        if (Row.EndSequence && Seq.empty())
+          continue;
+
+        // Relocate row address and add it to the current sequence.
+        Row.Address.Address += CurrRange->Value;
+        Seq.emplace_back(Row);
+
+        if (Row.EndSequence)
+          insertLineSequence(Seq, NewRows);
+      }
+
+      LineTable.Rows = std::move(NewRows);
+    }
+
+    Emitter->emitLineTableForUnit(LineTable, Unit, DebugStrPool,
+                                  DebugLineStrPool);
+  } else
+    Linker.reportWarning("Cann't load line table.", ObjFile);
+}
+
 void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
   for (DwarfLinkerAccelTableKind AccelTableKind : Options.AccelTables) {
     switch (AccelTableKind) {
@@ -2372,8 +2361,7 @@ Error DWARFLinker::loadClangModule(objFileLoader Loader, const DWARFDie &CUDie,
 }
 
 uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
-    DWARFContext &DwarfContext, const DWARFFile &File,
-    OffsetsStringPool &StringPool, bool IsLittleEndian) {
+    DWARFContext &DwarfContext, const DWARFFile &File, bool IsLittleEndian) {
   uint64_t OutputDebugInfoSize =
       Linker.Options.NoOutput ? 0 : Emitter->getDebugInfoSectionSize();
   const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
@@ -2392,9 +2380,8 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
       // already has a DIE inside of it.
       CurrentUnit->createOutputDIE();
       rememberUnitForMacroOffset(*CurrentUnit);
-      cloneDIE(InputDIE, File, *CurrentUnit, StringPool, 0 /* PC offset */,
-               UnitHeaderSize, 0, IsLittleEndian,
-               CurrentUnit->getOutputUnitDIE());
+      cloneDIE(InputDIE, File, *CurrentUnit, 0 /* PC offset */, UnitHeaderSize,
+               0, IsLittleEndian, CurrentUnit->getOutputUnitDIE());
     }
 
     OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
@@ -2402,9 +2389,7 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
     if (!Linker.Options.NoOutput) {
       assert(Emitter);
 
-      if (LLVM_LIKELY(!Linker.Options.Update) ||
-          Linker.needToTranslateStrings())
-        Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext, File);
+      generateLineTableForUnit(*CurrentUnit);
 
       Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
 
@@ -2430,7 +2415,7 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
   if (!Linker.Options.NoOutput) {
     assert(Emitter);
     // Emit macro tables.
-    Emitter->emitMacroTables(File.Dwarf, UnitMacroMap, StringPool);
+    Emitter->emitMacroTables(File.Dwarf, UnitMacroMap, DebugStrPool);
 
     // Emit all the compile unit's debug information.
     for (auto &CurrentUnit : CompileUnits) {
@@ -2517,9 +2502,6 @@ bool DWARFLinker::emitPaperTrailWarnings(const DWARFFile &File,
 }
 
 void DWARFLinker::copyInvariantDebugSection(DWARFContext &Dwarf) {
-  if (!needToTranslateStrings())
-    TheDwarfEmitter->emitSectionContents(
-        Dwarf.getDWARFObj().getLineSection().Data, "debug_line");
   TheDwarfEmitter->emitSectionContents(Dwarf.getDWARFObj().getLocSection().Data,
                                        "debug_loc");
   TheDwarfEmitter->emitSectionContents(
@@ -2569,7 +2551,8 @@ Error DWARFLinker::link() {
   // This Dwarf string pool which is used for emission. It must be used
   // serially as the order of calling getStringOffset matters for
   // reproducibility.
-  OffsetsStringPool OffsetsStringPool(StringsTranslator, true);
+  OffsetsStringPool DebugStrPool(StringsTranslator, true);
+  OffsetsStringPool DebugLineStrPool(StringsTranslator, false);
 
   // ODR Contexts for the optimize.
   DeclContextTree ODRContexts;
@@ -2582,7 +2565,7 @@ Error DWARFLinker::link() {
         outs() << "OBJECT FILE: " << OptContext.File.FileName << "\n";
     }
 
-    if (emitPaperTrailWarnings(OptContext.File, OffsetsStringPool))
+    if (emitPaperTrailWarnings(OptContext.File, DebugStrPool))
       continue;
 
     if (!OptContext.File.Dwarf)
@@ -2635,8 +2618,8 @@ Error DWARFLinker::link() {
     }
 
     for (auto &CU : OptContext.ModuleUnits) {
-      if (Error Err =
-              cloneModuleUnit(OptContext, CU, ODRContexts, OffsetsStringPool))
+      if (Error Err = cloneModuleUnit(OptContext, CU, ODRContexts, DebugStrPool,
+                                      DebugLineStrPool))
         reportWarning(toString(std::move(Err)), CU.File);
     }
   }
@@ -2733,9 +2716,9 @@ Error DWARFLinker::link() {
           getDebugInfoSize(*OptContext.File.Dwarf);
       SizeByObject[OptContext.File.FileName].Output =
           DIECloner(*this, TheDwarfEmitter, OptContext.File, DIEAlloc,
-                    OptContext.CompileUnits, Options.Update)
+                    OptContext.CompileUnits, Options.Update, DebugStrPool,
+                    DebugLineStrPool)
               .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
-                                    OffsetsStringPool,
                                     OptContext.File.Dwarf->isLittleEndian());
     }
     if (!Options.NoOutput && !OptContext.CompileUnits.empty() &&
@@ -2753,7 +2736,8 @@ Error DWARFLinker::link() {
     // Emit everything that's global.
     if (!Options.NoOutput) {
       TheDwarfEmitter->emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
-      TheDwarfEmitter->emitStrings(OffsetsStringPool);
+      TheDwarfEmitter->emitStrings(DebugStrPool);
+      TheDwarfEmitter->emitLineStrings(DebugLineStrPool);
       for (DwarfLinkerAccelTableKind TableKind : Options.AccelTables) {
         switch (TableKind) {
         case DwarfLinkerAccelTableKind::Apple:
@@ -2867,7 +2851,8 @@ Error DWARFLinker::link() {
 
 Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
                                    DeclContextTree &ODRContexts,
-                                   OffsetsStringPool &OffsetsStringPool,
+                                   OffsetsStringPool &DebugStrPool,
+                                   OffsetsStringPool &DebugLineStrPool,
                                    unsigned Indent) {
   assert(Unit.Unit.get() != nullptr);
 
@@ -2894,8 +2879,8 @@ Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
   CompileUnits.emplace_back(std::move(Unit.Unit));
   assert(TheDwarfEmitter);
   DIECloner(*this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,
-            Options.Update)
-      .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File, OffsetsStringPool,
+            Options.Update, DebugStrPool, DebugLineStrPool)
+      .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
                             Unit.File.Dwarf->isLittleEndian());
   return Error::success();
 }

diff  --git a/llvm/lib/DWARFLinker/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
index 249f145c41644..ebc765ed2b9fd 100644
--- a/llvm/lib/DWARFLinker/DWARFStreamer.cpp
+++ b/llvm/lib/DWARFLinker/DWARFStreamer.cpp
@@ -240,16 +240,18 @@ void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
     // Emit a null terminator.
     Asm->emitInt8(0);
   }
+}
 
-#if 0
-  if (DwarfVersion >= 5) {
-    // Emit an empty string offset section.
-    Asm->OutStreamer->switchSection(MOFI->getDwarfStrOffSection());
-    Asm->emitDwarfUnitLength(4, "Length of String Offsets Set");
-    Asm->emitInt16(DwarfVersion);
-    Asm->emitInt16(0);
+/// Emit the debug_line_str section stored in \p Pool.
+void DwarfStreamer::emitLineStrings(const NonRelocatableStringpool &Pool) {
+  Asm->OutStreamer->switchSection(MOFI->getDwarfLineStrSection());
+  std::vector<DwarfStringPoolEntryRef> Entries = Pool.getEntriesForEmission();
+  for (auto Entry : Entries) {
+    // Emit the string itself.
+    Asm->OutStreamer->emitBytes(Entry.getString());
+    // Emit a null terminator.
+    Asm->emitInt8(0);
   }
-#endif
 }
 
 void DwarfStreamer::emitDebugNames(
@@ -631,27 +633,225 @@ void DwarfStreamer::emitDwarfDebugLocListsTableFragment(
   LocListsSectionSize += 1;
 }
 
-void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
-                                         StringRef PrologueBytes,
-                                         unsigned MinInstLength,
-                                         std::vector<DWARFDebugLine::Row> &Rows,
-                                         unsigned PointerSize) {
+void DwarfStreamer::emitLineTableForUnit(
+    const DWARFDebugLine::LineTable &LineTable, const CompileUnit &Unit,
+    OffsetsStringPool &DebugStrPool, OffsetsStringPool &DebugLineStrPool) {
   // Switch to the section where the table will be emitted into.
   MS->switchSection(MC->getObjectFileInfo()->getDwarfLineSection());
+
   MCSymbol *LineStartSym = MC->createTempSymbol();
   MCSymbol *LineEndSym = MC->createTempSymbol();
 
-  // The first 4 bytes is the total length of the information for this
-  // compilation unit (not including these 4 bytes for the length).
-  Asm->emitLabelDifference(LineEndSym, LineStartSym, 4);
+  // unit_length.
+  if (LineTable.Prologue.FormParams.Format == dwarf::DwarfFormat::DWARF64) {
+    MS->emitInt32(dwarf::DW_LENGTH_DWARF64);
+    LineSectionSize += 4;
+  }
+  emitLabelDifference(LineEndSym, LineStartSym,
+                      LineTable.Prologue.FormParams.Format, LineSectionSize);
   Asm->OutStreamer->emitLabel(LineStartSym);
-  // Copy Prologue.
-  MS->emitBytes(PrologueBytes);
-  LineSectionSize += PrologueBytes.size() + 4;
+
+  // Emit prologue.
+  emitLineTablePrologue(LineTable.Prologue, DebugStrPool, DebugLineStrPool);
+
+  // Emit rows.
+  emitLineTableRows(LineTable, LineEndSym,
+                    Unit.getOrigUnit().getAddressByteSize());
+}
+
+void DwarfStreamer::emitLineTablePrologue(const DWARFDebugLine::Prologue &P,
+                                          OffsetsStringPool &DebugStrPool,
+                                          OffsetsStringPool &DebugLineStrPool) {
+  MCSymbol *PrologueStartSym = MC->createTempSymbol();
+  MCSymbol *PrologueEndSym = MC->createTempSymbol();
+
+  // version (uhalf).
+  MS->emitInt16(P.getVersion());
+  LineSectionSize += 2;
+  if (P.getVersion() == 5) {
+    // address_size (ubyte).
+    MS->emitInt8(P.getAddressSize());
+    LineSectionSize += 1;
+
+    // segment_selector_size (ubyte).
+    MS->emitInt8(P.SegSelectorSize);
+    LineSectionSize += 1;
+  }
+
+  // header_length.
+  emitLabelDifference(PrologueEndSym, PrologueStartSym, P.FormParams.Format,
+                      LineSectionSize);
+
+  Asm->OutStreamer->emitLabel(PrologueStartSym);
+  emitLineTableProloguePayload(P, DebugStrPool, DebugLineStrPool);
+  Asm->OutStreamer->emitLabel(PrologueEndSym);
+}
+
+void DwarfStreamer::emitLineTablePrologueV2IncludeAndFileTable(
+    const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+    OffsetsStringPool &DebugLineStrPool) {
+  // include_directories (sequence of path names).
+  for (const DWARFFormValue &Include : P.IncludeDirectories)
+    emitLineTableString(P, Include, DebugStrPool, DebugLineStrPool);
+  // The last entry is followed by a single null byte.
+  MS->emitInt8(0);
+  LineSectionSize += 1;
+
+  // file_names (sequence of file entries).
+  for (const DWARFDebugLine::FileNameEntry &File : P.FileNames) {
+    // A null-terminated string containing the full or relative path name of a
+    // source file.
+    emitLineTableString(P, File.Name, DebugStrPool, DebugLineStrPool);
+    // An unsigned LEB128 number representing the directory index of a directory
+    // in the include_directories section.
+    LineSectionSize += MS->emitULEB128IntValue(File.DirIdx);
+    // An unsigned LEB128 number representing the (implementation-defined) time
+    // of last modification for the file, or 0 if not available.
+    LineSectionSize += MS->emitULEB128IntValue(File.ModTime);
+    // An unsigned LEB128 number representing the length in bytes of the file,
+    // or 0 if not available.
+    LineSectionSize += MS->emitULEB128IntValue(File.Length);
+  }
+  // The last entry is followed by a single null byte.
+  MS->emitInt8(0);
+  LineSectionSize += 1;
+}
+
+void DwarfStreamer::emitLineTablePrologueV5IncludeAndFileTable(
+    const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+    OffsetsStringPool &DebugLineStrPool) {
+  if (P.IncludeDirectories.empty()) {
+    // directory_entry_format_count(ubyte).
+    MS->emitInt8(0);
+    LineSectionSize += 1;
+  } else {
+    // directory_entry_format_count(ubyte).
+    MS->emitInt8(1);
+    LineSectionSize += 1;
+
+    // directory_entry_format (sequence of ULEB128 pairs).
+    LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_path);
+    LineSectionSize +=
+        MS->emitULEB128IntValue(P.IncludeDirectories[0].getForm());
+  }
+
+  // directories_count (ULEB128).
+  LineSectionSize += MS->emitULEB128IntValue(P.IncludeDirectories.size());
+  // directories (sequence of directory names).
+  for (auto Include : P.IncludeDirectories)
+    emitLineTableString(P, Include, DebugStrPool, DebugLineStrPool);
+
+  if (P.FileNames.empty()) {
+    // file_name_entry_format_count (ubyte).
+    MS->emitInt8(0);
+    LineSectionSize += 1;
+  } else {
+    // file_name_entry_format_count (ubyte).
+    MS->emitInt8(2);
+    LineSectionSize += 1;
+
+    // file_name_entry_format (sequence of ULEB128 pairs).
+    LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_path);
+    LineSectionSize += MS->emitULEB128IntValue(P.FileNames[0].Name.getForm());
+
+    LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_directory_index);
+    LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_FORM_data1);
+  }
+
+  // file_names_count (ULEB128).
+  LineSectionSize += MS->emitULEB128IntValue(P.FileNames.size());
+
+  // file_names (sequence of file name entries).
+  for (auto File : P.FileNames) {
+    emitLineTableString(P, File.Name, DebugStrPool, DebugLineStrPool);
+    MS->emitInt8(File.DirIdx);
+    LineSectionSize += 1;
+  }
+}
+
+void DwarfStreamer::emitLineTableString(const DWARFDebugLine::Prologue &P,
+                                        const DWARFFormValue &String,
+                                        OffsetsStringPool &DebugStrPool,
+                                        OffsetsStringPool &DebugLineStrPool) {
+  std::optional<const char *> StringVal = dwarf::toString(String);
+  if (!StringVal) {
+    warn("Cann't read string from line table.");
+    return;
+  }
+
+  switch (String.getForm()) {
+  case dwarf::DW_FORM_string: {
+    StringRef TranslatedString =
+        (Translator) ? Translator(*StringVal) : *StringVal;
+    Asm->OutStreamer->emitBytes(TranslatedString.data());
+    Asm->emitInt8(0);
+    LineSectionSize += TranslatedString.size() + 1;
+  } break;
+  case dwarf::DW_FORM_strp:
+  case dwarf::DW_FORM_line_strp: {
+    DwarfStringPoolEntryRef StringRef =
+        String.getForm() == dwarf::DW_FORM_strp
+            ? DebugStrPool.getEntry(*StringVal)
+            : DebugLineStrPool.getEntry(*StringVal);
+
+    emitIntOffset(StringRef.getOffset(), P.FormParams.Format, LineSectionSize);
+  } break;
+  default:
+    warn("Unsupported string form inside line table.");
+    break;
+  };
+}
+
+void DwarfStreamer::emitLineTableProloguePayload(
+    const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool,
+    OffsetsStringPool &DebugLineStrPool) {
+  // minimum_instruction_length (ubyte).
+  MS->emitInt8(P.MinInstLength);
+  LineSectionSize += 1;
+  if (P.FormParams.Version >= 4) {
+    // maximum_operations_per_instruction (ubyte).
+    MS->emitInt8(P.MaxOpsPerInst);
+    LineSectionSize += 1;
+  }
+  // default_is_stmt (ubyte).
+  MS->emitInt8(P.DefaultIsStmt);
+  LineSectionSize += 1;
+  // line_base (sbyte).
+  MS->emitInt8(P.LineBase);
+  LineSectionSize += 1;
+  // line_range (ubyte).
+  MS->emitInt8(P.LineRange);
+  LineSectionSize += 1;
+  // opcode_base (ubyte).
+  MS->emitInt8(P.OpcodeBase);
+  LineSectionSize += 1;
+
+  // standard_opcode_lengths (array of ubyte).
+  for (auto Length : P.StandardOpcodeLengths) {
+    MS->emitInt8(Length);
+    LineSectionSize += 1;
+  }
+
+  if (P.FormParams.Version < 5)
+    emitLineTablePrologueV2IncludeAndFileTable(P, DebugStrPool,
+                                               DebugLineStrPool);
+  else
+    emitLineTablePrologueV5IncludeAndFileTable(P, DebugStrPool,
+                                               DebugLineStrPool);
+}
+
+void DwarfStreamer::emitLineTableRows(
+    const DWARFDebugLine::LineTable &LineTable, MCSymbol *LineEndSym,
+    unsigned AddressByteSize) {
+
+  MCDwarfLineTableParams Params;
+  Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase;
+  Params.DWARF2LineBase = LineTable.Prologue.LineBase;
+  Params.DWARF2LineRange = LineTable.Prologue.LineRange;
 
   SmallString<128> EncodingBuffer;
 
-  if (Rows.empty()) {
+  if (LineTable.Rows.empty()) {
     // We only have the dummy entry, dsymutil emits an entry with a 0
     // address in that case.
     MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::max(), 0,
@@ -672,17 +872,19 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
 
   unsigned RowsSinceLastSequence = 0;
 
-  for (DWARFDebugLine::Row &Row : Rows) {
+  for (const DWARFDebugLine::Row &Row : LineTable.Rows) {
     int64_t AddressDelta;
     if (Address == -1ULL) {
       MS->emitIntValue(dwarf::DW_LNS_extended_op, 1);
-      MS->emitULEB128IntValue(PointerSize + 1);
+      MS->emitULEB128IntValue(AddressByteSize + 1);
       MS->emitIntValue(dwarf::DW_LNE_set_address, 1);
-      MS->emitIntValue(Row.Address.Address, PointerSize);
-      LineSectionSize += 2 + PointerSize + getULEB128Size(PointerSize + 1);
+      MS->emitIntValue(Row.Address.Address, AddressByteSize);
+      LineSectionSize +=
+          2 + AddressByteSize + getULEB128Size(AddressByteSize + 1);
       AddressDelta = 0;
     } else {
-      AddressDelta = (Row.Address.Address - Address) / MinInstLength;
+      AddressDelta =
+          (Row.Address.Address - Address) / LineTable.Prologue.MinInstLength;
     }
 
     // FIXME: code copied and transformed from MCDwarf.cpp::EmitDwarfLineTable.
@@ -734,7 +936,8 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
 
     int64_t LineDelta = int64_t(Row.Line) - LastLine;
     if (!Row.EndSequence) {
-      MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta, EncodingBuffer);
+      MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta,
+                              EncodingBuffer);
       MS->emitBytes(EncodingBuffer);
       LineSectionSize += EncodingBuffer.size();
       EncodingBuffer.resize(0);
@@ -774,86 +977,19 @@ void DwarfStreamer::emitLineTableForUnit(MCDwarfLineTableParams Params,
   MS->emitLabel(LineEndSym);
 }
 
-/// Copy the debug_line over to the updated binary while unobfuscating the file
-/// names and directories.
-void DwarfStreamer::translateLineTable(DataExtractor Data, uint64_t Offset) {
-  MS->switchSection(MC->getObjectFileInfo()->getDwarfLineSection());
-  StringRef Contents = Data.getData();
-
-  // We have to deconstruct the line table header, because it contains to
-  // length fields that will need to be updated when we change the length of
-  // the files and directories in there.
-  unsigned UnitLength = Data.getU32(&Offset);
-  uint64_t UnitEnd = Offset + UnitLength;
-  MCSymbol *BeginLabel = MC->createTempSymbol();
-  MCSymbol *EndLabel = MC->createTempSymbol();
-  unsigned Version = Data.getU16(&Offset);
-
-  if (Version > 5) {
-    warn("Unsupported line table version: dropping contents and not "
-         "unobfsucating line table.");
-    return;
-  }
-
-  Asm->emitLabelDifference(EndLabel, BeginLabel, 4);
-  Asm->OutStreamer->emitLabel(BeginLabel);
-  Asm->emitInt16(Version);
-  LineSectionSize += 6;
-
-  MCSymbol *HeaderBeginLabel = MC->createTempSymbol();
-  MCSymbol *HeaderEndLabel = MC->createTempSymbol();
-  Asm->emitLabelDifference(HeaderEndLabel, HeaderBeginLabel, 4);
-  Asm->OutStreamer->emitLabel(HeaderBeginLabel);
-  Offset += 4;
-  LineSectionSize += 4;
-
-  uint64_t AfterHeaderLengthOffset = Offset;
-  // Skip to the directories.
-  Offset += (Version >= 4) ? 5 : 4;
-  unsigned OpcodeBase = Data.getU8(&Offset);
-  Offset += OpcodeBase - 1;
-  Asm->OutStreamer->emitBytes(Contents.slice(AfterHeaderLengthOffset, Offset));
-  LineSectionSize += Offset - AfterHeaderLengthOffset;
-
-  // Offset points to the first directory.
-  while (const char *Dir = Data.getCStr(&Offset)) {
-    if (Dir[0] == 0)
-      break;
-
-    StringRef Translated = Translator(Dir);
-    Asm->OutStreamer->emitBytes(Translated);
-    Asm->emitInt8(0);
-    LineSectionSize += Translated.size() + 1;
-  }
-  Asm->emitInt8(0);
-  LineSectionSize += 1;
-
-  while (const char *File = Data.getCStr(&Offset)) {
-    if (File[0] == 0)
-      break;
-
-    StringRef Translated = Translator(File);
-    Asm->OutStreamer->emitBytes(Translated);
-    Asm->emitInt8(0);
-    LineSectionSize += Translated.size() + 1;
-
-    uint64_t OffsetBeforeLEBs = Offset;
-    Asm->emitULEB128(Data.getULEB128(&Offset));
-    Asm->emitULEB128(Data.getULEB128(&Offset));
-    Asm->emitULEB128(Data.getULEB128(&Offset));
-    LineSectionSize += Offset - OffsetBeforeLEBs;
-  }
-  Asm->emitInt8(0);
-  LineSectionSize += 1;
-
-  Asm->OutStreamer->emitLabel(HeaderEndLabel);
-
-  // Copy the actual line table program over.
-  Asm->OutStreamer->emitBytes(Contents.slice(Offset, UnitEnd));
-  LineSectionSize += UnitEnd - Offset;
+void DwarfStreamer::emitIntOffset(uint64_t Offset, dwarf::DwarfFormat Format,
+                                  uint64_t &SectionSize) {
+  uint8_t Size = dwarf::getDwarfOffsetByteSize(Format);
+  MS->emitIntValue(Offset, Size);
+  SectionSize += Size;
+}
 
-  Asm->OutStreamer->emitLabel(EndLabel);
-  Offset = UnitEnd;
+void DwarfStreamer::emitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo,
+                                        dwarf::DwarfFormat Format,
+                                        uint64_t &SectionSize) {
+  uint8_t Size = dwarf::getDwarfOffsetByteSize(Format);
+  Asm->emitLabelDifference(Hi, Lo, Size);
+  SectionSize += Size;
 }
 
 /// Emit the pubnames or pubtypes section contribution for \p

diff  --git a/llvm/test/tools/dsymutil/Inputs/dwarf5-linetable.o b/llvm/test/tools/dsymutil/Inputs/dwarf5-linetable.o
new file mode 100644
index 0000000000000..c4d504083e69e
Binary files /dev/null and b/llvm/test/tools/dsymutil/Inputs/dwarf5-linetable.o 
diff er

diff  --git a/llvm/test/tools/dsymutil/Inputs/dwarf5.o b/llvm/test/tools/dsymutil/Inputs/dwarf5.o
deleted file mode 100644
index a9767f6d93762..0000000000000
Binary files a/llvm/test/tools/dsymutil/Inputs/dwarf5.o and /dev/null 
diff er

diff  --git a/llvm/test/tools/dsymutil/X86/dwarf5-linetable.test b/llvm/test/tools/dsymutil/X86/dwarf5-linetable.test
index c4ee8bd4e1d1d..008e133ec6301 100644
--- a/llvm/test/tools/dsymutil/X86/dwarf5-linetable.test
+++ b/llvm/test/tools/dsymutil/X86/dwarf5-linetable.test
@@ -1,16 +1,16 @@
-# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/ -y %s -o - | llvm-dwarfdump -debug-line - | FileCheck %s
+# RUN: dsymutil -f -oso-prepend-path=%p/../Inputs/ -y %s -o - | llvm-dwarfdump -debug-line -debug-line-str --verbose - | FileCheck %s
 
 # Source:
 #   int main() {
 #     return 0;
 #   }
 # Compile with:
-#   clang -gdwarf-5 dwarf5.c -c -o dwarf5.o
+#   clang -gdwarf-5 dwarf5-linetable.c -c -o dwarf5-linetable.o
 
 ---
 triple:          'x86_64-apple-darwin'
 objects:
-  - filename:        dwarf5.o
+  - filename:        dwarf5-linetable.o
     timestamp:       1513021112
     symbols:
       - { sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000FA0, size: 0x0000000F }
@@ -21,3 +21,9 @@ objects:
 # CHECK: Line table prologue:
 # CHECK: total_length:
 # CHECK: version: 5
+# CHECK: include_directories[  0] =  .debug_line_str[0x00000000] = "/Users/buildslave/avl_test/test-line-str"
+# CHECK: file_names[  0]:
+# CHECK: name:  .debug_line_str[0x00000029] = "dwarf5-linetable.c"
+# CHECK: .debug_line_str contents:
+# CHECK: "/Users/buildslave/avl_test/test-line-str"
+# CHECK: "dwarf5-linetable.c"

diff  --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-line-str.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-line-str.test
new file mode 100644
index 0000000000000..8f2957350484e
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/dwarf5-line-str.test
@@ -0,0 +1,129 @@
+## Test that DWARFv5 DW_FORM_line_strp and corresponding .debug_line_str
+## table are correctly recognized and copied into the result.
+
+# RUN: yaml2obj %s -o %t.o
+
+# RUN: llvm-dwarfutil %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s --check-prefix VERIFY-CHECK
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s
+#
+# RUN: llvm-dwarfutil --no-garbage-collection %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s --check-prefix VERIFY-CHECK
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s
+#
+# RUN: llvm-dwarfutil --no-garbage-collection --build-accelerator=DWARF %t.o %t1
+# RUN: llvm-dwarfdump -verify %t1 | FileCheck %s --check-prefix VERIFY-CHECK
+# RUN: llvm-dwarfdump -a --verbose %t1 | FileCheck %s
+
+#VERIFY-CHECK: No errors.
+
+#CHECK: .debug_info
+#CHECK: DW_TAG_compile_unit
+#CHECK: DW_TAG_subprogram
+#CHECK: DW_AT_name [DW_FORM_line_strp]  ( .debug_line_str[0x00000000] = "foo1")
+#CHECK: .debug_line
+#CHECK: include_directories[  0] =  .debug_line_str[0x00000000] = "foo1"
+#CHECK: include_directories[  1] =  .debug_line_str[0x00000000] = "foo1"
+#CHECK: file_names[  0]:
+#CHECK:            name:  .debug_line_str[0x00000000] = "foo1"
+#CHECK: file_names[  1]:
+#CHECK:            name:  .debug_line_str[0x00000000] = "foo1"
+#CHECK: .debug_line_str
+#CHECK: "foo1"
+
+--- !ELF
+FileHeader:
+  Class:    ELFCLASS64
+  Data:     ELFDATA2LSB
+  Type:     ET_REL
+  Machine:  EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1130
+    Size:            0x60
+  - Name:            .debug_line_str
+    Type:            SHT_PROGBITS
+    Flags:           [  ]
+    Content:         "666f6f3100"
+  - Name:            .debug_line
+    Type:            SHT_PROGBITS
+    Flags:           [  ]
+    Content:         "2a00000005000801220000000102030405050102030401011f02000000000000000001011f020000000000000000"
+DWARF:
+  debug_abbrev:
+    - Table:
+      - Tag:      DW_TAG_compile_unit
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_producer
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_language
+            Form:      DW_FORM_data2
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addrx
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+          - Attribute: DW_AT_addr_base
+            Form:      DW_FORM_sec_offset
+          - Attribute: DW_AT_stmt_list
+            Form:      DW_FORM_sec_offset
+      - Tag:      DW_TAG_subprogram
+        Children: DW_CHILDREN_yes
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_line_strp
+          - Attribute: DW_AT_low_pc
+            Form:      DW_FORM_addrx
+          - Attribute: DW_AT_high_pc
+            Form:      DW_FORM_data8
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+      - Tag:      DW_TAG_base_type
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+      - Tag:      DW_TAG_variable
+        Children: DW_CHILDREN_no
+        Attributes:
+          - Attribute: DW_AT_name
+            Form:      DW_FORM_string
+          - Attribute: DW_AT_const_value
+            Form:      DW_FORM_implicit_const
+            Value:     33
+          - Attribute: DW_AT_type
+            Form:      DW_FORM_ref4
+  debug_info:
+    - Version: 5
+      UnitType:   DW_UT_compile
+      Entries:
+        - AbbrCode: 1
+          Values:
+            - CStr: by_hand
+            - Value:  0x04
+            - CStr: CU1
+            - Value:  0x0
+            - Value:  0x10
+            - Value:  0x8
+            - Value:  0x0
+        - AbbrCode: 2
+          Values:
+            - Value: 0x0
+            - Value: 0x0
+            - Value: 0x10
+            - Value: 0x3f
+        - AbbrCode: 0
+        - AbbrCode: 3
+          Values:
+            - CStr: int
+        - AbbrCode: 0
+  debug_addr:
+    - Version: 5
+      AddressSize: 0x08
+      Entries:
+        - Address: 0x1130
+...


        


More information about the llvm-commits mailing list