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 "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"
28 /// The core of the Dsymutil Dwarf linking logic.
30 /// The link of the dwarf information from the object files will be
31 /// driven by DWARFLinker. DwarfLinkerForBinary reads DebugMap objects
32 /// and pass information to the DWARFLinker. DWARFLinker
33 /// optimizes DWARF taking into account valid relocations.
34 /// Finally, optimized DWARF is passed to DwarfLinkerForBinary through
35 /// DWARFEmitter interface.
36 class DwarfLinkerForBinary
{
38 DwarfLinkerForBinary(raw_fd_ostream
&OutFile
, BinaryHolder
&BinHolder
,
39 LinkOptions Options
, std::mutex
&ErrorHandlerMutex
)
40 : OutFile(OutFile
), BinHolder(BinHolder
), Options(std::move(Options
)),
41 ErrorHandlerMutex(ErrorHandlerMutex
) {}
43 /// Link the contents of the DebugMap.
44 bool link(const DebugMap
&);
46 void reportWarning(Twine Warning
, Twine Context
= {},
47 const DWARFDie
*DIE
= nullptr) const;
48 void reportError(Twine Error
, Twine Context
= {},
49 const DWARFDie
*DIE
= nullptr) const;
51 /// Returns true if input verification is enabled and verification errors were
53 bool InputVerificationFailed() const { return HasVerificationErrors
; }
55 /// Flags passed to DwarfLinker::lookForDIEsToKeep
57 TF_Keep
= 1 << 0, ///< Mark the traversed DIEs as kept.
58 TF_InFunctionScope
= 1 << 1, ///< Current scope is a function scope.
59 TF_DependencyWalk
= 1 << 2, ///< Walking the dependencies of a kept DIE.
60 TF_ParentWalk
= 1 << 3, ///< Walking up the parents of a kept DIE.
61 TF_ODR
= 1 << 4, ///< Use the ODR while keeping dependents.
62 TF_SkipPC
= 1 << 5, ///< Skip all location attributes.
67 /// Keeps track of relocations.
68 template <typename AddressesMapBase
>
69 class AddressManager
: public AddressesMapBase
{
74 const DebugMapObject::DebugMapEntry
*Mapping
;
76 ValidReloc(uint64_t Offset
, uint32_t Size
, uint64_t Addend
,
77 const DebugMapObject::DebugMapEntry
*Mapping
)
78 : Offset(Offset
), Size(Size
), Addend(Addend
), Mapping(Mapping
) {}
80 bool operator<(const ValidReloc
&RHS
) const {
81 return Offset
< RHS
.Offset
;
83 bool operator<(uint64_t RHS
) const { return Offset
< RHS
; }
86 const DwarfLinkerForBinary
&Linker
;
88 /// The valid relocations for the current DebugMapObject.
89 /// This vector is sorted by relocation offset.
91 std::vector
<ValidReloc
> ValidDebugInfoRelocs
;
92 std::vector
<ValidReloc
> ValidDebugAddrRelocs
;
95 StringRef SrcFileName
;
97 /// Returns list of valid relocations from \p Relocs,
98 /// between \p StartOffset and \p NextOffset.
100 /// \returns true if any relocation is found.
101 std::vector
<ValidReloc
>
102 getRelocations(const std::vector
<ValidReloc
> &Relocs
, uint64_t StartPos
,
105 /// Resolve specified relocation \p Reloc.
107 /// \returns resolved value.
108 uint64_t relocate(const ValidReloc
&Reloc
) const;
110 /// \returns value for the specified \p Reloc.
111 int64_t getRelocValue(const ValidReloc
&Reloc
);
113 /// Print contents of debug map entry for the specified \p Reloc.
114 void printReloc(const ValidReloc
&Reloc
);
117 AddressManager(DwarfLinkerForBinary
&Linker
, const object::ObjectFile
&Obj
,
118 const DebugMapObject
&DMO
)
119 : Linker(Linker
), SrcFileName(DMO
.getObjectFilename()) {
120 findValidRelocsInDebugSections(Obj
, DMO
);
122 ~AddressManager() override
{ clear(); }
124 bool hasValidRelocs() override
{
125 return !ValidDebugInfoRelocs
.empty() || !ValidDebugAddrRelocs
.empty();
128 /// \defgroup FindValidRelocations Translate debug map into a list
129 /// of relevant relocations
132 bool findValidRelocsInDebugSections(const object::ObjectFile
&Obj
,
133 const DebugMapObject
&DMO
);
135 bool findValidRelocs(const object::SectionRef
&Section
,
136 const object::ObjectFile
&Obj
,
137 const DebugMapObject
&DMO
,
138 std::vector
<ValidReloc
> &ValidRelocs
);
140 void findValidRelocsMachO(const object::SectionRef
&Section
,
141 const object::MachOObjectFile
&Obj
,
142 const DebugMapObject
&DMO
,
143 std::vector
<ValidReloc
> &ValidRelocs
);
146 /// Checks that there is a relocation in the \p Relocs array against a
147 /// debug map entry between \p StartOffset and \p NextOffset.
149 /// \returns relocation value if relocation exist, otherwise std::nullopt.
150 std::optional
<int64_t>
151 hasValidRelocationAt(const std::vector
<ValidReloc
> &Relocs
,
152 uint64_t StartOffset
, uint64_t EndOffset
);
154 std::optional
<int64_t> getExprOpAddressRelocAdjustment(
155 DWARFUnit
&U
, const DWARFExpression::Operation
&Op
,
156 uint64_t StartOffset
, uint64_t EndOffset
) override
;
158 std::optional
<int64_t>
159 getSubprogramRelocAdjustment(const DWARFDie
&DIE
) override
;
161 bool applyValidRelocs(MutableArrayRef
<char> Data
, uint64_t BaseOffset
,
162 bool IsLittleEndian
) override
;
164 void clear() override
{
165 ValidDebugInfoRelocs
.clear();
166 ValidDebugAddrRelocs
.clear();
171 /// \defgroup Helpers Various helper methods.
174 template <typename OutStreamer
>
175 bool createStreamer(const Triple
&TheTriple
,
176 typename
OutStreamer::OutputFileType FileType
,
177 std::unique_ptr
<OutStreamer
> &Streamer
,
178 raw_fd_ostream
&OutFile
);
180 /// Attempt to load a debug object from disk.
181 ErrorOr
<const object::ObjectFile
&> loadObject(const DebugMapObject
&Obj
,
182 const Triple
&triple
);
184 template <typename OutDWARFFile
, typename AddressesMap
>
185 ErrorOr
<std::unique_ptr
<OutDWARFFile
>> loadObject(const DebugMapObject
&Obj
,
186 const DebugMap
&DebugMap
,
187 remarks::RemarkLinker
&RL
);
189 void collectRelocationsToApplyToSwiftReflectionSections(
190 const object::SectionRef
&Section
, StringRef
&Contents
,
191 const llvm::object::MachOObjectFile
*MO
,
192 const std::vector
<uint64_t> &SectionToOffsetInDwarf
,
193 const llvm::dsymutil::DebugMapObject
*Obj
,
194 std::vector
<MachOUtils::DwarfRelocationApplicationInfo
>
195 &RelocationsToApply
) const;
197 Error
copySwiftInterfaces(StringRef Architecture
) const;
199 template <typename OutStreamer
>
200 void copySwiftReflectionMetadata(
201 const llvm::dsymutil::DebugMapObject
*Obj
, OutStreamer
*Streamer
,
202 std::vector
<uint64_t> &SectionToOffsetInDwarf
,
203 std::vector
<MachOUtils::DwarfRelocationApplicationInfo
>
204 &RelocationsToApply
);
206 template <typename Linker
, typename OutDwarfFile
, typename AddressMapBase
>
207 bool linkImpl(const DebugMap
&Map
,
208 typename
Linker::OutputFileType ObjectType
);
210 raw_fd_ostream
&OutFile
;
211 BinaryHolder
&BinHolder
;
213 std::mutex
&ErrorHandlerMutex
;
215 std::vector
<std::string
> EmptyWarnings
;
217 /// A list of all .swiftinterface files referenced by the debug
218 /// info, mapping Module name to path on disk. The entries need to
219 /// be uniqued and sorted and there are only few entries expected
220 /// per compile unit, which is why this is a std::map.
221 std::map
<std::string
, std::string
> ParseableSwiftInterfaces
;
223 bool ModuleCacheHintDisplayed
= false;
224 bool ArchiveHintDisplayed
= false;
225 bool HasVerificationErrors
= false;
228 } // end namespace dsymutil
229 } // end namespace llvm
231 #endif // LLVM_TOOLS_DSYMUTIL_DWARFLINKER_H