diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/DWARFLinker/Parallel/OutputSections.cpp | 523 |
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); + }); +} |