| //===- DWARFLinker.h --------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H |
| #define LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H |
| |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/CodeGen/AsmPrinter.h" |
| #include "llvm/DWARFLinkerParallel/DWARFFile.h" |
| #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
| #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
| #include "llvm/MC/MCDwarf.h" |
| #include "llvm/TargetParser/Triple.h" |
| |
| /// ------------------------------------------------------------------ |
| /// The core of the Dwarf linking logic. |
| /// |
| /// The generation of the dwarf information from the object files will be |
| /// driven by the selection of 'root DIEs', which are DIEs that |
| /// describe variables or functions that resolves to the corresponding |
| /// code section(and thus have entries in the Addresses map). All the debug |
| /// information that will be generated(the DIEs, but also the line |
| /// tables, ranges, ...) is derived from that set of root DIEs. |
| /// |
| /// The root DIEs are identified because they contain relocations that |
| /// points to code section(the low_pc for a function, the location for |
| /// a variable). These relocations are gathered as a very first step |
| /// when we start processing a object file by AddressesMap. |
| /// |
| /// The overall linking process looks like this: |
| /// |
| /// parrallel_for_each(ObjectFile) { |
| /// for_each (Compile Unit) { |
| /// 1. Load Clang modules. |
| /// } |
| /// |
| /// parrallel_for_each(Compile Unit) { |
| /// 1. Load input DWARF for Compile Unit. |
| /// 2. Report warnings for Clang modules. |
| /// 3. Analyze live DIEs and type names(if ODR deduplication is requested). |
| /// 4. Clone DIEs(Generate output DIEs and resulting DWARF tables). |
| /// The result is in an OutDebugInfoBytes, which is an ELF file |
| /// containing DWARF tables corresponding to the current compile unit. |
| /// 5. Cleanup Input and Output DIEs. |
| /// } |
| /// |
| /// Deallocate loaded Object file. |
| /// } |
| /// |
| /// if (ODR deduplication is requested) |
| /// Generate an artificial compilation unit ("Type Table": used to partially |
| /// generate DIEs at the clone stage). |
| /// |
| /// for_each (ObjectFile) { |
| /// for_each (Compile Unit) { |
| /// 1. Set offsets to Compile Units DWARF tables. |
| /// 2. Sort offsets/attributes/patches to have a predictable result. |
| /// 3. Patch size/offsets fields. |
| /// 4. Generate index tables. |
| /// 5. Move DWARF tables of compile units into the resulting file. |
| /// } |
| /// } |
| /// |
| /// Every compile unit is processed separately, visited only once |
| /// (except case inter-CU references exist), and used data is freed |
| /// after the compile unit is processed. The resulting file is glued together |
| /// from the generated debug tables which correspond to separate compile units. |
| /// |
| /// Handling inter-CU references: inter-CU references are hard to process |
| /// using only one pass. f.e. if CU1 references CU100 and CU100 references |
| /// CU1, we could not finish handling of CU1 until we finished CU100. |
| /// Thus we either need to load all CUs into the memory, either load CUs several |
| /// times. This implementation loads inter-connected CU into memory at the first |
| /// pass and processes them at the second pass. |
| /// |
| /// ODR deduplication: Artificial compilation unit will be constructed to keep |
| /// type dies. All types are moved into that compilation unit. Type's references |
| /// are patched so that they point to the corresponding types from artificial |
| /// compilation unit. All partial type definitions would be merged into single |
| /// type definition. |
| /// |
| |
| namespace llvm { |
| namespace dwarflinker_parallel { |
| |
| /// ExtraDwarfEmitter allows adding extra data to the DWARFLinker output. |
| /// The finish() method should be called after all extra data are emitted. |
| class ExtraDwarfEmitter { |
| public: |
| virtual ~ExtraDwarfEmitter() = default; |
| |
| /// Dump the file to the disk. |
| virtual void finish() = 0; |
| |
| /// Emit section named SecName with data SecData. |
| virtual void emitSectionContents(StringRef SecData, StringRef SecName) = 0; |
| |
| /// Emit temporarily symbol named \p SymName inside section \p SecName. |
| virtual MCSymbol *emitTempSym(StringRef SecName, StringRef SymName) = 0; |
| |
| /// Emit the swift_ast section stored in \p Buffer. |
| virtual void emitSwiftAST(StringRef Buffer) = 0; |
| |
| /// Emit the swift reflection section stored in \p Buffer. |
| virtual void emitSwiftReflectionSection( |
| llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind, |
| StringRef Buffer, uint32_t Alignment, uint32_t Size) = 0; |
| |
| /// Returns underlying AsmPrinter. |
| virtual AsmPrinter &getAsmPrinter() const = 0; |
| }; |
| |
| class DWARFLinker { |
| public: |
| /// Type of output file. |
| enum class OutputFileType { |
| Object, |
| Assembly, |
| }; |
| |
| /// The kind of accelerator tables we should emit. |
| enum class AccelTableKind : uint8_t { |
| Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc. |
| Pub, ///< .debug_pubnames, .debug_pubtypes |
| DebugNames ///< .debug_names. |
| }; |
| |
| using MessageHandlerTy = std::function<void( |
| const Twine &Warning, StringRef Context, const DWARFDie *DIE)>; |
| using ObjFileLoaderTy = std::function<ErrorOr<DWARFFile &>( |
| StringRef ContainerName, StringRef Path)>; |
| using InputVerificationHandlerTy = std::function<void(const DWARFFile &File)>; |
| using ObjectPrefixMapTy = std::map<std::string, std::string>; |
| using CompileUnitHandlerTy = function_ref<void(const DWARFUnit &Unit)>; |
| using TranslatorFuncTy = std::function<StringRef(StringRef)>; |
| using SwiftInterfacesMapTy = std::map<std::string, std::string>; |
| |
| virtual ~DWARFLinker() = default; |
| |
| /// Creates dwarf linker instance. |
| static std::unique_ptr<DWARFLinker> |
| createLinker(MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler, |
| TranslatorFuncTy StringsTranslator = nullptr); |
| |
| /// Creates emitter for output dwarf. |
| virtual Error createEmitter(const Triple &TheTriple, OutputFileType FileType, |
| raw_pwrite_stream &OutFile) = 0; |
| |
| /// Returns previously created dwarf emitter. May be nullptr. |
| virtual ExtraDwarfEmitter *getEmitter() = 0; |
| |
| /// Add object file to be linked. Pre-load compile unit die. Call |
| /// \p OnCUDieLoaded for each compile unit die. If specified \p File |
| /// has reference to the Clang module then such module would be |
| /// pre-loaded by \p Loader for !Update case. |
| /// |
| /// \pre NoODR, Update options should be set before call to addObjectFile. |
| virtual void addObjectFile( |
| DWARFFile &File, ObjFileLoaderTy Loader = nullptr, |
| CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) = 0; |
| |
| /// Link debug info for added files. |
| virtual Error link() = 0; |
| |
| /// \defgroup Methods setting various linking options: |
| /// |
| /// @{ |
| |
| /// Allows to generate log of linking process to the standard output. |
| virtual void setVerbosity(bool Verbose) = 0; |
| |
| /// Print statistics to standard output. |
| virtual void setStatistics(bool Statistics) = 0; |
| |
| /// Verify the input DWARF. |
| virtual void setVerifyInputDWARF(bool Verify) = 0; |
| |
| /// Do not unique types according to ODR. |
| virtual void setNoODR(bool NoODR) = 0; |
| |
| /// Update index tables only(do not modify rest of DWARF). |
| virtual void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) = 0; |
| |
| /// Allow generating valid, but non-deterministic output. |
| virtual void |
| setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) = 0; |
| |
| /// Set to keep the enclosing function for a static variable. |
| virtual void setKeepFunctionForStatic(bool KeepFunctionForStatic) = 0; |
| |
| /// Use specified number of threads for parallel files linking. |
| virtual void setNumThreads(unsigned NumThreads) = 0; |
| |
| /// Add kind of accelerator tables to be generated. |
| virtual void addAccelTableKind(AccelTableKind Kind) = 0; |
| |
| /// Set prepend path for clang modules. |
| virtual void setPrependPath(const std::string &Ppath) = 0; |
| |
| /// Set estimated objects files amount, for preliminary data allocation. |
| virtual void setEstimatedObjfilesAmount(unsigned ObjFilesNum) = 0; |
| |
| /// Set verification handler which would be used to report verification |
| /// errors. |
| virtual void |
| setInputVerificationHandler(InputVerificationHandlerTy Handler) = 0; |
| |
| /// Set map for Swift interfaces. |
| virtual void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) = 0; |
| |
| /// Set prefix map for objects. |
| virtual void setObjectPrefixMap(ObjectPrefixMapTy *Map) = 0; |
| |
| /// Set target DWARF version. |
| virtual Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) = 0; |
| /// @} |
| }; |
| |
| } // end namespace dwarflinker_parallel |
| } // end namespace llvm |
| |
| #endif // LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H |