Fix test failures introduced by PR #113697 (#116941)
[llvm-project.git] / llvm / tools / dsymutil / DwarfLinkerForBinary.cpp
blobf6a35708dc0765f14183416da388ad811ac2fd25
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/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"
83 #include <algorithm>
84 #include <cassert>
85 #include <cinttypes>
86 #include <climits>
87 #include <cstdint>
88 #include <cstdlib>
89 #include <cstring>
90 #include <limits>
91 #include <map>
92 #include <memory>
93 #include <optional>
94 #include <string>
95 #include <system_error>
96 #include <tuple>
97 #include <utility>
98 #include <vector>
100 namespace llvm {
102 static mc::RegisterMCTargetOptionsFlags MOF;
104 using namespace dwarf_linker;
106 namespace dsymutil {
108 static void dumpDIE(const DWARFDie *DIE, bool Verbose) {
109 if (!DIE || !Verbose)
110 return;
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) {
145 auto ObjectEntry =
146 BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp());
147 if (!ObjectEntry) {
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);
156 if (!Object) {
157 auto Err = Object.takeError();
158 reportWarning(Twine(Obj.getObjectFilename()) + ": " +
159 toStringWithoutConsuming(Err),
160 Obj.getObjectFilename());
161 return errorToErrorCode(std::move(Err));
164 return *Object;
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
172 // archives.
173 if (!IsArchive)
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());
186 if (!NewE)
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())
200 continue;
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()));
217 Path.append(".yml");
219 std::error_code EC;
220 raw_fd_ostream OS(Path.str(), EC, sys::fs::OF_Text);
221 if (EC)
222 return errorCodeToError(EC);
224 RM.print(OS);
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
231 // to serialize.
232 if (RL.empty())
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.
248 Path += '-';
249 Path += ArchName;
252 std::error_code EC;
253 raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC,
254 Options.RemarksFormat == remarks::Format::Bitstream
255 ? sys::fs::OF_None
256 : sys::fs::OF_Text);
257 if (EC)
258 return errorCodeToError(EC);
260 if (Error E = RL.serialize(OS, Options.RemarksFormat))
261 return E;
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;
273 if (ErrorOrObj) {
274 auto Context = DWARFContext::create(
275 *ErrorOrObj, DWARFContext::ProcessDebugRelocations::Process, nullptr,
277 [&](Error Err) {
278 handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
279 reportError(Info.message());
282 [&](Error Warning) {
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.
317 if (!ObjectEntry) {
318 // Any errors will be diagnosed later in the main loop, ignore them here.
319 llvm::consumeError(ObjectEntry.takeError());
320 return false;
323 auto Object =
324 ObjectEntry->getObjectAs<object::MachOObjectFile>(Map.getTriple());
325 if (!Object) {
326 // Any errors will be diagnosed later in the main loop, ignore them here.
327 llvm::consumeError(Object.takeError());
328 return false;
331 for (auto &Section : Object->sections()) {
332 llvm::Expected<llvm::StringRef> NameOrErr =
333 Object->getSectionName(Section.getRawDataRefImpl());
334 if (!NameOrErr) {
335 llvm::consumeError(NameOrErr.takeError());
336 continue;
338 NameOrErr->consume_back("__TEXT");
339 auto ReflectionSectionKind =
340 Object->mapReflectionSectionNameToEnumValue(*NameOrErr);
341 if (Object->isReflectionSectionStrippable(ReflectionSectionKind)) {
342 return true;
346 return false;
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()) {
358 auto OF =
359 llvm::object::ObjectFile::createObjectFile(Obj->getObjectFilename());
360 if (!OF) {
361 llvm::consumeError(OF.takeError());
362 continue;
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());
368 if (!NameOrErr) {
369 llvm::consumeError(NameOrErr.takeError());
370 continue;
372 NameOrErr->consume_back("__TEXT");
373 auto ReflSectionKind =
374 MO->mapReflectionSectionNameToEnumValue(*NameOrErr);
375 switch (ReflSectionKind) {
376 case Swift5ReflectionSectionKind::assocty:
377 AssocTySize += Section.getSize();
378 break;
379 case Swift5ReflectionSectionKind::fieldmd:
380 FieldMdSize += Section.getSize();
381 break;
382 default:
383 break;
388 // Initialize the vector with enough space to fit every reflection section
389 // kind.
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)
406 const {
407 for (auto It = Section.relocation_begin(); It != Section.relocation_end();
408 ++It) {
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())) {
414 reportWarning(
415 "Unimplemented relocation type in strippable reflection section ",
416 Obj->getObjectFilename());
417 continue;
420 auto CalculateAddressOfSymbolInDwarfSegment =
421 [&]() -> std::optional<int64_t> {
422 auto Symbol = It->getSymbol();
423 auto SymbolAbsoluteAddress = Symbol->getAddress();
424 if (!SymbolAbsoluteAddress)
425 return {};
426 auto Section = Symbol->getSection();
427 if (!Section) {
428 llvm::consumeError(Section.takeError());
429 return {};
432 if ((*Section)->getObject()->section_end() == *Section)
433 return {};
435 auto SectionStart = (*Section)->getAddress();
436 auto SymbolAddressInSection = *SymbolAbsoluteAddress - SectionStart;
437 auto SectionName = (*Section)->getName();
438 if (!SectionName)
439 return {};
440 auto ReflSectionKind =
441 MO->mapReflectionSectionNameToEnumValue(*SectionName);
443 int64_t SectionStartInLinkedBinary =
444 SectionToOffsetInDwarf[ReflSectionKind];
446 auto Addr = SectionStartInLinkedBinary + SymbolAddressInSection;
447 return Addr;
450 // The first symbol should always be in the section we're currently
451 // iterating over.
452 auto FirstSymbolAddress = CalculateAddressOfSymbolInDwarfSegment();
453 ++It;
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();
461 if (SymbolName) {
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)
484 continue;
486 auto SectionName = Section.getName();
487 if (!SectionName)
488 continue;
490 int32_t Addend;
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 {
503 std::error_code EC;
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()) {
517 InputPath.clear();
518 sys::path::append(InputPath, Options.PrependPath, InterfaceFile);
519 InterfaceFile = InputPath;
521 sys::path::append(Path, ModuleName);
522 Path.append(".swiftinterface");
523 if (Options.Verbose)
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;
542 auto OF =
543 llvm::object::ObjectFile::createObjectFile(Obj->getObjectFilename());
544 if (!OF) {
545 llvm::consumeError(OF.takeError());
546 return;
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>
553 SwiftSections;
554 for (auto &Section : MO->sections()) {
555 llvm::Expected<llvm::StringRef> NameOrErr =
556 MO->getSectionName(Section.getRawDataRefImpl());
557 if (!NameOrErr) {
558 llvm::consumeError(NameOrErr.takeError());
559 continue;
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])
573 continue;
574 auto &Section = *SwiftSections[SectionKind];
575 llvm::Expected<llvm::StringRef> SectionContents = Section.getContents();
576 if (!SectionContents)
577 continue;
578 const auto *MO =
579 llvm::cast<llvm::object::MachOObjectFile>(Section.getObject());
580 collectRelocationsToApplyToSwiftReflectionSections(
581 Section, *SectionContents, MO, SectionToOffsetInDwarf, Obj,
582 RelocationsToApply);
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
585 // place.
586 SectionToOffsetInDwarf[SectionKind] += Section.getSize();
587 Streamer->emitSwiftReflectionSection(SectionKind, *SectionContents,
588 Section.getAlignment().value(),
589 Section.getSize());
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) {
605 switch (TableKind) {
606 case DsymutilAccelTableKind::Apple:
607 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple);
608 return;
609 case DsymutilAccelTableKind::Dwarf:
610 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames);
611 return;
612 case DsymutilAccelTableKind::Pub:
613 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Pub);
614 return;
615 case DsymutilAccelTableKind::Default:
616 if (MaxDWARFVersion >= 5)
617 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames);
618 else
619 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple);
620 return;
621 case DsymutilAccelTableKind::None:
622 // Nothing to do.
623 return;
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);
655 else {
656 handleAllErrors(StreamerOrErr.takeError(), [&](const ErrorInfoBase &EI) {
657 reportError(EI.message(), "dwarf streamer init");
659 return false;
662 if constexpr (std::is_same<Linker, parallel::DWARFLinker>::value) {
663 GeneralLinker->setOutputDWARFHandler(
664 Map.getTriple(),
665 [&](std::shared_ptr<parallel::SectionDescriptorBase> Section) {
666 Streamer->emitSectionContents(Section->getContents(),
667 Section->getKind());
669 } else
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);
690 if (Options.Verbose)
691 errs() << Output;
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;
705 } else {
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(")");
711 if (IsClangModule) {
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
717 // now.
718 if (!ModuleCacheHintDisplayed) {
719 WithColor::note()
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
730 // a project though.
731 if (!ArchiveHintDisplayed) {
732 WithColor::note()
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) {
777 if (Options.Verbose)
778 outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
780 StringRef File = Obj->getObjectFilename();
781 auto ErrorOrMem = MemoryBuffer::getFile(File);
782 if (!ErrorOrMem) {
783 reportWarning("Could not open '" + File + "'");
784 continue;
786 sys::fs::file_status Stat;
787 if (auto Err = sys::fs::status(File, Stat)) {
788 reportWarning(Err.message());
789 continue;
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<>.
800 WithColor::warning()
801 << File << ": timestamp mismatch between swift interface file ("
802 << sys::TimePoint<>(ModificationTime) << ") and debug map ("
803 << sys::TimePoint<>(Obj->getTimestamp()) << ")\n";
804 continue;
808 // Copy the module into the .swift_ast section.
809 if (!Options.NoOutput)
810 Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
812 continue;
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,
820 OnCUDieLoaded);
821 } else {
822 ObjectsForLinking.push_back(
823 {std::make_unique<DWARFFile>(Obj->getObjectFilename(), nullptr,
824 nullptr),
825 DLBRelocMap});
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)
832 MaxDWARFVersion = 3;
834 if (Error E = GeneralLinker->setTargetDWARFVersion(MaxDWARFVersion))
835 return error(toString(std::move(E)));
837 setAcceleratorTables<Linker>(*GeneralLinker, Options.TheAccelTableKind,
838 MaxDWARFVersion);
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)
849 return true;
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,
866 RelocationsToApply);
868 Streamer->finish();
869 return true;
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());
882 return;
884 DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0);
885 bool SkipNext = false;
887 for (const object::RelocationRef &Reloc : Section.relocations()) {
888 if (SkipNext) {
889 SkipNext = false;
890 continue;
893 object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
894 MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
896 if (object::MachOObjectFile::isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
897 Obj.getArch())) {
898 SkipNext = true;
899 Linker.reportWarning("unsupported relocation in " + *Section.getName() +
900 " section.",
901 DMO.getObjectFilename());
902 continue;
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() +
909 " section.",
910 DMO.getObjectFilename());
911 continue;
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);
916 uint64_t SymAddress;
917 int64_t SymOffset;
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;
925 } else {
926 SymAddress = Addend;
927 SymOffset = 0;
930 auto Sym = Reloc.getSymbol();
931 if (Sym != Obj.symbol_end()) {
932 Expected<StringRef> SymbolName = Sym->getName();
933 if (!SymbolName) {
934 consumeError(SymbolName.takeError());
935 Linker.reportWarning("error getting relocation symbol name.",
936 DMO.getObjectFilename());
937 continue;
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);
960 else
961 Linker.reportWarning(Twine("unsupported object file type: ") +
962 Obj.getFileName(),
963 DMO.getObjectFilename());
964 if (Relocs.empty())
965 return false;
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.
971 llvm::sort(Relocs);
972 return true;
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;
987 else
988 consumeError(NameOrErr.takeError());
990 SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
991 if (SectionName == "debug_info")
992 FoundValidRelocs |=
993 findValidRelocs(Section, Obj, DMO, ValidDebugInfoRelocs);
994 if (SectionName == "debug_addr")
995 FoundValidRelocs |=
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);
1012 CurReloc++;
1015 return Res;
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));
1029 int64_t
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);
1034 return AddrAdjust;
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;
1046 if (Verbose)
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
1055 /// by \p Abbrev.
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()) {
1078 default: {
1079 assert(false && "Specified operation does not have address operand");
1080 } break;
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,
1089 Verbose);
1090 } break;
1091 case dwarf::DW_OP_constx:
1092 case dwarf::DW_OP_addrx: {
1093 return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset,
1094 Verbose);
1095 } break;
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);
1108 if (!LowPcIdx)
1109 return std::nullopt;
1111 dwarf::Form Form = Abbrev->getFormByIndex(*LowPcIdx);
1113 switch (Form) {
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;
1138 default:
1139 return std::nullopt;
1143 std::optional<StringRef>
1144 DwarfLinkerForBinary::AddressManager::getLibraryInstallName() {
1145 return LibInstallName;
1148 uint64_t
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);
1158 if (IsDWARF5)
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,
1167 OutputUnitOffset);
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());
1186 char Buf[8];
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];
1228 if (IsDWARF5)
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
1238 } // namespace llvm