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