[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