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/DenseMap.h"
16 #include "llvm/ADT/FoldingSet.h"
17 #include "llvm/ADT/Hashing.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/ADT/Twine.h"
22 #include "llvm/BinaryFormat/Dwarf.h"
23 #include "llvm/BinaryFormat/MachO.h"
24 #include "llvm/BinaryFormat/Swift.h"
25 #include "llvm/CodeGen/AccelTable.h"
26 #include "llvm/CodeGen/AsmPrinter.h"
27 #include "llvm/CodeGen/DIE.h"
28 #include "llvm/CodeGen/NonRelocatableStringpool.h"
29 #include "llvm/Config/config.h"
30 #include "llvm/DWARFLinker/Classic/DWARFLinker.h"
31 #include "llvm/DWARFLinker/Classic/DWARFStreamer.h"
32 #include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
33 #include "llvm/DebugInfo/DIContext.h"
34 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
35 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
36 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
37 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
38 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
39 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
40 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
41 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
42 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
43 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
44 #include "llvm/MC/MCAsmBackend.h"
45 #include "llvm/MC/MCAsmInfo.h"
46 #include "llvm/MC/MCCodeEmitter.h"
47 #include "llvm/MC/MCContext.h"
48 #include "llvm/MC/MCDwarf.h"
49 #include "llvm/MC/MCInstrInfo.h"
50 #include "llvm/MC/MCObjectFileInfo.h"
51 #include "llvm/MC/MCObjectWriter.h"
52 #include "llvm/MC/MCRegisterInfo.h"
53 #include "llvm/MC/MCSection.h"
54 #include "llvm/MC/MCStreamer.h"
55 #include "llvm/MC/MCSubtargetInfo.h"
56 #include "llvm/MC/MCTargetOptions.h"
57 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
58 #include "llvm/MC/TargetRegistry.h"
59 #include "llvm/Object/MachO.h"
60 #include "llvm/Object/ObjectFile.h"
61 #include "llvm/Object/SymbolicFile.h"
62 #include "llvm/Support/Allocator.h"
63 #include "llvm/Support/Casting.h"
64 #include "llvm/Support/Compiler.h"
65 #include "llvm/Support/DJB.h"
66 #include "llvm/Support/DataExtractor.h"
67 #include "llvm/Support/Error.h"
68 #include "llvm/Support/ErrorHandling.h"
69 #include "llvm/Support/ErrorOr.h"
70 #include "llvm/Support/FileSystem.h"
71 #include "llvm/Support/Format.h"
72 #include "llvm/Support/LEB128.h"
73 #include "llvm/Support/MathExtras.h"
74 #include "llvm/Support/MemoryBuffer.h"
75 #include "llvm/Support/Path.h"
76 #include "llvm/Support/ThreadPool.h"
77 #include "llvm/Support/ToolOutputFile.h"
78 #include "llvm/Support/WithColor.h"
79 #include "llvm/Support/raw_ostream.h"
80 #include "llvm/Target/TargetMachine.h"
81 #include "llvm/Target/TargetOptions.h"
82 #include "llvm/TargetParser/Triple.h"
95 #include <system_error>
102 static mc::RegisterMCTargetOptionsFlags MOF
;
104 using namespace dwarf_linker
;
108 static void dumpDIE(const DWARFDie
*DIE
, bool Verbose
) {
109 if (!DIE
|| !Verbose
)
112 DIDumpOptions DumpOpts
;
113 DumpOpts
.ChildRecurseDepth
= 0;
114 DumpOpts
.Verbose
= Verbose
;
116 WithColor::note() << " in DIE:\n";
117 DIE
->dump(errs(), 6 /* Indent */, DumpOpts
);
120 /// Report a warning to the user, optionally including information about a
121 /// specific \p DIE related to the warning.
122 void DwarfLinkerForBinary::reportWarning(Twine Warning
, Twine Context
,
123 const DWARFDie
*DIE
) const {
124 // FIXME: implement warning logging which does not block other threads.
125 if (ErrorHandlerMutex
.try_lock()) {
126 warn(Warning
, Context
);
127 dumpDIE(DIE
, Options
.Verbose
);
128 ErrorHandlerMutex
.unlock();
132 void DwarfLinkerForBinary::reportError(Twine Error
, Twine Context
,
133 const DWARFDie
*DIE
) const {
134 // FIXME: implement error logging which does not block other threads.
135 if (ErrorHandlerMutex
.try_lock()) {
136 error(Error
, Context
);
137 dumpDIE(DIE
, Options
.Verbose
);
138 ErrorHandlerMutex
.unlock();
142 ErrorOr
<const object::ObjectFile
&>
143 DwarfLinkerForBinary::loadObject(const DebugMapObject
&Obj
,
144 const Triple
&Triple
) {
146 BinHolder
.getObjectEntry(Obj
.getObjectFilename(), Obj
.getTimestamp());
148 auto Err
= ObjectEntry
.takeError();
149 reportWarning(Twine(Obj
.getObjectFilename()) + ": " +
150 toStringWithoutConsuming(Err
),
151 Obj
.getObjectFilename());
152 return errorToErrorCode(std::move(Err
));
155 auto Object
= ObjectEntry
->getObject(Triple
);
157 auto Err
= Object
.takeError();
158 reportWarning(Twine(Obj
.getObjectFilename()) + ": " +
159 toStringWithoutConsuming(Err
),
160 Obj
.getObjectFilename());
161 return errorToErrorCode(std::move(Err
));
167 static Error
remarksErrorHandler(const DebugMapObject
&DMO
,
168 DwarfLinkerForBinary
&Linker
,
169 std::unique_ptr
<FileError
> FE
) {
170 bool IsArchive
= DMO
.getObjectFilename().ends_with(")");
171 // Don't report errors for missing remark files from static
174 return Error(std::move(FE
));
176 std::string Message
= FE
->message();
177 Error E
= FE
->takeError();
178 Error NewE
= handleErrors(std::move(E
), [&](std::unique_ptr
<ECError
> EC
) {
179 if (EC
->convertToErrorCode() != std::errc::no_such_file_or_directory
)
180 return Error(std::move(EC
));
182 Linker
.reportWarning(Message
, DMO
.getObjectFilename());
183 return Error(Error::success());
187 return Error::success();
189 return createFileError(FE
->getFileName(), std::move(NewE
));
191 Error
DwarfLinkerForBinary::emitRelocations(
192 const DebugMap
&DM
, std::vector
<ObjectWithRelocMap
> &ObjectsForLinking
) {
193 // Return early if the "Resources" directory is not being written to.
194 if (!Options
.ResourceDir
)
195 return Error::success();
197 RelocationMap
RM(DM
.getTriple(), DM
.getBinaryPath());
198 for (auto &Obj
: ObjectsForLinking
) {
199 if (!Obj
.OutRelocs
->isInitialized())
201 Obj
.OutRelocs
->addValidRelocs(RM
);
204 SmallString
<128> InputPath
;
205 SmallString
<128> Path
;
206 // Create the "Relocations" directory in the "Resources" directory, and
207 // create an architecture-specific directory in the "Relocations" directory.
208 StringRef ArchName
= Triple::getArchName(RM
.getTriple().getArch(),
209 RM
.getTriple().getSubArch());
210 sys::path::append(Path
, *Options
.ResourceDir
, "Relocations", ArchName
);
211 if (std::error_code EC
= sys::fs::create_directories(Path
.str(), true,
212 sys::fs::perms::all_all
))
213 return errorCodeToError(EC
);
215 // Append the file name.
216 sys::path::append(Path
, sys::path::filename(DM
.getBinaryPath()));
220 raw_fd_ostream
OS(Path
.str(), EC
, sys::fs::OF_Text
);
222 return errorCodeToError(EC
);
225 return Error::success();
228 static Error
emitRemarks(const LinkOptions
&Options
, StringRef BinaryPath
,
229 StringRef ArchName
, const remarks::RemarkLinker
&RL
) {
230 // Make sure we don't create the directories and the file if there is nothing
233 return Error::success();
235 SmallString
<128> InputPath
;
236 SmallString
<128> Path
;
237 // Create the "Remarks" directory in the "Resources" directory.
238 sys::path::append(Path
, *Options
.ResourceDir
, "Remarks");
239 if (std::error_code EC
= sys::fs::create_directories(Path
.str(), true,
240 sys::fs::perms::all_all
))
241 return errorCodeToError(EC
);
243 // Append the file name.
244 // For fat binaries, also append a dash and the architecture name.
245 sys::path::append(Path
, sys::path::filename(BinaryPath
));
246 if (Options
.NumDebugMaps
> 1) {
247 // More than one debug map means we have a fat binary.
253 raw_fd_ostream
OS(Options
.NoOutput
? "-" : Path
.str(), EC
,
254 Options
.RemarksFormat
== remarks::Format::Bitstream
258 return errorCodeToError(EC
);
260 if (Error E
= RL
.serialize(OS
, Options
.RemarksFormat
))
263 return Error::success();
266 ErrorOr
<std::unique_ptr
<DWARFFile
>> DwarfLinkerForBinary::loadObject(
267 const DebugMapObject
&Obj
, const DebugMap
&DebugMap
,
268 remarks::RemarkLinker
&RL
,
269 std::shared_ptr
<DwarfLinkerForBinaryRelocationMap
> DLBRM
) {
270 auto ErrorOrObj
= loadObject(Obj
, DebugMap
.getTriple());
271 std::unique_ptr
<DWARFFile
> Res
;
274 auto Context
= DWARFContext::create(
275 *ErrorOrObj
, DWARFContext::ProcessDebugRelocations::Process
, nullptr,
278 handleAllErrors(std::move(Err
), [&](ErrorInfoBase
&Info
) {
279 reportError(Info
.message());
283 handleAllErrors(std::move(Warning
), [&](ErrorInfoBase
&Info
) {
284 reportWarning(Info
.message());
287 DLBRM
->init(*Context
);
288 Res
= std::make_unique
<DWARFFile
>(
289 Obj
.getObjectFilename(), std::move(Context
),
290 std::make_unique
<AddressManager
>(*this, *ErrorOrObj
, Obj
, DLBRM
),
291 [&](StringRef FileName
) { BinHolder
.eraseObjectEntry(FileName
); });
293 Error E
= RL
.link(*ErrorOrObj
);
294 if (Error NewE
= handleErrors(
295 std::move(E
), [&](std::unique_ptr
<FileError
> EC
) -> Error
{
296 return remarksErrorHandler(Obj
, *this, std::move(EC
));
298 return errorToErrorCode(std::move(NewE
));
300 return std::move(Res
);
303 return ErrorOrObj
.getError();
306 static bool binaryHasStrippableSwiftReflectionSections(
307 const DebugMap
&Map
, const LinkOptions
&Options
, BinaryHolder
&BinHolder
) {
308 // If the input binary has strippable swift5 reflection sections, there is no
309 // need to copy them to the .dSYM. Only copy them for binaries where the
310 // linker omitted the reflection metadata.
311 if (!Map
.getBinaryPath().empty() &&
312 Options
.FileType
== DWARFLinkerBase::OutputFileType::Object
) {
314 auto ObjectEntry
= BinHolder
.getObjectEntry(Map
.getBinaryPath());
315 // If ObjectEntry or Object has an error, no binary exists, therefore no
316 // reflection sections exist.
318 // Any errors will be diagnosed later in the main loop, ignore them here.
319 llvm::consumeError(ObjectEntry
.takeError());
324 ObjectEntry
->getObjectAs
<object::MachOObjectFile
>(Map
.getTriple());
326 // Any errors will be diagnosed later in the main loop, ignore them here.
327 llvm::consumeError(Object
.takeError());
331 for (auto &Section
: Object
->sections()) {
332 llvm::Expected
<llvm::StringRef
> NameOrErr
=
333 Object
->getSectionName(Section
.getRawDataRefImpl());
335 llvm::consumeError(NameOrErr
.takeError());
338 NameOrErr
->consume_back("__TEXT");
339 auto ReflectionSectionKind
=
340 Object
->mapReflectionSectionNameToEnumValue(*NameOrErr
);
341 if (Object
->isReflectionSectionStrippable(ReflectionSectionKind
)) {
349 /// Calculate the start of the strippable swift reflection sections in Dwarf.
350 /// Note that there's an assumption that the reflection sections will appear
351 /// in alphabetic order.
352 static std::vector
<uint64_t>
353 calculateStartOfStrippableReflectionSections(const DebugMap
&Map
) {
354 using llvm::binaryformat::Swift5ReflectionSectionKind
;
355 uint64_t AssocTySize
= 0;
356 uint64_t FieldMdSize
= 0;
357 for (const auto &Obj
: Map
.objects()) {
359 llvm::object::ObjectFile::createObjectFile(Obj
->getObjectFilename());
361 llvm::consumeError(OF
.takeError());
364 if (auto *MO
= dyn_cast
<llvm::object::MachOObjectFile
>(OF
->getBinary())) {
365 for (auto &Section
: MO
->sections()) {
366 llvm::Expected
<llvm::StringRef
> NameOrErr
=
367 MO
->getSectionName(Section
.getRawDataRefImpl());
369 llvm::consumeError(NameOrErr
.takeError());
372 NameOrErr
->consume_back("__TEXT");
373 auto ReflSectionKind
=
374 MO
->mapReflectionSectionNameToEnumValue(*NameOrErr
);
375 switch (ReflSectionKind
) {
376 case Swift5ReflectionSectionKind::assocty
:
377 AssocTySize
+= Section
.getSize();
379 case Swift5ReflectionSectionKind::fieldmd
:
380 FieldMdSize
+= Section
.getSize();
388 // Initialize the vector with enough space to fit every reflection section
390 std::vector
<uint64_t> SectionToOffset(Swift5ReflectionSectionKind::last
, 0);
391 SectionToOffset
[Swift5ReflectionSectionKind::assocty
] = 0;
392 SectionToOffset
[Swift5ReflectionSectionKind::fieldmd
] =
393 llvm::alignTo(AssocTySize
, 4);
394 SectionToOffset
[Swift5ReflectionSectionKind::reflstr
] = llvm::alignTo(
395 SectionToOffset
[Swift5ReflectionSectionKind::fieldmd
] + FieldMdSize
, 4);
397 return SectionToOffset
;
400 void DwarfLinkerForBinary::collectRelocationsToApplyToSwiftReflectionSections(
401 const object::SectionRef
&Section
, StringRef
&Contents
,
402 const llvm::object::MachOObjectFile
*MO
,
403 const std::vector
<uint64_t> &SectionToOffsetInDwarf
,
404 const llvm::dsymutil::DebugMapObject
*Obj
,
405 std::vector
<MachOUtils::DwarfRelocationApplicationInfo
> &RelocationsToApply
)
407 for (auto It
= Section
.relocation_begin(); It
!= Section
.relocation_end();
409 object::DataRefImpl RelocDataRef
= It
->getRawDataRefImpl();
410 MachO::any_relocation_info MachOReloc
= MO
->getRelocation(RelocDataRef
);
412 if (!object::MachOObjectFile::isMachOPairedReloc(
413 MO
->getAnyRelocationType(MachOReloc
), MO
->getArch())) {
415 "Unimplemented relocation type in strippable reflection section ",
416 Obj
->getObjectFilename());
420 auto CalculateAddressOfSymbolInDwarfSegment
=
421 [&]() -> std::optional
<int64_t> {
422 auto Symbol
= It
->getSymbol();
423 auto SymbolAbsoluteAddress
= Symbol
->getAddress();
424 if (!SymbolAbsoluteAddress
)
426 auto Section
= Symbol
->getSection();
428 llvm::consumeError(Section
.takeError());
432 if ((*Section
)->getObject()->section_end() == *Section
)
435 auto SectionStart
= (*Section
)->getAddress();
436 auto SymbolAddressInSection
= *SymbolAbsoluteAddress
- SectionStart
;
437 auto SectionName
= (*Section
)->getName();
440 auto ReflSectionKind
=
441 MO
->mapReflectionSectionNameToEnumValue(*SectionName
);
443 int64_t SectionStartInLinkedBinary
=
444 SectionToOffsetInDwarf
[ReflSectionKind
];
446 auto Addr
= SectionStartInLinkedBinary
+ SymbolAddressInSection
;
450 // The first symbol should always be in the section we're currently
452 auto FirstSymbolAddress
= CalculateAddressOfSymbolInDwarfSegment();
455 bool ShouldSubtractDwarfVM
= false;
456 // For the second symbol there are two possibilities.
457 std::optional
<int64_t> SecondSymbolAddress
;
458 auto Sym
= It
->getSymbol();
459 if (Sym
!= MO
->symbol_end()) {
460 Expected
<StringRef
> SymbolName
= Sym
->getName();
462 if (const auto *Mapping
= Obj
->lookupSymbol(*SymbolName
)) {
463 // First possibility: the symbol exists in the binary, and exists in a
464 // non-strippable section (for example, typeref, or __TEXT,__const),
465 // in which case we look up its address in the binary, which dsymutil
466 // will copy verbatim.
467 SecondSymbolAddress
= Mapping
->getValue().BinaryAddress
;
468 // Since the symbols live in different segments, we have to substract
469 // the start of the Dwarf's vmaddr so the value calculated points to
470 // the correct place.
471 ShouldSubtractDwarfVM
= true;
476 if (!SecondSymbolAddress
) {
477 // Second possibility, this symbol is not present in the main binary, and
478 // must be in one of the strippable sections (for example, reflstr).
479 // Calculate its address in the same way as we did the first one.
480 SecondSymbolAddress
= CalculateAddressOfSymbolInDwarfSegment();
483 if (!FirstSymbolAddress
|| !SecondSymbolAddress
)
486 auto SectionName
= Section
.getName();
491 memcpy(&Addend
, Contents
.data() + It
->getOffset(), sizeof(int32_t));
492 int32_t Value
= (*SecondSymbolAddress
+ Addend
) - *FirstSymbolAddress
;
493 auto ReflSectionKind
=
494 MO
->mapReflectionSectionNameToEnumValue(*SectionName
);
495 uint64_t AddressFromDwarfVM
=
496 SectionToOffsetInDwarf
[ReflSectionKind
] + It
->getOffset();
497 RelocationsToApply
.emplace_back(AddressFromDwarfVM
, Value
,
498 ShouldSubtractDwarfVM
);
502 Error
DwarfLinkerForBinary::copySwiftInterfaces(StringRef Architecture
) const {
504 SmallString
<128> InputPath
;
505 SmallString
<128> Path
;
506 sys::path::append(Path
, *Options
.ResourceDir
, "Swift", Architecture
);
507 if ((EC
= sys::fs::create_directories(Path
.str(), true,
508 sys::fs::perms::all_all
)))
509 return make_error
<StringError
>(
510 "cannot create directory: " + toString(errorCodeToError(EC
)), EC
);
511 unsigned BaseLength
= Path
.size();
513 for (auto &I
: ParseableSwiftInterfaces
) {
514 StringRef ModuleName
= I
.first
;
515 StringRef InterfaceFile
= I
.second
;
516 if (!Options
.PrependPath
.empty()) {
518 sys::path::append(InputPath
, Options
.PrependPath
, InterfaceFile
);
519 InterfaceFile
= InputPath
;
521 sys::path::append(Path
, ModuleName
);
522 Path
.append(".swiftinterface");
524 outs() << "copy parseable Swift interface " << InterfaceFile
<< " -> "
525 << Path
.str() << '\n';
527 // copy_file attempts an APFS clone first, so this should be cheap.
528 if ((EC
= sys::fs::copy_file(InterfaceFile
, Path
.str())))
529 reportWarning(Twine("cannot copy parseable Swift interface ") +
530 InterfaceFile
+ ": " + toString(errorCodeToError(EC
)));
531 Path
.resize(BaseLength
);
533 return Error::success();
536 void DwarfLinkerForBinary::copySwiftReflectionMetadata(
537 const llvm::dsymutil::DebugMapObject
*Obj
, classic::DwarfStreamer
*Streamer
,
538 std::vector
<uint64_t> &SectionToOffsetInDwarf
,
539 std::vector
<MachOUtils::DwarfRelocationApplicationInfo
>
540 &RelocationsToApply
) {
541 using binaryformat::Swift5ReflectionSectionKind
;
543 llvm::object::ObjectFile::createObjectFile(Obj
->getObjectFilename());
545 llvm::consumeError(OF
.takeError());
548 if (auto *MO
= dyn_cast
<llvm::object::MachOObjectFile
>(OF
->getBinary())) {
549 // Collect the swift reflection sections before emitting them. This is
550 // done so we control the order they're emitted.
551 std::array
<std::optional
<object::SectionRef
>,
552 Swift5ReflectionSectionKind::last
+ 1>
554 for (auto &Section
: MO
->sections()) {
555 llvm::Expected
<llvm::StringRef
> NameOrErr
=
556 MO
->getSectionName(Section
.getRawDataRefImpl());
558 llvm::consumeError(NameOrErr
.takeError());
561 NameOrErr
->consume_back("__TEXT");
562 auto ReflSectionKind
=
563 MO
->mapReflectionSectionNameToEnumValue(*NameOrErr
);
564 if (MO
->isReflectionSectionStrippable(ReflSectionKind
))
565 SwiftSections
[ReflSectionKind
] = Section
;
567 // Make sure we copy the sections in alphabetic order.
568 auto SectionKindsToEmit
= {Swift5ReflectionSectionKind::assocty
,
569 Swift5ReflectionSectionKind::fieldmd
,
570 Swift5ReflectionSectionKind::reflstr
};
571 for (auto SectionKind
: SectionKindsToEmit
) {
572 if (!SwiftSections
[SectionKind
])
574 auto &Section
= *SwiftSections
[SectionKind
];
575 llvm::Expected
<llvm::StringRef
> SectionContents
= Section
.getContents();
576 if (!SectionContents
)
579 llvm::cast
<llvm::object::MachOObjectFile
>(Section
.getObject());
580 collectRelocationsToApplyToSwiftReflectionSections(
581 Section
, *SectionContents
, MO
, SectionToOffsetInDwarf
, Obj
,
583 // Update the section start with the current section's contribution, so
584 // the next section we copy from a different .o file points to the correct
586 SectionToOffsetInDwarf
[SectionKind
] += Section
.getSize();
587 Streamer
->emitSwiftReflectionSection(SectionKind
, *SectionContents
,
588 Section
.getAlignment().value(),
594 bool DwarfLinkerForBinary::link(const DebugMap
&Map
) {
595 if (Options
.DWARFLinkerType
== DsymutilDWARFLinkerType::Parallel
)
596 return linkImpl
<parallel::DWARFLinker
>(Map
, Options
.FileType
);
598 return linkImpl
<classic::DWARFLinker
>(Map
, Options
.FileType
);
601 template <typename Linker
>
602 void setAcceleratorTables(Linker
&GeneralLinker
,
603 DsymutilAccelTableKind TableKind
,
604 uint16_t MaxDWARFVersion
) {
606 case DsymutilAccelTableKind::Apple
:
607 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::Apple
);
609 case DsymutilAccelTableKind::Dwarf
:
610 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::DebugNames
);
612 case DsymutilAccelTableKind::Pub
:
613 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::Pub
);
615 case DsymutilAccelTableKind::Default
:
616 if (MaxDWARFVersion
>= 5)
617 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::DebugNames
);
619 GeneralLinker
.addAccelTableKind(Linker::AccelTableKind::Apple
);
621 case DsymutilAccelTableKind::None
:
626 llvm_unreachable("All cases handled above!");
629 template <typename Linker
>
630 bool DwarfLinkerForBinary::linkImpl(
631 const DebugMap
&Map
, typename
Linker::OutputFileType ObjectType
) {
633 std::vector
<ObjectWithRelocMap
> ObjectsForLinking
;
635 DebugMap
DebugMap(Map
.getTriple(), Map
.getBinaryPath());
637 std::unique_ptr
<Linker
> GeneralLinker
= Linker::createLinker(
638 [&](const Twine
&Error
, StringRef Context
, const DWARFDie
*DIE
) {
639 reportError(Error
, Context
, DIE
);
641 [&](const Twine
&Warning
, StringRef Context
, const DWARFDie
*DIE
) {
642 reportWarning(Warning
, Context
, DIE
);
645 std::unique_ptr
<classic::DwarfStreamer
> Streamer
;
646 if (!Options
.NoOutput
) {
647 if (Expected
<std::unique_ptr
<classic::DwarfStreamer
>> StreamerOrErr
=
648 classic::DwarfStreamer::createStreamer(
649 Map
.getTriple(), ObjectType
, OutFile
,
650 [&](const Twine
&Warning
, StringRef Context
,
651 const DWARFDie
*DIE
) {
652 reportWarning(Warning
, Context
, DIE
);
654 Streamer
= std::move(*StreamerOrErr
);
656 handleAllErrors(StreamerOrErr
.takeError(), [&](const ErrorInfoBase
&EI
) {
657 reportError(EI
.message(), "dwarf streamer init");
662 if constexpr (std::is_same
<Linker
, parallel::DWARFLinker
>::value
) {
663 GeneralLinker
->setOutputDWARFHandler(
665 [&](std::shared_ptr
<parallel::SectionDescriptorBase
> Section
) {
666 Streamer
->emitSectionContents(Section
->getContents(),
670 GeneralLinker
->setOutputDWARFEmitter(Streamer
.get());
673 remarks::RemarkLinker RL
;
674 if (!Options
.RemarksPrependPath
.empty())
675 RL
.setExternalFilePrependPath(Options
.RemarksPrependPath
);
676 RL
.setKeepAllRemarks(Options
.RemarksKeepAll
);
677 GeneralLinker
->setObjectPrefixMap(&Options
.ObjectPrefixMap
);
679 GeneralLinker
->setVerbosity(Options
.Verbose
);
680 GeneralLinker
->setStatistics(Options
.Statistics
);
681 GeneralLinker
->setVerifyInputDWARF(Options
.VerifyInputDWARF
);
682 GeneralLinker
->setNoODR(Options
.NoODR
);
683 GeneralLinker
->setUpdateIndexTablesOnly(Options
.Update
);
684 GeneralLinker
->setNumThreads(Options
.Threads
);
685 GeneralLinker
->setPrependPath(Options
.PrependPath
);
686 GeneralLinker
->setKeepFunctionForStatic(Options
.KeepFunctionForStatic
);
687 GeneralLinker
->setInputVerificationHandler(
688 [&](const DWARFFile
&File
, llvm::StringRef Output
) {
689 std::lock_guard
<std::mutex
> Guard(ErrorHandlerMutex
);
692 warn("input verification failed", File
.FileName
);
693 HasVerificationErrors
= true;
695 auto Loader
= [&](StringRef ContainerName
,
696 StringRef Path
) -> ErrorOr
<DWARFFile
&> {
697 auto &Obj
= DebugMap
.addDebugMapObject(
698 Path
, sys::TimePoint
<std::chrono::seconds
>(), MachO::N_OSO
);
700 auto DLBRelocMap
= std::make_shared
<DwarfLinkerForBinaryRelocationMap
>();
701 if (ErrorOr
<std::unique_ptr
<DWARFFile
>> ErrorOrObj
=
702 loadObject(Obj
, DebugMap
, RL
, DLBRelocMap
)) {
703 ObjectsForLinking
.emplace_back(std::move(*ErrorOrObj
), DLBRelocMap
);
704 return *ObjectsForLinking
.back().Object
;
706 // Try and emit more helpful warnings by applying some heuristics.
707 StringRef ObjFile
= ContainerName
;
708 bool IsClangModule
= sys::path::extension(Path
) == ".pcm";
709 bool IsArchive
= ObjFile
.ends_with(")");
712 StringRef ModuleCacheDir
= sys::path::parent_path(Path
);
713 if (sys::fs::exists(ModuleCacheDir
)) {
714 // If the module's parent directory exists, we assume that the
715 // module cache has expired and was pruned by clang. A more
716 // adventurous dsymutil would invoke clang to rebuild the module
718 if (!ModuleCacheHintDisplayed
) {
720 << "The clang module cache may have expired since "
721 "this object file was built. Rebuilding the "
722 "object file will rebuild the module cache.\n";
723 ModuleCacheHintDisplayed
= true;
725 } else if (IsArchive
) {
726 // If the module cache directory doesn't exist at all and the
727 // object file is inside a static library, we assume that the
728 // static library was built on a different machine. We don't want
729 // to discourage module debugging for convenience libraries within
731 if (!ArchiveHintDisplayed
) {
733 << "Linking a static library that was built with "
734 "-gmodules, but the module cache was not found. "
735 "Redistributable static libraries should never be "
736 "built with module debugging enabled. The debug "
737 "experience will be degraded due to incomplete "
738 "debug information.\n";
739 ArchiveHintDisplayed
= true;
744 return ErrorOrObj
.getError();
747 llvm_unreachable("Unhandled DebugMap object");
749 GeneralLinker
->setSwiftInterfacesMap(&ParseableSwiftInterfaces
);
750 bool ReflectionSectionsPresentInBinary
= false;
751 // If there is no output specified, no point in checking the binary for swift5
752 // reflection sections.
753 if (!Options
.NoOutput
) {
754 ReflectionSectionsPresentInBinary
=
755 binaryHasStrippableSwiftReflectionSections(Map
, Options
, BinHolder
);
758 std::vector
<MachOUtils::DwarfRelocationApplicationInfo
> RelocationsToApply
;
759 if (!Options
.NoOutput
&& !ReflectionSectionsPresentInBinary
) {
760 auto SectionToOffsetInDwarf
=
761 calculateStartOfStrippableReflectionSections(Map
);
762 for (const auto &Obj
: Map
.objects())
763 copySwiftReflectionMetadata(Obj
.get(), Streamer
.get(),
764 SectionToOffsetInDwarf
, RelocationsToApply
);
767 uint16_t MaxDWARFVersion
= 0;
768 std::function
<void(const DWARFUnit
&Unit
)> OnCUDieLoaded
=
769 [&MaxDWARFVersion
](const DWARFUnit
&Unit
) {
770 MaxDWARFVersion
= std::max(Unit
.getVersion(), MaxDWARFVersion
);
773 for (const auto &Obj
: Map
.objects()) {
774 // N_AST objects (swiftmodule files) should get dumped directly into the
775 // appropriate DWARF section.
776 if (Obj
->getType() == MachO::N_AST
) {
778 outs() << "DEBUG MAP OBJECT: " << Obj
->getObjectFilename() << "\n";
780 StringRef File
= Obj
->getObjectFilename();
781 auto ErrorOrMem
= MemoryBuffer::getFile(File
);
783 reportWarning("Could not open '" + File
+ "'");
786 sys::fs::file_status Stat
;
787 if (auto Err
= sys::fs::status(File
, Stat
)) {
788 reportWarning(Err
.message());
791 if (!Options
.NoTimestamp
) {
792 // The modification can have sub-second precision so we need to cast
793 // away the extra precision that's not present in the debug map.
794 auto ModificationTime
=
795 std::chrono::time_point_cast
<std::chrono::seconds
>(
796 Stat
.getLastModificationTime());
797 if (Obj
->getTimestamp() != sys::TimePoint
<>() &&
798 ModificationTime
!= Obj
->getTimestamp()) {
799 // Not using the helper here as we can easily stream TimePoint<>.
801 << File
<< ": timestamp mismatch between swift interface file ("
802 << sys::TimePoint
<>(ModificationTime
) << ") and debug map ("
803 << sys::TimePoint
<>(Obj
->getTimestamp()) << ")\n";
808 // Copy the module into the .swift_ast section.
809 if (!Options
.NoOutput
)
810 Streamer
->emitSwiftAST((*ErrorOrMem
)->getBuffer());
815 auto DLBRelocMap
= std::make_shared
<DwarfLinkerForBinaryRelocationMap
>();
816 if (ErrorOr
<std::unique_ptr
<DWARFFile
>> ErrorOrObj
=
817 loadObject(*Obj
, Map
, RL
, DLBRelocMap
)) {
818 ObjectsForLinking
.emplace_back(std::move(*ErrorOrObj
), DLBRelocMap
);
819 GeneralLinker
->addObjectFile(*ObjectsForLinking
.back().Object
, Loader
,
822 ObjectsForLinking
.push_back(
823 {std::make_unique
<DWARFFile
>(Obj
->getObjectFilename(), nullptr,
826 GeneralLinker
->addObjectFile(*ObjectsForLinking
.back().Object
);
830 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
831 if (MaxDWARFVersion
== 0)
834 if (Error E
= GeneralLinker
->setTargetDWARFVersion(MaxDWARFVersion
))
835 return error(toString(std::move(E
)));
837 setAcceleratorTables
<Linker
>(*GeneralLinker
, Options
.TheAccelTableKind
,
840 // link debug info for loaded object files.
841 if (Error E
= GeneralLinker
->link())
842 return error(toString(std::move(E
)));
844 StringRef ArchName
= Map
.getTriple().getArchName();
845 if (Error E
= emitRemarks(Options
, Map
.getBinaryPath(), ArchName
, RL
))
846 return error(toString(std::move(E
)));
848 if (Options
.NoOutput
)
851 if (Error E
= emitRelocations(Map
, ObjectsForLinking
))
852 return error(toString(std::move(E
)));
854 if (Options
.ResourceDir
&& !ParseableSwiftInterfaces
.empty()) {
855 StringRef ArchName
= Triple::getArchTypeName(Map
.getTriple().getArch());
856 if (auto E
= copySwiftInterfaces(ArchName
))
857 return error(toString(std::move(E
)));
860 auto MapTriple
= Map
.getTriple();
861 if ((MapTriple
.isOSDarwin() || MapTriple
.isOSBinFormatMachO()) &&
862 !Map
.getBinaryPath().empty() &&
863 ObjectType
== Linker::OutputFileType::Object
)
864 return MachOUtils::generateDsymCompanion(
865 Options
.VFS
, Map
, *Streamer
->getAsmPrinter().OutStreamer
, OutFile
,
872 /// Iterate over the relocations of the given \p Section and
873 /// store the ones that correspond to debug map entries into the
874 /// ValidRelocs array.
875 void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
876 const object::SectionRef
&Section
, const object::MachOObjectFile
&Obj
,
877 const DebugMapObject
&DMO
, std::vector
<ValidReloc
> &ValidRelocs
) {
878 Expected
<StringRef
> ContentsOrErr
= Section
.getContents();
879 if (!ContentsOrErr
) {
880 consumeError(ContentsOrErr
.takeError());
881 Linker
.reportWarning("error reading section", DMO
.getObjectFilename());
884 DataExtractor
Data(*ContentsOrErr
, Obj
.isLittleEndian(), 0);
885 bool SkipNext
= false;
887 for (const object::RelocationRef
&Reloc
: Section
.relocations()) {
893 object::DataRefImpl RelocDataRef
= Reloc
.getRawDataRefImpl();
894 MachO::any_relocation_info MachOReloc
= Obj
.getRelocation(RelocDataRef
);
896 if (object::MachOObjectFile::isMachOPairedReloc(Obj
.getAnyRelocationType(MachOReloc
),
899 Linker
.reportWarning("unsupported relocation in " + *Section
.getName() +
901 DMO
.getObjectFilename());
905 unsigned RelocSize
= 1 << Obj
.getAnyRelocationLength(MachOReloc
);
906 uint64_t Offset64
= Reloc
.getOffset();
907 if ((RelocSize
!= 4 && RelocSize
!= 8)) {
908 Linker
.reportWarning("unsupported relocation in " + *Section
.getName() +
910 DMO
.getObjectFilename());
913 uint64_t OffsetCopy
= Offset64
;
914 // Mach-o uses REL relocations, the addend is at the relocation offset.
915 uint64_t Addend
= Data
.getUnsigned(&OffsetCopy
, RelocSize
);
919 if (Obj
.isRelocationScattered(MachOReloc
)) {
920 // The address of the base symbol for scattered relocations is
921 // stored in the reloc itself. The actual addend will store the
922 // base address plus the offset.
923 SymAddress
= Obj
.getScatteredRelocationValue(MachOReloc
);
924 SymOffset
= int64_t(Addend
) - SymAddress
;
930 auto Sym
= Reloc
.getSymbol();
931 if (Sym
!= Obj
.symbol_end()) {
932 Expected
<StringRef
> SymbolName
= Sym
->getName();
934 consumeError(SymbolName
.takeError());
935 Linker
.reportWarning("error getting relocation symbol name.",
936 DMO
.getObjectFilename());
939 if (const auto *Mapping
= DMO
.lookupSymbol(*SymbolName
))
940 ValidRelocs
.emplace_back(Offset64
, RelocSize
, Addend
, Mapping
->getKey(),
941 Mapping
->getValue());
942 } else if (const auto *Mapping
= DMO
.lookupObjectAddress(SymAddress
)) {
943 // Do not store the addend. The addend was the address of the symbol in
944 // the object file, the address in the binary that is stored in the debug
945 // map doesn't need to be offset.
946 ValidRelocs
.emplace_back(Offset64
, RelocSize
, SymOffset
,
947 Mapping
->getKey(), Mapping
->getValue());
952 /// Dispatch the valid relocation finding logic to the
953 /// appropriate handler depending on the object file format.
954 bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
955 const object::SectionRef
&Section
, const object::ObjectFile
&Obj
,
956 const DebugMapObject
&DMO
, std::vector
<ValidReloc
> &Relocs
) {
957 // Dispatch to the right handler depending on the file type.
958 if (auto *MachOObj
= dyn_cast
<object::MachOObjectFile
>(&Obj
))
959 findValidRelocsMachO(Section
, *MachOObj
, DMO
, Relocs
);
961 Linker
.reportWarning(Twine("unsupported object file type: ") +
963 DMO
.getObjectFilename());
967 // Sort the relocations by offset. We will walk the DIEs linearly in
968 // the file, this allows us to just keep an index in the relocation
969 // array that we advance during our walk, rather than resorting to
970 // some associative container. See DwarfLinkerForBinary::NextValidReloc.
975 /// Look for relocations in the debug_info and debug_addr section that match
976 /// entries in the debug map. These relocations will drive the Dwarf link by
977 /// indicating which DIEs refer to symbols present in the linked binary.
978 /// \returns whether there are any valid relocations in the debug info.
979 bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
980 const object::ObjectFile
&Obj
, const DebugMapObject
&DMO
) {
981 // Find the debug_info section.
982 bool FoundValidRelocs
= false;
983 for (const object::SectionRef
&Section
: Obj
.sections()) {
984 StringRef SectionName
;
985 if (Expected
<StringRef
> NameOrErr
= Section
.getName())
986 SectionName
= *NameOrErr
;
988 consumeError(NameOrErr
.takeError());
990 SectionName
= SectionName
.substr(SectionName
.find_first_not_of("._"));
991 if (SectionName
== "debug_info")
993 findValidRelocs(Section
, Obj
, DMO
, ValidDebugInfoRelocs
);
994 if (SectionName
== "debug_addr")
996 findValidRelocs(Section
, Obj
, DMO
, ValidDebugAddrRelocs
);
998 return FoundValidRelocs
;
1001 std::vector
<ValidReloc
> DwarfLinkerForBinary::AddressManager::getRelocations(
1002 const std::vector
<ValidReloc
> &Relocs
, uint64_t StartPos
, uint64_t EndPos
) {
1003 std::vector
<ValidReloc
> Res
;
1005 auto CurReloc
= partition_point(Relocs
, [StartPos
](const ValidReloc
&Reloc
) {
1006 return (uint64_t)Reloc
.Offset
< StartPos
;
1009 while (CurReloc
!= Relocs
.end() && CurReloc
->Offset
>= StartPos
&&
1010 (uint64_t)CurReloc
->Offset
< EndPos
) {
1011 Res
.push_back(*CurReloc
);
1018 void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc
&Reloc
) {
1019 const auto &Mapping
= Reloc
.SymbolMapping
;
1020 const uint64_t ObjectAddress
= Mapping
.ObjectAddress
1021 ? uint64_t(*Mapping
.ObjectAddress
)
1022 : std::numeric_limits
<uint64_t>::max();
1024 outs() << "Found valid debug map entry: " << Reloc
.SymbolName
<< "\t"
1025 << format("0x%016" PRIx64
" => 0x%016" PRIx64
"\n", ObjectAddress
,
1026 uint64_t(Mapping
.BinaryAddress
));
1030 DwarfLinkerForBinary::AddressManager::getRelocValue(const ValidReloc
&Reloc
) {
1031 int64_t AddrAdjust
= relocate(Reloc
);
1032 if (Reloc
.SymbolMapping
.ObjectAddress
)
1033 AddrAdjust
-= uint64_t(*Reloc
.SymbolMapping
.ObjectAddress
);
1037 std::optional
<int64_t>
1038 DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
1039 const std::vector
<ValidReloc
> &AllRelocs
, uint64_t StartOffset
,
1040 uint64_t EndOffset
, bool Verbose
) {
1041 std::vector
<ValidReloc
> Relocs
=
1042 getRelocations(AllRelocs
, StartOffset
, EndOffset
);
1043 if (Relocs
.size() == 0)
1044 return std::nullopt
;
1047 printReloc(Relocs
[0]);
1049 return getRelocValue(Relocs
[0]);
1052 /// Get the starting and ending (exclusive) offset for the
1053 /// attribute with index \p Idx descibed by \p Abbrev. \p Offset is
1054 /// supposed to point to the position of the first attribute described
1056 /// \return [StartOffset, EndOffset) as a pair.
1057 static std::pair
<uint64_t, uint64_t>
1058 getAttributeOffsets(const DWARFAbbreviationDeclaration
*Abbrev
, unsigned Idx
,
1059 uint64_t Offset
, const DWARFUnit
&Unit
) {
1060 DataExtractor Data
= Unit
.getDebugInfoExtractor();
1062 for (unsigned I
= 0; I
< Idx
; ++I
)
1063 DWARFFormValue::skipValue(Abbrev
->getFormByIndex(I
), Data
, &Offset
,
1064 Unit
.getFormParams());
1066 uint64_t End
= Offset
;
1067 DWARFFormValue::skipValue(Abbrev
->getFormByIndex(Idx
), Data
, &End
,
1068 Unit
.getFormParams());
1070 return std::make_pair(Offset
, End
);
1073 std::optional
<int64_t>
1074 DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(
1075 DWARFUnit
&U
, const DWARFExpression::Operation
&Op
, uint64_t StartOffset
,
1076 uint64_t EndOffset
, bool Verbose
) {
1077 switch (Op
.getCode()) {
1079 assert(false && "Specified operation does not have address operand");
1081 case dwarf::DW_OP_const2u
:
1082 case dwarf::DW_OP_const4u
:
1083 case dwarf::DW_OP_const8u
:
1084 case dwarf::DW_OP_const2s
:
1085 case dwarf::DW_OP_const4s
:
1086 case dwarf::DW_OP_const8s
:
1087 case dwarf::DW_OP_addr
: {
1088 return hasValidRelocationAt(ValidDebugInfoRelocs
, StartOffset
, EndOffset
,
1091 case dwarf::DW_OP_constx
:
1092 case dwarf::DW_OP_addrx
: {
1093 return hasValidRelocationAt(ValidDebugAddrRelocs
, StartOffset
, EndOffset
,
1098 return std::nullopt
;
1101 std::optional
<int64_t>
1102 DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(
1103 const DWARFDie
&DIE
, bool Verbose
) {
1104 const auto *Abbrev
= DIE
.getAbbreviationDeclarationPtr();
1106 std::optional
<uint32_t> LowPcIdx
=
1107 Abbrev
->findAttributeIndex(dwarf::DW_AT_low_pc
);
1109 return std::nullopt
;
1111 dwarf::Form Form
= Abbrev
->getFormByIndex(*LowPcIdx
);
1114 case dwarf::DW_FORM_addr
: {
1115 uint64_t Offset
= DIE
.getOffset() + getULEB128Size(Abbrev
->getCode());
1116 uint64_t LowPcOffset
, LowPcEndOffset
;
1117 std::tie(LowPcOffset
, LowPcEndOffset
) =
1118 getAttributeOffsets(Abbrev
, *LowPcIdx
, Offset
, *DIE
.getDwarfUnit());
1119 return hasValidRelocationAt(ValidDebugInfoRelocs
, LowPcOffset
,
1120 LowPcEndOffset
, Verbose
);
1122 case dwarf::DW_FORM_addrx
:
1123 case dwarf::DW_FORM_addrx1
:
1124 case dwarf::DW_FORM_addrx2
:
1125 case dwarf::DW_FORM_addrx3
:
1126 case dwarf::DW_FORM_addrx4
: {
1127 std::optional
<DWARFFormValue
> AddrValue
= DIE
.find(dwarf::DW_AT_low_pc
);
1128 if (std::optional
<uint64_t> AddressOffset
=
1129 DIE
.getDwarfUnit()->getIndexedAddressOffset(
1130 AddrValue
->getRawUValue()))
1131 return hasValidRelocationAt(
1132 ValidDebugAddrRelocs
, *AddressOffset
,
1133 *AddressOffset
+ DIE
.getDwarfUnit()->getAddressByteSize(), Verbose
);
1135 Linker
.reportWarning("no base offset for address table", SrcFileName
);
1136 return std::nullopt
;
1139 return std::nullopt
;
1143 std::optional
<StringRef
>
1144 DwarfLinkerForBinary::AddressManager::getLibraryInstallName() {
1145 return LibInstallName
;
1149 DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc
&Reloc
) const {
1150 return Reloc
.SymbolMapping
.BinaryAddress
+ Reloc
.Addend
;
1153 void DwarfLinkerForBinary::AddressManager::updateAndSaveValidRelocs(
1154 bool IsDWARF5
, uint64_t OriginalUnitOffset
, int64_t LinkedOffset
,
1155 uint64_t StartOffset
, uint64_t EndOffset
) {
1156 std::vector
<ValidReloc
> InRelocs
=
1157 getRelocations(ValidDebugInfoRelocs
, StartOffset
, EndOffset
);
1159 InRelocs
= getRelocations(ValidDebugAddrRelocs
, StartOffset
, EndOffset
);
1160 DwarfLinkerRelocMap
->updateAndSaveValidRelocs(
1161 IsDWARF5
, InRelocs
, OriginalUnitOffset
, LinkedOffset
);
1164 void DwarfLinkerForBinary::AddressManager::updateRelocationsWithUnitOffset(
1165 uint64_t OriginalUnitOffset
, uint64_t OutputUnitOffset
) {
1166 DwarfLinkerRelocMap
->updateRelocationsWithUnitOffset(OriginalUnitOffset
,
1169 /// Apply the valid relocations found by findValidRelocs() to
1170 /// the buffer \p Data, taking into account that Data is at \p BaseOffset
1171 /// in the debug_info section.
1173 /// Like for findValidRelocs(), this function must be called with
1174 /// monotonic \p BaseOffset values.
1176 /// \returns whether any reloc has been applied.
1177 bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
1178 MutableArrayRef
<char> Data
, uint64_t BaseOffset
, bool IsLittleEndian
) {
1180 std::vector
<ValidReloc
> Relocs
= getRelocations(
1181 ValidDebugInfoRelocs
, BaseOffset
, BaseOffset
+ Data
.size());
1183 for (const ValidReloc
&CurReloc
: Relocs
) {
1184 assert(CurReloc
.Offset
- BaseOffset
< Data
.size());
1185 assert(CurReloc
.Offset
- BaseOffset
+ CurReloc
.Size
<= Data
.size());
1187 uint64_t Value
= relocate(CurReloc
);
1188 for (unsigned I
= 0; I
!= CurReloc
.Size
; ++I
) {
1189 unsigned Index
= IsLittleEndian
? I
: (CurReloc
.Size
- I
- 1);
1190 Buf
[I
] = uint8_t(Value
>> (Index
* 8));
1192 assert(CurReloc
.Size
<= sizeof(Buf
));
1193 memcpy(&Data
[CurReloc
.Offset
- BaseOffset
], Buf
, CurReloc
.Size
);
1195 return Relocs
.size() > 0;
1198 void DwarfLinkerForBinaryRelocationMap::init(DWARFContext
&Context
) {
1199 for (const std::unique_ptr
<DWARFUnit
> &CU
: Context
.compile_units())
1200 StoredValidDebugInfoRelocsMap
.insert(
1201 std::make_pair(CU
->getOffset(), std::vector
<ValidReloc
>()));
1202 // FIXME: Support relocations debug_addr (DWARF5).
1205 void DwarfLinkerForBinaryRelocationMap::addValidRelocs(RelocationMap
&RM
) {
1206 for (const auto &DebugInfoRelocs
: StoredValidDebugInfoRelocsMap
) {
1207 for (const auto &InfoReloc
: DebugInfoRelocs
.second
)
1208 RM
.addRelocationMapEntry(InfoReloc
);
1210 // FIXME: Support relocations debug_addr (DWARF5).
1213 void DwarfLinkerForBinaryRelocationMap::updateRelocationsWithUnitOffset(
1214 uint64_t OriginalUnitOffset
, uint64_t OutputUnitOffset
) {
1215 std::vector
<ValidReloc
> &StoredValidDebugInfoRelocs
=
1216 StoredValidDebugInfoRelocsMap
[OriginalUnitOffset
];
1217 for (ValidReloc
&R
: StoredValidDebugInfoRelocs
) {
1218 R
.Offset
= (uint64_t)R
.Offset
+ OutputUnitOffset
;
1220 // FIXME: Support relocations debug_addr (DWARF5).
1223 void DwarfLinkerForBinaryRelocationMap::updateAndSaveValidRelocs(
1224 bool IsDWARF5
, std::vector
<ValidReloc
> &InRelocs
, uint64_t UnitOffset
,
1225 int64_t LinkedOffset
) {
1226 std::vector
<ValidReloc
> &OutRelocs
=
1227 StoredValidDebugInfoRelocsMap
[UnitOffset
];
1229 OutRelocs
= StoredValidDebugAddrRelocsMap
[UnitOffset
];
1231 for (ValidReloc
&R
: InRelocs
) {
1232 OutRelocs
.emplace_back(R
.Offset
+ LinkedOffset
, R
.Size
, R
.Addend
,
1233 R
.SymbolName
, R
.SymbolMapping
);
1237 } // namespace dsymutil