[lld] [lld][ELF] Implement merged .debug_names section (PR #88092)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 15 14:05:58 PDT 2024


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/88092

>From 6a046c3a67c284a6e3f1634dc92e0c528bf9409c Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 25 Mar 2024 00:00:27 -0700
Subject: [PATCH 01/23] [lld][ELF] Implement merged .debug_names section.

Update LLD to be able to generate a single merged .debug_names section (rather
than a set of appended sections). Option is controlled by a new flag, --debug-names.
Does not handle type units yet (coming soon).
---
 lld/ELF/Config.h                              |   1 +
 lld/ELF/DWARF.cpp                             |   1 +
 lld/ELF/DWARF.h                               |   4 +
 lld/ELF/Driver.cpp                            |   3 +
 lld/ELF/Options.td                            |   4 +
 lld/ELF/SyntheticSections.cpp                 | 758 ++++++++++++++++++
 lld/ELF/SyntheticSections.h                   | 134 ++++
 lld/docs/ld.lld.1                             |   4 +
 lld/test/ELF/Inputs/debug-names-2.s           | 191 +++++
 .../ELF/Inputs/debug-names-parent-idx-2.s     | 347 ++++++++
 lld/test/ELF/debug-names-bad-aug-string.s     | 189 +++++
 lld/test/ELF/debug-names-bad-die-idx-sizes.s  | 151 ++++
 lld/test/ELF/debug-names-bad-name-count.s     | 154 ++++
 lld/test/ELF/debug-names-bad-offsets-sizes.s  | 153 ++++
 lld/test/ELF/debug-names-bad-version.s        | 173 ++++
 lld/test/ELF/debug-names-invalid-attribute.s  | 179 +++++
 lld/test/ELF/debug-names-parent-idx.s         | 549 +++++++++++++
 lld/test/ELF/debug-names.s                    | 294 +++++++
 18 files changed, 3289 insertions(+)
 create mode 100644 lld/test/ELF/Inputs/debug-names-2.s
 create mode 100644 lld/test/ELF/Inputs/debug-names-parent-idx-2.s
 create mode 100644 lld/test/ELF/debug-names-bad-aug-string.s
 create mode 100644 lld/test/ELF/debug-names-bad-die-idx-sizes.s
 create mode 100644 lld/test/ELF/debug-names-bad-name-count.s
 create mode 100644 lld/test/ELF/debug-names-bad-offsets-sizes.s
 create mode 100644 lld/test/ELF/debug-names-bad-version.s
 create mode 100644 lld/test/ELF/debug-names-invalid-attribute.s
 create mode 100644 lld/test/ELF/debug-names-parent-idx.s
 create mode 100644 lld/test/ELF/debug-names.s

diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 83f293ab2ce578..33bfa42b0fcbf0 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -229,6 +229,7 @@ struct Config {
   bool cref;
   llvm::SmallVector<std::pair<llvm::GlobPattern, uint64_t>, 0>
       deadRelocInNonAlloc;
+  bool debugNames;
   bool demangle = true;
   bool dependentLibraries;
   bool disableVerify;
diff --git a/lld/ELF/DWARF.cpp b/lld/ELF/DWARF.cpp
index ac28aa8c7ca6e0..5d58e0c60a952e 100644
--- a/lld/ELF/DWARF.cpp
+++ b/lld/ELF/DWARF.cpp
@@ -40,6 +40,7 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
                 .Case(".debug_gnu_pubtypes", &gnuPubtypesSection)
                 .Case(".debug_line", &lineSection)
                 .Case(".debug_loclists", &loclistsSection)
+                .Case(".debug_names", &namesSection)
                 .Case(".debug_ranges", &rangesSection)
                 .Case(".debug_rnglists", &rnglistsSection)
                 .Case(".debug_str_offsets", &strOffsetsSection)
diff --git a/lld/ELF/DWARF.h b/lld/ELF/DWARF.h
index ada38a043bc22a..64c25c706c3437 100644
--- a/lld/ELF/DWARF.h
+++ b/lld/ELF/DWARF.h
@@ -62,6 +62,9 @@ template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
   const LLDDWARFSection &getGnuPubtypesSection() const override {
     return gnuPubtypesSection;
   }
+  const LLDDWARFSection &getNamesSection() const override {
+    return namesSection;
+  }
 
   StringRef getFileName() const override { return ""; }
   StringRef getAbbrevSection() const override { return abbrevSection; }
@@ -87,6 +90,7 @@ template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
   LLDDWARFSection infoSection;
   LLDDWARFSection lineSection;
   LLDDWARFSection loclistsSection;
+  LLDDWARFSection namesSection;
   LLDDWARFSection rangesSection;
   LLDDWARFSection rnglistsSection;
   LLDDWARFSection strOffsetsSection;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 86cc09621a9129..5fffdc51f34ddf 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -442,6 +442,8 @@ static void checkOptions() {
       error("-r and -pie may not be used together");
     if (config->exportDynamic)
       error("-r and --export-dynamic may not be used together");
+    if (config->debugNames)
+      error("-r and --debug-names may not be used together");
   }
 
   if (config->executeOnly) {
@@ -1234,6 +1236,7 @@ static void readConfigs(opt::InputArgList &args) {
   config->cref = args.hasArg(OPT_cref);
   config->optimizeBBJumps =
       args.hasFlag(OPT_optimize_bb_jumps, OPT_no_optimize_bb_jumps, false);
+  config->debugNames = args.hasFlag(OPT_debug_names, OPT_no_debug_names, false);
   config->demangle = args.hasFlag(OPT_demangle, OPT_no_demangle, true);
   config->dependencyFile = args.getLastArgValue(OPT_dependency_file);
   config->dependentLibraries = args.hasFlag(OPT_dependent_libraries, OPT_no_dependent_libraries, true);
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index c5e95d0d25c1ae..d470646ed0eeef 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -153,6 +153,10 @@ def : Flag<["--"], "no-color-diagnostics">, Alias<color_diagnostics>, AliasArgs<
 def cref: FF<"cref">,
   HelpText<"Output cross reference table. If -Map is specified, print to the map file">;
 
+defm debug_names: BB<"debug-names",
+    "Generate a merged .debug_names section",
+    "Do not generate a merged .debug_names section (default)">;
+
 defm demangle: B<"demangle",
     "Demangle symbol names (default)",
     "Do not demangle symbol names">;
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 0d7f393a9f3f4d..d440410faa54f4 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -14,6 +14,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SyntheticSections.h"
+
 #include "Config.h"
 #include "DWARF.h"
 #include "EhFrame.h"
@@ -34,7 +35,9 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/Support/DJB.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/LEB128.h"
 #include "llvm/Support/Parallel.h"
@@ -2711,6 +2714,759 @@ static uint32_t computeGdbHash(StringRef s) {
   return h;
 }
 
+DebugNamesSection::DebugNamesSection()
+    : SyntheticSection(0, SHT_PROGBITS, 1, ".debug_names") {}
+
+template <class ELFT, class RelTy>
+void DebugNamesSection::getNameRelocsImpl(
+    InputSection *sec, ArrayRef<RelTy> rels,
+    llvm::DenseMap<uint32_t, uint32_t> &relocs) {
+  for (auto &rel : rels) {
+    Symbol &sym = sec->getFile<ELFT>()->getRelocTargetSym(rel);
+    relocs[rel.r_offset] = sym.getVA(getAddend<ELFT>(rel));
+  }
+}
+
+template <class ELFT>
+void DebugNamesSection::getNameRelocs(
+    InputSectionBase *base, llvm::DenseMap<uint32_t, uint32_t> &relocs) {
+  auto *sec = cast<InputSection>(base);
+  const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>();
+  if (rels.areRelocsRel())
+    getNameRelocsImpl<ELFT>(sec, rels.rels, relocs);
+  else
+    getNameRelocsImpl<ELFT>(sec, rels.relas, relocs);
+}
+
+void DebugNamesSection::writeTo(uint8_t *buf) { invokeELFT(writeToImpl, buf); }
+
+template <class ELFT> void DebugNamesSection::writeToImpl(uint8_t *buf) {
+  SmallVector<uint32_t, 0> mergedCuOffsets;
+  SmallVector<uint32_t, 0> mergedTuOffsets;
+  llvm::DenseMap<uint32_t, uint32_t> strOffsets;
+  SmallVector<llvm::DenseMap<uint32_t, uint32_t>, 0> chunksRelocs;
+  chunksRelocs.reserve(numChunks);
+
+  for (size_t i = 0; i < numChunks; ++i) {
+    DebugNamesOutputChunk &chunk = outputChunks[i];
+    InputSectionBase *base = inputDebugNamesSections[i];
+    llvm::DenseMap<uint32_t, uint32_t> relocs;
+    getNameRelocs<ELFT>(base, relocs);
+    chunksRelocs.push_back(std::move(relocs));
+
+    // Update CuOffsets list with new data
+    for (uint32_t cuOffset : chunk.compilationUnits)
+      mergedCuOffsets.push_back(chunk.sec->outSecOff + cuOffset);
+
+    // TODO: Update TuOffsets list with new data
+  }
+
+  // Update the entries with the relocated string offsets.
+  for (auto &stringEntry : mergedEntries) {
+    uint32_t oldOffset = stringEntry.stringOffsetOffset;
+    uint32_t idx = stringEntry.chunkIdx;
+    stringEntry.relocatedEntryOffset = chunksRelocs[idx][oldOffset];
+  }
+
+  // Write out bytes for merged section.
+
+  // Write the header.
+  endian::write32<ELFT::Endianness>(buf + 0, mergedHdr.UnitLength);
+  endian::write16<ELFT::Endianness>(buf + 4, mergedHdr.Version);
+  endian::write32<ELFT::Endianness>(buf + 8, mergedHdr.CompUnitCount);
+  endian::write32<ELFT::Endianness>(buf + 12,
+                                          mergedHdr.LocalTypeUnitCount);
+  endian::write32<ELFT::Endianness>(buf + 16,
+                                          mergedHdr.ForeignTypeUnitCount);
+  endian::write32<ELFT::Endianness>(buf + 20, mergedHdr.BucketCount);
+  endian::write32<ELFT::Endianness>(buf + 24, mergedHdr.NameCount);
+  endian::write32<ELFT::Endianness>(buf + 28, mergedHdr.AbbrevTableSize);
+  endian::write32<ELFT::Endianness>(buf + 32,
+                                          mergedHdr.AugmentationStringSize);
+  buf += 36;
+  memcpy(buf, mergedHdr.AugmentationString.c_str(), 8);
+  buf += 8;
+
+  // Write the CU list.
+  for (uint32_t offset : mergedCuOffsets) {
+    endian::write32<ELFT::Endianness>(buf + 0, offset);
+    buf += 4;
+  }
+
+  // Write the local TU list.
+  // TODO: Fix this, once we get everything working without TUs.
+  if (mergedHdr.LocalTypeUnitCount != 0)
+    warn(".debug_names: type units are not handled in merged index");
+
+  // Write the foreign TU list.
+  // Currently LLVM does not emit foreign type units, so there should
+  // be nothing here to emit.
+  // TODO: Fix this, once we get everything working wtihout TUs.
+  if (mergedHdr.ForeignTypeUnitCount != 0)
+    warn(".debug_names: type units are not handled in merged index");
+
+  // Write the hash table.
+  // ... Write the buckets
+  uint32_t idx = 1;
+  for (const auto &bucket : bucketList) {
+    if (!bucket.empty())
+      endian::write32<ELFT::Endianness>(buf + 0, idx);
+    idx += bucket.size();
+    buf += 4;
+  }
+
+  // ...Write the hashes
+  for (const auto &bucket : bucketList) {
+    for (const auto &entry : bucket) {
+      uint32_t hashValue = entry->hashValue;
+      endian::write32<ELFT::Endianness>(buf + 0, hashValue);
+      buf += 4;
+    }
+  }
+
+  // Write the string offsets.
+  for (const auto &entry : mergedEntries) {
+    endian::write32<ELFT::Endianness>(buf + 0,
+                                            entry.relocatedEntryOffset);
+    buf += 4;
+  }
+
+  // Write the entry offsets.
+  for (const auto &entry : mergedEntries) {
+    endian::write32<ELFT::Endianness>(buf + 0, entry.entryOffset);
+    buf += 4;
+  }
+
+  // Write the abbrev table.
+  for (const auto *abbrev : mergedAbbrevTable) {
+    size_t uleb_size = encodeULEB128(abbrev->code, buf);
+    buf += uleb_size;
+    uleb_size = encodeULEB128(abbrev->tag, buf);
+    buf += uleb_size;
+    for (auto attr : abbrev->attributes) {
+      uleb_size = encodeULEB128(attr.Index, buf);
+      buf += uleb_size;
+      uleb_size = encodeULEB128(attr.Form, buf);
+      buf += uleb_size;
+    }
+    endian::write16<ELFT::Endianness>(buf + 0, 0); // attribute sentinels.
+    buf += 2;
+  }
+  *buf++ = 0; // abbrev table sentinel
+
+  // Write the entry pool.
+  for (const auto &stringEntry : mergedEntries) {
+    // Write all the entries for the string.
+    size_t uleb_size;
+    for (const auto &entry : stringEntry.indexEntries) {
+      uleb_size = encodeULEB128(entry->abbrevCode, buf);
+      buf += uleb_size;
+      for (const auto &value : entry->attrValues) {
+        if (value.attrSize > 0) {
+          endian::write32<ELFT::Endianness>(buf + 0, value.attrValue);
+          buf += value.attrSize;
+        }
+      }
+    }
+    *buf++ = 0; // Entry sentinel
+  }
+}
+
+bool DebugNamesSection::isNeeded() const { return numChunks > 0; }
+
+template <class ELFT>
+static void
+readCompileUnitOffsets(struct DebugNamesSection::DebugNamesSectionData &secData,
+                       DebugNamesSection::DebugNamesInputChunk &inputChunk,
+                       DebugNamesSection::DebugNamesOutputChunk &outputChunk,
+                       llvm::DWARFDataExtractor &namesExtractor) {
+  uint64_t offset = secData.locs.CUsBase;
+  uint64_t *offsetPtr = &offset;
+  for (size_t i = 0; i < secData.hdr.CompUnitCount; ++i) {
+    llvm::Error err = llvm::Error::success();
+    uint32_t value = namesExtractor.getU32(offsetPtr, &err);
+    if (err)
+      errorOrWarn(toString(inputChunk.namesSection->sec) +
+                  ": error reading CU offsets: " + toString(std::move(err)));
+    else
+      outputChunk.compilationUnits.push_back(value);
+  }
+}
+
+template <class ELFT>
+static void
+readEntryOffsets(struct DebugNamesSection::DebugNamesSectionData &secData,
+                 DebugNamesSection::DebugNamesInputChunk &chunk,
+                 llvm::DWARFDataExtractor &namesExtractor) {
+  secData.entryOffsets = std::make_unique<uint32_t[]>(secData.hdr.NameCount);
+  if (secData.locs.EntryOffsetsBase >= namesExtractor.getData().size())
+    errorOrWarn(toString(chunk.namesSection->sec) +
+                ": invalid entry offsets input");
+
+  uint64_t offset = secData.locs.EntryOffsetsBase;
+  uint64_t *offsetPtr = &offset;
+  for (size_t i = 0; i < secData.hdr.NameCount; ++i) {
+    llvm::Error err = llvm::Error::success();
+    uint32_t value = namesExtractor.getU32(offsetPtr, &err);
+    if (err)
+      errorOrWarn(toString(chunk.namesSection->sec) +
+                  ": error reading entry offsets: " + toString(std::move(err)));
+    else
+      secData.entryOffsets.get()[i] = value;
+  }
+}
+
+template <class ELFT>
+static void readAttributeValues(
+    SmallVector<DebugNamesSection::AttrValueData, 3> &values,
+    DebugNamesSection::DebugNamesInputChunk &chunk, uint64_t &offset,
+    struct DebugNamesSection::DebugNamesSectionData &secData,
+    int32_t &parentOffset, llvm::DWARFDataExtractor &namesExtractor,
+    const llvm::DWARFDebugNames::Abbrev &abbrev) {
+  const LLDDWARFSection &namesSection = *chunk.namesSection;
+  uint64_t *offsetPtr = &offset;
+  DebugNamesSection::AttrValueData cuOrTuAttr = {0, 0};
+  for (auto attr : abbrev.Attributes) {
+    llvm::Error err = llvm::Error::success();
+    DebugNamesSection::AttrValueData newAttr;
+    uint32_t value;
+    switch (attr.Form) {
+    case DW_FORM_flag_present: {
+      // Currently only DW_IDX_parent attributes (in .debug_names) can
+      // have this form. This form does not have a real value (nothing is
+      // emitted for it).
+      break;
+    }
+    case DW_FORM_data1:
+    case DW_FORM_ref1: {
+      newAttr.attrValue = namesExtractor.getU8(offsetPtr, &err);
+      newAttr.attrSize = 1;
+      break;
+    }
+    case DW_FORM_data2:
+    case DW_FORM_ref2: {
+      value = namesExtractor.getU16(offsetPtr, &err);
+      newAttr.attrValue = value;
+      newAttr.attrSize = 2;
+      break;
+    }
+    case DW_FORM_data4:
+    case DW_FORM_ref4: {
+      value = namesExtractor.getU32(offsetPtr, &err);
+      newAttr.attrValue = value;
+      newAttr.attrSize = 4;
+      if (attr.Index == dwarf::DW_IDX_parent)
+        parentOffset = value + secData.locs.EntriesBase;
+      break;
+    }
+    case DW_FORM_data8:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_sig8: {
+      value = namesExtractor.getU64(offsetPtr, &err);
+      newAttr.attrValue = value;
+      newAttr.attrSize = 8;
+      break;
+    }
+    default: {
+      errorOrWarn(toString(namesSection.sec) +
+                  Twine(": unrecognized form encoding ") + Twine(attr.Form) +
+                  " in .debug_names abbrev table");
+      break;
+    }
+    }
+    if (err)
+      errorOrWarn(
+          toString(namesSection.sec) +
+          ": error while reading attributes: " + toString(std::move(err)));
+    if (attr.Index == DW_IDX_compile_unit || attr.Index == DW_IDX_type_unit)
+      // Save it to put it at the end of the attributes list.
+      cuOrTuAttr = newAttr;
+    else if (attr.Form != DW_FORM_flag_present)
+      values.push_back(newAttr);
+  }
+
+  // Make sure the CU or TU index attribute is the last one in the list.
+  values.push_back(cuOrTuAttr);
+}
+
+template <class ELFT>
+static void readEntry(DebugNamesSection::NamedEntry &stringEntry,
+                      DebugNamesSection::DebugNamesInputChunk &chunk,
+                      DebugNamesSection::DebugNamesSectionData &secData,
+                      llvm::DWARFDataExtractor &namesExtractor,
+                      const llvm::DWARFDebugNames::NameIndex &ni) {
+  std::unique_ptr<LLDDWARFSection> &namesSection = chunk.namesSection;
+  uint64_t offset = stringEntry.entryOffset;
+  // Each entry ends with a zero 'sentinel' value
+  while (offset < namesSection->Data.size() &&
+         namesSection->Data[offset] != 0) {
+    // Read & store all entries (for the same string)
+    auto entry = std::make_unique<DebugNamesSection::IndexEntry>();
+    entry->poolOffset = offset;
+    llvm::Error err = llvm::Error::success();
+    uint64_t ulebValue = namesExtractor.getULEB128(&offset, &err);
+    if (err)
+      errorOrWarn(toString(chunk.namesSection->sec) +
+                  ": error reading entry: " + toString(std::move(err)));
+    entry->abbrevCode = static_cast<uint32_t>(ulebValue);
+    const auto &abbrevs = ni.getAbbrevs();
+    auto abbrevIt = abbrevs.find_as(entry->abbrevCode);
+    if (abbrevIt != abbrevs.end()) {
+      const llvm::DWARFDebugNames::Abbrev &abbrev = *abbrevIt;
+      readAttributeValues<ELFT>(entry->attrValues, chunk, offset, secData,
+                                entry->parentOffset, namesExtractor, abbrev);
+      stringEntry.indexEntries.push_back(std::move(entry));
+    }
+  }
+  if (offset >= namesSection->Data.size())
+    errorOrWarn(toString(chunk.namesSection->sec) +
+                ": encountered unexpected end of section while reading entry");
+}
+
+template <class ELFT>
+static void
+readEntries(struct DebugNamesSection::DebugNamesSectionData &secData,
+            DebugNamesSection::DebugNamesInputChunk &chunk,
+            llvm::DWARFDataExtractor &namesExtractor,
+            llvm::DataExtractor &strExtractor,
+            const llvm::DWARFDebugNames::NameIndex &ni) {
+  // Temporary map from entry offsets to address (pointer) of entry with that
+  // offset; used to find parent entries quickly.
+  DenseMap<uint32_t, DebugNamesSection::IndexEntry *> offsetMap;
+  // Reserve sizes for this chunk's hashes & namedEntries.
+  chunk.hashValues.reserve(secData.hdr.NameCount);
+  secData.namedEntries.reserve(secData.hdr.NameCount);
+  // Calculate the Entry Offsets, create initial records.
+  for (uint32_t i = 0; i < secData.hdr.NameCount; ++i) {
+    // Get string value
+    DebugNamesSection::NamedEntry stringEntry;
+    stringEntry.entryOffset =
+        secData.locs.EntriesBase + secData.entryOffsets[i];
+    uint64_t strOffsetOffset =
+        secData.locs.StringOffsetsBase + i * secData.dwarfSize;
+    stringEntry.stringOffsetOffset = strOffsetOffset;
+    uint64_t strOffset =
+        namesExtractor.getRelocatedValue(secData.dwarfSize, &strOffsetOffset);
+    StringRef name = strExtractor.getCStrRef(&strOffset);
+    stringEntry.name = name.data();
+    // Calculate hash
+    stringEntry.hashValue = caseFoldingDjbHash(name);
+    chunk.hashValues.push_back(stringEntry.hashValue);
+    // Read String Entry
+    readEntry<ELFT>(stringEntry, chunk, secData, namesExtractor, ni);
+    // Add index entries & offsets to our temporary map
+    for (const auto &entry : stringEntry.indexEntries)
+      offsetMap[entry->poolOffset] = entry.get();
+    secData.namedEntries.push_back(std::move(stringEntry));
+  }
+  // Find/assign pointers to any 'real' parent entries (needed to find correct
+  // parent entry offsets in merged data).
+  for (auto &stringEntry : secData.namedEntries)
+    for (auto &entry : stringEntry.indexEntries)
+      if (entry->parentOffset != -1)
+        entry->parentEntry = offsetMap[entry->parentOffset];
+}
+
+static uint16_t computeDebugNamesHeaderSize() {
+  // Size of the .debug_names section header, in bytes, for DWARF32:
+  uint16_t size = /* unit length */ 4 +
+                  /* version */ 2 +
+                  /* padding */ 2 +
+                  /* CU count */ 4 +
+                  /* TU count */ 4 +
+                  /* Foreign TU count */ 4 +
+                  /* Bucket Count */ 4 +
+                  /* Name Count */ 4 +
+                  /* Abbrev table size */ 4 +
+                  /* Augmentation string size */ 4 +
+                  /* augmentation string */ 8;
+  return size;
+}
+
+template <class ELFT>
+static void collectDebugNamesSectionData(
+    DebugNamesSection::DebugNamesInputChunk &chunk,
+    DebugNamesSection::DebugNamesOutputChunk &outputChunk,
+    llvm::DWARFDataExtractor &namesExtractor,
+    llvm::DataExtractor &strExtractor) {
+  for (const auto &ni : *chunk.debugNamesData) {
+    DebugNamesSection::DebugNamesSectionData secData;
+    secData.hdr = ni.getHeader();
+    if (secData.hdr.Format != DwarfFormat::DWARF32)
+      errorOrWarn(toString(chunk.namesSection->sec) + ": unsupported DWARF64");
+    secData.dwarfSize = dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
+    secData.hdrSize = computeDebugNamesHeaderSize();
+    if (secData.hdr.Version != 5)
+      errorOrWarn(toString(chunk.namesSection->sec) + ": unsupported version");
+    secData.locs = findDebugNamesOffsets(secData.hdrSize, secData.hdr);
+    readCompileUnitOffsets<ELFT>(secData, chunk, outputChunk, namesExtractor);
+    readEntryOffsets<ELFT>(secData, chunk, namesExtractor);
+    readEntries<ELFT>(secData, chunk, namesExtractor, strExtractor, ni);
+    chunk.sectionsData.push_back(std::move(secData));
+  }
+}
+
+void DebugNamesSection::collectMergedCounts(
+    MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
+  SmallVector<uint32_t, 0> tmpMergedCuOffsets;
+
+  mergedHdr.CompUnitCount = 0;
+  mergedHdr.LocalTypeUnitCount = 0;
+  mergedHdr.ForeignTypeUnitCount = 0;
+  mergedHdr.Version = 5;
+  mergedHdr.Format = DwarfFormat::DWARF32;
+  mergedHdr.AugmentationStringSize = 0;
+
+  for (size_t i = 0; i < numChunks; ++i) {
+    DebugNamesInputChunk &inputChunk = inputChunks[i];
+    DebugNamesOutputChunk &outputChunk = outputChunks[i];
+    inputChunk.baseCuOffsetIdx = tmpMergedCuOffsets.size();
+    for (uint32_t cuOffset : outputChunk.compilationUnits)
+      tmpMergedCuOffsets.push_back(outputChunk.sec->outSecOff + cuOffset);
+    for (const DebugNamesSectionData &data : inputChunk.sectionsData) {
+      mergedHdr.CompUnitCount += data.hdr.CompUnitCount;
+      mergedHdr.LocalTypeUnitCount += data.hdr.LocalTypeUnitCount;
+      mergedHdr.ForeignTypeUnitCount += data.hdr.ForeignTypeUnitCount;
+      // Set & check the Augmentation String.
+      if (mergedHdr.AugmentationStringSize == 0) {
+        mergedHdr.AugmentationStringSize = data.hdr.AugmentationStringSize;
+        mergedHdr.AugmentationString = data.hdr.AugmentationString;
+      } else if ((mergedHdr.AugmentationStringSize !=
+                  data.hdr.AugmentationStringSize) ||
+                 (mergedHdr.AugmentationString !=
+                  data.hdr.AugmentationString)) {
+        // There are conflicting augmentation strings, so it's best for the
+        // merged index to not use an augmentation string.
+        StringRef emptyString = "        ";
+        mergedHdr.AugmentationStringSize = 8;
+        mergedHdr.AugmentationString = emptyString;
+      }
+    }
+  }
+}
+
+void DebugNamesSection::Abbrev::Profile(llvm::FoldingSetNodeID &id) const {
+  id.AddInteger(tag);
+  for (const DWARFDebugNames::AttributeEncoding &attr : attributes) {
+    id.AddInteger(attr.Index);
+    id.AddInteger(attr.Form);
+  }
+}
+
+std::pair<uint8_t, dwarf::Form> DebugNamesSection::getMergedCuSizeData() {
+  // Once we've merged all the CU offsets into a single list, the original
+  // DWARF form/size (often 1 byte) may be too small to hold indices to all
+  // the offsets. Here we calculate what the right form/size needs to be for
+  // the merged index.
+  uint8_t size;
+  dwarf::Form form;
+  // TODO: Investigate possibly using llvm::DIEInteger::BestForm here
+  if (mergedHdr.CompUnitCount > 0xffffffff) {
+    form = DW_FORM_data8;
+    size = 8;
+  } else if (mergedHdr.CompUnitCount > 0xffff) {
+    form = DW_FORM_data4;
+    size = 4;
+  } else if (mergedHdr.CompUnitCount > 0xff) {
+    form = DW_FORM_data2;
+    size = 2;
+  } else {
+    form = DW_FORM_data1;
+    size = 1;
+  }
+
+  return {size, form};
+}
+
+void DebugNamesSection::getMergedAbbrevTable(
+    MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
+  MapVector<uint64_t, Abbrev> abbrevMap;
+  FoldingSet<DebugNamesSection::Abbrev> AbbreviationsSet;
+
+  // Need to determine what size form is needed for the DW_IDX_compile_unit
+  // attributes in the merged index. Will need to update the abbrevs to use
+  // the right form.
+  dwarf::Form compileUnitAttrForm = getMergedCuSizeData().second;
+
+  for (DebugNamesInputChunk &chunk : inputChunks) {
+    for (const auto &ni : *chunk.debugNamesData) {
+      const auto &abbrevs = ni.getAbbrevs();
+      for (const DWARFDebugNames::Abbrev &abbrev : abbrevs) {
+        // Create canonicalized abbrev.
+        DebugNamesSection::Abbrev newAbbrev;
+        DWARFDebugNames::AttributeEncoding cuOrTuAttr(DW_IDX_compile_unit,
+                                                      compileUnitAttrForm);
+        newAbbrev.code = abbrev.Code;
+        newAbbrev.tag = abbrev.Tag;
+        for (const auto attr : abbrev.Attributes) {
+          DWARFDebugNames::AttributeEncoding newAttr(attr.Index, attr.Form);
+          if (attr.Index == DW_IDX_compile_unit ||
+              attr.Index == DW_IDX_type_unit)
+            // Save it, to put it at the end.
+            cuOrTuAttr.Index = newAttr.Index;
+          else
+            newAbbrev.attributes.push_back(newAttr);
+        }
+        // Put the CU/TU index at the end of the attributes list.
+        newAbbrev.attributes.push_back(cuOrTuAttr);
+
+        // Next, check our abbreviations set to see if we've already seen the
+        // identical abbreviation.
+        uint32_t oldCode = newAbbrev.code;
+        uint32_t newCode;
+        FoldingSetNodeID id;
+        newAbbrev.Profile(id);
+        void *insertPos;
+        if (Abbrev *Existing =
+                AbbreviationsSet.FindNodeOrInsertPos(id, insertPos)) {
+          // Found it; we've already seen an identical abbreviation.
+          newCode = Existing->code;
+        } else {
+          // Didn't find it.
+          Abbrev *newAbbrev2 = new (Alloc) Abbrev(std::move(newAbbrev));
+          AbbreviationsSet.InsertNode(newAbbrev2, insertPos);
+          newCode = mergedAbbrevTable.size() + 1;
+          newAbbrev2->code = newCode;
+          mergedAbbrevTable.push_back(newAbbrev2);
+        }
+        chunk.abbrevCodeMap[oldCode] = newCode;
+      }
+    }
+  }
+
+  // Calculate the merged abbrev table size.
+  mergedHdr.AbbrevTableSize = 0;
+  for (Abbrev *a : mergedAbbrevTable) {
+    mergedHdr.AbbrevTableSize += getULEB128Size(a->code);
+    mergedHdr.AbbrevTableSize += getULEB128Size(a->tag);
+    for (const auto &attr : a->attributes) {
+      mergedHdr.AbbrevTableSize += getULEB128Size(attr.Index);
+      mergedHdr.AbbrevTableSize += getULEB128Size(attr.Form);
+    }
+    mergedHdr.AbbrevTableSize += 2; // attribute index & form sentinels
+  }
+  ++mergedHdr.AbbrevTableSize; // abbrev table sentinel
+}
+
+void DebugNamesSection::getMergedSymbols(
+    MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
+  // The number of symbols (& abbrevs) we will handle is very large; will use
+  // multi-threading to speed it up.
+  constexpr size_t numShards = 32;
+  const size_t concurrency =
+      llvm::bit_floor(std::min<size_t>(config->threadCount, numShards));
+  const size_t shift = 32 - llvm::countr_zero(numShards);
+
+  struct ShardData {
+    // Map to uniquify symbols by name
+    MapVector<CachedHashStringRef, NamedEntry> nameMap;
+  };
+
+  // Need to determine what size is needed for the DW_IDX_compile_unit
+  // attributes in the merged index. Will need to update the indexEntries
+  // to use the right size.
+  uint8_t compileUnitAttrSize = getMergedCuSizeData().first;
+
+  auto shardsPtr = std::make_unique<ShardData[]>(numShards);
+  MutableArrayRef<ShardData> shards(shardsPtr.get(), numShards);
+
+  parallelFor(0, concurrency, [&](size_t threadId) {
+    for (size_t i = 0; i < numChunks; ++i) {
+      DebugNamesInputChunk &chunk = inputChunks[i];
+      for (auto &secData : chunk.sectionsData) {
+        // Deduplicate the NamedEntry records (based on the string/name),
+        // using a map from string/name to NamedEntry records.
+        // Note there is a twist: If there is already a record for the current
+        // 'string' in the nameMap, we append all the indexEntries from the
+        // current record to the record that's in the nameMap. I.e. we
+        // deduplicate the *strings* but we keep all the IndexEntry records
+        // (moving them to the appropriate 'kept' NamedEntry record).
+        for (auto &stringEntry : secData.namedEntries) {
+          size_t shardId = stringEntry.hashValue >> shift;
+          if ((shardId & (concurrency - 1)) != threadId)
+            continue;
+
+          auto &shard = shards[shardId];
+          stringEntry.chunkIdx = i;
+          for (auto &entry : stringEntry.indexEntries) {
+            // The DW_IDX_compile_unit is always the last attribute (we set it
+            // up that way when we read/created the attributes). We need to
+            // update the index value to use the correct merged offset, and we
+            // need to fix the size of the index attribute.
+            uint8_t endPos = entry->attrValues.size() - 1;
+            entry->attrValues[endPos].attrValue += chunk.baseCuOffsetIdx;
+            entry->attrValues[endPos].attrSize = compileUnitAttrSize;
+            // Update the entry's abbrev code to match the merged
+            // abbreviations.
+            entry->abbrevCode = chunk.abbrevCodeMap[entry->abbrevCode];
+          }
+
+          CachedHashStringRef cachedHashName(stringEntry.name);
+          auto [it, inserted] =
+              shard.nameMap.try_emplace(cachedHashName, std::move(stringEntry));
+          if (!inserted) {
+            // Found the string already; don't add to map, but append
+            // entry/entries for it to existing map entry.
+            NamedEntry &found = it->second;
+            // Append the entries...
+            for (auto &entry : stringEntry.indexEntries)
+              found.indexEntries.push_back(std::move(entry));
+          }
+        }
+      }
+    }
+  });
+
+  // Combined the shared symbols into mergedEntries
+  for (auto &shard : shards)
+    for (auto &mapEntry : shard.nameMap)
+      mergedEntries.push_back(std::move(mapEntry.second));
+  mergedHdr.NameCount = mergedEntries.size();
+}
+
+void DebugNamesSection::computeUniqueHashes(
+    MutableArrayRef<DebugNamesInputChunk> &chunks) {
+  SmallVector<uint32_t, 0> uniques;
+  for (const auto &chunk : chunks)
+    uniques.append(chunk.hashValues);
+  llvm::sort(uniques);
+  mergedHdr.BucketCount = dwarf::getDebugNamesBucketCount(llvm::unique(uniques) - uniques.begin());
+}
+
+void DebugNamesSection::generateBuckets() {
+  bucketList.resize(mergedHdr.BucketCount);
+  for (auto &entry : mergedEntries) {
+    uint32_t bucketIdx = entry.hashValue % mergedHdr.BucketCount;
+    bucketList[bucketIdx].push_back(&entry);
+  }
+
+  // Sort the contents of the buckets by hash value so that the hash collisions
+  // end up together.
+  for (auto &bucket : bucketList)
+    llvm::stable_sort(bucket, [](NamedEntry *lhs, NamedEntry *rhs) {
+      return lhs->hashValue < rhs->hashValue;
+    });
+}
+
+void DebugNamesSection::calculateEntriesSizeAndOffsets() {
+  uint32_t offset = 0;
+  for (DebugNamesSection::NamedEntry &stringEntry : mergedEntries) {
+    stringEntry.entryOffset = offset;
+    for (auto &entry : stringEntry.indexEntries) {
+      uint32_t entrySize = 0;
+      entry->poolOffset = offset;
+      uint32_t ulebSize = getULEB128Size(entry->abbrevCode);
+      entrySize += ulebSize;
+      for (const auto &attr : entry->attrValues)
+        entrySize += attr.attrSize;
+      offset += entrySize;
+    }
+    // Add in sentinel size
+    ++offset;
+  }
+  mergedTotalEntriesSize = offset;
+}
+
+void DebugNamesSection::updateParentIndexEntries() {
+  for (DebugNamesSection::NamedEntry &stringEntry : mergedEntries) {
+    for (auto &childEntry : stringEntry.indexEntries) {
+      if (!childEntry->parentEntry)
+        continue;
+
+      // Abbrevs are indexed starting at 1; vector starts at 0. (abbrevCode
+      // corresponds to position in the merged table vector).
+      const Abbrev *abbrev = mergedAbbrevTable[childEntry->abbrevCode - 1];
+
+      // Found the abbrev. Find the index for the DW_IDX_parent attribute
+      // (in the abbrev) and update that value in the entry with the
+      // correct parent offset (in the merged entry pool).
+      for (size_t idx = 0, size = abbrev->attributes.size(); idx < size;
+           ++idx) {
+        auto attr = abbrev->attributes[idx];
+        if (attr.Index == DW_IDX_parent && attr.Form == DW_FORM_ref4)
+          childEntry->attrValues[idx].attrValue =
+              childEntry->parentEntry->poolOffset;
+      }
+    }
+  }
+}
+
+uint64_t DebugNamesSection::calculateMergedSectionSize() {
+  uint32_t hdrSize = computeDebugNamesHeaderSize();
+  mergedOffsets = findDebugNamesOffsets(hdrSize, mergedHdr);
+  // Add in the size for all the Entries, and make it 4-byte aligned.
+  mergedHdr.UnitLength =
+      alignTo(mergedOffsets.EntriesBase + mergedTotalEntriesSize, 4);
+  // Add in the first 4 bytes, whichs print out the length of the section.
+  return mergedHdr.UnitLength + 4;
+}
+
+template <class ELFT> DebugNamesSection *DebugNamesSection::create() {
+  llvm::TimeTraceScope timeScope("Create merged .debug_names");
+  SetVector<InputFile *> files;
+  SmallVector<InputSectionBase *, 0> sections;
+  for (InputSectionBase *s : ctx.inputSections) {
+    InputSection *isec = dyn_cast<InputSection>(s);
+    if (!isec)
+      continue;
+    // Mark original sections as dead, but save links to them for calculating
+    // relocations later.
+    if (s->name == ".debug_names") {
+      s->markDead();
+      sections.push_back(s);
+      files.insert(isec->file);
+    }
+  }
+  auto inputChunksPtr = std::make_unique<DebugNamesInputChunk[]>(files.size());
+  MutableArrayRef<DebugNamesInputChunk> inputChunks(inputChunksPtr.get(),
+                                                    files.size());
+  auto outputChunks = std::make_unique<DebugNamesOutputChunk[]>(files.size());
+  parallelFor(0, files.size(), [&](size_t i) {
+    ObjFile<ELFT> *file = cast<ObjFile<ELFT>>(files[i]);
+    auto dwarfCtx = std::make_unique<DWARFContext>(
+        std::make_unique<LLDDwarfObj<ELFT>>(file));
+    auto &dobj =
+        static_cast<const LLDDwarfObj<ELFT> &>(dwarfCtx->getDWARFObj());
+
+    // Extract llvm::DWARFDebugNames data from the .debug_names section. The
+    // .debug_names section needs the .debug_str section, to get the actual
+    // symbol names.
+    const StringRef &strSection = dobj.getStrSection();
+    const LLDDWARFSection &namesSection = dobj.getNamesSection();
+    llvm::DWARFDataExtractor namesExtractor(dobj, namesSection, config->isLE,
+                                            config->wordsize);
+    llvm::DataExtractor strExtractor(strSection, config->isLE,
+                                     config->wordsize);
+    inputChunks[i].debugNamesData =
+        std::make_unique<DWARFDebugNames>(namesExtractor, strExtractor);
+    inputChunks[i].namesSection =
+        std::make_unique<LLDDWARFSection>(namesSection);
+    if (llvm::Error E = inputChunks[i].debugNamesData->extract()) {
+      // Report an error here. We were unable to extract the data.
+      errorOrWarn(toString(dobj.getNamesSection().sec) + ": " +
+                  toString(std::move(E)));
+    }
+    outputChunks[i].sec = dobj.getInfoSection();
+    collectDebugNamesSectionData<ELFT>(inputChunks[i], outputChunks[i],
+                                       namesExtractor, strExtractor);
+  });
+
+  auto *ret = make<DebugNamesSection>();
+  ret->addSections(sections);
+  ret->outputChunks = std::move(outputChunks);
+  ret->numChunks = files.size();
+  ret->collectMergedCounts(inputChunks);
+  ret->getMergedAbbrevTable(inputChunks);
+  ret->getMergedSymbols(inputChunks);
+  ret->computeUniqueHashes(inputChunks);
+  inputChunksPtr.reset();
+  ret->generateBuckets();
+  ret->calculateEntriesSizeAndOffsets();
+  ret->updateParentIndexEntries();
+  ret->sectionSize = ret->calculateMergedSectionSize();
+  return ret;
+}
+
 GdbIndexSection::GdbIndexSection()
     : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {}
 
@@ -4272,6 +5028,8 @@ template <class ELFT> void elf::createSyntheticSections() {
   if (config->andFeatures || !ctx.aarch64PauthAbiCoreInfo.empty())
     add(*make<GnuPropertySection>());
 
+  if (config->debugNames)
+    add(*DebugNamesSection::create<ELFT>());
   if (config->gdbIndex) {
     in.gdbIndex = GdbIndexSection::create<ELFT>();
     add(*in.gdbIndex);
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 759b78668f5462..e0b01831edaa77 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -21,13 +21,17 @@
 #define LLD_ELF_SYNTHETIC_SECTIONS_H
 
 #include "Config.h"
+#include "DWARF.h"
 #include "InputSection.h"
 #include "Symbols.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
 #include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Allocator.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Parallel.h"
@@ -789,6 +793,136 @@ class RelroPaddingSection final : public SyntheticSection {
   void writeTo(uint8_t *buf) override {}
 };
 
+class DebugNamesSection final : public SyntheticSection {
+  // N.B. Everything in this class assumes that we are using DWARF32.
+  // If we move to DWARF64, most of this data will need to be re-sized,
+  // and the code that handles or manipulates it will need to be updated
+  // accordingly.
+
+public:
+  DebugNamesSection();
+  template <typename ELFT> static DebugNamesSection *create();
+  void writeTo(uint8_t *buf) override;
+  size_t getSize() const override { return sectionSize; }
+  bool isNeeded() const override;
+
+  void addSections(SmallVector<InputSectionBase *, 0> sec_list) {
+    inputDebugNamesSections = sec_list;
+  }
+
+  template <class ELFT> void writeToImpl(uint8_t *buf);
+
+  template <class ELFT, class RelTy>
+  void getNameRelocsImpl(InputSection *sec, ArrayRef<RelTy> rels,
+                         llvm::DenseMap<uint32_t, uint32_t> &relocs);
+
+  template <class ELFT>
+  void getNameRelocs(InputSectionBase *base,
+                     llvm::DenseMap<uint32_t, uint32_t> &relocs);
+
+  template <class ELFT>
+  void endianWrite(uint8_t size, uint8_t *buf_start, uint32_t offset,
+                   uint32_t data);
+
+  struct Abbrev : public llvm::FoldingSetNode {
+    uint32_t code;
+    uint32_t tag;
+    SmallVector<llvm::DWARFDebugNames::AttributeEncoding, 2> attributes;
+
+    void Profile(llvm::FoldingSetNodeID &id) const;
+  };
+
+  struct AttrValueData {
+    uint32_t attrValue;
+    uint8_t attrSize;
+  };
+
+  struct IndexEntry {
+    uint32_t abbrevCode;
+    uint32_t poolOffset;
+    union {
+      int32_t parentOffset = -1;
+      IndexEntry *parentEntry;
+    };
+    SmallVector<AttrValueData, 3> attrValues;
+  };
+
+  struct NamedEntry {
+    const char *name;
+    uint32_t hashValue;
+    uint32_t stringOffsetOffset;
+    uint32_t entryOffset;
+    uint32_t relocatedEntryOffset;
+    // The index of the chunk that 'name' points into, for looking up
+    // relocation data for this string.
+    uint32_t chunkIdx;
+    SmallVector<std::unique_ptr<IndexEntry>, 0> indexEntries;
+  };
+
+  struct SectionOffsetLocs {
+    uint64_t stringOffsetsBase;
+    uint64_t entryOffsetsBase;
+    uint64_t entriesBase;
+  };
+
+  struct DebugNamesSectionData {
+    llvm::DWARFDebugNames::Header hdr;
+    llvm::DWARFDebugNames::DWARFDebugNamesOffsets locs;
+    SmallVector<uint32_t, 0> tuOffsets;
+    SmallVector<Abbrev, 0> abbrevTable;
+    std::unique_ptr<uint32_t[]> entryOffsets;
+    SmallVector<NamedEntry, 0> namedEntries;
+    uint16_t dwarfSize;
+    uint16_t hdrSize;
+  };
+
+  // Per-file data used, while reading in the data, to generate the merged
+  // section information.
+  struct DebugNamesInputChunk {
+    uint32_t baseCuOffsetIdx;
+    std::unique_ptr<llvm::DWARFDebugNames> debugNamesData;
+    std::unique_ptr<LLDDWARFSection> namesSection;
+    SmallVector<DebugNamesSectionData, 0> sectionsData;
+    SmallVector<uint32_t, 0> hashValues;
+    llvm::DenseMap<uint32_t, uint32_t> abbrevCodeMap;
+  };
+
+  // Per-file data needed for correctly writing out the .debug_names section.
+  struct DebugNamesOutputChunk {
+    // Pointer to .debug_info section for this chunk/file, used for
+    // calculating correct relocated CU offsets in the merged index.
+    InputSection *sec;
+    SmallVector<uint32_t, 0> compilationUnits;
+    SmallVector<uint32_t, 0> typeUnits;
+  };
+
+  void collectMergedCounts(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
+  std::pair<uint8_t, llvm::dwarf::Form> getMergedCuSizeData();
+  void getMergedAbbrevTable(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
+  void getMergedSymbols(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
+  void computeUniqueHashes(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
+  void generateBuckets();
+  void calculateEntriesSizeAndOffsets();
+  void updateParentIndexEntries();
+  uint64_t calculateMergedSectionSize();
+
+  llvm::BumpPtrAllocator Alloc;
+
+private:
+  size_t sectionSize;
+  uint32_t mergedTotalEntriesSize;
+  uint32_t numChunks;
+  llvm::DWARFDebugNames::DWARFDebugNamesOffsets mergedOffsets;
+  std::unique_ptr<DebugNamesOutputChunk[]> outputChunks;
+  // Pointers to the original .debug_names sections; used for find the correct'
+  // string relocation values when writing out the merged index.
+  SmallVector<InputSectionBase *, 0> inputDebugNamesSections;
+  llvm::DWARFDebugNames::Header mergedHdr;
+  SmallVector<Abbrev *, 0> mergedAbbrevTable;
+  SmallVector<NamedEntry, 0> mergedEntries;
+  SmallVector<SmallVector<NamedEntry *, 0>, 0> bucketList;
+};
+
 class GdbIndexSection final : public SyntheticSection {
 public:
   struct AddressEntry {
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index e0316730f442ed..ba8ce8f784759a 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -172,6 +172,10 @@ This is like a generalized
 Output cross reference table. If
 .Fl Map
 is specified, print to the map file.
+.It Fl -debug-names
+Generate a merged
+.Li .debug_names
+section.
 .It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression
 Define a symbol alias.
 .Ar expression
diff --git a/lld/test/ELF/Inputs/debug-names-2.s b/lld/test/ELF/Inputs/debug-names-2.s
new file mode 100644
index 00000000000000..586788653dcc72
--- /dev/null
+++ b/lld/test/ELF/Inputs/debug-names-2.s
@@ -0,0 +1,191 @@
+#-- input file: debug-names-2.cpp
+## Generated with:
+##
+## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+##     -S debug-names-2.cpp -o debug-names-2.s
+##
+## debug-names-2.cpp contents:
+##
+## struct t1 { };
+## int main() {
+##   t1 v1;
+## }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x3d DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.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
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0x1b DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	3                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+	.long	62                              # DW_AT_type
+                                        # DW_AT_external
+	.byte	3                               # Abbrev [3] 0x32:0xb DW_TAG_variable
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	127
+	.byte	5                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	3                               # DW_AT_decl_line
+	.long	66                              # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	4                               # Abbrev [4] 0x3e:0x4 DW_TAG_base_type
+	.byte	4                               # DW_AT_name
+	.byte	5                               # DW_AT_encoding
+	.byte	4                               # DW_AT_byte_size
+	.byte	5                               # Abbrev [5] 0x42:0x6 DW_TAG_structure_type
+	.byte	5                               # DW_AT_calling_convention
+	.byte	6                               # DW_AT_name
+	.byte	1                               # DW_AT_byte_size
+	.byte	0                               # DW_AT_decl_file
+	.byte	1                               # DW_AT_decl_line
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	32                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names-2.cpp"             # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=122
+.Linfo_string3:
+	.asciz	"main"                          # string offset=139
+.Linfo_string4:
+	.asciz	"int"                           # string offset=144
+.Linfo_string5:
+	.asciz	"v1"                            # string offset=148
+.Linfo_string6:
+	.asciz	"t1"                            # string offset=151
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863786                         # Hash in Bucket 1
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	.Linfo_string6                  # String in Bucket 1: t1
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames2:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	66                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames0:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	3                               # Abbreviation code
+	.long	62                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/Inputs/debug-names-parent-idx-2.s b/lld/test/ELF/Inputs/debug-names-parent-idx-2.s
new file mode 100644
index 00000000000000..7eedaaee549450
--- /dev/null
+++ b/lld/test/ELF/Inputs/debug-names-parent-idx-2.s
@@ -0,0 +1,347 @@
+#-- input file: debug-names-parent-idx-2.cpp
+## Generated with:
+##
+## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
+##     -S debug-names-parent-idx-2.cpp -o debug-names-parent-idx-2.s
+##
+## foo.h contents:
+##
+## int foo();
+##
+## struct foo {
+##   int x;
+##   char y;
+##   struct foo *foo_ptr;
+## };
+##
+## namespace parent_test {
+##   int foo();
+## }
+##
+## debug-names-parent-index-2.cpp contents:
+##
+## #include "foo.h"
+## int foo () {
+##   struct foo struct2;
+##   struct2.x = 1024;
+##   struct2.y = 'r';
+##   struct2.foo_ptr = nullptr;
+##   return struct2.x * (int) struct2.y;
+## }
+##
+## namespace parent_test {
+## int foo () {
+##   return 25;
+## }
+## }
+##
+	.text
+	.globl	_Z3foov                         # -- Begin function _Z3foov
+	.p2align	4, 0x90
+	.type	_Z3foov, at function
+_Z3foov:                                # @_Z3foov
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	movl	$1024, -16(%rbp)                # imm = 0x400
+	movb	$114, -12(%rbp)
+	movq	$0, -8(%rbp)
+	movl	-16(%rbp), %eax
+	movsbl	-12(%rbp), %ecx
+	imull	%ecx, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z3foov, .Lfunc_end0-_Z3foov
+	.cfi_endproc
+                                        # -- End function
+	.globl	_ZN11parent_test3fooEv          # -- Begin function _ZN11parent_test3fooEv
+	.p2align	4, 0x90
+	.type	_ZN11parent_test3fooEv, at function
+_ZN11parent_test3fooEv:                 # @_ZN11parent_test3fooEv
+.Lfunc_begin1:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp2:
+	movl	$25, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp3:
+.Lfunc_end1:
+	.size	_ZN11parent_test3fooEv, .Lfunc_end1-_ZN11parent_test3fooEv
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x76 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.Lline_table_start0             # DW_AT_stmt_list
+	.byte	2                               # DW_AT_comp_dir
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin0       # DW_AT_high_pc
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0x4 DW_TAG_base_type
+	.byte	3                               # DW_AT_name
+	.byte	5                               # DW_AT_encoding
+	.byte	4                               # DW_AT_byte_size
+	.byte	3                               # Abbrev [3] 0x27:0x1c DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	5                               # DW_AT_linkage_name
+	.byte	6                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	4                               # DW_AT_decl_line
+	.long	35                              # DW_AT_type
+                                        # DW_AT_external
+	.byte	4                               # Abbrev [4] 0x37:0xb DW_TAG_variable
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	112
+	.byte	8                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	5                               # DW_AT_decl_line
+	.long	86                              # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	5                               # Abbrev [5] 0x43:0x13 DW_TAG_namespace
+	.byte	4                               # DW_AT_name
+	.byte	6                               # Abbrev [6] 0x45:0x10 DW_TAG_subprogram
+	.byte	1                               # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	7                               # DW_AT_linkage_name
+	.byte	6                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	16                              # DW_AT_decl_line
+	.long	35                              # DW_AT_type
+                                        # DW_AT_external
+	.byte	0                               # End Of Children Mark
+	.byte	7                               # Abbrev [7] 0x56:0x22 DW_TAG_structure_type
+	.byte	5                               # DW_AT_calling_convention
+	.byte	6                               # DW_AT_name
+	.byte	16                              # DW_AT_byte_size
+	.byte	1                               # DW_AT_decl_file
+	.byte	4                               # DW_AT_decl_line
+	.byte	8                               # Abbrev [8] 0x5c:0x9 DW_TAG_member
+	.byte	9                               # DW_AT_name
+	.long	35                              # DW_AT_type
+	.byte	1                               # DW_AT_decl_file
+	.byte	5                               # DW_AT_decl_line
+	.byte	0                               # DW_AT_data_member_location
+	.byte	8                               # Abbrev [8] 0x65:0x9 DW_TAG_member
+	.byte	10                              # DW_AT_name
+	.long	120                             # DW_AT_type
+	.byte	1                               # DW_AT_decl_file
+	.byte	6                               # DW_AT_decl_line
+	.byte	4                               # DW_AT_data_member_location
+	.byte	8                               # Abbrev [8] 0x6e:0x9 DW_TAG_member
+	.byte	12                              # DW_AT_name
+	.long	124                             # DW_AT_type
+	.byte	1                               # DW_AT_decl_file
+	.byte	7                               # DW_AT_decl_line
+	.byte	8                               # DW_AT_data_member_location
+	.byte	0                               # End Of Children Mark
+	.byte	2                               # Abbrev [2] 0x78:0x4 DW_TAG_base_type
+	.byte	11                              # DW_AT_name
+	.byte	6                               # DW_AT_encoding
+	.byte	1                               # DW_AT_byte_size
+	.byte	9                               # Abbrev [9] 0x7c:0x5 DW_TAG_pointer_type
+	.long	86                              # DW_AT_type
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	56                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names-parent-idx-2.cpp"  # string offset=104
+.Linfo_string2:
+	.asciz	"parent-idx-test"               # string offset=133
+.Linfo_string3:
+	.asciz	"int"                           # string offset=149
+.Linfo_string4:
+	.asciz	"foo"                           # string offset=153
+.Linfo_string5:
+	.asciz	"_Z3foov"                       # string offset=157
+.Linfo_string6:
+	.asciz	"parent_test"                   # string offset=165
+.Linfo_string7:
+	.asciz	"_ZN11parent_test3fooEv"        # string offset=177
+.Linfo_string8:
+	.asciz	"struct2"                       # string offset=200
+.Linfo_string9:
+	.asciz	"x"                             # string offset=208
+.Linfo_string10:
+	.asciz	"y"                             # string offset=210
+.Linfo_string11:
+	.asciz	"char"                          # string offset=212
+.Linfo_string12:
+	.asciz	"foo_ptr"                       # string offset=217
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+	.quad	.Lfunc_begin1
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	6                               # Header: bucket count
+	.long	6                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5                               # Bucket 3
+	.long	0                               # Bucket 4
+	.long	6                               # Bucket 5
+	.long	-1451972055                     # Hash in Bucket 1
+	.long	-1257882357                     # Hash in Bucket 1
+	.long	175265198                       # Hash in Bucket 2
+	.long	193495088                       # Hash in Bucket 2
+	.long	193491849                       # Hash in Bucket 3
+	.long	2090147939                      # Hash in Bucket 5
+	.long	.Linfo_string7                  # String in Bucket 1: _ZN11parent_test3fooEv
+	.long	.Linfo_string5                  # String in Bucket 1: _Z3foov
+	.long	.Linfo_string6                  # String in Bucket 2: parent_test
+	.long	.Linfo_string3                  # String in Bucket 2: int
+	.long	.Linfo_string4                  # String in Bucket 3: foo
+	.long	.Linfo_string11                 # String in Bucket 5: char
+	.long	.Lnames4-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames3-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 3
+	.long	.Lnames5-.Lnames_entries0       # Offset in Bucket 5
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	19                              # DW_FORM_ref4
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	57                              # DW_TAG_namespace
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	4                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	5                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames4:
+.L3:
+	.byte	1                               # Abbreviation code
+	.long	69                              # DW_IDX_die_offset
+	.long	.L5-.Lnames_entries0            # DW_IDX_parent
+	.byte	0                               # End of list: _ZN11parent_test3fooEv
+.Lnames2:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	39                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z3foov
+.Lnames3:
+.L5:
+	.byte	3                               # Abbreviation code
+	.long	67                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: parent_test
+.Lnames0:
+.L2:
+	.byte	4                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames1:
+	.byte	2                               # Abbreviation code
+	.long	39                              # DW_IDX_die_offset
+	.byte	1                               # DW_IDX_parent
+                                        # Abbreviation code
+	.long	69                              # DW_IDX_die_offset
+	.long	.L5-.Lnames_entries0            # DW_IDX_parent
+.L4:
+	.byte	5                               # Abbreviation code
+	.long	86                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: foo
+.Lnames5:
+.L1:
+	.byte	4                               # Abbreviation code
+	.long	120                             # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-bad-aug-string.s b/lld/test/ELF/debug-names-bad-aug-string.s
new file mode 100644
index 00000000000000..edf79f0fde5773
--- /dev/null
+++ b/lld/test/ELF/debug-names-bad-aug-string.s
@@ -0,0 +1,189 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2
+# RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+
+# RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
+
+# DWARF:      .debug_names contents:
+# DWARF:      Name Index @ 0x0 {
+# DWARF-NEXT:   Header {
+# DWARF-NEXT:     Length: 0xCC
+# DWARF-NEXT:     Format: DWARF32
+# DWARF-NEXT:     Version: 5
+# DWARF-NEXT:     CU count: 2
+# DWARF-NEXT:     Local TU count: 0
+# DWARF-NEXT:     Foreign TU count: 0
+# DWARF-NEXT:     Bucket count: 5
+# DWARF-NEXT:     Name count: 5
+# DWARF-NEXT:     Abbreviations table size: 0x1F
+# DWARF-NEXT:     Augmentation: '        '
+# DWARF:        Compilation Unit offsets [
+# DWARF-NEXT:     CU[0]: 0x00000000
+# DWARF-NEXT:     CU[1]: 0x00000041
+
+##
+## This file was generated by copying debug-names.s and manually
+## editing the 'Header: augmentation string' in the .debug_names section.
+##
+	.text
+	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
+	.p2align	4, 0x90
+	.type	_Z2f12t1, at function
+_Z2f12t1:                               # @_Z2f12t1
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z2f12t1, .Lfunc_end0-_Z2f12t1
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.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
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	3                               # DW_AT_linkage_name
+	.byte	4                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+                                        # DW_AT_external
+	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	127
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+	.long	58                              # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
+	.byte	5                               # DW_AT_calling_convention
+	.byte	5                               # DW_AT_name
+	.byte	1                               # DW_AT_byte_size
+	.byte	0                               # DW_AT_decl_file
+	.byte	1                               # DW_AT_decl_line
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	28                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names.cpp"               # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=120
+.Linfo_string3:
+	.asciz	"f1"                            # string offset=137
+.Linfo_string4:
+	.asciz	"_Z2f12t1"                      # string offset=140
+.Linfo_string5:
+	.asciz	"t1"                            # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"JUNK1234"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863324                         # Hash in Bucket 1
+	.long	5863786                         # Hash in Bucket 1
+	.long	1398125246                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: f1
+	.long	.Linfo_string5                  # String in Bucket 1: t1
+	.long	.Linfo_string4                  # String in Bucket 2: _Z2f12t1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: f1
+.Lnames2:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	58                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z2f12t1
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-bad-die-idx-sizes.s b/lld/test/ELF/debug-names-bad-die-idx-sizes.s
new file mode 100644
index 00000000000000..2da278a8dd5b7c
--- /dev/null
+++ b/lld/test/ELF/debug-names-bad-die-idx-sizes.s
@@ -0,0 +1,151 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+
+## This file was generated by first compiling main.cpp: 
+## clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+##      main.cpp
+##
+## Then manually edit the .debug_names section. In the entries, change the
+## size of the DW_IDX_die_offset from '.long' to '.byte'.
+##
+## main.cpp:
+## int main (int argc, char **argv) { }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.byte	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	2                               # Abbreviation code
+	.byte	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.byte	87                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-bad-name-count.s b/lld/test/ELF/debug-names-bad-name-count.s
new file mode 100644
index 00000000000000..4acfa182b11a91
--- /dev/null
+++ b/lld/test/ELF/debug-names-bad-name-count.s
@@ -0,0 +1,154 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+
+## This file was generated by first compiling main.cpp: 
+## clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+##      main.cpp
+##
+## Then manually edit .debug_names section: change value for
+## 'Header: name count' from 3 to 4.
+##
+## main.cpp:
+## int main (int argc, char **argv) { }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	4                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	87                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-bad-offsets-sizes.s b/lld/test/ELF/debug-names-bad-offsets-sizes.s
new file mode 100644
index 00000000000000..e11d19a9bf579c
--- /dev/null
+++ b/lld/test/ELF/debug-names-bad-offsets-sizes.s
@@ -0,0 +1,153 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+
+## This file was generated by first compiling main.cpp: 
+## clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+##      main.cpp
+##
+## Then manually edit .debug_names section. Change the sizes of
+## 'Offset in Bucket' values from '.long' to '.byte'.
+##
+## main.cpp:
+## int main (int argc, char **argv) { }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.byte	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.byte	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.byte	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	87                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-bad-version.s b/lld/test/ELF/debug-names-bad-version.s
new file mode 100644
index 00000000000000..f3914670af94a5
--- /dev/null
+++ b/lld/test/ELF/debug-names-bad-version.s
@@ -0,0 +1,173 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2
+#
+# RUN: not ld.lld --debug-names %t1.o %t2.o -o /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}:(.debug_names): unsupported version
+##
+## This file was generated by copying debug-names.s and manually
+## editing the 'Header: version' in the .debug_names section (changed it from
+## 5 to 4).
+	
+	.text
+	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
+	.p2align	4, 0x90
+	.type	_Z2f12t1, at function
+_Z2f12t1:                               # @_Z2f12t1
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z2f12t1, .Lfunc_end0-_Z2f12t1
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.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
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	3                               # DW_AT_linkage_name
+	.byte	4                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+                                        # DW_AT_external
+	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	127
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+	.long	58                              # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
+	.byte	5                               # DW_AT_calling_convention
+	.byte	5                               # DW_AT_name
+	.byte	1                               # DW_AT_byte_size
+	.byte	0                               # DW_AT_decl_file
+	.byte	1                               # DW_AT_decl_line
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	28                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names.cpp"               # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=120
+.Linfo_string3:
+	.asciz	"f1"                            # string offset=137
+.Linfo_string4:
+	.asciz	"_Z2f12t1"                      # string offset=140
+.Linfo_string5:
+	.asciz	"t1"                            # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	4                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863324                         # Hash in Bucket 1
+	.long	5863786                         # Hash in Bucket 1
+	.long	1398125246                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: f1
+	.long	.Linfo_string5                  # String in Bucket 1: t1
+	.long	.Linfo_string4                  # String in Bucket 2: _Z2f12t1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: f1
+.Lnames2:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	58                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z2f12t1
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-invalid-attribute.s b/lld/test/ELF/debug-names-invalid-attribute.s
new file mode 100644
index 00000000000000..9b1a915d81f882
--- /dev/null
+++ b/lld/test/ELF/debug-names-invalid-attribute.s
@@ -0,0 +1,179 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o  -o /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}:(.debug_names): unrecognized form encoding 16 in .debug_names abbrev table
+##
+## Generated by copying debug-names.s and manually editing it to make some
+## of the abbrev attributes invalid.
+	
+	.text
+	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
+	.p2align	4, 0x90
+	.type	_Z2f12t1, at function
+_Z2f12t1:                               # @_Z2f12t1
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z2f12t1, .Lfunc_end0-_Z2f12t1
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.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
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	3                               # DW_AT_linkage_name
+	.byte	4                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+                                        # DW_AT_external
+	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	127
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+	.long	58                              # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
+	.byte	5                               # DW_AT_calling_convention
+	.byte	5                               # DW_AT_name
+	.byte	1                               # DW_AT_byte_size
+	.byte	0                               # DW_AT_decl_file
+	.byte	1                               # DW_AT_decl_line
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	28                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names.cpp"               # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=120
+.Linfo_string3:
+	.asciz	"f1"                            # string offset=137
+.Linfo_string4:
+	.asciz	"_Z2f12t1"                      # string offset=140
+.Linfo_string5:
+	.asciz	"t1"                            # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863324                         # Hash in Bucket 1
+	.long	5863786                         # Hash in Bucket 1
+	.long	1398125246                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: f1
+	.long	.Linfo_string5                  # String in Bucket 1: t1
+	.long	.Linfo_string4                  # String in Bucket 2: _Z2f12t1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	16                              # DW_FORM_ref_addr
+	.byte	7                               # DW_IDX_unknown
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: f1
+.Lnames2:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	58                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames1:
+	.byte	3                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z2f12t1
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-parent-idx.s b/lld/test/ELF/debug-names-parent-idx.s
new file mode 100644
index 00000000000000..a4e8682cd9ee58
--- /dev/null
+++ b/lld/test/ELF/debug-names-parent-idx.s
@@ -0,0 +1,549 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-parent-idx-2.s -o %t2.o
+# RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+
+# RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
+
+# DWARF:      .debug_names contents:
+# DWARF:      Name Index @ 0x0 {
+# DWARF-NEXT:   Header {
+# DWARF-NEXT:     Length: 0x15C
+# DWARF-NEXT:     Format: DWARF32
+# DWARF-NEXT:     Version: 5
+# DWARF-NEXT:     CU count: 2
+# DWARF-NEXT:     Local TU count: 0
+# DWARF-NEXT:     Foreign TU count: 0
+# DWARF-NEXT:     Bucket count: 9
+# DWARF-NEXT:     Name count: 9
+# DWARF-NEXT:     Abbreviations table size: 0x33
+# DWARF-NEXT:     Augmentation: 'LLVM0700'
+# DWARF:        Compilation Unit offsets [
+# DWARF-NEXT:     CU[0]: 0x00000000
+# DWARF-NEXT:     CU[1]: 0x000000cc
+# DWARF:        Abbreviations [
+# DWARF-NEXT:     Abbreviation 0x1 {
+# DWARF-NEXT:       Tag: DW_TAG_base_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x2 {
+# DWARF-NEXT:       Tag: DW_TAG_subprogram
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x3 {
+# DWARF-NEXT:       Tag: DW_TAG_structure_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x4 {
+# DWARF-NEXT:       Tag: DW_TAG_subprogram
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x5 {
+# DWARF-NEXT:       Tag: DW_TAG_namespace
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:            String: 0x00000093 "bar"
+# DWARF-NEXT:       Entry @ 0xf7 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF:            String: 0x000000a9 "int"
+# DWARF-NEXT:       Entry @ 0xfe {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x0000008d
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x104 {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:            String: 0x000000ad "foo"
+# DWARF-NEXT:       Entry @ 0x10b {
+# DWARF-NEXT:         Abbrev: 0x3
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000096
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x111 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x117 {
+# DWARF-NEXT:         Abbrev: 0x4
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
+# DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x121 {
+# DWARF-NEXT:         Abbrev: 0x3
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000056
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:            String: 0x00000196 "parent_test"
+# DWARF-NEXT:       Entry @ 0x128 {
+# DWARF-NEXT:         Abbrev: 0x5
+# DWARF-NEXT:         Tag: DW_TAG_namespace
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000043
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:            String: 0x00000097 "_Z3barR3fooi"
+# DWARF-NEXT:       Entry @ 0x12f {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF:            String: 0x000000a4 "main"
+# DWARF-NEXT:       Entry @ 0x136 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000046
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF:            String: 0x000000b5 "char"
+# DWARF-NEXT:       Entry @ 0x13d {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x000000b8
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x143 {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000078
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:            String: 0x000001a2 "_ZN11parent_test3fooEv"
+# DWARF-NEXT:       Entry @ 0x14a {
+# DWARF-NEXT:         Abbrev: 0x4
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
+# DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:            String: 0x0000018e "_Z3foov"
+# DWARF-NEXT:       Entry @ 0x155 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+	
+#-- input file: debug-names-parent-idx.cpp
+## Generated with:
+##
+## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
+##     -S debug-names-parent-idx.cpp -o debug-names-parent-idx.s
+##
+## foo.h contents:
+##
+## int foo();
+##
+## struct foo {
+##   int x;
+##   char y;
+##   struct foo *foo_ptr;
+## };
+##
+## namespace parent_test {
+##   int foo();
+## }
+##
+##  debug-names-parent-idx.cpp contents:
+##
+## #include "foo.h"
+## void bar (struct foo &foo, int junk) {
+##   foo.x = foo.x * junk;
+## }
+## int main (int argc, char** argv) {
+##   struct foo my_struct;
+##   my_struct.x = 10;
+##   my_struct.y = 'q';
+##   my_struct.foo_ptr = nullptr;
+##   int junk = foo();
+##   bar(my_struct, junk);
+##   int junk2 = parent_test::foo();
+##   return 0;
+## }
+##
+	.text
+	.globl	_Z3barR3fooi                    # -- Begin function _Z3barR3fooi
+	.p2align	4, 0x90
+	.type	_Z3barR3fooi, at function
+_Z3barR3fooi:                           # @_Z3barR3fooi
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movq	%rdi, -8(%rbp)
+	movl	%esi, -12(%rbp)
+.Ltmp0:
+	movq	-8(%rbp), %rax
+	movl	(%rax), %ecx
+	imull	-12(%rbp), %ecx
+	movq	-8(%rbp), %rax
+	movl	%ecx, (%rax)
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z3barR3fooi, .Lfunc_end0-_Z3barR3fooi
+	.cfi_endproc
+                                        # -- End function
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin1:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	subq	$48, %rsp
+	movl	$0, -4(%rbp)
+	movl	%edi, -8(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp2:
+	movl	$10, -32(%rbp)
+	movb	$113, -28(%rbp)
+	movq	$0, -24(%rbp)
+	callq	_Z3foov at PLT
+	movl	%eax, -36(%rbp)
+	movl	-36(%rbp), %esi
+	leaq	-32(%rbp), %rdi
+	callq	_Z3barR3fooi
+	callq	_ZN11parent_test3fooEv at PLT
+	movl	%eax, -40(%rbp)
+	xorl	%eax, %eax
+	addq	$48, %rsp
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp3:
+.Lfunc_end1:
+	.size	main, .Lfunc_end1-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0xc0 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.Lline_table_start0             # DW_AT_stmt_list
+	.byte	2                               # DW_AT_comp_dir
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin0       # DW_AT_high_pc
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0x23 DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	3                               # DW_AT_linkage_name
+	.byte	4                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	3                               # DW_AT_decl_line
+                                        # DW_AT_external
+	.byte	3                               # Abbrev [3] 0x2f:0xb DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	120
+	.byte	7                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	3                               # DW_AT_decl_line
+	.long	145                             # DW_AT_type
+	.byte	3                               # Abbrev [3] 0x3a:0xb DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	116
+	.byte	12                              # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	3                               # DW_AT_decl_line
+	.long	141                             # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	4                               # Abbrev [4] 0x46:0x47 DW_TAG_subprogram
+	.byte	1                               # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	5                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	7                               # DW_AT_decl_line
+	.long	141                             # DW_AT_type
+                                        # DW_AT_external
+	.byte	3                               # Abbrev [3] 0x55:0xb DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	120
+	.byte	13                              # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	7                               # DW_AT_decl_line
+	.long	141                             # DW_AT_type
+	.byte	3                               # Abbrev [3] 0x60:0xb DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	112
+	.byte	14                              # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	7                               # DW_AT_decl_line
+	.long	193                             # DW_AT_type
+	.byte	5                               # Abbrev [5] 0x6b:0xb DW_TAG_variable
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	96
+	.byte	15                              # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	9                               # DW_AT_decl_line
+	.long	150                             # DW_AT_type
+	.byte	5                               # Abbrev [5] 0x76:0xb DW_TAG_variable
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	92
+	.byte	12                              # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	14                              # DW_AT_decl_line
+	.long	141                             # DW_AT_type
+	.byte	5                               # Abbrev [5] 0x81:0xb DW_TAG_variable
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	88
+	.byte	16                              # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	16                              # DW_AT_decl_line
+	.long	141                             # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	6                               # Abbrev [6] 0x8d:0x4 DW_TAG_base_type
+	.byte	6                               # DW_AT_name
+	.byte	5                               # DW_AT_encoding
+	.byte	4                               # DW_AT_byte_size
+	.byte	7                               # Abbrev [7] 0x91:0x5 DW_TAG_reference_type
+	.long	150                             # DW_AT_type
+	.byte	8                               # Abbrev [8] 0x96:0x22 DW_TAG_structure_type
+	.byte	5                               # DW_AT_calling_convention
+	.byte	7                               # DW_AT_name
+	.byte	16                              # DW_AT_byte_size
+	.byte	1                               # DW_AT_decl_file
+	.byte	4                               # DW_AT_decl_line
+	.byte	9                               # Abbrev [9] 0x9c:0x9 DW_TAG_member
+	.byte	8                               # DW_AT_name
+	.long	141                             # DW_AT_type
+	.byte	1                               # DW_AT_decl_file
+	.byte	5                               # DW_AT_decl_line
+	.byte	0                               # DW_AT_data_member_location
+	.byte	9                               # Abbrev [9] 0xa5:0x9 DW_TAG_member
+	.byte	9                               # DW_AT_name
+	.long	184                             # DW_AT_type
+	.byte	1                               # DW_AT_decl_file
+	.byte	6                               # DW_AT_decl_line
+	.byte	4                               # DW_AT_data_member_location
+	.byte	9                               # Abbrev [9] 0xae:0x9 DW_TAG_member
+	.byte	11                              # DW_AT_name
+	.long	188                             # DW_AT_type
+	.byte	1                               # DW_AT_decl_file
+	.byte	7                               # DW_AT_decl_line
+	.byte	8                               # DW_AT_data_member_location
+	.byte	0                               # End Of Children Mark
+	.byte	6                               # Abbrev [6] 0xb8:0x4 DW_TAG_base_type
+	.byte	10                              # DW_AT_name
+	.byte	6                               # DW_AT_encoding
+	.byte	1                               # DW_AT_byte_size
+	.byte	10                              # Abbrev [10] 0xbc:0x5 DW_TAG_pointer_type
+	.long	150                             # DW_AT_type
+	.byte	10                              # Abbrev [10] 0xc1:0x5 DW_TAG_pointer_type
+	.long	198                             # DW_AT_type
+	.byte	10                              # Abbrev [10] 0xc6:0x5 DW_TAG_pointer_type
+	.long	184                             # DW_AT_type
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	72                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names-parent-idx.cpp"    # string offset=104
+.Linfo_string2:
+	.asciz	"parent-idx-test"               # string offset=131
+.Linfo_string3:
+	.asciz	"bar"                           # string offset=147
+.Linfo_string4:
+	.asciz	"_Z3barR3fooi"                  # string offset=151
+.Linfo_string5:
+	.asciz	"main"                          # string offset=164
+.Linfo_string6:
+	.asciz	"int"                           # string offset=169
+.Linfo_string7:
+	.asciz	"foo"                           # string offset=173
+.Linfo_string8:
+	.asciz	"x"                             # string offset=177
+.Linfo_string9:
+	.asciz	"y"                             # string offset=179
+.Linfo_string10:
+	.asciz	"char"                          # string offset=181
+.Linfo_string11:
+	.asciz	"foo_ptr"                       # string offset=186
+.Linfo_string12:
+	.asciz	"junk"                          # string offset=194
+.Linfo_string13:
+	.asciz	"argc"                          # string offset=199
+.Linfo_string14:
+	.asciz	"argv"                          # string offset=204
+.Linfo_string15:
+	.asciz	"my_struct"                     # string offset=209
+.Linfo_string16:
+	.asciz	"junk2"                         # string offset=219
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+	.quad	.Lfunc_begin1
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	6                               # Header: bucket count
+	.long	6                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	1                               # Bucket 0
+	.long	0                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	4                               # Bucket 3
+	.long	5                               # Bucket 4
+	.long	6                               # Bucket 5
+	.long	193487034                       # Hash in Bucket 0
+	.long	193495088                       # Hash in Bucket 2
+	.long	1358986904                      # Hash in Bucket 2
+	.long	193491849                       # Hash in Bucket 3
+	.long	2090499946                      # Hash in Bucket 4
+	.long	2090147939                      # Hash in Bucket 5
+	.long	.Linfo_string3                  # String in Bucket 0: bar
+	.long	.Linfo_string6                  # String in Bucket 2: int
+	.long	.Linfo_string4                  # String in Bucket 2: _Z3barR3fooi
+	.long	.Linfo_string7                  # String in Bucket 3: foo
+	.long	.Linfo_string5                  # String in Bucket 4: main
+	.long	.Linfo_string10                 # String in Bucket 5: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 0
+	.long	.Lnames3-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames4-.Lnames_entries0       # Offset in Bucket 3
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 4
+	.long	.Lnames5-.Lnames_entries0       # Offset in Bucket 5
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L2:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: bar
+.Lnames3:
+.L1:
+	.byte	2                               # Abbreviation code
+	.long	141                             # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z3barR3fooi
+.Lnames4:
+.L4:
+	.byte	3                               # Abbreviation code
+	.long	150                             # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: foo
+.Lnames2:
+.L0:
+	.byte	1                               # Abbreviation code
+	.long	70                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames5:
+.L3:
+	.byte	2                               # Abbreviation code
+	.long	184                             # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.addrsig_sym _Z3barR3fooi
+	.addrsig_sym _Z3foov
+	.addrsig_sym _ZN11parent_test3fooEv
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names.s b/lld/test/ELF/debug-names.s
new file mode 100644
index 00000000000000..ce013303f65f67
--- /dev/null
+++ b/lld/test/ELF/debug-names.s
@@ -0,0 +1,294 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
+# RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+
+# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM
+# RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
+# RUN: llvm-readelf -SW %t | FileCheck %s --check-prefix=READELF
+	
+# DISASM:       Disassembly of section .text:
+# DISASM-EMPTY:
+# DISASM:       <_Z2f12t1>:
+# DISASM-CHECK:   201180: 55       pushq %rbp
+# DISASM-CHECK:   201181: 48 89 e5 movq  %rsp, %rbp
+# DISASM-CHECK:   201184: 5d       popq  %rbp
+# DISASM-CHECK:   201185: c3       retq
+# DISASM-CHECK:   201186: cc       int3
+# DISASM-CHECK:   201187: cc       int3
+# DISASM-CHECK:   201188: cc       int3
+# DISASM-CHECK:   201189: cc       int3
+# DISASM-CHECK:   20118a: cc       int3
+# DISASM-CHECK:   20118b: cc       int3
+# DISASM-CHECK:   20118c: cc       int3
+# DISASM-CHECK:   20118d: cc       int3
+# DISASM-CHECK:   20118e: cc       int3
+# DISASM-CHECK:   20118f: cc       int3
+# DISASM:       <main>:
+# DISASM-CHECK:   201190: 55       pushq %rbp
+# DISASM-CHECK:   201191: 48 89 e5 movq  %rsp, %rbp
+# DISASM-CHECK:   201194: 31 c0    xorl  %eax, %eax
+# DISASM-CHECK:   201196: 5d       popq  %rbp
+# DISASM-CHECK:   201197: c3       retq
+
+# DWARF:      .debug_names contents:
+# DWARF:      Name Index @ 0x0 {
+# DWARF-NEXT:   Header {
+# DWARF-NEXT:     Length: 0xCC
+# DWARF-NEXT:     Format: DWARF32
+# DWARF-NEXT:     Version: 5
+# DWARF-NEXT:     CU count: 2
+# DWARF-NEXT:     Local TU count: 0
+# DWARF-NEXT:     Foreign TU count: 0
+# DWARF-NEXT:     Bucket count: 5
+# DWARF-NEXT:     Name count: 5
+# DWARF-NEXT:     Abbreviations table size: 0x1F
+# DWARF-NEXT:     Augmentation: 'LLVM0700'
+# DWARF:        Compilation Unit offsets [
+# DWARF-NEXT:     CU[0]: 0x00000000
+# DWARF-NEXT:     CU[1]: 0x00000041
+# DWARF:          Abbreviations [
+# DWARF-NEXT:     Abbreviation 0x1 {
+# DWARF:            Tag: DW_TAG_structure_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x2 {
+# DWARF-NEXT:       Tag: DW_TAG_subprogram
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x3 {
+# DWARF-NEXT:       Tag: DW_TAG_base_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:        Bucket 0 [
+# DWARF:        Bucket 1 [
+# DWARF:            String: 0x00000089 "f1"
+# DWARF-NEXT:       Entry @ 0xa3 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF:            String: 0x00000095 "t1"
+# DWARF-NEXT:       Entry @ 0xaa {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x0000003a
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0xb0 {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000042
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:            String: 0x00000130 "int"
+# DWARF-NEXT:       Entry @ 0xb7 {
+# DWARF-NEXT:         Abbrev: 0x3
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x0000003e
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:        Bucket 2 [
+# DWARF:        Bucket 3 [
+# DWARF:            String: 0x0000008c "_Z2f12t1"
+# DWARF-NEXT:       Entry @ 0xbe {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF:        Bucket 4 [
+# DWARF:            String: 0x0000012b "main"
+# DWARF-NEXT:       Entry @ 0xc5 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+
+# READELF: .debug_names PROGBITS 0000000000000000 0003eb 0000d0
+
+# RUN: ld.lld --debug-names --no-debug-names %t1.o %t2.o -o %t
+# RUN: llvm-readelf -SW %t | FileCheck %s --check-prefix=NO_DBG_NAMES
+	
+
+# NO_DBG_NAMES: .debug_names  PROGBITS  0000000000000000 00037c 000110
+	
+#-- input file: debug-names.cpp
+## Generated with:
+##
+## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+##     -S debug-names.cpp -o debug-names.s
+##
+## debug-names.cpp contents:
+##
+## struct t1 { };
+## void f1(t1) { }
+##
+##
+	.text
+	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
+	.p2align	4, 0x90
+	.type	_Z2f12t1, at function
+_Z2f12t1:                               # @_Z2f12t1
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z2f12t1, .Lfunc_end0-_Z2f12t1
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.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
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	3                               # DW_AT_linkage_name
+	.byte	4                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+                                        # DW_AT_external
+	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	127
+	.byte	0                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+	.long	58                              # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
+	.byte	5                               # DW_AT_calling_convention
+	.byte	5                               # DW_AT_name
+	.byte	1                               # DW_AT_byte_size
+	.byte	0                               # DW_AT_decl_file
+	.byte	1                               # DW_AT_decl_line
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	28                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names.cpp"               # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=120
+.Linfo_string3:
+	.asciz	"f1"                            # string offset=137
+.Linfo_string4:
+	.asciz	"_Z2f12t1"                      # string offset=140
+.Linfo_string5:
+	.asciz	"t1"                            # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863324                         # Hash in Bucket 1
+	.long	5863786                         # Hash in Bucket 1
+	.long	1398125246                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: f1
+	.long	.Linfo_string5                  # String in Bucket 1: t1
+	.long	.Linfo_string4                  # String in Bucket 2: _Z2f12t1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: f1
+.Lnames2:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	58                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z2f12t1
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:

>From 46339e6451baeb8d582226cfc206bbe76d597035 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 25 Mar 2024 19:48:29 -0700
Subject: [PATCH 02/23] [lld][ELF] Implement merged .debug_names section.

Fix two typos in test cases.
---
 lld/test/ELF/debug-names-bad-aug-string.s | 2 +-
 lld/test/ELF/debug-names-bad-version.s    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lld/test/ELF/debug-names-bad-aug-string.s b/lld/test/ELF/debug-names-bad-aug-string.s
index edf79f0fde5773..ec1651362497e6 100644
--- a/lld/test/ELF/debug-names-bad-aug-string.s
+++ b/lld/test/ELF/debug-names-bad-aug-string.s
@@ -1,6 +1,6 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
 # RUN: ld.lld --debug-names %t1.o %t2.o -o %t
 
 # RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
diff --git a/lld/test/ELF/debug-names-bad-version.s b/lld/test/ELF/debug-names-bad-version.s
index f3914670af94a5..bf1855151c20da 100644
--- a/lld/test/ELF/debug-names-bad-version.s
+++ b/lld/test/ELF/debug-names-bad-version.s
@@ -1,6 +1,6 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
 #
 # RUN: not ld.lld --debug-names %t1.o %t2.o -o /dev/null 2>&1 | FileCheck %s
 #

>From a90417463d3819c3c7bc5b10b7fc3e36caf48dc9 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 25 Mar 2024 23:38:38 -0700
Subject: [PATCH 03/23] [lld][ELF] Implement merged .debug_names section.

Clean up some error checking and reporting, and add some new tests.
---
 lld/ELF/SyntheticSections.cpp                 |  52 +++---
 lld/test/ELF/debug-names-dwarf64.s            | 151 +++++++++++++++++
 .../ELF/debug-names-invalid-abbrev-code.s     | 151 +++++++++++++++++
 .../ELF/debug-names-invalid-attribute-2.s     | 150 +++++++++++++++++
 .../ELF/debug-names-invalid-attribute-3.s     | 154 ++++++++++++++++++
 lld/test/ELF/debug-names-invalid-parent-idx.s | 153 +++++++++++++++++
 6 files changed, 788 insertions(+), 23 deletions(-)
 create mode 100644 lld/test/ELF/debug-names-dwarf64.s
 create mode 100644 lld/test/ELF/debug-names-invalid-abbrev-code.s
 create mode 100644 lld/test/ELF/debug-names-invalid-attribute-2.s
 create mode 100644 lld/test/ELF/debug-names-invalid-attribute-3.s
 create mode 100644 lld/test/ELF/debug-names-invalid-parent-idx.s

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index d440410faa54f4..bc3083141f7665 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2877,42 +2877,36 @@ bool DebugNamesSection::isNeeded() const { return numChunks > 0; }
 template <class ELFT>
 static void
 readCompileUnitOffsets(struct DebugNamesSection::DebugNamesSectionData &secData,
-                       DebugNamesSection::DebugNamesInputChunk &inputChunk,
                        DebugNamesSection::DebugNamesOutputChunk &outputChunk,
                        llvm::DWARFDataExtractor &namesExtractor) {
   uint64_t offset = secData.locs.CUsBase;
   uint64_t *offsetPtr = &offset;
   for (size_t i = 0; i < secData.hdr.CompUnitCount; ++i) {
     llvm::Error err = llvm::Error::success();
+    // This call to namesExtractor can't fail; if there were a problem with the
+    // input, it would have been caught in the call to NamesIndex::extract, in
+    // DebugNamesSection::create.
     uint32_t value = namesExtractor.getU32(offsetPtr, &err);
-    if (err)
-      errorOrWarn(toString(inputChunk.namesSection->sec) +
-                  ": error reading CU offsets: " + toString(std::move(err)));
-    else
-      outputChunk.compilationUnits.push_back(value);
+    llvm::cantFail(std::move(err));
+    outputChunk.compilationUnits.push_back(value);
   }
 }
 
 template <class ELFT>
 static void
 readEntryOffsets(struct DebugNamesSection::DebugNamesSectionData &secData,
-                 DebugNamesSection::DebugNamesInputChunk &chunk,
                  llvm::DWARFDataExtractor &namesExtractor) {
   secData.entryOffsets = std::make_unique<uint32_t[]>(secData.hdr.NameCount);
-  if (secData.locs.EntryOffsetsBase >= namesExtractor.getData().size())
-    errorOrWarn(toString(chunk.namesSection->sec) +
-                ": invalid entry offsets input");
-
   uint64_t offset = secData.locs.EntryOffsetsBase;
   uint64_t *offsetPtr = &offset;
   for (size_t i = 0; i < secData.hdr.NameCount; ++i) {
     llvm::Error err = llvm::Error::success();
+    // This call to namesExtractor can't fail; if there were a problem with the
+    // input, it would have been caught in the call to NamesIndex::extract, in
+    // DebugNamesSection::create.
     uint32_t value = namesExtractor.getU32(offsetPtr, &err);
-    if (err)
-      errorOrWarn(toString(chunk.namesSection->sec) +
-                  ": error reading entry offsets: " + toString(std::move(err)));
-    else
-      secData.entryOffsets.get()[i] = value;
+    llvm::cantFail(std::move(err));
+    secData.entryOffsets.get()[i] = value;
   }
 }
 
@@ -2930,11 +2924,17 @@ static void readAttributeValues(
     llvm::Error err = llvm::Error::success();
     DebugNamesSection::AttrValueData newAttr;
     uint32_t value;
+    if (attr.Index == DW_IDX_parent &&
+        attr.Form != DW_FORM_flag_present &&
+        attr.Form != DW_FORM_ref4)
+      errorOrWarn(toString(namesSection.sec) + ": invalid form for DW_IDX_parent");
     switch (attr.Form) {
     case DW_FORM_flag_present: {
       // Currently only DW_IDX_parent attributes (in .debug_names) can
       // have this form. This form does not have a real value (nothing is
       // emitted for it).
+      if (attr.Index != DW_IDX_parent)
+        errorOrWarn(toString(namesSection.sec) + ": invalid form for attribute");
       break;
     }
     case DW_FORM_data1:
@@ -3004,10 +3004,11 @@ static void readEntry(DebugNamesSection::NamedEntry &stringEntry,
     auto entry = std::make_unique<DebugNamesSection::IndexEntry>();
     entry->poolOffset = offset;
     llvm::Error err = llvm::Error::success();
+    // This call to namesExtractor can't fail; if there were a problem with the
+    // input, it would have been caught in the call to NamesIndex::extract, in
+    // DebugNamesSection::create.
     uint64_t ulebValue = namesExtractor.getULEB128(&offset, &err);
-    if (err)
-      errorOrWarn(toString(chunk.namesSection->sec) +
-                  ": error reading entry: " + toString(std::move(err)));
+    llvm::cantFail(std::move(err));
     entry->abbrevCode = static_cast<uint32_t>(ulebValue);
     const auto &abbrevs = ni.getAbbrevs();
     auto abbrevIt = abbrevs.find_as(entry->abbrevCode);
@@ -3016,7 +3017,9 @@ static void readEntry(DebugNamesSection::NamedEntry &stringEntry,
       readAttributeValues<ELFT>(entry->attrValues, chunk, offset, secData,
                                 entry->parentOffset, namesExtractor, abbrev);
       stringEntry.indexEntries.push_back(std::move(entry));
-    }
+    } else
+      errorOrWarn(toString(chunk.namesSection->sec) +
+                  ": invalid abbrev code in entry");
   }
   if (offset >= namesSection->Data.size())
     errorOrWarn(toString(chunk.namesSection->sec) +
@@ -3092,15 +3095,18 @@ static void collectDebugNamesSectionData(
   for (const auto &ni : *chunk.debugNamesData) {
     DebugNamesSection::DebugNamesSectionData secData;
     secData.hdr = ni.getHeader();
-    if (secData.hdr.Format != DwarfFormat::DWARF32)
+    if (secData.hdr.Format != DwarfFormat::DWARF32) {
       errorOrWarn(toString(chunk.namesSection->sec) + ": unsupported DWARF64");
+      // Don't try to continue; we can't parse DWARF64 at the moment.
+      return;
+    }
     secData.dwarfSize = dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
     secData.hdrSize = computeDebugNamesHeaderSize();
     if (secData.hdr.Version != 5)
       errorOrWarn(toString(chunk.namesSection->sec) + ": unsupported version");
     secData.locs = findDebugNamesOffsets(secData.hdrSize, secData.hdr);
-    readCompileUnitOffsets<ELFT>(secData, chunk, outputChunk, namesExtractor);
-    readEntryOffsets<ELFT>(secData, chunk, namesExtractor);
+    readCompileUnitOffsets<ELFT>(secData, outputChunk, namesExtractor);
+    readEntryOffsets<ELFT>(secData, namesExtractor);
     readEntries<ELFT>(secData, chunk, namesExtractor, strExtractor, ni);
     chunk.sectionsData.push_back(std::move(secData));
   }
diff --git a/lld/test/ELF/debug-names-dwarf64.s b/lld/test/ELF/debug-names-dwarf64.s
new file mode 100644
index 00000000000000..4391142c5558c2
--- /dev/null
+++ b/lld/test/ELF/debug-names-dwarf64.s
@@ -0,0 +1,151 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}(.debug_names): unsupported DWARF64
+##
+## This file was generated by:
+## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+##    -gdwarf64 -gpubnames main.cpp
+##
+## main.cpp
+## int main (int argc, char **argv) { }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	4294967295                      # DWARF64 Mark
+	.quad	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.quad	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	4294967295                      # DWARF64 Mark
+	.quad	68                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 9b37e60051f362e8e22c88785239fd5dfbfdf105)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	4294967295                      # DWARF64 Mark
+	.quad	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.quad	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.quad	.Linfo_string3                  # String in Bucket 1: main
+	.quad	.Linfo_string4                  # String in Bucket 2: int
+	.quad	.Linfo_string7                  # String in Bucket 2: char
+	.quad	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.quad	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.quad	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L2:
+	.byte	1                               # Abbreviation code
+	.long	59                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L1:
+	.byte	2                               # Abbreviation code
+	.long	97                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	111                             # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 9b37e60051f362e8e22c88785239fd5dfbfdf105)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-invalid-abbrev-code.s b/lld/test/ELF/debug-names-invalid-abbrev-code.s
new file mode 100644
index 00000000000000..14970e0d10433c
--- /dev/null
+++ b/lld/test/ELF/debug-names-invalid-abbrev-code.s
@@ -0,0 +1,151 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}(.debug_names): invalid abbrev code in entry
+# CHECK: error: {{.*}}(.debug_names): invalid abbrev code in entry
+##
+## This file was generated by:
+## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+##    -gpubnames main.cpp
+##
+## Then manually changing an abbrev code.
+## 
+## main.cpp
+## int main (int argc, char **argv) { }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	3                               # Abbreviation code
+	.long	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	87                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-invalid-attribute-2.s b/lld/test/ELF/debug-names-invalid-attribute-2.s
new file mode 100644
index 00000000000000..44e74911bd0353
--- /dev/null
+++ b/lld/test/ELF/debug-names-invalid-attribute-2.s
@@ -0,0 +1,150 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}(.debug_names): error while reading attributes: unexpected end of data at offset 0x80 while reading [0x7e, 0x82)
+##
+## This file was generated by:
+## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+##    -gpubnames main.cpp
+##
+## Then manually editing .debug_names section, commenting out a
+## DW_IDX_die_offset in an entry.
+## 
+## main.cpp
+## int main (int argc, char **argv) { }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+#	.long	87                              # DW_IDX_die_offset
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-invalid-attribute-3.s b/lld/test/ELF/debug-names-invalid-attribute-3.s
new file mode 100644
index 00000000000000..1e6ea8074975f5
--- /dev/null
+++ b/lld/test/ELF/debug-names-invalid-attribute-3.s
@@ -0,0 +1,154 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}(.debug_names): invalid form for attribute
+##
+## This file was generated by:
+## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+##    -gpubnames main.cpp
+##
+## 
+## Then manually changing the first .debug_names abbrev, so that the
+## DW_IDX_die_offset uses DW_FORM_flag_present (invalid) & the DW_IDX_parent
+## uses DW_FORM_ref4. Also updated the sizes of the values in the entry
+## that uses the abbrev, to match the sizes of the forms.
+## 
+## main.cpp
+## int main (int argc, char **argv) { }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	25                              # DW_FORM_flag_present
+	.byte	4                               # DW_IDX_parent
+	.byte	19                              # DW_FORM_ref4
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.byte	35                              # DW_IDX_die_offset
+	.long	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	87                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-invalid-parent-idx.s b/lld/test/ELF/debug-names-invalid-parent-idx.s
new file mode 100644
index 00000000000000..be5df8b155250e
--- /dev/null
+++ b/lld/test/ELF/debug-names-invalid-parent-idx.s
@@ -0,0 +1,153 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+#
+# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
+#
+# CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
+# CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
+# CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
+##
+## This file was generated by:
+## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+##    -gpubnames main.cpp
+##
+## Then manually editing .debug_names section, changing the form for a 
+## DW_IDX_parent from DW_FORM_flag_present to DW_FORM_ref1 (invalid).
+## 
+## main.cpp
+## int main (int argc, char **argv) { }
+##
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	17                              # DW_FORM_ref1
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	87                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:

>From 5b7ff5b5cd5c137d29d467aebfa2615ac25c00df Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 26 Mar 2024 22:48:27 -0700
Subject: [PATCH 04/23] [lld][ELF] Implement merged .debug_names section.

Update and fix debug-names* tests. Make entire DebugNamesSection
a template <class ELFT> section. Fix formatting and other
review comments.
---
 lld/ELF/SyntheticSections.cpp                 | 238 +++++----
 lld/ELF/SyntheticSections.h                   |  17 +-
 lld/test/ELF/Inputs/debug-names-2.s           |  45 +-
 .../ELF/Inputs/debug-names-parent-idx-2.s     |  98 +---
 lld/test/ELF/debug-names-bad-aug-string.s     |  84 +--
 lld/test/ELF/debug-names-bad-die-idx-sizes.s  |  32 +-
 lld/test/ELF/debug-names-bad-name-count.s     |  39 +-
 lld/test/ELF/debug-names-bad-offsets-sizes.s  |  37 +-
 lld/test/ELF/debug-names-bad-version.s        |  21 +-
 lld/test/ELF/debug-names-dwarf64.s            |  28 +-
 .../ELF/debug-names-invalid-abbrev-code.s     |  34 +-
 .../ELF/debug-names-invalid-attribute-2.s     |  34 +-
 .../ELF/debug-names-invalid-attribute-3.s     |  39 +-
 lld/test/ELF/debug-names-invalid-attribute.s  |  53 +-
 lld/test/ELF/debug-names-invalid-flags.s      | 148 ++++++
 lld/test/ELF/debug-names-invalid-parent-idx.s |  38 +-
 lld/test/ELF/debug-names-parent-idx.s         | 496 +++++++-----------
 lld/test/ELF/debug-names.s                    | 263 ++++------
 18 files changed, 752 insertions(+), 992 deletions(-)
 create mode 100644 lld/test/ELF/debug-names-invalid-flags.s

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index bc3083141f7665..776bf719a01d77 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2714,13 +2714,15 @@ static uint32_t computeGdbHash(StringRef s) {
   return h;
 }
 
-DebugNamesSection::DebugNamesSection()
+template <class ELFT>
+DebugNamesSection<ELFT>::DebugNamesSection()
     : SyntheticSection(0, SHT_PROGBITS, 1, ".debug_names") {}
 
-template <class ELFT, class RelTy>
-void DebugNamesSection::getNameRelocsImpl(
+template <class ELFT>
+template <class RelTy>
+void DebugNamesSection<ELFT>::getNameRelocsImpl(
     InputSection *sec, ArrayRef<RelTy> rels,
-    llvm::DenseMap<uint32_t, uint32_t> &relocs) {
+    DenseMap<uint32_t, uint32_t> &relocs) {
   for (auto &rel : rels) {
     Symbol &sym = sec->getFile<ELFT>()->getRelocTargetSym(rel);
     relocs[rel.r_offset] = sym.getVA(getAddend<ELFT>(rel));
@@ -2728,31 +2730,28 @@ void DebugNamesSection::getNameRelocsImpl(
 }
 
 template <class ELFT>
-void DebugNamesSection::getNameRelocs(
-    InputSectionBase *base, llvm::DenseMap<uint32_t, uint32_t> &relocs) {
+void DebugNamesSection<ELFT>::getNameRelocs(
+    InputSectionBase *base, DenseMap<uint32_t, uint32_t> &relocs) {
   auto *sec = cast<InputSection>(base);
   const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>();
   if (rels.areRelocsRel())
-    getNameRelocsImpl<ELFT>(sec, rels.rels, relocs);
+    getNameRelocsImpl(sec, rels.rels, relocs);
   else
-    getNameRelocsImpl<ELFT>(sec, rels.relas, relocs);
+    getNameRelocsImpl(sec, rels.relas, relocs);
 }
 
-void DebugNamesSection::writeTo(uint8_t *buf) { invokeELFT(writeToImpl, buf); }
-
-template <class ELFT> void DebugNamesSection::writeToImpl(uint8_t *buf) {
+template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   SmallVector<uint32_t, 0> mergedCuOffsets;
   SmallVector<uint32_t, 0> mergedTuOffsets;
-  llvm::DenseMap<uint32_t, uint32_t> strOffsets;
-  SmallVector<llvm::DenseMap<uint32_t, uint32_t>, 0> chunksRelocs;
+  DenseMap<uint32_t, uint32_t> strOffsets;
+  SmallVector<DenseMap<uint32_t, uint32_t>, 0> chunksRelocs;
   chunksRelocs.reserve(numChunks);
 
   for (size_t i = 0; i < numChunks; ++i) {
     DebugNamesOutputChunk &chunk = outputChunks[i];
     InputSectionBase *base = inputDebugNamesSections[i];
-    llvm::DenseMap<uint32_t, uint32_t> relocs;
-    getNameRelocs<ELFT>(base, relocs);
-    chunksRelocs.push_back(std::move(relocs));
+    DenseMap<uint32_t, uint32_t> &relocs = chunksRelocs.emplace_back();
+    getNameRelocs(base, relocs);
 
     // Update CuOffsets list with new data
     for (uint32_t cuOffset : chunk.compilationUnits)
@@ -2839,15 +2838,11 @@ template <class ELFT> void DebugNamesSection::writeToImpl(uint8_t *buf) {
 
   // Write the abbrev table.
   for (const auto *abbrev : mergedAbbrevTable) {
-    size_t uleb_size = encodeULEB128(abbrev->code, buf);
-    buf += uleb_size;
-    uleb_size = encodeULEB128(abbrev->tag, buf);
-    buf += uleb_size;
+    buf += encodeULEB128(abbrev->code, buf);
+    buf += encodeULEB128(abbrev->tag, buf);
     for (auto attr : abbrev->attributes) {
-      uleb_size = encodeULEB128(attr.Index, buf);
-      buf += uleb_size;
-      uleb_size = encodeULEB128(attr.Form, buf);
-      buf += uleb_size;
+      buf += encodeULEB128(attr.Index, buf);
+      buf += encodeULEB128(attr.Form, buf);
     }
     endian::write16<ELFT::Endianness>(buf + 0, 0); // attribute sentinels.
     buf += 2;
@@ -2857,10 +2852,8 @@ template <class ELFT> void DebugNamesSection::writeToImpl(uint8_t *buf) {
   // Write the entry pool.
   for (const auto &stringEntry : mergedEntries) {
     // Write all the entries for the string.
-    size_t uleb_size;
     for (const auto &entry : stringEntry.indexEntries) {
-      uleb_size = encodeULEB128(entry->abbrevCode, buf);
-      buf += uleb_size;
+      buf += encodeULEB128(entry->abbrevCode, buf);
       for (const auto &value : entry->attrValues) {
         if (value.attrSize > 0) {
           endian::write32<ELFT::Endianness>(buf + 0, value.attrValue);
@@ -2872,69 +2865,74 @@ template <class ELFT> void DebugNamesSection::writeToImpl(uint8_t *buf) {
   }
 }
 
-bool DebugNamesSection::isNeeded() const { return numChunks > 0; }
+template <class ELFT> bool DebugNamesSection<ELFT>::isNeeded() const {
+  return numChunks > 0;
+}
 
 template <class ELFT>
-static void
-readCompileUnitOffsets(struct DebugNamesSection::DebugNamesSectionData &secData,
-                       DebugNamesSection::DebugNamesOutputChunk &outputChunk,
-                       llvm::DWARFDataExtractor &namesExtractor) {
+static void readCompileUnitOffsets(
+    typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+    typename DebugNamesSection<ELFT>::DebugNamesOutputChunk &outputChunk,
+    DWARFDataExtractor &namesExtractor) {
   uint64_t offset = secData.locs.CUsBase;
   uint64_t *offsetPtr = &offset;
   for (size_t i = 0; i < secData.hdr.CompUnitCount; ++i) {
-    llvm::Error err = llvm::Error::success();
+    Error err = Error::success();
     // This call to namesExtractor can't fail; if there were a problem with the
     // input, it would have been caught in the call to NamesIndex::extract, in
     // DebugNamesSection::create.
     uint32_t value = namesExtractor.getU32(offsetPtr, &err);
-    llvm::cantFail(std::move(err));
+    cantFail(std::move(err));
     outputChunk.compilationUnits.push_back(value);
   }
 }
 
 template <class ELFT>
-static void
-readEntryOffsets(struct DebugNamesSection::DebugNamesSectionData &secData,
-                 llvm::DWARFDataExtractor &namesExtractor) {
+static void readEntryOffsets(
+    typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+    DWARFDataExtractor &namesExtractor) {
   secData.entryOffsets = std::make_unique<uint32_t[]>(secData.hdr.NameCount);
   uint64_t offset = secData.locs.EntryOffsetsBase;
   uint64_t *offsetPtr = &offset;
   for (size_t i = 0; i < secData.hdr.NameCount; ++i) {
-    llvm::Error err = llvm::Error::success();
+    Error err = Error::success();
     // This call to namesExtractor can't fail; if there were a problem with the
     // input, it would have been caught in the call to NamesIndex::extract, in
     // DebugNamesSection::create.
     uint32_t value = namesExtractor.getU32(offsetPtr, &err);
-    llvm::cantFail(std::move(err));
+    cantFail(std::move(err));
     secData.entryOffsets.get()[i] = value;
   }
 }
 
 template <class ELFT>
 static void readAttributeValues(
-    SmallVector<DebugNamesSection::AttrValueData, 3> &values,
-    DebugNamesSection::DebugNamesInputChunk &chunk, uint64_t &offset,
-    struct DebugNamesSection::DebugNamesSectionData &secData,
-    int32_t &parentOffset, llvm::DWARFDataExtractor &namesExtractor,
-    const llvm::DWARFDebugNames::Abbrev &abbrev) {
+    SmallVector<typename DebugNamesSection<ELFT>::AttrValueData, 3> &values,
+    typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
+    uint64_t &offset,
+    typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+    int32_t &parentOffset, DWARFDataExtractor &namesExtractor,
+    const DWARFDebugNames::Abbrev &abbrev) {
   const LLDDWARFSection &namesSection = *chunk.namesSection;
   uint64_t *offsetPtr = &offset;
-  DebugNamesSection::AttrValueData cuOrTuAttr = {0, 0};
+  typename DebugNamesSection<ELFT>::AttrValueData cuOrTuAttr = {0, 0};
   for (auto attr : abbrev.Attributes) {
-    llvm::Error err = llvm::Error::success();
-    DebugNamesSection::AttrValueData newAttr;
+    Error err = Error::success();
+    typename DebugNamesSection<ELFT>::AttrValueData newAttr;
     uint32_t value;
     if (attr.Index == DW_IDX_parent &&
         attr.Form != DW_FORM_flag_present &&
         attr.Form != DW_FORM_ref4)
-      errorOrWarn(toString(namesSection.sec) + ": invalid form for DW_IDX_parent");
+      errorOrWarn(toString(namesSection.sec) +
+                  Twine(": invalid form for DW_IDX_parent"));
     switch (attr.Form) {
     case DW_FORM_flag_present: {
       // Currently only DW_IDX_parent attributes (in .debug_names) can
       // have this form. This form does not have a real value (nothing is
       // emitted for it).
       if (attr.Index != DW_IDX_parent)
-        errorOrWarn(toString(namesSection.sec) + ": invalid form for attribute");
+        errorOrWarn(toString(namesSection.sec) +
+                    Twine(": invalid form for attribute"));
       break;
     }
     case DW_FORM_data1:
@@ -2970,14 +2968,14 @@ static void readAttributeValues(
     default: {
       errorOrWarn(toString(namesSection.sec) +
                   Twine(": unrecognized form encoding ") + Twine(attr.Form) +
-                  " in .debug_names abbrev table");
+                  Twine(" in .debug_names abbrev table"));
       break;
     }
     }
     if (err)
-      errorOrWarn(
-          toString(namesSection.sec) +
-          ": error while reading attributes: " + toString(std::move(err)));
+      errorOrWarn(toString(namesSection.sec) +
+                  Twine(": error while reading attributes: ") +
+                  toString(std::move(err)));
     if (attr.Index == DW_IDX_compile_unit || attr.Index == DW_IDX_type_unit)
       // Save it to put it at the end of the attributes list.
       cuOrTuAttr = newAttr;
@@ -2990,59 +2988,61 @@ static void readAttributeValues(
 }
 
 template <class ELFT>
-static void readEntry(DebugNamesSection::NamedEntry &stringEntry,
-                      DebugNamesSection::DebugNamesInputChunk &chunk,
-                      DebugNamesSection::DebugNamesSectionData &secData,
-                      llvm::DWARFDataExtractor &namesExtractor,
-                      const llvm::DWARFDebugNames::NameIndex &ni) {
+static void
+readEntry(typename DebugNamesSection<ELFT>::NamedEntry &stringEntry,
+          typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
+          typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+          DWARFDataExtractor &namesExtractor,
+          const DWARFDebugNames::NameIndex &ni) {
   std::unique_ptr<LLDDWARFSection> &namesSection = chunk.namesSection;
   uint64_t offset = stringEntry.entryOffset;
   // Each entry ends with a zero 'sentinel' value
   while (offset < namesSection->Data.size() &&
          namesSection->Data[offset] != 0) {
     // Read & store all entries (for the same string)
-    auto entry = std::make_unique<DebugNamesSection::IndexEntry>();
+    auto entry =
+        std::make_unique<typename DebugNamesSection<ELFT>::IndexEntry>();
     entry->poolOffset = offset;
-    llvm::Error err = llvm::Error::success();
+    Error err = Error::success();
     // This call to namesExtractor can't fail; if there were a problem with the
     // input, it would have been caught in the call to NamesIndex::extract, in
     // DebugNamesSection::create.
     uint64_t ulebValue = namesExtractor.getULEB128(&offset, &err);
-    llvm::cantFail(std::move(err));
+    cantFail(std::move(err));
     entry->abbrevCode = static_cast<uint32_t>(ulebValue);
     const auto &abbrevs = ni.getAbbrevs();
     auto abbrevIt = abbrevs.find_as(entry->abbrevCode);
     if (abbrevIt != abbrevs.end()) {
-      const llvm::DWARFDebugNames::Abbrev &abbrev = *abbrevIt;
+      const DWARFDebugNames::Abbrev &abbrev = *abbrevIt;
       readAttributeValues<ELFT>(entry->attrValues, chunk, offset, secData,
                                 entry->parentOffset, namesExtractor, abbrev);
       stringEntry.indexEntries.push_back(std::move(entry));
     } else
       errorOrWarn(toString(chunk.namesSection->sec) +
-                  ": invalid abbrev code in entry");
+                  Twine(": invalid abbrev code in entry"));
   }
   if (offset >= namesSection->Data.size())
-    errorOrWarn(toString(chunk.namesSection->sec) +
-                ": encountered unexpected end of section while reading entry");
+    errorOrWarn(
+        toString(chunk.namesSection->sec) +
+        Twine(": encountered unexpected end of section while reading entry"));
 }
 
 template <class ELFT>
 static void
-readEntries(struct DebugNamesSection::DebugNamesSectionData &secData,
-            DebugNamesSection::DebugNamesInputChunk &chunk,
-            llvm::DWARFDataExtractor &namesExtractor,
-            llvm::DataExtractor &strExtractor,
-            const llvm::DWARFDebugNames::NameIndex &ni) {
+readEntries(typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+            typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
+            DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor,
+            const DWARFDebugNames::NameIndex &ni) {
   // Temporary map from entry offsets to address (pointer) of entry with that
   // offset; used to find parent entries quickly.
-  DenseMap<uint32_t, DebugNamesSection::IndexEntry *> offsetMap;
+  DenseMap<uint32_t, typename DebugNamesSection<ELFT>::IndexEntry *> offsetMap;
   // Reserve sizes for this chunk's hashes & namedEntries.
   chunk.hashValues.reserve(secData.hdr.NameCount);
   secData.namedEntries.reserve(secData.hdr.NameCount);
   // Calculate the Entry Offsets, create initial records.
   for (uint32_t i = 0; i < secData.hdr.NameCount; ++i) {
     // Get string value
-    DebugNamesSection::NamedEntry stringEntry;
+    typename DebugNamesSection<ELFT>::NamedEntry stringEntry;
     stringEntry.entryOffset =
         secData.locs.EntriesBase + secData.entryOffsets[i];
     uint64_t strOffsetOffset =
@@ -3088,22 +3088,23 @@ static uint16_t computeDebugNamesHeaderSize() {
 
 template <class ELFT>
 static void collectDebugNamesSectionData(
-    DebugNamesSection::DebugNamesInputChunk &chunk,
-    DebugNamesSection::DebugNamesOutputChunk &outputChunk,
-    llvm::DWARFDataExtractor &namesExtractor,
-    llvm::DataExtractor &strExtractor) {
+    typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
+    typename DebugNamesSection<ELFT>::DebugNamesOutputChunk &outputChunk,
+    DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor) {
   for (const auto &ni : *chunk.debugNamesData) {
-    DebugNamesSection::DebugNamesSectionData secData;
+    typename DebugNamesSection<ELFT>::DebugNamesSectionData secData;
     secData.hdr = ni.getHeader();
     if (secData.hdr.Format != DwarfFormat::DWARF32) {
-      errorOrWarn(toString(chunk.namesSection->sec) + ": unsupported DWARF64");
+      errorOrWarn(toString(chunk.namesSection->sec) +
+                  Twine(": unsupported DWARF64"));
       // Don't try to continue; we can't parse DWARF64 at the moment.
       return;
     }
     secData.dwarfSize = dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
     secData.hdrSize = computeDebugNamesHeaderSize();
     if (secData.hdr.Version != 5)
-      errorOrWarn(toString(chunk.namesSection->sec) + ": unsupported version");
+      errorOrWarn(toString(chunk.namesSection->sec) +
+                  Twine(": unsupported version"));
     secData.locs = findDebugNamesOffsets(secData.hdrSize, secData.hdr);
     readCompileUnitOffsets<ELFT>(secData, outputChunk, namesExtractor);
     readEntryOffsets<ELFT>(secData, namesExtractor);
@@ -3112,10 +3113,10 @@ static void collectDebugNamesSectionData(
   }
 }
 
-void DebugNamesSection::collectMergedCounts(
+template <class ELFT>
+void DebugNamesSection<ELFT>::collectMergedCounts(
     MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
   SmallVector<uint32_t, 0> tmpMergedCuOffsets;
-
   mergedHdr.CompUnitCount = 0;
   mergedHdr.LocalTypeUnitCount = 0;
   mergedHdr.ForeignTypeUnitCount = 0;
@@ -3143,15 +3144,15 @@ void DebugNamesSection::collectMergedCounts(
                   data.hdr.AugmentationString)) {
         // There are conflicting augmentation strings, so it's best for the
         // merged index to not use an augmentation string.
-        StringRef emptyString = "        ";
         mergedHdr.AugmentationStringSize = 8;
-        mergedHdr.AugmentationString = emptyString;
+        mergedHdr.AugmentationString = "        ";
       }
     }
   }
 }
 
-void DebugNamesSection::Abbrev::Profile(llvm::FoldingSetNodeID &id) const {
+template <class ELFT>
+void DebugNamesSection<ELFT>::Abbrev::Profile(FoldingSetNodeID &id) const {
   id.AddInteger(tag);
   for (const DWARFDebugNames::AttributeEncoding &attr : attributes) {
     id.AddInteger(attr.Index);
@@ -3159,14 +3160,15 @@ void DebugNamesSection::Abbrev::Profile(llvm::FoldingSetNodeID &id) const {
   }
 }
 
-std::pair<uint8_t, dwarf::Form> DebugNamesSection::getMergedCuSizeData() {
+template <class ELFT>
+std::pair<uint8_t, dwarf::Form> DebugNamesSection<ELFT>::getMergedCuSizeData() {
   // Once we've merged all the CU offsets into a single list, the original
   // DWARF form/size (often 1 byte) may be too small to hold indices to all
   // the offsets. Here we calculate what the right form/size needs to be for
   // the merged index.
   uint8_t size;
   dwarf::Form form;
-  // TODO: Investigate possibly using llvm::DIEInteger::BestForm here
+  // TODO: Investigate possibly using DIEInteger::BestForm here
   if (mergedHdr.CompUnitCount > 0xffffffff) {
     form = DW_FORM_data8;
     size = 8;
@@ -3184,10 +3186,11 @@ std::pair<uint8_t, dwarf::Form> DebugNamesSection::getMergedCuSizeData() {
   return {size, form};
 }
 
-void DebugNamesSection::getMergedAbbrevTable(
+template <class ELFT>
+void DebugNamesSection<ELFT>::getMergedAbbrevTable(
     MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
   MapVector<uint64_t, Abbrev> abbrevMap;
-  FoldingSet<DebugNamesSection::Abbrev> AbbreviationsSet;
+  FoldingSet<Abbrev> AbbreviationsSet;
 
   // Need to determine what size form is needed for the DW_IDX_compile_unit
   // attributes in the merged index. Will need to update the abbrevs to use
@@ -3199,7 +3202,7 @@ void DebugNamesSection::getMergedAbbrevTable(
       const auto &abbrevs = ni.getAbbrevs();
       for (const DWARFDebugNames::Abbrev &abbrev : abbrevs) {
         // Create canonicalized abbrev.
-        DebugNamesSection::Abbrev newAbbrev;
+        Abbrev newAbbrev;
         DWARFDebugNames::AttributeEncoding cuOrTuAttr(DW_IDX_compile_unit,
                                                       compileUnitAttrForm);
         newAbbrev.code = abbrev.Code;
@@ -3254,14 +3257,15 @@ void DebugNamesSection::getMergedAbbrevTable(
   ++mergedHdr.AbbrevTableSize; // abbrev table sentinel
 }
 
-void DebugNamesSection::getMergedSymbols(
+template <class ELFT>
+void DebugNamesSection<ELFT>::getMergedSymbols(
     MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
   // The number of symbols (& abbrevs) we will handle is very large; will use
   // multi-threading to speed it up.
   constexpr size_t numShards = 32;
   const size_t concurrency =
-      llvm::bit_floor(std::min<size_t>(config->threadCount, numShards));
-  const size_t shift = 32 - llvm::countr_zero(numShards);
+      bit_floor(std::min<size_t>(config->threadCount, numShards));
+  const size_t shift = 32 - countr_zero(numShards);
 
   struct ShardData {
     // Map to uniquify symbols by name
@@ -3330,7 +3334,8 @@ void DebugNamesSection::getMergedSymbols(
   mergedHdr.NameCount = mergedEntries.size();
 }
 
-void DebugNamesSection::computeUniqueHashes(
+template <class ELFT>
+void DebugNamesSection<ELFT>::computeUniqueHashes(
     MutableArrayRef<DebugNamesInputChunk> &chunks) {
   SmallVector<uint32_t, 0> uniques;
   for (const auto &chunk : chunks)
@@ -3339,7 +3344,7 @@ void DebugNamesSection::computeUniqueHashes(
   mergedHdr.BucketCount = dwarf::getDebugNamesBucketCount(llvm::unique(uniques) - uniques.begin());
 }
 
-void DebugNamesSection::generateBuckets() {
+template <class ELFT> void DebugNamesSection<ELFT>::generateBuckets() {
   bucketList.resize(mergedHdr.BucketCount);
   for (auto &entry : mergedEntries) {
     uint32_t bucketIdx = entry.hashValue % mergedHdr.BucketCount;
@@ -3349,20 +3354,20 @@ void DebugNamesSection::generateBuckets() {
   // Sort the contents of the buckets by hash value so that the hash collisions
   // end up together.
   for (auto &bucket : bucketList)
-    llvm::stable_sort(bucket, [](NamedEntry *lhs, NamedEntry *rhs) {
+    stable_sort(bucket, [](NamedEntry *lhs, NamedEntry *rhs) {
       return lhs->hashValue < rhs->hashValue;
     });
 }
 
-void DebugNamesSection::calculateEntriesSizeAndOffsets() {
+template <class ELFT>
+void DebugNamesSection<ELFT>::calculateEntriesSizeAndOffsets() {
   uint32_t offset = 0;
-  for (DebugNamesSection::NamedEntry &stringEntry : mergedEntries) {
+  for (NamedEntry &stringEntry : mergedEntries) {
     stringEntry.entryOffset = offset;
     for (auto &entry : stringEntry.indexEntries) {
       uint32_t entrySize = 0;
       entry->poolOffset = offset;
-      uint32_t ulebSize = getULEB128Size(entry->abbrevCode);
-      entrySize += ulebSize;
+      entrySize += getULEB128Size(entry->abbrevCode);
       for (const auto &attr : entry->attrValues)
         entrySize += attr.attrSize;
       offset += entrySize;
@@ -3373,8 +3378,8 @@ void DebugNamesSection::calculateEntriesSizeAndOffsets() {
   mergedTotalEntriesSize = offset;
 }
 
-void DebugNamesSection::updateParentIndexEntries() {
-  for (DebugNamesSection::NamedEntry &stringEntry : mergedEntries) {
+template <class ELFT> void DebugNamesSection<ELFT>::updateParentIndexEntries() {
+  for (NamedEntry &stringEntry : mergedEntries) {
     for (auto &childEntry : stringEntry.indexEntries) {
       if (!childEntry->parentEntry)
         continue;
@@ -3397,7 +3402,8 @@ void DebugNamesSection::updateParentIndexEntries() {
   }
 }
 
-uint64_t DebugNamesSection::calculateMergedSectionSize() {
+template <class ELFT>
+uint64_t DebugNamesSection<ELFT>::calculateMergedSectionSize() {
   uint32_t hdrSize = computeDebugNamesHeaderSize();
   mergedOffsets = findDebugNamesOffsets(hdrSize, mergedHdr);
   // Add in the size for all the Entries, and make it 4-byte aligned.
@@ -3407,8 +3413,9 @@ uint64_t DebugNamesSection::calculateMergedSectionSize() {
   return mergedHdr.UnitLength + 4;
 }
 
-template <class ELFT> DebugNamesSection *DebugNamesSection::create() {
-  llvm::TimeTraceScope timeScope("Create merged .debug_names");
+template <class ELFT>
+DebugNamesSection<ELFT> *DebugNamesSection<ELFT>::create() {
+  TimeTraceScope timeScope("Create merged .debug_names");
   SetVector<InputFile *> files;
   SmallVector<InputSectionBase *, 0> sections;
   for (InputSectionBase *s : ctx.inputSections) {
@@ -3428,28 +3435,26 @@ template <class ELFT> DebugNamesSection *DebugNamesSection::create() {
                                                     files.size());
   auto outputChunks = std::make_unique<DebugNamesOutputChunk[]>(files.size());
   parallelFor(0, files.size(), [&](size_t i) {
-    ObjFile<ELFT> *file = cast<ObjFile<ELFT>>(files[i]);
+    auto *file = cast<ObjFile<ELFT>>(files[i]);
     auto dwarfCtx = std::make_unique<DWARFContext>(
         std::make_unique<LLDDwarfObj<ELFT>>(file));
     auto &dobj =
         static_cast<const LLDDwarfObj<ELFT> &>(dwarfCtx->getDWARFObj());
 
-    // Extract llvm::DWARFDebugNames data from the .debug_names section. The
+    // Extract DWARFDebugNames data from the .debug_names section. The
     // .debug_names section needs the .debug_str section, to get the actual
     // symbol names.
-    const StringRef &strSection = dobj.getStrSection();
+    const StringRef strSection = dobj.getStrSection();
     const LLDDWARFSection &namesSection = dobj.getNamesSection();
-    llvm::DWARFDataExtractor namesExtractor(dobj, namesSection, config->isLE,
-                                            config->wordsize);
-    llvm::DataExtractor strExtractor(strSection, config->isLE,
-                                     config->wordsize);
+    DWARFDataExtractor namesExtractor(dobj, namesSection, config->isLE,
+                                      config->wordsize);
+    DataExtractor strExtractor(strSection, config->isLE, config->wordsize);
     inputChunks[i].debugNamesData =
         std::make_unique<DWARFDebugNames>(namesExtractor, strExtractor);
     inputChunks[i].namesSection =
         std::make_unique<LLDDWARFSection>(namesSection);
-    if (llvm::Error E = inputChunks[i].debugNamesData->extract()) {
-      // Report an error here. We were unable to extract the data.
-      errorOrWarn(toString(dobj.getNamesSection().sec) + ": " +
+    if (Error E = inputChunks[i].debugNamesData->extract()) {
+      errorOrWarn(toString(dobj.getNamesSection().sec) + Twine(": ") +
                   toString(std::move(E)));
     }
     outputChunks[i].sec = dobj.getInfoSection();
@@ -3458,13 +3463,14 @@ template <class ELFT> DebugNamesSection *DebugNamesSection::create() {
   });
 
   auto *ret = make<DebugNamesSection>();
-  ret->addSections(sections);
+  ret->inputDebugNamesSections = sections;
   ret->outputChunks = std::move(outputChunks);
   ret->numChunks = files.size();
   ret->collectMergedCounts(inputChunks);
   ret->getMergedAbbrevTable(inputChunks);
   ret->getMergedSymbols(inputChunks);
   ret->computeUniqueHashes(inputChunks);
+  // inputChunks are needed any more. Reset now to save memory.
   inputChunksPtr.reset();
   ret->generateBuckets();
   ret->calculateEntriesSizeAndOffsets();
@@ -5035,7 +5041,7 @@ template <class ELFT> void elf::createSyntheticSections() {
     add(*make<GnuPropertySection>());
 
   if (config->debugNames)
-    add(*DebugNamesSection::create<ELFT>());
+    add(*DebugNamesSection<ELFT>::create());
   if (config->gdbIndex) {
     in.gdbIndex = GdbIndexSection::create<ELFT>();
     add(*in.gdbIndex);
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index e0b01831edaa77..24ffdb3db4946b 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -793,7 +793,7 @@ class RelroPaddingSection final : public SyntheticSection {
   void writeTo(uint8_t *buf) override {}
 };
 
-class DebugNamesSection final : public SyntheticSection {
+template <class ELFT> class DebugNamesSection final : public SyntheticSection {
   // N.B. Everything in this class assumes that we are using DWARF32.
   // If we move to DWARF64, most of this data will need to be re-sized,
   // and the code that handles or manipulates it will need to be updated
@@ -801,29 +801,18 @@ class DebugNamesSection final : public SyntheticSection {
 
 public:
   DebugNamesSection();
-  template <typename ELFT> static DebugNamesSection *create();
+  static DebugNamesSection *create();
   void writeTo(uint8_t *buf) override;
   size_t getSize() const override { return sectionSize; }
   bool isNeeded() const override;
 
-  void addSections(SmallVector<InputSectionBase *, 0> sec_list) {
-    inputDebugNamesSections = sec_list;
-  }
-
-  template <class ELFT> void writeToImpl(uint8_t *buf);
-
-  template <class ELFT, class RelTy>
+  template <class RelTy>
   void getNameRelocsImpl(InputSection *sec, ArrayRef<RelTy> rels,
                          llvm::DenseMap<uint32_t, uint32_t> &relocs);
 
-  template <class ELFT>
   void getNameRelocs(InputSectionBase *base,
                      llvm::DenseMap<uint32_t, uint32_t> &relocs);
 
-  template <class ELFT>
-  void endianWrite(uint8_t size, uint8_t *buf_start, uint32_t offset,
-                   uint32_t data);
-
   struct Abbrev : public llvm::FoldingSetNode {
     uint32_t code;
     uint32_t tag;
diff --git a/lld/test/ELF/Inputs/debug-names-2.s b/lld/test/ELF/Inputs/debug-names-2.s
index 586788653dcc72..83ddbd2050d40b 100644
--- a/lld/test/ELF/Inputs/debug-names-2.s
+++ b/lld/test/ELF/Inputs/debug-names-2.s
@@ -1,11 +1,10 @@
 #-- input file: debug-names-2.cpp
 ## Generated with:
-##
 ## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
 ##     -S debug-names-2.cpp -o debug-names-2.s
-##
+
 ## debug-names-2.cpp contents:
-##
+
 ## struct t1 { };
 ## int main() {
 ##   t1 v1;
@@ -46,46 +45,6 @@ main:                                   # @main
 	.byte	1                               # DWARF Unit Type
 	.byte	8                               # Address Size (in bytes)
 	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-	.byte	1                               # Abbrev [1] 0xc:0x3d DW_TAG_compile_unit
-	.byte	0                               # DW_AT_producer
-	.short	33                              # DW_AT_language
-	.byte	1                               # DW_AT_name
-	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
-	.long	.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
-	.long	.Laddr_table_base0              # DW_AT_addr_base
-	.byte	2                               # Abbrev [2] 0x23:0x1b DW_TAG_subprogram
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	3                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-	.long	62                              # DW_AT_type
-                                        # DW_AT_external
-	.byte	3                               # Abbrev [3] 0x32:0xb DW_TAG_variable
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	127
-	.byte	5                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	3                               # DW_AT_decl_line
-	.long	66                              # DW_AT_type
-	.byte	0                               # End Of Children Mark
-	.byte	4                               # Abbrev [4] 0x3e:0x4 DW_TAG_base_type
-	.byte	4                               # DW_AT_name
-	.byte	5                               # DW_AT_encoding
-	.byte	4                               # DW_AT_byte_size
-	.byte	5                               # Abbrev [5] 0x42:0x6 DW_TAG_structure_type
-	.byte	5                               # DW_AT_calling_convention
-	.byte	6                               # DW_AT_name
-	.byte	1                               # DW_AT_byte_size
-	.byte	0                               # DW_AT_decl_file
-	.byte	1                               # DW_AT_decl_line
-	.byte	0                               # End Of Children Mark
 .Ldebug_info_end0:
 	.section	.debug_str_offsets,"", at progbits
 	.long	32                              # Length of String Offsets Set
diff --git a/lld/test/ELF/Inputs/debug-names-parent-idx-2.s b/lld/test/ELF/Inputs/debug-names-parent-idx-2.s
index 7eedaaee549450..ebd93c01d85189 100644
--- a/lld/test/ELF/Inputs/debug-names-parent-idx-2.s
+++ b/lld/test/ELF/Inputs/debug-names-parent-idx-2.s
@@ -1,25 +1,25 @@
 #-- input file: debug-names-parent-idx-2.cpp
 ## Generated with:
-##
+
 ## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
 ##     -S debug-names-parent-idx-2.cpp -o debug-names-parent-idx-2.s
-##
+
 ## foo.h contents:
-##
+
 ## int foo();
-##
+
 ## struct foo {
 ##   int x;
 ##   char y;
 ##   struct foo *foo_ptr;
 ## };
-##
+
 ## namespace parent_test {
 ##   int foo();
 ## }
-##
+
 ## debug-names-parent-index-2.cpp contents:
-##
+
 ## #include "foo.h"
 ## int foo () {
 ##   struct foo struct2;
@@ -28,13 +28,13 @@
 ##   struct2.foo_ptr = nullptr;
 ##   return struct2.x * (int) struct2.y;
 ## }
-##
+
 ## namespace parent_test {
 ## int foo () {
 ##   return 25;
 ## }
 ## }
-##
+
 	.text
 	.globl	_Z3foov                         # -- Begin function _Z3foov
 	.p2align	4, 0x90
@@ -97,86 +97,6 @@ _ZN11parent_test3fooEv:                 # @_ZN11parent_test3fooEv
 	.byte	1                               # DWARF Unit Type
 	.byte	8                               # Address Size (in bytes)
 	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-	.byte	1                               # Abbrev [1] 0xc:0x76 DW_TAG_compile_unit
-	.byte	0                               # DW_AT_producer
-	.short	33                              # DW_AT_language
-	.byte	1                               # DW_AT_name
-	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
-	.long	.Lline_table_start0             # DW_AT_stmt_list
-	.byte	2                               # DW_AT_comp_dir
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end1-.Lfunc_begin0       # DW_AT_high_pc
-	.long	.Laddr_table_base0              # DW_AT_addr_base
-	.byte	2                               # Abbrev [2] 0x23:0x4 DW_TAG_base_type
-	.byte	3                               # DW_AT_name
-	.byte	5                               # DW_AT_encoding
-	.byte	4                               # DW_AT_byte_size
-	.byte	3                               # Abbrev [3] 0x27:0x1c DW_TAG_subprogram
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	5                               # DW_AT_linkage_name
-	.byte	6                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	4                               # DW_AT_decl_line
-	.long	35                              # DW_AT_type
-                                        # DW_AT_external
-	.byte	4                               # Abbrev [4] 0x37:0xb DW_TAG_variable
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	112
-	.byte	8                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	5                               # DW_AT_decl_line
-	.long	86                              # DW_AT_type
-	.byte	0                               # End Of Children Mark
-	.byte	5                               # Abbrev [5] 0x43:0x13 DW_TAG_namespace
-	.byte	4                               # DW_AT_name
-	.byte	6                               # Abbrev [6] 0x45:0x10 DW_TAG_subprogram
-	.byte	1                               # DW_AT_low_pc
-	.long	.Lfunc_end1-.Lfunc_begin1       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	7                               # DW_AT_linkage_name
-	.byte	6                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	16                              # DW_AT_decl_line
-	.long	35                              # DW_AT_type
-                                        # DW_AT_external
-	.byte	0                               # End Of Children Mark
-	.byte	7                               # Abbrev [7] 0x56:0x22 DW_TAG_structure_type
-	.byte	5                               # DW_AT_calling_convention
-	.byte	6                               # DW_AT_name
-	.byte	16                              # DW_AT_byte_size
-	.byte	1                               # DW_AT_decl_file
-	.byte	4                               # DW_AT_decl_line
-	.byte	8                               # Abbrev [8] 0x5c:0x9 DW_TAG_member
-	.byte	9                               # DW_AT_name
-	.long	35                              # DW_AT_type
-	.byte	1                               # DW_AT_decl_file
-	.byte	5                               # DW_AT_decl_line
-	.byte	0                               # DW_AT_data_member_location
-	.byte	8                               # Abbrev [8] 0x65:0x9 DW_TAG_member
-	.byte	10                              # DW_AT_name
-	.long	120                             # DW_AT_type
-	.byte	1                               # DW_AT_decl_file
-	.byte	6                               # DW_AT_decl_line
-	.byte	4                               # DW_AT_data_member_location
-	.byte	8                               # Abbrev [8] 0x6e:0x9 DW_TAG_member
-	.byte	12                              # DW_AT_name
-	.long	124                             # DW_AT_type
-	.byte	1                               # DW_AT_decl_file
-	.byte	7                               # DW_AT_decl_line
-	.byte	8                               # DW_AT_data_member_location
-	.byte	0                               # End Of Children Mark
-	.byte	2                               # Abbrev [2] 0x78:0x4 DW_TAG_base_type
-	.byte	11                              # DW_AT_name
-	.byte	6                               # DW_AT_encoding
-	.byte	1                               # DW_AT_byte_size
-	.byte	9                               # Abbrev [9] 0x7c:0x5 DW_TAG_pointer_type
-	.long	86                              # DW_AT_type
-	.byte	0                               # End Of Children Mark
 .Ldebug_info_end0:
 	.section	.debug_str_offsets,"", at progbits
 	.long	56                              # Length of String Offsets Set
diff --git a/lld/test/ELF/debug-names-bad-aug-string.s b/lld/test/ELF/debug-names-bad-aug-string.s
index ec1651362497e6..0c4f625fad7c18 100644
--- a/lld/test/ELF/debug-names-bad-aug-string.s
+++ b/lld/test/ELF/debug-names-bad-aug-string.s
@@ -1,31 +1,30 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
-# RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+// This file was generated by copying debug-names.s and manually
+// editing the 'Header: augmentation string' in the .debug_names section.
 
-# RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
+// RUN: ld.lld --debug-names %t1.o %t2.o -o %t
 
-# DWARF:      .debug_names contents:
-# DWARF:      Name Index @ 0x0 {
-# DWARF-NEXT:   Header {
-# DWARF-NEXT:     Length: 0xCC
-# DWARF-NEXT:     Format: DWARF32
-# DWARF-NEXT:     Version: 5
-# DWARF-NEXT:     CU count: 2
-# DWARF-NEXT:     Local TU count: 0
-# DWARF-NEXT:     Foreign TU count: 0
-# DWARF-NEXT:     Bucket count: 5
-# DWARF-NEXT:     Name count: 5
-# DWARF-NEXT:     Abbreviations table size: 0x1F
-# DWARF-NEXT:     Augmentation: '        '
-# DWARF:        Compilation Unit offsets [
-# DWARF-NEXT:     CU[0]: 0x00000000
-# DWARF-NEXT:     CU[1]: 0x00000041
+// RUN: llvm-dwarfdump -debug-names %t \
+// RUN:   | FileCheck -DFILE=%t1.o -DFILE=%t2.o %s --check-prefix=DWARF
 
-##
-## This file was generated by copying debug-names.s and manually
-## editing the 'Header: augmentation string' in the .debug_names section.
-##
+// DWARF:      .debug_names contents:
+// DWARF:      Name Index @ 0x0 {
+// DWARF-NEXT:   Header {
+// DWARF-NEXT:     Length: 0xCC
+// DWARF-NEXT:     Format: DWARF32
+// DWARF-NEXT:     Version: 5
+// DWARF-NEXT:     CU count: 2
+// DWARF-NEXT:     Local TU count: 0
+// DWARF-NEXT:     Foreign TU count: 0
+// DWARF-NEXT:     Bucket count: 5
+// DWARF-NEXT:     Name count: 5
+// DWARF-NEXT:     Abbreviations table size: 0x1F
+// DWARF-NEXT:     Augmentation: '        '
+// DWARF:        Compilation Unit offsets [
+// DWARF-NEXT:     CU[0]: 0x00000000
+// DWARF-NEXT:     CU[1]: 0x0000000c
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -60,41 +59,6 @@ _Z2f12t1:                               # @_Z2f12t1
 	.byte	1                               # DWARF Unit Type
 	.byte	8                               # Address Size (in bytes)
 	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
-	.byte	0                               # DW_AT_producer
-	.short	33                              # DW_AT_language
-	.byte	1                               # DW_AT_name
-	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
-	.long	.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
-	.long	.Laddr_table_base0              # DW_AT_addr_base
-	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	3                               # DW_AT_linkage_name
-	.byte	4                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-                                        # DW_AT_external
-	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	127
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-	.long	58                              # DW_AT_type
-	.byte	0                               # End Of Children Mark
-	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
-	.byte	5                               # DW_AT_calling_convention
-	.byte	5                               # DW_AT_name
-	.byte	1                               # DW_AT_byte_size
-	.byte	0                               # DW_AT_decl_file
-	.byte	1                               # DW_AT_decl_line
-	.byte	0                               # End Of Children Mark
 .Ldebug_info_end0:
 	.section	.debug_str_offsets,"", at progbits
 	.long	28                              # Length of String Offsets Set
diff --git a/lld/test/ELF/debug-names-bad-die-idx-sizes.s b/lld/test/ELF/debug-names-bad-die-idx-sizes.s
index 2da278a8dd5b7c..e73d013f3b0edb 100644
--- a/lld/test/ELF/debug-names-bad-die-idx-sizes.s
+++ b/lld/test/ELF/debug-names-bad-die-idx-sizes.s
@@ -1,20 +1,20 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+// This file was generated by first compiling main.cpp: 
+// clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+//      main.cpp
+// Then manually edit the .debug_names section. In the entries, change the
+// size of the DW_IDX_die_offset from '.long' to '.byte'.
+
+// Contents of main.cpp:
+// int main (int argc, char **argv) { }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+
+// RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+// RUN:   | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
 
-## This file was generated by first compiling main.cpp: 
-## clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-##      main.cpp
-##
-## Then manually edit the .debug_names section. In the entries, change the
-## size of the DW_IDX_die_offset from '.long' to '.byte'.
-##
-## main.cpp:
-## int main (int argc, char **argv) { }
-##
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-bad-name-count.s b/lld/test/ELF/debug-names-bad-name-count.s
index 4acfa182b11a91..cda4484b0e4c67 100644
--- a/lld/test/ELF/debug-names-bad-name-count.s
+++ b/lld/test/ELF/debug-names-bad-name-count.s
@@ -1,23 +1,24 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+	
+// RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+// RUN:   FileCheck -DFILE=%t1.o %s
+	
+// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+
+// This file was generated by first compiling main.cpp: 
+// clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+//      main.cpp
+
+// Then manually edit .debug_names section: change value for
+// 'Header: name count' from 3 to 4.
+
+// Contents of main.cpp:
+// int main (int argc, char **argv) { }
 
-## This file was generated by first compiling main.cpp: 
-## clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-##      main.cpp
-##
-## Then manually edit .debug_names section: change value for
-## 'Header: name count' from 3 to 4.
-##
-## main.cpp:
-## int main (int argc, char **argv) { }
-##
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-bad-offsets-sizes.s b/lld/test/ELF/debug-names-bad-offsets-sizes.s
index e11d19a9bf579c..3e7f36b2e2175e 100644
--- a/lld/test/ELF/debug-names-bad-offsets-sizes.s
+++ b/lld/test/ELF/debug-names-bad-offsets-sizes.s
@@ -1,22 +1,23 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-# CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+// This file was generated by first compiling main.cpp: 
+// clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+//      main.cpp
+
+// Then manually edit .debug_names section. Change the sizes of
+// 'Offset in Bucket' values from '.long' to '.byte'.
+
+// Contentsof main.cpp:
+// int main (int argc, char **argv) { }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+
+// RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+// RUN:   | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
 
-## This file was generated by first compiling main.cpp: 
-## clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-##      main.cpp
-##
-## Then manually edit .debug_names section. Change the sizes of
-## 'Offset in Bucket' values from '.long' to '.byte'.
-##
-## main.cpp:
-## int main (int argc, char **argv) { }
-##
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-bad-version.s b/lld/test/ELF/debug-names-bad-version.s
index bf1855151c20da..6a299805ca090f 100644
--- a/lld/test/ELF/debug-names-bad-version.s
+++ b/lld/test/ELF/debug-names-bad-version.s
@@ -1,15 +1,14 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
-#
-# RUN: not ld.lld --debug-names %t1.o %t2.o -o /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}:(.debug_names): unsupported version
-##
-## This file was generated by copying debug-names.s and manually
-## editing the 'Header: version' in the .debug_names section (changed it from
-## 5 to 4).
+// This file was generated by copying debug-names.s and manually
+// editing the 'Header: version' in the .debug_names section (changed it from
+// 5 to 4).
 	
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
+// RUN: not ld.lld --debug-names %t1.o %t2.o -o /dev/null 2>&1 | FileCheck %s
+
+// CHECK: error: {{.*}}:(.debug_names): unsupported version
+
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-dwarf64.s b/lld/test/ELF/debug-names-dwarf64.s
index 4391142c5558c2..790f2ddeba3972 100644
--- a/lld/test/ELF/debug-names-dwarf64.s
+++ b/lld/test/ELF/debug-names-dwarf64.s
@@ -1,17 +1,17 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}(.debug_names): unsupported DWARF64
-##
-## This file was generated by:
-## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-##    -gdwarf64 -gpubnames main.cpp
-##
-## main.cpp
-## int main (int argc, char **argv) { }
-##
+// This file was generated by:
+// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+//    -gdwarf64 -gpubnames main.cpp
+
+// Contents of main.cpp
+// int main (int argc, char **argv) { }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
+// RUN:   | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: {{.*}}(.debug_names): unsupported DWARF64
+
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-invalid-abbrev-code.s b/lld/test/ELF/debug-names-invalid-abbrev-code.s
index 14970e0d10433c..54c0105ae56b5e 100644
--- a/lld/test/ELF/debug-names-invalid-abbrev-code.s
+++ b/lld/test/ELF/debug-names-invalid-abbrev-code.s
@@ -1,20 +1,20 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}(.debug_names): invalid abbrev code in entry
-# CHECK: error: {{.*}}(.debug_names): invalid abbrev code in entry
-##
-## This file was generated by:
-## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-##    -gpubnames main.cpp
-##
-## Then manually changing an abbrev code.
-## 
-## main.cpp
-## int main (int argc, char **argv) { }
-##
+// This file was generated by:
+// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+//    -gpubnames main.cpp
+
+// Then manually changing an abbrev code.
+
+// Contents of main.cpp
+// int main (int argc, char **argv) { }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
+// RUN:    | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: {{.*}}(.debug_names): invalid abbrev code in entry
+// CHECK: error: {{.*}}(.debug_names): invalid abbrev code in entry
+
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-invalid-attribute-2.s b/lld/test/ELF/debug-names-invalid-attribute-2.s
index 44e74911bd0353..16706f0054c312 100644
--- a/lld/test/ELF/debug-names-invalid-attribute-2.s
+++ b/lld/test/ELF/debug-names-invalid-attribute-2.s
@@ -1,20 +1,20 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}(.debug_names): error while reading attributes: unexpected end of data at offset 0x80 while reading [0x7e, 0x82)
-##
-## This file was generated by:
-## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-##    -gpubnames main.cpp
-##
-## Then manually editing .debug_names section, commenting out a
-## DW_IDX_die_offset in an entry.
-## 
-## main.cpp
-## int main (int argc, char **argv) { }
-##
+// This file was generated by:
+// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+//    -gpubnames main.cpp
+
+// Then manually editing .debug_names section, commenting out a
+// DW_IDX_die_offset in an entry.
+
+// Contents of main.cpp
+// int main (int argc, char **argv) { }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
+// RUN:    | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: {{.*}}(.debug_names): error while reading attributes: unexpected end of data at offset 0x80 while reading [0x7e, 0x82)
+
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-invalid-attribute-3.s b/lld/test/ELF/debug-names-invalid-attribute-3.s
index 1e6ea8074975f5..9b99cbe87d5a0e 100644
--- a/lld/test/ELF/debug-names-invalid-attribute-3.s
+++ b/lld/test/ELF/debug-names-invalid-attribute-3.s
@@ -1,23 +1,22 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}(.debug_names): invalid form for attribute
-##
-## This file was generated by:
-## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-##    -gpubnames main.cpp
-##
-## 
-## Then manually changing the first .debug_names abbrev, so that the
-## DW_IDX_die_offset uses DW_FORM_flag_present (invalid) & the DW_IDX_parent
-## uses DW_FORM_ref4. Also updated the sizes of the values in the entry
-## that uses the abbrev, to match the sizes of the forms.
-## 
-## main.cpp
-## int main (int argc, char **argv) { }
-##
+// This file was generated by:
+// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+//    -gpubnames main.cpp
+
+// Then manually changing the first .debug_names abbrev, so that the
+// DW_IDX_die_offset uses DW_FORM_flag_present (invalid) & the DW_IDX_parent
+// uses DW_FORM_ref4. Also updated the sizes of the values in the entry
+// that uses the abbrev, to match the sizes of the forms.
+
+// Contents of main.cpp
+// int main (int argc, char **argv) { }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
+// RUN:   | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: {{.*}}(.debug_names): invalid form for attribute
+
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-invalid-attribute.s b/lld/test/ELF/debug-names-invalid-attribute.s
index 9b1a915d81f882..303337c0295da7 100644
--- a/lld/test/ELF/debug-names-invalid-attribute.s
+++ b/lld/test/ELF/debug-names-invalid-attribute.s
@@ -1,13 +1,13 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o  -o /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}:(.debug_names): unrecognized form encoding 16 in .debug_names abbrev table
-##
-## Generated by copying debug-names.s and manually editing it to make some
-## of the abbrev attributes invalid.
+// Generated by copying debug-names.s and manually editing it to make some
+// of the abbrev attributes invalid.
 	
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: not ld.lld --debug-names %t1.o  -o /dev/null 2>&1 \
+// RUN:    | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: {{.*}}:(.debug_names): unrecognized form encoding 16 in .debug_names abbrev table
+
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -42,41 +42,6 @@ _Z2f12t1:                               # @_Z2f12t1
 	.byte	1                               # DWARF Unit Type
 	.byte	8                               # Address Size (in bytes)
 	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
-	.byte	0                               # DW_AT_producer
-	.short	33                              # DW_AT_language
-	.byte	1                               # DW_AT_name
-	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
-	.long	.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
-	.long	.Laddr_table_base0              # DW_AT_addr_base
-	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	3                               # DW_AT_linkage_name
-	.byte	4                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-                                        # DW_AT_external
-	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	127
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-	.long	58                              # DW_AT_type
-	.byte	0                               # End Of Children Mark
-	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
-	.byte	5                               # DW_AT_calling_convention
-	.byte	5                               # DW_AT_name
-	.byte	1                               # DW_AT_byte_size
-	.byte	0                               # DW_AT_decl_file
-	.byte	1                               # DW_AT_decl_line
-	.byte	0                               # End Of Children Mark
 .Ldebug_info_end0:
 	.section	.debug_str_offsets,"", at progbits
 	.long	28                              # Length of String Offsets Set
diff --git a/lld/test/ELF/debug-names-invalid-flags.s b/lld/test/ELF/debug-names-invalid-flags.s
new file mode 100644
index 00000000000000..96cd4da243b688
--- /dev/null
+++ b/lld/test/ELF/debug-names-invalid-flags.s
@@ -0,0 +1,148 @@
+// This file was generated by:
+// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+//    -gpubnames main.cpp
+
+// Contents of main.cpp
+// int main (int argc, char **argv) { }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: not ld.lld --debug-names -r %t1.o  -o  /dev/null 2>&1 \
+// RUN:   | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: -r and --debug-names may not be used together
+
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+.Linfo_string1:
+	.asciz	"main.cpp"                      # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=113
+.Linfo_string3:
+	.asciz	"main"                          # string offset=130
+.Linfo_string4:
+	.asciz	"int"                           # string offset=135
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=139
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=144
+.Linfo_string7:
+	.asciz	"char"                          # string offset=149
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	87                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-invalid-parent-idx.s b/lld/test/ELF/debug-names-invalid-parent-idx.s
index be5df8b155250e..698183880445a6 100644
--- a/lld/test/ELF/debug-names-invalid-parent-idx.s
+++ b/lld/test/ELF/debug-names-invalid-parent-idx.s
@@ -1,22 +1,22 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-#
-# RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 | FileCheck %s
-#
-# CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
-# CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
-# CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
-##
-## This file was generated by:
-## clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-##    -gpubnames main.cpp
-##
-## Then manually editing .debug_names section, changing the form for a 
-## DW_IDX_parent from DW_FORM_flag_present to DW_FORM_ref1 (invalid).
-## 
-## main.cpp
-## int main (int argc, char **argv) { }
-##
+// This file was generated by:
+// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+//    -gpubnames main.cpp
+
+// Then manually editing .debug_names section, changing the form for a 
+// DW_IDX_parent from DW_FORM_flag_present to DW_FORM_ref1 (invalid).
+
+// Contents of main.cpp
+// int main (int argc, char **argv) { }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
+// RUN:    | FileCheck -DFILE=%t1.o %s
+
+// CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
+// CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
+// CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
+
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-parent-idx.s b/lld/test/ELF/debug-names-parent-idx.s
index a4e8682cd9ee58..cda9203fd21670 100644
--- a/lld/test/ELF/debug-names-parent-idx.s
+++ b/lld/test/ELF/debug-names-parent-idx.s
@@ -1,188 +1,188 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-parent-idx-2.s -o %t2.o
-# RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+// Generated with:
 
-# RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
+// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
+//     -S debug-names-parent-idx.cpp -o debug-names-parent-idx.s
+
+// foo.h contents:
+
+// int foo();
+
+// struct foo {
+//   int x;
+//   char y;
+//   struct foo *foo_ptr;
+// };
+
+// namespace parent_test {
+//   int foo();
+// }
+
+//  debug-names-parent-idx.cpp contents:
+
+// #include "foo.h"
+// void bar (struct foo &foo, int junk) {
+//   foo.x = foo.x * junk;
+// }
+// int main (int argc, char** argv) {
+//   struct foo my_struct;
+//   my_struct.x = 10;
+//   my_struct.y = 'q';
+//   my_struct.foo_ptr = nullptr;
+//   int junk = foo();
+//   bar(my_struct, junk);
+//   int junk2 = parent_test::foo();
+//   return 0;
+// }
+
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-parent-idx-2.s -o %t2.o
+// RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+
+// RUN: llvm-dwarfdump -debug-names %t \
+// RUN:    | FileCheck -DFILE=%t1.o -DFILE=%t2.o %s --check-prefix=DWARF
+
+// DWARF:      .debug_names contents:
+// DWARF:      Name Index @ 0x0 {
+// DWARF-NEXT:   Header {
+// DWARF-NEXT:     Length: 0x15C
+// DWARF-NEXT:     Format: DWARF32
+// DWARF-NEXT:     Version: 5
+// DWARF-NEXT:     CU count: 2
+// DWARF-NEXT:     Local TU count: 0
+// DWARF-NEXT:     Foreign TU count: 0
+// DWARF-NEXT:     Bucket count: 9
+// DWARF-NEXT:     Name count: 9
+// DWARF-NEXT:     Abbreviations table size: 0x33
+// DWARF-NEXT:     Augmentation: 'LLVM0700'
+// DWARF:        Compilation Unit offsets [
+// DWARF-NEXT:     CU[0]: 0x00000000
+// DWARF-NEXT:     CU[1]: 0x0000000c
+// DWARF:        Abbreviations [
+// DWARF-NEXT:     Abbreviation 0x1 {
+// DWARF-NEXT:       Tag: DW_TAG_base_type
+// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+// DWARF:          Abbreviation 0x2 {
+// DWARF-NEXT:       Tag: DW_TAG_subprogram
+// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+// DWARF:          Abbreviation 0x3 {
+// DWARF-NEXT:       Tag: DW_TAG_structure_type
+// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+// DWARF:          Abbreviation 0x4 {
+// DWARF-NEXT:       Tag: DW_TAG_subprogram
+// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_parent: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+// DWARF:          Abbreviation 0x5 {
+// DWARF-NEXT:       Tag: DW_TAG_namespace
+// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+// DWARF:            String: 0x00000093 "bar"
+// DWARF-NEXT:       Entry @ 0xf7 {
+// DWARF-NEXT:         Abbrev: 0x2
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF:            String: 0x000000a9 "int"
+// DWARF-NEXT:       Entry @ 0xfe {
+// DWARF-NEXT:         Abbrev: 0x1
+// DWARF-NEXT:         Tag: DW_TAG_base_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x0000008d
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF-NEXT:       }
+// DWARF-NEXT:       Entry @ 0x104 {
+// DWARF-NEXT:         Abbrev: 0x1
+// DWARF-NEXT:         Tag: DW_TAG_base_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF:            String: 0x000000ad "foo"
+// DWARF-NEXT:       Entry @ 0x10b {
+// DWARF-NEXT:         Abbrev: 0x3
+// DWARF-NEXT:         Tag: DW_TAG_structure_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000096
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF-NEXT:       }
+// DWARF-NEXT:       Entry @ 0x111 {
+// DWARF-NEXT:         Abbrev: 0x2
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF-NEXT:       }
+// DWARF-NEXT:       Entry @ 0x117 {
+// DWARF-NEXT:         Abbrev: 0x4
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
+// DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF-NEXT:       }
+// DWARF-NEXT:       Entry @ 0x121 {
+// DWARF-NEXT:         Abbrev: 0x3
+// DWARF-NEXT:         Tag: DW_TAG_structure_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000056
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF:            String: 0x00000196 "parent_test"
+// DWARF-NEXT:       Entry @ 0x128 {
+// DWARF-NEXT:         Abbrev: 0x5
+// DWARF-NEXT:         Tag: DW_TAG_namespace
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000043
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF:            String: 0x00000097 "_Z3barR3fooi"
+// DWARF-NEXT:       Entry @ 0x12f {
+// DWARF-NEXT:         Abbrev: 0x2
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF:            String: 0x000000a4 "main"
+// DWARF-NEXT:       Entry @ 0x136 {
+// DWARF-NEXT:         Abbrev: 0x2
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000046
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF:            String: 0x000000b5 "char"
+// DWARF-NEXT:       Entry @ 0x13d {
+// DWARF-NEXT:         Abbrev: 0x1
+// DWARF-NEXT:         Tag: DW_TAG_base_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x000000b8
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF-NEXT:       }
+// DWARF-NEXT:       Entry @ 0x143 {
+// DWARF-NEXT:         Abbrev: 0x1
+// DWARF-NEXT:         Tag: DW_TAG_base_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000078
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF:            String: 0x000001a2 "_ZN11parent_test3fooEv"
+// DWARF-NEXT:       Entry @ 0x14a {
+// DWARF-NEXT:         Abbrev: 0x4
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
+// DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF:            String: 0x0000018e "_Z3foov"
+// DWARF-NEXT:       Entry @ 0x155 {
+// DWARF-NEXT:         Abbrev: 0x2
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
 
-# DWARF:      .debug_names contents:
-# DWARF:      Name Index @ 0x0 {
-# DWARF-NEXT:   Header {
-# DWARF-NEXT:     Length: 0x15C
-# DWARF-NEXT:     Format: DWARF32
-# DWARF-NEXT:     Version: 5
-# DWARF-NEXT:     CU count: 2
-# DWARF-NEXT:     Local TU count: 0
-# DWARF-NEXT:     Foreign TU count: 0
-# DWARF-NEXT:     Bucket count: 9
-# DWARF-NEXT:     Name count: 9
-# DWARF-NEXT:     Abbreviations table size: 0x33
-# DWARF-NEXT:     Augmentation: 'LLVM0700'
-# DWARF:        Compilation Unit offsets [
-# DWARF-NEXT:     CU[0]: 0x00000000
-# DWARF-NEXT:     CU[1]: 0x000000cc
-# DWARF:        Abbreviations [
-# DWARF-NEXT:     Abbreviation 0x1 {
-# DWARF-NEXT:       Tag: DW_TAG_base_type
-# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-# DWARF:          Abbreviation 0x2 {
-# DWARF-NEXT:       Tag: DW_TAG_subprogram
-# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-# DWARF:          Abbreviation 0x3 {
-# DWARF-NEXT:       Tag: DW_TAG_structure_type
-# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-# DWARF:          Abbreviation 0x4 {
-# DWARF-NEXT:       Tag: DW_TAG_subprogram
-# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_parent: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-# DWARF:          Abbreviation 0x5 {
-# DWARF-NEXT:       Tag: DW_TAG_namespace
-# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-# DWARF:            String: 0x00000093 "bar"
-# DWARF-NEXT:       Entry @ 0xf7 {
-# DWARF-NEXT:         Abbrev: 0x2
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF:            String: 0x000000a9 "int"
-# DWARF-NEXT:       Entry @ 0xfe {
-# DWARF-NEXT:         Abbrev: 0x1
-# DWARF-NEXT:         Tag: DW_TAG_base_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x0000008d
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF-NEXT:       }
-# DWARF-NEXT:       Entry @ 0x104 {
-# DWARF-NEXT:         Abbrev: 0x1
-# DWARF-NEXT:         Tag: DW_TAG_base_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF:            String: 0x000000ad "foo"
-# DWARF-NEXT:       Entry @ 0x10b {
-# DWARF-NEXT:         Abbrev: 0x3
-# DWARF-NEXT:         Tag: DW_TAG_structure_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000096
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF-NEXT:       }
-# DWARF-NEXT:       Entry @ 0x111 {
-# DWARF-NEXT:         Abbrev: 0x2
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF-NEXT:       }
-# DWARF-NEXT:       Entry @ 0x117 {
-# DWARF-NEXT:         Abbrev: 0x4
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
-# DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF-NEXT:       }
-# DWARF-NEXT:       Entry @ 0x121 {
-# DWARF-NEXT:         Abbrev: 0x3
-# DWARF-NEXT:         Tag: DW_TAG_structure_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000056
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF:            String: 0x00000196 "parent_test"
-# DWARF-NEXT:       Entry @ 0x128 {
-# DWARF-NEXT:         Abbrev: 0x5
-# DWARF-NEXT:         Tag: DW_TAG_namespace
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000043
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF:            String: 0x00000097 "_Z3barR3fooi"
-# DWARF-NEXT:       Entry @ 0x12f {
-# DWARF-NEXT:         Abbrev: 0x2
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF:            String: 0x000000a4 "main"
-# DWARF-NEXT:       Entry @ 0x136 {
-# DWARF-NEXT:         Abbrev: 0x2
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000046
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF:            String: 0x000000b5 "char"
-# DWARF-NEXT:       Entry @ 0x13d {
-# DWARF-NEXT:         Abbrev: 0x1
-# DWARF-NEXT:         Tag: DW_TAG_base_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x000000b8
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF-NEXT:       }
-# DWARF-NEXT:       Entry @ 0x143 {
-# DWARF-NEXT:         Abbrev: 0x1
-# DWARF-NEXT:         Tag: DW_TAG_base_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000078
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF:            String: 0x000001a2 "_ZN11parent_test3fooEv"
-# DWARF-NEXT:       Entry @ 0x14a {
-# DWARF-NEXT:         Abbrev: 0x4
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
-# DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF:            String: 0x0000018e "_Z3foov"
-# DWARF-NEXT:       Entry @ 0x155 {
-# DWARF-NEXT:         Abbrev: 0x2
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-	
-#-- input file: debug-names-parent-idx.cpp
-## Generated with:
-##
-## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
-##     -S debug-names-parent-idx.cpp -o debug-names-parent-idx.s
-##
-## foo.h contents:
-##
-## int foo();
-##
-## struct foo {
-##   int x;
-##   char y;
-##   struct foo *foo_ptr;
-## };
-##
-## namespace parent_test {
-##   int foo();
-## }
-##
-##  debug-names-parent-idx.cpp contents:
-##
-## #include "foo.h"
-## void bar (struct foo &foo, int junk) {
-##   foo.x = foo.x * junk;
-## }
-## int main (int argc, char** argv) {
-##   struct foo my_struct;
-##   my_struct.x = 10;
-##   my_struct.y = 'q';
-##   my_struct.foo_ptr = nullptr;
-##   int junk = foo();
-##   bar(my_struct, junk);
-##   int junk2 = parent_test::foo();
-##   return 0;
-## }
-##
 	.text
 	.globl	_Z3barR3fooi                    # -- Begin function _Z3barR3fooi
 	.p2align	4, 0x90
@@ -261,136 +261,6 @@ main:                                   # @main
 	.byte	1                               # DWARF Unit Type
 	.byte	8                               # Address Size (in bytes)
 	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-	.byte	1                               # Abbrev [1] 0xc:0xc0 DW_TAG_compile_unit
-	.byte	0                               # DW_AT_producer
-	.short	33                              # DW_AT_language
-	.byte	1                               # DW_AT_name
-	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
-	.long	.Lline_table_start0             # DW_AT_stmt_list
-	.byte	2                               # DW_AT_comp_dir
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end1-.Lfunc_begin0       # DW_AT_high_pc
-	.long	.Laddr_table_base0              # DW_AT_addr_base
-	.byte	2                               # Abbrev [2] 0x23:0x23 DW_TAG_subprogram
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	3                               # DW_AT_linkage_name
-	.byte	4                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	3                               # DW_AT_decl_line
-                                        # DW_AT_external
-	.byte	3                               # Abbrev [3] 0x2f:0xb DW_TAG_formal_parameter
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	120
-	.byte	7                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	3                               # DW_AT_decl_line
-	.long	145                             # DW_AT_type
-	.byte	3                               # Abbrev [3] 0x3a:0xb DW_TAG_formal_parameter
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	116
-	.byte	12                              # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	3                               # DW_AT_decl_line
-	.long	141                             # DW_AT_type
-	.byte	0                               # End Of Children Mark
-	.byte	4                               # Abbrev [4] 0x46:0x47 DW_TAG_subprogram
-	.byte	1                               # DW_AT_low_pc
-	.long	.Lfunc_end1-.Lfunc_begin1       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	5                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	7                               # DW_AT_decl_line
-	.long	141                             # DW_AT_type
-                                        # DW_AT_external
-	.byte	3                               # Abbrev [3] 0x55:0xb DW_TAG_formal_parameter
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	120
-	.byte	13                              # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	7                               # DW_AT_decl_line
-	.long	141                             # DW_AT_type
-	.byte	3                               # Abbrev [3] 0x60:0xb DW_TAG_formal_parameter
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	112
-	.byte	14                              # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	7                               # DW_AT_decl_line
-	.long	193                             # DW_AT_type
-	.byte	5                               # Abbrev [5] 0x6b:0xb DW_TAG_variable
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	96
-	.byte	15                              # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	9                               # DW_AT_decl_line
-	.long	150                             # DW_AT_type
-	.byte	5                               # Abbrev [5] 0x76:0xb DW_TAG_variable
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	92
-	.byte	12                              # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	14                              # DW_AT_decl_line
-	.long	141                             # DW_AT_type
-	.byte	5                               # Abbrev [5] 0x81:0xb DW_TAG_variable
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	88
-	.byte	16                              # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	16                              # DW_AT_decl_line
-	.long	141                             # DW_AT_type
-	.byte	0                               # End Of Children Mark
-	.byte	6                               # Abbrev [6] 0x8d:0x4 DW_TAG_base_type
-	.byte	6                               # DW_AT_name
-	.byte	5                               # DW_AT_encoding
-	.byte	4                               # DW_AT_byte_size
-	.byte	7                               # Abbrev [7] 0x91:0x5 DW_TAG_reference_type
-	.long	150                             # DW_AT_type
-	.byte	8                               # Abbrev [8] 0x96:0x22 DW_TAG_structure_type
-	.byte	5                               # DW_AT_calling_convention
-	.byte	7                               # DW_AT_name
-	.byte	16                              # DW_AT_byte_size
-	.byte	1                               # DW_AT_decl_file
-	.byte	4                               # DW_AT_decl_line
-	.byte	9                               # Abbrev [9] 0x9c:0x9 DW_TAG_member
-	.byte	8                               # DW_AT_name
-	.long	141                             # DW_AT_type
-	.byte	1                               # DW_AT_decl_file
-	.byte	5                               # DW_AT_decl_line
-	.byte	0                               # DW_AT_data_member_location
-	.byte	9                               # Abbrev [9] 0xa5:0x9 DW_TAG_member
-	.byte	9                               # DW_AT_name
-	.long	184                             # DW_AT_type
-	.byte	1                               # DW_AT_decl_file
-	.byte	6                               # DW_AT_decl_line
-	.byte	4                               # DW_AT_data_member_location
-	.byte	9                               # Abbrev [9] 0xae:0x9 DW_TAG_member
-	.byte	11                              # DW_AT_name
-	.long	188                             # DW_AT_type
-	.byte	1                               # DW_AT_decl_file
-	.byte	7                               # DW_AT_decl_line
-	.byte	8                               # DW_AT_data_member_location
-	.byte	0                               # End Of Children Mark
-	.byte	6                               # Abbrev [6] 0xb8:0x4 DW_TAG_base_type
-	.byte	10                              # DW_AT_name
-	.byte	6                               # DW_AT_encoding
-	.byte	1                               # DW_AT_byte_size
-	.byte	10                              # Abbrev [10] 0xbc:0x5 DW_TAG_pointer_type
-	.long	150                             # DW_AT_type
-	.byte	10                              # Abbrev [10] 0xc1:0x5 DW_TAG_pointer_type
-	.long	198                             # DW_AT_type
-	.byte	10                              # Abbrev [10] 0xc6:0x5 DW_TAG_pointer_type
-	.long	184                             # DW_AT_type
-	.byte	0                               # End Of Children Mark
 .Ldebug_info_end0:
 	.section	.debug_str_offsets,"", at progbits
 	.long	72                              # Length of String Offsets Set
diff --git a/lld/test/ELF/debug-names.s b/lld/test/ELF/debug-names.s
index ce013303f65f67..ca6d32998542b5 100644
--- a/lld/test/ELF/debug-names.s
+++ b/lld/test/ELF/debug-names.s
@@ -1,136 +1,110 @@
-# REQUIRES: x86
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
-# RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+// Generated with:
 
-# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM
-# RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
-# RUN: llvm-readelf -SW %t | FileCheck %s --check-prefix=READELF
-	
-# DISASM:       Disassembly of section .text:
-# DISASM-EMPTY:
-# DISASM:       <_Z2f12t1>:
-# DISASM-CHECK:   201180: 55       pushq %rbp
-# DISASM-CHECK:   201181: 48 89 e5 movq  %rsp, %rbp
-# DISASM-CHECK:   201184: 5d       popq  %rbp
-# DISASM-CHECK:   201185: c3       retq
-# DISASM-CHECK:   201186: cc       int3
-# DISASM-CHECK:   201187: cc       int3
-# DISASM-CHECK:   201188: cc       int3
-# DISASM-CHECK:   201189: cc       int3
-# DISASM-CHECK:   20118a: cc       int3
-# DISASM-CHECK:   20118b: cc       int3
-# DISASM-CHECK:   20118c: cc       int3
-# DISASM-CHECK:   20118d: cc       int3
-# DISASM-CHECK:   20118e: cc       int3
-# DISASM-CHECK:   20118f: cc       int3
-# DISASM:       <main>:
-# DISASM-CHECK:   201190: 55       pushq %rbp
-# DISASM-CHECK:   201191: 48 89 e5 movq  %rsp, %rbp
-# DISASM-CHECK:   201194: 31 c0    xorl  %eax, %eax
-# DISASM-CHECK:   201196: 5d       popq  %rbp
-# DISASM-CHECK:   201197: c3       retq
+// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+//     -S debug-names.cpp -o debug-names.s
 
-# DWARF:      .debug_names contents:
-# DWARF:      Name Index @ 0x0 {
-# DWARF-NEXT:   Header {
-# DWARF-NEXT:     Length: 0xCC
-# DWARF-NEXT:     Format: DWARF32
-# DWARF-NEXT:     Version: 5
-# DWARF-NEXT:     CU count: 2
-# DWARF-NEXT:     Local TU count: 0
-# DWARF-NEXT:     Foreign TU count: 0
-# DWARF-NEXT:     Bucket count: 5
-# DWARF-NEXT:     Name count: 5
-# DWARF-NEXT:     Abbreviations table size: 0x1F
-# DWARF-NEXT:     Augmentation: 'LLVM0700'
-# DWARF:        Compilation Unit offsets [
-# DWARF-NEXT:     CU[0]: 0x00000000
-# DWARF-NEXT:     CU[1]: 0x00000041
-# DWARF:          Abbreviations [
-# DWARF-NEXT:     Abbreviation 0x1 {
-# DWARF:            Tag: DW_TAG_structure_type
-# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-# DWARF:          Abbreviation 0x2 {
-# DWARF-NEXT:       Tag: DW_TAG_subprogram
-# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-# DWARF:          Abbreviation 0x3 {
-# DWARF-NEXT:       Tag: DW_TAG_base_type
-# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-# DWARF:        Bucket 0 [
-# DWARF:        Bucket 1 [
-# DWARF:            String: 0x00000089 "f1"
-# DWARF-NEXT:       Entry @ 0xa3 {
-# DWARF-NEXT:         Abbrev: 0x2
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF:            String: 0x00000095 "t1"
-# DWARF-NEXT:       Entry @ 0xaa {
-# DWARF-NEXT:         Abbrev: 0x1
-# DWARF-NEXT:         Tag: DW_TAG_structure_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x0000003a
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF-NEXT:       }
-# DWARF-NEXT:       Entry @ 0xb0 {
-# DWARF-NEXT:         Abbrev: 0x1
-# DWARF-NEXT:         Tag: DW_TAG_structure_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000042
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF:            String: 0x00000130 "int"
-# DWARF-NEXT:       Entry @ 0xb7 {
-# DWARF-NEXT:         Abbrev: 0x3
-# DWARF-NEXT:         Tag: DW_TAG_base_type
-# DWARF-NEXT:         DW_IDX_die_offset: 0x0000003e
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-# DWARF:        Bucket 2 [
-# DWARF:        Bucket 3 [
-# DWARF:            String: 0x0000008c "_Z2f12t1"
-# DWARF-NEXT:       Entry @ 0xbe {
-# DWARF-NEXT:         Abbrev: 0x2
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-# DWARF:        Bucket 4 [
-# DWARF:            String: 0x0000012b "main"
-# DWARF-NEXT:       Entry @ 0xc5 {
-# DWARF-NEXT:         Abbrev: 0x2
-# DWARF-NEXT:         Tag: DW_TAG_subprogram
-# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// debug-names.cpp contents:
 
-# READELF: .debug_names PROGBITS 0000000000000000 0003eb 0000d0
+// struct t1 { };
+// void f1(t1) { }
 
-# RUN: ld.lld --debug-names --no-debug-names %t1.o %t2.o -o %t
-# RUN: llvm-readelf -SW %t | FileCheck %s --check-prefix=NO_DBG_NAMES
-	
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
 
-# NO_DBG_NAMES: .debug_names  PROGBITS  0000000000000000 00037c 000110
+// RUN: ld.lld --debug-names --no-debug-names %t1.o %t2.o -o %t
+// RUN: llvm-readelf -SW %t | FileCheck %s --check-prefix=NO_DBG_NAMES
 	
-#-- input file: debug-names.cpp
-## Generated with:
-##
-## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-##     -S debug-names.cpp -o debug-names.s
-##
-## debug-names.cpp contents:
-##
-## struct t1 { };
-## void f1(t1) { }
-##
-##
+// NO_DBG_NAMES: .debug_names  PROGBITS  0000000000000000 [[#%x,]] 000110
+	
+// RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+
+// RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
+// RUN: llvm-readelf -SW %t \
+// RUN:    | FileCheck -DFILE=%t1.o -DFILE=%t2.o %s --check-prefix=READELF
+
+// READELF: .debug_names PROGBITS 0000000000000000 [[#%x,]] 0000d0
+
+// DWARF:      .debug_names contents:
+// DWARF:      Name Index @ 0x0 {
+// DWARF-NEXT:   Header {
+// DWARF-NEXT:     Length: 0xCC
+// DWARF-NEXT:     Format: DWARF32
+// DWARF-NEXT:     Version: 5
+// DWARF-NEXT:     CU count: 2
+// DWARF-NEXT:     Local TU count: 0
+// DWARF-NEXT:     Foreign TU count: 0
+// DWARF-NEXT:     Bucket count: 5
+// DWARF-NEXT:     Name count: 5
+// DWARF-NEXT:     Abbreviations table size: 0x1F
+// DWARF-NEXT:     Augmentation: 'LLVM0700'
+// DWARF:        Compilation Unit offsets [
+// DWARF-NEXT:     CU[0]: 0x00000000
+// DWARF-NEXT:     CU[1]: 0x0000000c
+// DWARF:          Abbreviations [
+// DWARF-NEXT:     Abbreviation 0x1 {
+// DWARF:            Tag: DW_TAG_structure_type
+// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+// DWARF:          Abbreviation 0x2 {
+// DWARF-NEXT:       Tag: DW_TAG_subprogram
+// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+// DWARF:          Abbreviation 0x3 {
+// DWARF-NEXT:       Tag: DW_TAG_base_type
+// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+// DWARF:        Bucket 0 [
+// DWARF:        Bucket 1 [
+// DWARF:            String: 0x00000089 "f1"
+// DWARF-NEXT:       Entry @ 0xa3 {
+// DWARF-NEXT:         Abbrev: 0x2
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF:            String: 0x00000095 "t1"
+// DWARF-NEXT:       Entry @ 0xaa {
+// DWARF-NEXT:         Abbrev: 0x1
+// DWARF-NEXT:         Tag: DW_TAG_structure_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x0000003a
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF-NEXT:       }
+// DWARF-NEXT:       Entry @ 0xb0 {
+// DWARF-NEXT:         Abbrev: 0x1
+// DWARF-NEXT:         Tag: DW_TAG_structure_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000042
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF:            String: 0x00000130 "int"
+// DWARF-NEXT:       Entry @ 0xb7 {
+// DWARF-NEXT:         Abbrev: 0x3
+// DWARF-NEXT:         Tag: DW_TAG_base_type
+// DWARF-NEXT:         DW_IDX_die_offset: 0x0000003e
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+// DWARF:        Bucket 2 [
+// DWARF:        Bucket 3 [
+// DWARF:            String: 0x0000008c "_Z2f12t1"
+// DWARF-NEXT:       Entry @ 0xbe {
+// DWARF-NEXT:         Abbrev: 0x2
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+// DWARF:        Bucket 4 [
+// DWARF:            String: 0x0000012b "main"
+// DWARF-NEXT:       Entry @ 0xc5 {
+// DWARF-NEXT:         Abbrev: 0x2
+// DWARF-NEXT:         Tag: DW_TAG_subprogram
+// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -165,41 +139,6 @@ _Z2f12t1:                               # @_Z2f12t1
 	.byte	1                               # DWARF Unit Type
 	.byte	8                               # Address Size (in bytes)
 	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
-	.byte	0                               # DW_AT_producer
-	.short	33                              # DW_AT_language
-	.byte	1                               # DW_AT_name
-	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
-	.long	.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
-	.long	.Laddr_table_base0              # DW_AT_addr_base
-	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	3                               # DW_AT_linkage_name
-	.byte	4                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-                                        # DW_AT_external
-	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	127
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-	.long	58                              # DW_AT_type
-	.byte	0                               # End Of Children Mark
-	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
-	.byte	5                               # DW_AT_calling_convention
-	.byte	5                               # DW_AT_name
-	.byte	1                               # DW_AT_byte_size
-	.byte	0                               # DW_AT_decl_file
-	.byte	1                               # DW_AT_decl_line
-	.byte	0                               # End Of Children Mark
 .Ldebug_info_end0:
 	.section	.debug_str_offsets,"", at progbits
 	.long	28                              # Length of String Offsets Set

>From 932aa047c913d620e2eb49b9e6c94deee2b5c4c5 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 26 Mar 2024 23:04:50 -0700
Subject: [PATCH 05/23] [lld][ELF] Implement merged .debug_names section.

Fix code formatting issue.
---
 lld/ELF/SyntheticSections.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 776bf719a01d77..389fda9bf436b2 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2920,8 +2920,7 @@ static void readAttributeValues(
     Error err = Error::success();
     typename DebugNamesSection<ELFT>::AttrValueData newAttr;
     uint32_t value;
-    if (attr.Index == DW_IDX_parent &&
-        attr.Form != DW_FORM_flag_present &&
+    if (attr.Index == DW_IDX_parent && attr.Form != DW_FORM_flag_present &&
         attr.Form != DW_FORM_ref4)
       errorOrWarn(toString(namesSection.sec) +
                   Twine(": invalid form for DW_IDX_parent"));

>From 2723b34681b6058be0419fb0252dcc97abbf7474 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 27 Mar 2024 00:28:52 -0700
Subject: [PATCH 06/23] [lld][ELF] Implement merged .debug_names section

Update for-loop to make sure unnecessary evaluations/calculations are
not performed on condition checks.
---
 lld/ELF/SyntheticSections.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 389fda9bf436b2..28efc126df86dd 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3039,7 +3039,7 @@ readEntries(typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
   chunk.hashValues.reserve(secData.hdr.NameCount);
   secData.namedEntries.reserve(secData.hdr.NameCount);
   // Calculate the Entry Offsets, create initial records.
-  for (uint32_t i = 0; i < secData.hdr.NameCount; ++i) {
+  for (uint32_t i = 0, e = secData.hdr.NameCount; i != e; ++i) {
     // Get string value
     typename DebugNamesSection<ELFT>::NamedEntry stringEntry;
     stringEntry.entryOffset =

>From 64e666a208b0786ef97706262177290d6e0638d7 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 27 Mar 2024 07:52:09 -0700
Subject: [PATCH 07/23] [lld][ELF] Implement merged .debug_names section.

Move '-r' and '--debug-names' test to driver.test; remove
debug-names-invalid-flags.s test.
---
 lld/test/ELF/debug-names-invalid-flags.s | 148 -----------------------
 1 file changed, 148 deletions(-)
 delete mode 100644 lld/test/ELF/debug-names-invalid-flags.s

diff --git a/lld/test/ELF/debug-names-invalid-flags.s b/lld/test/ELF/debug-names-invalid-flags.s
deleted file mode 100644
index 96cd4da243b688..00000000000000
--- a/lld/test/ELF/debug-names-invalid-flags.s
+++ /dev/null
@@ -1,148 +0,0 @@
-// This file was generated by:
-// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-//    -gpubnames main.cpp
-
-// Contents of main.cpp
-// int main (int argc, char **argv) { }
-
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: not ld.lld --debug-names -r %t1.o  -o  /dev/null 2>&1 \
-// RUN:   | FileCheck -DFILE=%t1.o %s
-
-// CHECK: error: -r and --debug-names may not be used together
-
-	.text
-	.globl	main                            # -- Begin function main
-	.p2align	4, 0x90
-	.type	main, at function
-main:                                   # @main
-.Lfunc_begin0:
-	.cfi_startproc
-# %bb.0:                                # %entry
-	pushq	%rbp
-	.cfi_def_cfa_offset 16
-	.cfi_offset %rbp, -16
-	movq	%rsp, %rbp
-	.cfi_def_cfa_register %rbp
-	movl	%edi, -4(%rbp)
-	movq	%rsi, -16(%rbp)
-.Ltmp0:
-	xorl	%eax, %eax
-	popq	%rbp
-	.cfi_def_cfa %rsp, 8
-	retq
-.Ltmp1:
-.Lfunc_end0:
-	.size	main, .Lfunc_end0-main
-	.cfi_endproc
-                                        # -- End function
-	.section	.debug_abbrev,"", at progbits
-	.byte	0                               # EOM(1)
-	.byte	0                               # EOM(2)
-	.byte	0                               # EOM(3)
-	.section	.debug_info,"", at progbits
-.Lcu_begin0:
-	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
-.Ldebug_info_start0:
-	.short	5                               # DWARF version number
-	.byte	1                               # DWARF Unit Type
-	.byte	8                               # Address Size (in bytes)
-	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-.Ldebug_info_end0:
-	.section	.debug_str_offsets,"", at progbits
-	.long	36                              # Length of String Offsets Set
-	.short	5
-	.short	0
-.Lstr_offsets_base0:
-	.section	.debug_str,"MS", at progbits,1
-.Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
-.Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
-.Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
-.Linfo_string3:
-	.asciz	"main"                          # string offset=130
-.Linfo_string4:
-	.asciz	"int"                           # string offset=135
-.Linfo_string5:
-	.asciz	"argc"                          # string offset=139
-.Linfo_string6:
-	.asciz	"argv"                          # string offset=144
-.Linfo_string7:
-	.asciz	"char"                          # string offset=149
-.Laddr_table_base0:
-	.quad	.Lfunc_begin0
-.Ldebug_addr_end0:
-	.section	.debug_names,"", at progbits
-	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
-.Lnames_start0:
-	.short	5                               # Header: version
-	.short	0                               # Header: padding
-	.long	1                               # Header: compilation unit count
-	.long	0                               # Header: local type unit count
-	.long	0                               # Header: foreign type unit count
-	.long	3                               # Header: bucket count
-	.long	3                               # Header: name count
-	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
-	.long	8                               # Header: augmentation string size
-	.ascii	"LLVM0700"                      # Header: augmentation string
-	.long	.Lcu_begin0                     # Compilation unit 0
-	.long	0                               # Bucket 0
-	.long	1                               # Bucket 1
-	.long	2                               # Bucket 2
-	.long	2090499946                      # Hash in Bucket 1
-	.long	193495088                       # Hash in Bucket 2
-	.long	2090147939                      # Hash in Bucket 2
-	.long	.Linfo_string3                  # String in Bucket 1: main
-	.long	.Linfo_string4                  # String in Bucket 2: int
-	.long	.Linfo_string7                  # String in Bucket 2: char
-	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
-	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
-	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
-.Lnames_abbrev_start0:
-	.byte	1                               # Abbrev code
-	.byte	46                              # DW_TAG_subprogram
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	2                               # Abbrev code
-	.byte	36                              # DW_TAG_base_type
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev list
-.Lnames_abbrev_end0:
-.Lnames_entries0:
-.Lnames0:
-.L1:
-	.byte	1                               # Abbreviation code
-	.long	35                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: main
-.Lnames1:
-.L0:
-	.byte	2                               # Abbreviation code
-	.long	73                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: int
-.Lnames2:
-.L2:
-	.byte	2                               # Abbreviation code
-	.long	87                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: char
-	.p2align	2, 0x0
-.Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
-	.section	".note.GNU-stack","", at progbits
-	.addrsig
-	.section	.debug_line,"", at progbits
-.Lline_table_start0:

>From 28444182704374a45a3684b5e958540953cae6de Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 29 Mar 2024 07:33:14 -0700
Subject: [PATCH 08/23] [lld][ELF] Implement merged .debug_names section.

Address various review comments.
---
 lld/ELF/SyntheticSections.cpp | 65 +++++++++++++++--------------------
 lld/ELF/SyntheticSections.h   |  4 +--
 2 files changed, 29 insertions(+), 40 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 28efc126df86dd..32eb19568f6159 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2747,7 +2747,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   SmallVector<DenseMap<uint32_t, uint32_t>, 0> chunksRelocs;
   chunksRelocs.reserve(numChunks);
 
-  for (size_t i = 0; i < numChunks; ++i) {
+  for (size_t i = 0, e = numChunks; i != e; ++i) {
     DebugNamesOutputChunk &chunk = outputChunks[i];
     InputSectionBase *base = inputDebugNamesSections[i];
     DenseMap<uint32_t, uint32_t> &relocs = chunksRelocs.emplace_back();
@@ -2798,9 +2798,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
     warn(".debug_names: type units are not handled in merged index");
 
   // Write the foreign TU list.
-  // Currently LLVM does not emit foreign type units, so there should
-  // be nothing here to emit.
-  // TODO: Fix this, once we get everything working wtihout TUs.
+  // TODO: Fix this, once we get everything working without TUs.
   if (mergedHdr.ForeignTypeUnitCount != 0)
     warn(".debug_names: type units are not handled in merged index");
 
@@ -2855,10 +2853,8 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
     for (const auto &entry : stringEntry.indexEntries) {
       buf += encodeULEB128(entry->abbrevCode, buf);
       for (const auto &value : entry->attrValues) {
-        if (value.attrSize > 0) {
-          endian::write32<ELFT::Endianness>(buf + 0, value.attrValue);
-          buf += value.attrSize;
-        }
+        endian::write32<ELFT::Endianness>(buf + 0, value.attrValue);
+        buf += value.attrSize;
       }
     }
     *buf++ = 0; // Entry sentinel
@@ -2876,33 +2872,26 @@ static void readCompileUnitOffsets(
     DWARFDataExtractor &namesExtractor) {
   uint64_t offset = secData.locs.CUsBase;
   uint64_t *offsetPtr = &offset;
-  for (size_t i = 0; i < secData.hdr.CompUnitCount; ++i) {
-    Error err = Error::success();
-    // This call to namesExtractor can't fail; if there were a problem with the
-    // input, it would have been caught in the call to NamesIndex::extract, in
-    // DebugNamesSection::create.
-    uint32_t value = namesExtractor.getU32(offsetPtr, &err);
-    cantFail(std::move(err));
-    outputChunk.compilationUnits.push_back(value);
-  }
+  outputChunk.compilationUnits.resize(secData.hdr.CompUnitCount);
+  uint32_t *bufferPtr =
+      namesExtractor.getU32(offsetPtr, outputChunk.compilationUnits.begin(),
+                            secData.hdr.CompUnitCount);
+  if (!bufferPtr)
+    errorOrWarn(toString(outputChunk.sec) +
+                Twine(": error while reading CU offsets"));
 }
 
 template <class ELFT>
 static void readEntryOffsets(
     typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
     DWARFDataExtractor &namesExtractor) {
-  secData.entryOffsets = std::make_unique<uint32_t[]>(secData.hdr.NameCount);
+  secData.entryOffsets.resize(secData.hdr.NameCount);
   uint64_t offset = secData.locs.EntryOffsetsBase;
   uint64_t *offsetPtr = &offset;
-  for (size_t i = 0; i < secData.hdr.NameCount; ++i) {
-    Error err = Error::success();
-    // This call to namesExtractor can't fail; if there were a problem with the
-    // input, it would have been caught in the call to NamesIndex::extract, in
-    // DebugNamesSection::create.
-    uint32_t value = namesExtractor.getU32(offsetPtr, &err);
-    cantFail(std::move(err));
-    secData.entryOffsets.get()[i] = value;
-  }
+  uint32_t *bufferPtr = namesExtractor.getU32(
+      offsetPtr, secData.entryOffsets.begin(), secData.hdr.NameCount);
+  if (!bufferPtr)
+    errorOrWarn(Twine(": error while reading entry offsets"));
 }
 
 template <class ELFT>
@@ -2975,7 +2964,7 @@ static void readAttributeValues(
       errorOrWarn(toString(namesSection.sec) +
                   Twine(": error while reading attributes: ") +
                   toString(std::move(err)));
-    if (attr.Index == DW_IDX_compile_unit || attr.Index == DW_IDX_type_unit)
+    if (attr.Index == DW_IDX_compile_unit)
       // Save it to put it at the end of the attributes list.
       cuOrTuAttr = newAttr;
     else if (attr.Form != DW_FORM_flag_present)
@@ -3090,8 +3079,9 @@ static void collectDebugNamesSectionData(
     typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
     typename DebugNamesSection<ELFT>::DebugNamesOutputChunk &outputChunk,
     DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor) {
-  for (const auto &ni : *chunk.debugNamesData) {
-    typename DebugNamesSection<ELFT>::DebugNamesSectionData secData;
+  for (const DWARFDebugNames::NameIndex &ni : *chunk.debugNamesData) {
+    typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData =
+        chunk.sectionsData.emplace_back();
     secData.hdr = ni.getHeader();
     if (secData.hdr.Format != DwarfFormat::DWARF32) {
       errorOrWarn(toString(chunk.namesSection->sec) +
@@ -3108,7 +3098,6 @@ static void collectDebugNamesSectionData(
     readCompileUnitOffsets<ELFT>(secData, outputChunk, namesExtractor);
     readEntryOffsets<ELFT>(secData, namesExtractor);
     readEntries<ELFT>(secData, chunk, namesExtractor, strExtractor, ni);
-    chunk.sectionsData.push_back(std::move(secData));
   }
 }
 
@@ -3123,7 +3112,7 @@ void DebugNamesSection<ELFT>::collectMergedCounts(
   mergedHdr.Format = DwarfFormat::DWARF32;
   mergedHdr.AugmentationStringSize = 0;
 
-  for (size_t i = 0; i < numChunks; ++i) {
+  for (size_t i = 0, e = numChunks; i != e; ++i) {
     DebugNamesInputChunk &inputChunk = inputChunks[i];
     DebugNamesOutputChunk &outputChunk = outputChunks[i];
     inputChunk.baseCuOffsetIdx = tmpMergedCuOffsets.size();
@@ -3197,7 +3186,7 @@ void DebugNamesSection<ELFT>::getMergedAbbrevTable(
   dwarf::Form compileUnitAttrForm = getMergedCuSizeData().second;
 
   for (DebugNamesInputChunk &chunk : inputChunks) {
-    for (const auto &ni : *chunk.debugNamesData) {
+    for (const DWARFDebugNames::NameIndex &ni : *chunk.debugNamesData) {
       const auto &abbrevs = ni.getAbbrevs();
       for (const DWARFDebugNames::Abbrev &abbrev : abbrevs) {
         // Create canonicalized abbrev.
@@ -3208,8 +3197,7 @@ void DebugNamesSection<ELFT>::getMergedAbbrevTable(
         newAbbrev.tag = abbrev.Tag;
         for (const auto attr : abbrev.Attributes) {
           DWARFDebugNames::AttributeEncoding newAttr(attr.Index, attr.Form);
-          if (attr.Index == DW_IDX_compile_unit ||
-              attr.Index == DW_IDX_type_unit)
+          if (attr.Index == DW_IDX_compile_unit)
             // Save it, to put it at the end.
             cuOrTuAttr.Index = newAttr.Index;
           else
@@ -3231,7 +3219,8 @@ void DebugNamesSection<ELFT>::getMergedAbbrevTable(
           newCode = Existing->code;
         } else {
           // Didn't find it.
-          Abbrev *newAbbrev2 = new (Alloc) Abbrev(std::move(newAbbrev));
+          Abbrev *newAbbrev2 =
+              new (abbrevAlloc.Allocate()) Abbrev(std::move(newAbbrev));
           AbbreviationsSet.InsertNode(newAbbrev2, insertPos);
           newCode = mergedAbbrevTable.size() + 1;
           newAbbrev2->code = newCode;
@@ -3280,7 +3269,7 @@ void DebugNamesSection<ELFT>::getMergedSymbols(
   MutableArrayRef<ShardData> shards(shardsPtr.get(), numShards);
 
   parallelFor(0, concurrency, [&](size_t threadId) {
-    for (size_t i = 0; i < numChunks; ++i) {
+    for (size_t i = 0, e = numChunks; i != e; ++i) {
       DebugNamesInputChunk &chunk = inputChunks[i];
       for (auto &secData : chunk.sectionsData) {
         // Deduplicate the NamedEntry records (based on the string/name),
@@ -3390,7 +3379,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::updateParentIndexEntries() {
       // Found the abbrev. Find the index for the DW_IDX_parent attribute
       // (in the abbrev) and update that value in the entry with the
       // correct parent offset (in the merged entry pool).
-      for (size_t idx = 0, size = abbrev->attributes.size(); idx < size;
+      for (size_t idx = 0, size = abbrev->attributes.size(); idx != size;
            ++idx) {
         auto attr = abbrev->attributes[idx];
         if (attr.Index == DW_IDX_parent && attr.Form == DW_FORM_ref4)
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 24ffdb3db4946b..297f2ca6e27d85 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -859,7 +859,7 @@ template <class ELFT> class DebugNamesSection final : public SyntheticSection {
     llvm::DWARFDebugNames::DWARFDebugNamesOffsets locs;
     SmallVector<uint32_t, 0> tuOffsets;
     SmallVector<Abbrev, 0> abbrevTable;
-    std::unique_ptr<uint32_t[]> entryOffsets;
+    SmallVector<uint32_t, 0> entryOffsets;
     SmallVector<NamedEntry, 0> namedEntries;
     uint16_t dwarfSize;
     uint16_t hdrSize;
@@ -895,7 +895,7 @@ template <class ELFT> class DebugNamesSection final : public SyntheticSection {
   void updateParentIndexEntries();
   uint64_t calculateMergedSectionSize();
 
-  llvm::BumpPtrAllocator Alloc;
+  llvm::SpecificBumpPtrAllocator<Abbrev> abbrevAlloc;
 
 private:
   size_t sectionSize;

>From c17e68b9981182b26e7f1edf3b8d02be76110b5d Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 29 Mar 2024 07:36:10 -0700
Subject: [PATCH 09/23] [lld][ELF] Implement merged .debug_names section.

Fix comment,
---
 lld/ELF/SyntheticSections.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 32eb19568f6159..7db2524597cc6d 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3458,7 +3458,7 @@ DebugNamesSection<ELFT> *DebugNamesSection<ELFT>::create() {
   ret->getMergedAbbrevTable(inputChunks);
   ret->getMergedSymbols(inputChunks);
   ret->computeUniqueHashes(inputChunks);
-  // inputChunks are needed any more. Reset now to save memory.
+  // inputChunks are not needed any more. Reset now to save memory.
   inputChunksPtr.reset();
   ret->generateBuckets();
   ret->calculateEntriesSizeAndOffsets();

>From c4d7537e1a6c4e20d781a5227865f0ea7ddb8485 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 29 Mar 2024 09:08:28 -0700
Subject: [PATCH 10/23] [lld][ELF] Implement merged .debug_names section.

Replace "ELFT::TargetEndianness" with "ELFT::Endianness"
---
 lld/ELF/SyntheticSections.cpp | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 7db2524597cc6d..3ae8e1f97c5c1a 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2773,15 +2773,12 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   endian::write32<ELFT::Endianness>(buf + 0, mergedHdr.UnitLength);
   endian::write16<ELFT::Endianness>(buf + 4, mergedHdr.Version);
   endian::write32<ELFT::Endianness>(buf + 8, mergedHdr.CompUnitCount);
-  endian::write32<ELFT::Endianness>(buf + 12,
-                                          mergedHdr.LocalTypeUnitCount);
-  endian::write32<ELFT::Endianness>(buf + 16,
-                                          mergedHdr.ForeignTypeUnitCount);
+  endian::write32<ELFT::Endianness>(buf + 12, mergedHdr.LocalTypeUnitCount);
+  endian::write32<ELFT::Endianness>(buf + 16, mergedHdr.ForeignTypeUnitCount);
   endian::write32<ELFT::Endianness>(buf + 20, mergedHdr.BucketCount);
   endian::write32<ELFT::Endianness>(buf + 24, mergedHdr.NameCount);
   endian::write32<ELFT::Endianness>(buf + 28, mergedHdr.AbbrevTableSize);
-  endian::write32<ELFT::Endianness>(buf + 32,
-                                          mergedHdr.AugmentationStringSize);
+  endian::write32<ELFT::Endianness>(buf + 32, mergedHdr.AugmentationStringSize);
   buf += 36;
   memcpy(buf, mergedHdr.AugmentationString.c_str(), 8);
   buf += 8;
@@ -2823,8 +2820,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
 
   // Write the string offsets.
   for (const auto &entry : mergedEntries) {
-    endian::write32<ELFT::Endianness>(buf + 0,
-                                            entry.relocatedEntryOffset);
+    endian::write32<ELFT::Endianness>(buf + 0, entry.relocatedEntryOffset);
     buf += 4;
   }
 

>From 06171a85f7e1d896f247d7f168d07308cab7bfad Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Fri, 29 Mar 2024 15:32:40 -0700
Subject: [PATCH 11/23] [lld][ELF] Implement merged .debug_names section.

Set augmentation string size from the augmentation string (for error
handling case).
---
 lld/ELF/SyntheticSections.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 3ae8e1f97c5c1a..0a56a6fb888f40 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3128,8 +3128,8 @@ void DebugNamesSection<ELFT>::collectMergedCounts(
                   data.hdr.AugmentationString)) {
         // There are conflicting augmentation strings, so it's best for the
         // merged index to not use an augmentation string.
-        mergedHdr.AugmentationStringSize = 8;
         mergedHdr.AugmentationString = "        ";
+        mergedHdr.AugmentationStringSize = mergedHdr.AugmentationString.size();
       }
     }
   }

>From 11898cac5255897fd94ed73b1d75c6bbe9d9bc67 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 1 Apr 2024 21:58:31 -0700
Subject: [PATCH 12/23] [lld][ELF] Implement merged .debug_names section.

Update debug-names*.s tests, to use split file format rather than
multiple files.

Reduce the use of 'auto' in DebugNamesSection work, replacing it with
actual type names.  Use UINT*_MAXINT rather than constant values.
---
 lld/ELF/SyntheticSections.cpp | 43 ++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 0a56a6fb888f40..c87b29e34f69de 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2761,7 +2761,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   }
 
   // Update the entries with the relocated string offsets.
-  for (auto &stringEntry : mergedEntries) {
+  for (NamedEntry &stringEntry : mergedEntries) {
     uint32_t oldOffset = stringEntry.stringOffsetOffset;
     uint32_t idx = stringEntry.chunkIdx;
     stringEntry.relocatedEntryOffset = chunksRelocs[idx][oldOffset];
@@ -2802,7 +2802,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   // Write the hash table.
   // ... Write the buckets
   uint32_t idx = 1;
-  for (const auto &bucket : bucketList) {
+  for (const SmallVector<NamedEntry *, 0> &bucket : bucketList) {
     if (!bucket.empty())
       endian::write32<ELFT::Endianness>(buf + 0, idx);
     idx += bucket.size();
@@ -2819,7 +2819,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   }
 
   // Write the string offsets.
-  for (const auto &entry : mergedEntries) {
+  for (const NamedEntry &entry : mergedEntries) {
     endian::write32<ELFT::Endianness>(buf + 0, entry.relocatedEntryOffset);
     buf += 4;
   }
@@ -2831,10 +2831,10 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   }
 
   // Write the abbrev table.
-  for (const auto *abbrev : mergedAbbrevTable) {
+  for (const Abbrev *abbrev : mergedAbbrevTable) {
     buf += encodeULEB128(abbrev->code, buf);
     buf += encodeULEB128(abbrev->tag, buf);
-    for (auto attr : abbrev->attributes) {
+    for (DWARFDebugNames::AttributeEncoding attr : abbrev->attributes) {
       buf += encodeULEB128(attr.Index, buf);
       buf += encodeULEB128(attr.Form, buf);
     }
@@ -2846,7 +2846,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   // Write the entry pool.
   for (const auto &stringEntry : mergedEntries) {
     // Write all the entries for the string.
-    for (const auto &entry : stringEntry.indexEntries) {
+    for (const std::unique_ptr<IndexEntry> &entry : stringEntry.indexEntries) {
       buf += encodeULEB128(entry->abbrevCode, buf);
       for (const auto &value : entry->attrValues) {
         endian::write32<ELFT::Endianness>(buf + 0, value.attrValue);
@@ -2901,7 +2901,7 @@ static void readAttributeValues(
   const LLDDWARFSection &namesSection = *chunk.namesSection;
   uint64_t *offsetPtr = &offset;
   typename DebugNamesSection<ELFT>::AttrValueData cuOrTuAttr = {0, 0};
-  for (auto attr : abbrev.Attributes) {
+  for (DWARFDebugNames::AttributeEncoding attr : abbrev.Attributes) {
     Error err = Error::success();
     typename DebugNamesSection<ELFT>::AttrValueData newAttr;
     uint32_t value;
@@ -3153,13 +3153,13 @@ std::pair<uint8_t, dwarf::Form> DebugNamesSection<ELFT>::getMergedCuSizeData() {
   uint8_t size;
   dwarf::Form form;
   // TODO: Investigate possibly using DIEInteger::BestForm here
-  if (mergedHdr.CompUnitCount > 0xffffffff) {
+  if (mergedHdr.CompUnitCount > UINT32_MAX) {
     form = DW_FORM_data8;
     size = 8;
-  } else if (mergedHdr.CompUnitCount > 0xffff) {
+  } else if (mergedHdr.CompUnitCount > UINT16_MAX) {
     form = DW_FORM_data4;
     size = 4;
-  } else if (mergedHdr.CompUnitCount > 0xff) {
+  } else if (mergedHdr.CompUnitCount > UINT8_MAX) {
     form = DW_FORM_data2;
     size = 2;
   } else {
@@ -3191,7 +3191,8 @@ void DebugNamesSection<ELFT>::getMergedAbbrevTable(
                                                       compileUnitAttrForm);
         newAbbrev.code = abbrev.Code;
         newAbbrev.tag = abbrev.Tag;
-        for (const auto attr : abbrev.Attributes) {
+        for (const DWARFDebugNames::AttributeEncoding attr :
+             abbrev.Attributes) {
           DWARFDebugNames::AttributeEncoding newAttr(attr.Index, attr.Form);
           if (attr.Index == DW_IDX_compile_unit)
             // Save it, to put it at the end.
@@ -3232,7 +3233,7 @@ void DebugNamesSection<ELFT>::getMergedAbbrevTable(
   for (Abbrev *a : mergedAbbrevTable) {
     mergedHdr.AbbrevTableSize += getULEB128Size(a->code);
     mergedHdr.AbbrevTableSize += getULEB128Size(a->tag);
-    for (const auto &attr : a->attributes) {
+    for (const DWARFDebugNames::AttributeEncoding &attr : a->attributes) {
       mergedHdr.AbbrevTableSize += getULEB128Size(attr.Index);
       mergedHdr.AbbrevTableSize += getULEB128Size(attr.Form);
     }
@@ -3267,7 +3268,7 @@ void DebugNamesSection<ELFT>::getMergedSymbols(
   parallelFor(0, concurrency, [&](size_t threadId) {
     for (size_t i = 0, e = numChunks; i != e; ++i) {
       DebugNamesInputChunk &chunk = inputChunks[i];
-      for (auto &secData : chunk.sectionsData) {
+      for (DebugNamesSectionData &secData : chunk.sectionsData) {
         // Deduplicate the NamedEntry records (based on the string/name),
         // using a map from string/name to NamedEntry records.
         // Note there is a twist: If there is already a record for the current
@@ -3275,14 +3276,14 @@ void DebugNamesSection<ELFT>::getMergedSymbols(
         // current record to the record that's in the nameMap. I.e. we
         // deduplicate the *strings* but we keep all the IndexEntry records
         // (moving them to the appropriate 'kept' NamedEntry record).
-        for (auto &stringEntry : secData.namedEntries) {
+        for (NamedEntry &stringEntry : secData.namedEntries) {
           size_t shardId = stringEntry.hashValue >> shift;
           if ((shardId & (concurrency - 1)) != threadId)
             continue;
 
           auto &shard = shards[shardId];
           stringEntry.chunkIdx = i;
-          for (auto &entry : stringEntry.indexEntries) {
+          for (std::unique_ptr<IndexEntry> &entry : stringEntry.indexEntries) {
             // The DW_IDX_compile_unit is always the last attribute (we set it
             // up that way when we read/created the attributes). We need to
             // update the index value to use the correct merged offset, and we
@@ -3312,7 +3313,7 @@ void DebugNamesSection<ELFT>::getMergedSymbols(
   });
 
   // Combined the shared symbols into mergedEntries
-  for (auto &shard : shards)
+  for (ShardData &shard : shards)
     for (auto &mapEntry : shard.nameMap)
       mergedEntries.push_back(std::move(mapEntry.second));
   mergedHdr.NameCount = mergedEntries.size();
@@ -3330,14 +3331,14 @@ void DebugNamesSection<ELFT>::computeUniqueHashes(
 
 template <class ELFT> void DebugNamesSection<ELFT>::generateBuckets() {
   bucketList.resize(mergedHdr.BucketCount);
-  for (auto &entry : mergedEntries) {
+  for (NamedEntry &entry : mergedEntries) {
     uint32_t bucketIdx = entry.hashValue % mergedHdr.BucketCount;
     bucketList[bucketIdx].push_back(&entry);
   }
 
   // Sort the contents of the buckets by hash value so that the hash collisions
   // end up together.
-  for (auto &bucket : bucketList)
+  for (SmallVector<NamedEntry *, 0> &bucket : bucketList)
     stable_sort(bucket, [](NamedEntry *lhs, NamedEntry *rhs) {
       return lhs->hashValue < rhs->hashValue;
     });
@@ -3348,7 +3349,7 @@ void DebugNamesSection<ELFT>::calculateEntriesSizeAndOffsets() {
   uint32_t offset = 0;
   for (NamedEntry &stringEntry : mergedEntries) {
     stringEntry.entryOffset = offset;
-    for (auto &entry : stringEntry.indexEntries) {
+    for (std::unique_ptr<IndexEntry> &entry : stringEntry.indexEntries) {
       uint32_t entrySize = 0;
       entry->poolOffset = offset;
       entrySize += getULEB128Size(entry->abbrevCode);
@@ -3364,7 +3365,7 @@ void DebugNamesSection<ELFT>::calculateEntriesSizeAndOffsets() {
 
 template <class ELFT> void DebugNamesSection<ELFT>::updateParentIndexEntries() {
   for (NamedEntry &stringEntry : mergedEntries) {
-    for (auto &childEntry : stringEntry.indexEntries) {
+    for (std::unique_ptr<IndexEntry> &childEntry : stringEntry.indexEntries) {
       if (!childEntry->parentEntry)
         continue;
 
@@ -3377,7 +3378,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::updateParentIndexEntries() {
       // correct parent offset (in the merged entry pool).
       for (size_t idx = 0, size = abbrev->attributes.size(); idx != size;
            ++idx) {
-        auto attr = abbrev->attributes[idx];
+        DWARFDebugNames::AttributeEncoding attr = abbrev->attributes[idx];
         if (attr.Index == DW_IDX_parent && attr.Form == DW_FORM_ref4)
           childEntry->attrValues[idx].attrValue =
               childEntry->parentEntry->poolOffset;

>From c8b69048ce6d0aa8da4756c9c86a988a8d46e385 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 1 Apr 2024 22:19:18 -0700
Subject: [PATCH 13/23] [lld][ELF] Implement merged .debug_names section.

Update tests to up split-file instead of multiple files.
---
 lld/test/ELF/Inputs/debug-names-2.s           | 150 ---------
 .../ELF/Inputs/debug-names-parent-idx-2.s     | 267 ----------------
 lld/test/ELF/debug-names-bad-aug-string.s     | 169 ++++++++++-
 lld/test/ELF/debug-names-bad-version.s        | 165 +++++++++-
 lld/test/ELF/debug-names-parent-idx.s         | 286 +++++++++++++++++-
 lld/test/ELF/debug-names.s                    | 178 ++++++++++-
 6 files changed, 774 insertions(+), 441 deletions(-)
 delete mode 100644 lld/test/ELF/Inputs/debug-names-2.s
 delete mode 100644 lld/test/ELF/Inputs/debug-names-parent-idx-2.s

diff --git a/lld/test/ELF/Inputs/debug-names-2.s b/lld/test/ELF/Inputs/debug-names-2.s
deleted file mode 100644
index 83ddbd2050d40b..00000000000000
--- a/lld/test/ELF/Inputs/debug-names-2.s
+++ /dev/null
@@ -1,150 +0,0 @@
-#-- input file: debug-names-2.cpp
-## Generated with:
-## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-##     -S debug-names-2.cpp -o debug-names-2.s
-
-## debug-names-2.cpp contents:
-
-## struct t1 { };
-## int main() {
-##   t1 v1;
-## }
-##
-	.text
-	.globl	main                            # -- Begin function main
-	.p2align	4, 0x90
-	.type	main, at function
-main:                                   # @main
-.Lfunc_begin0:
-	.cfi_startproc
-# %bb.0:                                # %entry
-	pushq	%rbp
-	.cfi_def_cfa_offset 16
-	.cfi_offset %rbp, -16
-	movq	%rsp, %rbp
-	.cfi_def_cfa_register %rbp
-.Ltmp0:
-	xorl	%eax, %eax
-	popq	%rbp
-	.cfi_def_cfa %rsp, 8
-	retq
-.Ltmp1:
-.Lfunc_end0:
-	.size	main, .Lfunc_end0-main
-	.cfi_endproc
-                                        # -- End function
-	.section	.debug_abbrev,"", at progbits
-	.byte	0                               # EOM(1)
-	.byte	0                               # EOM(2)
-	.byte	0                               # EOM(3)
-	.section	.debug_info,"", at progbits
-.Lcu_begin0:
-	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
-.Ldebug_info_start0:
-	.short	5                               # DWARF version number
-	.byte	1                               # DWARF Unit Type
-	.byte	8                               # Address Size (in bytes)
-	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-.Ldebug_info_end0:
-	.section	.debug_str_offsets,"", at progbits
-	.long	32                              # Length of String Offsets Set
-	.short	5
-	.short	0
-.Lstr_offsets_base0:
-	.section	.debug_str,"MS", at progbits,1
-.Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
-.Linfo_string1:
-	.asciz	"debug-names-2.cpp"             # string offset=104
-.Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=122
-.Linfo_string3:
-	.asciz	"main"                          # string offset=139
-.Linfo_string4:
-	.asciz	"int"                           # string offset=144
-.Linfo_string5:
-	.asciz	"v1"                            # string offset=148
-.Linfo_string6:
-	.asciz	"t1"                            # string offset=151
-.Laddr_table_base0:
-	.quad	.Lfunc_begin0
-.Ldebug_addr_end0:
-	.section	.debug_names,"", at progbits
-	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
-.Lnames_start0:
-	.short	5                               # Header: version
-	.short	0                               # Header: padding
-	.long	1                               # Header: compilation unit count
-	.long	0                               # Header: local type unit count
-	.long	0                               # Header: foreign type unit count
-	.long	3                               # Header: bucket count
-	.long	3                               # Header: name count
-	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
-	.long	8                               # Header: augmentation string size
-	.ascii	"LLVM0700"                      # Header: augmentation string
-	.long	.Lcu_begin0                     # Compilation unit 0
-	.long	0                               # Bucket 0
-	.long	1                               # Bucket 1
-	.long	3                               # Bucket 2
-	.long	5863786                         # Hash in Bucket 1
-	.long	2090499946                      # Hash in Bucket 1
-	.long	193495088                       # Hash in Bucket 2
-	.long	.Linfo_string6                  # String in Bucket 1: t1
-	.long	.Linfo_string3                  # String in Bucket 1: main
-	.long	.Linfo_string4                  # String in Bucket 2: int
-	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
-	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
-	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
-.Lnames_abbrev_start0:
-	.byte	1                               # Abbrev code
-	.byte	19                              # DW_TAG_structure_type
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	2                               # Abbrev code
-	.byte	46                              # DW_TAG_subprogram
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	3                               # Abbrev code
-	.byte	36                              # DW_TAG_base_type
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev list
-.Lnames_abbrev_end0:
-.Lnames_entries0:
-.Lnames2:
-.L1:
-	.byte	1                               # Abbreviation code
-	.long	66                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: t1
-.Lnames0:
-.L2:
-	.byte	2                               # Abbreviation code
-	.long	35                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: main
-.Lnames1:
-.L0:
-	.byte	3                               # Abbreviation code
-	.long	62                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: int
-	.p2align	2, 0x0
-.Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
-	.section	".note.GNU-stack","", at progbits
-	.addrsig
-	.section	.debug_line,"", at progbits
-.Lline_table_start0:
diff --git a/lld/test/ELF/Inputs/debug-names-parent-idx-2.s b/lld/test/ELF/Inputs/debug-names-parent-idx-2.s
deleted file mode 100644
index ebd93c01d85189..00000000000000
--- a/lld/test/ELF/Inputs/debug-names-parent-idx-2.s
+++ /dev/null
@@ -1,267 +0,0 @@
-#-- input file: debug-names-parent-idx-2.cpp
-## Generated with:
-
-## - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
-##     -S debug-names-parent-idx-2.cpp -o debug-names-parent-idx-2.s
-
-## foo.h contents:
-
-## int foo();
-
-## struct foo {
-##   int x;
-##   char y;
-##   struct foo *foo_ptr;
-## };
-
-## namespace parent_test {
-##   int foo();
-## }
-
-## debug-names-parent-index-2.cpp contents:
-
-## #include "foo.h"
-## int foo () {
-##   struct foo struct2;
-##   struct2.x = 1024;
-##   struct2.y = 'r';
-##   struct2.foo_ptr = nullptr;
-##   return struct2.x * (int) struct2.y;
-## }
-
-## namespace parent_test {
-## int foo () {
-##   return 25;
-## }
-## }
-
-	.text
-	.globl	_Z3foov                         # -- Begin function _Z3foov
-	.p2align	4, 0x90
-	.type	_Z3foov, at function
-_Z3foov:                                # @_Z3foov
-.Lfunc_begin0:
-	.cfi_startproc
-# %bb.0:                                # %entry
-	pushq	%rbp
-	.cfi_def_cfa_offset 16
-	.cfi_offset %rbp, -16
-	movq	%rsp, %rbp
-	.cfi_def_cfa_register %rbp
-.Ltmp0:
-	movl	$1024, -16(%rbp)                # imm = 0x400
-	movb	$114, -12(%rbp)
-	movq	$0, -8(%rbp)
-	movl	-16(%rbp), %eax
-	movsbl	-12(%rbp), %ecx
-	imull	%ecx, %eax
-	popq	%rbp
-	.cfi_def_cfa %rsp, 8
-	retq
-.Ltmp1:
-.Lfunc_end0:
-	.size	_Z3foov, .Lfunc_end0-_Z3foov
-	.cfi_endproc
-                                        # -- End function
-	.globl	_ZN11parent_test3fooEv          # -- Begin function _ZN11parent_test3fooEv
-	.p2align	4, 0x90
-	.type	_ZN11parent_test3fooEv, at function
-_ZN11parent_test3fooEv:                 # @_ZN11parent_test3fooEv
-.Lfunc_begin1:
-	.cfi_startproc
-# %bb.0:                                # %entry
-	pushq	%rbp
-	.cfi_def_cfa_offset 16
-	.cfi_offset %rbp, -16
-	movq	%rsp, %rbp
-	.cfi_def_cfa_register %rbp
-.Ltmp2:
-	movl	$25, %eax
-	popq	%rbp
-	.cfi_def_cfa %rsp, 8
-	retq
-.Ltmp3:
-.Lfunc_end1:
-	.size	_ZN11parent_test3fooEv, .Lfunc_end1-_ZN11parent_test3fooEv
-	.cfi_endproc
-                                        # -- End function
-	.section	.debug_abbrev,"", at progbits
-	.byte	0                               # EOM(1)
-	.byte	0                               # EOM(2)
-	.byte	0                               # EOM(3)
-	.section	.debug_info,"", at progbits
-.Lcu_begin0:
-	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
-.Ldebug_info_start0:
-	.short	5                               # DWARF version number
-	.byte	1                               # DWARF Unit Type
-	.byte	8                               # Address Size (in bytes)
-	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-.Ldebug_info_end0:
-	.section	.debug_str_offsets,"", at progbits
-	.long	56                              # Length of String Offsets Set
-	.short	5
-	.short	0
-.Lstr_offsets_base0:
-	.section	.debug_str,"MS", at progbits,1
-.Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
-.Linfo_string1:
-	.asciz	"debug-names-parent-idx-2.cpp"  # string offset=104
-.Linfo_string2:
-	.asciz	"parent-idx-test"               # string offset=133
-.Linfo_string3:
-	.asciz	"int"                           # string offset=149
-.Linfo_string4:
-	.asciz	"foo"                           # string offset=153
-.Linfo_string5:
-	.asciz	"_Z3foov"                       # string offset=157
-.Linfo_string6:
-	.asciz	"parent_test"                   # string offset=165
-.Linfo_string7:
-	.asciz	"_ZN11parent_test3fooEv"        # string offset=177
-.Linfo_string8:
-	.asciz	"struct2"                       # string offset=200
-.Linfo_string9:
-	.asciz	"x"                             # string offset=208
-.Linfo_string10:
-	.asciz	"y"                             # string offset=210
-.Linfo_string11:
-	.asciz	"char"                          # string offset=212
-.Linfo_string12:
-	.asciz	"foo_ptr"                       # string offset=217
-.Laddr_table_base0:
-	.quad	.Lfunc_begin0
-	.quad	.Lfunc_begin1
-.Ldebug_addr_end0:
-	.section	.debug_names,"", at progbits
-	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
-.Lnames_start0:
-	.short	5                               # Header: version
-	.short	0                               # Header: padding
-	.long	1                               # Header: compilation unit count
-	.long	0                               # Header: local type unit count
-	.long	0                               # Header: foreign type unit count
-	.long	6                               # Header: bucket count
-	.long	6                               # Header: name count
-	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
-	.long	8                               # Header: augmentation string size
-	.ascii	"LLVM0700"                      # Header: augmentation string
-	.long	.Lcu_begin0                     # Compilation unit 0
-	.long	0                               # Bucket 0
-	.long	1                               # Bucket 1
-	.long	3                               # Bucket 2
-	.long	5                               # Bucket 3
-	.long	0                               # Bucket 4
-	.long	6                               # Bucket 5
-	.long	-1451972055                     # Hash in Bucket 1
-	.long	-1257882357                     # Hash in Bucket 1
-	.long	175265198                       # Hash in Bucket 2
-	.long	193495088                       # Hash in Bucket 2
-	.long	193491849                       # Hash in Bucket 3
-	.long	2090147939                      # Hash in Bucket 5
-	.long	.Linfo_string7                  # String in Bucket 1: _ZN11parent_test3fooEv
-	.long	.Linfo_string5                  # String in Bucket 1: _Z3foov
-	.long	.Linfo_string6                  # String in Bucket 2: parent_test
-	.long	.Linfo_string3                  # String in Bucket 2: int
-	.long	.Linfo_string4                  # String in Bucket 3: foo
-	.long	.Linfo_string11                 # String in Bucket 5: char
-	.long	.Lnames4-.Lnames_entries0       # Offset in Bucket 1
-	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
-	.long	.Lnames3-.Lnames_entries0       # Offset in Bucket 2
-	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 2
-	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 3
-	.long	.Lnames5-.Lnames_entries0       # Offset in Bucket 5
-.Lnames_abbrev_start0:
-	.byte	1                               # Abbrev code
-	.byte	46                              # DW_TAG_subprogram
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	19                              # DW_FORM_ref4
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	2                               # Abbrev code
-	.byte	46                              # DW_TAG_subprogram
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	3                               # Abbrev code
-	.byte	57                              # DW_TAG_namespace
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	4                               # Abbrev code
-	.byte	36                              # DW_TAG_base_type
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	5                               # Abbrev code
-	.byte	19                              # DW_TAG_structure_type
-	.byte	3                               # DW_IDX_die_offset
-	.byte	19                              # DW_FORM_ref4
-	.byte	4                               # DW_IDX_parent
-	.byte	25                              # DW_FORM_flag_present
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev
-	.byte	0                               # End of abbrev list
-.Lnames_abbrev_end0:
-.Lnames_entries0:
-.Lnames4:
-.L3:
-	.byte	1                               # Abbreviation code
-	.long	69                              # DW_IDX_die_offset
-	.long	.L5-.Lnames_entries0            # DW_IDX_parent
-	.byte	0                               # End of list: _ZN11parent_test3fooEv
-.Lnames2:
-.L0:
-	.byte	2                               # Abbreviation code
-	.long	39                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: _Z3foov
-.Lnames3:
-.L5:
-	.byte	3                               # Abbreviation code
-	.long	67                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: parent_test
-.Lnames0:
-.L2:
-	.byte	4                               # Abbreviation code
-	.long	35                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: int
-.Lnames1:
-	.byte	2                               # Abbreviation code
-	.long	39                              # DW_IDX_die_offset
-	.byte	1                               # DW_IDX_parent
-                                        # Abbreviation code
-	.long	69                              # DW_IDX_die_offset
-	.long	.L5-.Lnames_entries0            # DW_IDX_parent
-.L4:
-	.byte	5                               # Abbreviation code
-	.long	86                              # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: foo
-.Lnames5:
-.L1:
-	.byte	4                               # Abbreviation code
-	.long	120                             # DW_IDX_die_offset
-	.byte	0                               # DW_IDX_parent
-                                        # End of list: char
-	.p2align	2, 0x0
-.Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
-	.section	".note.GNU-stack","", at progbits
-	.addrsig
-	.section	.debug_line,"", at progbits
-.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-bad-aug-string.s b/lld/test/ELF/debug-names-bad-aug-string.s
index 0c4f625fad7c18..bf46f4ccef03db 100644
--- a/lld/test/ELF/debug-names-bad-aug-string.s
+++ b/lld/test/ELF/debug-names-bad-aug-string.s
@@ -2,12 +2,17 @@
 // editing the 'Header: augmentation string' in the .debug_names section.
 
 // REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
-// RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+// RUN: rm -rf %t && split-file %s %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-bad-aug-string.s \
+// RUN:     -o %t/debug-names-bad-aug-string.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-2.s \
+// RUN:     -o %t/debug-names-2.o
+// RUN: ld.lld --debug-names %t/debug-names-bad-aug-string.o \
+// RUN:     %t/debug-names-2.o -o %t/debug-names-bad-aug-string
 
-// RUN: llvm-dwarfdump -debug-names %t \
-// RUN:   | FileCheck -DFILE=%t1.o -DFILE=%t2.o %s --check-prefix=DWARF
+// RUN: llvm-dwarfdump -debug-names %t/debug-names-bad-aug-string \
+// RUN:   | FileCheck -DFILE=%t/debug-names-bad-aug-string.o \
+// RUN:     -DFILE=%t/debug-names-2.o %s --check-prefix=DWARF
 
 // DWARF:      .debug_names contents:
 // DWARF:      Name Index @ 0x0 {
@@ -25,6 +30,8 @@
 // DWARF:        Compilation Unit offsets [
 // DWARF-NEXT:     CU[0]: 0x00000000
 // DWARF-NEXT:     CU[1]: 0x0000000c
+	
+#--- debug-names-bad-aug-string.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -151,3 +158,155 @@ _Z2f12t1:                               # @_Z2f12t1
 	.addrsig
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
+
+#--- debug-names-2.s
+// input file: debug-names-2.cpp
+// Generated with:
+// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+//     -S debug-names-2.cpp -o debug-names-2.s
+
+// debug-names-2.cpp contents:
+
+// struct t1 { };
+// int main() {
+//   t1 v1;
+// }
+//
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	32                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names-2.cpp"             # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=122
+.Linfo_string3:
+	.asciz	"main"                          # string offset=139
+.Linfo_string4:
+	.asciz	"int"                           # string offset=144
+.Linfo_string5:
+	.asciz	"v1"                            # string offset=148
+.Linfo_string6:
+	.asciz	"t1"                            # string offset=151
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863786                         # Hash in Bucket 1
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	.Linfo_string6                  # String in Bucket 1: t1
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames2:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	66                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames0:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	3                               # Abbreviation code
+	.long	62                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-bad-version.s b/lld/test/ELF/debug-names-bad-version.s
index 6a299805ca090f..eda1eaa03039bf 100644
--- a/lld/test/ELF/debug-names-bad-version.s
+++ b/lld/test/ELF/debug-names-bad-version.s
@@ -3,12 +3,17 @@
 // 5 to 4).
 	
 // REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
-// RUN: not ld.lld --debug-names %t1.o %t2.o -o /dev/null 2>&1 | FileCheck %s
+// RUN: rm -rf %t && split-file %s %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-bad-version.s \
+// RUN:     -o %t/debug-names-bad-version.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-2.s \
+// RUN:     -o %t/debug-names-2.o
+// RUN: not ld.lld --debug-names %t/debug-names-bad-version.o \
+// RUN:     %t/debug-names-2.o -o /dev/null 2>&1 | FileCheck %s
 
 // CHECK: error: {{.*}}:(.debug_names): unsupported version
-
+	
+#--- debug-names-bad-version.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -170,3 +175,155 @@ _Z2f12t1:                               # @_Z2f12t1
 	.addrsig
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
+
+#--- debug-names-2.s
+// input file: debug-names-2.cpp
+// Generated with:
+// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+//     -S debug-names-2.cpp -o debug-names-2.s
+
+// debug-names-2.cpp contents:
+
+// struct t1 { };
+// int main() {
+//   t1 v1;
+// }
+//
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	32                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names-2.cpp"             # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=122
+.Linfo_string3:
+	.asciz	"main"                          # string offset=139
+.Linfo_string4:
+	.asciz	"int"                           # string offset=144
+.Linfo_string5:
+	.asciz	"v1"                            # string offset=148
+.Linfo_string6:
+	.asciz	"t1"                            # string offset=151
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863786                         # Hash in Bucket 1
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	.Linfo_string6                  # String in Bucket 1: t1
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames2:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	66                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames0:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	3                               # Abbreviation code
+	.long	62                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-parent-idx.s b/lld/test/ELF/debug-names-parent-idx.s
index cda9203fd21670..b44455bb498ef8 100644
--- a/lld/test/ELF/debug-names-parent-idx.s
+++ b/lld/test/ELF/debug-names-parent-idx.s
@@ -1,4 +1,4 @@
-// Generated with:
+// debug-names-parent-idx.s generated with:
 
 // - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
 //     -S debug-names-parent-idx.cpp -o debug-names-parent-idx.s
@@ -35,12 +35,17 @@
 // }
 
 // REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-parent-idx-2.s -o %t2.o
-// RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+// RUN: rm -rf %t && split-file %s %t 
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-parent-idx.s \
+// RUN:     -o %t/debug-names-parent-idx.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-parent-idx-2.s \
+// RUN:     -o %t/debug-names-parent-idx-2.o
+// RUN: ld.lld --debug-names %t/debug-names-parent-idx.o \
+// RUN:     %t/debug-names-parent-idx-2.o -o %t/debug-names-parent-idx
 
-// RUN: llvm-dwarfdump -debug-names %t \
-// RUN:    | FileCheck -DFILE=%t1.o -DFILE=%t2.o %s --check-prefix=DWARF
+// RUN: llvm-dwarfdump -debug-names %t/debug-names-parent-idx \
+// RUN:    | FileCheck -DFILE=%t/debug-names-parent-idx.o \
+// RUN:      -DFILE=%t/debug-names-parent-idx-2.o %s --check-prefix=DWARF
 
 // DWARF:      .debug_names contents:
 // DWARF:      Name Index @ 0x0 {
@@ -183,6 +188,7 @@
 // DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
 // DWARF-NEXT:         DW_IDX_compile_unit: 0x01
 
+#--- debug-names-parent-idx.s
 	.text
 	.globl	_Z3barR3fooi                    # -- Begin function _Z3barR3fooi
 	.p2align	4, 0x90
@@ -417,3 +423,271 @@ main:                                   # @main
 	.addrsig_sym _ZN11parent_test3fooEv
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
+	
+#--- debug-names-parent-idx-2.s
+// Generated with:
+
+// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
+//     -S debug-names-parent-idx-2.cpp -o debug-names-parent-idx-2.s
+
+// foo.h contents:
+
+// int foo();
+
+//struct foo {
+//   int x;
+//   char y;
+//   struct foo *foo_ptr;
+// };
+
+// namespace parent_test {
+//   int foo();
+// }
+
+// debug-names-parent-index-2.cpp contents:
+
+// #include "foo.h"
+// int foo () {
+//   struct foo struct2;
+//   struct2.x = 1024;
+//   struct2.y = 'r';
+//   struct2.foo_ptr = nullptr;
+//   return struct2.x * (int) struct2.y;
+// }
+
+// namespace parent_test {
+// int foo () {
+//   return 25;
+// }
+// }
+
+	.text
+	.globl	_Z3foov                         # -- Begin function _Z3foov
+	.p2align	4, 0x90
+	.type	_Z3foov, at function
+_Z3foov:                                # @_Z3foov
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	movl	$1024, -16(%rbp)                # imm = 0x400
+	movb	$114, -12(%rbp)
+	movq	$0, -8(%rbp)
+	movl	-16(%rbp), %eax
+	movsbl	-12(%rbp), %ecx
+	imull	%ecx, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z3foov, .Lfunc_end0-_Z3foov
+	.cfi_endproc
+                                        # -- End function
+	.globl	_ZN11parent_test3fooEv          # -- Begin function _ZN11parent_test3fooEv
+	.p2align	4, 0x90
+	.type	_ZN11parent_test3fooEv, at function
+_ZN11parent_test3fooEv:                 # @_ZN11parent_test3fooEv
+.Lfunc_begin1:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp2:
+	movl	$25, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp3:
+.Lfunc_end1:
+	.size	_ZN11parent_test3fooEv, .Lfunc_end1-_ZN11parent_test3fooEv
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	56                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names-parent-idx-2.cpp"  # string offset=104
+.Linfo_string2:
+	.asciz	"parent-idx-test"               # string offset=133
+.Linfo_string3:
+	.asciz	"int"                           # string offset=149
+.Linfo_string4:
+	.asciz	"foo"                           # string offset=153
+.Linfo_string5:
+	.asciz	"_Z3foov"                       # string offset=157
+.Linfo_string6:
+	.asciz	"parent_test"                   # string offset=165
+.Linfo_string7:
+	.asciz	"_ZN11parent_test3fooEv"        # string offset=177
+.Linfo_string8:
+	.asciz	"struct2"                       # string offset=200
+.Linfo_string9:
+	.asciz	"x"                             # string offset=208
+.Linfo_string10:
+	.asciz	"y"                             # string offset=210
+.Linfo_string11:
+	.asciz	"char"                          # string offset=212
+.Linfo_string12:
+	.asciz	"foo_ptr"                       # string offset=217
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+	.quad	.Lfunc_begin1
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	6                               # Header: bucket count
+	.long	6                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5                               # Bucket 3
+	.long	0                               # Bucket 4
+	.long	6                               # Bucket 5
+	.long	-1451972055                     # Hash in Bucket 1
+	.long	-1257882357                     # Hash in Bucket 1
+	.long	175265198                       # Hash in Bucket 2
+	.long	193495088                       # Hash in Bucket 2
+	.long	193491849                       # Hash in Bucket 3
+	.long	2090147939                      # Hash in Bucket 5
+	.long	.Linfo_string7                  # String in Bucket 1: _ZN11parent_test3fooEv
+	.long	.Linfo_string5                  # String in Bucket 1: _Z3foov
+	.long	.Linfo_string6                  # String in Bucket 2: parent_test
+	.long	.Linfo_string3                  # String in Bucket 2: int
+	.long	.Linfo_string4                  # String in Bucket 3: foo
+	.long	.Linfo_string11                 # String in Bucket 5: char
+	.long	.Lnames4-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames3-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 3
+	.long	.Lnames5-.Lnames_entries0       # Offset in Bucket 5
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	19                              # DW_FORM_ref4
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	57                              # DW_TAG_namespace
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	4                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	5                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames4:
+.L3:
+	.byte	1                               # Abbreviation code
+	.long	69                              # DW_IDX_die_offset
+	.long	.L5-.Lnames_entries0            # DW_IDX_parent
+	.byte	0                               # End of list: _ZN11parent_test3fooEv
+.Lnames2:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	39                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z3foov
+.Lnames3:
+.L5:
+	.byte	3                               # Abbreviation code
+	.long	67                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: parent_test
+.Lnames0:
+.L2:
+	.byte	4                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames1:
+	.byte	2                               # Abbreviation code
+	.long	39                              # DW_IDX_die_offset
+	.byte	1                               # DW_IDX_parent
+                                        # Abbreviation code
+	.long	69                              # DW_IDX_die_offset
+	.long	.L5-.Lnames_entries0            # DW_IDX_parent
+.L4:
+	.byte	5                               # Abbreviation code
+	.long	86                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: foo
+.Lnames5:
+.L1:
+	.byte	4                               # Abbreviation code
+	.long	120                             # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names.s b/lld/test/ELF/debug-names.s
index ca6d32998542b5..baadadd98ebf4f 100644
--- a/lld/test/ELF/debug-names.s
+++ b/lld/test/ELF/debug-names.s
@@ -1,4 +1,4 @@
-// Generated with:
+// debug_names.s was gGenerated with:
 
 // - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
 //     -S debug-names.cpp -o debug-names.s
@@ -9,19 +9,27 @@
 // void f1(t1) { }
 
 // REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %p/Inputs/debug-names-2.s -o %t2.o
+// RUN: rm -rf %t && split-file %s %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names.s \
+// RUN:     -o %t/debug-names.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-2.s \
+// RUN:     -o %t/debug-names-2.o
 
-// RUN: ld.lld --debug-names --no-debug-names %t1.o %t2.o -o %t
-// RUN: llvm-readelf -SW %t | FileCheck %s --check-prefix=NO_DBG_NAMES
+// RUN: ld.lld --debug-names --no-debug-names %t/debug-names.o \
+// RUN:     %t/debug-names-2.o -o %t/debug-names
+// RUN: llvm-readelf -SW %t/debug-names \
+// RUN:     | FileCheck %s --check-prefix=NO_DBG_NAMES
 	
 // NO_DBG_NAMES: .debug_names  PROGBITS  0000000000000000 [[#%x,]] 000110
 	
-// RUN: ld.lld --debug-names %t1.o %t2.o -o %t
+// RUN: ld.lld --debug-names %t/debug-names.o %t/debug-names-2.o \
+// RUN:     -o %t/debug-names
 
-// RUN: llvm-dwarfdump -debug-names %t | FileCheck %s --check-prefix=DWARF
-// RUN: llvm-readelf -SW %t \
-// RUN:    | FileCheck -DFILE=%t1.o -DFILE=%t2.o %s --check-prefix=READELF
+// RUN: llvm-dwarfdump -debug-names %t/debug-names \
+// RUN:     | FileCheck %s --check-prefix=DWARF
+// RUN: llvm-readelf -SW %t/debug-names \
+// RUN:    | FileCheck -DFILE=%t/debug-names.o \
+// RUN:      -DFILE=%t/debug-names-2.o %s --check-prefix=READELF
 
 // READELF: .debug_names PROGBITS 0000000000000000 [[#%x,]] 0000d0
 
@@ -105,6 +113,7 @@
 // DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
 // DWARF-NEXT:         DW_IDX_compile_unit: 0x01
 
+#--- debug-names.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -231,3 +240,154 @@ _Z2f12t1:                               # @_Z2f12t1
 	.addrsig
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
+
+#--- debug-names-2.s
+// Generated with:
+// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+//     -S debug-names-2.cpp -o debug-names-2.s
+
+// debug-names-2.cpp contents:
+
+// struct t1 { };
+// int main() {
+//   t1 v1;
+// }
+//
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	32                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+.Linfo_string1:
+	.asciz	"debug-names-2.cpp"             # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=122
+.Linfo_string3:
+	.asciz	"main"                          # string offset=139
+.Linfo_string4:
+	.asciz	"int"                           # string offset=144
+.Linfo_string5:
+	.asciz	"v1"                            # string offset=148
+.Linfo_string6:
+	.asciz	"t1"                            # string offset=151
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863786                         # Hash in Bucket 1
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	.Linfo_string6                  # String in Bucket 1: t1
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames2:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	66                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames0:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	3                               # Abbreviation code
+	.long	62                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:

>From e4442221c8c8197e5970b92fc86c8cf7517f319b Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 7 Apr 2024 12:41:58 -0700
Subject: [PATCH 14/23] Simplify and optimize .debug_names and removed dead TU
 code

[ELF] Add --debug-names to create merged .debug_names

`clang -g -gpubnames` (with optional -gsplit-dwarf) creates the
`.debug_names` section ("per-CU" index). By default lld concatenates
input `.debug_names` sections into an output `.debug_names` section.
LLDB can consume the concatenated section but the lookup performance is
not good.

This patch adds --debug-names to create a per-module index by combining
the per-CU indexes into a single index that covers the entire load
module. The produced `.debug_names` is a replacement for `.gdb_index`.

Type units (-fdebug-types-section) are not handled yet.

Co-authored-by: Fangrui Song <i at maskray.me>
---
 lld/ELF/SyntheticSections.cpp                 | 1211 +++++++----------
 lld/ELF/SyntheticSections.h                   |  160 +--
 lld/ELF/Writer.cpp                            |    1 +
 lld/docs/ReleaseNotes.rst                     |    2 +
 lld/test/ELF/debug-names-bad-aug-string.s     |   78 +-
 lld/test/ELF/debug-names-bad-die-idx-sizes.s  |   25 +-
 lld/test/ELF/debug-names-bad-name-count.s     |   30 +-
 lld/test/ELF/debug-names-bad-offsets-sizes.s  |   28 +-
 lld/test/ELF/debug-names-bad-version.s        |   45 +-
 lld/test/ELF/debug-names-dwarf64.s            |   20 +-
 .../ELF/debug-names-invalid-abbrev-code.s     |   23 +-
 .../ELF/debug-names-invalid-attribute-2.s     |   24 +-
 .../ELF/debug-names-invalid-attribute-3.s     |   28 +-
 lld/test/ELF/debug-names-invalid-attribute.s  |   14 +-
 lld/test/ELF/debug-names-invalid-parent-idx.s |   27 +-
 lld/test/ELF/debug-names-parent-idx.s         |  468 ++++---
 lld/test/ELF/debug-names.s                    |  251 ++--
 lld/test/ELF/driver.test                      |    3 +-
 18 files changed, 1171 insertions(+), 1267 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index c87b29e34f69de..be307f1b001f31 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -14,7 +14,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "SyntheticSections.h"
-
 #include "Config.h"
 #include "DWARF.h"
 #include "EhFrame.h"
@@ -31,6 +30,7 @@
 #include "lld/Common/Strings.h"
 #include "lld/Common/Version.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Sequence.h"
 #include "llvm/ADT/SetOperations.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/BinaryFormat/Dwarf.h"
@@ -2714,754 +2714,584 @@ static uint32_t computeGdbHash(StringRef s) {
   return h;
 }
 
-template <class ELFT>
-DebugNamesSection<ELFT>::DebugNamesSection()
-    : SyntheticSection(0, SHT_PROGBITS, 1, ".debug_names") {}
-
-template <class ELFT>
-template <class RelTy>
-void DebugNamesSection<ELFT>::getNameRelocsImpl(
-    InputSection *sec, ArrayRef<RelTy> rels,
-    DenseMap<uint32_t, uint32_t> &relocs) {
-  for (auto &rel : rels) {
-    Symbol &sym = sec->getFile<ELFT>()->getRelocTargetSym(rel);
-    relocs[rel.r_offset] = sym.getVA(getAddend<ELFT>(rel));
-  }
-}
-
-template <class ELFT>
-void DebugNamesSection<ELFT>::getNameRelocs(
-    InputSectionBase *base, DenseMap<uint32_t, uint32_t> &relocs) {
-  auto *sec = cast<InputSection>(base);
-  const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>();
-  if (rels.areRelocsRel())
-    getNameRelocsImpl(sec, rels.rels, relocs);
-  else
-    getNameRelocsImpl(sec, rels.relas, relocs);
-}
-
-template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
-  SmallVector<uint32_t, 0> mergedCuOffsets;
-  SmallVector<uint32_t, 0> mergedTuOffsets;
-  DenseMap<uint32_t, uint32_t> strOffsets;
-  SmallVector<DenseMap<uint32_t, uint32_t>, 0> chunksRelocs;
-  chunksRelocs.reserve(numChunks);
-
-  for (size_t i = 0, e = numChunks; i != e; ++i) {
-    DebugNamesOutputChunk &chunk = outputChunks[i];
-    InputSectionBase *base = inputDebugNamesSections[i];
-    DenseMap<uint32_t, uint32_t> &relocs = chunksRelocs.emplace_back();
-    getNameRelocs(base, relocs);
-
-    // Update CuOffsets list with new data
-    for (uint32_t cuOffset : chunk.compilationUnits)
-      mergedCuOffsets.push_back(chunk.sec->outSecOff + cuOffset);
-
-    // TODO: Update TuOffsets list with new data
-  }
-
-  // Update the entries with the relocated string offsets.
-  for (NamedEntry &stringEntry : mergedEntries) {
-    uint32_t oldOffset = stringEntry.stringOffsetOffset;
-    uint32_t idx = stringEntry.chunkIdx;
-    stringEntry.relocatedEntryOffset = chunksRelocs[idx][oldOffset];
-  }
-
-  // Write out bytes for merged section.
-
-  // Write the header.
-  endian::write32<ELFT::Endianness>(buf + 0, mergedHdr.UnitLength);
-  endian::write16<ELFT::Endianness>(buf + 4, mergedHdr.Version);
-  endian::write32<ELFT::Endianness>(buf + 8, mergedHdr.CompUnitCount);
-  endian::write32<ELFT::Endianness>(buf + 12, mergedHdr.LocalTypeUnitCount);
-  endian::write32<ELFT::Endianness>(buf + 16, mergedHdr.ForeignTypeUnitCount);
-  endian::write32<ELFT::Endianness>(buf + 20, mergedHdr.BucketCount);
-  endian::write32<ELFT::Endianness>(buf + 24, mergedHdr.NameCount);
-  endian::write32<ELFT::Endianness>(buf + 28, mergedHdr.AbbrevTableSize);
-  endian::write32<ELFT::Endianness>(buf + 32, mergedHdr.AugmentationStringSize);
-  buf += 36;
-  memcpy(buf, mergedHdr.AugmentationString.c_str(), 8);
-  buf += 8;
-
-  // Write the CU list.
-  for (uint32_t offset : mergedCuOffsets) {
-    endian::write32<ELFT::Endianness>(buf + 0, offset);
-    buf += 4;
-  }
-
-  // Write the local TU list.
-  // TODO: Fix this, once we get everything working without TUs.
-  if (mergedHdr.LocalTypeUnitCount != 0)
-    warn(".debug_names: type units are not handled in merged index");
-
-  // Write the foreign TU list.
-  // TODO: Fix this, once we get everything working without TUs.
-  if (mergedHdr.ForeignTypeUnitCount != 0)
-    warn(".debug_names: type units are not handled in merged index");
-
-  // Write the hash table.
-  // ... Write the buckets
-  uint32_t idx = 1;
-  for (const SmallVector<NamedEntry *, 0> &bucket : bucketList) {
-    if (!bucket.empty())
-      endian::write32<ELFT::Endianness>(buf + 0, idx);
-    idx += bucket.size();
-    buf += 4;
-  }
-
-  // ...Write the hashes
-  for (const auto &bucket : bucketList) {
-    for (const auto &entry : bucket) {
-      uint32_t hashValue = entry->hashValue;
-      endian::write32<ELFT::Endianness>(buf + 0, hashValue);
-      buf += 4;
-    }
-  }
-
-  // Write the string offsets.
-  for (const NamedEntry &entry : mergedEntries) {
-    endian::write32<ELFT::Endianness>(buf + 0, entry.relocatedEntryOffset);
-    buf += 4;
-  }
-
-  // Write the entry offsets.
-  for (const auto &entry : mergedEntries) {
-    endian::write32<ELFT::Endianness>(buf + 0, entry.entryOffset);
-    buf += 4;
-  }
-
-  // Write the abbrev table.
-  for (const Abbrev *abbrev : mergedAbbrevTable) {
-    buf += encodeULEB128(abbrev->code, buf);
-    buf += encodeULEB128(abbrev->tag, buf);
-    for (DWARFDebugNames::AttributeEncoding attr : abbrev->attributes) {
-      buf += encodeULEB128(attr.Index, buf);
-      buf += encodeULEB128(attr.Form, buf);
-    }
-    endian::write16<ELFT::Endianness>(buf + 0, 0); // attribute sentinels.
-    buf += 2;
-  }
-  *buf++ = 0; // abbrev table sentinel
-
-  // Write the entry pool.
-  for (const auto &stringEntry : mergedEntries) {
-    // Write all the entries for the string.
-    for (const std::unique_ptr<IndexEntry> &entry : stringEntry.indexEntries) {
-      buf += encodeULEB128(entry->abbrevCode, buf);
-      for (const auto &value : entry->attrValues) {
-        endian::write32<ELFT::Endianness>(buf + 0, value.attrValue);
-        buf += value.attrSize;
-      }
-    }
-    *buf++ = 0; // Entry sentinel
-  }
-}
-
-template <class ELFT> bool DebugNamesSection<ELFT>::isNeeded() const {
-  return numChunks > 0;
-}
-
-template <class ELFT>
-static void readCompileUnitOffsets(
-    typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
-    typename DebugNamesSection<ELFT>::DebugNamesOutputChunk &outputChunk,
-    DWARFDataExtractor &namesExtractor) {
-  uint64_t offset = secData.locs.CUsBase;
-  uint64_t *offsetPtr = &offset;
-  outputChunk.compilationUnits.resize(secData.hdr.CompUnitCount);
-  uint32_t *bufferPtr =
-      namesExtractor.getU32(offsetPtr, outputChunk.compilationUnits.begin(),
-                            secData.hdr.CompUnitCount);
-  if (!bufferPtr)
-    errorOrWarn(toString(outputChunk.sec) +
-                Twine(": error while reading CU offsets"));
-}
-
-template <class ELFT>
-static void readEntryOffsets(
-    typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
-    DWARFDataExtractor &namesExtractor) {
-  secData.entryOffsets.resize(secData.hdr.NameCount);
-  uint64_t offset = secData.locs.EntryOffsetsBase;
-  uint64_t *offsetPtr = &offset;
-  uint32_t *bufferPtr = namesExtractor.getU32(
-      offsetPtr, secData.entryOffsets.begin(), secData.hdr.NameCount);
-  if (!bufferPtr)
-    errorOrWarn(Twine(": error while reading entry offsets"));
-}
-
-template <class ELFT>
-static void readAttributeValues(
-    SmallVector<typename DebugNamesSection<ELFT>::AttrValueData, 3> &values,
-    typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
-    uint64_t &offset,
-    typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
-    int32_t &parentOffset, DWARFDataExtractor &namesExtractor,
-    const DWARFDebugNames::Abbrev &abbrev) {
-  const LLDDWARFSection &namesSection = *chunk.namesSection;
-  uint64_t *offsetPtr = &offset;
-  typename DebugNamesSection<ELFT>::AttrValueData cuOrTuAttr = {0, 0};
-  for (DWARFDebugNames::AttributeEncoding attr : abbrev.Attributes) {
-    Error err = Error::success();
-    typename DebugNamesSection<ELFT>::AttrValueData newAttr;
-    uint32_t value;
-    if (attr.Index == DW_IDX_parent && attr.Form != DW_FORM_flag_present &&
-        attr.Form != DW_FORM_ref4)
-      errorOrWarn(toString(namesSection.sec) +
-                  Twine(": invalid form for DW_IDX_parent"));
-    switch (attr.Form) {
-    case DW_FORM_flag_present: {
-      // Currently only DW_IDX_parent attributes (in .debug_names) can
-      // have this form. This form does not have a real value (nothing is
-      // emitted for it).
-      if (attr.Index != DW_IDX_parent)
-        errorOrWarn(toString(namesSection.sec) +
-                    Twine(": invalid form for attribute"));
-      break;
-    }
-    case DW_FORM_data1:
-    case DW_FORM_ref1: {
-      newAttr.attrValue = namesExtractor.getU8(offsetPtr, &err);
-      newAttr.attrSize = 1;
-      break;
-    }
-    case DW_FORM_data2:
-    case DW_FORM_ref2: {
-      value = namesExtractor.getU16(offsetPtr, &err);
-      newAttr.attrValue = value;
-      newAttr.attrSize = 2;
-      break;
-    }
-    case DW_FORM_data4:
-    case DW_FORM_ref4: {
-      value = namesExtractor.getU32(offsetPtr, &err);
-      newAttr.attrValue = value;
-      newAttr.attrSize = 4;
-      if (attr.Index == dwarf::DW_IDX_parent)
-        parentOffset = value + secData.locs.EntriesBase;
-      break;
-    }
-    case DW_FORM_data8:
-    case DW_FORM_ref8:
-    case DW_FORM_ref_sig8: {
-      value = namesExtractor.getU64(offsetPtr, &err);
-      newAttr.attrValue = value;
-      newAttr.attrSize = 8;
-      break;
+// 4-byte alignment ensures that values in the hash lookup table and the name
+// table are aligned.
+DebugNamesBaseSection::DebugNamesBaseSection()
+    : SyntheticSection(0, SHT_PROGBITS, 4, ".debug_names") {}
+
+// Get the size of the .debug_names section header in bytes for DWARF32:
+static uint32_t getDebugNamesHeaderSize(uint32_t augmentationStringSize) {
+  return /* unit length */ 4 +
+         /* version */ 2 +
+         /* padding */ 2 +
+         /* CU count */ 4 +
+         /* TU count */ 4 +
+         /* Foreign TU count */ 4 +
+         /* Bucket Count */ 4 +
+         /* Name Count */ 4 +
+         /* Abbrev table size */ 4 +
+         /* Augmentation string size */ 4 +
+         /* Augmentation string */ augmentationStringSize;
+}
+
+void DebugNamesBaseSection::parseDebugNames(
+    InputChunk &inputChunk, OutputChunk &chunk,
+    DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor,
+    function_ref<SmallVector<uint32_t, 0>(
+        const DWARFDebugNames::Header &,
+        const DWARFDebugNames::DWARFDebugNamesOffsets &)>
+        readOffsets) {
+  const LLDDWARFSection namesSec = inputChunk.section;
+  DenseMap<uint32_t, IndexEntry *> offsetMap;
+  for (const DWARFDebugNames::NameIndex &ni : *inputChunk.llvmDebugNames) {
+    NameData &nd = inputChunk.nameData.emplace_back();
+    nd.hdr = ni.getHeader();
+    if (nd.hdr.Format != DwarfFormat::DWARF32) {
+      errorOrWarn(toString(namesSec.sec) + Twine(": unsupported DWARF64"));
+      return;
     }
-    default: {
-      errorOrWarn(toString(namesSection.sec) +
-                  Twine(": unrecognized form encoding ") + Twine(attr.Form) +
-                  Twine(" in .debug_names abbrev table"));
-      break;
+    if (nd.hdr.Version != 5) {
+      errorOrWarn(toString(namesSec.sec) + Twine(": unsupported version ") +
+                  Twine(nd.hdr.Version));
+      return;
     }
+    const uint32_t dwarfSize =
+        dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
+    const uint32_t hdrSize =
+        getDebugNamesHeaderSize(nd.hdr.AugmentationStringSize);
+    auto locs = findDebugNamesOffsets(hdrSize, nd.hdr);
+    if (locs.EntriesBase > namesExtractor.getData().size()) {
+      errorOrWarn(toString(namesSec.sec) +
+                  Twine(": index entry is out of bounds"));
+      return;
     }
-    if (err)
-      errorOrWarn(toString(namesSection.sec) +
-                  Twine(": error while reading attributes: ") +
-                  toString(std::move(err)));
-    if (attr.Index == DW_IDX_compile_unit)
-      // Save it to put it at the end of the attributes list.
-      cuOrTuAttr = newAttr;
-    else if (attr.Form != DW_FORM_flag_present)
-      values.push_back(newAttr);
-  }
 
-  // Make sure the CU or TU index attribute is the last one in the list.
-  values.push_back(cuOrTuAttr);
-}
+    SmallVector<uint32_t, 0> entryOffsets = readOffsets(nd.hdr, locs);
+
+    // Read the entry pool.
+    offsetMap.clear();
+    nd.nameEntries.resize(nd.hdr.NameCount);
+    for (auto i : seq(nd.hdr.NameCount)) {
+      NameEntry &ne = nd.nameEntries[i];
+      uint64_t strOffset = locs.StringOffsetsBase + i * dwarfSize;
+      ne.stringOffset = strOffset;
+      uint64_t strp = namesExtractor.getRelocatedValue(dwarfSize, &strOffset);
+      StringRef name = strExtractor.getCStrRef(&strp);
+      ne.name = name.data();
+      ne.hashValue = caseFoldingDjbHash(name);
+
+      // Read a series of index entries that end with abbreviation code 0.
+      const char *errMsg = nullptr;
+      uint64_t offset = locs.EntriesBase + entryOffsets[i];
+      while (offset < namesSec.Data.size() && namesSec.Data[offset] != 0) {
+        auto ie = makeThreadLocal<IndexEntry>();
+        ie->poolOffset = offset;
+        Error err = Error::success();
+        ie->abbrevCode =
+            static_cast<uint32_t>(namesExtractor.getULEB128(&offset, &err));
+        if (err) {
+          consumeError(std::move(err));
+          errMsg = ": invalid abbrev code in entry";
+          break;
+        }
+        auto it = ni.getAbbrevs().find_as(ie->abbrevCode);
+        if (it == ni.getAbbrevs().end()) {
+          errMsg = ": invalid abbrev code in entry";
+          break;
+        }
 
-template <class ELFT>
-static void
-readEntry(typename DebugNamesSection<ELFT>::NamedEntry &stringEntry,
-          typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
-          typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
-          DWARFDataExtractor &namesExtractor,
-          const DWARFDebugNames::NameIndex &ni) {
-  std::unique_ptr<LLDDWARFSection> &namesSection = chunk.namesSection;
-  uint64_t offset = stringEntry.entryOffset;
-  // Each entry ends with a zero 'sentinel' value
-  while (offset < namesSection->Data.size() &&
-         namesSection->Data[offset] != 0) {
-    // Read & store all entries (for the same string)
-    auto entry =
-        std::make_unique<typename DebugNamesSection<ELFT>::IndexEntry>();
-    entry->poolOffset = offset;
-    Error err = Error::success();
-    // This call to namesExtractor can't fail; if there were a problem with the
-    // input, it would have been caught in the call to NamesIndex::extract, in
-    // DebugNamesSection::create.
-    uint64_t ulebValue = namesExtractor.getULEB128(&offset, &err);
-    cantFail(std::move(err));
-    entry->abbrevCode = static_cast<uint32_t>(ulebValue);
-    const auto &abbrevs = ni.getAbbrevs();
-    auto abbrevIt = abbrevs.find_as(entry->abbrevCode);
-    if (abbrevIt != abbrevs.end()) {
-      const DWARFDebugNames::Abbrev &abbrev = *abbrevIt;
-      readAttributeValues<ELFT>(entry->attrValues, chunk, offset, secData,
-                                entry->parentOffset, namesExtractor, abbrev);
-      stringEntry.indexEntries.push_back(std::move(entry));
-    } else
-      errorOrWarn(toString(chunk.namesSection->sec) +
-                  Twine(": invalid abbrev code in entry"));
-  }
-  if (offset >= namesSection->Data.size())
-    errorOrWarn(
-        toString(chunk.namesSection->sec) +
-        Twine(": encountered unexpected end of section while reading entry"));
-}
+        AttrValue attr, cuAttr = {0, 0};
+        for (DWARFDebugNames::AttributeEncoding a : it->Attributes) {
+          if (a.Index == dwarf::DW_IDX_parent) {
+            if (a.Form == dwarf::DW_FORM_ref4) {
+              attr.attrValue = namesExtractor.getU32(&offset, &err);
+              attr.attrSize = 4;
+              ie->parentOffset = locs.EntriesBase + attr.attrValue;
+            } else if (a.Form != DW_FORM_flag_present) {
+              errMsg = ": invalid form for DW_IDX_parent";
+            }
+          } else {
+            switch (a.Form) {
+            case DW_FORM_data1:
+            case DW_FORM_ref1: {
+              attr.attrValue = namesExtractor.getU8(&offset, &err);
+              attr.attrSize = 1;
+              break;
+            }
+            case DW_FORM_data2:
+            case DW_FORM_ref2: {
+              attr.attrValue = namesExtractor.getU16(&offset, &err);
+              attr.attrSize = 2;
+              break;
+            }
+            case DW_FORM_data4:
+            case DW_FORM_ref4: {
+              attr.attrValue = namesExtractor.getU32(&offset, &err);
+              attr.attrSize = 4;
+              break;
+            }
+            default:
+              errorOrWarn(toString(namesSec.sec) +
+                          Twine(": unrecognized form encoding ") +
+                          Twine(a.Form) + Twine(" in abbrev table"));
+              return;
+            }
+          }
+          if (err) {
+            errorOrWarn(toString(namesSec.sec) +
+                        Twine(": error while reading attributes: ") +
+                        toString(std::move(err)));
+            return;
+          }
+          if (a.Index == DW_IDX_compile_unit)
+            cuAttr = attr;
+          else if (a.Form != DW_FORM_flag_present)
+            ie->attrValues.push_back(attr);
+        }
 
-template <class ELFT>
-static void
-readEntries(typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
-            typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
-            DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor,
-            const DWARFDebugNames::NameIndex &ni) {
-  // Temporary map from entry offsets to address (pointer) of entry with that
-  // offset; used to find parent entries quickly.
-  DenseMap<uint32_t, typename DebugNamesSection<ELFT>::IndexEntry *> offsetMap;
-  // Reserve sizes for this chunk's hashes & namedEntries.
-  chunk.hashValues.reserve(secData.hdr.NameCount);
-  secData.namedEntries.reserve(secData.hdr.NameCount);
-  // Calculate the Entry Offsets, create initial records.
-  for (uint32_t i = 0, e = secData.hdr.NameCount; i != e; ++i) {
-    // Get string value
-    typename DebugNamesSection<ELFT>::NamedEntry stringEntry;
-    stringEntry.entryOffset =
-        secData.locs.EntriesBase + secData.entryOffsets[i];
-    uint64_t strOffsetOffset =
-        secData.locs.StringOffsetsBase + i * secData.dwarfSize;
-    stringEntry.stringOffsetOffset = strOffsetOffset;
-    uint64_t strOffset =
-        namesExtractor.getRelocatedValue(secData.dwarfSize, &strOffsetOffset);
-    StringRef name = strExtractor.getCStrRef(&strOffset);
-    stringEntry.name = name.data();
-    // Calculate hash
-    stringEntry.hashValue = caseFoldingDjbHash(name);
-    chunk.hashValues.push_back(stringEntry.hashValue);
-    // Read String Entry
-    readEntry<ELFT>(stringEntry, chunk, secData, namesExtractor, ni);
-    // Add index entries & offsets to our temporary map
-    for (const auto &entry : stringEntry.indexEntries)
-      offsetMap[entry->poolOffset] = entry.get();
-    secData.namedEntries.push_back(std::move(stringEntry));
-  }
-  // Find/assign pointers to any 'real' parent entries (needed to find correct
-  // parent entry offsets in merged data).
-  for (auto &stringEntry : secData.namedEntries)
-    for (auto &entry : stringEntry.indexEntries)
-      if (entry->parentOffset != -1)
-        entry->parentEntry = offsetMap[entry->parentOffset];
-}
-
-static uint16_t computeDebugNamesHeaderSize() {
-  // Size of the .debug_names section header, in bytes, for DWARF32:
-  uint16_t size = /* unit length */ 4 +
-                  /* version */ 2 +
-                  /* padding */ 2 +
-                  /* CU count */ 4 +
-                  /* TU count */ 4 +
-                  /* Foreign TU count */ 4 +
-                  /* Bucket Count */ 4 +
-                  /* Name Count */ 4 +
-                  /* Abbrev table size */ 4 +
-                  /* Augmentation string size */ 4 +
-                  /* augmentation string */ 8;
-  return size;
-}
+        // Canonicalize abbrev by placing the CU/TU index at the end.
+        ie->attrValues.push_back(cuAttr);
+        ne.indexEntries.push_back(std::move(ie));
+      }
+      if (offset >= namesSec.Data.size())
+        errMsg = ": index entry is out of bounds";
+      if (errMsg)
+        errorOrWarn(toString(namesSec.sec) + Twine(errMsg));
 
-template <class ELFT>
-static void collectDebugNamesSectionData(
-    typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
-    typename DebugNamesSection<ELFT>::DebugNamesOutputChunk &outputChunk,
-    DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor) {
-  for (const DWARFDebugNames::NameIndex &ni : *chunk.debugNamesData) {
-    typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData =
-        chunk.sectionsData.emplace_back();
-    secData.hdr = ni.getHeader();
-    if (secData.hdr.Format != DwarfFormat::DWARF32) {
-      errorOrWarn(toString(chunk.namesSection->sec) +
-                  Twine(": unsupported DWARF64"));
-      // Don't try to continue; we can't parse DWARF64 at the moment.
-      return;
+      for (IndexEntry &ie : ne.entries())
+        offsetMap[ie.poolOffset] = &ie;
     }
-    secData.dwarfSize = dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
-    secData.hdrSize = computeDebugNamesHeaderSize();
-    if (secData.hdr.Version != 5)
-      errorOrWarn(toString(chunk.namesSection->sec) +
-                  Twine(": unsupported version"));
-    secData.locs = findDebugNamesOffsets(secData.hdrSize, secData.hdr);
-    readCompileUnitOffsets<ELFT>(secData, outputChunk, namesExtractor);
-    readEntryOffsets<ELFT>(secData, namesExtractor);
-    readEntries<ELFT>(secData, chunk, namesExtractor, strExtractor, ni);
-  }
-}
 
-template <class ELFT>
-void DebugNamesSection<ELFT>::collectMergedCounts(
-    MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
-  SmallVector<uint32_t, 0> tmpMergedCuOffsets;
-  mergedHdr.CompUnitCount = 0;
-  mergedHdr.LocalTypeUnitCount = 0;
-  mergedHdr.ForeignTypeUnitCount = 0;
-  mergedHdr.Version = 5;
-  mergedHdr.Format = DwarfFormat::DWARF32;
-  mergedHdr.AugmentationStringSize = 0;
-
-  for (size_t i = 0, e = numChunks; i != e; ++i) {
-    DebugNamesInputChunk &inputChunk = inputChunks[i];
-    DebugNamesOutputChunk &outputChunk = outputChunks[i];
-    inputChunk.baseCuOffsetIdx = tmpMergedCuOffsets.size();
-    for (uint32_t cuOffset : outputChunk.compilationUnits)
-      tmpMergedCuOffsets.push_back(outputChunk.sec->outSecOff + cuOffset);
-    for (const DebugNamesSectionData &data : inputChunk.sectionsData) {
-      mergedHdr.CompUnitCount += data.hdr.CompUnitCount;
-      mergedHdr.LocalTypeUnitCount += data.hdr.LocalTypeUnitCount;
-      mergedHdr.ForeignTypeUnitCount += data.hdr.ForeignTypeUnitCount;
-      // Set & check the Augmentation String.
-      if (mergedHdr.AugmentationStringSize == 0) {
-        mergedHdr.AugmentationStringSize = data.hdr.AugmentationStringSize;
-        mergedHdr.AugmentationString = data.hdr.AugmentationString;
-      } else if ((mergedHdr.AugmentationStringSize !=
-                  data.hdr.AugmentationStringSize) ||
-                 (mergedHdr.AugmentationString !=
-                  data.hdr.AugmentationString)) {
-        // There are conflicting augmentation strings, so it's best for the
-        // merged index to not use an augmentation string.
-        mergedHdr.AugmentationString = "        ";
-        mergedHdr.AugmentationStringSize = mergedHdr.AugmentationString.size();
+    // Assign parent pointers, which will be used to update DW_IDX_parent index
+    // attributes. Note: offsetMap[0] does not exist, so parentOffset == 0 will
+    // get parentEntry == null as well.
+    for (NameEntry &ne : nd.nameEntries)
+      for (IndexEntry &ie : ne.entries())
+        ie.parentEntry = offsetMap.lookup(ie.parentOffset);
+  }
+}
+
+// Compute the form for output DW_IDX_compile_unit attributes similar to
+// DIEInteger::BestForm. The input forms (often DW_FORM_data1) may not hold all
+// CU indices.
+std::pair<uint8_t, dwarf::Form> static getMergedCuCountForm(
+    uint32_t compUnitCount) {
+  if (compUnitCount > UINT16_MAX)
+    return {4, DW_FORM_data4};
+  if (compUnitCount > UINT8_MAX)
+    return {2, DW_FORM_data2};
+  return {1, DW_FORM_data1};
+}
+
+void DebugNamesBaseSection::computeHdrAndAbbrevTable(
+    MutableArrayRef<InputChunk> inputChunks) {
+  TimeTraceScope timeScope("Merge .debug_names", "hdr and abbrev table");
+  size_t numCu = 0;
+  hdr.Format = DwarfFormat::DWARF32;
+  hdr.Version = 5;
+  hdr.CompUnitCount = 0;
+  hdr.LocalTypeUnitCount = 0;
+  hdr.ForeignTypeUnitCount = 0;
+  hdr.AugmentationStringSize = 0;
+
+  // Compute CU and TU counts.
+  for (auto i : seq(numChunks)) {
+    InputChunk &inputChunk = inputChunks[i];
+    inputChunk.baseCuIdx = numCu;
+    numCu += chunks[i].compUnits.size();
+    for (const NameData &nd : inputChunk.nameData) {
+      hdr.CompUnitCount += nd.hdr.CompUnitCount;
+      hdr.LocalTypeUnitCount += nd.hdr.LocalTypeUnitCount;
+      hdr.ForeignTypeUnitCount += nd.hdr.ForeignTypeUnitCount;
+      // If augmentation strings are not identical, use an empty string.
+      if (i == 0) {
+        hdr.AugmentationStringSize = nd.hdr.AugmentationStringSize;
+        hdr.AugmentationString = nd.hdr.AugmentationString;
+      } else if (hdr.AugmentationString != nd.hdr.AugmentationString) {
+        hdr.AugmentationStringSize = 0;
+        hdr.AugmentationString.clear();
       }
     }
   }
-}
-
-template <class ELFT>
-void DebugNamesSection<ELFT>::Abbrev::Profile(FoldingSetNodeID &id) const {
-  id.AddInteger(tag);
-  for (const DWARFDebugNames::AttributeEncoding &attr : attributes) {
-    id.AddInteger(attr.Index);
-    id.AddInteger(attr.Form);
-  }
-}
-
-template <class ELFT>
-std::pair<uint8_t, dwarf::Form> DebugNamesSection<ELFT>::getMergedCuSizeData() {
-  // Once we've merged all the CU offsets into a single list, the original
-  // DWARF form/size (often 1 byte) may be too small to hold indices to all
-  // the offsets. Here we calculate what the right form/size needs to be for
-  // the merged index.
-  uint8_t size;
-  dwarf::Form form;
-  // TODO: Investigate possibly using DIEInteger::BestForm here
-  if (mergedHdr.CompUnitCount > UINT32_MAX) {
-    form = DW_FORM_data8;
-    size = 8;
-  } else if (mergedHdr.CompUnitCount > UINT16_MAX) {
-    form = DW_FORM_data4;
-    size = 4;
-  } else if (mergedHdr.CompUnitCount > UINT8_MAX) {
-    form = DW_FORM_data2;
-    size = 2;
-  } else {
-    form = DW_FORM_data1;
-    size = 1;
-  }
-
-  return {size, form};
-}
 
-template <class ELFT>
-void DebugNamesSection<ELFT>::getMergedAbbrevTable(
-    MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
-  MapVector<uint64_t, Abbrev> abbrevMap;
-  FoldingSet<Abbrev> AbbreviationsSet;
-
-  // Need to determine what size form is needed for the DW_IDX_compile_unit
-  // attributes in the merged index. Will need to update the abbrevs to use
-  // the right form.
-  dwarf::Form compileUnitAttrForm = getMergedCuSizeData().second;
-
-  for (DebugNamesInputChunk &chunk : inputChunks) {
-    for (const DWARFDebugNames::NameIndex &ni : *chunk.debugNamesData) {
-      const auto &abbrevs = ni.getAbbrevs();
-      for (const DWARFDebugNames::Abbrev &abbrev : abbrevs) {
-        // Create canonicalized abbrev.
-        Abbrev newAbbrev;
-        DWARFDebugNames::AttributeEncoding cuOrTuAttr(DW_IDX_compile_unit,
-                                                      compileUnitAttrForm);
-        newAbbrev.code = abbrev.Code;
-        newAbbrev.tag = abbrev.Tag;
-        for (const DWARFDebugNames::AttributeEncoding attr :
-             abbrev.Attributes) {
-          DWARFDebugNames::AttributeEncoding newAttr(attr.Index, attr.Form);
-          if (attr.Index == DW_IDX_compile_unit)
-            // Save it, to put it at the end.
-            cuOrTuAttr.Index = newAttr.Index;
+  // Uniquify input abbrev tables and compute mapping from old abbrev code to
+  // new abbrev code.
+  FoldingSet<Abbrev> abbrevSet;
+  // Determine the form for the DW_IDX_compile_unit attributes in the merged
+  // index. The input form may not encode all possible CU indices.
+  const dwarf::Form cuAttrForm = getMergedCuCountForm(hdr.CompUnitCount).second;
+  for (InputChunk &inputChunk : inputChunks) {
+    for (auto [i, ni] : enumerate(*inputChunk.llvmDebugNames)) {
+      for (const DWARFDebugNames::Abbrev &oldAbbrev : ni.getAbbrevs()) {
+        // Canonicalize abbrev by placing the CU/TU index at the end,
+        // similar to `DebugNamesBaseSection::parse`.
+        Abbrev abbrev;
+        DWARFDebugNames::AttributeEncoding cuAttr(DW_IDX_compile_unit,
+                                                  cuAttrForm);
+        abbrev.code = oldAbbrev.Code;
+        abbrev.tag = oldAbbrev.Tag;
+        for (DWARFDebugNames::AttributeEncoding a : oldAbbrev.Attributes) {
+          if (a.Index == DW_IDX_compile_unit)
+            cuAttr.Index = a.Index;
           else
-            newAbbrev.attributes.push_back(newAttr);
+            abbrev.attributes.push_back({a.Index, a.Form});
         }
-        // Put the CU/TU index at the end of the attributes list.
-        newAbbrev.attributes.push_back(cuOrTuAttr);
+        abbrev.attributes.push_back(cuAttr);
 
-        // Next, check our abbreviations set to see if we've already seen the
-        // identical abbreviation.
-        uint32_t oldCode = newAbbrev.code;
-        uint32_t newCode;
+        // Profile the abbrev, get or assign a new code, then record the abbrev
+        // code mapping.
         FoldingSetNodeID id;
-        newAbbrev.Profile(id);
+        abbrev.Profile(id);
+        uint32_t newCode;
         void *insertPos;
-        if (Abbrev *Existing =
-                AbbreviationsSet.FindNodeOrInsertPos(id, insertPos)) {
-          // Found it; we've already seen an identical abbreviation.
-          newCode = Existing->code;
+        if (Abbrev *existing = abbrevSet.FindNodeOrInsertPos(id, insertPos)) {
+          newCode = existing->code;
         } else {
-          // Didn't find it.
-          Abbrev *newAbbrev2 =
-              new (abbrevAlloc.Allocate()) Abbrev(std::move(newAbbrev));
-          AbbreviationsSet.InsertNode(newAbbrev2, insertPos);
-          newCode = mergedAbbrevTable.size() + 1;
-          newAbbrev2->code = newCode;
-          mergedAbbrevTable.push_back(newAbbrev2);
+          Abbrev *abbrev2 =
+              new (abbrevAlloc.Allocate()) Abbrev(std::move(abbrev));
+          abbrevSet.InsertNode(abbrev2, insertPos);
+          abbrevTable.push_back(abbrev2);
+          newCode = abbrevTable.size();
+          abbrev2->code = newCode;
         }
-        chunk.abbrevCodeMap[oldCode] = newCode;
+        inputChunk.nameData[i].abbrevCodeMap[oldAbbrev.Code] = newCode;
       }
     }
   }
 
-  // Calculate the merged abbrev table size.
-  mergedHdr.AbbrevTableSize = 0;
-  for (Abbrev *a : mergedAbbrevTable) {
-    mergedHdr.AbbrevTableSize += getULEB128Size(a->code);
-    mergedHdr.AbbrevTableSize += getULEB128Size(a->tag);
-    for (const DWARFDebugNames::AttributeEncoding &attr : a->attributes) {
-      mergedHdr.AbbrevTableSize += getULEB128Size(attr.Index);
-      mergedHdr.AbbrevTableSize += getULEB128Size(attr.Form);
+  // Compute the merged abbrev table.
+  raw_svector_ostream os(abbrevTableBuf);
+  for (Abbrev *abbrev : abbrevTable) {
+    encodeULEB128(abbrev->code, os);
+    encodeULEB128(abbrev->tag, os);
+    for (DWARFDebugNames::AttributeEncoding a : abbrev->attributes) {
+      encodeULEB128(a.Index, os);
+      encodeULEB128(a.Form, os);
     }
-    mergedHdr.AbbrevTableSize += 2; // attribute index & form sentinels
+    os.write("\0", 2); // attribute specification end
   }
-  ++mergedHdr.AbbrevTableSize; // abbrev table sentinel
+  os.write(0); // abbrev table end
+  hdr.AbbrevTableSize = abbrevTableBuf.size();
 }
 
-template <class ELFT>
-void DebugNamesSection<ELFT>::getMergedSymbols(
-    MutableArrayRef<DebugNamesInputChunk> &inputChunks) {
-  // The number of symbols (& abbrevs) we will handle is very large; will use
-  // multi-threading to speed it up.
-  constexpr size_t numShards = 32;
+void DebugNamesBaseSection::Abbrev::Profile(FoldingSetNodeID &id) const {
+  id.AddInteger(tag);
+  for (const DWARFDebugNames::AttributeEncoding &attr : attributes) {
+    id.AddInteger(attr.Index);
+    id.AddInteger(attr.Form);
+  }
+}
+
+std::pair<uint32_t, uint32_t> DebugNamesBaseSection::computeEntryPool(
+    MutableArrayRef<InputChunk> inputChunks) {
+  TimeTraceScope timeScope("Merge .debug_names", "entry pool");
+  // Collect the compilation units for each unique name. Speed it up using
+  // multi-threading as the number of symbols can be in the order of millions.
   const size_t concurrency =
       bit_floor(std::min<size_t>(config->threadCount, numShards));
   const size_t shift = 32 - countr_zero(numShards);
-
-  struct ShardData {
-    // Map to uniquify symbols by name
-    MapVector<CachedHashStringRef, NamedEntry> nameMap;
-  };
-
-  // Need to determine what size is needed for the DW_IDX_compile_unit
-  // attributes in the merged index. Will need to update the indexEntries
-  // to use the right size.
-  uint8_t compileUnitAttrSize = getMergedCuSizeData().first;
-
-  auto shardsPtr = std::make_unique<ShardData[]>(numShards);
-  MutableArrayRef<ShardData> shards(shardsPtr.get(), numShards);
-
+  const uint8_t cuAttrSize = getMergedCuCountForm(hdr.CompUnitCount).first;
+  DenseMap<CachedHashStringRef, size_t> maps[numShards];
   parallelFor(0, concurrency, [&](size_t threadId) {
-    for (size_t i = 0, e = numChunks; i != e; ++i) {
-      DebugNamesInputChunk &chunk = inputChunks[i];
-      for (DebugNamesSectionData &secData : chunk.sectionsData) {
-        // Deduplicate the NamedEntry records (based on the string/name),
-        // using a map from string/name to NamedEntry records.
-        // Note there is a twist: If there is already a record for the current
-        // 'string' in the nameMap, we append all the indexEntries from the
-        // current record to the record that's in the nameMap. I.e. we
-        // deduplicate the *strings* but we keep all the IndexEntry records
-        // (moving them to the appropriate 'kept' NamedEntry record).
-        for (NamedEntry &stringEntry : secData.namedEntries) {
-          size_t shardId = stringEntry.hashValue >> shift;
+    for (auto i : seq(numChunks)) {
+      InputChunk &inputChunk = inputChunks[i];
+      for (NameData &nd : inputChunk.nameData) {
+        for (NameEntry &ne : nd.nameEntries) {
+          auto shardId = ne.hashValue >> shift;
           if ((shardId & (concurrency - 1)) != threadId)
             continue;
 
-          auto &shard = shards[shardId];
-          stringEntry.chunkIdx = i;
-          for (std::unique_ptr<IndexEntry> &entry : stringEntry.indexEntries) {
-            // The DW_IDX_compile_unit is always the last attribute (we set it
-            // up that way when we read/created the attributes). We need to
-            // update the index value to use the correct merged offset, and we
-            // need to fix the size of the index attribute.
-            uint8_t endPos = entry->attrValues.size() - 1;
-            entry->attrValues[endPos].attrValue += chunk.baseCuOffsetIdx;
-            entry->attrValues[endPos].attrSize = compileUnitAttrSize;
-            // Update the entry's abbrev code to match the merged
-            // abbreviations.
-            entry->abbrevCode = chunk.abbrevCodeMap[entry->abbrevCode];
+          ne.chunkIdx = i;
+          for (IndexEntry &ie : ne.entries()) {
+            ie.abbrevCode = nd.abbrevCodeMap[ie.abbrevCode];
+            // Update the DW_IDX_compile_unit attribute (the last one after
+            // canonicalization).
+            auto &back = ie.attrValues.back();
+            back.attrValue += inputChunk.baseCuIdx;
+            back.attrSize = cuAttrSize;
           }
 
-          CachedHashStringRef cachedHashName(stringEntry.name);
-          auto [it, inserted] =
-              shard.nameMap.try_emplace(cachedHashName, std::move(stringEntry));
-          if (!inserted) {
-            // Found the string already; don't add to map, but append
-            // entry/entries for it to existing map entry.
-            NamedEntry &found = it->second;
-            // Append the entries...
-            for (auto &entry : stringEntry.indexEntries)
-              found.indexEntries.push_back(std::move(entry));
-          }
+          auto &nameVec = nameVecs[shardId];
+          auto [it, inserted] = maps[shardId].try_emplace(
+              CachedHashStringRef(ne.name, ne.hashValue), nameVec.size());
+          if (inserted)
+            nameVec.push_back(std::move(ne));
+          else
+            nameVec[it->second].indexEntries.append(ne.indexEntries);
         }
       }
     }
   });
 
-  // Combined the shared symbols into mergedEntries
-  for (ShardData &shard : shards)
-    for (auto &mapEntry : shard.nameMap)
-      mergedEntries.push_back(std::move(mapEntry.second));
-  mergedHdr.NameCount = mergedEntries.size();
-}
-
-template <class ELFT>
-void DebugNamesSection<ELFT>::computeUniqueHashes(
-    MutableArrayRef<DebugNamesInputChunk> &chunks) {
-  SmallVector<uint32_t, 0> uniques;
-  for (const auto &chunk : chunks)
-    uniques.append(chunk.hashValues);
-  llvm::sort(uniques);
-  mergedHdr.BucketCount = dwarf::getDebugNamesBucketCount(llvm::unique(uniques) - uniques.begin());
-}
-
-template <class ELFT> void DebugNamesSection<ELFT>::generateBuckets() {
-  bucketList.resize(mergedHdr.BucketCount);
-  for (NamedEntry &entry : mergedEntries) {
-    uint32_t bucketIdx = entry.hashValue % mergedHdr.BucketCount;
-    bucketList[bucketIdx].push_back(&entry);
-  }
-
-  // Sort the contents of the buckets by hash value so that the hash collisions
-  // end up together.
-  for (SmallVector<NamedEntry *, 0> &bucket : bucketList)
-    stable_sort(bucket, [](NamedEntry *lhs, NamedEntry *rhs) {
-      return lhs->hashValue < rhs->hashValue;
-    });
-}
-
-template <class ELFT>
-void DebugNamesSection<ELFT>::calculateEntriesSizeAndOffsets() {
-  uint32_t offset = 0;
-  for (NamedEntry &stringEntry : mergedEntries) {
-    stringEntry.entryOffset = offset;
-    for (std::unique_ptr<IndexEntry> &entry : stringEntry.indexEntries) {
-      uint32_t entrySize = 0;
-      entry->poolOffset = offset;
-      entrySize += getULEB128Size(entry->abbrevCode);
-      for (const auto &attr : entry->attrValues)
-        entrySize += attr.attrSize;
-      offset += entrySize;
+  // Compute entry offsets parallelly. First, compute offsets relative to the
+  // current shard.
+  uint32_t offsets[numShards];
+  parallelFor(0, numShards, [&](size_t shard) {
+    uint32_t offset = 0;
+    for (NameEntry &ne : nameVecs[shard]) {
+      ne.entryOffset = offset;
+      for (IndexEntry &ie : ne.entries()) {
+        ie.poolOffset = offset;
+        offset += getULEB128Size(ie.abbrevCode);
+        for (AttrValue value : ie.attrValues)
+          offset += value.attrSize;
+      }
+      ++offset; // index entry sentinel
     }
-    // Add in sentinel size
-    ++offset;
-  }
-  mergedTotalEntriesSize = offset;
-}
-
-template <class ELFT> void DebugNamesSection<ELFT>::updateParentIndexEntries() {
-  for (NamedEntry &stringEntry : mergedEntries) {
-    for (std::unique_ptr<IndexEntry> &childEntry : stringEntry.indexEntries) {
-      if (!childEntry->parentEntry)
-        continue;
+    offsets[shard] = offset;
+  });
+  // Then add shard offsets.
+  std::partial_sum(offsets, std::end(offsets), offsets);
+  parallelFor(1, numShards, [&](size_t shard) {
+    uint32_t offset = offsets[shard - 1];
+    for (NameEntry &ne : nameVecs[shard]) {
+      ne.entryOffset += offset;
+      for (IndexEntry &ie : ne.entries())
+        ie.poolOffset += offset;
+    }
+  });
 
-      // Abbrevs are indexed starting at 1; vector starts at 0. (abbrevCode
-      // corresponds to position in the merged table vector).
-      const Abbrev *abbrev = mergedAbbrevTable[childEntry->abbrevCode - 1];
-
-      // Found the abbrev. Find the index for the DW_IDX_parent attribute
-      // (in the abbrev) and update that value in the entry with the
-      // correct parent offset (in the merged entry pool).
-      for (size_t idx = 0, size = abbrev->attributes.size(); idx != size;
-           ++idx) {
-        DWARFDebugNames::AttributeEncoding attr = abbrev->attributes[idx];
-        if (attr.Index == DW_IDX_parent && attr.Form == DW_FORM_ref4)
-          childEntry->attrValues[idx].attrValue =
-              childEntry->parentEntry->poolOffset;
+  // Update DW_IDX_parent attributes that use DW_FORM_ref4.
+  parallelFor(0, numShards, [&](size_t shard) {
+    for (NameEntry &ne : nameVecs[shard]) {
+      for (IndexEntry &ie : ne.entries()) {
+        if (!ie.parentEntry)
+          continue;
+        const Abbrev *abbrev = abbrevTable[ie.abbrevCode - 1];
+        for (auto i : seq(abbrev->attributes.size())) {
+          DWARFDebugNames::AttributeEncoding a = abbrev->attributes[i];
+          if (a.Index == DW_IDX_parent && a.Form == DW_FORM_ref4)
+            ie.attrValues[i].attrValue = ie.parentEntry->poolOffset;
+        }
       }
     }
-  }
-}
+  });
 
-template <class ELFT>
-uint64_t DebugNamesSection<ELFT>::calculateMergedSectionSize() {
-  uint32_t hdrSize = computeDebugNamesHeaderSize();
-  mergedOffsets = findDebugNamesOffsets(hdrSize, mergedHdr);
-  // Add in the size for all the Entries, and make it 4-byte aligned.
-  mergedHdr.UnitLength =
-      alignTo(mergedOffsets.EntriesBase + mergedTotalEntriesSize, 4);
-  // Add in the first 4 bytes, whichs print out the length of the section.
-  return mergedHdr.UnitLength + 4;
+  // Return (entry pool size, number of entries).
+  uint32_t num = 0;
+  for (auto &map : maps)
+    num += map.size();
+  return {offsets[numShards - 1], num};
 }
 
-template <class ELFT>
-DebugNamesSection<ELFT> *DebugNamesSection<ELFT>::create() {
-  TimeTraceScope timeScope("Create merged .debug_names");
+void DebugNamesBaseSection::init(
+    function_ref<void(InputFile *, InputChunk &, OutputChunk &)> parseFile) {
+  TimeTraceScope timeScope("Merge .debug_names");
+  // Collect and remove input .debug_names sections. Save InputSection pointers
+  // to relocate string offsets in `writeTo`.
   SetVector<InputFile *> files;
-  SmallVector<InputSectionBase *, 0> sections;
   for (InputSectionBase *s : ctx.inputSections) {
     InputSection *isec = dyn_cast<InputSection>(s);
     if (!isec)
       continue;
-    // Mark original sections as dead, but save links to them for calculating
-    // relocations later.
-    if (s->name == ".debug_names") {
+    if (!(s->flags & SHF_ALLOC) && s->name == ".debug_names") {
       s->markDead();
-      sections.push_back(s);
+      inputSections.push_back(isec);
       files.insert(isec->file);
     }
   }
-  auto inputChunksPtr = std::make_unique<DebugNamesInputChunk[]>(files.size());
-  MutableArrayRef<DebugNamesInputChunk> inputChunks(inputChunksPtr.get(),
-                                                    files.size());
-  auto outputChunks = std::make_unique<DebugNamesOutputChunk[]>(files.size());
-  parallelFor(0, files.size(), [&](size_t i) {
-    auto *file = cast<ObjFile<ELFT>>(files[i]);
-    auto dwarfCtx = std::make_unique<DWARFContext>(
-        std::make_unique<LLDDwarfObj<ELFT>>(file));
-    auto &dobj =
-        static_cast<const LLDDwarfObj<ELFT> &>(dwarfCtx->getDWARFObj());
-
-    // Extract DWARFDebugNames data from the .debug_names section. The
-    // .debug_names section needs the .debug_str section, to get the actual
-    // symbol names.
-    const StringRef strSection = dobj.getStrSection();
-    const LLDDWARFSection &namesSection = dobj.getNamesSection();
-    DWARFDataExtractor namesExtractor(dobj, namesSection, config->isLE,
-                                      config->wordsize);
-    DataExtractor strExtractor(strSection, config->isLE, config->wordsize);
-    inputChunks[i].debugNamesData =
-        std::make_unique<DWARFDebugNames>(namesExtractor, strExtractor);
-    inputChunks[i].namesSection =
-        std::make_unique<LLDDWARFSection>(namesSection);
-    if (Error E = inputChunks[i].debugNamesData->extract()) {
+
+  // Parse input .debug_names sections and extract InputChunk and OutputChunk
+  // data. OutputChunk contains CU information, which will be needed by
+  // `writeTo`.
+  auto inputChunksPtr = std::make_unique<InputChunk[]>(files.size());
+  MutableArrayRef<InputChunk> inputChunks(inputChunksPtr.get(), files.size());
+  numChunks = files.size();
+  chunks = std::make_unique<OutputChunk[]>(files.size());
+  {
+    TimeTraceScope timeScope("Merge .debug_names", "parse");
+    parallelFor(0, files.size(), [&](size_t i) {
+      parseFile(files[i], inputChunks[i], chunks[i]);
+    });
+  }
+
+  // Compute section header (except unit_length), abbrev table, and entry pool.
+  computeHdrAndAbbrevTable(inputChunks);
+  uint32_t entryPoolSize;
+  std::tie(entryPoolSize, hdr.NameCount) = computeEntryPool(inputChunks);
+  hdr.BucketCount = dwarf::getDebugNamesBucketCount(hdr.NameCount);
+
+  // Compute the section size. Subtract 4 to get the unit_length for DWARF32.
+  uint32_t hdrSize = getDebugNamesHeaderSize(hdr.AugmentationStringSize);
+  size = findDebugNamesOffsets(hdrSize, hdr).EntriesBase + entryPoolSize;
+  hdr.UnitLength = size - 4;
+}
+
+template <class ELFT> DebugNamesSection<ELFT>::DebugNamesSection() {
+  init([](InputFile *f, InputChunk &inputChunk, OutputChunk &chunk) {
+    auto *file = cast<ObjFile<ELFT>>(f);
+    DWARFContext dwarf(std::make_unique<LLDDwarfObj<ELFT>>(file));
+    auto &dobj = static_cast<const LLDDwarfObj<ELFT> &>(dwarf.getDWARFObj());
+    chunk.infoSec = dobj.getInfoSection();
+    DWARFDataExtractor namesExtractor(dobj, dobj.getNamesSection(),
+                                      ELFT::Endianness == endianness::little,
+                                      ELFT::Is64Bits ? 8 : 4);
+    // .debug_str is needed to get symbol names from string offsets.
+    DataExtractor strExtractor(dobj.getStrSection(),
+                               ELFT::Endianness == endianness::little,
+                               ELFT::Is64Bits ? 8 : 4);
+    inputChunk.section = dobj.getNamesSection();
+
+    inputChunk.llvmDebugNames.emplace(namesExtractor, strExtractor);
+    if (Error e = inputChunk.llvmDebugNames->extract()) {
       errorOrWarn(toString(dobj.getNamesSection().sec) + Twine(": ") +
-                  toString(std::move(E)));
+                  toString(std::move(e)));
     }
-    outputChunks[i].sec = dobj.getInfoSection();
-    collectDebugNamesSectionData<ELFT>(inputChunks[i], outputChunks[i],
-                                       namesExtractor, strExtractor);
+    parseDebugNames(
+        inputChunk, chunk, namesExtractor, strExtractor,
+        [&chunk, namesData = dobj.getNamesSection().Data.data()](
+            const DWARFDebugNames::Header &hdr,
+            const DWARFDebugNames::DWARFDebugNamesOffsets &locs) {
+          // Read CU offsets.
+          const char *p = namesData + locs.CUsBase;
+          chunk.compUnits.resize_for_overwrite(hdr.CompUnitCount);
+          for (auto i : seq(hdr.CompUnitCount))
+            chunk.compUnits[i] =
+                endian::readNext<uint32_t, ELFT::Endianness, unaligned>(p);
+
+          // Read entry offsets.
+          p = namesData + locs.EntryOffsetsBase;
+          SmallVector<uint32_t, 0> entryOffsets;
+          entryOffsets.resize_for_overwrite(hdr.NameCount);
+          for (auto i : seq(hdr.NameCount))
+            entryOffsets[i] =
+                endian::readNext<uint32_t, ELFT::Endianness, unaligned>(p);
+          return entryOffsets;
+        });
   });
+}
 
-  auto *ret = make<DebugNamesSection>();
-  ret->inputDebugNamesSections = sections;
-  ret->outputChunks = std::move(outputChunks);
-  ret->numChunks = files.size();
-  ret->collectMergedCounts(inputChunks);
-  ret->getMergedAbbrevTable(inputChunks);
-  ret->getMergedSymbols(inputChunks);
-  ret->computeUniqueHashes(inputChunks);
-  // inputChunks are not needed any more. Reset now to save memory.
-  inputChunksPtr.reset();
-  ret->generateBuckets();
-  ret->calculateEntriesSizeAndOffsets();
-  ret->updateParentIndexEntries();
-  ret->sectionSize = ret->calculateMergedSectionSize();
-  return ret;
+template <class ELFT>
+template <class RelTy>
+void DebugNamesSection<ELFT>::getNameRelocs(
+    InputSection *sec, ArrayRef<RelTy> rels,
+    DenseMap<uint32_t, uint32_t> &relocs) {
+  for (const RelTy &rel : rels) {
+    Symbol &sym = sec->file->getRelocTargetSym(rel);
+    relocs[rel.r_offset] = sym.getVA(getAddend<ELFT>(rel));
+  }
+}
+
+template <class ELFT> void DebugNamesSection<ELFT>::finalizeContents() {
+  // Get relocations of .debug_names sections.
+  auto relocs = std::make_unique<DenseMap<uint32_t, uint32_t>[]>(numChunks);
+  parallelFor(0, numChunks, [&](size_t i) {
+    InputSection *sec = inputSections[i];
+    auto rels = sec->template relsOrRelas<ELFT>();
+    if (rels.areRelocsRel())
+      getNameRelocs(sec, rels.rels, relocs.get()[i]);
+    else
+      getNameRelocs(sec, rels.relas, relocs.get()[i]);
+  });
+
+  // Relocate string offsets in the name table.
+  parallelForEach(nameVecs, [&](auto &nameVec) {
+    for (NameEntry &ne : nameVec)
+      ne.stringOffset = relocs.get()[ne.chunkIdx][ne.stringOffset];
+  });
+}
+
+template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
+  [[maybe_unused]] uint8_t *oldBuf = buf;
+  // Write the header.
+  endian::write32<ELFT::Endianness>(buf + 0, hdr.UnitLength);
+  endian::write16<ELFT::Endianness>(buf + 4, hdr.Version);
+  endian::write32<ELFT::Endianness>(buf + 8, hdr.CompUnitCount);
+  endian::write32<ELFT::Endianness>(buf + 12, hdr.LocalTypeUnitCount);
+  endian::write32<ELFT::Endianness>(buf + 16, hdr.ForeignTypeUnitCount);
+  endian::write32<ELFT::Endianness>(buf + 20, hdr.BucketCount);
+  endian::write32<ELFT::Endianness>(buf + 24, hdr.NameCount);
+  endian::write32<ELFT::Endianness>(buf + 28, hdr.AbbrevTableSize);
+  endian::write32<ELFT::Endianness>(buf + 32, hdr.AugmentationStringSize);
+  buf += 36;
+  memcpy(buf, hdr.AugmentationString.c_str(), hdr.AugmentationString.size());
+  buf += hdr.AugmentationStringSize;
+
+  // Write the CU list.
+  for (auto i : seq(numChunks)) {
+    OutputChunk &chunk = chunks[i];
+    for (uint32_t cuOffset : chunk.compUnits) {
+      endian::write32<ELFT::Endianness>(buf,
+                                        chunk.infoSec->outSecOff + cuOffset);
+      buf += 4;
+    }
+  }
+
+  if (hdr.LocalTypeUnitCount || hdr.ForeignTypeUnitCount)
+    warn(".debug_names: type units are not implemented");
+
+  // Write the hash lookup table.
+  SmallVector<SmallVector<NameEntry *, 0>, 0> buckets(hdr.BucketCount);
+  // Symbols enter into a bucket whose index is the hash modulo bucket_count.
+  for (auto &nameVec : nameVecs)
+    for (NameEntry &ne : nameVec)
+      buckets[ne.hashValue % hdr.BucketCount].push_back(&ne);
+
+  // Write buckets (accumulated bucket counts).
+  uint32_t bucketIdx = 1;
+  for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
+    if (!bucket.empty())
+      endian::write32<ELFT::Endianness>(buf, bucketIdx);
+    buf += 4;
+    bucketIdx += bucket.size();
+  }
+  // Write the hashes.
+  for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
+    for (const NameEntry *e : bucket) {
+      endian::write32<ELFT::Endianness>(buf, e->hashValue);
+      buf += 4;
+    }
+  }
+
+  // Write the name table. The name entries are ordered by bucket_idx and
+  // correspond one-to-one with the hash lookup table.
+  //
+  // First, write the relocated string offsets.
+  for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
+    for (const NameEntry *ne : bucket) {
+      endian::write32<ELFT::Endianness>(buf, ne->stringOffset);
+      buf += 4;
+    }
+  }
+  // Then write the entry offsets.
+  for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
+    for (const NameEntry *ne : bucket) {
+      endian::write32<ELFT::Endianness>(buf, ne->entryOffset);
+      buf += 4;
+    }
+  }
+
+  // Write the abbrev table.
+  memcpy(buf, abbrevTableBuf.data(), abbrevTableBuf.size());
+  buf += abbrevTableBuf.size();
+
+  // Write the entry pool. Unlike the name table, the name entries follow the
+  // nameVecs order computed by `computeEntryPool`.
+  for (auto &nameVec : nameVecs) {
+    for (NameEntry &ne : nameVec) {
+      for (const IndexEntry &ie : ne.entries()) {
+        buf += encodeULEB128(ie.abbrevCode, buf);
+        for (AttrValue value : ie.attrValues) {
+          switch (value.attrSize) {
+          case 1:
+            *buf = value.attrValue;
+            break;
+          case 2:
+            endian::write16<ELFT::Endianness>(buf, value.attrValue);
+            break;
+          case 4:
+            endian::write32<ELFT::Endianness>(buf, value.attrValue);
+            break;
+          default:
+            llvm_unreachable("invalid attrSize");
+          }
+          buf += value.attrSize;
+        }
+      }
+      ++buf; // index entry sentinel
+    }
+  }
+  assert(uint64_t(buf - oldBuf) == size);
 }
 
 GdbIndexSection::GdbIndexSection()
@@ -4616,6 +4446,7 @@ void InStruct::reset() {
   ppc32Got2.reset();
   ibtPlt.reset();
   relaPlt.reset();
+  debugNames.reset();
   gdbIndex.reset();
   shStrTab.reset();
   strTab.reset();
@@ -5025,8 +4856,10 @@ template <class ELFT> void elf::createSyntheticSections() {
   if (config->andFeatures || !ctx.aarch64PauthAbiCoreInfo.empty())
     add(*make<GnuPropertySection>());
 
-  if (config->debugNames)
-    add(*DebugNamesSection<ELFT>::create());
+  if (config->debugNames) {
+    in.debugNames = std::make_unique<DebugNamesSection<ELFT>>();
+    add(*in.debugNames);
+  }
   if (config->gdbIndex) {
     in.gdbIndex = GdbIndexSection::create<ELFT>();
     add(*in.gdbIndex);
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 297f2ca6e27d85..2d37cbdefb4ade 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -793,27 +793,11 @@ class RelroPaddingSection final : public SyntheticSection {
   void writeTo(uint8_t *buf) override {}
 };
 
-template <class ELFT> class DebugNamesSection final : public SyntheticSection {
-  // N.B. Everything in this class assumes that we are using DWARF32.
-  // If we move to DWARF64, most of this data will need to be re-sized,
-  // and the code that handles or manipulates it will need to be updated
-  // accordingly.
-
+// Used by the merged DWARF32 .debug_names (a per-module index). If we
+// move to DWARF64, most of this data will need to be re-sized.
+class DebugNamesBaseSection : public SyntheticSection {
 public:
-  DebugNamesSection();
-  static DebugNamesSection *create();
-  void writeTo(uint8_t *buf) override;
-  size_t getSize() const override { return sectionSize; }
-  bool isNeeded() const override;
-
-  template <class RelTy>
-  void getNameRelocsImpl(InputSection *sec, ArrayRef<RelTy> rels,
-                         llvm::DenseMap<uint32_t, uint32_t> &relocs);
-
-  void getNameRelocs(InputSectionBase *base,
-                     llvm::DenseMap<uint32_t, uint32_t> &relocs);
-
-  struct Abbrev : public llvm::FoldingSetNode {
+  struct Abbrev : llvm::FoldingSetNode {
     uint32_t code;
     uint32_t tag;
     SmallVector<llvm::DWARFDebugNames::AttributeEncoding, 2> attributes;
@@ -821,7 +805,7 @@ template <class ELFT> class DebugNamesSection final : public SyntheticSection {
     void Profile(llvm::FoldingSetNodeID &id) const;
   };
 
-  struct AttrValueData {
+  struct AttrValue {
     uint32_t attrValue;
     uint8_t attrSize;
   };
@@ -830,86 +814,103 @@ template <class ELFT> class DebugNamesSection final : public SyntheticSection {
     uint32_t abbrevCode;
     uint32_t poolOffset;
     union {
-      int32_t parentOffset = -1;
+      uint64_t parentOffset = 0;
       IndexEntry *parentEntry;
     };
-    SmallVector<AttrValueData, 3> attrValues;
+    SmallVector<AttrValue, 3> attrValues;
   };
 
-  struct NamedEntry {
+  struct NameEntry {
     const char *name;
     uint32_t hashValue;
-    uint32_t stringOffsetOffset;
+    uint32_t stringOffset;
     uint32_t entryOffset;
-    uint32_t relocatedEntryOffset;
-    // The index of the chunk that 'name' points into, for looking up
-    // relocation data for this string.
+    // Used to relocate `stringOffset` in the merged section.
     uint32_t chunkIdx;
-    SmallVector<std::unique_ptr<IndexEntry>, 0> indexEntries;
-  };
+    SmallVector<IndexEntry *, 0> indexEntries;
 
-  struct SectionOffsetLocs {
-    uint64_t stringOffsetsBase;
-    uint64_t entryOffsetsBase;
-    uint64_t entriesBase;
+    llvm::iterator_range<
+        llvm::pointee_iterator<typename SmallVector<IndexEntry *, 0>::iterator>>
+    entries() {
+      return llvm::make_pointee_range(indexEntries);
+    }
   };
 
-  struct DebugNamesSectionData {
+  // One name index described by an input .debug_names section. An InputChunk
+  // typically contains one single name index.
+  struct NameData {
     llvm::DWARFDebugNames::Header hdr;
-    llvm::DWARFDebugNames::DWARFDebugNamesOffsets locs;
-    SmallVector<uint32_t, 0> tuOffsets;
-    SmallVector<Abbrev, 0> abbrevTable;
-    SmallVector<uint32_t, 0> entryOffsets;
-    SmallVector<NamedEntry, 0> namedEntries;
-    uint16_t dwarfSize;
-    uint16_t hdrSize;
+    llvm::DenseMap<uint32_t, uint32_t> abbrevCodeMap;
+    SmallVector<NameEntry, 0> nameEntries;
   };
 
-  // Per-file data used, while reading in the data, to generate the merged
-  // section information.
-  struct DebugNamesInputChunk {
-    uint32_t baseCuOffsetIdx;
-    std::unique_ptr<llvm::DWARFDebugNames> debugNamesData;
-    std::unique_ptr<LLDDWARFSection> namesSection;
-    SmallVector<DebugNamesSectionData, 0> sectionsData;
-    SmallVector<uint32_t, 0> hashValues;
-    llvm::DenseMap<uint32_t, uint32_t> abbrevCodeMap;
+  // InputChunk and OutputChunk hold per-file contribution to the merged index.
+  // InputChunk instances will be discarded after `create` completes.
+  struct InputChunk {
+    uint32_t baseCuIdx;
+    LLDDWARFSection section;
+    SmallVector<NameData, 0> nameData;
+    std::optional<llvm::DWARFDebugNames> llvmDebugNames;
   };
 
-  // Per-file data needed for correctly writing out the .debug_names section.
-  struct DebugNamesOutputChunk {
-    // Pointer to .debug_info section for this chunk/file, used for
-    // calculating correct relocated CU offsets in the merged index.
-    InputSection *sec;
-    SmallVector<uint32_t, 0> compilationUnits;
-    SmallVector<uint32_t, 0> typeUnits;
+  struct OutputChunk {
+    // Pointer to the .debug_info section that contains compile units, used to
+    // compute the relocated CU offsets.
+    InputSection *infoSec;
+    SmallVector<uint32_t, 0> compUnits;
   };
 
-  void collectMergedCounts(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
-  std::pair<uint8_t, llvm::dwarf::Form> getMergedCuSizeData();
-  void getMergedAbbrevTable(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
-  void getMergedSymbols(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
-  void computeUniqueHashes(MutableArrayRef<DebugNamesInputChunk> &inputChunks);
-  void generateBuckets();
-  void calculateEntriesSizeAndOffsets();
-  void updateParentIndexEntries();
-  uint64_t calculateMergedSectionSize();
+  DebugNamesBaseSection();
+  size_t getSize() const override { return size; }
+  bool isNeeded() const override { return numChunks > 0; }
 
+protected:
+  void init(llvm::function_ref<void(InputFile *, InputChunk &, OutputChunk &)>);
+  static void
+  parseDebugNames(InputChunk &inputChunk, OutputChunk &chunk,
+                  llvm::DWARFDataExtractor &namesExtractor,
+                  llvm::DataExtractor &strExtractor,
+                  llvm::function_ref<SmallVector<uint32_t, 0>(
+                      const llvm::DWARFDebugNames::Header &hdr,
+                      const llvm::DWARFDebugNames::DWARFDebugNamesOffsets &)>
+                      readOffsets);
+  void computeHdrAndAbbrevTable(MutableArrayRef<InputChunk>);
+  std::pair<uint32_t, uint32_t> computeEntryPool(MutableArrayRef<InputChunk>);
+
+  // Input .debug_names sections for relocating string offsets in the name table
+  // in finalizeContents.
+  SmallVector<InputSection *, 0> inputSections;
+
+  llvm::DWARFDebugNames::Header hdr;
+  size_t numChunks;
+  std::unique_ptr<OutputChunk[]> chunks;
   llvm::SpecificBumpPtrAllocator<Abbrev> abbrevAlloc;
+  SmallVector<Abbrev *, 0> abbrevTable;
+  SmallVector<char, 0> abbrevTableBuf;
+
+  // Sharded name entries that will be used to compute bucket_count and the
+  // count name table.
+  static constexpr size_t numShards = 32;
+  SmallVector<NameEntry, 0> nameVecs[numShards];
+};
+
+// Complement DebugNamesBaseSection for ELFT-aware code: reading offsets,
+// relocating string offsets, and writeTo.
+template <class ELFT>
+class DebugNamesSection final : public DebugNamesBaseSection {
+public:
+  DebugNamesSection();
+  void finalizeContents() override;
+  void writeTo(uint8_t *buf) override;
+
+  template <class RelTy>
+  void getNameRelocs(InputSection *sec, ArrayRef<RelTy> rels,
+                     llvm::DenseMap<uint32_t, uint32_t> &relocs);
 
 private:
-  size_t sectionSize;
-  uint32_t mergedTotalEntriesSize;
-  uint32_t numChunks;
-  llvm::DWARFDebugNames::DWARFDebugNamesOffsets mergedOffsets;
-  std::unique_ptr<DebugNamesOutputChunk[]> outputChunks;
-  // Pointers to the original .debug_names sections; used for find the correct'
-  // string relocation values when writing out the merged index.
-  SmallVector<InputSectionBase *, 0> inputDebugNamesSections;
-  llvm::DWARFDebugNames::Header mergedHdr;
-  SmallVector<Abbrev *, 0> mergedAbbrevTable;
-  SmallVector<NamedEntry, 0> mergedEntries;
-  SmallVector<SmallVector<NamedEntry *, 0>, 0> bucketList;
+  static void readOffsets(InputChunk &inputChunk, OutputChunk &chunk,
+                          llvm::DWARFDataExtractor &namesExtractor,
+                          llvm::DataExtractor &strExtractor);
 };
 
 class GdbIndexSection final : public SyntheticSection {
@@ -1487,6 +1488,7 @@ struct InStruct {
   std::unique_ptr<IBTPltSection> ibtPlt;
   std::unique_ptr<RelocationBaseSection> relaPlt;
   // Non-SHF_ALLOC sections
+  std::unique_ptr<SyntheticSection> debugNames;
   std::unique_ptr<GdbIndexSection> gdbIndex;
   std::unique_ptr<StringTableSection> shStrTab;
   std::unique_ptr<StringTableSection> strTab;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index d2a9e872dab91e..240c16a4d8f69b 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1957,6 +1957,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
     // finalizeAddressDependentContent may have added local symbols to the
     // static symbol table.
     finalizeSynthetic(in.symTab.get());
+    finalizeSynthetic(in.debugNames.get());
     finalizeSynthetic(in.ppc64LongBranchTarget.get());
     finalizeSynthetic(in.armCmseSGSection.get());
   }
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index bf0c8e55d103e8..8efe877caf6aa4 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -32,6 +32,8 @@ ELF Improvements
 * ``GNU_PROPERTY_AARCH64_FEATURE_PAUTH`` notes, ``R_AARCH64_AUTH_ABS64`` and
   ``R_AARCH64_AUTH_RELATIVE`` relocations are now supported.
   (`#72714 <https://github.com/llvm/llvm-project/pull/72714>`_)
+* ``--debug-names`` is added to create a merged ``.debug_names`` index
+  from input ``.debug_names`` sections.
 
 Breaking changes
 ----------------
diff --git a/lld/test/ELF/debug-names-bad-aug-string.s b/lld/test/ELF/debug-names-bad-aug-string.s
index bf46f4ccef03db..1cf81cfef94dfc 100644
--- a/lld/test/ELF/debug-names-bad-aug-string.s
+++ b/lld/test/ELF/debug-names-bad-aug-string.s
@@ -1,37 +1,31 @@
-// This file was generated by copying debug-names.s and manually
-// editing the 'Header: augmentation string' in the .debug_names section.
+# This file was generated by copying debug-names.s and manually
+# editing the 'Header: augmentation string' in the .debug_names section.
 
-// REQUIRES: x86
-// RUN: rm -rf %t && split-file %s %t
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-bad-aug-string.s \
-// RUN:     -o %t/debug-names-bad-aug-string.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-2.s \
-// RUN:     -o %t/debug-names-2.o
-// RUN: ld.lld --debug-names %t/debug-names-bad-aug-string.o \
-// RUN:     %t/debug-names-2.o -o %t/debug-names-bad-aug-string
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-aug-string.s -o bad-aug-string.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
+# RUN: ld.lld --debug-names bad-aug-string.o b.o -o out
+# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
 
-// RUN: llvm-dwarfdump -debug-names %t/debug-names-bad-aug-string \
-// RUN:   | FileCheck -DFILE=%t/debug-names-bad-aug-string.o \
-// RUN:     -DFILE=%t/debug-names-2.o %s --check-prefix=DWARF
-
-// DWARF:      .debug_names contents:
-// DWARF:      Name Index @ 0x0 {
-// DWARF-NEXT:   Header {
-// DWARF-NEXT:     Length: 0xCC
-// DWARF-NEXT:     Format: DWARF32
-// DWARF-NEXT:     Version: 5
-// DWARF-NEXT:     CU count: 2
-// DWARF-NEXT:     Local TU count: 0
-// DWARF-NEXT:     Foreign TU count: 0
-// DWARF-NEXT:     Bucket count: 5
-// DWARF-NEXT:     Name count: 5
-// DWARF-NEXT:     Abbreviations table size: 0x1F
-// DWARF-NEXT:     Augmentation: '        '
-// DWARF:        Compilation Unit offsets [
-// DWARF-NEXT:     CU[0]: 0x00000000
-// DWARF-NEXT:     CU[1]: 0x0000000c
+# DWARF:      .debug_names contents:
+# DWARF:      Name Index @ 0x0 {
+# DWARF-NEXT:   Header {
+# DWARF-NEXT:     Length: 0xC0
+# DWARF-NEXT:     Format: DWARF32
+# DWARF-NEXT:     Version: 5
+# DWARF-NEXT:     CU count: 2
+# DWARF-NEXT:     Local TU count: 0
+# DWARF-NEXT:     Foreign TU count: 0
+# DWARF-NEXT:     Bucket count: 5
+# DWARF-NEXT:     Name count: 5
+# DWARF-NEXT:     Abbreviations table size: 0x1F
+# DWARF-NEXT:     Augmentation: ''
+# DWARF:        Compilation Unit offsets [
+# DWARF-NEXT:     CU[0]: 0x00000000
+# DWARF-NEXT:     CU[1]: 0x0000000c
 	
-#--- debug-names-bad-aug-string.s
+#--- bad-aug-string.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -159,19 +153,19 @@ _Z2f12t1:                               # @_Z2f12t1
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
 
-#--- debug-names-2.s
-// input file: debug-names-2.cpp
-// Generated with:
-// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-//     -S debug-names-2.cpp -o debug-names-2.s
+#--- b.s
+# input file: debug-names-2.cpp
+# Generated with:
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+#     -S debug-names-2.cpp -o b.s
 
-// debug-names-2.cpp contents:
+# debug-names-2.cpp contents:
 
-// struct t1 { };
-// int main() {
-//   t1 v1;
-// }
-//
+# struct t1 { };
+# int main() {
+#   t1 v1;
+# }
+#
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-bad-die-idx-sizes.s b/lld/test/ELF/debug-names-bad-die-idx-sizes.s
index e73d013f3b0edb..25a14d2e7a1912 100644
--- a/lld/test/ELF/debug-names-bad-die-idx-sizes.s
+++ b/lld/test/ELF/debug-names-bad-die-idx-sizes.s
@@ -1,19 +1,18 @@
-// This file was generated by first compiling main.cpp: 
-// clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-//      main.cpp
-// Then manually edit the .debug_names section. In the entries, change the
-// size of the DW_IDX_die_offset from '.long' to '.byte'.
+# This file was generated by first compiling main.cpp:
+# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+#      main.cpp
+# Then manually edit the .debug_names section. In the entries, change the
+# size of the DW_IDX_die_offset from '.long' to '.byte'.
 
-// Contents of main.cpp:
-// int main (int argc, char **argv) { }
+# Contents of main.cpp:
+# int main (int argc, char **argv) { }
 
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:   | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 
-// RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
-// RUN:   | FileCheck -DFILE=%t1.o %s
-
-// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
 
 	.text
 	.globl	main                            # -- Begin function main
diff --git a/lld/test/ELF/debug-names-bad-name-count.s b/lld/test/ELF/debug-names-bad-name-count.s
index cda4484b0e4c67..3410949b62fcd1 100644
--- a/lld/test/ELF/debug-names-bad-name-count.s
+++ b/lld/test/ELF/debug-names-bad-name-count.s
@@ -1,23 +1,23 @@
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
 	
-// RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
-// RUN:   FileCheck -DFILE=%t1.o %s
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:   FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 	
-// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
+# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
+# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
+# CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
 
-// This file was generated by first compiling main.cpp: 
-// clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-//      main.cpp
+# This file was generated by first compiling main.cpp:
+# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+#      main.cpp
 
-// Then manually edit .debug_names section: change value for
-// 'Header: name count' from 3 to 4.
+# Then manually edit .debug_names section: change value for
+# 'Header: name count' from 3 to 4.
 
-// Contents of main.cpp:
-// int main (int argc, char **argv) { }
+# Contents of main.cpp:
+# int main (int argc, char **argv) { }
 
 	.text
 	.globl	main                            # -- Begin function main
diff --git a/lld/test/ELF/debug-names-bad-offsets-sizes.s b/lld/test/ELF/debug-names-bad-offsets-sizes.s
index 3e7f36b2e2175e..e5b4570b216513 100644
--- a/lld/test/ELF/debug-names-bad-offsets-sizes.s
+++ b/lld/test/ELF/debug-names-bad-offsets-sizes.s
@@ -1,22 +1,22 @@
-// This file was generated by first compiling main.cpp: 
-// clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-//      main.cpp
+# This file was generated by first compiling main.cpp:
+# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
+#      main.cpp
 
-// Then manually edit .debug_names section. Change the sizes of
-// 'Offset in Bucket' values from '.long' to '.byte'.
+# Then manually edit .debug_names section. Change the sizes of
+# 'Offset in Bucket' values from '.long' to '.byte'.
 
-// Contentsof main.cpp:
-// int main (int argc, char **argv) { }
+# Contentsof main.cpp:
+# int main (int argc, char **argv) { }
 
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
 
-// RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
-// RUN:   | FileCheck -DFILE=%t1.o %s
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:   | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 
-// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
-// CHECK: error: {{.*}}:(.debug_names): encountered unexpected end of section while reading entry
+# CHECK:      error: [[FILE]]:(.debug_names): index entry is out of bounds
+# CHECK-NEXT: error: [[FILE]]:(.debug_names): index entry is out of bounds
+# CHECK-NEXT: error: [[FILE]]:(.debug_names): index entry is out of bounds
 
 	.text
 	.globl	main                            # -- Begin function main
diff --git a/lld/test/ELF/debug-names-bad-version.s b/lld/test/ELF/debug-names-bad-version.s
index eda1eaa03039bf..ac7d6853bfa623 100644
--- a/lld/test/ELF/debug-names-bad-version.s
+++ b/lld/test/ELF/debug-names-bad-version.s
@@ -1,19 +1,16 @@
-// This file was generated by copying debug-names.s and manually
-// editing the 'Header: version' in the .debug_names section (changed it from
-// 5 to 4).
+# This file was generated by copying debug-names.s and manually
+# editing the 'Header: version' in the .debug_names section (changed it from
+# 5 to 4).
 	
-// REQUIRES: x86
-// RUN: rm -rf %t && split-file %s %t
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-bad-version.s \
-// RUN:     -o %t/debug-names-bad-version.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-2.s \
-// RUN:     -o %t/debug-names-2.o
-// RUN: not ld.lld --debug-names %t/debug-names-bad-version.o \
-// RUN:     %t/debug-names-2.o -o /dev/null 2>&1 | FileCheck %s
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-version.s -o bad-version.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
+# RUN: not ld.lld --debug-names bad-version.o b.o 2>&1 | FileCheck %s --implicit-check-not=error:
 
-// CHECK: error: {{.*}}:(.debug_names): unsupported version
+# CHECK: error: bad-version.o:(.debug_names): unsupported version 4
 	
-#--- debug-names-bad-version.s
+#--- bad-version.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -176,19 +173,19 @@ _Z2f12t1:                               # @_Z2f12t1
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
 
-#--- debug-names-2.s
-// input file: debug-names-2.cpp
-// Generated with:
-// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-//     -S debug-names-2.cpp -o debug-names-2.s
+#--- b.s
+# input file: debug-names-2.cpp
+# Generated with:
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+#     -S debug-names-2.cpp -o b.s
 
-// debug-names-2.cpp contents:
+# debug-names-2.cpp contents:
 
-// struct t1 { };
-// int main() {
-//   t1 v1;
-// }
-//
+# struct t1 { };
+# int main() {
+#   t1 v1;
+# }
+#
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/debug-names-dwarf64.s b/lld/test/ELF/debug-names-dwarf64.s
index 790f2ddeba3972..515ea67945e616 100644
--- a/lld/test/ELF/debug-names-dwarf64.s
+++ b/lld/test/ELF/debug-names-dwarf64.s
@@ -1,16 +1,16 @@
-// This file was generated by:
-// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-//    -gdwarf64 -gpubnames main.cpp
+# This file was generated by:
+# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+#    -gdwarf64 -gpubnames main.cpp
 
-// Contents of main.cpp
-// int main (int argc, char **argv) { }
+# Contents of main.cpp
+# int main (int argc, char **argv) { }
 
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
-// RUN:   | FileCheck -DFILE=%t1.o %s
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:   | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 
-// CHECK: error: {{.*}}(.debug_names): unsupported DWARF64
+# CHECK: error: [[FILE]]:(.debug_names): unsupported DWARF64
 
 	.text
 	.globl	main                            # -- Begin function main
diff --git a/lld/test/ELF/debug-names-invalid-abbrev-code.s b/lld/test/ELF/debug-names-invalid-abbrev-code.s
index 54c0105ae56b5e..65d7f50f02d372 100644
--- a/lld/test/ELF/debug-names-invalid-abbrev-code.s
+++ b/lld/test/ELF/debug-names-invalid-abbrev-code.s
@@ -1,19 +1,18 @@
-// This file was generated by:
-// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-//    -gpubnames main.cpp
+# This file was generated by:
+# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+#    -gpubnames main.cpp
 
-// Then manually changing an abbrev code.
+# Then manually changing an abbrev code.
 
-// Contents of main.cpp
-// int main (int argc, char **argv) { }
+# Contents of main.cpp
+# int main (int argc, char **argv) { }
 
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
-// RUN:    | FileCheck -DFILE=%t1.o %s
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:    | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 
-// CHECK: error: {{.*}}(.debug_names): invalid abbrev code in entry
-// CHECK: error: {{.*}}(.debug_names): invalid abbrev code in entry
+# CHECK: error: [[FILE]]:(.debug_names): invalid abbrev code in entry
 
 	.text
 	.globl	main                            # -- Begin function main
diff --git a/lld/test/ELF/debug-names-invalid-attribute-2.s b/lld/test/ELF/debug-names-invalid-attribute-2.s
index 16706f0054c312..fbed524ef29f83 100644
--- a/lld/test/ELF/debug-names-invalid-attribute-2.s
+++ b/lld/test/ELF/debug-names-invalid-attribute-2.s
@@ -1,19 +1,19 @@
-// This file was generated by:
-// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-//    -gpubnames main.cpp
+# This file was generated by:
+# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+#    -gpubnames main.cpp
 
-// Then manually editing .debug_names section, commenting out a
-// DW_IDX_die_offset in an entry.
+# Then manually editing .debug_names section, commenting out a
+# DW_IDX_die_offset in an entry.
 
-// Contents of main.cpp
-// int main (int argc, char **argv) { }
+# Contents of main.cpp
+# int main (int argc, char **argv) { }
 
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
-// RUN:    | FileCheck -DFILE=%t1.o %s
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:    | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 
-// CHECK: error: {{.*}}(.debug_names): error while reading attributes: unexpected end of data at offset 0x80 while reading [0x7e, 0x82)
+# CHECK: error: [[FILE]]:(.debug_names): error while reading attributes: unexpected end of data at offset 0x80 while reading [0x7e, 0x82)
 
 	.text
 	.globl	main                            # -- Begin function main
diff --git a/lld/test/ELF/debug-names-invalid-attribute-3.s b/lld/test/ELF/debug-names-invalid-attribute-3.s
index 9b99cbe87d5a0e..465f0a92064b4c 100644
--- a/lld/test/ELF/debug-names-invalid-attribute-3.s
+++ b/lld/test/ELF/debug-names-invalid-attribute-3.s
@@ -1,21 +1,21 @@
-// This file was generated by:
-// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-//    -gpubnames main.cpp
+# This file was generated by:
+# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+#    -gpubnames main.cpp
 
-// Then manually changing the first .debug_names abbrev, so that the
-// DW_IDX_die_offset uses DW_FORM_flag_present (invalid) & the DW_IDX_parent
-// uses DW_FORM_ref4. Also updated the sizes of the values in the entry
-// that uses the abbrev, to match the sizes of the forms.
+# Then manually changing the first .debug_names abbrev, so that the
+# DW_IDX_die_offset uses DW_FORM_flag_present (invalid) & the DW_IDX_parent
+# uses DW_FORM_ref4. Also updated the sizes of the values in the entry
+# that uses the abbrev, to match the sizes of the forms.
 
-// Contents of main.cpp
-// int main (int argc, char **argv) { }
+# Contents of main.cpp
+# int main (int argc, char **argv) { }
 
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
-// RUN:   | FileCheck -DFILE=%t1.o %s
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:   | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 
-// CHECK: error: {{.*}}(.debug_names): invalid form for attribute
+# CHECK: error: [[FILE]]:(.debug_names): unrecognized form encoding 25 in abbrev table
 
 	.text
 	.globl	main                            # -- Begin function main
diff --git a/lld/test/ELF/debug-names-invalid-attribute.s b/lld/test/ELF/debug-names-invalid-attribute.s
index 303337c0295da7..19de19c313bcfe 100644
--- a/lld/test/ELF/debug-names-invalid-attribute.s
+++ b/lld/test/ELF/debug-names-invalid-attribute.s
@@ -1,12 +1,12 @@
-// Generated by copying debug-names.s and manually editing it to make some
-// of the abbrev attributes invalid.
+# Generated by copying debug-names.s and manually editing it to make some
+# of the abbrev attributes invalid.
 	
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: not ld.lld --debug-names %t1.o  -o /dev/null 2>&1 \
-// RUN:    | FileCheck -DFILE=%t1.o %s
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: not ld.lld --debug-names %t1.o  -o /dev/null 2>&1 \
+# RUN:    | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 
-// CHECK: error: {{.*}}:(.debug_names): unrecognized form encoding 16 in .debug_names abbrev table
+# CHECK: error: [[FILE]]:(.debug_names): unrecognized form encoding 16 in abbrev table
 
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
diff --git a/lld/test/ELF/debug-names-invalid-parent-idx.s b/lld/test/ELF/debug-names-invalid-parent-idx.s
index 698183880445a6..01e62fb99586a2 100644
--- a/lld/test/ELF/debug-names-invalid-parent-idx.s
+++ b/lld/test/ELF/debug-names-invalid-parent-idx.s
@@ -1,21 +1,20 @@
-// This file was generated by:
-// clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-//    -gpubnames main.cpp
+# This file was generated by:
+# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+#    -gpubnames main.cpp
 
-// Then manually editing .debug_names section, changing the form for a 
-// DW_IDX_parent from DW_FORM_flag_present to DW_FORM_ref1 (invalid).
+# Then manually editing .debug_names section, changing the form for a
+# DW_IDX_parent from DW_FORM_flag_present to DW_FORM_ref1 (invalid).
 
-// Contents of main.cpp
-// int main (int argc, char **argv) { }
+# Contents of main.cpp
+# int main (int argc, char **argv) { }
 
-// REQUIRES: x86
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-// RUN: not ld.lld --debug-names %t1.o  -o  /dev/null 2>&1 \
-// RUN:    | FileCheck -DFILE=%t1.o %s
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:    | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
 
-// CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
-// CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
-// CHECK: error: {{.*}}(.debug_names): invalid form for DW_IDX_parent
+# CHECK: error: [[FILE]]:(.debug_names): invalid form for DW_IDX_parent
+# CHECK: error: [[FILE]]:(.debug_names): invalid form for DW_IDX_parent
 
 	.text
 	.globl	main                            # -- Begin function main
diff --git a/lld/test/ELF/debug-names-parent-idx.s b/lld/test/ELF/debug-names-parent-idx.s
index b44455bb498ef8..22e382e45c9a10 100644
--- a/lld/test/ELF/debug-names-parent-idx.s
+++ b/lld/test/ELF/debug-names-parent-idx.s
@@ -1,192 +1,248 @@
-// debug-names-parent-idx.s generated with:
+# debug-names-parent-idx.s generated with:
 
-// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
-//     -S debug-names-parent-idx.cpp -o debug-names-parent-idx.s
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
+#     -S debug-names-parent-idx.cpp -o debug-names-parent-idx.s
 
-// foo.h contents:
+# foo.h contents:
 
-// int foo();
+# int foo();
 
-// struct foo {
-//   int x;
-//   char y;
-//   struct foo *foo_ptr;
-// };
+# struct foo {
+#   int x;
+#   char y;
+#   struct foo *foo_ptr;
+# };
 
-// namespace parent_test {
-//   int foo();
-// }
+# namespace parent_test {
+#   int foo();
+# }
 
-//  debug-names-parent-idx.cpp contents:
+#  debug-names-parent-idx.cpp contents:
 
-// #include "foo.h"
-// void bar (struct foo &foo, int junk) {
-//   foo.x = foo.x * junk;
-// }
-// int main (int argc, char** argv) {
-//   struct foo my_struct;
-//   my_struct.x = 10;
-//   my_struct.y = 'q';
-//   my_struct.foo_ptr = nullptr;
-//   int junk = foo();
-//   bar(my_struct, junk);
-//   int junk2 = parent_test::foo();
-//   return 0;
-// }
+# #include "foo.h"
+# void bar (struct foo &foo, int junk) {
+#   foo.x = foo.x * junk;
+# }
+# int main (int argc, char** argv) {
+#   struct foo my_struct;
+#   my_struct.x = 10;
+#   my_struct.y = 'q';
+#   my_struct.foo_ptr = nullptr;
+#   int junk = foo();
+#   bar(my_struct, junk);
+#   int junk2 = parent_test::foo();
+#   return 0;
+# }
 
-// REQUIRES: x86
-// RUN: rm -rf %t && split-file %s %t 
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-parent-idx.s \
-// RUN:     -o %t/debug-names-parent-idx.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-parent-idx-2.s \
-// RUN:     -o %t/debug-names-parent-idx-2.o
-// RUN: ld.lld --debug-names %t/debug-names-parent-idx.o \
-// RUN:     %t/debug-names-parent-idx-2.o -o %t/debug-names-parent-idx
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 debug-names-parent-idx.s \
+# RUN:     -o debug-names-parent-idx.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 debug-names-parent-idx-2.s \
+# RUN:     -o debug-names-parent-idx-2.o
+# RUN: ld.lld --debug-names debug-names-parent-idx.o \
+# RUN:     debug-names-parent-idx-2.o -o debug-names-parent-idx
 
-// RUN: llvm-dwarfdump -debug-names %t/debug-names-parent-idx \
-// RUN:    | FileCheck -DFILE=%t/debug-names-parent-idx.o \
-// RUN:      -DFILE=%t/debug-names-parent-idx-2.o %s --check-prefix=DWARF
+# RUN: llvm-dwarfdump -debug-names debug-names-parent-idx | FileCheck %s --check-prefix=DWARF
 
-// DWARF:      .debug_names contents:
-// DWARF:      Name Index @ 0x0 {
-// DWARF-NEXT:   Header {
-// DWARF-NEXT:     Length: 0x15C
-// DWARF-NEXT:     Format: DWARF32
-// DWARF-NEXT:     Version: 5
-// DWARF-NEXT:     CU count: 2
-// DWARF-NEXT:     Local TU count: 0
-// DWARF-NEXT:     Foreign TU count: 0
-// DWARF-NEXT:     Bucket count: 9
-// DWARF-NEXT:     Name count: 9
-// DWARF-NEXT:     Abbreviations table size: 0x33
-// DWARF-NEXT:     Augmentation: 'LLVM0700'
-// DWARF:        Compilation Unit offsets [
-// DWARF-NEXT:     CU[0]: 0x00000000
-// DWARF-NEXT:     CU[1]: 0x0000000c
-// DWARF:        Abbreviations [
-// DWARF-NEXT:     Abbreviation 0x1 {
-// DWARF-NEXT:       Tag: DW_TAG_base_type
-// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-// DWARF:          Abbreviation 0x2 {
-// DWARF-NEXT:       Tag: DW_TAG_subprogram
-// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-// DWARF:          Abbreviation 0x3 {
-// DWARF-NEXT:       Tag: DW_TAG_structure_type
-// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-// DWARF:          Abbreviation 0x4 {
-// DWARF-NEXT:       Tag: DW_TAG_subprogram
-// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_parent: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-// DWARF:          Abbreviation 0x5 {
-// DWARF-NEXT:       Tag: DW_TAG_namespace
-// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-// DWARF:            String: 0x00000093 "bar"
-// DWARF-NEXT:       Entry @ 0xf7 {
-// DWARF-NEXT:         Abbrev: 0x2
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF:            String: 0x000000a9 "int"
-// DWARF-NEXT:       Entry @ 0xfe {
-// DWARF-NEXT:         Abbrev: 0x1
-// DWARF-NEXT:         Tag: DW_TAG_base_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x0000008d
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF-NEXT:       }
-// DWARF-NEXT:       Entry @ 0x104 {
-// DWARF-NEXT:         Abbrev: 0x1
-// DWARF-NEXT:         Tag: DW_TAG_base_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF:            String: 0x000000ad "foo"
-// DWARF-NEXT:       Entry @ 0x10b {
-// DWARF-NEXT:         Abbrev: 0x3
-// DWARF-NEXT:         Tag: DW_TAG_structure_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000096
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF-NEXT:       }
-// DWARF-NEXT:       Entry @ 0x111 {
-// DWARF-NEXT:         Abbrev: 0x2
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF-NEXT:       }
-// DWARF-NEXT:       Entry @ 0x117 {
-// DWARF-NEXT:         Abbrev: 0x4
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
-// DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF-NEXT:       }
-// DWARF-NEXT:       Entry @ 0x121 {
-// DWARF-NEXT:         Abbrev: 0x3
-// DWARF-NEXT:         Tag: DW_TAG_structure_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000056
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF:            String: 0x00000196 "parent_test"
-// DWARF-NEXT:       Entry @ 0x128 {
-// DWARF-NEXT:         Abbrev: 0x5
-// DWARF-NEXT:         Tag: DW_TAG_namespace
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000043
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF:            String: 0x00000097 "_Z3barR3fooi"
-// DWARF-NEXT:       Entry @ 0x12f {
-// DWARF-NEXT:         Abbrev: 0x2
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF:            String: 0x000000a4 "main"
-// DWARF-NEXT:       Entry @ 0x136 {
-// DWARF-NEXT:         Abbrev: 0x2
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000046
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF:            String: 0x000000b5 "char"
-// DWARF-NEXT:       Entry @ 0x13d {
-// DWARF-NEXT:         Abbrev: 0x1
-// DWARF-NEXT:         Tag: DW_TAG_base_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x000000b8
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF-NEXT:       }
-// DWARF-NEXT:       Entry @ 0x143 {
-// DWARF-NEXT:         Abbrev: 0x1
-// DWARF-NEXT:         Tag: DW_TAG_base_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000078
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF:            String: 0x000001a2 "_ZN11parent_test3fooEv"
-// DWARF-NEXT:       Entry @ 0x14a {
-// DWARF-NEXT:         Abbrev: 0x4
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
-// DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF:            String: 0x0000018e "_Z3foov"
-// DWARF-NEXT:       Entry @ 0x155 {
-// DWARF-NEXT:         Abbrev: 0x2
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:      .debug_names contents:
+# DWARF:      Name Index @ 0x0 {
+# DWARF-NEXT:   Header {
+# DWARF-NEXT:     Length: 0x158
+# DWARF-NEXT:     Format: DWARF32
+# DWARF-NEXT:     Version: 5
+# DWARF-NEXT:     CU count: 2
+# DWARF-NEXT:     Local TU count: 0
+# DWARF-NEXT:     Foreign TU count: 0
+# DWARF-NEXT:     Bucket count: 9
+# DWARF-NEXT:     Name count: 9
+# DWARF-NEXT:     Abbreviations table size: 0x33
+# DWARF-NEXT:     Augmentation: 'LLVM0700'
+# DWARF:        Compilation Unit offsets [
+# DWARF-NEXT:     CU[0]: 0x00000000
+# DWARF-NEXT:     CU[1]: 0x0000000c
+# DWARF:        Abbreviations [
+# DWARF-NEXT:     Abbreviation 0x1 {
+# DWARF-NEXT:       Tag: DW_TAG_base_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x2 {
+# DWARF-NEXT:       Tag: DW_TAG_subprogram
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x3 {
+# DWARF-NEXT:       Tag: DW_TAG_structure_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x4 {
+# DWARF-NEXT:       Tag: DW_TAG_subprogram
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x5 {
+# DWARF-NEXT:       Tag: DW_TAG_namespace
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:        Bucket 0 [
+# DWARF-NEXT:     EMPTY
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 1 [
+# DWARF-NEXT:     Name 1 {
+# DWARF-NEXT:       Hash: 0xA974AA29
+# DWARF-NEXT:       String: 0x000001a2 "_ZN11parent_test3fooEv"
+# DWARF-NEXT:       Entry @ 0x14a {
+# DWARF-NEXT:         Abbrev: 0x4
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
+# DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:     Name 2 {
+# DWARF-NEXT:       Hash: 0xB5063D0B
+# DWARF-NEXT:       String: 0x0000018e "_Z3foov"
+# DWARF-NEXT:       Entry @ 0x155 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 2 [
+# DWARF-NEXT:     Name 3 {
+# DWARF-NEXT:       Hash: 0xB888030
+# DWARF-NEXT:       String: 0x000000a9 "int"
+# DWARF-NEXT:       Entry @ 0xfe {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x0000008d
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x104 {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 3 [
+# DWARF-NEXT:     Name 4 {
+# DWARF-NEXT:       Hash: 0xB8860BA
+# DWARF-NEXT:       String: 0x00000093 "bar"
+# DWARF-NEXT:       Entry @ 0xf7 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:     Name 5 {
+# DWARF-NEXT:       Hash: 0xB887389
+# DWARF-NEXT:       String: 0x000000ad "foo"
+# DWARF-NEXT:       Entry @ 0x10b {
+# DWARF-NEXT:         Abbrev: 0x3
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000096
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x111 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000027
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x117 {
+# DWARF-NEXT:         Abbrev: 0x4
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000045
+# DWARF-NEXT:         DW_IDX_parent: Entry @ 0x128
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x121 {
+# DWARF-NEXT:         Abbrev: 0x3
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000056
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 4 [
+# DWARF-NEXT:     EMPTY
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 5 [
+# DWARF-NEXT:     EMPTY
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 6 [
+# DWARF-NEXT:     EMPTY
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 7 [
+# DWARF-NEXT:     Name 6 {
+# DWARF-NEXT:       Hash: 0x7C9A7F6A
+# DWARF-NEXT:       String: 0x000000a4 "main"
+# DWARF-NEXT:       Entry @ 0x136 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000046
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 8 [
+# DWARF-NEXT:     Name 7 {
+# DWARF-NEXT:       Hash: 0xA7255AE
+# DWARF-NEXT:       String: 0x00000196 "parent_test"
+# DWARF-NEXT:       Entry @ 0x128 {
+# DWARF-NEXT:         Abbrev: 0x5
+# DWARF-NEXT:         Tag: DW_TAG_namespace
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000043
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:     Name 8 {
+# DWARF-NEXT:       Hash: 0x51007E98
+# DWARF-NEXT:       String: 0x00000097 "_Z3barR3fooi"
+# DWARF-NEXT:       Entry @ 0x12f {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:     Name 9 {
+# DWARF-NEXT:       Hash: 0x7C952063
+# DWARF-NEXT:       String: 0x000000b5 "char"
+# DWARF-NEXT:       Entry @ 0x13d {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x000000b8
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0x143 {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000078
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
 
 #--- debug-names-parent-idx.s
 	.text
@@ -425,41 +481,41 @@ main:                                   # @main
 .Lline_table_start0:
 	
 #--- debug-names-parent-idx-2.s
-// Generated with:
+# Generated with:
 
-// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
-//     -S debug-names-parent-idx-2.cpp -o debug-names-parent-idx-2.s
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
+#     -S debug-names-parent-idx-2.cpp -o debug-names-parent-idx-2.s
 
-// foo.h contents:
+# foo.h contents:
 
-// int foo();
+# int foo();
 
-//struct foo {
-//   int x;
-//   char y;
-//   struct foo *foo_ptr;
-// };
+#struct foo {
+#   int x;
+#   char y;
+#   struct foo *foo_ptr;
+# };
 
-// namespace parent_test {
-//   int foo();
-// }
+# namespace parent_test {
+#   int foo();
+# }
 
-// debug-names-parent-index-2.cpp contents:
+# debug-names-parent-index-2.cpp contents:
 
-// #include "foo.h"
-// int foo () {
-//   struct foo struct2;
-//   struct2.x = 1024;
-//   struct2.y = 'r';
-//   struct2.foo_ptr = nullptr;
-//   return struct2.x * (int) struct2.y;
-// }
+# #include "foo.h"
+# int foo () {
+#   struct foo struct2;
+#   struct2.x = 1024;
+#   struct2.y = 'r';
+#   struct2.foo_ptr = nullptr;
+#   return struct2.x * (int) struct2.y;
+# }
 
-// namespace parent_test {
-// int foo () {
-//   return 25;
-// }
-// }
+# namespace parent_test {
+# int foo () {
+#   return 25;
+# }
+# }
 
 	.text
 	.globl	_Z3foov                         # -- Begin function _Z3foov
diff --git a/lld/test/ELF/debug-names.s b/lld/test/ELF/debug-names.s
index baadadd98ebf4f..442653386977dc 100644
--- a/lld/test/ELF/debug-names.s
+++ b/lld/test/ELF/debug-names.s
@@ -1,119 +1,140 @@
-// debug_names.s was gGenerated with:
+# debug_names.s was gGenerated with:
 
-// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-//     -S debug-names.cpp -o debug-names.s
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+#     -S debug-names.cpp -o a.s
 
-// debug-names.cpp contents:
+# debug-names.cpp contents:
 
-// struct t1 { };
-// void f1(t1) { }
+# struct t1 { };
+# void f1(t1) { }
 
-// REQUIRES: x86
-// RUN: rm -rf %t && split-file %s %t
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names.s \
-// RUN:     -o %t/debug-names.o
-// RUN: llvm-mc -filetype=obj -triple=x86_64 %t/debug-names-2.s \
-// RUN:     -o %t/debug-names-2.o
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
 
-// RUN: ld.lld --debug-names --no-debug-names %t/debug-names.o \
-// RUN:     %t/debug-names-2.o -o %t/debug-names
-// RUN: llvm-readelf -SW %t/debug-names \
-// RUN:     | FileCheck %s --check-prefix=NO_DBG_NAMES
+# RUN: ld.lld --debug-names --no-debug-names a.o b.o -o out0
+# RUN: llvm-readelf -SW out0 | FileCheck %s --check-prefix=NO_MERGE
 	
-// NO_DBG_NAMES: .debug_names  PROGBITS  0000000000000000 [[#%x,]] 000110
+# NO_MERGE: Name              Type     Address          Off      Size   ES Flg Lk Inf Al
+# NO_MERGE: .debug_names      PROGBITS 0000000000000000 [[#%x,]] 000110 00      0   0  4
 	
-// RUN: ld.lld --debug-names %t/debug-names.o %t/debug-names-2.o \
-// RUN:     -o %t/debug-names
+# RUN: ld.lld --debug-names a.o b.o -o out
 
-// RUN: llvm-dwarfdump -debug-names %t/debug-names \
-// RUN:     | FileCheck %s --check-prefix=DWARF
-// RUN: llvm-readelf -SW %t/debug-names \
-// RUN:    | FileCheck -DFILE=%t/debug-names.o \
-// RUN:      -DFILE=%t/debug-names-2.o %s --check-prefix=READELF
+# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
+# RUN: llvm-readelf -SW out | FileCheck %s --check-prefix=READELF
 
-// READELF: .debug_names PROGBITS 0000000000000000 [[#%x,]] 0000d0
+# READELF: Name              Type     Address          Off      Size   ES Flg Lk Inf Al
+# READELF: .debug_names      PROGBITS 0000000000000000 [[#%x,]] 0000cc 00      0   0  4
 
-// DWARF:      .debug_names contents:
-// DWARF:      Name Index @ 0x0 {
-// DWARF-NEXT:   Header {
-// DWARF-NEXT:     Length: 0xCC
-// DWARF-NEXT:     Format: DWARF32
-// DWARF-NEXT:     Version: 5
-// DWARF-NEXT:     CU count: 2
-// DWARF-NEXT:     Local TU count: 0
-// DWARF-NEXT:     Foreign TU count: 0
-// DWARF-NEXT:     Bucket count: 5
-// DWARF-NEXT:     Name count: 5
-// DWARF-NEXT:     Abbreviations table size: 0x1F
-// DWARF-NEXT:     Augmentation: 'LLVM0700'
-// DWARF:        Compilation Unit offsets [
-// DWARF-NEXT:     CU[0]: 0x00000000
-// DWARF-NEXT:     CU[1]: 0x0000000c
-// DWARF:          Abbreviations [
-// DWARF-NEXT:     Abbreviation 0x1 {
-// DWARF:            Tag: DW_TAG_structure_type
-// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-// DWARF:          Abbreviation 0x2 {
-// DWARF-NEXT:       Tag: DW_TAG_subprogram
-// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-// DWARF:          Abbreviation 0x3 {
-// DWARF-NEXT:       Tag: DW_TAG_base_type
-// DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
-// DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
-// DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
-// DWARF:        Bucket 0 [
-// DWARF:        Bucket 1 [
-// DWARF:            String: 0x00000089 "f1"
-// DWARF-NEXT:       Entry @ 0xa3 {
-// DWARF-NEXT:         Abbrev: 0x2
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF:            String: 0x00000095 "t1"
-// DWARF-NEXT:       Entry @ 0xaa {
-// DWARF-NEXT:         Abbrev: 0x1
-// DWARF-NEXT:         Tag: DW_TAG_structure_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x0000003a
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF-NEXT:       }
-// DWARF-NEXT:       Entry @ 0xb0 {
-// DWARF-NEXT:         Abbrev: 0x1
-// DWARF-NEXT:         Tag: DW_TAG_structure_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000042
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF:            String: 0x00000130 "int"
-// DWARF-NEXT:       Entry @ 0xb7 {
-// DWARF-NEXT:         Abbrev: 0x3
-// DWARF-NEXT:         Tag: DW_TAG_base_type
-// DWARF-NEXT:         DW_IDX_die_offset: 0x0000003e
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
-// DWARF:        Bucket 2 [
-// DWARF:        Bucket 3 [
-// DWARF:            String: 0x0000008c "_Z2f12t1"
-// DWARF-NEXT:       Entry @ 0xbe {
-// DWARF-NEXT:         Abbrev: 0x2
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x00
-// DWARF:        Bucket 4 [
-// DWARF:            String: 0x0000012b "main"
-// DWARF-NEXT:       Entry @ 0xc5 {
-// DWARF-NEXT:         Abbrev: 0x2
-// DWARF-NEXT:         Tag: DW_TAG_subprogram
-// DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
-// DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
-// DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF:      .debug_names contents:
+# DWARF:      Name Index @ 0x0 {
+# DWARF-NEXT:   Header {
+# DWARF-NEXT:     Length: 0xC8
+# DWARF-NEXT:     Format: DWARF32
+# DWARF-NEXT:     Version: 5
+# DWARF-NEXT:     CU count: 2
+# DWARF-NEXT:     Local TU count: 0
+# DWARF-NEXT:     Foreign TU count: 0
+# DWARF-NEXT:     Bucket count: 5
+# DWARF-NEXT:     Name count: 5
+# DWARF-NEXT:     Abbreviations table size: 0x1F
+# DWARF-NEXT:     Augmentation: 'LLVM0700'
+# DWARF:        Compilation Unit offsets [
+# DWARF-NEXT:     CU[0]: 0x00000000
+# DWARF-NEXT:     CU[1]: 0x0000000c
+# DWARF:          Abbreviations [
+# DWARF-NEXT:     Abbreviation 0x1 {
+# DWARF:            Tag: DW_TAG_structure_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x2 {
+# DWARF-NEXT:       Tag: DW_TAG_subprogram
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x3 {
+# DWARF-NEXT:       Tag: DW_TAG_base_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:        Bucket 0 [
+# DWARF-NEXT:     EMPTY
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 1 [
+# DWARF-NEXT:     Name 1 {
+# DWARF-NEXT:       Hash: 0x59796A
+# DWARF-NEXT:       String: 0x00000095 "t1"
+# DWARF-NEXT:       Entry @ 0xaa {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x0000003a
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0xb0 {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000042
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:     Name 2 {
+# DWARF-NEXT:       Hash: 0x5355B2BE
+# DWARF-NEXT:       String: 0x0000008c "_Z2f12t1"
+# DWARF-NEXT:       Entry @ 0xbe {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:     Name 3 {
+# DWARF-NEXT:       Hash: 0x7C9A7F6A
+# DWARF-NEXT:       String: 0x0000012b "main"
+# DWARF-NEXT:       Entry @ 0xc5 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 2 [
+# DWARF-NEXT:     EMPTY
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 3 [
+# DWARF-NEXT:     Name 4 {
+# DWARF-NEXT:       Hash: 0xB888030
+# DWARF-NEXT:       String: 0x00000130 "int"
+# DWARF-NEXT:       Entry @ 0xb7 {
+# DWARF-NEXT:         Abbrev: 0x3
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x0000003e
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 4 [
+# DWARF-NEXT:     Name 5 {
+# DWARF-NEXT:       Hash: 0x59779C
+# DWARF-NEXT:       String: 0x00000089 "f1"
+# DWARF-NEXT:       Entry @ 0xa3 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
 
-#--- debug-names.s
+#--- a.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -241,18 +262,18 @@ _Z2f12t1:                               # @_Z2f12t1
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
 
-#--- debug-names-2.s
-// Generated with:
-// - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-//     -S debug-names-2.cpp -o debug-names-2.s
+#--- b.s
+# Generated with:
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+#     -S debug-names-2.cpp -o b.s
 
-// debug-names-2.cpp contents:
+# debug-names-2.cpp contents:
 
-// struct t1 { };
-// int main() {
-//   t1 v1;
-// }
-//
+# struct t1 { };
+# int main() {
+#   t1 v1;
+# }
+#
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
diff --git a/lld/test/ELF/driver.test b/lld/test/ELF/driver.test
index 49deb902aa0fd8..45d73607c8ac66 100644
--- a/lld/test/ELF/driver.test
+++ b/lld/test/ELF/driver.test
@@ -30,9 +30,10 @@
 # ERR2: error: -r and -pie may not be used together
 # ERR2: error: -r and --export-dynamic may not be used together
 
-# RUN: not ld.lld -r --icf=all --gdb-index %t -o /dev/null 2>&1 | FileCheck -check-prefix=ERR4 %s
+# RUN: not ld.lld -r --icf=all --gdb-index --debug-names %t -o /dev/null 2>&1 | FileCheck -check-prefix=ERR4 %s
 # ERR4: error: -r and --gdb-index may not be used together
 # ERR4: error: -r and --icf may not be used together
+# ERR4: error: -r and --debug-names may not be used together
 
 # RUN: not ld.lld -shared -pie %t -o /dev/null 2>&1 | FileCheck -check-prefix=ERR7 %s
 # ERR7: error: -shared and -pie may not be used together

>From 53b14cd9ce2b57da73d173fc876d2e9e199f5640 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Wed, 10 Apr 2024 23:33:53 -0700
Subject: [PATCH 15/23] [lld][ELF] Implement merged .debug_names section.

Migrate updates & fixes from maskray's lld-debug-names branch.
---
 lld/ELF/SyntheticSections.cpp | 47 +++++++++++++++++++++++++----------
 lld/ELF/SyntheticSections.h   | 16 ++++++------
 2 files changed, 43 insertions(+), 20 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index be307f1b001f31..3a71f8dd01cc60 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2784,6 +2784,7 @@ void DebugNamesBaseSection::parseDebugNames(
       const char *errMsg = nullptr;
       uint64_t offset = locs.EntriesBase + entryOffsets[i];
       while (offset < namesSec.Data.size() && namesSec.Data[offset] != 0) {
+        // Read & store all entries (for the same string).
         auto ie = makeThreadLocal<IndexEntry>();
         ie->poolOffset = offset;
         Error err = Error::success();
@@ -2871,9 +2872,9 @@ void DebugNamesBaseSection::parseDebugNames(
   }
 }
 
-// Compute the form for output DW_IDX_compile_unit attributes similar to
-// DIEInteger::BestForm. The input forms (often DW_FORM_data1) may not hold all
-// CU indices.
+// Compute the form for output DW_IDX_compile_unit attributes, similar to
+// DIEInteger::BestForm. The input form (often DW_FORM_data1) may not hold all
+// the merged CU indices.
 std::pair<uint8_t, dwarf::Form> static getMergedCuCountForm(
     uint32_t compUnitCount) {
   if (compUnitCount > UINT16_MAX)
@@ -2908,23 +2909,26 @@ void DebugNamesBaseSection::computeHdrAndAbbrevTable(
         hdr.AugmentationStringSize = nd.hdr.AugmentationStringSize;
         hdr.AugmentationString = nd.hdr.AugmentationString;
       } else if (hdr.AugmentationString != nd.hdr.AugmentationString) {
+        // There are conflicting augmentation strings, so it's best for the
+        // merged index to not use an augmentation string.
         hdr.AugmentationStringSize = 0;
         hdr.AugmentationString.clear();
       }
     }
   }
 
-  // Uniquify input abbrev tables and compute mapping from old abbrev code to
-  // new abbrev code.
+  // Create the merged abbrev table, uniquifyinng the input abbrev tables and
+  // computing mapping from old (per-cu) abbrev codes to new (merged) abbrev
+  // codes.
   FoldingSet<Abbrev> abbrevSet;
   // Determine the form for the DW_IDX_compile_unit attributes in the merged
-  // index. The input form may not encode all possible CU indices.
+  // index. The input form may not be big enough for all CU indices.
   const dwarf::Form cuAttrForm = getMergedCuCountForm(hdr.CompUnitCount).second;
   for (InputChunk &inputChunk : inputChunks) {
     for (auto [i, ni] : enumerate(*inputChunk.llvmDebugNames)) {
       for (const DWARFDebugNames::Abbrev &oldAbbrev : ni.getAbbrevs()) {
         // Canonicalize abbrev by placing the CU/TU index at the end,
-        // similar to `DebugNamesBaseSection::parse`.
+        // similar to 'parseDebugNames'.
         Abbrev abbrev;
         DWARFDebugNames::AttributeEncoding cuAttr(DW_IDX_compile_unit,
                                                   cuAttrForm);
@@ -2936,6 +2940,7 @@ void DebugNamesBaseSection::computeHdrAndAbbrevTable(
           else
             abbrev.attributes.push_back({a.Index, a.Form});
         }
+        // Put the CU/TU index at the end of the attributes list.
         abbrev.attributes.push_back(cuAttr);
 
         // Profile the abbrev, get or assign a new code, then record the abbrev
@@ -2945,6 +2950,7 @@ void DebugNamesBaseSection::computeHdrAndAbbrevTable(
         uint32_t newCode;
         void *insertPos;
         if (Abbrev *existing = abbrevSet.FindNodeOrInsertPos(id, insertPos)) {
+          // Found it; we've already seen an identical abbreviation.
           newCode = existing->code;
         } else {
           Abbrev *abbrev2 =
@@ -2985,17 +2991,22 @@ void DebugNamesBaseSection::Abbrev::Profile(FoldingSetNodeID &id) const {
 std::pair<uint32_t, uint32_t> DebugNamesBaseSection::computeEntryPool(
     MutableArrayRef<InputChunk> inputChunks) {
   TimeTraceScope timeScope("Merge .debug_names", "entry pool");
-  // Collect the compilation units for each unique name. Speed it up using
-  // multi-threading as the number of symbols can be in the order of millions.
+  // Collect and de-duplicate all the names (preserving all the entries).
+  // Speed it up using multithreading, as the number of symbols can be in the
+  // order of millions.
   const size_t concurrency =
       bit_floor(std::min<size_t>(config->threadCount, numShards));
   const size_t shift = 32 - countr_zero(numShards);
   const uint8_t cuAttrSize = getMergedCuCountForm(hdr.CompUnitCount).first;
   DenseMap<CachedHashStringRef, size_t> maps[numShards];
+
   parallelFor(0, concurrency, [&](size_t threadId) {
     for (auto i : seq(numChunks)) {
       InputChunk &inputChunk = inputChunks[i];
       for (NameData &nd : inputChunk.nameData) {
+        // Deduplicate the NameEntry records (based on the string/name),
+        // appending all IndexEntries from duplicate NameEntry records to
+        // the single preserved copy.
         for (NameEntry &ne : nd.nameEntries) {
           auto shardId = ne.hashValue >> shift;
           if ((shardId & (concurrency - 1)) != threadId)
@@ -3003,9 +3014,11 @@ std::pair<uint32_t, uint32_t> DebugNamesBaseSection::computeEntryPool(
 
           ne.chunkIdx = i;
           for (IndexEntry &ie : ne.entries()) {
+            // Update the IndexEntry's abbrev code to match the merged
+            // abbreviations.
             ie.abbrevCode = nd.abbrevCodeMap[ie.abbrevCode];
             // Update the DW_IDX_compile_unit attribute (the last one after
-            // canonicalization).
+            // canonicalization) to have correct merged offset value and size.
             auto &back = ie.attrValues.back();
             back.attrValue += inputChunk.baseCuIdx;
             back.attrSize = cuAttrSize;
@@ -3017,13 +3030,13 @@ std::pair<uint32_t, uint32_t> DebugNamesBaseSection::computeEntryPool(
           if (inserted)
             nameVec.push_back(std::move(ne));
           else
-            nameVec[it->second].indexEntries.append(ne.indexEntries);
+            nameVec[it->second].indexEntries.append(std::move(ne.indexEntries));
         }
       }
     }
   });
 
-  // Compute entry offsets parallelly. First, compute offsets relative to the
+  // Compute entry offsets in parallel. First, comptute offsets relative to the
   // current shard.
   uint32_t offsets[numShards];
   parallelFor(0, numShards, [&](size_t shard) {
@@ -3051,12 +3064,15 @@ std::pair<uint32_t, uint32_t> DebugNamesBaseSection::computeEntryPool(
     }
   });
 
-  // Update DW_IDX_parent attributes that use DW_FORM_ref4.
+  // Update the DW_IDX_parent entries that refer to real parents (have
+  // DW_FORM_ref4).
   parallelFor(0, numShards, [&](size_t shard) {
     for (NameEntry &ne : nameVecs[shard]) {
       for (IndexEntry &ie : ne.entries()) {
         if (!ie.parentEntry)
           continue;
+        // Abbrevs are indexed starting at 1; vector starts at 0. (abbrevCode
+        // corresponds to position in the merged table vector).
         const Abbrev *abbrev = abbrevTable[ie.abbrevCode - 1];
         for (auto i : seq(abbrev->attributes.size())) {
           DWARFDebugNames::AttributeEncoding a = abbrev->attributes[i];
@@ -3217,6 +3233,8 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
     }
   }
 
+  // Write the local TU list, then the foreign TU list..
+  // TODO: Fix this, once we get everything working without TUs.
   if (hdr.LocalTypeUnitCount || hdr.ForeignTypeUnitCount)
     warn(".debug_names: type units are not implemented");
 
@@ -3253,6 +3271,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
       buf += 4;
     }
   }
+
   // Then write the entry offsets.
   for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
     for (const NameEntry *ne : bucket) {
@@ -3269,6 +3288,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   // nameVecs order computed by `computeEntryPool`.
   for (auto &nameVec : nameVecs) {
     for (NameEntry &ne : nameVec) {
+      // Write all the entries for the string.
       for (const IndexEntry &ie : ne.entries()) {
         buf += encodeULEB128(ie.abbrevCode, buf);
         for (AttrValue value : ie.attrValues) {
@@ -4860,6 +4880,7 @@ template <class ELFT> void elf::createSyntheticSections() {
     in.debugNames = std::make_unique<DebugNamesSection<ELFT>>();
     add(*in.debugNames);
   }
+
   if (config->gdbIndex) {
     in.gdbIndex = GdbIndexSection::create<ELFT>();
     add(*in.gdbIndex);
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 2d37cbdefb4ade..3b813600721496 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -836,16 +836,17 @@ class DebugNamesBaseSection : public SyntheticSection {
     }
   };
 
-  // One name index described by an input .debug_names section. An InputChunk
-  // typically contains one single name index.
+  // The contents of one input .debug_names section. An InputChunk
+  // typically contains one NameData, but might contain more, especially
+  // in LTO builds.
   struct NameData {
     llvm::DWARFDebugNames::Header hdr;
     llvm::DenseMap<uint32_t, uint32_t> abbrevCodeMap;
     SmallVector<NameEntry, 0> nameEntries;
   };
 
-  // InputChunk and OutputChunk hold per-file contribution to the merged index.
-  // InputChunk instances will be discarded after `create` completes.
+  // InputChunk and OutputChunk hold per-file contributions to the merged index.
+  // InputChunk instances will be discarded after `init` completes.
   struct InputChunk {
     uint32_t baseCuIdx;
     LLDDWARFSection section;
@@ -874,11 +875,12 @@ class DebugNamesBaseSection : public SyntheticSection {
                       const llvm::DWARFDebugNames::Header &hdr,
                       const llvm::DWARFDebugNames::DWARFDebugNamesOffsets &)>
                       readOffsets);
-  void computeHdrAndAbbrevTable(MutableArrayRef<InputChunk>);
-  std::pair<uint32_t, uint32_t> computeEntryPool(MutableArrayRef<InputChunk>);
+  void computeHdrAndAbbrevTable(MutableArrayRef<InputChunk> inputChunks);
+  std::pair<uint32_t, uint32_t>
+  computeEntryPool(MutableArrayRef<InputChunk> inputChunks);
 
   // Input .debug_names sections for relocating string offsets in the name table
-  // in finalizeContents.
+  // in `finalizeContents`.
   SmallVector<InputSection *, 0> inputSections;
 
   llvm::DWARFDebugNames::Header hdr;

>From b5732b011503f464514f01c0df9e24b351598c09 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sun, 14 Apr 2024 10:07:17 -0700
Subject: [PATCH 16/23] [lld][ELF] Properly handle multiple (appended) indices
 within single .o

Current implementation does not properly handle reading multiple
(appended) .debug_names sections withih the same input .o file. This updates
the code that reads from the .debug_nemes section to add in the proper
offset when there are multiple appended .debug_names (could be generated
by LTO, e.g.).
---
 lld/ELF/SyntheticSections.cpp | 33 +++++++++++++++++++++++----------
 lld/ELF/SyntheticSections.h   |  2 ++
 2 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 3a71f8dd01cc60..12acbcc9a842ac 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2738,11 +2738,18 @@ void DebugNamesBaseSection::parseDebugNames(
     InputChunk &inputChunk, OutputChunk &chunk,
     DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor,
     function_ref<SmallVector<uint32_t, 0>(
+        uint32_t numCus,
+        uint32_t niOffset,
         const DWARFDebugNames::Header &,
         const DWARFDebugNames::DWARFDebugNamesOffsets &)>
         readOffsets) {
   const LLDDWARFSection namesSec = inputChunk.section;
   DenseMap<uint32_t, IndexEntry *> offsetMap;
+  // Number of CUs seen in previous NameIndex sections within current chunk.
+  uint32_t numCus = 0;
+  // Offset of current NameIndex section from start of .debug_names section in
+  // current chunk.
+  uint32_t niOffset = 0;
   for (const DWARFDebugNames::NameIndex &ni : *inputChunk.llvmDebugNames) {
     NameData &nd = inputChunk.nameData.emplace_back();
     nd.hdr = ni.getHeader();
@@ -2760,20 +2767,21 @@ void DebugNamesBaseSection::parseDebugNames(
     const uint32_t hdrSize =
         getDebugNamesHeaderSize(nd.hdr.AugmentationStringSize);
     auto locs = findDebugNamesOffsets(hdrSize, nd.hdr);
-    if (locs.EntriesBase > namesExtractor.getData().size()) {
+    if (locs.EntriesBase + niOffset > namesExtractor.getData().size()) {
       errorOrWarn(toString(namesSec.sec) +
                   Twine(": index entry is out of bounds"));
       return;
     }
 
-    SmallVector<uint32_t, 0> entryOffsets = readOffsets(nd.hdr, locs);
+    SmallVector<uint32_t, 0> entryOffsets = readOffsets(numCus, niOffset,
+                                                        nd.hdr, locs);
 
     // Read the entry pool.
     offsetMap.clear();
     nd.nameEntries.resize(nd.hdr.NameCount);
     for (auto i : seq(nd.hdr.NameCount)) {
       NameEntry &ne = nd.nameEntries[i];
-      uint64_t strOffset = locs.StringOffsetsBase + i * dwarfSize;
+      uint64_t strOffset = locs.StringOffsetsBase + niOffset + i * dwarfSize;
       ne.stringOffset = strOffset;
       uint64_t strp = namesExtractor.getRelocatedValue(dwarfSize, &strOffset);
       StringRef name = strExtractor.getCStrRef(&strp);
@@ -2782,7 +2790,7 @@ void DebugNamesBaseSection::parseDebugNames(
 
       // Read a series of index entries that end with abbreviation code 0.
       const char *errMsg = nullptr;
-      uint64_t offset = locs.EntriesBase + entryOffsets[i];
+      uint64_t offset = locs.EntriesBase + niOffset + entryOffsets[i];
       while (offset < namesSec.Data.size() && namesSec.Data[offset] != 0) {
         // Read & store all entries (for the same string).
         auto ie = makeThreadLocal<IndexEntry>();
@@ -2869,6 +2877,8 @@ void DebugNamesBaseSection::parseDebugNames(
     for (NameEntry &ne : nd.nameEntries)
       for (IndexEntry &ie : ne.entries())
         ie.parentEntry = offsetMap.lookup(ie.parentOffset);
+    numCus += nd.hdr.CompUnitCount;
+    niOffset += nd.hdr.UnitLength + 4;
   }
 }
 
@@ -3003,7 +3013,8 @@ std::pair<uint32_t, uint32_t> DebugNamesBaseSection::computeEntryPool(
   parallelFor(0, concurrency, [&](size_t threadId) {
     for (auto i : seq(numChunks)) {
       InputChunk &inputChunk = inputChunks[i];
-      for (NameData &nd : inputChunk.nameData) {
+      for (auto j : seq(inputChunk.nameData.size())) {
+        NameData &nd = inputChunk.nameData[j];
         // Deduplicate the NameEntry records (based on the string/name),
         // appending all IndexEntries from duplicate NameEntry records to
         // the single preserved copy.
@@ -3020,7 +3031,7 @@ std::pair<uint32_t, uint32_t> DebugNamesBaseSection::computeEntryPool(
             // Update the DW_IDX_compile_unit attribute (the last one after
             // canonicalization) to have correct merged offset value and size.
             auto &back = ie.attrValues.back();
-            back.attrValue += inputChunk.baseCuIdx;
+            back.attrValue += inputChunk.baseCuIdx + j;
             back.attrSize = cuAttrSize;
           }
 
@@ -3156,17 +3167,19 @@ template <class ELFT> DebugNamesSection<ELFT>::DebugNamesSection() {
     parseDebugNames(
         inputChunk, chunk, namesExtractor, strExtractor,
         [&chunk, namesData = dobj.getNamesSection().Data.data()](
+            uint32_t numCus,
+            uint32_t niOffset,
             const DWARFDebugNames::Header &hdr,
             const DWARFDebugNames::DWARFDebugNamesOffsets &locs) {
           // Read CU offsets.
-          const char *p = namesData + locs.CUsBase;
-          chunk.compUnits.resize_for_overwrite(hdr.CompUnitCount);
+          const char *p = namesData + niOffset + locs.CUsBase;
+          chunk.compUnits.resize_for_overwrite(numCus + hdr.CompUnitCount);
           for (auto i : seq(hdr.CompUnitCount))
-            chunk.compUnits[i] =
+            chunk.compUnits[i + numCus] =
                 endian::readNext<uint32_t, ELFT::Endianness, unaligned>(p);
 
           // Read entry offsets.
-          p = namesData + locs.EntryOffsetsBase;
+          p = namesData + niOffset + locs.EntryOffsetsBase;
           SmallVector<uint32_t, 0> entryOffsets;
           entryOffsets.resize_for_overwrite(hdr.NameCount);
           for (auto i : seq(hdr.NameCount))
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 3b813600721496..f15658e779bc20 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -872,6 +872,8 @@ class DebugNamesBaseSection : public SyntheticSection {
                   llvm::DWARFDataExtractor &namesExtractor,
                   llvm::DataExtractor &strExtractor,
                   llvm::function_ref<SmallVector<uint32_t, 0>(
+                      uint32_t numCUs,
+                      uint32_t niOffset,
                       const llvm::DWARFDebugNames::Header &hdr,
                       const llvm::DWARFDebugNames::DWARFDebugNamesOffsets &)>
                       readOffsets);

>From 5b4566d6a3ca317d923647778e7a150df821be21 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sun, 14 Apr 2024 13:16:06 -0700
Subject: [PATCH 17/23] [lld][ELF] Add & update tests:

New tests:
   - ppc-debug-names.s : Tests .debug_names merging for big endiamn & 32-bit
   - debug-names-missing-parent.s: Tests .debug_names merging works when a
      DW_IDX_parent attribute is missing.
Updated debug-names-bad-die-idx-sizes.s & debug-names-bad-name-count.s:
   - Added tests with --noinhibit_execc to generate warnings & not die

Fixed names of source files in debug_names.s & the new/updated tests.
---
 lld/test/ELF/debug-names-bad-die-idx-sizes.s |  32 +-
 lld/test/ELF/debug-names-bad-name-count.s    |  21 +-
 lld/test/ELF/debug-names-missing-parent.s    | 223 ++++++++++
 lld/test/ELF/debug-names.s                   |  50 +--
 lld/test/ELF/ppc32-debug-names.s             | 417 +++++++++++++++++++
 5 files changed, 698 insertions(+), 45 deletions(-)
 create mode 100644 lld/test/ELF/debug-names-missing-parent.s
 create mode 100644 lld/test/ELF/ppc32-debug-names.s

diff --git a/lld/test/ELF/debug-names-bad-die-idx-sizes.s b/lld/test/ELF/debug-names-bad-die-idx-sizes.s
index 25a14d2e7a1912..850629b3086603 100644
--- a/lld/test/ELF/debug-names-bad-die-idx-sizes.s
+++ b/lld/test/ELF/debug-names-bad-die-idx-sizes.s
@@ -1,10 +1,10 @@
-# This file was generated by first compiling main.cpp:
-# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-#      main.cpp
+# This file was generated by first compiling a.cpp:
+# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='/proc/self/cwd' a.cpp
+
 # Then manually edit the .debug_names section. In the entries, change the
 # size of the DW_IDX_die_offset from '.long' to '.byte'.
 
-# Contents of main.cpp:
+# Contents of a.cpp:
 # int main (int argc, char **argv) { }
 
 # REQUIRES: x86
@@ -14,6 +14,12 @@
 
 # CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
 
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: ld.lld --debug-names --noinhibit-exec %t1.o -o /dev/null 2>&1 \
+# RUN:    | FileCheck -DFILE=%t1.o %s --check-prefix=WARN
+
+# WARN: warning: [[FILE]]:(.debug_names): index entry is out of bounds
+
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
@@ -59,21 +65,21 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=130
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=135
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=139
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=144
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=149
+	.asciz	"char"                          # string offset=144
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -143,7 +149,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-bad-name-count.s b/lld/test/ELF/debug-names-bad-name-count.s
index 3410949b62fcd1..f660bc0512cc6f 100644
--- a/lld/test/ELF/debug-names-bad-name-count.s
+++ b/lld/test/ELF/debug-names-bad-name-count.s
@@ -1,22 +1,29 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
-	
+
 # RUN: not ld.lld --debug-names %t1.o -o /dev/null 2>&1 \
-# RUN:   FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
-	
+# RUN:   | FileCheck -DFILE=%t1.o --implicit-check-not=error: %s
+
 # CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
 # CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
 # CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
 # CHECK: error: [[FILE]]:(.debug_names): index entry is out of bounds
 
-# This file was generated by first compiling main.cpp:
-# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-#      main.cpp
+# RUN: ld.lld --noinhibit-exec --debug-names %t1.o -o /dev/null 2>&1 \
+# RUN:   | FileCheck -DFILE=%t1.o %s --check-prefix=WARN
+
+# WARN: warning: [[FILE]]:(.debug_names): index entry is out of bounds
+# WARN: warning: [[FILE]]:(.debug_names): index entry is out of bounds
+# WARN: warning: [[FILE]]:(.debug_names): index entry is out of bounds
+# WARN: warning: [[FILE]]:(.debug_names): index entry is out of bounds
+
+# This file was generated by first compiling a.cpp:
+# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='/proc/self/cwd' a.cpp
 
 # Then manually edit .debug_names section: change value for
 # 'Header: name count' from 3 to 4.
 
-# Contents of main.cpp:
+# Contents of a.cpp:
 # int main (int argc, char **argv) { }
 
 	.text
diff --git a/lld/test/ELF/debug-names-missing-parent.s b/lld/test/ELF/debug-names-missing-parent.s
new file mode 100644
index 00000000000000..5c7e0ad839a00e
--- /dev/null
+++ b/lld/test/ELF/debug-names-missing-parent.s
@@ -0,0 +1,223 @@
+# debug-names-missing-parent was generated with
+
+# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+#     -gpubnames a.cpp
+
+# a.cpp contents:
+
+# int main (int argc, char **argv) { }
+
+# Then manually edit the .s file:
+# - Remove DW_IDX_parent & DW_FORM_flag_present from DW_TAG_subprogram abbrev
+# - Remove DW_IDX_parent value from entry for 'main'
+
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t1.o
+# RUN: ld.lld --debug-names %t1.o -o %t
+# RUN: llvm-dwarfdump --debug-names %t | FileCheck %s --check-prefix=DWARF
+
+# DWARF:      .debug_names contents:
+# DWARF:      Name Index @ 0x0 {
+# DWARF-NEXT:     Header {
+# DWARF-NEXT:       Length: 0x8A
+# DWARF-NEXT:       Format: DWARF32
+# DWARF-NEXT:       Version: 5
+# DWARF-NEXT:       CU count: 1
+# DWARF-NEXT:       Local TU count: 0
+# DWARF-NEXT:       Foreign TU count: 0
+# DWARF-NEXT:       Bucket count: 3
+# DWARF-NEXT:       Name count: 3
+# DWARF-NEXT:       Abbreviations table size: 0x13
+# DWARF-NEXT:       Augmentation: 'LLVM0700'
+# DWARF:        Compilation Unit offsets [
+# DWARF-NEXT:      CU[0]: 0x00000000
+# DWARF:        Abbreviations [
+# DWARF-NEXT:      Abbreviation 0x1 {
+# DWARF:            Tag: DW_TAG_base_type
+# DWARF-NEXT:        DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:        DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:        DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x2 {
+# DWARF-NEXT:        Tag: DW_TAG_subprogram
+# DWARF-NEXT:        DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:        DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:        Bucket 0 [
+# DWARF-NEXT:      EMPTY
+# DWARF-NEXT:    ]
+# DWARF-NEXT:    Bucket 1 [
+# DWARF-NEXT:      Name 1 {
+# DWARF-NEXT:        Hash: 0x7C9A7F6A
+# DWARF-NEXT:        String: 0x0000007f "main"
+# DWARF-NEXT:        Entry @ 0x7a {
+# DWARF-NEXT:          Abbrev: 0x2
+# DWARF-NEXT:          Tag: DW_TAG_subprogram
+# DWARF-NEXT:          DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:          DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:        }
+# DWARF-NEXT:        Entry @ 0x80 {
+# DWARF-NEXT:          Abbrev: 0x1
+# DWARF-NEXT:          Tag: DW_TAG_base_type
+# DWARF-NEXT:          DW_IDX_die_offset: 0x00000049
+# DWARF-NEXT:          DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:          DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:        }
+# DWARF-NEXT:      }
+# DWARF-NEXT:    ]
+# DWARF-NEXT:    Bucket 2 [
+# DWARF-NEXT:      Name 2 {
+# DWARF-NEXT:        Hash: 0xB888030
+# DWARF-NEXT:        String: 0x00000084 "int"
+# DWARF-NEXT:        Entry @ 0x73 {
+# DWARF-NEXT:          Abbrev: 0x1
+# DWARF-NEXT:          Tag: DW_TAG_base_type
+# DWARF-NEXT:          DW_IDX_die_offset: 0x00000049
+# DWARF-NEXT:          DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:          DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:        }
+# DWARF-NEXT:      }
+# DWARF-NEXT:      Name 3 {
+# DWARF-NEXT:        Hash: 0x7C952063
+# DWARF-NEXT:        String: 0x00000092 "char"
+# DWARF-NEXT:        Entry @ 0x87 {
+# DWARF-NEXT:          Abbrev: 0x1
+# DWARF-NEXT:          Tag: DW_TAG_base_type
+# DWARF-NEXT:          DW_IDX_die_offset: 0x00000057
+# DWARF-NEXT:          DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:          DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:        }
+# DWARF-NEXT:      }
+# DWARF-NEXT:    ]
+
+# --- a.s
+
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+	movl	%edi, -4(%rbp)
+	movq	%rsi, -16(%rbp)
+.Ltmp0:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	36                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+	.asciz	"a.cpp"                         # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=110
+.Linfo_string3:
+	.asciz	"main"                          # string offset=127
+.Linfo_string4:
+	.asciz	"int"                           # string offset=132
+.Linfo_string5:
+	.asciz	"argc"                          # string offset=136
+.Linfo_string6:
+	.asciz	"argv"                          # string offset=141
+.Linfo_string7:
+	.asciz	"char"                          # string offset=146
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	2                               # Bucket 2
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	2090147939                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Linfo_string7                  # String in Bucket 2: char
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	73                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	87                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: char
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names.s b/lld/test/ELF/debug-names.s
index 442653386977dc..eb35281a224f0d 100644
--- a/lld/test/ELF/debug-names.s
+++ b/lld/test/ELF/debug-names.s
@@ -1,9 +1,9 @@
-# debug_names.s was gGenerated with:
+# debug-names.s was generated with:
 
 # - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-#     -S debug-names.cpp -o a.s
+#     -S a.cpp -o a.s
 
-# debug-names.cpp contents:
+# a.cpp contents:
 
 # struct t1 { };
 # void f1(t1) { }
@@ -65,7 +65,7 @@
 # DWARF-NEXT:   Bucket 1 [
 # DWARF-NEXT:     Name 1 {
 # DWARF-NEXT:       Hash: 0x59796A
-# DWARF-NEXT:       String: 0x00000095 "t1"
+# DWARF-NEXT:       String: 0x0000008b "t1"
 # DWARF-NEXT:       Entry @ 0xaa {
 # DWARF-NEXT:         Abbrev: 0x1
 # DWARF-NEXT:         Tag: DW_TAG_structure_type
@@ -83,7 +83,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 2 {
 # DWARF-NEXT:       Hash: 0x5355B2BE
-# DWARF-NEXT:       String: 0x0000008c "_Z2f12t1"
+# DWARF-NEXT:       String: 0x00000082 "_Z2f12t1"
 # DWARF-NEXT:       Entry @ 0xbe {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -94,7 +94,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 3 {
 # DWARF-NEXT:       Hash: 0x7C9A7F6A
-# DWARF-NEXT:       String: 0x0000012b "main"
+# DWARF-NEXT:       String: 0x00000115 "main"
 # DWARF-NEXT:       Entry @ 0xc5 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -110,7 +110,7 @@
 # DWARF-NEXT:   Bucket 3 [
 # DWARF-NEXT:     Name 4 {
 # DWARF-NEXT:       Hash: 0xB888030
-# DWARF-NEXT:       String: 0x00000130 "int"
+# DWARF-NEXT:       String: 0x0000011a "int"
 # DWARF-NEXT:       Entry @ 0xb7 {
 # DWARF-NEXT:         Abbrev: 0x3
 # DWARF-NEXT:         Tag: DW_TAG_base_type
@@ -123,7 +123,7 @@
 # DWARF-NEXT:   Bucket 4 [
 # DWARF-NEXT:     Name 5 {
 # DWARF-NEXT:       Hash: 0x59779C
-# DWARF-NEXT:       String: 0x00000089 "f1"
+# DWARF-NEXT:       String: 0x0000007f "f1"
 # DWARF-NEXT:       Entry @ 0xa3 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -177,17 +177,17 @@ _Z2f12t1:                               # @_Z2f12t1
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names.cpp"               # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=120
+	.asciz	"debug-names-test"              # string offset=110
 .Linfo_string3:
-	.asciz	"f1"                            # string offset=137
+	.asciz	"f1"                            # string offset=127
 .Linfo_string4:
-	.asciz	"_Z2f12t1"                      # string offset=140
+	.asciz	"_Z2f12t1"                      # string offset=130
 .Linfo_string5:
-	.asciz	"t1"                            # string offset=149
+	.asciz	"t1"                            # string offset=139
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -256,7 +256,7 @@ _Z2f12t1:                               # @_Z2f12t1
                                         # End of list: _Z2f12t1
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
@@ -265,9 +265,9 @@ _Z2f12t1:                               # @_Z2f12t1
 #--- b.s
 # Generated with:
 # - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-#     -S debug-names-2.cpp -o b.s
+#     -S b.cpp -o b.s
 
-# debug-names-2.cpp contents:
+# b.cpp contents:
 
 # struct t1 { };
 # int main() {
@@ -317,19 +317,19 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names-2.cpp"             # string offset=104
+	.asciz	"b.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=122
+	.asciz	"debug-names-test"              # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=139
+	.asciz	"main"                          # string offset=127
 .Linfo_string4:
-	.asciz	"int"                           # string offset=144
+	.asciz	"int"                           # string offset=132
 .Linfo_string5:
-	.asciz	"v1"                            # string offset=148
+	.asciz	"v1"                            # string offset=136
 .Linfo_string6:
-	.asciz	"t1"                            # string offset=151
+	.asciz	"t1"                            # string offset=139
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -407,7 +407,7 @@ main:                                   # @main
                                         # End of list: int
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/ppc32-debug-names.s b/lld/test/ELF/ppc32-debug-names.s
new file mode 100644
index 00000000000000..40d7cc5b4fa2f7
--- /dev/null
+++ b/lld/test/ELF/ppc32-debug-names.s
@@ -0,0 +1,417 @@
+# ppc-debug-names.s was generated with:
+
+# - clang++ --target=powerpc -g -O0 -gpubnames \
+#     -fdebug-compilation-dir='debug-names-test' -S a.cpp -o a.s
+
+# a.cpp contents:
+
+# struct t1 { };
+# void f1(t1) { }
+
+# REQUIRES: ppc
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=powerpc a.s -o a.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc b.s -o b.o
+
+# RUN: ld.lld --debug-names --no-debug-names a.o b.o -o out0
+# RUN: llvm-readelf -SW out0 | FileCheck %s --check-prefix=NO_MERGE
+	
+# NO_MERGE: Name              Type     Address          Off      Size   ES Flg Lk Inf Al
+# NO_MERGE: .debug_names      PROGBITS 00000000 [[#%x,]] 000110 00      0   0  4
+	
+# RUN: ld.lld --debug-names a.o b.o -o out
+
+# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
+# RUN: llvm-readelf -SW out | FileCheck %s --check-prefix=READELF
+
+# READELF: Name              Type     Address          Off      Size   ES Flg Lk Inf Al
+# READELF: .debug_names      PROGBITS 00000000 [[#%x,]] 0000cc 00      0   0  4
+
+# DWARF:      file format elf32-powerpc
+# DWARF:      .debug_names contents:
+# DWARF:      Name Index @ 0x0 {
+# DWARF-NEXT:   Header {
+# DWARF-NEXT:     Length: 0xC8
+# DWARF-NEXT:     Format: DWARF32
+# DWARF-NEXT:     Version: 5
+# DWARF-NEXT:     CU count: 2
+# DWARF-NEXT:     Local TU count: 0
+# DWARF-NEXT:     Foreign TU count: 0
+# DWARF-NEXT:     Bucket count: 5
+# DWARF-NEXT:     Name count: 5
+# DWARF-NEXT:     Abbreviations table size: 0x1F
+# DWARF-NEXT:     Augmentation: 'LLVM0700'
+# DWARF:        Compilation Unit offsets [
+# DWARF-NEXT:     CU[0]: 0x00000000
+# DWARF-NEXT:     CU[1]: 0x0000000c
+# DWARF:          Abbreviations [
+# DWARF-NEXT:     Abbreviation 0x1 {
+# DWARF:            Tag: DW_TAG_structure_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x2 {
+# DWARF-NEXT:       Tag: DW_TAG_subprogram
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:          Abbreviation 0x3 {
+# DWARF-NEXT:       Tag: DW_TAG_base_type
+# DWARF-NEXT:       DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT:       DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT:       DW_IDX_compile_unit: DW_FORM_data1
+# DWARF:        Bucket 0 [
+# DWARF-NEXT:     EMPTY
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 1 [
+# DWARF-NEXT:     Name 1 {
+# DWARF-NEXT:       Hash: 0x59796A
+# DWARF-NEXT:       String: 0x0000008b "t1"
+# DWARF-NEXT:       Entry @ 0xaa {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x0000003a
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:       Entry @ 0xb0 {
+# DWARF-NEXT:         Abbrev: 0x1
+# DWARF-NEXT:         Tag: DW_TAG_structure_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000042
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:     Name 2 {
+# DWARF-NEXT:       Hash: 0x5355B2BE
+# DWARF-NEXT:       String: 0x00000082 "_Z2f12t1"
+# DWARF-NEXT:       Entry @ 0xbe {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:     Name 3 {
+# DWARF-NEXT:       Hash: 0x7C9A7F6A
+# DWARF-NEXT:       String: 0x00000111 "main"
+# DWARF-NEXT:       Entry @ 0xc5 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 2 [
+# DWARF-NEXT:     EMPTY
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 3 [
+# DWARF-NEXT:     Name 4 {
+# DWARF-NEXT:       Hash: 0xB888030
+# DWARF-NEXT:       String: 0x00000116 "int"
+# DWARF-NEXT:       Entry @ 0xb7 {
+# DWARF-NEXT:         Abbrev: 0x3
+# DWARF-NEXT:         Tag: DW_TAG_base_type
+# DWARF-NEXT:         DW_IDX_die_offset: 0x0000003e
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x01
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+# DWARF-NEXT:   Bucket 4 [
+# DWARF-NEXT:     Name 5 {
+# DWARF-NEXT:       Hash: 0x59779C
+# DWARF-NEXT:       String: 0x0000007f "f1"
+# DWARF-NEXT:       Entry @ 0xa3 {
+# DWARF-NEXT:         Abbrev: 0x2
+# DWARF-NEXT:         Tag: DW_TAG_subprogram
+# DWARF-NEXT:         DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT:         DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT:         DW_IDX_compile_unit: 0x00
+# DWARF-NEXT:       }
+# DWARF-NEXT:     }
+# DWARF-NEXT:   ]
+
+#--- a.s
+	.text
+	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
+	.p2align	2
+	.type	_Z2f12t1, at function
+_Z2f12t1:                               # @_Z2f12t1
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	stwu 1, -16(1)
+	stw 31, 12(1)
+	.cfi_def_cfa_offset 16
+	.cfi_offset r31, -4
+	mr	31, 1
+	.cfi_def_cfa_register r31
+.Ltmp0:
+	lwz 31, 12(1)
+	addi 1, 1, 16
+	blr
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z2f12t1, .Lfunc_end0-.Lfunc_begin0
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	4                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	28                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+	.asciz	"a.cpp"                         # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=110
+.Linfo_string3:
+	.asciz	"f1"                            # string offset=127
+.Linfo_string4:
+	.asciz	"_Z2f12t1"                      # string offset=130
+.Linfo_string5:
+	.asciz	"t1"                            # string offset=139
+.Laddr_table_base0:
+	.long	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863324                         # Hash in Bucket 1
+	.long	5863786                         # Hash in Bucket 1
+	.long	1398125246                      # Hash in Bucket 2
+	.long	.Linfo_string3                  # String in Bucket 1: f1
+	.long	.Linfo_string5                  # String in Bucket 1: t1
+	.long	.Linfo_string4                  # String in Bucket 2: _Z2f12t1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: f1
+.Lnames2:
+.L0:
+	.byte	2                               # Abbreviation code
+	.long	58                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z2f12t1
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
+
+#--- b.s
+# Generated with:
+# - clang++ --target=powerpc -g -O0 -gpubnames \
+#     -fdebug-compilation-dir='debug-names-test' -S b.cpp -o b.s
+
+# b.cpp contents:
+
+# struct t1 { };
+# int main() {
+#   t1 v1;
+# }
+#
+	.text
+	.globl	main                            # -- Begin function main
+	.p2align	2
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	stwu 1, -16(1)
+	stw 31, 12(1)
+	.cfi_def_cfa_offset 16
+	.cfi_offset r31, -4
+	mr	31, 1
+	.cfi_def_cfa_register r31
+	li 3, 0
+.Ltmp0:
+	lwz 31, 12(1)
+	addi 1, 1, 16
+	blr
+.Ltmp1:
+.Lfunc_end0:
+	.size	main, .Lfunc_end0-.Lfunc_begin0
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	4                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	32                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+	.asciz	"b.cpp"                         # string offset=104
+.Linfo_string2:
+	.asciz	"debug-names-test"              # string offset=110
+.Linfo_string3:
+	.asciz	"main"                          # string offset=127
+.Linfo_string4:
+	.asciz	"int"                           # string offset=132
+.Linfo_string5:
+	.asciz	"v1"                            # string offset=136
+.Linfo_string6:
+	.asciz	"t1"                            # string offset=139
+.Laddr_table_base0:
+	.long	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	3                               # Header: bucket count
+	.long	3                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	3                               # Bucket 2
+	.long	5863786                         # Hash in Bucket 1
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 2
+	.long	.Linfo_string6                  # String in Bucket 1: t1
+	.long	.Linfo_string3                  # String in Bucket 1: main
+	.long	.Linfo_string4                  # String in Bucket 2: int
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames2:
+.L1:
+	.byte	1                               # Abbreviation code
+	.long	66                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames0:
+.L2:
+	.byte	2                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames1:
+.L0:
+	.byte	3                               # Abbreviation code
+	.long	62                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:

>From 8d712883000fef2d21832c1d600e64da4fc19548 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sun, 14 Apr 2024 13:37:38 -0700
Subject: [PATCH 18/23] [lld][ELF] Fix clang-format issues.

Fix clang-format issues.
---
 lld/ELF/SyntheticSections.cpp | 11 ++++-------
 lld/ELF/SyntheticSections.h   |  3 +--
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 12acbcc9a842ac..910ace1c757b43 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2738,9 +2738,7 @@ void DebugNamesBaseSection::parseDebugNames(
     InputChunk &inputChunk, OutputChunk &chunk,
     DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor,
     function_ref<SmallVector<uint32_t, 0>(
-        uint32_t numCus,
-        uint32_t niOffset,
-        const DWARFDebugNames::Header &,
+        uint32_t numCus, uint32_t niOffset, const DWARFDebugNames::Header &,
         const DWARFDebugNames::DWARFDebugNamesOffsets &)>
         readOffsets) {
   const LLDDWARFSection namesSec = inputChunk.section;
@@ -2773,8 +2771,8 @@ void DebugNamesBaseSection::parseDebugNames(
       return;
     }
 
-    SmallVector<uint32_t, 0> entryOffsets = readOffsets(numCus, niOffset,
-                                                        nd.hdr, locs);
+    SmallVector<uint32_t, 0> entryOffsets =
+        readOffsets(numCus, niOffset, nd.hdr, locs);
 
     // Read the entry pool.
     offsetMap.clear();
@@ -3167,8 +3165,7 @@ template <class ELFT> DebugNamesSection<ELFT>::DebugNamesSection() {
     parseDebugNames(
         inputChunk, chunk, namesExtractor, strExtractor,
         [&chunk, namesData = dobj.getNamesSection().Data.data()](
-            uint32_t numCus,
-            uint32_t niOffset,
+            uint32_t numCus, uint32_t niOffset,
             const DWARFDebugNames::Header &hdr,
             const DWARFDebugNames::DWARFDebugNamesOffsets &locs) {
           // Read CU offsets.
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index f15658e779bc20..534fac005e0b8b 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -872,8 +872,7 @@ class DebugNamesBaseSection : public SyntheticSection {
                   llvm::DWARFDataExtractor &namesExtractor,
                   llvm::DataExtractor &strExtractor,
                   llvm::function_ref<SmallVector<uint32_t, 0>(
-                      uint32_t numCUs,
-                      uint32_t niOffset,
+                      uint32_t numCUs, uint32_t niOffset,
                       const llvm::DWARFDebugNames::Header &hdr,
                       const llvm::DWARFDebugNames::DWARFDebugNamesOffsets &)>
                       readOffsets);

>From 7607c4d40149128f848055613edf9c3cf9ae890d Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Sun, 14 Apr 2024 16:29:47 -0700
Subject: [PATCH 19/23] [lld][ELF] Clean up file & directory names in tests.

Shorten file names to a.cpp, b.cpp, etc.
Replace debug-names-test directory with /proc/self/cwd.
---
 lld/test/ELF/debug-names-bad-aug-string.s     |  45 ++++----
 lld/test/ELF/debug-names-bad-name-count.s     |  18 +--
 lld/test/ELF/debug-names-bad-offsets-sizes.s  |  25 ++--
 lld/test/ELF/debug-names-bad-version.s        |  85 ++++----------
 lld/test/ELF/debug-names-dwarf64.s            |  24 ++--
 .../ELF/debug-names-invalid-abbrev-code.s     |  23 ++--
 .../ELF/debug-names-invalid-attribute-2.s     |  23 ++--
 .../ELF/debug-names-invalid-attribute-3.s     |  23 ++--
 lld/test/ELF/debug-names-invalid-attribute.s  |  16 +--
 lld/test/ELF/debug-names-invalid-parent-idx.s |  25 ++--
 lld/test/ELF/debug-names-missing-parent.s     |  21 ++--
 lld/test/ELF/debug-names-parent-idx.s         | 109 +++++++++---------
 lld/test/ELF/debug-names.s                    |  35 +++---
 lld/test/ELF/ppc32-debug-names.s              |  33 +++---
 14 files changed, 233 insertions(+), 272 deletions(-)

diff --git a/lld/test/ELF/debug-names-bad-aug-string.s b/lld/test/ELF/debug-names-bad-aug-string.s
index 1cf81cfef94dfc..62ed64aa5b5703 100644
--- a/lld/test/ELF/debug-names-bad-aug-string.s
+++ b/lld/test/ELF/debug-names-bad-aug-string.s
@@ -3,9 +3,9 @@
 
 # REQUIRES: x86
 # RUN: rm -rf %t && split-file %s %t && cd %t
-# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-aug-string.s -o bad-aug-string.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
 # RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
-# RUN: ld.lld --debug-names bad-aug-string.o b.o -o out
+# RUN: ld.lld --debug-names a.o b.o -o out
 # RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
 
 # DWARF:      .debug_names contents:
@@ -24,8 +24,8 @@
 # DWARF:        Compilation Unit offsets [
 # DWARF-NEXT:     CU[0]: 0x00000000
 # DWARF-NEXT:     CU[1]: 0x0000000c
-	
-#--- bad-aug-string.s
+
+#--- a.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -68,17 +68,17 @@ _Z2f12t1:                               # @_Z2f12t1
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names.cpp"               # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=120
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"f1"                            # string offset=137
+	.asciz	"f1"                            # string offset=125
 .Linfo_string4:
-	.asciz	"_Z2f12t1"                      # string offset=140
+	.asciz	"_Z2f12t1"                      # string offset=128
 .Linfo_string5:
-	.asciz	"t1"                            # string offset=149
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -147,19 +147,18 @@ _Z2f12t1:                               # @_Z2f12t1
                                         # End of list: _Z2f12t1
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
 
 #--- b.s
-# input file: debug-names-2.cpp
 # Generated with:
-# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-#     -S debug-names-2.cpp -o b.s
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwdt' \
+#     -S b.cpp -o b.s
 
-# debug-names-2.cpp contents:
+# b.cpp contents:
 
 # struct t1 { };
 # int main() {
@@ -209,19 +208,19 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names-2.cpp"             # string offset=104
+	.asciz	"b.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=122
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=139
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=144
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"v1"                            # string offset=148
+	.asciz	"v1"                            # string offset=134
 .Linfo_string6:
-	.asciz	"t1"                            # string offset=151
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -299,7 +298,7 @@ main:                                   # @main
                                         # End of list: int
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-bad-name-count.s b/lld/test/ELF/debug-names-bad-name-count.s
index f660bc0512cc6f..11a418177e1c16 100644
--- a/lld/test/ELF/debug-names-bad-name-count.s
+++ b/lld/test/ELF/debug-names-bad-name-count.s
@@ -71,21 +71,21 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=130
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=135
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=139
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=144
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=149
+	.asciz	"char"                          # string offset=144
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -155,7 +155,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-bad-offsets-sizes.s b/lld/test/ELF/debug-names-bad-offsets-sizes.s
index e5b4570b216513..e70a6215f3c874 100644
--- a/lld/test/ELF/debug-names-bad-offsets-sizes.s
+++ b/lld/test/ELF/debug-names-bad-offsets-sizes.s
@@ -1,11 +1,10 @@
-# This file was generated by first compiling main.cpp:
-# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='debug-names-test' \
-#      main.cpp
+# This file was generated by first compiling a.cpp:
+# clang++ -g -O0 -S -gpubnames -fdebug-compilation-dir='/proc/self/cwd' a.cpp
 
 # Then manually edit .debug_names section. Change the sizes of
 # 'Offset in Bucket' values from '.long' to '.byte'.
 
-# Contentsof main.cpp:
+# Contents of a.cpp:
 # int main (int argc, char **argv) { }
 
 # REQUIRES: x86
@@ -63,21 +62,21 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=130
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=135
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=139
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=144
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=149
+	.asciz	"char"                          # string offset=144
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -147,7 +146,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-bad-version.s b/lld/test/ELF/debug-names-bad-version.s
index ac7d6853bfa623..6f6ff2d507a9b2 100644
--- a/lld/test/ELF/debug-names-bad-version.s
+++ b/lld/test/ELF/debug-names-bad-version.s
@@ -4,13 +4,14 @@
 	
 # REQUIRES: x86
 # RUN: rm -rf %t && split-file %s %t && cd %t
-# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-version.s -o bad-version.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
 # RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
-# RUN: not ld.lld --debug-names bad-version.o b.o 2>&1 | FileCheck %s --implicit-check-not=error:
+# RUN: not ld.lld --debug-names a.o b.o 2>&1 \
+# RUN:    | FileCheck -DFILE=a.o %s --implicit-check-not=error:
 
-# CHECK: error: bad-version.o:(.debug_names): unsupported version 4
-	
-#--- bad-version.s
+# CHECK: error: [[FILE]]:(.debug_names): unsupported version 4
+
+#--- a.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -45,41 +46,6 @@ _Z2f12t1:                               # @_Z2f12t1
 	.byte	1                               # DWARF Unit Type
 	.byte	8                               # Address Size (in bytes)
 	.long	.debug_abbrev                   # Offset Into Abbrev. Section
-	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
-	.byte	0                               # DW_AT_producer
-	.short	33                              # DW_AT_language
-	.byte	1                               # DW_AT_name
-	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
-	.long	.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
-	.long	.Laddr_table_base0              # DW_AT_addr_base
-	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
-	.byte	0                               # DW_AT_low_pc
-	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
-	.byte	1                               # DW_AT_frame_base
-	.byte	86
-	.byte	3                               # DW_AT_linkage_name
-	.byte	4                               # DW_AT_name
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-                                        # DW_AT_external
-	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
-	.byte	2                               # DW_AT_location
-	.byte	145
-	.byte	127
-	.byte	0                               # DW_AT_decl_file
-	.byte	2                               # DW_AT_decl_line
-	.long	58                              # DW_AT_type
-	.byte	0                               # End Of Children Mark
-	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
-	.byte	5                               # DW_AT_calling_convention
-	.byte	5                               # DW_AT_name
-	.byte	1                               # DW_AT_byte_size
-	.byte	0                               # DW_AT_decl_file
-	.byte	1                               # DW_AT_decl_line
-	.byte	0                               # End Of Children Mark
 .Ldebug_info_end0:
 	.section	.debug_str_offsets,"", at progbits
 	.long	28                              # Length of String Offsets Set
@@ -88,17 +54,17 @@ _Z2f12t1:                               # @_Z2f12t1
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names.cpp"               # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=120
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"f1"                            # string offset=137
+	.asciz	"f1"                            # string offset=125
 .Linfo_string4:
-	.asciz	"_Z2f12t1"                      # string offset=140
+	.asciz	"_Z2f12t1"                      # string offset=128
 .Linfo_string5:
-	.asciz	"t1"                            # string offset=149
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -167,19 +133,18 @@ _Z2f12t1:                               # @_Z2f12t1
                                         # End of list: _Z2f12t1
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
 
 #--- b.s
-# input file: debug-names-2.cpp
 # Generated with:
-# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-#     -S debug-names-2.cpp -o b.s
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' \
+#     -S b.cpp -o b.s
 
-# debug-names-2.cpp contents:
+# b.cpp contents:
 
 # struct t1 { };
 # int main() {
@@ -217,7 +182,7 @@ main:                                   # @main
 .Lcu_begin0:
 	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
 .Ldebug_info_start0:
-	.short	5                               # DWARF version number
+	.short	4                               # DWARF version number
 	.byte	1                               # DWARF Unit Type
 	.byte	8                               # Address Size (in bytes)
 	.long	.debug_abbrev                   # Offset Into Abbrev. Section
@@ -229,19 +194,19 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names-2.cpp"             # string offset=104
+	.asciz	"b.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=122
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=139
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=144
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"v1"                            # string offset=148
+	.asciz	"v1"                            # string offset=134
 .Linfo_string6:
-	.asciz	"t1"                            # string offset=151
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -319,7 +284,7 @@ main:                                   # @main
                                         # End of list: int
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-dwarf64.s b/lld/test/ELF/debug-names-dwarf64.s
index 515ea67945e616..310e9379bf9aed 100644
--- a/lld/test/ELF/debug-names-dwarf64.s
+++ b/lld/test/ELF/debug-names-dwarf64.s
@@ -1,8 +1,8 @@
 # This file was generated by:
-# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-#    -gdwarf64 -gpubnames main.cpp
+# clang++ -g -O0 -S -fdebug-compilation-dir='/proc/self/cwd' \
+#    -gdwarf64 -gpubnames a.cpp
 
-# Contents of main.cpp
+# Contents of a.cpp
 # int main (int argc, char **argv) { }
 
 # REQUIRES: x86
@@ -59,21 +59,21 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 9b37e60051f362e8e22c88785239fd5dfbfdf105)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=130
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=135
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=139
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=144
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=149
+	.asciz	"char"                          # string offset=144
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -144,7 +144,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 9b37e60051f362e8e22c88785239fd5dfbfdf105)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-invalid-abbrev-code.s b/lld/test/ELF/debug-names-invalid-abbrev-code.s
index 65d7f50f02d372..5290eb86e276d2 100644
--- a/lld/test/ELF/debug-names-invalid-abbrev-code.s
+++ b/lld/test/ELF/debug-names-invalid-abbrev-code.s
@@ -1,10 +1,9 @@
 # This file was generated by:
-# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-#    -gpubnames main.cpp
+# clang++ -g -O0 -S -fdebug-compilation-dir='/proc/self/cwd' -gpubnames a.cpp
 
 # Then manually changing an abbrev code.
 
-# Contents of main.cpp
+# Contents of a.cpp
 # int main (int argc, char **argv) { }
 
 # REQUIRES: x86
@@ -59,21 +58,21 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=130
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=135
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=139
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=144
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=149
+	.asciz	"char"                          # string offset=144
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -143,7 +142,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-invalid-attribute-2.s b/lld/test/ELF/debug-names-invalid-attribute-2.s
index fbed524ef29f83..6ea8c5e1e3f693 100644
--- a/lld/test/ELF/debug-names-invalid-attribute-2.s
+++ b/lld/test/ELF/debug-names-invalid-attribute-2.s
@@ -1,11 +1,10 @@
 # This file was generated by:
-# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-#    -gpubnames main.cpp
+# clang++ -g -O0 -S -fdebug-compilation-dir='/proc/self/cwd' -gpubnames a.cpp
 
 # Then manually editing .debug_names section, commenting out a
 # DW_IDX_die_offset in an entry.
 
-# Contents of main.cpp
+# Contents of a.cpp
 # int main (int argc, char **argv) { }
 
 # REQUIRES: x86
@@ -60,21 +59,21 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=130
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=135
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=139
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=144
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=149
+	.asciz	"char"                          # string offset=144
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -143,7 +142,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-invalid-attribute-3.s b/lld/test/ELF/debug-names-invalid-attribute-3.s
index 465f0a92064b4c..1674498df7e30f 100644
--- a/lld/test/ELF/debug-names-invalid-attribute-3.s
+++ b/lld/test/ELF/debug-names-invalid-attribute-3.s
@@ -1,13 +1,12 @@
 # This file was generated by:
-# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-#    -gpubnames main.cpp
+# clang++ -g -O0 -S -fdebug-compilation-dir='/proc/self/cwd' -gpubnames a.cpp
 
 # Then manually changing the first .debug_names abbrev, so that the
 # DW_IDX_die_offset uses DW_FORM_flag_present (invalid) & the DW_IDX_parent
 # uses DW_FORM_ref4. Also updated the sizes of the values in the entry
 # that uses the abbrev, to match the sizes of the forms.
 
-# Contents of main.cpp
+# Contents of a.cpp
 # int main (int argc, char **argv) { }
 
 # REQUIRES: x86
@@ -62,21 +61,21 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=130
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=135
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=139
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=144
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=149
+	.asciz	"char"                          # string offset=144
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -146,7 +145,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-invalid-attribute.s b/lld/test/ELF/debug-names-invalid-attribute.s
index 19de19c313bcfe..52b9c6f7ade95e 100644
--- a/lld/test/ELF/debug-names-invalid-attribute.s
+++ b/lld/test/ELF/debug-names-invalid-attribute.s
@@ -1,4 +1,4 @@
-# Generated by copying debug-names.s and manually editing it to make some
+# Generated by copying a.s from debug-names.s and manually editing it to make some
 # of the abbrev attributes invalid.
 	
 # REQUIRES: x86
@@ -50,17 +50,17 @@ _Z2f12t1:                               # @_Z2f12t1
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names.cpp"               # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=120
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"f1"                            # string offset=137
+	.asciz	"f1"                            # string offset=125
 .Linfo_string4:
-	.asciz	"_Z2f12t1"                      # string offset=140
+	.asciz	"_Z2f12t1"                      # string offset=128
 .Linfo_string5:
-	.asciz	"t1"                            # string offset=149
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -137,7 +137,7 @@ _Z2f12t1:                               # @_Z2f12t1
                                         # End of list: _Z2f12t1
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-invalid-parent-idx.s b/lld/test/ELF/debug-names-invalid-parent-idx.s
index 01e62fb99586a2..5db11ee10b32ea 100644
--- a/lld/test/ELF/debug-names-invalid-parent-idx.s
+++ b/lld/test/ELF/debug-names-invalid-parent-idx.s
@@ -1,11 +1,11 @@
 # This file was generated by:
-# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
-#    -gpubnames main.cpp
+# clang++ -g -O0 -S -fdebug-compilation-dir='/proc/self/cwd' \
+#    -gpubnames a.cpp
 
 # Then manually editing .debug_names section, changing the form for a
 # DW_IDX_parent from DW_FORM_flag_present to DW_FORM_ref1 (invalid).
 
-# Contents of main.cpp
+# Contents of a.cpp
 # int main (int argc, char **argv) { }
 
 # REQUIRES: x86
@@ -22,6 +22,7 @@
 	.type	main, at function
 main:                                   # @main
 .Lfunc_begin0:
+	.file	0 "/proc/self/cwd" "a.cpp" md5 0xb5f4ba9cf33ca376f9981b3284aa785f
 	.cfi_startproc
 # %bb.0:                                # %entry
 	pushq	%rbp
@@ -61,21 +62,21 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"main.cpp"                      # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=113
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=130
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=135
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=139
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=144
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=149
+	.asciz	"char"                          # string offset=144
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -145,7 +146,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git d33d5630b281debe6eabd67e323bcf767340fb6a)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names-missing-parent.s b/lld/test/ELF/debug-names-missing-parent.s
index 5c7e0ad839a00e..480d047504934a 100644
--- a/lld/test/ELF/debug-names-missing-parent.s
+++ b/lld/test/ELF/debug-names-missing-parent.s
@@ -1,6 +1,6 @@
 # debug-names-missing-parent was generated with
 
-# clang++ -g -O0 -S -fdebug-compilation-dir='debug-names-test' \
+# clang++ -g -O0 -S -fdebug-compilation-dir='/proc/self/cwd' \
 #     -gpubnames a.cpp
 
 # a.cpp contents:
@@ -47,7 +47,7 @@
 # DWARF-NEXT:    Bucket 1 [
 # DWARF-NEXT:      Name 1 {
 # DWARF-NEXT:        Hash: 0x7C9A7F6A
-# DWARF-NEXT:        String: 0x0000007f "main"
+# DWARF-NEXT:        String: 0x0000007d "main"
 # DWARF-NEXT:        Entry @ 0x7a {
 # DWARF-NEXT:          Abbrev: 0x2
 # DWARF-NEXT:          Tag: DW_TAG_subprogram
@@ -66,7 +66,7 @@
 # DWARF-NEXT:    Bucket 2 [
 # DWARF-NEXT:      Name 2 {
 # DWARF-NEXT:        Hash: 0xB888030
-# DWARF-NEXT:        String: 0x00000084 "int"
+# DWARF-NEXT:        String: 0x00000082 "int"
 # DWARF-NEXT:        Entry @ 0x73 {
 # DWARF-NEXT:          Abbrev: 0x1
 # DWARF-NEXT:          Tag: DW_TAG_base_type
@@ -77,7 +77,7 @@
 # DWARF-NEXT:      }
 # DWARF-NEXT:      Name 3 {
 # DWARF-NEXT:        Hash: 0x7C952063
-# DWARF-NEXT:        String: 0x00000092 "char"
+# DWARF-NEXT:        String: 0x0000008b "char"
 # DWARF-NEXT:        Entry @ 0x87 {
 # DWARF-NEXT:          Abbrev: 0x1
 # DWARF-NEXT:          Tag: DW_TAG_base_type
@@ -139,17 +139,18 @@ main:                                   # @main
 .Linfo_string1:
 	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=110
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=127
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=132
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"argc"                          # string offset=136
+	.asciz	"argc"                          # string offset=134
 .Linfo_string6:
-	.asciz	"argv"                          # string offset=141
+	.asciz	"argv"                          # string offset=139
 .Linfo_string7:
-	.asciz	"char"                          # string offset=146
+	.asciz	"char"                          # string offset=144
+	.section	.debug_str_offsets,"", at progbits
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
diff --git a/lld/test/ELF/debug-names-parent-idx.s b/lld/test/ELF/debug-names-parent-idx.s
index 22e382e45c9a10..64551aa02e59f5 100644
--- a/lld/test/ELF/debug-names-parent-idx.s
+++ b/lld/test/ELF/debug-names-parent-idx.s
@@ -1,7 +1,7 @@
 # debug-names-parent-idx.s generated with:
 
-# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
-#     -S debug-names-parent-idx.cpp -o debug-names-parent-idx.s
+# clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' -S \
+#    a.cpp -o a.s
 
 # foo.h contents:
 
@@ -17,7 +17,7 @@
 #   int foo();
 # }
 
-#  debug-names-parent-idx.cpp contents:
+#  a.cpp contents:
 
 # #include "foo.h"
 # void bar (struct foo &foo, int junk) {
@@ -36,14 +36,11 @@
 
 # REQUIRES: x86
 # RUN: rm -rf %t && split-file %s %t && cd %t
-# RUN: llvm-mc -filetype=obj -triple=x86_64 debug-names-parent-idx.s \
-# RUN:     -o debug-names-parent-idx.o
-# RUN: llvm-mc -filetype=obj -triple=x86_64 debug-names-parent-idx-2.s \
-# RUN:     -o debug-names-parent-idx-2.o
-# RUN: ld.lld --debug-names debug-names-parent-idx.o \
-# RUN:     debug-names-parent-idx-2.o -o debug-names-parent-idx
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
+# RUN: ld.lld --debug-names a.o b.o -o out
 
-# RUN: llvm-dwarfdump -debug-names debug-names-parent-idx | FileCheck %s --check-prefix=DWARF
+# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
 
 # DWARF:      .debug_names contents:
 # DWARF:      Name Index @ 0x0 {
@@ -93,7 +90,7 @@
 # DWARF-NEXT:   Bucket 1 [
 # DWARF-NEXT:     Name 1 {
 # DWARF-NEXT:       Hash: 0xA974AA29
-# DWARF-NEXT:       String: 0x000001a2 "_ZN11parent_test3fooEv"
+# DWARF-NEXT:       String: 0x00000174 "_ZN11parent_test3fooEv"
 # DWARF-NEXT:       Entry @ 0x14a {
 # DWARF-NEXT:         Abbrev: 0x4
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -104,7 +101,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 2 {
 # DWARF-NEXT:       Hash: 0xB5063D0B
-# DWARF-NEXT:       String: 0x0000018e "_Z3foov"
+# DWARF-NEXT:       String: 0x00000160 "_Z3foov"
 # DWARF-NEXT:       Entry @ 0x155 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -117,7 +114,7 @@
 # DWARF-NEXT:   Bucket 2 [
 # DWARF-NEXT:     Name 3 {
 # DWARF-NEXT:       Hash: 0xB888030
-# DWARF-NEXT:       String: 0x000000a9 "int"
+# DWARF-NEXT:       String: 0x00000093 "int"
 # DWARF-NEXT:       Entry @ 0xfe {
 # DWARF-NEXT:         Abbrev: 0x1
 # DWARF-NEXT:         Tag: DW_TAG_base_type
@@ -137,7 +134,7 @@
 # DWARF-NEXT:   Bucket 3 [
 # DWARF-NEXT:     Name 4 {
 # DWARF-NEXT:       Hash: 0xB8860BA
-# DWARF-NEXT:       String: 0x00000093 "bar"
+# DWARF-NEXT:       String: 0x0000007d "bar"
 # DWARF-NEXT:       Entry @ 0xf7 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -148,7 +145,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 5 {
 # DWARF-NEXT:       Hash: 0xB887389
-# DWARF-NEXT:       String: 0x000000ad "foo"
+# DWARF-NEXT:       String: 0x00000097 "foo"
 # DWARF-NEXT:       Entry @ 0x10b {
 # DWARF-NEXT:         Abbrev: 0x3
 # DWARF-NEXT:         Tag: DW_TAG_structure_type
@@ -191,7 +188,7 @@
 # DWARF-NEXT:   Bucket 7 [
 # DWARF-NEXT:     Name 6 {
 # DWARF-NEXT:       Hash: 0x7C9A7F6A
-# DWARF-NEXT:       String: 0x000000a4 "main"
+# DWARF-NEXT:       String: 0x0000008e "main"
 # DWARF-NEXT:       Entry @ 0x136 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -204,7 +201,7 @@
 # DWARF-NEXT:   Bucket 8 [
 # DWARF-NEXT:     Name 7 {
 # DWARF-NEXT:       Hash: 0xA7255AE
-# DWARF-NEXT:       String: 0x00000196 "parent_test"
+# DWARF-NEXT:       String: 0x00000168 "parent_test"
 # DWARF-NEXT:       Entry @ 0x128 {
 # DWARF-NEXT:         Abbrev: 0x5
 # DWARF-NEXT:         Tag: DW_TAG_namespace
@@ -215,7 +212,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 8 {
 # DWARF-NEXT:       Hash: 0x51007E98
-# DWARF-NEXT:       String: 0x00000097 "_Z3barR3fooi"
+# DWARF-NEXT:       String: 0x00000081 "_Z3barR3fooi"
 # DWARF-NEXT:       Entry @ 0x12f {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -226,7 +223,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 9 {
 # DWARF-NEXT:       Hash: 0x7C952063
-# DWARF-NEXT:       String: 0x000000b5 "char"
+# DWARF-NEXT:       String: 0x0000009f "char"
 # DWARF-NEXT:       Entry @ 0x13d {
 # DWARF-NEXT:         Abbrev: 0x1
 # DWARF-NEXT:         Tag: DW_TAG_base_type
@@ -244,7 +241,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:   ]
 
-#--- debug-names-parent-idx.s
+#--- a.s
 	.text
 	.globl	_Z3barR3fooi                    # -- Begin function _Z3barR3fooi
 	.p2align	4, 0x90
@@ -331,39 +328,39 @@ main:                                   # @main
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names-parent-idx.cpp"    # string offset=104
+	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"parent-idx-test"               # string offset=131
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"bar"                           # string offset=147
+	.asciz	"bar"                           # string offset=125
 .Linfo_string4:
-	.asciz	"_Z3barR3fooi"                  # string offset=151
+	.asciz	"_Z3barR3fooi"                  # string offset=129
 .Linfo_string5:
-	.asciz	"main"                          # string offset=164
+	.asciz	"main"                          # string offset=142
 .Linfo_string6:
-	.asciz	"int"                           # string offset=169
+	.asciz	"int"                           # string offset=147
 .Linfo_string7:
-	.asciz	"foo"                           # string offset=173
+	.asciz	"foo"                           # string offset=151
 .Linfo_string8:
-	.asciz	"x"                             # string offset=177
+	.asciz	"x"                             # string offset=155
 .Linfo_string9:
-	.asciz	"y"                             # string offset=179
+	.asciz	"y"                             # string offset=157
 .Linfo_string10:
-	.asciz	"char"                          # string offset=181
+	.asciz	"char"                          # string offset=159
 .Linfo_string11:
-	.asciz	"foo_ptr"                       # string offset=186
+	.asciz	"foo_ptr"                       # string offset=164
 .Linfo_string12:
-	.asciz	"junk"                          # string offset=194
+	.asciz	"junk"                          # string offset=172
 .Linfo_string13:
-	.asciz	"argc"                          # string offset=199
+	.asciz	"argc"                          # string offset=177
 .Linfo_string14:
-	.asciz	"argv"                          # string offset=204
+	.asciz	"argv"                          # string offset=182
 .Linfo_string15:
-	.asciz	"my_struct"                     # string offset=209
+	.asciz	"my_struct"                     # string offset=187
 .Linfo_string16:
-	.asciz	"junk2"                         # string offset=219
+	.asciz	"junk2"                         # string offset=197
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 	.quad	.Lfunc_begin1
@@ -471,7 +468,7 @@ main:                                   # @main
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.addrsig_sym _Z3barR3fooi
@@ -480,11 +477,11 @@ main:                                   # @main
 	.section	.debug_line,"", at progbits
 .Lline_table_start0:
 	
-#--- debug-names-parent-idx-2.s
+#--- b.s
 # Generated with:
 
-# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='parent-idx-test' \
-#     -S debug-names-parent-idx-2.cpp -o debug-names-parent-idx-2.s
+# clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' -S \
+#     b.cpp -o b.s
 
 # foo.h contents:
 
@@ -500,7 +497,7 @@ main:                                   # @main
 #   int foo();
 # }
 
-# debug-names-parent-index-2.cpp contents:
+# b.cpp contents:
 
 # #include "foo.h"
 # int foo () {
@@ -587,31 +584,31 @@ _ZN11parent_test3fooEv:                 # @_ZN11parent_test3fooEv
 .Lstr_offsets_base0:
 	.section	.debug_str,"MS", at progbits,1
 .Linfo_string0:
-	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)" # string offset=0
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
 .Linfo_string1:
-	.asciz	"debug-names-parent-idx-2.cpp"  # string offset=104
+	.asciz	"b.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"parent-idx-test"               # string offset=133
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"int"                           # string offset=149
+	.asciz	"int"                           # string offset=125
 .Linfo_string4:
-	.asciz	"foo"                           # string offset=153
+	.asciz	"foo"                           # string offset=129
 .Linfo_string5:
-	.asciz	"_Z3foov"                       # string offset=157
+	.asciz	"_Z3foov"                       # string offset=133
 .Linfo_string6:
-	.asciz	"parent_test"                   # string offset=165
+	.asciz	"parent_test"                   # string offset=141
 .Linfo_string7:
-	.asciz	"_ZN11parent_test3fooEv"        # string offset=177
+	.asciz	"_ZN11parent_test3fooEv"        # string offset=153
 .Linfo_string8:
-	.asciz	"struct2"                       # string offset=200
+	.asciz	"struct2"                       # string offset=176
 .Linfo_string9:
-	.asciz	"x"                             # string offset=208
+	.asciz	"x"                             # string offset=184
 .Linfo_string10:
-	.asciz	"y"                             # string offset=210
+	.asciz	"y"                             # string offset=186
 .Linfo_string11:
-	.asciz	"char"                          # string offset=212
+	.asciz	"char"                          # string offset=188
 .Linfo_string12:
-	.asciz	"foo_ptr"                       # string offset=217
+	.asciz	"foo_ptr"                       # string offset=193
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 	.quad	.Lfunc_begin1
@@ -742,7 +739,7 @@ _ZN11parent_test3fooEv:                 # @_ZN11parent_test3fooEv
                                         # End of list: char
 	.p2align	2, 0x0
 .Lnames_end0:
-	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 4df364bc93af49ae413ec1ae8328f34ac70730c4)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
 	.section	".note.GNU-stack","", at progbits
 	.addrsig
 	.section	.debug_line,"", at progbits
diff --git a/lld/test/ELF/debug-names.s b/lld/test/ELF/debug-names.s
index eb35281a224f0d..4ca2cb1eabefae 100644
--- a/lld/test/ELF/debug-names.s
+++ b/lld/test/ELF/debug-names.s
@@ -1,7 +1,7 @@
 # debug-names.s was generated with:
 
-# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
-#     -S a.cpp -o a.s
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' \
+#    -S a.cpp -o a.s
 
 # a.cpp contents:
 
@@ -65,7 +65,7 @@
 # DWARF-NEXT:   Bucket 1 [
 # DWARF-NEXT:     Name 1 {
 # DWARF-NEXT:       Hash: 0x59796A
-# DWARF-NEXT:       String: 0x0000008b "t1"
+# DWARF-NEXT:       String: 0x00000089 "t1"
 # DWARF-NEXT:       Entry @ 0xaa {
 # DWARF-NEXT:         Abbrev: 0x1
 # DWARF-NEXT:         Tag: DW_TAG_structure_type
@@ -83,7 +83,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 2 {
 # DWARF-NEXT:       Hash: 0x5355B2BE
-# DWARF-NEXT:       String: 0x00000082 "_Z2f12t1"
+# DWARF-NEXT:       String: 0x00000080 "_Z2f12t1"
 # DWARF-NEXT:       Entry @ 0xbe {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -94,7 +94,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 3 {
 # DWARF-NEXT:       Hash: 0x7C9A7F6A
-# DWARF-NEXT:       String: 0x00000115 "main"
+# DWARF-NEXT:       String: 0x00000111 "main"
 # DWARF-NEXT:       Entry @ 0xc5 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -110,7 +110,7 @@
 # DWARF-NEXT:   Bucket 3 [
 # DWARF-NEXT:     Name 4 {
 # DWARF-NEXT:       Hash: 0xB888030
-# DWARF-NEXT:       String: 0x0000011a "int"
+# DWARF-NEXT:       String: 0x00000116 "int"
 # DWARF-NEXT:       Entry @ 0xb7 {
 # DWARF-NEXT:         Abbrev: 0x3
 # DWARF-NEXT:         Tag: DW_TAG_base_type
@@ -123,7 +123,7 @@
 # DWARF-NEXT:   Bucket 4 [
 # DWARF-NEXT:     Name 5 {
 # DWARF-NEXT:       Hash: 0x59779C
-# DWARF-NEXT:       String: 0x0000007f "f1"
+# DWARF-NEXT:       String: 0x0000007d "f1"
 # DWARF-NEXT:       Entry @ 0xa3 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -181,13 +181,13 @@ _Z2f12t1:                               # @_Z2f12t1
 .Linfo_string1:
 	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=110
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"f1"                            # string offset=127
+	.asciz	"f1"                            # string offset=125
 .Linfo_string4:
-	.asciz	"_Z2f12t1"                      # string offset=130
+	.asciz	"_Z2f12t1"                      # string offset=128
 .Linfo_string5:
-	.asciz	"t1"                            # string offset=139
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -264,7 +264,7 @@ _Z2f12t1:                               # @_Z2f12t1
 
 #--- b.s
 # Generated with:
-# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='debug-names-test' \
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' \
 #     -S b.cpp -o b.s
 
 # b.cpp contents:
@@ -274,6 +274,7 @@ _Z2f12t1:                               # @_Z2f12t1
 #   t1 v1;
 # }
 #
+
 	.text
 	.globl	main                            # -- Begin function main
 	.p2align	4, 0x90
@@ -321,15 +322,15 @@ main:                                   # @main
 .Linfo_string1:
 	.asciz	"b.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=110
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=127
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=132
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"v1"                            # string offset=136
+	.asciz	"v1"                            # string offset=134
 .Linfo_string6:
-	.asciz	"t1"                            # string offset=139
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.quad	.Lfunc_begin0
 .Ldebug_addr_end0:
diff --git a/lld/test/ELF/ppc32-debug-names.s b/lld/test/ELF/ppc32-debug-names.s
index 40d7cc5b4fa2f7..f091f961588d0c 100644
--- a/lld/test/ELF/ppc32-debug-names.s
+++ b/lld/test/ELF/ppc32-debug-names.s
@@ -1,7 +1,7 @@
 # ppc-debug-names.s was generated with:
 
 # - clang++ --target=powerpc -g -O0 -gpubnames \
-#     -fdebug-compilation-dir='debug-names-test' -S a.cpp -o a.s
+#     -fdebug-compilation-dir='/self/proc/cwd' -S a.cpp -o a.s
 
 # a.cpp contents:
 
@@ -66,7 +66,7 @@
 # DWARF-NEXT:   Bucket 1 [
 # DWARF-NEXT:     Name 1 {
 # DWARF-NEXT:       Hash: 0x59796A
-# DWARF-NEXT:       String: 0x0000008b "t1"
+# DWARF-NEXT:       String: 0x00000089 "t1"
 # DWARF-NEXT:       Entry @ 0xaa {
 # DWARF-NEXT:         Abbrev: 0x1
 # DWARF-NEXT:         Tag: DW_TAG_structure_type
@@ -84,7 +84,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 2 {
 # DWARF-NEXT:       Hash: 0x5355B2BE
-# DWARF-NEXT:       String: 0x00000082 "_Z2f12t1"
+# DWARF-NEXT:       String: 0x00000080 "_Z2f12t1"
 # DWARF-NEXT:       Entry @ 0xbe {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -95,7 +95,7 @@
 # DWARF-NEXT:     }
 # DWARF-NEXT:     Name 3 {
 # DWARF-NEXT:       Hash: 0x7C9A7F6A
-# DWARF-NEXT:       String: 0x00000111 "main"
+# DWARF-NEXT:       String: 0x0000010d "main"
 # DWARF-NEXT:       Entry @ 0xc5 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -111,7 +111,7 @@
 # DWARF-NEXT:   Bucket 3 [
 # DWARF-NEXT:     Name 4 {
 # DWARF-NEXT:       Hash: 0xB888030
-# DWARF-NEXT:       String: 0x00000116 "int"
+# DWARF-NEXT:       String: 0x00000112 "int"
 # DWARF-NEXT:       Entry @ 0xb7 {
 # DWARF-NEXT:         Abbrev: 0x3
 # DWARF-NEXT:         Tag: DW_TAG_base_type
@@ -124,7 +124,7 @@
 # DWARF-NEXT:   Bucket 4 [
 # DWARF-NEXT:     Name 5 {
 # DWARF-NEXT:       Hash: 0x59779C
-# DWARF-NEXT:       String: 0x0000007f "f1"
+# DWARF-NEXT:       String: 0x0000007d "f1"
 # DWARF-NEXT:       Entry @ 0xa3 {
 # DWARF-NEXT:         Abbrev: 0x2
 # DWARF-NEXT:         Tag: DW_TAG_subprogram
@@ -144,6 +144,7 @@ _Z2f12t1:                               # @_Z2f12t1
 .Lfunc_begin0:
 	.cfi_startproc
 # %bb.0:                                # %entry
+	#DEBUG_VALUE: f1: <- [$r3+0]
 	stwu 1, -16(1)
 	stw 31, 12(1)
 	.cfi_def_cfa_offset 16
@@ -183,13 +184,13 @@ _Z2f12t1:                               # @_Z2f12t1
 .Linfo_string1:
 	.asciz	"a.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=110
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"f1"                            # string offset=127
+	.asciz	"f1"                            # string offset=125
 .Linfo_string4:
-	.asciz	"_Z2f12t1"                      # string offset=130
+	.asciz	"_Z2f12t1"                      # string offset=128
 .Linfo_string5:
-	.asciz	"t1"                            # string offset=139
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.long	.Lfunc_begin0
 .Ldebug_addr_end0:
@@ -267,7 +268,7 @@ _Z2f12t1:                               # @_Z2f12t1
 #--- b.s
 # Generated with:
 # - clang++ --target=powerpc -g -O0 -gpubnames \
-#     -fdebug-compilation-dir='debug-names-test' -S b.cpp -o b.s
+#     -fdebug-compilation-dir='/self/proc/cwd' -S b.cpp -o b.s
 
 # b.cpp contents:
 
@@ -324,15 +325,15 @@ main:                                   # @main
 .Linfo_string1:
 	.asciz	"b.cpp"                         # string offset=104
 .Linfo_string2:
-	.asciz	"debug-names-test"              # string offset=110
+	.asciz	"/proc/self/cwd"                # string offset=110
 .Linfo_string3:
-	.asciz	"main"                          # string offset=127
+	.asciz	"main"                          # string offset=125
 .Linfo_string4:
-	.asciz	"int"                           # string offset=132
+	.asciz	"int"                           # string offset=130
 .Linfo_string5:
-	.asciz	"v1"                            # string offset=136
+	.asciz	"v1"                            # string offset=134
 .Linfo_string6:
-	.asciz	"t1"                            # string offset=139
+	.asciz	"t1"                            # string offset=137
 .Laddr_table_base0:
 	.long	.Lfunc_begin0
 .Ldebug_addr_end0:

>From 3721df40d983e3a9ba8bdd35796e556001461290 Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 15 Apr 2024 00:54:03 -0700
Subject: [PATCH 20/23] [lld][ELF] Add test for CompUnit > 1

Add code to update CU offsets correctly when there are multiple CUs
within one .o file. Also add test for this.
---
 lld/ELF/SyntheticSections.cpp        |  34 ++
 lld/ELF/SyntheticSections.h          |   2 +
 lld/test/ELF/debug-names-multi-cus.s | 645 +++++++++++++++++++++++++++
 3 files changed, 681 insertions(+)
 create mode 100644 lld/test/ELF/debug-names-multi-cus.s

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 910ace1c757b43..b69cc4cd967d5c 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3217,6 +3217,38 @@ template <class ELFT> void DebugNamesSection<ELFT>::finalizeContents() {
   });
 }
 
+template <class ELFT>
+void DebugNamesSection<ELFT>::updateMultiCuOffsets(OutputChunk &chunk) {
+  // Find the .debug_info section data for this chunk.
+  auto *file = cast<ObjFile<ELFT>>(chunk.infoSec->file);
+  DWARFContext dwarf(std::make_unique<LLDDwarfObj<ELFT>>(file));
+  auto &dobj = static_cast<const LLDDwarfObj<ELFT> &>(dwarf.getDWARFObj());
+  InputSection *infoSec = dobj.getInfoSection();
+  auto infoData = toStringRef(infoSec->contentMaybeDecompress());
+  const char *p = infoData.data();
+
+  // Skim through the CUs reading the unit lengths & types to find correct
+  // starting offsets for CUs (before relocation).
+  uint32_t nextCu = 0;
+  for (size_t i = 1, end = chunk.compUnits.size(); i < end; ++i) {
+    // First CU offset for each new (appended) .debug_names section starts at
+    // zero.
+    if (chunk.compUnits[i] == 0) {
+      // Skip to start of next CU and read the type & size.
+      p = infoData.data() + nextCu;
+      uint32_t unit_length =
+          endian::readNext<uint32_t, ELFT::Endianness, unaligned>(p);
+      [[maybe_unused]] uint16_t version =
+          endian::readNext<uint16_t, ELFT::Endianness, unaligned>(p);
+      uint8_t unitType =
+          endian::readNext<uint8_t, ELFT::Endianness, unaligned>(p);
+      if (unitType == dwarf::DW_UT_compile)
+        nextCu += unit_length + 4;
+    }
+    chunk.compUnits[i] += nextCu;
+  }
+}
+
 template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   [[maybe_unused]] uint8_t *oldBuf = buf;
   // Write the header.
@@ -3236,6 +3268,8 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   // Write the CU list.
   for (auto i : seq(numChunks)) {
     OutputChunk &chunk = chunks[i];
+    if (chunk.compUnits.size() > 1)
+      updateMultiCuOffsets(chunk);
     for (uint32_t cuOffset : chunk.compUnits) {
       endian::write32<ELFT::Endianness>(buf,
                                         chunk.infoSec->outSecOff + cuOffset);
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 534fac005e0b8b..cbf16c4011388b 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -910,6 +910,8 @@ class DebugNamesSection final : public DebugNamesBaseSection {
   void getNameRelocs(InputSection *sec, ArrayRef<RelTy> rels,
                      llvm::DenseMap<uint32_t, uint32_t> &relocs);
 
+  void updateMultiCuOffsets(OutputChunk &chunk);
+
 private:
   static void readOffsets(InputChunk &inputChunk, OutputChunk &chunk,
                           llvm::DWARFDataExtractor &namesExtractor,
diff --git a/lld/test/ELF/debug-names-multi-cus.s b/lld/test/ELF/debug-names-multi-cus.s
new file mode 100644
index 00000000000000..bc79a783f61dd7
--- /dev/null
+++ b/lld/test/ELF/debug-names-multi-cus.s
@@ -0,0 +1,645 @@
+# ab.s was generated by:
+
+# clang++ a.cpp -gpubnames a.cpp -g -emit-llvm -c \
+#    -fdebug-compilation-dir='/proc/self/cwd
+# clang++ b.cpp -gpubnames b.cpp -g -emit-llvm -c \
+#    -fdebug-compilation-dir='/proc/self/cwd
+# llvm-link a.bc b.bc -o ab.bc
+# clang++ ab.bc -S -o ab.s
+
+# a.cpp contains:
+# struct t1 { };
+# void f1(t1) { }
+
+# b.cpp contains:
+# struct t1 { };
+# int main() {
+#   t1 v1;
+# }
+
+
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 ab.s -o ab.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 c.s -o c.o
+# RUN: ld.lld --debug-names ab.o c.o -o out
+# RUN: llvm-dwarfdump --debug-names out \
+# RUN:    | FileCheck -DFILE=a.o %s --check-prefix=DWARF
+
+# DWARF:	Compilation Unit offsets [
+# DWARF-NEXT:     CU[0]: 0x00000000
+# DWARF-NEXT:     CU[1]: 0x00000041
+# DWARF-NEXT:     CU[2]: 0x00000084
+# DWARF-NEXT:   ]
+
+# RUN: ld.lld --debug-names c.o ab.o -o out2
+# RUN: llvm-dwarfdump --debug-names out2 \
+# RUN:    | FileCheck -DFILE=a.o %s --check-prefix=DWARF2
+	
+# DWARF2:	Compilation Unit offsets [
+# DWARF2-NEXT:     CU[0]: 0x00000000
+# DWARF2-NEXT:     CU[1]: 0x00000030
+# DWARF2-NEXT:     CU[2]: 0x00000071
+# DWARF2-NEXT:   ]
+
+#--- ab.s
+	.text
+	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
+	.p2align	4, 0x90
+	.type	_Z2f12t1, at function
+_Z2f12t1:                               # @_Z2f12t1
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z2f12t1, .Lfunc_end0-_Z2f12t1
+	.cfi_endproc
+                                        # -- End function
+	.globl	main                            # -- Begin function main
+	.p2align	4, 0x90
+	.type	main, at function
+main:                                   # @main
+.Lfunc_begin1:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp2:
+	xorl	%eax, %eax
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp3:
+.Lfunc_end1:
+	.size	main, .Lfunc_end1-main
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	1                               # Abbreviation Code
+	.byte	17                              # DW_TAG_compile_unit
+	.byte	1                               # DW_CHILDREN_yes
+	.byte	37                              # DW_AT_producer
+	.byte	37                              # DW_FORM_strx1
+	.byte	19                              # DW_AT_language
+	.byte	5                               # DW_FORM_data2
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	114                             # DW_AT_str_offsets_base
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	16                              # DW_AT_stmt_list
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	27                              # DW_AT_comp_dir
+	.byte	37                              # DW_FORM_strx1
+	.byte	17                              # DW_AT_low_pc
+	.byte	27                              # DW_FORM_addrx
+	.byte	18                              # DW_AT_high_pc
+	.byte	6                               # DW_FORM_data4
+	.byte	115                             # DW_AT_addr_base
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	2                               # Abbreviation Code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	1                               # DW_CHILDREN_yes
+	.byte	17                              # DW_AT_low_pc
+	.byte	27                              # DW_FORM_addrx
+	.byte	18                              # DW_AT_high_pc
+	.byte	6                               # DW_FORM_data4
+	.byte	64                              # DW_AT_frame_base
+	.byte	24                              # DW_FORM_exprloc
+	.byte	110                             # DW_AT_linkage_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	58                              # DW_AT_decl_file
+	.byte	11                              # DW_FORM_data1
+	.byte	59                              # DW_AT_decl_line
+	.byte	11                              # DW_FORM_data1
+	.byte	63                              # DW_AT_external
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	3                               # Abbreviation Code
+	.byte	5                               # DW_TAG_formal_parameter
+	.byte	0                               # DW_CHILDREN_no
+	.byte	2                               # DW_AT_location
+	.byte	24                              # DW_FORM_exprloc
+	.byte	58                              # DW_AT_decl_file
+	.byte	11                              # DW_FORM_data1
+	.byte	59                              # DW_AT_decl_line
+	.byte	11                              # DW_FORM_data1
+	.byte	73                              # DW_AT_type
+	.byte	19                              # DW_FORM_ref4
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	4                               # Abbreviation Code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	0                               # DW_CHILDREN_no
+	.byte	54                              # DW_AT_calling_convention
+	.byte	11                              # DW_FORM_data1
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	11                              # DW_AT_byte_size
+	.byte	11                              # DW_FORM_data1
+	.byte	58                              # DW_AT_decl_file
+	.byte	11                              # DW_FORM_data1
+	.byte	59                              # DW_AT_decl_line
+	.byte	11                              # DW_FORM_data1
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	5                               # Abbreviation Code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	1                               # DW_CHILDREN_yes
+	.byte	17                              # DW_AT_low_pc
+	.byte	27                              # DW_FORM_addrx
+	.byte	18                              # DW_AT_high_pc
+	.byte	6                               # DW_FORM_data4
+	.byte	64                              # DW_AT_frame_base
+	.byte	24                              # DW_FORM_exprloc
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	58                              # DW_AT_decl_file
+	.byte	11                              # DW_FORM_data1
+	.byte	59                              # DW_AT_decl_line
+	.byte	11                              # DW_FORM_data1
+	.byte	73                              # DW_AT_type
+	.byte	19                              # DW_FORM_ref4
+	.byte	63                              # DW_AT_external
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	6                               # Abbreviation Code
+	.byte	52                              # DW_TAG_variable
+	.byte	0                               # DW_CHILDREN_no
+	.byte	2                               # DW_AT_location
+	.byte	24                              # DW_FORM_exprloc
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	58                              # DW_AT_decl_file
+	.byte	11                              # DW_FORM_data1
+	.byte	59                              # DW_AT_decl_line
+	.byte	11                              # DW_FORM_data1
+	.byte	73                              # DW_AT_type
+	.byte	16                              # DW_FORM_ref_addr
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	7                               # Abbreviation Code
+	.byte	36                              # DW_TAG_base_type
+	.byte	0                               # DW_CHILDREN_no
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	62                              # DW_AT_encoding
+	.byte	11                              # DW_FORM_data1
+	.byte	11                              # DW_AT_byte_size
+	.byte	11                              # DW_FORM_data1
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.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
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0x17 DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	4                               # DW_AT_linkage_name
+	.byte	5                               # DW_AT_name
+	.byte	1                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+                                        # DW_AT_external
+	.byte	3                               # Abbrev [3] 0x2f:0xa DW_TAG_formal_parameter
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	127
+	.byte	1                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+	.long	58                              # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	4                               # Abbrev [4] 0x3a:0x6 DW_TAG_structure_type
+	.byte	5                               # DW_AT_calling_convention
+	.byte	8                               # DW_AT_name
+	.byte	1                               # DW_AT_byte_size
+	.byte	1                               # DW_AT_decl_file
+	.byte	1                               # DW_AT_decl_line
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+.Lcu_begin1:
+	.long	.Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
+.Ldebug_info_start1:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x37 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	3                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.Lline_table_start0             # DW_AT_stmt_list
+	.byte	2                               # DW_AT_comp_dir
+	.byte	1                               # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1       # DW_AT_high_pc
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	5                               # Abbrev [5] 0x23:0x1b DW_TAG_subprogram
+	.byte	1                               # DW_AT_low_pc
+	.long	.Lfunc_end1-.Lfunc_begin1       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	6                               # DW_AT_name
+	.byte	2                               # DW_AT_decl_file
+	.byte	2                               # DW_AT_decl_line
+	.long	62                              # DW_AT_type
+                                        # DW_AT_external
+	.byte	6                               # Abbrev [6] 0x32:0xb DW_TAG_variable
+	.byte	2                               # DW_AT_location
+	.byte	145
+	.byte	127
+	.byte	9                               # DW_AT_name
+	.byte	2                               # DW_AT_decl_file
+	.byte	3                               # DW_AT_decl_line
+	.long	.debug_info+58                  # DW_AT_type
+	.byte	0                               # End Of Children Mark
+	.byte	7                               # Abbrev [7] 0x3e:0x4 DW_TAG_base_type
+	.byte	7                               # DW_AT_name
+	.byte	5                               # DW_AT_encoding
+	.byte	4                               # DW_AT_byte_size
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end1:
+	.section	.debug_str_offsets,"", at progbits
+	.long	44                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 7607c4d40149128f848055613edf9c3cf9ae890d)" # string offset=0
+.Linfo_string1:
+	.asciz	"a.cpp"                         # string offset=104
+.Linfo_string2:
+	.asciz	"/proc/self/cwd"                # string offset=110
+.Linfo_string3:
+	.asciz	"f1"                            # string offset=125
+.Linfo_string4:
+	.asciz	"_Z2f12t1"                      # string offset=128
+.Linfo_string5:
+	.asciz	"b.cpp"                         # string offset=137
+.Linfo_string6:
+	.asciz	"main"                          # string offset=143
+.Linfo_string7:
+	.asciz	"int"                           # string offset=148
+.Linfo_string8:
+	.asciz	"t1"                            # string offset=152
+.Linfo_string9:
+	.asciz	"v1"                            # string offset=155
+	.section	.debug_str_offsets,"", at progbits
+	.long	.Linfo_string0
+	.long	.Linfo_string1
+	.long	.Linfo_string2
+	.long	.Linfo_string5
+	.long	.Linfo_string4
+	.long	.Linfo_string3
+	.long	.Linfo_string6
+	.long	.Linfo_string7
+	.long	.Linfo_string8
+	.long	.Linfo_string9
+	.section	.debug_addr,"", at progbits
+	.long	.Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+	.short	5                               # DWARF version number
+	.byte	8                               # Address size
+	.byte	0                               # Segment selector size
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+	.quad	.Lfunc_begin1
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	2                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	5                               # Header: bucket count
+	.long	5                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	.Lcu_begin1                     # Compilation unit 1
+	.long	0                               # Bucket 0
+	.long	1                               # Bucket 1
+	.long	0                               # Bucket 2
+	.long	4                               # Bucket 3
+	.long	5                               # Bucket 4
+	.long	5863786                         # Hash in Bucket 1
+	.long	1398125246                      # Hash in Bucket 1
+	.long	2090499946                      # Hash in Bucket 1
+	.long	193495088                       # Hash in Bucket 3
+	.long	5863324                         # Hash in Bucket 4
+	.long	.Linfo_string8                  # String in Bucket 1: t1
+	.long	.Linfo_string4                  # String in Bucket 1: _Z2f12t1
+	.long	.Linfo_string6                  # String in Bucket 1: main
+	.long	.Linfo_string7                  # String in Bucket 3: int
+	.long	.Linfo_string3                  # String in Bucket 4: f1
+	.long	.Lnames4-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames2-.Lnames_entries0       # Offset in Bucket 1
+	.long	.Lnames3-.Lnames_entries0       # Offset in Bucket 3
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 4
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	19                              # DW_TAG_structure_type
+	.byte	1                               # DW_IDX_compile_unit
+	.byte	11                              # DW_FORM_data1
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	2                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	1                               # DW_IDX_compile_unit
+	.byte	11                              # DW_FORM_data1
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	3                               # Abbrev code
+	.byte	36                              # DW_TAG_base_type
+	.byte	1                               # DW_IDX_compile_unit
+	.byte	11                              # DW_FORM_data1
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames4:
+.L0:
+	.byte	1                               # Abbreviation code
+	.byte	0                               # DW_IDX_compile_unit
+	.long	58                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: t1
+.Lnames1:
+.L3:
+	.byte	2                               # Abbreviation code
+	.byte	0                               # DW_IDX_compile_unit
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z2f12t1
+.Lnames2:
+.L2:
+	.byte	2                               # Abbreviation code
+	.byte	1                               # DW_IDX_compile_unit
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: main
+.Lnames3:
+.L1:
+	.byte	3                               # Abbreviation code
+	.byte	1                               # DW_IDX_compile_unit
+	.long	62                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: int
+.Lnames0:
+	.byte	2                               # Abbreviation code
+	.byte	0                               # DW_IDX_compile_unit
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: f1
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 7607c4d40149128f848055613edf9c3cf9ae890d)"
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 7607c4d40149128f848055613edf9c3cf9ae890d)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:
+
+#--- c.s
+# Generated with:
+# - clang++ -g -gpubnames -fdebug-compilation-dir='/proc/self/cwd' \
+#     -S c.cpp -o c.s
+
+# c.cpp contents:
+
+# void null() { }
+
+	.text
+	.globl	_Z4nullv                        # -- Begin function _Z4nullv
+	.p2align	4, 0x90
+	.type	_Z4nullv, at function
+_Z4nullv:                               # @_Z4nullv
+.Lfunc_begin0:
+	.cfi_startproc
+# %bb.0:                                # %entry
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register %rbp
+.Ltmp0:
+	popq	%rbp
+	.cfi_def_cfa %rsp, 8
+	retq
+.Ltmp1:
+.Lfunc_end0:
+	.size	_Z4nullv, .Lfunc_end0-_Z4nullv
+	.cfi_endproc
+                                        # -- End function
+	.section	.debug_abbrev,"", at progbits
+	.byte	1                               # Abbreviation Code
+	.byte	17                              # DW_TAG_compile_unit
+	.byte	1                               # DW_CHILDREN_yes
+	.byte	37                              # DW_AT_producer
+	.byte	37                              # DW_FORM_strx1
+	.byte	19                              # DW_AT_language
+	.byte	5                               # DW_FORM_data2
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	114                             # DW_AT_str_offsets_base
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	16                              # DW_AT_stmt_list
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	27                              # DW_AT_comp_dir
+	.byte	37                              # DW_FORM_strx1
+	.byte	17                              # DW_AT_low_pc
+	.byte	27                              # DW_FORM_addrx
+	.byte	18                              # DW_AT_high_pc
+	.byte	6                               # DW_FORM_data4
+	.byte	115                             # DW_AT_addr_base
+	.byte	23                              # DW_FORM_sec_offset
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	2                               # Abbreviation Code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	0                               # DW_CHILDREN_no
+	.byte	17                              # DW_AT_low_pc
+	.byte	27                              # DW_FORM_addrx
+	.byte	18                              # DW_AT_high_pc
+	.byte	6                               # DW_FORM_data4
+	.byte	64                              # DW_AT_frame_base
+	.byte	24                              # DW_FORM_exprloc
+	.byte	110                             # DW_AT_linkage_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	3                               # DW_AT_name
+	.byte	37                              # DW_FORM_strx1
+	.byte	58                              # DW_AT_decl_file
+	.byte	11                              # DW_FORM_data1
+	.byte	59                              # DW_AT_decl_line
+	.byte	11                              # DW_FORM_data1
+	.byte	63                              # DW_AT_external
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # EOM(1)
+	.byte	0                               # EOM(2)
+	.byte	0                               # EOM(3)
+	.section	.debug_info,"", at progbits
+.Lcu_begin0:
+	.long	.Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+	.short	5                               # DWARF version number
+	.byte	1                               # DWARF Unit Type
+	.byte	8                               # Address Size (in bytes)
+	.long	.debug_abbrev                   # Offset Into Abbrev. Section
+	.byte	1                               # Abbrev [1] 0xc:0x24 DW_TAG_compile_unit
+	.byte	0                               # DW_AT_producer
+	.short	33                              # DW_AT_language
+	.byte	1                               # DW_AT_name
+	.long	.Lstr_offsets_base0             # DW_AT_str_offsets_base
+	.long	.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
+	.long	.Laddr_table_base0              # DW_AT_addr_base
+	.byte	2                               # Abbrev [2] 0x23:0xc DW_TAG_subprogram
+	.byte	0                               # DW_AT_low_pc
+	.long	.Lfunc_end0-.Lfunc_begin0       # DW_AT_high_pc
+	.byte	1                               # DW_AT_frame_base
+	.byte	86
+	.byte	3                               # DW_AT_linkage_name
+	.byte	4                               # DW_AT_name
+	.byte	0                               # DW_AT_decl_file
+	.byte	1                               # DW_AT_decl_line
+                                        # DW_AT_external
+	.byte	0                               # End Of Children Mark
+.Ldebug_info_end0:
+	.section	.debug_str_offsets,"", at progbits
+	.long	24                              # Length of String Offsets Set
+	.short	5
+	.short	0
+.Lstr_offsets_base0:
+	.section	.debug_str,"MS", at progbits,1
+.Linfo_string0:
+	.asciz	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 7607c4d40149128f848055613edf9c3cf9ae890d)" # string offset=0
+.Linfo_string1:
+	.asciz	"c.cpp"                         # string offset=104
+.Linfo_string2:
+	.asciz	"/proc/self/cwd"                # string offset=110
+.Linfo_string3:
+	.asciz	"null"                          # string offset=125
+.Linfo_string4:
+	.asciz	"_Z4nullv"                      # string offset=130
+	.section	.debug_str_offsets,"", at progbits
+	.long	.Linfo_string0
+	.long	.Linfo_string1
+	.long	.Linfo_string2
+	.long	.Linfo_string4
+	.long	.Linfo_string3
+	.section	.debug_addr,"", at progbits
+	.long	.Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+	.short	5                               # DWARF version number
+	.byte	8                               # Address size
+	.byte	0                               # Segment selector size
+.Laddr_table_base0:
+	.quad	.Lfunc_begin0
+.Ldebug_addr_end0:
+	.section	.debug_names,"", at progbits
+	.long	.Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+	.short	5                               # Header: version
+	.short	0                               # Header: padding
+	.long	1                               # Header: compilation unit count
+	.long	0                               # Header: local type unit count
+	.long	0                               # Header: foreign type unit count
+	.long	2                               # Header: bucket count
+	.long	2                               # Header: name count
+	.long	.Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+	.long	8                               # Header: augmentation string size
+	.ascii	"LLVM0700"                      # Header: augmentation string
+	.long	.Lcu_begin0                     # Compilation unit 0
+	.long	1                               # Bucket 0
+	.long	2                               # Bucket 1
+	.long	2090557760                      # Hash in Bucket 0
+	.long	1488390083                      # Hash in Bucket 1
+	.long	.Linfo_string3                  # String in Bucket 0: null
+	.long	.Linfo_string4                  # String in Bucket 1: _Z4nullv
+	.long	.Lnames0-.Lnames_entries0       # Offset in Bucket 0
+	.long	.Lnames1-.Lnames_entries0       # Offset in Bucket 1
+.Lnames_abbrev_start0:
+	.byte	1                               # Abbrev code
+	.byte	46                              # DW_TAG_subprogram
+	.byte	3                               # DW_IDX_die_offset
+	.byte	19                              # DW_FORM_ref4
+	.byte	4                               # DW_IDX_parent
+	.byte	25                              # DW_FORM_flag_present
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev
+	.byte	0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L0:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: null
+.Lnames1:
+	.byte	1                               # Abbreviation code
+	.long	35                              # DW_IDX_die_offset
+	.byte	0                               # DW_IDX_parent
+                                        # End of list: _Z4nullv
+	.p2align	2, 0x0
+.Lnames_end0:
+	.ident	"clang version 19.0.0git (git at github.com:llvm/llvm-project.git 7607c4d40149128f848055613edf9c3cf9ae890d)"
+	.section	".note.GNU-stack","", at progbits
+	.addrsig
+	.section	.debug_line,"", at progbits
+.Lline_table_start0:

>From 174fa5bef6ea85dc68ce75da927c5ef723d1566d Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Mon, 15 Apr 2024 10:33:31 -0700
Subject: [PATCH 21/23] [lld][ELF] Clean up updateMultiCuOffset.

Use the existing .debug_info section pointer in chunk, rather than
rebuilding it.
---
 lld/ELF/SyntheticSections.cpp | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index b69cc4cd967d5c..3f7931c4d24862 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3219,20 +3219,13 @@ template <class ELFT> void DebugNamesSection<ELFT>::finalizeContents() {
 
 template <class ELFT>
 void DebugNamesSection<ELFT>::updateMultiCuOffsets(OutputChunk &chunk) {
-  // Find the .debug_info section data for this chunk.
-  auto *file = cast<ObjFile<ELFT>>(chunk.infoSec->file);
-  DWARFContext dwarf(std::make_unique<LLDDwarfObj<ELFT>>(file));
-  auto &dobj = static_cast<const LLDDwarfObj<ELFT> &>(dwarf.getDWARFObj());
-  InputSection *infoSec = dobj.getInfoSection();
-  auto infoData = toStringRef(infoSec->contentMaybeDecompress());
+  auto infoData = toStringRef(chunk.infoSec->contentMaybeDecompress());
   const char *p = infoData.data();
 
   // Skim through the CUs reading the unit lengths & types to find correct
   // starting offsets for CUs (before relocation).
   uint32_t nextCu = 0;
   for (size_t i = 1, end = chunk.compUnits.size(); i < end; ++i) {
-    // First CU offset for each new (appended) .debug_names section starts at
-    // zero.
     if (chunk.compUnits[i] == 0) {
       // Skip to start of next CU and read the type & size.
       p = infoData.data() + nextCu;

>From d81d3598e589b24443eca55e53b140040e67862d Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Mon, 15 Apr 2024 13:03:30 -0700
Subject: [PATCH 22/23] writeTo: Use endian::writeNext and rename oldBuf

---
 lld/ELF/SyntheticSections.cpp | 64 +++++++++++++++--------------------
 1 file changed, 27 insertions(+), 37 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 3f7931c4d24862..dd07236aef29fc 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3243,18 +3243,19 @@ void DebugNamesSection<ELFT>::updateMultiCuOffsets(OutputChunk &chunk) {
 }
 
 template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
-  [[maybe_unused]] uint8_t *oldBuf = buf;
+  [[maybe_unused]] const uint8_t *const beginBuf = buf;
   // Write the header.
-  endian::write32<ELFT::Endianness>(buf + 0, hdr.UnitLength);
-  endian::write16<ELFT::Endianness>(buf + 4, hdr.Version);
-  endian::write32<ELFT::Endianness>(buf + 8, hdr.CompUnitCount);
-  endian::write32<ELFT::Endianness>(buf + 12, hdr.LocalTypeUnitCount);
-  endian::write32<ELFT::Endianness>(buf + 16, hdr.ForeignTypeUnitCount);
-  endian::write32<ELFT::Endianness>(buf + 20, hdr.BucketCount);
-  endian::write32<ELFT::Endianness>(buf + 24, hdr.NameCount);
-  endian::write32<ELFT::Endianness>(buf + 28, hdr.AbbrevTableSize);
-  endian::write32<ELFT::Endianness>(buf + 32, hdr.AugmentationStringSize);
-  buf += 36;
+  endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.UnitLength);
+  endian::writeNext<uint16_t, ELFT::Endianness>(buf, hdr.Version);
+  buf += 2; // padding
+  endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.CompUnitCount);
+  endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.LocalTypeUnitCount);
+  endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.ForeignTypeUnitCount);
+  endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.BucketCount);
+  endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.NameCount);
+  endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.AbbrevTableSize);
+  endian::writeNext<uint32_t, ELFT::Endianness>(buf,
+                                                hdr.AugmentationStringSize);
   memcpy(buf, hdr.AugmentationString.c_str(), hdr.AugmentationString.size());
   buf += hdr.AugmentationStringSize;
 
@@ -3264,9 +3265,8 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
     if (chunk.compUnits.size() > 1)
       updateMultiCuOffsets(chunk);
     for (uint32_t cuOffset : chunk.compUnits) {
-      endian::write32<ELFT::Endianness>(buf,
-                                        chunk.infoSec->outSecOff + cuOffset);
-      buf += 4;
+      endian::writeNext<uint32_t, ELFT::Endianness>(
+          buf, chunk.infoSec->outSecOff + cuOffset);
     }
   }
 
@@ -3291,31 +3291,22 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
     bucketIdx += bucket.size();
   }
   // Write the hashes.
-  for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
-    for (const NameEntry *e : bucket) {
-      endian::write32<ELFT::Endianness>(buf, e->hashValue);
-      buf += 4;
-    }
-  }
+  for (const SmallVector<NameEntry *, 0> &bucket : buckets)
+    for (const NameEntry *e : bucket)
+      endian::writeNext<uint32_t, ELFT::Endianness>(buf, e->hashValue);
 
   // Write the name table. The name entries are ordered by bucket_idx and
   // correspond one-to-one with the hash lookup table.
   //
   // First, write the relocated string offsets.
-  for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
-    for (const NameEntry *ne : bucket) {
-      endian::write32<ELFT::Endianness>(buf, ne->stringOffset);
-      buf += 4;
-    }
-  }
+  for (const SmallVector<NameEntry *, 0> &bucket : buckets)
+    for (const NameEntry *ne : bucket)
+      endian::writeNext<uint32_t, ELFT::Endianness>(buf, ne->stringOffset);
 
   // Then write the entry offsets.
-  for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
-    for (const NameEntry *ne : bucket) {
-      endian::write32<ELFT::Endianness>(buf, ne->entryOffset);
-      buf += 4;
-    }
-  }
+  for (const SmallVector<NameEntry *, 0> &bucket : buckets)
+    for (const NameEntry *ne : bucket)
+      endian::writeNext<uint32_t, ELFT::Endianness>(buf, ne->entryOffset);
 
   // Write the abbrev table.
   memcpy(buf, abbrevTableBuf.data(), abbrevTableBuf.size());
@@ -3331,24 +3322,23 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
         for (AttrValue value : ie.attrValues) {
           switch (value.attrSize) {
           case 1:
-            *buf = value.attrValue;
+            *buf++ = value.attrValue;
             break;
           case 2:
-            endian::write16<ELFT::Endianness>(buf, value.attrValue);
+            endian::writeNext<uint16_t, ELFT::Endianness>(buf, value.attrValue);
             break;
           case 4:
-            endian::write32<ELFT::Endianness>(buf, value.attrValue);
+            endian::writeNext<uint32_t, ELFT::Endianness>(buf, value.attrValue);
             break;
           default:
             llvm_unreachable("invalid attrSize");
           }
-          buf += value.attrSize;
         }
       }
       ++buf; // index entry sentinel
     }
   }
-  assert(uint64_t(buf - oldBuf) == size);
+  assert(uint64_t(buf - beginBuf) == size);
 }
 
 GdbIndexSection::GdbIndexSection()

>From a81528642d1c7df57db4f82f6d06ba686e9a3a46 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Mon, 15 Apr 2024 13:28:31 -0700
Subject: [PATCH 23/23] Fix CU list offsets when there are 3+ CUs in one
 relocatable file

---
 lld/ELF/SyntheticSections.cpp | 38 +++++++----------------------------
 lld/ELF/SyntheticSections.h   |  3 +--
 2 files changed, 8 insertions(+), 33 deletions(-)

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index dd07236aef29fc..89d3967eed1de5 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3170,6 +3170,7 @@ template <class ELFT> DebugNamesSection<ELFT>::DebugNamesSection() {
             const DWARFDebugNames::DWARFDebugNamesOffsets &locs) {
           // Read CU offsets.
           const char *p = namesData + niOffset + locs.CUsBase;
+          chunk.cusBase = niOffset + locs.CUsBase;
           chunk.compUnits.resize_for_overwrite(numCus + hdr.CompUnitCount);
           for (auto i : seq(hdr.CompUnitCount))
             chunk.compUnits[i + numCus] =
@@ -3208,6 +3209,10 @@ template <class ELFT> void DebugNamesSection<ELFT>::finalizeContents() {
       getNameRelocs(sec, rels.rels, relocs.get()[i]);
     else
       getNameRelocs(sec, rels.relas, relocs.get()[i]);
+
+    OutputChunk &chunk = chunks.get()[i];
+    for (auto [j, cuOffset] : enumerate(chunk.compUnits))
+      cuOffset = relocs.get()[i].lookup(chunk.cusBase + j * 4);
   });
 
   // Relocate string offsets in the name table.
@@ -3217,31 +3222,6 @@ template <class ELFT> void DebugNamesSection<ELFT>::finalizeContents() {
   });
 }
 
-template <class ELFT>
-void DebugNamesSection<ELFT>::updateMultiCuOffsets(OutputChunk &chunk) {
-  auto infoData = toStringRef(chunk.infoSec->contentMaybeDecompress());
-  const char *p = infoData.data();
-
-  // Skim through the CUs reading the unit lengths & types to find correct
-  // starting offsets for CUs (before relocation).
-  uint32_t nextCu = 0;
-  for (size_t i = 1, end = chunk.compUnits.size(); i < end; ++i) {
-    if (chunk.compUnits[i] == 0) {
-      // Skip to start of next CU and read the type & size.
-      p = infoData.data() + nextCu;
-      uint32_t unit_length =
-          endian::readNext<uint32_t, ELFT::Endianness, unaligned>(p);
-      [[maybe_unused]] uint16_t version =
-          endian::readNext<uint16_t, ELFT::Endianness, unaligned>(p);
-      uint8_t unitType =
-          endian::readNext<uint8_t, ELFT::Endianness, unaligned>(p);
-      if (unitType == dwarf::DW_UT_compile)
-        nextCu += unit_length + 4;
-    }
-    chunk.compUnits[i] += nextCu;
-  }
-}
-
 template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   [[maybe_unused]] const uint8_t *const beginBuf = buf;
   // Write the header.
@@ -3262,12 +3242,8 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   // Write the CU list.
   for (auto i : seq(numChunks)) {
     OutputChunk &chunk = chunks[i];
-    if (chunk.compUnits.size() > 1)
-      updateMultiCuOffsets(chunk);
-    for (uint32_t cuOffset : chunk.compUnits) {
-      endian::writeNext<uint32_t, ELFT::Endianness>(
-          buf, chunk.infoSec->outSecOff + cuOffset);
-    }
+    for (uint32_t cuOffset : chunk.compUnits)
+      endian::writeNext<uint32_t, ELFT::Endianness>(buf, cuOffset);
   }
 
   // Write the local TU list, then the foreign TU list..
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index cbf16c4011388b..e3946ba0ae8f54 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -858,6 +858,7 @@ class DebugNamesBaseSection : public SyntheticSection {
     // Pointer to the .debug_info section that contains compile units, used to
     // compute the relocated CU offsets.
     InputSection *infoSec;
+    uint32_t cusBase;
     SmallVector<uint32_t, 0> compUnits;
   };
 
@@ -910,8 +911,6 @@ class DebugNamesSection final : public DebugNamesBaseSection {
   void getNameRelocs(InputSection *sec, ArrayRef<RelTy> rels,
                      llvm::DenseMap<uint32_t, uint32_t> &relocs);
 
-  void updateMultiCuOffsets(OutputChunk &chunk);
-
 private:
   static void readOffsets(InputChunk &inputChunk, OutputChunk &chunk,
                           llvm::DWARFDataExtractor &namesExtractor,



More information about the llvm-commits mailing list