brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.2 KiB · 5043e91 Raw
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 &notePatch(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(&notePatch(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