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 }; 74 75 const DwarfLinkerForBinary &Linker; 76 77 /// The valid relocations for the current DebugMapObject. 78 /// This vector is sorted by relocation offset. 79 std::vector<ValidReloc> ValidRelocs; 80 81 /// Index into ValidRelocs of the next relocation to consider. As we walk 82 /// the DIEs in acsending file offset and as ValidRelocs is sorted by file 83 /// offset, keeping this index up to date is all we have to do to have a 84 /// cheap lookup during the root DIE selection and during DIE cloning. 85 unsigned NextValidReloc = 0; 86 87 RangesTy AddressRanges; 88 89 public: AddressManager(DwarfLinkerForBinary & Linker,const object::ObjectFile & Obj,const DebugMapObject & DMO)90 AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj, 91 const DebugMapObject &DMO) 92 : Linker(Linker) { 93 findValidRelocsInDebugInfo(Obj, DMO); 94 95 // Iterate over the debug map entries and put all the ones that are 96 // functions (because they have a size) into the Ranges map. This map is 97 // very similar to the FunctionRanges that are stored in each unit, with 2 98 // notable differences: 99 // 100 // 1. Obviously this one is global, while the other ones are per-unit. 101 // 102 // 2. This one contains not only the functions described in the DIE 103 // tree, but also the ones that are only in the debug map. 104 // 105 // The latter information is required to reproduce dsymutil's logic while 106 // linking line tables. The cases where this information matters look like 107 // bugs that need to be investigated, but for now we need to reproduce 108 // dsymutil's behavior. 109 // FIXME: Once we understood exactly if that information is needed, 110 // maybe totally remove this (or try to use it to do a real 111 // -gline-tables-only on Darwin. 112 for (const auto &Entry : DMO.symbols()) { 113 const auto &Mapping = Entry.getValue(); 114 if (Mapping.Size && Mapping.ObjectAddress) 115 AddressRanges[*Mapping.ObjectAddress] = ObjFileAddressRange( 116 *Mapping.ObjectAddress + Mapping.Size, 117 int64_t(Mapping.BinaryAddress) - *Mapping.ObjectAddress); 118 } 119 } ~AddressManager()120 virtual ~AddressManager() override { clear(); } 121 areRelocationsResolved()122 virtual bool areRelocationsResolved() const override { return true; } 123 124 bool hasValidRelocs(bool ResetRelocsPtr = true) override { 125 if (ResetRelocsPtr) 126 NextValidReloc = 0; 127 return !ValidRelocs.empty(); 128 } 129 130 /// \defgroup FindValidRelocations Translate debug map into a list 131 /// of relevant relocations 132 /// 133 /// @{ 134 bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj, 135 const DebugMapObject &DMO); 136 137 bool findValidRelocs(const object::SectionRef &Section, 138 const object::ObjectFile &Obj, 139 const DebugMapObject &DMO); 140 141 void findValidRelocsMachO(const object::SectionRef &Section, 142 const object::MachOObjectFile &Obj, 143 const DebugMapObject &DMO); 144 /// @} 145 146 bool hasValidRelocationAt(uint64_t StartOffset, uint64_t EndOffset, 147 CompileUnit::DIEInfo &Info) override; 148 149 bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset, 150 bool IsLittleEndian) override; 151 getValidAddressRanges()152 RangesTy &getValidAddressRanges() override { return AddressRanges; } 153 clear()154 void clear() override { 155 AddressRanges.clear(); 156 ValidRelocs.clear(); 157 NextValidReloc = 0; 158 } 159 }; 160 161 private: 162 /// \defgroup Helpers Various helper methods. 163 /// 164 /// @{ 165 bool createStreamer(const Triple &TheTriple, raw_fd_ostream &OutFile); 166 167 /// Attempt to load a debug object from disk. 168 ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj, 169 const Triple &triple); 170 ErrorOr<DWARFFile &> loadObject(const DebugMapObject &Obj, 171 const DebugMap &DebugMap, 172 remarks::RemarkLinker &RL); 173 174 raw_fd_ostream &OutFile; 175 BinaryHolder &BinHolder; 176 LinkOptions Options; 177 std::unique_ptr<DwarfStreamer> Streamer; 178 std::vector<std::unique_ptr<DWARFFile>> ObjectsForLinking; 179 std::vector<std::unique_ptr<DWARFContext>> ContextForLinking; 180 std::vector<std::unique_ptr<AddressManager>> AddressMapForLinking; 181 std::vector<std::string> EmptyWarnings; 182 183 /// A list of all .swiftinterface files referenced by the debug 184 /// info, mapping Module name to path on disk. The entries need to 185 /// be uniqued and sorted and there are only few entries expected 186 /// per compile unit, which is why this is a std::map. 187 std::map<std::string, std::string> ParseableSwiftInterfaces; 188 189 bool ModuleCacheHintDisplayed = false; 190 bool ArchiveHintDisplayed = false; 191 }; 192 193 } // end namespace dsymutil 194 } // end namespace llvm 195 196 #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H 197