diff options
Diffstat (limited to 'contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic')
4 files changed, 1720 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h b/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h new file mode 100644 index 000000000000..d3aaa3baadc4 --- /dev/null +++ b/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinker.h @@ -0,0 +1,867 @@ +//===- DWARFLinker.h --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DWARFLINKER_CLASSIC_DWARFLINKER_H +#define LLVM_DWARFLINKER_CLASSIC_DWARFLINKER_H + +#include "llvm/ADT/AddressRanges.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/AccelTable.h" +#include "llvm/CodeGen/NonRelocatableStringpool.h" +#include "llvm/DWARFLinker/Classic/DWARFLinkerCompileUnit.h" +#include "llvm/DWARFLinker/DWARFLinkerBase.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include <map> + +namespace llvm { +class DWARFExpression; +class DWARFUnit; +class DataExtractor; +template <typename T> class SmallVectorImpl; + +namespace dwarf_linker { +namespace classic { +class DeclContextTree; + +using Offset2UnitMap = DenseMap<uint64_t, CompileUnit *>; + +struct DebugDieValuePool { + DenseMap<uint64_t, uint64_t> DieValueMap; + SmallVector<uint64_t> DieValues; + + uint64_t getValueIndex(uint64_t Value) { + DenseMap<uint64_t, uint64_t>::iterator It = DieValueMap.find(Value); + if (It == DieValueMap.end()) { + It = DieValueMap.insert(std::make_pair(Value, DieValues.size())).first; + DieValues.push_back(Value); + } + return It->second; + } + + void clear() { + DieValueMap.clear(); + DieValues.clear(); + } +}; + +/// DwarfEmitter presents interface to generate all debug info tables. +class DwarfEmitter { +public: + virtual ~DwarfEmitter() = default; + + /// Emit section named SecName with data SecData. + virtual void emitSectionContents(StringRef SecData, StringRef SecName) = 0; + + /// Emit the abbreviation table \p Abbrevs to the .debug_abbrev section. + virtual void + emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs, + unsigned DwarfVersion) = 0; + + /// Emit the string table described by \p Pool into .debug_str table. + virtual void emitStrings(const NonRelocatableStringpool &Pool) = 0; + + /// Emit the debug string offset table described by \p StringOffsets into the + /// .debug_str_offsets table. + virtual void emitStringOffsets(const SmallVector<uint64_t> &StringOffsets, + uint16_t TargetDWARFVersion) = 0; + + /// Emit the string table described by \p Pool into .debug_line_str table. + virtual void emitLineStrings(const NonRelocatableStringpool &Pool) = 0; + + /// Emit DWARF debug names. + virtual void emitDebugNames(DWARF5AccelTable &Table) = 0; + + /// Emit Apple namespaces accelerator table. + virtual void + emitAppleNamespaces(AccelTable<AppleAccelTableStaticOffsetData> &Table) = 0; + + /// Emit Apple names accelerator table. + virtual void + emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> &Table) = 0; + + /// Emit Apple Objective-C accelerator table. + virtual void + emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> &Table) = 0; + + /// Emit Apple type accelerator table. + virtual void + emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &Table) = 0; + + /// Emit debug ranges (.debug_ranges, .debug_rnglists) header. + virtual MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) = 0; + + /// Emit debug ranges (.debug_ranges, .debug_rnglists) fragment. + virtual void emitDwarfDebugRangeListFragment( + const CompileUnit &Unit, const AddressRanges &LinkedRanges, + PatchLocation Patch, DebugDieValuePool &AddrPool) = 0; + + /// Emit debug ranges (.debug_ranges, .debug_rnglists) footer. + virtual void emitDwarfDebugRangeListFooter(const CompileUnit &Unit, + MCSymbol *EndLabel) = 0; + + /// Emit debug locations (.debug_loc, .debug_loclists) header. + virtual MCSymbol *emitDwarfDebugLocListHeader(const CompileUnit &Unit) = 0; + + /// Emit debug locations (.debug_loc, .debug_loclists) fragment. + virtual void emitDwarfDebugLocListFragment( + const CompileUnit &Unit, + const DWARFLocationExpressionsVector &LinkedLocationExpression, + PatchLocation Patch, DebugDieValuePool &AddrPool) = 0; + + /// Emit debug locations (.debug_loc, .debug_loclists) footer. + virtual void emitDwarfDebugLocListFooter(const CompileUnit &Unit, + MCSymbol *EndLabel) = 0; + + /// Emit .debug_addr header. + virtual MCSymbol *emitDwarfDebugAddrsHeader(const CompileUnit &Unit) = 0; + + /// Emit the addresses described by \p Addrs into the .debug_addr section. + virtual void emitDwarfDebugAddrs(const SmallVector<uint64_t> &Addrs, + uint8_t AddrSize) = 0; + + /// Emit .debug_addr footer. + virtual void emitDwarfDebugAddrsFooter(const CompileUnit &Unit, + MCSymbol *EndLabel) = 0; + + /// Emit .debug_aranges entries for \p Unit + virtual void + emitDwarfDebugArangesTable(const CompileUnit &Unit, + const AddressRanges &LinkedRanges) = 0; + + /// Emit specified \p LineTable into .debug_line table. + virtual void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable, + const CompileUnit &Unit, + OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool) = 0; + + /// Emit the .debug_pubnames contribution for \p Unit. + virtual void emitPubNamesForUnit(const CompileUnit &Unit) = 0; + + /// Emit the .debug_pubtypes contribution for \p Unit. + virtual void emitPubTypesForUnit(const CompileUnit &Unit) = 0; + + /// Emit a CIE. + virtual void emitCIE(StringRef CIEBytes) = 0; + + /// Emit an FDE with data \p Bytes. + virtual void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint64_t Address, + StringRef Bytes) = 0; + + /// Emit the compilation unit header for \p Unit in the + /// .debug_info section. + /// + /// As a side effect, this also switches the current Dwarf version + /// of the MC layer to the one of U.getOrigUnit(). + virtual void emitCompileUnitHeader(CompileUnit &Unit, + unsigned DwarfVersion) = 0; + + /// Recursively emit the DIE tree rooted at \p Die. + virtual void emitDIE(DIE &Die) = 0; + + /// Emit all available macro tables(DWARFv4 and DWARFv5). + /// Use \p UnitMacroMap to get compilation unit by macro table offset. + /// Side effects: Fill \p StringPool with macro strings, update + /// DW_AT_macro_info, DW_AT_macros attributes for corresponding compile + /// units. + virtual void emitMacroTables(DWARFContext *Context, + const Offset2UnitMap &UnitMacroMap, + OffsetsStringPool &StringPool) = 0; + + /// Returns size of generated .debug_line section. + virtual uint64_t getLineSectionSize() const = 0; + + /// Returns size of generated .debug_frame section. + virtual uint64_t getFrameSectionSize() const = 0; + + /// Returns size of generated .debug_ranges section. + virtual uint64_t getRangesSectionSize() const = 0; + + /// Returns size of generated .debug_rnglists section. + virtual uint64_t getRngListsSectionSize() const = 0; + + /// Returns size of generated .debug_info section. + virtual uint64_t getDebugInfoSectionSize() const = 0; + + /// Returns size of generated .debug_macinfo section. + virtual uint64_t getDebugMacInfoSectionSize() const = 0; + + /// Returns size of generated .debug_macro section. + virtual uint64_t getDebugMacroSectionSize() const = 0; + + /// Returns size of generated .debug_loclists section. + virtual uint64_t getLocListsSectionSize() const = 0; + + /// Returns size of generated .debug_addr section. + virtual uint64_t getDebugAddrSectionSize() 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>>; + +/// 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 called ValidRelocs in the +/// AddressesInfo and are gathered as a very first step when we start +/// processing a object file. +class DWARFLinker : public DWARFLinkerBase { +public: + DWARFLinker(MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler, + std::function<StringRef(StringRef)> StringsTranslator) + : StringsTranslator(StringsTranslator), ErrorHandler(ErrorHandler), + WarningHandler(WarningHandler) {} + + static std::unique_ptr<DWARFLinker> createLinker( + MessageHandlerTy ErrorHandler, MessageHandlerTy WarningHandler, + std::function<StringRef(StringRef)> StringsTranslator = nullptr) { + return std::make_unique<DWARFLinker>(ErrorHandler, WarningHandler, + StringsTranslator); + } + + Error createEmitter(const Triple &TheTriple, OutputFileType FileType, + raw_pwrite_stream &OutFile); + + DwarfEmitter *getEmitter(); + + /// Add object file to be linked. Pre-load compile unit die. Call + /// \p OnCUDieLoaded for each compile unit die. If specified \p File + /// 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 objFiles. Object files are linked all together. + Error link() override; + + /// A number of 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 Update) override { + Options.Update = Update; + } + + /// Allow generating valid, but non-deterministic output. + void setAllowNonDeterministicOutput(bool) override { /* Nothing to do. */ + } + + /// Set whether 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(!llvm::is_contained(Options.AccelTables, Kind)); + Options.AccelTables.emplace_back(Kind); + } + + /// Set prepend path for clang modules. + void setPrependPath(StringRef 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(); + } + +private: + /// Flags passed to DwarfLinker::lookForDIEsToKeep + enum TraversalFlags { + TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept. + TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope. + TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE. + TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE. + TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents. + TF_SkipPC = 1 << 5, ///< Skip all location attributes. + }; + + /// The distinct types of work performed by the work loop. + enum class WorklistItemType { + /// Given a DIE, look for DIEs to be kept. + LookForDIEsToKeep, + /// Given a DIE, look for children of this DIE to be kept. + LookForChildDIEsToKeep, + /// Given a DIE, look for DIEs referencing this DIE to be kept. + LookForRefDIEsToKeep, + /// Given a DIE, look for parent DIEs to be kept. + LookForParentDIEsToKeep, + /// Given a DIE, update its incompleteness based on whether its children are + /// incomplete. + UpdateChildIncompleteness, + /// Given a DIE, update its incompleteness based on whether the DIEs it + /// references are incomplete. + UpdateRefIncompleteness, + /// Given a DIE, mark it as ODR Canonical if applicable. + MarkODRCanonicalDie, + }; + + /// This class represents an item in the work list. The type defines what kind + /// of work needs to be performed when processing the current item. The flags + /// and info fields are optional based on the type. + struct WorklistItem { + DWARFDie Die; + WorklistItemType Type; + CompileUnit &CU; + unsigned Flags; + union { + const unsigned AncestorIdx; + CompileUnit::DIEInfo *OtherInfo; + }; + + WorklistItem(DWARFDie Die, CompileUnit &CU, unsigned Flags, + WorklistItemType T = WorklistItemType::LookForDIEsToKeep) + : Die(Die), Type(T), CU(CU), Flags(Flags), AncestorIdx(0) {} + + WorklistItem(DWARFDie Die, CompileUnit &CU, WorklistItemType T, + CompileUnit::DIEInfo *OtherInfo = nullptr) + : Die(Die), Type(T), CU(CU), Flags(0), OtherInfo(OtherInfo) {} + + WorklistItem(unsigned AncestorIdx, CompileUnit &CU, unsigned Flags) + : Type(WorklistItemType::LookForParentDIEsToKeep), CU(CU), Flags(Flags), + AncestorIdx(AncestorIdx) {} + }; + + /// Verify the given DWARF file. + void verifyInput(const DWARFFile &File); + + /// returns true if we need to translate strings. + bool needToTranslateStrings() { return StringsTranslator != nullptr; } + + void reportWarning(const Twine &Warning, const DWARFFile &File, + const DWARFDie *DIE = nullptr) const { + if (WarningHandler != nullptr) + WarningHandler(Warning, File.FileName, DIE); + } + + void reportError(const Twine &Warning, const DWARFFile &File, + const DWARFDie *DIE = nullptr) const { + if (ErrorHandler != nullptr) + ErrorHandler(Warning, File.FileName, DIE); + } + + void copyInvariantDebugSection(DWARFContext &Dwarf); + + /// 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 = std::vector<RefModuleUnit>; + + /// Keeps track of data associated with one object during linking. + struct LinkContext { + DWARFFile &File; + UnitListTy CompileUnits; + ModuleUnitListTy ModuleUnits; + bool Skip = false; + + LinkContext(DWARFFile &File) : File(File) {} + + /// Clear part of the context that's no longer needed when we're done with + /// the debug object. + void clear() { + CompileUnits.clear(); + ModuleUnits.clear(); + File.unload(); + } + }; + + /// Called before emitting object data + void cleanupAuxiliarryData(LinkContext &Context); + + /// Look at the parent of the given DIE and decide whether they should be + /// kept. + void lookForParentDIEsToKeep(unsigned AncestorIdx, CompileUnit &CU, + unsigned Flags, + SmallVectorImpl<WorklistItem> &Worklist); + + /// Look at the children of the given DIE and decide whether they should be + /// kept. + void lookForChildDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, + unsigned Flags, + SmallVectorImpl<WorklistItem> &Worklist); + + /// Look at DIEs referenced by the given DIE and decide whether they should be + /// kept. All DIEs referenced though attributes should be kept. + void lookForRefDIEsToKeep(const DWARFDie &Die, CompileUnit &CU, + unsigned Flags, const UnitListTy &Units, + const DWARFFile &File, + SmallVectorImpl<WorklistItem> &Worklist); + + /// Mark context corresponding to the specified \p Die as having canonical + /// die, if applicable. + void markODRCanonicalDie(const DWARFDie &Die, CompileUnit &CU); + + /// \defgroup FindRootDIEs Find DIEs corresponding to Address map entries. + /// + /// @{ + /// Recursively walk the \p DIE tree and look for DIEs to + /// keep. Store that information in \p CU's DIEInfo. + /// + /// The return value indicates whether the DIE is incomplete. + void lookForDIEsToKeep(AddressesMap &RelocMgr, const UnitListTy &Units, + const DWARFDie &DIE, const DWARFFile &File, + CompileUnit &CU, unsigned Flags); + + /// Check whether specified \p CUDie is a Clang module reference. + /// if \p Quiet is false then display error messages. + /// \return first == true if CUDie is a Clang module reference. + /// second == true if module is already loaded. + std::pair<bool, bool> isClangModuleRef(const DWARFDie &CUDie, + std::string &PCMFile, + LinkContext &Context, unsigned Indent, + bool Quiet); + + /// If this compile unit is really a skeleton CU that points to a + /// clang module, register it in ClangModules and return true. + /// + /// A skeleton CU is a CU without children, a DW_AT_gnu_dwo_name + /// pointing to the module, and a DW_AT_gnu_dwo_id with the module + /// hash. + bool registerModuleReference(const DWARFDie &CUDie, LinkContext &Context, + ObjFileLoaderTy Loader, + CompileUnitHandlerTy OnCUDieLoaded, + unsigned Indent = 0); + + /// Recursively add the debug info in this clang module .pcm + /// file (and all the modules imported by it in a bottom-up fashion) + /// to ModuleUnits. + Error loadClangModule(ObjFileLoaderTy Loader, const DWARFDie &CUDie, + const std::string &PCMFile, LinkContext &Context, + CompileUnitHandlerTy OnCUDieLoaded, + unsigned Indent = 0); + + /// Clone specified Clang module unit \p Unit. + Error cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit, + DeclContextTree &ODRContexts, + OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool, + DebugDieValuePool &StringOffsetPool, + unsigned Indent = 0); + + unsigned shouldKeepDIE(AddressesMap &RelocMgr, const DWARFDie &DIE, + const DWARFFile &File, CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, unsigned Flags); + + /// This function checks whether variable has DWARF expression containing + /// operation referencing live address(f.e. DW_OP_addr, DW_OP_addrx...). + /// \returns first is true if the expression has an operation referencing an + /// address. + /// second is the relocation adjustment value if the live address is + /// referenced. + std::pair<bool, std::optional<int64_t>> + getVariableRelocAdjustment(AddressesMap &RelocMgr, const DWARFDie &DIE); + + /// Check if a variable describing DIE should be kept. + /// \returns updated TraversalFlags. + unsigned shouldKeepVariableDIE(AddressesMap &RelocMgr, const DWARFDie &DIE, + CompileUnit::DIEInfo &MyInfo, unsigned Flags); + + unsigned shouldKeepSubprogramDIE(AddressesMap &RelocMgr, const DWARFDie &DIE, + const DWARFFile &File, CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, + unsigned Flags); + + /// Resolve the DIE attribute reference that has been extracted in \p + /// RefValue. The resulting DIE might be in another CompileUnit which is + /// stored into \p ReferencedCU. \returns null if resolving fails for any + /// reason. + DWARFDie resolveDIEReference(const DWARFFile &File, const UnitListTy &Units, + const DWARFFormValue &RefValue, + const DWARFDie &DIE, CompileUnit *&RefCU); + + /// @} + + /// \defgroup Methods used to link the debug information + /// + /// @{ + + struct DWARFLinkerOptions; + + class DIECloner { + DWARFLinker &Linker; + DwarfEmitter *Emitter; + DWARFFile &ObjFile; + OffsetsStringPool &DebugStrPool; + OffsetsStringPool &DebugLineStrPool; + DebugDieValuePool &StringOffsetPool; + DebugDieValuePool AddrPool; + + /// Allocator used for all the DIEValue objects. + BumpPtrAllocator &DIEAlloc; + + std::vector<std::unique_ptr<CompileUnit>> &CompileUnits; + + /// Keeps mapping from offset of the macro table to corresponding + /// compile unit. + Offset2UnitMap UnitMacroMap; + + bool Update; + + public: + DIECloner(DWARFLinker &Linker, DwarfEmitter *Emitter, DWARFFile &ObjFile, + BumpPtrAllocator &DIEAlloc, + std::vector<std::unique_ptr<CompileUnit>> &CompileUnits, + bool Update, OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool, + DebugDieValuePool &StringOffsetPool) + : Linker(Linker), Emitter(Emitter), ObjFile(ObjFile), + DebugStrPool(DebugStrPool), DebugLineStrPool(DebugLineStrPool), + StringOffsetPool(StringOffsetPool), DIEAlloc(DIEAlloc), + CompileUnits(CompileUnits), Update(Update) {} + + /// Recursively clone \p InputDIE into an tree of DIE objects + /// where useless (as decided by lookForDIEsToKeep()) bits have been + /// stripped out and addresses have been rewritten according to the + /// address map. + /// + /// \param OutOffset is the offset the cloned DIE in the output + /// compile unit. + /// \param PCOffset (while cloning a function scope) is the offset + /// applied to the entry point of the function to get the linked address. + /// \param Die the output DIE to use, pass NULL to create one. + /// \returns the root of the cloned tree or null if nothing was selected. + DIE *cloneDIE(const DWARFDie &InputDIE, const DWARFFile &File, + CompileUnit &U, int64_t PCOffset, uint32_t OutOffset, + unsigned Flags, bool IsLittleEndian, DIE *Die = nullptr); + + /// Construct the output DIE tree by cloning the DIEs we + /// chose to keep above. If there are no valid relocs, then there's + /// nothing to clone/emit. + uint64_t cloneAllCompileUnits(DWARFContext &DwarfContext, + const DWARFFile &File, bool IsLittleEndian); + + /// Emit the .debug_addr section for the \p Unit. + void emitDebugAddrSection(CompileUnit &Unit, + const uint16_t DwarfVersion) const; + + using ExpressionHandlerRef = function_ref<void( + SmallVectorImpl<uint8_t> &, SmallVectorImpl<uint8_t> &, + int64_t AddrRelocAdjustment)>; + + /// Compute and emit debug locations (.debug_loc, .debug_loclists) + /// for \p Unit, patch the attributes referencing it. + void generateUnitLocations(CompileUnit &Unit, const DWARFFile &File, + ExpressionHandlerRef ExprHandler); + + private: + using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec; + + /// Information gathered and exchanged between the various + /// clone*Attributes helpers about the attributes of a particular DIE. + struct AttributesInfo { + /// Names. + DwarfStringPoolEntryRef Name, MangledName, NameWithoutTemplate; + + /// Offsets in the string pool. + uint32_t NameOffset = 0; + uint32_t MangledNameOffset = 0; + + /// Offset to apply to PC addresses inside a function. + int64_t PCOffset = 0; + + /// Does the DIE have a low_pc attribute? + bool HasLowPc = false; + + /// Does the DIE have a ranges attribute? + bool HasRanges = false; + + /// Is this DIE only a declaration? + bool IsDeclaration = false; + + /// Is there a DW_AT_str_offsets_base in the CU? + bool AttrStrOffsetBaseSeen = false; + + /// Is there a DW_AT_APPLE_origin in the CU? + bool HasAppleOrigin = false; + + AttributesInfo() = default; + }; + + /// Helper for cloneDIE. + unsigned cloneAttribute(DIE &Die, const DWARFDie &InputDIE, + const DWARFFile &File, CompileUnit &U, + const DWARFFormValue &Val, + const AttributeSpec AttrSpec, unsigned AttrSize, + AttributesInfo &AttrInfo, bool IsLittleEndian); + + /// Clone a string attribute described by \p AttrSpec and add + /// it to \p Die. + /// \returns the size of the new attribute. + unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, const DWARFUnit &U, + AttributesInfo &Info); + + /// Clone an attribute referencing another DIE and add + /// it to \p Die. + /// \returns the size of the new attribute. + unsigned cloneDieReferenceAttribute(DIE &Die, const DWARFDie &InputDIE, + AttributeSpec AttrSpec, + unsigned AttrSize, + const DWARFFormValue &Val, + const DWARFFile &File, + CompileUnit &Unit); + + /// Clone a DWARF expression that may be referencing another DIE. + void cloneExpression(DataExtractor &Data, DWARFExpression Expression, + const DWARFFile &File, CompileUnit &Unit, + SmallVectorImpl<uint8_t> &OutputBuffer, + int64_t AddrRelocAdjustment, bool IsLittleEndian); + + /// Clone an attribute referencing another DIE and add + /// it to \p Die. + /// \returns the size of the new attribute. + unsigned cloneBlockAttribute(DIE &Die, const DWARFDie &InputDIE, + const DWARFFile &File, CompileUnit &Unit, + AttributeSpec AttrSpec, + const DWARFFormValue &Val, + bool IsLittleEndian); + + /// Clone an attribute referencing another DIE and add + /// it to \p Die. + /// \returns the size of the new attribute. + unsigned cloneAddressAttribute(DIE &Die, const DWARFDie &InputDIE, + AttributeSpec AttrSpec, unsigned AttrSize, + const DWARFFormValue &Val, + const CompileUnit &Unit, + AttributesInfo &Info); + + /// Clone a scalar attribute and add it to \p Die. + /// \returns the size of the new attribute. + unsigned cloneScalarAttribute(DIE &Die, const DWARFDie &InputDIE, + const DWARFFile &File, CompileUnit &U, + AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize, + AttributesInfo &Info); + + /// Get the potential name and mangled name for the entity + /// described by \p Die and store them in \Info if they are not + /// already there. + /// \returns is a name was found. + bool getDIENames(const DWARFDie &Die, AttributesInfo &Info, + OffsetsStringPool &StringPool, bool StripTemplate = false); + + uint32_t hashFullyQualifiedName(DWARFDie DIE, CompileUnit &U, + const DWARFFile &File, + int RecurseDepth = 0); + + /// Helper for cloneDIE. + void addObjCAccelerator(CompileUnit &Unit, const DIE *Die, + DwarfStringPoolEntryRef Name, + OffsetsStringPool &StringPool, bool SkipPubSection); + + void rememberUnitForMacroOffset(CompileUnit &Unit); + + /// Clone and emit the line table for the specified \p Unit. + /// Translate directories and file names if necessary. + /// Relocate address ranges. + void generateLineTableForUnit(CompileUnit &Unit); + }; + + /// Assign an abbreviation number to \p Abbrev + void assignAbbrev(DIEAbbrev &Abbrev); + + /// Compute and emit debug ranges(.debug_aranges, .debug_ranges, + /// .debug_rnglists) for \p Unit, patch the attributes referencing it. + void generateUnitRanges(CompileUnit &Unit, const DWARFFile &File, + DebugDieValuePool &AddrPool) const; + + /// Emit the accelerator entries for \p Unit. + void emitAcceleratorEntriesForUnit(CompileUnit &Unit); + + /// Patch the frame info for an object file and emit it. + void patchFrameInfoForObject(LinkContext &Context); + + /// FoldingSet that uniques the abbreviations. + FoldingSet<DIEAbbrev> AbbreviationsSet; + + /// Storage for the unique Abbreviations. + /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot be + /// changed to a vector of unique_ptrs. + std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations; + + /// DIELoc objects that need to be destructed (but not freed!). + std::vector<DIELoc *> DIELocs; + + /// DIEBlock objects that need to be destructed (but not freed!). + std::vector<DIEBlock *> DIEBlocks; + + /// Allocator used for all the DIEValue objects. + BumpPtrAllocator DIEAlloc; + /// @} + + std::unique_ptr<DwarfStreamer> TheDwarfEmitter; + std::vector<LinkContext> ObjectContexts; + + /// The CIEs that have been emitted in the output section. The actual CIE + /// data serves a the key to this StringMap, this takes care of comparing the + /// semantics of CIEs defined in different object files. + StringMap<uint32_t> EmittedCIEs; + + /// Offset of the last CIE that has been emitted in the output + /// .debug_frame section. + uint32_t LastCIEOffset = 0; + + /// Apple accelerator tables. + DWARF5AccelTable DebugNames; + AccelTable<AppleAccelTableStaticOffsetData> AppleNames; + AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces; + AccelTable<AppleAccelTableStaticOffsetData> AppleObjc; + AccelTable<AppleAccelTableStaticTypeData> AppleTypes; + + /// Mapping the PCM filename to the DwoId. + StringMap<uint64_t> ClangModules; + + std::function<StringRef(StringRef)> StringsTranslator = nullptr; + + /// A unique ID that identifies each compile unit. + unsigned UniqueUnitID = 0; + + // error handler + MessageHandlerTy ErrorHandler = nullptr; + + // warning handler + MessageHandlerTy WarningHandler = nullptr; + + /// 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 + bool Update = false; + + /// Whether we want a static variable to force us to keep its enclosing + /// function. + bool KeepFunctionForStatic = 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 + 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. + SwiftInterfacesMapTy *ParseableSwiftInterfaces = nullptr; + + /// A list of remappings to apply to file paths. + ObjectPrefixMapTy *ObjectPrefixMap = nullptr; + } Options; +}; + +} // end of namespace classic +} // end of namespace dwarf_linker +} // end of namespace llvm + +#endif // LLVM_DWARFLINKER_CLASSIC_DWARFLINKER_H diff --git a/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinkerCompileUnit.h b/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinkerCompileUnit.h new file mode 100644 index 000000000000..bfe544946fd9 --- /dev/null +++ b/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinkerCompileUnit.h @@ -0,0 +1,336 @@ +//===- 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_DWARFLINKER_CLASSIC_DWARFLINKERCOMPILEUNIT_H +#define LLVM_DWARFLINKER_CLASSIC_DWARFLINKERCOMPILEUNIT_H + +#include "llvm/ADT/AddressRanges.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include <optional> + +namespace llvm { +namespace dwarf_linker { +namespace classic { + +class DeclContext; + +/// Mapped value in the address map is the offset to apply to the +/// linked address. +using RangesTy = AddressRangesMap; + +// This structure keeps patch for the attribute and, optionally, +// the value of relocation which should be applied. Currently, +// only location attribute needs to have relocation: either to the +// function ranges if location attribute is of type 'loclist', +// either to the operand of DW_OP_addr/DW_OP_addrx if location attribute +// is of type 'exprloc'. +// ASSUMPTION: Location attributes of 'loclist' type containing 'exprloc' +// with address expression operands are not supported yet. +struct PatchLocation { + DIE::value_iterator I; + int64_t RelocAdjustment = 0; + + PatchLocation() = default; + PatchLocation(DIE::value_iterator I) : I(I) {} + PatchLocation(DIE::value_iterator I, int64_t Reloc) + : I(I), RelocAdjustment(Reloc) {} + + void set(uint64_t New) const { + assert(I); + const auto &Old = *I; + assert(Old.getType() == DIEValue::isInteger); + *I = DIEValue(Old.getAttribute(), Old.getForm(), DIEInteger(New)); + } + + uint64_t get() const { + assert(I); + return I->getDIEInteger().getValue(); + } +}; + +using RngListAttributesTy = SmallVector<PatchLocation>; +using LocListAttributesTy = SmallVector<PatchLocation>; + +/// Stores all information relating to a compile unit, be it in its original +/// instance in the object file to its brand new cloned and generated DIE tree. +class CompileUnit { +public: + /// Information gathered about a DIE in the object file. + struct DIEInfo { + /// Address offset to apply to the described entity. + int64_t AddrAdjust; + + /// ODR Declaration context. + DeclContext *Ctxt; + + /// Cloned version of that DIE. + DIE *Clone; + + /// The index of this DIE's parent. + uint32_t ParentIdx; + + /// Is the DIE part of the linked output? + bool Keep : 1; + + /// Was this DIE's entity found in the map? + bool InDebugMap : 1; + + /// Is this a pure forward declaration we can strip? + bool Prune : 1; + + /// Does DIE transitively refer an incomplete decl? + bool Incomplete : 1; + + /// Is DIE in the clang module scope? + bool InModuleScope : 1; + + /// Is ODR marking done? + bool ODRMarkingDone : 1; + + /// Is this a reference to a DIE that hasn't been cloned yet? + bool UnclonedReference : 1; + + /// Is this a variable with a location attribute referencing address? + bool HasLocationExpressionAddr : 1; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump(); +#endif // if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + }; + + CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR, + StringRef ClangModuleName) + : OrigUnit(OrigUnit), ID(ID), ClangModuleName(ClangModuleName) { + Info.resize(OrigUnit.getNumDIEs()); + + auto CUDie = OrigUnit.getUnitDIE(false); + if (!CUDie) { + HasODR = false; + return; + } + if (auto Lang = dwarf::toUnsigned(CUDie.find(dwarf::DW_AT_language))) + HasODR = CanUseODR && (*Lang == dwarf::DW_LANG_C_plus_plus || + *Lang == dwarf::DW_LANG_C_plus_plus_03 || + *Lang == dwarf::DW_LANG_C_plus_plus_11 || + *Lang == dwarf::DW_LANG_C_plus_plus_14 || + *Lang == dwarf::DW_LANG_ObjC_plus_plus); + else + HasODR = false; + } + + DWARFUnit &getOrigUnit() const { return OrigUnit; } + + unsigned getUniqueID() const { return ID; } + + void createOutputDIE() { NewUnit.emplace(OrigUnit.getUnitDIE().getTag()); } + + DIE *getOutputUnitDIE() const { + if (NewUnit) + return &const_cast<BasicDIEUnit &>(*NewUnit).getUnitDie(); + return nullptr; + } + + bool hasODR() const { return HasODR; } + bool isClangModule() const { return !ClangModuleName.empty(); } + uint16_t getLanguage(); + /// Return the DW_AT_LLVM_sysroot of the compile unit or an empty StringRef. + StringRef getSysRoot(); + + const std::string &getClangModuleName() const { return ClangModuleName; } + + DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; } + const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; } + + DIEInfo &getInfo(const DWARFDie &Die) { + unsigned Idx = getOrigUnit().getDIEIndex(Die); + return Info[Idx]; + } + + uint64_t getStartOffset() const { return StartOffset; } + uint64_t getNextUnitOffset() const { return NextUnitOffset; } + void setStartOffset(uint64_t DebugInfoSize) { StartOffset = DebugInfoSize; } + + std::optional<uint64_t> getLowPc() const { return LowPc; } + uint64_t getHighPc() const { return HighPc; } + bool hasLabelAt(uint64_t Addr) const { return Labels.count(Addr); } + + const RangesTy &getFunctionRanges() const { return Ranges; } + + const RngListAttributesTy &getRangesAttributes() { return RangeAttributes; } + + std::optional<PatchLocation> getUnitRangesAttribute() const { + return UnitRangeAttribute; + } + + const LocListAttributesTy &getLocationAttributes() const { + return LocationAttributes; + } + + /// Mark every DIE in this unit as kept. This function also + /// marks variables as InDebugMap so that they appear in the + /// reconstructed accelerator tables. + void markEverythingAsKept(); + + /// Compute the end offset for this unit. Must be called after the CU's DIEs + /// have been cloned. \returns the next unit offset (which is also the + /// current debug_info section size). + uint64_t computeNextUnitOffset(uint16_t DwarfVersion); + + /// Keep track of a forward reference to DIE \p Die in \p RefUnit by \p + /// Attr. The attribute should be fixed up later to point to the absolute + /// offset of \p Die in the debug_info section or to the canonical offset of + /// \p Ctxt if it is non-null. + void noteForwardReference(DIE *Die, const CompileUnit *RefUnit, + DeclContext *Ctxt, PatchLocation Attr); + + /// Apply all fixups recorded by noteForwardReference(). + void fixupForwardReferences(); + + /// Add the low_pc of a label that is relocated by applying + /// offset \p PCOffset. + void addLabelLowPc(uint64_t LabelLowPc, int64_t PcOffset); + + /// Add a function range [\p LowPC, \p HighPC) that is relocated by applying + /// offset \p PCOffset. + void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset); + + /// Keep track of a DW_AT_range attribute that we will need to patch up later. + void noteRangeAttribute(const DIE &Die, PatchLocation Attr); + + /// Keep track of a location attribute pointing to a location list in the + /// debug_loc section. + void noteLocationAttribute(PatchLocation Attr); + + /// Add a name accelerator entry for \a Die with \a Name. + void addNamespaceAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name); + + /// Add a name accelerator entry for \a Die with \a Name. + void addNameAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, + bool SkipPubnamesSection = false); + + /// Add various accelerator entries for \p Die with \p Name which is stored + /// in the string table at \p Offset. \p Name must be an Objective-C + /// selector. + void addObjCAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, + bool SkipPubnamesSection = false); + + /// Add a type accelerator entry for \p Die with \p Name which is stored in + /// the string table at \p Offset. + void addTypeAccelerator(const DIE *Die, DwarfStringPoolEntryRef Name, + bool ObjcClassImplementation, + uint32_t QualifiedNameHash); + + struct AccelInfo { + /// Name of the entry. + DwarfStringPoolEntryRef Name; + + /// DIE this entry describes. + const DIE *Die; + + /// Hash of the fully qualified name. + uint32_t QualifiedNameHash; + + /// Emit this entry only in the apple_* sections. + bool SkipPubSection; + + /// Is this an ObjC class implementation? + bool ObjcClassImplementation; + + AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die, + bool SkipPubSection = false) + : Name(Name), Die(Die), SkipPubSection(SkipPubSection) {} + + AccelInfo(DwarfStringPoolEntryRef Name, const DIE *Die, + uint32_t QualifiedNameHash, bool ObjCClassIsImplementation) + : Name(Name), Die(Die), QualifiedNameHash(QualifiedNameHash), + SkipPubSection(false), + ObjcClassImplementation(ObjCClassIsImplementation) {} + }; + + const std::vector<AccelInfo> &getPubnames() const { return Pubnames; } + const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; } + const std::vector<AccelInfo> &getNamespaces() const { return Namespaces; } + const std::vector<AccelInfo> &getObjC() const { return ObjC; } + + MCSymbol *getLabelBegin() { return LabelBegin; } + void setLabelBegin(MCSymbol *S) { LabelBegin = S; } + +private: + DWARFUnit &OrigUnit; + unsigned ID; + std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. + std::optional<BasicDIEUnit> NewUnit; + MCSymbol *LabelBegin = nullptr; + + uint64_t StartOffset; + uint64_t NextUnitOffset; + + std::optional<uint64_t> LowPc; + uint64_t HighPc = 0; + + /// A list of attributes to fixup with the absolute offset of + /// a DIE in the debug_info section. + /// + /// The offsets for the attributes in this array couldn't be set while + /// cloning because for cross-cu forward references the target DIE's offset + /// isn't known you emit the reference attribute. + std::vector< + std::tuple<DIE *, const CompileUnit *, DeclContext *, PatchLocation>> + ForwardDIEReferences; + + /// The ranges in that map are the PC ranges for functions in this unit, + /// associated with the PC offset to apply to the addresses to get + /// the linked address. + RangesTy Ranges; + + /// The DW_AT_low_pc of each DW_TAG_label. + SmallDenseMap<uint64_t, uint64_t, 1> Labels; + + /// 'rnglist'(DW_AT_ranges, DW_AT_start_scope) attributes to patch after + /// we have gathered all the unit's function addresses. + /// @{ + RngListAttributesTy RangeAttributes; + std::optional<PatchLocation> UnitRangeAttribute; + /// @} + + /// Location attributes that need to be transferred from the + /// original debug_loc section to the linked one. They are stored + /// along with the PC offset that is to be applied to their + /// function's address or to be applied to address operands of + /// location expression. + LocListAttributesTy LocationAttributes; + + /// Accelerator entries for the unit, both for the pub* + /// sections and the apple* ones. + /// @{ + std::vector<AccelInfo> Pubnames; + std::vector<AccelInfo> Pubtypes; + std::vector<AccelInfo> Namespaces; + std::vector<AccelInfo> ObjC; + /// @} + + /// Is this unit subject to the ODR rule? + bool HasODR; + + /// The DW_AT_language of this unit. + uint16_t Language = 0; + + /// 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; +}; + +} // end of namespace classic +} // end of namespace dwarf_linker +} // end of namespace llvm + +#endif // LLVM_DWARFLINKER_CLASSIC_DWARFLINKERCOMPILEUNIT_H diff --git a/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinkerDeclContext.h b/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinkerDeclContext.h new file mode 100644 index 000000000000..b00f68c3be84 --- /dev/null +++ b/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFLinkerDeclContext.h @@ -0,0 +1,193 @@ +//===- DWARFLinkerDeclContext.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_DWARFLINKER_CLASSIC_DWARFLINKERDECLCONTEXT_H +#define LLVM_DWARFLINKER_CLASSIC_DWARFLINKERDECLCONTEXT_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/NonRelocatableStringpool.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include <atomic> + +namespace llvm { +namespace dwarf_linker { +namespace classic { + +class CompileUnit; +struct DeclMapInfo; + +/// Small helper that resolves and caches file paths. This helps reduce the +/// number of calls to realpath which is expensive. We assume the input are +/// files, and cache the realpath of their parent. This way we can quickly +/// resolve different files under the same path. +class CachedPathResolver { +public: + /// Resolve a path by calling realpath and cache its result. The returned + /// StringRef is interned in the given \p StringPool. + StringRef resolve(const std::string &Path, + NonRelocatableStringpool &StringPool) { + StringRef FileName = sys::path::filename(Path); + StringRef ParentPath = sys::path::parent_path(Path); + + // If the ParentPath has not yet been resolved, resolve and cache it for + // future look-ups. + if (!ResolvedPaths.count(ParentPath)) { + SmallString<256> RealPath; + sys::fs::real_path(ParentPath, RealPath); + ResolvedPaths.insert( + {ParentPath, std::string(RealPath.c_str(), RealPath.size())}); + } + + // Join the file name again with the resolved path. + SmallString<256> ResolvedPath(ResolvedPaths[ParentPath]); + sys::path::append(ResolvedPath, FileName); + return StringPool.internString(ResolvedPath); + } + +private: + StringMap<std::string> ResolvedPaths; +}; + +/// A DeclContext is a named program scope that is used for ODR uniquing of +/// types. +/// +/// The set of DeclContext for the ODR-subject parts of a Dwarf link is +/// expanded (and uniqued) with each new object file processed. We need to +/// determine the context of each DIE in an linked object file to see if the +/// corresponding type has already been emitted. +/// +/// The contexts are conceptually organized as a tree (eg. a function scope is +/// contained in a namespace scope that contains other scopes), but +/// storing/accessing them in an actual tree is too inefficient: we need to be +/// able to very quickly query a context for a given child context by name. +/// Storing a StringMap in each DeclContext would be too space inefficient. +/// +/// The solution here is to give each DeclContext a link to its parent (this +/// allows to walk up the tree), but to query the existence of a specific +/// DeclContext using a separate DenseMap keyed on the hash of the fully +/// qualified name of the context. +class DeclContext { +public: + using Map = DenseSet<DeclContext *, DeclMapInfo>; + + DeclContext() : DefinedInClangModule(0), Parent(*this) {} + + DeclContext(unsigned Hash, uint32_t Line, uint32_t ByteSize, uint16_t Tag, + StringRef Name, StringRef File, const DeclContext &Parent, + DWARFDie LastSeenDIE = DWARFDie(), unsigned CUId = 0) + : QualifiedNameHash(Hash), Line(Line), ByteSize(ByteSize), Tag(Tag), + DefinedInClangModule(0), Name(Name), File(File), Parent(Parent), + LastSeenDIE(LastSeenDIE), LastSeenCompileUnitID(CUId) {} + + uint32_t getQualifiedNameHash() const { return QualifiedNameHash; } + + bool setLastSeenDIE(CompileUnit &U, const DWARFDie &Die); + + void setHasCanonicalDIE() { HasCanonicalDIE = true; } + + bool hasCanonicalDIE() const { return HasCanonicalDIE; } + + uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; } + void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset = Offset; } + + bool isDefinedInClangModule() const { return DefinedInClangModule; } + void setDefinedInClangModule(bool Val) { DefinedInClangModule = Val; } + + uint16_t getTag() const { return Tag; } + +private: + friend DeclMapInfo; + + unsigned QualifiedNameHash = 0; + uint32_t Line = 0; + uint32_t ByteSize = 0; + uint16_t Tag = dwarf::DW_TAG_compile_unit; + unsigned DefinedInClangModule : 1; + StringRef Name; + StringRef File; + const DeclContext &Parent; + DWARFDie LastSeenDIE; + uint32_t LastSeenCompileUnitID = 0; + std::atomic<uint32_t> CanonicalDIEOffset = {0}; + bool HasCanonicalDIE = false; +}; + +/// This class gives a tree-like API to the DenseMap that stores the +/// DeclContext objects. It holds the BumpPtrAllocator where these objects will +/// be allocated. +class DeclContextTree { +public: + /// Get the child of \a Context described by \a DIE in \a Unit. The + /// required strings will be interned in \a StringPool. + /// \returns The child DeclContext along with one bit that is set if + /// this context is invalid. + /// + /// An invalid context means it shouldn't be considered for uniquing, but its + /// not returning null, because some children of that context might be + /// uniquing candidates. + /// + /// FIXME: The invalid bit along the return value is to emulate some + /// dsymutil-classic functionality. + PointerIntPair<DeclContext *, 1> getChildDeclContext(DeclContext &Context, + const DWARFDie &DIE, + CompileUnit &Unit, + bool InClangModule); + + DeclContext &getRoot() { return Root; } + +private: + BumpPtrAllocator Allocator; + DeclContext Root; + DeclContext::Map Contexts; + + /// Cached resolved paths from the line table. + /// The key is <UniqueUnitID, FileIdx>. + using ResolvedPathsMap = DenseMap<std::pair<unsigned, unsigned>, StringRef>; + ResolvedPathsMap ResolvedPaths; + + /// Helper that resolves and caches fragments of file paths. + CachedPathResolver PathResolver; + + /// String pool keeping real path bodies. + NonRelocatableStringpool StringPool; + + StringRef getResolvedPath(CompileUnit &CU, unsigned FileNum, + const DWARFDebugLine::LineTable &LineTable); +}; + +/// Info type for the DenseMap storing the DeclContext pointers. +struct DeclMapInfo : private DenseMapInfo<DeclContext *> { + using DenseMapInfo<DeclContext *>::getEmptyKey; + using DenseMapInfo<DeclContext *>::getTombstoneKey; + + static unsigned getHashValue(const DeclContext *Ctxt) { + return Ctxt->QualifiedNameHash; + } + + static bool isEqual(const DeclContext *LHS, const DeclContext *RHS) { + if (RHS == getEmptyKey() || RHS == getTombstoneKey()) + return RHS == LHS; + return LHS->QualifiedNameHash == RHS->QualifiedNameHash && + LHS->Line == RHS->Line && LHS->ByteSize == RHS->ByteSize && + LHS->Name.data() == RHS->Name.data() && + LHS->File.data() == RHS->File.data() && + LHS->Parent.QualifiedNameHash == RHS->Parent.QualifiedNameHash; + } +}; + +} // end of namespace classic +} // end of namespace dwarf_linker +} // end of namespace llvm + +#endif // LLVM_DWARFLINKER_CLASSIC_DWARFLINKERDECLCONTEXT_H diff --git a/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFStreamer.h b/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFStreamer.h new file mode 100644 index 000000000000..f010c348f121 --- /dev/null +++ b/contrib/llvm-project/llvm/include/llvm/DWARFLinker/Classic/DWARFStreamer.h @@ -0,0 +1,324 @@ +//===- DwarfStreamer.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_DWARFLINKER_CLASSIC_DWARFSTREAMER_H +#define LLVM_DWARFLINKER_CLASSIC_DWARFSTREAMER_H + +#include "DWARFLinker.h" +#include "llvm/BinaryFormat/Swift.h" +#include "llvm/CodeGen/AsmPrinter.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/MCSubtargetInfo.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +template <typename DataT> class AccelTable; + +class MCCodeEmitter; +class DWARFDebugMacro; + +namespace dwarf_linker { +namespace classic { + +/// User of DwarfStreamer should call initialization code +/// for AsmPrinter: +/// +/// InitializeAllTargetInfos(); +/// InitializeAllTargetMCs(); +/// InitializeAllTargets(); +/// InitializeAllAsmPrinters(); + +/// The Dwarf streaming logic. +/// +/// All interactions with the MC layer that is used to build the debug +/// information binary representation are handled in this class. +class DwarfStreamer : public DwarfEmitter { +public: + DwarfStreamer(DWARFLinkerBase::OutputFileType OutFileType, + raw_pwrite_stream &OutFile, + std::function<StringRef(StringRef Input)> Translator, + DWARFLinkerBase::MessageHandlerTy Warning) + : OutFile(OutFile), OutFileType(OutFileType), Translator(Translator), + WarningHandler(Warning) {} + virtual ~DwarfStreamer() = default; + + Error init(Triple TheTriple, StringRef Swift5ReflectionSegmentName); + + /// Dump the file to the disk. + void finish() override; + + 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 compilation unit header for \p Unit in the + /// debug_info section. + /// + /// As a side effect, this also switches the current Dwarf version + /// of the MC layer to the one of U.getOrigUnit(). + void emitCompileUnitHeader(CompileUnit &Unit, unsigned DwarfVersion) override; + + /// Recursively emit the DIE tree rooted at \p Die. + void emitDIE(DIE &Die) override; + + /// Emit the abbreviation table \p Abbrevs to the debug_abbrev section. + void emitAbbrevs(const std::vector<std::unique_ptr<DIEAbbrev>> &Abbrevs, + unsigned DwarfVersion) override; + + /// Emit contents of section SecName From Obj. + void emitSectionContents(StringRef SecData, StringRef SecName) override; + + /// Emit the string table described by \p Pool into .debug_str table. + void emitStrings(const NonRelocatableStringpool &Pool) override; + + /// Emit the debug string offset table described by \p StringOffsets into the + /// .debug_str_offsets table. + void emitStringOffsets(const SmallVector<uint64_t> &StringOffset, + uint16_t TargetDWARFVersion) override; + + /// Emit the string table described by \p Pool into .debug_line_str table. + void emitLineStrings(const NonRelocatableStringpool &Pool) override; + + /// 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; + + /// Emit debug ranges(.debug_ranges, .debug_rnglists) header. + MCSymbol *emitDwarfDebugRangeListHeader(const CompileUnit &Unit) override; + + /// Emit debug ranges(.debug_ranges, .debug_rnglists) fragment. + void emitDwarfDebugRangeListFragment(const CompileUnit &Unit, + const AddressRanges &LinkedRanges, + PatchLocation Patch, + DebugDieValuePool &AddrPool) override; + + /// Emit debug ranges(.debug_ranges, .debug_rnglists) footer. + void emitDwarfDebugRangeListFooter(const CompileUnit &Unit, + MCSymbol *EndLabel) override; + + /// Emit debug locations(.debug_loc, .debug_loclists) header. + MCSymbol *emitDwarfDebugLocListHeader(const CompileUnit &Unit) override; + + /// Emit .debug_addr header. + MCSymbol *emitDwarfDebugAddrsHeader(const CompileUnit &Unit) override; + + /// Emit the addresses described by \p Addrs into .debug_addr table. + void emitDwarfDebugAddrs(const SmallVector<uint64_t> &Addrs, + uint8_t AddrSize) override; + + /// Emit .debug_addr footer. + void emitDwarfDebugAddrsFooter(const CompileUnit &Unit, + MCSymbol *EndLabel) override; + + /// Emit debug ranges(.debug_loc, .debug_loclists) fragment. + void emitDwarfDebugLocListFragment( + const CompileUnit &Unit, + const DWARFLocationExpressionsVector &LinkedLocationExpression, + PatchLocation Patch, DebugDieValuePool &AddrPool) override; + + /// Emit debug ranges(.debug_loc, .debug_loclists) footer. + void emitDwarfDebugLocListFooter(const CompileUnit &Unit, + MCSymbol *EndLabel) override; + + /// Emit .debug_aranges entries for \p Unit + void emitDwarfDebugArangesTable(const CompileUnit &Unit, + const AddressRanges &LinkedRanges) override; + + uint64_t getRangesSectionSize() const override { return RangesSectionSize; } + + uint64_t getRngListsSectionSize() const override { + return RngListsSectionSize; + } + + /// Emit .debug_line table entry for specified \p LineTable + void emitLineTableForUnit(const DWARFDebugLine::LineTable &LineTable, + const CompileUnit &Unit, + OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool) override; + + uint64_t getLineSectionSize() const override { return LineSectionSize; } + + /// Emit the .debug_pubnames contribution for \p Unit. + void emitPubNamesForUnit(const CompileUnit &Unit) override; + + /// Emit the .debug_pubtypes contribution for \p Unit. + void emitPubTypesForUnit(const CompileUnit &Unit) override; + + /// Emit a CIE. + void emitCIE(StringRef CIEBytes) override; + + /// Emit an FDE with data \p Bytes. + void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint64_t Address, + StringRef Bytes) override; + + /// Emit DWARF debug names. + void emitDebugNames(DWARF5AccelTable &Table) override; + + /// Emit Apple namespaces accelerator table. + void emitAppleNamespaces( + AccelTable<AppleAccelTableStaticOffsetData> &Table) override; + + /// Emit Apple names accelerator table. + void + emitAppleNames(AccelTable<AppleAccelTableStaticOffsetData> &Table) override; + + /// Emit Apple Objective-C accelerator table. + void + emitAppleObjc(AccelTable<AppleAccelTableStaticOffsetData> &Table) override; + + /// Emit Apple type accelerator table. + void + emitAppleTypes(AccelTable<AppleAccelTableStaticTypeData> &Table) override; + + uint64_t getFrameSectionSize() const override { return FrameSectionSize; } + + uint64_t getDebugInfoSectionSize() const override { + return DebugInfoSectionSize; + } + + uint64_t getDebugMacInfoSectionSize() const override { + return MacInfoSectionSize; + } + + uint64_t getDebugMacroSectionSize() const override { + return MacroSectionSize; + } + + uint64_t getLocListsSectionSize() const override { + return LocListsSectionSize; + } + + uint64_t getDebugAddrSectionSize() const override { return AddrSectionSize; } + + void emitMacroTables(DWARFContext *Context, + const Offset2UnitMap &UnitMacroMap, + OffsetsStringPool &StringPool) override; + +private: + inline void warn(const Twine &Warning, StringRef Context = "") { + if (WarningHandler) + WarningHandler(Warning, Context, nullptr); + } + + void emitMacroTableImpl(const DWARFDebugMacro *MacroTable, + const Offset2UnitMap &UnitMacroMap, + OffsetsStringPool &StringPool, uint64_t &OutOffset); + + /// Emit piece of .debug_ranges for \p LinkedRanges. + void emitDwarfDebugRangesTableFragment(const CompileUnit &Unit, + const AddressRanges &LinkedRanges, + PatchLocation Patch); + + /// Emit piece of .debug_rnglists for \p LinkedRanges. + void emitDwarfDebugRngListsTableFragment(const CompileUnit &Unit, + const AddressRanges &LinkedRanges, + PatchLocation Patch, + DebugDieValuePool &AddrPool); + + /// Emit piece of .debug_loc for \p LinkedRanges. + void emitDwarfDebugLocTableFragment( + const CompileUnit &Unit, + const DWARFLocationExpressionsVector &LinkedLocationExpression, + PatchLocation Patch); + + /// Emit piece of .debug_loclists for \p LinkedRanges. + void emitDwarfDebugLocListsTableFragment( + const CompileUnit &Unit, + const DWARFLocationExpressionsVector &LinkedLocationExpression, + PatchLocation Patch, DebugDieValuePool &AddrPool); + + /// \defgroup Line table emission + /// @{ + void emitLineTablePrologue(const DWARFDebugLine::Prologue &P, + OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool); + void emitLineTableString(const DWARFDebugLine::Prologue &P, + const DWARFFormValue &String, + OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool); + void emitLineTableProloguePayload(const DWARFDebugLine::Prologue &P, + OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool); + void emitLineTablePrologueV2IncludeAndFileTable( + const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool); + void emitLineTablePrologueV5IncludeAndFileTable( + const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool, + OffsetsStringPool &DebugLineStrPool); + void emitLineTableRows(const DWARFDebugLine::LineTable &LineTable, + MCSymbol *LineEndSym, unsigned AddressByteSize); + void emitIntOffset(uint64_t Offset, dwarf::DwarfFormat Format, + uint64_t &SectionSize); + void emitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo, + dwarf::DwarfFormat Format, uint64_t &SectionSize); + /// @} + + /// \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; + uint64_t AddrSectionSize = 0; + uint64_t StrOffsetSectionSize = 0; + + /// Keep track of emitted CUs and their Unique ID. + struct EmittedUnit { + unsigned ID; + MCSymbol *LabelBegin; + }; + std::vector<EmittedUnit> EmittedUnits; + + /// 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); + + DWARFLinkerBase::MessageHandlerTy WarningHandler = nullptr; +}; + +} // end of namespace classic +} // end of namespace dwarf_linker +} // end of namespace llvm + +#endif // LLVM_DWARFLINKER_CLASSIC_DWARFSTREAMER_H |