[llvm] [BOLT][DebugInfo] Add DWARF64 support for BOLT (PR #206437)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 10 02:20:15 PDT 2026


https://github.com/Thrrreeee updated https://github.com/llvm/llvm-project/pull/206437

>From 79239633974ab3e592c0bcc20e32e114f8552058 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Mon, 29 Jun 2026 17:13:37 +0800
Subject: [PATCH 1/4] [BOLT] support for DWARF64 Format

---
 bolt/include/bolt/Core/DIEBuilder.h           |   4 +-
 bolt/include/bolt/Core/DebugData.h            |  47 +--
 bolt/include/bolt/Core/DebugNames.h           |   7 +-
 bolt/lib/Core/BinaryContext.cpp               |   1 +
 bolt/lib/Core/DebugData.cpp                   | 151 ++++++----
 bolt/lib/Core/DebugNames.cpp                  |  49 ++--
 bolt/lib/Core/GDBIndex.cpp                    |  10 +-
 bolt/lib/Rewrite/DWARFRewriter.cpp            |  60 ++--
 bolt/test/X86/dwarf64-debug-info-aranges.test |  46 +++
 bolt/test/X86/dwarf64-debug-names.test        | 111 ++++++++
 bolt/test/X86/dwarf64-loclists.test           | 166 +++++++++++
 .../X86/dwarf64-lowpc-highpc-convert.test     | 143 ++++++++++
 bolt/test/X86/dwarf64-ref-addr.test           | 134 +++++++++
 bolt/test/X86/dwarf64-split-dwarf.test        |  56 ++++
 bolt/test/X86/dwarf64-str-offsets.test        | 144 ++++++++++
 .../mixed-dwarf32-dwarf64-debug-names.test    | 173 +++++++++++
 .../X86/mixed-dwarf32-dwarf64-rnglists.test   | 241 ++++++++++++++++
 .../mixed-dwarf32-dwarf64-str-offsets.test    | 269 ++++++++++++++++++
 18 files changed, 1694 insertions(+), 118 deletions(-)
 create mode 100644 bolt/test/X86/dwarf64-debug-info-aranges.test
 create mode 100644 bolt/test/X86/dwarf64-debug-names.test
 create mode 100644 bolt/test/X86/dwarf64-loclists.test
 create mode 100644 bolt/test/X86/dwarf64-lowpc-highpc-convert.test
 create mode 100644 bolt/test/X86/dwarf64-ref-addr.test
 create mode 100644 bolt/test/X86/dwarf64-split-dwarf.test
 create mode 100644 bolt/test/X86/dwarf64-str-offsets.test
 create mode 100644 bolt/test/X86/mixed-dwarf32-dwarf64-debug-names.test
 create mode 100644 bolt/test/X86/mixed-dwarf32-dwarf64-rnglists.test
 create mode 100644 bolt/test/X86/mixed-dwarf32-dwarf64-str-offsets.test

diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h
index 8fba755e154d5..a9ccd35c90298 100644
--- a/bolt/include/bolt/Core/DIEBuilder.h
+++ b/bolt/include/bolt/Core/DIEBuilder.h
@@ -56,8 +56,8 @@ class DIEBuilder {
     std::vector<std::unique_ptr<DIEInfo>> DieInfoVector;
     DIE *UnitDie = nullptr;
     uint32_t UnitId = 0;
-    uint32_t UnitOffset = 0;
-    uint32_t UnitLength = 0;
+    uint64_t UnitOffset = 0;
+    uint64_t UnitLength = 0;
     bool IsConstructed = false;
     // A map of DIE offsets in original DWARF section to DIE ID.
     // Which is used to access DieInfoVector.
diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index 67a1c5c739c25..7462ec87068ea 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -64,15 +64,15 @@ std::optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
 
 // DWARF5 Header in order of encoding.
 // Types represent encoding sizes.
-using UnitLengthType = uint32_t;
+using UnitLengthType = uint64_t;
 using VersionType = uint16_t;
 using AddressSizeType = uint8_t;
 using SegmentSelectorType = uint8_t;
 using OffsetEntryCountType = uint32_t;
 /// Get DWARF5 Header size.
 /// Rangelists and Loclists have the same header.
-constexpr uint32_t getDWARF5RngListLocListHeaderSize() {
-  return sizeof(UnitLengthType) + sizeof(VersionType) +
+inline uint32_t getDWARF5RngListLocListHeaderSize(dwarf::DwarfFormat Format) {
+  return dwarf::getUnitLengthFieldByteSize(Format) + sizeof(VersionType) +
          sizeof(AddressSizeType) + sizeof(SegmentSelectorType) +
          sizeof(OffsetEntryCountType);
 }
@@ -150,10 +150,11 @@ using DebugBufferVector = SmallVector<char, 16>;
 
 /// Map of old CU offset to new offset and length.
 struct CUInfo {
-  uint32_t Offset;
-  uint32_t Length;
+  uint64_t Offset;
+  uint64_t Length;
+  dwarf::DwarfFormat Format;
 };
-using CUOffsetMap = std::map<uint32_t, CUInfo>;
+using CUOffsetMap = std::map<uint64_t, CUInfo>;
 
 enum class RangesWriterKind { DebugRangesWriter, DebugRangeListsWriter };
 /// Serializes the .debug_ranges DWARF section.
@@ -269,9 +270,9 @@ class DebugRangeListsSectionWriter : public DebugRangesSectionWriter {
   DWARFUnit *CU;
   /// Current relative offset of range list entry within this CUs rangelist
   /// body.
-  uint32_t CurrentOffset{0};
+  uint64_t CurrentOffset{0};
   /// Contains relative offset of each range list entry.
-  SmallVector<uint32_t, 1> RangeEntries;
+  SmallVector<uint64_t, 1> RangeEntries;
 
   std::unique_ptr<DebugBufferVector> CUBodyBuffer;
   std::unique_ptr<raw_svector_ostream> CUBodyStream;
@@ -418,9 +419,10 @@ class DebugAddrWriterDwarf5 : public DebugAddrWriter {
   DebugAddrWriterDwarf5() = delete;
   DebugAddrWriterDwarf5(BinaryContext *BC) : DebugAddrWriter(BC) {}
   DebugAddrWriterDwarf5(BinaryContext *BC, uint8_t AddressByteSize,
-                        std::optional<uint64_t> AddrOffsetSectionBase)
+                        std::optional<uint64_t> AddrOffsetSectionBase,
+                        dwarf::DwarfFormat Format)
       : DebugAddrWriter(BC, AddressByteSize),
-        AddrOffsetSectionBase(AddrOffsetSectionBase) {}
+        AddrOffsetSectionBase(AddrOffsetSectionBase), Format(Format) {}
 
   /// Write out entries in to .debug_addr section for CUs.
   virtual std::optional<uint64_t> finalize(const size_t BufferSize) override;
@@ -441,8 +443,12 @@ class DebugAddrWriterDwarf5 : public DebugAddrWriter {
   }
 
 private:
+  // TODO: This is a temporary solution.
+  uint32_t getHeaderSize() const {
+    return dwarf::getUnitLengthFieldByteSize(Format) + 4;
+  }
   std::optional<uint64_t> AddrOffsetSectionBase = std::nullopt;
-  static constexpr uint32_t HeaderSize = 8;
+  dwarf::DwarfFormat Format = dwarf::DwarfFormat::DWARF32;
 };
 
 /// This class is NOT thread safe.
@@ -455,7 +461,7 @@ class DebugStrOffsetsWriter {
   }
 
   /// Update Str offset in .debug_str in .debug_str_offsets.
-  void updateAddressMap(uint32_t Index, uint32_t Address,
+  void updateAddressMap(uint32_t Index, uint64_t Address,
                         const DWARFUnit &Unit);
 
   /// Get offset for given index in original .debug_str_offsets section.
@@ -493,10 +499,10 @@ class DebugStrOffsetsWriter {
 private:
   std::unique_ptr<DebugStrOffsetsBufferVector> StrOffsetsBuffer;
   std::unique_ptr<raw_svector_ostream> StrOffsetsStream;
-  std::map<uint32_t, uint32_t> IndexToAddressMap;
+  std::map<uint32_t, uint64_t> IndexToAddressMap;
   [[maybe_unused]]
   DenseSet<uint64_t> DebugStrOffsetFinalized;
-  SmallVector<uint32_t, 5> StrOffsets;
+  SmallVector<uint64_t, 5> StrOffsets;
   std::unordered_map<uint64_t, uint64_t> ProcessedBaseOffsets;
   bool StrOffsetSectionWasModified = false;
   BinaryContext &BC;
@@ -660,7 +666,7 @@ class DebugLoclistWriter : public DebugLocWriter {
   // Used for DWARF5 to store location lists before being finalized.
   std::unique_ptr<DebugBufferVector> LocBodyBuffer;
   std::unique_ptr<raw_svector_ostream> LocBodyStream;
-  std::vector<uint32_t> RelativeLocListOffsets;
+  std::vector<uint64_t> RelativeLocListOffsets;
   uint32_t NumberOfEntries{0};
 };
 
@@ -788,8 +794,9 @@ class DwarfLineTable {
   /// Raw data representing complete debug line section for the unit.
   StringRef RawData;
 
-  /// DWARF Version
-  uint16_t DwarfVersion;
+  /// DWARF version and format for this line table.
+  uint16_t DwarfVersion = 0;
+  dwarf::DwarfFormat Format = dwarf::DWARF32;
 
 public:
   /// Emit line info for all units in the binary context.
@@ -847,6 +854,12 @@ class DwarfLineTable {
 
   // Returns DWARF Version for this line table.
   uint16_t getDwarfVersion() const { return DwarfVersion; }
+
+  /// Sets DWARF format for this line table.
+  void setFormat(dwarf::DwarfFormat F) { Format = F; }
+
+  /// Returns DWARF format for this line table.
+  dwarf::DwarfFormat getFormat() const { return Format; }
 };
 
 /// ClusteredRows represents a collection of debug line table row references.
diff --git a/bolt/include/bolt/Core/DebugNames.h b/bolt/include/bolt/Core/DebugNames.h
index 297f004b2a45b..4213cfc7283b6 100644
--- a/bolt/include/bolt/Core/DebugNames.h
+++ b/bolt/include/bolt/Core/DebugNames.h
@@ -107,15 +107,15 @@ class DWARF5AcceleratorTable {
   struct HashData {
     uint64_t StrOffset;
     uint32_t HashValue;
-    uint32_t EntryOffset;
+    uint64_t EntryOffset;
     std::vector<BOLTDWARF5AccelTableData *> Values;
   };
   using HashList = std::vector<HashData *>;
   using BucketList = std::vector<HashList>;
   /// Contains all the offsets of CUs.
-  SmallVector<uint32_t, 1> CUList;
+  SmallVector<uint64_t, 1> CUList;
   /// Contains all the offsets of local TUs.
-  SmallVector<uint32_t, 1> LocalTUList;
+  SmallVector<uint64_t, 1> LocalTUList;
   /// Contains all the type hashes for split dwarf TUs.
   SmallVector<uint64_t, 1> ForeignTUList;
   using StringEntries =
@@ -131,6 +131,7 @@ class DWARF5AcceleratorTable {
   uint32_t BucketCount = 0;
   uint32_t UniqueHashCount = 0;
   uint32_t AbbrevTableSize = 0;
+  dwarf::DwarfFormat Format = dwarf::DwarfFormat::DWARF32;
   uint32_t CUIndexEncodingSize = 4;
   uint32_t TUIndexEncodingSize = 4;
   uint32_t AugmentationStringSize = 0;
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index 43ce56ef083b5..07864b3d2d98b 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -1896,6 +1896,7 @@ void BinaryContext::preprocessDebugInfo() {
         LineTable->Prologue.FileNames;
 
     uint16_t DwarfVersion = LineTable->Prologue.getVersion();
+    BinaryLineTable.setFormat(LineTable->Prologue.getFormParams().Format);
     if (DwarfVersion >= 5) {
       std::optional<MD5::MD5Result> Checksum;
       if (LineTable->Prologue.ContentTypes.HasMD5)
diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
index db51343908717..6a27d630cd0f6 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -189,6 +189,7 @@ uint64_t DebugRangeListsSectionWriter::addRanges(
 }
 
 struct LocListsRangelistsHeader {
+  dwarf::DwarfFormat Format;
   UnitLengthType UnitLength; // Size of loclist entries section, not including
                              // size of header.
   VersionType Version;
@@ -197,6 +198,16 @@ struct LocListsRangelistsHeader {
   OffsetEntryCountType OffsetEntryCount;
 };
 
+static void writeDwarfOffset(raw_ostream &OS, dwarf::DwarfFormat Format,
+                             uint64_t Value,
+                             endianness Endian = llvm::endianness::little) {
+  if (Format == dwarf::DwarfFormat::DWARF64) {
+    support::endian::write(OS, Value, Endian);
+    return;
+  }
+  support::endian::write(OS, static_cast<uint32_t>(Value), Endian);
+}
+
 static std::unique_ptr<DebugBufferVector>
 getDWARF5Header(const LocListsRangelistsHeader &Header) {
   std::unique_ptr<DebugBufferVector> HeaderBuffer =
@@ -206,11 +217,14 @@ getDWARF5Header(const LocListsRangelistsHeader &Header) {
 
   // 7.29 length of the set of entries for this compilation unit, not including
   // the length field itself
-  const uint32_t HeaderSize =
-      getDWARF5RngListLocListHeaderSize() - sizeof(UnitLengthType);
+  const uint32_t HeaderSize = getDWARF5RngListLocListHeaderSize(Header.Format) -
+                              dwarf::getUnitLengthFieldByteSize(Header.Format);
 
-  support::endian::write(*HeaderStream, Header.UnitLength + HeaderSize,
-                         llvm::endianness::little);
+  if (Header.Format == dwarf::DwarfFormat::DWARF64)
+    support::endian::write(*HeaderStream, dwarf::DW_LENGTH_DWARF64,
+                           llvm::endianness::little);
+  writeDwarfOffset(*HeaderStream, Header.Format,
+                   Header.UnitLength + HeaderSize);
   support::endian::write(*HeaderStream, Header.Version,
                          llvm::endianness::little);
   support::endian::write(*HeaderStream, Header.AddressSize,
@@ -312,15 +326,15 @@ void DebugRangeListsSectionWriter::finalizeSection() {
       std::make_unique<DebugBufferVector>();
   std::unique_ptr<raw_svector_ostream> CUArrayStream =
       std::make_unique<raw_svector_ostream>(*CUArrayBuffer);
-  constexpr uint32_t SizeOfArrayEntry = 4;
-  const uint32_t SizeOfArraySection = RangeEntries.size() * SizeOfArrayEntry;
-  for (uint32_t Offset : RangeEntries)
-    support::endian::write(*CUArrayStream, Offset + SizeOfArraySection,
-                           llvm::endianness::little);
-
-  std::unique_ptr<DebugBufferVector> Header = getDWARF5Header(
-      {static_cast<uint32_t>(SizeOfArraySection + CUBodyBuffer->size()), 5, 8,
-       0, static_cast<uint32_t>(RangeEntries.size())});
+  const dwarf::DwarfFormat Format = CU->getFormParams().Format;
+  const uint64_t SizeOfArraySection =
+      RangeEntries.size() * dwarf::getDwarfOffsetByteSize(Format);
+  for (uint64_t Offset : RangeEntries)
+    writeDwarfOffset(*CUArrayStream, Format, Offset + SizeOfArraySection);
+
+  std::unique_ptr<DebugBufferVector> Header =
+      getDWARF5Header({Format, SizeOfArraySection + CUBodyBuffer->size(), 5, 8,
+                       0, static_cast<uint32_t>(RangeEntries.size())});
   *RangesStream << *Header;
   *RangesStream << *CUArrayBuffer;
   *RangesStream << *CUBodyBuffer;
@@ -349,27 +363,37 @@ void DebugARangesSectionWriter::writeARangesSection(
     const uint64_t Offset = CUOffsetAddressRangesPair.first;
     const DebugAddressRangesVector &AddressRanges =
         CUOffsetAddressRangesPair.second;
+    assert(CUMap.count(Offset) && "Original CU offset is not found in CU Map");
+    const CUInfo &Info = CUMap.find(Offset)->second;
+    const dwarf::DwarfFormat Format = Info.Format;
+    const uint8_t DwarfOffsetByteSize = dwarf::getDwarfOffsetByteSize(Format);
 
     // Emit header.
 
-    // Size of this set: 8 (size of the header) + 4 (padding after header)
-    // + 2*sizeof(uint64_t) bytes for each of the ranges, plus an extra
-    // pair of uint64_t's for the terminating, zero-length range.
-    // Does not include size field itself.
-    uint32_t Size = 8 + 4 + 2 * sizeof(uint64_t) * (AddressRanges.size() + 1);
+    // Size of this set: header(8/16 bytes depending on the DWARF format),
+    // padding after header (4/8 bytes), and address/length pairs for each
+    // range, plus an extra pair of uint64_t's for the terminating, zero-length
+    // range. Does not include size field itself.
+
+    // Header size: version(2) + offset(4/8) + address size(1) + segment(1).
+    const uint64_t HeaderSize = sizeof(uint16_t) + DwarfOffsetByteSize +
+                                sizeof(uint8_t) + sizeof(uint8_t);
+
+    const uint64_t Size = HeaderSize + DwarfOffsetByteSize +
+                          2 * sizeof(uint64_t) * (AddressRanges.size() + 1);
 
     // Header field #1: set size.
-    support::endian::write(RangesStream, Size, llvm::endianness::little);
+    if (Format == dwarf::DwarfFormat::DWARF64)
+      support::endian::write(RangesStream, dwarf::DW_LENGTH_DWARF64,
+                             llvm::endianness::little);
+    writeDwarfOffset(RangesStream, Format, Size);
 
     // Header field #2: version number, 2 as per the specification.
     support::endian::write(RangesStream, static_cast<uint16_t>(2),
                            llvm::endianness::little);
 
-    assert(CUMap.count(Offset) && "Original CU offset is not found in CU Map");
     // Header field #3: debug info offset of the correspondent compile unit.
-    support::endian::write(
-        RangesStream, static_cast<uint32_t>(CUMap.find(Offset)->second.Offset),
-        llvm::endianness::little);
+    writeDwarfOffset(RangesStream, Format, Info.Offset);
 
     // Header field #4: address size.
     // 8 since we only write ELF64 binaries for now.
@@ -378,9 +402,8 @@ void DebugARangesSectionWriter::writeARangesSection(
     // Header field #5: segment size of target architecture.
     RangesStream << char(0);
 
-    // Padding before address table - 4 bytes in the 64-bit-pointer case.
-    support::endian::write(RangesStream, static_cast<uint32_t>(0),
-                           llvm::endianness::little);
+    // Padding before address table - 4/8 bytes.
+    writeDwarfOffset(RangesStream, Format, 0);
 
     writeAddressRanges(RangesStream, AddressRanges, true);
   }
@@ -482,8 +505,9 @@ std::optional<uint64_t> DebugAddrWriter::finalize(const size_t BufferSize) {
 
 void DebugAddrWriterDwarf5::updateAddrBase(DIEBuilder &DIEBlder, DWARFUnit &CU,
                                            const uint64_t Offset) {
-  /// Header for DWARF5 has size 8, so we add it to the offset.
-  updateAddressBase(DIEBlder, *this, CU, Offset + HeaderSize);
+  /// Header for DWARF5 has size 8 bytes in DWARF32 or 16 bytes in DWARF64,
+  /// so we add it to the offset.
+  updateAddressBase(DIEBlder, *this, CU, Offset + getHeaderSize());
 }
 
 DenseMap<uint64_t, uint64_t> DebugAddrWriter::UnmodifiedAddressOffsets;
@@ -506,8 +530,7 @@ DebugAddrWriterDwarf5::finalize(const size_t BufferSize) {
     if (!AddrOffsetSectionBase)
       return std::nullopt;
     // Address base offset is to the first entry.
-    // The size of header is 8 bytes.
-    uint64_t Offset = *AddrOffsetSectionBase - HeaderSize;
+    uint64_t Offset = *AddrOffsetSectionBase - getHeaderSize();
     auto Iter = UnmodifiedAddressOffsets.find(Offset);
     if (Iter != UnmodifiedAddressOffsets.end())
       return Iter->second;
@@ -527,8 +550,10 @@ DebugAddrWriterDwarf5::finalize(const size_t BufferSize) {
   // Sorting address in increasing order of indices.
   llvm::sort(SortedMap, llvm::less_first());
   // Writing out Header
-  const uint32_t Length = SortedMap.size() * AddressByteSize + 4;
-  support::endian::write(*AddressStream, Length, Endian);
+  const uint64_t Length = SortedMap.size() * AddressByteSize + 4;
+  if (Format == dwarf::DwarfFormat::DWARF64)
+    support::endian::write(*AddressStream, dwarf::DW_LENGTH_DWARF64, Endian);
+  writeDwarfOffset(*AddressStream, Format, Length, Endian);
   support::endian::write(*AddressStream, static_cast<uint16_t>(5), Endian);
   support::endian::write(*AddressStream, static_cast<uint8_t>(AddressByteSize),
                          Endian);
@@ -677,7 +702,7 @@ static void writeDWARF5LocList(uint32_t &NumberOfEntries, DIEValue &AttrInfo,
                                DebugLocationsVector &LocList, DIE &Die,
                                DIEBuilder &DIEBldr, DebugAddrWriter &AddrWriter,
                                DebugBufferVector &LocBodyBuffer,
-                               std::vector<uint32_t> &RelativeLocListOffsets,
+                               std::vector<uint64_t> &RelativeLocListOffsets,
                                DWARFUnit &CU,
                                raw_svector_ostream &LocBodyStream) {
 
@@ -742,7 +767,8 @@ void DebugLoclistWriter::finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die) {
     if (!isSplitDwarf() && LocListBaseAttrInfo.getType())
       DIEBldr.replaceValue(&Die, dwarf::DW_AT_loclists_base,
                            LocListBaseAttrInfo.getForm(),
-                           DIEInteger(getDWARF5RngListLocListHeaderSize()));
+                           DIEInteger(getDWARF5RngListLocListHeaderSize(
+                               CU.getFormParams().Format)));
     return;
   }
 
@@ -751,23 +777,23 @@ void DebugLoclistWriter::finalizeDWARF5(DIEBuilder &DIEBldr, DIE &Die) {
   std::unique_ptr<raw_svector_ostream> LocArrayStream =
       std::make_unique<raw_svector_ostream>(*LocArrayBuffer);
 
-  const uint32_t SizeOfArraySection = NumberOfEntries * sizeof(uint32_t);
+  const dwarf::DwarfFormat Format = CU.getFormParams().Format;
+  const uint64_t SizeOfArraySection =
+      NumberOfEntries * dwarf::getDwarfOffsetByteSize(Format);
   // Write out IndexArray
-  for (uint32_t RelativeOffset : RelativeLocListOffsets)
-    support::endian::write(
-        *LocArrayStream,
-        static_cast<uint32_t>(SizeOfArraySection + RelativeOffset),
-        llvm::endianness::little);
+  for (uint64_t RelativeOffset : RelativeLocListOffsets)
+    writeDwarfOffset(*LocArrayStream, Format,
+                     SizeOfArraySection + RelativeOffset);
 
-  std::unique_ptr<DebugBufferVector> Header = getDWARF5Header(
-      {static_cast<uint32_t>(SizeOfArraySection + LocBodyBuffer->size()), 5, 8,
-       0, NumberOfEntries});
+  std::unique_ptr<DebugBufferVector> Header =
+      getDWARF5Header({Format, SizeOfArraySection + LocBodyBuffer->size(), 5, 8,
+                       0, NumberOfEntries});
   *LocStream << *Header;
   *LocStream << *LocArrayBuffer;
   *LocStream << *LocBodyBuffer;
 
   if (!isSplitDwarf()) {
-    const uint64_t LocalBase = getDWARF5RngListLocListHeaderSize();
+    const uint64_t LocalBase = getDWARF5RngListLocListHeaderSize(Format);
     DIEValue LocListBaseAttrInfo =
         Die.findAttribute(dwarf::DW_AT_loclists_base);
     if (LocListBaseAttrInfo.getType()) {
@@ -855,15 +881,20 @@ void DebugStrOffsetsWriter::initialize(DWARFUnit &Unit) {
   if (!Contr)
     return;
   const uint8_t DwarfOffsetByteSize = Contr->getDwarfOffsetByteSize();
-  assert(DwarfOffsetByteSize == 4 &&
-         "Dwarf String Offsets Byte Size is not supported.");
-  StrOffsets.reserve(Contr->Size);
-  for (uint64_t Offset = 0; Offset < Contr->Size; Offset += DwarfOffsetByteSize)
-    StrOffsets.push_back(support::endian::read32le(
-        StrOffsetsSection.Data.data() + Contr->Base + Offset));
+  StrOffsets.reserve(Contr->Size / DwarfOffsetByteSize);
+  for (uint64_t Offset = 0; Offset < Contr->Size;
+       Offset += DwarfOffsetByteSize) {
+    uint64_t Value =
+        DwarfOffsetByteSize == 4
+            ? support::endian::read32le(StrOffsetsSection.Data.data() +
+                                        Contr->Base + Offset)
+            : support::endian::read64le(StrOffsetsSection.Data.data() +
+                                        Contr->Base + Offset);
+    StrOffsets.push_back(Value);
+  }
 }
 
-void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint32_t Address,
+void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint64_t Address,
                                              const DWARFUnit &Unit) {
   assert(DebugStrOffsetFinalized.count(Unit.getOffset()) == 0 &&
          "Cannot update address map since debug_str_offsets was already "
@@ -897,10 +928,14 @@ void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit,
     // Update String Offsets that were modified.
     for (const auto &Entry : IndexToAddressMap)
       StrOffsets[Entry.first] = Entry.second;
+    const dwarf::DwarfFormat Format = Unit.getFormParams().Format;
     // Writing out the header for each section.
-    support::endian::write(*StrOffsetsStream,
-                           static_cast<uint32_t>(StrOffsets.size() * 4 + 4),
-                           llvm::endianness::little);
+    if (Format == dwarf::DwarfFormat::DWARF64)
+      support::endian::write(*StrOffsetsStream, dwarf::DW_LENGTH_DWARF64,
+                             llvm::endianness::little);
+    writeDwarfOffset(*StrOffsetsStream, Format,
+                     StrOffsets.size() * dwarf::getDwarfOffsetByteSize(Format) +
+                         sizeof(uint16_t) + sizeof(uint16_t));
     support::endian::write(*StrOffsetsStream, static_cast<uint16_t>(5),
                            llvm::endianness::little);
     support::endian::write(*StrOffsetsStream, static_cast<uint16_t>(0),
@@ -912,9 +947,8 @@ void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit,
       DIEBldr.replaceValue(&Die, dwarf::DW_AT_str_offsets_base,
                            StrListBaseAttrInfo.getForm(),
                            DIEInteger(BaseOffset));
-    for (const uint32_t Offset : StrOffsets)
-      support::endian::write(*StrOffsetsStream, Offset,
-                             llvm::endianness::little);
+    for (const uint64_t Offset : StrOffsets)
+      writeDwarfOffset(*StrOffsetsStream, Format, Offset);
   } else {
     DIEBldr.replaceValue(&Die, dwarf::DW_AT_str_offsets_base,
                          StrListBaseAttrInfo.getForm(),
@@ -1235,15 +1269,18 @@ void DwarfLineTable::emit(BinaryContext &BC, MCStreamer &Streamer) {
   Streamer.switchSection(BC.MOFI->getDwarfLineSection());
 
   const uint16_t DwarfVersion = BC.Ctx->getDwarfVersion();
+  const dwarf::DwarfFormat Format = BC.Ctx->getDwarfFormat();
   // Handle the rest of the Compile Units.
   for (auto &CUIDTablePair : LineTables) {
     Streamer.getContext().setDwarfVersion(
         CUIDTablePair.second.getDwarfVersion());
+    Streamer.getContext().setDwarfFormat(CUIDTablePair.second.getFormat());
     CUIDTablePair.second.emitCU(&Streamer, Params, LineStr, BC);
   }
 
   // Resetting DWARF version for rest of the flow.
   BC.Ctx->setDwarfVersion(DwarfVersion);
+  BC.Ctx->setDwarfFormat(Format);
 
   // Still need to write the section out for the ExecutionEngine, and temp in
   // memory object we are constructing.
diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp
index 83f229c24a269..42f6e9edd8d11 100644
--- a/bolt/lib/Core/DebugNames.cpp
+++ b/bolt/lib/Core/DebugNames.cpp
@@ -19,6 +19,15 @@
 
 namespace llvm {
 namespace bolt {
+static void writeOffset(raw_ostream &OS, uint64_t Value,
+                        dwarf::DwarfFormat Format) {
+  if (Format == dwarf::DwarfFormat::DWARF64)
+    support::endian::write(OS, Value, llvm::endianness::little);
+  else
+    support::endian::write(OS, static_cast<uint32_t>(Value),
+                         llvm::endianness::little);
+}
+
 DWARF5AcceleratorTable::DWARF5AcceleratorTable(
     const bool CreateDebugNames, BinaryContext &BC,
     DebugStrWriter &MainBinaryStrWriter)
@@ -105,6 +114,10 @@ void DWARF5AcceleratorTable::setCurrentUnit(DWARFUnit &Unit,
                                             const uint64_t UnitStartOffset) {
   CurrentUnit = nullptr;
   CurrentUnitOffset = UnitStartOffset;
+  // .debug_names is emitted as a single contribution, so mixed DWARF32/DWARF64
+  // inputs need one common section offset size. Use DWARF64 if any unit is DWARF64.
+  if (Unit.getFormParams().Format == dwarf::DwarfFormat::DWARF64)
+    Format = dwarf::DwarfFormat::DWARF64;
   std::optional<uint64_t> DWOID = Unit.getDWOId();
   // We process skeleton CUs after DWO Units for it.
   // Patching offset in CU list to correct one.
@@ -273,8 +286,11 @@ static uint64_t getNameOffset(BinaryContext &BC, DWARFUnit &Unit,
   }
 
   const uint8_t DwarfOffsetByteSize = Contr->getDwarfOffsetByteSize();
-  return support::endian::read32le(StrOffsetsSection.Data.data() + Contr->Base +
-                                   Index * DwarfOffsetByteSize);
+  const char *OffsetPtr =
+      StrOffsetsSection.Data.data() + Contr->Base + Index * DwarfOffsetByteSize;
+  if (DwarfOffsetByteSize == sizeof(uint64_t))
+    return support::endian::read64le(OffsetPtr);
+  return support::endian::read32le(OffsetPtr);
 }
 
 static uint64_t getEntryID(const BOLTDWARF5AccelTableData &Entry) {
@@ -566,7 +582,7 @@ void DWARF5AcceleratorTable::finalize() {
   CUIndexForm = DIEInteger::BestForm(/*IsSigned*/ false, CUList.size() - 1);
   TUIndexForm = DIEInteger::BestForm(
       /*IsSigned*/ false, LocalTUList.size() + ForeignTUList.size() - 1);
-  const dwarf::FormParams FormParams{5, 4, dwarf::DwarfFormat::DWARF32, false};
+  const dwarf::FormParams FormParams{5, 4, Format, false};
   CUIndexEncodingSize = *dwarf::getFixedFormByteSize(CUIndexForm, FormParams);
   TUIndexEncodingSize = *dwarf::getFixedFormByteSize(TUIndexForm, FormParams);
 }
@@ -768,11 +784,13 @@ static constexpr uint32_t getDebugNamesHeaderSize() {
 
 void DWARF5AcceleratorTable::emitHeader() const {
   constexpr uint32_t HeaderSize = getDebugNamesHeaderSize();
-  // Header Length
-  support::endian::write(*FullTableStream,
-                         static_cast<uint32_t>(HeaderSize + StrBuffer->size() +
-                                               AugmentationStringSize),
-                         llvm::endianness::little);
+  // .debug_names Header 
+  // Length (DWARF64 needs escaped marker)
+  if (Format == dwarf::DwarfFormat::DWARF64)
+    support::endian::write(*FullTableStream, dwarf::DW_LENGTH_DWARF64,
+                           llvm::endianness::little);
+  writeOffset(*FullTableStream,
+              HeaderSize + StrBuffer->size() + AugmentationStringSize, Format);
   // Version
   support::endian::write(*FullTableStream, static_cast<uint16_t>(5),
                          llvm::endianness::little);
@@ -811,12 +829,12 @@ void DWARF5AcceleratorTable::emitHeader() const {
 }
 
 void DWARF5AcceleratorTable::emitCUList() const {
-  for (const uint32_t CUID : CUList)
-    support::endian::write(*StrStream, CUID, llvm::endianness::little);
+  for (const uint64_t CUID : CUList)
+    writeOffset(*StrStream, CUID, Format);
 }
 void DWARF5AcceleratorTable::emitTUList() const {
-  for (const uint32_t TUID : LocalTUList)
-    support::endian::write(*StrStream, TUID, llvm::endianness::little);
+  for (const uint64_t TUID : LocalTUList)
+    writeOffset(*StrStream, TUID, Format);
 
   for (const uint64_t TUID : ForeignTUList)
     support::endian::write(*StrStream, TUID, llvm::endianness::little);
@@ -839,16 +857,13 @@ void DWARF5AcceleratorTable::emitHashes() const {
 void DWARF5AcceleratorTable::emitStringOffsets() const {
   for (const auto &Bucket : getBuckets()) {
     for (const DWARF5AcceleratorTable::HashData *Hash : Bucket)
-      support::endian::write(*StrStream, static_cast<uint32_t>(Hash->StrOffset),
-                             llvm::endianness::little);
+      writeOffset(*StrStream, Hash->StrOffset, Format);
   }
 }
 void DWARF5AcceleratorTable::emitOffsets() const {
   for (const auto &Bucket : getBuckets()) {
     for (const DWARF5AcceleratorTable::HashData *Hash : Bucket)
-      support::endian::write(*StrStream,
-                             static_cast<uint32_t>(Hash->EntryOffset),
-                             llvm::endianness::little);
+      writeOffset(*StrStream, Hash->EntryOffset, Format);
   }
 }
 void DWARF5AcceleratorTable::emitAbbrevs() {
diff --git a/bolt/lib/Core/GDBIndex.cpp b/bolt/lib/Core/GDBIndex.cpp
index 4c34f5ee7fca7..f29fb1735a461 100644
--- a/bolt/lib/Core/GDBIndex.cpp
+++ b/bolt/lib/Core/GDBIndex.cpp
@@ -48,7 +48,7 @@ void GDBIndex::updateGdbIndexSection(
   Data += 24;
 
   // Map CUs offsets to indices and verify existing index table.
-  std::map<uint32_t, uint32_t> OffsetToIndexMap;
+  std::map<uint64_t, uint32_t> OffsetToIndexMap;
   const uint32_t CUListSize = CUTypesOffset - CUListOffset;
   const uint32_t TUListSize = AddressTableOffset - CUTypesOffset;
   const unsigned NUmCUsEncoded = CUListSize / 16;
@@ -133,7 +133,7 @@ void GDBIndex::updateGdbIndexSection(
   write32le(Buffer + 20, ConstantPoolOffset + Delta);
   Buffer += 24;
 
-  using MapEntry = std::pair<uint32_t, CUInfo>;
+  using MapEntry = std::pair<uint64_t, CUInfo>;
   std::vector<MapEntry> CUVector(CUMap.begin(), CUMap.end());
   // Remove the CUs we won't emit anyway.
   CUVector.erase(std::remove_if(CUVector.begin(), CUVector.end(),
@@ -182,8 +182,10 @@ void GDBIndex::updateGdbIndexSection(
   // Writing out CU List <Offset, Size>
   for (auto &CUInfo : CUVector) {
     write64le(Buffer, CUInfo.second.Offset);
-    // Length encoded in CU doesn't contain first 4 bytes that encode length.
-    write64le(Buffer + 8, CUInfo.second.Length + 4);
+    // Length encoded in CU doesn't contain the unit length field.
+    write64le(Buffer + 8,
+              CUInfo.second.Length +
+                  dwarf::getUnitLengthFieldByteSize(CUInfo.second.Format));
     Buffer += 16;
   }
   sortGDBIndexTUEntryVector();
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 31bb74a6488a6..734ce272a73ee 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -250,7 +250,9 @@ class DIEStreamer : public DwarfStreamer {
     llvm::AsmPrinter &Asm = getAsmPrinter();
 
     // Emit size of content not including length itself
-    Asm.emitInt32(Unit.getHeaderSize() + UnitDIE.getSize() - 4);
+    Asm.emitDwarfUnitLength(Unit.getHeaderSize() + UnitDIE.getSize() -
+                                Asm.getUnitLengthFieldByteSize(),
+                            "Length of Unit");
     Asm.emitInt16(Version);
 
     // DWARF v5 reorders the address size and adds a unit type.
@@ -259,7 +261,7 @@ class DIEStreamer : public DwarfStreamer {
       Asm.emitInt8(Asm.MAI.getCodePointerSize());
     }
 
-    Asm.emitInt32(0);
+    Asm.emitDwarfLengthOrOffset(0);
     if (Version <= 4) {
       Asm.emitInt8(Asm.MAI.getCodePointerSize());
     }
@@ -521,6 +523,8 @@ static void emitDWOBuilder(const std::string &DWOName,
   std::unique_ptr<DIEStreamer> Streamer =
       createDIEStreamer(*TheTriple, *ObjOS, "DwoStreamerInitAug2",
                         DWODIEBuilder, GDBIndexSection);
+  Streamer->getAsmPrinter().OutContext.setDwarfFormat(
+      CU.getFormParams().Format);
   if (SplitCU.getContext().getMaxDWOVersion() >= 5) {
     for (DWARFUnit *CU : DWODIEBuilder.getDWARF5TUVector())
       emitUnit(DWODIEBuilder, *Streamer, *CU);
@@ -839,7 +843,8 @@ void DWARFRewriter::createRangeLocListAndAddressWriters() {
     const uint16_t DwarfVersion = CU.getVersion();
     if (DwarfVersion >= 5) {
       auto AddrW = std::make_unique<DebugAddrWriterDwarf5>(
-          &BC, CU.getAddressByteSize(), CU.getAddrOffsetSectionBase());
+          &BC, CU.getAddressByteSize(), CU.getAddrOffsetSectionBase(),
+          CU.getFormParams().Format);
       RangeListsSectionWriter->setAddressWriter(AddrW.get());
       LocListWritersByCU[CU.getOffset()] =
           std::make_unique<DebugLoclistWriter>(CU, DwarfVersion, false, *AddrW);
@@ -906,7 +911,7 @@ void DWARFRewriter::processMainBinaryCU(DWARFUnit &Unit, DIEBuilder &DIEBlder,
   if (DWARFVersion >= 5) {
     LocalWriter.RngListsWriter->setAddressWriter(&AddressWriter);
     RangesBase = RangesSectionWriter.getSectionOffset() +
-                 getDWARF5RngListLocListHeaderSize();
+                 getDWARF5RngListLocListHeaderSize(Unit.getFormParams().Format);
     RangesSectionWriter.initSection(Unit);
   } else if (SplitCU) {
     // DWARF4: only split-dwarf CUs need a ranges base
@@ -1628,8 +1633,7 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
         RangesWriterIterator->second->setDie(&Die);
       } else {
         DIEBldr.replaceValue(&Die, RangesBaseInfo.getAttribute(),
-                             RangesBaseInfo.getForm(),
-                             DIEInteger(static_cast<uint32_t>(*RangesBase)));
+                             RangesBaseInfo.getForm(), DIEInteger(*RangesBase));
       }
       RangesBase = std::nullopt;
     }
@@ -1814,11 +1818,15 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
       continue;
     updateLineTable(*CU);
     emitUnit(DIEBlder, Streamer, *CU);
-    uint32_t StartOffset = CUOffset;
+    uint64_t StartOffset = CUOffset;
     DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU);
     CUOffset += CU->getHeaderSize();
     CUOffset += UnitDIE->getSize();
-    CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};
+    const dwarf::DwarfFormat Format = CU->getFormParams().Format;
+    CUMap[CU->getOffset()] = {StartOffset,
+                              CUOffset - StartOffset -
+                                  dwarf::getUnitLengthFieldByteSize(Format),
+                              Format};
   }
 
   // Emit Type Unit of DWARF 4 to .debug_type section
@@ -2015,12 +2023,18 @@ void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
   }
   // generate debug_info and CUMap
   for (DWARFUnit *CU : CUs) {
+    Streamer.getAsmPrinter().OutContext.setDwarfFormat(
+        CU->getFormParams().Format);
     emitUnit(DIEBlder, Streamer, *CU);
-    const uint32_t StartOffset = CUOffset;
+    const uint64_t StartOffset = CUOffset;
     DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU);
     CUOffset += CU->getHeaderSize();
     CUOffset += UnitDIE->getSize();
-    CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4};
+    const dwarf::DwarfFormat Format = CU->getFormParams().Format;
+    CUMap[CU->getOffset()] = {StartOffset,
+                              CUOffset - StartOffset -
+                                  dwarf::getUnitLengthFieldByteSize(Format),
+                              Format};
   }
 }
 
@@ -2081,11 +2095,15 @@ static void UpdateStrAndStrOffsets(StringRef StrDWOContent,
                                    StringRef StrOffsetsContent,
                                    SmallVectorImpl<StringRef> &StrDWOOutData,
                                    std::string &StrOffsetsOutData,
-                                   unsigned DwarfVersion, bool IsLittleEndian) {
+                                   const DWARFUnit &CU, bool IsLittleEndian) {
   const llvm::endianness Endian =
       IsLittleEndian ? llvm::endianness::little : llvm::endianness::big;
-  const uint64_t HeaderOffset = (DwarfVersion >= 5) ? 8 : 0;
-  constexpr size_t SizeOfOffset = sizeof(int32_t);
+  const dwarf::DwarfFormat Format = CU.getFormParams().Format;
+  uint64_t HeaderOffset = 0;
+  if (CU.getVersion() >= 5) {
+    HeaderOffset = dwarf::getUnitLengthFieldByteSize(Format) + 4;
+  }
+  const size_t SizeOfOffset = dwarf::getDwarfOffsetByteSize(Format);
   const uint64_t NumOffsets =
       (StrOffsetsContent.size() - HeaderOffset) / SizeOfOffset;
 
@@ -2105,7 +2123,8 @@ static void UpdateStrAndStrOffsets(StringRef StrDWOContent,
   std::optional<StringFragment> CurrentFragment;
   uint64_t AccumulatedStrLen = 0;
   for (uint64_t I = 0; I < NumOffsets; ++I) {
-    const uint64_t StrOffset = Extractor.getU32(&ExtractionOffset);
+    const uint64_t StrOffset =
+        Extractor.getUnsigned(&ExtractionOffset, SizeOfOffset);
     const uint64_t StringLength = getStringLength(StrDWOContent, StrOffset);
     if (!CurrentFragment) {
       // First init.
@@ -2125,9 +2144,14 @@ static void UpdateStrAndStrOffsets(StringRef StrDWOContent,
       // Updating str offsets.
       if (StrOffsetsOutData.empty())
         StrOffsetsOutData = StrOffsetsContent.str();
-      llvm::support::endian::write32(
-          &StrOffsetsOutData[HeaderOffset + I * SizeOfOffset],
-          static_cast<uint32_t>(AccumulatedStrLen), Endian);
+      if (Format == dwarf::DwarfFormat::DWARF64)
+        llvm::support::endian::write64(
+            &StrOffsetsOutData[HeaderOffset + I * SizeOfOffset],
+            AccumulatedStrLen, Endian);
+      else
+        llvm::support::endian::write32(
+            &StrOffsetsOutData[HeaderOffset + I * SizeOfOffset],
+            static_cast<uint32_t>(AccumulatedStrLen), Endian);
     }
     AccumulatedStrLen += StringLength;
   }
@@ -2343,7 +2367,7 @@ void DWARFRewriter::writeDWOFiles(
     // .debug_str.dwo slice for a single CU needs to be extracted according to
     // .debug_str_offsets.dwo.
     UpdateStrAndStrOffsets(StrDWOContent, StrOffsetsContent, StrDWOOutData,
-                           StrOffsetsOutData, CU.getVersion(),
+                           StrOffsetsOutData, CU,
                            (*DWOCU)->getContext().isLittleEndian());
     auto SectionIter = KnownSections.find("debug_str.dwo");
     if (SectionIter != KnownSections.end()) {
diff --git a/bolt/test/X86/dwarf64-debug-info-aranges.test b/bolt/test/X86/dwarf64-debug-info-aranges.test
new file mode 100644
index 0000000000000..c71764f76b653
--- /dev/null
+++ b/bolt/test/X86/dwarf64-debug-info-aranges.test
@@ -0,0 +1,46 @@
+# REQUIRES: system-linux
+
+# RUN: rm -rf %t
+# RUN: split-file %s %t
+# RUN: %clang %cflags -gdwarf-5 -gdwarf64 -Wl,-q -Wl,-e,main \
+# RUN:   %t/main.c -o %t.exe
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections --keep-aranges
+# RUN: llvm-dwarfdump --debug-info --debug-aranges --debug-line %t.bolt | \
+# RUN:   FileCheck %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+## BOLT must preserve DWARF64 .debug_info, .debug_aranges, and .debug_line
+## contributions whose offsets use the DWARF64 offset size.
+
+# CHECK-LABEL: .debug_info contents:
+# CHECK: Compile Unit: length = 0x{{[0-9a-f]+}}, format = DWARF64, version = 0x0005
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_ranges
+# CHECK-SAME: rangelist =
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_name{{.*}}"helper"
+# CHECK: DW_AT_type{{.*}}"int"
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_name{{.*}}"main"
+# CHECK: DW_AT_type{{.*}}"int"
+# CHECK: DW_TAG_base_type
+# CHECK: DW_AT_name{{.*}}"int"
+
+# CHECK-LABEL: .debug_aranges contents:
+# CHECK: Address Range Header: length = 0x{{[0-9a-f]+}}, format = DWARF64, version = 0x0002, cu_offset = 0x0000000000000000, addr_size = 0x08, seg_size = 0x00
+# CHECK: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}})
+# CHECK: [0x{{[0-9a-f]+}}, 0x{{[0-9a-f]+}})
+
+# CHECK-LABEL: .debug_line contents:
+# CHECK: total_length:
+# CHECK-NEXT: format: DWARF64
+# CHECK: version: 5
+
+#--- main.c
+int helper(int x) {
+  return x + 1;
+}
+
+int main(void) {
+  return helper(41);
+}
diff --git a/bolt/test/X86/dwarf64-debug-names.test b/bolt/test/X86/dwarf64-debug-names.test
new file mode 100644
index 0000000000000..601afec7b0f43
--- /dev/null
+++ b/bolt/test/X86/dwarf64-debug-names.test
@@ -0,0 +1,111 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t.o -o %t.exe
+# RUN: llvm-dwarfdump --debug-info %t.exe | FileCheck --check-prefix=INPUT %s
+# RUN: llvm-bolt %t.exe --update-debug-sections --create-debug-names-section \
+# RUN:   -o %t.bolt
+# RUN: llvm-dwarfdump --debug-info --debug-names %t.bolt | \
+# RUN:   FileCheck --check-prefix=BOLT %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+# INPUT-LABEL: .debug_info contents:
+# INPUT: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# INPUT: DW_AT_name{{.*}}"dwarf64-debug-names.s"
+# INPUT: DW_TAG_subprogram
+# INPUT: DW_AT_name{{.*}}"main"
+# INPUT: DW_TAG_subprogram
+# INPUT: DW_AT_name{{.*}}"helper"
+
+# BOLT-LABEL: .debug_info contents:
+# BOLT: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# BOLT: DW_AT_name{{.*}}"dwarf64-debug-names.s"
+# BOLT: DW_TAG_subprogram
+# BOLT: DW_AT_name{{.*}}"main"
+# BOLT: DW_TAG_subprogram
+# BOLT: DW_AT_name{{.*}}"helper"
+
+# BOLT-LABEL: .debug_names contents:
+# BOLT: Header {
+# BOLT: Format: DWARF64
+# BOLT: CU count: 1
+# BOLT: Name count: 2
+# BOLT: CU[0]: 0x00000000
+# BOLT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT: String: {{.*}} "main"
+# BOLT: DW_IDX_die_offset: 0x
+# BOLT: String: {{.*}} "helper"
+# BOLT: DW_IDX_die_offset: 0x
+
+  .text
+  .globl main
+  .type main, at function
+main:
+  callq helper
+  retq
+.Lmain_end:
+  .size main, .Lmain_end-main
+
+  .globl helper
+  .type helper, at function
+helper:
+  movl $42, %eax
+  retq
+.Lhelper_end:
+  .size helper, .Lhelper_end-helper
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x13                      # DW_AT_language
+  .byte 0x05                      # DW_FORM_data2
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x01                      # DW_FORM_addr
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu_end-.Lcu_start       # DWARF64 unit length
+.Lcu_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev                  # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .quad .Lstr_file                # DW_AT_name
+  .short 0x000c                   # DW_LANG_C99
+  .byte 2                         # DW_TAG_subprogram
+  .quad .Lstr_main                # DW_AT_name
+  .quad main                      # DW_AT_low_pc
+  .long .Lmain_end-main           # DW_AT_high_pc
+  .byte 2                         # DW_TAG_subprogram
+  .quad .Lstr_helper              # DW_AT_name
+  .quad helper                    # DW_AT_low_pc
+  .long .Lhelper_end-helper       # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_file:
+  .asciz "dwarf64-debug-names.s"
+.Lstr_main:
+  .asciz "main"
+.Lstr_helper:
+  .asciz "helper"
diff --git a/bolt/test/X86/dwarf64-loclists.test b/bolt/test/X86/dwarf64-loclists.test
new file mode 100644
index 0000000000000..704c861d81de3
--- /dev/null
+++ b/bolt/test/X86/dwarf64-loclists.test
@@ -0,0 +1,166 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t.o -o %t.exe
+# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | \
+# RUN:   FileCheck --check-prefix=INPUT %s
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --show-form --verbose --debug-addr --debug-loclists \
+# RUN:   --debug-info %t.bolt | FileCheck --check-prefix=BOLT %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+## Check that BOLT rewrites a DWARF64 v5 loclistx location list and that the
+## decoded PC range tracks the rewritten function address.
+
+# INPUT-LABEL: .debug_info contents:
+# INPUT: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# INPUT: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000000000014)
+# INPUT: DW_TAG_variable
+# INPUT: DW_AT_location [DW_FORM_loclistx]
+# INPUT-SAME: loclist = 0x0000001c
+
+# BOLT-LABEL: .debug_info contents:
+# BOLT: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# BOLT: DW_AT_loclists_base [DW_FORM_sec_offset] (0x0000000000000014)
+# BOLT: DW_TAG_variable
+# BOLT: DW_AT_location [DW_FORM_loclistx]
+# BOLT-SAME: loclist = 0x0000001c
+# BOLT-NEXT: [
+# BOLT-SAME: 0x[[#%.16x,ADDR:]]
+# BOLT-SAME: 0x[[#ADDR + 3]]
+
+# BOLT-LABEL: .debug_loclists contents:
+# BOLT: locations list header: length = 0x{{[0-9a-f]+}}, format = DWARF64
+# BOLT: 0x0000001c:
+# BOLT-NEXT: DW_LLE_startx_length
+# BOLT-SAME: 0x0000000000000003
+# BOLT-SAME: DW_OP_reg0 RAX
+
+# BOLT-LABEL: .debug_addr contents:
+# BOLT: Address table header: length = 0x{{[0-9a-f]+}}, format = DWARF64
+# BOLT: Addrs: [
+# BOLT-NEXT: 0x[[#ADDR]]
+# BOLT-NEXT: 0x0000000000000000
+
+  .text
+  .globl main
+  .type main, at function
+main:
+.Lfunc_begin0:
+  .file 0 "." "dwarf64-loclists.s"
+  .loc 0 1 0
+  xorl %eax, %eax
+  .loc 0 2 0
+  retq
+.Lfunc_end0:
+  .size main, .Lfunc_end0-main
+
+  .section .debug_loclists,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Ldebug_list_end-.Ldebug_list_start
+.Ldebug_list_start:
+  .short 5                        # Version
+  .byte 8                         # Address size
+  .byte 0                         # Segment selector size
+  .long 1                         # Offset entry count
+.Lloclists_table_base0:
+  .quad .Ldebug_loc0-.Lloclists_table_base0
+.Ldebug_loc0:
+  .byte 4                         # DW_LLE_offset_pair
+  .uleb128 .Lfunc_begin0-.Lfunc_begin0
+  .uleb128 .Lfunc_end0-.Lfunc_begin0
+  .byte 1                         # Loc expr size
+  .byte 0x50                      # DW_OP_reg0
+  .byte 0                         # DW_LLE_end_of_list
+.Ldebug_list_end:
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x73                      # DW_AT_addr_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .ascii "\214\001"               # DW_AT_loclists_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 3                         # Abbrev code
+  .byte 0x34                      # DW_TAG_variable
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x02                      # DW_AT_location
+  .byte 0x22                      # DW_FORM_loclistx
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu_end-.Lcu_start       # DWARF64 unit length
+.Lcu_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev                  # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .quad .Lstr_file                # DW_AT_name
+  .quad .Lline_table_start0       # DW_AT_stmt_list
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+  .quad .Laddr_table_base0        # DW_AT_addr_base
+  .quad .Lloclists_table_base0    # DW_AT_loclists_base
+  .byte 2                         # DW_TAG_subprogram
+  .quad .Lstr_main                # DW_AT_name
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+  .byte 3                         # DW_TAG_variable
+  .quad .Lstr_x                   # DW_AT_name
+  .byte 0                         # DW_AT_location
+  .byte 0                         # End subprogram children
+  .byte 0                         # End CU children
+.Lcu_end:
+
+  .section .debug_addr,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Ldebug_addr_end-.Ldebug_addr_start
+.Ldebug_addr_start:
+  .short 5                        # Version
+  .byte 8                         # Address size
+  .byte 0                         # Segment selector size
+.Laddr_table_base0:
+  .quad .Lfunc_begin0
+.Ldebug_addr_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_file:
+  .asciz "dwarf64-loclists.s"
+.Lstr_main:
+  .asciz "main"
+.Lstr_x:
+  .asciz "x"
+
+  .section .debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf64-lowpc-highpc-convert.test b/bolt/test/X86/dwarf64-lowpc-highpc-convert.test
new file mode 100644
index 0000000000000..10e192c0c431e
--- /dev/null
+++ b/bolt/test/X86/dwarf64-lowpc-highpc-convert.test
@@ -0,0 +1,143 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t.o -o %t.exe
+# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | \
+# RUN:   FileCheck --check-prefix=INPUT %s
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections \
+# RUN:   --always-convert-to-ranges
+# RUN: llvm-dwarfdump --show-form --verbose --debug-addr --debug-rnglists \
+# RUN:   --debug-info %t.bolt | FileCheck --check-prefix=BOLT %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+## Check that BOLT rewrites a DWARF64 v5 CU with addrx low_pc/high_pc into
+## DWARF64 rnglists and that the decoded range uses the rewritten PC address.
+
+# INPUT-LABEL: .debug_info contents:
+# INPUT: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# INPUT: DW_AT_low_pc [DW_FORM_addrx]{{.*}}(indexed (00000000)
+# INPUT-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000003)
+# INPUT: DW_TAG_subprogram
+# INPUT: DW_AT_low_pc [DW_FORM_addrx]{{.*}}(indexed (00000000)
+# INPUT-NEXT: DW_AT_high_pc [DW_FORM_data4] (0x00000003)
+
+# BOLT-LABEL: .debug_info contents:
+# BOLT: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# BOLT: DW_AT_low_pc [DW_FORM_addrx]
+# BOLT-SAME: address = 0x0000000000000000
+# BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx]
+# BOLT-SAME: rangelist = 0x00000024
+# BOLT-NEXT: [
+# BOLT-SAME: 0x[[#%.16x,ADDR:]]
+# BOLT-SAME: 0x[[#ADDR + 3]]
+# BOLT: DW_AT_addr_base [DW_FORM_sec_offset]
+# BOLT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000000000014)
+# BOLT: DW_TAG_subprogram
+# BOLT: DW_AT_ranges [DW_FORM_rnglistx]
+# BOLT-SAME: rangelist = 0x00000028
+# BOLT-NEXT: [
+# BOLT-SAME: 0x[[#ADDR]]
+# BOLT-SAME: 0x[[#ADDR + 3]]
+
+# BOLT-LABEL: .debug_addr contents:
+# BOLT: Address table header: length = 0x{{[0-9a-f]+}}, format = DWARF64
+# BOLT: Addrs: [
+# BOLT-NEXT: 0x[[#ADDR]]
+# BOLT-NEXT: 0x0000000000000000
+
+# BOLT-LABEL: .debug_rnglists contents:
+# BOLT: range list header: length = 0x{{[0-9a-f]+}}, format = DWARF64
+# BOLT: 0x0000000000000010 => 0x00000024
+# BOLT: 0x0000000000000014 => 0x00000028
+# BOLT: 0x00000024: [DW_RLE_startx_length]:
+# BOLT-SAME: [0x[[#ADDR]], 0x[[#ADDR + 3]])
+# BOLT: 0x00000028: [DW_RLE_startx_length]:
+# BOLT-SAME: [0x[[#ADDR]], 0x[[#ADDR + 3]])
+
+  .text
+  .globl main
+  .type main, at function
+main:
+.Lfunc_begin0:
+  .file 0 "." "dwarf64-lowpc-highpc-convert.s"
+  .loc 0 1 0
+  pushq %rbp
+  .loc 0 2 0
+  popq %rbp
+  .loc 0 3 0
+  retq
+.Lfunc_end0:
+  .size main, .Lfunc_end0-main
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x73                      # DW_AT_addr_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu_end-.Lcu_start       # DWARF64 unit length
+.Lcu_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev                  # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .quad .Lstr_file                # DW_AT_name
+  .quad .Lline_table_start0       # DW_AT_stmt_list
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+  .quad .Laddr_table_base0        # DW_AT_addr_base
+  .byte 2                         # DW_TAG_subprogram
+  .quad .Lstr_main                # DW_AT_name
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu_end:
+
+  .section .debug_addr,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Ldebug_addr_end-.Ldebug_addr_start
+.Ldebug_addr_start:
+  .short 5                        # Version
+  .byte 8                         # Address size
+  .byte 0                         # Segment selector size
+.Laddr_table_base0:
+  .quad .Lfunc_begin0
+.Ldebug_addr_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_file:
+  .asciz "dwarf64-lowpc-highpc-convert.s"
+.Lstr_main:
+  .asciz "main"
+
+  .section .debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf64-ref-addr.test b/bolt/test/X86/dwarf64-ref-addr.test
new file mode 100644
index 0000000000000..4d75fcddd99da
--- /dev/null
+++ b/bolt/test/X86/dwarf64-ref-addr.test
@@ -0,0 +1,134 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t.o -o %t.exe
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt | \
+# RUN:   FileCheck %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+## Check that a DWARF64 DW_FORM_ref_addr inside .debug_info is cloned and
+## rewritten as an 8-byte debug-info offset.
+
+# CHECK-LABEL: .debug_info contents:
+# CHECK: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name [DW_FORM_strp]{{.*}}"main-cu"
+# CHECK: DW_TAG_variable
+# CHECK: DW_AT_name [DW_FORM_strp]{{.*}}"global"
+# CHECK: DW_AT_type [DW_FORM_ref_addr] (0x{{[0-9a-f]+}} "int")
+# CHECK: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# CHECK: DW_TAG_compile_unit
+# CHECK: DW_AT_name [DW_FORM_strp]{{.*}}"type-cu"
+# CHECK: DW_TAG_base_type
+# CHECK: DW_AT_name [DW_FORM_strp]{{.*}}"int"
+
+  .text
+  .globl main
+  .type main, at function
+main:
+.Lfunc_begin0:
+  .file 0 "." "dwarf64-ref-addr.s"
+  .loc 0 1 0
+  xorl %eax, %eax
+  retq
+.Lfunc_end0:
+  .size main, .Lfunc_end0-main
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x01                      # DW_FORM_addr
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x34                      # DW_TAG_variable
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x49                      # DW_AT_type
+  .byte 0x10                      # DW_FORM_ref_addr
+  .byte 0
+  .byte 0
+  .byte 3                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0
+  .byte 0
+  .byte 4                         # Abbrev code
+  .byte 0x24                      # DW_TAG_base_type
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x3e                      # DW_AT_encoding
+  .byte 0x0b                      # DW_FORM_data1
+  .byte 0x0b                      # DW_AT_byte_size
+  .byte 0x0b                      # DW_FORM_data1
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+.Lcu0_begin:
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu0_end-.Lcu0_start     # DWARF64 unit length
+.Lcu0_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev                  # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .quad .Lstr_main_cu             # DW_AT_name
+  .quad .Lline_table_start0       # DW_AT_stmt_list
+  .quad main                      # DW_AT_low_pc
+  .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+  .byte 2                         # DW_TAG_variable
+  .quad .Lstr_global              # DW_AT_name
+  .quad .Lint_die                 # DW_AT_type
+  .byte 0                         # End children
+.Lcu0_end:
+
+.Lcu1_begin:
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu1_end-.Lcu1_start     # DWARF64 unit length
+.Lcu1_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev                  # Abbrev offset
+  .byte 3                         # DW_TAG_compile_unit
+  .quad .Lstr_type_cu             # DW_AT_name
+  .quad .Lline_table_start0       # DW_AT_stmt_list
+.Lint_die:
+  .byte 4                         # DW_TAG_base_type
+  .quad .Lstr_int                 # DW_AT_name
+  .byte 0x05                      # DW_ATE_signed
+  .byte 4                         # DW_AT_byte_size
+  .byte 0                         # End children
+.Lcu1_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_main_cu:
+  .asciz "main-cu"
+.Lstr_type_cu:
+  .asciz "type-cu"
+.Lstr_global:
+  .asciz "global"
+.Lstr_int:
+  .asciz "int"
+
+  .section .debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf64-split-dwarf.test b/bolt/test/X86/dwarf64-split-dwarf.test
new file mode 100644
index 0000000000000..085c9a407f251
--- /dev/null
+++ b/bolt/test/X86/dwarf64-split-dwarf.test
@@ -0,0 +1,56 @@
+# REQUIRES: system-linux
+
+# RUN: rm -rf %t
+# RUN: split-file %s %t
+# RUN: %clang %cflags -gdwarf-5 -gdwarf64 -gsplit-dwarf=split -c \
+# RUN:   %t/main.c -o %t/main.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t/main.o -o %t.exe
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-info --debug-str-offsets --dwo %t.bolt | \
+# RUN:   FileCheck --check-prefix=BOLT %s
+# RUN: llvm-dwarfdump --debug-str-offsets %t/main.dwo.dwo | \
+# RUN:   FileCheck --check-prefix=DWO %s
+# RUN: llvm-dwarfdump --verify %t.bolt %t/main.dwo.dwo
+
+## Check DWARF64 split-DWARF rewriting.
+
+# BOLT-LABEL: .debug_info contents:
+# BOLT: Compile Unit: length = 0x{{[0-9a-f]+}}, format = DWARF64, version = 0x0005, unit_type = DW_UT_skeleton
+# BOLT: DW_TAG_skeleton_unit
+# BOLT: DW_AT_dwo_name{{.*}}"{{.*}}main.dwo.dwo"
+# BOLT: DW_AT_ranges
+# BOLT: DW_AT_rnglists_base
+
+# BOLT: DW_TAG_compile_unit
+# BOLT: DW_TAG_subprogram
+# BOLT: DW_AT_low_pc{{.*}}0x{{[0-9a-f]+}}
+# BOLT: DW_AT_name{{.*}}"helper"
+# BOLT: DW_TAG_subprogram
+# BOLT: DW_AT_name{{.*}}"main"
+# BOLT: DW_AT_low_pc{{.*}}0x{{[0-9a-f]+}}
+# BOLT: DW_TAG_variable
+# BOLT: DW_AT_name{{.*}}"global"
+# BOLT: DW_TAG_base_type
+# BOLT: DW_AT_name{{.*}}"int"
+
+# BOLT-LABEL: .debug_str_offsets contents:
+# BOLT: Contribution size = {{[0-9]+}}, Format = DWARF64, Version = 5
+# BOLT: "{{.*}}main.dwo.dwo"
+
+# DWO-LABEL: .debug_str_offsets.dwo contents:
+# DWO: Contribution size = {{[0-9]+}}, Format = DWARF64, Version = 5
+# DWO: "global"
+# DWO: "int"
+# DWO: "helper"
+# DWO: "main"
+
+#--- main.c
+int global;
+
+int helper(int x) {
+  return global + x;
+}
+
+int main(void) {
+  return helper(1);
+}
diff --git a/bolt/test/X86/dwarf64-str-offsets.test b/bolt/test/X86/dwarf64-str-offsets.test
new file mode 100644
index 0000000000000..2d8cfd348a428
--- /dev/null
+++ b/bolt/test/X86/dwarf64-str-offsets.test
@@ -0,0 +1,144 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t.o -o %t.exe
+# RUN: llvm-dwarfdump --show-form --verbose --debug-info \
+# RUN:   --debug-str-offsets %t.exe | FileCheck --check-prefix=INPUT %s
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --show-form --verbose --debug-info \
+# RUN:   --debug-str-offsets %t.bolt | FileCheck --check-prefix=BOLT %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+## Check that BOLT preserves DWARF64 .debug_str_offsets contributions and keeps
+## DW_FORM_strx references decodable after rewriting debug info.
+
+# INPUT-LABEL: .debug_info contents:
+# INPUT: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# INPUT: DW_AT_producer [DW_FORM_strx1] (indexed (00000000) string = "producer")
+# INPUT: DW_AT_name [DW_FORM_strx1] (indexed (00000001) string = "dwarf64-str-offsets.s")
+# INPUT: DW_TAG_subprogram
+# INPUT: DW_AT_name [DW_FORM_strx1] (indexed (00000003) string = "main")
+# INPUT-LABEL: .debug_str_offsets contents:
+# INPUT: Contribution size = 36, Format = DWARF64, Version = 5
+
+# BOLT-LABEL: .debug_info contents:
+# BOLT: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# BOLT: DW_AT_producer [DW_FORM_strx1] (indexed (00000000) string = "producer")
+# BOLT: DW_AT_name [DW_FORM_strx1] (indexed (00000001) string = "dwarf64-str-offsets.s")
+# BOLT: DW_TAG_subprogram
+# BOLT: DW_AT_name [DW_FORM_strx1] (indexed (00000003) string = "main")
+# BOLT-LABEL: .debug_str_offsets contents:
+# BOLT: Contribution size = 36, Format = DWARF64, Version = 5
+  .text
+  .globl main
+  .type main, at function
+main:
+.Lfunc_begin0:
+  .file 0 "." "dwarf64-str-offsets.s"
+  .loc 0 1 0
+  xorl %eax, %eax
+  retq
+.Lfunc_end0:
+  .size main, .Lfunc_end0-main
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x25                      # DW_AT_producer
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x13                      # DW_AT_language
+  .byte 0x05                      # DW_FORM_data2
+  .byte 0x03                      # DW_AT_name
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x72                      # DW_AT_str_offsets_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x1b                      # DW_AT_comp_dir
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x73                      # DW_AT_addr_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu_end-.Lcu_start       # DWARF64 unit length
+.Lcu_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev                  # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .byte 0                         # DW_AT_producer
+  .short 0x000c                   # DW_LANG_C99
+  .byte 1                         # DW_AT_name
+  .quad .Lstr_offsets_base0       # DW_AT_str_offsets_base
+  .quad .Lline_table_start0       # DW_AT_stmt_list
+  .byte 2                         # DW_AT_comp_dir
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+  .quad .Laddr_table_base0        # DW_AT_addr_base
+  .byte 2                         # DW_TAG_subprogram
+  .byte 3                         # DW_AT_name
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu_end:
+
+  .section .debug_str_offsets,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lstr_offsets_end-.Lstr_offsets_start
+.Lstr_offsets_start:
+  .short 5                        # Version
+  .short 0                        # Padding
+.Lstr_offsets_base0:
+  .quad .Lstr_producer
+  .quad .Lstr_file
+  .quad .Lstr_comp_dir
+  .quad .Lstr_main
+.Lstr_offsets_end:
+
+  .section .debug_addr,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Ldebug_addr_end-.Ldebug_addr_start
+.Ldebug_addr_start:
+  .short 5                        # Version
+  .byte 8                         # Address size
+  .byte 0                         # Segment selector size
+.Laddr_table_base0:
+  .quad .Lfunc_begin0
+.Ldebug_addr_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_producer:
+  .asciz "producer"
+.Lstr_file:
+  .asciz "dwarf64-str-offsets.s"
+.Lstr_comp_dir:
+  .asciz "."
+.Lstr_main:
+  .asciz "main"
+
+  .section .debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/mixed-dwarf32-dwarf64-debug-names.test b/bolt/test/X86/mixed-dwarf32-dwarf64-debug-names.test
new file mode 100644
index 0000000000000..1d55204fd8776
--- /dev/null
+++ b/bolt/test/X86/mixed-dwarf32-dwarf64-debug-names.test
@@ -0,0 +1,173 @@
+# REQUIRES: system-linux
+
+# RUN: rm -rf %t
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %t/dwarf32.s \
+# RUN:   -o %t/dwarf32.o
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %t/dwarf64.s \
+# RUN:   -o %t/dwarf64.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t/dwarf32.o %t/dwarf64.o -o %t.exe
+# RUN: llvm-dwarfdump --debug-info %t.exe | FileCheck --check-prefix=INPUT %s
+# RUN: llvm-bolt %t.exe --update-debug-sections --create-debug-names-section \
+# RUN:   -o %t.bolt
+# RUN: llvm-dwarfdump --debug-info --debug-names %t.bolt | \
+# RUN:   FileCheck --check-prefix=BOLT %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+# INPUT-LABEL: .debug_info contents:
+# INPUT: Compile Unit:{{.*}} format = DWARF32
+# INPUT: DW_AT_name{{.*}}"dwarf32.s"
+# INPUT: DW_TAG_subprogram
+# INPUT: DW_AT_name{{.*}}"main"
+# INPUT: Compile Unit:{{.*}} format = DWARF64
+# INPUT: DW_AT_name{{.*}}"dwarf64.s"
+# INPUT: DW_TAG_subprogram
+# INPUT: DW_AT_name{{.*}}"bar"
+
+# BOLT-LABEL: .debug_info contents:
+# BOLT: Compile Unit:{{.*}} format = DWARF32
+# BOLT: DW_AT_name{{.*}}"dwarf32.s"
+# BOLT: DW_TAG_subprogram
+# BOLT: DW_AT_name{{.*}}"main"
+# BOLT: Compile Unit:{{.*}} format = DWARF64
+# BOLT: DW_AT_name{{.*}}"dwarf64.s"
+# BOLT: DW_TAG_subprogram
+# BOLT: DW_AT_name{{.*}}"bar"
+
+# BOLT-LABEL: .debug_names contents:
+# BOLT: Header {
+# BOLT: Format: DWARF64
+# BOLT: CU count: 2
+# BOLT: Name count: 2
+# BOLT: Compilation Unit offsets [
+# BOLT: CU[0]: 0x00000000
+# BOLT: CU[1]: [[CU1:0x[0-9a-f]+]]
+# BOLT: DW_IDX_compile_unit: DW_FORM_data1
+# BOLT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT: String: {{.*}} "bar"
+# BOLT: DW_IDX_compile_unit: 0x01
+# BOLT: DW_IDX_die_offset: [[#%#x,BAR_DIE:]]
+# BOLT: String: {{.*}} "main"
+# BOLT: DW_IDX_compile_unit: 0x00
+# BOLT: DW_IDX_die_offset: [[#%#x,MAIN_DIE:]]
+
+#--- dwarf32.s
+  .text
+  .globl main
+  .type main, at function
+main:
+  callq bar
+  retq
+.Lmain_end:
+  .size main, .Lmain_end-main
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev32:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x13                      # DW_AT_language
+  .byte 0x05                      # DW_FORM_data2
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x01                      # DW_FORM_addr
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+.Lcu32_begin:
+  .long .Lcu32_end-.Lcu32_start   # DWARF32 unit length
+.Lcu32_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .long .Labbrev32                # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .long .Lstr_dwarf32             # DW_AT_name
+  .short 0x000c                   # DW_LANG_C99
+  .byte 2                         # DW_TAG_subprogram
+  .long .Lstr_main                # DW_AT_name
+  .quad main                      # DW_AT_low_pc
+  .long .Lmain_end-main           # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu32_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_dwarf32:
+  .asciz "dwarf32.s"
+.Lstr_main:
+  .asciz "main"
+
+#--- dwarf64.s
+  .text
+  .globl bar
+  .type bar, at function
+bar:
+  movl $42, %eax
+  retq
+.Lbar_end:
+  .size bar, .Lbar_end-bar
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev64:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x13                      # DW_AT_language
+  .byte 0x05                      # DW_FORM_data2
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x01                      # DW_FORM_addr
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+.Lcu64_begin:
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu64_end-.Lcu64_start   # DWARF64 unit length
+.Lcu64_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev64                # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .quad .Lstr_dwarf64             # DW_AT_name
+  .short 0x000c                   # DW_LANG_C99
+  .byte 2                         # DW_TAG_subprogram
+  .quad .Lstr_bar                 # DW_AT_name
+  .quad bar                       # DW_AT_low_pc
+  .long .Lbar_end-bar             # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu64_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_dwarf64:
+  .asciz "dwarf64.s"
+.Lstr_bar:
+  .asciz "bar"
diff --git a/bolt/test/X86/mixed-dwarf32-dwarf64-rnglists.test b/bolt/test/X86/mixed-dwarf32-dwarf64-rnglists.test
new file mode 100644
index 0000000000000..282af6d02565e
--- /dev/null
+++ b/bolt/test/X86/mixed-dwarf32-dwarf64-rnglists.test
@@ -0,0 +1,241 @@
+# REQUIRES: system-linux
+
+# RUN: rm -rf %t
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %t/dwarf32.s \
+# RUN:   -o %t/dwarf32.o
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %t/dwarf64.s \
+# RUN:   -o %t/dwarf64.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t/dwarf32.o %t/dwarf64.o -o %t.exe
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections \
+# RUN:   --always-convert-to-ranges
+# RUN: llvm-dwarfdump --show-form --verbose --debug-info --debug-addr \
+# RUN:   --debug-rnglists %t.bolt | FileCheck %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+## Check that mixed-format binaries keep per-CU DWARF32/DWARF64 encoding for
+## regenerated .debug_rnglists and .debug_addr contributions.
+
+# CHECK-LABEL: .debug_info contents:
+# CHECK: Compile Unit:{{.*}} format = DWARF32, version = 0x0005
+# CHECK: DW_AT_name [DW_FORM_strp]{{.*}}"dwarf32.s"
+# CHECK: DW_AT_low_pc [DW_FORM_addrx]
+# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx]
+# CHECK-SAME: rangelist =
+# CHECK-NEXT: [
+# CHECK-SAME: [[MAIN_BEGIN:0x[0-9a-f]+]]
+# CHECK-SAME: [[MAIN_END:0x[0-9a-f]+]]
+# CHECK: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x{{[0-9a-f]+}})
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_name [DW_FORM_strp]{{.*}}"main"
+# CHECK: DW_AT_ranges [DW_FORM_rnglistx]
+# CHECK-SAME: rangelist =
+# CHECK-NEXT: [
+# CHECK-SAME: [[MAIN_BEGIN]]
+# CHECK-SAME: [[MAIN_END]]
+# CHECK: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# CHECK: DW_AT_name [DW_FORM_strp]{{.*}}"dwarf64.s"
+# CHECK: DW_AT_low_pc [DW_FORM_addrx]
+# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx]
+# CHECK-SAME: rangelist =
+# CHECK-NEXT: [
+# CHECK-SAME: [[BAR_BEGIN:0x[0-9a-f]+]]
+# CHECK-SAME: [[BAR_END:0x[0-9a-f]+]]
+# CHECK: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x{{[0-9a-f]+}})
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_name [DW_FORM_strp]{{.*}}"bar"
+# CHECK: DW_AT_ranges [DW_FORM_rnglistx]
+# CHECK-SAME: rangelist =
+# CHECK-NEXT: [
+# CHECK-SAME: [[BAR_BEGIN]]
+# CHECK-SAME: [[BAR_END]]
+
+# CHECK-LABEL: .debug_addr contents:
+# CHECK: Address table header: length = 0x{{[0-9a-f]+}}, format = DWARF32
+# CHECK: Addrs: [
+# CHECK-NEXT: [[MAIN_BEGIN]]
+# CHECK-NEXT: 0x0000000000000000
+# CHECK: Address table header: length = 0x{{[0-9a-f]+}}, format = DWARF64
+# CHECK: Addrs: [
+# CHECK-NEXT: [[BAR_BEGIN]]
+# CHECK-NEXT: 0x0000000000000000
+
+# CHECK-LABEL: .debug_rnglists contents:
+# CHECK: range list header: length = 0x{{[0-9a-f]+}}, format = DWARF32
+# CHECK: 0x{{[0-9a-f]+}} => 0x{{[0-9a-f]+}}
+# CHECK: [DW_RLE_startx_length]:
+# CHECK: range list header: length = 0x{{[0-9a-f]+}}, format = DWARF64
+# CHECK: 0x{{[0-9a-f]+}} => 0x{{[0-9a-f]+}}
+# CHECK: [DW_RLE_startx_length]:
+
+#--- dwarf32.s
+  .text
+  .globl main
+  .type main, at function
+main:
+.Lfunc32_begin:
+  .file 0 "." "dwarf32.s"
+  .loc 0 1 0
+  callq bar
+  .loc 0 2 0
+  retq
+.Lfunc32_end:
+  .size main, .Lfunc32_end-main
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev32:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x73                      # DW_AT_addr_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+  .long .Lcu32_end-.Lcu32_start   # DWARF32 unit length
+.Lcu32_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .long .Labbrev32                # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .long .Lstr_dwarf32             # DW_AT_name
+  .long .Lline_table_start32      # DW_AT_stmt_list
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc32_end-.Lfunc32_begin # DW_AT_high_pc
+  .long .Laddr_table_base32       # DW_AT_addr_base
+  .byte 2                         # DW_TAG_subprogram
+  .long .Lstr_main                # DW_AT_name
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc32_end-.Lfunc32_begin # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu32_end:
+
+  .section .debug_addr,"", at progbits
+  .long .Ldebug_addr32_end-.Ldebug_addr32_start
+.Ldebug_addr32_start:
+  .short 5                        # Version
+  .byte 8                         # Address size
+  .byte 0                         # Segment selector size
+.Laddr_table_base32:
+  .quad .Lfunc32_begin
+.Ldebug_addr32_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_dwarf32:
+  .asciz "dwarf32.s"
+.Lstr_main:
+  .asciz "main"
+
+  .section .debug_line,"", at progbits
+.Lline_table_start32:
+
+#--- dwarf64.s
+  .text
+  .globl bar
+  .type bar, at function
+bar:
+.Lfunc64_begin:
+  .file 0 "." "dwarf64.s"
+  .loc 0 1 0
+  movl $42, %eax
+  .loc 0 2 0
+  retq
+.Lfunc64_end:
+  .size bar, .Lfunc64_end-bar
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev64:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x73                      # DW_AT_addr_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x0e                      # DW_FORM_strp
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu64_end-.Lcu64_start   # DWARF64 unit length
+.Lcu64_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev64                # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .quad .Lstr_dwarf64             # DW_AT_name
+  .quad .Lline_table_start64      # DW_AT_stmt_list
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc64_end-.Lfunc64_begin # DW_AT_high_pc
+  .quad .Laddr_table_base64       # DW_AT_addr_base
+  .byte 2                         # DW_TAG_subprogram
+  .quad .Lstr_bar                 # DW_AT_name
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc64_end-.Lfunc64_begin # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu64_end:
+
+  .section .debug_addr,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Ldebug_addr64_end-.Ldebug_addr64_start
+.Ldebug_addr64_start:
+  .short 5                        # Version
+  .byte 8                         # Address size
+  .byte 0                         # Segment selector size
+.Laddr_table_base64:
+  .quad .Lfunc64_begin
+.Ldebug_addr64_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_dwarf64:
+  .asciz "dwarf64.s"
+.Lstr_bar:
+  .asciz "bar"
+
+  .section .debug_line,"", at progbits
+.Lline_table_start64:
diff --git a/bolt/test/X86/mixed-dwarf32-dwarf64-str-offsets.test b/bolt/test/X86/mixed-dwarf32-dwarf64-str-offsets.test
new file mode 100644
index 0000000000000..ed3d9acd8189c
--- /dev/null
+++ b/bolt/test/X86/mixed-dwarf32-dwarf64-str-offsets.test
@@ -0,0 +1,269 @@
+# REQUIRES: system-linux
+
+# RUN: rm -rf %t
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %t/dwarf32.s \
+# RUN:   -o %t/dwarf32.o
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %t/dwarf64.s \
+# RUN:   -o %t/dwarf64.o
+# RUN: %clang %cflags -Wl,-q -Wl,-e,main %t/dwarf32.o %t/dwarf64.o -o %t.exe
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --show-form --verbose --debug-info \
+# RUN:   --debug-str-offsets %t.bolt | FileCheck %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+## Check that BOLT keeps each .debug_str_offsets contribution in its CU's
+## original DWARF format when a binary contains both DWARF32 and DWARF64 units.
+
+# CHECK-LABEL: .debug_info contents:
+# CHECK: Compile Unit:{{.*}} format = DWARF32, version = 0x0005
+# CHECK: DW_AT_producer [DW_FORM_strx1] (indexed (00000000) string = "producer32")
+# CHECK: DW_AT_name [DW_FORM_strx1] (indexed (00000001) string = "dwarf32.s")
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_name [DW_FORM_strx1] (indexed (00000003) string = "main")
+# CHECK: Compile Unit:{{.*}} format = DWARF64, version = 0x0005
+# CHECK: DW_AT_producer [DW_FORM_strx1] (indexed (00000000) string = "producer64")
+# CHECK: DW_AT_name [DW_FORM_strx1] (indexed (00000001) string = "dwarf64.s")
+# CHECK: DW_TAG_subprogram
+# CHECK: DW_AT_name [DW_FORM_strx1] (indexed (00000003) string = "bar")
+
+# CHECK-LABEL: .debug_str_offsets contents:
+# CHECK: Contribution size = 20, Format = DWARF32, Version = 5
+# CHECK: 0x{{[0-9a-f]+}}: 00000000 "producer32"
+# CHECK: 0x{{[0-9a-f]+}}: {{[0-9a-f]+}} "dwarf32.s"
+# CHECK: 0x{{[0-9a-f]+}}: {{[0-9a-f]+}} "."
+# CHECK: 0x{{[0-9a-f]+}}: {{[0-9a-f]+}} "main"
+# CHECK: Contribution size = 36, Format = DWARF64, Version = 5
+# CHECK: 0x{{[0-9a-f]+}}: {{[0-9a-f]+}} "producer64"
+# CHECK: 0x{{[0-9a-f]+}}: {{[0-9a-f]+}} "dwarf64.s"
+# CHECK: 0x{{[0-9a-f]+}}: {{[0-9a-f]+}} "."
+# CHECK: 0x{{[0-9a-f]+}}: {{[0-9a-f]+}} "bar"
+
+#--- dwarf32.s
+  .text
+  .globl main
+  .type main, at function
+main:
+.Lfunc32_begin:
+  .file 0 "." "dwarf32.s"
+  .loc 0 1 0
+  callq bar
+  .loc 0 2 0
+  retq
+.Lfunc32_end:
+  .size main, .Lfunc32_end-main
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev32:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x25                      # DW_AT_producer
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x13                      # DW_AT_language
+  .byte 0x05                      # DW_FORM_data2
+  .byte 0x03                      # DW_AT_name
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x72                      # DW_AT_str_offsets_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x1b                      # DW_AT_comp_dir
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x73                      # DW_AT_addr_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+  .long .Lcu32_end-.Lcu32_start   # DWARF32 unit length
+.Lcu32_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .long .Labbrev32                # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .byte 0                         # DW_AT_producer
+  .short 0x000c                   # DW_LANG_C99
+  .byte 1                         # DW_AT_name
+  .long .Lstr_offsets_base32      # DW_AT_str_offsets_base
+  .long .Lline_table_start32      # DW_AT_stmt_list
+  .byte 2                         # DW_AT_comp_dir
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc32_end-.Lfunc32_begin # DW_AT_high_pc
+  .long .Laddr_table_base32       # DW_AT_addr_base
+  .byte 2                         # DW_TAG_subprogram
+  .byte 3                         # DW_AT_name
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc32_end-.Lfunc32_begin # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu32_end:
+
+  .section .debug_str_offsets,"", at progbits
+  .long .Lstr_offsets32_end-.Lstr_offsets32_start
+.Lstr_offsets32_start:
+  .short 5                        # Version
+  .short 0                        # Padding
+.Lstr_offsets_base32:
+  .long .Lstr_producer32
+  .long .Lstr_file32
+  .long .Lstr_comp_dir32
+  .long .Lstr_main
+.Lstr_offsets32_end:
+
+  .section .debug_addr,"", at progbits
+  .long .Ldebug_addr32_end-.Ldebug_addr32_start
+.Ldebug_addr32_start:
+  .short 5                        # Version
+  .byte 8                         # Address size
+  .byte 0                         # Segment selector size
+.Laddr_table_base32:
+  .quad .Lfunc32_begin
+.Ldebug_addr32_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_producer32:
+  .asciz "producer32"
+.Lstr_file32:
+  .asciz "dwarf32.s"
+.Lstr_comp_dir32:
+  .asciz "."
+.Lstr_main:
+  .asciz "main"
+
+  .section .debug_line,"", at progbits
+.Lline_table_start32:
+
+#--- dwarf64.s
+  .text
+  .globl bar
+  .type bar, at function
+bar:
+.Lfunc64_begin:
+  .file 0 "." "dwarf64.s"
+  .loc 0 1 0
+  movl $42, %eax
+  .loc 0 2 0
+  retq
+.Lfunc64_end:
+  .size bar, .Lfunc64_end-bar
+
+  .section .debug_abbrev,"", at progbits
+.Labbrev64:
+  .byte 1                         # Abbrev code
+  .byte 0x11                      # DW_TAG_compile_unit
+  .byte 1                         # DW_CHILDREN_yes
+  .byte 0x25                      # DW_AT_producer
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x13                      # DW_AT_language
+  .byte 0x05                      # DW_FORM_data2
+  .byte 0x03                      # DW_AT_name
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x72                      # DW_AT_str_offsets_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x10                      # DW_AT_stmt_list
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0x1b                      # DW_AT_comp_dir
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x73                      # DW_AT_addr_base
+  .byte 0x17                      # DW_FORM_sec_offset
+  .byte 0
+  .byte 0
+  .byte 2                         # Abbrev code
+  .byte 0x2e                      # DW_TAG_subprogram
+  .byte 0                         # DW_CHILDREN_no
+  .byte 0x03                      # DW_AT_name
+  .byte 0x25                      # DW_FORM_strx1
+  .byte 0x11                      # DW_AT_low_pc
+  .byte 0x1b                      # DW_FORM_addrx
+  .byte 0x12                      # DW_AT_high_pc
+  .byte 0x06                      # DW_FORM_data4
+  .byte 0x3f                      # DW_AT_external
+  .byte 0x19                      # DW_FORM_flag_present
+  .byte 0
+  .byte 0
+  .byte 0
+
+  .section .debug_info,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lcu64_end-.Lcu64_start   # DWARF64 unit length
+.Lcu64_start:
+  .short 5                        # Version
+  .byte 1                         # DW_UT_compile
+  .byte 8                         # Address size
+  .quad .Labbrev64                # Abbrev offset
+  .byte 1                         # DW_TAG_compile_unit
+  .byte 0                         # DW_AT_producer
+  .short 0x000c                   # DW_LANG_C99
+  .byte 1                         # DW_AT_name
+  .quad .Lstr_offsets_base64      # DW_AT_str_offsets_base
+  .quad .Lline_table_start64      # DW_AT_stmt_list
+  .byte 2                         # DW_AT_comp_dir
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc64_end-.Lfunc64_begin # DW_AT_high_pc
+  .quad .Laddr_table_base64       # DW_AT_addr_base
+  .byte 2                         # DW_TAG_subprogram
+  .byte 3                         # DW_AT_name
+  .byte 0                         # DW_AT_low_pc
+  .long .Lfunc64_end-.Lfunc64_begin # DW_AT_high_pc
+  .byte 0                         # End children
+.Lcu64_end:
+
+  .section .debug_str_offsets,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Lstr_offsets64_end-.Lstr_offsets64_start
+.Lstr_offsets64_start:
+  .short 5                        # Version
+  .short 0                        # Padding
+.Lstr_offsets_base64:
+  .quad .Lstr_producer64
+  .quad .Lstr_file64
+  .quad .Lstr_comp_dir64
+  .quad .Lstr_bar
+.Lstr_offsets64_end:
+
+  .section .debug_addr,"", at progbits
+  .long 0xffffffff                # DWARF64 marker
+  .quad .Ldebug_addr64_end-.Ldebug_addr64_start
+.Ldebug_addr64_start:
+  .short 5                        # Version
+  .byte 8                         # Address size
+  .byte 0                         # Segment selector size
+.Laddr_table_base64:
+  .quad .Lfunc64_begin
+.Ldebug_addr64_end:
+
+  .section .debug_str,"MS", at progbits,1
+.Lstr_producer64:
+  .asciz "producer64"
+.Lstr_file64:
+  .asciz "dwarf64.s"
+.Lstr_comp_dir64:
+  .asciz "."
+.Lstr_bar:
+  .asciz "bar"
+
+  .section .debug_line,"", at progbits
+.Lline_table_start64:

>From 1372b92961c46bd8d765b0dc690623b2f1e40dd9 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Mon, 29 Jun 2026 17:25:57 +0800
Subject: [PATCH 2/4] fix format

---
 bolt/lib/Core/DebugNames.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp
index 42f6e9edd8d11..7ee01a59cae08 100644
--- a/bolt/lib/Core/DebugNames.cpp
+++ b/bolt/lib/Core/DebugNames.cpp
@@ -25,7 +25,7 @@ static void writeOffset(raw_ostream &OS, uint64_t Value,
     support::endian::write(OS, Value, llvm::endianness::little);
   else
     support::endian::write(OS, static_cast<uint32_t>(Value),
-                         llvm::endianness::little);
+                           llvm::endianness::little);
 }
 
 DWARF5AcceleratorTable::DWARF5AcceleratorTable(
@@ -115,7 +115,8 @@ void DWARF5AcceleratorTable::setCurrentUnit(DWARFUnit &Unit,
   CurrentUnit = nullptr;
   CurrentUnitOffset = UnitStartOffset;
   // .debug_names is emitted as a single contribution, so mixed DWARF32/DWARF64
-  // inputs need one common section offset size. Use DWARF64 if any unit is DWARF64.
+  // inputs need one common section offset size. Use DWARF64 if any unit is
+  // DWARF64.
   if (Unit.getFormParams().Format == dwarf::DwarfFormat::DWARF64)
     Format = dwarf::DwarfFormat::DWARF64;
   std::optional<uint64_t> DWOID = Unit.getDWOId();
@@ -784,7 +785,7 @@ static constexpr uint32_t getDebugNamesHeaderSize() {
 
 void DWARF5AcceleratorTable::emitHeader() const {
   constexpr uint32_t HeaderSize = getDebugNamesHeaderSize();
-  // .debug_names Header 
+  // .debug_names Header
   // Length (DWARF64 needs escaped marker)
   if (Format == dwarf::DwarfFormat::DWARF64)
     support::endian::write(*FullTableStream, dwarf::DW_LENGTH_DWARF64,

>From 0bac4f6dd928f4ccb9a877270560ac103ebf5c6d Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Thu, 9 Jul 2026 20:17:53 +0800
Subject: [PATCH 3/4] double check and fix

---
 bolt/include/bolt/Core/DebugData.h        |   2 +-
 bolt/include/bolt/Rewrite/DWARFRewriter.h |   2 +-
 bolt/lib/Core/DebugData.cpp               |  10 +-
 bolt/lib/Rewrite/DWARFRewriter.cpp        |   6 +-
 bolt/test/X86/dwarf64-types.test          | 137 ++++++++++++++++++++++
 5 files changed, 146 insertions(+), 11 deletions(-)
 create mode 100644 bolt/test/X86/dwarf64-types.test

diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index 7462ec87068ea..565fddcf70324 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -684,7 +684,7 @@ class BinaryPatcher {
 /// the contents of a certain portion with a string or an integer.
 class SimpleBinaryPatcher : public BinaryPatcher {
 private:
-  std::vector<std::pair<uint32_t, std::string>> Patches;
+  std::vector<std::pair<uint64_t, std::string>> Patches;
 
   /// Adds a patch to replace the contents of \p ByteSize bytes with the integer
   /// \p NewValue encoded in little-endian, with the least-significant byte
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index 3c6e90cf27e93..b70f098ac9980 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -111,7 +111,7 @@ class DWARFRewriter {
   enum class DWARFVersion { DWARFLegacy, DWARF5 };
 
   /// Used to track last CU offset for GDB Index.
-  uint32_t CUOffset{0};
+  uint64_t CUOffset{0};
 
   llvm::ThreadPoolInterface &
   getOrCreateDebugInfoThreadPool(unsigned ThreadCount);
diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
index 6a27d630cd0f6..51e2fd4804d2b 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -238,8 +238,8 @@ getDWARF5Header(const LocListsRangelistsHeader &Header) {
 
 struct OffsetEntry {
   uint32_t Index;
-  uint32_t StartOffset;
-  uint32_t EndOffset;
+  uint64_t StartOffset;
+  uint64_t EndOffset;
 };
 template <typename DebugVector, typename ListEntry, typename DebugAddressEntry>
 static bool emitWithBase(raw_ostream &OS, const DebugVector &Entries,
@@ -259,8 +259,8 @@ static bool emitWithBase(raw_ostream &OS, const DebugVector &Entries,
     // In case rnglists or loclists are not sorted.
     if (Base > Entry.LowPC)
       break;
-    uint32_t StartOffset = Entry.LowPC - Base;
-    uint32_t EndOffset = Entry.HighPC - Base;
+    uint64_t StartOffset = Entry.LowPC - Base;
+    uint64_t EndOffset = Entry.HighPC - Base;
     if (encodeULEB128(EndOffset, TempBuffer) > 2)
       break;
     Offsets.push_back({Index, StartOffset, EndOffset});
@@ -861,7 +861,7 @@ void SimpleBinaryPatcher::addLE32Patch(uint64_t Offset, uint32_t NewValue,
 std::string SimpleBinaryPatcher::patchBinary(StringRef BinaryContents) {
   std::string BinaryContentsStr = std::string(BinaryContents);
   for (const auto &Patch : Patches) {
-    uint32_t Offset = Patch.first;
+    uint64_t Offset = Patch.first;
     const std::string &ByteSequence = Patch.second;
     assert(Offset + ByteSequence.size() <= BinaryContents.size() &&
            "Applied patch runs over binary size.");
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 734ce272a73ee..847291c8e2ea2 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -501,6 +501,8 @@ createDIEStreamer(const Triple &TheTriple, raw_pwrite_stream &OutFile,
 static void emitUnit(DIEBuilder &DIEBldr, DIEStreamer &Streamer,
                      DWARFUnit &Unit) {
   DIE *UnitDIE = DIEBldr.getUnitDIEbyUnit(Unit);
+  Streamer.getAsmPrinter().OutContext.setDwarfFormat(
+      Unit.getFormParams().Format);
   Streamer.emitUnit(Unit, *UnitDIE);
 }
 
@@ -523,8 +525,6 @@ static void emitDWOBuilder(const std::string &DWOName,
   std::unique_ptr<DIEStreamer> Streamer =
       createDIEStreamer(*TheTriple, *ObjOS, "DwoStreamerInitAug2",
                         DWODIEBuilder, GDBIndexSection);
-  Streamer->getAsmPrinter().OutContext.setDwarfFormat(
-      CU.getFormParams().Format);
   if (SplitCU.getContext().getMaxDWOVersion() >= 5) {
     for (DWARFUnit *CU : DWODIEBuilder.getDWARF5TUVector())
       emitUnit(DWODIEBuilder, *Streamer, *CU);
@@ -2023,8 +2023,6 @@ void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder,
   }
   // generate debug_info and CUMap
   for (DWARFUnit *CU : CUs) {
-    Streamer.getAsmPrinter().OutContext.setDwarfFormat(
-        CU->getFormParams().Format);
     emitUnit(DIEBlder, Streamer, *CU);
     const uint64_t StartOffset = CUOffset;
     DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU);
diff --git a/bolt/test/X86/dwarf64-types.test b/bolt/test/X86/dwarf64-types.test
new file mode 100644
index 0000000000000..d5dfcfd52be37
--- /dev/null
+++ b/bolt/test/X86/dwarf64-types.test
@@ -0,0 +1,137 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t.o
+# RUN: %clang %cflags -no-pie %t.o -o %t.exe -Wl,-q
+# RUN: llvm-dwarfdump --debug-types %t.exe | FileCheck --check-prefix=INPUT %s
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-types %t.bolt | FileCheck --check-prefix=BOLT %s
+# RUN: llvm-dwarfdump --verify %t.bolt
+
+## BOLT must preserve DWARF64 type unit headers when rewriting .debug_types.
+
+# INPUT-LABEL: .debug_types contents:
+# INPUT: Type Unit: length = 0x{{[0-9a-f]+}}, format = DWARF64, version = 0x0004
+# INPUT-SAME: name = 'Foo'
+# INPUT: DW_TAG_type_unit
+# INPUT: DW_TAG_structure_type
+# INPUT: DW_AT_name{{.*}}"Foo"
+
+# BOLT-LABEL: .debug_types contents:
+# BOLT: Type Unit: length = 0x{{[0-9a-f]+}}, format = DWARF64, version = 0x0004
+# BOLT-SAME: name = 'Foo'
+# BOLT: DW_TAG_type_unit
+# BOLT: DW_TAG_structure_type
+# BOLT: DW_AT_name{{.*}}"Foo"
+
+	.text
+	.file	"dwarf64-types.s"
+	.file	1 "/" "dwarf64-types.s"
+	.globl	main
+	.type	main, at function
+main:
+	.loc	1 1 0
+	pushq	%rbp
+	movq	%rsp, %rbp
+	xorl	%eax, %eax
+	popq	%rbp
+	retq
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Lcu_end0-.Lcu_start0
+.Lcu_start0:
+	.short	4
+	.long	.debug_abbrev
+	.byte	8
+	.byte	1
+	.long	.Lstr_producer-.Ldebug_str
+	.short	12
+	.long	.Lstr_cu_name-.Ldebug_str
+	.quad	main
+	.long	.Lfunc_end0-main
+	.long	0
+	.byte	2
+	.quad	main
+	.long	.Lfunc_end0-main
+	.long	.Lstr_main-.Ldebug_str
+	.byte	0
+.Lcu_end0:
+
+	.section	.debug_types,"", at progbits
+.Ltypes_begin0:
+	.long	0xffffffff
+	.quad	.Ltypes_end0-.Ltypes_start0
+.Ltypes_start0:
+	.short	4
+	.quad	0
+	.byte	8
+	.quad	0x123456789abcdef0
+	.quad	.Ltype_die0-.Ltypes_begin0
+	.byte	3
+	.short	12
+.Ltype_die0:
+	.byte	4
+	.quad	.Lstr_foo-.Ldebug_str
+	.byte	8
+	.byte	0
+.Ltypes_end0:
+
+	.section	.debug_abbrev,"", at progbits
+	.byte	1
+	.byte	17
+	.byte	1
+	.byte	37
+	.byte	14
+	.byte	19
+	.byte	5
+	.byte	3
+	.byte	14
+	.byte	17
+	.byte	1
+	.byte	18
+	.byte	6
+	.byte	16
+	.byte	23
+	.byte	0
+	.byte	0
+	.byte	2
+	.byte	46
+	.byte	0
+	.byte	17
+	.byte	1
+	.byte	18
+	.byte	6
+	.byte	3
+	.byte	14
+	.byte	0
+	.byte	0
+	.byte	3
+	.byte	65
+	.byte	1
+	.byte	19
+	.byte	5
+	.byte	0
+	.byte	0
+	.byte	4
+	.byte	19
+	.byte	0
+	.byte	3
+	.byte	14
+	.byte	11
+	.byte	11
+	.byte	0
+	.byte	0
+	.byte	0
+
+	.section	.debug_str,"MS", at progbits,1
+.Ldebug_str:
+.Lstr_producer:
+	.asciz	"hand-written DWARF64 type test"
+.Lstr_cu_name:
+	.asciz	"dwarf64-types.s"
+.Lstr_main:
+	.asciz	"main"
+.Lstr_foo:
+	.asciz	"Foo"

>From 0057d740d0768edfe3c18a410ee6959afea13085 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Fri, 10 Jul 2026 17:19:51 +0800
Subject: [PATCH 4/4] fix temporary solution

---
 bolt/include/bolt/Core/DebugData.h | 4 ----
 bolt/lib/Core/DebugData.cpp        | 8 ++++++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h
index 565fddcf70324..fa729f401a848 100644
--- a/bolt/include/bolt/Core/DebugData.h
+++ b/bolt/include/bolt/Core/DebugData.h
@@ -443,10 +443,6 @@ class DebugAddrWriterDwarf5 : public DebugAddrWriter {
   }
 
 private:
-  // TODO: This is a temporary solution.
-  uint32_t getHeaderSize() const {
-    return dwarf::getUnitLengthFieldByteSize(Format) + 4;
-  }
   std::optional<uint64_t> AddrOffsetSectionBase = std::nullopt;
   dwarf::DwarfFormat Format = dwarf::DwarfFormat::DWARF32;
 };
diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp
index 51e2fd4804d2b..aa7db9607b158 100644
--- a/bolt/lib/Core/DebugData.cpp
+++ b/bolt/lib/Core/DebugData.cpp
@@ -131,6 +131,10 @@ writeAddressRanges(raw_svector_ostream &Stream,
   return AddressRanges.size() * 16 + 16;
 }
 
+static uint32_t getHeaderSize(dwarf::DwarfFormat Format) {
+  return dwarf::getUnitLengthFieldByteSize(Format) + 4;
+}
+
 DebugRangesSectionWriter::DebugRangesSectionWriter() {
   RangesBuffer = std::make_unique<DebugBufferVector>();
   RangesStream = std::make_unique<raw_svector_ostream>(*RangesBuffer);
@@ -507,7 +511,7 @@ void DebugAddrWriterDwarf5::updateAddrBase(DIEBuilder &DIEBlder, DWARFUnit &CU,
                                            const uint64_t Offset) {
   /// Header for DWARF5 has size 8 bytes in DWARF32 or 16 bytes in DWARF64,
   /// so we add it to the offset.
-  updateAddressBase(DIEBlder, *this, CU, Offset + getHeaderSize());
+  updateAddressBase(DIEBlder, *this, CU, Offset + getHeaderSize(Format));
 }
 
 DenseMap<uint64_t, uint64_t> DebugAddrWriter::UnmodifiedAddressOffsets;
@@ -530,7 +534,7 @@ DebugAddrWriterDwarf5::finalize(const size_t BufferSize) {
     if (!AddrOffsetSectionBase)
       return std::nullopt;
     // Address base offset is to the first entry.
-    uint64_t Offset = *AddrOffsetSectionBase - getHeaderSize();
+    uint64_t Offset = *AddrOffsetSectionBase - getHeaderSize(Format);
     auto Iter = UnmodifiedAddressOffsets.find(Offset);
     if (Iter != UnmodifiedAddressOffsets.end())
       return Iter->second;



More information about the llvm-commits mailing list