This patch creates skeleton implementation for the DWARFLinkerParallel.
It also integrates DWARFLinkerParallel into dsymutil and llvm-dwarfutil,
so that empty DWARFLinker::link() can be called. To do this new command
line option is added "--linker apple/llvm". Additionally it changes
existing DWARFLinker interfaces/implementations to be compatible:
use Error for error reporting for the DWARFStreamer, make DWARFFile to
owner of referenced resources, other small refactorings.
Differential Revision: https://reviews.llvm.org/D147952
#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"
#include <map>
namespace llvm {
-class DWARFContext;
class DWARFExpression;
class DWARFUnit;
class DataExtractor;
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
/// 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<std::unique_ptr<CompileUnit>>;
/// 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<DWARFContext> Dwarf,
+ std::unique_ptr<AddressesMap> Addresses,
const std::vector<std::string> &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<DWARFContext> Dwarf;
/// Helpful address information(list of valid address ranges, relocations).
- AddressesMap *Addresses = nullptr;
+ std::unique_ptr<AddressesMap> Addresses;
/// Warnings for this object file.
const std::vector<std::string> &Warnings;
};
-typedef std::function<void(const Twine &Warning, StringRef Context,
- const DWARFDie *DIE)>
- messageHandler;
-typedef std::function<void(const DWARFFile &File)> inputVerificationHandler;
-typedef std::function<ErrorOr<DWARFFile &>(StringRef ContainerName,
- StringRef Path)>
- objFileLoader;
typedef std::map<std::string, std::string> swiftInterfacesMap;
typedef std::map<std::string, std::string> objectPrefixMap;
/// processing a object file.
class DWARFLinker {
public:
- DWARFLinker(DwarfEmitter *Emitter,
- DwarfLinkerClient ClientID = DwarfLinkerClient::General)
- : TheDwarfEmitter(Emitter), DwarfLinkerClientID(ClientID) {}
+ typedef std::function<void(const Twine &Warning, StringRef Context,
+ const DWARFDie *DIE)>
+ messageHandler;
+ DWARFLinker(messageHandler ErrorHandler, messageHandler WarningHandler,
+ std::function<StringRef(StringRef)> StringsTranslator)
+ : DwarfLinkerClientID(DwarfLinkerClient::Dsymutil),
+ StringsTranslator(StringsTranslator), ErrorHandler(ErrorHandler),
+ WarningHandler(WarningHandler) {}
+
+ static std::unique_ptr<DWARFLinker> createLinker(
+ messageHandler ErrorHandler, messageHandler WarningHandler,
+ std::function<StringRef(StringRef)> StringsTranslator = nullptr) {
+ return std::make_unique<DWARFLinker>(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<void(const DWARFFile &File)> inputVerificationHandler;
+ typedef std::function<ErrorOr<DWARFFile &>(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
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:
/// 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) {
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);
/// 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<StringRef(StringRef)> 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) {
/// 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);
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.
BumpPtrAllocator DIEAlloc;
/// @}
- DwarfEmitter *TheDwarfEmitter;
+ std::unique_ptr<DwarfStreamer> TheDwarfEmitter;
std::vector<LinkContext> ObjectContexts;
/// The CIEs that have been emitted in the output section. The actual CIE
/// 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.
/// Verify the input DWARF.
bool VerifyInputDWARF = false;
- /// Skip emitting output
- bool NoOutput = false;
-
/// Do not unique types according to ODR
bool NoODR = false;
unsigned Threads = 1;
/// The accelerator table kinds
- SmallVector<DwarfLinkerAccelTableKind, 1> AccelTables;
+ SmallVector<AccelTableKind, 1> 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;
namespace llvm {
template <typename DataT> class AccelTable;
-enum class OutputFileType {
- Object,
- Assembly,
-};
-
/// User of DwarfStreamer should call initialization code
/// for AsmPrinter:
///
/// 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<StringRef(StringRef Input)> 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.
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;
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);
/// 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<StringRef(StringRef Input)> Translator;
uint64_t RangesSectionSize = 0;
const CompileUnit &Unit,
const std::vector<CompileUnit::AccelInfo> &Names);
- messageHandler ErrorHandler = nullptr;
- messageHandler WarningHandler = nullptr;
+ DWARFLinker::messageHandler WarningHandler = nullptr;
};
} // end namespace llvm
--- /dev/null
+//===- 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 <functional>
+#include <memory>
+
+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<void(StringRef FileName)>;
+
+ DWARFFile(StringRef Name, std::unique_ptr<DWARFContext> Dwarf,
+ std::unique_ptr<AddressesMap> Addresses,
+ const std::vector<std::string> &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<DWARFContext> Dwarf;
+
+ /// Helpful address information(list of valid address ranges, relocations).
+ std::unique_ptr<AddressesMap> Addresses;
+
+ /// Warnings for object file.
+ const std::vector<std::string> &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
#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<void(
+ const Twine &Warning, StringRef Context, const DWARFDie *DIE)>;
+ using ObjFileLoaderTy = std::function<ErrorOr<DWARFFile &>(
+ StringRef ContainerName, StringRef Path)>;
+ using InputVerificationHandlerTy = std::function<void(const DWARFFile &File)>;
+ using ObjectPrefixMapTy = std::map<std::string, std::string>;
+ using CompileUnitHandlerTy = function_ref<void(const DWARFUnit &Unit)>;
+ using TranslatorFuncTy = std::function<StringRef(StringRef)>;
+ using SwiftInterfacesMapTy = std::map<std::string, std::string>;
+
+ virtual ~DWARFLinker() = default;
+
+ /// Creates dwarf linker instance.
+ static std::unique_ptr<DWARFLinker>
+ createLinker(MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler,
+ TranslatorFuncTy StringsTranslator = nullptr);
+
+ /// Creates emitter for output dwarf.
+ virtual Error createEmitter(const Triple &TheTriple, OutputFileType FileType,
+ raw_pwrite_stream &OutFile) = 0;
+
+ /// Returns previously created dwarf emitter. May be nullptr.
+ virtual ExtraDwarfEmitter *getEmitter() = 0;
+
+ /// Add object file to be linked. Pre-load compile unit die. Call
+ /// \p OnCUDieLoaded for each compile unit die. If specified \p File
+ /// has reference to the Clang module then such module would be
+ /// pre-loaded by \p Loader for !Update case.
+ ///
+ /// \pre NoODR, Update options should be set before call to addObjectFile.
+ virtual void addObjectFile(
+ DWARFFile &File, ObjFileLoaderTy Loader = nullptr,
+ CompileUnitHandlerTy OnCUDieLoaded = [](const DWARFUnit &) {}) = 0;
+
+ /// Link debug info for added files.
+ virtual Error link() = 0;
+
+ /// \defgroup Methods setting various linking options:
+ ///
+ /// @{
+
+ /// Allows to generate log of linking process to the standard output.
+ virtual void setVerbosity(bool Verbose) = 0;
+
+ /// Print statistics to standard output.
+ virtual void setStatistics(bool Statistics) = 0;
+
+ /// Verify the input DWARF.
+ virtual void setVerifyInputDWARF(bool Verify) = 0;
+
+ /// Do not unique types according to ODR.
+ virtual void setNoODR(bool NoODR) = 0;
+
+ /// Update index tables only(do not modify rest of DWARF).
+ virtual void setUpdateIndexTablesOnly(bool UpdateIndexTablesOnly) = 0;
+
+ /// Allow generating valid, but non-deterministic output.
+ virtual void
+ setAllowNonDeterministicOutput(bool AllowNonDeterministicOutput) = 0;
+
+ /// Set to keep the enclosing function for a static variable.
+ virtual void setKeepFunctionForStatic(bool KeepFunctionForStatic) = 0;
+
+ /// Use specified number of threads for parallel files linking.
+ virtual void setNumThreads(unsigned NumThreads) = 0;
+
+ /// Add kind of accelerator tables to be generated.
+ virtual void addAccelTableKind(AccelTableKind Kind) = 0;
+
+ /// Set prepend path for clang modules.
+ virtual void setPrependPath(const std::string &Ppath) = 0;
+
+ /// Set estimated objects files amount, for preliminary data allocation.
+ virtual void setEstimatedObjfilesAmount(unsigned ObjFilesNum) = 0;
+
+ /// Set verification handler which would be used to report verification
+ /// errors.
+ virtual void
+ setInputVerificationHandler(InputVerificationHandlerTy Handler) = 0;
+
+ /// Set map for Swift interfaces.
+ virtual void setSwiftInterfacesMap(SwiftInterfacesMapTy *Map) = 0;
+
+ /// Set prefix map for objects.
+ virtual void setObjectPrefixMap(ObjectPrefixMapTy *Map) = 0;
+
+ /// Set target DWARF version.
+ virtual Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) = 0;
+ /// @}
+};
+
+} // end namespace dwarflinker_parallel
} // end namespace llvm
#endif // LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H
Handler(*Entry);
}
+ std::function<StringRef(StringRef)> getTranslator() {
+ return StringsTranslator;
+ }
+
protected:
/// List of strings for emission.
StringsVector StringEntriesForEmission;
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
std::shared_ptr<DWARFUnit> 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
#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"
}
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.
}
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() +
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());
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) {
OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
- if (!Linker.Options.NoOutput) {
- assert(Emitter);
+ if (Emitter != nullptr) {
generateLineTableForUnit(*CurrentUnit);
}
}
- 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) {
}
Error DWARFLinker::link() {
- assert(Options.NoOutput || TheDwarfEmitter);
assert((Options.TargetDWARFVersion != 0) &&
"TargetDWARFVersion should be set");
// 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.
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(),
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;
}
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());
}
}
+Error DWARFLinker::createEmitter(const Triple &TheTriple,
+ OutputFileType FileType,
+ raw_pwrite_stream &OutFile) {
+
+ TheDwarfEmitter = std::make_unique<DwarfStreamer>(
+ FileType, OutFile, StringsTranslator, WarningHandler);
+
+ return TheDwarfEmitter->init(TheTriple, "__DWARF");
+}
+
+DwarfEmitter *DWARFLinker::getEmitter() { return TheDwarfEmitter.get(); }
+
} // namespace llvm
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));
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(
true);
break;
}
- case OutputFileType::Object: {
+ case DWARFLinker::OutputFileType::Object: {
MS = TheTarget->createMCObjectStreamer(
TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE),
}
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<MCStreamer>(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;
MacInfoSectionSize = 0;
MacroSectionSize = 0;
- return true;
+ return Error::success();
}
void DwarfStreamer::finish() { MS->finish(); }
add_llvm_component_library(LLVMDWARFLinkerParallel
+ DWARFEmitterImpl.cpp
DWARFLinker.cpp
+ DWARFLinkerImpl.cpp
+ OutputSections.cpp
StringPool.cpp
ADDITIONAL_HEADER_DIRS
--- /dev/null
+//===- 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<formatted_raw_ostream>(OutFile), true, true, MIP,
+ std::unique_ptr<MCCodeEmitter>(MCE), std::unique_ptr<MCAsmBackend>(MAB),
+ true);
+ break;
+ }
+ case DWARFLinker::OutputFileType::Object: {
+ MS = TheTarget->createMCObjectStreamer(
+ TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
+ MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(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<MCStreamer>(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
--- /dev/null
+//===- 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 <typename DataT> class AccelTable;
+class MCCodeEmitter;
+class DWARFDebugMacro;
+
+namespace dwarflinker_parallel {
+
+struct UnitStartSymbol {
+ unsigned UnitID = 0;
+ MCSymbol *Symbol = 0;
+};
+using UnitStartSymbolsTy = SmallVector<UnitStartSymbol>;
+using Offset2UnitMapTy = DenseMap<uint64_t, CompileUnit *>;
+
+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<StringRef(StringRef Input)> 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<std::unique_ptr<DIEAbbrev>> &Abbrevs,
+ unsigned DwarfVersion) {}
+
+ void emitStrings(const StringTable &Strings) {}
+
+ void emitLineStrings(const StringTable &Strings) {}
+
+ void emitDebugNames(AccelTable<DWARF5AccelTableStaticData> &,
+ UnitStartSymbolsTy &UnitOffsets) {}
+
+ void emitAppleNamespaces(AccelTable<AppleAccelTableStaticOffsetData> &) {}
+
+ void emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> &) {}
+
+ void emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> &) {}
+
+ void emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &) {}
+
+ 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<DWARFDebugLine::Row> &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<MCRegisterInfo> MRI;
+ std::unique_ptr<MCAsmInfo> MAI;
+ std::unique_ptr<MCObjectFileInfo> MOFI;
+ std::unique_ptr<MCContext> MC;
+ MCAsmBackend *MAB; // Owned by MCStreamer
+ std::unique_ptr<MCInstrInfo> MII;
+ std::unique_ptr<MCSubtargetInfo> MSTI;
+ MCInstPrinter *MIP; // Owned by AsmPrinter
+ MCCodeEmitter *MCE; // Owned by MCStreamer
+ MCStreamer *MS; // Owned by AsmPrinter
+ std::unique_ptr<TargetMachine> TM;
+ std::unique_ptr<AsmPrinter> Asm;
+ /// @}
+
+ /// The output file we stream the linked Dwarf to.
+ raw_pwrite_stream &OutFile;
+ DWARFLinker::OutputFileType OutFileType = DWARFLinker::OutputFileType::Object;
+ std::function<StringRef(StringRef Input)> 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<EmittedUnit> 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<CompileUnit::AccelInfo> &Names);
+
+ DWARFLinker::MessageHandlerTy WarningHandler = nullptr;
+};
+
+} // end namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFEMITTERIMPL_H
//
//===----------------------------------------------------------------------===//
-#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>
+llvm::dwarflinker_parallel::DWARFLinker::createLinker(
+ MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler,
+ TranslatorFuncTy StringsTranslator) {
+ return std::make_unique<DWARFLinkerImpl>(ErrorHandler, WarningHandler,
+ StringsTranslator);
+}
--- /dev/null
+//===- 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 <optional>
+
+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<DWARFFormValue> find(uint32_t DieIdx,
+ ArrayRef<dwarf::Attribute> Attrs) const {
+ assert(OrigUnit != nullptr);
+ return find(OrigUnit->getDebugInfoEntry(DieIdx), Attrs);
+ }
+
+ std::optional<DWARFFormValue> find(const DWARFDebugInfoEntry *Die,
+ ArrayRef<dwarf::Attribute> 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<uint32_t> 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
--- /dev/null
+//=== 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<CompileUnit> &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<DwarfEmitterImpl>(
+ FileType, OutFile, OutputStrings.getTranslator(), WarningHandler);
+
+ return TheDwarfEmitter->init(TheTriple, "__DWARF");
+}
+
+ExtraDwarfEmitter *DWARFLinkerImpl::getEmitter() {
+ return TheDwarfEmitter.get();
+}
+
+} // end of namespace dwarflinker_parallel
+} // namespace llvm
--- /dev/null
+//===- 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<uint64_t, CompileUnit *>;
+
+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<std::unique_ptr<CompileUnit>>;
+
+ /// 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<CompileUnit> 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<CompileUnit> Unit;
+ };
+ using ModuleUnitListTy = SmallVector<RefModuleUnit>;
+
+ /// 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<AccelTableKind, 1> 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<unsigned> 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<std::unique_ptr<LinkContext>> ObjectContexts;
+
+ /// The emitter of final dwarf file.
+ std::unique_ptr<DwarfEmitterImpl> TheDwarfEmitter;
+ /// @}
+};
+
+} // end namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H
--- /dev/null
+//===- 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<void(
+ const Twine &Error, StringRef Context, const DWARFDie *DIE)>;
+
+/// 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<bool> IsInterconnectedCU = {false};
+
+ UnitMessageHandlerTy WarningHandler;
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
--- /dev/null
+//=== 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::DebugSectionKind>
+OutputSections::parseDebugSectionName(llvm::StringRef SecName) {
+ return llvm::StringSwitch<std::optional<OutputSections::DebugSectionKind>>(
+ 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
--- /dev/null
+//===- 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 <array>
+#include <cstdint>
+
+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<DebugSectionKind> 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<DebugSectionKind>::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<typename std::underlying_type<DebugSectionKind>::type>(
+ SectionKind)] = Offset;
+ }
+
+protected:
+ /// Offsets to the debug sections composing this object.
+ std::array<uint64_t, SectionKindsNum> Offsets = {0};
+};
+
+} // end of namespace dwarflinker_parallel
+} // end namespace llvm
+
+#endif // LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
--- /dev/null
+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.
--- /dev/null
+## This test checks that debug info related to deleted code (marked with
+## 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
+
+#CHECK: LLVM parallel dwarflinker is not implemented yet.
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Address: 0x1000
+ Size: 0x1b
+DWARF:
+ debug_abbrev:
+ - Table:
+ - Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_producer
+ Form: DW_FORM_string
+ - Attribute: DW_AT_language
+ Form: DW_FORM_data2
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_data8
+ - Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_data8
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_member
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_declaration
+ Form: DW_FORM_flag_present
+ - Tag: DW_TAG_class_type
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ - Attribute: DW_AT_declaration
+ Form: DW_FORM_flag_present
+ - Tag: DW_TAG_template_type_parameter
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_type
+ Form: DW_FORM_ref4
+ - Tag: DW_TAG_base_type
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_string
+ debug_info:
+ - Version: 4
+ Entries:
+ - AbbrCode: 1
+ Values:
+ - CStr: by_hand
+ - Value: 0x04
+ - CStr: CU1
+ - Value: 0x1000
+ - Value: 0x1b
+ - AbbrCode: 3
+ Values:
+ - CStr: class1
+ - AbbrCode: 4
+ Values:
+ - Value: 0x0000006c
+ - CStr: member1
+ - AbbrCode: 0
+ - AbbrCode: 3
+ Values:
+ - CStr: class2
+ - AbbrCode: 4
+ Values:
+ - Value: 0x0000006c
+ - CStr: member1
+ - AbbrCode: 0
+ - AbbrCode: 3
+ Values:
+ - CStr: class3
+ - AbbrCode: 4
+ Values:
+ - Value: 0x0000006c
+ - CStr: member1
+ - AbbrCode: 0
+ - AbbrCode: 8
+ Values:
+ - CStr: int
+ - AbbrCode: 2
+ Values:
+ - CStr: foo1
+ - Value: 0x1000
+ - Value: 0x10
+ - Value: 0x0000002a
+ - AbbrCode: 2
+ Values:
+ - CStr: foo2
+ - Value: 0x0
+ - Value: 0x100
+ - Value: 0x00000040
+ - AbbrCode: 0
+...
# 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
CodeGen
CodeGenTypes
DWARFLinker
+ DWARFLinkerParallel
DebugInfoDWARF
MC
Object
#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"
dumpDIE(DIE, Options.Verbose);
}
-bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple,
- raw_fd_ostream &OutFile) {
- if (Options.NoOutput)
- return true;
-
- Streamer = std::make_unique<DwarfStreamer>(
- 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<const object::ObjectFile &>
DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
const Triple &Triple) {
return Error::success();
}
-ErrorOr<DWARFFile &>
+template <typename OutDWARFFile, typename AddressesMap>
+ErrorOr<std::unique_ptr<OutDWARFFile>>
DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
const DebugMap &DebugMap,
remarks::RemarkLinker &RL) {
auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
+ std::unique_ptr<OutDWARFFile> Res;
if (ErrorOrObj) {
- ContextForLinking.push_back(
- std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj)));
- AddressMapForLinking.push_back(
- std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj));
-
- ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
- Obj.getObjectFilename(), ContextForLinking.back().get(),
- AddressMapForLinking.back().get(),
- Obj.empty() ? Obj.getWarnings() : EmptyWarnings));
+ Res = std::make_unique<OutDWARFFile>(
+ Obj.getObjectFilename(), DWARFContext::create(*ErrorOrObj),
+ std::make_unique<AddressesMap>(*this, *ErrorOrObj, Obj),
+ Obj.empty() ? Obj.getWarnings() : EmptyWarnings);
Error E = RL.link(*ErrorOrObj);
if (Error NewE = handleErrors(
}))
return errorToErrorCode(std::move(NewE));
- return *ObjectsForLinking.back();
+ return Res;
}
return ErrorOrObj.getError();
// 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
return Error::success();
}
+template <typename OutStreamer>
void DwarfLinkerForBinary::copySwiftReflectionMetadata(
- const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer,
+ const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer,
std::vector<uint64_t> &SectionToOffsetInDwarf,
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
&RelocationsToApply) {
}
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<dwarflinker_parallel::DWARFLinker,
+ dwarflinker_parallel::DWARFFile,
+ AddressManager<dwarflinker_parallel::AddressesMap>>(
+ Map, DWARFLinkerOutputType);
+ }
- DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
+ return linkImpl<DWARFLinker, DWARFFile, AddressManager<AddressesMap>>(
+ Map, Options.FileType);
+}
- DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil);
+template <typename Linker>
+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 <typename Linker, typename OutDwarfFile, typename AddressMap>
+bool DwarfLinkerForBinary::linkImpl(
+ const DebugMap &Map, typename Linker::OutputFileType ObjectType) {
+
+ std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking;
+
+ DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
std::function<StringRef(StringRef)> 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<Linker> 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<DWARFFile &> {
+ auto Loader = [&](StringRef ContainerName,
+ StringRef Path) -> ErrorOr<OutDwarfFile &> {
auto &Obj = DebugMap.addDebugMapObject(
Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
- if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
- return *ErrorOrObj;
+ if (ErrorOr<std::unique_ptr<OutDwarfFile>> ErrorOrObj =
+ loadObject<OutDwarfFile, AddressMap>(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;
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.
auto SectionToOffsetInDwarf =
calculateStartOfStrippableReflectionSections(Map);
for (const auto &Obj : Map.objects())
- copySwiftReflectionMetadata(Obj.get(), Streamer.get(),
+ copySwiftReflectionMetadata(Obj.get(), GeneralLinker->getEmitter(),
SectionToOffsetInDwarf, RelocationsToApply);
}
// 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<DWARFFile>(
+ if (ErrorOr<std::unique_ptr<OutDwarfFile>> ErrorOrObj =
+ loadObject<OutDwarfFile, AddressMap>(*Obj, Map, RL)) {
+ ObjectsForLinking.emplace_back(std::move(*ErrorOrObj));
+ GeneralLinker->addObjectFile(*ObjectsForLinking.back(), Loader,
+ OnCUDieLoaded);
+ } else {
+ ObjectsForLinking.push_back(std::make_unique<OutDwarfFile>(
Obj->getObjectFilename(), nullptr, nullptr,
Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
- GeneralLinker.addObjectFile(*ObjectsForLinking.back());
+ GeneralLinker->addObjectFile(*ObjectsForLinking.back());
}
}
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<Linker>(*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();
}
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<ValidReloc> &ValidRelocs) {
+template <typename AddressesMapBase>
+void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
+ findValidRelocsMachO(const object::SectionRef &Section,
+ const object::MachOObjectFile &Obj,
+ const DebugMapObject &DMO,
+ std::vector<ValidReloc> &ValidRelocs) {
Expected<StringRef> ContentsOrErr = Section.getContents();
if (!ContentsOrErr) {
consumeError(ContentsOrErr.takeError());
/// Dispatch the valid relocation finding logic to the
/// appropriate handler depending on the object file format.
-bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
+template <typename AddressesMapBase>
+bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::findValidRelocs(
const object::SectionRef &Section, const object::ObjectFile &Obj,
const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
// Dispatch to the right handler depending on the file type.
/// 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 <typename AddressesMapBase>
+bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
+ findValidRelocsInDebugSections(const object::ObjectFile &Obj,
+ const DebugMapObject &DMO) {
// Find the debug_info section.
bool FoundValidRelocs = false;
for (const object::SectionRef &Section : Obj.sections()) {
return FoundValidRelocs;
}
-std::vector<DwarfLinkerForBinary::AddressManager::ValidReloc>
-DwarfLinkerForBinary::AddressManager::getRelocations(
+template <typename AddressesMapBase>
+std::vector<
+ typename DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
+DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocations(
const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {
- std::vector<DwarfLinkerForBinary::AddressManager::ValidReloc> Res;
+ std::vector<
+ DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
+ Res;
auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) {
return Reloc.Offset < StartPos;
return Res;
}
-void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc &Reloc) {
+template <typename AddressesMapBase>
+void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::printReloc(
+ const ValidReloc &Reloc) {
const auto &Mapping = Reloc.Mapping->getValue();
const uint64_t ObjectAddress = Mapping.ObjectAddress
? uint64_t(*Mapping.ObjectAddress)
uint64_t(Mapping.BinaryAddress));
}
-int64_t
-DwarfLinkerForBinary::AddressManager::getRelocValue(const ValidReloc &Reloc) {
+template <typename AddressesMapBase>
+int64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocValue(
+ const ValidReloc &Reloc) {
int64_t AddrAdjust = relocate(Reloc);
if (Reloc.Mapping->getValue().ObjectAddress)
AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress);
return AddrAdjust;
}
+template <typename AddressesMapBase>
std::optional<int64_t>
-DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
+DwarfLinkerForBinary::AddressManager<AddressesMapBase>::hasValidRelocationAt(
const std::vector<ValidReloc> &AllRelocs, uint64_t StartOffset,
uint64_t EndOffset) {
std::vector<ValidReloc> Relocs =
return std::make_pair(Offset, End);
}
-std::optional<int64_t>
-DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(
- DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,
- uint64_t EndOffset) {
+template <typename AddressesMapBase>
+std::optional<int64_t> DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
+ 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");
return std::nullopt;
}
-std::optional<int64_t>
-DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(
- const DWARFDie &DIE) {
+template <typename AddressesMapBase>
+std::optional<int64_t> DwarfLinkerForBinary::AddressManager<
+ AddressesMapBase>::getSubprogramRelocAdjustment(const DWARFDie &DIE) {
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
std::optional<uint32_t> LowPcIdx =
}
}
-uint64_t
-DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {
+template <typename AddressesMapBase>
+uint64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::relocate(
+ const ValidReloc &Reloc) const {
return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend;
}
/// monotonic \p BaseOffset values.
///
/// \returns whether any reloc has been applied.
-bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
+template <typename AddressesMapBase>
+bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::applyValidRelocs(
MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
std::vector<ValidReloc> Relocs = getRelocations(
ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());
private:
/// Keeps track of relocations.
- class AddressManager : public AddressesMap {
+ template <typename AddressesMapBase>
+ class AddressManager : public AddressesMapBase {
struct ValidReloc {
uint64_t Offset;
uint32_t Size;
std::optional<int64_t> getExprOpAddressRelocAdjustment(
DWARFUnit &U, const DWARFExpression::Operation &Op,
uint64_t StartOffset, uint64_t EndOffset) override;
+
std::optional<int64_t>
getSubprogramRelocAdjustment(const DWARFDie &DIE) override;
/// \defgroup Helpers Various helper methods.
///
/// @{
- bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile);
+ template <typename OutStreamer>
+ bool createStreamer(const Triple &TheTriple,
+ typename OutStreamer::OutputFileType FileType,
+ std::unique_ptr<OutStreamer> &Streamer,
+ raw_fd_ostream &OutFile);
/// Attempt to load a debug object from disk.
ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
const Triple &triple);
- ErrorOr<DWARFFile &> loadObject(const DebugMapObject &Obj,
- const DebugMap &DebugMap,
- remarks::RemarkLinker &RL);
+
+ template <typename OutDWARFFile, typename AddressesMap>
+ ErrorOr<std::unique_ptr<OutDWARFFile>> loadObject(const DebugMapObject &Obj,
+ const DebugMap &DebugMap,
+ remarks::RemarkLinker &RL);
void collectRelocationsToApplyToSwiftReflectionSections(
const object::SectionRef &Section, StringRef &Contents,
Error copySwiftInterfaces(StringRef Architecture) const;
+ template <typename OutStreamer>
void copySwiftReflectionMetadata(
- const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer,
+ const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer,
std::vector<uint64_t> &SectionToOffsetInDwarf,
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
&RelocationsToApply);
+ template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
+ bool linkImpl(const DebugMap &Map,
+ typename Linker::OutputFileType ObjectType);
+
raw_fd_ostream &OutFile;
BinaryHolder &BinHolder;
LinkOptions Options;
std::mutex &ErrorHandlerMutex;
- std::unique_ptr<DwarfStreamer> Streamer;
- std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking;
- std::vector<std::unique_ptr<DWARFContext>> ContextForLinking;
- std::vector<std::unique_ptr<AddressManager>> AddressMapForLinking;
std::vector<std::string> EmptyWarnings;
/// A list of all .swiftinterface files referenced by the debug
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;
/// 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;
unsigned Threads = 1;
// Output file type.
- OutputFileType FileType = OutputFileType::Object;
+ DWARFLinker::OutputFileType FileType = DWARFLinker::OutputFileType::Object;
/// The accelerator table kind
DsymutilAccelTableKind TheAccelTableKind;
HelpText<"Drop remarks without valid debug locations. Without this flags, "
"all remarks are kept.">,
Group<grp_general>;
+
+def linker: Separate<["--", "-"], "linker">,
+ MetaVarName<"<DWARF linker type>">,
+ HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">,
+ Group<grp_general>;
+def: Joined<["--", "-"], "linker=">, Alias<linker>;
return DsymutilAccelTableKind::Default;
}
+static Expected<DsymutilDWARFLinkerType>
+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<StringError>("invalid DWARF linker type specified: '" +
+ S +
+ "'. Supported values are 'apple', "
+ "'llvm'.",
+ inconvertibleErrorCode());
+ }
+
+ return DsymutilDWARFLinkerType::Apple;
+}
+
static Expected<ReproducerMode> getReproducerMode(opt::InputArgList &Args) {
if (Args.hasArg(OPT_gen_reproducer))
return ReproducerMode::GenerateOnExit;
return AccelKind.takeError();
}
+ if (Expected<DsymutilDWARFLinkerType> DWARFLinkerType =
+ getDWARFLinkerType(Args)) {
+ Options.LinkOpts.DWARFLinkerType = *DWARFLinkerType;
+ } else {
+ return DWARFLinkerType.takeError();
+ }
+
if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap))
Options.SymbolMap = SymbolMap->getValue();
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());
AllTargetsInfos
CodeGenTypes
DWARFLinker
+ DWARFLinkerParallel
DebugInfoDWARF
MC
ObjCopy
#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"
// exec: [LowPC, HighPC] is not inside address ranges of .text sections
//
// universal: maxpc and bfd
-class ObjFileAddressMap : public AddressesMap {
+template <typename AddressMapBase>
+class ObjFileAddressMap : public AddressMapBase {
public:
ObjFileAddressMap(DWARFContext &Context, const Options &Options,
object::ObjectFile &ObjFile)
.Default(false);
}
-static std::optional<DwarfLinkerAccelTableKind>
+template <typename AccelTableKind>
+static std::optional<AccelTableKind>
getAcceleratorTableKind(StringRef SecName) {
- return llvm::StringSwitch<std::optional<DwarfLinkerAccelTableKind>>(SecName)
- .Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub)
- .Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub)
- .Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames)
+ return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)
+ .Case(".debug_pubnames", AccelTableKind::Pub)
+ .Case(".debug_pubtypes", AccelTableKind::Pub)
+ .Case(".debug_names", AccelTableKind::DebugNames)
.Default(std::nullopt);
}
return Message;
}
-Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
- raw_pwrite_stream &OutStream) {
-
+template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
+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);
WithColor::error(errs(), Context) << Message << '\n';
};
- // Create output streamer.
- DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr,
- ReportWarn, ReportWarn);
+ // Create DWARF linker.
+ std::unique_ptr<Linker> 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<DWARFContext> 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<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
- std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1);
+ std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking(1);
std::vector<std::string> EmptyWarnings;
// Add object files to the DWARFLinker.
- AddresssMapForLinking[0] =
- std::make_unique<ObjFileAddressMap>(*Context, Options, File);
+ std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
+ std::unique_ptr<ObjFileAddressMap<AddressMapBase>> AddressesMap(
+ std::make_unique<ObjFileAddressMap<AddressMapBase>>(*Context, Options,
+ File));
- ObjectsForLinking[0] = std::make_unique<DWARFFile>(
- File.getFileName(), &*Context, AddresssMapForLinking[0].get(),
- EmptyWarnings);
+ ObjectsForLinking[0] =
+ std::make_unique<OutDwarfFile>(File.getFileName(), std::move(Context),
+ std::move(AddressesMap), EmptyWarnings);
uint16_t MaxDWARFVersion = 0;
std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
};
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<DwarfLinkerAccelTableKind> AccelTables;
+ SmallVector<typename Linker::AccelTableKind> AccelTables;
switch (Options.AccelTableKind) {
case DwarfUtilAccelKind::None:
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<StringRef> AccelTableNamesToReplace;
- SmallVector<StringRef> 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<DwarfLinkerAccelTableKind> 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<OutDwarfFile> &CurFile : ObjectsForLinking) {
+ SmallVector<StringRef> AccelTableNamesToReplace;
+ SmallVector<StringRef> 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<typename Linker::AccelTableKind> SrcAccelTableKind =
+ getAcceleratorTableKind<typename Linker::AccelTableKind>(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<dwarflinker_parallel::DWARFLinker,
+ dwarflinker_parallel::DWARFFile,
+ dwarflinker_parallel::AddressesMap>(File, Options,
+ OutStream);
+ else
+ return linkDebugInfoImpl<DWARFLinker, DWARFFile, AddressesMap>(
+ File, Options, OutStream);
+}
+
} // end of namespace dwarfutil
} // end of namespace llvm
bool Verbose = false;
int NumThreads = 0;
bool Verify = false;
+ bool UseLLVMDWARFLinker = false;
DwarfUtilAccelKind AccelTableKind = DwarfUtilAccelKind::None;
std::string getSeparateDebugFileName() const {
Alias<help>,
HelpText<"Alias for --help">;
+def linker: Separate<["--", "-"], "linker">,
+ MetaVarName<"<DWARF linker type>">,
+ HelpText<"Specify the desired type of DWARF linker. Defaults to 'apple'">;
+def: Joined<["--", "-"], "linker=">, Alias<linker>;
+
defm odr_deduplication : BB<"odr-deduplication",
"Do ODR deduplication for debug types(default)",
"Don`t do ODR deduplication for debug types">;
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();