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. setOutputDWARFHandler(const Triple & TargetTriple,SectionHandlerTy SectionHandler)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. setVerbosity(bool Verbose)59 void setVerbosity(bool Verbose) override { 60 GlobalData.Options.Verbose = Verbose; 61 } 62 63 /// Print statistics to standard output. setStatistics(bool Statistics)64 void setStatistics(bool Statistics) override { 65 GlobalData.Options.Statistics = Statistics; 66 } 67 68 /// Verify the input DWARF. setVerifyInputDWARF(bool Verify)69 void setVerifyInputDWARF(bool Verify) override { 70 GlobalData.Options.VerifyInputDWARF = Verify; 71 } 72 73 /// Do not unique types according to ODR. setNoODR(bool NoODR)74 void setNoODR(bool NoODR) override { GlobalData.Options.NoODR = NoODR; } 75 76 /// Update index tables only(do not modify rest of DWARF). setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly)77 void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override { 78 GlobalData.Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly; 79 } 80 81 /// Allow generating valid, but non-deterministic output. 82 void setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput)83 setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override { 84 GlobalData.Options.AllowNonDeterministicOutput = 85 AllowNonDeterministicOutput; 86 } 87 88 /// Set to keep the enclosing function for a static variable. setKeepFunctionForStatic(bool KeepFunctionForStatic)89 void setKeepFunctionForStatic(bool KeepFunctionForStatic) override { 90 GlobalData.Options.KeepFunctionForStatic = KeepFunctionForStatic; 91 } 92 93 /// Use specified number of threads for parallel files linking. setNumThreads(unsigned NumThreads)94 void setNumThreads(unsigned NumThreads) override { 95 GlobalData.Options.Threads = NumThreads; 96 } 97 98 /// Add kind of accelerator tables to be generated. addAccelTableKind(AccelTableKind Kind)99 void addAccelTableKind(AccelTableKind Kind) override { 100 assert(!llvm::is_contained(GlobalData.getOptions().AccelTables, Kind)); 101 GlobalData.Options.AccelTables.emplace_back(Kind); 102 } 103 104 /// Set prepend path for clang modules. setPrependPath(StringRef Ppath)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 setInputVerificationHandler(InputVerificationHandlerTy Handler)115 setInputVerificationHandler(InputVerificationHandlerTy Handler) override { 116 GlobalData.Options.InputVerificationHandler = Handler; 117 } 118 119 /// Set map for Swift interfaces. setSwiftInterfacesMap(SwiftInterfacesMapTy * Map)120 void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override { 121 GlobalData.Options.ParseableSwiftInterfaces = Map; 122 } 123 124 /// Set prefix map for objects. setObjectPrefixMap(ObjectPrefixMapTy * Map)125 void setObjectPrefixMap(ObjectPrefixMapTy *Map) override { 126 GlobalData.Options.ObjectPrefixMap = Map; 127 } 128 129 /// Set target DWARF version. setTargetDWARFVersion(uint16_t TargetDWARFVersion)130 Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override { 131 if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5)) 132 return createStringError(std::errc::invalid_argument, 133 "unsupported DWARF version: %d", 134 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. getInputDebugInfoSizeLinkContext238 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 CompileUnits, Offset, 272 [](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