[lld] [lld][ELF] Implement merged .debug_names section (PR #88092)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 10 11:17:24 PDT 2024
================
@@ -2711,6 +2714,581 @@ 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;
+}
+
+void DebugNamesBaseSection::parse(
+ InputChunk &inputChunk, OutputChunk &chunk,
+ DWARFDataExtractor &namesExtractor, DataExtractor &strExtractor,
+ function_ref<SmallVector<uint32_t, 0>(
+ const DWARFDebugNames::Header &,
+ const DWARFDebugNames::DWARFDebugNamesOffsets &)>
+ readOffsets) {
+ const LLDDWARFSection namesSec = inputChunk.section;
+ DenseMap<uint32_t, IndexEntry *> offsetMap;
+ SmallVector<uint32_t, 0> entryOffsets;
+ for (const DWARFDebugNames::NameIndex &llvmNi : *inputChunk.llvmDebugNames) {
+ NameIndex &ni = inputChunk.nameIndices.emplace_back();
+ ni.hdr = llvmNi.getHeader();
+ if (ni.hdr.Format != DwarfFormat::DWARF32) {
+ errorOrWarn(toString(namesSec.sec) + Twine(": unsupported DWARF64"));
+ return;
+ }
+ if (ni.hdr.Version != 5) {
+ errorOrWarn(toString(namesSec.sec) + Twine(": unsupported version ") +
+ Twine(ni.hdr.Version));
+ return;
+ }
+ const uint32_t dwarfSize =
+ dwarf::getDwarfOffsetByteSize(DwarfFormat::DWARF32);
+ const uint32_t hdrSize =
+ getDebugNamesHeaderSize(ni.hdr.AugmentationStringSize);
+ auto locs = findDebugNamesOffsets(hdrSize, ni.hdr);
+ if (locs.EntriesBase > namesExtractor.getData().size()) {
+ errorOrWarn(toString(namesSec.sec) +
+ Twine(": index entry is out of bounds"));
+ return;
+ }
+
+ SmallVector<uint32_t, 0> entryOffsets = readOffsets(ni.hdr, locs);
+
+ // Read the entry pool.
+ offsetMap.clear();
+ ni.nameEntries.resize(ni.hdr.NameCount);
+ for (auto i : seq(ni.hdr.NameCount)) {
+ NameTableEntry &nte = ni.nameEntries[i];
+ uint64_t strOffset = locs.StringOffsetsBase + i * dwarfSize;
+ nte.stringOffset = strOffset;
+ uint64_t strp = namesExtractor.getRelocatedValue(dwarfSize, &strOffset);
+ StringRef name = strExtractor.getCStrRef(&strp);
+ nte.name = name.data();
+ nte.hashValue = caseFoldingDjbHash(name);
+
+ // Read a series of index entries that end with abbreviation code 0.
+ const char *errMsg = nullptr;
+ uint64_t off = locs.EntriesBase + entryOffsets[i];
+ while (off < namesSec.Data.size() && namesSec.Data[off] != 0) {
+ auto ie = makeThreadLocal<IndexEntry>();
+ ie->poolOffset = off;
+ Error err = Error::success();
+ ie->abbrevCode =
+ static_cast<uint32_t>(namesExtractor.getULEB128(&off, &err));
+ if (err) {
+ consumeError(std::move(err));
+ errMsg = ": invalid abbrev code in entry";
+ break;
+ }
+ auto it = llvmNi.getAbbrevs().find_as(ie->abbrevCode);
+ if (it == llvmNi.getAbbrevs().end()) {
+ errMsg = ": invalid abbrev code in entry";
+ break;
+ }
+
+ AttrValue attr, cuAttr = {0, 0};
+ for (DWARFDebugNames::AttributeEncoding a : it->Attributes) {
+ if (a.Index == dwarf::DW_IDX_parent) {
+ if (a.Form == dwarf::DW_FORM_ref4) {
+ attr.attrValue = namesExtractor.getU32(&off, &err);
+ attr.attrSize = 4;
+ ie->parentOffset = locs.EntriesBase + attr.attrValue;
+ } else if (a.Form != DW_FORM_flag_present) {
+ errMsg = ": invalid form for DW_IDX_parent";
+ }
+ } else {
+ switch (a.Form) {
+ case DW_FORM_data1:
+ case DW_FORM_ref1: {
+ attr.attrValue = namesExtractor.getU8(&off, &err);
+ attr.attrSize = 1;
+ break;
+ }
+ case DW_FORM_data2:
+ case DW_FORM_ref2: {
+ attr.attrValue = namesExtractor.getU16(&off, &err);
+ attr.attrSize = 2;
+ break;
+ }
+ case DW_FORM_data4:
+ case DW_FORM_ref4: {
+ attr.attrValue = namesExtractor.getU32(&off, &err);
+ attr.attrSize = 4;
+ break;
+ }
+ default:
+ errorOrWarn(toString(namesSec.sec) +
+ Twine(": unrecognized form encoding ") +
+ Twine(a.Form) + Twine(" in abbrev table"));
+ return;
+ }
+ }
+ if (err) {
+ errorOrWarn(toString(namesSec.sec) +
+ Twine(": error while reading attributes: ") +
+ toString(std::move(err)));
+ return;
+ }
+ if (a.Index == DW_IDX_compile_unit)
+ cuAttr = attr;
+ else if (a.Form != DW_FORM_flag_present)
+ ie->attrValues.push_back(attr);
+ }
+
+ // Canonicalize abbrev by placing the CU/TU index at the end.
+ ie->attrValues.push_back(cuAttr);
+ nte.indexEntries.push_back(std::move(ie));
+ }
+ if (off >= namesSec.Data.size())
+ errMsg = ": index entry is out of bounds";
+ if (errMsg)
+ errorOrWarn(toString(namesSec.sec) + Twine(errMsg));
+
+ for (IndexEntry &ie : nte.entries())
+ offsetMap[ie.poolOffset] = &ie;
+ }
+
+ // Assign parent pointers, which will be used to update DW_IDX_parent index
+ // attributes.
+ for (NameTableEntry &nte : ni.nameEntries)
+ for (IndexEntry &ie : nte.entries())
+ ie.parentEntry =
+ ie.parentOffset == 0 ? nullptr : offsetMap.lookup(ie.parentOffset);
+ }
+}
+
+// Compute the form for output DW_IDX_compile_unit attributes similar to
+// DIEInteger::BestForm. The input forms (often DW_FORM_data1) may not hold all
+// CU indices.
+std::pair<uint8_t, dwarf::Form>
+static getMergedCuCountForm(uint32_t compUnitCount) {
+ if (compUnitCount > UINT16_MAX)
+ return {4, DW_FORM_data4};
+ if (compUnitCount > UINT8_MAX)
+ return {2, DW_FORM_data2};
+ return {1, DW_FORM_data1};
+}
+
+void DebugNamesBaseSection::computeHdrAndAbbrevTable(
+ MutableArrayRef<InputChunk> inputChunks) {
+ TimeTraceScope timeScope("Merge .debug_names", "hdr and abbrev table");
+ size_t numCu = 0;
+ hdr.Format = DwarfFormat::DWARF32;
+ hdr.Version = 5;
+ hdr.CompUnitCount = 0;
+ hdr.LocalTypeUnitCount = 0;
+ hdr.ForeignTypeUnitCount = 0;
+ hdr.AugmentationStringSize = 0;
+
+ // Compute CU and TU counts.
+ for (auto i : seq(numChunks)) {
+ InputChunk &inputChunk = inputChunks[i];
+ inputChunk.baseCuIdx = numCu;
+ numCu += chunks[i].compUnits.size();
+ for (const NameIndex &data : inputChunk.nameIndices) {
+ hdr.CompUnitCount += data.hdr.CompUnitCount;
+ hdr.LocalTypeUnitCount += data.hdr.LocalTypeUnitCount;
+ hdr.ForeignTypeUnitCount += data.hdr.ForeignTypeUnitCount;
+ // If augmentation strings are not identical, use an empty string.
+ if (i == 0) {
+ hdr.AugmentationStringSize = data.hdr.AugmentationStringSize;
+ hdr.AugmentationString = data.hdr.AugmentationString;
+ } else if (hdr.AugmentationString != data.hdr.AugmentationString) {
+ hdr.AugmentationStringSize = 0;
+ hdr.AugmentationString.clear();
+ }
+ }
+ }
+
+ // Uniquify input abbrev tables and compute mapping from old abbrev code to
+ // new abbrev code.
+ FoldingSet<Abbrev> abbrevSet;
+ const dwarf::Form cuAttrForm = getMergedCuCountForm(hdr.CompUnitCount).second;
+ for (InputChunk &chunk : inputChunks) {
+ for (auto [i, llvmNi] : enumerate(*chunk.llvmDebugNames)) {
----------------
cmtice wrote:
Is there any way to make this a reference, rather than a copy?
https://github.com/llvm/llvm-project/pull/88092
More information about the llvm-commits
mailing list