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

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 8 14:22: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:
----------------
MaskRay wrote:

We don't handle DWARF64.  I removed this in my branch. The "Write the entry pool" code does not handle big-endian correctly. I will fix this in my branch.

https://github.com/llvm/llvm-project/pull/86508


More information about the llvm-commits mailing list