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

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 10 10:41:14 PDT 2024


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

>From bba264628c10357f92d8c0ebba498f561593a886 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/15] [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                 | 761 ++++++++++++++++++
 lld/ELF/SyntheticSections.h                   | 134 +++
 lld/ELF/Writer.cpp                            |   3 +
 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 +++++++
 19 files changed, 3295 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..03fac65754f020 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", &debugNamesSection)
                 .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 550659464a440a..90c802abfca374 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::TargetEndianness>(buf + 0, mergedHdr.UnitLength);
+  endian::write16<ELFT::TargetEndianness>(buf + 4, mergedHdr.Version);
+  endian::write32<ELFT::TargetEndianness>(buf + 8, mergedHdr.CompUnitCount);
+  endian::write32<ELFT::TargetEndianness>(buf + 12,
+                                          mergedHdr.LocalTypeUnitCount);
+  endian::write32<ELFT::TargetEndianness>(buf + 16,
+                                          mergedHdr.ForeignTypeUnitCount);
+  endian::write32<ELFT::TargetEndianness>(buf + 20, mergedHdr.BucketCount);
+  endian::write32<ELFT::TargetEndianness>(buf + 24, mergedHdr.NameCount);
+  endian::write32<ELFT::TargetEndianness>(buf + 28, mergedHdr.AbbrevTableSize);
+  endian::write32<ELFT::TargetEndianness>(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::TargetEndianness>(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::TargetEndianness>(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::TargetEndianness>(buf + 0, hashValue);
+      buf += 4;
+    }
+  }
+
+  // Write the string offsets.
+  for (const auto &entry : mergedEntries) {
+    endian::write32<ELFT::TargetEndianness>(buf + 0,
+                                            entry.relocatedEntryOffset);
+    buf += 4;
+  }
+
+  // Write the entry offsets.
+  for (const auto &entry : mergedEntries) {
+    endian::write32<ELFT::TargetEndianness>(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::TargetEndianness>(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::TargetEndianness>(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");
+    findDebugNamesOffsets(secData.locs, secData.hdrSize, secData.hdr.Format,
+                          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);
+  mergedHdr.BucketCount = dwarf::getDebugNamesBucketAndHashCount(uniques).first;
+}
+
+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();
+  findDebugNamesOffsets(mergedOffsets, hdrSize, mergedHdr.Format, 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") {}
 
@@ -3993,6 +4749,11 @@ template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF32BE>();
 template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF64LE>();
 template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF64BE>();
 
+template DebugNamesSection *DebugNamesSection::create<ELF32LE>();
+template DebugNamesSection *DebugNamesSection::create<ELF32BE>();
+template DebugNamesSection *DebugNamesSection::create<ELF64LE>();
+template DebugNamesSection *DebugNamesSection::create<ELF64BE>();
+
 template void elf::splitSections<ELF32LE>();
 template void elf::splitSections<ELF32BE>();
 template void elf::splitSections<ELF64LE>();
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 68b4cdb1dde045..678e5cc239a7f5 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/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 021b9bb0d5e226..0d40540f0aaab2 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -570,6 +570,9 @@ template <class ELFT> void elf::createSyntheticSections() {
     add(*in.gdbIndex);
   }
 
+  if (config->debugNames)
+    add(*DebugNamesSection::create<ELFT>());
+
   // .note.GNU-stack is always added when we are creating a re-linkable
   // object file. Other linkers are using the presence of this marker
   // section to control the executable-ness of the stack area, but that
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 bbba4174b39cefcccacbe114094f6dfc94145804 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/15] [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 5d1732ef75f1c3e4286c064033a9fa5044758241 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/15] [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 90c802abfca374..0f0de300c412b5 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,16 +3095,19 @@ 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");
     findDebugNamesOffsets(secData.locs, secData.hdrSize, secData.hdr.Format,
                           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 07f98fdfe70cf93b825c2fce295601733eb7dce5 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/15] [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                 | 244 ++++-----
 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, 755 insertions(+), 995 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 0f0de300c412b5..e9808844a66774 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::TargetEndianness>(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::TargetEndianness>(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"));
     findDebugNamesOffsets(secData.locs, secData.hdrSize, secData.hdr.Format,
                           secData.hdr);
     readCompileUnitOffsets<ELFT>(secData, outputChunk, namesExtractor);
@@ -3113,10 +3114,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;
@@ -3144,15 +3145,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);
@@ -3160,14 +3161,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;
@@ -3185,10 +3187,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
@@ -3200,7 +3203,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;
@@ -3255,14 +3258,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
@@ -3331,7 +3335,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::getDebugNamesBucketAndHashCount(uniques).first;
 }
 
-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();
   findDebugNamesOffsets(mergedOffsets, hdrSize, mergedHdr.Format, 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();
@@ -4755,10 +4761,10 @@ template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF32BE>();
 template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF64LE>();
 template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF64BE>();
 
-template DebugNamesSection *DebugNamesSection::create<ELF32LE>();
-template DebugNamesSection *DebugNamesSection::create<ELF32BE>();
-template DebugNamesSection *DebugNamesSection::create<ELF64LE>();
-template DebugNamesSection *DebugNamesSection::create<ELF64BE>();
+template DebugNamesSection<ELF32LE> *DebugNamesSection<ELF32LE>::create();
+template DebugNamesSection<ELF32BE> *DebugNamesSection<ELF32BE>::create();
+template DebugNamesSection<ELF64LE> *DebugNamesSection<ELF64LE>::create();
+template DebugNamesSection<ELF64BE> *DebugNamesSection<ELF64BE>::create();
 
 template void elf::splitSections<ELF32LE>();
 template void elf::splitSections<ELF32BE>();
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 678e5cc239a7f5..3e5290d09f364f 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 9056f562c5498a8d7670adf6cb76c9eb21164bc8 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/15] [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 e9808844a66774..8d697192d84f7d 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 840a59f23450aa41826eb1be4eec3cf85e16a34b Mon Sep 17 00:00:00 2001
From: Caroline Tice <cmtice at google.com>
Date: Tue, 26 Mar 2024 23:34:03 -0700
Subject: [PATCH 06/15] [lld][ELF] Implement merged .debug_names section.

Update Writer.cpp to call create for templated ELFT class/section.
---
 lld/ELF/Writer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 0d40540f0aaab2..c114135cf93f52 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -571,7 +571,7 @@ template <class ELFT> void elf::createSyntheticSections() {
   }
 
   if (config->debugNames)
-    add(*DebugNamesSection::create<ELFT>());
+    add(*DebugNamesSection<ELFT>::create());
 
   // .note.GNU-stack is always added when we are creating a re-linkable
   // object file. Other linkers are using the presence of this marker

>From cf5ce99766084c191a8d60ae0560ac4e3712d469 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 07/15] [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 8d697192d84f7d..56ead48f86a3b5 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 8379158af27ea1fb4723a5fc7a8b23a3bd4b15c6 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 08/15] [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 a167b762b653b85e1a4cbeecb34bfe22c7d7f435 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 09/15] [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 56ead48f86a3b5..b61d698f0e1d5b 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::TargetEndianness>(buf + 0, value.attrValue);
-          buf += value.attrSize;
-        }
+        endian::write32<ELFT::TargetEndianness>(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) +
@@ -3109,7 +3099,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));
   }
 }
 
@@ -3124,7 +3113,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();
@@ -3198,7 +3187,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.
@@ -3209,8 +3198,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
@@ -3232,7 +3220,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;
@@ -3281,7 +3270,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 3e5290d09f364f..2c69d7e9fe58f2 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 bc6ce7be5894a1e0419f48ed39b1ec36dd1e6732 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 10/15] [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 b61d698f0e1d5b..8686bd572db5e6 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 2b07be273bb66627b65c79eff47770ea7c65ff1a 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 11/15] [lld][ELF] Implement merged .debug_names section.

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

diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 8686bd572db5e6..e3720a12c4516e 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2770,25 +2770,22 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   // Write out bytes for merged section.
 
   // Write the header.
-  endian::write32<ELFT::TargetEndianness>(buf + 0, mergedHdr.UnitLength);
-  endian::write16<ELFT::TargetEndianness>(buf + 4, mergedHdr.Version);
-  endian::write32<ELFT::TargetEndianness>(buf + 8, mergedHdr.CompUnitCount);
-  endian::write32<ELFT::TargetEndianness>(buf + 12,
-                                          mergedHdr.LocalTypeUnitCount);
-  endian::write32<ELFT::TargetEndianness>(buf + 16,
-                                          mergedHdr.ForeignTypeUnitCount);
-  endian::write32<ELFT::TargetEndianness>(buf + 20, mergedHdr.BucketCount);
-  endian::write32<ELFT::TargetEndianness>(buf + 24, mergedHdr.NameCount);
-  endian::write32<ELFT::TargetEndianness>(buf + 28, mergedHdr.AbbrevTableSize);
-  endian::write32<ELFT::TargetEndianness>(buf + 32,
-                                          mergedHdr.AugmentationStringSize);
+  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::TargetEndianness>(buf + 0, offset);
+    endian::write32<ELFT::Endianness>(buf + 0, offset);
     buf += 4;
   }
 
@@ -2807,7 +2804,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   uint32_t idx = 1;
   for (const auto &bucket : bucketList) {
     if (!bucket.empty())
-      endian::write32<ELFT::TargetEndianness>(buf + 0, idx);
+      endian::write32<ELFT::Endianness>(buf + 0, idx);
     idx += bucket.size();
     buf += 4;
   }
@@ -2816,21 +2813,20 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
   for (const auto &bucket : bucketList) {
     for (const auto &entry : bucket) {
       uint32_t hashValue = entry->hashValue;
-      endian::write32<ELFT::TargetEndianness>(buf + 0, hashValue);
+      endian::write32<ELFT::Endianness>(buf + 0, hashValue);
       buf += 4;
     }
   }
 
   // Write the string offsets.
   for (const auto &entry : mergedEntries) {
-    endian::write32<ELFT::TargetEndianness>(buf + 0,
-                                            entry.relocatedEntryOffset);
+    endian::write32<ELFT::Endianness>(buf + 0, entry.relocatedEntryOffset);
     buf += 4;
   }
 
   // Write the entry offsets.
   for (const auto &entry : mergedEntries) {
-    endian::write32<ELFT::TargetEndianness>(buf + 0, entry.entryOffset);
+    endian::write32<ELFT::Endianness>(buf + 0, entry.entryOffset);
     buf += 4;
   }
 
@@ -2842,7 +2838,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
       buf += encodeULEB128(attr.Index, buf);
       buf += encodeULEB128(attr.Form, buf);
     }
