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