1 //===- tools/dsymutil/DwarfLinkerForBinary.cpp ----------------------------===//
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 #include "DwarfLinkerForBinary.h"
10 #include "BinaryHolder.h"
12 #include "MachOUtils.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/BitVector.h"
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/DenseMapInfo.h"
18 #include "llvm/ADT/DenseSet.h"
19 #include "llvm/ADT/FoldingSet.h"
20 #include "llvm/ADT/Hashing.h"
21 #include "llvm/ADT/PointerIntPair.h"
22 #include "llvm/ADT/STLExtras.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/ADT/Twine.h"
26 #include "llvm/BinaryFormat/Dwarf.h"
27 #include "llvm/BinaryFormat/MachO.h"
28 #include "llvm/BinaryFormat/Swift.h"
29 #include "llvm/CodeGen/AccelTable.h"
30 #include "llvm/CodeGen/AsmPrinter.h"
31 #include "llvm/CodeGen/DIE.h"
32 #include "llvm/CodeGen/NonRelocatableStringpool.h"
33 #include "llvm/Config/config.h"
34 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
35 #include "llvm/DWARFLinkerParallel/DWARFLinker.h"
36 #include "llvm/DebugInfo/DIContext.h"
37 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
38 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
39 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
40 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
41 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
42 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
43 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
44 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
45 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
46 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
47 #include "llvm/MC/MCAsmBackend.h"
48 #include "llvm/MC/MCAsmInfo.h"
49 #include "llvm/MC/MCCodeEmitter.h"
50 #include "llvm/MC/MCContext.h"
51 #include "llvm/MC/MCDwarf.h"
52 #include "llvm/MC/MCInstrInfo.h"
53 #include "llvm/MC/MCObjectFileInfo.h"
54 #include "llvm/MC/MCObjectWriter.h"
55 #include "llvm/MC/MCRegisterInfo.h"
56 #include "llvm/MC/MCSection.h"
57 #include "llvm/MC/MCStreamer.h"
58 #include "llvm/MC/MCSubtargetInfo.h"
59 #include "llvm/MC/MCTargetOptions.h"
60 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
61 #include "llvm/MC/TargetRegistry.h"
62 #include "llvm/Object/MachO.h"
63 #include "llvm/Object/ObjectFile.h"
64 #include "llvm/Object/SymbolicFile.h"
65 #include "llvm/Support/Allocator.h"
66 #include "llvm/Support/Casting.h"
67 #include "llvm/Support/Compiler.h"
68 #include "llvm/Support/DJB.h"
69 #include "llvm/Support/DataExtractor.h"
70 #include "llvm/Support/Error.h"
71 #include "llvm/Support/ErrorHandling.h"
72 #include "llvm/Support/ErrorOr.h"
73 #include "llvm/Support/FileSystem.h"
74 #include "llvm/Support/Format.h"
75 #include "llvm/Support/LEB128.h"
76 #include "llvm/Support/MathExtras.h"
77 #include "llvm/Support/MemoryBuffer.h"
78 #include "llvm/Support/Path.h"
79 #include "llvm/Support/ThreadPool.h"
80 #include "llvm/Support/ToolOutputFile.h"
81 #include "llvm/Support/WithColor.h"
82 #include "llvm/Support/raw_ostream.h"
83 #include "llvm/Target/TargetMachine.h"
84 #include "llvm/Target/TargetOptions.h"
85 #include "llvm/TargetParser/Triple.h"
98 #include <system_error>
105 static mc::RegisterMCTargetOptionsFlags MOF
;
109 static void dumpDIE(const DWARFDie
*DIE
, bool Verbose
) {
110 if (!DIE
|| !Verbose
)
113 DIDumpOptions DumpOpts
;
114 DumpOpts
.ChildRecurseDepth
= 0;
115 DumpOpts
.Verbose
= Verbose
;
117 WithColor::note() << " in DIE:\n";
118 DIE
->dump(errs(), 6 /* Indent */, DumpOpts
);
121 /// Report a warning to the user, optionally including information about a
122 /// specific \p DIE related to the warning.
123 void DwarfLinkerForBinary::reportWarning(Twine Warning
, Twine Context
,
124 const DWARFDie
*DIE
) const {
125 // FIXME: implement warning logging which does not block other threads.
126 if (ErrorHandlerMutex
.try_lock()) {
127 warn(Warning
, Context
);
128 dumpDIE(DIE
, Options
.Verbose
);
129 ErrorHandlerMutex
.unlock();
133 void DwarfLinkerForBinary::reportError(Twine Error
, Twine Context
,
134 const DWARFDie
*DIE
) const {
135 // FIXME: implement error logging which does not block other threads.
136 if (ErrorHandlerMutex
.try_lock()) {
137 error(Error
, Context
);
138 dumpDIE(DIE
, Options
.Verbose
);
139 ErrorHandlerMutex
.unlock();
143 ErrorOr
<const object::ObjectFile
&>
144 DwarfLinkerForBinary::loadObject(const DebugMapObject
&Obj
,
145 const Triple
&Triple
) {
147 BinHolder
.getObjectEntry(Obj
.getObjectFilename(), Obj
.getTimestamp());
149 auto Err
= ObjectEntry
.takeError();
150 reportWarning(Twine(Obj
.getObjectFilename()) + ": " +
151 toString(std::move(Err
)),
152 Obj
.getObjectFilename());
153 return errorToErrorCode(std::move(Err
));
156 auto Object
= ObjectEntry
->getObject(Triple
);
158 auto Err
= Object
.takeError();
159 reportWarning(Twine(Obj
.getObjectFilename()) + ": " +
160 toString(std::move(Err
)),
161 Obj
.getObjectFilename());
162 return errorToErrorCode(std::move(Err
));
168 static Error
remarksErrorHandler(const DebugMapObject
&DMO
,
169 DwarfLinkerForBinary
&Linker
,
170 std::unique_ptr
<FileError
> FE
) {
171 bool IsArchive
= DMO
.getObjectFilename().endswith(")");
172 // Don't report errors for missing remark files from static
175 return Error(std::move(FE
));
177 std::string Message
= FE
->message();
178 Error E
= FE
->takeError();
179 Error NewE
= handleErrors(std::move(E
), [&](std::unique_ptr
<ECError
> EC
) {
180 if (EC
->convertToErrorCode() != std::errc::no_such_file_or_directory
)
181 return Error(std::move(EC
));
183 Linker
.reportWarning(Message
, DMO
.getObjectFilename());
184 return Error(Error::success());
188 return Error::success();
190 return createFileError(FE
->getFileName(), std::move(NewE
));
192 template <typename OutDwarfFile
, typename AddressMap
>
193 Error
DwarfLinkerForBinary::emitRelocations(
195 std::vector
<ObjectWithRelocMap
<OutDwarfFile
>> &ObjectsForLinking
) {
196 // Return early if the "Resources" directory is not being written to.
197 if (!Options
.ResourceDir
)
198 return Error::success();
200 RelocationMap
RM(DM
.getTriple(), DM
.getBinaryPath());
201 for (auto &Obj
: ObjectsForLinking
) {
202 if (!Obj
.OutRelocs
->isInitialized())
204 Obj
.OutRelocs
->addValidRelocs(RM
);
207 SmallString
<128> InputPath
;
208 SmallString
<128> Path
;
209 // Create the "Relocations" directory in the "Resources" directory, and
210 // create an architecture-specific directory in the "Relocations" directory.
211 StringRef ArchName
= Triple::getArchName(RM
.getTriple().getArch(),
212 RM
.getTriple().getSubArch());
213 sys::path::append(Path
, *Options
.ResourceDir
, "Relocations", ArchName
);
214 if (std::error_code EC
= sys::fs::create_directories(Path
.str(), true,
215 sys::fs::perms::all_all
))
216 return errorCodeToError(EC
);
218 // Append the file name.
219 sys::path::append(Path
, sys::path::filename(DM
.getBinaryPath()));
223 raw_fd_ostream
OS(Path
.str(), EC
, sys::fs::OF_Text
);
225 return errorCodeToError(EC
);
228 return Error::success();
231 static Error
emitRemarks(const LinkOptions
&Options
, StringRef BinaryPath
,
232 StringRef ArchName
, const remarks::RemarkLinker
&RL
) {
233 // Make sure we don't create the directories and the file if there is nothing
236 return Error::success();
238 SmallString
<128> InputPath
;
239 SmallString
<128> Path
;
240 // Create the "Remarks" directory in the "Resources" directory.
241 sys::path::append(Path
, *Options
.ResourceDir
, "Remarks");
242 if (std::error_code EC
= sys::fs::create_directories(Path
.str(), true,
243 sys::fs::perms::all_all
))
244 return errorCodeToError(EC
);
246 // Append the file name.
247 // For fat binaries, also append a dash and the architecture name.
248 sys::path::append(Path
, sys::path::filename(BinaryPath
));
249 if (Options
.NumDebugMaps
> 1) {
250 // More than one debug map means we have a fat binary.
256 raw_fd_ostream
OS(Options
.NoOutput
? "-" : Path
.str(), EC
,
257 Options
.RemarksFormat
== remarks::Format::Bitstream
261 return errorCodeToError(EC
);
263 if (Error E
= RL
.serialize(OS
, Options
.RemarksFormat
))
266 return Error::success();
269 template <typename OutDWARFFile
, typename AddressesMap
>
270 ErrorOr
<std::unique_ptr
<OutDWARFFile
>> DwarfLinkerForBinary::loadObject(
271 const DebugMapObject
&Obj
, const DebugMap
&DebugMap
,
272 remarks::RemarkLinker
&RL
,
273 std::shared_ptr
<DwarfLinkerForBinaryRelocationMap
> DLBRM
) {
274 auto ErrorOrObj
= loadObject(Obj
, DebugMap
.getTriple());
275 std::unique_ptr
<OutDWARFFile
> Res
;
278 auto Context
= DWARFContext::create(
279 *ErrorOrObj
, DWARFContext::ProcessDebugRelocations::Process
, nullptr,
282 handleAllErrors(std::move(Err
), [&](ErrorInfoBase
&Info
) {
283 reportError(Info
.message());
287 handleAllErrors(std::move(Warning
), [&](ErrorInfoBase
&Info
) {
288 reportWarning(Info
.message());
291 DLBRM
->init(*Context
);
292 Res
= std::make_unique
<OutDWARFFile
>(
293 Obj
.getObjectFilename(), std::move(Context
),
294 std::make_unique
<AddressesMap
>(*this, *ErrorOrObj
, Obj
, DLBRM
),
295 [&](StringRef FileName
) { BinHolder
.eraseObjectEntry(FileName
); });
297 Error E
= RL
.link(*ErrorOrObj
);
298 if (Error NewE
= handleErrors(
299 std::move(E
), [&](std::unique_ptr
<FileError
> EC
) -> Error
{
300 return remarksErrorHandler(Obj
, *this, std::move(EC
));
302 return errorToErrorCode(std::move(NewE
));
304 return std::move(Res
);
307 return ErrorOrObj
.getError();
310 static bool binaryHasStrippableSwiftReflectionSections(
311 const DebugMap
&Map
, const LinkOptions
&Options
, BinaryHolder
&BinHolder
) {
312 // If the input binary has strippable swift5 reflection sections, there is no
313 // need to copy them to the .dSYM. Only copy them for binaries where the
314 // linker omitted the reflection metadata.
315 if (!Map
.getBinaryPath().empty() &&
316 Options
.FileType
== DWARFLinker::OutputFileType::Object
) {
318 auto ObjectEntry
= BinHolder
.getObjectEntry(Map
.getBinaryPath());
319 // If ObjectEntry or Object has an error, no binary exists, therefore no
320 // reflection sections exist.
322 // Any errors will be diagnosed later in the main loop, ignore them here.
323 llvm::consumeError(ObjectEntry
.takeError());
328 ObjectEntry
->getObjectAs
<object::MachOObjectFile
>(Map
.getTriple());
330 // Any errors will be diagnosed later in the main loop, ignore them here.
331 llvm::consumeError(Object
.takeError());
335 for (auto &Section
: Object
->sections()) {
336 llvm::Expected
<llvm::StringRef
> NameOrErr
=
337 Object
->getSectionName(Section
.getRawDataRefImpl());
339 llvm::consumeError(NameOrErr
.takeError());
342 NameOrErr
->consume_back("__TEXT");
343 auto ReflectionSectionKind
=
344 Object
->mapReflectionSectionNameToEnumValue(*NameOrErr
);
345 if (Object
->isReflectionSectionStrippable(ReflectionSectionKind
)) {
353 /// Calculate the start of the strippable swift reflection sections in Dwarf.
354 /// Note that there's an assumption that the reflection sections will appear
355 /// in alphabetic order.
356 static std::vector
<uint64_t>
357 calculateStartOfStrippableReflectionSections(const DebugMap
&Map
) {
358 using llvm::binaryformat::Swift5ReflectionSectionKind
;
359 uint64_t AssocTySize
= 0;
360 uint64_t FieldMdSize
= 0;
361 for (const auto &Obj
: Map
.objects()) {
363 llvm::object::ObjectFile::createObjectFile(Obj
->getObjectFilename());
365 llvm::consumeError(OF
.takeError());
368 if (auto *MO
= dyn_cast
<llvm::object::MachOObjectFile
>(OF
->getBinary())) {
369 for (auto &Section
: MO
->sections()) {
370 llvm::Expected
<llvm::StringRef
> NameOrErr
=
371 MO
->getSectionName(Section
.getRawDataRefImpl());
373 llvm::consumeError(NameOrErr
.takeError());
376 NameOrErr
->consume_back("__TEXT");
377 auto ReflSectionKind
=
378 MO
->mapReflectionSectionNameToEnumValue(*NameOrErr
);
379 switch (ReflSectionKind
) {
380 case Swift5ReflectionSectionKind::assocty
:
381 AssocTySize
+= Section
.getSize();
383 case Swift5ReflectionSectionKind::fieldmd
:
384 FieldMdSize
+= Section
.getSize();
392 // Initialize the vector with enough space to fit every reflection section
394 std::vector
<uint64_t> SectionToOffset(Swift5ReflectionSectionKind::last
, 0);
395 SectionToOffset
[Swift5ReflectionSectionKind::assocty
] = 0;
396 SectionToOffset
[Swift5ReflectionSectionKind::fieldmd
] =
397 llvm::alignTo(AssocTySize
, 4);
398 SectionToOffset
[Swift5ReflectionSectionKind::reflstr
] = llvm::alignTo(
399 SectionToOffset
[Swift5ReflectionSectionKind::fieldmd
] + FieldMdSize
, 4);
401 return SectionToOffset
;
404 void DwarfLinkerForBinary::collectRelocationsToApplyToSwiftReflectionSections(
405 const object::SectionRef
&Section
, StringRef
&Contents
,
406 const llvm::object::MachOObjectFile
*MO
,
407 const std::vector
<uint64_t> &SectionToOffsetInDwarf
,
408 const llvm::dsymutil::DebugMapObject
*Obj
,
409 std::vector
<MachOUtils::DwarfRelocationApplicationInfo
> &RelocationsToApply
)
411 for (auto It
= Section
.relocation_begin(); It
!= Section
.relocation_end();
413 object::DataRefImpl RelocDataRef
= It
->getRawDataRefImpl();
414 MachO::any_relocation_info MachOReloc
= MO
->getRelocation(RelocDataRef
);
416 if (!object::MachOObjectFile::isMachOPairedReloc(
417 MO
->getAnyRelocationType(MachOReloc
), MO
->getArch())) {
419 "Unimplemented relocation type in strippable reflection section ",
420 Obj
->getObjectFilename());
424 auto CalculateAddressOfSymbolInDwarfSegment
=
425 [&]() -> std::optional
<int64_t> {
426 auto Symbol
= It
->getSymbol();
427 auto SymbolAbsoluteAddress
= Symbol
->getAddress();
428 if (!SymbolAbsoluteAddress
)
430 auto Section
= Symbol
->getSection();
432 llvm::consumeError(Section
.takeError());
436 if ((*Section
)->getObject()->section_end() == *Section
)
439 auto SectionStart
= (*Section
)->getAddress();
440 auto SymbolAddressInSection
= *SymbolAbsoluteAddress
- SectionStart
;
441 auto SectionName
= (*Section
)->getName();
444 auto ReflSectionKind
=
445 MO
->mapReflectionSectionNameToEnumValue(*SectionName
);
447 int64_t SectionStartInLinkedBinary
=
448 SectionToOffsetInDwarf
[ReflSectionKind
];
450 auto Addr
= SectionStartInLinkedBinary
+ SymbolAddressInSection
;
454 // The first symbol should always be in the section we're currently
456 auto FirstSymbolAddress
= CalculateAddressOfSymbolInDwarfSegment();
459 bool ShouldSubtractDwarfVM
= false;
460 // For the second symbol there are two possibilities.
461 std::optional
<int64_t> SecondSymbolAddress
;
462 auto Sym
= It
->getSymbol();
463 if (Sym
!= MO
->symbol_end()) {
464 Expected
<StringRef
> SymbolName
= Sym
->getName();
466 if (const auto *Mapping
= Obj
->lookupSymbol(*SymbolName
)) {
467 // First possibility: the symbol exists in the binary, and exists in a
468 // non-strippable section (for example, typeref, or __TEXT,__const),
469 // in which case we look up its address in the binary, which dsymutil
470 // will copy verbatim.
471 SecondSymbolAddress
= Mapping
->getValue().BinaryAddress
;
472 // Since the symbols live in different segments, we have to substract
473 // the start of the Dwarf's vmaddr so the value calculated points to
474 // the correct place.
475 ShouldSubtractDwarfVM
= true;
480 if (!SecondSymbolAddress
) {
481 // Second possibility, this symbol is not present in the main binary, and
482 // must be in one of the strippable sections (for example, reflstr).
483 // Calculate its address in the same way as we did the first one.
484 SecondSymbolAddress
= CalculateAddressOfSymbolInDwarfSegment();
487 if (!FirstSymbolAddress
|| !SecondSymbolAddress
)
490 auto SectionName
= Section
.getName();
495 memcpy(&Addend
, Contents
.data() + It
->getOffset(), sizeof(int32_t));
496 int32_t Value
= (*SecondSymbolAddress
+ Addend
) - *FirstSymbolAddress
;
497 auto ReflSectionKind
=
498 MO
->mapReflectionSectionNameToEnumValue(*SectionName
);
499 uint64_t AddressFromDwarfVM
=
500 SectionToOffsetInDwarf
[ReflSectionKind
] + It
->getOffset();
501 RelocationsToApply
.emplace_back(AddressFromDwarfVM
, Value
,
502 ShouldSubtractDwarfVM
);
506 Error
DwarfLinkerForBinary::copySwiftInterfaces(StringRef Architecture
) const {
508 SmallString
<128> InputPath
;
509 SmallString
<128> Path
;
510 sys::path::append(Path
, *Options
.ResourceDir
, "Swift", Architecture
);
511 if ((EC
= sys::fs::create_directories(Path
.str(), true,
512 sys::fs::perms::all_all
)))
513 return make_error
<StringError
>(
514 "cannot create directory: " + toString(errorCodeToError(EC
)), EC
);
515 unsigned BaseLength
= Path
.size();
517 for (auto &I
: ParseableSwiftInterfaces
) {
518 StringRef ModuleName
= I
.first
;
519 StringRef InterfaceFile
= I
.second
;
520 if (!Options
.PrependPath
.empty()) {
522 sys::path::append(InputPath
, Options
.PrependPath
, InterfaceFile
);
523 InterfaceFile
= InputPath
;
525 sys::path::append(Path
, ModuleName
);
526 Path
.append(".swiftinterface");
528 outs() << "copy parseable Swift interface " << InterfaceFile
<< " -> "
529 << Path
.str() << '\n';
531 // copy_file attempts an APFS clone first, so this should be cheap.
532 if ((EC
= sys::fs::copy_file(InterfaceFile
, Path
.str())))
533 reportWarning(Twine("cannot copy parseable Swift interface ") +
534 InterfaceFile
+ ": " + toString(errorCodeToError(EC
)));
535 Path
.resize(BaseLength
);
537 return Error::success();
540 template <typename OutStreamer
>
541 void DwarfLinkerForBinary::copySwiftReflectionMetadata(
542 const llvm::dsymutil::DebugMapObject
*Obj
, OutStreamer
*Streamer
,
543 std::vector
<uint64_t> &SectionToOffsetInDwarf
,
544 std::vector
<MachOUtils::DwarfRelocationApplicationInfo
>
545 &RelocationsToApply
) {
546 using binaryformat::Swift5ReflectionSectionKind
;
548 llvm::object::ObjectFile::createObjectFile(Obj
->getObjectFilename());
550 llvm::consumeError(OF
.takeError());
553 if (auto *MO
= dyn_cast
<llvm::object::MachOObjectFile
>(OF
->getBinary())) {
554 // Collect the swift reflection sections before emitting them. This is
555 // done so we control the order they're emitted.
556 std::array
<std::optional
<object::SectionRef
>,
557 Swift5ReflectionSectionKind::last
+ 1>
559 for (auto &Section
: MO
->sections()) {
560 llvm::Expected
<llvm::StringRef
> NameOrErr
=
561 MO
->getSectionName(Section
.getRawDataRefImpl());
563 llvm::consumeError(NameOrErr
.takeError());
566 NameOrErr
->consume_back("__TEXT");
567 auto ReflSectionKind
=
568 MO
->mapReflectionSectionNameToEnumValue(*NameOrErr
);
569 if (MO
->isReflectionSectionStrippable(ReflSectionKind
))
570 SwiftSections
[ReflSectionKind
] = Section
;
572 // Make sure we copy the sections in alphabetic order.
573 auto SectionKindsToEmit
= {Swift5ReflectionSectionKind::assocty
,
574 Swift5ReflectionSectionKind::fieldmd
,
575 Swift5ReflectionSectionKind::reflstr
};
576 for (auto SectionKind
: SectionKindsToEmit
) {
577 if (!SwiftSections
[SectionKind
])
579 auto &Section
= *SwiftSections
[SectionKind
];
580 llvm::Expected
<llvm::StringRef
> SectionContents
= Section
.getContents();
581 if (!SectionContents
)
584 llvm::cast
<llvm::object::MachOObjectFile
>(Section
.getObject());
585 collectRelocationsToApplyToSwiftReflectionSections(
586 Section
, *SectionContents
, MO
, SectionToOffsetInDwarf
, Obj
,
588 // Update the section start with the current section's contribution, so
589 // the next section we copy from a different .o file points to the correct
591 SectionToOffsetInDwarf
[SectionKind
] += Section
.getSize();
592 Streamer
->emitSwiftReflectionSection(SectionKind
, *SectionContents
,
593 Section
.getAlignment().value(),
599 bool DwarfLinkerForBinary::link(const DebugMap
&Map
) {
600 if (Options
.DWARFLinkerType
== DsymutilDWARFLinkerType::LLVM
) {
601 dwarflinker_parallel::DWARFLinker::OutputFileType DWARFLinkerOutputType
;
602 switch (Options
.FileType
) {
603 case DWARFLinker::OutputFileType::Object
:
604 DWARFLinkerOutputType
=
605 dwarflinker_parallel::DWARFLinker::OutputFileType::Object
;
608 case DWARFLinker::OutputFileType::Assembly
:
609 DWARFLinkerOutputType
=
610 dwarflinker_parallel::DWARFLinker::OutputFileType::Assembly
;
614 return linkImpl
<dwarflinker_parallel::DWARFLinker
,
615 dwarflinker_parallel::DWARFFile
,
616 AddressManager
<dwarflinker_parallel::AddressesMap
>>(
617 Map
, DWARFLinkerOutputType
);
620 return linkImpl
<DWARFLinker
, DWARFFile
, AddressManager
<AddressesMap
>>(
621 Map
, Options
.FileType
);
624 template <typename Linker
>
625 void setAcceleratorTables(Linker
&GeneralLinker
,
626 DsymutilAccelTableKind TableKind
,
627 uint16_t MaxDWARFVersion
) {
629 case DsymutilAccelTableKind::Apple
:
630 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::Apple
);
632 case DsymutilAccelTableKind::Dwarf
:
633 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::DebugNames
);
635 case DsymutilAccelTableKind::Pub
:
636 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::Pub
);
638 case DsymutilAccelTableKind::Default
:
639 if (MaxDWARFVersion
>= 5)
640 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::DebugNames
);
642 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::Apple
);
644 case DsymutilAccelTableKind::None
:
649 llvm_unreachable("All cases handled above!");
652 template <typename Linker
, typename OutDwarfFile
, typename AddressMap
>
653 bool DwarfLinkerForBinary::linkImpl(
654 const DebugMap
&Map
, typename
Linker::OutputFileType ObjectType
) {
656 std::vector
<ObjectWithRelocMap
<OutDwarfFile
>> ObjectsForLinking
;
658 DebugMap
DebugMap(Map
.getTriple(), Map
.getBinaryPath());
660 std::function
<StringRef(StringRef
)> TranslationLambda
= [&](StringRef Input
) {
661 assert(Options
.Translator
);
662 return Options
.Translator(Input
);
665 std::unique_ptr
<Linker
> GeneralLinker
= Linker::createLinker(
666 [&](const Twine
&Error
, StringRef Context
, const DWARFDie
*DIE
) {
667 reportError(Error
, Context
, DIE
);
669 [&](const Twine
&Warning
, StringRef Context
, const DWARFDie
*DIE
) {
670 reportWarning(Warning
, Context
, DIE
);
672 Options
.Translator
? TranslationLambda
: nullptr);
674 if (!Options
.NoOutput
) {
675 if (Error Err
= GeneralLinker
->createEmitter(Map
.getTriple(), ObjectType
,
677 handleAllErrors(std::move(Err
), [&](const ErrorInfoBase
&EI
) {
678 reportError(EI
.message(), "dwarf streamer init");
684 remarks::RemarkLinker RL
;
685 if (!Options
.RemarksPrependPath
.empty())
686 RL
.setExternalFilePrependPath(Options
.RemarksPrependPath
);
687 RL
.setKeepAllRemarks(Options
.RemarksKeepAll
);
688 GeneralLinker
->setObjectPrefixMap(&Options
.ObjectPrefixMap
);
690 GeneralLinker
->setVerbosity(Options
.Verbose
);
691 GeneralLinker
->setStatistics(Options
.Statistics
);
692 GeneralLinker
->setVerifyInputDWARF(Options
.VerifyInputDWARF
);
693 GeneralLinker
->setNoODR(Options
.NoODR
);
694 GeneralLinker
->setUpdateIndexTablesOnly(Options
.Update
);
695 GeneralLinker
->setNumThreads(Options
.Threads
);
696 GeneralLinker
->setPrependPath(Options
.PrependPath
);
697 GeneralLinker
->setKeepFunctionForStatic(Options
.KeepFunctionForStatic
);
698 GeneralLinker
->setInputVerificationHandler([&](const OutDwarfFile
&File
, llvm::StringRef Output
) {
699 std::lock_guard
<std::mutex
> Guard(ErrorHandlerMutex
);
702 warn("input verification failed", File
.FileName
);
703 HasVerificationErrors
= true;
705 auto Loader
= [&](StringRef ContainerName
,
706 StringRef Path
) -> ErrorOr
<OutDwarfFile
&> {
707 auto &Obj
= DebugMap
.addDebugMapObject(
708 Path
, sys::TimePoint
<std::chrono::seconds
>(), MachO::N_OSO
);
710 auto DLBRelocMap
= std::make_shared
<DwarfLinkerForBinaryRelocationMap
>();
711 if (ErrorOr
<std::unique_ptr
<OutDwarfFile
>> ErrorOrObj
=
712 loadObject
<OutDwarfFile
, AddressMap
>(Obj
, DebugMap
, RL
,
714 ObjectsForLinking
.emplace_back(std::move(*ErrorOrObj
), DLBRelocMap
);
715 return *ObjectsForLinking
.back().Object
;
717 // Try and emit more helpful warnings by applying some heuristics.
718 StringRef ObjFile
= ContainerName
;
719 bool IsClangModule
= sys::path::extension(Path
).equals(".pcm");
720 bool IsArchive
= ObjFile
.endswith(")");
723 StringRef ModuleCacheDir
= sys::path::parent_path(Path
);
724 if (sys::fs::exists(ModuleCacheDir
)) {
725 // If the module's parent directory exists, we assume that the
726 // module cache has expired and was pruned by clang. A more
727 // adventurous dsymutil would invoke clang to rebuild the module
729 if (!ModuleCacheHintDisplayed
) {
731 << "The clang module cache may have expired since "
732 "this object file was built. Rebuilding the "
733 "object file will rebuild the module cache.\n";
734 ModuleCacheHintDisplayed
= true;
736 } else if (IsArchive
) {
737 // If the module cache directory doesn't exist at all and the
738 // object file is inside a static library, we assume that the
739 // static library was built on a different machine. We don't want
740 // to discourage module debugging for convenience libraries within
742 if (!ArchiveHintDisplayed
) {
744 << "Linking a static library that was built with "
745 "-gmodules, but the module cache was not found. "
746 "Redistributable static libraries should never be "
747 "built with module debugging enabled. The debug "
748 "experience will be degraded due to incomplete "
749 "debug information.\n";
750 ArchiveHintDisplayed
= true;
755 return ErrorOrObj
.getError();
758 llvm_unreachable("Unhandled DebugMap object");
760 GeneralLinker
->setSwiftInterfacesMap(&ParseableSwiftInterfaces
);
761 bool ReflectionSectionsPresentInBinary
= false;
762 // If there is no output specified, no point in checking the binary for swift5
763 // reflection sections.
764 if (!Options
.NoOutput
) {
765 ReflectionSectionsPresentInBinary
=
766 binaryHasStrippableSwiftReflectionSections(Map
, Options
, BinHolder
);
769 std::vector
<MachOUtils::DwarfRelocationApplicationInfo
> RelocationsToApply
;
770 if (!Options
.NoOutput
&& !ReflectionSectionsPresentInBinary
) {
771 auto SectionToOffsetInDwarf
=
772 calculateStartOfStrippableReflectionSections(Map
);
773 for (const auto &Obj
: Map
.objects())
774 copySwiftReflectionMetadata(Obj
.get(), GeneralLinker
->getEmitter(),
775 SectionToOffsetInDwarf
, RelocationsToApply
);
778 uint16_t MaxDWARFVersion
= 0;
779 std::function
<void(const DWARFUnit
&Unit
)> OnCUDieLoaded
=
780 [&MaxDWARFVersion
](const DWARFUnit
&Unit
) {
781 MaxDWARFVersion
= std::max(Unit
.getVersion(), MaxDWARFVersion
);
784 for (const auto &Obj
: Map
.objects()) {
785 // N_AST objects (swiftmodule files) should get dumped directly into the
786 // appropriate DWARF section.
787 if (Obj
->getType() == MachO::N_AST
) {
789 outs() << "DEBUG MAP OBJECT: " << Obj
->getObjectFilename() << "\n";
791 StringRef File
= Obj
->getObjectFilename();
792 auto ErrorOrMem
= MemoryBuffer::getFile(File
);
794 reportWarning("Could not open '" + File
+ "'");
797 sys::fs::file_status Stat
;
798 if (auto Err
= sys::fs::status(File
, Stat
)) {
799 reportWarning(Err
.message());
802 if (!Options
.NoTimestamp
) {
803 // The modification can have sub-second precision so we need to cast
804 // away the extra precision that's not present in the debug map.
805 auto ModificationTime
=
806 std::chrono::time_point_cast
<std::chrono::seconds
>(
807 Stat
.getLastModificationTime());
808 if (Obj
->getTimestamp() != sys::TimePoint
<>() &&
809 ModificationTime
!= Obj
->getTimestamp()) {
810 // Not using the helper here as we can easily stream TimePoint<>.
812 << File
<< ": timestamp mismatch between swift interface file ("
813 << sys::TimePoint
<>(ModificationTime
) << ") and debug map ("
814 << sys::TimePoint
<>(Obj
->getTimestamp()) << ")\n";
819 // Copy the module into the .swift_ast section.
820 if (!Options
.NoOutput
)
821 GeneralLinker
->getEmitter()->emitSwiftAST((*ErrorOrMem
)->getBuffer());
826 auto DLBRelocMap
= std::make_shared
<DwarfLinkerForBinaryRelocationMap
>();
827 if (ErrorOr
<std::unique_ptr
<OutDwarfFile
>> ErrorOrObj
=
828 loadObject
<OutDwarfFile
, AddressMap
>(*Obj
, Map
, RL
, DLBRelocMap
)) {
829 ObjectsForLinking
.emplace_back(std::move(*ErrorOrObj
), DLBRelocMap
);
830 GeneralLinker
->addObjectFile(*ObjectsForLinking
.back().Object
, Loader
,
833 ObjectsForLinking
.push_back(
834 {std::make_unique
<OutDwarfFile
>(Obj
->getObjectFilename(), nullptr,
837 GeneralLinker
->addObjectFile(*ObjectsForLinking
.back().Object
);
841 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
842 if (MaxDWARFVersion
== 0)
845 if (Error E
= GeneralLinker
->setTargetDWARFVersion(MaxDWARFVersion
))
846 return error(toString(std::move(E
)));
848 setAcceleratorTables
<Linker
>(*GeneralLinker
, Options
.TheAccelTableKind
,
851 // link debug info for loaded object files.
852 if (Error E
= GeneralLinker
->link())
853 return error(toString(std::move(E
)));
855 StringRef ArchName
= Map
.getTriple().getArchName();
856 if (Error E
= emitRemarks(Options
, Map
.getBinaryPath(), ArchName
, RL
))
857 return error(toString(std::move(E
)));
859 if (Options
.NoOutput
)
863 emitRelocations
<OutDwarfFile
, AddressMap
>(Map
, ObjectsForLinking
))
864 return error(toString(std::move(E
)));
866 if (Options
.ResourceDir
&& !ParseableSwiftInterfaces
.empty()) {
867 StringRef ArchName
= Triple::getArchTypeName(Map
.getTriple().getArch());
868 if (auto E
= copySwiftInterfaces(ArchName
))
869 return error(toString(std::move(E
)));
872 if (Map
.getTriple().isOSDarwin() && !Map
.getBinaryPath().empty() &&
873 ObjectType
== Linker::OutputFileType::Object
)
874 return MachOUtils::generateDsymCompanion(
875 Options
.VFS
, Map
, Options
.Translator
,
876 *GeneralLinker
->getEmitter()->getAsmPrinter().OutStreamer
, OutFile
,
879 GeneralLinker
->getEmitter()->finish();
883 /// Iterate over the relocations of the given \p Section and
884 /// store the ones that correspond to debug map entries into the
885 /// ValidRelocs array.
886 template <typename AddressesMapBase
>
887 void DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::
888 findValidRelocsMachO(const object::SectionRef
&Section
,
889 const object::MachOObjectFile
&Obj
,
890 const DebugMapObject
&DMO
,
891 std::vector
<ValidReloc
> &ValidRelocs
) {
892 Expected
<StringRef
> ContentsOrErr
= Section
.getContents();
893 if (!ContentsOrErr
) {
894 consumeError(ContentsOrErr
.takeError());
895 Linker
.reportWarning("error reading section", DMO
.getObjectFilename());
898 DataExtractor
Data(*ContentsOrErr
, Obj
.isLittleEndian(), 0);
899 bool SkipNext
= false;
901 for (const object::RelocationRef
&Reloc
: Section
.relocations()) {
907 object::DataRefImpl RelocDataRef
= Reloc
.getRawDataRefImpl();
908 MachO::any_relocation_info MachOReloc
= Obj
.getRelocation(RelocDataRef
);
910 if (object::MachOObjectFile::isMachOPairedReloc(Obj
.getAnyRelocationType(MachOReloc
),
913 Linker
.reportWarning("unsupported relocation in " + *Section
.getName() +
915 DMO
.getObjectFilename());
919 unsigned RelocSize
= 1 << Obj
.getAnyRelocationLength(MachOReloc
);
920 uint64_t Offset64
= Reloc
.getOffset();
921 if ((RelocSize
!= 4 && RelocSize
!= 8)) {
922 Linker
.reportWarning("unsupported relocation in " + *Section
.getName() +
924 DMO
.getObjectFilename());
927 uint64_t OffsetCopy
= Offset64
;
928 // Mach-o uses REL relocations, the addend is at the relocation offset.
929 uint64_t Addend
= Data
.getUnsigned(&OffsetCopy
, RelocSize
);
933 if (Obj
.isRelocationScattered(MachOReloc
)) {
934 // The address of the base symbol for scattered relocations is
935 // stored in the reloc itself. The actual addend will store the
936 // base address plus the offset.
937 SymAddress
= Obj
.getScatteredRelocationValue(MachOReloc
);
938 SymOffset
= int64_t(Addend
) - SymAddress
;
944 auto Sym
= Reloc
.getSymbol();
945 if (Sym
!= Obj
.symbol_end()) {
946 Expected
<StringRef
> SymbolName
= Sym
->getName();
948 consumeError(SymbolName
.takeError());
949 Linker
.reportWarning("error getting relocation symbol name.",
950 DMO
.getObjectFilename());
953 if (const auto *Mapping
= DMO
.lookupSymbol(*SymbolName
))
954 ValidRelocs
.emplace_back(Offset64
, RelocSize
, Addend
, Mapping
->getKey(),
955 Mapping
->getValue());
956 } else if (const auto *Mapping
= DMO
.lookupObjectAddress(SymAddress
)) {
957 // Do not store the addend. The addend was the address of the symbol in
958 // the object file, the address in the binary that is stored in the debug
959 // map doesn't need to be offset.
960 ValidRelocs
.emplace_back(Offset64
, RelocSize
, SymOffset
,
961 Mapping
->getKey(), Mapping
->getValue());
966 /// Dispatch the valid relocation finding logic to the
967 /// appropriate handler depending on the object file format.
968 template <typename AddressesMapBase
>
969 bool DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::findValidRelocs(
970 const object::SectionRef
&Section
, const object::ObjectFile
&Obj
,
971 const DebugMapObject
&DMO
, std::vector
<ValidReloc
> &Relocs
) {
972 // Dispatch to the right handler depending on the file type.
973 if (auto *MachOObj
= dyn_cast
<object::MachOObjectFile
>(&Obj
))
974 findValidRelocsMachO(Section
, *MachOObj
, DMO
, Relocs
);
976 Linker
.reportWarning(Twine("unsupported object file type: ") +
978 DMO
.getObjectFilename());
982 // Sort the relocations by offset. We will walk the DIEs linearly in
983 // the file, this allows us to just keep an index in the relocation
984 // array that we advance during our walk, rather than resorting to
985 // some associative container. See DwarfLinkerForBinary::NextValidReloc.
990 /// Look for relocations in the debug_info and debug_addr section that match
991 /// entries in the debug map. These relocations will drive the Dwarf link by
992 /// indicating which DIEs refer to symbols present in the linked binary.
993 /// \returns whether there are any valid relocations in the debug info.
994 template <typename AddressesMapBase
>
995 bool DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::
996 findValidRelocsInDebugSections(const object::ObjectFile
&Obj
,
997 const DebugMapObject
&DMO
) {
998 // Find the debug_info section.
999 bool FoundValidRelocs
= false;
1000 for (const object::SectionRef
&Section
: Obj
.sections()) {
1001 StringRef SectionName
;
1002 if (Expected
<StringRef
> NameOrErr
= Section
.getName())
1003 SectionName
= *NameOrErr
;
1005 consumeError(NameOrErr
.takeError());
1007 SectionName
= SectionName
.substr(SectionName
.find_first_not_of("._"));
1008 if (SectionName
== "debug_info")
1010 findValidRelocs(Section
, Obj
, DMO
, ValidDebugInfoRelocs
);
1011 if (SectionName
== "debug_addr")
1013 findValidRelocs(Section
, Obj
, DMO
, ValidDebugAddrRelocs
);
1015 return FoundValidRelocs
;
1018 template <typename AddressesMapBase
>
1019 std::vector
<ValidReloc
>
1020 DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::getRelocations(
1021 const std::vector
<ValidReloc
> &Relocs
, uint64_t StartPos
, uint64_t EndPos
) {
1022 std::vector
<ValidReloc
> Res
;
1024 auto CurReloc
= partition_point(Relocs
, [StartPos
](const ValidReloc
&Reloc
) {
1025 return (uint64_t)Reloc
.Offset
< StartPos
;
1028 while (CurReloc
!= Relocs
.end() && CurReloc
->Offset
>= StartPos
&&
1029 (uint64_t)CurReloc
->Offset
< EndPos
) {
1030 Res
.push_back(*CurReloc
);
1037 template <typename AddressesMapBase
>
1038 void DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::printReloc(
1039 const ValidReloc
&Reloc
) {
1040 const auto &Mapping
= Reloc
.SymbolMapping
;
1041 const uint64_t ObjectAddress
= Mapping
.ObjectAddress
1042 ? uint64_t(*Mapping
.ObjectAddress
)
1043 : std::numeric_limits
<uint64_t>::max();
1045 outs() << "Found valid debug map entry: " << Reloc
.SymbolName
<< "\t"
1046 << format("0x%016" PRIx64
" => 0x%016" PRIx64
"\n", ObjectAddress
,
1047 uint64_t(Mapping
.BinaryAddress
));
1050 template <typename AddressesMapBase
>
1051 int64_t DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::getRelocValue(
1052 const ValidReloc
&Reloc
) {
1053 int64_t AddrAdjust
= relocate(Reloc
);
1054 if (Reloc
.SymbolMapping
.ObjectAddress
)
1055 AddrAdjust
-= uint64_t(*Reloc
.SymbolMapping
.ObjectAddress
);
1059 template <typename AddressesMapBase
>
1060 std::optional
<int64_t>
1061 DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::hasValidRelocationAt(
1062 const std::vector
<ValidReloc
> &AllRelocs
, uint64_t StartOffset
,
1063 uint64_t EndOffset
) {
1064 std::vector
<ValidReloc
> Relocs
=
1065 getRelocations(AllRelocs
, StartOffset
, EndOffset
);
1067 if (Relocs
.size() == 0)
1068 return std::nullopt
;
1070 if (Linker
.Options
.Verbose
)
1071 printReloc(Relocs
[0]);
1073 return getRelocValue(Relocs
[0]);
1076 /// Get the starting and ending (exclusive) offset for the
1077 /// attribute with index \p Idx descibed by \p Abbrev. \p Offset is
1078 /// supposed to point to the position of the first attribute described
1080 /// \return [StartOffset, EndOffset) as a pair.
1081 static std::pair
<uint64_t, uint64_t>
1082 getAttributeOffsets(const DWARFAbbreviationDeclaration
*Abbrev
, unsigned Idx
,
1083 uint64_t Offset
, const DWARFUnit
&Unit
) {
1084 DataExtractor Data
= Unit
.getDebugInfoExtractor();
1086 for (unsigned I
= 0; I
< Idx
; ++I
)
1087 DWARFFormValue::skipValue(Abbrev
->getFormByIndex(I
), Data
, &Offset
,
1088 Unit
.getFormParams());
1090 uint64_t End
= Offset
;
1091 DWARFFormValue::skipValue(Abbrev
->getFormByIndex(Idx
), Data
, &End
,
1092 Unit
.getFormParams());
1094 return std::make_pair(Offset
, End
);
1097 template <typename AddressesMapBase
>
1098 std::optional
<int64_t> DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::
1099 getExprOpAddressRelocAdjustment(DWARFUnit
&U
,
1100 const DWARFExpression::Operation
&Op
,
1101 uint64_t StartOffset
, uint64_t EndOffset
) {
1102 switch (Op
.getCode()) {
1104 assert(false && "Specified operation does not have address operand");
1106 case dwarf::DW_OP_const2u
:
1107 case dwarf::DW_OP_const4u
:
1108 case dwarf::DW_OP_const8u
:
1109 case dwarf::DW_OP_const2s
:
1110 case dwarf::DW_OP_const4s
:
1111 case dwarf::DW_OP_const8s
:
1112 case dwarf::DW_OP_addr
: {
1113 return hasValidRelocationAt(ValidDebugInfoRelocs
, StartOffset
, EndOffset
);
1115 case dwarf::DW_OP_constx
:
1116 case dwarf::DW_OP_addrx
: {
1117 return hasValidRelocationAt(ValidDebugAddrRelocs
, StartOffset
, EndOffset
);
1121 return std::nullopt
;
1124 template <typename AddressesMapBase
>
1125 std::optional
<int64_t> DwarfLinkerForBinary::AddressManager
<
1126 AddressesMapBase
>::getSubprogramRelocAdjustment(const DWARFDie
&DIE
) {
1127 const auto *Abbrev
= DIE
.getAbbreviationDeclarationPtr();
1129 std::optional
<uint32_t> LowPcIdx
=
1130 Abbrev
->findAttributeIndex(dwarf::DW_AT_low_pc
);
1132 return std::nullopt
;
1134 dwarf::Form Form
= Abbrev
->getFormByIndex(*LowPcIdx
);
1137 case dwarf::DW_FORM_addr
: {
1138 uint64_t Offset
= DIE
.getOffset() + getULEB128Size(Abbrev
->getCode());
1139 uint64_t LowPcOffset
, LowPcEndOffset
;
1140 std::tie(LowPcOffset
, LowPcEndOffset
) =
1141 getAttributeOffsets(Abbrev
, *LowPcIdx
, Offset
, *DIE
.getDwarfUnit());
1142 return hasValidRelocationAt(ValidDebugInfoRelocs
, LowPcOffset
,
1145 case dwarf::DW_FORM_addrx
:
1146 case dwarf::DW_FORM_addrx1
:
1147 case dwarf::DW_FORM_addrx2
:
1148 case dwarf::DW_FORM_addrx3
:
1149 case dwarf::DW_FORM_addrx4
: {
1150 std::optional
<DWARFFormValue
> AddrValue
= DIE
.find(dwarf::DW_AT_low_pc
);
1151 if (std::optional
<uint64_t> AddressOffset
=
1152 DIE
.getDwarfUnit()->getIndexedAddressOffset(
1153 AddrValue
->getRawUValue()))
1154 return hasValidRelocationAt(ValidDebugAddrRelocs
, *AddressOffset
,
1156 DIE
.getDwarfUnit()->getAddressByteSize());
1158 Linker
.reportWarning("no base offset for address table", SrcFileName
);
1159 return std::nullopt
;
1162 return std::nullopt
;
1166 template <typename AddressesMapBase
>
1167 std::optional
<StringRef
> DwarfLinkerForBinary::AddressManager
<
1168 AddressesMapBase
>::getLibraryInstallName() {
1169 return LibInstallName
;
1172 template <typename AddressesMapBase
>
1173 uint64_t DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::relocate(
1174 const ValidReloc
&Reloc
) const {
1175 return Reloc
.SymbolMapping
.BinaryAddress
+ Reloc
.Addend
;
1178 template <typename AddressesMapBase
>
1179 void DwarfLinkerForBinary::AddressManager
<
1180 AddressesMapBase
>::updateAndSaveValidRelocs(bool IsDWARF5
,
1181 uint64_t OriginalUnitOffset
,
1182 int64_t LinkedOffset
,
1183 uint64_t StartOffset
,
1184 uint64_t EndOffset
) {
1185 std::vector
<ValidReloc
> InRelocs
=
1186 getRelocations(ValidDebugInfoRelocs
, StartOffset
, EndOffset
);
1188 InRelocs
= getRelocations(ValidDebugAddrRelocs
, StartOffset
, EndOffset
);
1189 DwarfLinkerRelocMap
->updateAndSaveValidRelocs(
1190 IsDWARF5
, InRelocs
, OriginalUnitOffset
, LinkedOffset
);
1193 template <typename AddressesMapBase
>
1194 void DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::
1195 updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset
,
1196 uint64_t OutputUnitOffset
) {
1197 DwarfLinkerRelocMap
->updateRelocationsWithUnitOffset(OriginalUnitOffset
,
1200 /// Apply the valid relocations found by findValidRelocs() to
1201 /// the buffer \p Data, taking into account that Data is at \p BaseOffset
1202 /// in the debug_info section.
1204 /// Like for findValidRelocs(), this function must be called with
1205 /// monotonic \p BaseOffset values.
1207 /// \returns whether any reloc has been applied.
1208 template <typename AddressesMapBase
>
1209 bool DwarfLinkerForBinary::AddressManager
<AddressesMapBase
>::applyValidRelocs(
1210 MutableArrayRef
<char> Data
, uint64_t BaseOffset
, bool IsLittleEndian
) {
1212 std::vector
<ValidReloc
> Relocs
= getRelocations(
1213 ValidDebugInfoRelocs
, BaseOffset
, BaseOffset
+ Data
.size());
1215 for (const ValidReloc
&CurReloc
: Relocs
) {
1216 assert(CurReloc
.Offset
- BaseOffset
< Data
.size());
1217 assert(CurReloc
.Offset
- BaseOffset
+ CurReloc
.Size
<= Data
.size());
1219 uint64_t Value
= relocate(CurReloc
);
1220 for (unsigned I
= 0; I
!= CurReloc
.Size
; ++I
) {
1221 unsigned Index
= IsLittleEndian
? I
: (CurReloc
.Size
- I
- 1);
1222 Buf
[I
] = uint8_t(Value
>> (Index
* 8));
1224 assert(CurReloc
.Size
<= sizeof(Buf
));
1225 memcpy(&Data
[CurReloc
.Offset
- BaseOffset
], Buf
, CurReloc
.Size
);
1227 return Relocs
.size() > 0;
1230 void DwarfLinkerForBinaryRelocationMap::init(DWARFContext
&Context
) {
1231 for (const std::unique_ptr
<DWARFUnit
> &CU
: Context
.compile_units())
1232 StoredValidDebugInfoRelocsMap
.insert(
1233 std::make_pair(CU
->getOffset(), std::vector
<ValidReloc
>()));
1234 // FIXME: Support relocations debug_addr (DWARF5).
1237 void DwarfLinkerForBinaryRelocationMap::addValidRelocs(RelocationMap
&RM
) {
1238 for (const auto &DebugInfoRelocs
: StoredValidDebugInfoRelocsMap
) {
1239 for (const auto &InfoReloc
: DebugInfoRelocs
.second
)
1240 RM
.addRelocationMapEntry(InfoReloc
);
1242 // FIXME: Support relocations debug_addr (DWARF5).
1245 void DwarfLinkerForBinaryRelocationMap::updateRelocationsWithUnitOffset(
1246 uint64_t OriginalUnitOffset
, uint64_t OutputUnitOffset
) {
1247 std::vector
<ValidReloc
> &StoredValidDebugInfoRelocs
=
1248 StoredValidDebugInfoRelocsMap
[OriginalUnitOffset
];
1249 for (ValidReloc
&R
: StoredValidDebugInfoRelocs
) {
1250 R
.Offset
= (uint64_t)R
.Offset
+ OutputUnitOffset
;
1252 // FIXME: Support relocations debug_addr (DWARF5).
1255 void DwarfLinkerForBinaryRelocationMap::updateAndSaveValidRelocs(
1256 bool IsDWARF5
, std::vector
<ValidReloc
> &InRelocs
, uint64_t UnitOffset
,
1257 int64_t LinkedOffset
) {
1258 std::vector
<ValidReloc
> &OutRelocs
=
1259 StoredValidDebugInfoRelocsMap
[UnitOffset
];
1261 OutRelocs
= StoredValidDebugAddrRelocsMap
[UnitOffset
];
1263 for (ValidReloc
&R
: InRelocs
) {
1264 OutRelocs
.emplace_back(R
.Offset
+ LinkedOffset
, R
.Size
, R
.Addend
,
1265 R
.SymbolName
, R
.SymbolMapping
);
1269 } // namespace dsymutil