| //===- 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_DWARFLINKER_H |
| #define LLVM_DWARFLINKER_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/DWARFLinkerCompileUnit.h" |
| #include "llvm/DebugInfo/DWARF/DWARFContext.h" |
| #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" |
| #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" |
| #include "llvm/DebugInfo/DWARF/DWARFDie.h" |
| #include "llvm/DebugInfo/DWARF/DWARFExpression.h" |
| #include <map> |
| |
| namespace llvm { |
| class DWARFExpression; |
| class DWARFUnit; |
| class DataExtractor; |
| class DeclContextTree; |
| template <typename T> class SmallVectorImpl; |
| |
| enum class DwarfLinkerClient { Dsymutil, LLD, General }; |
| |
| /// AddressesMap represents information about valid addresses used |
| /// by debug information. Valid addresses are those which points to |
| /// live code sections. i.e. relocations for these addresses point |
| /// into sections which would be/are placed into resulting binary. |
| class AddressesMap { |
| public: |
| virtual ~AddressesMap(); |
| |
| /// Checks that there are valid relocations against a .debug_info |
| /// section. |
| virtual bool hasValidRelocs() = 0; |
| |
| /// Checks that the specified DWARF expression operand \p Op references live |
| /// code section and returns the relocation adjustment value (to get the |
| /// linked address this value might be added to the source expression operand |
| /// address). |
| /// \returns relocation adjustment value or std::nullopt if there is no |
| /// corresponding live address. |
| virtual std::optional<int64_t> |
| getExprOpAddressRelocAdjustment(DWARFUnit &U, |
| const DWARFExpression::Operation &Op, |
| uint64_t StartOffset, uint64_t EndOffset) = 0; |
| |
| /// Checks that the specified subprogram \p DIE references the live code |
| /// section and returns the relocation adjustment value (to get the linked |
| /// address this value might be added to the source subprogram address). |
| /// Allowed kinds of input DIE: DW_TAG_subprogram, DW_TAG_label. |
| /// \returns relocation adjustment value or std::nullopt if there is no |
| /// corresponding live address. |
| virtual std::optional<int64_t> |
| getSubprogramRelocAdjustment(const DWARFDie &DIE) = 0; |
| |
| /// Apply the valid relocations to the buffer \p Data, taking into |
| /// account that Data is at \p BaseOffset in the .debug_info section. |
| /// |
| /// \returns true whether any reloc has been applied. |
| virtual bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset, |
| bool IsLittleEndian) = 0; |
| |
| /// Returns all valid functions address ranges(i.e., those ranges |
| /// which points to sections with code). |
| virtual RangesTy &getValidAddressRanges() = 0; |
| |
| /// Erases all data. |
| virtual void clear() = 0; |
| }; |
| |
| using Offset2UnitMap = DenseMap<uint64_t, CompileUnit *>; |
| |
| /// DwarfEmitter presents interface to generate all debug info tables. |
| class DwarfEmitter { |
| public: |
| virtual ~DwarfEmitter(); |
| |
| /// Emit DIE containing warnings. |
| virtual void emitPaperTrailWarningsDie(DIE &Die) = 0; |
| |
| /// 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 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(AccelTable<DWARF5AccelTableStaticData> &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) = 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) = 0; |
| |
| /// Emit debug locations (.debug_loc, .debug_loclists) footer. |
| virtual void emitDwarfDebugLocListFooter(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; |
| |
| /// Dump the file to the disk. |
| virtual void finish() = 0; |
| |
| /// Emit the swift_ast section stored in \p Buffer. |
| virtual void emitSwiftAST(StringRef Buffer) = 0; |
| |
| /// Emit the swift reflection section stored in \p Buffer. |
| virtual void emitSwiftReflectionSection( |
| llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind, |
| StringRef Buffer, uint32_t Alignment, uint32_t Size) = 0; |
| |
| /// Returns underlying AsmPrinter. |
| virtual AsmPrinter &getAsmPrinter() const = 0; |
| }; |
| |
| class DwarfStreamer; |
| using UnitListTy = std::vector<std::unique_ptr<CompileUnit>>; |
| |
| /// This class represents DWARF information for source file |
| /// and its address map. |
| class DWARFFile { |
| public: |
| DWARFFile(StringRef Name, std::unique_ptr<DWARFContext> Dwarf, |
| std::unique_ptr<AddressesMap> Addresses, |
| const std::vector<std::string> &Warnings) |
| : FileName(Name), Dwarf(std::move(Dwarf)), |
| Addresses(std::move(Addresses)), Warnings(Warnings) {} |
| |
| /// The object file name. |
| StringRef FileName; |
| |
| /// The source DWARF information. |
| std::unique_ptr<DWARFContext> Dwarf; |
| |
| /// Helpful address information(list of valid address ranges, relocations). |
| std::unique_ptr<AddressesMap> Addresses; |
| |
| /// Warnings for this object file. |
| const std::vector<std::string> &Warnings; |
| }; |
| |
| typedef std::map<std::string, std::string> swiftInterfacesMap; |
| typedef std::map<std::string, std::string> objectPrefixMap; |
| |
| typedef function_ref<void(const DWARFUnit &Unit)> CompileUnitHandler; |
| |
| /// 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: |
| typedef std::function<void(const Twine &Warning, StringRef Context, |
| const DWARFDie *DIE)> |
| messageHandler; |
| DWARFLinker(messageHandler ErrorHandler, messageHandler WarningHandler, |
| std::function<StringRef(StringRef)> StringsTranslator) |
| : DwarfLinkerClientID(DwarfLinkerClient::Dsymutil), |
| StringsTranslator(StringsTranslator), ErrorHandler(ErrorHandler), |
| WarningHandler(WarningHandler) {} |
| |
| static std::unique_ptr<DWARFLinker> createLinker( |
| messageHandler ErrorHandler, messageHandler WarningHandler, |
| std::function<StringRef(StringRef)> StringsTranslator = nullptr) { |
| return std::make_unique<DWARFLinker>(ErrorHandler, WarningHandler, |
| StringsTranslator); |
| } |
| |
| /// Type of output file. |
| enum class OutputFileType { |
| Object, |
| Assembly, |
| }; |
| |
| /// The kind of accelerator tables we should emit. |
| enum class AccelTableKind : uint8_t { |
| Apple, ///< .apple_names, .apple_namespaces, .apple_types, .apple_objc. |
| Pub, ///< .debug_pubnames, .debug_pubtypes |
| DebugNames ///< .debug_names. |
| }; |
| typedef std::function<void(const DWARFFile &File)> inputVerificationHandler; |
| typedef std::function<ErrorOr<DWARFFile &>(StringRef ContainerName, |
| StringRef Path)> |
| objFileLoader; |
| |
| Error createEmitter(const Triple &TheTriple, OutputFileType FileType, |
| raw_pwrite_stream &OutFile); |
| |
| DwarfEmitter *getEmitter(); |
| |
| /// Add object file to be linked. Pre-load compile unit die. Call |
| /// \p OnCUDieLoaded for each compile unit die. If specified \p File |
| /// 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, objFileLoader Loader = nullptr, |
| CompileUnitHandler OnCUDieLoaded = [](const DWARFUnit &) {}); |
| |
| /// Link debug info for added objFiles. Object files are linked all together. |
| Error link(); |
| |
| /// A number of methods setting various linking options: |
| |
| /// Allows to generate log of linking process to the standard output. |
| void setVerbosity(bool Verbose) { Options.Verbose = Verbose; } |
| |
| /// Print statistics to standard output. |
| void setStatistics(bool Statistics) { Options.Statistics = Statistics; } |
| |
| /// Verify the input DWARF. |
| void setVerifyInputDWARF(bool Verify) { Options.VerifyInputDWARF = Verify; } |
| |
| /// Do not unique types according to ODR. |
| void setNoODR(bool NoODR) { Options.NoODR = NoODR; } |
| |
| /// Update index tables only(do not modify rest of DWARF). |
| void setUpdateIndexTablesOnly(bool Update) { Options.Update = Update; } |
| |
| /// Allow generating valid, but non-deterministic output. |
| void setAllowNonDeterministicOutput(bool) { /* Nothing to do. */ |
| } |
| |
| /// Set whether to keep the enclosing function for a static variable. |
| void setKeepFunctionForStatic(bool KeepFunctionForStatic) { |
| Options.KeepFunctionForStatic = KeepFunctionForStatic; |
| } |
| |
| /// Use specified number of threads for parallel files linking. |
| void setNumThreads(unsigned NumThreads) { Options.Threads = NumThreads; } |
| |
| /// Add kind of accelerator tables to be generated. |
| void addAccelTableKind(AccelTableKind Kind) { |
| assert(std::find(Options.AccelTables.begin(), Options.AccelTables.end(), |
| Kind) == Options.AccelTables.end()); |
| Options.AccelTables.emplace_back(Kind); |
| } |
| |
| /// Set prepend path for clang modules. |
| void setPrependPath(const std::string &Ppath) { Options.PrependPath = Ppath; } |
| |
| /// Set estimated objects files amount, for preliminary data allocation. |
| void setEstimatedObjfilesAmount(unsigned ObjFilesNum) { |
| ObjectContexts.reserve(ObjFilesNum); |
| } |
| |
| /// Set verification handler which would be used to report verification |
| /// errors. |
| void setInputVerificationHandler(inputVerificationHandler Handler) { |
| Options.InputVerificationHandler = Handler; |
| } |
| |
| /// Set map for Swift interfaces. |
| void setSwiftInterfacesMap(swiftInterfacesMap *Map) { |
| Options.ParseableSwiftInterfaces = Map; |
| } |
| |
| /// Set prefix map for objects. |
| void setObjectPrefixMap(objectPrefixMap *Map) { |
| Options.ObjectPrefixMap = Map; |
| } |
| |
| /// Set target DWARF version. |
| Error setTargetDWARFVersion(uint16_t TargetDWARFVersion) { |
| 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); |
| } |
| |
| /// Emit warnings as Dwarf compile units to leave a trail after linking. |
| bool emitPaperTrailWarnings(const DWARFFile &File, |
| OffsetsStringPool &StringPool); |
| |
| 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(); |
| File.Addresses->clear(); |
| } |
| }; |
| |
| /// 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, RangesTy &Ranges, |
| 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, |
| objFileLoader Loader, |
| CompileUnitHandler 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(objFileLoader Loader, const DWARFDie &CUDie, |
| const std::string &PCMFile, LinkContext &Context, |
| CompileUnitHandler OnCUDieLoaded, unsigned Indent = 0); |
| |
| /// Clone specified Clang module unit \p Unit. |
| Error cloneModuleUnit(LinkContext &Context, RefModuleUnit &Unit, |
| DeclContextTree &ODRContexts, |
| OffsetsStringPool &DebugStrPool, |
| OffsetsStringPool &DebugLineStrPool, |
| unsigned Indent = 0); |
| |
| unsigned shouldKeepDIE(AddressesMap &RelocMgr, RangesTy &Ranges, |
| 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 relocation adjustment value if live address is referenced. |
| 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, RangesTy &Ranges, |
| 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; |
| |
| /// 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) |
| : Linker(Linker), Emitter(Emitter), ObjFile(ObjFile), |
| DebugStrPool(DebugStrPool), DebugLineStrPool(DebugLineStrPool), |
| 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); |
| |
| 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; |
| |
| 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) 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) 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(const DWARFFile &, RangesTy &Ranges, |
| DWARFContext &, unsigned AddressSize); |
| |
| /// 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. |
| AccelTable<DWARF5AccelTableStaticData> DebugNames; |
| AccelTable<AppleAccelTableStaticOffsetData> AppleNames; |
| AccelTable<AppleAccelTableStaticOffsetData> AppleNamespaces; |
| AccelTable<AppleAccelTableStaticOffsetData> AppleObjc; |
| AccelTable<AppleAccelTableStaticTypeData> AppleTypes; |
| |
| /// Mapping the PCM filename to the DwoId. |
| StringMap<uint64_t> ClangModules; |
| |
| DwarfLinkerClient DwarfLinkerClientID; |
| |
| std::function<StringRef(StringRef)> StringsTranslator = nullptr; |
| |
| /// A unique ID that identifies each compile unit. |
| unsigned UniqueUnitID = 0; |
| |
| // error handler |
| messageHandler ErrorHandler = nullptr; |
| |
| // warning handler |
| messageHandler WarningHandler = nullptr; |
| |
| /// linking options |
| struct DWARFLinkerOptions { |
| /// DWARF version for the output. |
| 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 |
| inputVerificationHandler 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. |
| swiftInterfacesMap *ParseableSwiftInterfaces = nullptr; |
| |
| /// A list of remappings to apply to file paths. |
| objectPrefixMap *ObjectPrefixMap = nullptr; |
| } Options; |
| }; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_DWARFLINKER_DWARFLINKER_H |