472 lines · c
1//===- OutputSections.h -----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H10#define LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H11 12#include "ArrayList.h"13#include "StringEntryToDwarfStringPoolEntryMap.h"14#include "llvm/ADT/SmallString.h"15#include "llvm/ADT/StringRef.h"16#include "llvm/BinaryFormat/Dwarf.h"17#include "llvm/CodeGen/DwarfStringPoolEntry.h"18#include "llvm/DWARFLinker/StringPool.h"19#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"20#include "llvm/DebugInfo/DWARF/DWARFObject.h"21#include "llvm/Object/ObjectFile.h"22#include "llvm/Support/Endian.h"23#include "llvm/Support/Error.h"24#include "llvm/Support/FormatVariadic.h"25#include "llvm/Support/LEB128.h"26#include "llvm/Support/MemoryBufferRef.h"27#include "llvm/Support/raw_ostream.h"28#include <array>29#include <cstdint>30 31namespace llvm {32namespace dwarf_linker {33namespace parallel {34 35class TypeUnit;36 37/// There are fields(sizes, offsets) which should be updated after38/// sections are generated. To remember offsets and related data39/// the descendants of SectionPatch structure should be used.40 41struct SectionPatch {42 uint64_t PatchOffset = 0;43};44 45/// This structure is used to update strings offsets into .debug_str.46struct DebugStrPatch : SectionPatch {47 const StringEntry *String = nullptr;48};49 50/// This structure is used to update strings offsets into .debug_line_str.51struct DebugLineStrPatch : SectionPatch {52 const StringEntry *String = nullptr;53};54 55/// This structure is used to update range list offset into56/// .debug_ranges/.debug_rnglists.57struct DebugRangePatch : SectionPatch {58 /// Indicates patch which points to immediate compile unit's attribute.59 bool IsCompileUnitRanges = false;60};61 62/// This structure is used to update location list offset into63/// .debug_loc/.debug_loclists.64struct DebugLocPatch : SectionPatch {65 int64_t AddrAdjustmentValue = 0;66};67 68/// This structure is used to update offset with start of another section.69struct SectionDescriptor;70struct DebugOffsetPatch : SectionPatch {71 DebugOffsetPatch(uint64_t PatchOffset, SectionDescriptor *SectionPtr,72 bool AddLocalValue = false)73 : SectionPatch({PatchOffset}), SectionPtr(SectionPtr, AddLocalValue) {}74 75 PointerIntPair<SectionDescriptor *, 1> SectionPtr;76};77 78/// This structure is used to update reference to the DIE.79struct DebugDieRefPatch : SectionPatch {80 DebugDieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU, CompileUnit *RefCU,81 uint32_t RefIdx);82 83 PointerIntPair<CompileUnit *, 1> RefCU;84 uint64_t RefDieIdxOrClonedOffset = 0;85};86 87/// This structure is used to update reference to the DIE of ULEB128 form.88struct DebugULEB128DieRefPatch : SectionPatch {89 DebugULEB128DieRefPatch(uint64_t PatchOffset, CompileUnit *SrcCU,90 CompileUnit *RefCU, uint32_t RefIdx);91 92 PointerIntPair<CompileUnit *, 1> RefCU;93 uint64_t RefDieIdxOrClonedOffset = 0;94};95 96/// This structure is used to update reference to the type DIE.97struct DebugDieTypeRefPatch : SectionPatch {98 DebugDieTypeRefPatch(uint64_t PatchOffset, TypeEntry *RefTypeName);99 100 TypeEntry *RefTypeName = nullptr;101};102 103/// This structure is used to update reference to the type DIE.104struct DebugType2TypeDieRefPatch : SectionPatch {105 DebugType2TypeDieRefPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,106 TypeEntry *RefTypeName);107 108 DIE *Die = nullptr;109 TypeEntry *TypeName = nullptr;110 TypeEntry *RefTypeName = nullptr;111};112 113struct DebugTypeStrPatch : SectionPatch {114 DebugTypeStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,115 StringEntry *String);116 117 DIE *Die = nullptr;118 TypeEntry *TypeName = nullptr;119 StringEntry *String = nullptr;120};121 122struct DebugTypeLineStrPatch : SectionPatch {123 DebugTypeLineStrPatch(uint64_t PatchOffset, DIE *Die, TypeEntry *TypeName,124 StringEntry *String);125 126 DIE *Die = nullptr;127 TypeEntry *TypeName = nullptr;128 StringEntry *String = nullptr;129};130 131struct DebugTypeDeclFilePatch {132 DebugTypeDeclFilePatch(DIE *Die, TypeEntry *TypeName, StringEntry *Directory,133 StringEntry *FilePath);134 135 DIE *Die = nullptr;136 TypeEntry *TypeName = nullptr;137 StringEntry *Directory = nullptr;138 StringEntry *FilePath = nullptr;139 uint32_t FileID = 0;140};141 142/// Type for section data.143using OutSectionDataTy = SmallString<0>;144 145/// Type for list of pointers to patches offsets.146using OffsetsPtrVector = SmallVector<uint64_t *>;147 148class OutputSections;149 150/// This structure is used to keep data of the concrete section.151/// Like data bits, list of patches, format.152struct SectionDescriptor : SectionDescriptorBase {153 friend OutputSections;154 155 SectionDescriptor(DebugSectionKind SectionKind, LinkingGlobalData &GlobalData,156 dwarf::FormParams Format, llvm::endianness Endianess)157 : SectionDescriptorBase(SectionKind, Format, Endianess), OS(Contents),158 ListDebugStrPatch(&GlobalData.getAllocator()),159 ListDebugLineStrPatch(&GlobalData.getAllocator()),160 ListDebugRangePatch(&GlobalData.getAllocator()),161 ListDebugLocPatch(&GlobalData.getAllocator()),162 ListDebugDieRefPatch(&GlobalData.getAllocator()),163 ListDebugULEB128DieRefPatch(&GlobalData.getAllocator()),164 ListDebugOffsetPatch(&GlobalData.getAllocator()),165 ListDebugDieTypeRefPatch(&GlobalData.getAllocator()),166 ListDebugType2TypeDieRefPatch(&GlobalData.getAllocator()),167 ListDebugTypeStrPatch(&GlobalData.getAllocator()),168 ListDebugTypeLineStrPatch(&GlobalData.getAllocator()),169 ListDebugTypeDeclFilePatch(&GlobalData.getAllocator()),170 GlobalData(GlobalData) {}171 172 /// Erase whole section content(data bits, list of patches).173 void clearAllSectionData();174 175 /// Erase only section output data bits.176 void clearSectionContent();177 178 /// When objects(f.e. compile units) are glued into the single file,179 /// the debug sections corresponding to the concrete object are assigned180 /// with offsets inside the whole file. This field keeps offset181 /// to the debug section, corresponding to this object.182 uint64_t StartOffset = 0;183 184protected:185 /// Section data bits.186 OutSectionDataTy Contents;187 188public:189 /// Stream which stores data to the Contents.190 raw_svector_ostream OS;191 192 /// Section patches.193#define ADD_PATCHES_LIST(T) \194 T ¬ePatch(const T &Patch) { return List##T.add(Patch); } \195 ArrayList<T> List##T;196 197 ADD_PATCHES_LIST(DebugStrPatch)198 ADD_PATCHES_LIST(DebugLineStrPatch)199 ADD_PATCHES_LIST(DebugRangePatch)200 ADD_PATCHES_LIST(DebugLocPatch)201 ADD_PATCHES_LIST(DebugDieRefPatch)202 ADD_PATCHES_LIST(DebugULEB128DieRefPatch)203 ADD_PATCHES_LIST(DebugOffsetPatch)204 ADD_PATCHES_LIST(DebugDieTypeRefPatch)205 ADD_PATCHES_LIST(DebugType2TypeDieRefPatch)206 ADD_PATCHES_LIST(DebugTypeStrPatch)207 ADD_PATCHES_LIST(DebugTypeLineStrPatch)208 ADD_PATCHES_LIST(DebugTypeDeclFilePatch)209 210 /// While creating patches, offsets to attributes may be partially211 /// unknown(because size of abbreviation number is unknown). In such case we212 /// remember patch itself and pointer to patch application offset to add size213 /// of abbreviation number later.214 template <typename T>215 void notePatchWithOffsetUpdate(const T &Patch,216 OffsetsPtrVector &PatchesOffsetsList) {217 PatchesOffsetsList.emplace_back(¬ePatch(Patch).PatchOffset);218 }219 220 /// Some sections are emitted using AsmPrinter. In that case "Contents"221 /// member of SectionDescriptor contains elf file. This method searches222 /// for section data inside elf file and remember offset to it.223 void setSizesForSectionCreatedByAsmPrinter();224 225 /// Returns section content.226 StringRef getContents() override {227 if (SectionOffsetInsideAsmPrinterOutputStart == 0)228 return Contents;229 230 return Contents.slice(SectionOffsetInsideAsmPrinterOutputStart,231 SectionOffsetInsideAsmPrinterOutputEnd);232 }233 234 /// Emit unit length into the current section contents.235 void emitUnitLength(uint64_t Length) {236 maybeEmitDwarf64Mark();237 emitIntVal(Length, getFormParams().getDwarfOffsetByteSize());238 }239 240 /// Emit DWARF64 mark into the current section contents.241 void maybeEmitDwarf64Mark() {242 if (getFormParams().Format != dwarf::DWARF64)243 return;244 emitIntVal(dwarf::DW_LENGTH_DWARF64, 4);245 }246 247 /// Emit specified offset value into the current section contents.248 void emitOffset(uint64_t Val) {249 emitIntVal(Val, getFormParams().getDwarfOffsetByteSize());250 }251 252 /// Emit specified integer value into the current section contents.253 void emitIntVal(uint64_t Val, unsigned Size);254 255 void emitString(dwarf::Form StringForm, const char *StringVal);256 257 void emitBinaryData(llvm::StringRef Data);258 259 /// Emit specified inplace string value into the current section contents.260 void emitInplaceString(StringRef String) {261 OS << String;262 emitIntVal(0, 1);263 }264 265 /// Emit string placeholder into the current section contents.266 void emitStringPlaceholder() {267 // emit bad offset which should be updated later.268 emitOffset(0xBADDEF);269 }270 271 /// Write specified \p Value of \p AttrForm to the \p PatchOffset.272 void apply(uint64_t PatchOffset, dwarf::Form AttrForm, uint64_t Val);273 274 /// Returns integer value of \p Size located by specified \p PatchOffset.275 uint64_t getIntVal(uint64_t PatchOffset, unsigned Size);276 277protected:278 /// Writes integer value \p Val of \p Size by specified \p PatchOffset.279 void applyIntVal(uint64_t PatchOffset, uint64_t Val, unsigned Size);280 281 /// Writes integer value \p Val of ULEB128 format by specified \p PatchOffset.282 void applyULEB128(uint64_t PatchOffset, uint64_t Val);283 284 /// Writes integer value \p Val of SLEB128 format by specified \p PatchOffset.285 void applySLEB128(uint64_t PatchOffset, uint64_t Val);286 287 /// Sets output format.288 void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianess) {289 this->Format = Format;290 this->Endianess = Endianess;291 }292 293 LinkingGlobalData &GlobalData;294 295 /// Some sections are generated using AsmPrinter. The real section data296 /// located inside elf file in that case. Following fields points to the297 /// real section content inside elf file.298 size_t SectionOffsetInsideAsmPrinterOutputStart = 0;299 size_t SectionOffsetInsideAsmPrinterOutputEnd = 0;300};301 302/// This class keeps contents and offsets to the debug sections. Any objects303/// which is supposed to be emitted into the debug sections should use this304/// class to track debug sections offsets and keep sections data.305class OutputSections {306public:307 OutputSections(LinkingGlobalData &GlobalData) : GlobalData(GlobalData) {}308 309 /// Sets output format for all keeping sections.310 void setOutputFormat(dwarf::FormParams Format, llvm::endianness Endianness) {311 this->Format = Format;312 this->Endianness = Endianness;313 }314 315 /// Returns descriptor for the specified section of \p SectionKind.316 /// The descriptor should already be created. The llvm_unreachable317 /// would be raised if it is not.318 const SectionDescriptor &319 getSectionDescriptor(DebugSectionKind SectionKind) const {320 SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);321 322 if (It == SectionDescriptors.end())323 llvm_unreachable(324 formatv("Section {0} does not exist", getSectionName(SectionKind))325 .str()326 .c_str());327 328 return *It->second;329 }330 331 /// Returns descriptor for the specified section of \p SectionKind.332 /// The descriptor should already be created. The llvm_unreachable333 /// would be raised if it is not.334 SectionDescriptor &getSectionDescriptor(DebugSectionKind SectionKind) {335 SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);336 337 if (It == SectionDescriptors.end())338 llvm_unreachable(339 formatv("Section {0} does not exist", getSectionName(SectionKind))340 .str()341 .c_str());342 343 assert(It->second.get() != nullptr);344 345 return *It->second;346 }347 348 /// Returns descriptor for the specified section of \p SectionKind.349 /// Returns std::nullopt if section descriptor is not created yet.350 std::optional<const SectionDescriptor *>351 tryGetSectionDescriptor(DebugSectionKind SectionKind) const {352 SectionsSetTy::const_iterator It = SectionDescriptors.find(SectionKind);353 354 if (It == SectionDescriptors.end())355 return std::nullopt;356 357 return It->second.get();358 }359 360 /// Returns descriptor for the specified section of \p SectionKind.361 /// Returns std::nullopt if section descriptor is not created yet.362 std::optional<SectionDescriptor *>363 tryGetSectionDescriptor(DebugSectionKind SectionKind) {364 SectionsSetTy::iterator It = SectionDescriptors.find(SectionKind);365 366 if (It == SectionDescriptors.end())367 return std::nullopt;368 369 return It->second.get();370 }371 372 /// Returns descriptor for the specified section of \p SectionKind.373 /// If descriptor does not exist then creates it.374 SectionDescriptor &375 getOrCreateSectionDescriptor(DebugSectionKind SectionKind) {376 auto [It, Inserted] = SectionDescriptors.try_emplace(SectionKind);377 378 if (Inserted)379 It->second = std::make_shared<SectionDescriptor>(SectionKind, GlobalData,380 Format, Endianness);381 382 return *It->second;383 }384 385 /// Erases data of all sections.386 void eraseSections() {387 for (auto &Section : SectionDescriptors)388 Section.second->clearAllSectionData();389 }390 391 /// Enumerate all sections and call \p Handler for each.392 void forEach(function_ref<void(SectionDescriptor &)> Handler) {393 for (auto &Section : SectionDescriptors) {394 assert(Section.second.get() != nullptr);395 Handler(*(Section.second));396 }397 }398 399 /// Enumerate all sections and call \p Handler for each.400 void forEach(401 function_ref<void(std::shared_ptr<SectionDescriptor> Section)> Handler) {402 for (auto &Section : SectionDescriptors)403 Handler(Section.second);404 }405 406 /// Enumerate all sections, for each section set current offset407 /// (kept by \p SectionSizesAccumulator), update current offset with section408 /// length.409 void assignSectionsOffsetAndAccumulateSize(410 std::array<uint64_t, SectionKindsNum> &SectionSizesAccumulator) {411 for (auto &Section : SectionDescriptors) {412 Section.second->StartOffset =413 SectionSizesAccumulator[static_cast<uint8_t>(414 Section.second->getKind())];415 SectionSizesAccumulator[static_cast<uint8_t>(416 Section.second->getKind())] += Section.second->getContents().size();417 }418 }419 420 /// Enumerate all sections, for each section apply all section patches.421 void applyPatches(SectionDescriptor &Section,422 StringEntryToDwarfStringPoolEntryMap &DebugStrStrings,423 StringEntryToDwarfStringPoolEntryMap &DebugLineStrStrings,424 TypeUnit *TypeUnitPtr);425 426 /// Endiannes for the sections.427 llvm::endianness getEndianness() const { return Endianness; }428 429 /// Return DWARF version.430 uint16_t getVersion() const { return Format.Version; }431 432 /// Return size of header of debug_info table.433 uint16_t getDebugInfoHeaderSize() const {434 return Format.Version >= 5 ? 12 : 11;435 }436 437 /// Return size of header of debug_ table.438 uint16_t getDebugAddrHeaderSize() const {439 assert(Format.Version >= 5);440 return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;441 }442 443 /// Return size of header of debug_str_offsets table.444 uint16_t getDebugStrOffsetsHeaderSize() const {445 assert(Format.Version >= 5);446 return Format.Format == dwarf::DwarfFormat::DWARF32 ? 8 : 16;447 }448 449 /// Return size of address.450 const dwarf::FormParams &getFormParams() const { return Format; }451 452protected:453 LinkingGlobalData &GlobalData;454 455 /// Format for sections.456 dwarf::FormParams Format = {4, 4, dwarf::DWARF32};457 458 /// Endiannes for sections.459 llvm::endianness Endianness = llvm::endianness::native;460 461 /// All keeping sections.462 using SectionsSetTy =463 std::map<DebugSectionKind, std::shared_ptr<SectionDescriptor>>;464 SectionsSetTy SectionDescriptors;465};466 467} // end of namespace parallel468} // end of namespace dwarf_linker469} // end of namespace llvm470 471#endif // LLVM_LIB_DWARFLINKER_PARALLEL_OUTPUTSECTIONS_H472