381 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H10#define LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H11 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 21namespace llvm {22namespace dwarf_linker {23namespace parallel {24 25/// This class links debug info.26class DWARFLinkerImpl : public DWARFLinker {27public:28 DWARFLinkerImpl(MessageHandlerTy ErrorHandler,29 MessageHandlerTy WarningHandler);30 31 /// Add object file to be linked. Pre-load compile unit die. Call32 /// \p OnCUDieLoaded for each compile unit die. If specified \p File33 /// has reference to the Clang module then such module would be34 /// 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 not46 /// 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 void83 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(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 verification113 /// errors.114 void115 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(std::errc::invalid_argument,133 "unsupported DWARF version: %d",134 TargetDWARFVersion);135 136 GlobalData.Options.TargetDWARFVersion = TargetDWARFVersion;137 return Error::success();138 }139 /// @}140 141protected: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 data160 /// 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 info165 /// 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 loaded189 /// 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 were195 /// discovered. It is used for restarting units processing196 /// 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 a217 /// clang module, register it in ClangModules and return true.218 ///219 /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name220 /// pointing to the module, and a DW_AT_gnu_dwo_id with the module221 /// 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 .pcm227 /// 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 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 and281 /// 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, compile301 /// 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 parallel377} // end of namespace dwarf_linker378} // end of namespace llvm379 380#endif // LLVM_LIB_DWARFLINKER_PARALLEL_DWARFLINKERIMPL_H381