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//===----------------------------------------------------------------------===//
8
9#include "DwarfLinkerForBinary.h"
10#include "BinaryHolder.h"
11#include "DebugMap.h"
12#include "MachOUtils.h"
13#include "PseudoProbeLinker.h"
14#include "SwiftModule.h"
15#include "dsymutil.h"
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/DenseMap.h"
18#include "llvm/ADT/Hashing.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/ADT/StringSet.h"
23#include "llvm/ADT/Twine.h"
24#include "llvm/BinaryFormat/Dwarf.h"
25#include "llvm/BinaryFormat/MachO.h"
26#include "llvm/BinaryFormat/Swift.h"
27#include "llvm/CodeGen/AccelTable.h"
28#include "llvm/CodeGen/AsmPrinter.h"
29#include "llvm/CodeGen/DIE.h"
30#include "llvm/CodeGen/NonRelocatableStringpool.h"
31#include "llvm/Config/config.h"
32#include "llvm/DWARFLinker/Classic/DWARFLinker.h"
33#include "llvm/DWARFLinker/Classic/DWARFStreamer.h"
34#include "llvm/DWARFLinker/Parallel/DWARFLinker.h"
35#include "llvm/DebugInfo/DIContext.h"
36#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
37#include "llvm/DebugInfo/DWARF/DWARFContext.h"
38#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
39#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
40#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
41#include "llvm/DebugInfo/DWARF/DWARFDie.h"
42#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
43#include "llvm/DebugInfo/DWARF/DWARFSection.h"
44#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
45#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"
46#include "llvm/MC/MCAsmBackend.h"
47#include "llvm/MC/MCAsmInfo.h"
48#include "llvm/MC/MCCodeEmitter.h"
49#include "llvm/MC/MCContext.h"
50#include "llvm/MC/MCDwarf.h"
51#include "llvm/MC/MCInstrInfo.h"
52#include "llvm/MC/MCObjectFileInfo.h"
53#include "llvm/MC/MCObjectWriter.h"
54#include "llvm/MC/MCRegisterInfo.h"
55#include "llvm/MC/MCSection.h"
56#include "llvm/MC/MCStreamer.h"
57#include "llvm/MC/MCSubtargetInfo.h"
58#include "llvm/MC/MCTargetOptions.h"
59#include "llvm/MC/MCTargetOptionsCommandFlags.h"
60#include "llvm/MC/TargetRegistry.h"
61#include "llvm/Object/MachO.h"
62#include "llvm/Object/ObjectFile.h"
63#include "llvm/Object/SymbolicFile.h"
64#include "llvm/Support/Allocator.h"
65#include "llvm/Support/Casting.h"
66#include "llvm/Support/Compiler.h"
67#include "llvm/Support/DJB.h"
68#include "llvm/Support/DataExtractor.h"
69#include "llvm/Support/Error.h"
70#include "llvm/Support/ErrorHandling.h"
71#include "llvm/Support/ErrorOr.h"
72#include "llvm/Support/FileSystem.h"
73#include "llvm/Support/Format.h"
74#include "llvm/Support/LEB128.h"
75#include "llvm/Support/MathExtras.h"
76#include "llvm/Support/MemoryBuffer.h"
77#include "llvm/Support/Path.h"
78#include "llvm/Support/ThreadPool.h"
79#include "llvm/Support/ToolOutputFile.h"
80#include "llvm/Support/WithColor.h"
81#include "llvm/Support/raw_ostream.h"
82#include "llvm/Target/TargetMachine.h"
83#include "llvm/Target/TargetOptions.h"
84#include "llvm/TargetParser/Triple.h"
85#include <algorithm>
86#include <cassert>
87#include <cinttypes>
88#include <climits>
89#include <cstdint>
90#include <cstdlib>
91#include <cstring>
92#include <limits>
93#include <memory>
94#include <optional>
95#include <string>
96#include <system_error>
97#include <tuple>
98#include <utility>
99#include <vector>
100
101namespace llvm {
102
103static mc::RegisterMCTargetOptionsFlags MOF;
104
105using namespace dwarf_linker;
106
107namespace dsymutil {
108
109static void dumpDIE(const DWARFDie *DIE, bool Verbose) {
110 if (!DIE || !Verbose)
111 return;
112
113 DIDumpOptions DumpOpts;
114 DumpOpts.ChildRecurseDepth = 0;
115 DumpOpts.Verbose = Verbose;
116
117 WithColor::note() << " in DIE:\n";
118 DIE->dump(OS&: errs(), indent: 6 /* Indent */, DumpOpts);
119}
120
121/// Report a warning to the user, optionally including information about a
122/// specific \p DIE related to the warning.
123void 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, Verbose: Options.Verbose);
129 ErrorHandlerMutex.unlock();
130 }
131}
132
133void 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, Verbose: Options.Verbose);
139 ErrorHandlerMutex.unlock();
140 }
141}
142
143ErrorOr<const object::ObjectFile &>
144DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
145 const Triple &Triple) {
146 auto ObjectEntry =
147 BinHolder.getObjectEntry(Filename: Obj.getObjectFilename(), Timestamp: Obj.getTimestamp());
148 if (!ObjectEntry) {
149 auto Err = ObjectEntry.takeError();
150 reportWarning(Warning: Twine(Obj.getObjectFilename()) + ": " +
151 toStringWithoutConsuming(E: Err),
152 Context: Obj.getObjectFilename());
153 return errorToErrorCode(Err: std::move(Err));
154 }
155
156 auto Object = ObjectEntry->getObject(T: Triple);
157 if (!Object) {
158 auto Err = Object.takeError();
159 reportWarning(Warning: Twine(Obj.getObjectFilename()) + ": " +
160 toStringWithoutConsuming(E: Err),
161 Context: Obj.getObjectFilename());
162 return errorToErrorCode(Err: std::move(Err));
163 }
164
165 return *Object;
166}
167
168static Error remarksErrorHandler(const DebugMapObject &DMO,
169 DwarfLinkerForBinary &Linker,
170 std::unique_ptr<FileError> FE) {
171 bool IsArchive = DMO.getObjectFilename().ends_with(Suffix: ")");
172 // Don't report errors for missing remark files from static
173 // archives.
174 if (!IsArchive)
175 return Error(std::move(FE));
176
177 std::string Message = FE->message();
178 Error E = FE->takeError();
179 Error NewE = handleErrors(E: std::move(E), Hs: [&](std::unique_ptr<ECError> EC) {
180 if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory)
181 return Error(std::move(EC));
182
183 Linker.reportWarning(Warning: Message, Context: DMO.getObjectFilename());
184 return Error(Error::success());
185 });
186
187 if (!NewE)
188 return Error::success();
189
190 return createFileError(F: FE->getFileName(), E: std::move(NewE));
191}
192Error DwarfLinkerForBinary::emitRelocations(
193 const DebugMap &DM, std::vector<ObjectWithRelocMap> &ObjectsForLinking) {
194 // Return early if the "Resources" directory is not being written to.
195 if (!Options.ResourceDir)
196 return Error::success();
197
198 RelocationMap RM(DM.getTriple(), DM.getBinaryPath());
199 for (auto &Obj : ObjectsForLinking) {
200 if (!Obj.OutRelocs->isInitialized())
201 continue;
202 Obj.OutRelocs->addValidRelocs(RM);
203 }
204
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(Kind: RM.getTriple().getArch(),
209 SubArch: RM.getTriple().getSubArch());
210 sys::path::append(path&: Path, a: *Options.ResourceDir, b: "Relocations", c: ArchName);
211 if (std::error_code EC = sys::fs::create_directories(path: Path.str(), IgnoreExisting: true,
212 Perms: sys::fs::perms::all_all))
213 return errorCodeToError(EC);
214
215 // Append the file name.
216 sys::path::append(path&: Path, a: sys::path::filename(path: DM.getBinaryPath()));
217 Path.append(RHS: ".yml");
218
219 std::error_code EC;
220 raw_fd_ostream OS(Path.str(), EC, sys::fs::OF_Text);
221 if (EC)
222 return errorCodeToError(EC);
223
224 RM.print(OS);
225 return Error::success();
226}
227
228static 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();
234
235 SmallString<128> Path;
236 // Create the "Remarks" directory in the "Resources" directory.
237 sys::path::append(path&: Path, a: *Options.ResourceDir, b: "Remarks");
238 if (std::error_code EC = sys::fs::create_directories(path: Path.str(), IgnoreExisting: true,
239 Perms: sys::fs::perms::all_all))
240 return errorCodeToError(EC);
241
242 // Append the file name.
243 // For fat binaries, also append a dash and the architecture name.
244 sys::path::append(path&: Path, a: sys::path::filename(path: BinaryPath));
245 if (Options.NumDebugMaps > 1) {
246 // More than one debug map means we have a fat binary.
247 Path += '-';
248 Path += ArchName;
249 }
250
251 std::error_code EC;
252 raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC,
253 Options.RemarksFormat == remarks::Format::Bitstream
254 ? sys::fs::OF_None
255 : sys::fs::OF_Text);
256 if (EC)
257 return errorCodeToError(EC);
258
259 if (Error E = RL.serialize(OS, RemarksFormat: Options.RemarksFormat))
260 return E;
261
262 return Error::success();
263}
264
265ErrorOr<std::unique_ptr<DWARFFile>> DwarfLinkerForBinary::loadObject(
266 const DebugMapObject &Obj, const DebugMap &DebugMap,
267 remarks::RemarkLinker &RL, PseudoProbeLinker &PL,
268 std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM) {
269 auto ErrorOrObj = loadObject(Obj, Triple: DebugMap.getTriple());
270 std::unique_ptr<DWARFFile> Res;
271
272 if (ErrorOrObj) {
273 auto Context = DWARFContext::create(
274 Obj: *ErrorOrObj, RelocAction: DWARFContext::ProcessDebugRelocations::Process, L: nullptr,
275 DWPName: "",
276 RecoverableErrorHandler: [&](Error Err) {
277 handleAllErrors(E: std::move(Err), Handlers: [&](ErrorInfoBase &Info) {
278 reportError(Error: Info.message());
279 });
280 },
281 WarningHandler: [&](Error Warning) {
282 handleAllErrors(E: std::move(Warning), Handlers: [&](ErrorInfoBase &Info) {
283 reportWarning(Warning: Info.message());
284 });
285 });
286 DLBRM->init(Context&: *Context);
287 Res = std::make_unique<DWARFFile>(
288 args: Obj.getObjectFilename(), args: std::move(Context),
289 args: std::make_unique<AddressManager>(args&: *this, args: *ErrorOrObj, args: Obj, args&: DLBRM),
290 args: [&](StringRef FileName) { BinHolder.eraseObjectEntry(Filename: FileName); });
291
292 if (Error E = PL.collect(Obj: *ErrorOrObj))
293 reportWarning(Warning: toString(E: std::move(E)), Context: Obj.getObjectFilename());
294
295 Error E = RL.link(Obj: *ErrorOrObj);
296 // FIXME: Remark parsing errors are not propagated to the user.
297 if (Error NewE = handleErrors(
298 E: std::move(E), Hs: [&](std::unique_ptr<FileError> EC) -> Error {
299 return remarksErrorHandler(DMO: Obj, Linker&: *this, FE: std::move(EC));
300 }))
301 return errorToErrorCode(Err: std::move(NewE));
302
303 return std::move(Res);
304 }
305
306 return ErrorOrObj.getError();
307}
308
309static bool binaryHasStrippableSwiftReflectionSections(
310 const DebugMap &Map, const LinkOptions &Options, BinaryHolder &BinHolder) {
311 // If the input binary has strippable swift5 reflection sections, there is no
312 // need to copy them to the .dSYM. Only copy them for binaries where the
313 // linker omitted the reflection metadata.
314 if (!Map.getBinaryPath().empty() &&
315 Options.FileType == DWARFLinkerBase::OutputFileType::Object) {
316
317 auto ObjectEntry = BinHolder.getObjectEntry(Filename: Map.getBinaryPath());
318 // If ObjectEntry or Object has an error, no binary exists, therefore no
319 // reflection sections exist.
320 if (!ObjectEntry) {
321 // Any errors will be diagnosed later in the main loop, ignore them here.
322 llvm::consumeError(Err: ObjectEntry.takeError());
323 return false;
324 }
325
326 auto Object =
327 ObjectEntry->getObjectAs<object::MachOObjectFile>(T: Map.getTriple());
328 if (!Object) {
329 // Any errors will be diagnosed later in the main loop, ignore them here.
330 llvm::consumeError(Err: Object.takeError());
331 return false;
332 }
333
334 for (auto &Section : Object->sections()) {
335 llvm::Expected<llvm::StringRef> NameOrErr =
336 Object->getSectionName(Sec: Section.getRawDataRefImpl());
337 if (!NameOrErr) {
338 llvm::consumeError(Err: NameOrErr.takeError());
339 continue;
340 }
341 NameOrErr->consume_back(Suffix: "__TEXT");
342 auto ReflectionSectionKind =
343 Object->mapReflectionSectionNameToEnumValue(SectionName: *NameOrErr);
344 if (Object->isReflectionSectionStrippable(ReflectionSectionKind)) {
345 return true;
346 }
347 }
348 }
349 return false;
350}
351
352/// Calculate the start of the strippable swift reflection sections in Dwarf.
353/// Note that there's an assumption that the reflection sections will appear
354/// in alphabetic order.
355static std::vector<uint64_t>
356calculateStartOfStrippableReflectionSections(const DebugMap &Map) {
357 using llvm::binaryformat::Swift5ReflectionSectionKind;
358 uint64_t AssocTySize = 0;
359 uint64_t FieldMdSize = 0;
360 for (const auto &Obj : Map.objects()) {
361 auto OF =
362 llvm::object::ObjectFile::createObjectFile(ObjectPath: Obj->getObjectFilename());
363 if (!OF) {
364 llvm::consumeError(Err: OF.takeError());
365 continue;
366 }
367 if (auto *MO = dyn_cast<llvm::object::MachOObjectFile>(Val: OF->getBinary())) {
368 for (auto &Section : MO->sections()) {
369 llvm::Expected<llvm::StringRef> NameOrErr =
370 MO->getSectionName(Sec: Section.getRawDataRefImpl());
371 if (!NameOrErr) {
372 llvm::consumeError(Err: NameOrErr.takeError());
373 continue;
374 }
375 NameOrErr->consume_back(Suffix: "__TEXT");
376 auto ReflSectionKind =
377 MO->mapReflectionSectionNameToEnumValue(SectionName: *NameOrErr);
378 switch (ReflSectionKind) {
379 case Swift5ReflectionSectionKind::assocty:
380 AssocTySize += Section.getSize();
381 break;
382 case Swift5ReflectionSectionKind::fieldmd:
383 FieldMdSize += Section.getSize();
384 break;
385 default:
386 break;
387 }
388 }
389 }
390 }
391 // Initialize the vector with enough space to fit every reflection section
392 // kind.
393 std::vector<uint64_t> SectionToOffset(Swift5ReflectionSectionKind::last, 0);
394 SectionToOffset[Swift5ReflectionSectionKind::assocty] = 0;
395 SectionToOffset[Swift5ReflectionSectionKind::fieldmd] =
396 llvm::alignTo(Value: AssocTySize, Align: 4);
397 SectionToOffset[Swift5ReflectionSectionKind::reflstr] = llvm::alignTo(
398 Value: SectionToOffset[Swift5ReflectionSectionKind::fieldmd] + FieldMdSize, Align: 4);
399
400 return SectionToOffset;
401}
402
403void DwarfLinkerForBinary::collectRelocationsToApplyToSwiftReflectionSections(
404 const object::SectionRef &Section, StringRef &Contents,
405 const llvm::object::MachOObjectFile *MO,
406 const std::vector<uint64_t> &SectionToOffsetInDwarf,
407 const llvm::dsymutil::DebugMapObject *Obj,
408 std::vector<MachOUtils::DwarfRelocationApplicationInfo> &RelocationsToApply)
409 const {
410 for (auto It = Section.relocation_begin(); It != Section.relocation_end();
411 ++It) {
412 object::DataRefImpl RelocDataRef = It->getRawDataRefImpl();
413 MachO::any_relocation_info MachOReloc = MO->getRelocation(Rel: RelocDataRef);
414
415 if (!object::MachOObjectFile::isMachOPairedReloc(
416 RelocType: MO->getAnyRelocationType(RE: MachOReloc), Arch: MO->getArch())) {
417 reportWarning(
418 Warning: "Unimplemented relocation type in strippable reflection section ",
419 Context: Obj->getObjectFilename());
420 continue;
421 }
422
423 auto CalculateAddressOfSymbolInDwarfSegment =
424 [&]() -> std::optional<int64_t> {
425 auto Symbol = It->getSymbol();
426 auto SymbolAbsoluteAddress = Symbol->getAddress();
427 if (!SymbolAbsoluteAddress)
428 return {};
429 auto Section = Symbol->getSection();
430 if (!Section) {
431 llvm::consumeError(Err: Section.takeError());
432 return {};
433 }
434
435 if ((*Section)->getObject()->section_end() == *Section)
436 return {};
437
438 auto SectionStart = (*Section)->getAddress();
439 auto SymbolAddressInSection = *SymbolAbsoluteAddress - SectionStart;
440 auto SectionName = (*Section)->getName();
441 if (!SectionName)
442 return {};
443 auto ReflSectionKind =
444 MO->mapReflectionSectionNameToEnumValue(SectionName: *SectionName);
445
446 int64_t SectionStartInLinkedBinary =
447 SectionToOffsetInDwarf[ReflSectionKind];
448
449 auto Addr = SectionStartInLinkedBinary + SymbolAddressInSection;
450 return Addr;
451 };
452
453 // The first symbol should always be in the section we're currently
454 // iterating over.
455 auto FirstSymbolAddress = CalculateAddressOfSymbolInDwarfSegment();
456 ++It;
457
458 bool ShouldSubtractDwarfVM = false;
459 // For the second symbol there are two possibilities.
460 std::optional<int64_t> SecondSymbolAddress;
461 auto Sym = It->getSymbol();
462 if (Sym != MO->symbol_end()) {
463 Expected<StringRef> SymbolName = Sym->getName();
464 if (SymbolName) {
465 if (const auto *Mapping = Obj->lookupSymbol(SymbolName: *SymbolName)) {
466 // First possibility: the symbol exists in the binary, and exists in a
467 // non-strippable section (for example, typeref, or __TEXT,__const),
468 // in which case we look up its address in the binary, which dsymutil
469 // will copy verbatim.
470 SecondSymbolAddress = Mapping->getValue().BinaryAddress;
471 // Since the symbols live in different segments, we have to substract
472 // the start of the Dwarf's vmaddr so the value calculated points to
473 // the correct place.
474 ShouldSubtractDwarfVM = true;
475 }
476 }
477 }
478
479 if (!SecondSymbolAddress) {
480 // Second possibility, this symbol is not present in the main binary, and
481 // must be in one of the strippable sections (for example, reflstr).
482 // Calculate its address in the same way as we did the first one.
483 SecondSymbolAddress = CalculateAddressOfSymbolInDwarfSegment();
484 }
485
486 if (!FirstSymbolAddress || !SecondSymbolAddress)
487 continue;
488
489 auto SectionName = Section.getName();
490 if (!SectionName)
491 continue;
492
493 int32_t Addend;
494 memcpy(dest: &Addend, src: Contents.data() + It->getOffset(), n: sizeof(int32_t));
495 int32_t Value = (*SecondSymbolAddress + Addend) - *FirstSymbolAddress;
496 auto ReflSectionKind =
497 MO->mapReflectionSectionNameToEnumValue(SectionName: *SectionName);
498 uint64_t AddressFromDwarfVM =
499 SectionToOffsetInDwarf[ReflSectionKind] + It->getOffset();
500 RelocationsToApply.emplace_back(args&: AddressFromDwarfVM, args&: Value,
501 args&: ShouldSubtractDwarfVM);
502 }
503}
504
505Error DwarfLinkerForBinary::copySwiftInterfaces(StringRef Architecture) const {
506 std::error_code EC;
507 SmallString<128> InputPath;
508 SmallString<128> Path;
509 sys::path::append(path&: Path, a: *Options.ResourceDir, b: "Swift", c: Architecture);
510 if ((EC = sys::fs::create_directories(path: Path.str(), IgnoreExisting: true,
511 Perms: sys::fs::perms::all_all)))
512 return make_error<StringError>(
513 Args: "cannot create directory: " + toString(E: errorCodeToError(EC)), Args&: EC);
514 unsigned BaseLength = Path.size();
515
516 for (auto &I : ParseableSwiftInterfaces) {
517 StringRef ModuleName = I.first;
518 StringRef InterfaceFile = I.second;
519 if (!Options.PrependPath.empty()) {
520 InputPath.clear();
521 sys::path::append(path&: InputPath, a: Options.PrependPath, b: InterfaceFile);
522 InterfaceFile = InputPath;
523 }
524 sys::path::append(path&: Path, a: ModuleName);
525 Path.append(RHS: ".swiftinterface");
526 if (Options.Verbose)
527 outs() << "copy parseable Swift interface " << InterfaceFile << " -> "
528 << Path.str() << '\n';
529
530 // copy_file attempts an APFS clone first, so this should be cheap.
531 if ((EC = sys::fs::copy_file(From: InterfaceFile, To: Path.str())))
532 reportWarning(Warning: Twine("cannot copy parseable Swift interface ") +
533 InterfaceFile + ": " + toString(E: errorCodeToError(EC)));
534 Path.resize(N: BaseLength);
535 }
536 return Error::success();
537}
538
539Error DwarfLinkerForBinary::copyEmbeddedResources() const {
540 if (!Options.ResourceDir || Options.EmbedResources.empty())
541 return Error::success();
542
543 auto copyOneFile = [&](StringRef SrcPath,
544 StringRef DstPath) -> std::error_code {
545 if (auto EC = sys::fs::create_directories(path: sys::path::parent_path(path: DstPath),
546 IgnoreExisting: true, Perms: sys::fs::perms::all_all))
547 return EC;
548
549 if (Options.Verbose)
550 outs() << "embed resource " << SrcPath << " -> " << DstPath << '\n';
551
552 return sys::fs::copy_file(From: SrcPath, To: DstPath);
553 };
554
555 for (const auto &Entry : Options.EmbedResources) {
556 StringRef Dst = Entry.first();
557 StringRef Src = Entry.second;
558 bool IsDir = false;
559 if (auto EC = sys::fs::is_directory(path: Src, result&: IsDir))
560 return make_error<StringError>(Args: "cannot embed resource " + Src + ": " +
561 toString(E: errorCodeToError(EC)),
562 Args&: EC);
563
564 if (IsDir) {
565 std::error_code EC;
566 for (sys::fs::recursive_directory_iterator I(Src, EC), E; I != E && !EC;
567 I.increment(ec&: EC)) {
568 if (I->type() == sys::fs::file_type::directory_file)
569 continue;
570 StringRef FilePath = I->path();
571 StringRef Relative = FilePath.substr(Start: StringRef(Src).size());
572 if (!Relative.empty() && sys::path::is_separator(value: Relative.front()))
573 Relative = Relative.drop_front();
574 SmallString<128> DestPath;
575 sys::path::append(path&: DestPath, a: *Options.ResourceDir, b: Dst, c: Relative);
576 if (auto CopyEC = copyOneFile(FilePath, DestPath))
577 return make_error<StringError>(Args: "cannot embed resource " + FilePath +
578 ": " +
579 toString(E: errorCodeToError(EC: CopyEC)),
580 Args&: CopyEC);
581 }
582 if (EC)
583 return make_error<StringError>(Args: "cannot read directory " + Src + ": " +
584 toString(E: errorCodeToError(EC)),
585 Args&: EC);
586 } else {
587 SmallString<128> DestPath;
588 sys::path::append(path&: DestPath, a: *Options.ResourceDir, b: Dst);
589 if (auto EC = copyOneFile(Src, DestPath))
590 return make_error<StringError>(Args: "cannot embed resource " + Src + ": " +
591 toString(E: errorCodeToError(EC)),
592 Args&: EC);
593 }
594 }
595 return Error::success();
596}
597
598void DwarfLinkerForBinary::copySwiftReflectionMetadata(
599 const llvm::dsymutil::DebugMapObject *Obj, classic::DwarfStreamer *Streamer,
600 std::vector<uint64_t> &SectionToOffsetInDwarf,
601 std::vector<MachOUtils::DwarfRelocationApplicationInfo>
602 &RelocationsToApply) {
603 using binaryformat::Swift5ReflectionSectionKind;
604 auto OF =
605 llvm::object::ObjectFile::createObjectFile(ObjectPath: Obj->getObjectFilename());
606 if (!OF) {
607 llvm::consumeError(Err: OF.takeError());
608 return;
609 }
610 if (auto *MO = dyn_cast<llvm::object::MachOObjectFile>(Val: OF->getBinary())) {
611 // Collect the swift reflection sections before emitting them. This is
612 // done so we control the order they're emitted.
613 std::array<std::optional<object::SectionRef>,
614 Swift5ReflectionSectionKind::last + 1>
615 SwiftSections;
616 for (auto &Section : MO->sections()) {
617 llvm::Expected<llvm::StringRef> NameOrErr =
618 MO->getSectionName(Sec: Section.getRawDataRefImpl());
619 if (!NameOrErr) {
620 llvm::consumeError(Err: NameOrErr.takeError());
621 continue;
622 }
623 NameOrErr->consume_back(Suffix: "__TEXT");
624 auto ReflSectionKind =
625 MO->mapReflectionSectionNameToEnumValue(SectionName: *NameOrErr);
626 if (MO->isReflectionSectionStrippable(ReflectionSectionKind: ReflSectionKind))
627 SwiftSections[ReflSectionKind] = Section;
628 }
629 // Make sure we copy the sections in alphabetic order.
630 auto SectionKindsToEmit = {Swift5ReflectionSectionKind::assocty,
631 Swift5ReflectionSectionKind::fieldmd,
632 Swift5ReflectionSectionKind::reflstr};
633 for (auto SectionKind : SectionKindsToEmit) {
634 if (!SwiftSections[SectionKind])
635 continue;
636 auto &Section = *SwiftSections[SectionKind];
637 llvm::Expected<llvm::StringRef> SectionContents = Section.getContents();
638 if (!SectionContents)
639 continue;
640 const auto *MO =
641 llvm::cast<llvm::object::MachOObjectFile>(Val: Section.getObject());
642 collectRelocationsToApplyToSwiftReflectionSections(
643 Section, Contents&: *SectionContents, MO, SectionToOffsetInDwarf, Obj,
644 RelocationsToApply);
645 // Update the section start with the current section's contribution, so
646 // the next section we copy from a different .o file points to the correct
647 // place.
648 SectionToOffsetInDwarf[SectionKind] += Section.getSize();
649 Streamer->emitSwiftReflectionSection(ReflSectionKind: SectionKind, Buffer: *SectionContents,
650 Alignment: Section.getAlignment().value(),
651 Size: Section.getSize());
652 }
653 }
654}
655
656bool DwarfLinkerForBinary::link(const DebugMap &Map) {
657 if (Options.DWARFLinkerType == DsymutilDWARFLinkerType::Parallel)
658 return linkImpl<parallel::DWARFLinker>(Map, ObjectType: Options.FileType);
659
660 return linkImpl<classic::DWARFLinker>(Map, ObjectType: Options.FileType);
661}
662
663template <typename Linker>
664void setAcceleratorTables(Linker &GeneralLinker,
665 DsymutilAccelTableKind TableKind,
666 uint16_t MaxDWARFVersion) {
667 switch (TableKind) {
668 case DsymutilAccelTableKind::Apple:
669 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple);
670 return;
671 case DsymutilAccelTableKind::Dwarf:
672 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames);
673 return;
674 case DsymutilAccelTableKind::Pub:
675 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Pub);
676 return;
677 case DsymutilAccelTableKind::Default:
678 if (MaxDWARFVersion >= 5)
679 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::DebugNames);
680 else
681 GeneralLinker.addAccelTableKind(Linker::AccelTableKind::Apple);
682 return;
683 case DsymutilAccelTableKind::None:
684 // Nothing to do.
685 return;
686 }
687
688 llvm_unreachable("All cases handled above!");
689}
690
691template <typename Linker>
692bool DwarfLinkerForBinary::linkImpl(
693 const DebugMap &Map, typename Linker::OutputFileType ObjectType) {
694
695 std::vector<ObjectWithRelocMap> ObjectsForLinking;
696
697 DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
698
699 std::unique_ptr<Linker> GeneralLinker = Linker::createLinker(
700 [&](const Twine &Error, StringRef Context, const DWARFDie *DIE) {
701 reportError(Error, Context, DIE);
702 },
703 [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
704 reportWarning(Warning, Context, DIE);
705 });
706
707 std::unique_ptr<classic::DwarfStreamer> Streamer;
708 if (!Options.NoOutput) {
709 if (Expected<std::unique_ptr<classic::DwarfStreamer>> StreamerOrErr =
710 classic::DwarfStreamer::createStreamer(
711 TheTriple: Map.getTriple(), FileType: ObjectType, OutFile,
712 Warning: [&](const Twine &Warning, StringRef Context,
713 const DWARFDie *DIE) {
714 reportWarning(Warning, Context, DIE);
715 }))
716 Streamer = std::move(*StreamerOrErr);
717 else {
718 handleAllErrors(StreamerOrErr.takeError(), [&](const ErrorInfoBase &EI) {
719 reportError(Error: EI.message(), Context: "dwarf streamer init");
720 });
721 return false;
722 }
723
724 if constexpr (std::is_same<Linker, parallel::DWARFLinker>::value) {
725 GeneralLinker->setOutputDWARFHandler(
726 Map.getTriple(),
727 [&](std::shared_ptr<parallel::SectionDescriptorBase> Section) {
728 Streamer->emitSectionContents(SecData: Section->getContents(),
729 SecKind: Section->getKind());
730 });
731 } else
732 GeneralLinker->setOutputDWARFEmitter(Streamer.get());
733 }
734
735 PseudoProbeLinker PL(Options);
736 remarks::RemarkLinker RL;
737 if (!Options.RemarksPrependPath.empty())
738 RL.setExternalFilePrependPath(Options.RemarksPrependPath);
739 RL.setKeepAllRemarks(Options.RemarksKeepAll);
740 GeneralLinker->setObjectPrefixMap(&Options.ObjectPrefixMap);
741
742 GeneralLinker->setVerbosity(Options.Verbose);
743 GeneralLinker->setStatistics(Options.Statistics);
744 GeneralLinker->setVerifyInputDWARF(Options.VerifyInputDWARF);
745 GeneralLinker->setNoODR(Options.NoODR);
746 GeneralLinker->setUpdateIndexTablesOnly(Options.Update);
747 GeneralLinker->setNumThreads(Options.Threads);
748 GeneralLinker->setPrependPath(Options.PrependPath);
749 GeneralLinker->setKeepFunctionForStatic(Options.KeepFunctionForStatic);
750 GeneralLinker->setThreadPool(ThreadPool);
751 GeneralLinker->setInputVerificationHandler(
752 [&](const DWARFFile &File, llvm::StringRef Output) {
753 std::lock_guard<std::mutex> Guard(ErrorHandlerMutex);
754 if (Options.Verbose)
755 errs() << Output;
756 warn(Warning: "input verification failed", Context: File.FileName);
757 HasVerificationErrors = true;
758 });
759 auto Loader = [&](StringRef ContainerName,
760 StringRef Path) -> ErrorOr<DWARFFile &> {
761 auto &Obj = DebugMap.addDebugMapObject(
762 ObjectFilePath: Path, Timestamp: sys::TimePoint<std::chrono::seconds>(), Type: MachO::N_OSO);
763
764 auto DLBRelocMap = std::make_shared<DwarfLinkerForBinaryRelocationMap>();
765 if (ErrorOr<std::unique_ptr<DWARFFile>> ErrorOrObj =
766 loadObject(Obj, DebugMap, RL, PL, DLBRM: DLBRelocMap)) {
767 ObjectsForLinking.emplace_back(args: std::move(*ErrorOrObj), args&: DLBRelocMap);
768 return *ObjectsForLinking.back().Object;
769 } else {
770 // Try and emit more helpful warnings by applying some heuristics.
771 StringRef ObjFile = ContainerName;
772 bool IsClangModule = sys::path::extension(path: Path) == ".pcm";
773 bool IsArchive = ObjFile.ends_with(Suffix: ")");
774
775 if (IsClangModule) {
776 StringRef ModuleCacheDir = sys::path::parent_path(path: Path);
777 if (sys::fs::exists(Path: ModuleCacheDir)) {
778 // If the module's parent directory exists, we assume that the
779 // module cache has expired and was pruned by clang. A more
780 // adventurous dsymutil would invoke clang to rebuild the module
781 // now.
782 if (!ModuleCacheHintDisplayed) {
783 WithColor::note()
784 << "The clang module cache may have expired since "
785 "this object file was built. Rebuilding the "
786 "object file will rebuild the module cache.\n";
787 ModuleCacheHintDisplayed = true;
788 }
789 } else if (IsArchive) {
790 // If the module cache directory doesn't exist at all and the
791 // object file is inside a static library, we assume that the
792 // static library was built on a different machine. We don't want
793 // to discourage module debugging for convenience libraries within
794 // a project though.
795 if (!ArchiveHintDisplayed) {
796 WithColor::note()
797 << "Linking a static library that was built with "
798 "-gmodules, but the module cache was not found. "
799 "Redistributable static libraries should never be "
800 "built with module debugging enabled. The debug "
801 "experience will be degraded due to incomplete "
802 "debug information.\n";
803 ArchiveHintDisplayed = true;
804 }
805 }
806 }
807
808 return ErrorOrObj.getError();
809 }
810
811 llvm_unreachable("Unhandled DebugMap object");
812 };
813 GeneralLinker->setSwiftInterfacesMap(&ParseableSwiftInterfaces);
814 bool ReflectionSectionsPresentInBinary = false;
815 // If there is no output specified, no point in checking the binary for swift5
816 // reflection sections.
817 if (!Options.NoOutput) {
818 ReflectionSectionsPresentInBinary =
819 binaryHasStrippableSwiftReflectionSections(Map, Options, BinHolder);
820 }
821
822 std::vector<MachOUtils::DwarfRelocationApplicationInfo> RelocationsToApply;
823 if (!Options.NoOutput && !ReflectionSectionsPresentInBinary) {
824 auto SectionToOffsetInDwarf =
825 calculateStartOfStrippableReflectionSections(Map);
826 for (const auto &Obj : Map.objects())
827 copySwiftReflectionMetadata(Obj: Obj.get(), Streamer: Streamer.get(),
828 SectionToOffsetInDwarf, RelocationsToApply);
829 }
830
831 uint16_t MaxDWARFVersion = 0;
832 std::function<void(const DWARFUnit &Unit)> OnCUDieLoaded =
833 [&MaxDWARFVersion](const DWARFUnit &Unit) {
834 MaxDWARFVersion = std::max(a: Unit.getVersion(), b: MaxDWARFVersion);
835 };
836
837 if (Options.ResourceDir) {
838 // Collect .cas-config files. The build system might put these
839 // anywhere in the build directory, so dsymutil scans all parent
840 // paths of each object file. Their contents is a JSON dictionary,
841 // so this loop aggregates them in a JSON array.
842 llvm::StringSet<> VisitedPaths;
843 std::string CASConfigs = "[\n";
844 raw_string_ostream CASConfigStream(CASConfigs);
845 bool First = true;
846 for (const auto &Obj : Map.objects()) {
847 StringRef ObjPath = Obj->getObjectFilename();
848 for (StringRef Dir = sys::path::parent_path(path: ObjPath); !Dir.empty();
849 Dir = sys::path::parent_path(path: Dir)) {
850 if (!VisitedPaths.insert(key: Dir).second)
851 break;
852
853 SmallString<256> CASConfigPath(Dir);
854 sys::path::append(path&: CASConfigPath, a: ".cas-config");
855 auto BufferOrErr = MemoryBuffer::getFile(Filename: CASConfigPath);
856 if (!BufferOrErr)
857 continue;
858
859 if (!First)
860 CASConfigStream << ",\n";
861 First = false;
862 CASConfigStream << (*BufferOrErr)->getBuffer().rtrim(Char: '\n');
863 }
864 }
865 CASConfigStream << "\n]\n";
866 if (!First) {
867 std::error_code EC;
868 SmallString<128> CASConfigsPath;
869 sys::path::append(path&: CASConfigsPath, a: *Options.ResourceDir);
870 EC = sys::fs::create_directories(path: CASConfigsPath.str(), IgnoreExisting: true,
871 Perms: sys::fs::perms::all_all);
872 if (EC) {
873 reportWarning(Warning: "could not create directory '" + CASConfigsPath +
874 "': " + EC.message());
875 } else {
876 sys::path::append(path&: CASConfigsPath, a: "CASConfigs.json");
877 raw_fd_ostream OS(CASConfigsPath.str(), EC, sys::fs::OF_Text);
878 if (EC)
879 reportWarning(Warning: "could not open '" + CASConfigsPath +
880 "': " + EC.message());
881 else
882 OS << CASConfigs;
883 }
884 }
885 }
886
887 llvm::StringSet<> SwiftModules;
888 for (const auto &Obj : Map.objects()) {
889 // N_AST objects (swiftmodule files) should get dumped directly into the
890 // appropriate DWARF section.
891 if (Obj->getType() == MachO::N_AST) {
892 if (Options.Verbose)
893 outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
894
895 StringRef File = Obj->getObjectFilename();
896 if (!SwiftModules.insert(key: File).second)
897 continue;
898
899 auto ErrorOrMem = MemoryBuffer::getFile(Filename: File);
900 if (!ErrorOrMem) {
901 reportWarning(Warning: "could not open '" + File + "'");
902 continue;
903 }
904 auto FromInterfaceOrErr =
905 IsBuiltFromSwiftInterface(data: (*ErrorOrMem)->getBuffer());
906 if (!FromInterfaceOrErr) {
907 reportWarning(Warning: "could not parse binary Swift module: " +
908 toString(E: FromInterfaceOrErr.takeError()),
909 Context: Obj->getObjectFilename());
910 // Only skip swiftmodules that could be parsed and are positively
911 // identified as textual. Do so only when the option allows.
912 } else if (*FromInterfaceOrErr &&
913 !Options.IncludeSwiftModulesFromInterface) {
914 if (Options.Verbose)
915 outs() << "Skipping compiled textual Swift interface: "
916 << Obj->getObjectFilename() << "\n";
917 continue;
918 }
919
920 sys::fs::file_status Stat;
921 if (auto Err = sys::fs::status(path: File, result&: Stat)) {
922 reportWarning(Warning: Err.message());
923 continue;
924 }
925 if (!Options.NoTimestamp) {
926 // The modification can have sub-second precision so we need to cast
927 // away the extra precision that's not present in the debug map.
928 auto ModificationTime =
929 std::chrono::time_point_cast<std::chrono::seconds>(
930 t: Stat.getLastModificationTime());
931 if (Obj->getTimestamp() != sys::TimePoint<>() &&
932 ModificationTime != Obj->getTimestamp()) {
933 // Not using the helper here as we can easily stream TimePoint<>.
934 WithColor::warning()
935 << File << ": timestamp mismatch between swift interface file ("
936 << sys::TimePoint<>(ModificationTime) << ") and debug map ("
937 << sys::TimePoint<>(Obj->getTimestamp()) << ")\n";
938 continue;
939 }
940 }
941
942 // Copy the module into the .swift_ast section.
943 if (!Options.NoOutput)
944 Streamer->emitSwiftAST(Buffer: (*ErrorOrMem)->getBuffer());
945
946 continue;
947 }
948
949 auto DLBRelocMap = std::make_shared<DwarfLinkerForBinaryRelocationMap>();
950 if (ErrorOr<std::unique_ptr<DWARFFile>> ErrorOrObj =
951 loadObject(Obj: *Obj, DebugMap: Map, RL, PL, DLBRM: DLBRelocMap)) {
952 ObjectsForLinking.emplace_back(args: std::move(*ErrorOrObj), args&: DLBRelocMap);
953 GeneralLinker->addObjectFile(*ObjectsForLinking.back().Object, Loader,
954 OnCUDieLoaded);
955 } else {
956 ObjectsForLinking.push_back(
957 x: {std::make_unique<DWARFFile>(args: Obj->getObjectFilename(), args: nullptr,
958 args: nullptr),
959 DLBRelocMap});
960 GeneralLinker->addObjectFile(*ObjectsForLinking.back().Object);
961 }
962 }
963
964 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
965 if (MaxDWARFVersion == 0)
966 MaxDWARFVersion = 3;
967
968 if (Error E = GeneralLinker->setTargetDWARFVersion(MaxDWARFVersion))
969 return error(Error: toString(E: std::move(E)));
970
971 setAcceleratorTables<Linker>(*GeneralLinker, Options.TheAccelTableKind,
972 MaxDWARFVersion);
973
974 // link debug info for loaded object files.
975 if (Error E = GeneralLinker->link())
976 return error(Error: toString(E: std::move(E)));
977
978 StringRef ArchName = Map.getTriple().getArchName();
979 if (Error E = emitRemarks(Options, BinaryPath: Map.getBinaryPath(), ArchName, RL))
980 return error(Error: toString(E: std::move(E)));
981
982 if (Error E = PL.emit(TheTriple: Map.getTriple()))
983 return error(Error: toString(E: std::move(E)));
984
985 if (Options.NoOutput)
986 return true;
987
988 if (Error E = emitRelocations(DM: Map, ObjectsForLinking))
989 return error(Error: toString(E: std::move(E)));
990
991 if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {
992 StringRef ArchName = Triple::getArchTypeName(Kind: Map.getTriple().getArch());
993 if (auto E = copySwiftInterfaces(Architecture: ArchName))
994 return error(Error: toString(E: std::move(E)));
995 }
996
997 if (auto E = copyEmbeddedResources())
998 return error(Error: toString(E: std::move(E)));
999
1000 auto MapTriple = Map.getTriple();
1001 if ((MapTriple.isOSDarwin() || MapTriple.isOSBinFormatMachO()) &&
1002 !Map.getBinaryPath().empty() &&
1003 ObjectType == Linker::OutputFileType::Object)
1004 return MachOUtils::generateDsymCompanion(
1005 VFS: Options.VFS, DM: Map, MS&: *Streamer->getAsmPrinter().OutStreamer, OutFile,
1006 RelocationsToApply, AllowSectionHeaderOffsetOverflow: Options.AllowSectionHeaderOffsetOverflow);
1007
1008 Streamer->finish();
1009 return true;
1010}
1011
1012/// Iterate over the relocations of the given \p Section and
1013/// store the ones that correspond to debug map entries into the
1014/// ValidRelocs array.
1015void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
1016 const object::SectionRef &Section, const object::MachOObjectFile &Obj,
1017 const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {
1018 Expected<StringRef> ContentsOrErr = Section.getContents();
1019 if (!ContentsOrErr) {
1020 consumeError(Err: ContentsOrErr.takeError());
1021 Linker.reportWarning(Warning: "error reading section", Context: DMO.getObjectFilename());
1022 return;
1023 }
1024 DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian());
1025 bool SkipNext = false;
1026
1027 for (const object::RelocationRef &Reloc : Section.relocations()) {
1028 if (SkipNext) {
1029 SkipNext = false;
1030 continue;
1031 }
1032
1033 object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
1034 MachO::any_relocation_info MachOReloc = Obj.getRelocation(Rel: RelocDataRef);
1035
1036 if (object::MachOObjectFile::isMachOPairedReloc(RelocType: Obj.getAnyRelocationType(RE: MachOReloc),
1037 Arch: Obj.getArch())) {
1038 SkipNext = true;
1039 Linker.reportWarning(Warning: "unsupported relocation in " + *Section.getName() +
1040 " section.",
1041 Context: DMO.getObjectFilename());
1042 continue;
1043 }
1044
1045 unsigned RelocSize = 1 << Obj.getAnyRelocationLength(RE: MachOReloc);
1046 uint64_t Offset64 = Reloc.getOffset();
1047 if ((RelocSize != 4 && RelocSize != 8)) {
1048 Linker.reportWarning(Warning: "unsupported relocation in " + *Section.getName() +
1049 " section.",
1050 Context: DMO.getObjectFilename());
1051 continue;
1052 }
1053 uint64_t OffsetCopy = Offset64;
1054 // Mach-o uses REL relocations, the addend is at the relocation offset.
1055 uint64_t Addend = Data.getUnsigned(offset_ptr: &OffsetCopy, byte_size: RelocSize);
1056 uint64_t SymAddress;
1057 int64_t SymOffset;
1058
1059 if (Obj.isRelocationScattered(RE: MachOReloc)) {
1060 // The address of the base symbol for scattered relocations is
1061 // stored in the reloc itself. The actual addend will store the
1062 // base address plus the offset.
1063 SymAddress = Obj.getScatteredRelocationValue(RE: MachOReloc);
1064 SymOffset = int64_t(Addend) - SymAddress;
1065 } else {
1066 SymAddress = Addend;
1067 SymOffset = 0;
1068 }
1069
1070 auto Sym = Reloc.getSymbol();
1071 if (Sym != Obj.symbol_end()) {
1072 Expected<StringRef> SymbolName = Sym->getName();
1073 if (!SymbolName) {
1074 consumeError(Err: SymbolName.takeError());
1075 Linker.reportWarning(Warning: "error getting relocation symbol name.",
1076 Context: DMO.getObjectFilename());
1077 continue;
1078 }
1079 if (const auto *Mapping = DMO.lookupSymbol(SymbolName: *SymbolName))
1080 ValidRelocs.emplace_back(args&: Offset64, args&: RelocSize, args&: Addend, args: Mapping->getKey(),
1081 args: Mapping->getValue());
1082 } else if (const auto *Mapping = DMO.lookupObjectAddress(Address: SymAddress)) {
1083 // Do not store the addend. The addend was the address of the symbol in
1084 // the object file, the address in the binary that is stored in the debug
1085 // map doesn't need to be offset.
1086 ValidRelocs.emplace_back(args&: Offset64, args&: RelocSize, args&: SymOffset,
1087 args: Mapping->getKey(), args: Mapping->getValue());
1088 }
1089 }
1090}
1091
1092/// Dispatch the valid relocation finding logic to the
1093/// appropriate handler depending on the object file format.
1094bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
1095 const object::SectionRef &Section, const object::ObjectFile &Obj,
1096 const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {
1097 // Dispatch to the right handler depending on the file type.
1098 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(Val: &Obj))
1099 findValidRelocsMachO(Section, Obj: *MachOObj, DMO, ValidRelocs&: Relocs);
1100 else
1101 Linker.reportWarning(Warning: Twine("unsupported object file type: ") +
1102 Obj.getFileName(),
1103 Context: DMO.getObjectFilename());
1104 if (Relocs.empty())
1105 return false;
1106
1107 // Sort the relocations by offset. We will walk the DIEs linearly in
1108 // the file, this allows us to just keep an index in the relocation
1109 // array that we advance during our walk, rather than resorting to
1110 // some associative container. See DwarfLinkerForBinary::NextValidReloc.
1111 llvm::sort(C&: Relocs);
1112 return true;
1113}
1114
1115/// Look for relocations in the debug_info and debug_addr section that match
1116/// entries in the debug map. These relocations will drive the Dwarf link by
1117/// indicating which DIEs refer to symbols present in the linked binary.
1118/// \returns whether there are any valid relocations in the debug info.
1119bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(
1120 const object::ObjectFile &Obj, const DebugMapObject &DMO) {
1121 // Find the debug_info section.
1122 bool FoundValidRelocs = false;
1123 for (const object::SectionRef &Section : Obj.sections()) {
1124 StringRef SectionName;
1125 if (Expected<StringRef> NameOrErr = Section.getName())
1126 SectionName = *NameOrErr;
1127 else
1128 consumeError(Err: NameOrErr.takeError());
1129
1130 SectionName = SectionName.substr(Start: SectionName.find_first_not_of(Chars: "._"));
1131 if (SectionName == "debug_info")
1132 FoundValidRelocs |=
1133 findValidRelocs(Section, Obj, DMO, Relocs&: ValidDebugInfoRelocs);
1134 if (SectionName == "debug_addr")
1135 FoundValidRelocs |=
1136 findValidRelocs(Section, Obj, DMO, Relocs&: ValidDebugAddrRelocs);
1137 }
1138 return FoundValidRelocs;
1139}
1140
1141std::vector<ValidReloc> DwarfLinkerForBinary::AddressManager::getRelocations(
1142 const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {
1143 std::vector<ValidReloc> Res;
1144
1145 auto CurReloc = partition_point(Range: Relocs, P: [StartPos](const ValidReloc &Reloc) {
1146 return (uint64_t)Reloc.Offset < StartPos;
1147 });
1148
1149 while (CurReloc != Relocs.end() && CurReloc->Offset >= StartPos &&
1150 (uint64_t)CurReloc->Offset < EndPos) {
1151 Res.push_back(x: *CurReloc);
1152 CurReloc++;
1153 }
1154
1155 return Res;
1156}
1157
1158void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc &Reloc) {
1159 const auto &Mapping = Reloc.SymbolMapping;
1160 const uint64_t ObjectAddress = Mapping.ObjectAddress
1161 ? uint64_t(*Mapping.ObjectAddress)
1162 : std::numeric_limits<uint64_t>::max();
1163
1164 outs() << "Found valid debug map entry: " << Reloc.SymbolName << "\t"
1165 << format(Fmt: "0x%016" PRIx64 " => 0x%016" PRIx64 "\n", Vals: ObjectAddress,
1166 Vals: uint64_t(Mapping.BinaryAddress));
1167}
1168
1169int64_t
1170DwarfLinkerForBinary::AddressManager::getRelocValue(const ValidReloc &Reloc) {
1171 int64_t AddrAdjust = relocate(Reloc);
1172 if (Reloc.SymbolMapping.ObjectAddress)
1173 AddrAdjust -= uint64_t(*Reloc.SymbolMapping.ObjectAddress);
1174 return AddrAdjust;
1175}
1176
1177std::optional<int64_t>
1178DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
1179 const std::vector<ValidReloc> &AllRelocs, uint64_t StartOffset,
1180 uint64_t EndOffset, bool Verbose) {
1181 std::vector<ValidReloc> Relocs =
1182 getRelocations(Relocs: AllRelocs, StartPos: StartOffset, EndPos: EndOffset);
1183 if (Relocs.size() == 0)
1184 return std::nullopt;
1185
1186 if (Verbose)
1187 printReloc(Reloc: Relocs[0]);
1188
1189 return getRelocValue(Reloc: Relocs[0]);
1190}
1191
1192/// Get the starting and ending (exclusive) offset for the
1193/// attribute with index \p Idx descibed by \p Abbrev. \p Offset is
1194/// supposed to point to the position of the first attribute described
1195/// by \p Abbrev.
1196/// \return [StartOffset, EndOffset) as a pair.
1197static std::pair<uint64_t, uint64_t>
1198getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
1199 uint64_t Offset, const DWARFUnit &Unit) {
1200 DataExtractor Data = Unit.getDebugInfoExtractor();
1201
1202 for (unsigned I = 0; I < Idx; ++I)
1203 DWARFFormValue::skipValue(Form: Abbrev->getFormByIndex(idx: I), DebugInfoData: Data, OffsetPtr: &Offset,
1204 FormParams: Unit.getFormParams());
1205
1206 uint64_t End = Offset;
1207 DWARFFormValue::skipValue(Form: Abbrev->getFormByIndex(idx: Idx), DebugInfoData: Data, OffsetPtr: &End,
1208 FormParams: Unit.getFormParams());
1209
1210 return std::make_pair(x&: Offset, y&: End);
1211}
1212
1213std::optional<int64_t>
1214DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(
1215 DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,
1216 uint64_t EndOffset, bool Verbose) {
1217 switch (Op.getCode()) {
1218 default: {
1219 assert(false && "Specified operation does not have address operand");
1220 } break;
1221 case dwarf::DW_OP_const2u:
1222 case dwarf::DW_OP_const4u:
1223 case dwarf::DW_OP_const8u:
1224 case dwarf::DW_OP_const2s:
1225 case dwarf::DW_OP_const4s:
1226 case dwarf::DW_OP_const8s:
1227 case dwarf::DW_OP_addr: {
1228 return hasValidRelocationAt(AllRelocs: ValidDebugInfoRelocs, StartOffset, EndOffset,
1229 Verbose);
1230 } break;
1231 case dwarf::DW_OP_constx:
1232 case dwarf::DW_OP_addrx: {
1233 return hasValidRelocationAt(AllRelocs: ValidDebugAddrRelocs, StartOffset, EndOffset,
1234 Verbose);
1235 } break;
1236 }
1237
1238 return std::nullopt;
1239}
1240
1241std::optional<int64_t>
1242DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(
1243 const DWARFDie &DIE, bool Verbose) {
1244 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
1245
1246 std::optional<uint32_t> LowPcIdx =
1247 Abbrev->findAttributeIndex(attr: dwarf::DW_AT_low_pc);
1248 if (!LowPcIdx)
1249 return std::nullopt;
1250
1251 dwarf::Form Form = Abbrev->getFormByIndex(idx: *LowPcIdx);
1252
1253 switch (Form) {
1254 case dwarf::DW_FORM_addr: {
1255 uint64_t Offset = DIE.getOffset() + getULEB128Size(Value: Abbrev->getCode());
1256 uint64_t LowPcOffset, LowPcEndOffset;
1257 std::tie(args&: LowPcOffset, args&: LowPcEndOffset) =
1258 getAttributeOffsets(Abbrev, Idx: *LowPcIdx, Offset, Unit: *DIE.getDwarfUnit());
1259 return hasValidRelocationAt(AllRelocs: ValidDebugInfoRelocs, StartOffset: LowPcOffset,
1260 EndOffset: LowPcEndOffset, Verbose);
1261 }
1262 case dwarf::DW_FORM_addrx:
1263 case dwarf::DW_FORM_addrx1:
1264 case dwarf::DW_FORM_addrx2:
1265 case dwarf::DW_FORM_addrx3:
1266 case dwarf::DW_FORM_addrx4: {
1267 std::optional<DWARFFormValue> AddrValue = DIE.find(Attr: dwarf::DW_AT_low_pc);
1268 if (std::optional<uint64_t> AddressOffset =
1269 DIE.getDwarfUnit()->getIndexedAddressOffset(
1270 Index: AddrValue->getRawUValue()))
1271 return hasValidRelocationAt(
1272 AllRelocs: ValidDebugAddrRelocs, StartOffset: *AddressOffset,
1273 EndOffset: *AddressOffset + DIE.getDwarfUnit()->getAddressByteSize(), Verbose);
1274
1275 Linker.reportWarning(Warning: "no base offset for address table", Context: SrcFileName);
1276 return std::nullopt;
1277 }
1278 default:
1279 return std::nullopt;
1280 }
1281}
1282
1283std::optional<StringRef>
1284DwarfLinkerForBinary::AddressManager::getLibraryInstallName() {
1285 return LibInstallName;
1286}
1287
1288uint64_t
1289DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {
1290 return Reloc.SymbolMapping.BinaryAddress + Reloc.Addend;
1291}
1292
1293void DwarfLinkerForBinary::AddressManager::updateAndSaveValidRelocs(
1294 bool IsDWARF5, uint64_t OriginalUnitOffset, int64_t LinkedOffset,
1295 uint64_t StartOffset, uint64_t EndOffset) {
1296 std::vector<ValidReloc> InRelocs =
1297 getRelocations(Relocs: ValidDebugInfoRelocs, StartPos: StartOffset, EndPos: EndOffset);
1298 if (IsDWARF5)
1299 InRelocs = getRelocations(Relocs: ValidDebugAddrRelocs, StartPos: StartOffset, EndPos: EndOffset);
1300 DwarfLinkerRelocMap->updateAndSaveValidRelocs(
1301 IsDWARF5, InRelocs, UnitOffset: OriginalUnitOffset, LinkedOffset);
1302}
1303
1304void DwarfLinkerForBinary::AddressManager::updateRelocationsWithUnitOffset(
1305 uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) {
1306 DwarfLinkerRelocMap->updateRelocationsWithUnitOffset(OriginalUnitOffset,
1307 OutputUnitOffset);
1308}
1309/// Apply the valid relocations found by findValidRelocs() to
1310/// the buffer \p Data, taking into account that Data is at \p BaseOffset
1311/// in the debug_info section.
1312///
1313/// Like for findValidRelocs(), this function must be called with
1314/// monotonic \p BaseOffset values.
1315///
1316/// \returns whether any reloc has been applied.
1317bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
1318 MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
1319
1320 std::vector<ValidReloc> Relocs = getRelocations(
1321 Relocs: ValidDebugInfoRelocs, StartPos: BaseOffset, EndPos: BaseOffset + Data.size());
1322
1323 for (const ValidReloc &CurReloc : Relocs) {
1324 assert(CurReloc.Offset - BaseOffset < Data.size());
1325 assert(CurReloc.Offset - BaseOffset + CurReloc.Size <= Data.size());
1326 char Buf[8];
1327 uint64_t Value = relocate(Reloc: CurReloc);
1328 for (unsigned I = 0; I != CurReloc.Size; ++I) {
1329 unsigned Index = IsLittleEndian ? I : (CurReloc.Size - I - 1);
1330 Buf[I] = uint8_t(Value >> (Index * 8));
1331 }
1332 assert(CurReloc.Size <= sizeof(Buf));
1333 memcpy(dest: &Data[CurReloc.Offset - BaseOffset], src: Buf, n: CurReloc.Size);
1334 }
1335 return Relocs.size() > 0;
1336}
1337
1338void DwarfLinkerForBinaryRelocationMap::init(DWARFContext &Context) {
1339 for (const std::unique_ptr<DWARFUnit> &CU : Context.compile_units())
1340 StoredValidDebugInfoRelocsMap.insert(
1341 KV: std::make_pair(x: CU->getOffset(), y: std::vector<ValidReloc>()));
1342 // FIXME: Support relocations debug_addr (DWARF5).
1343}
1344
1345void DwarfLinkerForBinaryRelocationMap::addValidRelocs(RelocationMap &RM) {
1346 for (const auto &DebugInfoRelocs : StoredValidDebugInfoRelocsMap) {
1347 for (const auto &InfoReloc : DebugInfoRelocs.second)
1348 RM.addRelocationMapEntry(Relocation: InfoReloc);
1349 }
1350 // FIXME: Support relocations debug_addr (DWARF5).
1351}
1352
1353void DwarfLinkerForBinaryRelocationMap::updateRelocationsWithUnitOffset(
1354 uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) {
1355 std::vector<ValidReloc> &StoredValidDebugInfoRelocs =
1356 StoredValidDebugInfoRelocsMap[OriginalUnitOffset];
1357 for (ValidReloc &R : StoredValidDebugInfoRelocs) {
1358 R.Offset = (uint64_t)R.Offset + OutputUnitOffset;
1359 }
1360 // FIXME: Support relocations debug_addr (DWARF5).
1361}
1362
1363void DwarfLinkerForBinaryRelocationMap::updateAndSaveValidRelocs(
1364 bool IsDWARF5, std::vector<ValidReloc> &InRelocs, uint64_t UnitOffset,
1365 int64_t LinkedOffset) {
1366 std::vector<ValidReloc> &OutRelocs =
1367 StoredValidDebugInfoRelocsMap[UnitOffset];
1368 if (IsDWARF5)
1369 OutRelocs = StoredValidDebugAddrRelocsMap[UnitOffset];
1370
1371 for (ValidReloc &R : InRelocs) {
1372 OutRelocs.emplace_back(args: R.Offset + LinkedOffset, args&: R.Size, args&: R.Addend,
1373 args&: R.SymbolName, args&: R.SymbolMapping);
1374 }
1375}
1376
1377} // namespace dsymutil
1378} // namespace llvm
1379