-    endian::write16<ELFT::TargetEndianness>(buf + 0, 0); // attribute sentinels.
+    endian::write16<ELFT::Endianness>(buf + 0, 0); // attribute sentinels.
     buf += 2;
   }
   *buf++ = 0; // abbrev table sentinel
@@ -2853,7 +2849,7 @@ 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) {
-        endian::write32<ELFT::TargetEndianness>(buf + 0, value.attrValue);
+        endian::write32<ELFT::Endianness>(buf + 0, value.attrValue);
         buf += value.attrSize;
       }
     }

>From bc98bafb06b3afa8a56b678e2ed26eac0f645048 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 12/15] [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 e3720a12c4516e..8b8679c4ca983f 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3129,8 +3129,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 e3c35bba20aea4490ba1a8ce0086fc6021a62a8f 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 13/15] [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 8b8679c4ca983f..087dbe51def97e 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;
@@ -3154,13 +3154,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 {
@@ -3192,7 +3192,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.
@@ -3233,7 +3234,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);
     }
@@ -3268,7 +3269,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
@@ -3276,14 +3277,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
@@ -3313,7 +3314,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 39d3db36ecace4d0dc1a1a7947a7044958c890ad 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 14/15] [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 adcc83e6761bc1b12eed4e61aa0428b7a64eb636 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 15/15] 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/DWARF.cpp                             |    2 +-
 lld/ELF/SyntheticSections.cpp                 | 1202 +++++++----------
 lld/ELF/SyntheticSections.h                   |  153 +--
 lld/ELF/Writer.cpp                            |    8 +-
 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         |  410 +++---
 lld/test/ELF/debug-names.s                    |  224 ++-
 lld/test/ELF/driver.test                      |    3 +-
 19 files changed, 1077 insertions(+), 1269 deletions(-)

