1259 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DwarfLinkerForBinary.h"10#include "BinaryHolder.h"11#include "DebugMap.h"12#include "MachOUtils.h"13#include "SwiftModule.h"14#include "dsymutil.h"15#include "llvm/ADT/ArrayRef.h"16#include "llvm/ADT/DenseMap.h"17#include "llvm/ADT/FoldingSet.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(errs(), 6 /* Indent */, DumpOpts);119}120 121/// Report a warning to the user, optionally including information about a122/// 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, 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, 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(Obj.getObjectFilename(), Obj.getTimestamp());148 if (!ObjectEntry) {149 auto Err = ObjectEntry.takeError();150 reportWarning(Twine(Obj.getObjectFilename()) + ": " +151 toStringWithoutConsuming(Err),152 Obj.getObjectFilename());153 return errorToErrorCode(std::move(Err));154 }155 156 auto Object = ObjectEntry->getObject(Triple);157 if (!Object) {158 auto Err = Object.takeError();159 reportWarning(Twine(Obj.getObjectFilename()) + ": " +160 toStringWithoutConsuming(Err),161 Obj.getObjectFilename());162 return errorToErrorCode(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(")");172 // Don't report errors for missing remark files from static173 // 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(std::move(E), [&](std::unique_ptr<ECError> EC) {180 if (EC->convertToErrorCode() != std::errc::no_such_file_or_directory)181 return Error(std::move(EC));182 183 Linker.reportWarning(Message, DMO.getObjectFilename());184 return Error(Error::success());185 });186 187 if (!NewE)188 return Error::success();189 190 return createFileError(FE->getFileName(), 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, and207 // 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 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 nothing231 // 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, *Options.ResourceDir, "Remarks");238 if (std::error_code EC = sys::fs::create_directories(Path.str(), true,239 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, sys::path::filename(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::Bitstream254 ? sys::fs::OF_None255 : sys::fs::OF_Text);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 265ErrorOr<std::unique_ptr<DWARFFile>> DwarfLinkerForBinary::loadObject(266 const DebugMapObject &Obj, const DebugMap &DebugMap,267 remarks::RemarkLinker &RL,268 std::shared_ptr<DwarfLinkerForBinaryRelocationMap> DLBRM) {269 auto ErrorOrObj = loadObject(Obj, DebugMap.getTriple());270 std::unique_ptr<DWARFFile> Res;271 272 if (ErrorOrObj) {273 auto Context = DWARFContext::create(274 *ErrorOrObj, DWARFContext::ProcessDebugRelocations::Process, nullptr,275 "",276 [&](Error Err) {277 handleAllErrors(std::move(Err), [&](ErrorInfoBase &Info) {278 reportError(Info.message());279 });280 },281 [&](Error Warning) {282 handleAllErrors(std::move(Warning), [&](ErrorInfoBase &Info) {283 reportWarning(Info.message());284 });285 });286 DLBRM->init(*Context);287 Res = std::make_unique<DWARFFile>(288 Obj.getObjectFilename(), std::move(Context),289 std::make_unique<AddressManager>(*this, *ErrorOrObj, Obj, DLBRM),290 [&](StringRef FileName) { BinHolder.eraseObjectEntry(FileName); });291 292 Error E = RL.link(*ErrorOrObj);293 // FIXME: Remark parsing errors are not propagated to the user.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 306static bool binaryHasStrippableSwiftReflectionSections(307 const DebugMap &Map, const LinkOptions &Options, BinaryHolder &BinHolder) {308 // If the input binary has strippable swift5 reflection sections, there is no309 // need to copy them to the .dSYM. Only copy them for binaries where the310 // 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 no316 // 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 appear351/// in alphabetic order.352static std::vector<uint64_t>353calculateStartOfStrippableReflectionSections(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 section389 // 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 400void 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 currently451 // 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 a464 // non-strippable section (for example, typeref, or __TEXT,__const),465 // in which case we look up its address in the binary, which dsymutil466 // will copy verbatim.467 SecondSymbolAddress = Mapping->getValue().BinaryAddress;468 // Since the symbols live in different segments, we have to substract469 // the start of the Dwarf's vmaddr so the value calculated points to470 // 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, and478 // 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 502Error 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 536void 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 is550 // 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, so584 // the next section we copy from a different .o file points to the correct585 // place.586 SectionToOffsetInDwarf[SectionKind] += Section.getSize();587 Streamer->emitSwiftReflectionSection(SectionKind, *SectionContents,588 Section.getAlignment().value(),589 Section.getSize());590 }591 }592}593 594bool 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 601template <typename Linker>602void 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 else619 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 629template <typename Linker>630bool 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 } else670 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 the715 // module cache has expired and was pruned by clang. A more716 // adventurous dsymutil would invoke clang to rebuild the module717 // 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 the727 // object file is inside a static library, we assume that the728 // static library was built on a different machine. We don't want729 // to discourage module debugging for convenience libraries within730 // 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 swift5752 // 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 llvm::StringSet<> SwiftModules;774 for (const auto &Obj : Map.objects()) {775 // N_AST objects (swiftmodule files) should get dumped directly into the776 // appropriate DWARF section.777 if (Obj->getType() == MachO::N_AST) {778 if (Options.Verbose)779 outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";780 781 StringRef File = Obj->getObjectFilename();782 if (!SwiftModules.insert(File).second)783 continue;784 785 auto ErrorOrMem = MemoryBuffer::getFile(File);786 if (!ErrorOrMem) {787 reportWarning("Could not open '" + File + "'");788 continue;789 }790 auto FromInterfaceOrErr =791 IsBuiltFromSwiftInterface((*ErrorOrMem)->getBuffer());792 if (!FromInterfaceOrErr) {793 reportWarning("Could not parse binary Swift module: " +794 toString(FromInterfaceOrErr.takeError()),795 Obj->getObjectFilename());796 // Only skip swiftmodules that could be parsed and are positively797 // identified as textual. Do so only when the option allows.798 } else if (*FromInterfaceOrErr &&799 !Options.IncludeSwiftModulesFromInterface) {800 if (Options.Verbose)801 outs() << "Skipping compiled textual Swift interface: "802 << Obj->getObjectFilename() << "\n";803 continue;804 }805 806 sys::fs::file_status Stat;807 if (auto Err = sys::fs::status(File, Stat)) {808 reportWarning(Err.message());809 continue;810 }811 if (!Options.NoTimestamp) {812 // The modification can have sub-second precision so we need to cast813 // away the extra precision that's not present in the debug map.814 auto ModificationTime =815 std::chrono::time_point_cast<std::chrono::seconds>(816 Stat.getLastModificationTime());817 if (Obj->getTimestamp() != sys::TimePoint<>() &&818 ModificationTime != Obj->getTimestamp()) {819 // Not using the helper here as we can easily stream TimePoint<>.820 WithColor::warning()821 << File << ": timestamp mismatch between swift interface file ("822 << sys::TimePoint<>(ModificationTime) << ") and debug map ("823 << sys::TimePoint<>(Obj->getTimestamp()) << ")\n";824 continue;825 }826 }827 828 // Copy the module into the .swift_ast section.829 if (!Options.NoOutput)830 Streamer->emitSwiftAST((*ErrorOrMem)->getBuffer());831 832 continue;833 }834 835 auto DLBRelocMap = std::make_shared<DwarfLinkerForBinaryRelocationMap>();836 if (ErrorOr<std::unique_ptr<DWARFFile>> ErrorOrObj =837 loadObject(*Obj, Map, RL, DLBRelocMap)) {838 ObjectsForLinking.emplace_back(std::move(*ErrorOrObj), DLBRelocMap);839 GeneralLinker->addObjectFile(*ObjectsForLinking.back().Object, Loader,840 OnCUDieLoaded);841 } else {842 ObjectsForLinking.push_back(843 {std::make_unique<DWARFFile>(Obj->getObjectFilename(), nullptr,844 nullptr),845 DLBRelocMap});846 GeneralLinker->addObjectFile(*ObjectsForLinking.back().Object);847 }848 }849 850 // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway.851 if (MaxDWARFVersion == 0)852 MaxDWARFVersion = 3;853 854 if (Error E = GeneralLinker->setTargetDWARFVersion(MaxDWARFVersion))855 return error(toString(std::move(E)));856 857 setAcceleratorTables<Linker>(*GeneralLinker, Options.TheAccelTableKind,858 MaxDWARFVersion);859 860 // link debug info for loaded object files.861 if (Error E = GeneralLinker->link())862 return error(toString(std::move(E)));863 864 StringRef ArchName = Map.getTriple().getArchName();865 if (Error E = emitRemarks(Options, Map.getBinaryPath(), ArchName, RL))866 return error(toString(std::move(E)));867 868 if (Options.NoOutput)869 return true;870 871 if (Error E = emitRelocations(Map, ObjectsForLinking))872 return error(toString(std::move(E)));873 874 if (Options.ResourceDir && !ParseableSwiftInterfaces.empty()) {875 StringRef ArchName = Triple::getArchTypeName(Map.getTriple().getArch());876 if (auto E = copySwiftInterfaces(ArchName))877 return error(toString(std::move(E)));878 }879 880 auto MapTriple = Map.getTriple();881 if ((MapTriple.isOSDarwin() || MapTriple.isOSBinFormatMachO()) &&882 !Map.getBinaryPath().empty() &&883 ObjectType == Linker::OutputFileType::Object)884 return MachOUtils::generateDsymCompanion(885 Options.VFS, Map, *Streamer->getAsmPrinter().OutStreamer, OutFile,886 RelocationsToApply);887 888 Streamer->finish();889 return true;890}891 892/// Iterate over the relocations of the given \p Section and893/// store the ones that correspond to debug map entries into the894/// ValidRelocs array.895void DwarfLinkerForBinary::AddressManager::findValidRelocsMachO(896 const object::SectionRef &Section, const object::MachOObjectFile &Obj,897 const DebugMapObject &DMO, std::vector<ValidReloc> &ValidRelocs) {898 Expected<StringRef> ContentsOrErr = Section.getContents();899 if (!ContentsOrErr) {900 consumeError(ContentsOrErr.takeError());901 Linker.reportWarning("error reading section", DMO.getObjectFilename());902 return;903 }904 DataExtractor Data(*ContentsOrErr, Obj.isLittleEndian(), 0);905 bool SkipNext = false;906 907 for (const object::RelocationRef &Reloc : Section.relocations()) {908 if (SkipNext) {909 SkipNext = false;910 continue;911 }912 913 object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();914 MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);915 916 if (object::MachOObjectFile::isMachOPairedReloc(Obj.getAnyRelocationType(MachOReloc),917 Obj.getArch())) {918 SkipNext = true;919 Linker.reportWarning("unsupported relocation in " + *Section.getName() +920 " section.",921 DMO.getObjectFilename());922 continue;923 }924 925 unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);926 uint64_t Offset64 = Reloc.getOffset();927 if ((RelocSize != 4 && RelocSize != 8)) {928 Linker.reportWarning("unsupported relocation in " + *Section.getName() +929 " section.",930 DMO.getObjectFilename());931 continue;932 }933 uint64_t OffsetCopy = Offset64;934 // Mach-o uses REL relocations, the addend is at the relocation offset.935 uint64_t Addend = Data.getUnsigned(&OffsetCopy, RelocSize);936 uint64_t SymAddress;937 int64_t SymOffset;938 939 if (Obj.isRelocationScattered(MachOReloc)) {940 // The address of the base symbol for scattered relocations is941 // stored in the reloc itself. The actual addend will store the942 // base address plus the offset.943 SymAddress = Obj.getScatteredRelocationValue(MachOReloc);944 SymOffset = int64_t(Addend) - SymAddress;945 } else {946 SymAddress = Addend;947 SymOffset = 0;948 }949 950 auto Sym = Reloc.getSymbol();951 if (Sym != Obj.symbol_end()) {952 Expected<StringRef> SymbolName = Sym->getName();953 if (!SymbolName) {954 consumeError(SymbolName.takeError());955 Linker.reportWarning("error getting relocation symbol name.",956 DMO.getObjectFilename());957 continue;958 }959 if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))960 ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping->getKey(),961 Mapping->getValue());962 } else if (const auto *Mapping = DMO.lookupObjectAddress(SymAddress)) {963 // Do not store the addend. The addend was the address of the symbol in964 // the object file, the address in the binary that is stored in the debug965 // map doesn't need to be offset.966 ValidRelocs.emplace_back(Offset64, RelocSize, SymOffset,967 Mapping->getKey(), Mapping->getValue());968 }969 }970}971 972/// Dispatch the valid relocation finding logic to the973/// appropriate handler depending on the object file format.974bool DwarfLinkerForBinary::AddressManager::findValidRelocs(975 const object::SectionRef &Section, const object::ObjectFile &Obj,976 const DebugMapObject &DMO, std::vector<ValidReloc> &Relocs) {977 // Dispatch to the right handler depending on the file type.978 if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))979 findValidRelocsMachO(Section, *MachOObj, DMO, Relocs);980 else981 Linker.reportWarning(Twine("unsupported object file type: ") +982 Obj.getFileName(),983 DMO.getObjectFilename());984 if (Relocs.empty())985 return false;986 987 // Sort the relocations by offset. We will walk the DIEs linearly in988 // the file, this allows us to just keep an index in the relocation989 // array that we advance during our walk, rather than resorting to990 // some associative container. See DwarfLinkerForBinary::NextValidReloc.991 llvm::sort(Relocs);992 return true;993}994 995/// Look for relocations in the debug_info and debug_addr section that match996/// entries in the debug map. These relocations will drive the Dwarf link by997/// indicating which DIEs refer to symbols present in the linked binary.998/// \returns whether there are any valid relocations in the debug info.999bool DwarfLinkerForBinary::AddressManager::findValidRelocsInDebugSections(1000 const object::ObjectFile &Obj, const DebugMapObject &DMO) {1001 // Find the debug_info section.1002 bool FoundValidRelocs = false;1003 for (const object::SectionRef &Section : Obj.sections()) {1004 StringRef SectionName;1005 if (Expected<StringRef> NameOrErr = Section.getName())1006 SectionName = *NameOrErr;1007 else1008 consumeError(NameOrErr.takeError());1009 1010 SectionName = SectionName.substr(SectionName.find_first_not_of("._"));1011 if (SectionName == "debug_info")1012 FoundValidRelocs |=1013 findValidRelocs(Section, Obj, DMO, ValidDebugInfoRelocs);1014 if (SectionName == "debug_addr")1015 FoundValidRelocs |=1016 findValidRelocs(Section, Obj, DMO, ValidDebugAddrRelocs);1017 }1018 return FoundValidRelocs;1019}1020 1021std::vector<ValidReloc> DwarfLinkerForBinary::AddressManager::getRelocations(1022 const std::vector<ValidReloc> &Relocs, uint64_t StartPos, uint64_t EndPos) {1023 std::vector<ValidReloc> Res;1024 1025 auto CurReloc = partition_point(Relocs, [StartPos](const ValidReloc &Reloc) {1026 return (uint64_t)Reloc.Offset < StartPos;1027 });1028 1029 while (CurReloc != Relocs.end() && CurReloc->Offset >= StartPos &&1030 (uint64_t)CurReloc->Offset < EndPos) {1031 Res.push_back(*CurReloc);1032 CurReloc++;1033 }1034 1035 return Res;1036}1037 1038void DwarfLinkerForBinary::AddressManager::printReloc(const ValidReloc &Reloc) {1039 const auto &Mapping = Reloc.SymbolMapping;1040 const uint64_t ObjectAddress = Mapping.ObjectAddress1041 ? uint64_t(*Mapping.ObjectAddress)1042 : std::numeric_limits<uint64_t>::max();1043 1044 outs() << "Found valid debug map entry: " << Reloc.SymbolName << "\t"1045 << format("0x%016" PRIx64 " => 0x%016" PRIx64 "\n", ObjectAddress,1046 uint64_t(Mapping.BinaryAddress));1047}1048 1049int64_t1050DwarfLinkerForBinary::AddressManager::getRelocValue(const ValidReloc &Reloc) {1051 int64_t AddrAdjust = relocate(Reloc);1052 if (Reloc.SymbolMapping.ObjectAddress)1053 AddrAdjust -= uint64_t(*Reloc.SymbolMapping.ObjectAddress);1054 return AddrAdjust;1055}1056 1057std::optional<int64_t>1058DwarfLinkerForBinary::AddressManager::hasValidRelocationAt(1059 const std::vector<ValidReloc> &AllRelocs, uint64_t StartOffset,1060 uint64_t EndOffset, bool Verbose) {1061 std::vector<ValidReloc> Relocs =1062 getRelocations(AllRelocs, StartOffset, EndOffset);1063 if (Relocs.size() == 0)1064 return std::nullopt;1065 1066 if (Verbose)1067 printReloc(Relocs[0]);1068 1069 return getRelocValue(Relocs[0]);1070}1071 1072/// Get the starting and ending (exclusive) offset for the1073/// attribute with index \p Idx descibed by \p Abbrev. \p Offset is1074/// supposed to point to the position of the first attribute described1075/// by \p Abbrev.1076/// \return [StartOffset, EndOffset) as a pair.1077static std::pair<uint64_t, uint64_t>1078getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,1079 uint64_t Offset, const DWARFUnit &Unit) {1080 DataExtractor Data = Unit.getDebugInfoExtractor();1081 1082 for (unsigned I = 0; I < Idx; ++I)1083 DWARFFormValue::skipValue(Abbrev->getFormByIndex(I), Data, &Offset,1084 Unit.getFormParams());1085 1086 uint64_t End = Offset;1087 DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End,1088 Unit.getFormParams());1089 1090 return std::make_pair(Offset, End);1091}1092 1093std::optional<int64_t>1094DwarfLinkerForBinary::AddressManager::getExprOpAddressRelocAdjustment(1095 DWARFUnit &U, const DWARFExpression::Operation &Op, uint64_t StartOffset,1096 uint64_t EndOffset, bool Verbose) {1097 switch (Op.getCode()) {1098 default: {1099 assert(false && "Specified operation does not have address operand");1100 } break;1101 case dwarf::DW_OP_const2u:1102 case dwarf::DW_OP_const4u:1103 case dwarf::DW_OP_const8u:1104 case dwarf::DW_OP_const2s:1105 case dwarf::DW_OP_const4s:1106 case dwarf::DW_OP_const8s:1107 case dwarf::DW_OP_addr: {1108 return hasValidRelocationAt(ValidDebugInfoRelocs, StartOffset, EndOffset,1109 Verbose);1110 } break;1111 case dwarf::DW_OP_constx:1112 case dwarf::DW_OP_addrx: {1113 return hasValidRelocationAt(ValidDebugAddrRelocs, StartOffset, EndOffset,1114 Verbose);1115 } break;1116 }1117 1118 return std::nullopt;1119}1120 1121std::optional<int64_t>1122DwarfLinkerForBinary::AddressManager::getSubprogramRelocAdjustment(1123 const DWARFDie &DIE, bool Verbose) {1124 const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();1125 1126 std::optional<uint32_t> LowPcIdx =1127 Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc);1128 if (!LowPcIdx)1129 return std::nullopt;1130 1131 dwarf::Form Form = Abbrev->getFormByIndex(*LowPcIdx);1132 1133 switch (Form) {1134 case dwarf::DW_FORM_addr: {1135 uint64_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());1136 uint64_t LowPcOffset, LowPcEndOffset;1137 std::tie(LowPcOffset, LowPcEndOffset) =1138 getAttributeOffsets(Abbrev, *LowPcIdx, Offset, *DIE.getDwarfUnit());1139 return hasValidRelocationAt(ValidDebugInfoRelocs, LowPcOffset,1140 LowPcEndOffset, Verbose);1141 }1142 case dwarf::DW_FORM_addrx:1143 case dwarf::DW_FORM_addrx1:1144 case dwarf::DW_FORM_addrx2:1145 case dwarf::DW_FORM_addrx3:1146 case dwarf::DW_FORM_addrx4: {1147 std::optional<DWARFFormValue> AddrValue = DIE.find(dwarf::DW_AT_low_pc);1148 if (std::optional<uint64_t> AddressOffset =1149 DIE.getDwarfUnit()->getIndexedAddressOffset(1150 AddrValue->getRawUValue()))1151 return hasValidRelocationAt(1152 ValidDebugAddrRelocs, *AddressOffset,1153 *AddressOffset + DIE.getDwarfUnit()->getAddressByteSize(), Verbose);1154 1155 Linker.reportWarning("no base offset for address table", SrcFileName);1156 return std::nullopt;1157 }1158 default:1159 return std::nullopt;1160 }1161}1162 1163std::optional<StringRef>1164DwarfLinkerForBinary::AddressManager::getLibraryInstallName() {1165 return LibInstallName;1166}1167 1168uint64_t1169DwarfLinkerForBinary::AddressManager::relocate(const ValidReloc &Reloc) const {1170 return Reloc.SymbolMapping.BinaryAddress + Reloc.Addend;1171}1172 1173void DwarfLinkerForBinary::AddressManager::updateAndSaveValidRelocs(1174 bool IsDWARF5, uint64_t OriginalUnitOffset, int64_t LinkedOffset,1175 uint64_t StartOffset, uint64_t EndOffset) {1176 std::vector<ValidReloc> InRelocs =1177 getRelocations(ValidDebugInfoRelocs, StartOffset, EndOffset);1178 if (IsDWARF5)1179 InRelocs = getRelocations(ValidDebugAddrRelocs, StartOffset, EndOffset);1180 DwarfLinkerRelocMap->updateAndSaveValidRelocs(1181 IsDWARF5, InRelocs, OriginalUnitOffset, LinkedOffset);1182}1183 1184void DwarfLinkerForBinary::AddressManager::updateRelocationsWithUnitOffset(1185 uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) {1186 DwarfLinkerRelocMap->updateRelocationsWithUnitOffset(OriginalUnitOffset,1187 OutputUnitOffset);1188}1189/// Apply the valid relocations found by findValidRelocs() to1190/// the buffer \p Data, taking into account that Data is at \p BaseOffset1191/// in the debug_info section.1192///1193/// Like for findValidRelocs(), this function must be called with1194/// monotonic \p BaseOffset values.1195///1196/// \returns whether any reloc has been applied.1197bool DwarfLinkerForBinary::AddressManager::applyValidRelocs(1198 MutableArrayRef<char> Data, uint64_t BaseOffset, bool IsLittleEndian) {1199 1200 std::vector<ValidReloc> Relocs = getRelocations(1201 ValidDebugInfoRelocs, BaseOffset, BaseOffset + Data.size());1202 1203 for (const ValidReloc &CurReloc : Relocs) {1204 assert(CurReloc.Offset - BaseOffset < Data.size());1205 assert(CurReloc.Offset - BaseOffset + CurReloc.Size <= Data.size());1206 char Buf[8];1207 uint64_t Value = relocate(CurReloc);1208 for (unsigned I = 0; I != CurReloc.Size; ++I) {1209 unsigned Index = IsLittleEndian ? I : (CurReloc.Size - I - 1);1210 Buf[I] = uint8_t(Value >> (Index * 8));1211 }1212 assert(CurReloc.Size <= sizeof(Buf));1213 memcpy(&Data[CurReloc.Offset - BaseOffset], Buf, CurReloc.Size);1214 }1215 return Relocs.size() > 0;1216}1217 1218void DwarfLinkerForBinaryRelocationMap::init(DWARFContext &Context) {1219 for (const std::unique_ptr<DWARFUnit> &CU : Context.compile_units())1220 StoredValidDebugInfoRelocsMap.insert(1221 std::make_pair(CU->getOffset(), std::vector<ValidReloc>()));1222 // FIXME: Support relocations debug_addr (DWARF5).1223}1224 1225void DwarfLinkerForBinaryRelocationMap::addValidRelocs(RelocationMap &RM) {1226 for (const auto &DebugInfoRelocs : StoredValidDebugInfoRelocsMap) {1227 for (const auto &InfoReloc : DebugInfoRelocs.second)1228 RM.addRelocationMapEntry(InfoReloc);1229 }1230 // FIXME: Support relocations debug_addr (DWARF5).1231}1232 1233void DwarfLinkerForBinaryRelocationMap::updateRelocationsWithUnitOffset(1234 uint64_t OriginalUnitOffset, uint64_t OutputUnitOffset) {1235 std::vector<ValidReloc> &StoredValidDebugInfoRelocs =1236 StoredValidDebugInfoRelocsMap[OriginalUnitOffset];1237 for (ValidReloc &R : StoredValidDebugInfoRelocs) {1238 R.Offset = (uint64_t)R.Offset + OutputUnitOffset;1239 }1240 // FIXME: Support relocations debug_addr (DWARF5).1241}1242 1243void DwarfLinkerForBinaryRelocationMap::updateAndSaveValidRelocs(1244 bool IsDWARF5, std::vector<ValidReloc> &InRelocs, uint64_t UnitOffset,1245 int64_t LinkedOffset) {1246 std::vector<ValidReloc> &OutRelocs =1247 StoredValidDebugInfoRelocsMap[UnitOffset];1248 if (IsDWARF5)1249 OutRelocs = StoredValidDebugAddrRelocsMap[UnitOffset];1250 1251 for (ValidReloc &R : InRelocs) {1252 OutRelocs.emplace_back(R.Offset + LinkedOffset, R.Size, R.Addend,1253 R.SymbolName, R.SymbolMapping);1254 }1255}1256 1257} // namespace dsymutil1258} // namespace llvm1259