1 //===- tools/dsymutil/DwarfLinkerForBinary.h --------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
10 #define LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H
12 #include "BinaryHolder.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"
30 /// DwarfLinkerForBinaryRelocationMap contains the logic to handle the
31 /// relocations and to store them inside an associated RelocationMap.
32 class DwarfLinkerForBinaryRelocationMap
{
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
51 DenseMap
<uint64_t, std::vector
<ValidReloc
>> StoredValidDebugInfoRelocsMap
;
52 DenseMap
<uint64_t, std::vector
<ValidReloc
>> StoredValidDebugAddrRelocsMap
;
55 DwarfLinkerForBinaryRelocationMap() = default;
58 template <typename OutDwarfFile
> struct 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.
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
{
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
92 bool InputVerificationFailed() const { return HasVerificationErrors
; }
94 /// Flags passed to DwarfLinker::lookForDIEsToKeep
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.
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.
115 std::vector
<ValidReloc
> ValidDebugInfoRelocs
;
116 std::vector
<ValidReloc
> ValidDebugAddrRelocs
;
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
,
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
);
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
);
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.
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
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
);
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();
232 /// \defgroup Helpers Various helper methods.
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(
274 std::vector
<ObjectWithRelocMap
<OutDwarfFile
>> &ObjectsForLinking
);
276 raw_fd_ostream
&OutFile
;
277 BinaryHolder
&BinHolder
;
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