diff --git a/lld/ELF/DWARF.cpp b/lld/ELF/DWARF.cpp
index 03fac65754f020..5d58e0c60a952e 100644
--- a/lld/ELF/DWARF.cpp
+++ b/lld/ELF/DWARF.cpp
@@ -40,7 +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", &debugNamesSection)
+                .Case(".debug_names", &namesSection)
                 .Case(".debug_ranges", &rangesSection)
                 .Case(".debug_rnglists", &rnglistsSection)
                 .Case(".debug_str_offsets", &strOffsetsSection)
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 087dbe51def97e..7dc5169d7388b7 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,579 @@ 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;
+// 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::parse(
+    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;
+  SmallVector<uint32_t, 0> entryOffsets;
+  for (const DWARFDebugNames::NameIndex &llvmNi : *inputChunk.llvmDebugNames) {
+    NameIndex &ni = inputChunk.nameIndices.emplace_back();
+    ni.hdr = llvmNi.getHeader();
+    if (ni.hdr.Format != DwarfFormat::DWARF32) {
+      errorOrWarn(toString(namesSec.sec) + Twine(": unsupported DWARF64"));
+      return;
     }
-  }
-
-  // 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);
+    if (ni.hdr.Version != 5) {
+      errorOrWarn(toString(namesSec.sec) + Twine(": unsupported version ") +
+                  Twine(ni.hdr.Version));
+      return;
     }
