Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / tools / dsymutil / DwarfLinkerForBinary.cpp
bloba8fea1e2712271db29bfb7002ac8325fee170898
1 //===- tools/dsymutil/DwarfLinkerForBinary.cpp ----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "DwarfLinkerForBinary.h"
10 #include "BinaryHolder.h"
11 #include "DebugMap.h"
12 #include "MachOUtils.h"
13 #include "dsymutil.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"
86 #include <algorithm>
87 #include <cassert>
88 #include <cinttypes>
89 #include <climits>
90 #include <cstdint>
91 #include <cstdlib>
92 #include <cstring>
93 #include <limits>
94 #include <map>
95 #include <memory>
96 #include <optional>
97 #include <string>
98 #include <system_error>
99 #include <tuple>
100 #include <utility>
101 #include <vector>
103 namespace llvm {
105 static mc::RegisterMCTargetOptionsFlags MOF;
107 namespace dsymutil {
109 static void dumpDIE(const DWARFDie *DIE, bool Verbose) {
110 if (!DIE || !Verbose)
111 return;
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) {
146 auto ObjectEntry =
147 BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp());
148 if (!ObjectEntry) {
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);
157 if (!Object) {
158 auto Err = Object.takeError();
159 reportWarning(Twine(Obj.getObjectFilename()) + ": " +
160 toString(std::move(Err)),
161 Obj.getObjectFilename());
162 return errorToErrorCode(std::move(Err));
165 return *Object;
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
173 // archives.
174 if (!IsArchive)
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());
187 if (!NewE)
188 return Error::success();
190 return createFileError(FE->getFileName(), std::move(NewE));
192 template <typename OutDwarfFile, typename AddressMap>
193 Error DwarfLinkerForBinary::emitRelocations(
194 const DebugMap &DM,
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())
203 continue;
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()));
220 Path.append(".yml");
222 std::error_code EC;
223 raw_fd_ostream OS(Path.str(), EC, sys::fs::OF_Text);
224 if (EC)
225 return errorCodeToError(EC);
227 RM.print(OS);
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
234 // to serialize.
235 if (RL.empty())
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.
251 Path += '-';
252 Path += ArchName;
255 std::error_code EC;
256 raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC,
257 Options.RemarksFormat == remarks::Format::Bitstream
258 ? sys::fs::OF_None
259 : sys::fs::OF_Text);
260 if (EC)
261 return errorCodeToError(EC);
263 if (Error E = RL.serialize(OS, Options.RemarksFormat))
264 return E;
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;
277 if (ErrorOrObj) {
278 auto Context = DWARFContext::create(
279 *ErrorOrObj, DWARFContext::ProcessDebugRelocations::Process, nullptr,
281 [&](Error Err) {
282 handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
283 reportError(Info.message());
286 [&](Error Warning) {
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.
321 if (!ObjectEntry) {
322 // Any errors will be diagnosed later in the main loop, ignore them here.
323 llvm::consumeError(ObjectEntry.takeError());
324 return false;
327 auto Object =
328 ObjectEntry->getObjectAs<object::MachOObjectFile>(Map.getTriple());
329 if (!Object) {
330 // Any errors will be diagnosed later in the main loop, ignore them here.
331 llvm::consumeError(Object.takeError());
332 return false;
335 for (auto &Section : Object->sections()) {
336 llvm::Expected<llvm::StringRef> NameOrErr =
337 Object->getSectionName(Section.getRawDataRefImpl());
338 if (!NameOrErr) {
339 llvm::consumeError(NameOrErr.takeError());
340 continue;
342 NameOrErr->consume_back("__TEXT");
343 auto ReflectionSectionKind =
344 Object->mapReflectionSectionNameToEnumValue(*NameOrErr);
345 if (Object->isReflectionSectionStrippable(ReflectionSectionKind)) {
346 return true;
350 return false;
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()) {
362 auto OF =
363 llvm::object::ObjectFile::createObjectFile(Obj->getObjectFilename());
364 if (!OF) {
365 llvm::consumeError(OF.takeError());
366 continue;
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());
372 if (!NameOrErr) {
373 llvm::consumeError(NameOrErr.takeError());
374 continue;
376 NameOrErr->consume_back("__TEXT");
377 auto ReflSectionKind =
378 MO->mapReflectionSectionNameToEnumValue(*NameOrErr);
379 switch (ReflSectionKind) {
380 case Swift5ReflectionSectionKind::assocty:
381 AssocTySize += Section.getSize();
382 break;
383 case Swift5ReflectionSectionKind::fieldmd:
384 FieldMdSize += Section.getSize();
385 break;
386 default:
387 break;
392 // Initialize the vector with enough space to fit every reflection section
393 // kind.
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)
410 const {
411 for (auto It = Section.relocation_begin(); It != Section.relocation_end();
412 ++It) {
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())) {
418 reportWarning(
419 "Unimplemented relocation type in strippable reflection section ",
420 Obj->getObjectFilename());
421 continue;
424 auto CalculateAddressOfSymbolInDwarfSegment =
425 [&]() -> std::optional<int64_t> {
426 auto Symbol = It->getSymbol();
427 auto SymbolAbsoluteAddress = Symbol->getAddress();
428 if (!SymbolAbsoluteAddress)
429 return {};
430 auto Section = Symbol->getSection();
431 if (!Section) {
432 llvm::consumeError(Section.takeError());
433 return {};
436 if ((*Section)->getObject()->section_end() == *Section)
437 return {};
439 auto SectionStart = (*Section)->getAddress();
440 auto SymbolAddressInSection = *SymbolAbsoluteAddress - SectionStart;
441 auto SectionName = (*Section)->getName();
442 if (!SectionName)
443 return {};
444 auto ReflSectionKind =
445 MO->mapReflectionSectionNameToEnumValue(*SectionName);
447 int64_t SectionStartInLinkedBinary =
448 SectionToOffsetInDwarf[ReflSectionKind];
450 auto Addr = SectionStartInLinkedBinary + SymbolAddressInSection;
451 return Addr;
454 // The first symbol should always be in the section we're currently
455 // iterating over.
456 auto FirstSymbolAddress = CalculateAddressOfSymbolInDwarfSegment();
457 ++It;
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();
465 if (SymbolName) {
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)
488 continue;
490 auto SectionName = Section.getName();
491 if (!SectionName)
492 continue;
494 int32_t Addend;
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 {
507 std::error_code EC;
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()) {
521 InputPath.clear();
522 sys::path::append(InputPath, Options.PrependPath, InterfaceFile);
523 InterfaceFile = InputPath;
525 sys::path::append(Path, ModuleName);
526 Path.append(".swiftinterface");
527 if (Options.Verbose)
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;
547 auto OF =
548 llvm::object::ObjectFile::createObjectFile(Obj->getObjectFilename());
549 if (!OF) {
550 llvm::consumeError(OF.takeError());
551 return;
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>
558 SwiftSections;
559 for (auto &Section : MO->sections()) {
560 llvm::Expected<llvm::StringRef> NameOrErr =
561 MO->getSectionName(Section.getRawDataRefImpl());
562 if (!NameOrErr) {
563 llvm::consumeError(NameOrErr.takeError());
564 continue;
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])
578 continue;
579 auto &Section = *SwiftSections[SectionKind];
580 llvm::Expected<llvm::StringRef> SectionContents = Section.getContents();
581 if (!SectionContents)
582 continue;
583 const auto *MO =
584 llvm::cast<llvm::object::MachOObjectFile>(Section.getObject());
585 collectRelocationsToApplyToSwiftReflectionSections(
586 Section, *SectionContents, MO, SectionToOffsetInDwarf, Obj,
587 RelocationsToApply);
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
590 // place.
591 SectionToOffsetInDwarf[SectionKind] += Section.getSize();
592 Streamer->emitSwiftReflectionSection(SectionKind, *SectionContents,
593 Section.getAlignment().value(),
594 Section.getSize());
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;
606 break;
608 case DWARFLinker::OutputFileType::Assembly:
609 DWARFLinkerOutputType =
610 dwarflinker_parallel::DWARFLinker::OutputFileType::Assembly;
611 break;
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) {
628 switch (TableKind) {
629 case DsymutilAccelTableKind::Apple:
630 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple);
631 return;
632 case DsymutilAccelTableKind::Dwarf:
633 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames);
634 return;
635 case DsymutilAccelTableKind::Pub:
636 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Pub);
637 return;
638 case DsymutilAccelTableKind::Default:
639 if (MaxDWARFVersion >= 5)
640 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames);
641 else
642 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple);
643 return;
644 case DsymutilAccelTableKind::None:
645 // Nothing to do.
646 return;
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,
676 OutFile)) {
677 handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
678 reportError(EI.message(), "dwarf streamer init");
680 return false;
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);
700 if (Options.Verbose)
701 errs() << Output;
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,
713 DLBRelocMap)) {
714 ObjectsForLinking.emplace_back(std::move(*ErrorOrObj), DLBRelocMap);
715 return *ObjectsForLinking.back().Object;
716 } else {
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(")");
722 if (IsClangModule) {
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
728 // now.
729 if (!ModuleCacheHintDisplayed) {
730 WithColor::note()
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
741 // a project though.
742 if (!ArchiveHintDisplayed) {
743 WithColor::note()
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) {
788 if (Options.Verbose)
789 outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
791 StringRef File = Obj->getObjectFilename();
792 auto ErrorOrMem = MemoryBuffer::getFile(File);
793 if (!ErrorOrMem) {
794 reportWarning("Could not open '" + File + "'");
795 continue;
797 sys::fs::file_status Stat;
798 if (auto Err = sys::fs::status(File, Stat)) {
799 reportWarning(Err.message());
800 continue;
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<>.
811 WithColor::warning()
812 << File << ": timestamp mismatch between swift interface file ("
813 << sys::TimePoint<>(ModificationTime) << ") and debug map ("
814 << sys::TimePoint<>(Obj->getTimestamp()) << ")\n";
815 continue;
819 // Copy the module into the .swift_ast section.
820 if (!Options.NoOutput)
821 GeneralLinker->getEmitter()->emitSwiftAST((*ErrorOrMem)->getBuffer());
823 continue;
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,
831 OnCUDieLoaded);
832 } else {
833 ObjectsForLinking.push_back(
834 {std::make_unique<OutDwarfFile>(Obj->getObjectFilename(), nullptr,
835 nullptr),
836 DLBRelocMap});
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)
843 MaxDWARFVersion = 3;
845 if (Error E = GeneralLinker->setTargetDWARFVersion(MaxDWARFVersion))
846 return error(toString(std::move(E)));
848 setAcceleratorTables<Linker>(*GeneralLinker, Options.TheAccelTableKind,
849 MaxDWARFVersion);
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)
860 return true;
862 if (Error E =
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,
877 RelocationsToApply);
879 GeneralLinker->getEmitter()->finish();
880 return true;
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());
896 return;
898 DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0);
899 bool SkipNext = false;
901 for (const object::RelocationRef &Reloc : Section.relocations()) {
902 if (SkipNext) {
903 SkipNext = false;
904 continue;
907 object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
908 MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
910 if (object::MachOObjectFile::isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
911 Obj.getArch())) {
912 SkipNext = true;
913 Linker.reportWarning("unsupported relocation in " + *Section.getName() +
914 " section.",
915 DMO.getObjectFilename());
916 continue;
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() +
923 " section.",
924 DMO.getObjectFilename());
925 continue;
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);
930 uint64_t SymAddress;
931 int64_t SymOffset;
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;
939 } else {
940 SymAddress = Addend;
941 SymOffset = 0;
944 auto Sym = Reloc.getSymbol();
945 if (Sym != Obj.symbol_end()) {
946 Expected<StringRef> SymbolName = Sym->getName();
947 if (!SymbolName) {
948 consumeError(SymbolName.takeError());
949 Linker.reportWarning("error getting relocation symbol name.",
950 DMO.getObjectFilename());
951 continue;
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);
975 else
976 Linker.reportWarning(Twine("unsupported object file type: ") +
977 Obj.getFileName(),
978 DMO.getObjectFilename());
979 if (Relocs.empty())
980 return false;
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.
986 llvm::sort(Relocs);
987 return true;
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;
1004 else
1005 consumeError(NameOrErr.takeError());
1007 SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
1008 if (SectionName == "debug_info")
1009 FoundValidRelocs |=
1010 findValidRelocs(Section, Obj, DMO, ValidDebugInfoRelocs);
1011 if (SectionName == "debug_addr")
1012 FoundValidRelocs |=
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);
1031 CurReloc++;
1034 return Res;
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);
1056 return AddrAdjust;
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
1079 /// by \p Abbrev.
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()) {
1103 default: {
1104 assert(false && "Specified operation does not have address operand");
1105 } break;
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);
1114 } break;
1115 case dwarf::DW_OP_constx:
1116 case dwarf::DW_OP_addrx: {
1117 return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset);
1118 } break;
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);
1131 if (!LowPcIdx)
1132 return std::nullopt;
1134 dwarf::Form Form = Abbrev->getFormByIndex(*LowPcIdx);
1136 switch (Form) {
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,
1143 LowPcEndOffset);
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,
1155 *AddressOffset +
1156 DIE.getDwarfUnit()->getAddressByteSize());
1158 Linker.reportWarning("no base offset for address table", SrcFileName);
1159 return std::nullopt;
1161 default:
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);
1187 if (IsDWARF5)
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,
1198 OutputUnitOffset);
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());
1218 char Buf[8];
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];
1260 if (IsDWARF5)
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
1270 } // namespace llvm