| 1 | //===- DWARFLinkerImpl.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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H |
| 10 | #define LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H |
| 11 | |
| 12 | #include "DWARFEmitterImpl.h" |
| 13 | #include "DWARFLinkerCompileUnit.h" |
| 14 | #include "DWARFLinkerTypeUnit.h" |
| 15 | #include "StringEntryToDwarfStringPoolEntryMap.h" |
| 16 | #include "llvm/ADT/AddressRanges.h" |
| 17 | #include "llvm/CodeGen/AccelTable.h" |
| 18 | #include "llvm/DWARFLinker/Parallel/DWARFLinker.h" |
| 19 | #include "llvm/DWARFLinker/StringPool.h" |
| 20 | |
| 21 | namespace llvm { |
| 22 | namespace dwarf_linker { |
| 23 | namespace parallel { |
| 24 | |
| 25 | /// This class links debug info. |
| 26 | class DWARFLinkerImpl : public DWARFLinker { |
| 27 | public: |
| 28 | DWARFLinkerImpl(MessageHandlerTy ErrorHandler, |
| 29 | MessageHandlerTy WarningHandler); |
| 30 | |
| 31 | /// Add object file to be linked. Pre-load compile unit die. Call |
| 32 | /// \p OnCUDieLoaded for each compile unit die. If specified \p File |
| 33 | /// has reference to the Clang module then such module would be |
| 34 | /// pre-loaded by \p Loader for !Update case. |
| 35 | /// |
| 36 | /// \pre NoODR, Update options should be set before call to addObjectFile. |
| 37 | void addObjectFile( |
| 38 | DWARFFile &File, ObjFileLoaderTy Loader = nullptr, |
| 39 | |
| 40 | CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override; |
| 41 | |
| 42 | /// Link debug info for added files. |
| 43 | Error link() override; |
| 44 | |
| 45 | /// Set output DWARF handler. May be not set if output generation is not |
| 46 | /// necessary. |
| 47 | void setOutputDWARFHandler(const Triple &TargetTriple, |
| 48 | SectionHandlerTy SectionHandler) override { |
| 49 | GlobalData.setTargetTriple(TargetTriple); |
| 50 | this->SectionHandler = SectionHandler; |
| 51 | } |
| 52 | |
| 53 | /// \defgroup Methods setting various linking options: |
| 54 | /// |
| 55 | /// @{ |
| 56 | /// |
| 57 | |
| 58 | /// Allows to generate log of linking process to the standard output. |
| 59 | void setVerbosity(bool Verbose) override { |
| 60 | GlobalData.Options.Verbose = Verbose; |
| 61 | } |
| 62 | |
| 63 | /// Print statistics to standard output. |
| 64 | void setStatistics(bool Statistics) override { |
| 65 | GlobalData.Options.Statistics = Statistics; |
| 66 | } |
| 67 | |
| 68 | /// Verify the input DWARF. |
| 69 | void setVerifyInputDWARF(bool Verify) override { |
| 70 | GlobalData.Options.VerifyInputDWARF = Verify; |
| 71 | } |
| 72 | |
| 73 | /// Do not unique types according to ODR. |
| 74 | void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; } |
| 75 | |
| 76 | /// Update index tables only(do not modify rest of DWARF). |
| 77 | void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override { |
| 78 | GlobalData.Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly; |
| 79 | } |
| 80 | |
| 81 | /// Allow generating valid, but non-deterministic output. |
| 82 | void |
| 83 | setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override { |
| 84 | GlobalData.Options.AllowNonDeterministicOutput = |
| 85 | AllowNonDeterministicOutput; |
| 86 | } |
| 87 | |
| 88 | /// Set to keep the enclosing function for a static variable. |
| 89 | void setKeepFunctionForStatic(bool KeepFunctionForStatic) override { |
| 90 | GlobalData.Options.KeepFunctionForStatic = KeepFunctionForStatic; |
| 91 | } |
| 92 | |
| 93 | /// Use specified number of threads for parallel files linking. |
| 94 | void setNumThreads(unsigned NumThreads) override { |
| 95 | GlobalData.Options.Threads = NumThreads; |
| 96 | } |
| 97 | |
| 98 | /// Add kind of accelerator tables to be generated. |
| 99 | void addAccelTableKind(AccelTableKind Kind) override { |
| 100 | assert(!llvm::is_contained(GlobalData.getOptions().AccelTables, Kind)); |
| 101 | GlobalData.Options.AccelTables.emplace_back(Args&: Kind); |
| 102 | } |
| 103 | |
| 104 | /// Set prepend path for clang modules. |
| 105 | void setPrependPath(StringRef Ppath) override { |
| 106 | GlobalData.Options.PrependPath = Ppath; |
| 107 | } |
| 108 | |
| 109 | /// Set estimated objects files amount, for preliminary data allocation. |
| 110 | void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override; |
| 111 | |
| 112 | /// Set verification handler which would be used to report verification |
| 113 | /// errors. |
| 114 | void |
| 115 | setInputVerificationHandler(InputVerificationHandlerTy Handler) override { |
| 116 | GlobalData.Options.InputVerificationHandler = Handler; |
| 117 | } |
| 118 | |
| 119 | /// Set map for Swift interfaces. |
| 120 | void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override { |
| 121 | GlobalData.Options.ParseableSwiftInterfaces = Map; |
| 122 | } |
| 123 | |
| 124 | /// Set prefix map for objects. |
| 125 | void setObjectPrefixMap(ObjectPrefixMapTy *Map) override { |
| 126 | GlobalData.Options.ObjectPrefixMap = Map; |
| 127 | } |
| 128 | |
| 129 | /// Set target DWARF version. |
| 130 | Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override { |
| 131 | if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5)) |
| 132 | return createStringError(EC: std::errc::invalid_argument, |
| 133 | Fmt: "unsupported DWARF version: %d" , |
| 134 | Vals: TargetDWARFVersion); |
| 135 | |
| 136 | GlobalData.Options.TargetDWARFVersion = TargetDWARFVersion; |
| 137 | return Error::success(); |
| 138 | } |
| 139 | /// @} |
| 140 | |
| 141 | protected: |
| 142 | /// Verify input DWARF file. |
| 143 | void verifyInput(const DWARFFile &File); |
| 144 | |
| 145 | /// Validate specified options. |
| 146 | Error validateAndUpdateOptions(); |
| 147 | |
| 148 | /// Take already linked compile units and glue them into single file. |
| 149 | void glueCompileUnitsAndWriteToTheOutput(); |
| 150 | |
| 151 | /// Hold the input and output of the debug info size in bytes. |
| 152 | struct DebugInfoSize { |
| 153 | uint64_t Input; |
| 154 | uint64_t Output; |
| 155 | }; |
| 156 | |
| 157 | friend class DependencyTracker; |
| 158 | /// Keeps track of data associated with one object during linking. |
| 159 | /// i.e. source file descriptor, compilation units, output data |
| 160 | /// for compilation units common tables. |
| 161 | struct LinkContext : public OutputSections { |
| 162 | using UnitListTy = SmallVector<std::unique_ptr<CompileUnit>>; |
| 163 | |
| 164 | /// Keep information for referenced clang module: already loaded DWARF info |
| 165 | /// of the clang module and a CompileUnit of the module. |
| 166 | struct RefModuleUnit { |
| 167 | RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit); |
| 168 | RefModuleUnit(RefModuleUnit &&Other); |
| 169 | RefModuleUnit(const RefModuleUnit &) = delete; |
| 170 | |
| 171 | DWARFFile &File; |
| 172 | std::unique_ptr<CompileUnit> Unit; |
| 173 | }; |
| 174 | using ModuleUnitListTy = SmallVector<RefModuleUnit>; |
| 175 | |
| 176 | /// Object file descriptor. |
| 177 | DWARFFile &InputDWARFFile; |
| 178 | |
| 179 | /// Set of Compilation Units(may be accessed asynchroniously for reading). |
| 180 | UnitListTy CompileUnits; |
| 181 | |
| 182 | /// Set of Compile Units for modules. |
| 183 | ModuleUnitListTy ModulesCompileUnits; |
| 184 | |
| 185 | /// Size of Debug info before optimizing. |
| 186 | uint64_t OriginalDebugInfoSize = 0; |
| 187 | |
| 188 | /// Flag indicating that all inter-connected units are loaded |
| 189 | /// and the dwarf linking process for these units is started. |
| 190 | bool InterCUProcessingStarted = false; |
| 191 | |
| 192 | StringMap<uint64_t> &ClangModules; |
| 193 | |
| 194 | /// Flag indicating that new inter-connected compilation units were |
| 195 | /// discovered. It is used for restarting units processing |
| 196 | /// if new inter-connected units were found. |
| 197 | std::atomic<bool> HasNewInterconnectedCUs = {false}; |
| 198 | |
| 199 | std::atomic<bool> HasNewGlobalDependency = {false}; |
| 200 | |
| 201 | /// Counter for compile units ID. |
| 202 | std::atomic<size_t> &UniqueUnitID; |
| 203 | |
| 204 | LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File, |
| 205 | StringMap<uint64_t> &ClangModules, |
| 206 | std::atomic<size_t> &UniqueUnitID); |
| 207 | |
| 208 | /// Check whether specified \p CUDie is a Clang module reference. |
| 209 | /// if \p Quiet is false then display error messages. |
| 210 | /// \return first == true if CUDie is a Clang module reference. |
| 211 | /// second == true if module is already loaded. |
| 212 | std::pair<bool, bool> isClangModuleRef(const DWARFDie &CUDie, |
| 213 | std::string &PCMFile, |
| 214 | unsigned Indent, bool Quiet); |
| 215 | |
| 216 | /// If this compile unit is really a skeleton CU that points to a |
| 217 | /// clang module, register it in ClangModules and return true. |
| 218 | /// |
| 219 | /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name |
| 220 | /// pointing to the module, and a DW_AT_gnu_dwo_id with the module |
| 221 | /// hash. |
| 222 | bool registerModuleReference(const DWARFDie &CUDie, ObjFileLoaderTy Loader, |
| 223 | CompileUnitHandlerTy OnCUDieLoaded, |
| 224 | unsigned Indent = 0); |
| 225 | |
| 226 | /// Recursively add the debug info in this clang module .pcm |
| 227 | /// file (and all the modules imported by it in a bottom-up fashion) |
| 228 | /// to ModuleUnits. |
| 229 | Error loadClangModule(ObjFileLoaderTy Loader, const DWARFDie &CUDie, |
| 230 | const std::string &PCMFile, |
| 231 | CompileUnitHandlerTy OnCUDieLoaded, |
| 232 | unsigned Indent = 0); |
| 233 | |
| 234 | /// Add Compile Unit corresponding to the module. |
| 235 | void addModulesCompileUnit(RefModuleUnit &&Unit); |
| 236 | |
| 237 | /// Computes the total size of the debug info. |
| 238 | uint64_t getInputDebugInfoSize() const { |
| 239 | uint64_t Size = 0; |
| 240 | |
| 241 | if (InputDWARFFile.Dwarf == nullptr) |
| 242 | return Size; |
| 243 | |
| 244 | for (auto &Unit : InputDWARFFile.Dwarf->compile_units()) |
| 245 | Size += Unit->getLength(); |
| 246 | |
| 247 | return Size; |
| 248 | } |
| 249 | |
| 250 | /// Link compile units for this context. |
| 251 | Error link(TypeUnit *ArtificialTypeUnit); |
| 252 | |
| 253 | /// Link specified compile unit until specified stage. |
| 254 | void linkSingleCompileUnit( |
| 255 | CompileUnit &CU, TypeUnit *ArtificialTypeUnit, |
| 256 | enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned); |
| 257 | |
| 258 | /// Emit invariant sections. |
| 259 | Error emitInvariantSections(); |
| 260 | |
| 261 | /// Clone and emit .debug_frame. |
| 262 | Error cloneAndEmitDebugFrame(); |
| 263 | |
| 264 | /// Emit FDE record. |
| 265 | void emitFDE(uint32_t CIEOffset, uint32_t AddrSize, uint64_t Address, |
| 266 | StringRef FDEBytes, SectionDescriptor &Section); |
| 267 | |
| 268 | std::function<CompileUnit *(uint64_t)> getUnitForOffset = |
| 269 | [&](uint64_t Offset) -> CompileUnit * { |
| 270 | auto CU = llvm::upper_bound( |
| 271 | Range&: CompileUnits, Value&: Offset, |
| 272 | C: [](uint64_t LHS, const std::unique_ptr<CompileUnit> &RHS) { |
| 273 | return LHS < RHS->getOrigUnit().getNextUnitOffset(); |
| 274 | }); |
| 275 | |
| 276 | return CU != CompileUnits.end() ? CU->get() : nullptr; |
| 277 | }; |
| 278 | }; |
| 279 | |
| 280 | /// Enumerate all compile units and assign offsets to their sections and |
| 281 | /// strings. |
| 282 | void assignOffsets(); |
| 283 | |
| 284 | /// Enumerate all compile units and assign offsets to their sections. |
| 285 | void assignOffsetsToSections(); |
| 286 | |
| 287 | /// Enumerate all compile units and assign offsets to their strings. |
| 288 | void assignOffsetsToStrings(); |
| 289 | |
| 290 | /// Print statistic for processed Debug Info. |
| 291 | void printStatistic(); |
| 292 | |
| 293 | enum StringDestinationKind : uint8_t { DebugStr, DebugLineStr }; |
| 294 | |
| 295 | /// Enumerates all strings. |
| 296 | void forEachOutputString( |
| 297 | function_ref<void(StringDestinationKind, const StringEntry *)> |
| 298 | StringHandler); |
| 299 | |
| 300 | /// Enumerates sections for modules, invariant for object files, compile |
| 301 | /// units. |
| 302 | void forEachObjectSectionsSet( |
| 303 | function_ref<void(OutputSections &SectionsSet)> SectionsSetHandler); |
| 304 | |
| 305 | /// Enumerates all compile and type units. |
| 306 | void forEachCompileAndTypeUnit(function_ref<void(DwarfUnit *CU)> UnitHandler); |
| 307 | |
| 308 | /// Enumerates all comple units. |
| 309 | void forEachCompileUnit(function_ref<void(CompileUnit *CU)> UnitHandler); |
| 310 | |
| 311 | /// Enumerates all patches and update them with the correct values. |
| 312 | void patchOffsetsAndSizes(); |
| 313 | |
| 314 | /// Emit debug sections common for all input files. |
| 315 | void emitCommonSectionsAndWriteCompileUnitsToTheOutput(); |
| 316 | |
| 317 | /// Emit apple accelerator sections. |
| 318 | void emitAppleAcceleratorSections(const Triple &TargetTriple); |
| 319 | |
| 320 | /// Emit .debug_names section. |
| 321 | void emitDWARFv5DebugNamesSection(const Triple &TargetTriple); |
| 322 | |
| 323 | /// Emit string sections. |
| 324 | void emitStringSections(); |
| 325 | |
| 326 | /// Cleanup data(string pools) after output sections are generated. |
| 327 | void cleanupDataAfterDWARFOutputIsWritten(); |
| 328 | |
| 329 | /// Enumerate all compile units and put their data into the output stream. |
| 330 | void writeCompileUnitsToTheOutput(); |
| 331 | |
| 332 | /// Enumerate common sections and put their data into the output stream. |
| 333 | void writeCommonSectionsToTheOutput(); |
| 334 | |
| 335 | /// \defgroup Data members accessed asinchroniously. |
| 336 | /// |
| 337 | /// @{ |
| 338 | |
| 339 | /// Unique ID for compile unit. |
| 340 | std::atomic<size_t> UniqueUnitID; |
| 341 | |
| 342 | /// Mapping the PCM filename to the DwoId. |
| 343 | StringMap<uint64_t> ClangModules; |
| 344 | std::mutex ClangModulesMutex; |
| 345 | |
| 346 | /// Type unit. |
| 347 | std::unique_ptr<TypeUnit> ArtificialTypeUnit; |
| 348 | /// @} |
| 349 | |
| 350 | /// \defgroup Data members accessed sequentially. |
| 351 | /// |
| 352 | /// @{ |
| 353 | /// Data global for the whole linking process. |
| 354 | LinkingGlobalData GlobalData; |
| 355 | |
| 356 | /// DwarfStringPoolEntries for .debug_str section. |
| 357 | StringEntryToDwarfStringPoolEntryMap DebugStrStrings; |
| 358 | |
| 359 | /// DwarfStringPoolEntries for .debug_line_str section. |
| 360 | StringEntryToDwarfStringPoolEntryMap DebugLineStrStrings; |
| 361 | |
| 362 | /// Keeps all linking contexts. |
| 363 | SmallVector<std::unique_ptr<LinkContext>> ObjectContexts; |
| 364 | |
| 365 | /// Common sections. |
| 366 | OutputSections CommonSections; |
| 367 | |
| 368 | /// Hanler for output sections. |
| 369 | SectionHandlerTy SectionHandler = nullptr; |
| 370 | |
| 371 | /// Overall compile units number. |
| 372 | uint64_t OverallNumberOfCU = 0; |
| 373 | /// @} |
| 374 | }; |
| 375 | |
| 376 | } // end of namespace parallel |
| 377 | } // end of namespace dwarf_linker |
| 378 | } // end of namespace llvm |
| 379 | |
| 380 | #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H |
| 381 | |