//=== 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; 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> Obj = object::ObjectFile::createObjectFile(Mem); if (!Obj) { consumeError(Obj.takeError()); Contents.clear(); return; } for (const object::SectionRef &Sect : (*Obj).get()->sections()) { Expected SectNameOrErr = Sect.getName(); if (!SectNameOrErr) { consumeError(SectNameOrErr.takeError()); continue; } if (std::optional SectKind = parseDebugTableName(*SectNameOrErr)) { if (*SectKind == SectionKind) { Expected 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(Val)); } break; case 2: { uint16_t ShortVal = static_cast(Val); if (Endianess != llvm::endianness::native) sys::swapByteOrder(ShortVal); OS.write(reinterpret_cast(&ShortVal), Size); } break; case 4: { uint32_t ShortVal = static_cast(Val); if (Endianess != llvm::endianness::native) sys::swapByteOrder(ShortVal); OS.write(reinterpret_cast(&ShortVal), Size); } break; case 8: { if (Endianess != llvm::endianness::native) sys::swapByteOrder(Val); OS.write(reinterpret_cast(&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( (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(getContents().data() + PatchOffset), static_cast(Val), Endianess); } break; case 2: { support::endian::write( const_cast(getContents().data() + PatchOffset), static_cast(Val), Endianess); } break; case 4: { support::endian::write( const_cast(getContents().data() + PatchOffset), static_cast(Val), Endianess); } break; case 8: { support::endian::write( const_cast(getContents().data() + PatchOffset), static_cast(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(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(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 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 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); }); }