mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 17:36:06 +00:00
[DWARFLinkerParallel] Add interface files, create a skeleton implementation.
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
This commit is contained in:
parent
7a258706e3
commit
e0ba9b2ace
@ -14,6 +14,7 @@
|
|||||||
#include "llvm/CodeGen/AccelTable.h"
|
#include "llvm/CodeGen/AccelTable.h"
|
||||||
#include "llvm/CodeGen/NonRelocatableStringpool.h"
|
#include "llvm/CodeGen/NonRelocatableStringpool.h"
|
||||||
#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
|
#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
|
||||||
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
|
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
||||||
@ -21,7 +22,6 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class DWARFContext;
|
|
||||||
class DWARFExpression;
|
class DWARFExpression;
|
||||||
class DWARFUnit;
|
class DWARFUnit;
|
||||||
class DataExtractor;
|
class DataExtractor;
|
||||||
@ -30,13 +30,6 @@ template <typename T> class SmallVectorImpl;
|
|||||||
|
|
||||||
enum class DwarfLinkerClient { Dsymutil, LLD, General };
|
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
|
/// AddressesMap represents information about valid addresses used
|
||||||
/// by debug information. Valid addresses are those which points to
|
/// by debug information. Valid addresses are those which points to
|
||||||
/// live code sections. i.e. relocations for these addresses point
|
/// live code sections. i.e. relocations for these addresses point
|
||||||
@ -221,39 +214,48 @@ public:
|
|||||||
|
|
||||||
/// Returns size of generated .debug_loclists section.
|
/// Returns size of generated .debug_loclists section.
|
||||||
virtual uint64_t getLocListsSectionSize() const = 0;
|
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>>;
|
using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>;
|
||||||
|
|
||||||
/// This class represents DWARF information for source file
|
/// This class represents DWARF information for source file
|
||||||
/// and its address map.
|
/// and its address map.
|
||||||
class DWARFFile {
|
class DWARFFile {
|
||||||
public:
|
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)
|
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.
|
/// The object file name.
|
||||||
StringRef FileName;
|
StringRef FileName;
|
||||||
|
|
||||||
/// The source DWARF information.
|
/// The source DWARF information.
|
||||||
DWARFContext *Dwarf = nullptr;
|
std::unique_ptr<DWARFContext> Dwarf;
|
||||||
|
|
||||||
/// Helpful address information(list of valid address ranges, relocations).
|
/// Helpful address information(list of valid address ranges, relocations).
|
||||||
AddressesMap *Addresses = nullptr;
|
std::unique_ptr<AddressesMap> Addresses;
|
||||||
|
|
||||||
/// Warnings for this object file.
|
/// Warnings for this object file.
|
||||||
const std::vector<std::string> &Warnings;
|
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> swiftInterfacesMap;
|
||||||
typedef std::map<std::string, std::string> objectPrefixMap;
|
typedef std::map<std::string, std::string> objectPrefixMap;
|
||||||
|
|
||||||
@ -275,9 +277,43 @@ typedef function_ref<void(const DWARFUnit &Unit)> CompileUnitHandler;
|
|||||||
/// processing a object file.
|
/// processing a object file.
|
||||||
class DWARFLinker {
|
class DWARFLinker {
|
||||||
public:
|
public:
|
||||||
DWARFLinker(DwarfEmitter *Emitter,
|
typedef std::function<void(const Twine &Warning, StringRef Context,
|
||||||
DwarfLinkerClient ClientID = DwarfLinkerClient::General)
|
const DWARFDie *DIE)>
|
||||||
: TheDwarfEmitter(Emitter), DwarfLinkerClientID(ClientID) {}
|
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
|
/// Add object file to be linked. Pre-load compile unit die. Call
|
||||||
/// \p OnCUDieLoaded for each compile unit die. If specified \p File
|
/// \p OnCUDieLoaded for each compile unit die. If specified \p File
|
||||||
@ -289,8 +325,7 @@ public:
|
|||||||
DWARFFile &File, objFileLoader Loader = nullptr,
|
DWARFFile &File, objFileLoader Loader = nullptr,
|
||||||
CompileUnitHandler OnCUDieLoaded = [](const DWARFUnit &) {});
|
CompileUnitHandler OnCUDieLoaded = [](const DWARFUnit &) {});
|
||||||
|
|
||||||
/// Link debug info for added objFiles. Object
|
/// Link debug info for added objFiles. Object files are linked all together.
|
||||||
/// files are linked all together.
|
|
||||||
Error link();
|
Error link();
|
||||||
|
|
||||||
/// A number of methods setting various linking options:
|
/// A number of methods setting various linking options:
|
||||||
@ -304,14 +339,15 @@ public:
|
|||||||
/// Verify the input DWARF.
|
/// Verify the input DWARF.
|
||||||
void setVerifyInputDWARF(bool Verify) { Options.VerifyInputDWARF = Verify; }
|
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.
|
/// Do not unique types according to ODR.
|
||||||
void setNoODR(bool NoODR) { Options.NoODR = NoODR; }
|
void setNoODR(bool NoODR) { Options.NoODR = NoODR; }
|
||||||
|
|
||||||
/// update existing DWARF info(for the linked binary).
|
/// Update index tables only(do not modify rest of DWARF).
|
||||||
void setUpdate(bool Update) { Options.Update = Update; }
|
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.
|
/// Set whether to keep the enclosing function for a static variable.
|
||||||
void setKeepFunctionForStatic(bool KeepFunctionForStatic) {
|
void setKeepFunctionForStatic(bool KeepFunctionForStatic) {
|
||||||
@ -322,7 +358,7 @@ public:
|
|||||||
void setNumThreads(unsigned NumThreads) { Options.Threads = NumThreads; }
|
void setNumThreads(unsigned NumThreads) { Options.Threads = NumThreads; }
|
||||||
|
|
||||||
/// Add kind of accelerator tables to be generated.
|
/// 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(),
|
assert(std::find(Options.AccelTables.begin(), Options.AccelTables.end(),
|
||||||
Kind) == Options.AccelTables.end());
|
Kind) == Options.AccelTables.end());
|
||||||
Options.AccelTables.emplace_back(Kind);
|
Options.AccelTables.emplace_back(Kind);
|
||||||
@ -331,27 +367,11 @@ public:
|
|||||||
/// Set prepend path for clang modules.
|
/// Set prepend path for clang modules.
|
||||||
void setPrependPath(const std::string &Ppath) { Options.PrependPath = Ppath; }
|
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.
|
/// Set estimated objects files amount, for preliminary data allocation.
|
||||||
void setEstimatedObjfilesAmount(unsigned ObjFilesNum) {
|
void setEstimatedObjfilesAmount(unsigned ObjFilesNum) {
|
||||||
ObjectContexts.reserve(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
|
/// Set verification handler which would be used to report verification
|
||||||
/// errors.
|
/// errors.
|
||||||
void setInputVerificationHandler(inputVerificationHandler Handler) {
|
void setInputVerificationHandler(inputVerificationHandler Handler) {
|
||||||
@ -370,7 +390,7 @@ public:
|
|||||||
|
|
||||||
/// Set target DWARF version.
|
/// Set target DWARF version.
|
||||||
Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) {
|
Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) {
|
||||||
if (TargetDWARFVersion < 1 || TargetDWARFVersion > 5)
|
if ((TargetDWARFVersion < 1) || (TargetDWARFVersion > 5))
|
||||||
return createStringError(std::errc::invalid_argument,
|
return createStringError(std::errc::invalid_argument,
|
||||||
"unsupported DWARF version: %d",
|
"unsupported DWARF version: %d",
|
||||||
TargetDWARFVersion);
|
TargetDWARFVersion);
|
||||||
@ -444,14 +464,14 @@ private:
|
|||||||
|
|
||||||
void reportWarning(const Twine &Warning, const DWARFFile &File,
|
void reportWarning(const Twine &Warning, const DWARFFile &File,
|
||||||
const DWARFDie *DIE = nullptr) const {
|
const DWARFDie *DIE = nullptr) const {
|
||||||
if (Options.WarningHandler != nullptr)
|
if (WarningHandler != nullptr)
|
||||||
Options.WarningHandler(Warning, File.FileName, DIE);
|
WarningHandler(Warning, File.FileName, DIE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reportError(const Twine &Warning, const DWARFFile &File,
|
void reportError(const Twine &Warning, const DWARFFile &File,
|
||||||
const DWARFDie *DIE = nullptr) const {
|
const DWARFDie *DIE = nullptr) const {
|
||||||
if (Options.ErrorHandler != nullptr)
|
if (ErrorHandler != nullptr)
|
||||||
Options.ErrorHandler(Warning, File.FileName, DIE);
|
ErrorHandler(Warning, File.FileName, DIE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emit warnings as Dwarf compile units to leave a trail after linking.
|
/// Emit warnings as Dwarf compile units to leave a trail after linking.
|
||||||
@ -799,7 +819,7 @@ private:
|
|||||||
BumpPtrAllocator DIEAlloc;
|
BumpPtrAllocator DIEAlloc;
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
DwarfEmitter *TheDwarfEmitter;
|
std::unique_ptr<DwarfStreamer> TheDwarfEmitter;
|
||||||
std::vector<LinkContext> ObjectContexts;
|
std::vector<LinkContext> ObjectContexts;
|
||||||
|
|
||||||
/// The CIEs that have been emitted in the output section. The actual CIE
|
/// The CIEs that have been emitted in the output section. The actual CIE
|
||||||
@ -828,6 +848,12 @@ private:
|
|||||||
/// A unique ID that identifies each compile unit.
|
/// A unique ID that identifies each compile unit.
|
||||||
unsigned UniqueUnitID = 0;
|
unsigned UniqueUnitID = 0;
|
||||||
|
|
||||||
|
// error handler
|
||||||
|
messageHandler ErrorHandler = nullptr;
|
||||||
|
|
||||||
|
// warning handler
|
||||||
|
messageHandler WarningHandler = nullptr;
|
||||||
|
|
||||||
/// linking options
|
/// linking options
|
||||||
struct DWARFLinkerOptions {
|
struct DWARFLinkerOptions {
|
||||||
/// DWARF version for the output.
|
/// DWARF version for the output.
|
||||||
@ -842,9 +868,6 @@ private:
|
|||||||
/// Verify the input DWARF.
|
/// Verify the input DWARF.
|
||||||
bool VerifyInputDWARF = false;
|
bool VerifyInputDWARF = false;
|
||||||
|
|
||||||
/// Skip emitting output
|
|
||||||
bool NoOutput = false;
|
|
||||||
|
|
||||||
/// Do not unique types according to ODR
|
/// Do not unique types according to ODR
|
||||||
bool NoODR = false;
|
bool NoODR = false;
|
||||||
|
|
||||||
@ -859,17 +882,11 @@ private:
|
|||||||
unsigned Threads = 1;
|
unsigned Threads = 1;
|
||||||
|
|
||||||
/// The accelerator table kinds
|
/// The accelerator table kinds
|
||||||
SmallVector<DwarfLinkerAccelTableKind, 1> AccelTables;
|
SmallVector<AccelTableKind, 1> AccelTables;
|
||||||
|
|
||||||
/// Prepend path for the clang modules.
|
/// Prepend path for the clang modules.
|
||||||
std::string PrependPath;
|
std::string PrependPath;
|
||||||
|
|
||||||
// warning handler
|
|
||||||
messageHandler WarningHandler = nullptr;
|
|
||||||
|
|
||||||
// error handler
|
|
||||||
messageHandler ErrorHandler = nullptr;
|
|
||||||
|
|
||||||
// input verification handler
|
// input verification handler
|
||||||
inputVerificationHandler InputVerificationHandler = nullptr;
|
inputVerificationHandler InputVerificationHandler = nullptr;
|
||||||
|
|
||||||
|
@ -23,11 +23,6 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
template <typename DataT> class AccelTable;
|
template <typename DataT> class AccelTable;
|
||||||
|
|
||||||
enum class OutputFileType {
|
|
||||||
Object,
|
|
||||||
Assembly,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// User of DwarfStreamer should call initialization code
|
/// User of DwarfStreamer should call initialization code
|
||||||
/// for AsmPrinter:
|
/// for AsmPrinter:
|
||||||
///
|
///
|
||||||
@ -45,18 +40,19 @@ class DWARFDebugMacro;
|
|||||||
/// information binary representation are handled in this class.
|
/// information binary representation are handled in this class.
|
||||||
class DwarfStreamer : public DwarfEmitter {
|
class DwarfStreamer : public DwarfEmitter {
|
||||||
public:
|
public:
|
||||||
DwarfStreamer(OutputFileType OutFileType, raw_pwrite_stream &OutFile,
|
DwarfStreamer(DWARFLinker::OutputFileType OutFileType,
|
||||||
|
raw_pwrite_stream &OutFile,
|
||||||
std::function<StringRef(StringRef Input)> Translator,
|
std::function<StringRef(StringRef Input)> Translator,
|
||||||
messageHandler Error, messageHandler Warning)
|
DWARFLinker::messageHandler Warning)
|
||||||
: OutFile(OutFile), OutFileType(OutFileType), Translator(Translator),
|
: 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.
|
/// 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
|
/// Set the current output section to debug_info and change
|
||||||
/// the MC Dwarf version to \p DwarfVersion.
|
/// the MC Dwarf version to \p DwarfVersion.
|
||||||
@ -89,12 +85,12 @@ public:
|
|||||||
void emitLineStrings(const NonRelocatableStringpool &Pool) override;
|
void emitLineStrings(const NonRelocatableStringpool &Pool) override;
|
||||||
|
|
||||||
/// Emit the swift_ast section stored in \p Buffer.
|
/// 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.
|
/// Emit the swift reflection section stored in \p Buffer.
|
||||||
void emitSwiftReflectionSection(
|
void emitSwiftReflectionSection(
|
||||||
llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind,
|
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.
|
/// Emit debug ranges(.debug_ranges, .debug_rnglists) header.
|
||||||
MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) override;
|
MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) override;
|
||||||
@ -194,11 +190,6 @@ public:
|
|||||||
OffsetsStringPool &StringPool) override;
|
OffsetsStringPool &StringPool) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void error(const Twine &Error, StringRef Context = "") {
|
|
||||||
if (ErrorHandler)
|
|
||||||
ErrorHandler(Error, Context, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void warn(const Twine &Warning, StringRef Context = "") {
|
inline void warn(const Twine &Warning, StringRef Context = "") {
|
||||||
if (WarningHandler)
|
if (WarningHandler)
|
||||||
WarningHandler(Warning, Context, nullptr);
|
WarningHandler(Warning, Context, nullptr);
|
||||||
@ -274,7 +265,7 @@ private:
|
|||||||
|
|
||||||
/// The output file we stream the linked Dwarf to.
|
/// The output file we stream the linked Dwarf to.
|
||||||
raw_pwrite_stream &OutFile;
|
raw_pwrite_stream &OutFile;
|
||||||
OutputFileType OutFileType = OutputFileType::Object;
|
DWARFLinker::OutputFileType OutFileType = DWARFLinker::OutputFileType::Object;
|
||||||
std::function<StringRef(StringRef Input)> Translator;
|
std::function<StringRef(StringRef Input)> Translator;
|
||||||
|
|
||||||
uint64_t RangesSectionSize = 0;
|
uint64_t RangesSectionSize = 0;
|
||||||
@ -300,8 +291,7 @@ private:
|
|||||||
const CompileUnit &Unit,
|
const CompileUnit &Unit,
|
||||||
const std::vector<CompileUnit::AccelInfo> &Names);
|
const std::vector<CompileUnit::AccelInfo> &Names);
|
||||||
|
|
||||||
messageHandler ErrorHandler = nullptr;
|
DWARFLinker::messageHandler WarningHandler = nullptr;
|
||||||
messageHandler WarningHandler = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
73
llvm/include/llvm/DWARFLinkerParallel/DWARFFile.h
Normal file
73
llvm/include/llvm/DWARFLinkerParallel/DWARFFile.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
//===- DWARFFile.h ----------------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_DWARFLINKERPARALLEL_DWARFFILE_H
|
||||||
|
#define LLVM_DWARFLINKERPARALLEL_DWARFFILE_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/AddressesMap.h"
|
||||||
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||||
|
#include "llvm/Support/Endian.h"
|
||||||
|
#include <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
|
@ -9,10 +9,219 @@
|
|||||||
#ifndef LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H
|
#ifndef LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H
|
||||||
#define 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 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
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H
|
#endif // LLVM_DWARFLINKERPARALLEL_DWARFLINKER_H
|
||||||
|
@ -67,6 +67,10 @@ public:
|
|||||||
Handler(*Entry);
|
Handler(*Entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::function<StringRef(StringRef)> getTranslator() {
|
||||||
|
return StringsTranslator;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// List of strings for emission.
|
/// List of strings for emission.
|
||||||
StringsVector StringEntriesForEmission;
|
StringsVector StringEntriesForEmission;
|
||||||
|
@ -43,6 +43,9 @@ class DWARFObject;
|
|||||||
class raw_ostream;
|
class raw_ostream;
|
||||||
struct DIDumpOptions;
|
struct DIDumpOptions;
|
||||||
struct DWARFSection;
|
struct DWARFSection;
|
||||||
|
namespace dwarflinker_parallel {
|
||||||
|
class CompileUnit;
|
||||||
|
}
|
||||||
|
|
||||||
/// Base class describing the header of any kind of "unit." Some information
|
/// 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
|
/// is specific to certain unit types. We separate this class out so we can
|
||||||
@ -253,6 +256,8 @@ class DWARFUnit {
|
|||||||
std::shared_ptr<DWARFUnit> DWO;
|
std::shared_ptr<DWARFUnit> DWO;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend dwarflinker_parallel::CompileUnit;
|
||||||
|
|
||||||
/// Return the index of a \p Die entry inside the unit's DIE vector.
|
/// 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
|
/// It is illegal to call this method with a DIE that hasn't be
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/CodeGen/NonRelocatableStringpool.h"
|
#include "llvm/CodeGen/NonRelocatableStringpool.h"
|
||||||
#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
|
#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
|
||||||
|
#include "llvm/DWARFLinker/DWARFStreamer.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
|
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
|
||||||
@ -2056,7 +2057,7 @@ void DWARFLinker::DIECloner::rememberUnitForMacroOffset(CompileUnit &Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
|
void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
|
||||||
if (LLVM_UNLIKELY(Linker.Options.NoOutput))
|
if (LLVM_UNLIKELY(Emitter == nullptr))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Check whether DW_AT_stmt_list attribute is presented.
|
// Check whether DW_AT_stmt_list attribute is presented.
|
||||||
@ -2177,9 +2178,9 @@ void DWARFLinker::DIECloner::generateLineTableForUnit(CompileUnit &Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
|
void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
|
||||||
for (DwarfLinkerAccelTableKind AccelTableKind : Options.AccelTables) {
|
for (AccelTableKind AccelTableKind : Options.AccelTables) {
|
||||||
switch (AccelTableKind) {
|
switch (AccelTableKind) {
|
||||||
case DwarfLinkerAccelTableKind::Apple: {
|
case AccelTableKind::Apple: {
|
||||||
// Add namespaces.
|
// Add namespaces.
|
||||||
for (const auto &Namespace : Unit.getNamespaces())
|
for (const auto &Namespace : Unit.getNamespaces())
|
||||||
AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() +
|
AppleNamespaces.addName(Namespace.Name, Namespace.Die->getOffset() +
|
||||||
@ -2201,11 +2202,11 @@ void DWARFLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
|
|||||||
AppleObjc.addName(ObjC.Name,
|
AppleObjc.addName(ObjC.Name,
|
||||||
ObjC.Die->getOffset() + Unit.getStartOffset());
|
ObjC.Die->getOffset() + Unit.getStartOffset());
|
||||||
} break;
|
} break;
|
||||||
case DwarfLinkerAccelTableKind::Pub: {
|
case AccelTableKind::Pub: {
|
||||||
TheDwarfEmitter->emitPubNamesForUnit(Unit);
|
TheDwarfEmitter->emitPubNamesForUnit(Unit);
|
||||||
TheDwarfEmitter->emitPubTypesForUnit(Unit);
|
TheDwarfEmitter->emitPubTypesForUnit(Unit);
|
||||||
} break;
|
} break;
|
||||||
case DwarfLinkerAccelTableKind::DebugNames: {
|
case AccelTableKind::DebugNames: {
|
||||||
for (const auto &Namespace : Unit.getNamespaces())
|
for (const auto &Namespace : Unit.getNamespaces())
|
||||||
DebugNames.addName(Namespace.Name, Namespace.Die->getOffset(),
|
DebugNames.addName(Namespace.Name, Namespace.Die->getOffset(),
|
||||||
Namespace.Die->getTag(), Unit.getUniqueID());
|
Namespace.Die->getTag(), Unit.getUniqueID());
|
||||||
@ -2524,7 +2525,7 @@ Error DWARFLinker::loadClangModule(objFileLoader Loader, const DWARFDie &CUDie,
|
|||||||
uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
|
uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
|
||||||
DWARFContext &DwarfContext, const DWARFFile &File, bool IsLittleEndian) {
|
DWARFContext &DwarfContext, const DWARFFile &File, bool IsLittleEndian) {
|
||||||
uint64_t OutputDebugInfoSize =
|
uint64_t OutputDebugInfoSize =
|
||||||
Linker.Options.NoOutput ? 0 : Emitter->getDebugInfoSectionSize();
|
(Emitter == nullptr) ? 0 : Emitter->getDebugInfoSectionSize();
|
||||||
const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
|
const uint64_t StartOutputDebugInfoSize = OutputDebugInfoSize;
|
||||||
|
|
||||||
for (auto &CurrentUnit : CompileUnits) {
|
for (auto &CurrentUnit : CompileUnits) {
|
||||||
@ -2547,8 +2548,7 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
|
|||||||
|
|
||||||
OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
|
OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset(DwarfVersion);
|
||||||
|
|
||||||
if (!Linker.Options.NoOutput) {
|
if (Emitter != nullptr) {
|
||||||
assert(Emitter);
|
|
||||||
|
|
||||||
generateLineTableForUnit(*CurrentUnit);
|
generateLineTableForUnit(*CurrentUnit);
|
||||||
|
|
||||||
@ -2575,10 +2575,10 @@ uint64_t DWARFLinker::DIECloner::cloneAllCompileUnits(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Linker.Options.NoOutput) {
|
if (Emitter != nullptr) {
|
||||||
assert(Emitter);
|
assert(Emitter);
|
||||||
// Emit macro tables.
|
// Emit macro tables.
|
||||||
Emitter->emitMacroTables(File.Dwarf, UnitMacroMap, DebugStrPool);
|
Emitter->emitMacroTables(File.Dwarf.get(), UnitMacroMap, DebugStrPool);
|
||||||
|
|
||||||
// Emit all the compile unit's debug information.
|
// Emit all the compile unit's debug information.
|
||||||
for (auto &CurrentUnit : CompileUnits) {
|
for (auto &CurrentUnit : CompileUnits) {
|
||||||
@ -2703,7 +2703,6 @@ void DWARFLinker::addObjectFile(DWARFFile &File, objFileLoader Loader,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error DWARFLinker::link() {
|
Error DWARFLinker::link() {
|
||||||
assert(Options.NoOutput || TheDwarfEmitter);
|
|
||||||
assert((Options.TargetDWARFVersion != 0) &&
|
assert((Options.TargetDWARFVersion != 0) &&
|
||||||
"TargetDWARFVersion should be set");
|
"TargetDWARFVersion should be set");
|
||||||
|
|
||||||
@ -2793,7 +2792,8 @@ Error DWARFLinker::link() {
|
|||||||
// later. This prevents undeterminism when analyze and clone execute
|
// later. This prevents undeterminism when analyze and clone execute
|
||||||
// concurrently, as clone set the canonical DIE offset and analyze reads it.
|
// concurrently, as clone set the canonical DIE offset and analyze reads it.
|
||||||
const uint64_t ModulesEndOffset =
|
const uint64_t ModulesEndOffset =
|
||||||
Options.NoOutput ? 0 : TheDwarfEmitter->getDebugInfoSectionSize();
|
(TheDwarfEmitter == nullptr) ? 0
|
||||||
|
: TheDwarfEmitter->getDebugInfoSectionSize();
|
||||||
|
|
||||||
// These variables manage the list of processed object files.
|
// These variables manage the list of processed object files.
|
||||||
// The mutex and condition variable are to ensure that this is thread safe.
|
// The mutex and condition variable are to ensure that this is thread safe.
|
||||||
@ -2878,13 +2878,13 @@ Error DWARFLinker::link() {
|
|||||||
SizeByObject[OptContext.File.FileName].Input =
|
SizeByObject[OptContext.File.FileName].Input =
|
||||||
getDebugInfoSize(*OptContext.File.Dwarf);
|
getDebugInfoSize(*OptContext.File.Dwarf);
|
||||||
SizeByObject[OptContext.File.FileName].Output =
|
SizeByObject[OptContext.File.FileName].Output =
|
||||||
DIECloner(*this, TheDwarfEmitter, OptContext.File, DIEAlloc,
|
DIECloner(*this, TheDwarfEmitter.get(), OptContext.File, DIEAlloc,
|
||||||
OptContext.CompileUnits, Options.Update, DebugStrPool,
|
OptContext.CompileUnits, Options.Update, DebugStrPool,
|
||||||
DebugLineStrPool)
|
DebugLineStrPool)
|
||||||
.cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
|
.cloneAllCompileUnits(*OptContext.File.Dwarf, OptContext.File,
|
||||||
OptContext.File.Dwarf->isLittleEndian());
|
OptContext.File.Dwarf->isLittleEndian());
|
||||||
}
|
}
|
||||||
if (!Options.NoOutput && !OptContext.CompileUnits.empty() &&
|
if ((TheDwarfEmitter != nullptr) && !OptContext.CompileUnits.empty() &&
|
||||||
LLVM_LIKELY(!Options.Update))
|
LLVM_LIKELY(!Options.Update))
|
||||||
patchFrameInfoForObject(
|
patchFrameInfoForObject(
|
||||||
OptContext.File, OptContext.File.Addresses->getValidAddressRanges(),
|
OptContext.File, OptContext.File.Addresses->getValidAddressRanges(),
|
||||||
@ -2897,23 +2897,23 @@ Error DWARFLinker::link() {
|
|||||||
|
|
||||||
auto EmitLambda = [&]() {
|
auto EmitLambda = [&]() {
|
||||||
// Emit everything that's global.
|
// Emit everything that's global.
|
||||||
if (!Options.NoOutput) {
|
if (TheDwarfEmitter != nullptr) {
|
||||||
TheDwarfEmitter->emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
|
TheDwarfEmitter->emitAbbrevs(Abbreviations, Options.TargetDWARFVersion);
|
||||||
TheDwarfEmitter->emitStrings(DebugStrPool);
|
TheDwarfEmitter->emitStrings(DebugStrPool);
|
||||||
TheDwarfEmitter->emitLineStrings(DebugLineStrPool);
|
TheDwarfEmitter->emitLineStrings(DebugLineStrPool);
|
||||||
for (DwarfLinkerAccelTableKind TableKind : Options.AccelTables) {
|
for (AccelTableKind TableKind : Options.AccelTables) {
|
||||||
switch (TableKind) {
|
switch (TableKind) {
|
||||||
case DwarfLinkerAccelTableKind::Apple:
|
case AccelTableKind::Apple:
|
||||||
TheDwarfEmitter->emitAppleNamespaces(AppleNamespaces);
|
TheDwarfEmitter->emitAppleNamespaces(AppleNamespaces);
|
||||||
TheDwarfEmitter->emitAppleNames(AppleNames);
|
TheDwarfEmitter->emitAppleNames(AppleNames);
|
||||||
TheDwarfEmitter->emitAppleTypes(AppleTypes);
|
TheDwarfEmitter->emitAppleTypes(AppleTypes);
|
||||||
TheDwarfEmitter->emitAppleObjc(AppleObjc);
|
TheDwarfEmitter->emitAppleObjc(AppleObjc);
|
||||||
break;
|
break;
|
||||||
case DwarfLinkerAccelTableKind::Pub:
|
case AccelTableKind::Pub:
|
||||||
// Already emitted by emitAcceleratorEntriesForUnit.
|
// Already emitted by emitAcceleratorEntriesForUnit.
|
||||||
// Already emitted by emitAcceleratorEntriesForUnit.
|
// Already emitted by emitAcceleratorEntriesForUnit.
|
||||||
break;
|
break;
|
||||||
case DwarfLinkerAccelTableKind::DebugNames:
|
case AccelTableKind::DebugNames:
|
||||||
TheDwarfEmitter->emitDebugNames(DebugNames);
|
TheDwarfEmitter->emitDebugNames(DebugNames);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3041,7 +3041,7 @@ Error DWARFLinker::cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit,
|
|||||||
UnitListTy CompileUnits;
|
UnitListTy CompileUnits;
|
||||||
CompileUnits.emplace_back(std::move(Unit.Unit));
|
CompileUnits.emplace_back(std::move(Unit.Unit));
|
||||||
assert(TheDwarfEmitter);
|
assert(TheDwarfEmitter);
|
||||||
DIECloner(*this, TheDwarfEmitter, Unit.File, DIEAlloc, CompileUnits,
|
DIECloner(*this, TheDwarfEmitter.get(), Unit.File, DIEAlloc, CompileUnits,
|
||||||
Options.Update, DebugStrPool, DebugLineStrPool)
|
Options.Update, DebugStrPool, DebugLineStrPool)
|
||||||
.cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
|
.cloneAllCompileUnits(*Unit.File.Dwarf, Unit.File,
|
||||||
Unit.File.Dwarf->isLittleEndian());
|
Unit.File.Dwarf->isLittleEndian());
|
||||||
@ -3059,4 +3059,16 @@ void DWARFLinker::verifyInput(const DWARFFile &File) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -28,33 +28,37 @@
|
|||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
bool DwarfStreamer::init(Triple TheTriple,
|
Error DwarfStreamer::init(Triple TheTriple,
|
||||||
StringRef Swift5ReflectionSegmentName) {
|
StringRef Swift5ReflectionSegmentName) {
|
||||||
std::string ErrorStr;
|
std::string ErrorStr;
|
||||||
std::string TripleName;
|
std::string TripleName;
|
||||||
StringRef Context = "dwarf streamer init";
|
|
||||||
|
|
||||||
// Get the target.
|
// Get the target.
|
||||||
const Target *TheTarget =
|
const Target *TheTarget =
|
||||||
TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
|
TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
|
||||||
if (!TheTarget)
|
if (!TheTarget)
|
||||||
return error(ErrorStr, Context), false;
|
return createStringError(std::errc::invalid_argument, ErrorStr.c_str());
|
||||||
|
|
||||||
TripleName = TheTriple.getTriple();
|
TripleName = TheTriple.getTriple();
|
||||||
|
|
||||||
// Create all the MC Objects.
|
// Create all the MC Objects.
|
||||||
MRI.reset(TheTarget->createMCRegInfo(TripleName));
|
MRI.reset(TheTarget->createMCRegInfo(TripleName));
|
||||||
if (!MRI)
|
if (!MRI)
|
||||||
return error(Twine("no register info for target ") + TripleName, Context),
|
return createStringError(std::errc::invalid_argument,
|
||||||
false;
|
"no register info for target %s",
|
||||||
|
TripleName.c_str());
|
||||||
|
|
||||||
MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
|
MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
|
||||||
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
|
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
|
||||||
if (!MAI)
|
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, "", ""));
|
MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
|
||||||
if (!MSTI)
|
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,
|
MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr,
|
||||||
nullptr, true, Swift5ReflectionSegmentName));
|
nullptr, true, Swift5ReflectionSegmentName));
|
||||||
@ -63,18 +67,24 @@ bool DwarfStreamer::init(Triple TheTriple,
|
|||||||
|
|
||||||
MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
|
MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
|
||||||
if (!MAB)
|
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());
|
MII.reset(TheTarget->createMCInstrInfo());
|
||||||
if (!MII)
|
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);
|
MCE = TheTarget->createMCCodeEmitter(*MII, *MC);
|
||||||
if (!MCE)
|
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) {
|
switch (OutFileType) {
|
||||||
case OutputFileType::Assembly: {
|
case DWARFLinker::OutputFileType::Assembly: {
|
||||||
MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(),
|
MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(),
|
||||||
*MAI, *MII, *MRI);
|
*MAI, *MII, *MRI);
|
||||||
MS = TheTarget->createAsmStreamer(
|
MS = TheTarget->createAsmStreamer(
|
||||||
@ -83,7 +93,7 @@ bool DwarfStreamer::init(Triple TheTriple,
|
|||||||
true);
|
true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OutputFileType::Object: {
|
case DWARFLinker::OutputFileType::Object: {
|
||||||
MS = TheTarget->createMCObjectStreamer(
|
MS = TheTarget->createMCObjectStreamer(
|
||||||
TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
|
TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB),
|
||||||
MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE),
|
MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE),
|
||||||
@ -94,17 +104,23 @@ bool DwarfStreamer::init(Triple TheTriple,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!MS)
|
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.
|
// Finally create the AsmPrinter we'll use to emit the DIEs.
|
||||||
TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
|
TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
|
||||||
std::nullopt));
|
std::nullopt));
|
||||||
if (!TM)
|
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)));
|
Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
|
||||||
if (!Asm)
|
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);
|
Asm->setDwarfUsesRelocationsAcrossSections(false);
|
||||||
|
|
||||||
RangesSectionSize = 0;
|
RangesSectionSize = 0;
|
||||||
@ -117,7 +133,7 @@ bool DwarfStreamer::init(Triple TheTriple,
|
|||||||
MacInfoSectionSize = 0;
|
MacInfoSectionSize = 0;
|
||||||
MacroSectionSize = 0;
|
MacroSectionSize = 0;
|
||||||
|
|
||||||
return true;
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DwarfStreamer::finish() { MS->finish(); }
|
void DwarfStreamer::finish() { MS->finish(); }
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
add_llvm_component_library(LLVMDWARFLinkerParallel
|
add_llvm_component_library(LLVMDWARFLinkerParallel
|
||||||
|
DWARFEmitterImpl.cpp
|
||||||
DWARFLinker.cpp
|
DWARFLinker.cpp
|
||||||
|
DWARFLinkerImpl.cpp
|
||||||
|
OutputSections.cpp
|
||||||
StringPool.cpp
|
StringPool.cpp
|
||||||
|
|
||||||
ADDITIONAL_HEADER_DIRS
|
ADDITIONAL_HEADER_DIRS
|
||||||
|
131
llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.cpp
Normal file
131
llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.cpp
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
//===- DWARFEmitterImpl.cpp -----------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "DWARFEmitterImpl.h"
|
||||||
|
#include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h"
|
||||||
|
#include "llvm/MC/MCAsmBackend.h"
|
||||||
|
#include "llvm/MC/MCCodeEmitter.h"
|
||||||
|
#include "llvm/MC/MCObjectWriter.h"
|
||||||
|
#include "llvm/MC/MCSubtargetInfo.h"
|
||||||
|
#include "llvm/MC/MCTargetOptions.h"
|
||||||
|
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
|
||||||
|
#include "llvm/MC/TargetRegistry.h"
|
||||||
|
#include "llvm/Support/FormattedStream.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace dwarflinker_parallel {
|
||||||
|
|
||||||
|
Error DwarfEmitterImpl::init(Triple TheTriple,
|
||||||
|
StringRef Swift5ReflectionSegmentName) {
|
||||||
|
std::string ErrorStr;
|
||||||
|
std::string TripleName;
|
||||||
|
|
||||||
|
// Get the target.
|
||||||
|
const Target *TheTarget =
|
||||||
|
TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
|
||||||
|
if (!TheTarget)
|
||||||
|
return createStringError(std::errc::invalid_argument, ErrorStr.c_str());
|
||||||
|
TripleName = TheTriple.getTriple();
|
||||||
|
|
||||||
|
// Create all the MC Objects.
|
||||||
|
MRI.reset(TheTarget->createMCRegInfo(TripleName));
|
||||||
|
if (!MRI)
|
||||||
|
return createStringError(std::errc::invalid_argument,
|
||||||
|
"no register info for target %s",
|
||||||
|
TripleName.c_str());
|
||||||
|
|
||||||
|
MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags();
|
||||||
|
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
|
||||||
|
if (!MAI)
|
||||||
|
return createStringError(std::errc::invalid_argument,
|
||||||
|
"no asm info for target %s", TripleName.c_str());
|
||||||
|
|
||||||
|
MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
|
||||||
|
if (!MSTI)
|
||||||
|
return createStringError(std::errc::invalid_argument,
|
||||||
|
"no subtarget info for target %s",
|
||||||
|
TripleName.c_str());
|
||||||
|
|
||||||
|
MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr,
|
||||||
|
nullptr, true, Swift5ReflectionSegmentName));
|
||||||
|
MOFI.reset(TheTarget->createMCObjectFileInfo(*MC, /*PIC=*/false, false));
|
||||||
|
MC->setObjectFileInfo(MOFI.get());
|
||||||
|
|
||||||
|
MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
|
||||||
|
if (!MAB)
|
||||||
|
return createStringError(std::errc::invalid_argument,
|
||||||
|
"no asm backend for target %s",
|
||||||
|
TripleName.c_str());
|
||||||
|
|
||||||
|
MII.reset(TheTarget->createMCInstrInfo());
|
||||||
|
if (!MII)
|
||||||
|
return createStringError(std::errc::invalid_argument,
|
||||||
|
"no instr info info for target %s",
|
||||||
|
TripleName.c_str());
|
||||||
|
|
||||||
|
MCE = TheTarget->createMCCodeEmitter(*MII, *MC);
|
||||||
|
if (!MCE)
|
||||||
|
return createStringError(std::errc::invalid_argument,
|
||||||
|
"no code emitter for target %s",
|
||||||
|
TripleName.c_str());
|
||||||
|
|
||||||
|
switch (OutFileType) {
|
||||||
|
case DWARFLinker::OutputFileType::Assembly: {
|
||||||
|
MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(),
|
||||||
|
*MAI, *MII, *MRI);
|
||||||
|
MS = TheTarget->createAsmStreamer(
|
||||||
|
*MC, std::make_unique<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
|
274
llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.h
Normal file
274
llvm/lib/DWARFLinkerParallel/DWARFEmitterImpl.h
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
//===- DwarfEmitterImpl.h ---------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFEMITTERIMPL_H
|
||||||
|
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFEMITTERIMPL_H
|
||||||
|
|
||||||
|
#include "DWARFLinkerCompileUnit.h"
|
||||||
|
#include "llvm/BinaryFormat/Swift.h"
|
||||||
|
#include "llvm/CodeGen/AccelTable.h"
|
||||||
|
#include "llvm/CodeGen/AsmPrinter.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/StringTable.h"
|
||||||
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
|
#include "llvm/MC/MCContext.h"
|
||||||
|
#include "llvm/MC/MCInstrInfo.h"
|
||||||
|
#include "llvm/MC/MCObjectFileInfo.h"
|
||||||
|
#include "llvm/MC/MCRegisterInfo.h"
|
||||||
|
#include "llvm/MC/MCStreamer.h"
|
||||||
|
#include "llvm/MC/MCSubtargetInfo.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
/// User of DwarfEmitterImpl should call initialization code
|
||||||
|
/// for AsmPrinter:
|
||||||
|
///
|
||||||
|
/// InitializeAllTargetInfos();
|
||||||
|
/// InitializeAllTargetMCs();
|
||||||
|
/// InitializeAllTargets();
|
||||||
|
/// InitializeAllAsmPrinters();
|
||||||
|
|
||||||
|
template <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
|
@ -6,8 +6,12 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
#include "DWARFLinkerImpl.h"
|
||||||
|
|
||||||
namespace llvm {
|
std::unique_ptr<llvm::dwarflinker_parallel::DWARFLinker>
|
||||||
namespace dwarflinker_parallel {} // end of namespace dwarflinker_parallel
|
llvm::dwarflinker_parallel::DWARFLinker::createLinker(
|
||||||
} // namespace llvm
|
MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler,
|
||||||
|
TranslatorFuncTy StringsTranslator) {
|
||||||
|
return std::make_unique<DWARFLinkerImpl>(ErrorHandler, WarningHandler,
|
||||||
|
StringsTranslator);
|
||||||
|
}
|
||||||
|
163
llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
Normal file
163
llvm/lib/DWARFLinkerParallel/DWARFLinkerCompileUnit.h
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
//===- DWARFLinkerCompileUnit.h ---------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
|
||||||
|
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERCOMPILEUNIT_H
|
||||||
|
|
||||||
|
#include "DWARFLinkerUnit.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/DWARFFile.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||||
|
#include <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
|
46
llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
Normal file
46
llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
//=== DWARFLinkerImpl.cpp -------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "DWARFLinkerImpl.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace dwarflinker_parallel {
|
||||||
|
|
||||||
|
/// Similar to DWARFUnitSection::getUnitForOffset(), but returning our
|
||||||
|
/// CompileUnit object instead.
|
||||||
|
CompileUnit *
|
||||||
|
DWARFLinkerImpl::LinkContext::getUnitForOffset(CompileUnit &CurrentCU,
|
||||||
|
uint64_t Offset) const {
|
||||||
|
if (CurrentCU.isClangModule())
|
||||||
|
return &CurrentCU;
|
||||||
|
|
||||||
|
auto CU = llvm::upper_bound(
|
||||||
|
CompileUnits, Offset,
|
||||||
|
[](uint64_t LHS, const std::unique_ptr<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
|
320
llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
Normal file
320
llvm/lib/DWARFLinkerParallel/DWARFLinkerImpl.h
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
//===- DWARFLinkerImpl.h ----------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H
|
||||||
|
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERIMPL_H
|
||||||
|
|
||||||
|
#include "DWARFEmitterImpl.h"
|
||||||
|
#include "DWARFLinkerCompileUnit.h"
|
||||||
|
#include "llvm/ADT/AddressRanges.h"
|
||||||
|
#include "llvm/CodeGen/AccelTable.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/StringPool.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/StringTable.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace dwarflinker_parallel {
|
||||||
|
|
||||||
|
using Offset2UnitMapTy = DenseMap<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
|
185
llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
Normal file
185
llvm/lib/DWARFLinkerParallel/DWARFLinkerUnit.h
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
//===- DWARFLinkerUnit.h ----------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
|
||||||
|
#define LLVM_LIB_DWARFLINKERPARALLEL_DWARFLINKERUNIT_H
|
||||||
|
|
||||||
|
#include "OutputSections.h"
|
||||||
|
#include "llvm/CodeGen/DIE.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/StringPool.h"
|
||||||
|
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||||
|
#include "llvm/Support/LEB128.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace dwarflinker_parallel {
|
||||||
|
|
||||||
|
using UnitMessageHandlerTy = function_ref<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
|
36
llvm/lib/DWARFLinkerParallel/OutputSections.cpp
Normal file
36
llvm/lib/DWARFLinkerParallel/OutputSections.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//=== OutputSections.cpp --------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "OutputSections.h"
|
||||||
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
namespace dwarflinker_parallel {
|
||||||
|
|
||||||
|
std::optional<OutputSections::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
|
67
llvm/lib/DWARFLinkerParallel/OutputSections.h
Normal file
67
llvm/lib/DWARFLinkerParallel/OutputSections.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
//===- OutputSections.h -----------------------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
|
||||||
|
#define LLVM_LIB_DWARFLINKERPARALLEL_OUTPUTSECTIONS_H
|
||||||
|
|
||||||
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include <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
|
@ -0,0 +1,4 @@
|
|||||||
|
RUN: cat %p/../../Inputs/basic.macho.x86_64 > %t1
|
||||||
|
RUN: dsymutil --linker llvm -accelerator=Pub -f -oso-prepend-path=%p/../.. %t1 2>&1 | FileCheck %s --allow-empty
|
||||||
|
|
||||||
|
#CHECK: LLVM parallel dwarflinker is not implemented yet.
|
@ -0,0 +1,134 @@
|
|||||||
|
## 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
|
||||||
|
...
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
# RUN: llvm-dwarfutil %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
|
# 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 --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
|
||||||
|
|
||||||
# RUN: llvm-dwarfutil --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
|
# RUN: llvm-dwarfutil --no-garbage-collection --garbage-collection %t.o - | llvm-dwarfdump -a - | FileCheck %s --check-prefixes=CHECK,CHECK-GC
|
||||||
|
@ -10,6 +10,7 @@ set(LLVM_LINK_COMPONENTS
|
|||||||
CodeGen
|
CodeGen
|
||||||
CodeGenTypes
|
CodeGenTypes
|
||||||
DWARFLinker
|
DWARFLinker
|
||||||
|
DWARFLinkerParallel
|
||||||
DebugInfoDWARF
|
DebugInfoDWARF
|
||||||
MC
|
MC
|
||||||
Object
|
Object
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "llvm/CodeGen/NonRelocatableStringpool.h"
|
#include "llvm/CodeGen/NonRelocatableStringpool.h"
|
||||||
#include "llvm/Config/config.h"
|
#include "llvm/Config/config.h"
|
||||||
#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
|
#include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||||
#include "llvm/DebugInfo/DIContext.h"
|
#include "llvm/DebugInfo/DIContext.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||||
@ -134,22 +135,6 @@ void DwarfLinkerForBinary::reportError(Twine Error, Twine Context,
|
|||||||
dumpDIE(DIE, Options.Verbose);
|
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 &>
|
ErrorOr<const object::ObjectFile &>
|
||||||
DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
|
DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
|
||||||
const Triple &Triple) {
|
const Triple &Triple) {
|
||||||
@ -238,22 +223,19 @@ static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath,
|
|||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<DWARFFile &>
|
template <typename OutDWARFFile, typename AddressesMap>
|
||||||
|
ErrorOr<std::unique_ptr<OutDWARFFile>>
|
||||||
DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
|
DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
|
||||||
const DebugMap &DebugMap,
|
const DebugMap &DebugMap,
|
||||||
remarks::RemarkLinker &RL) {
|
remarks::RemarkLinker &RL) {
|
||||||
auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
|
auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
|
||||||
|
std::unique_ptr<OutDWARFFile> Res;
|
||||||
|
|
||||||
if (ErrorOrObj) {
|
if (ErrorOrObj) {
|
||||||
ContextForLinking.push_back(
|
Res = std::make_unique<OutDWARFFile>(
|
||||||
std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj)));
|
Obj.getObjectFilename(), DWARFContext::create(*ErrorOrObj),
|
||||||
AddressMapForLinking.push_back(
|
std::make_unique<AddressesMap>(*this, *ErrorOrObj, Obj),
|
||||||
std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj));
|
Obj.empty() ? Obj.getWarnings() : EmptyWarnings);
|
||||||
|
|
||||||
ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
|
|
||||||
Obj.getObjectFilename(), ContextForLinking.back().get(),
|
|
||||||
AddressMapForLinking.back().get(),
|
|
||||||
Obj.empty() ? Obj.getWarnings() : EmptyWarnings));
|
|
||||||
|
|
||||||
Error E = RL.link(*ErrorOrObj);
|
Error E = RL.link(*ErrorOrObj);
|
||||||
if (Error NewE = handleErrors(
|
if (Error NewE = handleErrors(
|
||||||
@ -262,7 +244,7 @@ DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
|
|||||||
}))
|
}))
|
||||||
return errorToErrorCode(std::move(NewE));
|
return errorToErrorCode(std::move(NewE));
|
||||||
|
|
||||||
return *ObjectsForLinking.back();
|
return Res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ErrorOrObj.getError();
|
return ErrorOrObj.getError();
|
||||||
@ -274,7 +256,7 @@ static bool binaryHasStrippableSwiftReflectionSections(
|
|||||||
// need to copy them to the .dSYM. Only copy them for binaries where the
|
// need to copy them to the .dSYM. Only copy them for binaries where the
|
||||||
// linker omitted the reflection metadata.
|
// linker omitted the reflection metadata.
|
||||||
if (!Map.getBinaryPath().empty() &&
|
if (!Map.getBinaryPath().empty() &&
|
||||||
Options.FileType == OutputFileType::Object) {
|
Options.FileType == DWARFLinker::OutputFileType::Object) {
|
||||||
|
|
||||||
auto ObjectEntry = BinHolder.getObjectEntry(Map.getBinaryPath());
|
auto ObjectEntry = BinHolder.getObjectEntry(Map.getBinaryPath());
|
||||||
// If ObjectEntry or Object has an error, no binary exists, therefore no
|
// If ObjectEntry or Object has an error, no binary exists, therefore no
|
||||||
@ -498,8 +480,9 @@ Error DwarfLinkerForBinary::copySwiftInterfaces(StringRef Architecture) const {
|
|||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename OutStreamer>
|
||||||
void DwarfLinkerForBinary::copySwiftReflectionMetadata(
|
void DwarfLinkerForBinary::copySwiftReflectionMetadata(
|
||||||
const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer,
|
const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer,
|
||||||
std::vector<uint64_t> &SectionToOffsetInDwarf,
|
std::vector<uint64_t> &SectionToOffsetInDwarf,
|
||||||
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
|
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
|
||||||
&RelocationsToApply) {
|
&RelocationsToApply) {
|
||||||
@ -557,59 +540,117 @@ void DwarfLinkerForBinary::copySwiftReflectionMetadata(
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DwarfLinkerForBinary::link(const DebugMap &Map) {
|
bool DwarfLinkerForBinary::link(const DebugMap &Map) {
|
||||||
if (!createStreamer(Map.getTriple(), OutFile))
|
if (Options.DWARFLinkerType == DsymutilDWARFLinkerType::LLVM) {
|
||||||
return false;
|
dwarflinker_parallel::DWARFLinker::OutputFileType DWARFLinkerOutputType;
|
||||||
|
switch (Options.FileType) {
|
||||||
|
case DWARFLinker::OutputFileType::Object:
|
||||||
|
DWARFLinkerOutputType =
|
||||||
|
dwarflinker_parallel::DWARFLinker::OutputFileType::Object;
|
||||||
|
break;
|
||||||
|
|
||||||
ObjectsForLinking.clear();
|
case DWARFLinker::OutputFileType::Assembly:
|
||||||
ContextForLinking.clear();
|
DWARFLinkerOutputType =
|
||||||
AddressMapForLinking.clear();
|
dwarflinker_parallel::DWARFLinker::OutputFileType::Assembly;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return linkImpl<dwarflinker_parallel::DWARFLinker,
|
||||||
|
dwarflinker_parallel::DWARFFile,
|
||||||
|
AddressManager<dwarflinker_parallel::AddressesMap>>(
|
||||||
|
Map, DWARFLinkerOutputType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return linkImpl<DWARFLinker, DWARFFile, AddressManager<AddressesMap>>(
|
||||||
|
Map, Options.FileType);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
|
||||||
|
|
||||||
DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil);
|
|
||||||
|
|
||||||
remarks::RemarkLinker RL;
|
|
||||||
if (!Options.RemarksPrependPath.empty())
|
|
||||||
RL.setExternalFilePrependPath(Options.RemarksPrependPath);
|
|
||||||
RL.setKeepAllRemarks(Options.RemarksKeepAll);
|
|
||||||
GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap);
|
|
||||||
|
|
||||||
std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) {
|
std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) {
|
||||||
assert(Options.Translator);
|
assert(Options.Translator);
|
||||||
return Options.Translator(Input);
|
return Options.Translator(Input);
|
||||||
};
|
};
|
||||||
|
|
||||||
GeneralLinker.setVerbosity(Options.Verbose);
|
std::unique_ptr<Linker> GeneralLinker = Linker::createLinker(
|
||||||
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(
|
|
||||||
[&](const Twine &Error, StringRef Context, const DWARFDie *DIE) {
|
[&](const Twine &Error, StringRef Context, const DWARFDie *DIE) {
|
||||||
reportError(Error, Context, 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);
|
reportWarning("input verification failed", File.FileName);
|
||||||
HasVerificationErrors = true;
|
HasVerificationErrors = true;
|
||||||
});
|
});
|
||||||
objFileLoader Loader = [&DebugMap, &RL,
|
auto Loader = [&](StringRef ContainerName,
|
||||||
this](StringRef ContainerName,
|
StringRef Path) -> ErrorOr<OutDwarfFile &> {
|
||||||
StringRef Path) -> ErrorOr<DWARFFile &> {
|
|
||||||
auto &Obj = DebugMap.addDebugMapObject(
|
auto &Obj = DebugMap.addDebugMapObject(
|
||||||
Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
|
Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
|
||||||
|
|
||||||
if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
|
if (ErrorOr<std::unique_ptr<OutDwarfFile>> ErrorOrObj =
|
||||||
return *ErrorOrObj;
|
loadObject<OutDwarfFile, AddressMap>(Obj, DebugMap, RL)) {
|
||||||
|
ObjectsForLinking.emplace_back(std::move(*ErrorOrObj));
|
||||||
|
return *ObjectsForLinking.back();
|
||||||
} else {
|
} else {
|
||||||
// Try and emit more helpful warnings by applying some heuristics.
|
// Try and emit more helpful warnings by applying some heuristics.
|
||||||
StringRef ObjFile = ContainerName;
|
StringRef ObjFile = ContainerName;
|
||||||
@ -654,7 +695,7 @@ bool DwarfLinkerForBinary::link(const DebugMap &Map) {
|
|||||||
|
|
||||||
llvm_unreachable("Unhandled DebugMap object");
|
llvm_unreachable("Unhandled DebugMap object");
|
||||||
};
|
};
|
||||||
GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces);
|
GeneralLinker->setSwiftInterfacesMap(&ParseableSwiftInterfaces);
|
||||||
bool ReflectionSectionsPresentInBinary = false;
|
bool ReflectionSectionsPresentInBinary = false;
|
||||||
// If there is no output specified, no point in checking the binary for swift5
|
// If there is no output specified, no point in checking the binary for swift5
|
||||||
// reflection sections.
|
// reflection sections.
|
||||||
@ -668,7 +709,7 @@ bool DwarfLinkerForBinary::link(const DebugMap &Map) {
|
|||||||
auto SectionToOffsetInDwarf =
|
auto SectionToOffsetInDwarf =
|
||||||
calculateStartOfStrippableReflectionSections(Map);
|
calculateStartOfStrippableReflectionSections(Map);
|
||||||
for (const auto &Obj : Map.objects())
|
for (const auto &Obj : Map.objects())
|
||||||
copySwiftReflectionMetadata(Obj.get(), Streamer.get(),
|
copySwiftReflectionMetadata(Obj.get(), GeneralLinker->getEmitter(),
|
||||||
SectionToOffsetInDwarf, RelocationsToApply);
|
SectionToOffsetInDwarf, RelocationsToApply);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,18 +756,21 @@ bool DwarfLinkerForBinary::link(const DebugMap &Map) {
|
|||||||
|
|
||||||
// Copy the module into the .swift_ast section.
|
// Copy the module into the .swift_ast section.
|
||||||
if (!Options.NoOutput)
|
if (!Options.NoOutput)
|
||||||
Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
|
GeneralLinker->getEmitter()->emitSwiftAST((*ErrorOrMem)->getBuffer());
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto ErrorOrObj = loadObject(*Obj, Map, RL))
|
if (ErrorOr<std::unique_ptr<OutDwarfFile>> ErrorOrObj =
|
||||||
GeneralLinker.addObjectFile(*ErrorOrObj, Loader, OnCUDieLoaded);
|
loadObject<OutDwarfFile, AddressMap>(*Obj, Map, RL)) {
|
||||||
else {
|
ObjectsForLinking.emplace_back(std::move(*ErrorOrObj));
|
||||||
ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
|
GeneralLinker->addObjectFile(*ObjectsForLinking.back(), Loader,
|
||||||
|
OnCUDieLoaded);
|
||||||
|
} else {
|
||||||
|
ObjectsForLinking.push_back(std::make_unique<OutDwarfFile>(
|
||||||
Obj->getObjectFilename(), nullptr, nullptr,
|
Obj->getObjectFilename(), nullptr, nullptr,
|
||||||
Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
|
Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
|
||||||
GeneralLinker.addObjectFile(*ObjectsForLinking.back());
|
GeneralLinker->addObjectFile(*ObjectsForLinking.back());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -734,32 +778,14 @@ bool DwarfLinkerForBinary::link(const DebugMap &Map) {
|
|||||||
if (MaxDWARFVersion == 0)
|
if (MaxDWARFVersion == 0)
|
||||||
MaxDWARFVersion = 3;
|
MaxDWARFVersion = 3;
|
||||||
|
|
||||||
if (Error E = GeneralLinker.setTargetDWARFVersion(MaxDWARFVersion))
|
if (Error E = GeneralLinker->setTargetDWARFVersion(MaxDWARFVersion))
|
||||||
return error(toString(std::move(E)));
|
return error(toString(std::move(E)));
|
||||||
|
|
||||||
switch (Options.TheAccelTableKind) {
|
setAcceleratorTables<Linker>(*GeneralLinker, Options.TheAccelTableKind,
|
||||||
case DsymutilAccelTableKind::Apple:
|
MaxDWARFVersion);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// link debug info for loaded object files.
|
// link debug info for loaded object files.
|
||||||
if (Error E = GeneralLinker.link())
|
if (Error E = GeneralLinker->link())
|
||||||
return error(toString(std::move(E)));
|
return error(toString(std::move(E)));
|
||||||
|
|
||||||
StringRef ArchName = Map.getTriple().getArchName();
|
StringRef ArchName = Map.getTriple().getArchName();
|
||||||
@ -776,21 +802,25 @@ bool DwarfLinkerForBinary::link(const DebugMap &Map) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() &&
|
if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() &&
|
||||||
Options.FileType == OutputFileType::Object)
|
ObjectType == Linker::OutputFileType::Object)
|
||||||
return MachOUtils::generateDsymCompanion(
|
return MachOUtils::generateDsymCompanion(
|
||||||
Options.VFS, Map, Options.Translator,
|
Options.VFS, Map, Options.Translator,
|
||||||
*Streamer->getAsmPrinter().OutStreamer, OutFile, RelocationsToApply);
|
*GeneralLinker->getEmitter()->getAsmPrinter().OutStreamer, OutFile,
|
||||||
|
RelocationsToApply);
|
||||||
|
|
||||||
Streamer->finish();
|
GeneralLinker->getEmitter()->finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterate over the relocations of the given \p Section and
|
/// Iterate over the relocations of the given \p Section and
|
||||||
/// store the ones that correspond to debug map entries into the
|
/// store the ones that correspond to debug map entries into the
|
||||||
/// ValidRelocs array.
|
/// ValidRelocs array.
|
||||||
void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
|
template <typename AddressesMapBase>
|
||||||
const object::SectionRef &Section, const object::MachOObjectFile &Obj,
|
void DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
|
||||||
const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {
|
findValidRelocsMachO(const object::SectionRef &Section,
|
||||||
|
const object::MachOObjectFile &Obj,
|
||||||
|
const DebugMapObject &DMO,
|
||||||
|
std::vector<ValidReloc> &ValidRelocs) {
|
||||||
Expected<StringRef> ContentsOrErr = Section.getContents();
|
Expected<StringRef> ContentsOrErr = Section.getContents();
|
||||||
if (!ContentsOrErr) {
|
if (!ContentsOrErr) {
|
||||||
consumeError(ContentsOrErr.takeError());
|
consumeError(ContentsOrErr.takeError());
|
||||||
@ -865,7 +895,8 @@ void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
|
|||||||
|
|
||||||
/// Dispatch the valid relocation finding logic to the
|
/// Dispatch the valid relocation finding logic to the
|
||||||
/// appropriate handler depending on the object file format.
|
/// 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 object::SectionRef &Section, const object::ObjectFile &Obj,
|
||||||
const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
|
const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
|
||||||
// Dispatch to the right handler depending on the file type.
|
// Dispatch to the right handler depending on the file type.
|
||||||
@ -890,8 +921,10 @@ bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
|
|||||||
/// entries in the debug map. These relocations will drive the Dwarf link by
|
/// entries in the debug map. These relocations will drive the Dwarf link by
|
||||||
/// indicating which DIEs refer to symbols present in the linked binary.
|
/// indicating which DIEs refer to symbols present in the linked binary.
|
||||||
/// \returns whether there are any valid relocations in the debug info.
|
/// \returns whether there are any valid relocations in the debug info.
|
||||||
bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
|
template <typename AddressesMapBase>
|
||||||
const object::ObjectFile &Obj, const DebugMapObject &DMO) {
|
bool DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
|
||||||
|
findValidRelocsInDebugSections(const object::ObjectFile &Obj,
|
||||||
|
const DebugMapObject &DMO) {
|
||||||
// Find the debug_info section.
|
// Find the debug_info section.
|
||||||
bool FoundValidRelocs = false;
|
bool FoundValidRelocs = false;
|
||||||
for (const object::SectionRef &Section : Obj.sections()) {
|
for (const object::SectionRef &Section : Obj.sections()) {
|
||||||
@ -912,10 +945,14 @@ bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
|
|||||||
return FoundValidRelocs;
|
return FoundValidRelocs;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<DwarfLinkerForBinary::AddressManager::ValidReloc>
|
template <typename AddressesMapBase>
|
||||||
DwarfLinkerForBinary::AddressManager::getRelocations(
|
std::vector<
|
||||||
|
typename DwarfLinkerForBinary::AddressManager<AddressesMapBase>::ValidReloc>
|
||||||
|
DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocations(
|
||||||
const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {
|
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) {
|
auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) {
|
||||||
return Reloc.Offset < StartPos;
|
return Reloc.Offset < StartPos;
|
||||||
@ -930,7 +967,9 @@ DwarfLinkerForBinary::AddressManager::getRelocations(
|
|||||||
return Res;
|
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 auto &Mapping = Reloc.Mapping->getValue();
|
||||||
const uint64_t ObjectAddress = Mapping.ObjectAddress
|
const uint64_t ObjectAddress = Mapping.ObjectAddress
|
||||||
? uint64_t(*Mapping.ObjectAddress)
|
? uint64_t(*Mapping.ObjectAddress)
|
||||||
@ -941,16 +980,18 @@ void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc &Reloc) {
|
|||||||
uint64_t(Mapping.BinaryAddress));
|
uint64_t(Mapping.BinaryAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t
|
template <typename AddressesMapBase>
|
||||||
DwarfLinkerForBinary::AddressManager::getRelocValue(const ValidReloc &Reloc) {
|
int64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::getRelocValue(
|
||||||
|
const ValidReloc &Reloc) {
|
||||||
int64_t AddrAdjust = relocate(Reloc);
|
int64_t AddrAdjust = relocate(Reloc);
|
||||||
if (Reloc.Mapping->getValue().ObjectAddress)
|
if (Reloc.Mapping->getValue().ObjectAddress)
|
||||||
AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress);
|
AddrAdjust -= uint64_t(*Reloc.Mapping->getValue().ObjectAddress);
|
||||||
return AddrAdjust;
|
return AddrAdjust;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename AddressesMapBase>
|
||||||
std::optional<int64_t>
|
std::optional<int64_t>
|
||||||
DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
|
DwarfLinkerForBinary::AddressManager<AddressesMapBase>::hasValidRelocationAt(
|
||||||
const std::vector<ValidReloc> &AllRelocs, uint64_t StartOffset,
|
const std::vector<ValidReloc> &AllRelocs, uint64_t StartOffset,
|
||||||
uint64_t EndOffset) {
|
uint64_t EndOffset) {
|
||||||
std::vector<ValidReloc> Relocs =
|
std::vector<ValidReloc> Relocs =
|
||||||
@ -986,10 +1027,11 @@ getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
|
|||||||
return std::make_pair(Offset, End);
|
return std::make_pair(Offset, End);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<int64_t>
|
template <typename AddressesMapBase>
|
||||||
DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(
|
std::optional<int64_t> DwarfLinkerForBinary::AddressManager<AddressesMapBase>::
|
||||||
DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,
|
getExprOpAddressRelocAdjustment(DWARFUnit &U,
|
||||||
uint64_t EndOffset) {
|
const DWARFExpression::Operation &Op,
|
||||||
|
uint64_t StartOffset, uint64_t EndOffset) {
|
||||||
switch (Op.getCode()) {
|
switch (Op.getCode()) {
|
||||||
default: {
|
default: {
|
||||||
assert(false && "Specified operation does not have address operand");
|
assert(false && "Specified operation does not have address operand");
|
||||||
@ -1010,9 +1052,9 @@ DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<int64_t>
|
template <typename AddressesMapBase>
|
||||||
DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(
|
std::optional<int64_t> DwarfLinkerForBinary::AddressManager<
|
||||||
const DWARFDie &DIE) {
|
AddressesMapBase>::getSubprogramRelocAdjustment(const DWARFDie &DIE) {
|
||||||
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
|
const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
|
||||||
|
|
||||||
std::optional<uint32_t> LowPcIdx =
|
std::optional<uint32_t> LowPcIdx =
|
||||||
@ -1053,8 +1095,9 @@ DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t
|
template <typename AddressesMapBase>
|
||||||
DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {
|
uint64_t DwarfLinkerForBinary::AddressManager<AddressesMapBase>::relocate(
|
||||||
|
const ValidReloc &Reloc) const {
|
||||||
return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend;
|
return Reloc.Mapping->getValue().BinaryAddress + Reloc.Addend;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1066,7 +1109,8 @@ DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {
|
|||||||
/// monotonic \p BaseOffset values.
|
/// monotonic \p BaseOffset values.
|
||||||
///
|
///
|
||||||
/// \returns whether any reloc has been applied.
|
/// \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) {
|
MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
|
||||||
std::vector<ValidReloc> Relocs = getRelocations(
|
std::vector<ValidReloc> Relocs = getRelocations(
|
||||||
ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());
|
ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());
|
||||||
|
@ -65,7 +65,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
/// Keeps track of relocations.
|
/// Keeps track of relocations.
|
||||||
class AddressManager : public AddressesMap {
|
template <typename AddressesMapBase>
|
||||||
|
class AddressManager : public AddressesMapBase {
|
||||||
struct ValidReloc {
|
struct ValidReloc {
|
||||||
uint64_t Offset;
|
uint64_t Offset;
|
||||||
uint32_t Size;
|
uint32_t Size;
|
||||||
@ -180,6 +181,7 @@ private:
|
|||||||
std::optional<int64_t> getExprOpAddressRelocAdjustment(
|
std::optional<int64_t> getExprOpAddressRelocAdjustment(
|
||||||
DWARFUnit &U, const DWARFExpression::Operation &Op,
|
DWARFUnit &U, const DWARFExpression::Operation &Op,
|
||||||
uint64_t StartOffset, uint64_t EndOffset) override;
|
uint64_t StartOffset, uint64_t EndOffset) override;
|
||||||
|
|
||||||
std::optional<int64_t>
|
std::optional<int64_t>
|
||||||
getSubprogramRelocAdjustment(const DWARFDie &DIE) override;
|
getSubprogramRelocAdjustment(const DWARFDie &DIE) override;
|
||||||
|
|
||||||
@ -199,12 +201,18 @@ private:
|
|||||||
/// \defgroup Helpers Various helper methods.
|
/// \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.
|
/// Attempt to load a debug object from disk.
|
||||||
ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
|
ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
|
||||||
const Triple &triple);
|
const Triple &triple);
|
||||||
ErrorOr<DWARFFile &> loadObject(const DebugMapObject &Obj,
|
|
||||||
|
template <typename OutDWARFFile, typename AddressesMap>
|
||||||
|
ErrorOr<std::unique_ptr<OutDWARFFile>> loadObject(const DebugMapObject &Obj,
|
||||||
const DebugMap &DebugMap,
|
const DebugMap &DebugMap,
|
||||||
remarks::RemarkLinker &RL);
|
remarks::RemarkLinker &RL);
|
||||||
|
|
||||||
@ -218,21 +226,22 @@ private:
|
|||||||
|
|
||||||
Error copySwiftInterfaces(StringRef Architecture) const;
|
Error copySwiftInterfaces(StringRef Architecture) const;
|
||||||
|
|
||||||
|
template <typename OutStreamer>
|
||||||
void copySwiftReflectionMetadata(
|
void copySwiftReflectionMetadata(
|
||||||
const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer,
|
const llvm::dsymutil::DebugMapObject *Obj, OutStreamer *Streamer,
|
||||||
std::vector<uint64_t> &SectionToOffsetInDwarf,
|
std::vector<uint64_t> &SectionToOffsetInDwarf,
|
||||||
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
|
std::vector<MachOUtils::DwarfRelocationApplicationInfo>
|
||||||
&RelocationsToApply);
|
&RelocationsToApply);
|
||||||
|
|
||||||
|
template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
|
||||||
|
bool linkImpl(const DebugMap &Map,
|
||||||
|
typename Linker::OutputFileType ObjectType);
|
||||||
|
|
||||||
raw_fd_ostream &OutFile;
|
raw_fd_ostream &OutFile;
|
||||||
BinaryHolder &BinHolder;
|
BinaryHolder &BinHolder;
|
||||||
LinkOptions Options;
|
LinkOptions Options;
|
||||||
std::mutex &ErrorHandlerMutex;
|
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;
|
std::vector<std::string> EmptyWarnings;
|
||||||
|
|
||||||
/// A list of all .swiftinterface files referenced by the debug
|
/// A list of all .swiftinterface files referenced by the debug
|
||||||
|
@ -31,6 +31,11 @@ enum class DsymutilAccelTableKind : uint8_t {
|
|||||||
Pub, ///< .debug_pubnames, .debug_pubtypes
|
Pub, ///< .debug_pubnames, .debug_pubtypes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class DsymutilDWARFLinkerType : uint8_t {
|
||||||
|
Apple, /// Apple`s implementation of DWARFLinker.
|
||||||
|
LLVM /// LLVM implementation of DWARFLinker.
|
||||||
|
};
|
||||||
|
|
||||||
struct LinkOptions {
|
struct LinkOptions {
|
||||||
/// Verbosity
|
/// Verbosity
|
||||||
bool Verbose = false;
|
bool Verbose = false;
|
||||||
@ -57,6 +62,9 @@ struct LinkOptions {
|
|||||||
/// function.
|
/// function.
|
||||||
bool KeepFunctionForStatic = false;
|
bool KeepFunctionForStatic = false;
|
||||||
|
|
||||||
|
/// Type of DWARFLinker to use.
|
||||||
|
DsymutilDWARFLinkerType DWARFLinkerType = DsymutilDWARFLinkerType::Apple;
|
||||||
|
|
||||||
/// Use a 64-bit header when emitting universal binaries.
|
/// Use a 64-bit header when emitting universal binaries.
|
||||||
bool Fat64 = false;
|
bool Fat64 = false;
|
||||||
|
|
||||||
@ -64,7 +72,7 @@ struct LinkOptions {
|
|||||||
unsigned Threads = 1;
|
unsigned Threads = 1;
|
||||||
|
|
||||||
// Output file type.
|
// Output file type.
|
||||||
OutputFileType FileType = OutputFileType::Object;
|
DWARFLinker::OutputFileType FileType = DWARFLinker::OutputFileType::Object;
|
||||||
|
|
||||||
/// The accelerator table kind
|
/// The accelerator table kind
|
||||||
DsymutilAccelTableKind TheAccelTableKind;
|
DsymutilAccelTableKind TheAccelTableKind;
|
||||||
|
@ -199,3 +199,9 @@ def remarks_drop_without_debug: Flag<["--", "-"], "remarks-drop-without-debug">,
|
|||||||
HelpText<"Drop remarks without valid debug locations. Without this flags, "
|
HelpText<"Drop remarks without valid debug locations. Without this flags, "
|
||||||
"all remarks are kept.">,
|
"all remarks are kept.">,
|
||||||
Group<grp_general>;
|
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>;
|
||||||
|
@ -241,6 +241,24 @@ getAccelTableKind(opt::InputArgList &Args) {
|
|||||||
return DsymutilAccelTableKind::Default;
|
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) {
|
static Expected<ReproducerMode> getReproducerMode(opt::InputArgList &Args) {
|
||||||
if (Args.hasArg(OPT_gen_reproducer))
|
if (Args.hasArg(OPT_gen_reproducer))
|
||||||
return ReproducerMode::GenerateOnExit;
|
return ReproducerMode::GenerateOnExit;
|
||||||
@ -330,6 +348,13 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
|
|||||||
return AccelKind.takeError();
|
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))
|
if (opt::Arg *SymbolMap = Args.getLastArg(OPT_symbolmap))
|
||||||
Options.SymbolMap = SymbolMap->getValue();
|
Options.SymbolMap = SymbolMap->getValue();
|
||||||
|
|
||||||
@ -362,7 +387,7 @@ static Expected<DsymutilOptions> getOptions(opt::InputArgList &Args) {
|
|||||||
Options.Toolchain = Toolchain->getValue();
|
Options.Toolchain = Toolchain->getValue();
|
||||||
|
|
||||||
if (Args.hasArg(OPT_assembly))
|
if (Args.hasArg(OPT_assembly))
|
||||||
Options.LinkOpts.FileType = OutputFileType::Assembly;
|
Options.LinkOpts.FileType = DWARFLinker::OutputFileType::Assembly;
|
||||||
|
|
||||||
if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
|
if (opt::Arg *NumThreads = Args.getLastArg(OPT_threads))
|
||||||
Options.LinkOpts.Threads = atoi(NumThreads->getValue());
|
Options.LinkOpts.Threads = atoi(NumThreads->getValue());
|
||||||
|
@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS
|
|||||||
AllTargetsInfos
|
AllTargetsInfos
|
||||||
CodeGenTypes
|
CodeGenTypes
|
||||||
DWARFLinker
|
DWARFLinker
|
||||||
|
DWARFLinkerParallel
|
||||||
DebugInfoDWARF
|
DebugInfoDWARF
|
||||||
MC
|
MC
|
||||||
ObjCopy
|
ObjCopy
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
#include "llvm/DWARFLinker/DWARFLinker.h"
|
#include "llvm/DWARFLinker/DWARFLinker.h"
|
||||||
#include "llvm/DWARFLinker/DWARFStreamer.h"
|
#include "llvm/DWARFLinker/DWARFStreamer.h"
|
||||||
|
#include "llvm/DWARFLinkerParallel/DWARFLinker.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
|
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
|
||||||
#include "llvm/Object/ObjectFile.h"
|
#include "llvm/Object/ObjectFile.h"
|
||||||
@ -37,7 +38,8 @@ namespace dwarfutil {
|
|||||||
// exec: [LowPC, HighPC] is not inside address ranges of .text sections
|
// exec: [LowPC, HighPC] is not inside address ranges of .text sections
|
||||||
//
|
//
|
||||||
// universal: maxpc and bfd
|
// universal: maxpc and bfd
|
||||||
class ObjFileAddressMap : public AddressesMap {
|
template <typename AddressMapBase>
|
||||||
|
class ObjFileAddressMap : public AddressMapBase {
|
||||||
public:
|
public:
|
||||||
ObjFileAddressMap(DWARFContext &Context, const Options &Options,
|
ObjFileAddressMap(DWARFContext &Context, const Options &Options,
|
||||||
object::ObjectFile &ObjFile)
|
object::ObjectFile &ObjFile)
|
||||||
@ -224,12 +226,13 @@ static bool knownByDWARFUtil(StringRef SecName) {
|
|||||||
.Default(false);
|
.Default(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<DwarfLinkerAccelTableKind>
|
template <typename AccelTableKind>
|
||||||
|
static std::optional<AccelTableKind>
|
||||||
getAcceleratorTableKind(StringRef SecName) {
|
getAcceleratorTableKind(StringRef SecName) {
|
||||||
return llvm::StringSwitch<std::optional<DwarfLinkerAccelTableKind>>(SecName)
|
return llvm::StringSwitch<std::optional<AccelTableKind>>(SecName)
|
||||||
.Case(".debug_pubnames", DwarfLinkerAccelTableKind::Pub)
|
.Case(".debug_pubnames", AccelTableKind::Pub)
|
||||||
.Case(".debug_pubtypes", DwarfLinkerAccelTableKind::Pub)
|
.Case(".debug_pubtypes", AccelTableKind::Pub)
|
||||||
.Case(".debug_names", DwarfLinkerAccelTableKind::DebugNames)
|
.Case(".debug_names", AccelTableKind::DebugNames)
|
||||||
.Default(std::nullopt);
|
.Default(std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,9 +278,9 @@ static std::string getMessageForDeletedAcceleratorTables(
|
|||||||
return Message;
|
return Message;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
|
template <typename Linker, typename OutDwarfFile, typename AddressMapBase>
|
||||||
|
Error linkDebugInfoImpl(object::ObjectFile &File, const Options &Options,
|
||||||
raw_pwrite_stream &OutStream) {
|
raw_pwrite_stream &OutStream) {
|
||||||
|
|
||||||
auto ReportWarn = [&](const Twine &Message, StringRef Context,
|
auto ReportWarn = [&](const Twine &Message, StringRef Context,
|
||||||
const DWARFDie *Die) {
|
const DWARFDie *Die) {
|
||||||
warning(Message, Context);
|
warning(Message, Context);
|
||||||
@ -297,39 +300,33 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
|
|||||||
WithColor::error(errs(), Context) << Message << '\n';
|
WithColor::error(errs(), Context) << Message << '\n';
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create output streamer.
|
|
||||||
DwarfStreamer OutStreamer(OutputFileType::Object, OutStream, nullptr,
|
|
||||||
ReportWarn, 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, "");
|
|
||||||
|
|
||||||
std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
|
|
||||||
|
|
||||||
// Create DWARF linker.
|
// Create DWARF linker.
|
||||||
DWARFLinker DebugInfoLinker(&OutStreamer, DwarfLinkerClient::LLD);
|
std::unique_ptr<Linker> DebugInfoLinker =
|
||||||
|
Linker::createLinker(ReportErr, ReportWarn);
|
||||||
|
|
||||||
DebugInfoLinker.setEstimatedObjfilesAmount(1);
|
Triple TargetTriple = File.makeTriple();
|
||||||
DebugInfoLinker.setErrorHandler(ReportErr);
|
if (Error Err = DebugInfoLinker->createEmitter(
|
||||||
DebugInfoLinker.setWarningHandler(ReportWarn);
|
TargetTriple, Linker::OutputFileType::Object, OutStream))
|
||||||
DebugInfoLinker.setNumThreads(Options.NumThreads);
|
return Err;
|
||||||
DebugInfoLinker.setNoODR(!Options.DoODRDeduplication);
|
|
||||||
DebugInfoLinker.setVerbosity(Options.Verbose);
|
|
||||||
DebugInfoLinker.setUpdate(!Options.DoGarbageCollection);
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking(1);
|
DebugInfoLinker->setEstimatedObjfilesAmount(1);
|
||||||
std::vector<std::unique_ptr<AddressesMap>> AddresssMapForLinking(1);
|
DebugInfoLinker->setNumThreads(Options.NumThreads);
|
||||||
|
DebugInfoLinker->setNoODR(!Options.DoODRDeduplication);
|
||||||
|
DebugInfoLinker->setVerbosity(Options.Verbose);
|
||||||
|
DebugInfoLinker->setUpdateIndexTablesOnly(!Options.DoGarbageCollection);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<OutDwarfFile>> ObjectsForLinking(1);
|
||||||
std::vector<std::string> EmptyWarnings;
|
std::vector<std::string> EmptyWarnings;
|
||||||
|
|
||||||
// Add object files to the DWARFLinker.
|
// Add object files to the DWARFLinker.
|
||||||
AddresssMapForLinking[0] =
|
std::unique_ptr<DWARFContext> Context = DWARFContext::create(File);
|
||||||
std::make_unique<ObjFileAddressMap>(*Context, Options, File);
|
std::unique_ptr<ObjFileAddressMap<AddressMapBase>> AddressesMap(
|
||||||
|
std::make_unique<ObjFileAddressMap<AddressMapBase>>(*Context, Options,
|
||||||
|
File));
|
||||||
|
|
||||||
ObjectsForLinking[0] = std::make_unique<DWARFFile>(
|
ObjectsForLinking[0] =
|
||||||
File.getFileName(), &*Context, AddresssMapForLinking[0].get(),
|
std::make_unique<OutDwarfFile>(File.getFileName(), std::move(Context),
|
||||||
EmptyWarnings);
|
std::move(AddressesMap), EmptyWarnings);
|
||||||
|
|
||||||
uint16_t MaxDWARFVersion = 0;
|
uint16_t MaxDWARFVersion = 0;
|
||||||
std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
|
std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
|
||||||
@ -338,17 +335,17 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
|
|||||||
};
|
};
|
||||||
|
|
||||||
for (size_t I = 0; I < ObjectsForLinking.size(); I++)
|
for (size_t I = 0; I < ObjectsForLinking.size(); I++)
|
||||||
DebugInfoLinker.addObjectFile(*ObjectsForLinking[I], nullptr,
|
DebugInfoLinker->addObjectFile(*ObjectsForLinking[I], nullptr,
|
||||||
OnCUDieLoaded);
|
OnCUDieLoaded);
|
||||||
|
|
||||||
// If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
|
// If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
|
||||||
if (MaxDWARFVersion == 0)
|
if (MaxDWARFVersion == 0)
|
||||||
MaxDWARFVersion = 3;
|
MaxDWARFVersion = 3;
|
||||||
|
|
||||||
if (Error Err = DebugInfoLinker.setTargetDWARFVersion(MaxDWARFVersion))
|
if (Error Err = DebugInfoLinker->setTargetDWARFVersion(MaxDWARFVersion))
|
||||||
return Err;
|
return Err;
|
||||||
|
|
||||||
SmallVector<DwarfLinkerAccelTableKind> AccelTables;
|
SmallVector<typename Linker::AccelTableKind> AccelTables;
|
||||||
|
|
||||||
switch (Options.AccelTableKind) {
|
switch (Options.AccelTableKind) {
|
||||||
case DwarfUtilAccelKind::None:
|
case DwarfUtilAccelKind::None:
|
||||||
@ -356,23 +353,24 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
|
|||||||
break;
|
break;
|
||||||
case DwarfUtilAccelKind::DWARF:
|
case DwarfUtilAccelKind::DWARF:
|
||||||
// use .debug_names for all DWARF versions.
|
// use .debug_names for all DWARF versions.
|
||||||
AccelTables.push_back(DwarfLinkerAccelTableKind::DebugNames);
|
AccelTables.push_back(Linker::AccelTableKind::DebugNames);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add accelerator tables to DWARFLinker.
|
// Add accelerator tables to DWARFLinker.
|
||||||
for (DwarfLinkerAccelTableKind Table : AccelTables)
|
for (typename Linker::AccelTableKind Table : AccelTables)
|
||||||
DebugInfoLinker.addAccelTableKind(Table);
|
DebugInfoLinker->addAccelTableKind(Table);
|
||||||
|
|
||||||
|
for (std::unique_ptr<OutDwarfFile> &CurFile : ObjectsForLinking) {
|
||||||
SmallVector<StringRef> AccelTableNamesToReplace;
|
SmallVector<StringRef> AccelTableNamesToReplace;
|
||||||
SmallVector<StringRef> AccelTableNamesToDelete;
|
SmallVector<StringRef> AccelTableNamesToDelete;
|
||||||
|
|
||||||
// Unknown debug sections or non-requested accelerator sections would be
|
// Unknown debug sections or non-requested accelerator sections would be
|
||||||
// removed. Display warning for such sections.
|
// removed. Display warning for such sections.
|
||||||
for (SectionName Sec : Context->getDWARFObj().getSectionNames()) {
|
for (SectionName Sec : CurFile->Dwarf->getDWARFObj().getSectionNames()) {
|
||||||
if (isDebugSection(Sec.Name)) {
|
if (isDebugSection(Sec.Name)) {
|
||||||
std::optional<DwarfLinkerAccelTableKind> SrcAccelTableKind =
|
std::optional<typename Linker::AccelTableKind> SrcAccelTableKind =
|
||||||
getAcceleratorTableKind(Sec.Name);
|
getAcceleratorTableKind<typename Linker::AccelTableKind>(Sec.Name);
|
||||||
|
|
||||||
if (SrcAccelTableKind) {
|
if (SrcAccelTableKind) {
|
||||||
assert(knownByDWARFUtil(Sec.Name));
|
assert(knownByDWARFUtil(Sec.Name));
|
||||||
@ -385,7 +383,8 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
|
|||||||
} else if (!knownByDWARFUtil(Sec.Name)) {
|
} else if (!knownByDWARFUtil(Sec.Name)) {
|
||||||
assert(!SrcAccelTableKind);
|
assert(!SrcAccelTableKind);
|
||||||
warning(
|
warning(
|
||||||
formatv("'{0}' is not currently supported: section will be skipped",
|
formatv(
|
||||||
|
"'{0}' is not currently supported: section will be skipped",
|
||||||
Sec.Name),
|
Sec.Name),
|
||||||
Options.InputFileName);
|
Options.InputFileName);
|
||||||
}
|
}
|
||||||
@ -402,14 +401,27 @@ Error linkDebugInfo(object::ObjectFile &File, const Options &Options,
|
|||||||
if (!AccelTableNamesToDelete.empty())
|
if (!AccelTableNamesToDelete.empty())
|
||||||
warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
|
warning(getMessageForDeletedAcceleratorTables(AccelTableNamesToDelete),
|
||||||
Options.InputFileName);
|
Options.InputFileName);
|
||||||
|
}
|
||||||
|
|
||||||
// Link debug info.
|
// Link debug info.
|
||||||
if (Error Err = DebugInfoLinker.link())
|
if (Error Err = DebugInfoLinker->link())
|
||||||
return Err;
|
return Err;
|
||||||
|
|
||||||
OutStreamer.finish();
|
DebugInfoLinker->getEmitter()->finish();
|
||||||
return Error::success();
|
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 dwarfutil
|
||||||
} // end of namespace llvm
|
} // end of namespace llvm
|
||||||
|
@ -40,6 +40,7 @@ struct Options {
|
|||||||
bool Verbose = false;
|
bool Verbose = false;
|
||||||
int NumThreads = 0;
|
int NumThreads = 0;
|
||||||
bool Verify = false;
|
bool Verify = false;
|
||||||
|
bool UseLLVMDWARFLinker = false;
|
||||||
DwarfUtilAccelKind AccelTableKind = DwarfUtilAccelKind::None;
|
DwarfUtilAccelKind AccelTableKind = DwarfUtilAccelKind::None;
|
||||||
|
|
||||||
std::string getSeparateDebugFileName() const {
|
std::string getSeparateDebugFileName() const {
|
||||||
|
@ -20,6 +20,11 @@ def h : Flag<["-"], "h">,
|
|||||||
Alias<help>,
|
Alias<help>,
|
||||||
HelpText<"Alias for --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",
|
defm odr_deduplication : BB<"odr-deduplication",
|
||||||
"Do ODR deduplication for debug types(default)",
|
"Do ODR deduplication for debug types(default)",
|
||||||
"Don`t do ODR deduplication for debug types">;
|
"Don`t do ODR deduplication for debug types">;
|
||||||
|
@ -123,6 +123,18 @@ static Error validateAndSetOptions(opt::InputArgList &Args, Options &Options) {
|
|||||||
formatv("unknown tombstone value: '{0}'", S).str().c_str());
|
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)) {
|
if (opt::Arg *BuildAccelerator = Args.getLastArg(OPT_build_accelerator)) {
|
||||||
StringRef S = BuildAccelerator->getValue();
|
StringRef S = BuildAccelerator->getValue();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user