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