//===- tools/dsymutil/DwarfLinkerForBinary.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_TOOLS_DSYMUTIL_DWARFLINKER_H #define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H #include "BinaryHolder.h" #include "DebugMap.h" #include "LinkUtils.h" #include "MachOUtils.h" #include "RelocationMap.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Remarks/RemarkFormat.h" #include "llvm/Remarks/RemarkLinker.h" #include #include namespace llvm { using namespace dwarf_linker; namespace dsymutil { /// DwarfLinkerForBinaryRelocationMap contains the logic to handle the /// relocations and to store them inside an associated RelocationMap. class DwarfLinkerForBinaryRelocationMap { public: void init(DWARFContext &Context); bool isInitialized() { return StoredValidDebugInfoRelocsMap.getMemorySize() != 0; } void addValidRelocs(RelocationMap &RM); void updateAndSaveValidRelocs(bool IsDWARF5, std::vector &InRelocs, uint64_t UnitOffset, int64_t LinkedOffset); void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset); /// Map compilation unit offset to the valid relocations to store /// @{ DenseMap> StoredValidDebugInfoRelocsMap; DenseMap> StoredValidDebugAddrRelocsMap; /// @} DwarfLinkerForBinaryRelocationMap() = default; }; struct ObjectWithRelocMap { ObjectWithRelocMap( std::unique_ptr Object, std::shared_ptr OutRelocs) : Object(std::move(Object)), OutRelocs(OutRelocs) {} std::unique_ptr Object; std::shared_ptr OutRelocs; }; /// The core of the Dsymutil Dwarf linking logic. /// /// The link of the dwarf information from the object files will be /// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects /// and pass information to the DWARFLinker. DWARFLinker /// optimizes DWARF taking into account valid relocations. /// Finally, optimized DWARF is passed to DwarfLinkerForBinary through /// DWARFEmitter interface. class DwarfLinkerForBinary { public: DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, LinkOptions Options, std::mutex &ErrorHandlerMutex) : OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)), ErrorHandlerMutex(ErrorHandlerMutex) {} /// Link the contents of the DebugMap. bool link(const DebugMap &); void reportWarning(Twine Warning, Twine Context = {}, const DWARFDie *DIE = nullptr) const; void reportError(Twine Error, Twine Context = {}, const DWARFDie *DIE = nullptr) const; /// Returns true if input verification is enabled and verification errors were /// found. bool InputVerificationFailed() const { return HasVerificationErrors; } /// 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. }; private: /// Keeps track of relocations. class AddressManager : public dwarf_linker::AddressesMap { const DwarfLinkerForBinary &Linker; /// The valid relocations for the current DebugMapObject. /// These vectors are sorted by relocation offset. /// { std::vector ValidDebugInfoRelocs; std::vector ValidDebugAddrRelocs; /// } StringRef SrcFileName; uint8_t DebugMapObjectType; std::shared_ptr DwarfLinkerRelocMap; std::optional LibInstallName; /// Returns list of valid relocations from \p Relocs, /// between \p StartOffset and \p NextOffset. /// /// \returns true if any relocation is found. std::vector getRelocations(const std::vector &Relocs, uint64_t StartPos, uint64_t EndPos); /// Resolve specified relocation \p Reloc. /// /// \returns resolved value. uint64_t relocate(const ValidReloc &Reloc) const; /// \returns value for the specified \p Reloc. int64_t getRelocValue(const ValidReloc &Reloc); /// Print contents of debug map entry for the specified \p Reloc. void printReloc(const ValidReloc &Reloc); public: AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj, const DebugMapObject &DMO, std::shared_ptr DLBRM) : Linker(Linker), SrcFileName(DMO.getObjectFilename()), DebugMapObjectType(MachO::N_OSO), DwarfLinkerRelocMap(DLBRM) { if (DMO.getRelocationMap().has_value()) { DebugMapObjectType = MachO::N_LIB; LibInstallName.emplace(DMO.getInstallName().value()); const RelocationMap &RM = DMO.getRelocationMap().value(); for (const auto &Reloc : RM.relocations()) { const auto *DebugMapEntry = DMO.lookupSymbol(Reloc.SymbolName); if (!DebugMapEntry) continue; std::optional ObjAddress; ObjAddress.emplace(DebugMapEntry->getValue().ObjectAddress.value()); ValidDebugInfoRelocs.emplace_back( Reloc.Offset, Reloc.Size, Reloc.Addend, Reloc.SymbolName, SymbolMapping(ObjAddress, DebugMapEntry->getValue().BinaryAddress, DebugMapEntry->getValue().Size)); // FIXME: Support relocations debug_addr. } } else { findValidRelocsInDebugSections(Obj, DMO); } } ~AddressManager() override { clear(); } bool hasValidRelocs() override { return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty(); } /// \defgroup FindValidRelocations Translate debug map into a list /// of relevant relocations /// /// @{ bool findValidRelocsInDebugSections(const object::ObjectFile &Obj, const DebugMapObject &DMO); bool findValidRelocs(const object::SectionRef &Section, const object::ObjectFile &Obj, const DebugMapObject &DMO, std::vector &ValidRelocs); void findValidRelocsMachO(const object::SectionRef &Section, const object::MachOObjectFile &Obj, const DebugMapObject &DMO, std::vector &ValidRelocs); /// @} /// Checks that there is a relocation in the \p Relocs array against a /// debug map entry between \p StartOffset and \p NextOffset. /// Print debug output if \p Verbose is set. /// /// \returns relocation value if relocation exist, otherwise std::nullopt. std::optional hasValidRelocationAt(const std::vector &Relocs, uint64_t StartOffset, uint64_t EndOffset, bool Verbose); std::optional getExprOpAddressRelocAdjustment( DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset, uint64_t EndOffset, bool Verbose) override; std::optional getSubprogramRelocAdjustment(const DWARFDie &DIE, bool Verbose) override; std::optional getLibraryInstallName() override; bool applyValidRelocs(MutableArrayRef Data, uint64_t BaseOffset, bool IsLittleEndian) override; bool needToSaveValidRelocs() override { return true; } void updateAndSaveValidRelocs(bool IsDWARF5, uint64_t OriginalUnitOffset, int64_t LinkedOffset, uint64_t StartOffset, uint64_t EndOffset) override; void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) override; void clear() override { ValidDebugInfoRelocs.clear(); ValidDebugAddrRelocs.clear(); } }; private: /// \defgroup Helpers Various helper methods. /// /// @{ template bool createStreamer(const Triple &TheTriple, typename OutStreamer::OutputFileType FileType, std::unique_ptr &Streamer, raw_fd_ostream &OutFile); /// Attempt to load a debug object from disk. ErrorOr loadObject(const DebugMapObject &Obj, const Triple &triple); ErrorOr> loadObject(const DebugMapObject &Obj, const DebugMap &DebugMap, remarks::RemarkLinker &RL, std::shared_ptr DLBRM); void collectRelocationsToApplyToSwiftReflectionSections( const object::SectionRef &Section, StringRef &Contents, const llvm::object::MachOObjectFile *MO, const std::vector &SectionToOffsetInDwarf, const llvm::dsymutil::DebugMapObject *Obj, std::vector &RelocationsToApply) const; Error copySwiftInterfaces(StringRef Architecture) const; void copySwiftReflectionMetadata( const llvm::dsymutil::DebugMapObject *Obj, classic::DwarfStreamer *Streamer, std::vector &SectionToOffsetInDwarf, std::vector &RelocationsToApply); template bool linkImpl(const DebugMap &Map, typename Linker::OutputFileType ObjectType); Error emitRelocations(const DebugMap &DM, std::vector &ObjectsForLinking); raw_fd_ostream &OutFile; BinaryHolder &BinHolder; LinkOptions Options; std::mutex &ErrorHandlerMutex; std::vector EmptyWarnings; /// 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. std::map ParseableSwiftInterfaces; bool ModuleCacheHintDisplayed = false; bool ArchiveHintDisplayed = false; bool HasVerificationErrors = false; }; } // end namespace dsymutil } // end namespace llvm #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H