| 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/ADT/SmallString.h" |
| 18 | #include "llvm/CodeGen/AccelTable.h" |
| 19 | #include "llvm/DWARFLinker/Parallel/DWARFLinker.h" |
| 20 | #include "llvm/DWARFLinker/StringPool.h" |
| 21 | |
| 22 | namespace llvm { |
| 23 | namespace dwarf_linker { |
| 24 | namespace parallel { |
| 25 | |
| 26 | /// This class links debug info. |
| 27 | class DWARFLinkerImpl : public DWARFLinker { |
| 28 | public: |
| 29 | DWARFLinkerImpl(MessageHandlerTy ErrorHandler, |
| 30 | MessageHandlerTy WarningHandler); |
| 31 | |
| 32 | /// Add object file to be linked. Pre-load compile unit die. Call |
| 33 | /// \p OnCUDieLoaded for each compile unit die. If specified \p File |
| 34 | /// has reference to the Clang module then such module would be |
| 35 | /// pre-loaded by \p Loader for !Update case. |
| 36 | /// |
| 37 | /// \pre NoODR, Update options should be set before call to addObjectFile. |
| 38 | void addObjectFile( |
| 39 | DWARFFile &File, ObjFileLoaderTy Loader = nullptr, |
| 40 | |
| 41 | CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override; |
| 42 | |
| 43 | /// Link debug info for added files. |
| 44 | Error link() override; |
| 45 | |
| 46 | /// Set output DWARF handler. May be not set if output generation is not |
| 47 | /// necessary. |
| 48 | void setOutputDWARFHandler(const Triple &TargetTriple, |
| 49 | SectionHandlerTy SectionHandler) override { |
| 50 | GlobalData.setTargetTriple(TargetTriple); |
| 51 | this->SectionHandler = SectionHandler; |
| 52 | } |
| 53 | |
| 54 | /// \defgroup Methods setting various linking options: |
| 55 | /// |
| 56 | /// @{ |
| 57 | /// |
| 58 | |
| 59 | /// Allows to generate log of linking process to the standard output. |
| 60 | void setVerbosity(bool Verbose) override { |
| 61 | GlobalData.Options.Verbose = Verbose; |
| 62 | } |
| 63 | |
| 64 | /// Print statistics to standard output. |
| 65 | void setStatistics(bool Statistics) override { |
| 66 | GlobalData.Options.Statistics = Statistics; |
| 67 | } |
| 68 | |
| 69 | /// Verify the input DWARF. |
| 70 | void setVerifyInputDWARF(bool Verify) override { |
| 71 | GlobalData.Options.VerifyInputDWARF = Verify; |
| 72 | } |
| 73 | |
| 74 | /// Do not unique types according to ODR. |
| 75 | void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; } |
| 76 | |
| 77 | /// Update index tables only(do not modify rest of DWARF). |
| 78 | void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override { |
| 79 | GlobalData.Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly; |
| 80 | } |
| 81 | |
| 82 | /// Set to keep the enclosing function for a static variable. |
| 83 | void setKeepFunctionForStatic(bool KeepFunctionForStatic) override { |
| 84 | GlobalData.Options.KeepFunctionForStatic = KeepFunctionForStatic; |
| 85 | } |
| 86 | |
| 87 | /// Use specified number of threads for parallel files linking. |
| 88 | void setNumThreads(unsigned NumThreads) override { |
| 89 | GlobalData.Options.Threads = NumThreads; |
| 90 | } |
| 91 | |
| 92 | /// Use the specified thread pool to link the object files. |
| 93 | void setThreadPool(ThreadPoolInterface *Pool) override { ThreadPool = Pool; } |
| 94 | |
| 95 | /// Add kind of accelerator tables to be generated. |
| 96 | void addAccelTableKind(AccelTableKind Kind) override { |
| 97 | assert(!llvm::is_contained(GlobalData.getOptions().AccelTables, Kind)); |
| 98 | GlobalData.Options.AccelTables.emplace_back(Args&: Kind); |
| 99 | } |
| 100 | |
| 101 | /// Set prepend path for clang modules. |
| 102 | void setPrependPath(StringRef Ppath) override { |
| 103 | GlobalData.Options.PrependPath = Ppath; |
| 104 | } |
| 105 | |
| 106 | /// Set estimated objects files amount, for preliminary data allocation. |
| 107 | void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override; |
| 108 | |
| 109 | /// Set verification handler which would be used to report verification |
| 110 | /// errors. |
| 111 | void |
| 112 | setInputVerificationHandler(InputVerificationHandlerTy Handler) override { |
| 113 | GlobalData.Options.InputVerificationHandler = Handler; |
| 114 | } |
| 115 | |
| 116 | /// Set map for Swift interfaces. |
| 117 | void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override { |
| 118 | GlobalData.Options.ParseableSwiftInterfaces = Map; |
| 119 | } |
| 120 | |
| 121 | /// Set prefix map for objects. |
| 122 | void setObjectPrefixMap(ObjectPrefixMapTy *Map) override { |
| 123 | GlobalData.Options.ObjectPrefixMap = Map; |
| 124 | } |
| 125 | |
| 126 | /// Set target DWARF version. |
| 127 | Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override { |
| 128 | if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5)) |
| 129 | return createStringError(EC: std::errc::invalid_argument, |
| 130 | Fmt: "unsupported DWARF version: %d" , |
| 131 | Vals: TargetDWARFVersion); |
| 132 | |
| 133 | GlobalData.Options.TargetDWARFVersion = TargetDWARFVersion; |
| 134 | return Error::success(); |
| 135 | } |
| 136 | /// @} |
| 137 | |
| 138 | protected: |
| 139 | /// Verify input DWARF file. |
| 140 | void verifyInput(const DWARFFile &File); |
| 141 | |
| 142 | /// Validate specified options. |
| 143 | Error validateAndUpdateOptions(); |
| 144 | |
| 145 | /// Take already linked compile units and glue them into single file. |
| 146 | void glueCompileUnitsAndWriteToTheOutput(); |
| 147 | |
| 148 | /// Hold the input and output of the debug info size in bytes. |
| 149 | struct DebugInfoSize { |
| 150 | uint64_t Input; |
| 151 | uint64_t Output; |
| 152 | }; |
| 153 | |
| 154 | friend class DependencyTracker; |
| 155 | /// Keeps track of data associated with one object during linking. |
| 156 | /// i.e. source file descriptor, compilation units, output data |
| 157 | /// for compilation units common tables. |
| 158 | struct LinkContext : public OutputSections { |
| 159 | using UnitListTy = SmallVector<std::unique_ptr<CompileUnit>>; |
| 160 | |
| 161 | /// Keep information for referenced clang module: already loaded DWARF info |
| 162 | /// of the clang module and a CompileUnit of the module. |
| 163 | struct RefModuleUnit { |
| 164 | RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit); |
| 165 | RefModuleUnit(RefModuleUnit &&Other); |
| 166 | RefModuleUnit(const RefModuleUnit &) = delete; |
| 167 | |
| 168 | DWARFFile &File; |
| 169 | std::unique_ptr<CompileUnit> Unit; |
| 170 | }; |
| 171 | using ModuleUnitListTy = SmallVector<RefModuleUnit>; |
| 172 | |
| 173 | /// Object file descriptor. |
| 174 | DWARFFile &InputDWARFFile; |
| 175 | |
| 176 | /// Set of Compilation Units(may be accessed asynchroniously for reading). |
| 177 | UnitListTy CompileUnits; |
| 178 | |
| 179 | /// Set of Compile Units for modules. |
| 180 | ModuleUnitListTy ModulesCompileUnits; |
| 181 | |
| 182 | /// Index of this object file in the link order (used for deterministic |
| 183 | /// type DIE allocation). |
| 184 | uint64_t ObjectFileIdx = 0; |
| 185 | |
| 186 | /// Size of Debug info before optimizing. |
| 187 | uint64_t OriginalDebugInfoSize = 0; |
| 188 | |
| 189 | /// Flag indicating that all inter-connected units are loaded |
| 190 | /// and the dwarf linking process for these units is started. |
| 191 | bool InterCUProcessingStarted = false; |
| 192 | |
| 193 | StringMap<uint64_t> &ClangModules; |
| 194 | |
| 195 | /// Flag indicating that new inter-connected compilation units were |
| 196 | /// discovered. It is used for restarting units processing |
| 197 | /// if new inter-connected units were found. |
| 198 | std::atomic<bool> HasNewInterconnectedCUs = {false}; |
| 199 | |
| 200 | std::atomic<bool> HasNewGlobalDependency = {false}; |
| 201 | |
| 202 | /// Counter for compile units ID. |
| 203 | std::atomic<size_t> &UniqueUnitID; |
| 204 | |
| 205 | LinkContext(LinkingGlobalData &GlobalData, DWARFFile &File, |
| 206 | uint64_t ObjFileIdx, StringMap<uint64_t> &ClangModules, |
| 207 | std::atomic<size_t> &UniqueUnitID); |
| 208 | |
| 209 | /// Check whether specified \p CUDie is a Clang module reference. |
| 210 | /// if \p Quiet is false then display error messages. |
| 211 | /// \return first == true if CUDie is a Clang module reference. |
| 212 | /// second == true if module is already loaded. |
| 213 | std::pair<bool, bool> isClangModuleRef(const DWARFDie &CUDie, |
| 214 | std::string &PCMFile, |
| 215 | unsigned Indent, bool Quiet); |
| 216 | |
| 217 | /// If this compile unit is really a skeleton CU that points to a |
| 218 | /// clang module, register it in ClangModules and return true. |
| 219 | /// |
| 220 | /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name |
| 221 | /// pointing to the module, and a DW_AT_gnu_dwo_id with the module |
| 222 | /// hash. |
| 223 | bool registerModuleReference(const DWARFDie &CUDie, ObjFileLoaderTy Loader, |
| 224 | CompileUnitHandlerTy OnCUDieLoaded, |
| 225 | unsigned Indent = 0); |
| 226 | |
| 227 | /// Recursively add the debug info in this clang module .pcm |
| 228 | /// file (and all the modules imported by it in a bottom-up fashion) |
| 229 | /// to ModuleUnits. |
| 230 | Error loadClangModule(ObjFileLoaderTy Loader, const DWARFDie &CUDie, |
| 231 | const std::string &PCMFile, |
| 232 | CompileUnitHandlerTy OnCUDieLoaded, |
| 233 | unsigned Indent = 0); |
| 234 | |
| 235 | /// Add Compile Unit corresponding to the module. |
| 236 | void addModulesCompileUnit(RefModuleUnit &&Unit); |
| 237 | |
| 238 | /// Computes the total size of the debug info. |
| 239 | uint64_t getInputDebugInfoSize() const { |
| 240 | uint64_t Size = 0; |
| 241 | |
| 242 | if (InputDWARFFile.Dwarf == nullptr) |
| 243 | return Size; |
| 244 | |
| 245 | for (auto &Unit : InputDWARFFile.Dwarf->compile_units()) |
| 246 | Size += Unit->getLength(); |
| 247 | |
| 248 | return Size; |
| 249 | } |
| 250 | |
| 251 | /// Section + local offset of a .debug_frame CIE that has been (or will |
| 252 | /// be) emitted by some LinkContext. Stored in CIERegistry so that any |
| 253 | /// FDE referencing the same CIE bytes can resolve its CIE_pointer to |
| 254 | /// OwnerSection->StartOffset + LocalOffset at output time, even when |
| 255 | /// the FDE lives in a different LinkContext's section. |
| 256 | struct CIELocation { |
| 257 | SectionDescriptor *OwnerSection; |
| 258 | uint32_t LocalOffset; |
| 259 | }; |
| 260 | |
| 261 | /// Linker-wide registry for .debug_frame CIEs. The key is the raw CIE |
| 262 | /// bytes. Populated by a serial pass over ObjectContexts (so ownership |
| 263 | /// is deterministic — first LinkContext wins) and then consumed |
| 264 | /// read-only by a parallel emission pass that writes each context's |
| 265 | /// .debug_frame section. SectionDescriptor pointers remain valid until |
| 266 | /// linking completes because they live in std::map-held shared_ptrs. |
| 267 | using CIERegistry = StringMap<CIELocation>; |
| 268 | |
| 269 | /// Result of scanning one LinkContext's input .debug_frame. Produced |
| 270 | /// by scanFrameData() during the parallel link phase and consumed by |
| 271 | /// the serial CIE-registry merge and parallel emission passes. Owns a |
| 272 | /// copy of the raw frame bytes so the StringRef views below remain |
| 273 | /// valid after the input DWARFContext is unloaded. |
| 274 | struct FrameScanResult { |
| 275 | /// Owning copy of the input .debug_frame bytes. |
| 276 | SmallString<0> FrameData; |
| 277 | |
| 278 | /// Address size of the input object, used by emitFDE to size the |
| 279 | /// FDE's initial_location field. |
| 280 | unsigned AddressSize = 0; |
| 281 | |
| 282 | /// Unique CIEs referenced by at least one retained FDE in this |
| 283 | /// context, in first-reference order. Each element is a view into |
| 284 | /// FrameData and is a key into the linker-wide CIERegistry. |
| 285 | SmallVector<StringRef> CIEs; |
| 286 | |
| 287 | /// FDEs retained for emission. CIEBytes is the registry key; |
| 288 | /// Instructions is the FDE body after the initial_length / |
| 289 | /// CIE_pointer / initial_location fields. |
| 290 | struct FDE { |
| 291 | StringRef CIEBytes; |
| 292 | uint64_t Address = 0; |
| 293 | StringRef Instructions; |
| 294 | }; |
| 295 | SmallVector<FDE> FDEs; |
| 296 | |
| 297 | /// CIEs this context owns, set during the serial CIE-registry |
| 298 | /// merge. Emission writes these at local offsets 0, |
| 299 | /// OwnedCIEs[0].size(), ... in order. |
| 300 | SmallVector<StringRef> OwnedCIEs; |
| 301 | }; |
| 302 | std::unique_ptr<FrameScanResult> FrameScan; |
| 303 | |
| 304 | /// Link compile units for this context. |
| 305 | Error link(TypeUnit *ArtificialTypeUnit); |
| 306 | |
| 307 | /// Link specified compile unit until specified stage. |
| 308 | void linkSingleCompileUnit( |
| 309 | CompileUnit &CU, TypeUnit *ArtificialTypeUnit, |
| 310 | enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned); |
| 311 | |
| 312 | /// Emit invariant sections. |
| 313 | Error emitInvariantSections(); |
| 314 | |
| 315 | /// Unload the input DWARFContext after scanning the input .debug_frame into |
| 316 | /// FrameScan. |
| 317 | Error unloadInput(); |
| 318 | |
| 319 | /// Parse this context's input .debug_frame into FrameScan. Deferred |
| 320 | /// CIE/FDE emission happens later against the scan result alone. |
| 321 | Error scanFrameData(); |
| 322 | |
| 323 | /// Register this context's CIEs with the linker-wide registry. |
| 324 | void registerCIEs(CIERegistry &CIEs); |
| 325 | |
| 326 | /// Emit this context's .debug_frame section. Safe to call in parallel |
| 327 | /// across contexts because each call writes only to its own |
| 328 | /// SectionDescriptor. |
| 329 | Error emitDebugFrame(const CIERegistry &CIEs); |
| 330 | |
| 331 | /// Emit FDE record. |
| 332 | void emitFDE(uint32_t CIEOffset, uint32_t AddrSize, uint64_t Address, |
| 333 | StringRef FDEBytes, SectionDescriptor &Section); |
| 334 | |
| 335 | std::function<CompileUnit *(uint64_t)> getUnitForOffset = |
| 336 | [&](uint64_t Offset) -> CompileUnit * { |
| 337 | auto CU = llvm::upper_bound( |
| 338 | Range&: CompileUnits, Value&: Offset, |
| 339 | C: [](uint64_t LHS, const std::unique_ptr<CompileUnit> &RHS) { |
| 340 | return LHS < RHS->getOrigUnit().getNextUnitOffset(); |
| 341 | }); |
| 342 | |
| 343 | return CU != CompileUnits.end() ? CU->get() : nullptr; |
| 344 | }; |
| 345 | }; |
| 346 | |
| 347 | /// Enumerate all compile units and assign offsets to their sections and |
| 348 | /// strings. |
| 349 | void assignOffsets(); |
| 350 | |
| 351 | /// Enumerate all compile units and assign offsets to their sections. |
| 352 | void assignOffsetsToSections(); |
| 353 | |
| 354 | /// Enumerate all compile units and assign offsets to their strings. |
| 355 | void assignOffsetsToStrings(); |
| 356 | |
| 357 | /// Print statistic for processed Debug Info. |
| 358 | void printStatistic(); |
| 359 | |
| 360 | enum StringDestinationKind : uint8_t { DebugStr, DebugLineStr }; |
| 361 | |
| 362 | /// Enumerates all strings. |
| 363 | void forEachOutputString( |
| 364 | function_ref<void(StringDestinationKind, const StringEntry *)> |
| 365 | StringHandler); |
| 366 | |
| 367 | /// Enumerates sections for modules, invariant for object files, compile |
| 368 | /// units. |
| 369 | void forEachObjectSectionsSet( |
| 370 | function_ref<void(OutputSections &SectionsSet)> SectionsSetHandler); |
| 371 | |
| 372 | /// Enumerates all compile and type units. |
| 373 | void forEachCompileAndTypeUnit(function_ref<void(DwarfUnit *CU)> UnitHandler); |
| 374 | |
| 375 | /// Enumerates all comple units. |
| 376 | void forEachCompileUnit(function_ref<void(CompileUnit *CU)> UnitHandler); |
| 377 | |
| 378 | /// Enumerates all patches and update them with the correct values. |
| 379 | void patchOffsetsAndSizes(); |
| 380 | |
| 381 | /// Emit debug sections common for all input files. |
| 382 | void emitCommonSectionsAndWriteCompileUnitsToTheOutput(); |
| 383 | |
| 384 | /// Emit apple accelerator sections. |
| 385 | void emitAppleAcceleratorSections(const Triple &TargetTriple); |
| 386 | |
| 387 | /// Emit .debug_names section. |
| 388 | void emitDWARFv5DebugNamesSection(const Triple &TargetTriple); |
| 389 | |
| 390 | /// Emit string sections. |
| 391 | void emitStringSections(); |
| 392 | |
| 393 | /// Cleanup data(string pools) after output sections are generated. |
| 394 | void cleanupDataAfterDWARFOutputIsWritten(); |
| 395 | |
| 396 | /// Enumerate all compile units and put their data into the output stream. |
| 397 | void writeCompileUnitsToTheOutput(); |
| 398 | |
| 399 | /// Enumerate common sections and put their data into the output stream. |
| 400 | void writeCommonSectionsToTheOutput(); |
| 401 | |
| 402 | /// \defgroup Data members accessed asinchroniously. |
| 403 | /// |
| 404 | /// @{ |
| 405 | |
| 406 | /// Unique ID for compile unit. |
| 407 | std::atomic<size_t> UniqueUnitID; |
| 408 | |
| 409 | /// Mapping the PCM filename to the DwoId. |
| 410 | StringMap<uint64_t> ClangModules; |
| 411 | std::mutex ClangModulesMutex; |
| 412 | |
| 413 | /// Type unit. |
| 414 | std::unique_ptr<TypeUnit> ArtificialTypeUnit; |
| 415 | /// @} |
| 416 | |
| 417 | /// \defgroup Data members accessed sequentially. |
| 418 | /// |
| 419 | /// @{ |
| 420 | /// Data global for the whole linking process. |
| 421 | LinkingGlobalData GlobalData; |
| 422 | |
| 423 | /// DwarfStringPoolEntries for .debug_str section. |
| 424 | StringEntryToDwarfStringPoolEntryMap DebugStrStrings; |
| 425 | |
| 426 | /// DwarfStringPoolEntries for .debug_line_str section. |
| 427 | StringEntryToDwarfStringPoolEntryMap DebugLineStrStrings; |
| 428 | |
| 429 | /// Keeps all linking contexts. |
| 430 | SmallVector<std::unique_ptr<LinkContext>> ObjectContexts; |
| 431 | |
| 432 | /// Common sections. |
| 433 | OutputSections CommonSections; |
| 434 | |
| 435 | /// Hanler for output sections. |
| 436 | SectionHandlerTy SectionHandler = nullptr; |
| 437 | |
| 438 | /// Thread pool that links the object files, or null to use a private pool. |
| 439 | ThreadPoolInterface *ThreadPool = nullptr; |
| 440 | /// @} |
| 441 | }; |
| 442 | |
| 443 | } // end of namespace parallel |
| 444 | } // end of namespace dwarf_linker |
| 445 | } // end of namespace llvm |
| 446 | |
| 447 | #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H |
| 448 | |