1 //===- tools/dsymutil/DwarfLinkerForBinary.h --------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H 10 #define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H 11 12 #include "BinaryHolder.h" 13 #include "DebugMap.h" 14 #include "LinkUtils.h" 15 #include "MachOUtils.h" 16 #include "llvm/DWARFLinker/DWARFLinker.h" 17 #include "llvm/DWARFLinker/DWARFLinkerCompileUnit.h" 18 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h" 19 #include "llvm/DWARFLinker/DWARFStreamer.h" 20 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 21 #include "llvm/Remarks/RemarkFormat.h" 22 #include "llvm/Remarks/RemarkLinker.h" 23 24 namespace llvm { 25 namespace dsymutil { 26 27 /// The core of the Dsymutil Dwarf linking logic. 28 /// 29 /// The link of the dwarf information from the object files will be 30 /// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects 31 /// and pass information to the DWARFLinker. DWARFLinker 32 /// optimizes DWARF taking into account valid relocations. 33 /// Finally, optimized DWARF is passed to DwarfLinkerForBinary through 34 /// DWARFEmitter interface. 35 class DwarfLinkerForBinary { 36 public: DwarfLinkerForBinary(raw_fd_ostream & OutFile,BinaryHolder & BinHolder,LinkOptions Options)37 DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder, 38 LinkOptions Options) 39 : OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)) {} 40 41 /// Link the contents of the DebugMap. 42 bool link(const DebugMap &); 43 44 void reportWarning(const Twine &Warning, StringRef Context, 45 const DWARFDie *DIE = nullptr) const; 46 47 /// Flags passed to DwarfLinker::lookForDIEsToKeep 48 enum TraversalFlags { 49 TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept. 50 TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope. 51 TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE. 52 TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE. 53 TF_ODR = 1 << 4, ///< Use the ODR while keeping dependents. 54 TF_SkipPC = 1 << 5, ///< Skip all location attributes. 55 }; 56 57 private: 58 59 /// Keeps track of relocations. 60 class AddressManager : public AddressesMap { 61 struct ValidReloc { 62 uint64_t Offset; 63 uint32_t Size; 64 uint64_t Addend; 65 const DebugMapObject::DebugMapEntry *Mapping; 66 ValidRelocValidReloc67 ValidReloc(uint64_t Offset, uint32_t Size, uint64_t Addend, 68 const DebugMapObject::DebugMapEntry *Mapping) 69 : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {} 70 71 bool operator<(const ValidReloc &RHS) const { 72 return Offset < RHS.Offset; 73 } 74 bool operator<(uint64_t RHS) const { return Offset < RHS; } 75 }; 76 77 const DwarfLinkerForBinary &Linker; 78 79 /// The valid relocations for the current DebugMapObject. 80 /// This vector is sorted by relocation offset. 81 /// { 82 std::vector<ValidReloc> ValidDebugInfoRelocs; 83 std::vector<ValidReloc> ValidDebugAddrRelocs; 84 /// } 85 86 RangesTy AddressRanges; 87 88 StringRef SrcFileName; 89 90 /// Returns list of valid relocations from \p Relocs, 91 /// between \p StartOffset and \p NextOffset. 92 /// 93 /// \returns true if any relocation is found. 94 std::vector<ValidReloc> 95 getRelocations(const std::vector<ValidReloc> &Relocs, uint64_t StartPos, 96 uint64_t EndPos); 97 98 /// Resolve specified relocation \p Reloc. 99 /// 100 /// \returns resolved value. 101 uint64_t relocate(const ValidReloc &Reloc) const; 102 103 /// Fill \p Info with address information for the specified \p Reloc. 104 void fillDieInfo(const ValidReloc &Reloc, CompileUnit::DIEInfo &Info); 105 106 /// Print contents of debug map entry for the specified \p Reloc. 107 void printReloc(const ValidReloc &Reloc); 108 109 public: AddressManager(DwarfLinkerForBinary & Linker,const object::ObjectFile & Obj,const DebugMapObject & DMO)110 AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj, 111 const DebugMapObject &DMO) 112 : Linker(Linker), SrcFileName(DMO.getObjectFilename()) { 113 findValidRelocsInDebugSections(Obj, DMO); 114 115 // Iterate over the debug map entries and put all the ones that are 116 // functions (because they have a size) into the Ranges map. This map is 117 // very similar to the FunctionRanges that are stored in each unit, with 2 118 // notable differences: 119 // 120 // 1. Obviously this one is global, while the other ones are per-unit. 121 // 122 // 2. This one contains not only the functions described in the DIE 123 // tree, but also the ones that are only in the debug map. 124 // 125 // The latter information is required to reproduce dsymutil's logic while 126 // linking line tables. The cases where this information matters look like 127 // bugs that need to be investigated, but for now we need to reproduce 128 // dsymutil's behavior. 129 // FIXME: Once we understood exactly if that information is needed, 130 // maybe totally remove this (or try to use it to do a real 131 // -gline-tables-only on Darwin. 132 for (const auto &Entry : DMO.symbols()) { 133 const auto &Mapping = Entry.getValue(); 134 if (Mapping.Size && Mapping.ObjectAddress) 135 AddressRanges.insert( 136 {*Mapping.ObjectAddress, *Mapping.ObjectAddress + Mapping.Size}, 137 int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress); 138 } 139 } ~AddressManager()140 ~AddressManager() override { clear(); } 141 hasValidRelocs()142 bool hasValidRelocs() override { 143 return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty(); 144 } 145 146 /// \defgroup FindValidRelocations Translate debug map into a list 147 /// of relevant relocations 148 /// 149 /// @{ 150 bool findValidRelocsInDebugSections(const object::ObjectFile &Obj, 151 const DebugMapObject &DMO); 152 153 bool findValidRelocs(const object::SectionRef &Section, 154 const object::ObjectFile &Obj, 155 const DebugMapObject &DMO, 156 std::vector<ValidReloc> &ValidRelocs); 157 158 void findValidRelocsMachO(const object::SectionRef &Section, 159 const object::MachOObjectFile &Obj, 160 const DebugMapObject &DMO, 161 std::vector<ValidReloc> &ValidRelocs); 162 /// @} 163 164 /// Checks that there is a relocation in the \p Relocs array against a 165 /// debug map entry between \p StartOffset and \p NextOffset. 166 /// 167 /// \returns true and sets Info.InDebugMap if it is the case. 168 bool hasValidRelocationAt(const std::vector<ValidReloc> &Relocs, 169 uint64_t StartOffset, uint64_t EndOffset, 170 CompileUnit::DIEInfo &Info); 171 172 bool isLiveVariable(const DWARFDie &DIE, 173 CompileUnit::DIEInfo &Info) override; 174 bool isLiveSubprogram(const DWARFDie &DIE, 175 CompileUnit::DIEInfo &Info) override; 176 177 bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset, 178 bool IsLittleEndian) override; 179 180 llvm::Expected<uint64_t> relocateIndexedAddr(uint64_t StartOffset, 181 uint64_t EndOffset) override; 182 getValidAddressRanges()183 RangesTy &getValidAddressRanges() override { return AddressRanges; } 184 clear()185 void clear() override { 186 AddressRanges.clear(); 187 ValidDebugInfoRelocs.clear(); 188 ValidDebugAddrRelocs.clear(); 189 } 190 }; 191 192 private: 193 /// \defgroup Helpers Various helper methods. 194 /// 195 /// @{ 196 bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile); 197 198 /// Attempt to load a debug object from disk. 199 ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj, 200 const Triple &triple); 201 ErrorOr<DWARFFile &> loadObject(const DebugMapObject &Obj, 202 const DebugMap &DebugMap, 203 remarks::RemarkLinker &RL); 204 205 void collectRelocationsToApplyToSwiftReflectionSections( 206 const object::SectionRef &Section, StringRef &Contents, 207 const llvm::object::MachOObjectFile *MO, 208 const std::vector<uint64_t> &SectionToOffsetInDwarf, 209 const llvm::dsymutil::DebugMapObject *Obj, 210 std::vector<MachOUtils::DwarfRelocationApplicationInfo> 211 &RelocationsToApply) const; 212 213 void copySwiftReflectionMetadata( 214 const llvm::dsymutil::DebugMapObject *Obj, DwarfStreamer *Streamer, 215 std::vector<uint64_t> &SectionToOffsetInDwarf, 216 std::vector<MachOUtils::DwarfRelocationApplicationInfo> 217 &RelocationsToApply); 218 219 raw_fd_ostream &OutFile; 220 BinaryHolder &BinHolder; 221 LinkOptions Options; 222 std::unique_ptr<DwarfStreamer> Streamer; 223 std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking; 224 std::vector<std::unique_ptr<DWARFContext>> ContextForLinking; 225 std::vector<std::unique_ptr<AddressManager>> AddressMapForLinking; 226 std::vector<std::string> EmptyWarnings; 227 228 /// A list of all .swiftinterface files referenced by the debug 229 /// info, mapping Module name to path on disk. The entries need to 230 /// be uniqued and sorted and there are only few entries expected 231 /// per compile unit, which is why this is a std::map. 232 std::map<std::string, std::string> ParseableSwiftInterfaces; 233 234 bool ModuleCacheHintDisplayed = false; 235 bool ArchiveHintDisplayed = false; 236 }; 237 238 } // end namespace dsymutil 239 } // end namespace llvm 240 241 #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H 242