diff --git a/llvm/include/llvm/DWARFLinker/DWARFLinker.h b/llvm/include/llvm/DWARFLinker/DWARFLinker.h --- a/llvm/include/llvm/DWARFLinker/DWARFLinker.h +++ b/llvm/include/llvm/DWARFLinker/DWARFLinker.h @@ -14,6 +14,7 @@ #include "llvm/CodeGen/AccelTable.h" #include "llvm/CodeGen/NonRelocatableStringpool.h" #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" @@ -21,7 +22,6 @@ #include namespace llvm { -class DWARFContext; class DWARFExpression; class DWARFUnit; class DataExtractor; @@ -30,13 +30,6 @@ enum class DwarfLinkerClient { Dsymutil, LLD, General }; -/// The kind of accelerator tables we should emit. -enum class DwarfLinkerAccelTableKind : uint8_t { - Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc. - Pub, ///< .debug_pubnames, .debug_pubtypes - DebugNames ///< .debug_names. -}; - /// AddressesMap represents information about valid addresses used /// by debug information. Valid addresses are those which points to /// live code sections. i.e. relocations for these addresses point @@ -221,39 +214,48 @@ /// Returns size of generated .debug_loclists section. virtual uint64_t getLocListsSectionSize() const = 0; + + /// Dump the file to the disk. + virtual void finish() = 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 DwarfStreamer; using UnitListTy = std::vector>; /// This class represents DWARF information for source file /// and its address map. class DWARFFile { public: - DWARFFile(StringRef Name, DWARFContext *Dwarf, AddressesMap *Addresses, + DWARFFile(StringRef Name, std::unique_ptr Dwarf, + std::unique_ptr Addresses, const std::vector &Warnings) - : FileName(Name), Dwarf(Dwarf), Addresses(Addresses), Warnings(Warnings) { - } + : FileName(Name), Dwarf(std::move(Dwarf)), + Addresses(std::move(Addresses)), Warnings(Warnings) {} /// The object file name. StringRef FileName; /// The source DWARF information. - DWARFContext *Dwarf = nullptr; + std::unique_ptr Dwarf; /// Helpful address information(list of valid address ranges, relocations). - AddressesMap *Addresses = nullptr; + std::unique_ptr Addresses; /// Warnings for this object file. const std::vector &Warnings; }; -typedef std::function - messageHandler; -typedef std::function inputVerificationHandler; -typedef std::function(StringRef ContainerName, - StringRef Path)> - objFileLoader; typedef std::map swiftInterfacesMap; typedef std::map objectPrefixMap; @@ -275,9 +277,43 @@ /// processing a object file. class DWARFLinker { public: - DWARFLinker(DwarfEmitter *Emitter, - DwarfLinkerClient ClientID = DwarfLinkerClient::General) - : TheDwarfEmitter(Emitter), DwarfLinkerClientID(ClientID) {} + typedef std::function + messageHandler; + DWARFLinker(messageHandler ErrorHandler, messageHandler WarningHandler, + std::function StringsTranslator) + : DwarfLinkerClientID(DwarfLinkerClient::Dsymutil), + StringsTranslator(StringsTranslator), ErrorHandler(ErrorHandler), + WarningHandler(WarningHandler) {} + + static std::unique_ptr createLinker( + messageHandler ErrorHandler, messageHandler WarningHandler, + std::function StringsTranslator = nullptr) { + return std::make_unique(ErrorHandler, WarningHandler, + StringsTranslator); + } + + /// 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. + }; + typedef std::function inputVerificationHandler; + typedef std::function(StringRef ContainerName, + StringRef Path)> + objFileLoader; + + Error createEmitter(const Triple &TheTriple, OutputFileType FileType, + raw_pwrite_stream &OutFile); + + DwarfEmitter *getEmitter(); /// Add object file to be linked. Pre-load compile unit die. Call /// \p OnCUDieLoaded for each compile unit die. If specified \p File @@ -289,8 +325,7 @@ DWARFFile &File, objFileLoader Loader = nullptr, CompileUnitHandler OnCUDieLoaded = [](const DWARFUnit &) {}); - /// Link debug info for added objFiles. Object - /// files are linked all together. + /// Link debug info for added objFiles. Object files are linked all together. Error link(); /// A number of methods setting various linking options: @@ -304,14 +339,15 @@ /// Verify the input DWARF. void setVerifyInputDWARF(bool Verify) { Options.VerifyInputDWARF = Verify; } - /// Do not emit linked dwarf info. - void setNoOutput(bool NoOut) { Options.NoOutput = NoOut; } - /// Do not unique types according to ODR. void setNoODR(bool NoODR) { Options.NoODR = NoODR; } - /// update existing DWARF info(for the linked binary). - void setUpdate(bool Update) { Options.Update = Update; } + /// Update index tables only(do not modify rest of DWARF). + void setUpdateIndexTablesOnly(bool Update) { Options.Update = Update; } + + /// Allow generating valid, but non-deterministic output. + void setAllowNonDeterministicOutput(bool) { /* Nothing to do. */ + } /// Set whether to keep the enclosing function for a static variable. void setKeepFunctionForStatic(bool KeepFunctionForStatic) { @@ -322,7 +358,7 @@ void setNumThreads(unsigned NumThreads) { Options.Threads = NumThreads; } /// Add kind of accelerator tables to be generated. - void addAccelTableKind(DwarfLinkerAccelTableKind Kind) { + void addAccelTableKind(AccelTableKind Kind) { assert(std::find(Options.AccelTables.begin(), Options.AccelTables.end(), Kind) == Options.AccelTables.end()); Options.AccelTables.emplace_back(Kind); @@ -331,27 +367,11 @@ /// Set prepend path for clang modules. void setPrependPath(const std::string &Ppath) { Options.PrependPath = Ppath; } - /// Set translator which would be used for strings. - void - setStringsTranslator(std::function StringsTranslator) { - this->StringsTranslator = StringsTranslator; - } - /// Set estimated objects files amount, for preliminary data allocation. void setEstimatedObjfilesAmount(unsigned ObjFilesNum) { ObjectContexts.reserve(ObjFilesNum); } - /// Set warning handler which would be used to report warnings. - void setWarningHandler(messageHandler Handler) { - Options.WarningHandler = Handler; - } - - /// Set error handler which would be used to report errors. - void setErrorHandler(messageHandler Handler) { - Options.ErrorHandler = Handler; - } - /// Set verification handler which would be used to report verification /// errors. void setInputVerificationHandler(inputVerificationHandler Handler) { @@ -370,7 +390,7 @@ /// Set target DWARF version. Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) { - if (TargetDWARFVersion < 1 || TargetDWARFVersion > 5) + if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5)) return createStringError(std::errc::invalid_argument, "unsupported DWARF version: %d", TargetDWARFVersion); @@ -444,14 +464,14 @@ void reportWarning(const Twine &Warning, const DWARFFile &File, const DWARFDie *DIE = nullptr) const { - if (Options.WarningHandler != nullptr) - Options.WarningHandler(Warning, File.FileName, DIE); + if (WarningHandler != nullptr) + WarningHandler(Warning, File.FileName, DIE); } void reportError(const Twine &Warning, const DWARFFile &File, const DWARFDie *DIE = nullptr) const { - if (Options.ErrorHandler != nullptr) - Options.ErrorHandler(Warning, File.FileName, DIE); + if (ErrorHandler != nullptr) + ErrorHandler(Warning, File.FileName, DIE); } /// Emit warnings as Dwarf compile units to leave a trail after linking. @@ -799,7 +819,7 @@ BumpPtrAllocator DIEAlloc; /// @} - DwarfEmitter *TheDwarfEmitter; + std::unique_ptr TheDwarfEmitter; std::vector ObjectContexts; /// The CIEs that have been emitted in the output section. The actual CIE @@ -828,6 +848,12 @@ /// A unique ID that identifies each compile unit. unsigned UniqueUnitID = 0; + // error handler + messageHandler ErrorHandler = nullptr; + + // warning handler + messageHandler WarningHandler = nullptr; + /// linking options struct DWARFLinkerOptions { /// DWARF version for the output. @@ -842,9 +868,6 @@ /// Verify the input DWARF. bool VerifyInputDWARF = false; - /// Skip emitting output - bool NoOutput = false; - /// Do not unique types according to ODR bool NoODR = false; @@ -859,17 +882,11 @@ unsigned Threads = 1; /// The accelerator table kinds - SmallVector AccelTables; + SmallVector AccelTables; /// Prepend path for the clang modules. std::string PrependPath; - // warning handler - messageHandler WarningHandler = nullptr; - - // error handler - messageHandler ErrorHandler = nullptr; - // input verification handler inputVerificationHandler InputVerificationHandler = nullptr; diff --git a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h --- a/llvm/include/llvm/DWARFLinker/DWARFStreamer.h +++ b/llvm/include/llvm/DWARFLinker/DWARFStreamer.h @@ -23,11 +23,6 @@ namespace llvm { template class AccelTable; -enum class OutputFileType { - Object, - Assembly, -}; - /// User of DwarfStreamer should call initialization code /// for AsmPrinter: /// @@ -45,18 +40,19 @@ /// information binary representation are handled in this class. class DwarfStreamer : public DwarfEmitter { public: - DwarfStreamer(OutputFileType OutFileType, raw_pwrite_stream &OutFile, + DwarfStreamer(DWARFLinker::OutputFileType OutFileType, + raw_pwrite_stream &OutFile, std::function Translator, - messageHandler Error, messageHandler Warning) + DWARFLinker::messageHandler Warning) : OutFile(OutFile), OutFileType(OutFileType), Translator(Translator), - ErrorHandler(Error), WarningHandler(Warning) {} + WarningHandler(Warning) {} - bool init(Triple TheTriple, StringRef Swift5ReflectionSegmentName); + Error init(Triple TheTriple, StringRef Swift5ReflectionSegmentName); /// Dump the file to the disk. - void finish(); + void finish() override; - AsmPrinter &getAsmPrinter() const { return *Asm; } + AsmPrinter &getAsmPrinter() const override { return *Asm; } /// Set the current output section to debug_info and change /// the MC Dwarf version to \p DwarfVersion. @@ -89,12 +85,12 @@ void emitLineStrings(const NonRelocatableStringpool &Pool) override; /// Emit the swift_ast section stored in \p Buffer. - void emitSwiftAST(StringRef Buffer); + void emitSwiftAST(StringRef Buffer) override; /// Emit the swift reflection section stored in \p Buffer. void emitSwiftReflectionSection( llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind, - StringRef Buffer, uint32_t Alignment, uint32_t Size); + StringRef Buffer, uint32_t Alignment, uint32_t Size) override; /// Emit debug ranges(.debug_ranges, .debug_rnglists) header. MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) override; @@ -194,11 +190,6 @@ OffsetsStringPool &StringPool) override; private: - inline void error(const Twine &Error, StringRef Context = "") { - if (ErrorHandler) - ErrorHandler(Error, Context, nullptr); - } - inline void warn(const Twine &Warning, StringRef Context = "") { if (WarningHandler) WarningHandler(Warning, Context, nullptr); @@ -274,7 +265,7 @@ /// The output file we stream the linked Dwarf to. raw_pwrite_stream &OutFile; - OutputFileType OutFileType = OutputFileType::Object; + DWARFLinker::OutputFileType OutFileType = DWARFLinker::OutputFileType::Object; std::function Translator; uint64_t RangesSectionSize = 0; @@ -300,8 +291,7 @@ const CompileUnit &Unit, const std::vector &Names); - messageHandler ErrorHandler = nullptr; - messageHandler WarningHandler = nullptr; + DWARFLinker::messageHandler WarningHandler = nullptr; }; } // end namespace llvm diff --git a/llvm/include/llvm/DWARFLinkerParallel/DWARFFile.h b/llvm/include/llvm/DWARFLinkerParallel/DWARFFile.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/DWARFLinkerParallel/DWARFFile.h @@ -0,0 +1,73 @@ +//===- DWARFFile.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_DWARFFILE_H +#define LLVM_DWARFLINKERPARALLEL_DWARFFILE_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DWARFLinkerParallel/AddressesMap.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Support/Endian.h" +#include +#include + +namespace llvm { +namespace dwarflinker_parallel { + +/// This class represents DWARF information for source file +/// and it's address map. +/// +/// May be used asynchroniously for reading. +class DWARFFile { +public: + using UnloadCallbackTy = std::function; + + DWARFFile(StringRef Name, std::unique_ptr Dwarf, + std::unique_ptr Addresses, + const std::vector &Warnings, + UnloadCallbackTy UnloadFunc = nullptr) + : FileName(Name), Dwarf(std::move(Dwarf)), + Addresses(std::move(Addresses)), Warnings(Warnings), + UnloadFunc(UnloadFunc) { + if (this->Dwarf) + Endianess = this->Dwarf->isLittleEndian() ? support::endianness::little + : support::endianness::big; + } + + /// Object file name. + StringRef FileName; + + /// Source DWARF information. + std::unique_ptr Dwarf; + + /// Helpful address information(list of valid address ranges, relocations). + std::unique_ptr Addresses; + + /// Warnings for object file. + const std::vector &Warnings; + + /// Endiannes of source DWARF information. + support::endianness Endianess = support::endianness::little; + + /// Callback to the module keeping object file to unload. + UnloadCallbackTy UnloadFunc; + + /// Unloads object file and corresponding AddressesMap and Dwarf Context. + void unload() { + Addresses.reset(); + Dwarf.reset(); + + if (UnloadFunc) + UnloadFunc(FileName); + } +}; + +} // end namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_DWARFLINKERPARALLEL_DWARFFILE_H diff --git a/llvm/include/llvm/DWARFLinkerParallel/DWARFLinker.h b/llvm/include/llvm/DWARFLinkerParallel/DWARFLinker.h --- a/llvm/include/llvm/DWARFLinkerParallel/DWARFLinker.h +++ b/llvm/include/llvm/DWARFLinkerParallel/DWARFLinker.h @@ -9,10 +9,219 @@ #ifndef LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H #define LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H -#include "llvm/DWARFLinkerParallel/AddressesMap.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 {} // end namespace dwarflinker_parallel +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; + using ObjFileLoaderTy = std::function( + StringRef ContainerName, StringRef Path)>; + using InputVerificationHandlerTy = std::function; + using ObjectPrefixMapTy = std::map; + using CompileUnitHandlerTy = function_ref; + using TranslatorFuncTy = std::function; + using SwiftInterfacesMapTy = std::map; + + virtual ~DWARFLinker() = default; + + /// Creates dwarf linker instance. + static std::unique_ptr + 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 diff --git a/llvm/include/llvm/DWARFLinkerParallel/StringTable.h b/llvm/include/llvm/DWARFLinkerParallel/StringTable.h --- a/llvm/include/llvm/DWARFLinkerParallel/StringTable.h +++ b/llvm/include/llvm/DWARFLinkerParallel/StringTable.h @@ -67,6 +67,10 @@ Handler(*Entry); } + std::function getTranslator() { + return StringsTranslator; + } + protected: /// List of strings for emission. StringsVector StringEntriesForEmission; diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -43,6 +43,9 @@ class raw_ostream; struct DIDumpOptions; struct DWARFSection; +namespace dwarflinker_parallel { +class CompileUnit; +} /// Base class describing the header of any kind of "unit." Some information /// is specific to certain unit types. We separate this class out so we can @@ -253,6 +256,8 @@ std::shared_ptr DWO; protected: + friend dwarflinker_parallel::CompileUnit; + /// Return the index of a \p Die entry inside the unit's DIE vector. /// /// It is illegal to call this method with a DIE that hasn't be diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/NonRelocatableStringpool.h" #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" +#include "llvm/DWARFLinker/DWARFStreamer.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" @@ -2056,7 +2057,7 @@ } void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) { - if (LLVM_UNLIKELY(Linker.Options.NoOutput)) + if (LLVM_UNLIKELY(Emitter == nullptr)) return; // Check whether DW_AT_stmt_list attribute is presented. @@ -2177,9 +2178,9 @@ } void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) { - for (DwarfLinkerAccelTableKind AccelTableKind : Options.AccelTables) { + for (AccelTableKind AccelTableKind : Options.AccelTables) { switch (AccelTableKind) { - case DwarfLinkerAccelTableKind::Apple: { + case AccelTableKind::Apple: { // Add namespaces. for (const auto &Namespace : Unit.getNamespaces()) AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() + @@ -2201,11 +2202,11 @@ AppleObjc.addName(ObjC.Name, ObjC.Die->getOffset() + Unit.getStartOffset()); } break; - case DwarfLinkerAccelTableKind::Pub: { + case AccelTableKind::Pub: { TheDwarfEmitter->emitPubNamesForUnit(Unit); TheDwarfEmitter->emitPubTypesForUnit(Unit); } break; - case DwarfLinkerAccelTableKind::DebugNames: { + case AccelTableKind::DebugNames: { for (const auto &Namespace : Unit.getNamespaces()) DebugNames.addName(Namespace.Name, Namespace.Die->getOffset(), Namespace.Die->getTag(), Unit.getUniqueID()); @@ -2524,7 +2525,7 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits( DWARFContext &DwarfContext, const DWARFFile &File, bool IsLittleEndian) { uint64_t OutputDebugInfoSize = - Linker.Options.NoOutput ? 0 : Emitter->getDebugInfoSectionSize(); + (Emitter == nullptr) ? 0 : Emitter->getDebugInfoSectionSize(); const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize; for (auto &CurrentUnit : CompileUnits) { @@ -2547,8 +2548,7 @@ OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion); - if (!Linker.Options.NoOutput) { - assert(Emitter); + if (Emitter != nullptr) { generateLineTableForUnit(*CurrentUnit); @@ -2575,10 +2575,10 @@ } } - if (!Linker.Options.NoOutput) { + if (Emitter != nullptr) { assert(Emitter); // Emit macro tables. - Emitter->emitMacroTables(File.Dwarf, UnitMacroMap, DebugStrPool); + Emitter->emitMacroTables(File.Dwarf.get(), UnitMacroMap, DebugStrPool); // Emit all the compile unit's debug information. for (auto &CurrentUnit : CompileUnits) { @@ -2703,7 +2703,6 @@ } Error DWARFLinker::link() { - assert(Options.NoOutput || TheDwarfEmitter); assert((Options.TargetDWARFVersion != 0) && "TargetDWARFVersion should be set"); @@ -2793,7 +2792,8 @@ // later. This prevents undeterminism when analyze and clone execute // concurrently, as clone set the canonical DIE offset and analyze reads it. const uint64_t ModulesEndOffset = - Options.NoOutput ? 0 : TheDwarfEmitter->getDebugInfoSectionSize(); + (TheDwarfEmitter == nullptr) ? 0 + : TheDwarfEmitter->getDebugInfoSectionSize(); // These variables manage the list of processed object files. // The mutex and condition variable are to ensure that this is thread safe. @@ -2878,13 +2878,13 @@ SizeByObject[OptContext.File.FileName].Input = getDebugInfoSize(*OptContext.File.Dwarf); SizeByObject[OptContext.File.FileName].Output = - DIECloner(*this, TheDwarfEmitter, OptContext.File, DIEAlloc, + DIECloner(*this, TheDwarfEmitter.get(), OptContext.File, DIEAlloc, OptContext.CompileUnits, Options.Update, DebugStrPool, DebugLineStrPool) .cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File, OptContext.File.Dwarf->isLittleEndian()); } - if (!Options.NoOutput && !OptContext.CompileUnits.empty() && + if ((TheDwarfEmitter != nullptr) && !OptContext.CompileUnits.empty() && LLVM_LIKELY(!Options.Update)) patchFrameInfoForObject( OptContext.File, OptContext.File.Addresses->getValidAddressRanges(), @@ -2897,23 +2897,23 @@ auto EmitLambda = [&]() { // Emit everything that's global. - if (!Options.NoOutput) { + if (TheDwarfEmitter != nullptr) { TheDwarfEmitter->emitAbbrevs(Abbreviations, Options.TargetDWARFVersion); TheDwarfEmitter->emitStrings(DebugStrPool); TheDwarfEmitter->emitLineStrings(DebugLineStrPool); - for (DwarfLinkerAccelTableKind TableKind : Options.AccelTables) { + for (AccelTableKind TableKind : Options.AccelTables) { switch (TableKind) { - case DwarfLinkerAccelTableKind::Apple: + case AccelTableKind::Apple: TheDwarfEmitter->emitAppleNamespaces(AppleNamespaces); TheDwarfEmitter->emitAppleNames(AppleNames); TheDwarfEmitter->emitAppleTypes(AppleTypes); TheDwarfEmitter->emitAppleObjc(AppleObjc); break; - case DwarfLinkerAccelTableKind::Pub: + case AccelTableKind::Pub: // Already emitted by emitAcceleratorEntriesForUnit. // Already emitted by emitAcceleratorEntriesForUnit. break; - case DwarfLinkerAccelTableKind::DebugNames: + case AccelTableKind::DebugNames: TheDwarfEmitter->emitDebugNames(DebugNames); break; } @@ -3041,7 +3041,7 @@ UnitListTy CompileUnits; CompileUnits.emplace_back(std::move(Unit.Unit)); assert(TheDwarfEmitter); - DIECloner(*this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits, + DIECloner(*this, TheDwarfEmitter.get(), Unit.File, DIEAlloc, CompileUnits, Options.Update, DebugStrPool, DebugLineStrPool) .cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File, Unit.File.Dwarf->isLittleEndian()); @@ -3059,4 +3059,16 @@ } } +Error DWARFLinker::createEmitter(const Triple &TheTriple, + OutputFileType FileType, + raw_pwrite_stream &OutFile) { + + TheDwarfEmitter = std::make_unique( + FileType, OutFile, StringsTranslator, WarningHandler); + + return TheDwarfEmitter->init(TheTriple, "__DWARF"); +} + +DwarfEmitter *DWARFLinker::getEmitter() { return TheDwarfEmitter.get(); } + } // namespace llvm diff --git a/llvm/lib/DWARFLinker/DWARFStreamer.cpp b/llvm/lib/DWARFLinker/DWARFStreamer.cpp --- a/llvm/lib/DWARFLinker/DWARFStreamer.cpp +++ b/llvm/lib/DWARFLinker/DWARFStreamer.cpp @@ -28,33 +28,37 @@ namespace llvm { -bool DwarfStreamer::init(Triple TheTriple, - StringRef Swift5ReflectionSegmentName) { +Error DwarfStreamer::init(Triple TheTriple, + StringRef Swift5ReflectionSegmentName) { std::string ErrorStr; std::string TripleName; - StringRef Context = "dwarf streamer init"; // Get the target. const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); if (!TheTarget) - return error(ErrorStr, Context), false; + return createStringError(std::errc::invalid_argument, ErrorStr.c_str()); + TripleName = TheTriple.getTriple(); // Create all the MC Objects. MRI.reset(TheTarget->createMCRegInfo(TripleName)); if (!MRI) - return error(Twine("no register info for target ") + TripleName, Context), - false; + return createStringError(std::errc::invalid_argument, + "no register info for target %s", + TripleName.c_str()); MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags(); MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); if (!MAI) - return error("no asm info for target " + TripleName, Context), false; + return createStringError(std::errc::invalid_argument, + "no asm info for target %s", TripleName.c_str()); MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); if (!MSTI) - return error("no subtarget info for target " + TripleName, Context), false; + return createStringError(std::errc::invalid_argument, + "no subtarget info for target %s", + TripleName.c_str()); MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr, nullptr, true, Swift5ReflectionSegmentName)); @@ -63,18 +67,24 @@ MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions); if (!MAB) - return error("no asm backend for target " + TripleName, Context), false; + return createStringError(std::errc::invalid_argument, + "no asm backend for target %s", + TripleName.c_str()); MII.reset(TheTarget->createMCInstrInfo()); if (!MII) - return error("no instr info info for target " + TripleName, Context), false; + return createStringError(std::errc::invalid_argument, + "no instr info info for target %s", + TripleName.c_str()); MCE = TheTarget->createMCCodeEmitter(*MII, *MC); if (!MCE) - return error("no code emitter for target " + TripleName, Context), false; + return createStringError(std::errc::invalid_argument, + "no code emitter for target %s", + TripleName.c_str()); switch (OutFileType) { - case OutputFileType::Assembly: { + case DWARFLinker::OutputFileType::Assembly: { MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(), *MAI, *MII, *MRI); MS = TheTarget->createAsmStreamer( @@ -83,7 +93,7 @@ true); break; } - case OutputFileType::Object: { + case DWARFLinker::OutputFileType::Object: { MS = TheTarget->createMCObjectStreamer( TheTriple, *MC, std::unique_ptr(MAB), MAB->createObjectWriter(OutFile), std::unique_ptr(MCE), @@ -94,17 +104,23 @@ } if (!MS) - return error("no object streamer for target " + TripleName, Context), false; + return createStringError(std::errc::invalid_argument, + "no object streamer for target %s", + TripleName.c_str()); // Finally create the AsmPrinter we'll use to emit the DIEs. TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(), std::nullopt)); if (!TM) - return error("no target machine for target " + TripleName, Context), false; + return createStringError(std::errc::invalid_argument, + "no target machine for target %s", + TripleName.c_str()); Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr(MS))); if (!Asm) - return error("no asm printer for target " + TripleName, Context), false; + return createStringError(std::errc::invalid_argument, + "no asm printer for target %s", + TripleName.c_str()); Asm->setDwarfUsesRelocationsAcrossSections(false); RangesSectionSize = 0; @@ -117,7 +133,7 @@ MacInfoSectionSize = 0; MacroSectionSize = 0; - return true; + return Error::success(); } void DwarfStreamer::finish() { MS->finish(); } diff --git a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt --- a/llvm/lib/DWARFLinkerParallel/CMakeLists.txt +++ b/llvm/lib/DWARFLinkerParallel/CMakeLists.txt @@ -1,5 +1,8 @@ add_llvm_component_library(LLVMDWARFLinkerParallel + DWARFEmitterImpl.cpp DWARFLinker.cpp + DWARFLinkerImpl.cpp + OutputSections.cpp StringPool.cpp ADDITIONAL_HEADER_DIRS diff --git a/llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.h b/llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.h new file mode 100644 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.h @@ -0,0 +1,274 @@ +//===- DwarfEmitterImpl.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_LIB_DWARFLINKERPARALLEL_DWARFEMITTERIMPL_H +#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFEMITTERIMPL_H + +#include "DWARFLinkerCompileUnit.h" +#include "llvm/BinaryFormat/Swift.h" +#include "llvm/CodeGen/AccelTable.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/DWARFLinkerParallel/DWARFLinker.h" +#include "llvm/DWARFLinkerParallel/StringTable.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { + +/// User of DwarfEmitterImpl should call initialization code +/// for AsmPrinter: +/// +/// InitializeAllTargetInfos(); +/// InitializeAllTargetMCs(); +/// InitializeAllTargets(); +/// InitializeAllAsmPrinters(); + +template class AccelTable; +class MCCodeEmitter; +class DWARFDebugMacro; + +namespace dwarflinker_parallel { + +struct UnitStartSymbol { + unsigned UnitID = 0; + MCSymbol *Symbol = 0; +}; +using UnitStartSymbolsTy = SmallVector; +using Offset2UnitMapTy = DenseMap; + +struct RangeAttrPatch; +struct LocAttrPatch; + +/// The Dwarf emission logic. +/// +/// All interactions with the MC layer that is used to build the debug +/// information binary representation are handled in this class. +class DwarfEmitterImpl : public ExtraDwarfEmitter { +public: + DwarfEmitterImpl(DWARFLinker::OutputFileType OutFileType, + raw_pwrite_stream &OutFile, + std::function Translator, + DWARFLinker::MessageHandlerTy Warning) + : OutFile(OutFile), OutFileType(OutFileType), Translator(Translator), + WarningHandler(Warning) {} + + Error init(Triple TheTriple, StringRef Swift5ReflectionSegmentName); + + /// Dump the file to the disk. + void finish() override { MS->finish(); } + + AsmPrinter &getAsmPrinter() const override { return *Asm; } + + /// Set the current output section to debug_info and change + /// the MC Dwarf version to \p DwarfVersion. + void switchToDebugInfoSection(unsigned DwarfVersion) {} + + /// Emit the swift_ast section stored in \p Buffer. + void emitSwiftAST(StringRef Buffer) override {} + + /// Emit the swift reflection section stored in \p Buffer. + void emitSwiftReflectionSection( + llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind, + StringRef Buffer, uint32_t Alignment, uint32_t Size) override {} + + void emitPaperTrailWarningsDie(DIE &Die) {} + + void emitSectionContents(StringRef SecData, StringRef SecName) override {} + + MCSymbol *emitTempSym(StringRef SecName, StringRef SymName) override { + return nullptr; + } + + void emitAbbrevs(const SmallVector> &Abbrevs, + unsigned DwarfVersion) {} + + void emitStrings(const StringTable &Strings) {} + + void emitLineStrings(const StringTable &Strings) {} + + void emitDebugNames(AccelTable &, + UnitStartSymbolsTy &UnitOffsets) {} + + void emitAppleNamespaces(AccelTable &) {} + + void emitAppleNames(AccelTable &) {} + + void emitAppleObjc(AccelTable &) {} + + void emitAppleTypes(AccelTable &) {} + + MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) { + return nullptr; + } + + void emitDwarfDebugRangeListFragment(const CompileUnit &Unit, + const AddressRanges &LinkedRanges, + RangeAttrPatch &Patch) {} + + void emitDwarfDebugRangeListFooter(const CompileUnit &Unit, + MCSymbol *EndLabel) {} + + MCSymbol *emitDwarfDebugLocListHeader(const CompileUnit &Unit) { + return nullptr; + } + + void emitDwarfDebugLocListFragment( + const CompileUnit &Unit, + const DWARFLocationExpressionsVector &LinkedLocationExpression, + LocAttrPatch &Patch) {} + + void emitDwarfDebugLocListFooter(const CompileUnit &Unit, + MCSymbol *EndLabel) {} + + void emitDwarfDebugArangesTable(const CompileUnit &Unit, + const AddressRanges &LinkedRanges) {} + + void translateLineTable(DataExtractor LineData, uint64_t Offset) {} + + void emitLineTableForUnit(MCDwarfLineTableParams Params, + StringRef PrologueBytes, unsigned MinInstLength, + std::vector &Rows, + unsigned AdddressSize) {} + + void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable, + const CompileUnit &Unit, const StringTable &Strings, + const StringTable &LineTableStrings) {} + + void emitPubNamesForUnit(const CompileUnit &Unit) {} + + void emitPubTypesForUnit(const CompileUnit &Unit) {} + + void emitCIE(StringRef CIEBytes) {} + + void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint64_t Address, + StringRef Bytes) {} + + void emitCompileUnitHeader(CompileUnit &Unit, unsigned DwarfVersion) {} + + void emitDIE(DIE &Die) {} + + void emitMacroTables(DWARFContext *Context, + const Offset2UnitMapTy &UnitMacroMap, + StringTable &Strings) {} + + /// Returns size of generated .debug_line section. + uint64_t getDebugLineSectionSize() const { return LineSectionSize; } + + /// Returns size of generated .debug_frame section. + uint64_t getDebugFrameSectionSize() const { return FrameSectionSize; } + + /// Returns size of generated .debug_ranges section. + uint64_t getDebugRangesSectionSize() const { return RangesSectionSize; } + + /// Returns size of generated .debug_rnglists section. + uint64_t getDebugRngListsSectionSize() const { return RngListsSectionSize; } + + /// Returns size of generated .debug_info section. + uint64_t getDebugInfoSectionSize() const { return DebugInfoSectionSize; } + + /// Returns size of generated .debug_macinfo section. + uint64_t getDebugMacInfoSectionSize() const { return MacInfoSectionSize; } + + /// Returns size of generated .debug_macro section. + uint64_t getDebugMacroSectionSize() const { return MacroSectionSize; } + + /// Returns size of generated .debug_loc section. + uint64_t getDebugLocSectionSize() const { return LocSectionSize; } + + /// Returns size of generated .debug_loclists section. + uint64_t getDebugLocListsSectionSize() const { return LocListsSectionSize; } + +private: + inline void warn(const Twine &Warning, StringRef Context = "") { + if (WarningHandler) + WarningHandler(Warning, Context, nullptr); + } + + void emitMacroTableImpl(const DWARFDebugMacro *MacroTable, + const Offset2UnitMapTy &UnitMacroMap, + StringPool &StringPool, uint64_t &OutOffset) {} + + /// Emit piece of .debug_ranges for \p LinkedRanges. + void emitDwarfDebugRangesTableFragment(const CompileUnit &Unit, + const AddressRanges &LinkedRanges, + RangeAttrPatch &Patch) {} + + /// Emit piece of .debug_rnglists for \p LinkedRanges. + void emitDwarfDebugRngListsTableFragment(const CompileUnit &Unit, + const AddressRanges &LinkedRanges, + RangeAttrPatch &Patch) {} + + /// Emit piece of .debug_loc for \p LinkedRanges. + void emitDwarfDebugLocTableFragment( + const CompileUnit &Unit, + const DWARFLocationExpressionsVector &LinkedLocationExpression, + LocAttrPatch &Patch) {} + + /// Emit piece of .debug_loclists for \p LinkedRanges. + void emitDwarfDebugLocListsTableFragment( + const CompileUnit &Unit, + const DWARFLocationExpressionsVector &LinkedLocationExpression, + LocAttrPatch &Patch) {} + + /// \defgroup MCObjects MC layer objects constructed by the streamer + /// @{ + std::unique_ptr MRI; + std::unique_ptr MAI; + std::unique_ptr MOFI; + std::unique_ptr MC; + MCAsmBackend *MAB; // Owned by MCStreamer + std::unique_ptr MII; + std::unique_ptr MSTI; + MCInstPrinter *MIP; // Owned by AsmPrinter + MCCodeEmitter *MCE; // Owned by MCStreamer + MCStreamer *MS; // Owned by AsmPrinter + std::unique_ptr TM; + std::unique_ptr Asm; + /// @} + + /// The output file we stream the linked Dwarf to. + raw_pwrite_stream &OutFile; + DWARFLinker::OutputFileType OutFileType = DWARFLinker::OutputFileType::Object; + std::function Translator; + + uint64_t RangesSectionSize = 0; + uint64_t RngListsSectionSize = 0; + uint64_t LocSectionSize = 0; + uint64_t LocListsSectionSize = 0; + uint64_t LineSectionSize = 0; + uint64_t FrameSectionSize = 0; + uint64_t DebugInfoSectionSize = 0; + uint64_t MacInfoSectionSize = 0; + uint64_t MacroSectionSize = 0; + + /// Keep track of emitted CUs and their Unique ID. + struct EmittedUnit { + unsigned ID; + MCSymbol *LabelBegin; + }; + std::vector EmittedUnitsTy; + + /// Emit the pubnames or pubtypes section contribution for \p + /// Unit into \p Sec. The data is provided in \p Names. + void emitPubSectionForUnit(MCSection *Sec, StringRef Name, + const CompileUnit &Unit, + const std::vector &Names); + + DWARFLinker::MessageHandlerTy WarningHandler = nullptr; +}; + +} // end namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFEMITTERIMPL_H diff --git a/llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.cpp b/llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.cpp @@ -0,0 +1,131 @@ +//===- DWARFEmitterImpl.cpp -----------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DWARFEmitterImpl.h" +#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/FormattedStream.h" + +namespace llvm { +namespace dwarflinker_parallel { + +Error DwarfEmitterImpl::init(Triple TheTriple, + StringRef Swift5ReflectionSegmentName) { + std::string ErrorStr; + std::string TripleName; + + // Get the target. + const Target *TheTarget = + TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); + if (!TheTarget) + return createStringError(std::errc::invalid_argument, ErrorStr.c_str()); + TripleName = TheTriple.getTriple(); + + // Create all the MC Objects. + MRI.reset(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return createStringError(std::errc::invalid_argument, + "no register info for target %s", + TripleName.c_str()); + + MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags(); + MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); + if (!MAI) + return createStringError(std::errc::invalid_argument, + "no asm info for target %s", TripleName.c_str()); + + MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); + if (!MSTI) + return createStringError(std::errc::invalid_argument, + "no subtarget info for target %s", + TripleName.c_str()); + + MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr, + nullptr, true, Swift5ReflectionSegmentName)); + MOFI.reset(TheTarget->createMCObjectFileInfo(*MC, /*PIC=*/false, false)); + MC->setObjectFileInfo(MOFI.get()); + + MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions); + if (!MAB) + return createStringError(std::errc::invalid_argument, + "no asm backend for target %s", + TripleName.c_str()); + + MII.reset(TheTarget->createMCInstrInfo()); + if (!MII) + return createStringError(std::errc::invalid_argument, + "no instr info info for target %s", + TripleName.c_str()); + + MCE = TheTarget->createMCCodeEmitter(*MII, *MC); + if (!MCE) + return createStringError(std::errc::invalid_argument, + "no code emitter for target %s", + TripleName.c_str()); + + switch (OutFileType) { + case DWARFLinker::OutputFileType::Assembly: { + MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(), + *MAI, *MII, *MRI); + MS = TheTarget->createAsmStreamer( + *MC, std::make_unique(OutFile), true, true, MIP, + std::unique_ptr(MCE), std::unique_ptr(MAB), + true); + break; + } + case DWARFLinker::OutputFileType::Object: { + MS = TheTarget->createMCObjectStreamer( + TheTriple, *MC, std::unique_ptr(MAB), + MAB->createObjectWriter(OutFile), std::unique_ptr(MCE), + *MSTI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false); + break; + } + } + + if (!MS) + return createStringError(std::errc::invalid_argument, + "no object streamer for target %s", + TripleName.c_str()); + + // Finally create the AsmPrinter we'll use to emit the DIEs. + TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(), + std::nullopt)); + if (!TM) + return createStringError(std::errc::invalid_argument, + "no target machine for target %s", + TripleName.c_str()); + + Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr(MS))); + if (!Asm) + return createStringError(std::errc::invalid_argument, + "no asm printer for target %s", + TripleName.c_str()); + Asm->setDwarfUsesRelocationsAcrossSections(false); + + RangesSectionSize = 0; + RngListsSectionSize = 0; + LocSectionSize = 0; + LocListsSectionSize = 0; + LineSectionSize = 0; + FrameSectionSize = 0; + DebugInfoSectionSize = 0; + MacInfoSectionSize = 0; + MacroSectionSize = 0; + + return Error::success(); +} + +} // end of namespace dwarflinker_parallel +} // namespace llvm diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp --- a/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinker.cpp @@ -6,8 +6,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/DWARFLinkerParallel/DWARFLinker.h" +#include "DWARFLinkerImpl.h" -namespace llvm { -namespace dwarflinker_parallel {} // end of namespace dwarflinker_parallel -} // namespace llvm +std::unique_ptr +llvm::dwarflinker_parallel::DWARFLinker::createLinker( + MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler, + TranslatorFuncTy StringsTranslator) { + return std::make_unique(ErrorHandler, WarningHandler, + StringsTranslator); +} diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h new file mode 100644 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h @@ -0,0 +1,163 @@ +//===- DWARFLinkerCompileUnit.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_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H +#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H + +#include "DWARFLinkerUnit.h" +#include "llvm/DWARFLinkerParallel/DWARFFile.h" +#include "llvm/DWARFLinkerParallel/DWARFLinker.h" +#include + +namespace llvm { +namespace dwarflinker_parallel { + +struct LinkContext; +class DWARFFile; + +/// Stores all information related to a compile unit, be it in its original +/// instance of the object file or its brand new cloned and generated DIE tree. +class CompileUnit : public DwarfUnit { +public: + CompileUnit(LinkContext &Context, unsigned ID, StringRef ClangModuleName, + DWARFFile &File, + DWARFLinker::SwiftInterfacesMapTy *SwiftInterfaces, + UnitMessageHandlerTy WarningHandler) + : DwarfUnit(ID, ClangModuleName, WarningHandler), Context(Context), + ContaingFile(File), ParseableSwiftInterfaces(SwiftInterfaces) { + FormParams.Version = 4; + FormParams.Format = dwarf::DWARF32; + FormParams.AddrSize = 4; + UnitName = ContaingFile.FileName; + } + + CompileUnit(LinkContext &Context, DWARFUnit &OrigUnit, unsigned ID, + StringRef ClangModuleName, DWARFFile &File, + UnitMessageHandlerTy WarningHandler) + : DwarfUnit(ID, ClangModuleName, WarningHandler), Context(Context), + ContaingFile(File), OrigUnit(&OrigUnit) { + DWARFDie CUDie = OrigUnit.getUnitDIE(); + if (!CUDie) + return; + + if (File.Dwarf) + Endianess = File.Dwarf->isLittleEndian() ? support::endianness::little + : support::endianness::big; + + FormParams.Version = OrigUnit.getVersion(); + FormParams.Format = dwarf::DWARF32; + FormParams.AddrSize = OrigUnit.getAddressByteSize(); + + Language = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language), 0); + + UnitName = ContaingFile.FileName; + SysRoot = dwarf::toStringRef(CUDie.find(dwarf::DW_AT_LLVM_sysroot)).str(); + } + + /// \defgroup Helper methods to access OrigUnit. + /// + /// @{ + + /// Returns paired compile unit from input DWARF. + DWARFUnit &getOrigUnit() const { + assert(OrigUnit != nullptr); + return *OrigUnit; + } + + const DWARFDebugInfoEntry * + getFirstChildEntry(const DWARFDebugInfoEntry *Die) const { + assert(OrigUnit != nullptr); + return OrigUnit->getFirstChildEntry(Die); + } + + const DWARFDebugInfoEntry * + getSiblingEntry(const DWARFDebugInfoEntry *Die) const { + assert(OrigUnit != nullptr); + return OrigUnit->getSiblingEntry(Die); + } + + DWARFDie getParent(const DWARFDebugInfoEntry *Die) { + assert(OrigUnit != nullptr); + return OrigUnit->getParent(Die); + } + + DWARFDie getDIEAtIndex(unsigned Index) { + assert(OrigUnit != nullptr); + return OrigUnit->getDIEAtIndex(Index); + } + + const DWARFDebugInfoEntry *getDebugInfoEntry(unsigned Index) const { + assert(OrigUnit != nullptr); + return OrigUnit->getDebugInfoEntry(Index); + } + + DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) { + assert(OrigUnit != nullptr); + return OrigUnit->getUnitDIE(ExtractUnitDIEOnly); + } + + DWARFDie getDIE(const DWARFDebugInfoEntry *Die) { + assert(OrigUnit != nullptr); + return DWARFDie(OrigUnit, Die); + } + + uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) const { + assert(OrigUnit != nullptr); + return OrigUnit->getDIEIndex(Die); + } + + uint32_t getDIEIndex(const DWARFDie &Die) const { + assert(OrigUnit != nullptr); + return OrigUnit->getDIEIndex(Die); + } + + std::optional find(uint32_t DieIdx, + ArrayRef Attrs) const { + assert(OrigUnit != nullptr); + return find(OrigUnit->getDebugInfoEntry(DieIdx), Attrs); + } + + std::optional find(const DWARFDebugInfoEntry *Die, + ArrayRef Attrs) const { + if (!Die) + return std::nullopt; + auto AbbrevDecl = Die->getAbbreviationDeclarationPtr(); + if (AbbrevDecl) { + for (auto Attr : Attrs) { + if (auto Value = AbbrevDecl->getAttributeValue(Die->getOffset(), Attr, + *OrigUnit)) + return Value; + } + } + return std::nullopt; + } + + std::optional getDIEIndexForOffset(uint64_t Offset) { + return OrigUnit->getDIEIndexForOffset(Offset); + } + + /// @} + +private: + /// Context containing this compilation unit. + LinkContext &Context; + + /// DWARFFile containing this compile unit. + DWARFFile &ContaingFile; + + /// Pointer to the paired compile unit from the input DWARF. + DWARFUnit *OrigUnit = nullptr; + + /// Map for swift interfaces. + DWARFLinker::SwiftInterfacesMapTy *ParseableSwiftInterfaces = nullptr; +}; + +} // end of namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h new file mode 100644 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h @@ -0,0 +1,320 @@ +//===- DWARFLinkerImpl.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_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H +#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H + +#include "DWARFEmitterImpl.h" +#include "DWARFLinkerCompileUnit.h" +#include "llvm/ADT/AddressRanges.h" +#include "llvm/CodeGen/AccelTable.h" +#include "llvm/DWARFLinkerParallel/DWARFLinker.h" +#include "llvm/DWARFLinkerParallel/StringPool.h" +#include "llvm/DWARFLinkerParallel/StringTable.h" + +namespace llvm { +namespace dwarflinker_parallel { + +using Offset2UnitMapTy = DenseMap; + +struct RangeAttrPatch; +struct LocAttrPatch; + +class DWARFLinkerImpl : public DWARFLinker { +public: + DWARFLinkerImpl(MessageHandlerTy ErrorHandler, + MessageHandlerTy WarningHandler, + TranslatorFuncTy StringsTranslator) + : UniqueUnitID(0), ErrorHandler(ErrorHandler), + WarningHandler(WarningHandler), + OutputStrings(Strings, StringsTranslator) {} + + Error createEmitter(const Triple &TheTriple, OutputFileType FileType, + raw_pwrite_stream &OutFile) override; + + ExtraDwarfEmitter *getEmitter() override; + + /// 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. + void addObjectFile( + DWARFFile &File, ObjFileLoaderTy Loader = nullptr, + CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) override {} + + /// Link debug info for added files. + Error link() override { + reportWarning("LLVM parallel dwarflinker is not implemented yet.", ""); + return Error::success(); + } + + /// \defgroup Methods setting various linking options: + /// + /// @{ + /// + + /// Allows to generate log of linking process to the standard output. + void setVerbosity(bool Verbose) override { Options.Verbose = Verbose; } + + /// Print statistics to standard output. + void setStatistics(bool Statistics) override { + Options.Statistics = Statistics; + } + + /// Verify the input DWARF. + void setVerifyInputDWARF(bool Verify) override { + Options.VerifyInputDWARF = Verify; + } + + /// Do not unique types according to ODR. + void setNoODR(bool NoODR) override { Options.NoODR = NoODR; } + + /// Update index tables only(do not modify rest of DWARF). + void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) override { + Options.UpdateIndexTablesOnly = UpdateIndexTablesOnly; + } + + /// Allow generating valid, but non-deterministic output. + void + setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) override { + Options.AllowNonDeterministicOutput = AllowNonDeterministicOutput; + } + + /// Set to keep the enclosing function for a static variable. + void setKeepFunctionForStatic(bool KeepFunctionForStatic) override { + Options.KeepFunctionForStatic = KeepFunctionForStatic; + } + + /// Use specified number of threads for parallel files linking. + void setNumThreads(unsigned NumThreads) override { + Options.Threads = NumThreads; + } + + /// Add kind of accelerator tables to be generated. + void addAccelTableKind(AccelTableKind Kind) override { + assert(std::find(Options.AccelTables.begin(), Options.AccelTables.end(), + Kind) == Options.AccelTables.end()); + Options.AccelTables.emplace_back(Kind); + } + + /// Set prepend path for clang modules. + void setPrependPath(const std::string &Ppath) override { + Options.PrependPath = Ppath; + } + + /// Set estimated objects files amount, for preliminary data allocation. + void setEstimatedObjfilesAmount(unsigned ObjFilesNum) override { + ObjectContexts.reserve(ObjFilesNum); + } + + /// Set verification handler which would be used to report verification + /// errors. + void + setInputVerificationHandler(InputVerificationHandlerTy Handler) override { + Options.InputVerificationHandler = Handler; + } + + /// Set map for Swift interfaces. + void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) override { + Options.ParseableSwiftInterfaces = Map; + } + + /// Set prefix map for objects. + void setObjectPrefixMap(ObjectPrefixMapTy *Map) override { + Options.ObjectPrefixMap = Map; + } + + /// Set target DWARF version. + Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) override { + if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5)) + return createStringError(std::errc::invalid_argument, + "unsupported DWARF version: %d", + TargetDWARFVersion); + + Options.TargetDWARFVersion = TargetDWARFVersion; + return Error::success(); + } + /// @} + +protected: + /// Reports Warning. + void reportWarning(const Twine &Warning, const DWARFFile &File, + const DWARFDie *DIE = nullptr) const { + if (WarningHandler != nullptr) + WarningHandler(Warning, File.FileName, DIE); + } + + /// Reports Warning. + void reportWarning(const Twine &Warning, StringRef FileName, + const DWARFDie *DIE = nullptr) const { + if (WarningHandler != nullptr) + WarningHandler(Warning, FileName, DIE); + } + + /// Reports Error. + void reportError(const Twine &Warning, StringRef FileName, + const DWARFDie *DIE = nullptr) const { + if (ErrorHandler != nullptr) + ErrorHandler(Warning, FileName, DIE); + } + + /// Returns next available unique Compile Unit ID. + unsigned getNextUniqueUnitID() { return UniqueUnitID.fetch_add(1); } + + /// Keeps track of data associated with one object during linking. + /// i.e. source file descriptor, compilation units, output data + /// for compilation units common tables. + struct LinkContext : public OutputSections { + using UnitListTy = SmallVector>; + + /// Keep information for referenced clang module: already loaded DWARF info + /// of the clang module and a CompileUnit of the module. + struct RefModuleUnit { + RefModuleUnit(DWARFFile &File, std::unique_ptr Unit) + : File(File), Unit(std::move(Unit)) {} + RefModuleUnit(RefModuleUnit &&Other) + : File(Other.File), Unit(std::move(Other.Unit)) {} + RefModuleUnit(const RefModuleUnit &) = delete; + + DWARFFile &File; + std::unique_ptr Unit; + }; + using ModuleUnitListTy = SmallVector; + + /// Object file descriptor. + DWARFFile &File; + + /// Set of Compilation Units(may be accessed asynchroniously for reading). + UnitListTy CompileUnits; + + /// Set of Compile Units for modules. + ModuleUnitListTy ModulesCompileUnits; + + /// Size of Debug info before optimizing. + uint64_t OriginalDebugInfoSize = 0; + + /// Output sections, common for all compilation units. + OutTablesFileTy OutDebugInfoBytes; + + /// Endianness for the final file. + support::endianness Endianess = support::endianness::little; + + LinkContext(DWARFFile &File) : File(File) { + if (File.Dwarf) { + if (!File.Dwarf->compile_units().empty()) + CompileUnits.reserve(File.Dwarf->getNumCompileUnits()); + + Endianess = File.Dwarf->isLittleEndian() ? support::endianness::little + : support::endianness::big; + } + } + + /// Add Compile Unit corresponding to the module. + void addModulesCompileUnit(RefModuleUnit &&Unit) { + ModulesCompileUnits.emplace_back(std::move(Unit)); + } + + /// Return Endiannes of the source DWARF information. + support::endianness getEndianness() { return Endianess; } + + /// \returns pointer to compilation unit which corresponds \p Offset. + CompileUnit *getUnitForOffset(CompileUnit &CU, uint64_t Offset) const; + }; + + /// linking options + struct DWARFLinkerOptions { + /// DWARF version for the output. + uint16_t TargetDWARFVersion = 0; + + /// Generate processing log to the standard output. + bool Verbose = false; + + /// Print statistics. + bool Statistics = false; + + /// Verify the input DWARF. + bool VerifyInputDWARF = false; + + /// Do not unique types according to ODR + bool NoODR = false; + + /// Update index tables. + bool UpdateIndexTablesOnly = false; + + /// Whether we want a static variable to force us to keep its enclosing + /// function. + bool KeepFunctionForStatic = false; + + /// Allow to generate valid, but non deterministic output. + bool AllowNonDeterministicOutput = false; + + /// Number of threads. + unsigned Threads = 1; + + /// The accelerator table kinds + SmallVector AccelTables; + + /// Prepend path for the clang modules. + std::string PrependPath; + + /// input verification handler(it might be called asynchronously). + InputVerificationHandlerTy InputVerificationHandler = nullptr; + + /// A list of all .swiftinterface files referenced by the debug + /// info, mapping Module name to path on disk. The entries need to + /// be uniqued and sorted and there are only few entries expected + /// per compile unit, which is why this is a std::map. + /// this is dsymutil specific fag. + /// + /// (it might be called asynchronously). + SwiftInterfacesMapTy *ParseableSwiftInterfaces = nullptr; + + /// A list of remappings to apply to file paths. + /// + /// (it might be called asynchronously). + ObjectPrefixMapTy *ObjectPrefixMap = nullptr; + } Options; + + /// \defgroup Data members accessed asinchroniously. + /// + /// @{ + + /// Unique ID for compile unit. + std::atomic UniqueUnitID; + + /// Strings pool. Keeps all strings. + StringPool Strings; + + /// error handler(it might be called asynchronously). + MessageHandlerTy ErrorHandler = nullptr; + + /// warning handler(it might be called asynchronously). + MessageHandlerTy WarningHandler = nullptr; + /// @} + + /// \defgroup Data members accessed sequentially. + /// + /// @{ + + /// Set of strings which should be emitted. + StringTable OutputStrings; + + /// Keeps all linking contexts. + SmallVector> ObjectContexts; + + /// The emitter of final dwarf file. + std::unique_ptr TheDwarfEmitter; + /// @} +}; + +} // end namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp @@ -0,0 +1,46 @@ +//=== DWARFLinkerImpl.cpp -------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "DWARFLinkerImpl.h" + +namespace llvm { +namespace dwarflinker_parallel { + +/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our +/// CompileUnit object instead. +CompileUnit * +DWARFLinkerImpl::LinkContext::getUnitForOffset(CompileUnit &CurrentCU, + uint64_t Offset) const { + if (CurrentCU.isClangModule()) + return &CurrentCU; + + auto CU = llvm::upper_bound( + CompileUnits, Offset, + [](uint64_t LHS, const std::unique_ptr &RHS) { + return LHS < RHS->getOrigUnit().getNextUnitOffset(); + }); + + return CU != CompileUnits.end() ? CU->get() : nullptr; +} + +Error DWARFLinkerImpl::createEmitter(const Triple &TheTriple, + OutputFileType FileType, + raw_pwrite_stream &OutFile) { + + TheDwarfEmitter = std::make_unique( + FileType, OutFile, OutputStrings.getTranslator(), WarningHandler); + + return TheDwarfEmitter->init(TheTriple, "__DWARF"); +} + +ExtraDwarfEmitter *DWARFLinkerImpl::getEmitter() { + return TheDwarfEmitter.get(); +} + +} // end of namespace dwarflinker_parallel +} // namespace llvm diff --git a/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h new file mode 100644 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h @@ -0,0 +1,185 @@ +//===- DWARFLinkerUnit.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_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H +#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H + +#include "OutputSections.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/DWARFLinkerParallel/StringPool.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/Support/LEB128.h" + +namespace llvm { +namespace dwarflinker_parallel { + +using UnitMessageHandlerTy = function_ref; + +/// Each unit keeps output data as a file with debug tables +/// corresponding to the concrete unit. +using OutTablesFileTy = SmallString<0>; + +/// Base class for all Dwarf units(Compile unit/Type table unit). +class DwarfUnit : public OutputSections { +public: + virtual ~DwarfUnit() {} + DwarfUnit(unsigned ID, StringRef ClangModuleName, + UnitMessageHandlerTy WarningHandler) + : ID(ID), ClangModuleName(ClangModuleName), + WarningHandler(WarningHandler) { + FormParams.Version = 4; + FormParams.Format = dwarf::DWARF32; + FormParams.AddrSize = 4; + } + + /// Endiannes for the compile unit. + support::endianness getEndianness() const { return Endianess; } + + /// Return DWARF version. + uint16_t getVersion() const { return FormParams.Version; } + + /// Return size of header of debug_info table. + uint16_t getHeaderSize() const { return FormParams.Version >= 5 ? 12 : 11; } + + /// Return size of address. + uint8_t getAddressByteSize() const { return FormParams.AddrSize; } + + /// Return size of reference. + uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } + + /// Return format of the Dwarf(DWARF32 or DWARF64). + /// TODO: DWARF64 is not currently supported. + dwarf::DwarfFormat getDwarfFormat() const { return FormParams.Format; } + + /// Unique id of the unit. + unsigned getUniqueID() const { return ID; } + + /// Return language of this unit. + uint16_t getLanguage() const { return Language; } + + /// Set size of this(newly generated) compile unit. + void setUnitSize(uint64_t UnitSize) { this->UnitSize = UnitSize; } + + /// Returns size of this(newly generated) compile unit. + uint64_t getUnitSize() const { return UnitSize; } + + /// Returns this unit name. + StringRef getUnitName() const { return UnitName; } + + /// Return the DW_AT_LLVM_sysroot of the compile unit or an empty StringRef. + StringRef getSysRoot() { return SysRoot; } + + /// Create a Die for this unit. + void setOutputDIE(DIE *UnitDie) { NewUnit = UnitDie; } + + /// Return Die for this compile unit. + DIE *getOutputUnitDIE() const { return NewUnit; } + + /// Return true if this compile unit is from Clang module. + bool isClangModule() const { return !ClangModuleName.empty(); } + + /// Return Clang module name; + const std::string &getClangModuleName() const { return ClangModuleName; } + + /// Returns generated file keeping debug tables for this compile unit. + OutTablesFileTy &getOutDwarfBits() { return OutDebugInfoBits; } + + /// Erases generated file keeping debug tables for this compile unit. + void eraseDwarfBits() { OutDebugInfoBits = OutTablesFileTy(); } + + MCSymbol *getLabelBegin() { return LabelBegin; } + void setLabelBegin(MCSymbol *S) { LabelBegin = S; } + + /// Error reporting methods. + /// @{ + + void reportWarning(const Twine &Warning, + const DWARFDie *Die = nullptr) const { + if (WarningHandler) + WarningHandler(Warning, getUnitName(), Die); + } + void reportWarning(Error Warning) const { + handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) { + if (WarningHandler) + WarningHandler(Info.message(), getUnitName(), nullptr); + }); + } + /// @} + + /// This structure keeps fields which would be used for creating accelerator + /// table. + struct AccelInfo { + AccelInfo(StringEntry *Name, const DIE *Die, bool SkipPubSection = false); + AccelInfo(StringEntry *Name, const DIE *Die, uint32_t QualifiedNameHash, + bool ObjCClassIsImplementation); + + /// Name of the entry. + StringEntry *Name = nullptr; + + /// Tag of the DIE this entry describes. + dwarf::Tag Tag = dwarf::DW_TAG_null; + + /// Output offset of the DIE this entry describes. + uint64_t OutOffset = 0; + + /// Hash of the fully qualified name. + uint32_t QualifiedNameHash = 0; + + /// Emit this entry only in the apple_* sections. + bool SkipPubSection = false; + + /// Is this an ObjC class implementation? + bool ObjcClassImplementation = false; + + /// Cloned Die containing acceleration info. + const DIE *Die = nullptr; + }; + +protected: + /// Unique ID for the unit. + unsigned ID = 0; + + /// Properties of the unit. + dwarf::FormParams FormParams; + + /// DIE for newly generated compile unit. + DIE *NewUnit = nullptr; + + /// The DW_AT_language of this unit. + uint16_t Language = 0; + + /// The name of this unit. + std::string UnitName; + + /// The DW_AT_LLVM_sysroot of this unit. + std::string SysRoot; + + /// If this is a Clang module, this holds the module's name. + std::string ClangModuleName; + + uint64_t UnitSize = 0; + + /// Elf file containg generated debug tables for this compile unit. + OutTablesFileTy OutDebugInfoBits; + + /// Endiannes for this compile unit. + support::endianness Endianess = support::endianness::little; + + MCSymbol *LabelBegin = nullptr; + + /// true if current unit references_to/is_referenced by other unit. + std::atomic IsInterconnectedCU = {false}; + + UnitMessageHandlerTy WarningHandler; +}; + +} // end of namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H diff --git a/llvm/lib/DWARFLinkerParallel/OutputSections.h b/llvm/lib/DWARFLinkerParallel/OutputSections.h new file mode 100644 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/OutputSections.h @@ -0,0 +1,67 @@ +//===- OutputSections.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_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H +#define LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H + +#include "llvm/ADT/StringRef.h" +#include +#include + +namespace llvm { +namespace dwarflinker_parallel { + +/// This class keeps offsets to the debug sections. Any object which is +/// supposed to be emitted into the debug section should use this class to +/// track debug sections offsets. +class OutputSections { +public: + /// List of tracked debug sections. + enum class DebugSectionKind : uint8_t { + DebugInfo = 0, + DebugLine, + DebugFrame, + DebugRange, + DebugRngLists, + DebugLoc, + DebugLocLists, + DebugARanges, + DebugAbbrev, + DebugMacinfo, + DebugMacro, + }; + constexpr static size_t SectionKindsNum = 11; + + /// Recognise the section name and match it with the DebugSectionKind. + static std::optional parseDebugSectionName(StringRef Name); + + /// When objects(f.e. compile units) are glued into the single file, + /// the debug sections corresponding to the concrete object are assigned + /// with offsets inside the whole file. This method returns offset + /// to the \p SectionKind debug section, corresponding to this object. + uint64_t getStartOffset(DebugSectionKind SectionKind) const { + return Offsets[static_cast< + typename std::underlying_type::type>(SectionKind)]; + } + + /// Set offset to the start of specified \p SectionKind debug section, + /// corresponding to this object. + void setStartOffset(DebugSectionKind SectionKind, uint64_t Offset) { + Offsets[static_cast::type>( + SectionKind)] = Offset; + } + +protected: + /// Offsets to the debug sections composing this object. + std::array Offsets = {0}; +}; + +} // end of namespace dwarflinker_parallel +} // end namespace llvm + +#endif // LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H diff --git a/llvm/lib/DWARFLinkerParallel/OutputSections.cpp b/llvm/lib/DWARFLinkerParallel/OutputSections.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/DWARFLinkerParallel/OutputSections.cpp @@ -0,0 +1,36 @@ +//=== OutputSections.cpp --------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "OutputSections.h" +#include "llvm/ADT/StringSwitch.h" + +namespace llvm { +namespace dwarflinker_parallel { + +std::optional +OutputSections::parseDebugSectionName(llvm::StringRef SecName) { + return llvm::StringSwitch>( + SecName) + .Case("debug_info", DebugSectionKind::DebugInfo) + .Case("debug_line", DebugSectionKind::DebugLine) + .Case("debug_frame", DebugSectionKind::DebugFrame) + .Case("debug_ranges", DebugSectionKind::DebugRange) + .Case("debug_rnglists", DebugSectionKind::DebugRngLists) + .Case("debug_loc", DebugSectionKind::DebugLoc) + .Case("debug_loclists", DebugSectionKind::DebugLocLists) + .Case("debug_aranges", DebugSectionKind::DebugARanges) + .Case("debug_abbrev", DebugSectionKind::DebugAbbrev) + .Case("debug_macinfo", DebugSectionKind::DebugMacinfo) + .Case("debug_macro", DebugSectionKind::DebugMacro) + .Default(std::nullopt); + + return std::nullopt; +} + +} // end of namespace dwarflinker_parallel +} // end of namespace llvm diff --git a/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/basic-linking-x86.test b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/basic-linking-x86.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/DWARFLinkerParallel/basic-linking-x86.test @@ -0,0 +1,4 @@ +RUN: cat %p/../../Inputs/basic.macho.x86_64 > %t1 +RUN: dsymutil --linker llvm -accelerator=Pub -f -oso-prepend-path=%p/../.. %t1 2>&1 | FileCheck %s --allow-empty + +#CHECK: LLVM parallel dwarflinker is not implemented yet. diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/DWARFLinkerParallel/gc-default.test copy from llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test copy to llvm/test/tools/llvm-dwarfutil/ELF/X86/DWARFLinkerParallel/gc-default.test --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/DWARFLinkerParallel/gc-default.test @@ -2,37 +2,9 @@ ## default tombstone value) is removed. # RUN: yaml2obj %s -o %t.o +# RUN: llvm-dwarfutil --linker llvm %t.o %t1.out 2>&1 | FileCheck %s --allow-empty -# RUN: llvm-dwarfutil %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC - -# RUN: llvm-dwarfutil --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC - -# RUN: llvm-dwarfutil --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC - -# RUN: llvm-dwarfutil --garbage-collection --no-garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-NOGC - -# RUN: llvm-dwarfutil %t.o --tombstone=universal - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC - -# CHECK: DW_TAG_compile_unit -# CHECK: DW_AT_name{{.*}}"CU1" -# CHECK: DW_TAG_class_type -# CHECK: DW_AT_name{{.*}}"class1" -# CHECK-GC-NOT: DW_TAG_class_type -# CHECK-GC-NOT: "class2" -# CHECK-GC-NOT: "class3" -# CHECK-NOGC: DW_TAG_class_type -# CHECK-NOGC: "class2" -# CHECK-NOGC: "class3" -# CHECK: DW_TAG_subprogram -# CHECK: DW_AT_name{{.*}}"foo1" -# CHECK: DW_AT_low_pc{{.*}}0x0000000000001000 -# CHECK: DW_AT_high_pc{{.*}}0x0000000000001010 -# CHECK: DW_AT_type{{.*}}"class1" -# CHECK-GC-NOT: DW_TAG_subprogram -# CHECK-GC-NOT: "foo2" -# CHECK-NOGC: DW_TAG_subprogram -# CHECK-NOGC: "foo2" - +#CHECK: LLVM parallel dwarflinker is not implemented yet. --- !ELF FileHeader: diff --git a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test --- a/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test +++ b/llvm/test/tools/llvm-dwarfutil/ELF/X86/gc-default.test @@ -5,6 +5,8 @@ # RUN: llvm-dwarfutil %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC +# RUN: llvm-dwarfutil --linker apple %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC + # RUN: llvm-dwarfutil --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC # RUN: llvm-dwarfutil --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC diff --git a/llvm/tools/dsymutil/CMakeLists.txt b/llvm/tools/dsymutil/CMakeLists.txt --- a/llvm/tools/dsymutil/CMakeLists.txt +++ b/llvm/tools/dsymutil/CMakeLists.txt @@ -10,6 +10,7 @@ CodeGen CodeGenTypes DWARFLinker + DWARFLinkerParallel DebugInfoDWARF MC Object diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.h b/llvm/tools/dsymutil/DwarfLinkerForBinary.h --- a/llvm/tools/dsymutil/DwarfLinkerForBinary.h +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.h @@ -65,7 +65,8 @@ private: /// Keeps track of relocations. - class AddressManager : public AddressesMap { + template + class AddressManager : public AddressesMapBase { struct ValidReloc { uint64_t Offset; uint32_t Size; @@ -180,6 +181,7 @@ std::optional getExprOpAddressRelocAdjustment( DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset, uint64_t EndOffset) override; + std::optional getSubprogramRelocAdjustment(const DWARFDie &DIE) override; @@ -199,14 +201,20 @@ /// \defgroup Helpers Various helper methods. /// /// @{ - bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile); + template + bool createStreamer(const Triple &TheTriple, + typename OutStreamer::OutputFileType FileType, + std::unique_ptr &Streamer, + raw_fd_ostream &OutFile); /// Attempt to load a debug object from disk. ErrorOr loadObject(const DebugMapObject &Obj, const Triple &triple); - ErrorOr loadObject(const DebugMapObject &Obj, - const DebugMap &DebugMap, - remarks::RemarkLinker &RL); + + template + ErrorOr> loadObject(const DebugMapObject &Obj, + const DebugMap &DebugMap, + remarks::RemarkLinker &RL); void collectRelocationsToApplyToSwiftReflectionSections( const object::SectionRef &Section, StringRef &Contents, @@ -218,21 +226,22 @@ Error copySwiftInterfaces(StringRef Architecture) const; + template void copySwiftReflectionMetadata( - const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer, + const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer, std::vector &SectionToOffsetInDwarf, std::vector &RelocationsToApply); + template + bool linkImpl(const DebugMap &Map, + typename Linker::OutputFileType ObjectType); + raw_fd_ostream &OutFile; BinaryHolder &BinHolder; LinkOptions Options; std::mutex &ErrorHandlerMutex; - std::unique_ptr Streamer; - std::vector> ObjectsForLinking; - std::vector> ContextForLinking; - std::vector> AddressMapForLinking; std::vector EmptyWarnings; /// A list of all .swiftinterface files referenced by the debug diff --git a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp --- a/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp +++ b/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp @@ -33,6 +33,7 @@ #include "llvm/CodeGen/NonRelocatableStringpool.h" #include "llvm/Config/config.h" #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" +#include "llvm/DWARFLinkerParallel/DWARFLinker.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" @@ -134,22 +135,6 @@ dumpDIE(DIE, Options.Verbose); } -bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple, - raw_fd_ostream &OutFile) { - if (Options.NoOutput) - return true; - - Streamer = std::make_unique( - Options.FileType, OutFile, Options.Translator, - [&](const Twine &Error, StringRef Context, const DWARFDie *) { - reportError(Error, Context); - }, - [&](const Twine &Warning, StringRef Context, const DWARFDie *) { - reportWarning(Warning, Context); - }); - return Streamer->init(TheTriple, "__DWARF"); -} - ErrorOr DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj, const Triple &Triple) { @@ -238,22 +223,19 @@ return Error::success(); } -ErrorOr +template +ErrorOr> DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj, const DebugMap &DebugMap, remarks::RemarkLinker &RL) { auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple()); + std::unique_ptr Res; if (ErrorOrObj) { - ContextForLinking.push_back( - std::unique_ptr(DWARFContext::create(*ErrorOrObj))); - AddressMapForLinking.push_back( - std::make_unique(*this, *ErrorOrObj, Obj)); - - ObjectsForLinking.push_back(std::make_unique( - Obj.getObjectFilename(), ContextForLinking.back().get(), - AddressMapForLinking.back().get(), - Obj.empty() ? Obj.getWarnings() : EmptyWarnings)); + Res = std::make_unique( + Obj.getObjectFilename(), DWARFContext::create(*ErrorOrObj), + std::make_unique(*this, *ErrorOrObj, Obj), + Obj.empty() ? Obj.getWarnings() : EmptyWarnings); Error E = RL.link(*ErrorOrObj); if (Error NewE = handleErrors( @@ -262,7 +244,7 @@ })) return errorToErrorCode(std::move(NewE)); - return *ObjectsForLinking.back(); + return Res; } return ErrorOrObj.getError(); @@ -274,7 +256,7 @@ // need to copy them to the .dSYM. Only copy them for binaries where the // linker omitted the reflection metadata. if (!Map.getBinaryPath().empty() && - Options.FileType == OutputFileType::Object) { + Options.FileType == DWARFLinker::OutputFileType::Object) { auto ObjectEntry = BinHolder.getObjectEntry(Map.getBinaryPath()); // If ObjectEntry or Object has an error, no binary exists, therefore no @@ -498,8 +480,9 @@ return Error::success(); } +template void DwarfLinkerForBinary::copySwiftReflectionMetadata( - const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer, + const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer, std::vector &SectionToOffsetInDwarf, std::vector &RelocationsToApply) { @@ -557,59 +540,117 @@ } bool DwarfLinkerForBinary::link(const DebugMap &Map) { - if (!createStreamer(Map.getTriple(), OutFile)) - return false; + if (Options.DWARFLinkerType == DsymutilDWARFLinkerType::LLVM) { + dwarflinker_parallel::DWARFLinker::OutputFileType DWARFLinkerOutputType; + switch (Options.FileType) { + case DWARFLinker::OutputFileType::Object: + DWARFLinkerOutputType = + dwarflinker_parallel::DWARFLinker::OutputFileType::Object; + break; + + case DWARFLinker::OutputFileType::Assembly: + DWARFLinkerOutputType = + dwarflinker_parallel::DWARFLinker::OutputFileType::Assembly; + break; + } - ObjectsForLinking.clear(); - ContextForLinking.clear(); - AddressMapForLinking.clear(); + return linkImpl>( + Map, DWARFLinkerOutputType); + } - DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath()); + return linkImpl>( + Map, Options.FileType); +} - DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil); +template +void setAcceleratorTables(Linker &GeneralLinker, + DsymutilAccelTableKind TableKind, + uint16_t MaxDWARFVersion) { + switch (TableKind) { + case DsymutilAccelTableKind::Apple: + GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple); + return; + case DsymutilAccelTableKind::Dwarf: + GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames); + return; + case DsymutilAccelTableKind::Pub: + GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Pub); + return; + case DsymutilAccelTableKind::Default: + if (MaxDWARFVersion >= 5) + GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames); + else + GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple); + return; + case DsymutilAccelTableKind::None: + // Nothing to do. + return; + } - remarks::RemarkLinker RL; - if (!Options.RemarksPrependPath.empty()) - RL.setExternalFilePrependPath(Options.RemarksPrependPath); - RL.setKeepAllRemarks(Options.RemarksKeepAll); - GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap); + llvm_unreachable("All cases handled above!"); +} + +template +bool DwarfLinkerForBinary::linkImpl( + const DebugMap &Map, typename Linker::OutputFileType ObjectType) { + + std::vector> ObjectsForLinking; + + DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath()); std::function TranslationLambda = [&](StringRef Input) { assert(Options.Translator); return Options.Translator(Input); }; - GeneralLinker.setVerbosity(Options.Verbose); - GeneralLinker.setStatistics(Options.Statistics); - GeneralLinker.setVerifyInputDWARF(Options.VerifyInputDWARF); - GeneralLinker.setNoOutput(Options.NoOutput); - GeneralLinker.setNoODR(Options.NoODR); - GeneralLinker.setUpdate(Options.Update); - GeneralLinker.setNumThreads(Options.Threads); - GeneralLinker.setPrependPath(Options.PrependPath); - GeneralLinker.setKeepFunctionForStatic(Options.KeepFunctionForStatic); - if (Options.Translator) - GeneralLinker.setStringsTranslator(TranslationLambda); - GeneralLinker.setWarningHandler( - [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) { - reportWarning(Warning, Context, DIE); - }); - GeneralLinker.setErrorHandler( + std::unique_ptr GeneralLinker = Linker::createLinker( [&](const Twine &Error, StringRef Context, const DWARFDie *DIE) { reportError(Error, Context, DIE); + }, + [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) { + reportWarning(Warning, Context, DIE); + }, + Options.Translator ? TranslationLambda : nullptr); + + if (!Options.NoOutput) { + if (Error Err = GeneralLinker->createEmitter(Map.getTriple(), ObjectType, + OutFile)) { + handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { + reportError(EI.message(), "dwarf streamer init"); }); - GeneralLinker.setInputVerificationHandler([&](const DWARFFile &File) { + return false; + } + } + + remarks::RemarkLinker RL; + if (!Options.RemarksPrependPath.empty()) + RL.setExternalFilePrependPath(Options.RemarksPrependPath); + RL.setKeepAllRemarks(Options.RemarksKeepAll); + GeneralLinker->setObjectPrefixMap(&Options.ObjectPrefixMap); + + GeneralLinker->setVerbosity(Options.Verbose); + GeneralLinker->setStatistics(Options.Statistics); + GeneralLinker->setVerifyInputDWARF(Options.VerifyInputDWARF); + GeneralLinker->setNoODR(Options.NoODR); + GeneralLinker->setUpdateIndexTablesOnly(Options.Update); + GeneralLinker->setNumThreads(Options.Threads); + GeneralLinker->setPrependPath(Options.PrependPath); + GeneralLinker->setKeepFunctionForStatic(Options.KeepFunctionForStatic); + GeneralLinker->setInputVerificationHandler([&](const OutDwarfFile &File) { reportWarning("input verification failed", File.FileName); HasVerificationErrors = true; }); - objFileLoader Loader = [&DebugMap, &RL, - this](StringRef ContainerName, - StringRef Path) -> ErrorOr { + auto Loader = [&](StringRef ContainerName, + StringRef Path) -> ErrorOr { auto &Obj = DebugMap.addDebugMapObject( Path, sys::TimePoint(), MachO::N_OSO); - if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) { - return *ErrorOrObj; + if (ErrorOr> ErrorOrObj = + loadObject(Obj, DebugMap, RL)) { + ObjectsForLinking.emplace_back(std::move(*ErrorOrObj)); + return *ObjectsForLinking.back(); } else { // Try and emit more helpful warnings by applying some heuristics. StringRef ObjFile = ContainerName; @@ -654,7 +695,7 @@ llvm_unreachable("Unhandled DebugMap object"); }; - GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces); + GeneralLinker->setSwiftInterfacesMap(&ParseableSwiftInterfaces); bool ReflectionSectionsPresentInBinary = false; // If there is no output specified, no point in checking the binary for swift5 // reflection sections. @@ -668,7 +709,7 @@ auto SectionToOffsetInDwarf = calculateStartOfStrippableReflectionSections(Map); for (const auto &Obj : Map.objects()) - copySwiftReflectionMetadata(Obj.get(), Streamer.get(), + copySwiftReflectionMetadata(Obj.get(), GeneralLinker->getEmitter(), SectionToOffsetInDwarf, RelocationsToApply); } @@ -715,18 +756,21 @@ // Copy the module into the .swift_ast section. if (!Options.NoOutput) - Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer()); + GeneralLinker->getEmitter()->emitSwiftAST((*ErrorOrMem)->getBuffer()); continue; } - if (auto ErrorOrObj = loadObject(*Obj, Map, RL)) - GeneralLinker.addObjectFile(*ErrorOrObj, Loader, OnCUDieLoaded); - else { - ObjectsForLinking.push_back(std::make_unique( + if (ErrorOr> ErrorOrObj = + loadObject(*Obj, Map, RL)) { + ObjectsForLinking.emplace_back(std::move(*ErrorOrObj)); + GeneralLinker->addObjectFile(*ObjectsForLinking.back(), Loader, + OnCUDieLoaded); + } else { + ObjectsForLinking.push_back(std::make_unique( Obj->getObjectFilename(), nullptr, nullptr, Obj->empty() ? Obj->getWarnings() : EmptyWarnings)); - GeneralLinker.addObjectFile(*ObjectsForLinking.back()); + GeneralLinker->addObjectFile(*ObjectsForLinking.back()); } } @@ -734,32 +778,14 @@ if (MaxDWARFVersion == 0) MaxDWARFVersion = 3; - if (Error E = GeneralLinker.setTargetDWARFVersion(MaxDWARFVersion)) + if (Error E = GeneralLinker->setTargetDWARFVersion(MaxDWARFVersion)) return error(toString(std::move(E))); - switch (Options.TheAccelTableKind) { - case DsymutilAccelTableKind::Apple: - GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Apple); - break; - case DsymutilAccelTableKind::Dwarf: - GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::DebugNames); - break; - case DsymutilAccelTableKind::Pub: - GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Pub); - break; - case DsymutilAccelTableKind::Default: - if (MaxDWARFVersion >= 5) - GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::DebugNames); - else - GeneralLinker.addAccelTableKind(DwarfLinkerAccelTableKind::Apple); - break; - case DsymutilAccelTableKind::None: - // Nothing to do. - break; - } + setAcceleratorTables(*GeneralLinker, Options.TheAccelTableKind, + MaxDWARFVersion); // link debug info for loaded object files. - if (Error E = GeneralLinker.link()) + if (Error E = GeneralLinker->link()) return error(toString(std::move(E))); StringRef ArchName = Map.getTriple().getArchName(); @@ -776,21 +802,25 @@ } if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() && - Options.FileType == OutputFileType::Object) + ObjectType == Linker::OutputFileType::Object) return MachOUtils::generateDsymCompanion( Options.VFS, Map, Options.Translator, - *Streamer->getAsmPrinter().OutStreamer, OutFile, RelocationsToApply); + *GeneralLinker->getEmitter()->getAsmPrinter().OutStreamer, OutFile, + RelocationsToApply); - Streamer->finish(); + GeneralLinker->getEmitter()->finish(); return true; } /// Iterate over the relocations of the given \p Section and /// store the ones that correspond to debug map entries into the /// ValidRelocs array. -void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO( - const object::SectionRef &Section, const object::MachOObjectFile &Obj, - const DebugMapObject &DMO, std::vector &ValidRelocs) { +template +void DwarfLinkerForBinary::AddressManager:: + findValidRelocsMachO(const object::SectionRef &Section, + const object::MachOObjectFile &Obj, + const DebugMapObject &DMO, + std::vector &ValidRelocs) { Expected ContentsOrErr = Section.getContents(); if (!ContentsOrErr) { consumeError(ContentsOrErr.takeError()); @@ -865,7 +895,8 @@ /// Dispatch the valid relocation finding logic to the /// appropriate handler depending on the object file format. -bool DwarfLinkerForBinary::AddressManager::findValidRelocs( +template +bool DwarfLinkerForBinary::AddressManager::findValidRelocs( const object::SectionRef &Section, const object::ObjectFile &Obj, const DebugMapObject &DMO, std::vector &Relocs) { // Dispatch to the right handler depending on the file type. @@ -890,8 +921,10 @@ /// entries in the debug map. These relocations will drive the Dwarf link by /// indicating which DIEs refer to symbols present in the linked binary. /// \returns whether there are any valid relocations in the debug info. -bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections( - const object::ObjectFile &Obj, const DebugMapObject &DMO) { +template +bool DwarfLinkerForBinary::AddressManager:: + findValidRelocsInDebugSections(const object::ObjectFile &Obj, + const DebugMapObject &DMO) { // Find the debug_info section. bool FoundValidRelocs = false; for (const object::SectionRef &Section : Obj.sections()) { @@ -912,10 +945,14 @@ return FoundValidRelocs; } -std::vector -DwarfLinkerForBinary::AddressManager::getRelocations( +template +std::vector< + typename DwarfLinkerForBinary::AddressManager::ValidReloc> +DwarfLinkerForBinary::AddressManager::getRelocations( const std::vector &Relocs, uint64_t StartPos, uint64_t EndPos) { - std::vector Res; + std::vector< + DwarfLinkerForBinary::AddressManager::ValidReloc> + Res; auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) { return Reloc.Offset < StartPos; @@ -930,7 +967,9 @@ return Res; } -void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc &Reloc) { +template +void DwarfLinkerForBinary::AddressManager::printReloc( + const ValidReloc &Reloc) { const auto &Mapping = Reloc.Mapping->getValue(); const uint64_t ObjectAddress = Mapping.ObjectAddress ? uint64_t(*Mapping.ObjectAddress) @@ -941,16 +980,18 @@ uint64_t(Mapping.BinaryAddress)); } -int64_t -DwarfLinkerForBinary::AddressManager::getRelocValue(const ValidReloc &Reloc) { +template +int64_t DwarfLinkerForBinary::AddressManager::getRelocValue( + const ValidReloc &Reloc) { int64_t AddrAdjust = relocate(Reloc); if (Reloc.Mapping->getValue().ObjectAddress) AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress); return AddrAdjust; } +template std::optional -DwarfLinkerForBinary::AddressManager::hasValidRelocationAt( +DwarfLinkerForBinary::AddressManager::hasValidRelocationAt( const std::vector &AllRelocs, uint64_t StartOffset, uint64_t EndOffset) { std::vector Relocs = @@ -986,10 +1027,11 @@ return std::make_pair(Offset, End); } -std::optional -DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment( - DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset, - uint64_t EndOffset) { +template +std::optional DwarfLinkerForBinary::AddressManager:: + getExprOpAddressRelocAdjustment(DWARFUnit &U, + const DWARFExpression::Operation &Op, + uint64_t StartOffset, uint64_t EndOffset) { switch (Op.getCode()) { default: { assert(false && "Specified operation does not have address operand"); @@ -1010,9 +1052,9 @@ return std::nullopt; } -std::optional -DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment( - const DWARFDie &DIE) { +template +std::optional DwarfLinkerForBinary::AddressManager< + AddressesMapBase>::getSubprogramRelocAdjustment(const DWARFDie &DIE) { const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); std::optional LowPcIdx = @@ -1053,8 +1095,9 @@ } } -uint64_t -DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const { +template +uint64_t DwarfLinkerForBinary::AddressManager::relocate( + const ValidReloc &Reloc) const { return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend; } @@ -1066,7 +1109,8 @@ /// monotonic \p BaseOffset values. /// /// \returns whether any reloc has been applied. -bool DwarfLinkerForBinary::AddressManager::applyValidRelocs( +template +bool DwarfLinkerForBinary::AddressManager::applyValidRelocs( MutableArrayRef Data, uint64_t BaseOffset, bool IsLittleEndian) { std::vector Relocs = getRelocations( ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size()); diff --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h --- a/llvm/tools/dsymutil/LinkUtils.h +++ b/llvm/tools/dsymutil/LinkUtils.h @@ -31,6 +31,11 @@ Pub, ///< .debug_pubnames, .debug_pubtypes }; +enum class DsymutilDWARFLinkerType : uint8_t { + Apple, /// Apple`s implementation of DWARFLinker. + LLVM /// LLVM implementation of DWARFLinker. +}; + struct LinkOptions { /// Verbosity bool Verbose = false; @@ -57,6 +62,9 @@ /// function. bool KeepFunctionForStatic = false; + /// Type of DWARFLinker to use. + DsymutilDWARFLinkerType DWARFLinkerType = DsymutilDWARFLinkerType::Apple; + /// Use a 64-bit header when emitting universal binaries. bool Fat64 = false; @@ -64,7 +72,7 @@ unsigned Threads = 1; // Output file type. - OutputFileType FileType = OutputFileType::Object; + DWARFLinker::OutputFileType FileType = DWARFLinker::OutputFileType::Object; /// The accelerator table kind DsymutilAccelTableKind TheAccelTableKind; diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td --- a/llvm/tools/dsymutil/Options.td +++ b/llvm/tools/dsymutil/Options.td @@ -199,3 +199,9 @@ HelpText<"Drop remarks without valid debug locations. Without this flags, " "all remarks are kept.">, Group; + +def linker: Separate<["--", "-"], "linker">, + MetaVarName<"">, + HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">, + Group; +def: Joined<["--", "-"], "linker=">, Alias; diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -241,6 +241,24 @@ return DsymutilAccelTableKind::Default; } +static Expected +getDWARFLinkerType(opt::InputArgList &Args) { + if (opt::Arg *LinkerType = Args.getLastArg(OPT_linker)) { + StringRef S = LinkerType->getValue(); + if (S == "apple") + return DsymutilDWARFLinkerType::Apple; + if (S == "llvm") + return DsymutilDWARFLinkerType::LLVM; + return make_error("invalid DWARF linker type specified: '" + + S + + "'. Supported values are 'apple', " + "'llvm'.", + inconvertibleErrorCode()); + } + + return DsymutilDWARFLinkerType::Apple; +} + static Expected getReproducerMode(opt::InputArgList &Args) { if (Args.hasArg(OPT_gen_reproducer)) return ReproducerMode::GenerateOnExit; @@ -330,6 +348,13 @@ return AccelKind.takeError(); } + if (Expected DWARFLinkerType = + getDWARFLinkerType(Args)) { + Options.LinkOpts.DWARFLinkerType = *DWARFLinkerType; + } else { + return DWARFLinkerType.takeError(); + } + if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap)) Options.SymbolMap = SymbolMap->getValue(); @@ -362,7 +387,7 @@ Options.Toolchain = Toolchain->getValue(); if (Args.hasArg(OPT_assembly)) - Options.LinkOpts.FileType = OutputFileType::Assembly; + Options.LinkOpts.FileType = DWARFLinker::OutputFileType::Assembly; if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads)) Options.LinkOpts.Threads = atoi(NumThreads->getValue()); diff --git a/llvm/tools/llvm-dwarfutil/CMakeLists.txt b/llvm/tools/llvm-dwarfutil/CMakeLists.txt --- a/llvm/tools/llvm-dwarfutil/CMakeLists.txt +++ b/llvm/tools/llvm-dwarfutil/CMakeLists.txt @@ -8,6 +8,7 @@ AllTargetsInfos CodeGenTypes DWARFLinker + DWARFLinkerParallel DebugInfoDWARF MC ObjCopy diff --git a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp --- a/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp +++ b/llvm/tools/llvm-dwarfutil/DebugInfoLinker.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/DWARFLinker/DWARFLinker.h" #include "llvm/DWARFLinker/DWARFStreamer.h" +#include "llvm/DWARFLinkerParallel/DWARFLinker.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/Object/ObjectFile.h" @@ -37,7 +38,8 @@ // exec: [LowPC, HighPC] is not inside address ranges of .text sections // // universal: maxpc and bfd -class ObjFileAddressMap : public AddressesMap { +template +class ObjFileAddressMap : public AddressMapBase { public: ObjFileAddressMap(DWARFContext &Context, const Options &Options, object::ObjectFile &ObjFile) @@ -224,12 +226,13 @@ .Default(false); } -static std::optional +template +static std::optional getAcceleratorTableKind(StringRef SecName) { - return llvm::StringSwitch>(SecName) - .Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub) - .Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub) - .Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames) + return llvm::StringSwitch>(SecName) + .Case(".debug_pubnames", AccelTableKind::Pub) + .Case(".debug_pubtypes", AccelTableKind::Pub) + .Case(".debug_names", AccelTableKind::DebugNames) .Default(std::nullopt); } @@ -275,9 +278,9 @@ return Message; } -Error linkDebugInfo(object::ObjectFile &File, const Options &Options, - raw_pwrite_stream &OutStream) { - +template +Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options, + raw_pwrite_stream &OutStream) { auto ReportWarn = [&](const Twine &Message, StringRef Context, const DWARFDie *Die) { warning(Message, Context); @@ -297,39 +300,33 @@ WithColor::error(errs(), Context) << Message << '\n'; }; - // Create output streamer. - DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr, - ReportWarn, ReportWarn); + // Create DWARF linker. + std::unique_ptr DebugInfoLinker = + Linker::createLinker(ReportErr, ReportWarn); + Triple TargetTriple = File.makeTriple(); - if (!OutStreamer.init(TargetTriple, formatv("cannot create a stream for {0}", - TargetTriple.getTriple()) - .str())) - return createStringError(std::errc::invalid_argument, ""); + if (Error Err = DebugInfoLinker->createEmitter( + TargetTriple, Linker::OutputFileType::Object, OutStream)) + return Err; - std::unique_ptr Context = DWARFContext::create(File); + DebugInfoLinker->setEstimatedObjfilesAmount(1); + DebugInfoLinker->setNumThreads(Options.NumThreads); + DebugInfoLinker->setNoODR(!Options.DoODRDeduplication); + DebugInfoLinker->setVerbosity(Options.Verbose); + DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection); - // Create DWARF linker. - DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD); - - DebugInfoLinker.setEstimatedObjfilesAmount(1); - DebugInfoLinker.setErrorHandler(ReportErr); - DebugInfoLinker.setWarningHandler(ReportWarn); - DebugInfoLinker.setNumThreads(Options.NumThreads); - DebugInfoLinker.setNoODR(!Options.DoODRDeduplication); - DebugInfoLinker.setVerbosity(Options.Verbose); - DebugInfoLinker.setUpdate(!Options.DoGarbageCollection); - - std::vector> ObjectsForLinking(1); - std::vector> AddresssMapForLinking(1); + std::vector> ObjectsForLinking(1); std::vector EmptyWarnings; // Add object files to the DWARFLinker. - AddresssMapForLinking[0] = - std::make_unique(*Context, Options, File); + std::unique_ptr Context = DWARFContext::create(File); + std::unique_ptr> AddressesMap( + std::make_unique>(*Context, Options, + File)); - ObjectsForLinking[0] = std::make_unique( - File.getFileName(), &*Context, AddresssMapForLinking[0].get(), - EmptyWarnings); + ObjectsForLinking[0] = + std::make_unique(File.getFileName(), std::move(Context), + std::move(AddressesMap), EmptyWarnings); uint16_t MaxDWARFVersion = 0; std::function OnCUDieLoaded = @@ -338,17 +335,17 @@ }; for (size_t I = 0; I < ObjectsForLinking.size(); I++) - DebugInfoLinker.addObjectFile(*ObjectsForLinking[I], nullptr, - OnCUDieLoaded); + DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr, + OnCUDieLoaded); // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway. if (MaxDWARFVersion == 0) MaxDWARFVersion = 3; - if (Error Err = DebugInfoLinker.setTargetDWARFVersion(MaxDWARFVersion)) + if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion)) return Err; - SmallVector AccelTables; + SmallVector AccelTables; switch (Options.AccelTableKind) { case DwarfUtilAccelKind::None: @@ -356,60 +353,75 @@ break; case DwarfUtilAccelKind::DWARF: // use .debug_names for all DWARF versions. - AccelTables.push_back(DwarfLinkerAccelTableKind::DebugNames); + AccelTables.push_back(Linker::AccelTableKind::DebugNames); break; } // Add accelerator tables to DWARFLinker. - for (DwarfLinkerAccelTableKind Table : AccelTables) - DebugInfoLinker.addAccelTableKind(Table); - - SmallVector AccelTableNamesToReplace; - SmallVector AccelTableNamesToDelete; - - // Unknown debug sections or non-requested accelerator sections would be - // removed. Display warning for such sections. - for (SectionName Sec : Context->getDWARFObj().getSectionNames()) { - if (isDebugSection(Sec.Name)) { - std::optional SrcAccelTableKind = - getAcceleratorTableKind(Sec.Name); - - if (SrcAccelTableKind) { - assert(knownByDWARFUtil(Sec.Name)); - - if (Options.AccelTableKind == DwarfUtilAccelKind::None) - AccelTableNamesToDelete.push_back(Sec.Name); - else if (std::find(AccelTables.begin(), AccelTables.end(), - *SrcAccelTableKind) == AccelTables.end()) - AccelTableNamesToReplace.push_back(Sec.Name); - } else if (!knownByDWARFUtil(Sec.Name)) { - assert(!SrcAccelTableKind); - warning( - formatv("'{0}' is not currently supported: section will be skipped", - Sec.Name), - Options.InputFileName); + for (typename Linker::AccelTableKind Table : AccelTables) + DebugInfoLinker->addAccelTableKind(Table); + + for (std::unique_ptr &CurFile : ObjectsForLinking) { + SmallVector AccelTableNamesToReplace; + SmallVector AccelTableNamesToDelete; + + // Unknown debug sections or non-requested accelerator sections would be + // removed. Display warning for such sections. + for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) { + if (isDebugSection(Sec.Name)) { + std::optional SrcAccelTableKind = + getAcceleratorTableKind(Sec.Name); + + if (SrcAccelTableKind) { + assert(knownByDWARFUtil(Sec.Name)); + + if (Options.AccelTableKind == DwarfUtilAccelKind::None) + AccelTableNamesToDelete.push_back(Sec.Name); + else if (std::find(AccelTables.begin(), AccelTables.end(), + *SrcAccelTableKind) == AccelTables.end()) + AccelTableNamesToReplace.push_back(Sec.Name); + } else if (!knownByDWARFUtil(Sec.Name)) { + assert(!SrcAccelTableKind); + warning( + formatv( + "'{0}' is not currently supported: section will be skipped", + Sec.Name), + Options.InputFileName); + } } } - } - // Display message for the replaced accelerator tables. - if (!AccelTableNamesToReplace.empty()) - warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace, - Options.AccelTableKind), - Options.InputFileName); + // Display message for the replaced accelerator tables. + if (!AccelTableNamesToReplace.empty()) + warning(getMessageForReplacedAcceleratorTables(AccelTableNamesToReplace, + Options.AccelTableKind), + Options.InputFileName); - // Display message for the removed accelerator tables. - if (!AccelTableNamesToDelete.empty()) - warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete), - Options.InputFileName); + // Display message for the removed accelerator tables. + if (!AccelTableNamesToDelete.empty()) + warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete), + Options.InputFileName); + } // Link debug info. - if (Error Err = DebugInfoLinker.link()) + if (Error Err = DebugInfoLinker->link()) return Err; - OutStreamer.finish(); + DebugInfoLinker->getEmitter()->finish(); return Error::success(); } +Error linkDebugInfo(object::ObjectFile &File, const Options &Options, + raw_pwrite_stream &OutStream) { + if (Options.UseLLVMDWARFLinker) + return linkDebugInfoImpl(File, Options, + OutStream); + else + return linkDebugInfoImpl( + File, Options, OutStream); +} + } // end of namespace dwarfutil } // end of namespace llvm diff --git a/llvm/tools/llvm-dwarfutil/Options.h b/llvm/tools/llvm-dwarfutil/Options.h --- a/llvm/tools/llvm-dwarfutil/Options.h +++ b/llvm/tools/llvm-dwarfutil/Options.h @@ -40,6 +40,7 @@ bool Verbose = false; int NumThreads = 0; bool Verify = false; + bool UseLLVMDWARFLinker = false; DwarfUtilAccelKind AccelTableKind = DwarfUtilAccelKind::None; std::string getSeparateDebugFileName() const { diff --git a/llvm/tools/llvm-dwarfutil/Options.td b/llvm/tools/llvm-dwarfutil/Options.td --- a/llvm/tools/llvm-dwarfutil/Options.td +++ b/llvm/tools/llvm-dwarfutil/Options.td @@ -20,6 +20,11 @@ Alias, HelpText<"Alias for --help">; +def linker: Separate<["--", "-"], "linker">, + MetaVarName<"">, + HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">; +def: Joined<["--", "-"], "linker=">, Alias; + defm odr_deduplication : BB<"odr-deduplication", "Do ODR deduplication for debug types(default)", "Don`t do ODR deduplication for debug types">; diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp --- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp +++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp @@ -123,6 +123,18 @@ formatv("unknown tombstone value: '{0}'", S).str().c_str()); } + if (opt::Arg *LinkerKind = Args.getLastArg(OPT_linker)) { + StringRef S = LinkerKind->getValue(); + if (S == "apple") + Options.UseLLVMDWARFLinker = false; + else if (S == "llvm") + Options.UseLLVMDWARFLinker = true; + else + return createStringError( + std::errc::invalid_argument, + formatv("unknown linker kind value: '{0}'", S).str().c_str()); + } + if (opt::Arg *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) { StringRef S = BuildAccelerator->getValue();