aboutsummaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
authorcmtice <cmtice@google.com>2024-04-18 14:41:14 -0700
committerGitHub <noreply@github.com>2024-04-18 14:41:14 -0700
commit16711b431b843dd2143d38fdf6b0591dfb1783e0 (patch)
tree3267917461f7640e1dfb8eae2377528aace354f8 /lld
parent6e6da74c8b936e457ca5e56a828823ae6a9f9066 (diff)
downloadllvm-16711b431b843dd2143d38fdf6b0591dfb1783e0.zip
llvm-16711b431b843dd2143d38fdf6b0591dfb1783e0.tar.gz
llvm-16711b431b843dd2143d38fdf6b0591dfb1783e0.tar.bz2
[lld][ELF] Add --debug-names to create merged .debug_names. (#86508)
`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@maskray.me> --------- Co-authored-by: Fangrui Song <i@maskray.me>
Diffstat (limited to 'lld')
-rw-r--r--lld/ELF/Config.h1
-rw-r--r--lld/ELF/DWARF.cpp1
-rw-r--r--lld/ELF/DWARF.h4
-rw-r--r--lld/ELF/Driver.cpp3
-rw-r--r--lld/ELF/Options.td4
-rw-r--r--lld/ELF/SyntheticSections.cpp610
-rw-r--r--lld/ELF/SyntheticSections.h133
-rw-r--r--lld/ELF/Writer.cpp1
-rw-r--r--lld/docs/ReleaseNotes.rst3
-rw-r--r--lld/docs/ld.lld.14
-rw-r--r--lld/test/ELF/Inputs/debug-names-a.s239
-rw-r--r--lld/test/ELF/Inputs/debug-names-b.s358
-rw-r--r--lld/test/ELF/debug-names-bad.s97
-rw-r--r--lld/test/ELF/debug-names-die-offset-form-flag-present.s152
-rw-r--r--lld/test/ELF/debug-names-different-aug-string.s14
-rw-r--r--lld/test/ELF/debug-names-dwarf64.s250
-rw-r--r--lld/test/ELF/debug-names-missing-parent.s234
-rw-r--r--lld/test/ELF/debug-names-multi-cus.s789
-rw-r--r--lld/test/ELF/debug-names-nonames.s33
-rw-r--r--lld/test/ELF/debug-names-parent-idx.s746
-rw-r--r--lld/test/ELF/debug-names-type-units.s895
-rw-r--r--lld/test/ELF/debug-names.s430
-rw-r--r--lld/test/ELF/driver.test3
-rw-r--r--lld/test/ELF/ppc32-debug-names.s418
24 files changed, 5421 insertions, 1 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 83f293a..33bfa42 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 ac28aa8..5d58e0c 100644
--- a/lld/ELF/DWARF.cpp
+++ b/lld/ELF/DWARF.cpp
@@ -40,6 +40,7 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *obj) {
.Case(".debug_gnu_pubtypes", &gnuPubtypesSection)
.Case(".debug_line", &lineSection)
.Case(".debug_loclists", &loclistsSection)
+ .Case(".debug_names", &namesSection)
.Case(".debug_ranges", &rangesSection)
.Case(".debug_rnglists", &rnglistsSection)
.Case(".debug_str_offsets", &strOffsetsSection)
diff --git a/lld/ELF/DWARF.h b/lld/ELF/DWARF.h
index ada38a0..64c25c7 100644
--- a/lld/ELF/DWARF.h
+++ b/lld/ELF/DWARF.h
@@ -62,6 +62,9 @@ public:
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 @@ private:
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 86cc096..5fffdc5 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 c5e95d0..d470646 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 0d7f393..7b9ada4 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -30,15 +30,19 @@
#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"
#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"
#include "llvm/Support/TimeProfiler.h"
+#include <cinttypes>
#include <cstdlib>
using namespace llvm;
@@ -2711,6 +2715,606 @@ static uint32_t computeGdbHash(StringRef s) {
return h;
}
+// 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;
+}
+
+static Expected<DebugNamesBaseSection::IndexEntry *>
+readEntry(uint64_t &offset, const DWARFDebugNames::NameIndex &ni,
+ uint64_t entriesBase, DWARFDataExtractor &namesExtractor,
+ const LLDDWARFSection &namesSec) {
+ auto ie = makeThreadLocal<DebugNamesBaseSection::IndexEntry>();
+ ie->poolOffset = offset;
+ Error err = Error::success();
+ uint64_t ulebVal = namesExtractor.getULEB128(&offset, &err);
+ if (err)
+ return createStringError(inconvertibleErrorCode(),
+ "invalid abbrev code: %s",
+ toString(std::move(err)).c_str());
+ if (!isUInt<32>(ulebVal))
+ return createStringError(inconvertibleErrorCode(),
+ "abbrev code too large for DWARF32: %" PRIu64,
+ ulebVal);
+ ie->abbrevCode = static_cast<uint32_t>(ulebVal);
+ auto it = ni.getAbbrevs().find_as(ie->abbrevCode);
+ if (it == ni.getAbbrevs().end())
+ return createStringError(inconvertibleErrorCode(),
+ "abbrev code not found in abbrev table: %" PRIu32,
+ ie->abbrevCode);
+
+ DebugNamesBaseSection::AttrValue attr, cuAttr = {0, 0};
+ for (DWARFDebugNames::AttributeEncoding a : it->Attributes) {
+ if (a.Index == dwarf::DW_IDX_parent) {
+ if (a.Form == dwarf::DW_FORM_ref4) {
+ attr.attrValue = namesExtractor.getU32(&offset, &err);
+ attr.attrSize = 4;
+ ie->parentOffset = entriesBase + attr.attrValue;
+ } else if (a.Form != DW_FORM_flag_present)
+ return createStringError(inconvertibleErrorCode(),
+ "invalid form for DW_IDX_parent");
+ } else {
+ switch (a.Form) {
+ case DW_FORM_data1:
+ case DW_FORM_ref1: {
+ attr.attrValue = namesExtractor.getU8(&offset, &err);
+ attr.attrSize = 1;
+ break;
+ }
+ case DW_FORM_data2:
+ case DW_FORM_ref2: {
+ attr.attrValue = namesExtractor.getU16(&offset, &err);
+ attr.attrSize = 2;
+ break;
+ }
+ case DW_FORM_data4:
+ case DW_FORM_ref4: {
+ attr.attrValue = namesExtractor.getU32(&offset, &err);
+ attr.attrSize = 4;
+ break;
+ }
+ default:
+ return createStringError(
+ inconvertibleErrorCode(),
+ "unrecognized form encoding %d in abbrev table", a.Form);
+ }
+ }
+ if (err)
+ return createStringError(inconvertibleErrorCode(),
+ "error while reading attributes: %s",
+ toString(std::move(err)).c_str());
+ if (a.Index == DW_IDX_compile_unit)
+ cuAttr = attr;
+ else if (a.Form != DW_FORM_flag_present)
+ ie->attrValues.push_back(attr);
+ }
+ // Canonicalize abbrev by placing the CU/TU index at the end.
+ ie->attrValues.push_back(cuAttr);
+ return ie;
+}
+
+void DebugNamesBaseSection::parseDebugNames(
+ InputChunk &inputChunk, OutputChunk &chunk,
+ DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor,
+ function_ref<SmallVector<uint32_t, 0>(
+ uint32_t numCus, const DWARFDebugNames::Header &,
+ const DWARFDebugNames::DWARFDebugNamesOffsets &)>
+ readOffsets) {
+ const LLDDWARFSection &namesSec = inputChunk.section;
+ DenseMap<uint32_t, IndexEntry *> offsetMap;
+ // Number of CUs seen in previous NameIndex sections within current chunk.
+ uint32_t numCus = 0;
+ for (const DWARFDebugNames::NameIndex &ni : *inputChunk.llvmDebugNames) {
+ NameData &nd = inputChunk.nameData.emplace_back();
+ nd.hdr = ni.getHeader();
+ if (nd.hdr.Format != DwarfFormat::DWARF32) {
+ errorOrWarn(toString(namesSec.sec) +
+ Twine(": found DWARF64, which is currently unsupported"));
+ return;
+ }
+ if (nd.hdr.Version != 5) {
+ errorOrWarn(toString(namesSec.sec) + Twine(": unsupported version: ") +
+ Twine(nd.hdr.Version));
+ return;
+ }
+ uint32_t dwarfSize = dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
+ DWARFDebugNames::DWARFDebugNamesOffsets locs = ni.getOffsets();
+ if (locs.EntriesBase > namesExtractor.getData().size()) {
+ errorOrWarn(toString(namesSec.sec) +
+ Twine(": entry pool start is beyond end of section"));
+ return;
+ }
+
+ SmallVector<uint32_t, 0> entryOffsets = readOffsets(numCus, nd.hdr, locs);
+
+ // Read the entry pool.
+ offsetMap.clear();
+ nd.nameEntries.resize(nd.hdr.NameCount);
+ for (auto i : seq(nd.hdr.NameCount)) {
+ NameEntry &ne = nd.nameEntries[i];
+ uint64_t strOffset = locs.StringOffsetsBase + i * dwarfSize;
+ ne.stringOffset = strOffset;
+ uint64_t strp = namesExtractor.getRelocatedValue(dwarfSize, &strOffset);
+ StringRef name = strExtractor.getCStrRef(&strp);
+ ne.name = name.data();
+ ne.hashValue = caseFoldingDjbHash(name);
+
+ // Read a series of index entries that end with abbreviation code 0.
+ uint64_t offset = locs.EntriesBase + entryOffsets[i];
+ while (offset < namesSec.Data.size() && namesSec.Data[offset] != 0) {
+ // Read & store all entries (for the same string).
+ Expected<IndexEntry *> ieOrErr =
+ readEntry(offset, ni, locs.EntriesBase, namesExtractor, namesSec);
+ if (!ieOrErr) {
+ errorOrWarn(toString(namesSec.sec) + ": " +
+ toString(ieOrErr.takeError()));
+ return;
+ }
+ ne.indexEntries.push_back(std::move(*ieOrErr));
+ }
+ if (offset >= namesSec.Data.size())
+ errorOrWarn(toString(namesSec.sec) +
+ Twine(": index entry is out of bounds"));
+
+ for (IndexEntry &ie : ne.entries())
+ offsetMap[ie.poolOffset] = &ie;
+ }
+
+ // Assign parent pointers, which will be used to update DW_IDX_parent index
+ // attributes. Note: offsetMap[0] does not exist, so parentOffset == 0 will
+ // get parentEntry == null as well.
+ for (NameEntry &ne : nd.nameEntries)
+ for (IndexEntry &ie : ne.entries())
+ ie.parentEntry = offsetMap.lookup(ie.parentOffset);
+ numCus += nd.hdr.CompUnitCount;
+ }
+}
+
+// Compute the form for output DW_IDX_compile_unit attributes, similar to
+// DIEInteger::BestForm. The input form (often DW_FORM_data1) may not hold all
+// the merged CU indices.
+std::pair<uint8_t, dwarf::Form> static getMergedCuCountForm(
+ uint32_t compUnitCount) {
+ if (compUnitCount > UINT16_MAX)
+ return {4, DW_FORM_data4};
+ if (compUnitCount > UINT8_MAX)
+ return {2, DW_FORM_data2};
+ return {1, DW_FORM_data1};
+}
+
+void DebugNamesBaseSection::computeHdrAndAbbrevTable(
+ MutableArrayRef<InputChunk> inputChunks) {
+ TimeTraceScope timeScope("Merge .debug_names", "hdr and abbrev table");
+ size_t numCu = 0;
+ hdr.Format = DwarfFormat::DWARF32;
+ hdr.Version = 5;
+ hdr.CompUnitCount = 0;
+ hdr.LocalTypeUnitCount = 0;
+ hdr.ForeignTypeUnitCount = 0;
+ hdr.AugmentationStringSize = 0;
+
+ // Compute CU and TU counts.
+ for (auto i : seq(numChunks)) {
+ InputChunk &inputChunk = inputChunks[i];
+ inputChunk.baseCuIdx = numCu;
+ numCu += chunks[i].compUnits.size();
+ for (const NameData &nd : inputChunk.nameData) {
+ hdr.CompUnitCount += nd.hdr.CompUnitCount;
+ // TODO: We don't handle type units yet, so LocalTypeUnitCount &
+ // ForeignTypeUnitCount are left as 0.
+ if (nd.hdr.LocalTypeUnitCount || nd.hdr.ForeignTypeUnitCount)
+ warn(toString(inputChunk.section.sec) +
+ Twine(": type units are not implemented"));
+ // If augmentation strings are not identical, use an empty string.
+ if (i == 0) {
+ hdr.AugmentationStringSize = nd.hdr.AugmentationStringSize;
+ hdr.AugmentationString = nd.hdr.AugmentationString;
+ } else if (hdr.AugmentationString != nd.hdr.AugmentationString) {
+ // There are conflicting augmentation strings, so it's best for the
+ // merged index to not use an augmentation string.
+ hdr.AugmentationStringSize = 0;
+ hdr.AugmentationString.clear();
+ }
+ }
+ }
+
+ // Create the merged abbrev table, uniquifyinng the input abbrev tables and
+ // computing mapping from old (per-cu) abbrev codes to new (merged) abbrev
+ // codes.
+ FoldingSet<Abbrev> abbrevSet;
+ // Determine the form for the DW_IDX_compile_unit attributes in the merged
+ // index. The input form may not be big enough for all CU indices.
+ dwarf::Form cuAttrForm = getMergedCuCountForm(hdr.CompUnitCount).second;
+ for (InputChunk &inputChunk : inputChunks) {
+ for (auto [i, ni] : enumerate(*inputChunk.llvmDebugNames)) {
+ for (const DWARFDebugNames::Abbrev &oldAbbrev : ni.getAbbrevs()) {
+ // Canonicalize abbrev by placing the CU/TU index at the end,
+ // similar to 'parseDebugNames'.
+ 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
+ abbrev.attributes.push_back({a.Index, a.Form});
+ }
+ // Put the CU/TU index at the end of the attributes list.
+ abbrev.attributes.push_back(cuAttr);
+
+ // Profile the abbrev, get or assign a new code, then record the abbrev
+ // code mapping.
+ FoldingSetNodeID id;
+ abbrev.Profile(id);
+ uint32_t newCode;
+ void *insertPos;
+ if (Abbrev *existing = abbrevSet.FindNodeOrInsertPos(id, insertPos)) {
+ // Found it; we've already seen an identical abbreviation.
+ newCode = existing->code;
+ } else {
+ Abbrev *abbrev2 =
+ new (abbrevAlloc.Allocate()) Abbrev(std::move(abbrev));
+ abbrevSet.InsertNode(abbrev2, insertPos);
+ abbrevTable.push_back(abbrev2);
+ newCode = abbrevTable.size();
+ abbrev2->code = newCode;
+ }
+ inputChunk.nameData[i].abbrevCodeMap[oldAbbrev.Code] = newCode;
+ }
+ }
+ }
+
+ // 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);
+ }
+ os.write("\0", 2); // attribute specification end
+ }
+ os.write(0); // abbrev table end
+ hdr.AbbrevTableSize = abbrevTableBuf.size();
+}
+
+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 and de-duplicate all the names (preserving all the entries).
+ // Speed it up using multithreading, as the number of symbols can be in the
+ // order of millions.
+ const size_t concurrency =
+ bit_floor(std::min<size_t>(config->threadCount, numShards));
+ const size_t shift = 32 - countr_zero(numShards);
+ const uint8_t cuAttrSize = getMergedCuCountForm(hdr.CompUnitCount).first;
+ DenseMap<CachedHashStringRef, size_t> maps[numShards];
+
+ parallelFor(0, concurrency, [&](size_t threadId) {
+ for (auto i : seq(numChunks)) {
+ InputChunk &inputChunk = inputChunks[i];
+ for (auto j : seq(inputChunk.nameData.size())) {
+ NameData &nd = inputChunk.nameData[j];
+ // Deduplicate the NameEntry records (based on the string/name),
+ // appending all IndexEntries from duplicate NameEntry records to
+ // the single preserved copy.
+ for (NameEntry &ne : nd.nameEntries) {
+ auto shardId = ne.hashValue >> shift;
+ if ((shardId & (concurrency - 1)) != threadId)
+ continue;
+
+ ne.chunkIdx = i;
+ for (IndexEntry &ie : ne.entries()) {
+ // Update the IndexEntry's abbrev code to match the merged
+ // abbreviations.
+ ie.abbrevCode = nd.abbrevCodeMap[ie.abbrevCode];
+ // Update the DW_IDX_compile_unit attribute (the last one after
+ // canonicalization) to have correct merged offset value and size.
+ auto &back = ie.attrValues.back();
+ back.attrValue += inputChunk.baseCuIdx + j;
+ back.attrSize = cuAttrSize;
+ }
+
+ auto &nameVec = nameVecs[shardId];
+ auto [it, inserted] = maps[shardId].try_emplace(
+ CachedHashStringRef(ne.name, ne.hashValue), nameVec.size());
+ if (inserted)
+ nameVec.push_back(std::move(ne));
+ else
+ nameVec[it->second].indexEntries.append(std::move(ne.indexEntries));
+ }
+ }
+ }
+ });
+
+ // Compute entry offsets in parallel. First, compute offsets relative to the
+ // current shard.
+ uint32_t offsets[numShards];
+ parallelFor(0, numShards, [&](size_t shard) {
+ uint32_t offset = 0;
+ for (NameEntry &ne : nameVecs[shard]) {
+ ne.entryOffset = offset;
+ for (IndexEntry &ie : ne.entries()) {
+ ie.poolOffset = offset;
+ offset += getULEB128Size(ie.abbrevCode);
+ for (AttrValue value : ie.attrValues)
+ offset += value.attrSize;
+ }
+ ++offset; // index entry sentinel
+ }
+ offsets[shard] = offset;
+ });
+ // Then add shard offsets.
+ std::partial_sum(offsets, std::end(offsets), offsets);
+ parallelFor(1, numShards, [&](size_t shard) {
+ uint32_t offset = offsets[shard - 1];
+ for (NameEntry &ne : nameVecs[shard]) {
+ ne.entryOffset += offset;
+ for (IndexEntry &ie : ne.entries())
+ ie.poolOffset += offset;
+ }
+ });
+
+ // Update the DW_IDX_parent entries that refer to real parents (have
+ // DW_FORM_ref4).
+ parallelFor(0, numShards, [&](size_t shard) {
+ for (NameEntry &ne : nameVecs[shard]) {
+ for (IndexEntry &ie : ne.entries()) {
+ if (!ie.parentEntry)
+ continue;
+ // Abbrevs are indexed starting at 1; vector starts at 0. (abbrevCode
+ // corresponds to position in the merged table vector).
+ const Abbrev *abbrev = abbrevTable[ie.abbrevCode - 1];
+ for (const auto &[a, v] : zip_equal(abbrev->attributes, ie.attrValues))
+ if (a.Index == DW_IDX_parent && a.Form == DW_FORM_ref4)
+ v.attrValue = ie.parentEntry->poolOffset;
+ }
+ }
+ });
+
+ // Return (entry pool size, number of entries).
+ uint32_t num = 0;
+ for (auto &map : maps)
+ num += map.size();
+ return {offsets[numShards - 1], num};
+}
+
+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;
+ for (InputSectionBase *s : ctx.inputSections) {
+ InputSection *isec = dyn_cast<InputSection>(s);
+ if (!isec)
+ continue;
+ if (!(s->flags & SHF_ALLOC) && s->name == ".debug_names") {
+ s->markDead();
+ inputSections.push_back(isec);
+ files.insert(isec->file);
+ }
+ }
+
+ // 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)));
+ }
+ parseDebugNames(
+ inputChunk, chunk, namesExtractor, strExtractor,
+ [&chunk, namesData = dobj.getNamesSection().Data.data()](
+ uint32_t numCus, const DWARFDebugNames::Header &hdr,
+ const DWARFDebugNames::DWARFDebugNamesOffsets &locs) {
+ // Read CU offsets, which are relocated by .debug_info + X
+ // relocations. Record the section offset to be relocated by
+ // `finalizeContents`.
+ chunk.compUnits.resize_for_overwrite(numCus + hdr.CompUnitCount);
+ for (auto i : seq(hdr.CompUnitCount))
+ chunk.compUnits[numCus + i] = locs.CUsBase + i * 4;
+
+ // Read entry offsets.
+ const char *p = namesData + locs.EntryOffsetsBase;
+ SmallVector<uint32_t, 0> entryOffsets;
+ entryOffsets.resize_for_overwrite(hdr.NameCount);
+ for (uint32_t &offset : entryOffsets)
+ offset = endian::readNext<uint32_t, ELFT::Endianness, unaligned>(p);
+ return entryOffsets;
+ });
+ });
+}
+
+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 CU offsets with .debug_info + X relocations.
+ OutputChunk &chunk = chunks.get()[i];
+ for (auto [j, cuOffset] : enumerate(chunk.compUnits))
+ cuOffset = relocs.get()[i].lookup(cuOffset);
+ });
+
+ // Relocate string offsets in the name table with .debug_str + X relocations.
+ parallelForEach(nameVecs, [&](auto &nameVec) {
+ for (NameEntry &ne : nameVec)
+ ne.stringOffset = relocs.get()[ne.chunkIdx].lookup(ne.stringOffset);
+ });
+}
+
+template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
+ [[maybe_unused]] const uint8_t *const beginBuf = buf;
+ // Write the header.
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.UnitLength);
+ endian::writeNext<uint16_t, ELFT::Endianness>(buf, hdr.Version);
+ buf += 2; // padding
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.CompUnitCount);
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.LocalTypeUnitCount);
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.ForeignTypeUnitCount);
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.BucketCount);
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.NameCount);
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, hdr.AbbrevTableSize);
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf,
+ hdr.AugmentationStringSize);
+ memcpy(buf, hdr.AugmentationString.c_str(), hdr.AugmentationString.size());
+ buf += hdr.AugmentationStringSize;
+
+ // Write the CU list.
+ for (auto &chunk : getChunks())
+ for (uint32_t cuOffset : chunk.compUnits)
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, cuOffset);
+
+ // TODO: Write the local TU list, then the foreign TU list..
+
+ // Write the hash lookup table.
+ SmallVector<SmallVector<NameEntry *, 0>, 0> buckets(hdr.BucketCount);
+ // Symbols enter into a bucket whose index is the hash modulo bucket_count.
+ for (auto &nameVec : nameVecs)
+ for (NameEntry &ne : nameVec)
+ buckets[ne.hashValue % hdr.BucketCount].push_back(&ne);
+
+ // Write buckets (accumulated bucket counts).
+ uint32_t bucketIdx = 1;
+ for (const SmallVector<NameEntry *, 0> &bucket : buckets) {
+ if (!bucket.empty())
+ endian::write32<ELFT::Endianness>(buf, bucketIdx);
+ buf += 4;
+ bucketIdx += bucket.size();
+ }
+ // Write the hashes.
+ for (const SmallVector<NameEntry *, 0> &bucket : buckets)
+ for (const NameEntry *e : bucket)
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, e->hashValue);
+
+ // Write the name table. The name entries are ordered by bucket_idx and
+ // correspond one-to-one with the hash lookup table.
+ //
+ // First, write the relocated string offsets.
+ for (const SmallVector<NameEntry *, 0> &bucket : buckets)
+ for (const NameEntry *ne : bucket)
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, ne->stringOffset);
+
+ // Then write the entry offsets.
+ for (const SmallVector<NameEntry *, 0> &bucket : buckets)
+ for (const NameEntry *ne : bucket)
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, ne->entryOffset);
+
+ // Write the abbrev table.
+ buf = llvm::copy(abbrevTableBuf, buf);
+
+ // Write the entry pool. Unlike the name table, the name entries follow the
+ // nameVecs order computed by `computeEntryPool`.
+ for (auto &nameVec : nameVecs) {
+ for (NameEntry &ne : nameVec) {
+ // Write all the entries for the string.
+ for (const IndexEntry &ie : ne.entries()) {
+ buf += encodeULEB128(ie.abbrevCode, buf);
+ for (AttrValue value : ie.attrValues) {
+ switch (value.attrSize) {
+ case 1:
+ *buf++ = value.attrValue;
+ break;
+ case 2:
+ endian::writeNext<uint16_t, ELFT::Endianness>(buf, value.attrValue);
+ break;
+ case 4:
+ endian::writeNext<uint32_t, ELFT::Endianness>(buf, value.attrValue);
+ break;
+ default:
+ llvm_unreachable("invalid attrSize");
+ }
+ }
+ }
+ ++buf; // index entry sentinel
+ }
+ }
+ assert(uint64_t(buf - beginBuf) == size);
+}
+
GdbIndexSection::GdbIndexSection()
: SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {}
@@ -3863,6 +4467,7 @@ void InStruct::reset() {
ppc32Got2.reset();
ibtPlt.reset();
relaPlt.reset();
+ debugNames.reset();
gdbIndex.reset();
shStrTab.reset();
strTab.reset();
@@ -4272,6 +4877,11 @@ 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);
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 759b786..995fd4b 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,134 @@ public:
void writeTo(uint8_t *buf) override {}
};
+// 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:
+ struct Abbrev : llvm::FoldingSetNode {
+ uint32_t code;
+ uint32_t tag;
+ SmallVector<llvm::DWARFDebugNames::AttributeEncoding, 2> attributes;
+
+ void Profile(llvm::FoldingSetNodeID &id) const;
+ };
+
+ struct AttrValue {
+ uint32_t attrValue;
+ uint8_t attrSize;
+ };
+
+ struct IndexEntry {
+ uint32_t abbrevCode;
+ uint32_t poolOffset;
+ union {
+ uint64_t parentOffset = 0;
+ IndexEntry *parentEntry;
+ };
+ SmallVector<AttrValue, 3> attrValues;
+ };
+
+ struct NameEntry {
+ const char *name;
+ uint32_t hashValue;
+ uint32_t stringOffset;
+ uint32_t entryOffset;
+ // Used to relocate `stringOffset` in the merged section.
+ uint32_t chunkIdx;
+ SmallVector<IndexEntry *, 0> indexEntries;
+
+ llvm::iterator_range<
+ llvm::pointee_iterator<typename SmallVector<IndexEntry *, 0>::iterator>>
+ entries() {
+ return llvm::make_pointee_range(indexEntries);
+ }
+ };
+
+ // The contents of one input .debug_names section. An InputChunk
+ // typically contains one NameData, but might contain more, especially
+ // in LTO builds.
+ struct NameData {
+ llvm::DWARFDebugNames::Header hdr;
+ llvm::DenseMap<uint32_t, uint32_t> abbrevCodeMap;
+ SmallVector<NameEntry, 0> nameEntries;
+ };
+
+ // InputChunk and OutputChunk hold per-file contributions to the merged index.
+ // InputChunk instances will be discarded after `init` completes.
+ struct InputChunk {
+ uint32_t baseCuIdx;
+ LLDDWARFSection section;
+ SmallVector<NameData, 0> nameData;
+ std::optional<llvm::DWARFDebugNames> llvmDebugNames;
+ };
+
+ struct OutputChunk {
+ // Pointer to the .debug_info section that contains compile units, used to
+ // compute the relocated CU offsets.
+ InputSection *infoSec;
+ // This initially holds section offsets. After relocation, the section
+ // offsets are changed to CU offsets relative the the output section.
+ SmallVector<uint32_t, 0> compUnits;
+ };
+
+ DebugNamesBaseSection();
+ size_t getSize() const override { return size; }
+ bool isNeeded() const override { return numChunks > 0; }
+
+protected:
+ void init(llvm::function_ref<void(InputFile *, InputChunk &, OutputChunk &)>);
+ static void
+ parseDebugNames(InputChunk &inputChunk, OutputChunk &chunk,
+ llvm::DWARFDataExtractor &namesExtractor,
+ llvm::DataExtractor &strExtractor,
+ llvm::function_ref<SmallVector<uint32_t, 0>(
+ uint32_t numCUs, const llvm::DWARFDebugNames::Header &hdr,
+ const llvm::DWARFDebugNames::DWARFDebugNamesOffsets &)>
+ readOffsets);
+ void computeHdrAndAbbrevTable(MutableArrayRef<InputChunk> inputChunks);
+ std::pair<uint32_t, uint32_t>
+ computeEntryPool(MutableArrayRef<InputChunk> inputChunks);
+
+ // Input .debug_names sections for relocating string offsets in the name table
+ // in `finalizeContents`.
+ 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;
+
+ ArrayRef<OutputChunk> getChunks() const {
+ return ArrayRef(chunks.get(), numChunks);
+ }
+
+ // Sharded name entries that will be used to compute bucket_count and the
+ // count name table.
+ static constexpr size_t numShards = 32;
+ SmallVector<NameEntry, 0> nameVecs[numShards];
+};
+
+// Complement DebugNamesBaseSection for ELFT-aware code: reading offsets,
+// relocating string offsets, and writeTo.
+template <class ELFT>
+class DebugNamesSection final : public DebugNamesBaseSection {
+public:
+ DebugNamesSection();
+ void finalizeContents() override;
+ void writeTo(uint8_t *buf) override;
+
+ template <class RelTy>
+ void getNameRelocs(InputSection *sec, ArrayRef<RelTy> rels,
+ llvm::DenseMap<uint32_t, uint32_t> &relocs);
+
+private:
+ static void readOffsets(InputChunk &inputChunk, OutputChunk &chunk,
+ llvm::DWARFDataExtractor &namesExtractor,
+ llvm::DataExtractor &strExtractor);
+};
+
class GdbIndexSection final : public SyntheticSection {
public:
struct AddressEntry {
@@ -1364,6 +1496,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 d2a9e87..240c16a 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1957,6 +1957,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// finalizeAddressDependentContent may have added local symbols to the
// static symbol table.
finalizeSynthetic(in.symTab.get());
+ finalizeSynthetic(in.debugNames.get());
finalizeSynthetic(in.ppc64LongBranchTarget.get());
finalizeSynthetic(in.armCmseSGSection.get());
}
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index bf0c8e5..a7ed497 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -32,6 +32,9 @@ 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. Type units are not handled yet.
+ (`#86508 <https://github.com/llvm/llvm-project/pull/86508>`_)
Breaking changes
----------------
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index e031673..ba8ce8f 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-a.s b/lld/test/ELF/Inputs/debug-names-a.s
new file mode 100644
index 0000000..0adc520
--- /dev/null
+++ b/lld/test/ELF/Inputs/debug-names-a.s
@@ -0,0 +1,239 @@
+.ifdef GEN
+#--- a.cc
+struct t1 {};
+extern "C" void _start(t1) {}
+#--- gen
+clang --target=x86_64-linux -S -g -gpubnames a.cc -o -
+.endif
+ .text
+ .file "a.cc"
+ .globl _start # -- Begin function _start
+ .p2align 4, 0x90
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+ .file 0 "/proc/self/cwd" "a.cc" md5 0x6835f89a7d36054002b51e54e47d852e
+ .loc 0 2 0 # a.cc:2:0
+ .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:
+ .loc 0 2 29 prologue_end epilogue_begin # a.cc:2:29
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp1:
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-_start
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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:0x34 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:0x16 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
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x2e: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 57 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 4 # Abbrev [4] 0x39:0x6 DW_TAG_structure_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 4 # 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,"",@progbits
+ .long 24 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .byte 0 # string offset=0
+.Linfo_string1:
+ .asciz "a.cc" # string offset=1
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=6
+.Linfo_string3:
+ .asciz "_start" # string offset=21
+.Linfo_string4:
+ .asciz "t1" # string offset=28
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 2 # Header: bucket count
+ .long 2 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 1 # Bucket 0
+ .long 0 # Bucket 1
+ .long 5863786 # Hash in Bucket 0
+ .long -304389582 # Hash in Bucket 0
+ .long .Linfo_string4 # String in Bucket 0: t1
+ .long .Linfo_string3 # String in Bucket 0: _start
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 0
+.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 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames1:
+.L1:
+ .byte 1 # Abbreviation code
+ .long 57 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: t1
+.Lnames0:
+.L0:
+ .byte 2 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: _start
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/Inputs/debug-names-b.s b/lld/test/ELF/Inputs/debug-names-b.s
new file mode 100644
index 0000000..2e39967
--- /dev/null
+++ b/lld/test/ELF/Inputs/debug-names-b.s
@@ -0,0 +1,358 @@
+.ifdef GEN
+#--- b.cc
+struct t1 { };
+namespace ns {
+struct t2 {};
+}
+int main() { t1 v1; ns::t2 v2; }
+#--- gen
+clang --target=x86_64-linux -S -g -gpubnames b.cc -o -
+.endif
+ .text
+ .file "b.cc"
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@function
+main: # @main
+.Lfunc_begin0:
+ .file 0 "/proc/self/cwd" "b.cc" md5 0xcb70125759dcd65dfed077164397a2f4
+ .loc 0 5 0 # b.cc:5:0
+ .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:
+ .loc 0 5 32 prologue_end # b.cc:5:32
+ xorl %eax, %eax
+ .loc 0 5 32 epilogue_begin is_stmt 0 # b.cc:5:32
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp1:
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 57 # DW_TAG_namespace
+ .byte 1 # DW_CHILDREN_yes
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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:0x51 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:0x26 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 5 # DW_AT_decl_line
+ .long 73 # 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 5 # DW_AT_decl_line
+ .long 77 # DW_AT_type
+ .byte 3 # Abbrev [3] 0x3d:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 126
+ .byte 7 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 5 # DW_AT_decl_line
+ .long 85 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 4 # Abbrev [4] 0x49: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] 0x4d: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 6 # Abbrev [6] 0x53:0x9 DW_TAG_namespace
+ .byte 8 # DW_AT_name
+ .byte 5 # Abbrev [5] 0x55:0x6 DW_TAG_structure_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 9 # DW_AT_name
+ .byte 1 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 3 # DW_AT_decl_line
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 44 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .byte 0 # string offset=0
+.Linfo_string1:
+ .asciz "b.cc" # string offset=1
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=6
+.Linfo_string3:
+ .asciz "main" # string offset=21
+.Linfo_string4:
+ .asciz "int" # string offset=26
+.Linfo_string5:
+ .asciz "v1" # string offset=30
+.Linfo_string6:
+ .asciz "t1" # string offset=33
+.Linfo_string7:
+ .asciz "v2" # string offset=36
+.Linfo_string8:
+ .asciz "ns" # string offset=39
+.Linfo_string9:
+ .asciz "t2" # string offset=42
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .long .Linfo_string5
+ .long .Linfo_string6
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .long .Linfo_string9
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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 5 # Header: bucket count
+ .long 5 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 0 # Bucket 0
+ .long 1 # Bucket 1
+ .long 3 # Bucket 2
+ .long 4 # Bucket 3
+ .long 5 # Bucket 4
+ .long 5863786 # Hash in Bucket 1
+ .long 2090499946 # Hash in Bucket 1
+ .long 5863787 # Hash in Bucket 2
+ .long 193495088 # Hash in Bucket 3
+ .long 5863654 # Hash in Bucket 4
+ .long .Linfo_string6 # String in Bucket 1: t1
+ .long .Linfo_string3 # String in Bucket 1: main
+ .long .Linfo_string9 # String in Bucket 2: t2
+ .long .Linfo_string4 # String in Bucket 3: int
+ .long .Linfo_string8 # String in Bucket 4: ns
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 2
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 4
+.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 19 # DW_TAG_structure_type
+ .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 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 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 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames2:
+.L4:
+ .byte 1 # Abbreviation code
+ .long 77 # 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
+.Lnames4:
+.L3:
+ .byte 3 # Abbreviation code
+ .long 85 # DW_IDX_die_offset
+ .long .L1-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: t2
+.Lnames1:
+.L0:
+ .byte 4 # Abbreviation code
+ .long 73 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames3:
+.L1:
+ .byte 5 # Abbreviation code
+ .long 83 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: ns
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-bad.s b/lld/test/ELF/debug-names-bad.s
new file mode 100644
index 0000000..69a7f75
--- /dev/null
+++ b/lld/test/ELF/debug-names-bad.s
@@ -0,0 +1,97 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && mkdir %t && cd %t
+
+## Test errors in the header.
+# RUN: sed '/Header: version/s/5/4/' %S/Inputs/debug-names-a.s > bad-version.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-version.s -o bad-version.o
+# RUN: not ld.lld --debug-names bad-version.o 2>&1 | FileCheck %s --check-prefix=BAD-VERSION --implicit-check-not=error:
+
+# BAD-VERSION: error: bad-version.o:(.debug_names): unsupported version: 4
+
+# RUN: sed '/Header: name count/s/[0-9]/4/' %S/Inputs/debug-names-a.s > bad-name-count.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-name-count.s -o bad-name-count.o
+# RUN: not ld.lld --debug-names bad-name-count.o 2>&1 | FileCheck %s --check-prefix=BAD-NAME-COUNT --implicit-check-not=error:
+
+## Test errors in offsets.
+# BAD-NAME-COUNT: error: bad-name-count.o:(.debug_names): Section too small: cannot read abbreviations.
+
+# RUN: sed '/Offset in Bucket/s/long/byte/' %S/Inputs/debug-names-a.s > entry-offset-in-byte.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64 entry-offset-in-byte.s -o entry-offset-in-byte.o
+# RUN: not ld.lld --debug-names entry-offset-in-byte.o 2>&1 | FileCheck %s --check-prefix=ENTRY-OFFSET-IN-BYTE --implicit-check-not=error:
+
+# ENTRY-OFFSET-IN-BYTE-COUNT-2: error: entry-offset-in-byte.o:(.debug_names): index entry is out of bounds
+
+## Test errors in the abbrev table.
+# RUN: sed -E '/DW_IDX_parent/{n;s/[0-9]+.*DW_FORM_flag_present/16/}' %S/Inputs/debug-names-a.s > bad-parent-form.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-parent-form.s -o bad-parent-form.o
+# RUN: not ld.lld --debug-names bad-parent-form.o 2>&1 | FileCheck %s --check-prefix=BAD-PARENT-FORM --implicit-check-not=error:
+
+# BAD-PARENT-FORM: error: bad-parent-form.o:(.debug_names): invalid form for DW_IDX_parent
+
+# RUN: sed -E '/DW_IDX_die_offset/{n;s/[0-9]+.*DW_FORM_ref4/16/}' %S/Inputs/debug-names-a.s > bad-die-form.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-die-form.s -o bad-die-form.o
+# RUN: not ld.lld --debug-names bad-die-form.o 2>&1 | FileCheck %s --check-prefix=BAD-DIE-FORM --implicit-check-not=error:
+
+# BAD-DIE-FORM: error: bad-die-form.o:(.debug_names): unrecognized form encoding 16 in abbrev table
+
+## Test errors in the entry pool.
+# RUN: sed -E '/Lnames.:/{n;n;s/[0-9]+/3/}' %S/Inputs/debug-names-a.s > bad-abbrev-code.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bad-abbrev-code.s -o bad-abbrev-code.o
+# RUN: not ld.lld --debug-names bad-abbrev-code.o 2>&1 | FileCheck %s --check-prefix=BAD-ABBREV-CODE --implicit-check-not=error:
+# RUN: ld.lld --debug-names bad-abbrev-code.o -o bad-abbrev-code --noinhibit-exec
+# RUN: llvm-dwarfdump --debug-names bad-abbrev-code | FileCheck %s --check-prefix=BAD-ABBREV-CODE-DWARF
+
+# BAD-ABBREV-CODE: error: bad-abbrev-code.o:(.debug_names): abbrev code not found in abbrev table: 3
+
+# BAD-ABBREV-CODE-DWARF: Abbreviations [
+# BAD-ABBREV-CODE-DWARF-NEXT: Abbreviation 0x1 {
+# BAD-ABBREV-CODE-DWARF-NEXT: Tag: DW_TAG_subprogram
+# BAD-ABBREV-CODE-DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BAD-ABBREV-CODE-DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BAD-ABBREV-CODE-DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# BAD-ABBREV-CODE-DWARF-NEXT: }
+# BAD-ABBREV-CODE-DWARF-NEXT: Abbreviation 0x2 {
+# BAD-ABBREV-CODE-DWARF-NEXT: Tag: DW_TAG_structure_type
+# BAD-ABBREV-CODE-DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BAD-ABBREV-CODE-DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BAD-ABBREV-CODE-DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# BAD-ABBREV-CODE-DWARF-NEXT: }
+# BAD-ABBREV-CODE-DWARF-NEXT: ]
+# BAD-ABBREV-CODE-DWARF: Bucket 0
+# BAD-ABBREV-CODE-DWARF-NOT: Entry
+
+# RUN: sed -E '/Lnames0:/{n;n;n;s/.*DW_IDX_die_offset.*//}' %S/Inputs/debug-names-a.s > missing-die-offset0.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64 missing-die-offset0.s -o missing-die-offset0.o
+# RUN: ld.lld --debug-names missing-die-offset0.o --noinhibit-exec -o missing-die-offset0 2>&1 | FileCheck %s --check-prefix=MISSING-DIE-OFFSET0
+
+# MISSING-DIE-OFFSET0: warning: missing-die-offset0.o:(.debug_names): index entry is out of bounds
+
+# RUN: sed -E '/Lnames1:/{n;n;n;s/.*DW_IDX_die_offset.*//}' %S/Inputs/debug-names-a.s > missing-die-offset1.s
+# RUN: llvm-mc -filetype=obj -triple=x86_64 missing-die-offset1.s -o missing-die-offset1.o
+# RUN: ld.lld --debug-names missing-die-offset1.o -o missing-die-offset1
+# RUN: llvm-dwarfdump --debug-names missing-die-offset1 | FileCheck %s --check-prefix=MISSING-DIE-OFFSET1
+
+# MISSING-DIE-OFFSET1: Bucket 0 [
+# MISSING-DIE-OFFSET1-NEXT: Name 1 {
+# MISSING-DIE-OFFSET1-NEXT: Hash: 0x59796A
+# MISSING-DIE-OFFSET1-NEXT: String: {{.*}} "t1"
+# MISSING-DIE-OFFSET1-NEXT: Entry @ 0x65 {
+# MISSING-DIE-OFFSET1-NEXT: Abbrev: 0x2
+# MISSING-DIE-OFFSET1-NEXT: Tag: DW_TAG_structure_type
+# MISSING-DIE-OFFSET1-NEXT: DW_IDX_die_offset: 0x00230200
+# MISSING-DIE-OFFSET1-NEXT: DW_IDX_parent: <parent not indexed>
+# MISSING-DIE-OFFSET1-NEXT: DW_IDX_compile_unit: 0x00
+# MISSING-DIE-OFFSET1-NEXT: }
+# MISSING-DIE-OFFSET1-NEXT: }
+# MISSING-DIE-OFFSET1-NEXT: Name 2 {
+# MISSING-DIE-OFFSET1-NEXT: Hash: 0xEDDB6232
+# MISSING-DIE-OFFSET1-NEXT: String: {{.*}} "_start"
+# MISSING-DIE-OFFSET1-NEXT: Entry @ 0x6c {
+# MISSING-DIE-OFFSET1-NEXT: Abbrev: 0x1
+# MISSING-DIE-OFFSET1-NEXT: Tag: DW_TAG_subprogram
+# MISSING-DIE-OFFSET1-NEXT: DW_IDX_die_offset: 0x00000023
+# MISSING-DIE-OFFSET1-NEXT: DW_IDX_parent: <parent not indexed>
+# MISSING-DIE-OFFSET1-NEXT: DW_IDX_compile_unit: 0x00
+# MISSING-DIE-OFFSET1-NEXT: }
+# MISSING-DIE-OFFSET1-NEXT: }
+# MISSING-DIE-OFFSET1-NEXT: ]
diff --git a/lld/test/ELF/debug-names-die-offset-form-flag-present.s b/lld/test/ELF/debug-names-die-offset-form-flag-present.s
new file mode 100644
index 0000000..1674498
--- /dev/null
+++ b/lld/test/ELF/debug-names-die-offset-form-flag-present.s
@@ -0,0 +1,152 @@
+# This file was generated by:
+# clang++ -g -O0 -S -fdebug-compilation-dir='/proc/self/cwd' -gpubnames a.cpp
+
+# Then manually changing the first .debug_names abbrev, so that the
+# DW_IDX_die_offset uses DW_FORM_flag_present (invalid) & the DW_IDX_parent
+# uses DW_FORM_ref4. Also updated the sizes of the values in the entry
+# that uses the abbrev, to match the sizes of the forms.
+
+# Contents of a.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 --implicit-check-not=error: %s
+
+# CHECK: error: [[FILE]]:(.debug_names): unrecognized form encoding 25 in abbrev table
+
+ .text
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@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,"",@progbits
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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,"",@progbits
+ .long 36 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+ .asciz "a.cpp" # string offset=104
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=110
+.Linfo_string3:
+ .asciz "main" # string offset=125
+.Linfo_string4:
+ .asciz "int" # string offset=130
+.Linfo_string5:
+ .asciz "argc" # string offset=134
+.Linfo_string6:
+ .asciz "argv" # string offset=139
+.Linfo_string7:
+ .asciz "char" # string offset=144
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-different-aug-string.s b/lld/test/ELF/debug-names-different-aug-string.s
new file mode 100644
index 0000000..eb0c3fa
--- /dev/null
+++ b/lld/test/ELF/debug-names-different-aug-string.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && mkdir %t && cd %t
+# RUN: sed 's/LLVM0700/LLVM9999/' %S/Inputs/debug-names-a.s | llvm-mc -filetype=obj -triple=x86_64 -o a.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/debug-names-b.s -o b.o
+# RUN: ld.lld --debug-names a.o b.o -o out
+# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
+
+# DWARF: .debug_names contents:
+# DWARF: Name Index @ 0x0 {
+# DWARF-NEXT: Header {
+# DWARF-NEXT: Length:
+# DWARF-NEXT: Format: DWARF32
+# DWARF-NEXT: Version: 5
+# DWARF: Augmentation: ''
diff --git a/lld/test/ELF/debug-names-dwarf64.s b/lld/test/ELF/debug-names-dwarf64.s
new file mode 100644
index 0000000..8261e9e
--- /dev/null
+++ b/lld/test/ELF/debug-names-dwarf64.s
@@ -0,0 +1,250 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: not ld.lld --debug-names %t.o -o /dev/null 2>&1 | \
+# RUN: FileCheck -DFILE=%t.o --implicit-check-not=error: %s
+
+# CHECK: error: [[FILE]]:(.debug_names): found DWARF64, which is currently unsupported
+
+.ifdef GEN
+//--- a.cc
+struct t1 {};
+extern "C" void _start(t1) {}
+//--- gen
+clang --target=x86_64-linux -S -g -gpubnames -gdwarf64 a.cc -o -
+.endif
+ .text
+ .file "a.cc"
+ .globl _start # -- Begin function _start
+ .p2align 4, 0x90
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+ .file 0 "/proc/self/cwd" "a.cc" md5 0x6835f89a7d36054002b51e54e47d852e
+ .loc 0 2 0 # a.cc:2:0
+ .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:
+ .loc 0 2 29 prologue_end epilogue_begin # a.cc:2:29
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp1:
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-_start
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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
+ .byte 1 # Abbrev [1] 0x18:0x40 DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 1 # DW_AT_name
+ .quad .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .quad .Lline_table_start0 # DW_AT_stmt_list
+ .byte 2 # DW_AT_comp_dir
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .quad .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x3b:0x16 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
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x46: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 81 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 4 # Abbrev [4] 0x51:0x6 DW_TAG_structure_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 4 # 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,"",@progbits
+ .long 4294967295 # DWARF64 Mark
+ .quad 44 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .byte 0 # string offset=0
+.Linfo_string1:
+ .asciz "a.cc" # string offset=1
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=6
+.Linfo_string3:
+ .asciz "_start" # string offset=21
+.Linfo_string4:
+ .asciz "t1" # string offset=28
+ .section .debug_str_offsets,"",@progbits
+ .quad .Linfo_string0
+ .quad .Linfo_string1
+ .quad .Linfo_string2
+ .quad .Linfo_string3
+ .quad .Linfo_string4
+ .section .debug_addr,"",@progbits
+ .long 4294967295 # DWARF64 Mark
+ .quad .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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 2 # Header: bucket count
+ .long 2 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .quad .Lcu_begin0 # Compilation unit 0
+ .long 1 # Bucket 0
+ .long 0 # Bucket 1
+ .long 5863786 # Hash in Bucket 0
+ .long -304389582 # Hash in Bucket 0
+ .quad .Linfo_string4 # String in Bucket 0: t1
+ .quad .Linfo_string3 # String in Bucket 0: _start
+ .quad .Lnames1-.Lnames_entries0 # Offset in Bucket 0
+ .quad .Lnames0-.Lnames_entries0 # Offset in Bucket 0
+.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 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames1:
+.L1:
+ .byte 1 # Abbreviation code
+ .long 81 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: t1
+.Lnames0:
+.L0:
+ .byte 2 # Abbreviation code
+ .long 59 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: _start
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-missing-parent.s b/lld/test/ELF/debug-names-missing-parent.s
new file mode 100644
index 0000000..7140157
--- /dev/null
+++ b/lld/test/ELF/debug-names-missing-parent.s
@@ -0,0 +1,234 @@
+# REQUIRES: x86
+## Test clang-17-generated DW_TAG_subprogram, which do not contain DW_IDX_parent
+## attributes.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld --debug-names %t.o -o %t
+# RUN: llvm-dwarfdump --debug-info --debug-names %t | FileCheck %s --check-prefix=DWARF
+
+# DWARF: 0x00000023: DW_TAG_namespace
+# DWARF: 0x00000025: DW_TAG_subprogram
+
+# DWARF: String: {{.*}} "fa"
+# DWARF-NEXT: Entry @ 0x71 {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000025
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF: String: {{.*}} "ns"
+# DWARF-NEXT: Entry @ 0x78 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_namespace
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+
+.ifdef GEN
+//--- a.cc
+namespace ns {
+void fa() {}
+}
+//--- gen
+clang-17 --target=x86_64-linux -S -O1 -g -gpubnames a.cc -o -
+.endif
+ .text
+ .file "a.cc"
+ .globl _ZN2ns2faEv # -- Begin function _ZN2ns2faEv
+ .p2align 4, 0x90
+ .type _ZN2ns2faEv,@function
+_ZN2ns2faEv: # @_ZN2ns2faEv
+.Lfunc_begin0:
+ .file 0 "/proc/self/cwd" "a.cc" md5 0xb3281d5b5a0b2997d7d59d49bc912274
+ .cfi_startproc
+# %bb.0:
+ .loc 0 2 12 prologue_end # a.cc:2:12
+ retq
+.Ltmp0:
+.Lfunc_end0:
+ .size _ZN2ns2faEv, .Lfunc_end0-_ZN2ns2faEv
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 57 # DW_TAG_namespace
+ .byte 1 # DW_CHILDREN_yes
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 122 # DW_AT_call_all_calls
+ .byte 25 # DW_FORM_flag_present
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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:0x27 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:0xf DW_TAG_namespace
+ .byte 3 # DW_AT_name
+ .byte 3 # Abbrev [3] 0x25:0xc DW_TAG_subprogram
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 87
+ # DW_AT_call_all_calls
+ .byte 4 # DW_AT_linkage_name
+ .byte 5 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ # DW_AT_external
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 28 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .byte 0 # string offset=0
+.Linfo_string1:
+ .asciz "a.cc" # string offset=1
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=6
+.Linfo_string3:
+ .asciz "ns" # string offset=21
+.Linfo_string4:
+ .asciz "fa" # string offset=24
+.Linfo_string5:
+ .asciz "_ZN2ns2faEv" # string offset=27
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string5
+ .long .Linfo_string4
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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 5863372 # Hash in Bucket 1
+ .long 5863654 # Hash in Bucket 1
+ .long -1413999533 # Hash in Bucket 2
+ .long .Linfo_string4 # String in Bucket 1: fa
+ .long .Linfo_string3 # String in Bucket 1: ns
+ .long .Linfo_string5 # String in Bucket 2: _ZN2ns2faEv
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 2
+.Lnames_abbrev_start0:
+ .byte 46 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 57 # Abbrev code
+ .byte 57 # DW_TAG_namespace
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames1:
+ .byte 46 # Abbreviation code
+ .long 37 # DW_IDX_die_offset
+ .byte 0 # End of list: fa
+.Lnames0:
+ .byte 57 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 0 # End of list: ns
+.Lnames2:
+ .byte 46 # Abbreviation code
+ .long 37 # DW_IDX_die_offset
+ .byte 0 # End of list: _ZN2ns2faEv
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-multi-cus.s b/lld/test/ELF/debug-names-multi-cus.s
new file mode 100644
index 0000000..78fcdc2
--- /dev/null
+++ b/lld/test/ELF/debug-names-multi-cus.s
@@ -0,0 +1,789 @@
+# REQUIRES: x86
+## Test name indexes that contain multiple CU offsets due to LTO.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/debug-names-a.s -o a.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 bcd.s -o bcd.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 ef.s -o ef.o
+# RUN: ld.lld --debug-names a.o bcd.o ef.o -o out
+# RUN: llvm-dwarfdump --debug-info --debug-names out | FileCheck %s --check-prefix=DWARF
+
+## Place the multiple CU offsets in the second name index in an input file.
+# RUN: ld.lld -r a.o bcd.o -o abcd.o
+# RUN: ld.lld --debug-names abcd.o ef.o -o out
+# RUN: llvm-dwarfdump --debug-info --debug-names out | FileCheck %s --check-prefix=DWARF
+
+# DWARF: [[CU0:0x[^:]+]]: Compile Unit
+# DWARF: [[CU1:0x[^:]+]]: Compile Unit
+# DWARF: [[CU2:0x[^:]+]]: Compile Unit
+# DWARF: [[CU3:0x[^:]+]]: Compile Unit
+# DWARF: [[CU4:0x[^:]+]]: Compile Unit
+# DWARF: [[CU5:0x[^:]+]]: Compile Unit
+# DWARF: Compilation Unit offsets [
+# DWARF-NEXT: CU[0]: [[CU0]]
+# DWARF-NEXT: CU[1]: [[CU1]]
+# DWARF-NEXT: CU[2]: [[CU2]]
+# DWARF-NEXT: CU[3]: [[CU3]]
+# DWARF-NEXT: CU[4]: [[CU4]]
+# DWARF-NEXT: CU[5]: [[CU5]]
+# DWARF-NEXT: ]
+# DWARF: String: {{.*}} "vc"
+# DWARF: DW_IDX_compile_unit: 0x02
+# DWARF: String: {{.*}} "vd"
+# DWARF: DW_IDX_die_offset:
+# DWARF-SAME: 0x00000020
+# DWARF: DW_IDX_compile_unit:
+# DWARF-SAME: 0x03
+# DWARF: String: {{.*}} "ve"
+# DWARF: DW_IDX_die_offset:
+# DWARF-SAME: 0x0000001e
+# DWARF: DW_IDX_compile_unit:
+# DWARF-SAME: 0x04
+# DWARF: String: {{.*}} "vf"
+# DWARF: DW_IDX_compile_unit:
+# DWARF-SAME: 0x05
+# DWARF: String: {{.*}} "vb"
+# DWARF: DW_IDX_compile_unit:
+# DWARF-SAME: 0x01
+
+.ifdef GEN
+#--- b.cc
+[[gnu::used]] int vb;
+#--- c.cc
+[[gnu::used]] int vc;
+#--- d.cc
+namespace ns {
+[[gnu::used]] int vd;
+}
+
+//--- e.cc
+[[gnu::used]] int ve;
+//--- f.cc
+namespace ns {
+[[gnu::used]] int vf;
+}
+
+#--- gen
+clang --target=x86_64-linux -O1 -g -gpubnames -flto b.cc c.cc d.cc -nostdlib -fuse-ld=lld -Wl,--lto-emit-asm
+echo '#--- bcd.s'
+cat a.out.lto.s
+clang --target=x86_64-linux -O1 -g -gpubnames -flto e.cc f.cc -nostdlib -fuse-ld=lld -Wl,--lto-emit-asm
+echo '#--- ef.s'
+cat a.out.lto.s
+.endif
+#--- bcd.s
+ .text
+ .file "ld-temp.o"
+ .file 1 "/proc/self/cwd" "b.cc" md5 0x78dad32a49063326a4de543198e54944
+ .file 2 "/proc/self/cwd" "c.cc" md5 0x7a0f7bf2cb0ec8c297f794908d91ab1b
+ .file 3 "/proc/self/cwd" "d.cc" md5 0xf7e2af89615ce48bf9a98fdae55ab5ad
+ .type vb,@object # @vb
+ .section .bss.vb,"aw",@nobits
+ .globl vb
+ .p2align 2, 0x0
+vb:
+ .long 0 # 0x0
+ .size vb, 4
+
+ .type vc,@object # @vc
+ .section .bss.vc,"aw",@nobits
+ .globl vc
+ .p2align 2, 0x0
+vc:
+ .long 0 # 0x0
+ .size vc, 4
+
+ .type _ZN2ns2vdE,@object # @_ZN2ns2vdE
+ .section .bss._ZN2ns2vdE,"aw",@nobits
+ .globl _ZN2ns2vdE
+ .p2align 2, 0x0
+_ZN2ns2vdE:
+ .long 0 # 0x0
+ .size _ZN2ns2vdE, 4
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 16 # DW_FORM_ref_addr
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 57 # DW_TAG_namespace
+ .byte 1 # DW_CHILDREN_yes
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 16 # DW_FORM_ref_addr
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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:0x22 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
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x1e:0xb DW_TAG_variable
+ .byte 3 # DW_AT_name
+ .long 41 # DW_AT_type
+ # DW_AT_external
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .byte 2 # DW_AT_location
+ .byte 161
+ .byte 0
+ .byte 3 # Abbrev [3] 0x29:0x4 DW_TAG_base_type
+ .byte 4 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+.Lcu_begin1:
+ .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
+.Ldebug_info_start1:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0x1e DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 5 # 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
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 4 # Abbrev [4] 0x1e:0xb DW_TAG_variable
+ .byte 6 # DW_AT_name
+ .long .debug_info+41 # DW_AT_type
+ # DW_AT_external
+ .byte 2 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .byte 2 # DW_AT_location
+ .byte 161
+ .byte 1
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end1:
+.Lcu_begin2:
+ .long .Ldebug_info_end2-.Ldebug_info_start2 # Length of Unit
+.Ldebug_info_start2:
+ .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:0x22 DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 7 # 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
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 5 # Abbrev [5] 0x1e:0xf DW_TAG_namespace
+ .byte 8 # DW_AT_name
+ .byte 6 # Abbrev [6] 0x20:0xc DW_TAG_variable
+ .byte 9 # DW_AT_name
+ .long .debug_info+41 # DW_AT_type
+ # DW_AT_external
+ .byte 3 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .byte 2 # DW_AT_location
+ .byte 161
+ .byte 2
+ .byte 10 # DW_AT_linkage_name
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end2:
+ .section .debug_str_offsets,"",@progbits
+ .long 48 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .byte 0 # string offset=0
+.Linfo_string1:
+ .asciz "b.cc" # string offset=1
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=6
+.Linfo_string3:
+ .asciz "vb" # string offset=21
+.Linfo_string4:
+ .asciz "int" # string offset=24
+.Linfo_string5:
+ .asciz "c.cc" # string offset=28
+.Linfo_string6:
+ .asciz "vc" # string offset=33
+.Linfo_string7:
+ .asciz "d.cc" # string offset=36
+.Linfo_string8:
+ .asciz "ns" # string offset=41
+.Linfo_string9:
+ .asciz "vd" # string offset=44
+.Linfo_string10:
+ .asciz "_ZN2ns2vdE" # string offset=47
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .long .Linfo_string5
+ .long .Linfo_string6
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .long .Linfo_string9
+ .long .Linfo_string10
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad vb
+ .quad vc
+ .quad _ZN2ns2vdE
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 3 # 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 .Lcu_begin1 # Compilation unit 1
+ .long .Lcu_begin2 # Compilation unit 2
+ .long 1 # Bucket 0
+ .long 2 # Bucket 1
+ .long 3 # Bucket 2
+ .long 0 # Bucket 3
+ .long 4 # Bucket 4
+ .long 6 # Bucket 5
+ .long 5863902 # Hash in Bucket 0
+ .long 5863903 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 2
+ .long 5863654 # Hash in Bucket 4
+ .long -823734096 # Hash in Bucket 4
+ .long 5863901 # Hash in Bucket 5
+ .long .Linfo_string6 # String in Bucket 0: vc
+ .long .Linfo_string9 # String in Bucket 1: vd
+ .long .Linfo_string4 # String in Bucket 2: int
+ .long .Linfo_string8 # String in Bucket 4: ns
+ .long .Linfo_string10 # String in Bucket 4: _ZN2ns2vdE
+ .long .Linfo_string3 # String in Bucket 5: vb
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 2
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 4
+ .long .Lnames5-.Lnames_entries0 # Offset in Bucket 4
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 5
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 52 # DW_TAG_variable
+ .byte 1 # DW_IDX_compile_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 52 # DW_TAG_variable
+ .byte 1 # DW_IDX_compile_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 1 # DW_IDX_compile_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 4 # Abbrev code
+ .byte 57 # DW_TAG_namespace
+ .byte 1 # DW_IDX_compile_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames2:
+.L0:
+ .byte 1 # Abbreviation code
+ .byte 1 # DW_IDX_compile_unit
+ .long 30 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: vc
+.Lnames4:
+.L4:
+ .byte 2 # Abbreviation code
+ .byte 2 # DW_IDX_compile_unit
+ .long 32 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: vd
+.Lnames0:
+.L3:
+ .byte 3 # Abbreviation code
+ .byte 0 # DW_IDX_compile_unit
+ .long 41 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames3:
+.L2:
+ .byte 4 # Abbreviation code
+ .byte 2 # DW_IDX_compile_unit
+ .long 30 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: ns
+.Lnames5:
+ .byte 2 # Abbreviation code
+ .byte 2 # DW_IDX_compile_unit
+ .long 32 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: _ZN2ns2vdE
+.Lnames1:
+.L1:
+ .byte 1 # Abbreviation code
+ .byte 0 # DW_IDX_compile_unit
+ .long 30 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: vb
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .addrsig_sym vb
+ .addrsig_sym vc
+ .addrsig_sym _ZN2ns2vdE
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
+#--- ef.s
+ .text
+ .file "ld-temp.o"
+ .file 1 "/proc/self/cwd" "e.cc" md5 0xa8d6c645998197bd15436f2a351ebd6a
+ .file 2 "/proc/self/cwd" "f.cc" md5 0x6ec1ec6b7f003f84cb0bf3409e65b085
+ .type ve,@object # @ve
+ .section .bss.ve,"aw",@nobits
+ .globl ve
+ .p2align 2, 0x0
+ve:
+ .long 0 # 0x0
+ .size ve, 4
+
+ .type _ZN2ns2vfE,@object # @_ZN2ns2vfE
+ .section .bss._ZN2ns2vfE,"aw",@nobits
+ .globl _ZN2ns2vfE
+ .p2align 2, 0x0
+_ZN2ns2vfE:
+ .long 0 # 0x0
+ .size _ZN2ns2vfE, 4
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 62 # DW_AT_encoding
+ .byte 11 # DW_FORM_data1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 57 # DW_TAG_namespace
+ .byte 1 # DW_CHILDREN_yes
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 16 # DW_FORM_ref_addr
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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:0x22 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
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x1e:0xb DW_TAG_variable
+ .byte 3 # DW_AT_name
+ .long 41 # DW_AT_type
+ # DW_AT_external
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .byte 2 # DW_AT_location
+ .byte 161
+ .byte 0
+ .byte 3 # Abbrev [3] 0x29:0x4 DW_TAG_base_type
+ .byte 4 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+.Lcu_begin1:
+ .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
+.Ldebug_info_start1:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0x22 DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 5 # 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
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 4 # Abbrev [4] 0x1e:0xf DW_TAG_namespace
+ .byte 6 # DW_AT_name
+ .byte 5 # Abbrev [5] 0x20:0xc DW_TAG_variable
+ .byte 7 # DW_AT_name
+ .long .debug_info+41 # DW_AT_type
+ # DW_AT_external
+ .byte 2 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .byte 2 # DW_AT_location
+ .byte 161
+ .byte 1
+ .byte 8 # DW_AT_linkage_name
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end1:
+ .section .debug_str_offsets,"",@progbits
+ .long 40 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .byte 0 # string offset=0
+.Linfo_string1:
+ .asciz "e.cc" # string offset=1
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=6
+.Linfo_string3:
+ .asciz "ve" # string offset=21
+.Linfo_string4:
+ .asciz "int" # string offset=24
+.Linfo_string5:
+ .asciz "f.cc" # string offset=28
+.Linfo_string6:
+ .asciz "ns" # string offset=33
+.Linfo_string7:
+ .asciz "vf" # string offset=36
+.Linfo_string8:
+ .asciz "_ZN2ns2vfE" # string offset=39
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .long .Linfo_string5
+ .long .Linfo_string6
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad ve
+ .quad _ZN2ns2vfE
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 2 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 5 # Header: bucket count
+ .long 5 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long .Lcu_begin1 # Compilation unit 1
+ .long 1 # Bucket 0
+ .long 2 # Bucket 1
+ .long 0 # Bucket 2
+ .long 3 # Bucket 3
+ .long 4 # Bucket 4
+ .long 5863905 # Hash in Bucket 0
+ .long -823734030 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 3
+ .long 5863654 # Hash in Bucket 4
+ .long 5863904 # Hash in Bucket 4
+ .long .Linfo_string7 # String in Bucket 0: vf
+ .long .Linfo_string8 # String in Bucket 1: _ZN2ns2vfE
+ .long .Linfo_string4 # String in Bucket 3: int
+ .long .Linfo_string6 # String in Bucket 4: ns
+ .long .Linfo_string3 # String in Bucket 4: ve
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 4
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 4
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 52 # DW_TAG_variable
+ .byte 1 # DW_IDX_compile_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 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 1 # DW_IDX_compile_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 57 # DW_TAG_namespace
+ .byte 1 # DW_IDX_compile_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 4 # Abbrev code
+ .byte 52 # DW_TAG_variable
+ .byte 1 # DW_IDX_compile_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames3:
+.L2:
+ .byte 1 # Abbreviation code
+ .byte 1 # DW_IDX_compile_unit
+ .long 32 # DW_IDX_die_offset
+ .long .L0-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: vf
+.Lnames4:
+ .byte 1 # Abbreviation code
+ .byte 1 # DW_IDX_compile_unit
+ .long 32 # DW_IDX_die_offset
+ .long .L0-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: _ZN2ns2vfE
+.Lnames0:
+.L3:
+ .byte 2 # Abbreviation code
+ .byte 0 # DW_IDX_compile_unit
+ .long 41 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames2:
+.L0:
+ .byte 3 # Abbreviation code
+ .byte 1 # DW_IDX_compile_unit
+ .long 30 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: ns
+.Lnames1:
+.L1:
+ .byte 4 # Abbreviation code
+ .byte 0 # DW_IDX_compile_unit
+ .long 30 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: ve
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .addrsig_sym ve
+ .addrsig_sym _ZN2ns2vfE
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-nonames.s b/lld/test/ELF/debug-names-nonames.s
new file mode 100644
index 0000000..54b7c86
--- /dev/null
+++ b/lld/test/ELF/debug-names-nonames.s
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && mkdir %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/debug-names-a.s -o a.o
+# RUN: echo '.globl foo; foo:' | llvm-mc -filetype=obj -triple=x86_64 - -o b0.o
+
+# RUN: ld.lld --debug-names a.o b0.o -o out0
+# RUN: llvm-dwarfdump -debug-names out0 | FileCheck %s --check-prefix=DWARF
+
+# DWARF: .debug_names contents:
+# DWARF-NEXT: Name Index @ 0x0 {
+# DWARF-NEXT: Header {
+# DWARF-NEXT: Length: 0x6F
+# DWARF-NEXT: Format: DWARF32
+# DWARF-NEXT: Version: 5
+# DWARF-NEXT: CU count: 1
+# DWARF-NEXT: Local TU count: 0
+# DWARF-NEXT: Foreign TU count: 0
+# DWARF-NEXT: Bucket count: 2
+# DWARF-NEXT: Name count: 2
+# DWARF-NEXT: Abbreviations table size: 0x15
+# DWARF-NEXT: Augmentation: 'LLVM0700'
+# DWARF-NEXT: }
+# DWARF-NEXT: Compilation Unit offsets [
+# DWARF-NEXT: CU[0]: 0x00000000
+# DWARF-NEXT: ]
+
+## Test both files without .debug_names.
+# RUN: echo '.globl _start; _start:' | llvm-mc -filetype=obj -triple=x86_64 - -o a0.o
+# RUN: ld.lld --debug-names a0.o b0.o -o out1
+# RUN: llvm-readelf -SW out1 | FileCheck %s --check-prefix=ELF
+
+# ELF: Name Type Address Off Size ES Flg Lk Inf Al
+# ELF-NOT: .debug_names
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 0000000..64551aa
--- /dev/null
+++ b/lld/test/ELF/debug-names-parent-idx.s
@@ -0,0 +1,746 @@
+# debug-names-parent-idx.s generated with:
+
+# clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' -S \
+# a.cpp -o a.s
+
+# foo.h contents:
+
+# int foo();
+
+# struct foo {
+# int x;
+# char y;
+# struct foo *foo_ptr;
+# };
+
+# namespace parent_test {
+# int foo();
+# }
+
+# a.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: 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 a.o b.o -o out
+
+# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
+
+# DWARF: .debug_names contents:
+# DWARF: Name Index @ 0x0 {
+# DWARF-NEXT: Header {
+# DWARF-NEXT: Length: 0x158
+# DWARF-NEXT: Format: DWARF32
+# DWARF-NEXT: Version: 5
+# DWARF-NEXT: CU count: 2
+# DWARF-NEXT: Local TU count: 0
+# DWARF-NEXT: Foreign TU count: 0
+# DWARF-NEXT: Bucket count: 9
+# DWARF-NEXT: Name count: 9
+# DWARF-NEXT: Abbreviations table size: 0x33
+# DWARF-NEXT: Augmentation: 'LLVM0700'
+# DWARF: Compilation Unit offsets [
+# DWARF-NEXT: CU[0]: 0x00000000
+# DWARF-NEXT: CU[1]: 0x0000000c
+# DWARF: Abbreviations [
+# DWARF-NEXT: Abbreviation 0x1 {
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Abbreviation 0x2 {
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Abbreviation 0x3 {
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Abbreviation 0x4 {
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Abbreviation 0x5 {
+# DWARF-NEXT: Tag: DW_TAG_namespace
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Bucket 0 [
+# DWARF-NEXT: EMPTY
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 1 [
+# DWARF-NEXT: Name 1 {
+# DWARF-NEXT: Hash: 0xA974AA29
+# DWARF-NEXT: String: 0x00000174 "_ZN11parent_test3fooEv"
+# DWARF-NEXT: Entry @ 0x14a {
+# DWARF-NEXT: Abbrev: 0x4
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000045
+# DWARF-NEXT: DW_IDX_parent: Entry @ 0x128
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: Name 2 {
+# DWARF-NEXT: Hash: 0xB5063D0B
+# DWARF-NEXT: String: 0x00000160 "_Z3foov"
+# DWARF-NEXT: Entry @ 0x155 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000027
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 2 [
+# DWARF-NEXT: Name 3 {
+# DWARF-NEXT: Hash: 0xB888030
+# DWARF-NEXT: String: 0x00000093 "int"
+# DWARF-NEXT: Entry @ 0xfe {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x0000008d
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0x104 {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 3 [
+# DWARF-NEXT: Name 4 {
+# DWARF-NEXT: Hash: 0xB8860BA
+# DWARF-NEXT: String: 0x0000007d "bar"
+# DWARF-NEXT: Entry @ 0xf7 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: Name 5 {
+# DWARF-NEXT: Hash: 0xB887389
+# DWARF-NEXT: String: 0x00000097 "foo"
+# DWARF-NEXT: Entry @ 0x10b {
+# DWARF-NEXT: Abbrev: 0x3
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000096
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0x111 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000027
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0x117 {
+# DWARF-NEXT: Abbrev: 0x4
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000045
+# DWARF-NEXT: DW_IDX_parent: Entry @ 0x128
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0x121 {
+# DWARF-NEXT: Abbrev: 0x3
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000056
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 4 [
+# DWARF-NEXT: EMPTY
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 5 [
+# DWARF-NEXT: EMPTY
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 6 [
+# DWARF-NEXT: EMPTY
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 7 [
+# DWARF-NEXT: Name 6 {
+# DWARF-NEXT: Hash: 0x7C9A7F6A
+# DWARF-NEXT: String: 0x0000008e "main"
+# DWARF-NEXT: Entry @ 0x136 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000046
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 8 [
+# DWARF-NEXT: Name 7 {
+# DWARF-NEXT: Hash: 0xA7255AE
+# DWARF-NEXT: String: 0x00000168 "parent_test"
+# DWARF-NEXT: Entry @ 0x128 {
+# DWARF-NEXT: Abbrev: 0x5
+# DWARF-NEXT: Tag: DW_TAG_namespace
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000043
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: Name 8 {
+# DWARF-NEXT: Hash: 0x51007E98
+# DWARF-NEXT: String: 0x00000081 "_Z3barR3fooi"
+# DWARF-NEXT: Entry @ 0x12f {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: Name 9 {
+# DWARF-NEXT: Hash: 0x7C952063
+# DWARF-NEXT: String: 0x0000009f "char"
+# DWARF-NEXT: Entry @ 0x13d {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x000000b8
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0x143 {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000078
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+
+#--- a.s
+ .text
+ .globl _Z3barR3fooi # -- Begin function _Z3barR3fooi
+ .p2align 4, 0x90
+ .type _Z3barR3fooi,@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,@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@PLT
+ movl %eax, -36(%rbp)
+ movl -36(%rbp), %esi
+ leaq -32(%rbp), %rdi
+ callq _Z3barR3fooi
+ callq _ZN11parent_test3fooEv@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,"",@progbits
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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,"",@progbits
+ .long 72 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+ .asciz "a.cpp" # string offset=104
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=110
+.Linfo_string3:
+ .asciz "bar" # string offset=125
+.Linfo_string4:
+ .asciz "_Z3barR3fooi" # string offset=129
+.Linfo_string5:
+ .asciz "main" # string offset=142
+.Linfo_string6:
+ .asciz "int" # string offset=147
+.Linfo_string7:
+ .asciz "foo" # string offset=151
+.Linfo_string8:
+ .asciz "x" # string offset=155
+.Linfo_string9:
+ .asciz "y" # string offset=157
+.Linfo_string10:
+ .asciz "char" # string offset=159
+.Linfo_string11:
+ .asciz "foo_ptr" # string offset=164
+.Linfo_string12:
+ .asciz "junk" # string offset=172
+.Linfo_string13:
+ .asciz "argc" # string offset=177
+.Linfo_string14:
+ .asciz "argv" # string offset=182
+.Linfo_string15:
+ .asciz "my_struct" # string offset=187
+.Linfo_string16:
+ .asciz "junk2" # string offset=197
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+ .quad .Lfunc_begin1
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .addrsig_sym _Z3barR3fooi
+ .addrsig_sym _Z3foov
+ .addrsig_sym _ZN11parent_test3fooEv
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
+
+#--- b.s
+# Generated with:
+
+# clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' -S \
+# b.cpp -o b.s
+
+# foo.h contents:
+
+# int foo();
+
+#struct foo {
+# int x;
+# char y;
+# struct foo *foo_ptr;
+# };
+
+# namespace parent_test {
+# int foo();
+# }
+
+# b.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,@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,@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,"",@progbits
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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,"",@progbits
+ .long 56 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+ .asciz "b.cpp" # string offset=104
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=110
+.Linfo_string3:
+ .asciz "int" # string offset=125
+.Linfo_string4:
+ .asciz "foo" # string offset=129
+.Linfo_string5:
+ .asciz "_Z3foov" # string offset=133
+.Linfo_string6:
+ .asciz "parent_test" # string offset=141
+.Linfo_string7:
+ .asciz "_ZN11parent_test3fooEv" # string offset=153
+.Linfo_string8:
+ .asciz "struct2" # string offset=176
+.Linfo_string9:
+ .asciz "x" # string offset=184
+.Linfo_string10:
+ .asciz "y" # string offset=186
+.Linfo_string11:
+ .asciz "char" # string offset=188
+.Linfo_string12:
+ .asciz "foo_ptr" # string offset=193
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+ .quad .Lfunc_begin1
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/debug-names-type-units.s b/lld/test/ELF/debug-names-type-units.s
new file mode 100644
index 0000000..dda065b
--- /dev/null
+++ b/lld/test/ELF/debug-names-type-units.s
@@ -0,0 +1,895 @@
+# REQUIRES: x86
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.tu.s -o a.tu.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.foreign-tu.s -o a.foreign-tu.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64 b.s -o b.o
+
+# RUN: ld.lld --debug-names a.tu.o b.o -o out0 2>&1 | FileCheck --check-prefix=WARN %s
+# RUN: llvm-dwarfdump --debug-names out0 | FileCheck --check-prefix=DWARF %s
+
+# WARN: warning: a.tu.o:(.debug_names): type units are not implemented
+
+# DWARF: CU count: 2
+# DWARF-NEXT: Local TU count: 0
+# DWARF-NEXT: Foreign TU count: 0
+# DWARF: Compilation Unit offsets [
+# DWARF-NEXT: CU[0]:
+# DWARF-SAME: 0x0000002a
+# DWARF-NEXT: CU[1]:
+# DWARF-SAME: 0x0000006a
+# DWARF-NEXT: ]
+# DWARF: String: {{.*}} "t1"
+# DWARF-NEXT: Entry @ 0x8f {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_type_unit: 0x00
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0x96 {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000036
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0x9c {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000029
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+
+# RUN: ld.lld --debug-names a.foreign-tu.o b.o -o out1 2>&1 | FileCheck %s --check-prefix=WARN2
+# RUN: llvm-dwarfdump --debug-names out1 | FileCheck --check-prefix=DWARF2 %s
+
+# WARN2: warning: a.foreign-tu.o:(.debug_names): type units are not implemented
+
+# DWARF2: CU count: 2
+# DWARF2-NEXT: Local TU count: 0
+# DWARF2-NEXT: Foreign TU count: 0
+# DWARF2: Compilation Unit offsets [
+# DWARF2-NEXT: CU[0]:
+# DWARF2-SAME: 0x00000000
+# DWARF2-NEXT: CU[1]:
+# DWARF2-SAME: 0x00000028
+# DWARF2-NEXT: ]
+
+.ifdef GEN
+#--- a.cc
+struct t1 {};
+extern "C" void _start(t1) {}
+#--- b.cc
+struct t1 { } vb;
+#--- gen
+echo '#--- a.tu.s'
+clang --target=x86_64-linux -S -O1 -g -gpubnames -fdebug-types-section a.cc -o -
+echo '#--- a.foreign-tu.s'
+clang --target=x86_64-linux -S -O1 -g -gpubnames -fdebug-types-section -gsplit-dwarf a.cc -o -
+echo '#--- b.s'
+clang --target=x86_64-linux -S -O1 -g -gpubnames b.cc -o -
+.endif
+#--- a.tu.s
+ .text
+ .file "a.cc"
+ .globl _start # -- Begin function _start
+ .p2align 4, 0x90
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+ .file 0 "/proc/self/cwd" "a.cc" md5 0x6835f89a7d36054002b51e54e47d852e
+ .cfi_startproc
+# %bb.0: # %entry
+ .loc 0 2 29 prologue_end # a.cc:2:29
+ retq
+.Ltmp0:
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-_start
+ .cfi_endproc
+ # -- End function
+ .section .debug_info,"G",@progbits,14297044602779165170,comdat
+.Ltu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 2 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .quad -4149699470930386446 # Type Signature
+ .long 35 # Type DIE Offset
+ .byte 1 # Abbrev [1] 0x18:0x12 DW_TAG_type_unit
+ .short 33 # DW_AT_language
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .byte 2 # Abbrev [2] 0x23:0x6 DW_TAG_structure_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 4 # 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_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 65 # DW_TAG_type_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 122 # DW_AT_call_all_calls
+ .byte 25 # DW_FORM_flag_present
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 60 # DW_AT_declaration
+ .byte 25 # DW_FORM_flag_present
+ .byte 105 # DW_AT_signature
+ .byte 32 # DW_FORM_ref_sig8
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
+.Ldebug_info_start1:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 3 # Abbrev [3] 0xc:0x34 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 4 # Abbrev [4] 0x23:0x13 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 87
+ # DW_AT_call_all_calls
+ .byte 3 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ # DW_AT_external
+ .byte 5 # Abbrev [5] 0x2e:0x7 DW_TAG_formal_parameter
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .long 54 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0x36:0x9 DW_TAG_structure_type
+ # DW_AT_declaration
+ .quad -4149699470930386446 # DW_AT_signature
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end1:
+ .section .debug_str_offsets,"",@progbits
+ .long 24 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .byte 0 # string offset=0
+.Linfo_string1:
+ .asciz "a.cc" # string offset=1
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=6
+.Linfo_string3:
+ .asciz "_start" # string offset=21
+.Linfo_string4:
+ .asciz "t1" # string offset=28
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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 1 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 2 # Header: bucket count
+ .long 2 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long .Ltu_begin0 # Type unit 0
+ .long 1 # Bucket 0
+ .long 0 # Bucket 1
+ .long 5863786 # Hash in Bucket 0
+ .long -304389582 # Hash in Bucket 0
+ .long .Linfo_string4 # String in Bucket 0: t1
+ .long .Linfo_string3 # String in Bucket 0: _start
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 0
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 19 # DW_TAG_structure_type
+ .byte 2 # DW_IDX_type_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 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 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames1:
+.L1:
+ .byte 1 # Abbreviation code
+ .byte 0 # DW_IDX_type_unit
+ .long 35 # DW_IDX_die_offset
+.L0: # DW_IDX_parent
+ .byte 2 # Abbreviation code
+ .long 54 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: t1
+.Lnames0:
+ .byte 3 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: _start
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
+#--- a.foreign-tu.s
+ .text
+ .file "a.cc"
+ .globl _start # -- Begin function _start
+ .p2align 4, 0x90
+ .type _start,@function
+_start: # @_start
+.Lfunc_begin0:
+ .file 0 "/proc/self/cwd" "a.cc" md5 0x6835f89a7d36054002b51e54e47d852e
+ .cfi_startproc
+# %bb.0: # %entry
+ .loc 0 2 29 prologue_end # a.cc:2:29
+ retq
+.Ltmp0:
+.Lfunc_end0:
+ .size _start, .Lfunc_end0-_start
+ .cfi_endproc
+ # -- End function
+ .section .debug_info.dwo,"e",@progbits
+ .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit
+.Ldebug_info_dwo_start0:
+ .short 5 # DWARF version number
+ .byte 6 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long 0 # Offset Into Abbrev. Section
+ .quad -4149699470930386446 # Type Signature
+ .long 33 # Type DIE Offset
+ .byte 1 # Abbrev [1] 0x18:0x10 DW_TAG_type_unit
+ .short 33 # DW_AT_language
+ .byte 1 # DW_AT_comp_dir
+ .byte 2 # DW_AT_dwo_name
+ .long 0 # DW_AT_stmt_list
+ .byte 2 # Abbrev [2] 0x21:0x6 DW_TAG_structure_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 3 # 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_dwo_end0:
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 74 # DW_TAG_skeleton_unit
+ .byte 0 # DW_CHILDREN_no
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 118 # DW_AT_dwo_name
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 4 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .quad -2763464185488304260
+ .byte 1 # Abbrev [1] 0x14:0x14 DW_TAG_skeleton_unit
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .byte 0 # DW_AT_comp_dir
+ .byte 1 # DW_AT_dwo_name
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .long .Laddr_table_base0 # DW_AT_addr_base
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 12 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Lskel_string0:
+ .asciz "/proc/self/cwd" # string offset=0
+.Lskel_string1:
+ .asciz "_start" # string offset=15
+.Lskel_string2:
+ .asciz "t1" # string offset=22
+.Lskel_string3:
+ .asciz "a.dwo" # string offset=25
+ .section .debug_str_offsets,"",@progbits
+ .long .Lskel_string0
+ .long .Lskel_string3
+ .section .debug_str_offsets.dwo,"e",@progbits
+ .long 28 # Length of String Offsets Set
+ .short 5
+ .short 0
+ .section .debug_str.dwo,"eMS",@progbits,1
+.Linfo_string0:
+ .asciz "_start" # string offset=0
+.Linfo_string1:
+ .asciz "/proc/self/cwd" # string offset=7
+.Linfo_string2:
+ .asciz "a.dwo" # string offset=22
+.Linfo_string3:
+ .asciz "t1" # string offset=28
+.Linfo_string4:
+ .byte 0 # string offset=31
+.Linfo_string5:
+ .asciz "a.cc" # string offset=32
+ .section .debug_str_offsets.dwo,"e",@progbits
+ .long 0
+ .long 7
+ .long 22
+ .long 28
+ .long 31
+ .long 32
+ .section .debug_info.dwo,"e",@progbits
+ .long .Ldebug_info_dwo_end1-.Ldebug_info_dwo_start1 # Length of Unit
+.Ldebug_info_dwo_start1:
+ .short 5 # DWARF version number
+ .byte 5 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long 0 # Offset Into Abbrev. Section
+ .quad -2763464185488304260
+ .byte 3 # Abbrev [3] 0x14:0x23 DW_TAG_compile_unit
+ .byte 4 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 5 # DW_AT_name
+ .byte 2 # DW_AT_dwo_name
+ .byte 4 # Abbrev [4] 0x1a:0x13 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 87
+ # DW_AT_call_all_calls
+ .byte 0 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ # DW_AT_external
+ .byte 5 # Abbrev [5] 0x25:0x7 DW_TAG_formal_parameter
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .long 45 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0x2d:0x9 DW_TAG_structure_type
+ # DW_AT_declaration
+ .quad -4149699470930386446 # DW_AT_signature
+ .byte 0 # End Of Children Mark
+.Ldebug_info_dwo_end1:
+ .section .debug_abbrev.dwo,"e",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 65 # DW_TAG_type_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 118 # DW_AT_dwo_name
+ .byte 37 # DW_FORM_strx1
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 118 # DW_AT_dwo_name
+ .byte 37 # DW_FORM_strx1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 122 # DW_AT_call_all_calls
+ .byte 25 # DW_FORM_flag_present
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 60 # DW_AT_declaration
+ .byte 25 # DW_FORM_flag_present
+ .byte 105 # DW_AT_signature
+ .byte 32 # DW_FORM_ref_sig8
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_line.dwo,"e",@progbits
+.Ltmp1:
+ .long .Ldebug_line_end0-.Ldebug_line_start0 # unit length
+.Ldebug_line_start0:
+ .short 5
+ .byte 8
+ .byte 0
+ .long .Lprologue_end0-.Lprologue_start0
+.Lprologue_start0:
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte -5
+ .byte 14
+ .byte 1
+ .byte 1
+ .byte 1
+ .byte 8
+ .byte 1
+ .ascii "/proc/self/cwd"
+ .byte 0
+ .byte 3
+ .byte 1
+ .byte 8
+ .byte 2
+ .byte 15
+ .byte 5
+ .byte 30
+ .byte 1
+ .ascii "a.cc"
+ .byte 0
+ .byte 0
+ .byte 0x68, 0x35, 0xf8, 0x9a
+ .byte 0x7d, 0x36, 0x05, 0x40
+ .byte 0x02, 0xb5, 0x1e, 0x54
+ .byte 0xe4, 0x7d, 0x85, 0x2e
+.Lprologue_end0:
+.Ldebug_line_end0:
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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 1 # Header: foreign type unit count
+ .long 2 # Header: bucket count
+ .long 2 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .quad -4149699470930386446 # Type unit 0
+ .long 1 # Bucket 0
+ .long 0 # Bucket 1
+ .long 5863786 # Hash in Bucket 0
+ .long -304389582 # Hash in Bucket 0
+ .long .Lskel_string2 # String in Bucket 0: t1
+ .long .Lskel_string1 # String in Bucket 0: _start
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 0
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 19 # DW_TAG_structure_type
+ .byte 2 # DW_IDX_type_unit
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 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 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames1:
+.L2:
+ .byte 1 # Abbreviation code
+ .byte 0 # DW_IDX_type_unit
+ .long 33 # DW_IDX_die_offset
+.L1: # DW_IDX_parent
+ .byte 2 # Abbreviation code
+ .long 45 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: t1
+.Lnames0:
+.L0:
+ .byte 3 # Abbreviation code
+ .long 26 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: _start
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
+#--- b.s
+ .text
+ .file "b.cc"
+ .file 0 "/proc/self/cwd" "b.cc" md5 0xe69190c4224a66c796605e3a1324674b
+ .type vb,@object # @vb
+ .bss
+ .globl vb
+vb:
+ .zero 1
+ .size vb, 1
+
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 19 # DW_TAG_structure_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 11 # DW_AT_byte_size
+ .byte 11 # DW_FORM_data1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0x24 DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 1 # DW_AT_name
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .byte 2 # DW_AT_comp_dir
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x1e:0xb DW_TAG_variable
+ .byte 3 # DW_AT_name
+ .long 41 # DW_AT_type
+ # DW_AT_external
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .byte 2 # DW_AT_location
+ .byte 161
+ .byte 0
+ .byte 3 # Abbrev [3] 0x29:0x6 DW_TAG_structure_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 4 # 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,"",@progbits
+ .long 24 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .byte 0 # string offset=0
+.Linfo_string1:
+ .asciz "b.cc" # string offset=1
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=6
+.Linfo_string3:
+ .asciz "vb" # string offset=21
+.Linfo_string4:
+ .asciz "t1" # string offset=24
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad vb
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 2 # Header: bucket count
+ .long 2 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 1 # Bucket 0
+ .long 2 # Bucket 1
+ .long 5863786 # Hash in Bucket 0
+ .long 5863901 # Hash in Bucket 1
+ .long .Linfo_string4 # String in Bucket 0: t1
+ .long .Linfo_string3 # String in Bucket 1: vb
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 1
+.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 52 # DW_TAG_variable
+ .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 41 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: t1
+.Lnames1:
+.L0:
+ .byte 2 # Abbreviation code
+ .long 30 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: vb
+ .p2align 2, 0x0
+.Lnames_end0:
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@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 0000000..888dd90
--- /dev/null
+++ b/lld/test/ELF/debug-names.s
@@ -0,0 +1,430 @@
+# debug-names.s was generated with:
+
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' \
+# -S a.cpp -o a.s
+
+# a.cpp contents:
+
+# struct t1 { };
+# void f1(t1) { }
+
+# 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 a.o b.o -o out0
+# RUN: llvm-readelf -SW out0 | FileCheck %s --check-prefix=NO_MERGE
+
+# NO_MERGE: Name Type Address Off Size ES Flg Lk Inf Al
+# NO_MERGE: .debug_names PROGBITS 0000000000000000 [[#%x,]] 000110 00 0 0 4
+
+# RUN: ld.lld --debug-names a.o b.o -o out
+
+# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
+# RUN: llvm-readelf -SW out | FileCheck %s --check-prefix=READELF
+
+## Test we can handle concatenated .debug_names.
+# RUN: ld.lld -r a.o b.o -o ab.o
+# RUN: ld.lld --debug-names ab.o -o out1
+# RUN: llvm-dwarfdump -debug-names out1 | FileCheck %s --check-prefix=DWARF
+
+# READELF: Name Type Address Off Size ES Flg Lk Inf Al
+# READELF: .debug_names PROGBITS 0000000000000000 [[#%x,]] 0000cc 00 0 0 4
+
+## Test we can handle compressed input and --compress-debug-sections compresses output .debug_names.
+# RUN: %if zlib %{ llvm-objcopy --compress-debug-sections=zlib a.o a.zlib.o %}
+# RUN: %if zlib %{ ld.lld --debug-names --compress-debug-sections=zlib a.zlib.o b.o -o out.zlib %}
+# RUN: %if zlib %{ llvm-readelf -S out.zlib | FileCheck %s --check-prefix=READELF-ZLIB %}
+# RUN: %if zlib %{ llvm-objcopy --decompress-debug-sections out.zlib out.zlib.de %}
+# RUN: %if zlib %{ llvm-dwarfdump -debug-names out.zlib.de | FileCheck %s --check-prefix=DWARF %}
+
+# READELF-ZLIB: Name Type Address Off Size ES Flg Lk Inf Al
+# READELF-ZLIB: .debug_names PROGBITS 0000000000000000 [[#%x,]] [[#%x,]] 00 C 0 0 1
+
+# DWARF: .debug_names contents:
+# DWARF: Name Index @ 0x0 {
+# DWARF-NEXT: Header {
+# DWARF-NEXT: Length: 0xC8
+# DWARF-NEXT: Format: DWARF32
+# DWARF-NEXT: Version: 5
+# DWARF-NEXT: CU count: 2
+# DWARF-NEXT: Local TU count: 0
+# DWARF-NEXT: Foreign TU count: 0
+# DWARF-NEXT: Bucket count: 5
+# DWARF-NEXT: Name count: 5
+# DWARF-NEXT: Abbreviations table size: 0x1F
+# DWARF-NEXT: Augmentation: 'LLVM0700'
+# DWARF: Compilation Unit offsets [
+# DWARF-NEXT: CU[0]: 0x00000000
+# DWARF-NEXT: CU[1]: 0x0000000c
+# DWARF: Abbreviations [
+# DWARF-NEXT: Abbreviation 0x1 {
+# DWARF: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Abbreviation 0x2 {
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Abbreviation 0x3 {
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Bucket 0 [
+# DWARF-NEXT: EMPTY
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 1 [
+# DWARF-NEXT: Name 1 {
+# DWARF-NEXT: Hash: 0x59796A
+# DWARF-NEXT: String: 0x00000089 "t1"
+# DWARF-NEXT: Entry @ 0xaa {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x0000003a
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0xb0 {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000042
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: Name 2 {
+# DWARF-NEXT: Hash: 0x5355B2BE
+# DWARF-NEXT: String: 0x00000080 "_Z2f12t1"
+# DWARF-NEXT: Entry @ 0xbe {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: Name 3 {
+# DWARF-NEXT: Hash: 0x7C9A7F6A
+# DWARF-NEXT: String: 0x00000111 "main"
+# DWARF-NEXT: Entry @ 0xc5 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 2 [
+# DWARF-NEXT: EMPTY
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 3 [
+# DWARF-NEXT: Name 4 {
+# DWARF-NEXT: Hash: 0xB888030
+# DWARF-NEXT: String: 0x00000116 "int"
+# DWARF-NEXT: Entry @ 0xb7 {
+# DWARF-NEXT: Abbrev: 0x3
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x0000003e
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 4 [
+# DWARF-NEXT: Name 5 {
+# DWARF-NEXT: Hash: 0x59779C
+# DWARF-NEXT: String: 0x0000007d "f1"
+# DWARF-NEXT: Entry @ 0xa3 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+
+#--- a.s
+ .text
+ .globl _Z2f12t1 # -- Begin function _Z2f12t1
+ .p2align 4, 0x90
+ .type _Z2f12t1,@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,"",@progbits
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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,"",@progbits
+ .long 28 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+ .asciz "a.cpp" # string offset=104
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=110
+.Linfo_string3:
+ .asciz "f1" # string offset=125
+.Linfo_string4:
+ .asciz "_Z2f12t1" # string offset=128
+.Linfo_string5:
+ .asciz "t1" # string offset=137
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
+
+#--- b.s
+# Generated with:
+# - clang++ -g -O0 -gpubnames -fdebug-compilation-dir='/proc/self/cwd' \
+# -S b.cpp -o b.s
+
+# b.cpp contents:
+
+# struct t1 { };
+# int main() {
+# t1 v1;
+# }
+#
+
+ .text
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@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,"",@progbits
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@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,"",@progbits
+ .long 32 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+ .asciz "b.cpp" # string offset=104
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=110
+.Linfo_string3:
+ .asciz "main" # string offset=125
+.Linfo_string4:
+ .asciz "int" # string offset=130
+.Linfo_string5:
+ .asciz "v1" # string offset=134
+.Linfo_string6:
+ .asciz "t1" # string offset=137
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/lld/test/ELF/driver.test b/lld/test/ELF/driver.test
index 49deb90..45d7360 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
diff --git a/lld/test/ELF/ppc32-debug-names.s b/lld/test/ELF/ppc32-debug-names.s
new file mode 100644
index 0000000..3fc93ec
--- /dev/null
+++ b/lld/test/ELF/ppc32-debug-names.s
@@ -0,0 +1,418 @@
+# ppc32-debug-names.s was generated with:
+
+# clang++ --target=powerpc -g -gpubnames \
+# -fdebug-compilation-dir='/self/proc/cwd' -S a.cpp -o a.s
+
+# a.cpp contents:
+
+# struct t1 { };
+# void f1(t1) { }
+
+# REQUIRES: ppc
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=powerpc a.s -o a.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc b.s -o b.o
+
+# RUN: ld.lld --debug-names --no-debug-names a.o b.o -o out0
+# RUN: llvm-readelf -SW out0 | FileCheck %s --check-prefix=NO_MERGE
+
+# NO_MERGE: Name Type Address Off Size ES Flg Lk Inf Al
+# NO_MERGE: .debug_names PROGBITS 00000000 [[#%x,]] 000110 00 0 0 4
+
+# RUN: ld.lld --debug-names a.o b.o -o out
+
+# RUN: llvm-dwarfdump -debug-names out | FileCheck %s --check-prefix=DWARF
+# RUN: llvm-readelf -SW out | FileCheck %s --check-prefix=READELF
+
+# READELF: Name Type Address Off Size ES Flg Lk Inf Al
+# READELF: .debug_names PROGBITS 00000000 [[#%x,]] 0000cc 00 0 0 4
+
+# DWARF: file format elf32-powerpc
+# DWARF: .debug_names contents:
+# DWARF: Name Index @ 0x0 {
+# DWARF-NEXT: Header {
+# DWARF-NEXT: Length: 0xC8
+# DWARF-NEXT: Format: DWARF32
+# DWARF-NEXT: Version: 5
+# DWARF-NEXT: CU count: 2
+# DWARF-NEXT: Local TU count: 0
+# DWARF-NEXT: Foreign TU count: 0
+# DWARF-NEXT: Bucket count: 5
+# DWARF-NEXT: Name count: 5
+# DWARF-NEXT: Abbreviations table size: 0x1F
+# DWARF-NEXT: Augmentation: 'LLVM0700'
+# DWARF: Compilation Unit offsets [
+# DWARF-NEXT: CU[0]: 0x00000000
+# DWARF-NEXT: CU[1]: 0x0000000c
+# DWARF: Abbreviations [
+# DWARF-NEXT: Abbreviation 0x1 {
+# DWARF: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Abbreviation 0x2 {
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Abbreviation 0x3 {
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# DWARF-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# DWARF-NEXT: DW_IDX_compile_unit: DW_FORM_data1
+# DWARF: Bucket 0 [
+# DWARF-NEXT: EMPTY
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 1 [
+# DWARF-NEXT: Name 1 {
+# DWARF-NEXT: Hash: 0x59796A
+# DWARF-NEXT: String: 0x00000089 "t1"
+# DWARF-NEXT: Entry @ 0xaa {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x0000003a
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: Entry @ 0xb0 {
+# DWARF-NEXT: Abbrev: 0x1
+# DWARF-NEXT: Tag: DW_TAG_structure_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000042
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: Name 2 {
+# DWARF-NEXT: Hash: 0x5355B2BE
+# DWARF-NEXT: String: 0x00000080 "_Z2f12t1"
+# DWARF-NEXT: Entry @ 0xbe {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: Name 3 {
+# DWARF-NEXT: Hash: 0x7C9A7F6A
+# DWARF-NEXT: String: 0x0000010d "main"
+# DWARF-NEXT: Entry @ 0xc5 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 2 [
+# DWARF-NEXT: EMPTY
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 3 [
+# DWARF-NEXT: Name 4 {
+# DWARF-NEXT: Hash: 0xB888030
+# DWARF-NEXT: String: 0x00000112 "int"
+# DWARF-NEXT: Entry @ 0xb7 {
+# DWARF-NEXT: Abbrev: 0x3
+# DWARF-NEXT: Tag: DW_TAG_base_type
+# DWARF-NEXT: DW_IDX_die_offset: 0x0000003e
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x01
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+# DWARF-NEXT: Bucket 4 [
+# DWARF-NEXT: Name 5 {
+# DWARF-NEXT: Hash: 0x59779C
+# DWARF-NEXT: String: 0x0000007d "f1"
+# DWARF-NEXT: Entry @ 0xa3 {
+# DWARF-NEXT: Abbrev: 0x2
+# DWARF-NEXT: Tag: DW_TAG_subprogram
+# DWARF-NEXT: DW_IDX_die_offset: 0x00000023
+# DWARF-NEXT: DW_IDX_parent: <parent not indexed>
+# DWARF-NEXT: DW_IDX_compile_unit: 0x00
+# DWARF-NEXT: }
+# DWARF-NEXT: }
+# DWARF-NEXT: ]
+
+#--- a.s
+ .text
+ .globl _Z2f12t1 # -- Begin function _Z2f12t1
+ .p2align 2
+ .type _Z2f12t1,@function
+_Z2f12t1: # @_Z2f12t1
+.Lfunc_begin0:
+ .cfi_startproc
+# %bb.0: # %entry
+ #DEBUG_VALUE: f1: <- [$r3+0]
+ stwu 1, -16(1)
+ stw 31, 12(1)
+ .cfi_def_cfa_offset 16
+ .cfi_offset r31, -4
+ mr 31, 1
+ .cfi_def_cfa_register r31
+.Ltmp0:
+ lwz 31, 12(1)
+ addi 1, 1, 16
+ blr
+.Ltmp1:
+.Lfunc_end0:
+ .size _Z2f12t1, .Lfunc_end0-.Lfunc_begin0
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 4 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 28 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+ .asciz "a.cpp" # string offset=104
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=110
+.Linfo_string3:
+ .asciz "f1" # string offset=125
+.Linfo_string4:
+ .asciz "_Z2f12t1" # string offset=128
+.Linfo_string5:
+ .asciz "t1" # string offset=137
+.Laddr_table_base0:
+ .long .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
+
+#--- b.s
+# Generated with:
+# - clang++ --target=powerpc -g -O0 -gpubnames \
+# -fdebug-compilation-dir='/self/proc/cwd' -S b.cpp -o b.s
+
+# b.cpp contents:
+
+# struct t1 { };
+# int main() {
+# t1 v1;
+# }
+#
+ .text
+ .globl main # -- Begin function main
+ .p2align 2
+ .type main,@function
+main: # @main
+.Lfunc_begin0:
+ .cfi_startproc
+# %bb.0: # %entry
+ stwu 1, -16(1)
+ stw 31, 12(1)
+ .cfi_def_cfa_offset 16
+ .cfi_offset r31, -4
+ mr 31, 1
+ .cfi_def_cfa_register r31
+ li 3, 0
+.Ltmp0:
+ lwz 31, 12(1)
+ addi 1, 1, 16
+ blr
+.Ltmp1:
+.Lfunc_end0:
+ .size main, .Lfunc_end0-.Lfunc_begin0
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 4 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 32 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 19.0.0git (git@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)" # string offset=0
+.Linfo_string1:
+ .asciz "b.cpp" # string offset=104
+.Linfo_string2:
+ .asciz "/proc/self/cwd" # string offset=110
+.Linfo_string3:
+ .asciz "main" # string offset=125
+.Linfo_string4:
+ .asciz "int" # string offset=130
+.Linfo_string5:
+ .asciz "v1" # string offset=134
+.Linfo_string6:
+ .asciz "t1" # string offset=137
+.Laddr_table_base0:
+ .long .Lfunc_begin0
+.Ldebug_addr_end0:
+ .section .debug_names,"",@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@github.com:llvm/llvm-project.git 53b14cd9ce2b57da73d173fc876d2e9e199f5640)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0: