diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinkerParallel/OutputSections.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/DWARFLinkerParallel/OutputSections.cpp | 526 |
1 files changed, 511 insertions, 15 deletions
diff --git a/contrib/llvm-project/llvm/lib/DWARFLinkerParallel/OutputSections.cpp b/contrib/llvm-project/llvm/lib/DWARFLinkerParallel/OutputSections.cpp index 69c5bfaa7bdf..9c3e3ebd220a 100644 --- a/contrib/llvm-project/llvm/lib/DWARFLinkerParallel/OutputSections.cpp +++ b/contrib/llvm-project/llvm/lib/DWARFLinkerParallel/OutputSections.cpp @@ -7,30 +7,526 @@ //===----------------------------------------------------------------------===// #include "OutputSections.h" +#include "DWARFLinkerCompileUnit.h" +#include "DWARFLinkerTypeUnit.h" #include "llvm/ADT/StringSwitch.h" namespace llvm { namespace dwarflinker_parallel { -std::optional<OutputSections::DebugSectionKind> -OutputSections::parseDebugSectionName(llvm::StringRef SecName) { - return llvm::StringSwitch<std::optional<OutputSections::DebugSectionKind>>( - SecName) - .Case("debug_info", DebugSectionKind::DebugInfo) - .Case("debug_line", DebugSectionKind::DebugLine) - .Case("debug_frame", DebugSectionKind::DebugFrame) - .Case("debug_ranges", DebugSectionKind::DebugRange) - .Case("debug_rnglists", DebugSectionKind::DebugRngLists) - .Case("debug_loc", DebugSectionKind::DebugLoc) - .Case("debug_loclists", DebugSectionKind::DebugLocLists) - .Case("debug_aranges", DebugSectionKind::DebugARanges) - .Case("debug_abbrev", DebugSectionKind::DebugAbbrev) - .Case("debug_macinfo", DebugSectionKind::DebugMacinfo) - .Case("debug_macro", DebugSectionKind::DebugMacro) +static constexpr StringLiteral SectionNames[SectionKindsNum] = { + "debug_info", "debug_line", "debug_frame", "debug_ranges", + "debug_rnglists", "debug_loc", "debug_loclists", "debug_aranges", + "debug_abbrev", "debug_macinfo", "debug_macro", "debug_addr", + "debug_str", "debug_line_str", "debug_str_offsets", "debug_pubnames", + "debug_pubtypes", "debug_names", "apple_names", "apple_namespac", + "apple_objc", "apple_types"}; + +const StringLiteral &getSectionName(DebugSectionKind SectionKind) { + return SectionNames[static_cast<uint8_t>(SectionKind)]; +} + +std::optional<DebugSectionKind> 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::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); + }); +} + } // end of namespace dwarflinker_parallel } // end of namespace llvm |
