xref: /llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.h (revision 0ed8194256c6c96875ed9dd102d15ee8a9260fec)
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 "RelocationMap.h"
17 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
18 #include "llvm/Remarks/RemarkFormat.h"
19 #include "llvm/Remarks/RemarkLinker.h"
20 #include <mutex>
21 #include <optional>
22 
23 namespace llvm {
24 using namespace dwarf_linker;
25 
26 namespace dsymutil {
27 
28 /// DwarfLinkerForBinaryRelocationMap contains the logic to handle the
29 /// relocations and to store them inside an associated RelocationMap.
30 class DwarfLinkerForBinaryRelocationMap {
31 public:
32   void init(DWARFContext &Context);
33 
isInitialized()34   bool isInitialized() {
35     return StoredValidDebugInfoRelocsMap.getMemorySize() != 0;
36   }
37 
38   void addValidRelocs(RelocationMap &RM);
39 
40   void updateAndSaveValidRelocs(bool IsDWARF5,
41                                 std::vector<ValidReloc> &InRelocs,
42                                 uint64_t UnitOffset, int64_t LinkedOffset);
43 
44   void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
45                                        uint64_t OutputUnitOffset);
46 
47   /// Map compilation unit offset to the valid relocations to store
48   /// @{
49   DenseMap<uint64_t, std::vector<ValidReloc>> StoredValidDebugInfoRelocsMap;
50   DenseMap<uint64_t, std::vector<ValidReloc>> StoredValidDebugAddrRelocsMap;
51   /// @}
52 
53   DwarfLinkerForBinaryRelocationMap() = default;
54 };
55 
56 struct ObjectWithRelocMap {
ObjectWithRelocMapObjectWithRelocMap57   ObjectWithRelocMap(
58       std::unique_ptr<DWARFFile> Object,
59       std::shared_ptr<DwarfLinkerForBinaryRelocationMap> OutRelocs)
60       : Object(std::move(Object)), OutRelocs(OutRelocs) {}
61   std::unique_ptr<DWARFFile> Object;
62   std::shared_ptr<DwarfLinkerForBinaryRelocationMap> OutRelocs;
63 };
64 
65 /// The core of the Dsymutil Dwarf linking logic.
66 ///
67 /// The link of the dwarf information from the object files will be
68 /// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects
69 /// and pass information to the DWARFLinker. DWARFLinker
70 /// optimizes DWARF taking into account valid relocations.
71 /// Finally, optimized DWARF is passed to DwarfLinkerForBinary through
72 /// DWARFEmitter interface.
73 class DwarfLinkerForBinary {
74 public:
DwarfLinkerForBinary(raw_fd_ostream & OutFile,BinaryHolder & BinHolder,LinkOptions Options,std::mutex & ErrorHandlerMutex)75   DwarfLinkerForBinary(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
76                        LinkOptions Options, std::mutex &ErrorHandlerMutex)
77       : OutFile(OutFile), BinHolder(BinHolder), Options(std::move(Options)),
78         ErrorHandlerMutex(ErrorHandlerMutex) {}
79 
80   /// Link the contents of the DebugMap.
81   bool link(const DebugMap &);
82 
83   void reportWarning(Twine Warning, Twine Context = {},
84                      const DWARFDie *DIE = nullptr) const;
85   void reportError(Twine Error, Twine Context = {},
86                    const DWARFDie *DIE = nullptr) const;
87 
88   /// Returns true if input verification is enabled and verification errors were
89   /// found.
InputVerificationFailed()90   bool InputVerificationFailed() const { return HasVerificationErrors; }
91 
92   /// Flags passed to DwarfLinker::lookForDIEsToKeep
93   enum TraversalFlags {
94     TF_Keep = 1 << 0,            ///< Mark the traversed DIEs as kept.
95     TF_InFunctionScope = 1 << 1, ///< Current scope is a function scope.
96     TF_DependencyWalk = 1 << 2,  ///< Walking the dependencies of a kept DIE.
97     TF_ParentWalk = 1 << 3,      ///< Walking up the parents of a kept DIE.
98     TF_ODR = 1 << 4,             ///< Use the ODR while keeping dependents.
99     TF_SkipPC = 1 << 5,          ///< Skip all location attributes.
100   };
101 
102 private:
103 
104   /// Keeps track of relocations.
105   class AddressManager : public dwarf_linker::AddressesMap {
106 
107     const DwarfLinkerForBinary &Linker;
108 
109     /// The valid relocations for the current DebugMapObject.
110     /// These vectors are sorted by relocation offset.
111     /// {
112     std::vector<ValidReloc> ValidDebugInfoRelocs;
113     std::vector<ValidReloc> ValidDebugAddrRelocs;
114     /// }
115 
116     StringRef SrcFileName;
117 
118     uint8_t DebugMapObjectType;
119 
120     std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DwarfLinkerRelocMap;
121 
122     std::optional<std::string> LibInstallName;
123 
124     /// Returns list of valid relocations from \p Relocs,
125     /// between \p StartOffset and \p NextOffset.
126     ///
127     /// \returns true if any relocation is found.
128     std::vector<ValidReloc>
129     getRelocations(const std::vector<ValidReloc> &Relocs, uint64_t StartPos,
130                    uint64_t EndPos);
131 
132     /// Resolve specified relocation \p Reloc.
133     ///
134     /// \returns resolved value.
135     uint64_t relocate(const ValidReloc &Reloc) const;
136 
137     /// \returns value for the specified \p Reloc.
138     int64_t getRelocValue(const ValidReloc &Reloc);
139 
140     /// Print contents of debug map entry for the specified \p Reloc.
141     void printReloc(const ValidReloc &Reloc);
142 
143   public:
AddressManager(DwarfLinkerForBinary & Linker,const object::ObjectFile & Obj,const DebugMapObject & DMO,std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM)144     AddressManager(DwarfLinkerForBinary &Linker, const object::ObjectFile &Obj,
145                    const DebugMapObject &DMO,
146                    std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM)
147         : Linker(Linker), SrcFileName(DMO.getObjectFilename()),
148           DebugMapObjectType(MachO::N_OSO), DwarfLinkerRelocMap(DLBRM) {
149       if (DMO.getRelocationMap().has_value()) {
150         DebugMapObjectType = MachO::N_LIB;
151         LibInstallName.emplace(DMO.getInstallName().value());
152         const RelocationMap &RM = DMO.getRelocationMap().value();
153         for (const auto &Reloc : RM.relocations()) {
154           const auto *DebugMapEntry = DMO.lookupSymbol(Reloc.SymbolName);
155           if (!DebugMapEntry)
156             continue;
157           std::optional<uint64_t> ObjAddress;
158           ObjAddress.emplace(DebugMapEntry->getValue().ObjectAddress.value());
159           ValidDebugInfoRelocs.emplace_back(
160               Reloc.Offset, Reloc.Size, Reloc.Addend, Reloc.SymbolName,
161               SymbolMapping(ObjAddress, DebugMapEntry->getValue().BinaryAddress,
162                             DebugMapEntry->getValue().Size));
163           // FIXME: Support relocations debug_addr.
164         }
165       } else {
166         findValidRelocsInDebugSections(Obj, DMO);
167       }
168     }
~AddressManager()169     ~AddressManager() override { clear(); }
170 
hasValidRelocs()171     bool hasValidRelocs() override {
172       return !ValidDebugInfoRelocs.empty() || !ValidDebugAddrRelocs.empty();
173     }
174 
175     /// \defgroup FindValidRelocations Translate debug map into a list
176     /// of relevant relocations
177     ///
178     /// @{
179     bool findValidRelocsInDebugSections(const object::ObjectFile &Obj,
180                                         const DebugMapObject &DMO);
181 
182     bool findValidRelocs(const object::SectionRef &Section,
183                          const object::ObjectFile &Obj,
184                          const DebugMapObject &DMO,
185                          std::vector<ValidReloc> &ValidRelocs);
186 
187     void findValidRelocsMachO(const object::SectionRef &Section,
188                               const object::MachOObjectFile &Obj,
189                               const DebugMapObject &DMO,
190                               std::vector<ValidReloc> &ValidRelocs);
191     /// @}
192 
193     /// Checks that there is a relocation in the \p Relocs array against a
194     /// debug map entry between \p StartOffset and \p NextOffset.
195     /// Print debug output if \p Verbose is set.
196     ///
197     /// \returns relocation value if relocation exist, otherwise std::nullopt.
198     std::optional<int64_t>
199     hasValidRelocationAt(const std::vector<ValidReloc> &Relocs,
200                          uint64_t StartOffset, uint64_t EndOffset,
201                          bool Verbose);
202 
203     std::optional<int64_t> getExprOpAddressRelocAdjustment(
204         DWARFUnit &U, const DWARFExpression::Operation &Op,
205         uint64_t StartOffset, uint64_t EndOffset, bool Verbose) override;
206 
207     std::optional<int64_t> getSubprogramRelocAdjustment(const DWARFDie &DIE,
208                                                         bool Verbose) override;
209 
210     std::optional<StringRef> getLibraryInstallName() override;
211 
212     bool applyValidRelocs(MutableArrayRef<char> Data, uint64_t BaseOffset,
213                           bool IsLittleEndian) override;
214 
needToSaveValidRelocs()215     bool needToSaveValidRelocs() override { return true; }
216 
217     void updateAndSaveValidRelocs(bool IsDWARF5, uint64_t OriginalUnitOffset,
218                                   int64_t LinkedOffset, uint64_t StartOffset,
219                                   uint64_t EndOffset) override;
220 
221     void updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,
222                                          uint64_t OutputUnitOffset) override;
223 
clear()224     void clear() override {
225       ValidDebugInfoRelocs.clear();
226       ValidDebugAddrRelocs.clear();
227     }
228   };
229 
230 private:
231   /// \defgroup Helpers Various helper methods.
232   ///
233   /// @{
234   template <typename OutStreamer>
235   bool createStreamer(const Triple &TheTriple,
236                       typename OutStreamer::OutputFileType FileType,
237                       std::unique_ptr<OutStreamer> &Streamer,
238                       raw_fd_ostream &OutFile);
239 
240   /// Attempt to load a debug object from disk.
241   ErrorOr<const object::ObjectFile &> loadObject(const DebugMapObject &Obj,
242                                                  const Triple &triple);
243   ErrorOr<std::unique_ptr<dwarf_linker::DWARFFile>>
244   loadObject(const DebugMapObject &Obj, const DebugMap &DebugMap,
245              remarks::RemarkLinker &RL,
246              std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM);
247 
248   void collectRelocationsToApplyToSwiftReflectionSections(
249       const object::SectionRef &Section, StringRef &Contents,
250       const llvm::object::MachOObjectFile *MO,
251       const std::vector<uint64_t> &SectionToOffsetInDwarf,
252       const llvm::dsymutil::DebugMapObject *Obj,
253       std::vector<MachOUtils::DwarfRelocationApplicationInfo>
254           &RelocationsToApply) const;
255 
256   Error copySwiftInterfaces(StringRef Architecture) const;
257 
258   void copySwiftReflectionMetadata(
259       const llvm::dsymutil::DebugMapObject *Obj,
260       classic::DwarfStreamer *Streamer,
261       std::vector<uint64_t> &SectionToOffsetInDwarf,
262       std::vector<MachOUtils::DwarfRelocationApplicationInfo>
263           &RelocationsToApply);
264 
265   template <typename Linker>
266   bool linkImpl(const DebugMap &Map,
267                 typename Linker::OutputFileType ObjectType);
268 
269   Error emitRelocations(const DebugMap &DM,
270                         std::vector<ObjectWithRelocMap> &ObjectsForLinking);
271 
272   raw_fd_ostream &OutFile;
273   BinaryHolder &BinHolder;
274   LinkOptions Options;
275   std::mutex &ErrorHandlerMutex;
276 
277   std::vector<std::string> EmptyWarnings;
278 
279   /// A list of all .swiftinterface files referenced by the debug
280   /// info, mapping Module name to path on disk. The entries need to
281   /// be uniqued and sorted and there are only few entries expected
282   /// per compile unit, which is why this is a std::map.
283   std::map<std::string, std::string> ParseableSwiftInterfaces;
284 
285   bool ModuleCacheHintDisplayed = false;
286   bool ArchiveHintDisplayed = false;
287   bool HasVerificationErrors = false;
288 };
289 
290 } // end namespace dsymutil
291 } // end namespace llvm
292 
293 #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
294