-    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;
-      }
+    const uint32_t dwarfSize =
+        dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
+    const uint32_t hdrSize =
+        getDebugNamesHeaderSize(ni.hdr.AugmentationStringSize);
+    auto locs = findDebugNamesOffsets(hdrSize, ni.hdr);
+    if (locs.EntriesBase > namesExtractor.getData().size()) {
+      errorOrWarn(toString(namesSec.sec) +
+                  Twine(": index entry is out of bounds"));
+      return;
     }
-    *buf++ = 0; // Entry sentinel
-  }
-}
 
-template <class ELFT> bool DebugNamesSection<ELFT>::isNeeded() const {
-  return numChunks > 0;
-}
+    SmallVector<uint32_t, 0> entryOffsets = readOffsets(ni.hdr, locs);
+
+    // Read the entry pool.
+    offsetMap.clear();
+    ni.nameEntries.resize(ni.hdr.NameCount);
+    for (auto i : seq(ni.hdr.NameCount)) {
+      NameTableEntry &nte = ni.nameEntries[i];
+      uint64_t strOffset = locs.StringOffsetsBase + i * dwarfSize;
+      nte.stringOffset = strOffset;
+      uint64_t strp = namesExtractor.getRelocatedValue(dwarfSize, &strOffset);
+      StringRef name = strExtractor.getCStrRef(&strp);
+      nte.name = name.data();
+      nte.hashValue = caseFoldingDjbHash(name);
+
+      // Read a series of index entries that end with abbreviation code 0.
+      const char *errMsg = nullptr;
+      uint64_t off = locs.EntriesBase + entryOffsets[i];
+      while (off < namesSec.Data.size() && namesSec.Data[off] != 0) {
+        auto ie = makeThreadLocal<IndexEntry>();
+        ie->poolOffset = off;
+        Error err = Error::success();
+        ie->abbrevCode =
+            static_cast<uint32_t>(namesExtractor.getULEB128(&off, &err));
+        if (err) {
+          consumeError(std::move(err));
+          errMsg = ": invalid abbrev code in entry";
+          break;
+        }
+        auto it = llvmNi.getAbbrevs().find_as(ie->abbrevCode);
+        if (it == llvmNi.getAbbrevs().end()) {
+          errMsg = ": invalid abbrev code in entry";
+          break;
+        }
 
-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"));
-}
+        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(&off, &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(&off, &err);
+              attr.attrSize = 1;
+              break;
+            }
+            case DW_FORM_data2:
+            case DW_FORM_ref2: {
+              attr.attrValue = namesExtractor.getU16(&off, &err);
+              attr.attrSize = 2;
+              break;
+            }
+            case DW_FORM_data4:
+            case DW_FORM_ref4: {
+              attr.attrValue = namesExtractor.getU32(&off, &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 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"));
-}
+        // Canonicalize abbrev by placing the CU/TU index at the end.
+        ie->attrValues.push_back(cuAttr);
+        nte.indexEntries.push_back(std::move(ie));
+      }
+      if (off >= namesSec.Data.size())
+        errMsg = ": index entry is out of bounds";
+      if (errMsg)
+        errorOrWarn(toString(namesSec.sec) + Twine(errMsg));
 
-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;
-    }
-    default: {
-      errorOrWarn(toString(namesSection.sec) +
-                  Twine(": unrecognized form encoding ") + Twine(attr.Form) +
-                  Twine(" in .debug_names abbrev table"));
-      break;
-    }
+      for (IndexEntry &ie : nte.entries())
+        offsetMap[ie.poolOffset] = &ie;
     }
