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