brintos

brintos / llvm-project-archived public Read only

0
0
Text · 100.3 KiB · 6a285f5 Raw
2780 lines · cpp
1//===- bolt/Core/BinaryContext.cpp - Low-level context --------------------===//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// This file implements the BinaryContext class.10//11//===----------------------------------------------------------------------===//12 13#include "bolt/Core/BinaryContext.h"14#include "bolt/Core/BinaryEmitter.h"15#include "bolt/Core/BinaryFunction.h"16#include "bolt/Utils/CommandLineOpts.h"17#include "bolt/Utils/Utils.h"18#include "llvm/ADT/STLExtras.h"19#include "llvm/ADT/Twine.h"20#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"21#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"22#include "llvm/DebugInfo/DWARF/DWARFUnit.h"23#include "llvm/MC/MCAssembler.h"24#include "llvm/MC/MCContext.h"25#include "llvm/MC/MCDisassembler/MCDisassembler.h"26#include "llvm/MC/MCInstPrinter.h"27#include "llvm/MC/MCObjectStreamer.h"28#include "llvm/MC/MCObjectWriter.h"29#include "llvm/MC/MCRegisterInfo.h"30#include "llvm/MC/MCSectionELF.h"31#include "llvm/MC/MCStreamer.h"32#include "llvm/MC/MCSubtargetInfo.h"33#include "llvm/MC/MCSymbol.h"34#include "llvm/Support/CommandLine.h"35#include "llvm/Support/Error.h"36#include "llvm/Support/FileSystem.h"37#include "llvm/Support/Regex.h"38#include <algorithm>39#include <functional>40#include <iterator>41#include <unordered_set>42 43using namespace llvm;44 45#undef  DEBUG_TYPE46#define DEBUG_TYPE "bolt"47 48namespace opts {49 50static cl::opt<bool>51    NoHugePages("no-huge-pages",52                cl::desc("use regular size pages for code alignment"),53                cl::Hidden, cl::cat(BoltCategory));54 55static cl::opt<bool>56PrintDebugInfo("print-debug-info",57  cl::desc("print debug info when printing functions"),58  cl::Hidden,59  cl::ZeroOrMore,60  cl::cat(BoltCategory));61 62cl::opt<bool> PrintRelocations(63    "print-relocations",64    cl::desc("print relocations when printing functions/objects"), cl::Hidden,65    cl::cat(BoltCategory));66 67static cl::opt<bool>68PrintMemData("print-mem-data",69  cl::desc("print memory data annotations when printing functions"),70  cl::Hidden,71  cl::ZeroOrMore,72  cl::cat(BoltCategory));73 74cl::opt<std::string> CompDirOverride(75    "comp-dir-override",76    cl::desc("overrides DW_AT_comp_dir, and provides an alternative base "77             "location, which is used with DW_AT_dwo_name to construct a path "78             "to *.dwo files."),79    cl::Hidden, cl::init(""), cl::cat(BoltCategory));80 81static cl::opt<bool> CloneConstantIsland("clone-constant-island",82                                         cl::desc("clone constant islands"),83                                         cl::Hidden, cl::init(true),84                                         cl::ZeroOrMore, cl::cat(BoltCategory));85 86static cl::opt<bool>87    FailOnInvalidPadding("fail-on-invalid-padding", cl::Hidden, cl::init(false),88                         cl::desc("treat invalid code padding as error"),89                         cl::ZeroOrMore, cl::cat(BoltCategory));90} // namespace opts91 92namespace llvm {93namespace bolt {94 95char BOLTError::ID = 0;96 97BOLTError::BOLTError(bool IsFatal, const Twine &S)98    : IsFatal(IsFatal), Msg(S.str()) {}99 100void BOLTError::log(raw_ostream &OS) const {101  if (IsFatal)102    OS << "FATAL ";103  StringRef ErrMsg = StringRef(Msg);104  // Prepend our error prefix if it is missing105  if (ErrMsg.empty()) {106    OS << "BOLT-ERROR\n";107  } else {108    if (!ErrMsg.starts_with("BOLT-ERROR"))109      OS << "BOLT-ERROR: ";110    OS << ErrMsg << "\n";111  }112}113 114std::error_code BOLTError::convertToErrorCode() const {115  return inconvertibleErrorCode();116}117 118Error createNonFatalBOLTError(const Twine &S) {119  return make_error<BOLTError>(/*IsFatal*/ false, S);120}121 122Error createFatalBOLTError(const Twine &S) {123  return make_error<BOLTError>(/*IsFatal*/ true, S);124}125 126void BinaryContext::logBOLTErrorsAndQuitOnFatal(Error E) {127  handleAllErrors(Error(std::move(E)), [&](const BOLTError &E) {128    if (!E.getMessage().empty())129      E.log(this->errs());130    if (E.isFatal())131      exit(1);132  });133}134 135BinaryContext::BinaryContext(std::unique_ptr<MCContext> Ctx,136                             std::unique_ptr<DWARFContext> DwCtx,137                             std::unique_ptr<Triple> TheTriple,138                             std::shared_ptr<orc::SymbolStringPool> SSP,139                             const Target *TheTarget, std::string TripleName,140                             std::unique_ptr<MCCodeEmitter> MCE,141                             std::unique_ptr<MCObjectFileInfo> MOFI,142                             std::unique_ptr<const MCAsmInfo> AsmInfo,143                             std::unique_ptr<const MCInstrInfo> MII,144                             std::unique_ptr<const MCSubtargetInfo> STI,145                             std::unique_ptr<MCInstPrinter> InstPrinter,146                             std::unique_ptr<const MCInstrAnalysis> MIA,147                             std::unique_ptr<MCPlusBuilder> MIB,148                             std::unique_ptr<const MCRegisterInfo> MRI,149                             std::unique_ptr<MCDisassembler> DisAsm,150                             JournalingStreams Logger)151    : Ctx(std::move(Ctx)), DwCtx(std::move(DwCtx)),152      TheTriple(std::move(TheTriple)), SSP(std::move(SSP)),153      TheTarget(TheTarget), TripleName(TripleName), MCE(std::move(MCE)),154      MOFI(std::move(MOFI)), AsmInfo(std::move(AsmInfo)), MII(std::move(MII)),155      STI(std::move(STI)), InstPrinter(std::move(InstPrinter)),156      MIA(std::move(MIA)), MIB(std::move(MIB)), MRI(std::move(MRI)),157      DisAsm(std::move(DisAsm)), Logger(Logger), InitialDynoStats(isAArch64()) {158  RegularPageSize = isAArch64() ? RegularPageSizeAArch64 : RegularPageSizeX86;159  PageAlign = opts::NoHugePages ? RegularPageSize : HugePageSize;160}161 162BinaryContext::~BinaryContext() {163  for (BinarySection *Section : Sections)164    delete Section;165  for (BinaryFunction *InjectedFunction : InjectedBinaryFunctions)166    delete InjectedFunction;167  for (std::pair<const uint64_t, JumpTable *> JTI : JumpTables)168    delete JTI.second;169  clearBinaryData();170}171 172/// Create BinaryContext for a given architecture \p ArchName and173/// triple \p TripleName.174Expected<std::unique_ptr<BinaryContext>> BinaryContext::createBinaryContext(175    Triple TheTriple, std::shared_ptr<orc::SymbolStringPool> SSP,176    StringRef InputFileName, SubtargetFeatures *Features, bool IsPIC,177    std::unique_ptr<DWARFContext> DwCtx, JournalingStreams Logger) {178  StringRef ArchName = "";179  std::string FeaturesStr = "";180  switch (TheTriple.getArch()) {181  case llvm::Triple::x86_64:182    if (Features)183      return createFatalBOLTError(184          "x86_64 target does not use SubtargetFeatures");185    ArchName = "x86-64";186    FeaturesStr = "+nopl";187    break;188  case llvm::Triple::aarch64:189    if (Features)190      return createFatalBOLTError(191          "AArch64 target does not use SubtargetFeatures");192    ArchName = "aarch64";193    FeaturesStr = "+all";194    break;195  case llvm::Triple::riscv64: {196    ArchName = "riscv64";197    if (!Features)198      return createFatalBOLTError("RISCV target needs SubtargetFeatures");199    // We rely on relaxation for some transformations (e.g., promoting all calls200    // to PseudoCALL and then making JITLink relax them). Since the relax201    // feature is not stored in the object file, we manually enable it.202    Features->AddFeature("relax");203    FeaturesStr = Features->getString();204    break;205  }206  default:207    return createStringError(std::errc::not_supported,208                             "BOLT-ERROR: Unrecognized machine in ELF file");209  }210 211  const std::string TripleName = TheTriple.str();212 213  std::string Error;214  const Target *TheTarget =215      TargetRegistry::lookupTarget(ArchName, TheTriple, Error);216  if (!TheTarget)217    return createStringError(make_error_code(std::errc::not_supported),218                             Twine("BOLT-ERROR: ", Error));219 220  std::unique_ptr<const MCRegisterInfo> MRI(221      TheTarget->createMCRegInfo(TheTriple));222  if (!MRI)223    return createStringError(224        make_error_code(std::errc::not_supported),225        Twine("BOLT-ERROR: no register info for target ", TripleName));226 227  // Set up disassembler.228  std::unique_ptr<MCAsmInfo> AsmInfo(229      TheTarget->createMCAsmInfo(*MRI, TheTriple, MCTargetOptions()));230  if (!AsmInfo)231    return createStringError(232        make_error_code(std::errc::not_supported),233        Twine("BOLT-ERROR: no assembly info for target ", TripleName));234  // BOLT creates "func@PLT" symbols for PLT entries. In function assembly dump235  // we want to emit such names as using @PLT without double quotes to convey236  // variant kind to the assembler. BOLT doesn't rely on the linker so we can237  // override the default AsmInfo behavior to emit names the way we want.238  AsmInfo->setAllowAtInName(true);239 240  std::unique_ptr<const MCSubtargetInfo> STI(241      TheTarget->createMCSubtargetInfo(TheTriple, "", FeaturesStr));242  if (!STI)243    return createStringError(244        make_error_code(std::errc::not_supported),245        Twine("BOLT-ERROR: no subtarget info for target ", TripleName));246 247  std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());248  if (!MII)249    return createStringError(250        make_error_code(std::errc::not_supported),251        Twine("BOLT-ERROR: no instruction info for target ", TripleName));252 253  std::unique_ptr<MCContext> Ctx(254      new MCContext(TheTriple, AsmInfo.get(), MRI.get(), STI.get()));255  std::unique_ptr<MCObjectFileInfo> MOFI(256      TheTarget->createMCObjectFileInfo(*Ctx, IsPIC));257  Ctx->setObjectFileInfo(MOFI.get());258  // We do not support X86 Large code model. Change this in the future.259  bool Large = false;260  if (TheTriple.getArch() == llvm::Triple::aarch64)261    Large = true;262  unsigned LSDAEncoding =263      Large ? dwarf::DW_EH_PE_absptr : dwarf::DW_EH_PE_udata4;264  if (IsPIC) {265    LSDAEncoding = dwarf::DW_EH_PE_pcrel |266                   (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4);267  }268 269  std::unique_ptr<MCDisassembler> DisAsm(270      TheTarget->createMCDisassembler(*STI, *Ctx));271 272  if (!DisAsm)273    return createStringError(274        make_error_code(std::errc::not_supported),275        Twine("BOLT-ERROR: no disassembler info for target ", TripleName));276 277  std::unique_ptr<const MCInstrAnalysis> MIA(278      TheTarget->createMCInstrAnalysis(MII.get()));279  if (!MIA)280    return createStringError(281        make_error_code(std::errc::not_supported),282        Twine("BOLT-ERROR: failed to create instruction analysis for target ",283              TripleName));284 285  int AsmPrinterVariant = AsmInfo->getAssemblerDialect();286  std::unique_ptr<MCInstPrinter> InstructionPrinter(287      TheTarget->createMCInstPrinter(TheTriple, AsmPrinterVariant, *AsmInfo,288                                     *MII, *MRI));289  if (!InstructionPrinter)290    return createStringError(291        make_error_code(std::errc::not_supported),292        Twine("BOLT-ERROR: no instruction printer for target ", TripleName));293  InstructionPrinter->setPrintImmHex(true);294 295  std::unique_ptr<MCCodeEmitter> MCE(296      TheTarget->createMCCodeEmitter(*MII, *Ctx));297 298  auto BC = std::make_unique<BinaryContext>(299      std::move(Ctx), std::move(DwCtx), std::make_unique<Triple>(TheTriple),300      std::move(SSP), TheTarget, std::string(TripleName), std::move(MCE),301      std::move(MOFI), std::move(AsmInfo), std::move(MII), std::move(STI),302      std::move(InstructionPrinter), std::move(MIA), nullptr, std::move(MRI),303      std::move(DisAsm), Logger);304 305  BC->LSDAEncoding = LSDAEncoding;306 307  BC->MAB = std::unique_ptr<MCAsmBackend>(308      BC->TheTarget->createMCAsmBackend(*BC->STI, *BC->MRI, MCTargetOptions()));309 310  BC->setFilename(InputFileName);311 312  BC->HasFixedLoadAddress = !IsPIC;313 314  BC->SymbolicDisAsm = std::unique_ptr<MCDisassembler>(315      BC->TheTarget->createMCDisassembler(*BC->STI, *BC->Ctx));316 317  if (!BC->SymbolicDisAsm)318    return createStringError(319        make_error_code(std::errc::not_supported),320        Twine("BOLT-ERROR: no disassembler info for target ", TripleName));321 322  return std::move(BC);323}324 325bool BinaryContext::forceSymbolRelocations(StringRef SymbolName) const {326  if (opts::HotText &&327      (SymbolName == "__hot_start" || SymbolName == "__hot_end"))328    return true;329 330  if (opts::HotData &&331      (SymbolName == "__hot_data_start" || SymbolName == "__hot_data_end"))332    return true;333 334  if (SymbolName == "_end")335    return true;336 337  return false;338}339 340std::unique_ptr<MCObjectWriter>341BinaryContext::createObjectWriter(raw_pwrite_stream &OS) {342  return MAB->createObjectWriter(OS);343}344 345bool BinaryContext::validateObjectNesting() const {346  auto Itr = BinaryDataMap.begin();347  auto End = BinaryDataMap.end();348  bool Valid = true;349  while (Itr != End) {350    auto Next = std::next(Itr);351    while (Next != End &&352           Itr->second->getSection() == Next->second->getSection() &&353           Itr->second->containsRange(Next->second->getAddress(),354                                      Next->second->getSize())) {355      if (Next->second->Parent != Itr->second) {356        this->errs() << "BOLT-WARNING: object nesting incorrect for:\n"357                     << "BOLT-WARNING:  " << *Itr->second << "\n"358                     << "BOLT-WARNING:  " << *Next->second << "\n";359        Valid = false;360      }361      ++Next;362    }363    Itr = Next;364  }365  return Valid;366}367 368bool BinaryContext::validateHoles() const {369  bool Valid = true;370  for (BinarySection &Section : sections()) {371    for (const Relocation &Rel : Section.relocations()) {372      uint64_t RelAddr = Rel.Offset + Section.getAddress();373      const BinaryData *BD = getBinaryDataContainingAddress(RelAddr);374      if (!BD) {375        this->errs()376            << "BOLT-WARNING: no BinaryData found for relocation at address"377            << " 0x" << Twine::utohexstr(RelAddr) << " in " << Section.getName()378            << "\n";379        Valid = false;380      } else if (!BD->getAtomicRoot()) {381        this->errs()382            << "BOLT-WARNING: no atomic BinaryData found for relocation at "383            << "address 0x" << Twine::utohexstr(RelAddr) << " in "384            << Section.getName() << "\n";385        Valid = false;386      }387    }388  }389  return Valid;390}391 392void BinaryContext::updateObjectNesting(BinaryDataMapType::iterator GAI) {393  const uint64_t Address = GAI->second->getAddress();394  const uint64_t Size = GAI->second->getSize();395 396  auto fixParents = [&](BinaryDataMapType::iterator Itr,397                        BinaryData *NewParent) {398    BinaryData *OldParent = Itr->second->Parent;399    Itr->second->Parent = NewParent;400    ++Itr;401    while (Itr != BinaryDataMap.end() && OldParent &&402           Itr->second->Parent == OldParent) {403      Itr->second->Parent = NewParent;404      ++Itr;405    }406  };407 408  // Check if the previous symbol contains the newly added symbol.409  if (GAI != BinaryDataMap.begin()) {410    BinaryData *Prev = std::prev(GAI)->second;411    while (Prev) {412      if (Prev->getSection() == GAI->second->getSection() &&413          Prev->containsRange(Address, Size)) {414        fixParents(GAI, Prev);415      } else {416        fixParents(GAI, nullptr);417      }418      Prev = Prev->Parent;419    }420  }421 422  // Check if the newly added symbol contains any subsequent symbols.423  if (Size != 0) {424    BinaryData *BD = GAI->second->Parent ? GAI->second->Parent : GAI->second;425    auto Itr = std::next(GAI);426    while (427        Itr != BinaryDataMap.end() &&428        BD->containsRange(Itr->second->getAddress(), Itr->second->getSize())) {429      Itr->second->Parent = BD;430      ++Itr;431    }432  }433}434 435iterator_range<BinaryContext::binary_data_iterator>436BinaryContext::getSubBinaryData(BinaryData *BD) {437  auto Start = std::next(BinaryDataMap.find(BD->getAddress()));438  auto End = Start;439  while (End != BinaryDataMap.end() && BD->isAncestorOf(End->second))440    ++End;441  return make_range(Start, End);442}443 444std::pair<const MCSymbol *, uint64_t>445BinaryContext::handleAddressRef(uint64_t Address, BinaryFunction &BF,446                                bool IsPCRel) {447  if (isAArch64()) {448    // Check if this is an access to a constant island and create bookkeeping449    // to keep track of it and emit it later as part of this function.450    if (MCSymbol *IslandSym = BF.getOrCreateIslandAccess(Address))451      return std::make_pair(IslandSym, 0);452 453    // Detect custom code written in assembly that refers to arbitrary454    // constant islands from other functions. Write this reference so we455    // can pull this constant island and emit it as part of this function456    // too.457    auto IslandIter = AddressToConstantIslandMap.lower_bound(Address);458 459    if (IslandIter != AddressToConstantIslandMap.begin() &&460        (IslandIter == AddressToConstantIslandMap.end() ||461         IslandIter->first > Address))462      --IslandIter;463 464    if (IslandIter != AddressToConstantIslandMap.end()) {465      // Fall-back to referencing the original constant island in the presence466      // of dynamic relocs, as we currently do not support cloning them.467      // Notice: we might fail to link because of this, if the original constant468      // island we are referring would be emitted too far away.469      if (IslandIter->second->hasDynamicRelocationAtIsland() ||470          !opts::CloneConstantIsland) {471        MCSymbol *IslandSym =472            IslandIter->second->getOrCreateIslandAccess(Address);473        if (IslandSym)474          return std::make_pair(IslandSym, 0);475      } else if (MCSymbol *IslandSym =476                     IslandIter->second->getOrCreateProxyIslandAccess(Address,477                                                                      BF)) {478        LLVM_DEBUG(479            dbgs() << "BOLT-DEBUG: clone constant island at address 0x"480                   << Twine::utohexstr(IslandIter->first) << " with size of 0x"481                   << Twine::utohexstr(482                          IslandIter->second->estimateConstantIslandSize())483                   << " bytes, referenced by " << BF << "\n");484        BF.createIslandDependency(IslandSym, IslandIter->second);485        return std::make_pair(IslandSym, 0);486      }487    }488  }489 490  // Note that the address does not necessarily have to reside inside491  // a section, it could be an absolute address too.492  ErrorOr<BinarySection &> Section = getSectionForAddress(Address);493  if (Section && Section->isText()) {494    if (BF.containsAddress(Address, /*UseMaxSize=*/isAArch64())) {495      if (Address != BF.getAddress()) {496        // The address could potentially escape. Mark it as another entry497        // point into the function.498        if (opts::Verbosity >= 1) {499          this->outs() << "BOLT-INFO: potentially escaped address 0x"500                       << Twine::utohexstr(Address) << " in function " << BF501                       << '\n';502        }503        BF.HasInternalLabelReference = true;504        return std::make_pair(505            BF.addEntryPointAtOffset(Address - BF.getAddress()), 0);506      }507    } else {508      addInterproceduralReference(&BF, Address);509    }510  }511 512  // With relocations, catch jump table references outside of the basic block513  // containing the indirect jump.514  if (HasRelocations) {515    const MemoryContentsType MemType = analyzeMemoryAt(Address, BF);516    if (MemType == MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE && IsPCRel) {517      const MCSymbol *Symbol =518          getOrCreateJumpTable(BF, Address, JumpTable::JTT_PIC);519 520      return std::make_pair(Symbol, 0);521    }522  }523 524  if (BinaryData *BD = getBinaryDataContainingAddress(Address))525    return std::make_pair(BD->getSymbol(), Address - BD->getAddress());526 527  // TODO: use DWARF info to get size/alignment here?528  MCSymbol *TargetSymbol = getOrCreateGlobalSymbol(Address, "DATAat");529  LLVM_DEBUG(dbgs() << "Created symbol " << TargetSymbol->getName() << '\n');530  return std::make_pair(TargetSymbol, 0);531}532 533MCSymbol *BinaryContext::handleExternalBranchTarget(uint64_t Address,534                                                    BinaryFunction &BF) {535  if (BF.isInConstantIsland(Address)) {536    BF.setIgnored();537    this->outs() << "BOLT-WARNING: ignoring entry point at address 0x"538                 << Twine::utohexstr(Address)539                 << " in constant island of function " << BF << '\n';540    return nullptr;541  }542 543  const uint64_t Offset = Address - BF.getAddress();544  assert(Offset < BF.getSize() &&545         "Address should be inside the referenced function");546 547  return Offset ? BF.addEntryPointAtOffset(Offset) : BF.getSymbol();548}549 550MemoryContentsType BinaryContext::analyzeMemoryAt(uint64_t Address,551                                                  BinaryFunction &BF) {552  if (!isX86())553    return MemoryContentsType::UNKNOWN;554 555  ErrorOr<BinarySection &> Section = getSectionForAddress(Address);556  if (!Section) {557    // No section - possibly an absolute address. Since we don't allow558    // internal function addresses to escape the function scope - we559    // consider it a tail call.560    if (opts::Verbosity > 1) {561      this->errs() << "BOLT-WARNING: no section for address 0x"562                   << Twine::utohexstr(Address) << " referenced from function "563                   << BF << '\n';564    }565    return MemoryContentsType::UNKNOWN;566  }567 568  if (Section->isVirtual()) {569    // The contents are filled at runtime.570    return MemoryContentsType::UNKNOWN;571  }572 573  // No support for jump tables in code yet.574  if (Section->isText())575    return MemoryContentsType::UNKNOWN;576 577  // Start with checking for PIC jump table. We expect non-PIC jump tables578  // to have high 32 bits set to 0.579  if (analyzeJumpTable(Address, JumpTable::JTT_PIC, BF))580    return MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE;581 582  if (analyzeJumpTable(Address, JumpTable::JTT_NORMAL, BF))583    return MemoryContentsType::POSSIBLE_JUMP_TABLE;584 585  return MemoryContentsType::UNKNOWN;586}587 588bool BinaryContext::analyzeJumpTable(const uint64_t Address,589                                     const JumpTable::JumpTableType Type,590                                     const BinaryFunction &BF,591                                     const uint64_t NextJTAddress,592                                     JumpTable::AddressesType *EntriesAsAddress,593                                     bool *HasEntryInFragment) const {594  // Target address of __builtin_unreachable.595  const uint64_t UnreachableAddress = BF.getAddress() + BF.getSize();596 597  // Is one of the targets __builtin_unreachable?598  bool HasUnreachable = false;599 600  // Does one of the entries match function start address?601  bool HasStartAsEntry = false;602 603  // Number of targets other than __builtin_unreachable.604  uint64_t NumRealEntries = 0;605 606  // Size of the jump table without trailing __builtin_unreachable entries.607  size_t TrimmedSize = 0;608 609  auto addEntryAddress = [&](uint64_t EntryAddress, bool Unreachable = false) {610    if (!EntriesAsAddress)611      return;612    EntriesAsAddress->emplace_back(EntryAddress);613    if (!Unreachable)614      TrimmedSize = EntriesAsAddress->size();615  };616 617  auto printEntryDiagnostics = [&](raw_ostream &OS,618                                   const BinaryFunction *TargetBF) {619    OS << "FAIL: function doesn't contain this address\n";620    if (!TargetBF)621      return;622    OS << "  ! function containing this address: " << *TargetBF << '\n';623    if (!TargetBF->isFragment())624      return;625    OS << "  ! is a fragment with parents: ";626    ListSeparator LS;627    for (BinaryFunction *Parent : TargetBF->ParentFragments)628      OS << LS << *Parent;629    OS << '\n';630  };631 632  ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);633  if (!Section)634    return false;635 636  // The upper bound is defined by containing object, section limits, and637  // the next jump table in memory.638  uint64_t UpperBound = Section->getEndAddress();639  const BinaryData *JumpTableBD = getBinaryDataAtAddress(Address);640  if (JumpTableBD && JumpTableBD->getSize()) {641    assert(JumpTableBD->getEndAddress() <= UpperBound &&642           "data object cannot cross a section boundary");643    UpperBound = JumpTableBD->getEndAddress();644  }645  if (NextJTAddress)646    UpperBound = std::min(NextJTAddress, UpperBound);647 648  LLVM_DEBUG({649    using JTT = JumpTable::JumpTableType;650    dbgs() << formatv("BOLT-DEBUG: analyzeJumpTable @{0:x} in {1}, JTT={2}\n",651                      Address, BF.getPrintName(),652                      Type == JTT::JTT_PIC ? "PIC" : "Normal");653  });654  const uint64_t EntrySize = getJumpTableEntrySize(Type);655  for (uint64_t EntryAddress = Address; EntryAddress <= UpperBound - EntrySize;656       EntryAddress += EntrySize) {657    LLVM_DEBUG(dbgs() << "  * Checking 0x" << Twine::utohexstr(EntryAddress)658                      << " -> ");659    // Check if there's a proper relocation against the jump table entry.660    if (HasRelocations) {661      if (Type == JumpTable::JTT_PIC &&662          !DataPCRelocations.count(EntryAddress)) {663        LLVM_DEBUG(664            dbgs() << "FAIL: JTT_PIC table, no relocation for this address\n");665        break;666      }667      if (Type == JumpTable::JTT_NORMAL && !getRelocationAt(EntryAddress)) {668        LLVM_DEBUG(669            dbgs()670            << "FAIL: JTT_NORMAL table, no relocation for this address\n");671        break;672      }673    }674 675    const uint64_t Value =676        (Type == JumpTable::JTT_PIC)677            ? Address + *getSignedValueAtAddress(EntryAddress, EntrySize)678            : *getPointerAtAddress(EntryAddress);679 680    // __builtin_unreachable() case.681    if (Value == UnreachableAddress) {682      addEntryAddress(Value, /*Unreachable*/ true);683      HasUnreachable = true;684      LLVM_DEBUG(dbgs() << formatv("OK: {0:x} __builtin_unreachable\n", Value));685      continue;686    }687 688    // Function start is another special case. It is allowed in the jump table,689    // but we need at least one another regular entry to distinguish the table690    // from, e.g. a function pointer array.691    if (Value == BF.getAddress()) {692      HasStartAsEntry = true;693      addEntryAddress(Value);694      continue;695    }696 697    // Function or one of its fragments.698    const BinaryFunction *TargetBF = getBinaryFunctionContainingAddress(Value);699    if (!TargetBF || !areRelatedFragments(TargetBF, &BF)) {700      LLVM_DEBUG(printEntryDiagnostics(dbgs(), TargetBF));701      (void)printEntryDiagnostics;702      break;703    }704 705    // Check there's an instruction at this offset.706    if (TargetBF->getState() == BinaryFunction::State::Disassembled &&707        !TargetBF->getInstructionAtOffset(Value - TargetBF->getAddress())) {708      LLVM_DEBUG(dbgs() << formatv("FAIL: no instruction at {0:x}\n", Value));709      break;710    }711 712    ++NumRealEntries;713    LLVM_DEBUG(dbgs() << formatv("OK: {0:x} real entry\n", Value));714 715    if (TargetBF != &BF && HasEntryInFragment)716      *HasEntryInFragment = true;717    addEntryAddress(Value);718  }719 720  // Trim direct/normal jump table to exclude trailing unreachable entries that721  // can collide with a function address.722  if (Type == JumpTable::JTT_NORMAL && EntriesAsAddress &&723      TrimmedSize != EntriesAsAddress->size() &&724      getBinaryFunctionAtAddress(UnreachableAddress))725    EntriesAsAddress->resize(TrimmedSize);726 727  // It's a jump table if the number of real entries is more than 1, or there's728  // one real entry and one or more special targets. If there are only multiple729  // special targets, then it's not a jump table.730  return NumRealEntries + (HasUnreachable || HasStartAsEntry) >= 2;731}732 733void BinaryContext::populateJumpTables() {734  LLVM_DEBUG(dbgs() << "DataPCRelocations: " << DataPCRelocations.size()735                    << '\n');736  for (auto JTI = JumpTables.begin(), JTE = JumpTables.end(); JTI != JTE;737       ++JTI) {738    JumpTable *JT = JTI->second;739 740    if (!llvm::all_of(JT->Parents, std::mem_fn(&BinaryFunction::isSimple)))741      continue;742 743    uint64_t NextJTAddress = 0;744    auto NextJTI = std::next(JTI);745    if (NextJTI != JTE)746      NextJTAddress = NextJTI->second->getAddress();747 748    const bool Success =749        analyzeJumpTable(JT->getAddress(), JT->Type, *(JT->Parents[0]),750                         NextJTAddress, &JT->EntriesAsAddress, &JT->IsSplit);751    if (!Success) {752      LLVM_DEBUG({753        dbgs() << "failed to analyze ";754        JT->print(dbgs());755        if (NextJTI != JTE) {756          dbgs() << "next ";757          NextJTI->second->print(dbgs());758        }759      });760      llvm_unreachable("jump table heuristic failure");761    }762    for (BinaryFunction *Frag : JT->Parents) {763      if (JT->IsSplit)764        Frag->setHasIndirectTargetToSplitFragment(true);765      for (uint64_t EntryAddress : JT->EntriesAsAddress)766        // if target is builtin_unreachable767        if (EntryAddress == Frag->getAddress() + Frag->getSize()) {768          Frag->IgnoredBranches.emplace_back(EntryAddress - Frag->getAddress(),769                                             Frag->getSize());770        } else if (EntryAddress >= Frag->getAddress() &&771                   EntryAddress < Frag->getAddress() + Frag->getSize()) {772          Frag->registerReferencedOffset(EntryAddress - Frag->getAddress());773        }774    }775 776    // In strict mode, erase PC-relative relocation record. Later we check that777    // all such records are erased and thus have been accounted for.778    if (opts::StrictMode && JT->Type == JumpTable::JTT_PIC) {779      for (uint64_t Address = JT->getAddress();780           Address < JT->getAddress() + JT->getSize();781           Address += JT->EntrySize) {782        DataPCRelocations.erase(DataPCRelocations.find(Address));783      }784    }785 786    // Mark to skip the function and all its fragments.787    for (BinaryFunction *Frag : JT->Parents)788      if (Frag->hasIndirectTargetToSplitFragment())789        addFragmentsToSkip(Frag);790  }791 792  if (opts::StrictMode && DataPCRelocations.size()) {793    this->errs() << "BOLT-ERROR: " << DataPCRelocations.size()794                 << " unclaimed PC-relative relocation(s) left in data";795    if (opts::Verbosity) {796      this->errs() << ":\n";797      for (uint64_t RelocOffset : DataPCRelocations)798        this->errs() << "  @0x" << Twine::utohexstr(RelocOffset) << '\n';799    } else {800      this->errs() << ". Re-run with -v=1 to see the list\n";801    }802    this->errs() << "BOLT-ERROR: unable to proceed with --strict\n";803    exit(1);804  }805  clearList(DataPCRelocations);806}807 808void BinaryContext::skipMarkedFragments() {809  std::vector<BinaryFunction *> FragmentQueue;810  // Copy the functions to FragmentQueue.811  FragmentQueue.assign(FragmentsToSkip.begin(), FragmentsToSkip.end());812  auto addToWorklist = [&](BinaryFunction *Function) -> void {813    if (FragmentsToSkip.count(Function))814      return;815    FragmentQueue.push_back(Function);816    addFragmentsToSkip(Function);817  };818  // Functions containing split jump tables need to be skipped with all819  // fragments (transitively).820  for (size_t I = 0; I != FragmentQueue.size(); I++) {821    BinaryFunction *BF = FragmentQueue[I];822    assert(FragmentsToSkip.count(BF) &&823           "internal error in traversing function fragments");824    if (opts::Verbosity >= 1)825      this->errs() << "BOLT-WARNING: Ignoring " << BF->getPrintName() << '\n';826    BF->setSimple(false);827    BF->setHasIndirectTargetToSplitFragment(true);828 829    llvm::for_each(BF->Fragments, addToWorklist);830    llvm::for_each(BF->ParentFragments, addToWorklist);831  }832  if (!FragmentsToSkip.empty())833    this->errs() << "BOLT-WARNING: skipped " << FragmentsToSkip.size()834                 << " function" << (FragmentsToSkip.size() == 1 ? "" : "s")835                 << " due to cold fragments\n";836}837 838MCSymbol *BinaryContext::getOrCreateGlobalSymbol(uint64_t Address, Twine Prefix,839                                                 uint64_t Size,840                                                 uint16_t Alignment,841                                                 unsigned Flags) {842  auto Itr = BinaryDataMap.find(Address);843  if (Itr != BinaryDataMap.end()) {844    assert(Itr->second->getSize() == Size || !Size);845    return Itr->second->getSymbol();846  }847 848  std::string Name = (Prefix + "0x" + Twine::utohexstr(Address)).str();849  assert(!GlobalSymbols.count(Name) && "created name is not unique");850  return registerNameAtAddress(Name, Address, Size, Alignment, Flags);851}852 853MCSymbol *BinaryContext::getOrCreateUndefinedGlobalSymbol(StringRef Name) {854  return Ctx->getOrCreateSymbol(Name);855}856 857BinaryFunction *BinaryContext::createBinaryFunction(858    const std::string &Name, BinarySection &Section, uint64_t Address,859    uint64_t Size, uint64_t SymbolSize, uint16_t Alignment) {860  auto Result = BinaryFunctions.emplace(861      Address, BinaryFunction(Name, Section, Address, Size, *this));862  assert(Result.second == true && "unexpected duplicate function");863  BinaryFunction *BF = &Result.first->second;864  registerNameAtAddress(Name, Address, SymbolSize ? SymbolSize : Size,865                        Alignment);866  setSymbolToFunctionMap(BF->getSymbol(), BF);867  return BF;868}869 870const MCSymbol *871BinaryContext::getOrCreateJumpTable(BinaryFunction &Function, uint64_t Address,872                                    JumpTable::JumpTableType Type) {873  // Two fragments of same function access same jump table874  if (JumpTable *JT = getJumpTableContainingAddress(Address)) {875    assert(JT->Type == Type && "jump table types have to match");876    assert(Address == JT->getAddress() && "unexpected non-empty jump table");877 878    if (llvm::is_contained(JT->Parents, &Function))879      return JT->getFirstLabel();880 881    // Prevent associating a jump table to a specific fragment twice.882    auto isSibling = std::bind(&BinaryContext::areRelatedFragments, this,883                               &Function, std::placeholders::_1);884    assert(llvm::all_of(JT->Parents, isSibling) &&885           "cannot reuse jump table of a different function");886    (void)isSibling;887    if (opts::Verbosity > 2) {888      this->outs() << "BOLT-INFO: multiple fragments access the same jump table"889                   << ": " << *JT->Parents[0] << "; " << Function << '\n';890      JT->print(this->outs());891    }892    if (JT->Parents.size() == 1)893      JT->Parents.front()->setHasIndirectTargetToSplitFragment(true);894    Function.setHasIndirectTargetToSplitFragment(true);895    // Duplicate the entry for the parent function for easy access896    JT->Parents.push_back(&Function);897    Function.JumpTables.emplace(Address, JT);898    return JT->getFirstLabel();899  }900 901  // Reuse the existing symbol if possible.902  MCSymbol *JTLabel = nullptr;903  if (BinaryData *Object = getBinaryDataAtAddress(Address)) {904    if (!isInternalSymbolName(Object->getSymbol()->getName()))905      JTLabel = Object->getSymbol();906  }907 908  const uint64_t EntrySize = getJumpTableEntrySize(Type);909  if (!JTLabel) {910    const std::string JumpTableName = generateJumpTableName(Function, Address);911    JTLabel = registerNameAtAddress(JumpTableName, Address, 0, EntrySize);912  }913 914  LLVM_DEBUG(dbgs() << "BOLT-DEBUG: creating jump table " << JTLabel->getName()915                    << " in function " << Function << '\n');916 917  JumpTable *JT = new JumpTable(*JTLabel, Address, EntrySize, Type,918                                JumpTable::LabelMapType{{0, JTLabel}},919                                *getSectionForAddress(Address));920  JT->Parents.push_back(&Function);921  if (opts::Verbosity > 2)922    JT->print(this->outs());923  JumpTables.emplace(Address, JT);924 925  // Duplicate the entry for the parent function for easy access.926  Function.JumpTables.emplace(Address, JT);927  return JTLabel;928}929 930std::pair<uint64_t, const MCSymbol *>931BinaryContext::duplicateJumpTable(BinaryFunction &Function, JumpTable *JT,932                                  const MCSymbol *OldLabel) {933  auto L = scopeLock();934  unsigned Offset = 0;935  bool Found = false;936  for (std::pair<const unsigned, MCSymbol *> Elmt : JT->Labels) {937    if (Elmt.second != OldLabel)938      continue;939    Offset = Elmt.first;940    Found = true;941    break;942  }943  assert(Found && "Label not found");944  (void)Found;945  MCSymbol *NewLabel = Ctx->createNamedTempSymbol("duplicatedJT");946  JumpTable *NewJT =947      new JumpTable(*NewLabel, JT->getAddress(), JT->EntrySize, JT->Type,948                    JumpTable::LabelMapType{{Offset, NewLabel}},949                    *getSectionForAddress(JT->getAddress()));950  NewJT->Parents = JT->Parents;951  NewJT->Entries = JT->Entries;952  NewJT->Counts = JT->Counts;953  uint64_t JumpTableID = ++DuplicatedJumpTables;954  // Invert it to differentiate from regular jump tables whose IDs are their955  // addresses in the input binary memory space956  JumpTableID = ~JumpTableID;957  JumpTables.emplace(JumpTableID, NewJT);958  Function.JumpTables.emplace(JumpTableID, NewJT);959  return std::make_pair(JumpTableID, NewLabel);960}961 962std::string BinaryContext::generateJumpTableName(const BinaryFunction &BF,963                                                 uint64_t Address) {964  size_t Id;965  uint64_t Offset = 0;966  if (const JumpTable *JT = BF.getJumpTableContainingAddress(Address)) {967    Offset = Address - JT->getAddress();968    auto JTLabelsIt = JT->Labels.find(Offset);969    if (JTLabelsIt != JT->Labels.end())970      return std::string(JTLabelsIt->second->getName());971 972    auto JTIdsIt = JumpTableIds.find(JT->getAddress());973    assert(JTIdsIt != JumpTableIds.end());974    Id = JTIdsIt->second;975  } else {976    Id = JumpTableIds[Address] = BF.JumpTables.size();977  }978  return ("JUMP_TABLE/" + BF.getOneName().str() + "." + std::to_string(Id) +979          (Offset ? ("." + std::to_string(Offset)) : ""));980}981 982bool BinaryContext::hasValidCodePadding(const BinaryFunction &BF) {983  if (!isX86() && !isAArch64())984    return true;985 986  if (BF.getSize() == BF.getMaxSize())987    return true;988 989  ErrorOr<ArrayRef<unsigned char>> FunctionData = BF.getData();990  assert(FunctionData && "cannot get function as data");991 992  uint64_t Offset = BF.getSize();993  MCInst Instr;994  uint64_t InstrSize = 0;995  uint64_t InstrAddress = BF.getAddress() + Offset;996  using std::placeholders::_1;997 998  // Skip instructions that satisfy the predicate condition.999  auto skipInstructions = [&](std::function<bool(const MCInst &)> Predicate) {1000    const uint64_t StartOffset = Offset;1001    for (; Offset < BF.getMaxSize();1002         Offset += InstrSize, InstrAddress += InstrSize) {1003      if (!DisAsm->getInstruction(Instr, InstrSize, FunctionData->slice(Offset),1004                                  InstrAddress, nulls()))1005        break;1006      if (!Predicate(Instr))1007        break;1008    }1009 1010    return Offset - StartOffset;1011  };1012 1013  // Skip a sequence of zero bytes. For AArch64 we only skip 4's exact1014  // multiple number of zeros in case the following zeros belong to veneer.1015  auto skipZeros = [&]() {1016    const uint64_t StartOffset = Offset;1017    uint64_t CurrentOffset = Offset;1018    for (; CurrentOffset < BF.getMaxSize(); ++CurrentOffset)1019      if ((*FunctionData)[CurrentOffset] != 0)1020        break;1021 1022    uint64_t NumZeros = CurrentOffset - StartOffset;1023    if (isAArch64())1024      NumZeros &= ~((uint64_t)0x3);1025 1026    if (NumZeros == 0)1027      return false;1028    Offset += NumZeros;1029    InstrAddress += NumZeros;1030    return true;1031  };1032 1033  // Accept the whole padding area filled with breakpoints.1034  auto isBreakpoint = std::bind(&MCPlusBuilder::isBreakpoint, MIB.get(), _1);1035  if (skipInstructions(isBreakpoint) && Offset == BF.getMaxSize())1036    return true;1037 1038  auto isNoop = std::bind(&MCPlusBuilder::isNoop, MIB.get(), _1);1039 1040  // Some functions have a jump to the next function or to the padding area1041  // inserted after the body.1042  auto isSkipJump = [&](const MCInst &Instr) {1043    if (!isX86())1044      return false;1045    uint64_t TargetAddress = 0;1046    if (MIB->isUnconditionalBranch(Instr) &&1047        MIB->evaluateBranch(Instr, InstrAddress, InstrSize, TargetAddress)) {1048      if (TargetAddress >= InstrAddress + InstrSize &&1049          TargetAddress <= BF.getAddress() + BF.getMaxSize()) {1050        return true;1051      }1052    }1053    return false;1054  };1055 1056  // For veneers that are not already covered by binary functions, only those1057  // that handleAArch64Veneer() can recognize are checked here.1058  auto skipAArch64Veneer = [&]() {1059    if (!isAArch64() || Offset >= BF.getMaxSize())1060      return false;1061    BinaryFunction *BFVeneer = getBinaryFunctionContainingAddress(InstrAddress);1062    if (BFVeneer) {1063      // A binary function may have been created to point to this veneer.1064      Offset += BFVeneer->getSize();1065      assert(Offset <= BF.getMaxSize() &&1066             "AArch64 veneeer goes past the max size of function");1067      InstrAddress += BFVeneer->getSize();1068      return true;1069    }1070    const uint64_t AArch64VeneerSize = 12;1071    if (Offset + AArch64VeneerSize <= BF.getMaxSize() &&1072        handleAArch64Veneer(InstrAddress, /*MatchOnly*/ true)) {1073      Offset += AArch64VeneerSize;1074      InstrAddress += AArch64VeneerSize;1075      this->errs() << "BOLT-WARNING: found unmarked AArch64 veneer at 0x"1076                   << Twine::utohexstr(BF.getAddress() + Offset) << '\n';1077      return true;1078    }1079    return false;1080  };1081 1082  auto skipAArch64ConstantIsland = [&]() {1083    if (!isAArch64() || Offset >= BF.getMaxSize())1084      return false;1085    uint64_t Size;1086    if (BF.isInConstantIsland(InstrAddress, &Size)) {1087      Offset += Size;1088      InstrAddress += Size;1089      return true;1090    }1091    return false;1092  };1093 1094  // Skip over nops, jumps, and zero padding. Allow interleaving (this happens).1095  // For AArch64 also check veneers and skip constant islands.1096  while (skipAArch64Veneer() || skipAArch64ConstantIsland() ||1097         skipInstructions(isNoop) || skipInstructions(isSkipJump) ||1098         skipZeros())1099    ;1100 1101  if (Offset == BF.getMaxSize())1102    return true;1103 1104  this->errs() << "BOLT-WARNING: bad padding at address 0x"1105               << Twine::utohexstr(BF.getAddress() + BF.getSize())1106               << " starting at offset " << (Offset - BF.getSize())1107               << " in function " << BF << '\n'1108               << FunctionData->slice(BF.getSize(),1109                                      BF.getMaxSize() - BF.getSize())1110               << '\n';1111  return false;1112}1113 1114void BinaryContext::adjustCodePadding() {1115  uint64_t NumInvalid = 0;1116  for (auto &BFI : BinaryFunctions) {1117    BinaryFunction &BF = BFI.second;1118    if (!shouldEmit(BF))1119      continue;1120 1121    if (!hasValidCodePadding(BF)) {1122      NumInvalid++;1123      if (HasRelocations) {1124        this->errs() << "BOLT-WARNING: function " << BF1125                     << " has invalid padding. Ignoring the function\n";1126        BF.setIgnored();1127      } else {1128        BF.setMaxSize(BF.getSize());1129      }1130    }1131  }1132  if (NumInvalid && opts::FailOnInvalidPadding) {1133    this->errs() << "BOLT-ERROR: found " << NumInvalid1134                 << " instance(s) of invalid code padding\n";1135    exit(1);1136  }1137}1138 1139MCSymbol *BinaryContext::registerNameAtAddress(StringRef Name, uint64_t Address,1140                                               uint64_t Size,1141                                               uint16_t Alignment,1142                                               unsigned Flags) {1143  // Register the name with MCContext.1144  MCSymbol *Symbol = Ctx->getOrCreateSymbol(Name);1145 1146  auto GAI = BinaryDataMap.find(Address);1147  BinaryData *BD;1148  if (GAI == BinaryDataMap.end()) {1149    ErrorOr<BinarySection &> SectionOrErr = getSectionForAddress(Address);1150    BinarySection &Section =1151        SectionOrErr ? SectionOrErr.get() : absoluteSection();1152    BD = new BinaryData(*Symbol, Address, Size, Alignment ? Alignment : 1,1153                        Section, Flags);1154    GAI = BinaryDataMap.emplace(Address, BD).first;1155    GlobalSymbols[Name] = BD;1156    updateObjectNesting(GAI);1157  } else {1158    BD = GAI->second;1159    if (!BD->hasName(Name)) {1160      GlobalSymbols[Name] = BD;1161      BD->updateSize(Size);1162      BD->Symbols.push_back(Symbol);1163    }1164  }1165 1166  return Symbol;1167}1168 1169const BinaryData *1170BinaryContext::getBinaryDataContainingAddressImpl(uint64_t Address) const {1171  auto NI = BinaryDataMap.lower_bound(Address);1172  auto End = BinaryDataMap.end();1173  if ((NI != End && Address == NI->first) ||1174      ((NI != BinaryDataMap.begin()) && (NI-- != BinaryDataMap.begin()))) {1175    if (NI->second->containsAddress(Address))1176      return NI->second;1177 1178    // If this is a sub-symbol, see if a parent data contains the address.1179    const BinaryData *BD = NI->second->getParent();1180    while (BD) {1181      if (BD->containsAddress(Address))1182        return BD;1183      BD = BD->getParent();1184    }1185  }1186  return nullptr;1187}1188 1189BinaryData *BinaryContext::getGOTSymbol() {1190  // First tries to find a global symbol with that name1191  BinaryData *GOTSymBD = getBinaryDataByName("_GLOBAL_OFFSET_TABLE_");1192  if (GOTSymBD)1193    return GOTSymBD;1194 1195  // This symbol might be hidden from run-time link, so fetch the local1196  // definition if available.1197  GOTSymBD = getBinaryDataByName("_GLOBAL_OFFSET_TABLE_/1");1198  if (!GOTSymBD)1199    return nullptr;1200 1201  // If the local symbol is not unique, fail1202  unsigned Index = 2;1203  SmallString<30> Storage;1204  while (const BinaryData *BD =1205             getBinaryDataByName(Twine("_GLOBAL_OFFSET_TABLE_/")1206                                     .concat(Twine(Index++))1207                                     .toStringRef(Storage)))1208    if (BD->getAddress() != GOTSymBD->getAddress())1209      return nullptr;1210 1211  return GOTSymBD;1212}1213 1214bool BinaryContext::setBinaryDataSize(uint64_t Address, uint64_t Size) {1215  auto NI = BinaryDataMap.find(Address);1216  assert(NI != BinaryDataMap.end());1217  if (NI == BinaryDataMap.end())1218    return false;1219  // TODO: it's possible that a jump table starts at the same address1220  // as a larger blob of private data.  When we set the size of the1221  // jump table, it might be smaller than the total blob size.  In this1222  // case we just leave the original size since (currently) it won't really1223  // affect anything.1224  assert((!NI->second->Size || NI->second->Size == Size ||1225          (NI->second->isJumpTable() && NI->second->Size > Size)) &&1226         "can't change the size of a symbol that has already had its "1227         "size set");1228  if (!NI->second->Size) {1229    NI->second->Size = Size;1230    updateObjectNesting(NI);1231    return true;1232  }1233  return false;1234}1235 1236void BinaryContext::generateSymbolHashes() {1237  auto isPadding = [](const BinaryData &BD) {1238    StringRef Contents = BD.getSection().getContents();1239    StringRef SymData = Contents.substr(BD.getOffset(), BD.getSize());1240    return (BD.getName().starts_with("HOLEat") ||1241            SymData.find_first_not_of(0) == StringRef::npos);1242  };1243 1244  uint64_t NumCollisions = 0;1245  for (auto &Entry : BinaryDataMap) {1246    BinaryData &BD = *Entry.second;1247    StringRef Name = BD.getName();1248 1249    if (!isInternalSymbolName(Name))1250      continue;1251 1252    // First check if a non-anonymous alias exists and move it to the front.1253    if (BD.getSymbols().size() > 1) {1254      auto Itr = llvm::find_if(BD.getSymbols(), [&](const MCSymbol *Symbol) {1255        return !isInternalSymbolName(Symbol->getName());1256      });1257      if (Itr != BD.getSymbols().end()) {1258        size_t Idx = std::distance(BD.getSymbols().begin(), Itr);1259        std::swap(BD.getSymbols()[0], BD.getSymbols()[Idx]);1260        continue;1261      }1262    }1263 1264    // We have to skip 0 size symbols since they will all collide.1265    if (BD.getSize() == 0) {1266      continue;1267    }1268 1269    const uint64_t Hash = BD.getSection().hash(BD);1270    const size_t Idx = Name.find("0x");1271    std::string NewName =1272        (Twine(Name.substr(0, Idx)) + "_" + Twine::utohexstr(Hash)).str();1273    if (getBinaryDataByName(NewName)) {1274      // Ignore collisions for symbols that appear to be padding1275      // (i.e. all zeros or a "hole")1276      if (!isPadding(BD)) {1277        if (opts::Verbosity) {1278          this->errs() << "BOLT-WARNING: collision detected when hashing " << BD1279                       << " with new name (" << NewName << "), skipping.\n";1280        }1281        ++NumCollisions;1282      }1283      continue;1284    }1285    BD.Symbols.insert(BD.Symbols.begin(), Ctx->getOrCreateSymbol(NewName));1286    GlobalSymbols[NewName] = &BD;1287  }1288  if (NumCollisions) {1289    this->errs() << "BOLT-WARNING: " << NumCollisions1290                 << " collisions detected while hashing binary objects";1291    if (!opts::Verbosity)1292      this->errs() << ". Use -v=1 to see the list.";1293    this->errs() << '\n';1294  }1295}1296 1297bool BinaryContext::registerFragment(BinaryFunction &TargetFunction,1298                                     BinaryFunction &Function) {1299  assert(TargetFunction.isFragment() && "TargetFunction must be a fragment");1300  if (TargetFunction.isChildOf(Function))1301    return true;1302  TargetFunction.addParentFragment(Function);1303  Function.addFragment(TargetFunction);1304  FragmentClasses.unionSets(&TargetFunction, &Function);1305  if (!HasRelocations) {1306    TargetFunction.setSimple(false);1307    Function.setSimple(false);1308  }1309  if (opts::Verbosity >= 1) {1310    this->outs() << "BOLT-INFO: marking " << TargetFunction1311                 << " as a fragment of " << Function << '\n';1312  }1313  return true;1314}1315 1316void BinaryContext::addAdrpAddRelocAArch64(BinaryFunction &BF,1317                                           MCInst &LoadLowBits,1318                                           MCInst &LoadHiBits,1319                                           uint64_t Target) {1320  const MCSymbol *TargetSymbol;1321  uint64_t Addend = 0;1322  std::tie(TargetSymbol, Addend) = handleAddressRef(Target, BF,1323                                                    /*IsPCRel*/ true);1324  int64_t Val;1325  MIB->replaceImmWithSymbolRef(LoadHiBits, TargetSymbol, Addend, Ctx.get(), Val,1326                               ELF::R_AARCH64_ADR_PREL_PG_HI21);1327  MIB->replaceImmWithSymbolRef(LoadLowBits, TargetSymbol, Addend, Ctx.get(),1328                               Val, ELF::R_AARCH64_ADD_ABS_LO12_NC);1329}1330 1331bool BinaryContext::handleAArch64Veneer(uint64_t Address, bool MatchOnly) {1332  BinaryFunction *TargetFunction = getBinaryFunctionContainingAddress(Address);1333  if (TargetFunction)1334    return false;1335 1336  ErrorOr<BinarySection &> Section = getSectionForAddress(Address);1337  assert(Section && "cannot get section for referenced address");1338  if (!Section->isText())1339    return false;1340 1341  bool Ret = false;1342  StringRef SectionContents = Section->getContents();1343  uint64_t Offset = Address - Section->getAddress();1344  const uint64_t MaxSize = SectionContents.size() - Offset;1345  const uint8_t *Bytes =1346      reinterpret_cast<const uint8_t *>(SectionContents.data());1347  ArrayRef<uint8_t> Data(Bytes + Offset, MaxSize);1348 1349  auto matchVeneer = [&](BinaryFunction::InstrMapType &Instructions,1350                         MCInst &Instruction, uint64_t Offset,1351                         uint64_t AbsoluteInstrAddr,1352                         uint64_t TotalSize) -> bool {1353    MCInst *TargetHiBits, *TargetLowBits;1354    uint64_t TargetAddress, Count;1355    Count = MIB->matchLinkerVeneer(Instructions.begin(), Instructions.end(),1356                                   AbsoluteInstrAddr, Instruction, TargetHiBits,1357                                   TargetLowBits, TargetAddress);1358    if (!Count)1359      return false;1360 1361    if (MatchOnly)1362      return true;1363 1364    // NOTE The target symbol was created during disassemble's1365    // handleExternalReference1366    const MCSymbol *VeneerSymbol = getOrCreateGlobalSymbol(Address, "FUNCat");1367    BinaryFunction *Veneer = createBinaryFunction(VeneerSymbol->getName().str(),1368                                                  *Section, Address, TotalSize);1369    addAdrpAddRelocAArch64(*Veneer, *TargetLowBits, *TargetHiBits,1370                           TargetAddress);1371    MIB->addAnnotation(Instruction, "AArch64Veneer", true);1372    Veneer->addInstruction(Offset, std::move(Instruction));1373    --Count;1374    for (auto It = Instructions.rbegin(); Count != 0; ++It, --Count) {1375      MIB->addAnnotation(It->second, "AArch64Veneer", true);1376      Veneer->addInstruction(It->first, std::move(It->second));1377    }1378 1379    Veneer->getOrCreateLocalLabel(Address);1380    Veneer->setMaxSize(TotalSize);1381    Veneer->updateState(BinaryFunction::State::Disassembled);1382    LLVM_DEBUG(dbgs() << "BOLT-DEBUG: handling veneer function at 0x"1383                      << Twine::utohexstr(Address) << "\n");1384    return true;1385  };1386 1387  uint64_t Size = 0, TotalSize = 0;1388  BinaryFunction::InstrMapType VeneerInstructions;1389  for (Offset = 0; Offset < MaxSize; Offset += Size) {1390    MCInst Instruction;1391    const uint64_t AbsoluteInstrAddr = Address + Offset;1392    if (!SymbolicDisAsm->getInstruction(Instruction, Size, Data.slice(Offset),1393                                        AbsoluteInstrAddr, nulls()))1394      break;1395 1396    TotalSize += Size;1397    if (MIB->isBranch(Instruction)) {1398      Ret = matchVeneer(VeneerInstructions, Instruction, Offset,1399                        AbsoluteInstrAddr, TotalSize);1400      break;1401    }1402 1403    VeneerInstructions.emplace(Offset, std::move(Instruction));1404  }1405 1406  return Ret;1407}1408 1409void BinaryContext::processInterproceduralReferences() {1410  for (const std::pair<BinaryFunction *, uint64_t> &It :1411       InterproceduralReferences) {1412    BinaryFunction &Function = *It.first;1413    uint64_t Address = It.second;1414    // Process interprocedural references from ignored functions in BAT mode1415    // (non-simple in non-relocation mode) to properly register entry points1416    if (!Address || (Function.isIgnored() && !HasBATSection))1417      continue;1418 1419    BinaryFunction *TargetFunction =1420        getBinaryFunctionContainingAddress(Address);1421    if (&Function == TargetFunction)1422      continue;1423 1424    if (TargetFunction) {1425      if (TargetFunction->isFragment() &&1426          !areRelatedFragments(TargetFunction, &Function)) {1427        this->errs()1428            << "BOLT-WARNING: interprocedural reference between unrelated "1429               "fragments: "1430            << Function.getPrintName() << " and "1431            << TargetFunction->getPrintName() << '\n';1432      }1433 1434      // Create an extra entry point if needed. Can also render the target1435      // function ignored if the reference is invalid.1436      handleExternalBranchTarget(Address, *TargetFunction);1437 1438      continue;1439    }1440 1441    // Check if address falls in function padding space - this could be1442    // unmarked data in code. In this case adjust the padding space size.1443    ErrorOr<BinarySection &> Section = getSectionForAddress(Address);1444    assert(Section && "cannot get section for referenced address");1445 1446    if (!Section->isText())1447      continue;1448 1449    // PLT requires special handling and could be ignored in this context.1450    StringRef SectionName = Section->getName();1451    if (SectionName == ".plt" || SectionName == ".plt.got")1452      continue;1453 1454    // Check if it is aarch64 veneer written at Address1455    if (isAArch64() && handleAArch64Veneer(Address))1456      continue;1457 1458    if (opts::processAllFunctions()) {1459      this->errs() << "BOLT-ERROR: cannot process binaries with unmarked "1460                   << "object in code at address 0x"1461                   << Twine::utohexstr(Address) << " belonging to section "1462                   << SectionName << " in current mode\n";1463      exit(1);1464    }1465 1466    TargetFunction = getBinaryFunctionContainingAddress(Address,1467                                                        /*CheckPastEnd=*/false,1468                                                        /*UseMaxSize=*/true);1469    // We are not going to overwrite non-simple functions, but for simple1470    // ones - adjust the padding size.1471    if (TargetFunction && TargetFunction->isSimple()) {1472      this->errs()1473          << "BOLT-WARNING: function " << *TargetFunction1474          << " has an object detected in a padding region at address 0x"1475          << Twine::utohexstr(Address) << '\n';1476      TargetFunction->setMaxSize(TargetFunction->getSize());1477    }1478  }1479 1480  InterproceduralReferences.clear();1481}1482 1483void BinaryContext::postProcessSymbolTable() {1484  fixBinaryDataHoles();1485  bool Valid = true;1486  for (auto &Entry : BinaryDataMap) {1487    BinaryData *BD = Entry.second;1488    if ((BD->getName().starts_with("SYMBOLat") ||1489         BD->getName().starts_with("DATAat")) &&1490        !BD->getParent() && !BD->getSize() && !BD->isAbsolute() &&1491        BD->getSection()) {1492      this->errs() << "BOLT-WARNING: zero-sized top level symbol: " << *BD1493                   << "\n";1494      Valid = false;1495    }1496  }1497  assert(Valid);1498  (void)Valid;1499  generateSymbolHashes();1500}1501 1502void BinaryContext::foldFunction(BinaryFunction &ChildBF,1503                                 BinaryFunction &ParentBF) {1504  assert(!ChildBF.isMultiEntry() && !ParentBF.isMultiEntry() &&1505         "cannot merge functions with multiple entry points");1506 1507  std::unique_lock<llvm::sys::RWMutex> WriteCtxLock(CtxMutex, std::defer_lock);1508  std::unique_lock<llvm::sys::RWMutex> WriteSymbolMapLock(1509      SymbolToFunctionMapMutex, std::defer_lock);1510 1511  const StringRef ChildName = ChildBF.getOneName();1512 1513  // Move symbols over and update bookkeeping info.1514  for (MCSymbol *Symbol : ChildBF.getSymbols()) {1515    ParentBF.getSymbols().push_back(Symbol);1516    WriteSymbolMapLock.lock();1517    SymbolToFunctionMap[Symbol] = &ParentBF;1518    WriteSymbolMapLock.unlock();1519    // NB: there's no need to update BinaryDataMap and GlobalSymbols.1520  }1521  ChildBF.getSymbols().clear();1522 1523  // Reset function mapping for local symbols.1524  for (uint64_t RelOffset : ChildBF.getInternalRefDataRelocations()) {1525    const Relocation *Rel = getRelocationAt(RelOffset);1526    if (!Rel || !Rel->Symbol)1527      continue;1528 1529    WriteSymbolMapLock.lock();1530    SymbolToFunctionMap[Rel->Symbol] = nullptr;1531    WriteSymbolMapLock.unlock();1532  }1533 1534  // Move other names the child function is known under.1535  llvm::move(ChildBF.Aliases, std::back_inserter(ParentBF.Aliases));1536  ChildBF.Aliases.clear();1537 1538  if (HasRelocations) {1539    // Merge execution counts of ChildBF into those of ParentBF.1540    // Without relocations, we cannot reliably merge profiles as both functions1541    // continue to exist and either one can be executed.1542    ChildBF.mergeProfileDataInto(ParentBF);1543 1544    std::shared_lock<llvm::sys::RWMutex> ReadBfsLock(BinaryFunctionsMutex,1545                                                     std::defer_lock);1546    std::unique_lock<llvm::sys::RWMutex> WriteBfsLock(BinaryFunctionsMutex,1547                                                      std::defer_lock);1548    // Remove ChildBF from the global set of functions in relocs mode.1549    ReadBfsLock.lock();1550    auto FI = BinaryFunctions.find(ChildBF.getAddress());1551    ReadBfsLock.unlock();1552 1553    assert(FI != BinaryFunctions.end() && "function not found");1554    assert(&ChildBF == &FI->second && "function mismatch");1555 1556    WriteBfsLock.lock();1557    ChildBF.clearDisasmState();1558    FI = BinaryFunctions.erase(FI);1559    WriteBfsLock.unlock();1560 1561  } else {1562    // In non-relocation mode we keep the function, but rename it.1563    std::string NewName = "__ICF_" + ChildName.str();1564 1565    WriteCtxLock.lock();1566    ChildBF.getSymbols().push_back(Ctx->getOrCreateSymbol(NewName));1567    WriteCtxLock.unlock();1568 1569    ChildBF.setFolded(&ParentBF);1570  }1571 1572  ParentBF.setHasFunctionsFoldedInto();1573}1574 1575void BinaryContext::fixBinaryDataHoles() {1576  assert(validateObjectNesting() && "object nesting inconsistency detected");1577 1578  for (BinarySection &Section : allocatableSections()) {1579    std::vector<std::pair<uint64_t, uint64_t>> Holes;1580 1581    auto isNotHole = [&Section](const binary_data_iterator &Itr) {1582      BinaryData *BD = Itr->second;1583      bool isHole = (!BD->getParent() && !BD->getSize() && BD->isObject() &&1584                     (BD->getName().starts_with("SYMBOLat0x") ||1585                      BD->getName().starts_with("DATAat0x") ||1586                      BD->getName().starts_with("ANONYMOUS")));1587      return !isHole && BD->getSection() == Section && !BD->getParent();1588    };1589 1590    auto BDStart = BinaryDataMap.begin();1591    auto BDEnd = BinaryDataMap.end();1592    auto Itr = FilteredBinaryDataIterator(isNotHole, BDStart, BDEnd);1593    auto End = FilteredBinaryDataIterator(isNotHole, BDEnd, BDEnd);1594 1595    uint64_t EndAddress = Section.getAddress();1596 1597    while (Itr != End) {1598      if (Itr->second->getAddress() > EndAddress) {1599        uint64_t Gap = Itr->second->getAddress() - EndAddress;1600        Holes.emplace_back(EndAddress, Gap);1601      }1602      EndAddress = Itr->second->getEndAddress();1603      ++Itr;1604    }1605 1606    if (EndAddress < Section.getEndAddress())1607      Holes.emplace_back(EndAddress, Section.getEndAddress() - EndAddress);1608 1609    // If there is already a symbol at the start of the hole, grow that symbol1610    // to cover the rest.  Otherwise, create a new symbol to cover the hole.1611    for (std::pair<uint64_t, uint64_t> &Hole : Holes) {1612      BinaryData *BD = getBinaryDataAtAddress(Hole.first);1613      if (BD) {1614        // BD->getSection() can be != Section if there are sections that1615        // overlap.  In this case it is probably safe to just skip the holes1616        // since the overlapping section will not(?) have any symbols in it.1617        if (BD->getSection() == Section)1618          setBinaryDataSize(Hole.first, Hole.second);1619      } else {1620        getOrCreateGlobalSymbol(Hole.first, "HOLEat", Hole.second, 1);1621      }1622    }1623  }1624 1625  assert(validateObjectNesting() && "object nesting inconsistency detected");1626  assert(validateHoles() && "top level hole detected in object map");1627}1628 1629void BinaryContext::printGlobalSymbols(raw_ostream &OS) const {1630  const BinarySection *CurrentSection = nullptr;1631  bool FirstSection = true;1632 1633  for (auto &Entry : BinaryDataMap) {1634    const BinaryData *BD = Entry.second;1635    const BinarySection &Section = BD->getSection();1636    if (FirstSection || Section != *CurrentSection) {1637      uint64_t Address, Size;1638      StringRef Name = Section.getName();1639      if (Section) {1640        Address = Section.getAddress();1641        Size = Section.getSize();1642      } else {1643        Address = BD->getAddress();1644        Size = BD->getSize();1645      }1646      OS << "BOLT-INFO: Section " << Name << ", "1647         << "0x" + Twine::utohexstr(Address) << ":"1648         << "0x" + Twine::utohexstr(Address + Size) << "/" << Size << "\n";1649      CurrentSection = &Section;1650      FirstSection = false;1651    }1652 1653    OS << "BOLT-INFO: ";1654    const BinaryData *P = BD->getParent();1655    while (P) {1656      OS << "  ";1657      P = P->getParent();1658    }1659    OS << *BD << "\n";1660  }1661}1662 1663Expected<unsigned> BinaryContext::getDwarfFile(1664    StringRef Directory, StringRef FileName, unsigned FileNumber,1665    std::optional<MD5::MD5Result> Checksum, std::optional<StringRef> Source,1666    unsigned CUID, unsigned DWARFVersion) {1667  DwarfLineTable &Table = DwarfLineTablesCUMap[CUID];1668  return Table.tryGetFile(Directory, FileName, Checksum, Source, DWARFVersion,1669                          FileNumber);1670}1671 1672unsigned BinaryContext::addDebugFilenameToUnit(const uint32_t DestCUID,1673                                               const uint32_t SrcCUID,1674                                               unsigned FileIndex) {1675  DWARFCompileUnit *SrcUnit = DwCtx->getCompileUnitForOffset(SrcCUID);1676  const DWARFDebugLine::LineTable *LineTable =1677      DwCtx->getLineTableForUnit(SrcUnit);1678  const DWARFDebugLine::FileNameEntry &FileNameEntry =1679      LineTable->Prologue.getFileNameEntry(FileIndex);1680  // Dir indexes start at 1 and a dir index 01681  // means empty dir.1682  StringRef Dir = "";1683  if (FileNameEntry.DirIdx != 0) {1684    if (std::optional<const char *> DirName = dwarf::toString(1685            LineTable->Prologue.IncludeDirectories[FileNameEntry.DirIdx - 1])) {1686      Dir = *DirName;1687    }1688  }1689  StringRef FileName = "";1690  if (std::optional<const char *> FName = dwarf::toString(FileNameEntry.Name))1691    FileName = *FName;1692  assert(FileName != "");1693  DWARFCompileUnit *DstUnit = DwCtx->getCompileUnitForOffset(DestCUID);1694  return cantFail(getDwarfFile(Dir, FileName, 0, std::nullopt, std::nullopt,1695                               DestCUID, DstUnit->getVersion()));1696}1697 1698std::vector<BinaryFunction *> BinaryContext::getSortedFunctions() {1699  std::vector<BinaryFunction *> SortedFunctions(BinaryFunctions.size());1700  llvm::transform(llvm::make_second_range(BinaryFunctions),1701                  SortedFunctions.begin(),1702                  [](BinaryFunction &BF) { return &BF; });1703 1704  llvm::stable_sort(SortedFunctions, compareBinaryFunctionByIndex);1705  return SortedFunctions;1706}1707 1708std::vector<BinaryFunction *> BinaryContext::getAllBinaryFunctions() {1709  std::vector<BinaryFunction *> AllFunctions;1710  AllFunctions.reserve(BinaryFunctions.size() + InjectedBinaryFunctions.size());1711  llvm::transform(llvm::make_second_range(BinaryFunctions),1712                  std::back_inserter(AllFunctions),1713                  [](BinaryFunction &BF) { return &BF; });1714  llvm::copy(InjectedBinaryFunctions, std::back_inserter(AllFunctions));1715 1716  return AllFunctions;1717}1718 1719std::optional<DWARFUnit *> BinaryContext::getDWOCU(uint64_t DWOId) {1720  auto Iter = DWOCUs.find(DWOId);1721  if (Iter == DWOCUs.end())1722    return std::nullopt;1723 1724  return Iter->second;1725}1726 1727DWARFContext *BinaryContext::getDWOContext() const {1728  if (DWOCUs.empty())1729    return nullptr;1730  return &DWOCUs.begin()->second->getContext();1731}1732 1733bool BinaryContext::isValidDwarfUnit(DWARFUnit &DU) const {1734  // Invalid DWARF unit with a DWOId but lacking a dwo_name.1735  if (DU.getDWOId() && !DU.isDWOUnit() &&1736      !DU.getUnitDIE().find(1737          {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name})) {1738    this->outs() << "BOLT-ERROR: broken DWARF found in CU at offset 0x"1739                 << Twine::utohexstr(DU.getOffset()) << " (DWOId=0x"1740                 << Twine::utohexstr(*(DU.getDWOId()))1741                 << ", missing DW_AT_dwo_name / DW_AT_GNU_dwo_name)\n";1742    return false;1743  }1744  return true;1745}1746 1747/// Handles DWO sections that can either be in .o, .dwo or .dwp files.1748void BinaryContext::preprocessDWODebugInfo() {1749  for (const std::unique_ptr<DWARFUnit> &CU : DwCtx->compile_units()) {1750    DWARFUnit *const DwarfUnit = CU.get();1751    if (!isValidDwarfUnit(*DwarfUnit))1752      continue;1753    if (std::optional<uint64_t> DWOId = DwarfUnit->getDWOId()) {1754      std::string DWOName = dwarf::toString(1755          DwarfUnit->getUnitDIE().find(1756              {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),1757          "");1758      SmallString<16> AbsolutePath(DWOName);1759      std::string DWOCompDir = DwarfUnit->getCompilationDir();1760      if (!opts::CompDirOverride.empty()) {1761        DWOCompDir = opts::CompDirOverride;1762      } else if (!sys::fs::exists(DWOCompDir) && sys::fs::exists(DWOName)) {1763        DWOCompDir = ".";1764        this->outs()1765            << "BOLT-WARNING: Debug Fission: Debug Compilation Directory of "1766            << DWOName1767            << " does not exist. Relative path will be used to process .dwo "1768               "files.\n";1769      }1770      // Prevent failures when DWOName is already an absolute path.1771      sys::path::make_absolute(DWOCompDir, AbsolutePath);1772      DWARFUnit *DWOCU =1773          DwarfUnit->getNonSkeletonUnitDIE(false, AbsolutePath).getDwarfUnit();1774      if (!DWOCU->isDWOUnit()) {1775        this->outs()1776            << "BOLT-WARNING: Debug Fission: DWO debug information for "1777            << DWOName1778            << " was not retrieved and won't be updated. Please check "1779               "relative path or use '--comp-dir-override' to specify the base "1780               "location.\n";1781        continue;1782      }1783      DWOCUs[*DWOId] = DWOCU;1784    }1785  }1786  if (!DWOCUs.empty())1787    this->outs() << "BOLT-INFO: processing split DWARF\n";1788}1789 1790void BinaryContext::preprocessDebugInfo() {1791  struct CURange {1792    uint64_t LowPC;1793    uint64_t HighPC;1794    DWARFUnit *Unit;1795 1796    bool operator<(const CURange &Other) const { return LowPC < Other.LowPC; }1797  };1798 1799  // Building a map of address ranges to CUs similar to .debug_aranges and use1800  // it to assign CU to functions.1801  std::vector<CURange> AllRanges;1802  AllRanges.reserve(DwCtx->getNumCompileUnits());1803  for (const std::unique_ptr<DWARFUnit> &CU : DwCtx->compile_units()) {1804    Expected<DWARFAddressRangesVector> RangesOrError =1805        CU->getUnitDIE().getAddressRanges();1806    if (!RangesOrError) {1807      consumeError(RangesOrError.takeError());1808      continue;1809    }1810    for (DWARFAddressRange &Range : *RangesOrError) {1811      // Parts of the debug info could be invalidated due to corresponding code1812      // being removed from the binary by the linker. Hence we check if the1813      // address is a valid one.1814      if (containsAddress(Range.LowPC))1815        AllRanges.emplace_back(CURange{Range.LowPC, Range.HighPC, CU.get()});1816    }1817 1818    ContainsDwarf5 |= CU->getVersion() >= 5;1819    ContainsDwarfLegacy |= CU->getVersion() < 5;1820  }1821 1822  llvm::sort(AllRanges);1823  for (auto &KV : BinaryFunctions) {1824    const uint64_t FunctionAddress = KV.first;1825    BinaryFunction &Function = KV.second;1826 1827    auto It = llvm::partition_point(1828        AllRanges, [=](CURange R) { return R.HighPC <= FunctionAddress; });1829    if (It == AllRanges.end() || It->LowPC > FunctionAddress) {1830      continue;1831    }1832    Function.addDWARFUnit(It->Unit);1833 1834    // Go forward and add all units from ranges that cover the function.1835    while (++It != AllRanges.end()) {1836      if (It->LowPC > FunctionAddress || FunctionAddress >= It->HighPC)1837        break;1838      Function.addDWARFUnit(It->Unit);1839    }1840  }1841 1842  // Discover units with debug info that needs to be updated.1843  for (const auto &KV : BinaryFunctions) {1844    const BinaryFunction &BF = KV.second;1845    if (shouldEmit(BF) && !BF.getDWARFUnits().empty())1846      for (const auto &[_, Unit] : BF.getDWARFUnits())1847        ProcessedCUs.insert(Unit);1848  }1849  // Clear debug info for functions from units that we are not going to process.1850  for (auto &KV : BinaryFunctions) {1851    BinaryFunction &BF = KV.second;1852    // Collect units to remove to avoid iterator invalidation1853    SmallVector<DWARFUnit *, 1> UnitsToRemove;1854    for (const auto &[_, Unit] : BF.getDWARFUnits()) {1855      if (!ProcessedCUs.count(Unit))1856        UnitsToRemove.push_back(Unit);1857    }1858    // Remove the collected units1859    for (auto *Unit : UnitsToRemove) {1860      BF.removeDWARFUnit(Unit);1861    }1862  }1863 1864  if (opts::Verbosity >= 1) {1865    this->outs() << "BOLT-INFO: " << ProcessedCUs.size() << " out of "1866                 << DwCtx->getNumCompileUnits() << " CUs will be updated\n";1867  }1868 1869  preprocessDWODebugInfo();1870 1871  // Populate MCContext with DWARF files from all units.1872  StringRef GlobalPrefix = AsmInfo->getPrivateGlobalPrefix();1873  for (const std::unique_ptr<DWARFUnit> &CU : DwCtx->compile_units()) {1874    const uint64_t CUID = CU->getOffset();1875    DwarfLineTable &BinaryLineTable = getDwarfLineTable(CUID);1876    BinaryLineTable.setLabel(Ctx->getOrCreateSymbol(1877        GlobalPrefix + "line_table_start" + Twine(CUID)));1878 1879    if (!ProcessedCUs.count(CU.get()))1880      continue;1881 1882    const DWARFDebugLine::LineTable *LineTable =1883        DwCtx->getLineTableForUnit(CU.get());1884    const std::vector<DWARFDebugLine::FileNameEntry> &FileNames =1885        LineTable->Prologue.FileNames;1886 1887    uint16_t DwarfVersion = LineTable->Prologue.getVersion();1888    if (DwarfVersion >= 5) {1889      std::optional<MD5::MD5Result> Checksum;1890      if (LineTable->Prologue.ContentTypes.HasMD5)1891        Checksum = LineTable->Prologue.FileNames[0].Checksum;1892      std::optional<const char *> Name =1893          dwarf::toString(CU->getUnitDIE().find(dwarf::DW_AT_name), nullptr);1894      if (std::optional<uint64_t> DWOID = CU->getDWOId()) {1895        auto Iter = DWOCUs.find(*DWOID);1896        if (Iter == DWOCUs.end()) {1897          this->errs() << "BOLT-ERROR: DWO CU was not found for " << Name1898                       << '\n';1899          exit(1);1900        }1901        Name = dwarf::toString(1902            Iter->second->getUnitDIE().find(dwarf::DW_AT_name), nullptr);1903      }1904      BinaryLineTable.setRootFile(CU->getCompilationDir(), *Name, Checksum,1905                                  std::nullopt);1906    }1907 1908    BinaryLineTable.setDwarfVersion(DwarfVersion);1909 1910    // Assign a unique label to every line table, one per CU.1911    // Make sure empty debug line tables are registered too.1912    if (FileNames.empty()) {1913      cantFail(getDwarfFile("", "<unknown>", 0, std::nullopt, std::nullopt,1914                            CUID, DwarfVersion));1915      continue;1916    }1917    const uint32_t Offset = DwarfVersion < 5 ? 1 : 0;1918    for (size_t I = 0, Size = FileNames.size(); I != Size; ++I) {1919      // Dir indexes start at 1, as DWARF file numbers, and a dir index 01920      // means empty dir.1921      StringRef Dir = "";1922      if (FileNames[I].DirIdx != 0 || DwarfVersion >= 5)1923        if (std::optional<const char *> DirName = dwarf::toString(1924                LineTable->Prologue1925                    .IncludeDirectories[FileNames[I].DirIdx - Offset]))1926          Dir = *DirName;1927      StringRef FileName = "";1928      if (std::optional<const char *> FName =1929              dwarf::toString(FileNames[I].Name))1930        FileName = *FName;1931      assert(FileName != "");1932      std::optional<MD5::MD5Result> Checksum;1933      if (DwarfVersion >= 5 && LineTable->Prologue.ContentTypes.HasMD5)1934        Checksum = LineTable->Prologue.FileNames[I].Checksum;1935      cantFail(getDwarfFile(Dir, FileName, 0, Checksum, std::nullopt, CUID,1936                            DwarfVersion));1937    }1938  }1939}1940 1941bool BinaryContext::shouldEmit(const BinaryFunction &Function) const {1942  if (Function.isPseudo())1943    return false;1944 1945  if (opts::processAllFunctions())1946    return true;1947 1948  if (Function.isIgnored())1949    return false;1950 1951  // In relocation mode we will emit non-simple functions with CFG.1952  // If the function does not have a CFG it should be marked as ignored.1953  return HasRelocations || Function.isSimple();1954}1955 1956void BinaryContext::dump(const MCInst &Inst) const {1957  if (LLVM_UNLIKELY(!InstPrinter)) {1958    dbgs() << "Cannot dump for InstPrinter is not initialized.\n";1959    return;1960  }1961  InstPrinter->printInst(&Inst, 0, "", *STI, dbgs());1962  dbgs() << "\n";1963}1964 1965void BinaryContext::printCFI(raw_ostream &OS, const MCCFIInstruction &Inst) {1966  uint32_t Operation = Inst.getOperation();1967  switch (Operation) {1968  case MCCFIInstruction::OpSameValue:1969    OS << "OpSameValue Reg" << Inst.getRegister();1970    break;1971  case MCCFIInstruction::OpRememberState:1972    OS << "OpRememberState";1973    break;1974  case MCCFIInstruction::OpRestoreState:1975    OS << "OpRestoreState";1976    break;1977  case MCCFIInstruction::OpOffset:1978    OS << "OpOffset Reg" << Inst.getRegister() << " " << Inst.getOffset();1979    break;1980  case MCCFIInstruction::OpDefCfaRegister:1981    OS << "OpDefCfaRegister Reg" << Inst.getRegister();1982    break;1983  case MCCFIInstruction::OpDefCfaOffset:1984    OS << "OpDefCfaOffset " << Inst.getOffset();1985    break;1986  case MCCFIInstruction::OpDefCfa:1987    OS << "OpDefCfa Reg" << Inst.getRegister() << " " << Inst.getOffset();1988    break;1989  case MCCFIInstruction::OpRelOffset:1990    OS << "OpRelOffset Reg" << Inst.getRegister() << " " << Inst.getOffset();1991    break;1992  case MCCFIInstruction::OpAdjustCfaOffset:1993    OS << "OfAdjustCfaOffset " << Inst.getOffset();1994    break;1995  case MCCFIInstruction::OpEscape:1996    OS << "OpEscape";1997    break;1998  case MCCFIInstruction::OpRestore:1999    OS << "OpRestore Reg" << Inst.getRegister();2000    break;2001  case MCCFIInstruction::OpUndefined:2002    OS << "OpUndefined Reg" << Inst.getRegister();2003    break;2004  case MCCFIInstruction::OpRegister:2005    OS << "OpRegister Reg" << Inst.getRegister() << " Reg"2006       << Inst.getRegister2();2007    break;2008  case MCCFIInstruction::OpWindowSave:2009    OS << "OpWindowSave";2010    break;2011  case MCCFIInstruction::OpGnuArgsSize:2012    OS << "OpGnuArgsSize";2013    break;2014  case MCCFIInstruction::OpNegateRAState:2015    OS << "OpNegateRAState";2016    break;2017  default:2018    OS << "Op#" << Operation;2019    break;2020  }2021}2022 2023MarkerSymType BinaryContext::getMarkerType(const SymbolRef &Symbol) const {2024  // For aarch64 and riscv, the ABI defines mapping symbols so we identify data2025  // in the code section (see IHI0056B). $x identifies a symbol starting code or2026  // the end of a data chunk inside code, $d identifies start of data.2027  if (isX86() || ELFSymbolRef(Symbol).getSize())2028    return MarkerSymType::NONE;2029 2030  Expected<StringRef> NameOrError = Symbol.getName();2031  Expected<object::SymbolRef::Type> TypeOrError = Symbol.getType();2032 2033  if (!TypeOrError || !NameOrError)2034    return MarkerSymType::NONE;2035 2036  if (*TypeOrError != SymbolRef::ST_Unknown)2037    return MarkerSymType::NONE;2038 2039  if (*NameOrError == "$x" || NameOrError->starts_with("$x."))2040    return MarkerSymType::CODE;2041 2042  // $x<ISA>2043  if (isRISCV() && NameOrError->starts_with("$x"))2044    return MarkerSymType::CODE;2045 2046  if (*NameOrError == "$d" || NameOrError->starts_with("$d."))2047    return MarkerSymType::DATA;2048 2049  return MarkerSymType::NONE;2050}2051 2052bool BinaryContext::isMarker(const SymbolRef &Symbol) const {2053  return getMarkerType(Symbol) != MarkerSymType::NONE;2054}2055 2056static void printDebugInfo(raw_ostream &OS, const MCInst &Instruction,2057                           const BinaryFunction *Function,2058                           DWARFContext *DwCtx) {2059  const ClusteredRows *LineTableRows =2060      ClusteredRows::fromSMLoc(Instruction.getLoc());2061  if (LineTableRows == nullptr)2062    return;2063 2064  // File name and line number should be the same for all CUs.2065  // So it is sufficient to check the first one.2066  DebugLineTableRowRef RowRef = LineTableRows->getRows().front();2067  const DWARFDebugLine::LineTable *LineTable = DwCtx->getLineTableForUnit(2068      DwCtx->getCompileUnitForOffset(RowRef.DwCompileUnitIndex));2069 2070  if (!LineTable)2071    return;2072 2073  const DWARFDebugLine::Row &Row = LineTable->Rows[RowRef.RowIndex - 1];2074  StringRef FileName = "";2075 2076  if (std::optional<const char *> FName =2077          dwarf::toString(LineTable->Prologue.getFileNameEntry(Row.File).Name))2078    FileName = *FName;2079  OS << " # debug line " << FileName << ":" << Row.Line;2080  if (Row.Column)2081    OS << ":" << Row.Column;2082  if (Row.Discriminator)2083    OS << " discriminator:" << Row.Discriminator;2084}2085 2086ArrayRef<uint8_t> BinaryContext::extractData(uint64_t Address,2087                                             uint64_t Size) const {2088  ArrayRef<uint8_t> Res;2089 2090  const ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);2091  if (!Section || Section->isVirtual())2092    return Res;2093 2094  if (!Section->containsRange(Address, Size))2095    return Res;2096 2097  auto *Bytes =2098      reinterpret_cast<const uint8_t *>(Section->getContents().data());2099  return ArrayRef<uint8_t>(Bytes + Address - Section->getAddress(), Size);2100}2101 2102void BinaryContext::printData(raw_ostream &OS, ArrayRef<uint8_t> Data,2103                              uint64_t Offset) const {2104  DataExtractor DE(Data, AsmInfo->isLittleEndian(),2105                   AsmInfo->getCodePointerSize());2106  uint64_t DataOffset = 0;2107  while (DataOffset + 4 <= Data.size()) {2108    OS << format("    %08" PRIx64 ": \t.word\t0x", Offset + DataOffset);2109    const auto Word = DE.getUnsigned(&DataOffset, 4);2110    OS << Twine::utohexstr(Word) << '\n';2111  }2112  if (DataOffset + 2 <= Data.size()) {2113    OS << format("    %08" PRIx64 ": \t.short\t0x", Offset + DataOffset);2114    const auto Short = DE.getUnsigned(&DataOffset, 2);2115    OS << Twine::utohexstr(Short) << '\n';2116  }2117  if (DataOffset + 1 == Data.size()) {2118    OS << format("    %08" PRIx64 ": \t.byte\t0x%x\n", Offset + DataOffset,2119                 Data[DataOffset]);2120  }2121}2122 2123void BinaryContext::printInstruction(raw_ostream &OS, const MCInst &Instruction,2124                                     uint64_t Offset,2125                                     const BinaryFunction *Function,2126                                     bool PrintMCInst, bool PrintMemData,2127                                     bool PrintRelocations,2128                                     StringRef Endl) const {2129  OS << format("    %08" PRIx64 ": ", Offset);2130  if (MIB->isCFI(Instruction)) {2131    uint32_t Offset = Instruction.getOperand(0).getImm();2132    OS << "\t!CFI\t$" << Offset << "\t; ";2133    if (Function)2134      printCFI(OS, *Function->getCFIFor(Instruction));2135    OS << Endl;2136    return;2137  }2138  if (std::optional<uint32_t> DynamicID =2139          MIB->getDynamicBranchID(Instruction)) {2140    OS << "\tjit\t" << MIB->getTargetSymbol(Instruction)->getName()2141       << " # ID: " << DynamicID;2142  } else {2143    // If there are annotations on the instruction, the MCInstPrinter will fail2144    // to print the preferred alias as it only does so when the number of2145    // operands is as expected. See2146    // https://github.com/llvm/llvm-project/blob/782f1a0d895646c364a53f9dcdd6d4ec1f3e5ea0/llvm/lib/MC/MCInstPrinter.cpp#L1422147    // Therefore, create a temporary copy of the Inst from which the annotations2148    // are removed, and print that Inst.2149    MCInst InstNoAnnot = Instruction;2150    MIB->stripAnnotations(InstNoAnnot);2151    InstPrinter->printInst(&InstNoAnnot, 0, "", *STI, OS);2152  }2153  if (MIB->isCall(Instruction)) {2154    if (MIB->isTailCall(Instruction))2155      OS << " # TAILCALL ";2156    if (MIB->isInvoke(Instruction)) {2157      const std::optional<MCPlus::MCLandingPad> EHInfo =2158          MIB->getEHInfo(Instruction);2159      OS << " # handler: ";2160      if (EHInfo->first)2161        OS << *EHInfo->first;2162      else2163        OS << '0';2164      OS << "; action: " << EHInfo->second;2165      const int64_t GnuArgsSize = MIB->getGnuArgsSize(Instruction);2166      if (GnuArgsSize >= 0)2167        OS << "; GNU_args_size = " << GnuArgsSize;2168    }2169  } else if (MIB->isIndirectBranch(Instruction)) {2170    if (uint64_t JTAddress = MIB->getJumpTable(Instruction)) {2171      OS << " # JUMPTABLE @0x" << Twine::utohexstr(JTAddress);2172    } else {2173      OS << " # UNKNOWN CONTROL FLOW";2174    }2175  }2176  if (std::optional<uint32_t> Offset = MIB->getOffset(Instruction))2177    OS << " # Offset: " << *Offset;2178  if (std::optional<uint32_t> Size = MIB->getSize(Instruction))2179    OS << " # Size: " << *Size;2180  if (MCSymbol *Label = MIB->getInstLabel(Instruction))2181    OS << " # Label: " << *Label;2182 2183  MIB->printAnnotations(Instruction, OS, PrintMemData || opts::PrintMemData);2184 2185  if (opts::PrintDebugInfo)2186    printDebugInfo(OS, Instruction, Function, DwCtx.get());2187 2188  if ((opts::PrintRelocations || PrintRelocations) && Function) {2189    const uint64_t Size = computeCodeSize(&Instruction, &Instruction + 1);2190    Function->printRelocations(OS, Offset, Size);2191  }2192 2193  OS << Endl;2194 2195  if (PrintMCInst) {2196    Instruction.dump_pretty(OS, InstPrinter.get());2197    OS << Endl;2198  }2199}2200 2201std::optional<uint64_t>2202BinaryContext::getBaseAddressForMapping(uint64_t MMapAddress,2203                                        uint64_t FileOffset) const {2204  // Find a segment with a matching file offset.2205  for (auto &KV : SegmentMapInfo) {2206    const SegmentInfo &SegInfo = KV.second;2207    // Only consider executable segments.2208    if (!SegInfo.IsExecutable)2209      continue;2210    // FileOffset is got from perf event,2211    // and it is equal to alignDown(SegInfo.FileOffset, pagesize).2212    // If the pagesize is not equal to SegInfo.Alignment.2213    // FileOffset and SegInfo.FileOffset should be aligned first,2214    // and then judge whether they are equal.2215    if (alignDown(SegInfo.FileOffset, SegInfo.Alignment) ==2216        alignDown(FileOffset, SegInfo.Alignment)) {2217      // The function's offset from base address in VAS is aligned by pagesize2218      // instead of SegInfo.Alignment. Pagesize can't be got from perf events.2219      // However, The ELF document says that SegInfo.FileOffset should equal2220      // to SegInfo.Address, modulo the pagesize.2221      // Reference: https://refspecs.linuxfoundation.org/elf/elf.pdf2222 2223      // So alignDown(SegInfo.Address, pagesize) can be calculated by:2224      // alignDown(SegInfo.Address, pagesize)2225      //   = SegInfo.Address - (SegInfo.Address % pagesize)2226      //   = SegInfo.Address - (SegInfo.FileOffset % pagesize)2227      //   = SegInfo.Address - SegInfo.FileOffset +2228      //     alignDown(SegInfo.FileOffset, pagesize)2229      //   = SegInfo.Address - SegInfo.FileOffset + FileOffset2230      return MMapAddress - (SegInfo.Address - SegInfo.FileOffset + FileOffset);2231    }2232  }2233 2234  return std::nullopt;2235}2236 2237ErrorOr<BinarySection &> BinaryContext::getSectionForAddress(uint64_t Address) {2238  auto SI = AddressToSection.upper_bound(Address);2239  if (SI != AddressToSection.begin()) {2240    --SI;2241    uint64_t UpperBound = SI->first + SI->second->getSize();2242    if (!SI->second->getSize())2243      UpperBound += 1;2244    if (UpperBound > Address)2245      return *SI->second;2246  }2247  return std::make_error_code(std::errc::bad_address);2248}2249 2250ErrorOr<StringRef>2251BinaryContext::getSectionNameForAddress(uint64_t Address) const {2252  if (ErrorOr<const BinarySection &> Section = getSectionForAddress(Address))2253    return Section->getName();2254  return std::make_error_code(std::errc::bad_address);2255}2256 2257BinarySection &BinaryContext::registerSection(BinarySection *Section) {2258  auto Res = Sections.insert(Section);2259  (void)Res;2260  assert(Res.second && "can't register the same section twice.");2261 2262  // Only register allocatable sections in the AddressToSection map.2263  if (Section->isAllocatable() && Section->getAddress())2264    AddressToSection.insert(std::make_pair(Section->getAddress(), Section));2265  NameToSection.insert(2266      std::make_pair(std::string(Section->getName()), Section));2267  if (Section->hasSectionRef())2268    SectionRefToBinarySection.insert(2269        std::make_pair(Section->getSectionRef(), Section));2270 2271  LLVM_DEBUG(dbgs() << "BOLT-DEBUG: registering " << *Section << "\n");2272  return *Section;2273}2274 2275BinarySection &BinaryContext::registerSection(SectionRef Section) {2276  return registerSection(new BinarySection(*this, Section));2277}2278 2279BinarySection &2280BinaryContext::registerSection(const Twine &SectionName,2281                               const BinarySection &OriginalSection) {2282  return registerSection(2283      new BinarySection(*this, SectionName, OriginalSection));2284}2285 2286BinarySection &2287BinaryContext::registerOrUpdateSection(const Twine &Name, unsigned ELFType,2288                                       unsigned ELFFlags, uint8_t *Data,2289                                       uint64_t Size, unsigned Alignment) {2290  auto NamedSections = getSectionByName(Name);2291  if (NamedSections.begin() != NamedSections.end()) {2292    assert(std::next(NamedSections.begin()) == NamedSections.end() &&2293           "can only update unique sections");2294    BinarySection *Section = NamedSections.begin()->second;2295 2296    LLVM_DEBUG(dbgs() << "BOLT-DEBUG: updating " << *Section << " -> ");2297    const bool Flag = Section->isAllocatable();2298    (void)Flag;2299    Section->update(Data, Size, Alignment, ELFType, ELFFlags);2300    LLVM_DEBUG(dbgs() << *Section << "\n");2301    // FIXME: Fix section flags/attributes for MachO.2302    if (isELF())2303      assert(Flag == Section->isAllocatable() &&2304             "can't change section allocation status");2305    return *Section;2306  }2307 2308  return registerSection(2309      new BinarySection(*this, Name, Data, Size, Alignment, ELFType, ELFFlags));2310}2311 2312void BinaryContext::deregisterSectionName(const BinarySection &Section) {2313  auto NameRange = NameToSection.equal_range(Section.getName().str());2314  while (NameRange.first != NameRange.second) {2315    if (NameRange.first->second == &Section) {2316      NameToSection.erase(NameRange.first);2317      break;2318    }2319    ++NameRange.first;2320  }2321}2322 2323void BinaryContext::deregisterUnusedSections() {2324  ErrorOr<BinarySection &> AbsSection = getUniqueSectionByName("<absolute>");2325  for (auto SI = Sections.begin(); SI != Sections.end();) {2326    BinarySection *Section = *SI;2327    // We check getOutputData() instead of getOutputSize() because sometimes2328    // zero-sized .text.cold sections are allocated.2329    if (Section->hasSectionRef() || Section->getOutputData() ||2330        (AbsSection && Section == &AbsSection.get())) {2331      ++SI;2332      continue;2333    }2334 2335    LLVM_DEBUG(dbgs() << "LLVM-DEBUG: deregistering " << Section->getName()2336                      << '\n';);2337    deregisterSectionName(*Section);2338    SI = Sections.erase(SI);2339    delete Section;2340  }2341}2342 2343bool BinaryContext::deregisterSection(BinarySection &Section) {2344  BinarySection *SectionPtr = &Section;2345  auto Itr = Sections.find(SectionPtr);2346  if (Itr != Sections.end()) {2347    auto Range = AddressToSection.equal_range(SectionPtr->getAddress());2348    while (Range.first != Range.second) {2349      if (Range.first->second == SectionPtr) {2350        AddressToSection.erase(Range.first);2351        break;2352      }2353      ++Range.first;2354    }2355 2356    deregisterSectionName(*SectionPtr);2357    Sections.erase(Itr);2358    delete SectionPtr;2359    return true;2360  }2361  return false;2362}2363 2364void BinaryContext::renameSection(BinarySection &Section,2365                                  const Twine &NewName) {2366  auto Itr = Sections.find(&Section);2367  assert(Itr != Sections.end() && "Section must exist to be renamed.");2368  Sections.erase(Itr);2369 2370  deregisterSectionName(Section);2371 2372  Section.Name = NewName.str();2373  Section.setOutputName(Section.Name);2374 2375  NameToSection.insert(std::make_pair(Section.Name, &Section));2376 2377  // Reinsert with the new name.2378  Sections.insert(&Section);2379}2380 2381void BinaryContext::printSections(raw_ostream &OS) const {2382  for (BinarySection *const &Section : Sections)2383    OS << "BOLT-INFO: " << *Section << "\n";2384}2385 2386BinarySection &BinaryContext::absoluteSection() {2387  if (ErrorOr<BinarySection &> Section = getUniqueSectionByName("<absolute>"))2388    return *Section;2389  return registerOrUpdateSection("<absolute>", ELF::SHT_NULL, 0u);2390}2391 2392ErrorOr<uint64_t> BinaryContext::getUnsignedValueAtAddress(uint64_t Address,2393                                                           size_t Size) const {2394  const ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);2395  if (!Section)2396    return std::make_error_code(std::errc::bad_address);2397 2398  if (Section->isVirtual())2399    return 0;2400 2401  DataExtractor DE(Section->getContents(), AsmInfo->isLittleEndian(),2402                   AsmInfo->getCodePointerSize());2403  auto ValueOffset = static_cast<uint64_t>(Address - Section->getAddress());2404  return DE.getUnsigned(&ValueOffset, Size);2405}2406 2407ErrorOr<int64_t> BinaryContext::getSignedValueAtAddress(uint64_t Address,2408                                                        size_t Size) const {2409  const ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);2410  if (!Section)2411    return std::make_error_code(std::errc::bad_address);2412 2413  if (Section->isVirtual())2414    return 0;2415 2416  DataExtractor DE(Section->getContents(), AsmInfo->isLittleEndian(),2417                   AsmInfo->getCodePointerSize());2418  auto ValueOffset = static_cast<uint64_t>(Address - Section->getAddress());2419  return DE.getSigned(&ValueOffset, Size);2420}2421 2422void BinaryContext::addRelocation(uint64_t Address, MCSymbol *Symbol,2423                                  uint32_t Type, uint64_t Addend,2424                                  uint64_t Value) {2425  ErrorOr<BinarySection &> Section = getSectionForAddress(Address);2426  assert(Section && "cannot find section for address");2427  Section->addRelocation(Address - Section->getAddress(), Symbol, Type, Addend,2428                         Value);2429}2430 2431void BinaryContext::addDynamicRelocation(uint64_t Address, MCSymbol *Symbol,2432                                         uint32_t Type, uint64_t Addend,2433                                         uint64_t Value) {2434  ErrorOr<BinarySection &> Section = getSectionForAddress(Address);2435  assert(Section && "cannot find section for address");2436  Section->addDynamicRelocation(Address - Section->getAddress(), Symbol, Type,2437                                Addend, Value);2438}2439 2440bool BinaryContext::removeRelocationAt(uint64_t Address) {2441  ErrorOr<BinarySection &> Section = getSectionForAddress(Address);2442  assert(Section && "cannot find section for address");2443  return Section->removeRelocationAt(Address - Section->getAddress());2444}2445 2446const Relocation *BinaryContext::getRelocationAt(uint64_t Address) const {2447  ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);2448  if (!Section)2449    return nullptr;2450 2451  return Section->getRelocationAt(Address - Section->getAddress());2452}2453 2454const Relocation *2455BinaryContext::getDynamicRelocationAt(uint64_t Address) const {2456  ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);2457  if (!Section)2458    return nullptr;2459 2460  return Section->getDynamicRelocationAt(Address - Section->getAddress());2461}2462 2463void BinaryContext::markAmbiguousRelocations(BinaryData &BD,2464                                             const uint64_t Address) {2465  auto setImmovable = [&](BinaryData &BD) {2466    BinaryData *Root = BD.getAtomicRoot();2467    LLVM_DEBUG(if (Root->isMoveable()) {2468      dbgs() << "BOLT-DEBUG: setting " << *Root << " as immovable "2469             << "due to ambiguous relocation referencing 0x"2470             << Twine::utohexstr(Address) << '\n';2471    });2472    Root->setIsMoveable(false);2473  };2474 2475  if (Address == BD.getAddress()) {2476    setImmovable(BD);2477 2478    // Set previous symbol as immovable2479    BinaryData *Prev = getBinaryDataContainingAddress(Address - 1);2480    if (Prev && Prev->getEndAddress() == BD.getAddress())2481      setImmovable(*Prev);2482  }2483 2484  if (Address == BD.getEndAddress()) {2485    setImmovable(BD);2486 2487    // Set next symbol as immovable2488    BinaryData *Next = getBinaryDataContainingAddress(BD.getEndAddress());2489    if (Next && Next->getAddress() == BD.getEndAddress())2490      setImmovable(*Next);2491  }2492}2493 2494BinaryFunction *BinaryContext::getFunctionForSymbol(const MCSymbol *Symbol,2495                                                    uint64_t *EntryDesc) {2496  std::shared_lock<llvm::sys::RWMutex> Lock(SymbolToFunctionMapMutex);2497  auto BFI = SymbolToFunctionMap.find(Symbol);2498  if (BFI == SymbolToFunctionMap.end())2499    return nullptr;2500 2501  BinaryFunction *BF = BFI->second;2502  if (EntryDesc)2503    *EntryDesc = BF->getEntryIDForSymbol(Symbol);2504 2505  return BF;2506}2507 2508std::string2509BinaryContext::generateBugReportMessage(StringRef Message,2510                                        const BinaryFunction &Function) const {2511  std::string Msg;2512  raw_string_ostream SS(Msg);2513  SS << "=======================================\n";2514  SS << "BOLT is unable to proceed because it couldn't properly understand "2515        "this function.\n";2516  SS << "If you are running the most recent version of BOLT, you may "2517        "want to "2518        "report this and paste this dump.\nPlease check that there is no "2519        "sensitive contents being shared in this dump.\n";2520  SS << "\nOffending function: " << Function.getPrintName() << "\n\n";2521  ScopedPrinter SP(SS);2522  SP.printBinaryBlock("Function contents", *Function.getData());2523  SS << "\n";2524  const_cast<BinaryFunction &>(Function).print(SS, "");2525  SS << "ERROR: " << Message;2526  SS << "\n=======================================\n";2527  return Msg;2528}2529 2530BinaryFunction *2531BinaryContext::createInjectedBinaryFunction(const std::string &Name,2532                                            bool IsSimple) {2533  InjectedBinaryFunctions.push_back(new BinaryFunction(Name, *this, IsSimple));2534  BinaryFunction *BF = InjectedBinaryFunctions.back();2535  setSymbolToFunctionMap(BF->getSymbol(), BF);2536  BF->CurrentState = BinaryFunction::State::CFG;2537  return BF;2538}2539 2540BinaryFunction *2541BinaryContext::createInstructionPatch(uint64_t Address,2542                                      const InstructionListType &Instructions,2543                                      const Twine &Name) {2544  ErrorOr<BinarySection &> Section = getSectionForAddress(Address);2545  assert(Section && "cannot get section for patching");2546  assert(Section->hasSectionRef() && Section->isText() &&2547         "can only patch input file code sections");2548 2549  const uint64_t FileOffset =2550      Section->getInputFileOffset() + Address - Section->getAddress();2551 2552  std::string PatchName = Name.str();2553  if (PatchName.empty()) {2554    // Assign unique name to the patch.2555    static uint64_t N = 0;2556    PatchName = "__BP_" + std::to_string(N++);2557  }2558 2559  BinaryFunction *PBF = createInjectedBinaryFunction(PatchName);2560  PBF->setOutputAddress(Address);2561  PBF->setFileOffset(FileOffset);2562  PBF->setOriginSection(&Section.get());2563  PBF->addBasicBlock()->addInstructions(Instructions);2564  PBF->setIsPatch(true);2565 2566  // Don't create symbol table entry if the name wasn't specified.2567  if (Name.str().empty())2568    PBF->setAnonymous(true);2569 2570  return PBF;2571}2572 2573std::pair<size_t, size_t>2574BinaryContext::calculateEmittedSize(BinaryFunction &BF, bool FixBranches) {2575  // Use the original size for non-simple functions.2576  if (!BF.isSimple() || BF.isIgnored())2577    return std::make_pair(BF.getSize(), 0);2578 2579  // Adjust branch instruction to match the current layout.2580  if (FixBranches)2581    BF.fixBranches();2582 2583  // Create local MC context to isolate the effect of ephemeral code emission.2584  IndependentCodeEmitter MCEInstance = createIndependentMCCodeEmitter();2585  MCContext *LocalCtx = MCEInstance.LocalCtx.get();2586  MCAsmBackend *MAB =2587      TheTarget->createMCAsmBackend(*STI, *MRI, MCTargetOptions());2588 2589  SmallString<256> Code;2590  raw_svector_ostream VecOS(Code);2591 2592  std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(VecOS);2593  std::unique_ptr<MCStreamer> Streamer(TheTarget->createMCObjectStreamer(2594      *TheTriple, *LocalCtx, std::unique_ptr<MCAsmBackend>(MAB), std::move(OW),2595      std::unique_ptr<MCCodeEmitter>(MCEInstance.MCE.release()), *STI));2596 2597  Streamer->initSections(false, *STI);2598 2599  MCSection *Section = MCEInstance.LocalMOFI->getTextSection();2600  Section->setHasInstructions(true);2601 2602  // Create symbols in the LocalCtx so that they get destroyed with it.2603  MCSymbol *StartLabel = LocalCtx->createTempSymbol();2604  MCSymbol *EndLabel = LocalCtx->createTempSymbol();2605 2606  Streamer->switchSection(Section);2607  Streamer->emitLabel(StartLabel);2608  emitFunctionBody(*Streamer, BF, BF.getLayout().getMainFragment(),2609                   /*EmitCodeOnly=*/true);2610  Streamer->emitLabel(EndLabel);2611 2612  using LabelRange = std::pair<const MCSymbol *, const MCSymbol *>;2613  SmallVector<LabelRange> SplitLabels;2614  for (FunctionFragment &FF : BF.getLayout().getSplitFragments()) {2615    MCSymbol *const SplitStartLabel = LocalCtx->createTempSymbol();2616    MCSymbol *const SplitEndLabel = LocalCtx->createTempSymbol();2617    SplitLabels.emplace_back(SplitStartLabel, SplitEndLabel);2618 2619    MCSectionELF *const SplitSection = LocalCtx->getELFSection(2620        BF.getCodeSectionName(FF.getFragmentNum()), ELF::SHT_PROGBITS,2621        ELF::SHF_EXECINSTR | ELF::SHF_ALLOC);2622    SplitSection->setHasInstructions(true);2623    Streamer->switchSection(SplitSection);2624 2625    Streamer->emitLabel(SplitStartLabel);2626    emitFunctionBody(*Streamer, BF, FF, /*EmitCodeOnly=*/true);2627    Streamer->emitLabel(SplitEndLabel);2628  }2629 2630  MCAssembler &Assembler =2631      static_cast<MCObjectStreamer *>(Streamer.get())->getAssembler();2632  Assembler.layout();2633 2634  // Obtain fragment sizes.2635  std::vector<uint64_t> FragmentSizes;2636  // Main fragment size.2637  const uint64_t HotSize = Assembler.getSymbolOffset(*EndLabel) -2638                           Assembler.getSymbolOffset(*StartLabel);2639  FragmentSizes.push_back(HotSize);2640  // Split fragment sizes.2641  uint64_t ColdSize = 0;2642  for (const auto &Labels : SplitLabels) {2643    uint64_t Size = Assembler.getSymbolOffset(*Labels.second) -2644                    Assembler.getSymbolOffset(*Labels.first);2645    FragmentSizes.push_back(Size);2646    ColdSize += Size;2647  }2648 2649  // Populate new start and end offsets of each basic block.2650  uint64_t FragmentIndex = 0;2651  for (FunctionFragment &FF : BF.getLayout().fragments()) {2652    BinaryBasicBlock *PrevBB = nullptr;2653    for (BinaryBasicBlock *BB : FF) {2654      const uint64_t BBStartOffset =2655          Assembler.getSymbolOffset(*(BB->getLabel()));2656      BB->setOutputStartAddress(BBStartOffset);2657      if (PrevBB)2658        PrevBB->setOutputEndAddress(BBStartOffset);2659      PrevBB = BB;2660    }2661    if (PrevBB)2662      PrevBB->setOutputEndAddress(FragmentSizes[FragmentIndex]);2663    FragmentIndex++;2664  }2665 2666  // Clean-up the effect of the code emission.2667  for (const MCSymbol &Symbol : Assembler.symbols()) {2668    MCSymbol *MutableSymbol = const_cast<MCSymbol *>(&Symbol);2669    MutableSymbol->setFragment(nullptr);2670    MutableSymbol->setIsRegistered(false);2671  }2672 2673  return std::make_pair(HotSize, ColdSize);2674}2675 2676bool BinaryContext::validateInstructionEncoding(2677    ArrayRef<uint8_t> InputSequence) const {2678  MCInst Inst;2679  uint64_t InstSize;2680  DisAsm->getInstruction(Inst, InstSize, InputSequence, 0, nulls());2681  assert(InstSize == InputSequence.size() &&2682         "Disassembled instruction size does not match the sequence.");2683 2684  SmallString<256> Code;2685  SmallVector<MCFixup, 4> Fixups;2686 2687  MCE->encodeInstruction(Inst, Code, Fixups, *STI);2688  auto OutputSequence = ArrayRef<uint8_t>((uint8_t *)Code.data(), Code.size());2689  if (InputSequence != OutputSequence) {2690    if (opts::Verbosity > 1) {2691      this->errs() << "BOLT-WARNING: mismatched encoding detected\n"2692                   << "      input: " << InputSequence << '\n'2693                   << "     output: " << OutputSequence << '\n';2694    }2695    return false;2696  }2697 2698  return true;2699}2700 2701uint64_t BinaryContext::getHotThreshold() const {2702  static uint64_t Threshold = 0;2703  if (Threshold == 0) {2704    Threshold = std::max(2705        (uint64_t)opts::ExecutionCountThreshold,2706        NumProfiledFuncs ? SumExecutionCount / (2 * NumProfiledFuncs) : 1);2707  }2708  return Threshold;2709}2710 2711BinaryFunction *BinaryContext::getBinaryFunctionContainingAddress(2712    uint64_t Address, bool CheckPastEnd, bool UseMaxSize) {2713  auto FI = BinaryFunctions.upper_bound(Address);2714  if (FI == BinaryFunctions.begin())2715    return nullptr;2716  --FI;2717 2718  const uint64_t UsedSize =2719      UseMaxSize ? FI->second.getMaxSize() : FI->second.getSize();2720 2721  if (Address >= FI->first + UsedSize + (CheckPastEnd ? 1 : 0))2722    return nullptr;2723 2724  return &FI->second;2725}2726 2727BinaryFunction *BinaryContext::getBinaryFunctionAtAddress(uint64_t Address) {2728  // First, try to find a function starting at the given address. If the2729  // function was folded, this will get us the original folded function if it2730  // wasn't removed from the list, e.g. in non-relocation mode.2731  auto BFI = BinaryFunctions.find(Address);2732  if (BFI != BinaryFunctions.end())2733    return &BFI->second;2734 2735  // We might have folded the function matching the object at the given2736  // address. In such case, we look for a function matching the symbol2737  // registered at the original address. The new function (the one that the2738  // original was folded into) will hold the symbol.2739  if (const BinaryData *BD = getBinaryDataAtAddress(Address)) {2740    uint64_t EntryID = 0;2741    BinaryFunction *BF = getFunctionForSymbol(BD->getSymbol(), &EntryID);2742    if (BF && EntryID == 0)2743      return BF;2744  }2745  return nullptr;2746}2747 2748/// Deregister JumpTable registered at a given \p Address and delete it.2749void BinaryContext::deleteJumpTable(uint64_t Address) {2750  assert(JumpTables.count(Address) && "Must have a jump table at address");2751  JumpTable *JT = JumpTables.at(Address);2752  for (BinaryFunction *Parent : JT->Parents)2753    Parent->JumpTables.erase(Address);2754  JumpTables.erase(Address);2755  delete JT;2756}2757 2758DebugAddressRangesVector BinaryContext::translateModuleAddressRanges(2759    const DWARFAddressRangesVector &InputRanges) const {2760  DebugAddressRangesVector OutputRanges;2761 2762  for (const DWARFAddressRange Range : InputRanges) {2763    auto BFI = BinaryFunctions.lower_bound(Range.LowPC);2764    while (BFI != BinaryFunctions.end()) {2765      const BinaryFunction &Function = BFI->second;2766      if (Function.getAddress() >= Range.HighPC)2767        break;2768      const DebugAddressRangesVector FunctionRanges =2769          Function.getOutputAddressRanges();2770      llvm::move(FunctionRanges, std::back_inserter(OutputRanges));2771      std::advance(BFI, 1);2772    }2773  }2774 2775  return OutputRanges;2776}2777 2778} // namespace bolt2779} // namespace llvm2780