-    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);
-}
-
-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"));
-}
 
-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));
+    // Assign parent pointers, which will be used to update DW_IDX_parent index
+    // attributes.
+    for (NameTableEntry &nte : ni.nameEntries)
+      for (IndexEntry &ie : nte.entries())
+        ie.parentEntry =
+            ie.parentOffset == 0 ? nullptr : offsetMap.lookup(ie.parentOffset);
   }
-  // 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(
-    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;
-    }
-    secData.dwarfSize = dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
-    secData.hdrSize = computeDebugNamesHeaderSize();
-    if (secData.hdr.Version != 5)
-      errorOrWarn(toString(chunk.namesSection->sec) +
-                  Twine(": unsupported version"));
-    findDebugNamesOffsets(secData.locs, secData.hdrSize, secData.hdr.Format,
-                          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();
+// 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.baseCuOffsetIdx = numCu;
+    numCu += chunks[i].compUnits.size();
+    for (const NameIndex &data : inputChunk.nameIndices) {
+      hdr.CompUnitCount += data.hdr.CompUnitCount;
+      hdr.LocalTypeUnitCount += data.hdr.LocalTypeUnitCount;
+      hdr.ForeignTypeUnitCount += data.hdr.ForeignTypeUnitCount;
+      // If augmentation strings are not identical, use an empty string.
+      if (i == 0) {
+        hdr.AugmentationStringSize = data.hdr.AugmentationStringSize;
+        hdr.AugmentationString = data.hdr.AugmentationString;
+      } else if (hdr.AugmentationString != data.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;
+  const dwarf::Form cuAttrForm = getMergedCuCountForm(hdr.CompUnitCount).second;
+  for (InputChunk &chunk : inputChunks) {
+    for (auto [i, llvmNi] : enumerate(*chunk.llvmDebugNames)) {
+      for (const DWARFDebugNames::Abbrev &oldAbbrev : llvmNi.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;
+        chunk.nameIndices[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.
+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.
   constexpr size_t numShards = 32;
   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];
+  SmallVector<NameTableEntry, 0> nameVecs[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 &chunk = inputChunks[i];
+      for (NameIndex &ni : chunk.nameIndices) {
+        for (NameTableEntry &nte : ni.nameEntries) {
+          auto shardId = nte.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];
+          nte.chunkIdx = i;
+          for (IndexEntry &ie : nte.entries()) {
+            ie.abbrevCode = ni.abbrevCodeMap[ie.abbrevCode];
+            // Update the DW_IDX_compile_unit attribute (the last one ensured by
+            // `DebugNamesBaseSection::parse`).
+            auto &back = ie.attrValues.back();
+            back.attrValue += chunk.baseCuOffsetIdx;
+            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(nte.name, nte.hashValue), nameVec.size());
+          if (inserted)
+            nameVec.push_back(std::move(nte));
+          else
+            nameVec[it->second].indexEntries.append(nte.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);
-  mergedHdr.BucketCount = dwarf::getDebugNamesBucketAndHashCount(uniques).first;
-}
-
-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], nums[numShards];
+  parallelFor(0, numShards, [&](size_t shard) {
+    uint32_t offset = 0;
+    for (NameTableEntry &nte : nameVecs[shard]) {
+      nte.entryOffset = offset;
+      for (IndexEntry &ie : nte.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;
+    nums[shard] = maps[shard].size();
+  });
+  // 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 (NameTableEntry &nte : nameVecs[shard]) {
+      nte.entryOffset += offset;
+      for (IndexEntry &ie : nte.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;
+  // Allocate `names` to hold all NameTableEntry objects. Also update
+  // DW_IDX_parent attributes that use DW_FORM_ref4.
+  std::partial_sum(nums, std::end(nums), nums);
+  names.resize(nums[numShards - 1]);
+  parallelFor(0, numShards, [&](size_t shard) {
+    for (NameTableEntry &nte : nameVecs[shard]) {
+      for (IndexEntry &ie : nte.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;
+        }
       }
     }
-  }
-}
+    llvm::move(nameVecs[shard], names.begin() + (shard ? nums[shard - 1] : 0));
+  });
 
-template <class ELFT>
-uint64_t DebugNamesSection<ELFT>::calculateMergedSectionSize() {
-  uint32_t hdrSize = computeDebugNamesHeaderSize();
-  findDebugNamesOffsets(mergedOffsets, hdrSize, mergedHdr.Format, 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).
+  return {offsets[numShards - 1], nums[numShards - 1]};
 }
 
-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);
+    parse(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(names, [&](NameTableEntry &nte) {
+    nte.stringOffset = relocs.get()[nte.chunkIdx][nte.stringOffset];
+  });
+}
+
+template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
+  [[maybe_unused]] uint8_t *origBuf = 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<NameTableEntry *, 0>, 0> buckets(hdr.BucketCount);
+    for (NameTableEntry &nte : names)
+      buckets[nte.hashValue % hdr.BucketCount].push_back(&nte);
+    for (SmallVector<NameTableEntry *, 0> &bucket : buckets)
+      stable_sort(bucket, [](NameTableEntry *lhs, NameTableEntry *rhs) {
+        return lhs->hashValue < rhs->hashValue;
+      });
+    // Write buckets.
+    uint32_t bucketIdx = 1;
+    for (const SmallVector<NameTableEntry *, 0> &bucket : buckets) {
+      if (!bucket.empty())
+        endian::write32<ELFT::Endianness>(buf, bucketIdx);
+      buf += 4;
+      bucketIdx += bucket.size();
+    }
+    // Write hashes.
+    for (const SmallVector<NameTableEntry *, 0> &bucket : buckets) {
+      for (NameTableEntry *e : bucket) {
+        endian::write32<ELFT::Endianness>(buf, e->hashValue);
+        buf += 4;
+      }
+    }
+  }
+
+  // Write the relocated string offsets in the name table.
+  for (const NameTableEntry &nte : names) {
+    endian::write32<ELFT::Endianness>(buf, nte.stringOffset);
+    buf += 4;
+  }
+
+  // Write the entry offsets in the name table.
+  for (const NameTableEntry &nte : names) {
+    endian::write32<ELFT::Endianness>(buf, nte.entryOffset);
+    buf += 4;
+  }
+
+  // Write the abbrev table.
+  memcpy(buf, abbrevTableBuf.data(), abbrevTableBuf.size());
+  buf += abbrevTableBuf.size();
+
+  // Write the entry pool.
+  for (NameTableEntry &nte : names) {
+    for (const IndexEntry &ie : nte.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 - origBuf) == size);
 }
 
 GdbIndexSection::GdbIndexSection()
@@ -4614,6 +4439,7 @@ void InStruct::reset() {
   ppc32Got2.reset();
   ibtPlt.reset();
   relaPlt.reset();
+  debugNames.reset();
   gdbIndex.reset();
   shStrTab.reset();
   strTab.reset();
@@ -4741,16 +4567,16 @@ InStruct elf::in;
 std::vector<Partition> elf::partitions;
 Partition *elf::mainPart;
 
+template class elf::DebugNamesSection<ELF32LE>;
+template class elf::DebugNamesSection<ELF32BE>;
+template class elf::DebugNamesSection<ELF64LE>;
+template class elf::DebugNamesSection<ELF64BE>;
+
 template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF32LE>();
 template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF32BE>();
 template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF64LE>();
 template std::unique_ptr<GdbIndexSection> GdbIndexSection::create<ELF64BE>();
 
-template DebugNamesSection<ELF32LE> *DebugNamesSection<ELF32LE>::create();
-template DebugNamesSection<ELF32BE> *DebugNamesSection<ELF32BE>::create();
-template DebugNamesSection<ELF64LE> *DebugNamesSection<ELF64LE>::create();
-template DebugNamesSection<ELF64BE> *DebugNamesSection<ELF64BE>::create();
-
 template void elf::splitSections<ELF32LE>();
 template void elf::splitSections<ELF32BE>();
 template void elf::splitSections<ELF64LE>();
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 2c69d7e9fe58f2..f225c96c9ea6fb 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,98 @@ 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 NameTableEntry {
     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 NameIndex {
     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<NameTableEntry, 0> nameEntries;
   };
 
-  // Per-file data used, while reading in the data, to generate the merged
-  // section information.
-  struct DebugNamesInputChunk {
+  // InputChunk and OutputChunk hold per-file contribution to the merged index.
+  // InputChunk instances will be discarded after `create` completes.
+  struct InputChunk {
     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;
+    LLDDWARFSection section;
+    SmallVector<NameIndex, 0> nameIndices;
+    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 parse(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;
+  SmallVector<NameTableEntry, 0> names;
+};
+
+// 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 {
@@ -1483,6 +1479,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 c114135cf93f52..35520b8e9377b2 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -565,14 +565,15 @@ template <class ELFT> void elf::createSyntheticSections() {
   if (config->andFeatures || !ctx.aarch64PauthAbiCoreInfo.empty())
     add(*make<GnuPropertySection>());
 
+  if (config->debugNames) {
+    in.debugNames = std::make_unique<DebugNamesSection<ELFT>>();
+    add(*in.debugNames);
+  }
   if (config->gdbIndex) {
     in.gdbIndex = GdbIndexSection::create<ELFT>();
     add(*in.gdbIndex);
   }
 
-  if (config->debugNames)
-    add(*DebugNamesSection<ELFT>::create());
-
   // .note.GNU-stack is always added when we are creating a re-linkable
   // object file. Other linkers are using the presence of this marker
   // section to control the executable-ness of the stack area, but that
@@ -2247,6 +2248,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..69d38cdeddc1fc 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: {{.*}}:(.debug_names): index entry is out of bounds
+# CHECK: error: {{.*}}:(.debug_names): index entry is out of bounds
+# CHECK: error: {{.*}}:(.debug_names): index entry is out of bounds
+# CHECK: error: {{.*}}:(.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..a50f6e2806d39b 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: {{.*}}:(.debug_names): index entry is out of bounds
+# CHECK: error: {{.*}}:(.debug_names): index entry is out of bounds
+# CHECK: error: {{.*}}:(.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..ecf345e7786f38 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: {{.*}}:(.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..63ba496e0ab82e 100644
--- a/lld/test/ELF/debug-names-parent-idx.s
+++ b/lld/test/ELF/debug-names-parent-idx.s
@@ -1,192 +1,190 @@
-// 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:            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
 
 #--- debug-names-parent-idx.s
 	.text
@@ -425,41 +423,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..affdf75f473518 100644
--- a/lld/test/ELF/debug-names.s
+++ b/lld/test/ELF/debug-names.s
@@ -1,119 +1,113 @@
-// 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:        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.s
+#--- a.s
 	.text
 	.globl	_Z2f12t1                        # -- Begin function _Z2f12t1
 	.p2align	4, 0x90
@@ -241,18 +235,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



More information about the llvm-commits mailing list