|  | //===- DWARFLinkerImpl.h ----------------------------------------*- C++ -*-===// | 
|  | // | 
|  | // 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 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H | 
|  | #define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H | 
|  |  | 
|  | #include "DWARFEmitterImpl.h" | 
|  | #include "DWARFLinkerCompileUnit.h" | 
|  | #include "DWARFLinkerTypeUnit.h" | 
|  | #include "StringEntryToDwarfStringPoolEntryMap.h" | 
|  | #include "llvm/ADT/AddressRanges.h" | 
|  | #include "llvm/CodeGen/AccelTable.h" | 
|  | #include "llvm/DWARFLinkerParallel/DWARFLinker.h" | 
|  | #include "llvm/DWARFLinkerParallel/StringPool.h" | 
|  |  | 
|  | namespace llvm { | 
|  | namespace dwarflinker_parallel { | 
|  |  | 
|  | /// This class links debug info. | 
|  | class DWARFLinkerImpl : public DWARFLinker { | 
|  | public: | 
|  | DWARFLinkerImpl(MessageHandlerTy ErrorHandler, | 
|  | MessageHandlerTy WarningHandler, | 
|  | TranslatorFuncTy StringsTranslator); | 
|  |  | 
|  | /// Create debug info emitter. | 
|  | Error createEmitter(const Triple &TheTriple, OutputFileType FileType, | 
|  | raw_pwrite_stream &OutFile) override; | 
|  |  | 
|  | ExtraDwarfEmitter *getEmitter() override; | 
|  |  | 
|  | /// Add object file to be linked. Pre-load compile unit die. Call | 
|  | /// \p OnCUDieLoaded for each compile unit die. If specified \p File | 
|  | /// has reference to the Clang module then such module would be | 
|  | /// pre-loaded by \p Loader for !Update case. | 
|  | /// | 
|  | /// \pre NoODR, Update options should be set before call to addObjectFile. | 
|  | void addObjectFile( | 
|  | DWARFFile &File, ObjFileLoaderTy Loader = nullptr, | 
|  |  | 
|  | CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override; | 
|  |  | 
|  | /// Link debug info for added files. | 
|  | Error link() override; | 
|  |  | 
|  | /// \defgroup Methods setting various linking options: | 
|  | /// | 
|  | /// @{ | 
|  | /// | 
|  |  | 
|  | /// Allows to generate log of linking process to the standard output. | 
|  | void setVerbosity(bool Verbose) override { | 
|  | GlobalData.Options.Verbose = Verbose; | 
|  | } | 
|  |  | 
|  | /// Print statistics to standard output. | 
|  | void setStatistics(bool Statistics) override { | 
|  | GlobalData.Options.Statistics = Statistics; | 
|  | } | 
|  |  | 
|  | /// Verify the input DWARF. | 
|  | void setVerifyInputDWARF(bool Verify) override { | 
|  | GlobalData.Options.VerifyInputDWARF = Verify; | 
|  | } | 
|  |  | 
|  | /// Do not unique types according to ODR. | 
|  | void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; } | 
|  |  | 
|  | /// Update index tables only(do not modify rest of DWARF). | 
|  | void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override { | 
|  | GlobalData.Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly; | 
|  | } | 
|  |  | 
|  | /// Allow generating valid, but non-deterministic output. | 
|  | void | 
|  | setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override { | 
|  | GlobalData.Options.AllowNonDeterministicOutput = | 
|  | AllowNonDeterministicOutput; | 
|  | } | 
|  |  | 
|  | /// Set to keep the enclosing function for a static variable. | 
|  | void setKeepFunctionForStatic(bool KeepFunctionForStatic) override { | 
|  | GlobalData.Options.KeepFunctionForStatic = KeepFunctionForStatic; | 
|  | } | 
|  |  | 
|  | /// Use specified number of threads for parallel files linking. | 
|  | void setNumThreads(unsigned NumThreads) override { | 
|  | GlobalData.Options.Threads = NumThreads; | 
|  | } | 
|  |  | 
|  | /// Add kind of accelerator tables to be generated. | 
|  | void addAccelTableKind(AccelTableKind Kind) override { | 
|  | assert(!llvm::is_contained(GlobalData.getOptions().AccelTables, Kind)); | 
|  | GlobalData.Options.AccelTables.emplace_back(Kind); | 
|  | } | 
|  |  | 
|  | /// Set prepend path for clang modules. | 
|  | void setPrependPath(const std::string &Ppath) override { | 
|  | GlobalData.Options.PrependPath = Ppath; | 
|  | } | 
|  |  | 
|  | /// Set estimated objects files amount, for preliminary data allocation. | 
|  | void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override; | 
|  |  | 
|  | /// Set verification handler which would be used to report verification | 
|  | /// errors. | 
|  | void | 
|  | setInputVerificationHandler(InputVerificationHandlerTy Handler) override { | 
|  | GlobalData.Options.InputVerificationHandler = Handler; | 
|  | } | 
|  |  | 
|  | /// Set map for Swift interfaces. | 
|  | void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override { | 
|  | GlobalData.Options.ParseableSwiftInterfaces = Map; | 
|  | } | 
|  |  | 
|  | /// Set prefix map for objects. | 
|  | void setObjectPrefixMap(ObjectPrefixMapTy *Map) override { | 
|  | GlobalData.Options.ObjectPrefixMap = Map; | 
|  | } | 
|  |  | 
|  | /// Set target DWARF version. | 
|  | Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override { | 
|  | if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5)) | 
|  | return createStringError(std::errc::invalid_argument, | 
|  | "unsupported DWARF version: %d", | 
|  | TargetDWARFVersion); | 
|  |  | 
|  | GlobalData.Options.TargetDWARFVersion = TargetDWARFVersion; | 
|  | return Error::success(); | 
|  | } | 
|  | /// @} | 
|  |  | 
|  | protected: | 
|  | /// Verify input DWARF file. | 
|  | void verifyInput(const DWARFFile &File); | 
|  |  | 
|  | /// Validate specified options. | 
|  | Error validateAndUpdateOptions(); | 
|  |  | 
|  | /// Take already linked compile units and glue them into single file. | 
|  | void glueCompileUnitsAndWriteToTheOutput(); | 
|  |  | 
|  | /// Hold the input and output of the debug info size in bytes. | 
|  | struct DebugInfoSize { | 
|  | uint64_t Input; | 
|  | uint64_t Output; | 
|  | }; | 
|  |  | 
|  | friend class DependencyTracker; | 
|  | /// Keeps track of data associated with one object during linking. | 
|  | /// i.e. source file descriptor, compilation units, output data | 
|  | /// for compilation units common tables. | 
|  | struct LinkContext : public OutputSections { | 
|  | using UnitListTy = SmallVector<std::unique_ptr<CompileUnit>>; | 
|  |  | 
|  | /// Keep information for referenced clang module: already loaded DWARF info | 
|  | /// of the clang module and a CompileUnit of the module. | 
|  | struct RefModuleUnit { | 
|  | RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit); | 
|  | RefModuleUnit(RefModuleUnit &&Other); | 
|  | RefModuleUnit(const RefModuleUnit &) = delete; | 
|  |  | 
|  | DWARFFile &File; | 
|  | std::unique_ptr<CompileUnit> Unit; | 
|  | }; | 
|  | using ModuleUnitListTy = SmallVector<RefModuleUnit>; | 
|  |  | 
|  | /// Object file descriptor. | 
|  | DWARFFile &InputDWARFFile; | 
|  |  | 
|  | /// Set of Compilation Units(may be accessed asynchroniously for reading). | 
|  | UnitListTy CompileUnits; | 
|  |  | 
|  | /// Set of Compile Units for modules. | 
|  | ModuleUnitListTy ModulesCompileUnits; | 
|  |  | 
|  | /// Size of Debug info before optimizing. | 
|  | uint64_t OriginalDebugInfoSize = 0; | 
|  |  | 
|  | /// Flag indicating that all inter-connected units are loaded | 
|  | /// and the dwarf linking process for these units is started. | 
|  | bool InterCUProcessingStarted = false; | 
|  |  | 
|  | StringMap<uint64_t> &ClangModules; | 
|  |  | 
|  | std::optional<Triple> TargetTriple; | 
|  |  | 
|  | /// Flag indicating that new inter-connected compilation units were | 
|  | /// discovered. It is used for restarting units processing | 
|  | /// if new inter-connected units were found. | 
|  | std::atomic<bool> HasNewInterconnectedCUs = {false}; | 
|  |  | 
|  | std::atomic<bool> HasNewGlobalDependency = {false}; | 
|  |  | 
|  | /// Counter for compile units ID. | 
|  | std::atomic<size_t> &UniqueUnitID; | 
|  |  | 
|  | LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File, | 
|  | StringMap<uint64_t> &ClangModules, | 
|  | std::atomic<size_t> &UniqueUnitID, | 
|  | std::optional<Triple> TargetTriple); | 
|  |  | 
|  | /// Check whether specified \p CUDie is a Clang module reference. | 
|  | /// if \p Quiet is false then display error messages. | 
|  | /// \return first == true if CUDie is a Clang module reference. | 
|  | ///         second == true if module is already loaded. | 
|  | std::pair<bool, bool> isClangModuleRef(const DWARFDie &CUDie, | 
|  | std::string &PCMFile, | 
|  | unsigned Indent, bool Quiet); | 
|  |  | 
|  | /// If this compile unit is really a skeleton CU that points to a | 
|  | /// clang module, register it in ClangModules and return true. | 
|  | /// | 
|  | /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name | 
|  | /// pointing to the module, and a DW_AT_gnu_dwo_id with the module | 
|  | /// hash. | 
|  | bool registerModuleReference(const DWARFDie &CUDie, ObjFileLoaderTy Loader, | 
|  | CompileUnitHandlerTy OnCUDieLoaded, | 
|  | unsigned Indent = 0); | 
|  |  | 
|  | /// Recursively add the debug info in this clang module .pcm | 
|  | /// file (and all the modules imported by it in a bottom-up fashion) | 
|  | /// to ModuleUnits. | 
|  | Error loadClangModule(ObjFileLoaderTy Loader, const DWARFDie &CUDie, | 
|  | const std::string &PCMFile, | 
|  | CompileUnitHandlerTy OnCUDieLoaded, | 
|  | unsigned Indent = 0); | 
|  |  | 
|  | /// Add Compile Unit corresponding to the module. | 
|  | void addModulesCompileUnit(RefModuleUnit &&Unit); | 
|  |  | 
|  | /// Computes the total size of the debug info. | 
|  | uint64_t getInputDebugInfoSize() const { | 
|  | uint64_t Size = 0; | 
|  |  | 
|  | if (InputDWARFFile.Dwarf == nullptr) | 
|  | return Size; | 
|  |  | 
|  | for (auto &Unit : InputDWARFFile.Dwarf->compile_units()) | 
|  | Size += Unit->getLength(); | 
|  |  | 
|  | return Size; | 
|  | } | 
|  |  | 
|  | /// Link compile units for this context. | 
|  | Error link(TypeUnit *ArtificialTypeUnit); | 
|  |  | 
|  | /// Link specified compile unit until specified stage. | 
|  | void linkSingleCompileUnit( | 
|  | CompileUnit &CU, TypeUnit *ArtificialTypeUnit, | 
|  | enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned); | 
|  |  | 
|  | /// Emit invariant sections. | 
|  | Error emitInvariantSections(); | 
|  |  | 
|  | /// Clone and emit .debug_frame. | 
|  | Error cloneAndEmitDebugFrame(); | 
|  |  | 
|  | /// Emit FDE record. | 
|  | void emitFDE(uint32_t CIEOffset, uint32_t AddrSize, uint64_t Address, | 
|  | StringRef FDEBytes, SectionDescriptor &Section); | 
|  |  | 
|  | std::function<CompileUnit *(uint64_t)> getUnitForOffset = | 
|  | [&](uint64_t Offset) -> CompileUnit * { | 
|  | auto CU = llvm::upper_bound( | 
|  | CompileUnits, Offset, | 
|  | [](uint64_t LHS, const std::unique_ptr<CompileUnit> &RHS) { | 
|  | return LHS < RHS->getOrigUnit().getNextUnitOffset(); | 
|  | }); | 
|  |  | 
|  | return CU != CompileUnits.end() ? CU->get() : nullptr; | 
|  | }; | 
|  | }; | 
|  |  | 
|  | /// Enumerate all compile units and assign offsets to their sections and | 
|  | /// strings. | 
|  | void assignOffsets(); | 
|  |  | 
|  | /// Enumerate all compile units and assign offsets to their sections. | 
|  | void assignOffsetsToSections(); | 
|  |  | 
|  | /// Enumerate all compile units and assign offsets to their strings. | 
|  | void assignOffsetsToStrings(); | 
|  |  | 
|  | /// Print statistic for processed Debug Info. | 
|  | void printStatistic(); | 
|  |  | 
|  | enum StringDestinationKind : uint8_t { DebugStr, DebugLineStr }; | 
|  |  | 
|  | /// Enumerates all strings. | 
|  | void forEachOutputString( | 
|  | function_ref<void(StringDestinationKind, const StringEntry *)> | 
|  | StringHandler); | 
|  |  | 
|  | /// Enumerates sections for modules, invariant for object files, compile | 
|  | /// units. | 
|  | void forEachObjectSectionsSet( | 
|  | function_ref<void(OutputSections &SectionsSet)> SectionsSetHandler); | 
|  |  | 
|  | /// Enumerates all compile and type units. | 
|  | void forEachCompileAndTypeUnit(function_ref<void(DwarfUnit *CU)> UnitHandler); | 
|  |  | 
|  | /// Enumerates all comple units. | 
|  | void forEachCompileUnit(function_ref<void(CompileUnit *CU)> UnitHandler); | 
|  |  | 
|  | /// Enumerates all patches and update them with the correct values. | 
|  | void patchOffsetsAndSizes(); | 
|  |  | 
|  | /// Emit debug sections common for all input files. | 
|  | void emitCommonSectionsAndWriteCompileUnitsToTheOutput(); | 
|  |  | 
|  | /// Emit apple accelerator sections. | 
|  | void emitAppleAcceleratorSections(const Triple &TargetTriple); | 
|  |  | 
|  | /// Emit .debug_names section. | 
|  | void emitDWARFv5DebugNamesSection(const Triple &TargetTriple); | 
|  |  | 
|  | /// Emit string sections. | 
|  | void emitStringSections(); | 
|  |  | 
|  | /// Cleanup data(string pools) after output sections are generated. | 
|  | void cleanupDataAfterDWARFOutputIsWritten(); | 
|  |  | 
|  | /// Enumerate all compile units and put their data into the output stream. | 
|  | void writeCompileUnitsToTheOutput(); | 
|  |  | 
|  | /// Enumerate common sections and put their data into the output stream. | 
|  | void writeCommonSectionsToTheOutput(); | 
|  |  | 
|  | /// \defgroup Data members accessed asinchroniously. | 
|  | /// | 
|  | /// @{ | 
|  |  | 
|  | /// Unique ID for compile unit. | 
|  | std::atomic<size_t> UniqueUnitID; | 
|  |  | 
|  | /// Mapping the PCM filename to the DwoId. | 
|  | StringMap<uint64_t> ClangModules; | 
|  | std::mutex ClangModulesMutex; | 
|  |  | 
|  | /// Type unit. | 
|  | std::unique_ptr<TypeUnit> ArtificialTypeUnit; | 
|  | /// @} | 
|  |  | 
|  | /// \defgroup Data members accessed sequentially. | 
|  | /// | 
|  | /// @{ | 
|  | /// DwarfStringPoolEntries for .debug_str section. | 
|  | StringEntryToDwarfStringPoolEntryMap DebugStrStrings; | 
|  |  | 
|  | /// DwarfStringPoolEntries for .debug_line_str section. | 
|  | StringEntryToDwarfStringPoolEntryMap DebugLineStrStrings; | 
|  |  | 
|  | /// Keeps all linking contexts. | 
|  | SmallVector<std::unique_ptr<LinkContext>> ObjectContexts; | 
|  |  | 
|  | /// Common sections. | 
|  | OutputSections CommonSections; | 
|  |  | 
|  | /// The emitter of final dwarf file. | 
|  | std::unique_ptr<DwarfEmitterImpl> TheDwarfEmitter; | 
|  |  | 
|  | /// Overall compile units number. | 
|  | uint64_t OverallNumberOfCU = 0; | 
|  |  | 
|  | /// Data global for the whole linking process. | 
|  | LinkingGlobalData GlobalData; | 
|  | /// @} | 
|  | }; | 
|  |  | 
|  | } // end namespace dwarflinker_parallel | 
|  | } // end namespace llvm | 
|  |  | 
|  | #endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H |