aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.cpp523
1 files changed, 523 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.cpp b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.cpp
new file mode 100644
index 000000000000..cd1205b60f85
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.cpp
@@ -0,0 +1,523 @@
+//=== OutputSections.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "OutputSections.h"
+#include "DWARFLinkerCompileUnit.h"
+#include "DWARFLinkerTypeUnit.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace llvm;
+using namespace dwarf_linker;
+using namespace dwarf_linker::parallel;
+
+std::optional<DebugSectionKind>
+dwarf_linker::parallel::parseDebugTableName(llvm::StringRef SecName) {
+ return llvm::StringSwitch<std::optional<DebugSectionKind>>(
+ SecName.substr(SecName.find_first_not_of("._")))
+ .Case(getSectionName(DebugSectionKind::DebugInfo),
+ DebugSectionKind::DebugInfo)
+ .Case(getSectionName(DebugSectionKind::DebugLine),
+ DebugSectionKind::DebugLine)
+ .Case(getSectionName(DebugSectionKind::DebugFrame),
+ DebugSectionKind::DebugFrame)
+ .Case(getSectionName(DebugSectionKind::DebugRange),
+ DebugSectionKind::DebugRange)
+ .Case(getSectionName(DebugSectionKind::DebugRngLists),
+ DebugSectionKind::DebugRngLists)
+ .Case(getSectionName(DebugSectionKind::DebugLoc),
+ DebugSectionKind::DebugLoc)
+ .Case(getSectionName(DebugSectionKind::DebugLocLists),
+ DebugSectionKind::DebugLocLists)
+ .Case(getSectionName(DebugSectionKind::DebugARanges),
+ DebugSectionKind::DebugARanges)
+ .Case(getSectionName(DebugSectionKind::DebugAbbrev),
+ DebugSectionKind::DebugAbbrev)
+ .Case(getSectionName(DebugSectionKind::DebugMacinfo),
+ DebugSectionKind::DebugMacinfo)
+ .Case(getSectionName(DebugSectionKind::DebugMacro),
+ DebugSectionKind::DebugMacro)
+ .Case(getSectionName(DebugSectionKind::DebugAddr),
+ DebugSectionKind::DebugAddr)
+ .Case(getSectionName(DebugSectionKind::DebugStr),
+ DebugSectionKind::DebugStr)
+ .Case(getSectionName(DebugSectionKind::DebugLineStr),
+ DebugSectionKind::DebugLineStr)
+ .Case(getSectionName(DebugSectionKind::DebugStrOffsets),
+ DebugSectionKind::DebugStrOffsets)
+ .Case(getSectionName(DebugSectionKind::DebugPubNames),
+ DebugSectionKind::DebugPubNames)
+ .Case(getSectionName(DebugSectionKind::DebugPubTypes),
+ DebugSectionKind::DebugPubTypes)
+ .Case(getSectionName(DebugSectionKind::DebugNames),
+ DebugSectionKind::DebugNames)
+ .Case(getSectionName(DebugSectionKind::AppleNames),
+ DebugSectionKind::AppleNames)
+ .Case(getSectionName(DebugSectionKind::AppleNamespaces),
+ DebugSectionKind::AppleNamespaces)
+ .Case(getSectionName(DebugSectionKind::AppleObjC),
+ DebugSectionKind::AppleObjC)
+ .Case(getSectionName(DebugSectionKind::AppleTypes),
+ DebugSectionKind::AppleTypes)
+ .Default(std::nullopt);
+
+ return std::nullopt;
+}
+
+DebugDieRefPatch::DebugDieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU,
+ CompileUnit *RefCU, uint32_t RefIdx)
+ : SectionPatch({PatchOffset}),
+ RefCU(RefCU, (SrcCU != nullptr) &&
+ (SrcCU->getUniqueID() == RefCU->getUniqueID())),
+ RefDieIdxOrClonedOffset(RefIdx) {}
+
+DebugULEB128DieRefPatch::DebugULEB128DieRefPatch(uint64_t PatchOffset,
+ CompileUnit *SrcCU,
+ CompileUnit *RefCU,
+ uint32_t RefIdx)
+ : SectionPatch({PatchOffset}),
+ RefCU(RefCU, SrcCU->getUniqueID() == RefCU->getUniqueID()),
+ RefDieIdxOrClonedOffset(RefIdx) {}
+
+DebugDieTypeRefPatch::DebugDieTypeRefPatch(uint64_t PatchOffset,
+ TypeEntry *RefTypeName)
+ : SectionPatch({PatchOffset}), RefTypeName(RefTypeName) {}
+
+DebugType2TypeDieRefPatch::DebugType2TypeDieRefPatch(uint64_t PatchOffset,
+ DIE *Die,
+ TypeEntry *TypeName,
+ TypeEntry *RefTypeName)
+ : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+ RefTypeName(RefTypeName) {}
+
+DebugTypeStrPatch::DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die,
+ TypeEntry *TypeName, StringEntry *String)
+ : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+ String(String) {}
+
+DebugTypeLineStrPatch::DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die,
+ TypeEntry *TypeName,
+ StringEntry *String)
+ : SectionPatch({PatchOffset}), Die(Die), TypeName(TypeName),
+ String(String) {}
+
+DebugTypeDeclFilePatch::DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName,
+ StringEntry *Directory,
+ StringEntry *FilePath)
+ : Die(Die), TypeName(TypeName), Directory(Directory), FilePath(FilePath) {}
+
+void SectionDescriptor::clearAllSectionData() {
+ StartOffset = 0;
+ clearSectionContent();
+ ListDebugStrPatch.erase();
+ ListDebugLineStrPatch.erase();
+ ListDebugRangePatch.erase();
+ ListDebugLocPatch.erase();
+ ListDebugDieRefPatch.erase();
+ ListDebugULEB128DieRefPatch.erase();
+ ListDebugOffsetPatch.erase();
+ ListDebugType2TypeDieRefPatch.erase();
+ ListDebugTypeDeclFilePatch.erase();
+ ListDebugTypeLineStrPatch.erase();
+ ListDebugTypeStrPatch.erase();
+}
+
+void SectionDescriptor::clearSectionContent() { Contents = OutSectionDataTy(); }
+
+void SectionDescriptor::setSizesForSectionCreatedByAsmPrinter() {
+ if (Contents.empty())
+ return;
+
+ MemoryBufferRef Mem(Contents, "obj");
+ Expected<std::unique_ptr<object::ObjectFile>> Obj =
+ object::ObjectFile::createObjectFile(Mem);
+ if (!Obj) {
+ consumeError(Obj.takeError());
+ Contents.clear();
+ return;
+ }
+
+ for (const object::SectionRef &Sect : (*Obj).get()->sections()) {
+ Expected<StringRef> SectNameOrErr = Sect.getName();
+ if (!SectNameOrErr) {
+ consumeError(SectNameOrErr.takeError());
+ continue;
+ }
+ if (std::optional<DebugSectionKind> SectKind =
+ parseDebugTableName(*SectNameOrErr)) {
+ if (*SectKind == SectionKind) {
+ Expected<StringRef> Data = Sect.getContents();
+ if (!Data) {
+ consumeError(SectNameOrErr.takeError());
+ Contents.clear();
+ return;
+ }
+
+ SectionOffsetInsideAsmPrinterOutputStart =
+ Data->data() - Contents.data();
+ SectionOffsetInsideAsmPrinterOutputEnd =
+ SectionOffsetInsideAsmPrinterOutputStart + Data->size();
+ }
+ }
+ }
+}
+
+void SectionDescriptor::emitString(dwarf::Form StringForm,
+ const char *StringVal) {
+ assert(StringVal != nullptr);
+
+ switch (StringForm) {
+ case dwarf::DW_FORM_string: {
+ emitInplaceString(StringVal);
+ } break;
+ case dwarf::DW_FORM_strp: {
+ notePatch(DebugStrPatch{
+ {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
+ emitStringPlaceholder();
+ } break;
+ case dwarf::DW_FORM_line_strp: {
+ notePatch(DebugLineStrPatch{
+ {OS.tell()}, GlobalData.getStringPool().insert(StringVal).first});
+ emitStringPlaceholder();
+ } break;
+ default:
+ llvm_unreachable("Unsupported string form");
+ break;
+ };
+}
+
+void SectionDescriptor::emitIntVal(uint64_t Val, unsigned Size) {
+ switch (Size) {
+ case 1: {
+ OS.write(static_cast<uint8_t>(Val));
+ } break;
+ case 2: {
+ uint16_t ShortVal = static_cast<uint16_t>(Val);
+ if (Endianess != llvm::endianness::native)
+ sys::swapByteOrder(ShortVal);
+ OS.write(reinterpret_cast<const char *>(&ShortVal), Size);
+ } break;
+ case 4: {
+ uint32_t ShortVal = static_cast<uint32_t>(Val);
+ if (Endianess != llvm::endianness::native)
+ sys::swapByteOrder(ShortVal);
+ OS.write(reinterpret_cast<const char *>(&ShortVal), Size);
+ } break;
+ case 8: {
+ if (Endianess != llvm::endianness::native)
+ sys::swapByteOrder(Val);
+ OS.write(reinterpret_cast<const char *>(&Val), Size);
+ } break;
+ default:
+ llvm_unreachable("Unsupported integer type size");
+ }
+}
+
+void SectionDescriptor::emitBinaryData(llvm::StringRef Data) {
+ OS.write(Data.data(), Data.size());
+}
+
+void SectionDescriptor::apply(uint64_t PatchOffset, dwarf::Form AttrForm,
+ uint64_t Val) {
+ switch (AttrForm) {
+ case dwarf::DW_FORM_strp:
+ case dwarf::DW_FORM_line_strp: {
+ applyIntVal(PatchOffset, Val, Format.getDwarfOffsetByteSize());
+ } break;
+
+ case dwarf::DW_FORM_ref_addr: {
+ applyIntVal(PatchOffset, Val, Format.getRefAddrByteSize());
+ } break;
+ case dwarf::DW_FORM_ref1: {
+ applyIntVal(PatchOffset, Val, 1);
+ } break;
+ case dwarf::DW_FORM_ref2: {
+ applyIntVal(PatchOffset, Val, 2);
+ } break;
+ case dwarf::DW_FORM_ref4: {
+ applyIntVal(PatchOffset, Val, 4);
+ } break;
+ case dwarf::DW_FORM_ref8: {
+ applyIntVal(PatchOffset, Val, 8);
+ } break;
+
+ case dwarf::DW_FORM_data1: {
+ applyIntVal(PatchOffset, Val, 1);
+ } break;
+ case dwarf::DW_FORM_data2: {
+ applyIntVal(PatchOffset, Val, 2);
+ } break;
+ case dwarf::DW_FORM_data4: {
+ applyIntVal(PatchOffset, Val, 4);
+ } break;
+ case dwarf::DW_FORM_data8: {
+ applyIntVal(PatchOffset, Val, 8);
+ } break;
+ case dwarf::DW_FORM_udata: {
+ applyULEB128(PatchOffset, Val);
+ } break;
+ case dwarf::DW_FORM_sdata: {
+ applySLEB128(PatchOffset, Val);
+ } break;
+ case dwarf::DW_FORM_sec_offset: {
+ applyIntVal(PatchOffset, Val, Format.getDwarfOffsetByteSize());
+ } break;
+ case dwarf::DW_FORM_flag: {
+ applyIntVal(PatchOffset, Val, 1);
+ } break;
+
+ default:
+ llvm_unreachable("Unsupported attribute form");
+ break;
+ }
+}
+
+uint64_t SectionDescriptor::getIntVal(uint64_t PatchOffset, unsigned Size) {
+ assert(PatchOffset < getContents().size());
+ switch (Size) {
+ case 1: {
+ return *reinterpret_cast<const uint8_t *>(
+ (getContents().data() + PatchOffset));
+ }
+ case 2: {
+ return support::endian::read16(getContents().data() + PatchOffset,
+ Endianess);
+ }
+ case 4: {
+ return support::endian::read32(getContents().data() + PatchOffset,
+ Endianess);
+ }
+ case 8: {
+ return support::endian::read64(getContents().data() + PatchOffset,
+ Endianess);
+ }
+ }
+ llvm_unreachable("Unsupported integer type size");
+ return 0;
+}
+
+void SectionDescriptor::applyIntVal(uint64_t PatchOffset, uint64_t Val,
+ unsigned Size) {
+ assert(PatchOffset < getContents().size());
+
+ switch (Size) {
+ case 1: {
+ support::endian::write(
+ const_cast<char *>(getContents().data() + PatchOffset),
+ static_cast<uint8_t>(Val), Endianess);
+ } break;
+ case 2: {
+ support::endian::write(
+ const_cast<char *>(getContents().data() + PatchOffset),
+ static_cast<uint16_t>(Val), Endianess);
+ } break;
+ case 4: {
+ support::endian::write(
+ const_cast<char *>(getContents().data() + PatchOffset),
+ static_cast<uint32_t>(Val), Endianess);
+ } break;
+ case 8: {
+ support::endian::write(
+ const_cast<char *>(getContents().data() + PatchOffset),
+ static_cast<uint64_t>(Val), Endianess);
+ } break;
+ default:
+ llvm_unreachable("Unsupported integer type size");
+ }
+}
+
+void SectionDescriptor::applyULEB128(uint64_t PatchOffset, uint64_t Val) {
+ assert(PatchOffset < getContents().size());
+
+ uint8_t ULEB[16];
+ uint8_t DestSize = Format.getDwarfOffsetByteSize() + 1;
+ uint8_t RealSize = encodeULEB128(Val, ULEB, DestSize);
+
+ memcpy(const_cast<char *>(getContents().data() + PatchOffset), ULEB,
+ RealSize);
+}
+
+/// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset.
+void SectionDescriptor::applySLEB128(uint64_t PatchOffset, uint64_t Val) {
+ assert(PatchOffset < getContents().size());
+
+ uint8_t SLEB[16];
+ uint8_t DestSize = Format.getDwarfOffsetByteSize() + 1;
+ uint8_t RealSize = encodeSLEB128(Val, SLEB, DestSize);
+
+ memcpy(const_cast<char *>(getContents().data() + PatchOffset), SLEB,
+ RealSize);
+}
+
+void OutputSections::applyPatches(
+ SectionDescriptor &Section,
+ StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,
+ StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,
+ TypeUnit *TypeUnitPtr) {
+ Section.ListDebugStrPatch.forEach([&](DebugStrPatch &Patch) {
+ DwarfStringPoolEntryWithExtString *Entry =
+ DebugStrStrings.getExistingEntry(Patch.String);
+ assert(Entry != nullptr);
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset);
+ });
+ Section.ListDebugTypeStrPatch.forEach([&](DebugTypeStrPatch &Patch) {
+ assert(TypeUnitPtr != nullptr);
+ TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.TypeName->getKey())
+ .str()
+ .c_str());
+
+ if (&TypeEntry->getFinalDie() != Patch.Die)
+ return;
+
+ DwarfStringPoolEntryWithExtString *Entry =
+ DebugStrStrings.getExistingEntry(Patch.String);
+ assert(Entry != nullptr);
+
+ Patch.PatchOffset +=
+ Patch.Die->getOffset() + getULEB128Size(Patch.Die->getAbbrevNumber());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_strp, Entry->Offset);
+ });
+
+ Section.ListDebugLineStrPatch.forEach([&](DebugLineStrPatch &Patch) {
+ DwarfStringPoolEntryWithExtString *Entry =
+ DebugLineStrStrings.getExistingEntry(Patch.String);
+ assert(Entry != nullptr);
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset);
+ });
+ Section.ListDebugTypeLineStrPatch.forEach([&](DebugTypeLineStrPatch &Patch) {
+ assert(TypeUnitPtr != nullptr);
+ TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.TypeName->getKey())
+ .str()
+ .c_str());
+
+ if (&TypeEntry->getFinalDie() != Patch.Die)
+ return;
+
+ DwarfStringPoolEntryWithExtString *Entry =
+ DebugLineStrStrings.getExistingEntry(Patch.String);
+ assert(Entry != nullptr);
+
+ Patch.PatchOffset +=
+ Patch.Die->getOffset() + getULEB128Size(Patch.Die->getAbbrevNumber());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_line_strp, Entry->Offset);
+ });
+
+ std::optional<SectionDescriptor *> RangeSection;
+ if (Format.Version >= 5)
+ RangeSection = tryGetSectionDescriptor(DebugSectionKind::DebugRngLists);
+ else
+ RangeSection = tryGetSectionDescriptor(DebugSectionKind::DebugRange);
+
+ if (RangeSection) {
+ Section.ListDebugRangePatch.forEach([&](DebugRangePatch &Patch) {
+ uint64_t FinalValue =
+ Section.getIntVal(Patch.PatchOffset, Format.getDwarfOffsetByteSize());
+ FinalValue += (*RangeSection)->StartOffset;
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_sec_offset, FinalValue);
+ });
+ }
+
+ std::optional<SectionDescriptor *> LocationSection;
+ if (Format.Version >= 5)
+ LocationSection = tryGetSectionDescriptor(DebugSectionKind::DebugLocLists);
+ else
+ LocationSection = tryGetSectionDescriptor(DebugSectionKind::DebugLoc);
+
+ if (LocationSection) {
+ Section.ListDebugLocPatch.forEach([&](DebugLocPatch &Patch) {
+ uint64_t FinalValue =
+ Section.getIntVal(Patch.PatchOffset, Format.getDwarfOffsetByteSize());
+ FinalValue += (*LocationSection)->StartOffset;
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_sec_offset, FinalValue);
+ });
+ }
+
+ Section.ListDebugDieRefPatch.forEach([&](DebugDieRefPatch &Patch) {
+ uint64_t FinalOffset = Patch.RefDieIdxOrClonedOffset;
+ dwarf::Form FinalForm = dwarf::DW_FORM_ref4;
+
+ // Check whether it is local or inter-CU reference.
+ if (!Patch.RefCU.getInt()) {
+ SectionDescriptor &ReferencedSectionDescriptor =
+ Patch.RefCU.getPointer()->getSectionDescriptor(
+ DebugSectionKind::DebugInfo);
+
+ FinalForm = dwarf::DW_FORM_ref_addr;
+ FinalOffset += ReferencedSectionDescriptor.StartOffset;
+ }
+
+ Section.apply(Patch.PatchOffset, FinalForm, FinalOffset);
+ });
+
+ Section.ListDebugULEB128DieRefPatch.forEach(
+ [&](DebugULEB128DieRefPatch &Patch) {
+ assert(Patch.RefCU.getInt());
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_udata,
+ Patch.RefDieIdxOrClonedOffset);
+ });
+
+ Section.ListDebugDieTypeRefPatch.forEach([&](DebugDieTypeRefPatch &Patch) {
+ assert(TypeUnitPtr != nullptr);
+ assert(Patch.RefTypeName != nullptr);
+
+ TypeEntryBody *TypeEntry = Patch.RefTypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.RefTypeName->getKey())
+ .str()
+ .c_str());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_ref_addr,
+ TypeEntry->getFinalDie().getOffset());
+ });
+
+ Section.ListDebugType2TypeDieRefPatch.forEach(
+ [&](DebugType2TypeDieRefPatch &Patch) {
+ assert(TypeUnitPtr != nullptr);
+ TypeEntryBody *TypeEntry = Patch.TypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.TypeName->getKey())
+ .str()
+ .c_str());
+
+ if (&TypeEntry->getFinalDie() != Patch.Die)
+ return;
+
+ Patch.PatchOffset += Patch.Die->getOffset() +
+ getULEB128Size(Patch.Die->getAbbrevNumber());
+
+ assert(Patch.RefTypeName != nullptr);
+ TypeEntryBody *RefTypeEntry = Patch.RefTypeName->getValue().load();
+ assert(TypeEntry &&
+ formatv("No data for type {0}", Patch.RefTypeName->getKey())
+ .str()
+ .c_str());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_ref4,
+ RefTypeEntry->getFinalDie().getOffset());
+ });
+
+ Section.ListDebugOffsetPatch.forEach([&](DebugOffsetPatch &Patch) {
+ uint64_t FinalValue = Patch.SectionPtr.getPointer()->StartOffset;
+
+ // Check whether we need to read value from the original location.
+ if (Patch.SectionPtr.getInt())
+ FinalValue +=
+ Section.getIntVal(Patch.PatchOffset, Format.getDwarfOffsetByteSize());
+
+ Section.apply(Patch.PatchOffset, dwarf::DW_FORM_sec_offset, FinalValue);
+ });
+}