xref: /llvm-project/llvm/tools/dsymutil/DwarfLinkerForBinary.cpp (revision 44df1167f88cabbb4cfde816f279337379ea30b3)
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 "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>
99 
100 namespace llvm {
101 
102 static mc::RegisterMCTargetOptionsFlags MOF;
103 
104 using namespace dwarf_linker;
105 
106 namespace dsymutil {
107 
dumpDIE(const DWARFDie * DIE,bool Verbose)108 static void dumpDIE(const DWARFDie *DIE, bool Verbose) {
109   if (!DIE || !Verbose)
110     return;
111 
112   DIDumpOptions DumpOpts;
113   DumpOpts.ChildRecurseDepth = 0;
114   DumpOpts.Verbose = Verbose;
115 
116   WithColor::note() << "    in DIE:\n";
117   DIE->dump(errs(), 6 /* Indent */, DumpOpts);
118 }
119 
120 /// Report a warning to the user, optionally including information about a
121 /// specific \p DIE related to the warning.
reportWarning(Twine Warning,Twine Context,const DWARFDie * DIE) const122 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();
129   }
130 }
131 
reportError(Twine Error,Twine Context,const DWARFDie * DIE) const132 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();
139   }
140 }
141 
142 ErrorOr<const object::ObjectFile &>
loadObject(const DebugMapObject & Obj,const Triple & Triple)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));
153   }
154 
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));
162   }
163 
164   return *Object;
165 }
166 
remarksErrorHandler(const DebugMapObject & DMO,DwarfLinkerForBinary & Linker,std::unique_ptr<FileError> FE)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));
175 
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));
181 
182     Linker.reportWarning(Message, DMO.getObjectFilename());
183     return Error(Error::success());
184   });
185 
186   if (!NewE)
187     return Error::success();
188 
189   return createFileError(FE->getFileName(), std::move(NewE));
190 }
emitRelocations(const DebugMap & DM,std::vector<ObjectWithRelocMap> & ObjectsForLinking)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();
196 
197   RelocationMap RM(DM.getTriple(), DM.getBinaryPath());
198   for (auto &Obj : ObjectsForLinking) {
199     if (!Obj.OutRelocs->isInitialized())
200       continue;
201     Obj.OutRelocs->addValidRelocs(RM);
202   }
203 
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);
214 
215   // Append the file name.
216   sys::path::append(Path, sys::path::filename(DM.getBinaryPath()));
217   Path.append(".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 
emitRemarks(const LinkOptions & Options,StringRef BinaryPath,StringRef ArchName,const remarks::RemarkLinker & RL)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();
234 
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);
242 
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;
250   }
251 
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);
259 
260   if (Error E = RL.serialize(OS, Options.RemarksFormat))
261     return E;
262 
263   return Error::success();
264 }
265 
loadObject(const DebugMapObject & Obj,const DebugMap & DebugMap,remarks::RemarkLinker & RL,std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM)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;
272 
273   if (ErrorOrObj) {
274     auto Context = DWARFContext::create(
275         *ErrorOrObj, DWARFContext::ProcessDebugRelocations::Process, nullptr,
276         "",
277         [&](Error Err) {
278           handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {
279             reportError(Info.message());
280           });
281         },
282         [&](Error Warning) {
283           handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {
284             reportWarning(Info.message());
285           });
286         });
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); });
292 
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));
297             }))
298       return errorToErrorCode(std::move(NewE));
299 
300     return std::move(Res);
301   }
302 
303   return ErrorOrObj.getError();
304 }
305 
binaryHasStrippableSwiftReflectionSections(const DebugMap & Map,const LinkOptions & Options,BinaryHolder & BinHolder)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) {
313 
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;
321     }
322 
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;
329     }
330 
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;
337       }
338       NameOrErr->consume_back("__TEXT");
339       auto ReflectionSectionKind =
340           Object->mapReflectionSectionNameToEnumValue(*NameOrErr);
341       if (Object->isReflectionSectionStrippable(ReflectionSectionKind)) {
342         return true;
343       }
344     }
345   }
346   return false;
347 }
348 
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>
calculateStartOfStrippableReflectionSections(const DebugMap & Map)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;
363     }
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;
371         }
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;
384         }
385       }
386     }
387   }
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);
396 
397   return SectionToOffset;
398 }
399 
collectRelocationsToApplyToSwiftReflectionSections(const object::SectionRef & Section,StringRef & Contents,const llvm::object::MachOObjectFile * MO,const std::vector<uint64_t> & SectionToOffsetInDwarf,const llvm::dsymutil::DebugMapObject * Obj,std::vector<MachOUtils::DwarfRelocationApplicationInfo> & RelocationsToApply) const400 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);
411 
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;
418     }
419 
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 {};
430       }
431 
432       if ((*Section)->getObject()->section_end() == *Section)
433         return {};
434 
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);
442 
443       int64_t SectionStartInLinkedBinary =
444           SectionToOffsetInDwarf[ReflSectionKind];
445 
446       auto Addr = SectionStartInLinkedBinary + SymbolAddressInSection;
447       return Addr;
448     };
449 
450     // The first symbol should always be in the section we're currently
451     // iterating over.
452     auto FirstSymbolAddress = CalculateAddressOfSymbolInDwarfSegment();
453     ++It;
454 
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;
472         }
473       }
474     }
475 
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();
481     }
482 
483     if (!FirstSymbolAddress || !SecondSymbolAddress)
484       continue;
485 
486     auto SectionName = Section.getName();
487     if (!SectionName)
488       continue;
489 
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);
499   }
500 }
501 
copySwiftInterfaces(StringRef Architecture) const502 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();
512 
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;
520     }
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';
526 
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);
532   }
533   return Error::success();
534 }
535 
copySwiftReflectionMetadata(const llvm::dsymutil::DebugMapObject * Obj,classic::DwarfStreamer * Streamer,std::vector<uint64_t> & SectionToOffsetInDwarf,std::vector<MachOUtils::DwarfRelocationApplicationInfo> & RelocationsToApply)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;
547   }
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;
560       }
561       NameOrErr->consume_back("__TEXT");
562       auto ReflSectionKind =
563           MO->mapReflectionSectionNameToEnumValue(*NameOrErr);
564       if (MO->isReflectionSectionStrippable(ReflSectionKind))
565         SwiftSections[ReflSectionKind] = Section;
566     }
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());
590     }
591   }
592 }
593 
link(const DebugMap & Map)594 bool DwarfLinkerForBinary::link(const DebugMap &Map) {
595   if (Options.DWARFLinkerType == DsymutilDWARFLinkerType::Parallel)
596     return linkImpl<parallel::DWARFLinker>(Map, Options.FileType);
597 
598   return linkImpl<classic::DWARFLinker>(Map, Options.FileType);
599 }
600 
601 template <typename Linker>
setAcceleratorTables(Linker & GeneralLinker,DsymutilAccelTableKind TableKind,uint16_t MaxDWARFVersion)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;
624   }
625 
626   llvm_unreachable("All cases handled above!");
627 }
628 
629 template <typename Linker>
linkImpl(const DebugMap & Map,typename Linker::OutputFileType ObjectType)630 bool DwarfLinkerForBinary::linkImpl(
631     const DebugMap &Map, typename Linker::OutputFileType ObjectType) {
632 
633   std::vector<ObjectWithRelocMap> ObjectsForLinking;
634 
635   DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
636 
637   std::unique_ptr<Linker> GeneralLinker = Linker::createLinker(
638       [&](const Twine &Error, StringRef Context, const DWARFDie *DIE) {
639         reportError(Error, Context, DIE);
640       },
641       [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
642         reportWarning(Warning, Context, DIE);
643       });
644 
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);
653                 }))
654       Streamer = std::move(*StreamerOrErr);
655     else {
656       handleAllErrors(StreamerOrErr.takeError(), [&](const ErrorInfoBase &EI) {
657         reportError(EI.message(), "dwarf streamer init");
658       });
659       return false;
660     }
661 
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());
668           });
669     } else
670       GeneralLinker->setOutputDWARFEmitter(Streamer.get());
671   }
672 
673   remarks::RemarkLinker RL;
674   if (!Options.RemarksPrependPath.empty())
675     RL.setExternalFilePrependPath(Options.RemarksPrependPath);
676   RL.setKeepAllRemarks(Options.RemarksKeepAll);
677   GeneralLinker->setObjectPrefixMap(&Options.ObjectPrefixMap);
678 
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;
694       });
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);
699 
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(")");
710 
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;
724           }
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;
740           }
741         }
742       }
743 
744       return ErrorOrObj.getError();
745     }
746 
747     llvm_unreachable("Unhandled DebugMap object");
748   };
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);
756   }
757 
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);
765   }
766 
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);
771       };
772 
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";
779 
780       StringRef File = Obj->getObjectFilename();
781       auto ErrorOrMem = MemoryBuffer::getFile(File);
782       if (!ErrorOrMem) {
783         reportWarning("Could not open '" + File + "'");
784         continue;
785       }
786       sys::fs::file_status Stat;
787       if (auto Err = sys::fs::status(File, Stat)) {
788         reportWarning(Err.message());
789         continue;
790       }
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;
805         }
806       }
807 
808       // Copy the module into the .swift_ast section.
809       if (!Options.NoOutput)
810         Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
811 
812       continue;
813     }
814 
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);
827     }
828   }
829 
830   // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.
831   if (MaxDWARFVersion == 0)
832     MaxDWARFVersion = 3;
833 
834   if (Error E = GeneralLinker->setTargetDWARFVersion(MaxDWARFVersion))
835     return error(toString(std::move(E)));
836 
837   setAcceleratorTables<Linker>(*GeneralLinker, Options.TheAccelTableKind,
838                                MaxDWARFVersion);
839 
840   // link debug info for loaded object files.
841   if (Error E = GeneralLinker->link())
842     return error(toString(std::move(E)));
843 
844   StringRef ArchName = Map.getTriple().getArchName();
845   if (Error E = emitRemarks(Options, Map.getBinaryPath(), ArchName, RL))
846     return error(toString(std::move(E)));
847 
848   if (Options.NoOutput)
849     return true;
850 
851   if (Error E = emitRelocations(Map, ObjectsForLinking))
852     return error(toString(std::move(E)));
853 
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)));
858   }
859 
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);
867 
868   Streamer->finish();
869   return true;
870 }
871 
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.
findValidRelocsMachO(const object::SectionRef & Section,const object::MachOObjectFile & Obj,const DebugMapObject & DMO,std::vector<ValidReloc> & ValidRelocs)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;
883   }
884   DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0);
885   bool SkipNext = false;
886 
887   for (const object::RelocationRef &Reloc : Section.relocations()) {
888     if (SkipNext) {
889       SkipNext = false;
890       continue;
891     }
892 
893     object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
894     MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
895 
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;
903     }
904 
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;
912     }
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;
918 
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;
928     }
929 
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;
938       }
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());
948     }
949   }
950 }
951 
952 /// Dispatch the valid relocation finding logic to the
953 /// appropriate handler depending on the object file format.
findValidRelocs(const object::SectionRef & Section,const object::ObjectFile & Obj,const DebugMapObject & DMO,std::vector<ValidReloc> & Relocs)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;
966 
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;
973 }
974 
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.
findValidRelocsInDebugSections(const object::ObjectFile & Obj,const DebugMapObject & DMO)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());
989 
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);
997   }
998   return FoundValidRelocs;
999 }
1000 
getRelocations(const std::vector<ValidReloc> & Relocs,uint64_t StartPos,uint64_t EndPos)1001 std::vector<ValidReloc> DwarfLinkerForBinary::AddressManager::getRelocations(
1002     const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {
1003   std::vector<ValidReloc> Res;
1004 
1005   auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) {
1006     return (uint64_t)Reloc.Offset < StartPos;
1007   });
1008 
1009   while (CurReloc != Relocs.end() && CurReloc->Offset >= StartPos &&
1010          (uint64_t)CurReloc->Offset < EndPos) {
1011     Res.push_back(*CurReloc);
1012     CurReloc++;
1013   }
1014 
1015   return Res;
1016 }
1017 
printReloc(const ValidReloc & Reloc)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();
1023 
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));
1027 }
1028 
1029 int64_t
getRelocValue(const ValidReloc & Reloc)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;
1035 }
1036 
1037 std::optional<int64_t>
hasValidRelocationAt(const std::vector<ValidReloc> & AllRelocs,uint64_t StartOffset,uint64_t EndOffset,bool Verbose)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;
1045 
1046   if (Verbose)
1047     printReloc(Relocs[0]);
1048 
1049   return getRelocValue(Relocs[0]);
1050 }
1051 
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>
getAttributeOffsets(const DWARFAbbreviationDeclaration * Abbrev,unsigned Idx,uint64_t Offset,const DWARFUnit & Unit)1058 getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
1059                     uint64_t Offset, const DWARFUnit &Unit) {
1060   DataExtractor Data = Unit.getDebugInfoExtractor();
1061 
1062   for (unsigned I = 0; I < Idx; ++I)
1063     DWARFFormValue::skipValue(Abbrev->getFormByIndex(I), Data, &Offset,
1064                               Unit.getFormParams());
1065 
1066   uint64_t End = Offset;
1067   DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End,
1068                             Unit.getFormParams());
1069 
1070   return std::make_pair(Offset, End);
1071 }
1072 
1073 std::optional<int64_t>
getExprOpAddressRelocAdjustment(DWARFUnit & U,const DWARFExpression::Operation & Op,uint64_t StartOffset,uint64_t EndOffset,bool Verbose)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;
1096   }
1097 
1098   return std::nullopt;
1099 }
1100 
1101 std::optional<int64_t>
getSubprogramRelocAdjustment(const DWARFDie & DIE,bool Verbose)1102 DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(
1103     const DWARFDie &DIE, bool Verbose) {
1104   const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
1105 
1106   std::optional<uint32_t> LowPcIdx =
1107       Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc);
1108   if (!LowPcIdx)
1109     return std::nullopt;
1110 
1111   dwarf::Form Form = Abbrev->getFormByIndex(*LowPcIdx);
1112 
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);
1121   }
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);
1134 
1135     Linker.reportWarning("no base offset for address table", SrcFileName);
1136     return std::nullopt;
1137   }
1138   default:
1139     return std::nullopt;
1140   }
1141 }
1142 
1143 std::optional<StringRef>
getLibraryInstallName()1144 DwarfLinkerForBinary::AddressManager::getLibraryInstallName() {
1145   return LibInstallName;
1146 }
1147 
1148 uint64_t
relocate(const ValidReloc & Reloc) const1149 DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {
1150   return Reloc.SymbolMapping.BinaryAddress + Reloc.Addend;
1151 }
1152 
updateAndSaveValidRelocs(bool IsDWARF5,uint64_t OriginalUnitOffset,int64_t LinkedOffset,uint64_t StartOffset,uint64_t EndOffset)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);
1162 }
1163 
updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,uint64_t OutputUnitOffset)1164 void DwarfLinkerForBinary::AddressManager::updateRelocationsWithUnitOffset(
1165     uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) {
1166   DwarfLinkerRelocMap->updateRelocationsWithUnitOffset(OriginalUnitOffset,
1167                                                        OutputUnitOffset);
1168 }
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.
1172 ///
1173 /// Like for findValidRelocs(), this function must be called with
1174 /// monotonic \p BaseOffset values.
1175 ///
1176 /// \returns whether any reloc has been applied.
applyValidRelocs(MutableArrayRef<char> Data,uint64_t BaseOffset,bool IsLittleEndian)1177 bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
1178     MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
1179 
1180   std::vector<ValidReloc> Relocs = getRelocations(
1181       ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());
1182 
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));
1191     }
1192     assert(CurReloc.Size <= sizeof(Buf));
1193     memcpy(&Data[CurReloc.Offset - BaseOffset], Buf, CurReloc.Size);
1194   }
1195   return Relocs.size() > 0;
1196 }
1197 
init(DWARFContext & Context)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).
1203 }
1204 
addValidRelocs(RelocationMap & RM)1205 void DwarfLinkerForBinaryRelocationMap::addValidRelocs(RelocationMap &RM) {
1206   for (const auto &DebugInfoRelocs : StoredValidDebugInfoRelocsMap) {
1207     for (const auto &InfoReloc : DebugInfoRelocs.second)
1208       RM.addRelocationMapEntry(InfoReloc);
1209   }
1210   // FIXME: Support relocations debug_addr (DWARF5).
1211 }
1212 
updateRelocationsWithUnitOffset(uint64_t OriginalUnitOffset,uint64_t OutputUnitOffset)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;
1219   }
1220   // FIXME: Support relocations debug_addr (DWARF5).
1221 }
1222 
updateAndSaveValidRelocs(bool IsDWARF5,std::vector<ValidReloc> & InRelocs,uint64_t UnitOffset,int64_t LinkedOffset)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];
1230 
1231   for (ValidReloc &R : InRelocs) {
1232     OutRelocs.emplace_back(R.Offset + LinkedOffset, R.Size, R.Addend,
1233                            R.SymbolName, R.SymbolMapping);
1234   }
1235 }
1236 
1237 } // namespace dsymutil
1238 } // namespace llvm
1239