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/BitVector.h"
16 #include "llvm/ADT/DenseMap.h"
17 #include "llvm/ADT/DenseMapInfo.h"
18 #include "llvm/ADT/DenseSet.h"
19 #include "llvm/ADT/FoldingSet.h"
20 #include "llvm/ADT/Hashing.h"
21 #include "llvm/ADT/IntervalMap.h"
22 #include "llvm/ADT/None.h"
23 #include "llvm/ADT/Optional.h"
24 #include "llvm/ADT/PointerIntPair.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/ADT/StringMap.h"
28 #include "llvm/ADT/StringRef.h"
29 #include "llvm/ADT/Triple.h"
30 #include "llvm/ADT/Twine.h"
31 #include "llvm/BinaryFormat/Dwarf.h"
32 #include "llvm/BinaryFormat/MachO.h"
33 #include "llvm/CodeGen/AccelTable.h"
34 #include "llvm/CodeGen/AsmPrinter.h"
35 #include "llvm/CodeGen/DIE.h"
36 #include "llvm/CodeGen/NonRelocatableStringpool.h"
37 #include "llvm/Config/config.h"
38 #include "llvm/DWARFLinker/DWARFLinkerDeclContext.h"
39 #include "llvm/DebugInfo/DIContext.h"
40 #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
41 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
42 #include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
43 #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
44 #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
45 #include "llvm/DebugInfo/DWARF/DWARFDie.h"
46 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
47 #include "llvm/DebugInfo/DWARF/DWARFSection.h"
48 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
49 #include "llvm/MC/MCAsmBackend.h"
50 #include "llvm/MC/MCAsmInfo.h"
51 #include "llvm/MC/MCCodeEmitter.h"
52 #include "llvm/MC/MCContext.h"
53 #include "llvm/MC/MCDwarf.h"
54 #include "llvm/MC/MCInstrInfo.h"
55 #include "llvm/MC/MCObjectFileInfo.h"
56 #include "llvm/MC/MCObjectWriter.h"
57 #include "llvm/MC/MCRegisterInfo.h"
58 #include "llvm/MC/MCSection.h"
59 #include "llvm/MC/MCStreamer.h"
60 #include "llvm/MC/MCSubtargetInfo.h"
61 #include "llvm/MC/MCTargetOptions.h"
62 #include "llvm/Object/MachO.h"
63 #include "llvm/Object/ObjectFile.h"
64 #include "llvm/Object/SymbolicFile.h"
65 #include "llvm/Support/Allocator.h"
66 #include "llvm/Support/Casting.h"
67 #include "llvm/Support/Compiler.h"
68 #include "llvm/Support/DJB.h"
69 #include "llvm/Support/DataExtractor.h"
70 #include "llvm/Support/Error.h"
71 #include "llvm/Support/ErrorHandling.h"
72 #include "llvm/Support/ErrorOr.h"
73 #include "llvm/Support/FileSystem.h"
74 #include "llvm/Support/Format.h"
75 #include "llvm/Support/LEB128.h"
76 #include "llvm/Support/MathExtras.h"
77 #include "llvm/Support/MemoryBuffer.h"
78 #include "llvm/Support/Path.h"
79 #include "llvm/Support/TargetRegistry.h"
80 #include "llvm/Support/ThreadPool.h"
81 #include "llvm/Support/ToolOutputFile.h"
82 #include "llvm/Support/WithColor.h"
83 #include "llvm/Support/raw_ostream.h"
84 #include "llvm/Target/TargetMachine.h"
85 #include "llvm/Target/TargetOptions.h"
86 #include "llvm/MC/MCTargetOptionsCommandFlags.h"
87 #include <algorithm>
88 #include <cassert>
89 #include <cinttypes>
90 #include <climits>
91 #include <cstdint>
92 #include <cstdlib>
93 #include <cstring>
94 #include <limits>
95 #include <map>
96 #include <memory>
97 #include <string>
98 #include <system_error>
99 #include <tuple>
100 #include <utility>
101 #include <vector>
102
103 namespace llvm {
104
105 static mc::RegisterMCTargetOptionsFlags MOF;
106
107 namespace dsymutil {
108
copySwiftInterfaces(const std::map<std::string,std::string> & ParseableSwiftInterfaces,StringRef Architecture,const LinkOptions & Options)109 static Error copySwiftInterfaces(
110 const std::map<std::string, std::string> &ParseableSwiftInterfaces,
111 StringRef Architecture, const LinkOptions &Options) {
112 std::error_code EC;
113 SmallString<128> InputPath;
114 SmallString<128> Path;
115 sys::path::append(Path, *Options.ResourceDir, "Swift", Architecture);
116 if ((EC = sys::fs::create_directories(Path.str(), true,
117 sys::fs::perms::all_all)))
118 return make_error<StringError>(
119 "cannot create directory: " + toString(errorCodeToError(EC)), EC);
120 unsigned BaseLength = Path.size();
121
122 for (auto &I : ParseableSwiftInterfaces) {
123 StringRef ModuleName = I.first;
124 StringRef InterfaceFile = I.second;
125 if (!Options.PrependPath.empty()) {
126 InputPath.clear();
127 sys::path::append(InputPath, Options.PrependPath, InterfaceFile);
128 InterfaceFile = InputPath;
129 }
130 sys::path::append(Path, ModuleName);
131 Path.append(".swiftinterface");
132 if (Options.Verbose)
133 outs() << "copy parseable Swift interface " << InterfaceFile << " -> "
134 << Path.str() << '\n';
135
136 // copy_file attempts an APFS clone first, so this should be cheap.
137 if ((EC = sys::fs::copy_file(InterfaceFile, Path.str())))
138 warn(Twine("cannot copy parseable Swift interface ") + InterfaceFile +
139 ": " + toString(errorCodeToError(EC)));
140 Path.resize(BaseLength);
141 }
142 return Error::success();
143 }
144
145 /// Report a warning to the user, optionally including information about a
146 /// specific \p DIE related to the warning.
reportWarning(const Twine & Warning,StringRef Context,const DWARFDie * DIE) const147 void DwarfLinkerForBinary::reportWarning(const Twine &Warning,
148 StringRef Context,
149 const DWARFDie *DIE) const {
150
151 warn(Warning, Context);
152
153 if (!Options.Verbose || !DIE)
154 return;
155
156 DIDumpOptions DumpOpts;
157 DumpOpts.ChildRecurseDepth = 0;
158 DumpOpts.Verbose = Options.Verbose;
159
160 WithColor::note() << " in DIE:\n";
161 DIE->dump(errs(), 6 /* Indent */, DumpOpts);
162 }
163
createStreamer(const Triple & TheTriple,raw_fd_ostream & OutFile)164 bool DwarfLinkerForBinary::createStreamer(const Triple &TheTriple,
165 raw_fd_ostream &OutFile) {
166 if (Options.NoOutput)
167 return true;
168
169 Streamer = std::make_unique<DwarfStreamer>(
170 Options.FileType, OutFile, Options.Translator, Options.Minimize,
171 [&](const Twine &Error, StringRef Context, const DWARFDie *) {
172 error(Error, Context);
173 },
174 [&](const Twine &Warning, StringRef Context, const DWARFDie *) {
175 warn(Warning, Context);
176 });
177 return Streamer->init(TheTriple);
178 }
179
180 ErrorOr<const object::ObjectFile &>
loadObject(const DebugMapObject & Obj,const Triple & Triple)181 DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
182 const Triple &Triple) {
183 auto ObjectEntry =
184 BinHolder.getObjectEntry(Obj.getObjectFilename(), Obj.getTimestamp());
185 if (!ObjectEntry) {
186 auto Err = ObjectEntry.takeError();
187 reportWarning(Twine(Obj.getObjectFilename()) + ": " +
188 toString(std::move(Err)),
189 Obj.getObjectFilename());
190 return errorToErrorCode(std::move(Err));
191 }
192
193 auto Object = ObjectEntry->getObject(Triple);
194 if (!Object) {
195 auto Err = Object.takeError();
196 reportWarning(Twine(Obj.getObjectFilename()) + ": " +
197 toString(std::move(Err)),
198 Obj.getObjectFilename());
199 return errorToErrorCode(std::move(Err));
200 }
201
202 return *Object;
203 }
204
remarksErrorHandler(const DebugMapObject & DMO,DwarfLinkerForBinary & Linker,std::unique_ptr<FileError> FE)205 static Error remarksErrorHandler(const DebugMapObject &DMO,
206 DwarfLinkerForBinary &Linker,
207 std::unique_ptr<FileError> FE) {
208 bool IsArchive = DMO.getObjectFilename().endswith(")");
209 // Don't report errors for missing remark files from static
210 // archives.
211 if (!IsArchive)
212 return Error(std::move(FE));
213
214 std::string Message = FE->message();
215 Error E = FE->takeError();
216 Error NewE = handleErrors(std::move(E), [&](std::unique_ptr<ECError> EC) {
217 if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory)
218 return Error(std::move(EC));
219
220 Linker.reportWarning(Message, DMO.getObjectFilename());
221 return Error(Error::success());
222 });
223
224 if (!NewE)
225 return Error::success();
226
227 return createFileError(FE->getFileName(), std::move(NewE));
228 }
229
emitRemarks(const LinkOptions & Options,StringRef BinaryPath,StringRef ArchName,const remarks::RemarkLinker & RL)230 static Error emitRemarks(const LinkOptions &Options, StringRef BinaryPath,
231 StringRef ArchName, const remarks::RemarkLinker &RL) {
232 // Make sure we don't create the directories and the file if there is nothing
233 // to serialize.
234 if (RL.empty())
235 return Error::success();
236
237 SmallString<128> InputPath;
238 SmallString<128> Path;
239 // Create the "Remarks" directory in the "Resources" directory.
240 sys::path::append(Path, *Options.ResourceDir, "Remarks");
241 if (std::error_code EC = sys::fs::create_directories(Path.str(), true,
242 sys::fs::perms::all_all))
243 return errorCodeToError(EC);
244
245 // Append the file name.
246 // For fat binaries, also append a dash and the architecture name.
247 sys::path::append(Path, sys::path::filename(BinaryPath));
248 if (Options.NumDebugMaps > 1) {
249 // More than one debug map means we have a fat binary.
250 Path += '-';
251 Path += ArchName;
252 }
253
254 std::error_code EC;
255 raw_fd_ostream OS(Options.NoOutput ? "-" : Path.str(), EC, sys::fs::OF_None);
256 if (EC)
257 return errorCodeToError(EC);
258
259 if (Error E = RL.serialize(OS, Options.RemarksFormat))
260 return E;
261
262 return Error::success();
263 }
264
265 ErrorOr<DWARFFile &>
loadObject(const DebugMapObject & Obj,const DebugMap & DebugMap,remarks::RemarkLinker & RL)266 DwarfLinkerForBinary::loadObject(const DebugMapObject &Obj,
267 const DebugMap &DebugMap,
268 remarks::RemarkLinker &RL) {
269 auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());
270
271 if (ErrorOrObj) {
272 ContextForLinking.push_back(
273 std::unique_ptr<DWARFContext>(DWARFContext::create(*ErrorOrObj)));
274 AddressMapForLinking.push_back(
275 std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj));
276
277 ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
278 Obj.getObjectFilename(), ContextForLinking.back().get(),
279 AddressMapForLinking.back().get(),
280 Obj.empty() ? Obj.getWarnings() : EmptyWarnings));
281
282 Error E = RL.link(*ErrorOrObj);
283 if (Error NewE = handleErrors(
284 std::move(E), [&](std::unique_ptr<FileError> EC) -> Error {
285 return remarksErrorHandler(Obj, *this, std::move(EC));
286 }))
287 return errorToErrorCode(std::move(NewE));
288
289 return *ObjectsForLinking.back();
290 }
291
292 return ErrorOrObj.getError();
293 }
294
link(const DebugMap & Map)295 bool DwarfLinkerForBinary::link(const DebugMap &Map) {
296 if (!createStreamer(Map.getTriple(), OutFile))
297 return false;
298
299 ObjectsForLinking.clear();
300 ContextForLinking.clear();
301 AddressMapForLinking.clear();
302
303 DebugMap DebugMap(Map.getTriple(), Map.getBinaryPath());
304
305 DWARFLinker GeneralLinker(Streamer.get(), DwarfLinkerClient::Dsymutil);
306
307 remarks::RemarkLinker RL;
308 if (!Options.RemarksPrependPath.empty())
309 RL.setExternalFilePrependPath(Options.RemarksPrependPath);
310 GeneralLinker.setObjectPrefixMap(&Options.ObjectPrefixMap);
311
312 std::function<StringRef(StringRef)> TranslationLambda = [&](StringRef Input) {
313 assert(Options.Translator);
314 return Options.Translator(Input);
315 };
316
317 GeneralLinker.setVerbosity(Options.Verbose);
318 GeneralLinker.setStatistics(Options.Statistics);
319 GeneralLinker.setNoOutput(Options.NoOutput);
320 GeneralLinker.setNoODR(Options.NoODR);
321 GeneralLinker.setUpdate(Options.Update);
322 GeneralLinker.setNumThreads(Options.Threads);
323 GeneralLinker.setAccelTableKind(Options.TheAccelTableKind);
324 GeneralLinker.setPrependPath(Options.PrependPath);
325 if (Options.Translator)
326 GeneralLinker.setStringsTranslator(TranslationLambda);
327 GeneralLinker.setWarningHandler(
328 [&](const Twine &Warning, StringRef Context, const DWARFDie *DIE) {
329 reportWarning(Warning, Context, DIE);
330 });
331 GeneralLinker.setErrorHandler(
332 [&](const Twine &Error, StringRef Context, const DWARFDie *) {
333 error(Error, Context);
334 });
335 GeneralLinker.setObjFileLoader(
336 [&DebugMap, &RL, this](StringRef ContainerName,
337 StringRef Path) -> ErrorOr<DWARFFile &> {
338 auto &Obj = DebugMap.addDebugMapObject(
339 Path, sys::TimePoint<std::chrono::seconds>(), MachO::N_OSO);
340
341 if (auto ErrorOrObj = loadObject(Obj, DebugMap, RL)) {
342 return *ErrorOrObj;
343 } else {
344 // Try and emit more helpful warnings by applying some heuristics.
345 StringRef ObjFile = ContainerName;
346 bool IsClangModule = sys::path::extension(Path).equals(".pcm");
347 bool IsArchive = ObjFile.endswith(")");
348
349 if (IsClangModule) {
350 StringRef ModuleCacheDir = sys::path::parent_path(Path);
351 if (sys::fs::exists(ModuleCacheDir)) {
352 // If the module's parent directory exists, we assume that the
353 // module cache has expired and was pruned by clang. A more
354 // adventurous dsymutil would invoke clang to rebuild the module
355 // now.
356 if (!ModuleCacheHintDisplayed) {
357 WithColor::note()
358 << "The clang module cache may have expired since "
359 "this object file was built. Rebuilding the "
360 "object file will rebuild the module cache.\n";
361 ModuleCacheHintDisplayed = true;
362 }
363 } else if (IsArchive) {
364 // If the module cache directory doesn't exist at all and the
365 // object file is inside a static library, we assume that the
366 // static library was built on a different machine. We don't want
367 // to discourage module debugging for convenience libraries within
368 // a project though.
369 if (!ArchiveHintDisplayed) {
370 WithColor::note()
371 << "Linking a static library that was built with "
372 "-gmodules, but the module cache was not found. "
373 "Redistributable static libraries should never be "
374 "built with module debugging enabled. The debug "
375 "experience will be degraded due to incomplete "
376 "debug information.\n";
377 ArchiveHintDisplayed = true;
378 }
379 }
380 }
381
382 return ErrorOrObj.getError();
383 }
384
385 llvm_unreachable("Unhandled DebugMap object");
386 });
387 GeneralLinker.setSwiftInterfacesMap(&ParseableSwiftInterfaces);
388
389 for (const auto &Obj : Map.objects()) {
390 // N_AST objects (swiftmodule files) should get dumped directly into the
391 // appropriate DWARF section.
392 if (Obj->getType() == MachO::N_AST) {
393 if (Options.Verbose)
394 outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
395
396 StringRef File = Obj->getObjectFilename();
397 auto ErrorOrMem = MemoryBuffer::getFile(File);
398 if (!ErrorOrMem) {
399 warn("Could not open '" + File + "'\n");
400 continue;
401 }
402 sys::fs::file_status Stat;
403 if (auto Err = sys::fs::status(File, Stat)) {
404 warn(Err.message());
405 continue;
406 }
407 if (!Options.NoTimestamp) {
408 // The modification can have sub-second precision so we need to cast
409 // away the extra precision that's not present in the debug map.
410 auto ModificationTime =
411 std::chrono::time_point_cast<std::chrono::seconds>(
412 Stat.getLastModificationTime());
413 if (ModificationTime != Obj->getTimestamp()) {
414 // Not using the helper here as we can easily stream TimePoint<>.
415 WithColor::warning() << "Timestamp mismatch for " << File << ": "
416 << Stat.getLastModificationTime() << " and "
417 << sys::TimePoint<>(Obj->getTimestamp()) << "\n";
418 continue;
419 }
420 }
421
422 // Copy the module into the .swift_ast section.
423 if (!Options.NoOutput)
424 Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());
425
426 continue;
427 }
428
429 if (auto ErrorOrObj = loadObject(*Obj, Map, RL))
430 GeneralLinker.addObjectFile(*ErrorOrObj);
431 else {
432 ObjectsForLinking.push_back(std::make_unique<DWARFFile>(
433 Obj->getObjectFilename(), nullptr, nullptr,
434 Obj->empty() ? Obj->getWarnings() : EmptyWarnings));
435 GeneralLinker.addObjectFile(*ObjectsForLinking.back());
436 }
437 }
438
439 // link debug info for loaded object files.
440 GeneralLinker.link();
441
442 StringRef ArchName = Map.getTriple().getArchName();
443 if (Error E = emitRemarks(Options, Map.getBinaryPath(), ArchName, RL))
444 return error(toString(std::move(E)));
445
446 if (Options.NoOutput)
447 return true;
448
449 if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {
450 StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch());
451 if (auto E =
452 copySwiftInterfaces(ParseableSwiftInterfaces, ArchName, Options))
453 return error(toString(std::move(E)));
454 }
455
456 if (Map.getTriple().isOSDarwin() && !Map.getBinaryPath().empty() &&
457 Options.FileType == OutputFileType::Object)
458 return MachOUtils::generateDsymCompanion(
459 Options.VFS, Map, Options.Translator,
460 *Streamer->getAsmPrinter().OutStreamer, OutFile);
461
462 Streamer->finish();
463 return true;
464 }
465
isMachOPairedReloc(uint64_t RelocType,uint64_t Arch)466 static bool isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) {
467 switch (Arch) {
468 case Triple::x86:
469 return RelocType == MachO::GENERIC_RELOC_SECTDIFF ||
470 RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF;
471 case Triple::x86_64:
472 return RelocType == MachO::X86_64_RELOC_SUBTRACTOR;
473 case Triple::arm:
474 case Triple::thumb:
475 return RelocType == MachO::ARM_RELOC_SECTDIFF ||
476 RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
477 RelocType == MachO::ARM_RELOC_HALF ||
478 RelocType == MachO::ARM_RELOC_HALF_SECTDIFF;
479 case Triple::aarch64:
480 return RelocType == MachO::ARM64_RELOC_SUBTRACTOR;
481 default:
482 return false;
483 }
484 }
485
486 /// Iterate over the relocations of the given \p Section and
487 /// store the ones that correspond to debug map entries into the
488 /// ValidRelocs array.
findValidRelocsMachO(const object::SectionRef & Section,const object::MachOObjectFile & Obj,const DebugMapObject & DMO)489 void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(
490 const object::SectionRef &Section, const object::MachOObjectFile &Obj,
491 const DebugMapObject &DMO) {
492 Expected<StringRef> ContentsOrErr = Section.getContents();
493 if (!ContentsOrErr) {
494 consumeError(ContentsOrErr.takeError());
495 Linker.reportWarning("error reading section", DMO.getObjectFilename());
496 return;
497 }
498 DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0);
499 bool SkipNext = false;
500
501 for (const object::RelocationRef &Reloc : Section.relocations()) {
502 if (SkipNext) {
503 SkipNext = false;
504 continue;
505 }
506
507 object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
508 MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
509
510 if (isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),
511 Obj.getArch())) {
512 SkipNext = true;
513 Linker.reportWarning("unsupported relocation in debug_info section.",
514 DMO.getObjectFilename());
515 continue;
516 }
517
518 unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
519 uint64_t Offset64 = Reloc.getOffset();
520 if ((RelocSize != 4 && RelocSize != 8)) {
521 Linker.reportWarning("unsupported relocation in debug_info section.",
522 DMO.getObjectFilename());
523 continue;
524 }
525 uint64_t OffsetCopy = Offset64;
526 // Mach-o uses REL relocations, the addend is at the relocation offset.
527 uint64_t Addend = Data.getUnsigned(&OffsetCopy, RelocSize);
528 uint64_t SymAddress;
529 int64_t SymOffset;
530
531 if (Obj.isRelocationScattered(MachOReloc)) {
532 // The address of the base symbol for scattered relocations is
533 // stored in the reloc itself. The actual addend will store the
534 // base address plus the offset.
535 SymAddress = Obj.getScatteredRelocationValue(MachOReloc);
536 SymOffset = int64_t(Addend) - SymAddress;
537 } else {
538 SymAddress = Addend;
539 SymOffset = 0;
540 }
541
542 auto Sym = Reloc.getSymbol();
543 if (Sym != Obj.symbol_end()) {
544 Expected<StringRef> SymbolName = Sym->getName();
545 if (!SymbolName) {
546 consumeError(SymbolName.takeError());
547 Linker.reportWarning("error getting relocation symbol name.",
548 DMO.getObjectFilename());
549 continue;
550 }
551 if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
552 ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
553 } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) {
554 // Do not store the addend. The addend was the address of the symbol in
555 // the object file, the address in the binary that is stored in the debug
556 // map doesn't need to be offset.
557 ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset, Mapping);
558 }
559 }
560 }
561
562 /// Dispatch the valid relocation finding logic to the
563 /// appropriate handler depending on the object file format.
findValidRelocs(const object::SectionRef & Section,const object::ObjectFile & Obj,const DebugMapObject & DMO)564 bool DwarfLinkerForBinary::AddressManager::findValidRelocs(
565 const object::SectionRef &Section, const object::ObjectFile &Obj,
566 const DebugMapObject &DMO) {
567 // Dispatch to the right handler depending on the file type.
568 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
569 findValidRelocsMachO(Section, *MachOObj, DMO);
570 else
571 Linker.reportWarning(Twine("unsupported object file type: ") +
572 Obj.getFileName(),
573 DMO.getObjectFilename());
574 if (ValidRelocs.empty())
575 return false;
576
577 // Sort the relocations by offset. We will walk the DIEs linearly in
578 // the file, this allows us to just keep an index in the relocation
579 // array that we advance during our walk, rather than resorting to
580 // some associative container. See DwarfLinkerForBinary::NextValidReloc.
581 llvm::sort(ValidRelocs);
582 return true;
583 }
584
585 /// Look for relocations in the debug_info section that match
586 /// entries in the debug map. These relocations will drive the Dwarf
587 /// link by indicating which DIEs refer to symbols present in the
588 /// linked binary.
589 /// \returns whether there are any valid relocations in the debug info.
findValidRelocsInDebugInfo(const object::ObjectFile & Obj,const DebugMapObject & DMO)590 bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugInfo(
591 const object::ObjectFile &Obj, const DebugMapObject &DMO) {
592 // Find the debug_info section.
593 for (const object::SectionRef &Section : Obj.sections()) {
594 StringRef SectionName;
595 if (Expected<StringRef> NameOrErr = Section.getName())
596 SectionName = *NameOrErr;
597 else
598 consumeError(NameOrErr.takeError());
599
600 SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
601 if (SectionName != "debug_info")
602 continue;
603 return findValidRelocs(Section, Obj, DMO);
604 }
605 return false;
606 }
607
608 /// Checks that there is a relocation against an actual debug
609 /// map entry between \p StartOffset and \p NextOffset.
610 ///
611 /// This function must be called with offsets in strictly ascending
612 /// order because it never looks back at relocations it already 'went past'.
613 /// \returns true and sets Info.InDebugMap if it is the case.
hasValidRelocationAt(uint64_t StartOffset,uint64_t EndOffset,CompileUnit::DIEInfo & Info)614 bool DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(
615 uint64_t StartOffset, uint64_t EndOffset, CompileUnit::DIEInfo &Info) {
616 assert(NextValidReloc == 0 ||
617 StartOffset > ValidRelocs[NextValidReloc - 1].Offset);
618 if (NextValidReloc >= ValidRelocs.size())
619 return false;
620
621 uint64_t RelocOffset = ValidRelocs[NextValidReloc].Offset;
622
623 // We might need to skip some relocs that we didn't consider. For
624 // example the high_pc of a discarded DIE might contain a reloc that
625 // is in the list because it actually corresponds to the start of a
626 // function that is in the debug map.
627 while (RelocOffset < StartOffset && NextValidReloc < ValidRelocs.size() - 1)
628 RelocOffset = ValidRelocs[++NextValidReloc].Offset;
629
630 if (RelocOffset < StartOffset || RelocOffset >= EndOffset)
631 return false;
632
633 const auto &ValidReloc = ValidRelocs[NextValidReloc++];
634 const auto &Mapping = ValidReloc.Mapping->getValue();
635 const uint64_t BinaryAddress = Mapping.BinaryAddress;
636 const uint64_t ObjectAddress = Mapping.ObjectAddress
637 ? uint64_t(*Mapping.ObjectAddress)
638 : std::numeric_limits<uint64_t>::max();
639 if (Linker.Options.Verbose)
640 outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey()
641 << "\t"
642 << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress,
643 BinaryAddress);
644
645 Info.AddrAdjust = BinaryAddress + ValidReloc.Addend;
646 if (Mapping.ObjectAddress)
647 Info.AddrAdjust -= ObjectAddress;
648 Info.InDebugMap = true;
649 return true;
650 }
651
652 /// Apply the valid relocations found by findValidRelocs() to
653 /// the buffer \p Data, taking into account that Data is at \p BaseOffset
654 /// in the debug_info section.
655 ///
656 /// Like for findValidRelocs(), this function must be called with
657 /// monotonic \p BaseOffset values.
658 ///
659 /// \returns whether any reloc has been applied.
applyValidRelocs(MutableArrayRef<char> Data,uint64_t BaseOffset,bool IsLittleEndian)660 bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(
661 MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {
662 assert(areRelocationsResolved());
663 assert((NextValidReloc == 0 ||
664 BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
665 "BaseOffset should only be increasing.");
666 if (NextValidReloc >= ValidRelocs.size())
667 return false;
668
669 // Skip relocs that haven't been applied.
670 while (NextValidReloc < ValidRelocs.size() &&
671 ValidRelocs[NextValidReloc].Offset < BaseOffset)
672 ++NextValidReloc;
673
674 bool Applied = false;
675 uint64_t EndOffset = BaseOffset + Data.size();
676 while (NextValidReloc < ValidRelocs.size() &&
677 ValidRelocs[NextValidReloc].Offset >= BaseOffset &&
678 ValidRelocs[NextValidReloc].Offset < EndOffset) {
679 const auto &ValidReloc = ValidRelocs[NextValidReloc++];
680 assert(ValidReloc.Offset - BaseOffset < Data.size());
681 assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size());
682 char Buf[8];
683 uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress;
684 Value += ValidReloc.Addend;
685 for (unsigned I = 0; I != ValidReloc.Size; ++I) {
686 unsigned Index = IsLittleEndian ? I : (ValidReloc.Size - I - 1);
687 Buf[I] = uint8_t(Value >> (Index * 8));
688 }
689 assert(ValidReloc.Size <= sizeof(Buf));
690 memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size);
691 Applied = true;
692 }
693
694 return Applied;
695 }
696
linkDwarf(raw_fd_ostream & OutFile,BinaryHolder & BinHolder,const DebugMap & DM,LinkOptions Options)697 bool linkDwarf(raw_fd_ostream &OutFile, BinaryHolder &BinHolder,
698 const DebugMap &DM, LinkOptions Options) {
699 DwarfLinkerForBinary Linker(OutFile, BinHolder, std::move(Options));
700 return Linker.link(DM);
701 }
702
703 } // namespace dsymutil
704 } // namespace llvm
705