[lld] [lld][ELF] Implement merged .debug_names section. (PR #86508)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sun Apr 7 14:42:22 PDT 2024
================
@@ -2690,6 +2693,756 @@ static uint32_t computeGdbHash(StringRef s) {
return h;
}
+template <class ELFT>
+DebugNamesSection<ELFT>::DebugNamesSection()
+ : SyntheticSection(0, SHT_PROGBITS, 1, ".debug_names") {}
+
+template <class ELFT>
+template <class RelTy>
+void DebugNamesSection<ELFT>::getNameRelocsImpl(
+ InputSection *sec, ArrayRef<RelTy> rels,
+ DenseMap<uint32_t, uint32_t> &relocs) {
+ for (auto &rel : rels) {
+ Symbol &sym = sec->getFile<ELFT>()->getRelocTargetSym(rel);
+ relocs[rel.r_offset] = sym.getVA(getAddend<ELFT>(rel));
+ }
+}
+
+template <class ELFT>
+void DebugNamesSection<ELFT>::getNameRelocs(
+ InputSectionBase *base, DenseMap<uint32_t, uint32_t> &relocs) {
+ auto *sec = cast<InputSection>(base);
+ const RelsOrRelas<ELFT> rels = sec->template relsOrRelas<ELFT>();
+ if (rels.areRelocsRel())
+ getNameRelocsImpl(sec, rels.rels, relocs);
+ else
+ getNameRelocsImpl(sec, rels.relas, relocs);
+}
+
+template <class ELFT> void DebugNamesSection<ELFT>::writeTo(uint8_t *buf) {
+ SmallVector<uint32_t, 0> mergedCuOffsets;
+ SmallVector<uint32_t, 0> mergedTuOffsets;
+ DenseMap<uint32_t, uint32_t> strOffsets;
+ SmallVector<DenseMap<uint32_t, uint32_t>, 0> chunksRelocs;
+ chunksRelocs.reserve(numChunks);
+
+ for (size_t i = 0, e = numChunks; i != e; ++i) {
+ DebugNamesOutputChunk &chunk = outputChunks[i];
+ InputSectionBase *base = inputDebugNamesSections[i];
+ DenseMap<uint32_t, uint32_t> &relocs = chunksRelocs.emplace_back();
+ getNameRelocs(base, relocs);
+
+ // Update CuOffsets list with new data
+ for (uint32_t cuOffset : chunk.compilationUnits)
+ mergedCuOffsets.push_back(chunk.sec->outSecOff + cuOffset);
+
+ // TODO: Update TuOffsets list with new data
+ }
+
+ // Update the entries with the relocated string offsets.
+ for (NamedEntry &stringEntry : mergedEntries) {
+ uint32_t oldOffset = stringEntry.stringOffsetOffset;
+ uint32_t idx = stringEntry.chunkIdx;
+ stringEntry.relocatedEntryOffset = chunksRelocs[idx][oldOffset];
+ }
+
+ // Write out bytes for merged section.
+
+ // Write the header.
+ endian::write32<ELFT::Endianness>(buf + 0, mergedHdr.UnitLength);
+ endian::write16<ELFT::Endianness>(buf + 4, mergedHdr.Version);
+ endian::write32<ELFT::Endianness>(buf + 8, mergedHdr.CompUnitCount);
+ endian::write32<ELFT::Endianness>(buf + 12, mergedHdr.LocalTypeUnitCount);
+ endian::write32<ELFT::Endianness>(buf + 16, mergedHdr.ForeignTypeUnitCount);
+ endian::write32<ELFT::Endianness>(buf + 20, mergedHdr.BucketCount);
+ endian::write32<ELFT::Endianness>(buf + 24, mergedHdr.NameCount);
+ endian::write32<ELFT::Endianness>(buf + 28, mergedHdr.AbbrevTableSize);
+ endian::write32<ELFT::Endianness>(buf + 32, mergedHdr.AugmentationStringSize);
+ buf += 36;
+ memcpy(buf, mergedHdr.AugmentationString.c_str(), 8);
+ buf += 8;
+
+ // Write the CU list.
+ for (uint32_t offset : mergedCuOffsets) {
+ endian::write32<ELFT::Endianness>(buf + 0, offset);
+ buf += 4;
+ }
+
+ // Write the local TU list.
+ // TODO: Fix this, once we get everything working without TUs.
+ if (mergedHdr.LocalTypeUnitCount != 0)
+ warn(".debug_names: type units are not handled in merged index");
+
+ // Write the foreign TU list.
+ // TODO: Fix this, once we get everything working without TUs.
+ if (mergedHdr.ForeignTypeUnitCount != 0)
+ warn(".debug_names: type units are not handled in merged index");
+
+ // Write the hash table.
+ // ... Write the buckets
+ uint32_t idx = 1;
+ for (const SmallVector<NamedEntry *, 0> &bucket : bucketList) {
+ if (!bucket.empty())
+ endian::write32<ELFT::Endianness>(buf + 0, idx);
+ idx += bucket.size();
+ buf += 4;
+ }
+
+ // ...Write the hashes
+ for (const auto &bucket : bucketList) {
+ for (const auto &entry : bucket) {
+ uint32_t hashValue = entry->hashValue;
+ endian::write32<ELFT::Endianness>(buf + 0, hashValue);
+ buf += 4;
+ }
+ }
+
+ // Write the string offsets.
+ for (const NamedEntry &entry : mergedEntries) {
+ endian::write32<ELFT::Endianness>(buf + 0, entry.relocatedEntryOffset);
+ buf += 4;
+ }
+
+ // Write the entry offsets.
+ for (const auto &entry : mergedEntries) {
+ endian::write32<ELFT::Endianness>(buf + 0, entry.entryOffset);
+ buf += 4;
+ }
+
+ // Write the abbrev table.
+ for (const Abbrev *abbrev : mergedAbbrevTable) {
+ buf += encodeULEB128(abbrev->code, buf);
+ buf += encodeULEB128(abbrev->tag, buf);
+ for (DWARFDebugNames::AttributeEncoding attr : abbrev->attributes) {
+ buf += encodeULEB128(attr.Index, buf);
+ buf += encodeULEB128(attr.Form, buf);
+ }
+ endian::write16<ELFT::Endianness>(buf + 0, 0); // attribute sentinels.
+ buf += 2;
+ }
+ *buf++ = 0; // abbrev table sentinel
+
+ // Write the entry pool.
+ for (const auto &stringEntry : mergedEntries) {
+ // Write all the entries for the string.
+ for (const std::unique_ptr<IndexEntry> &entry : stringEntry.indexEntries) {
+ buf += encodeULEB128(entry->abbrevCode, buf);
+ for (const auto &value : entry->attrValues) {
+ endian::write32<ELFT::Endianness>(buf + 0, value.attrValue);
+ buf += value.attrSize;
+ }
+ }
+ *buf++ = 0; // Entry sentinel
+ }
+}
+
+template <class ELFT> bool DebugNamesSection<ELFT>::isNeeded() const {
+ return numChunks > 0;
+}
+
+template <class ELFT>
+static void readCompileUnitOffsets(
+ typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+ typename DebugNamesSection<ELFT>::DebugNamesOutputChunk &outputChunk,
+ DWARFDataExtractor &namesExtractor) {
+ uint64_t offset = secData.locs.CUsBase;
+ uint64_t *offsetPtr = &offset;
+ outputChunk.compilationUnits.resize(secData.hdr.CompUnitCount);
+ uint32_t *bufferPtr =
+ namesExtractor.getU32(offsetPtr, outputChunk.compilationUnits.begin(),
+ secData.hdr.CompUnitCount);
+ if (!bufferPtr)
+ errorOrWarn(toString(outputChunk.sec) +
+ Twine(": error while reading CU offsets"));
+}
+
+template <class ELFT>
+static void readEntryOffsets(
+ typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+ DWARFDataExtractor &namesExtractor) {
+ secData.entryOffsets.resize(secData.hdr.NameCount);
+ uint64_t offset = secData.locs.EntryOffsetsBase;
+ uint64_t *offsetPtr = &offset;
+ uint32_t *bufferPtr = namesExtractor.getU32(
+ offsetPtr, secData.entryOffsets.begin(), secData.hdr.NameCount);
+ if (!bufferPtr)
+ errorOrWarn(Twine(": error while reading entry offsets"));
+}
+
+template <class ELFT>
+static void readAttributeValues(
+ SmallVector<typename DebugNamesSection<ELFT>::AttrValueData, 3> &values,
+ typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
+ uint64_t &offset,
+ typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+ int32_t &parentOffset, DWARFDataExtractor &namesExtractor,
+ const DWARFDebugNames::Abbrev &abbrev) {
+ const LLDDWARFSection &namesSection = *chunk.namesSection;
+ uint64_t *offsetPtr = &offset;
+ typename DebugNamesSection<ELFT>::AttrValueData cuOrTuAttr = {0, 0};
+ for (DWARFDebugNames::AttributeEncoding attr : abbrev.Attributes) {
+ Error err = Error::success();
+ typename DebugNamesSection<ELFT>::AttrValueData newAttr;
+ uint32_t value;
+ if (attr.Index == DW_IDX_parent && attr.Form != DW_FORM_flag_present &&
+ attr.Form != DW_FORM_ref4)
+ errorOrWarn(toString(namesSection.sec) +
+ Twine(": invalid form for DW_IDX_parent"));
+ switch (attr.Form) {
+ case DW_FORM_flag_present: {
+ // Currently only DW_IDX_parent attributes (in .debug_names) can
+ // have this form. This form does not have a real value (nothing is
+ // emitted for it).
+ if (attr.Index != DW_IDX_parent)
+ errorOrWarn(toString(namesSection.sec) +
+ Twine(": invalid form for attribute"));
+ break;
+ }
+ case DW_FORM_data1:
+ case DW_FORM_ref1: {
+ newAttr.attrValue = namesExtractor.getU8(offsetPtr, &err);
+ newAttr.attrSize = 1;
+ break;
+ }
+ case DW_FORM_data2:
+ case DW_FORM_ref2: {
+ value = namesExtractor.getU16(offsetPtr, &err);
+ newAttr.attrValue = value;
+ newAttr.attrSize = 2;
+ break;
+ }
+ case DW_FORM_data4:
+ case DW_FORM_ref4: {
+ value = namesExtractor.getU32(offsetPtr, &err);
+ newAttr.attrValue = value;
+ newAttr.attrSize = 4;
+ if (attr.Index == dwarf::DW_IDX_parent)
+ parentOffset = value + secData.locs.EntriesBase;
+ break;
+ }
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8: {
+ value = namesExtractor.getU64(offsetPtr, &err);
+ newAttr.attrValue = value;
+ newAttr.attrSize = 8;
+ break;
+ }
+ default: {
+ errorOrWarn(toString(namesSection.sec) +
+ Twine(": unrecognized form encoding ") + Twine(attr.Form) +
+ Twine(" in .debug_names abbrev table"));
+ break;
+ }
+ }
+ if (err)
+ errorOrWarn(toString(namesSection.sec) +
+ Twine(": error while reading attributes: ") +
+ toString(std::move(err)));
+ if (attr.Index == DW_IDX_compile_unit)
+ // Save it to put it at the end of the attributes list.
+ cuOrTuAttr = newAttr;
+ else if (attr.Form != DW_FORM_flag_present)
+ values.push_back(newAttr);
+ }
+
+ // Make sure the CU or TU index attribute is the last one in the list.
+ values.push_back(cuOrTuAttr);
+}
+
+template <class ELFT>
+static void
+readEntry(typename DebugNamesSection<ELFT>::NamedEntry &stringEntry,
+ typename DebugNamesSection<ELFT>::DebugNamesInputChunk &chunk,
+ typename DebugNamesSection<ELFT>::DebugNamesSectionData &secData,
+ DWARFDataExtractor &namesExtractor,
+ const DWARFDebugNames::NameIndex &ni) {
+ std::unique_ptr<LLDDWARFSection> &namesSection = chunk.namesSection;
+ uint64_t offset = stringEntry.entryOffset;
+ // Each entry ends with a zero 'sentinel' value
+ while (offset < namesSection->Data.size() &&
+ namesSection->Data[offset] != 0) {
+ // Read & store all entries (for the same string)
+ auto entry =
+ std::make_unique<typename DebugNamesSection<ELFT>::IndexEntry>();
+ entry->poolOffset = offset;
+ Error err = Error::success();
+ // This call to namesExtractor can't fail; if there were a problem with the
----------------
MaskRay wrote:
This is incorrect. `DWARFDebugNames::NameIndex::getEntry` is not called, so `getULEB128` may fail.
I am figuring out a fix in my lld-debug-names branch.
https://github.com/llvm/llvm-project/pull/86508
More information about the llvm-commits
mailing list