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 /// 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 /// Allow generating valid, but non-deterministic output. 83 void 84 setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override { 85 GlobalData.Options.AllowNonDeterministicOutput = 86 AllowNonDeterministicOutput; 87 } 88 89 /// Set to keep the enclosing function for a static variable. 90 void setKeepFunctionForStatic(bool KeepFunctionForStatic) override { 91 GlobalData.Options.KeepFunctionForStatic = KeepFunctionForStatic; 92 } 93 94 /// Use specified number of threads for parallel files linking. 95 void setNumThreads(unsigned NumThreads) override { 96 GlobalData.Options.Threads = NumThreads; 97 } 98 99 /// Add kind of accelerator tables to be generated. 100 void addAccelTableKind(AccelTableKind Kind) override { 101 assert(!llvm::is_contained(GlobalData.getOptions().AccelTables, Kind)); 102 GlobalData.Options.AccelTables.emplace_back(Kind); 103 } 104 105 /// Set prepend path for clang modules. 106 void setPrependPath(StringRef Ppath) override { 107 GlobalData.Options.PrependPath = Ppath; 108 } 109 110 /// Set estimated objects files amount, for preliminary data allocation. 111 void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override; 112 113 /// Set verification handler which would be used to report verification 114 /// errors. 115 void 116 setInputVerificationHandler(InputVerificationHandlerTy Handler) override { 117 GlobalData.Options.InputVerificationHandler = Handler; 118 } 119 120 /// Set map for Swift interfaces. 121 void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override { 122 GlobalData.Options.ParseableSwiftInterfaces = Map; 123 } 124 125 /// Set prefix map for objects. 126 void setObjectPrefixMap(ObjectPrefixMapTy *Map) override { 127 GlobalData.Options.ObjectPrefixMap = Map; 128 } 129 130 /// Set target DWARF version. 131 Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override { 132 if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5)) 133 return createStringError(std::errc::invalid_argument, 134 "unsupported DWARF version: %d", 135 TargetDWARFVersion); 136 137 GlobalData.Options.TargetDWARFVersion = TargetDWARFVersion; 138 return Error::success(); 139 } 140 /// @} 141 142 protected: 143 /// Verify input DWARF file. 144 void verifyInput(const DWARFFile &File); 145 146 /// Validate specified options. 147 Error validateAndUpdateOptions(); 148 149 /// Take already linked compile units and glue them into single file. 150 void glueCompileUnitsAndWriteToTheOutput(); 151 152 /// Hold the input and output of the debug info size in bytes. 153 struct DebugInfoSize { 154 uint64_t Input; 155 uint64_t Output; 156 }; 157 158 friend class DependencyTracker; 159 /// Keeps track of data associated with one object during linking. 160 /// i.e. source file descriptor, compilation units, output data 161 /// for compilation units common tables. 162 struct LinkContext : public OutputSections { 163 using UnitListTy = SmallVector<std::unique_ptr<CompileUnit>>; 164 165 /// Keep information for referenced clang module: already loaded DWARF info 166 /// of the clang module and a CompileUnit of the module. 167 struct RefModuleUnit { 168 RefModuleUnit(DWARFFile &File, std::unique_ptr<CompileUnit> Unit); 169 RefModuleUnit(RefModuleUnit &&Other); 170 RefModuleUnit(const RefModuleUnit &) = delete; 171 172 DWARFFile &File; 173 std::unique_ptr<CompileUnit> Unit; 174 }; 175 using ModuleUnitListTy = SmallVector<RefModuleUnit>; 176 177 /// Object file descriptor. 178 DWARFFile &InputDWARFFile; 179 180 /// Set of Compilation Units(may be accessed asynchroniously for reading). 181 UnitListTy CompileUnits; 182 183 /// Set of Compile Units for modules. 184 ModuleUnitListTy ModulesCompileUnits; 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 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 /// Link compile units for this context. 252 Error link(TypeUnit *ArtificialTypeUnit); 253 254 /// Link specified compile unit until specified stage. 255 void linkSingleCompileUnit( 256 CompileUnit &CU, TypeUnit *ArtificialTypeUnit, 257 enum CompileUnit::Stage DoUntilStage = CompileUnit::Stage::Cleaned); 258 259 /// Emit invariant sections. 260 Error emitInvariantSections(); 261 262 /// Clone and emit .debug_frame. 263 Error cloneAndEmitDebugFrame(); 264 265 /// Emit FDE record. 266 void emitFDE(uint32_t CIEOffset, uint32_t AddrSize, uint64_t Address, 267 StringRef FDEBytes, SectionDescriptor &Section); 268 269 std::function<CompileUnit *(uint64_t)> getUnitForOffset = 270 [&](uint64_t Offset) -> CompileUnit * { 271 auto CU = llvm::upper_bound( 272 CompileUnits, Offset, 273 [](uint64_t LHS, const std::unique_ptr<CompileUnit> &RHS) { 274 return LHS < RHS->getOrigUnit().getNextUnitOffset(); 275 }); 276 277 return CU != CompileUnits.end() ? CU->get() : nullptr; 278 }; 279 }; 280 281 /// Enumerate all compile units and assign offsets to their sections and 282 /// strings. 283 void assignOffsets(); 284 285 /// Enumerate all compile units and assign offsets to their sections. 286 void assignOffsetsToSections(); 287 288 /// Enumerate all compile units and assign offsets to their strings. 289 void assignOffsetsToStrings(); 290 291 /// Print statistic for processed Debug Info. 292 void printStatistic(); 293 294 enum StringDestinationKind : uint8_t { DebugStr, DebugLineStr }; 295 296 /// Enumerates all strings. 297 void forEachOutputString( 298 function_ref<void(StringDestinationKind, const StringEntry *)> 299 StringHandler); 300 301 /// Enumerates sections for modules, invariant for object files, compile 302 /// units. 303 void forEachObjectSectionsSet( 304 function_ref<void(OutputSections &SectionsSet)> SectionsSetHandler); 305 306 /// Enumerates all compile and type units. 307 void forEachCompileAndTypeUnit(function_ref<void(DwarfUnit *CU)> UnitHandler); 308 309 /// Enumerates all comple units. 310 void forEachCompileUnit(function_ref<void(CompileUnit *CU)> UnitHandler); 311 312 /// Enumerates all patches and update them with the correct values. 313 void patchOffsetsAndSizes(); 314 315 /// Emit debug sections common for all input files. 316 void emitCommonSectionsAndWriteCompileUnitsToTheOutput(); 317 318 /// Emit apple accelerator sections. 319 void emitAppleAcceleratorSections(const Triple &TargetTriple); 320 321 /// Emit .debug_names section. 322 void emitDWARFv5DebugNamesSection(const Triple &TargetTriple); 323 324 /// Emit string sections. 325 void emitStringSections(); 326 327 /// Cleanup data(string pools) after output sections are generated. 328 void cleanupDataAfterDWARFOutputIsWritten(); 329 330 /// Enumerate all compile units and put their data into the output stream. 331 void writeCompileUnitsToTheOutput(); 332 333 /// Enumerate common sections and put their data into the output stream. 334 void writeCommonSectionsToTheOutput(); 335 336 /// \defgroup Data members accessed asinchroniously. 337 /// 338 /// @{ 339 340 /// Unique ID for compile unit. 341 std::atomic<size_t> UniqueUnitID; 342 343 /// Mapping the PCM filename to the DwoId. 344 StringMap<uint64_t> ClangModules; 345 std::mutex ClangModulesMutex; 346 347 /// Type unit. 348 std::unique_ptr<TypeUnit> ArtificialTypeUnit; 349 /// @} 350 351 /// \defgroup Data members accessed sequentially. 352 /// 353 /// @{ 354 /// DwarfStringPoolEntries for .debug_str section. 355 StringEntryToDwarfStringPoolEntryMap DebugStrStrings; 356 357 /// DwarfStringPoolEntries for .debug_line_str section. 358 StringEntryToDwarfStringPoolEntryMap DebugLineStrStrings; 359 360 /// Keeps all linking contexts. 361 SmallVector<std::unique_ptr<LinkContext>> ObjectContexts; 362 363 /// Common sections. 364 OutputSections CommonSections; 365 366 /// Hanler for output sections. 367 SectionHandlerTy SectionHandler = nullptr; 368 369 /// Overall compile units number. 370 uint64_t OverallNumberOfCU = 0; 371 372 /// Data global for the whole linking process. 373 LinkingGlobalData GlobalData; 374 /// @} 375 }; 376 377 } // end of namespace parallel 378 } // end of namespace dwarf_linker 379 } // end of namespace llvm 380 381 #endif // LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H 382