//===- 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_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H #define LLVM_LIB_DWARFLINKER_PARALLEL_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/DWARFLinker/Parallel/DWARFLinker.h" #include "llvm/DWARFLinker/StringPool.h" namespace llvm { namespace dwarf_linker { namespace 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(StringRef 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>; /// 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 Unit); RefModuleUnit(RefModuleUnit &&Other); RefModuleUnit(const RefModuleUnit &) = delete; DWARFFile &File; std::unique_ptr Unit; }; using ModuleUnitListTy = SmallVector; /// 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 &ClangModules; std::optional 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 HasNewInterconnectedCUs = {false}; std::atomic HasNewGlobalDependency = {false}; /// Counter for compile units ID. std::atomic &UniqueUnitID; LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File, StringMap &ClangModules, std::atomic &UniqueUnitID, std::optional 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 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 getUnitForOffset = [&](uint64_t Offset) -> CompileUnit * { auto CU = llvm::upper_bound( CompileUnits, Offset, [](uint64_t LHS, const std::unique_ptr &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 StringHandler); /// Enumerates sections for modules, invariant for object files, compile /// units. void forEachObjectSectionsSet( function_ref SectionsSetHandler); /// Enumerates all compile and type units. void forEachCompileAndTypeUnit(function_ref UnitHandler); /// Enumerates all comple units. void forEachCompileUnit(function_ref 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 UniqueUnitID; /// Mapping the PCM filename to the DwoId. StringMap ClangModules; std::mutex ClangModulesMutex; /// Type unit. std::unique_ptr 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> ObjectContexts; /// Common sections. OutputSections CommonSections; /// The emitter of final dwarf file. std::unique_ptr TheDwarfEmitter; /// Overall compile units number. uint64_t OverallNumberOfCU = 0; /// Data global for the whole linking process. LinkingGlobalData GlobalData; /// @} }; } // end of namespace parallel } // end of namespace dwarf_linker } // end of namespace llvm #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H