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