12f09f445SMaksim Panchenko //===- bolt/Core/BinaryFunction.cpp - Low-level function ------------------===// 2a34c753fSRafael Auler // 3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a34c753fSRafael Auler // 7a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8a34c753fSRafael Auler // 92f09f445SMaksim Panchenko // This file implements the BinaryFunction class. 102f09f445SMaksim Panchenko // 11a34c753fSRafael Auler //===----------------------------------------------------------------------===// 12a34c753fSRafael Auler 13a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h" 14a34c753fSRafael Auler #include "bolt/Core/BinaryBasicBlock.h" 15a7b69dbdSAmir Ayupov #include "bolt/Core/BinaryDomTree.h" 16a34c753fSRafael Auler #include "bolt/Core/DynoStats.h" 173e3a926bSspupyrev #include "bolt/Core/HashUtilities.h" 18a34c753fSRafael Auler #include "bolt/Core/MCPlusBuilder.h" 19a34c753fSRafael Auler #include "bolt/Utils/NameResolver.h" 20a34c753fSRafael Auler #include "bolt/Utils/NameShortener.h" 21a34c753fSRafael Auler #include "bolt/Utils/Utils.h" 225d8247d4SAmir Ayupov #include "llvm/ADT/STLExtras.h" 23a34c753fSRafael Auler #include "llvm/ADT/SmallSet.h" 24f7581a39SAmir Ayupov #include "llvm/ADT/StringExtras.h" 25a34c753fSRafael Auler #include "llvm/ADT/StringRef.h" 26ae585be1SRafael Auler #include "llvm/Demangle/Demangle.h" 27a34c753fSRafael Auler #include "llvm/MC/MCAsmInfo.h" 28a34c753fSRafael Auler #include "llvm/MC/MCContext.h" 29a34c753fSRafael Auler #include "llvm/MC/MCDisassembler/MCDisassembler.h" 30a34c753fSRafael Auler #include "llvm/MC/MCExpr.h" 31a34c753fSRafael Auler #include "llvm/MC/MCInst.h" 32a34c753fSRafael Auler #include "llvm/MC/MCInstPrinter.h" 3357f7c7d9Sserge-sans-paille #include "llvm/MC/MCRegisterInfo.h" 34a191ea7dSFabian Parzefall #include "llvm/MC/MCSymbol.h" 35a34c753fSRafael Auler #include "llvm/Object/ObjectFile.h" 36a34c753fSRafael Auler #include "llvm/Support/CommandLine.h" 37a34c753fSRafael Auler #include "llvm/Support/Debug.h" 38a34c753fSRafael Auler #include "llvm/Support/GraphWriter.h" 39a34c753fSRafael Auler #include "llvm/Support/LEB128.h" 40a34c753fSRafael Auler #include "llvm/Support/Regex.h" 41a34c753fSRafael Auler #include "llvm/Support/Timer.h" 42a34c753fSRafael Auler #include "llvm/Support/raw_ostream.h" 43a34c753fSRafael Auler #include <functional> 44a34c753fSRafael Auler #include <limits> 45a34c753fSRafael Auler #include <numeric> 46a34c753fSRafael Auler #include <string> 47a34c753fSRafael Auler 48a34c753fSRafael Auler #define DEBUG_TYPE "bolt" 49a34c753fSRafael Auler 50a34c753fSRafael Auler using namespace llvm; 51a34c753fSRafael Auler using namespace bolt; 52a34c753fSRafael Auler 53a34c753fSRafael Auler namespace opts { 54a34c753fSRafael Auler 55a34c753fSRafael Auler extern cl::OptionCategory BoltCategory; 56a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory; 57a34c753fSRafael Auler extern cl::OptionCategory BoltRelocCategory; 58a34c753fSRafael Auler 59a34c753fSRafael Auler extern cl::opt<bool> EnableBAT; 60a34c753fSRafael Auler extern cl::opt<bool> Instrument; 61a34c753fSRafael Auler extern cl::opt<bool> StrictMode; 62a34c753fSRafael Auler extern cl::opt<bool> UpdateDebugSections; 63a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity; 64a34c753fSRafael Auler 65a34c753fSRafael Auler extern bool processAllFunctions(); 66a34c753fSRafael Auler 67b92436efSFangrui Song cl::opt<bool> CheckEncoding( 68b92436efSFangrui Song "check-encoding", 69a34c753fSRafael Auler cl::desc("perform verification of LLVM instruction encoding/decoding. " 70a34c753fSRafael Auler "Every instruction in the input is decoded and re-encoded. " 71a34c753fSRafael Auler "If the resulting bytes do not match the input, a warning message " 72a34c753fSRafael Auler "is printed."), 73b92436efSFangrui Song cl::Hidden, cl::cat(BoltCategory)); 74a34c753fSRafael Auler 75b92436efSFangrui Song static cl::opt<bool> DotToolTipCode( 76b92436efSFangrui Song "dot-tooltip-code", 77b92436efSFangrui Song cl::desc("add basic block instructions as tool tips on nodes"), cl::Hidden, 78a34c753fSRafael Auler cl::cat(BoltCategory)); 79a34c753fSRafael Auler 80a34c753fSRafael Auler cl::opt<JumpTableSupportLevel> 81a34c753fSRafael Auler JumpTables("jump-tables", 82a34c753fSRafael Auler cl::desc("jump tables support (default=basic)"), 83a34c753fSRafael Auler cl::init(JTS_BASIC), 84a34c753fSRafael Auler cl::values( 85a34c753fSRafael Auler clEnumValN(JTS_NONE, "none", 86a34c753fSRafael Auler "do not optimize functions with jump tables"), 87a34c753fSRafael Auler clEnumValN(JTS_BASIC, "basic", 88a34c753fSRafael Auler "optimize functions with jump tables"), 89a34c753fSRafael Auler clEnumValN(JTS_MOVE, "move", 90a34c753fSRafael Auler "move jump tables to a separate section"), 91a34c753fSRafael Auler clEnumValN(JTS_SPLIT, "split", 92a34c753fSRafael Auler "split jump tables section into hot and cold based on " 93a34c753fSRafael Auler "function execution frequency"), 94a34c753fSRafael Auler clEnumValN(JTS_AGGRESSIVE, "aggressive", 95a34c753fSRafael Auler "aggressively split jump tables section based on usage " 96a34c753fSRafael Auler "of the tables")), 97a34c753fSRafael Auler cl::ZeroOrMore, 98a34c753fSRafael Auler cl::cat(BoltOptCategory)); 99a34c753fSRafael Auler 100b92436efSFangrui Song static cl::opt<bool> NoScan( 101b92436efSFangrui Song "no-scan", 102b92436efSFangrui Song cl::desc( 103b92436efSFangrui Song "do not scan cold functions for external references (may result in " 104a34c753fSRafael Auler "slower binary)"), 105b92436efSFangrui Song cl::Hidden, cl::cat(BoltOptCategory)); 106a34c753fSRafael Auler 107a34c753fSRafael Auler cl::opt<bool> 108a34c753fSRafael Auler PreserveBlocksAlignment("preserve-blocks-alignment", 109a34c753fSRafael Auler cl::desc("try to preserve basic block alignment"), 110a34c753fSRafael Auler cl::cat(BoltOptCategory)); 111a34c753fSRafael Auler 112a34c753fSRafael Auler cl::opt<bool> 113a34c753fSRafael Auler PrintDynoStats("dyno-stats", 114a34c753fSRafael Auler cl::desc("print execution info based on profile"), 115a34c753fSRafael Auler cl::cat(BoltCategory)); 116a34c753fSRafael Auler 117a34c753fSRafael Auler static cl::opt<bool> 118a34c753fSRafael Auler PrintDynoStatsOnly("print-dyno-stats-only", 119a34c753fSRafael Auler cl::desc("while printing functions output dyno-stats and skip instructions"), 120a34c753fSRafael Auler cl::init(false), 121a34c753fSRafael Auler cl::Hidden, 122a34c753fSRafael Auler cl::cat(BoltCategory)); 123a34c753fSRafael Auler 124a34c753fSRafael Auler static cl::list<std::string> 125a34c753fSRafael Auler PrintOnly("print-only", 126a34c753fSRafael Auler cl::CommaSeparated, 127a34c753fSRafael Auler cl::desc("list of functions to print"), 128a34c753fSRafael Auler cl::value_desc("func1,func2,func3,..."), 129a34c753fSRafael Auler cl::Hidden, 130a34c753fSRafael Auler cl::cat(BoltCategory)); 131a34c753fSRafael Auler 132a34c753fSRafael Auler cl::opt<bool> 133a34c753fSRafael Auler TimeBuild("time-build", 134a34c753fSRafael Auler cl::desc("print time spent constructing binary functions"), 135b92436efSFangrui Song cl::Hidden, cl::cat(BoltCategory)); 136a34c753fSRafael Auler 137a34c753fSRafael Auler cl::opt<bool> 138a34c753fSRafael Auler TrapOnAVX512("trap-avx512", 139a34c753fSRafael Auler cl::desc("in relocation mode trap upon entry to any function that uses " 140a34c753fSRafael Auler "AVX-512 instructions"), 141a34c753fSRafael Auler cl::init(false), 142a34c753fSRafael Auler cl::ZeroOrMore, 143a34c753fSRafael Auler cl::Hidden, 144a34c753fSRafael Auler cl::cat(BoltCategory)); 145a34c753fSRafael Auler 146a34c753fSRafael Auler bool shouldPrint(const BinaryFunction &Function) { 147a34c753fSRafael Auler if (Function.isIgnored()) 148a34c753fSRafael Auler return false; 149a34c753fSRafael Auler 150a34c753fSRafael Auler if (PrintOnly.empty()) 151a34c753fSRafael Auler return true; 152a34c753fSRafael Auler 153a34c753fSRafael Auler for (std::string &Name : opts::PrintOnly) { 154a34c753fSRafael Auler if (Function.hasNameRegex(Name)) { 155a34c753fSRafael Auler return true; 156a34c753fSRafael Auler } 157a34c753fSRafael Auler } 158a34c753fSRafael Auler 159a34c753fSRafael Auler return false; 160a34c753fSRafael Auler } 161a34c753fSRafael Auler 162a34c753fSRafael Auler } // namespace opts 163a34c753fSRafael Auler 164a34c753fSRafael Auler namespace llvm { 165a34c753fSRafael Auler namespace bolt { 166a34c753fSRafael Auler 167a34c753fSRafael Auler constexpr unsigned BinaryFunction::MinAlign; 168a34c753fSRafael Auler 169be2f67c4SAmir Ayupov template <typename R> static bool emptyRange(const R &Range) { 170a34c753fSRafael Auler return Range.begin() == Range.end(); 171a34c753fSRafael Auler } 172a34c753fSRafael Auler 173a34c753fSRafael Auler /// Gets debug line information for the instruction located at the given 174a34c753fSRafael Auler /// address in the original binary. The SMLoc's pointer is used 175a34c753fSRafael Auler /// to point to this information, which is represented by a 176a34c753fSRafael Auler /// DebugLineTableRowRef. The returned pointer is null if no debug line 177a34c753fSRafael Auler /// information for this instruction was found. 178be2f67c4SAmir Ayupov static SMLoc findDebugLineInformationForInstructionAt( 17940c2e0faSMaksim Panchenko uint64_t Address, DWARFUnit *Unit, 18040c2e0faSMaksim Panchenko const DWARFDebugLine::LineTable *LineTable) { 181a34c753fSRafael Auler // We use the pointer in SMLoc to store an instance of DebugLineTableRowRef, 182a34c753fSRafael Auler // which occupies 64 bits. Thus, we can only proceed if the struct fits into 183a34c753fSRafael Auler // the pointer itself. 184363be89cSKazu Hirata static_assert( 185363be89cSKazu Hirata sizeof(decltype(SMLoc().getPointer())) >= sizeof(DebugLineTableRowRef), 186a34c753fSRafael Auler "Cannot fit instruction debug line information into SMLoc's pointer"); 187a34c753fSRafael Auler 188a34c753fSRafael Auler SMLoc NullResult = DebugLineTableRowRef::NULL_ROW.toSMLoc(); 189a34c753fSRafael Auler uint32_t RowIndex = LineTable->lookupAddress( 190a34c753fSRafael Auler {Address, object::SectionedAddress::UndefSection}); 191a34c753fSRafael Auler if (RowIndex == LineTable->UnknownRowIndex) 192a34c753fSRafael Auler return NullResult; 193a34c753fSRafael Auler 194a34c753fSRafael Auler assert(RowIndex < LineTable->Rows.size() && 195a34c753fSRafael Auler "Line Table lookup returned invalid index."); 196a34c753fSRafael Auler 197a34c753fSRafael Auler decltype(SMLoc().getPointer()) Ptr; 198a34c753fSRafael Auler DebugLineTableRowRef *InstructionLocation = 199a34c753fSRafael Auler reinterpret_cast<DebugLineTableRowRef *>(&Ptr); 200a34c753fSRafael Auler 201a34c753fSRafael Auler InstructionLocation->DwCompileUnitIndex = Unit->getOffset(); 202a34c753fSRafael Auler InstructionLocation->RowIndex = RowIndex + 1; 203a34c753fSRafael Auler 204a34c753fSRafael Auler return SMLoc::getFromPointer(Ptr); 205a34c753fSRafael Auler } 206a34c753fSRafael Auler 207be2f67c4SAmir Ayupov static std::string buildSectionName(StringRef Prefix, StringRef Name, 208a34c753fSRafael Auler const BinaryContext &BC) { 209a34c753fSRafael Auler if (BC.isELF()) 210a34c753fSRafael Auler return (Prefix + Name).str(); 211a34c753fSRafael Auler static NameShortener NS; 212a34c753fSRafael Auler return (Prefix + Twine(NS.getID(Name))).str(); 213a34c753fSRafael Auler } 214a34c753fSRafael Auler 215be2f67c4SAmir Ayupov static raw_ostream &operator<<(raw_ostream &OS, 216be2f67c4SAmir Ayupov const BinaryFunction::State State) { 21740c2e0faSMaksim Panchenko switch (State) { 21840c2e0faSMaksim Panchenko case BinaryFunction::State::Empty: OS << "empty"; break; 21940c2e0faSMaksim Panchenko case BinaryFunction::State::Disassembled: OS << "disassembled"; break; 22040c2e0faSMaksim Panchenko case BinaryFunction::State::CFG: OS << "CFG constructed"; break; 22140c2e0faSMaksim Panchenko case BinaryFunction::State::CFG_Finalized: OS << "CFG finalized"; break; 22240c2e0faSMaksim Panchenko case BinaryFunction::State::EmittedCFG: OS << "emitted with CFG"; break; 22340c2e0faSMaksim Panchenko case BinaryFunction::State::Emitted: OS << "emitted"; break; 22440c2e0faSMaksim Panchenko } 22540c2e0faSMaksim Panchenko 22640c2e0faSMaksim Panchenko return OS; 22740c2e0faSMaksim Panchenko } 22840c2e0faSMaksim Panchenko 229a34c753fSRafael Auler std::string BinaryFunction::buildCodeSectionName(StringRef Name, 230a34c753fSRafael Auler const BinaryContext &BC) { 231a34c753fSRafael Auler return buildSectionName(BC.isELF() ? ".local.text." : ".l.text.", Name, BC); 232a34c753fSRafael Auler } 233a34c753fSRafael Auler 234a34c753fSRafael Auler std::string BinaryFunction::buildColdCodeSectionName(StringRef Name, 235a34c753fSRafael Auler const BinaryContext &BC) { 236a34c753fSRafael Auler return buildSectionName(BC.isELF() ? ".local.cold.text." : ".l.c.text.", Name, 237a34c753fSRafael Auler BC); 238a34c753fSRafael Auler } 239a34c753fSRafael Auler 240a34c753fSRafael Auler uint64_t BinaryFunction::Count = 0; 241a34c753fSRafael Auler 24272528ee4SAmir Ayupov std::optional<StringRef> 24372528ee4SAmir Ayupov BinaryFunction::hasNameRegex(const StringRef Name) const { 244a34c753fSRafael Auler const std::string RegexName = (Twine("^") + StringRef(Name) + "$").str(); 245a34c753fSRafael Auler Regex MatchName(RegexName); 24672528ee4SAmir Ayupov return forEachName( 247a34c753fSRafael Auler [&MatchName](StringRef Name) { return MatchName.match(Name); }); 248a34c753fSRafael Auler } 249a34c753fSRafael Auler 25072528ee4SAmir Ayupov std::optional<StringRef> 251a34c753fSRafael Auler BinaryFunction::hasRestoredNameRegex(const StringRef Name) const { 252a34c753fSRafael Auler const std::string RegexName = (Twine("^") + StringRef(Name) + "$").str(); 253a34c753fSRafael Auler Regex MatchName(RegexName); 25472528ee4SAmir Ayupov return forEachName([&MatchName](StringRef Name) { 255a34c753fSRafael Auler return MatchName.match(NameResolver::restore(Name)); 256a34c753fSRafael Auler }); 257a34c753fSRafael Auler } 258a34c753fSRafael Auler 259a34c753fSRafael Auler std::string BinaryFunction::getDemangledName() const { 260a34c753fSRafael Auler StringRef MangledName = NameResolver::restore(getOneName()); 261ae585be1SRafael Auler return demangle(MangledName.str()); 262a34c753fSRafael Auler } 263a34c753fSRafael Auler 264a34c753fSRafael Auler BinaryBasicBlock * 265a34c753fSRafael Auler BinaryFunction::getBasicBlockContainingOffset(uint64_t Offset) { 266a34c753fSRafael Auler if (Offset > Size) 267a34c753fSRafael Auler return nullptr; 268a34c753fSRafael Auler 269a34c753fSRafael Auler if (BasicBlockOffsets.empty()) 270a34c753fSRafael Auler return nullptr; 271a34c753fSRafael Auler 272a34c753fSRafael Auler /* 273a34c753fSRafael Auler * This is commented out because it makes BOLT too slow. 274a34c753fSRafael Auler * assert(std::is_sorted(BasicBlockOffsets.begin(), 275a34c753fSRafael Auler * BasicBlockOffsets.end(), 276a34c753fSRafael Auler * CompareBasicBlockOffsets()))); 277a34c753fSRafael Auler */ 278d2c87699SAmir Ayupov auto I = 279d2c87699SAmir Ayupov llvm::upper_bound(BasicBlockOffsets, BasicBlockOffset(Offset, nullptr), 280a34c753fSRafael Auler CompareBasicBlockOffsets()); 281a34c753fSRafael Auler assert(I != BasicBlockOffsets.begin() && "first basic block not at offset 0"); 282a34c753fSRafael Auler --I; 283a34c753fSRafael Auler BinaryBasicBlock *BB = I->second; 284a34c753fSRafael Auler return (Offset < BB->getOffset() + BB->getOriginalSize()) ? BB : nullptr; 285a34c753fSRafael Auler } 286a34c753fSRafael Auler 287a34c753fSRafael Auler void BinaryFunction::markUnreachableBlocks() { 288a34c753fSRafael Auler std::stack<BinaryBasicBlock *> Stack; 289a34c753fSRafael Auler 290d55dfeafSFabian Parzefall for (BinaryBasicBlock &BB : blocks()) 291d55dfeafSFabian Parzefall BB.markValid(false); 292a34c753fSRafael Auler 293a34c753fSRafael Auler // Add all entries and landing pads as roots. 294a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 295a34c753fSRafael Auler if (isEntryPoint(*BB) || BB->isLandingPad()) { 296a34c753fSRafael Auler Stack.push(BB); 297a34c753fSRafael Auler BB->markValid(true); 298a34c753fSRafael Auler continue; 299a34c753fSRafael Auler } 300a34c753fSRafael Auler // FIXME: 301a34c753fSRafael Auler // Also mark BBs with indirect jumps as reachable, since we do not 302933df2a4SMaksim Panchenko // support removing unused jump tables yet (GH-issue20). 303a34c753fSRafael Auler for (const MCInst &Inst : *BB) { 304a34c753fSRafael Auler if (BC.MIB->getJumpTable(Inst)) { 305a34c753fSRafael Auler Stack.push(BB); 306a34c753fSRafael Auler BB->markValid(true); 307a34c753fSRafael Auler break; 308a34c753fSRafael Auler } 309a34c753fSRafael Auler } 310a34c753fSRafael Auler } 311a34c753fSRafael Auler 312a34c753fSRafael Auler // Determine reachable BBs from the entry point 313a34c753fSRafael Auler while (!Stack.empty()) { 314a34c753fSRafael Auler BinaryBasicBlock *BB = Stack.top(); 315a34c753fSRafael Auler Stack.pop(); 316a34c753fSRafael Auler for (BinaryBasicBlock *Succ : BB->successors()) { 317a34c753fSRafael Auler if (Succ->isValid()) 318a34c753fSRafael Auler continue; 319a34c753fSRafael Auler Succ->markValid(true); 320a34c753fSRafael Auler Stack.push(Succ); 321a34c753fSRafael Auler } 322a34c753fSRafael Auler } 323a34c753fSRafael Auler } 324a34c753fSRafael Auler 325a34c753fSRafael Auler // Any unnecessary fallthrough jumps revealed after calling eraseInvalidBBs 326a34c753fSRafael Auler // will be cleaned up by fixBranches(). 327a34c753fSRafael Auler std::pair<unsigned, uint64_t> BinaryFunction::eraseInvalidBBs() { 3288477bc67SFabian Parzefall DenseSet<const BinaryBasicBlock *> InvalidBBs; 329a34c753fSRafael Auler unsigned Count = 0; 330a34c753fSRafael Auler uint64_t Bytes = 0; 3318477bc67SFabian Parzefall for (BinaryBasicBlock *const BB : BasicBlocks) { 3328477bc67SFabian Parzefall if (!BB->isValid()) { 333a34c753fSRafael Auler assert(!isEntryPoint(*BB) && "all entry blocks must be valid"); 3348477bc67SFabian Parzefall InvalidBBs.insert(BB); 335a34c753fSRafael Auler ++Count; 336a34c753fSRafael Auler Bytes += BC.computeCodeSize(BB->begin(), BB->end()); 337a34c753fSRafael Auler } 338a34c753fSRafael Auler } 3398477bc67SFabian Parzefall 3408477bc67SFabian Parzefall Layout.eraseBasicBlocks(InvalidBBs); 341a34c753fSRafael Auler 342a34c753fSRafael Auler BasicBlockListType NewBasicBlocks; 343a34c753fSRafael Auler for (auto I = BasicBlocks.begin(), E = BasicBlocks.end(); I != E; ++I) { 344a34c753fSRafael Auler BinaryBasicBlock *BB = *I; 3458477bc67SFabian Parzefall if (InvalidBBs.contains(BB)) { 346a34c753fSRafael Auler // Make sure the block is removed from the list of predecessors. 347a34c753fSRafael Auler BB->removeAllSuccessors(); 348a34c753fSRafael Auler DeletedBasicBlocks.push_back(BB); 3498477bc67SFabian Parzefall } else { 3508477bc67SFabian Parzefall NewBasicBlocks.push_back(BB); 351a34c753fSRafael Auler } 352a34c753fSRafael Auler } 353a34c753fSRafael Auler BasicBlocks = std::move(NewBasicBlocks); 354a34c753fSRafael Auler 3558477bc67SFabian Parzefall assert(BasicBlocks.size() == Layout.block_size()); 356a34c753fSRafael Auler 357a34c753fSRafael Auler // Update CFG state if needed 358a34c753fSRafael Auler if (Count > 0) 359a34c753fSRafael Auler recomputeLandingPads(); 360a34c753fSRafael Auler 361a34c753fSRafael Auler return std::make_pair(Count, Bytes); 362a34c753fSRafael Auler } 363a34c753fSRafael Auler 364a34c753fSRafael Auler bool BinaryFunction::isForwardCall(const MCSymbol *CalleeSymbol) const { 365a34c753fSRafael Auler // This function should work properly before and after function reordering. 366a34c753fSRafael Auler // In order to accomplish this, we use the function index (if it is valid). 367a34c753fSRafael Auler // If the function indices are not valid, we fall back to the original 368a34c753fSRafael Auler // addresses. This should be ok because the functions without valid indices 369a34c753fSRafael Auler // should have been ordered with a stable sort. 370a34c753fSRafael Auler const BinaryFunction *CalleeBF = BC.getFunctionForSymbol(CalleeSymbol); 371a34c753fSRafael Auler if (CalleeBF) { 372a34c753fSRafael Auler if (CalleeBF->isInjected()) 373a34c753fSRafael Auler return true; 374a34c753fSRafael Auler 375a34c753fSRafael Auler if (hasValidIndex() && CalleeBF->hasValidIndex()) { 376a34c753fSRafael Auler return getIndex() < CalleeBF->getIndex(); 377a34c753fSRafael Auler } else if (hasValidIndex() && !CalleeBF->hasValidIndex()) { 378a34c753fSRafael Auler return true; 379a34c753fSRafael Auler } else if (!hasValidIndex() && CalleeBF->hasValidIndex()) { 380a34c753fSRafael Auler return false; 381a34c753fSRafael Auler } else { 382a34c753fSRafael Auler return getAddress() < CalleeBF->getAddress(); 383a34c753fSRafael Auler } 384a34c753fSRafael Auler } else { 385a34c753fSRafael Auler // Absolute symbol. 386a34c753fSRafael Auler ErrorOr<uint64_t> CalleeAddressOrError = BC.getSymbolValue(*CalleeSymbol); 387a34c753fSRafael Auler assert(CalleeAddressOrError && "unregistered symbol found"); 388a34c753fSRafael Auler return *CalleeAddressOrError > getAddress(); 389a34c753fSRafael Auler } 390a34c753fSRafael Auler } 391a34c753fSRafael Auler 392be9d3edeSMaksim Panchenko void BinaryFunction::dump() const { 393d5c03defSFabian Parzefall // getDynoStats calls FunctionLayout::updateLayoutIndices and 394d5c03defSFabian Parzefall // BasicBlock::analyzeBranch. The former cannot be const, but should be 395d5c03defSFabian Parzefall // removed, the latter should be made const, but seems to require refactoring. 396d5c03defSFabian Parzefall // Forcing all callers to have a non-const reference to BinaryFunction to call 397d5c03defSFabian Parzefall // dump non-const however is not ideal either. Adding this const_cast is right 398d5c03defSFabian Parzefall // now the best solution. It is safe, because BinaryFunction itself is not 399d5c03defSFabian Parzefall // modified. Only BinaryBasicBlocks are actually modified (if it all) and we 400d5c03defSFabian Parzefall // have mutable pointers to those regardless whether this function is 401d5c03defSFabian Parzefall // const-qualified or not. 402be9d3edeSMaksim Panchenko const_cast<BinaryFunction &>(*this).print(dbgs(), ""); 403a34c753fSRafael Auler } 404a34c753fSRafael Auler 405be9d3edeSMaksim Panchenko void BinaryFunction::print(raw_ostream &OS, std::string Annotation) { 406a34c753fSRafael Auler if (!opts::shouldPrint(*this)) 407a34c753fSRafael Auler return; 408a34c753fSRafael Auler 409a34c753fSRafael Auler StringRef SectionName = 410a34c753fSRafael Auler OriginSection ? OriginSection->getName() : "<no origin section>"; 411a34c753fSRafael Auler OS << "Binary Function \"" << *this << "\" " << Annotation << " {"; 412a34c753fSRafael Auler std::vector<StringRef> AllNames = getNames(); 413a34c753fSRafael Auler if (AllNames.size() > 1) { 414a34c753fSRafael Auler OS << "\n All names : "; 415a34c753fSRafael Auler const char *Sep = ""; 416253b8f0aSAmir Ayupov for (const StringRef &Name : AllNames) { 417a34c753fSRafael Auler OS << Sep << Name; 418a34c753fSRafael Auler Sep = "\n "; 419a34c753fSRafael Auler } 420a34c753fSRafael Auler } 4219b6e7861SFabian Parzefall OS << "\n Number : " << FunctionNumber; 4229b6e7861SFabian Parzefall OS << "\n State : " << CurrentState; 4239b6e7861SFabian Parzefall OS << "\n Address : 0x" << Twine::utohexstr(Address); 4249b6e7861SFabian Parzefall OS << "\n Size : 0x" << Twine::utohexstr(Size); 4259b6e7861SFabian Parzefall OS << "\n MaxSize : 0x" << Twine::utohexstr(MaxSize); 4269b6e7861SFabian Parzefall OS << "\n Offset : 0x" << Twine::utohexstr(getFileOffset()); 4279b6e7861SFabian Parzefall OS << "\n Section : " << SectionName; 4289b6e7861SFabian Parzefall OS << "\n Orc Section : " << getCodeSectionName(); 4299b6e7861SFabian Parzefall OS << "\n LSDA : 0x" << Twine::utohexstr(getLSDAAddress()); 4309b6e7861SFabian Parzefall OS << "\n IsSimple : " << IsSimple; 4319b6e7861SFabian Parzefall OS << "\n IsMultiEntry: " << isMultiEntry(); 4329b6e7861SFabian Parzefall OS << "\n IsSplit : " << isSplit(); 4339b6e7861SFabian Parzefall OS << "\n BB Count : " << size(); 434a34c753fSRafael Auler 43540c2e0faSMaksim Panchenko if (HasFixedIndirectBranch) 436a34c753fSRafael Auler OS << "\n HasFixedIndirectBranch : true"; 43740c2e0faSMaksim Panchenko if (HasUnknownControlFlow) 438a34c753fSRafael Auler OS << "\n Unknown CF : true"; 43940c2e0faSMaksim Panchenko if (getPersonalityFunction()) 440a34c753fSRafael Auler OS << "\n Personality : " << getPersonalityFunction()->getName(); 44140c2e0faSMaksim Panchenko if (IsFragment) 442a34c753fSRafael Auler OS << "\n IsFragment : true"; 44340c2e0faSMaksim Panchenko if (isFolded()) 444a34c753fSRafael Auler OS << "\n FoldedInto : " << *getFoldedIntoFunction(); 44540c2e0faSMaksim Panchenko for (BinaryFunction *ParentFragment : ParentFragments) 446a34c753fSRafael Auler OS << "\n Parent : " << *ParentFragment; 447a34c753fSRafael Auler if (!Fragments.empty()) { 448a34c753fSRafael Auler OS << "\n Fragments : "; 449f7581a39SAmir Ayupov ListSeparator LS; 450f7581a39SAmir Ayupov for (BinaryFunction *Frag : Fragments) 451f7581a39SAmir Ayupov OS << LS << *Frag; 452a34c753fSRafael Auler } 45340c2e0faSMaksim Panchenko if (hasCFG()) 454a34c753fSRafael Auler OS << "\n Hash : " << Twine::utohexstr(computeHash()); 455a34c753fSRafael Auler if (isMultiEntry()) { 456a34c753fSRafael Auler OS << "\n Secondary Entry Points : "; 457f7581a39SAmir Ayupov ListSeparator LS; 458f7581a39SAmir Ayupov for (const auto &KV : SecondaryEntryPoints) 459f7581a39SAmir Ayupov OS << LS << KV.second->getName(); 460a34c753fSRafael Auler } 46140c2e0faSMaksim Panchenko if (FrameInstructions.size()) 462a34c753fSRafael Auler OS << "\n CFI Instrs : " << FrameInstructions.size(); 4638477bc67SFabian Parzefall if (!Layout.block_empty()) { 464a34c753fSRafael Auler OS << "\n BB Layout : "; 465f7581a39SAmir Ayupov ListSeparator LS; 4668477bc67SFabian Parzefall for (const BinaryBasicBlock *BB : Layout.blocks()) 467f7581a39SAmir Ayupov OS << LS << BB->getName(); 468a34c753fSRafael Auler } 4699b6e7861SFabian Parzefall if (getImageAddress()) 4709b6e7861SFabian Parzefall OS << "\n Image : 0x" << Twine::utohexstr(getImageAddress()); 471a34c753fSRafael Auler if (ExecutionCount != COUNT_NO_PROFILE) { 472a34c753fSRafael Auler OS << "\n Exec Count : " << ExecutionCount; 47392758a99Sspupyrev OS << "\n Branch Count: " << RawBranchCount; 474a34c753fSRafael Auler OS << "\n Profile Acc : " << format("%.1f%%", ProfileMatchRatio * 100.0f); 475a34c753fSRafael Auler } 476a34c753fSRafael Auler 4778477bc67SFabian Parzefall if (opts::PrintDynoStats && !getLayout().block_empty()) { 478a34c753fSRafael Auler OS << '\n'; 479a34c753fSRafael Auler DynoStats dynoStats = getDynoStats(*this); 480a34c753fSRafael Auler OS << dynoStats; 481a34c753fSRafael Auler } 482a34c753fSRafael Auler 483a34c753fSRafael Auler OS << "\n}\n"; 484a34c753fSRafael Auler 485be9d3edeSMaksim Panchenko if (opts::PrintDynoStatsOnly || !BC.InstPrinter) 486a34c753fSRafael Auler return; 487a34c753fSRafael Auler 488a34c753fSRafael Auler // Offset of the instruction in function. 489a34c753fSRafael Auler uint64_t Offset = 0; 490a34c753fSRafael Auler 491a34c753fSRafael Auler if (BasicBlocks.empty() && !Instructions.empty()) { 492a34c753fSRafael Auler // Print before CFG was built. 493a34c753fSRafael Auler for (const std::pair<const uint32_t, MCInst> &II : Instructions) { 494a34c753fSRafael Auler Offset = II.first; 495a34c753fSRafael Auler 496a34c753fSRafael Auler // Print label if exists at this offset. 497a34c753fSRafael Auler auto LI = Labels.find(Offset); 498a34c753fSRafael Auler if (LI != Labels.end()) { 499a34c753fSRafael Auler if (const MCSymbol *EntrySymbol = 500a34c753fSRafael Auler getSecondaryEntryPointSymbol(LI->second)) 501a34c753fSRafael Auler OS << EntrySymbol->getName() << " (Entry Point):\n"; 502a34c753fSRafael Auler OS << LI->second->getName() << ":\n"; 503a34c753fSRafael Auler } 504a34c753fSRafael Auler 505a34c753fSRafael Auler BC.printInstruction(OS, II.second, Offset, this); 506a34c753fSRafael Auler } 507a34c753fSRafael Auler } 508a34c753fSRafael Auler 5098477bc67SFabian Parzefall StringRef SplitPointMsg = ""; 51007f63b0aSFabian Parzefall for (const FunctionFragment &FF : Layout.fragments()) { 5118477bc67SFabian Parzefall OS << SplitPointMsg; 5128477bc67SFabian Parzefall SplitPointMsg = "------- HOT-COLD SPLIT POINT -------\n\n"; 5130f8412c1SFabian Parzefall for (const BinaryBasicBlock *BB : FF) { 51440c2e0faSMaksim Panchenko OS << BB->getName() << " (" << BB->size() 51540c2e0faSMaksim Panchenko << " instructions, align : " << BB->getAlignment() << ")\n"; 516a34c753fSRafael Auler 517a34c753fSRafael Auler if (isEntryPoint(*BB)) { 518a34c753fSRafael Auler if (MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(*BB)) 519a34c753fSRafael Auler OS << " Secondary Entry Point: " << EntrySymbol->getName() << '\n'; 520a34c753fSRafael Auler else 521a34c753fSRafael Auler OS << " Entry Point\n"; 522a34c753fSRafael Auler } 523a34c753fSRafael Auler 524a34c753fSRafael Auler if (BB->isLandingPad()) 525a34c753fSRafael Auler OS << " Landing Pad\n"; 526a34c753fSRafael Auler 527a34c753fSRafael Auler uint64_t BBExecCount = BB->getExecutionCount(); 528a34c753fSRafael Auler if (hasValidProfile()) { 529a34c753fSRafael Auler OS << " Exec Count : "; 530a34c753fSRafael Auler if (BB->getExecutionCount() != BinaryBasicBlock::COUNT_NO_PROFILE) 531a34c753fSRafael Auler OS << BBExecCount << '\n'; 532a34c753fSRafael Auler else 533a34c753fSRafael Auler OS << "<unknown>\n"; 534a34c753fSRafael Auler } 5353652483cSRafael Auler if (BB->getCFIState() >= 0) 536a34c753fSRafael Auler OS << " CFI State : " << BB->getCFIState() << '\n'; 537a34c753fSRafael Auler if (opts::EnableBAT) { 538a34c753fSRafael Auler OS << " Input offset: " << Twine::utohexstr(BB->getInputOffset()) 539a34c753fSRafael Auler << "\n"; 540a34c753fSRafael Auler } 541a34c753fSRafael Auler if (!BB->pred_empty()) { 542a34c753fSRafael Auler OS << " Predecessors: "; 543f7581a39SAmir Ayupov ListSeparator LS; 544f7581a39SAmir Ayupov for (BinaryBasicBlock *Pred : BB->predecessors()) 545f7581a39SAmir Ayupov OS << LS << Pred->getName(); 546a34c753fSRafael Auler OS << '\n'; 547a34c753fSRafael Auler } 548a34c753fSRafael Auler if (!BB->throw_empty()) { 549a34c753fSRafael Auler OS << " Throwers: "; 550f7581a39SAmir Ayupov ListSeparator LS; 551f7581a39SAmir Ayupov for (BinaryBasicBlock *Throw : BB->throwers()) 552f7581a39SAmir Ayupov OS << LS << Throw->getName(); 553a34c753fSRafael Auler OS << '\n'; 554a34c753fSRafael Auler } 555a34c753fSRafael Auler 556a34c753fSRafael Auler Offset = alignTo(Offset, BB->getAlignment()); 557a34c753fSRafael Auler 5588477bc67SFabian Parzefall // Note: offsets are imprecise since this is happening prior to 5598477bc67SFabian Parzefall // relaxation. 560a34c753fSRafael Auler Offset = BC.printInstructions(OS, BB->begin(), BB->end(), Offset, this); 561a34c753fSRafael Auler 562a34c753fSRafael Auler if (!BB->succ_empty()) { 563a34c753fSRafael Auler OS << " Successors: "; 564a34c753fSRafael Auler // For more than 2 successors, sort them based on frequency. 565a34c753fSRafael Auler std::vector<uint64_t> Indices(BB->succ_size()); 566a34c753fSRafael Auler std::iota(Indices.begin(), Indices.end(), 0); 567a34c753fSRafael Auler if (BB->succ_size() > 2 && BB->getKnownExecutionCount()) { 568d2c87699SAmir Ayupov llvm::stable_sort(Indices, [&](const uint64_t A, const uint64_t B) { 569a34c753fSRafael Auler return BB->BranchInfo[B] < BB->BranchInfo[A]; 570a34c753fSRafael Auler }); 571a34c753fSRafael Auler } 572f7581a39SAmir Ayupov ListSeparator LS; 573a34c753fSRafael Auler for (unsigned I = 0; I < Indices.size(); ++I) { 574a34c753fSRafael Auler BinaryBasicBlock *Succ = BB->Successors[Indices[I]]; 5758477bc67SFabian Parzefall const BinaryBasicBlock::BinaryBranchInfo &BI = 5768477bc67SFabian Parzefall BB->BranchInfo[Indices[I]]; 577f7581a39SAmir Ayupov OS << LS << Succ->getName(); 578a34c753fSRafael Auler if (ExecutionCount != COUNT_NO_PROFILE && 579a34c753fSRafael Auler BI.MispredictedCount != BinaryBasicBlock::COUNT_INFERRED) { 580a34c753fSRafael Auler OS << " (mispreds: " << BI.MispredictedCount 581a34c753fSRafael Auler << ", count: " << BI.Count << ")"; 582a34c753fSRafael Auler } else if (ExecutionCount != COUNT_NO_PROFILE && 583a34c753fSRafael Auler BI.Count != BinaryBasicBlock::COUNT_NO_PROFILE) { 584a34c753fSRafael Auler OS << " (inferred count: " << BI.Count << ")"; 585a34c753fSRafael Auler } 586a34c753fSRafael Auler } 587a34c753fSRafael Auler OS << '\n'; 588a34c753fSRafael Auler } 589a34c753fSRafael Auler 590a34c753fSRafael Auler if (!BB->lp_empty()) { 591a34c753fSRafael Auler OS << " Landing Pads: "; 592f7581a39SAmir Ayupov ListSeparator LS; 593a34c753fSRafael Auler for (BinaryBasicBlock *LP : BB->landing_pads()) { 594f7581a39SAmir Ayupov OS << LS << LP->getName(); 595a34c753fSRafael Auler if (ExecutionCount != COUNT_NO_PROFILE) { 596a34c753fSRafael Auler OS << " (count: " << LP->getExecutionCount() << ")"; 597a34c753fSRafael Auler } 598a34c753fSRafael Auler } 599a34c753fSRafael Auler OS << '\n'; 600a34c753fSRafael Auler } 601a34c753fSRafael Auler 602a34c753fSRafael Auler // In CFG_Finalized state we can miscalculate CFI state at exit. 603a34c753fSRafael Auler if (CurrentState == State::CFG) { 604a34c753fSRafael Auler const int32_t CFIStateAtExit = BB->getCFIStateAtExit(); 605a34c753fSRafael Auler if (CFIStateAtExit >= 0) 606a34c753fSRafael Auler OS << " CFI State: " << CFIStateAtExit << '\n'; 607a34c753fSRafael Auler } 608a34c753fSRafael Auler 609a34c753fSRafael Auler OS << '\n'; 610a34c753fSRafael Auler } 6118477bc67SFabian Parzefall } 612a34c753fSRafael Auler 613a34c753fSRafael Auler // Dump new exception ranges for the function. 614a34c753fSRafael Auler if (!CallSites.empty()) { 615a34c753fSRafael Auler OS << "EH table:\n"; 6163ac46f37SFabian Parzefall for (const FunctionFragment &FF : getLayout().fragments()) { 6173ac46f37SFabian Parzefall for (const auto &FCSI : getCallSites(FF.getFragmentNum())) { 6183ac46f37SFabian Parzefall const CallSite &CSI = FCSI.second; 619a34c753fSRafael Auler OS << " [" << *CSI.Start << ", " << *CSI.End << ") landing pad : "; 620a34c753fSRafael Auler if (CSI.LP) 621a34c753fSRafael Auler OS << *CSI.LP; 622a34c753fSRafael Auler else 623a34c753fSRafael Auler OS << "0"; 624a34c753fSRafael Auler OS << ", action : " << CSI.Action << '\n'; 625a34c753fSRafael Auler } 6263ac46f37SFabian Parzefall } 627a34c753fSRafael Auler OS << '\n'; 628a34c753fSRafael Auler } 629a34c753fSRafael Auler 630a34c753fSRafael Auler // Print all jump tables. 6313652483cSRafael Auler for (const std::pair<const uint64_t, JumpTable *> &JTI : JumpTables) 632a34c753fSRafael Auler JTI.second->print(OS); 633a34c753fSRafael Auler 634a34c753fSRafael Auler OS << "DWARF CFI Instructions:\n"; 635a34c753fSRafael Auler if (OffsetToCFI.size()) { 636a34c753fSRafael Auler // Pre-buildCFG information 637a34c753fSRafael Auler for (const std::pair<const uint32_t, uint32_t> &Elmt : OffsetToCFI) { 638a34c753fSRafael Auler OS << format(" %08x:\t", Elmt.first); 639a34c753fSRafael Auler assert(Elmt.second < FrameInstructions.size() && "Incorrect CFI offset"); 640a34c753fSRafael Auler BinaryContext::printCFI(OS, FrameInstructions[Elmt.second]); 641a34c753fSRafael Auler OS << "\n"; 642a34c753fSRafael Auler } 643a34c753fSRafael Auler } else { 644a34c753fSRafael Auler // Post-buildCFG information 645a34c753fSRafael Auler for (uint32_t I = 0, E = FrameInstructions.size(); I != E; ++I) { 646a34c753fSRafael Auler const MCCFIInstruction &CFI = FrameInstructions[I]; 647a34c753fSRafael Auler OS << format(" %d:\t", I); 648a34c753fSRafael Auler BinaryContext::printCFI(OS, CFI); 649a34c753fSRafael Auler OS << "\n"; 650a34c753fSRafael Auler } 651a34c753fSRafael Auler } 652a34c753fSRafael Auler if (FrameInstructions.empty()) 653a34c753fSRafael Auler OS << " <empty>\n"; 654a34c753fSRafael Auler 655a34c753fSRafael Auler OS << "End of Function \"" << *this << "\"\n\n"; 656a34c753fSRafael Auler } 657a34c753fSRafael Auler 65840c2e0faSMaksim Panchenko void BinaryFunction::printRelocations(raw_ostream &OS, uint64_t Offset, 659a34c753fSRafael Auler uint64_t Size) const { 660a34c753fSRafael Auler const char *Sep = " # Relocs: "; 661a34c753fSRafael Auler 662a34c753fSRafael Auler auto RI = Relocations.lower_bound(Offset); 663a34c753fSRafael Auler while (RI != Relocations.end() && RI->first < Offset + Size) { 664a34c753fSRafael Auler OS << Sep << "(R: " << RI->second << ")"; 665a34c753fSRafael Auler Sep = ", "; 666a34c753fSRafael Auler ++RI; 667a34c753fSRafael Auler } 668a34c753fSRafael Auler } 669a34c753fSRafael Auler 670be2f67c4SAmir Ayupov static std::string mutateDWARFExpressionTargetReg(const MCCFIInstruction &Instr, 671a34c753fSRafael Auler MCPhysReg NewReg) { 672a34c753fSRafael Auler StringRef ExprBytes = Instr.getValues(); 673a34c753fSRafael Auler assert(ExprBytes.size() > 1 && "DWARF expression CFI is too short"); 674a34c753fSRafael Auler uint8_t Opcode = ExprBytes[0]; 675a34c753fSRafael Auler assert((Opcode == dwarf::DW_CFA_expression || 676a34c753fSRafael Auler Opcode == dwarf::DW_CFA_val_expression) && 677a34c753fSRafael Auler "invalid DWARF expression CFI"); 678139744acSAmir Ayupov (void)Opcode; 679a34c753fSRafael Auler const uint8_t *const Start = 680a34c753fSRafael Auler reinterpret_cast<const uint8_t *>(ExprBytes.drop_front(1).data()); 681a34c753fSRafael Auler const uint8_t *const End = 682a34c753fSRafael Auler reinterpret_cast<const uint8_t *>(Start + ExprBytes.size() - 1); 683a34c753fSRafael Auler unsigned Size = 0; 684a34c753fSRafael Auler decodeULEB128(Start, &Size, End); 685a34c753fSRafael Auler assert(Size > 0 && "Invalid reg encoding for DWARF expression CFI"); 686a34c753fSRafael Auler SmallString<8> Tmp; 687a34c753fSRafael Auler raw_svector_ostream OSE(Tmp); 688a34c753fSRafael Auler encodeULEB128(NewReg, OSE); 689a34c753fSRafael Auler return Twine(ExprBytes.slice(0, 1)) 690a34c753fSRafael Auler .concat(OSE.str()) 691a34c753fSRafael Auler .concat(ExprBytes.drop_front(1 + Size)) 692a34c753fSRafael Auler .str(); 693a34c753fSRafael Auler } 694a34c753fSRafael Auler 695a34c753fSRafael Auler void BinaryFunction::mutateCFIRegisterFor(const MCInst &Instr, 696a34c753fSRafael Auler MCPhysReg NewReg) { 697a34c753fSRafael Auler const MCCFIInstruction *OldCFI = getCFIFor(Instr); 698a34c753fSRafael Auler assert(OldCFI && "invalid CFI instr"); 699a34c753fSRafael Auler switch (OldCFI->getOperation()) { 700a34c753fSRafael Auler default: 701a34c753fSRafael Auler llvm_unreachable("Unexpected instruction"); 702a34c753fSRafael Auler case MCCFIInstruction::OpDefCfa: 703a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::cfiDefCfa(nullptr, NewReg, 704a34c753fSRafael Auler OldCFI->getOffset())); 705a34c753fSRafael Auler break; 706a34c753fSRafael Auler case MCCFIInstruction::OpDefCfaRegister: 707a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::createDefCfaRegister(nullptr, NewReg)); 708a34c753fSRafael Auler break; 709a34c753fSRafael Auler case MCCFIInstruction::OpOffset: 710a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::createOffset(nullptr, NewReg, 711a34c753fSRafael Auler OldCFI->getOffset())); 712a34c753fSRafael Auler break; 713a34c753fSRafael Auler case MCCFIInstruction::OpRegister: 714a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::createRegister(nullptr, NewReg, 715a34c753fSRafael Auler OldCFI->getRegister2())); 716a34c753fSRafael Auler break; 717a34c753fSRafael Auler case MCCFIInstruction::OpSameValue: 718a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::createSameValue(nullptr, NewReg)); 719a34c753fSRafael Auler break; 720a34c753fSRafael Auler case MCCFIInstruction::OpEscape: 721a34c753fSRafael Auler setCFIFor(Instr, 722a34c753fSRafael Auler MCCFIInstruction::createEscape( 723a34c753fSRafael Auler nullptr, 724a34c753fSRafael Auler StringRef(mutateDWARFExpressionTargetReg(*OldCFI, NewReg)))); 725a34c753fSRafael Auler break; 726a34c753fSRafael Auler case MCCFIInstruction::OpRestore: 727a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::createRestore(nullptr, NewReg)); 728a34c753fSRafael Auler break; 729a34c753fSRafael Auler case MCCFIInstruction::OpUndefined: 730a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::createUndefined(nullptr, NewReg)); 731a34c753fSRafael Auler break; 732a34c753fSRafael Auler } 733a34c753fSRafael Auler } 734a34c753fSRafael Auler 735a34c753fSRafael Auler const MCCFIInstruction *BinaryFunction::mutateCFIOffsetFor(const MCInst &Instr, 736a34c753fSRafael Auler int64_t NewOffset) { 737a34c753fSRafael Auler const MCCFIInstruction *OldCFI = getCFIFor(Instr); 738a34c753fSRafael Auler assert(OldCFI && "invalid CFI instr"); 739a34c753fSRafael Auler switch (OldCFI->getOperation()) { 740a34c753fSRafael Auler default: 741a34c753fSRafael Auler llvm_unreachable("Unexpected instruction"); 742a34c753fSRafael Auler case MCCFIInstruction::OpDefCfaOffset: 743a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::cfiDefCfaOffset(nullptr, NewOffset)); 744a34c753fSRafael Auler break; 745a34c753fSRafael Auler case MCCFIInstruction::OpAdjustCfaOffset: 746a34c753fSRafael Auler setCFIFor(Instr, 747a34c753fSRafael Auler MCCFIInstruction::createAdjustCfaOffset(nullptr, NewOffset)); 748a34c753fSRafael Auler break; 749a34c753fSRafael Auler case MCCFIInstruction::OpDefCfa: 750a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::cfiDefCfa(nullptr, OldCFI->getRegister(), 751a34c753fSRafael Auler NewOffset)); 752a34c753fSRafael Auler break; 753a34c753fSRafael Auler case MCCFIInstruction::OpOffset: 754a34c753fSRafael Auler setCFIFor(Instr, MCCFIInstruction::createOffset( 755a34c753fSRafael Auler nullptr, OldCFI->getRegister(), NewOffset)); 756a34c753fSRafael Auler break; 757a34c753fSRafael Auler } 758a34c753fSRafael Auler return getCFIFor(Instr); 759a34c753fSRafael Auler } 760a34c753fSRafael Auler 761a34c753fSRafael Auler IndirectBranchType 76240c2e0faSMaksim Panchenko BinaryFunction::processIndirectBranch(MCInst &Instruction, unsigned Size, 763a34c753fSRafael Auler uint64_t Offset, 764a34c753fSRafael Auler uint64_t &TargetAddress) { 765a34c753fSRafael Auler const unsigned PtrSize = BC.AsmInfo->getCodePointerSize(); 766a34c753fSRafael Auler 767a34c753fSRafael Auler // The instruction referencing memory used by the branch instruction. 768a34c753fSRafael Auler // It could be the branch instruction itself or one of the instructions 769a34c753fSRafael Auler // setting the value of the register used by the branch. 770a34c753fSRafael Auler MCInst *MemLocInstr; 771a34c753fSRafael Auler 772a34c753fSRafael Auler // Address of the table referenced by MemLocInstr. Could be either an 773a34c753fSRafael Auler // array of function pointers, or a jump table. 774a34c753fSRafael Auler uint64_t ArrayStart = 0; 775a34c753fSRafael Auler 776a34c753fSRafael Auler unsigned BaseRegNum, IndexRegNum; 777a34c753fSRafael Auler int64_t DispValue; 778a34c753fSRafael Auler const MCExpr *DispExpr; 779a34c753fSRafael Auler 780a34c753fSRafael Auler // In AArch, identify the instruction adding the PC-relative offset to 781a34c753fSRafael Auler // jump table entries to correctly decode it. 782a34c753fSRafael Auler MCInst *PCRelBaseInstr; 783a34c753fSRafael Auler uint64_t PCRelAddr = 0; 784a34c753fSRafael Auler 785a34c753fSRafael Auler auto Begin = Instructions.begin(); 786a34c753fSRafael Auler if (BC.isAArch64()) { 787a34c753fSRafael Auler PreserveNops = BC.HasRelocations; 788a34c753fSRafael Auler // Start at the last label as an approximation of the current basic block. 789a34c753fSRafael Auler // This is a heuristic, since the full set of labels have yet to be 790a34c753fSRafael Auler // determined 791f40d25ddSAmir Ayupov for (const uint32_t Offset : 792f40d25ddSAmir Ayupov llvm::make_first_range(llvm::reverse(Labels))) { 793f40d25ddSAmir Ayupov auto II = Instructions.find(Offset); 794a34c753fSRafael Auler if (II != Instructions.end()) { 795a34c753fSRafael Auler Begin = II; 796a34c753fSRafael Auler break; 797a34c753fSRafael Auler } 798a34c753fSRafael Auler } 799a34c753fSRafael Auler } 800a34c753fSRafael Auler 80140c2e0faSMaksim Panchenko IndirectBranchType BranchType = BC.MIB->analyzeIndirectBranch( 80240c2e0faSMaksim Panchenko Instruction, Begin, Instructions.end(), PtrSize, MemLocInstr, BaseRegNum, 80340c2e0faSMaksim Panchenko IndexRegNum, DispValue, DispExpr, PCRelBaseInstr); 804a34c753fSRafael Auler 805a34c753fSRafael Auler if (BranchType == IndirectBranchType::UNKNOWN && !MemLocInstr) 806a34c753fSRafael Auler return BranchType; 807a34c753fSRafael Auler 808a34c753fSRafael Auler if (MemLocInstr != &Instruction) 809a34c753fSRafael Auler IndexRegNum = BC.MIB->getNoRegister(); 810a34c753fSRafael Auler 811a34c753fSRafael Auler if (BC.isAArch64()) { 812a34c753fSRafael Auler const MCSymbol *Sym = BC.MIB->getTargetSymbol(*PCRelBaseInstr, 1); 813a34c753fSRafael Auler assert(Sym && "Symbol extraction failed"); 814a34c753fSRafael Auler ErrorOr<uint64_t> SymValueOrError = BC.getSymbolValue(*Sym); 815a34c753fSRafael Auler if (SymValueOrError) { 816a34c753fSRafael Auler PCRelAddr = *SymValueOrError; 817a34c753fSRafael Auler } else { 818a34c753fSRafael Auler for (std::pair<const uint32_t, MCSymbol *> &Elmt : Labels) { 819a34c753fSRafael Auler if (Elmt.second == Sym) { 820a34c753fSRafael Auler PCRelAddr = Elmt.first + getAddress(); 821a34c753fSRafael Auler break; 822a34c753fSRafael Auler } 823a34c753fSRafael Auler } 824a34c753fSRafael Auler } 825a34c753fSRafael Auler uint64_t InstrAddr = 0; 826a34c753fSRafael Auler for (auto II = Instructions.rbegin(); II != Instructions.rend(); ++II) { 827a34c753fSRafael Auler if (&II->second == PCRelBaseInstr) { 828a34c753fSRafael Auler InstrAddr = II->first + getAddress(); 829a34c753fSRafael Auler break; 830a34c753fSRafael Auler } 831a34c753fSRafael Auler } 832a34c753fSRafael Auler assert(InstrAddr != 0 && "instruction not found"); 833a34c753fSRafael Auler // We do this to avoid spurious references to code locations outside this 834a34c753fSRafael Auler // function (for example, if the indirect jump lives in the last basic 835a34c753fSRafael Auler // block of the function, it will create a reference to the next function). 836a34c753fSRafael Auler // This replaces a symbol reference with an immediate. 837a34c753fSRafael Auler BC.MIB->replaceMemOperandDisp(*PCRelBaseInstr, 838a34c753fSRafael Auler MCOperand::createImm(PCRelAddr - InstrAddr)); 839a34c753fSRafael Auler // FIXME: Disable full jump table processing for AArch64 until we have a 840a34c753fSRafael Auler // proper way of determining the jump table limits. 841a34c753fSRafael Auler return IndirectBranchType::UNKNOWN; 842a34c753fSRafael Auler } 843a34c753fSRafael Auler 844a34c753fSRafael Auler // RIP-relative addressing should be converted to symbol form by now 845a34c753fSRafael Auler // in processed instructions (but not in jump). 846a34c753fSRafael Auler if (DispExpr) { 847a34c753fSRafael Auler const MCSymbol *TargetSym; 848a34c753fSRafael Auler uint64_t TargetOffset; 849a34c753fSRafael Auler std::tie(TargetSym, TargetOffset) = BC.MIB->getTargetSymbolInfo(DispExpr); 850a34c753fSRafael Auler ErrorOr<uint64_t> SymValueOrError = BC.getSymbolValue(*TargetSym); 851a34c753fSRafael Auler assert(SymValueOrError && "global symbol needs a value"); 852a34c753fSRafael Auler ArrayStart = *SymValueOrError + TargetOffset; 853a34c753fSRafael Auler BaseRegNum = BC.MIB->getNoRegister(); 854a34c753fSRafael Auler if (BC.isAArch64()) { 855a34c753fSRafael Auler ArrayStart &= ~0xFFFULL; 856a34c753fSRafael Auler ArrayStart += DispValue & 0xFFFULL; 857a34c753fSRafael Auler } 858a34c753fSRafael Auler } else { 859a34c753fSRafael Auler ArrayStart = static_cast<uint64_t>(DispValue); 860a34c753fSRafael Auler } 861a34c753fSRafael Auler 862a34c753fSRafael Auler if (BaseRegNum == BC.MRI->getProgramCounter()) 863a34c753fSRafael Auler ArrayStart += getAddress() + Offset + Size; 864a34c753fSRafael Auler 865a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: addressed memory is 0x" 866a34c753fSRafael Auler << Twine::utohexstr(ArrayStart) << '\n'); 867a34c753fSRafael Auler 868a34c753fSRafael Auler ErrorOr<BinarySection &> Section = BC.getSectionForAddress(ArrayStart); 869a34c753fSRafael Auler if (!Section) { 870a34c753fSRafael Auler // No section - possibly an absolute address. Since we don't allow 871a34c753fSRafael Auler // internal function addresses to escape the function scope - we 872a34c753fSRafael Auler // consider it a tail call. 873a34c753fSRafael Auler if (opts::Verbosity >= 1) { 874a34c753fSRafael Auler errs() << "BOLT-WARNING: no section for address 0x" 875a34c753fSRafael Auler << Twine::utohexstr(ArrayStart) << " referenced from function " 876a34c753fSRafael Auler << *this << '\n'; 877a34c753fSRafael Auler } 878a34c753fSRafael Auler return IndirectBranchType::POSSIBLE_TAIL_CALL; 879a34c753fSRafael Auler } 880a34c753fSRafael Auler if (Section->isVirtual()) { 881a34c753fSRafael Auler // The contents are filled at runtime. 882a34c753fSRafael Auler return IndirectBranchType::POSSIBLE_TAIL_CALL; 883a34c753fSRafael Auler } 884a34c753fSRafael Auler 885a34c753fSRafael Auler if (BranchType == IndirectBranchType::POSSIBLE_FIXED_BRANCH) { 886a34c753fSRafael Auler ErrorOr<uint64_t> Value = BC.getPointerAtAddress(ArrayStart); 887a34c753fSRafael Auler if (!Value) 888a34c753fSRafael Auler return IndirectBranchType::UNKNOWN; 889a34c753fSRafael Auler 89069a9bbf1SAmir Ayupov if (BC.getSectionForAddress(ArrayStart)->isWritable()) 891a34c753fSRafael Auler return IndirectBranchType::UNKNOWN; 892a34c753fSRafael Auler 893a34c753fSRafael Auler outs() << "BOLT-INFO: fixed indirect branch detected in " << *this 894a34c753fSRafael Auler << " at 0x" << Twine::utohexstr(getAddress() + Offset) 895a34c753fSRafael Auler << " referencing data at 0x" << Twine::utohexstr(ArrayStart) 896a34c753fSRafael Auler << " the destination value is 0x" << Twine::utohexstr(*Value) 897a34c753fSRafael Auler << '\n'; 898a34c753fSRafael Auler 899a34c753fSRafael Auler TargetAddress = *Value; 900a34c753fSRafael Auler return BranchType; 901a34c753fSRafael Auler } 902a34c753fSRafael Auler 903a34c753fSRafael Auler // Check if there's already a jump table registered at this address. 904a34c753fSRafael Auler MemoryContentsType MemType; 905a34c753fSRafael Auler if (JumpTable *JT = BC.getJumpTableContainingAddress(ArrayStart)) { 906a34c753fSRafael Auler switch (JT->Type) { 907a34c753fSRafael Auler case JumpTable::JTT_NORMAL: 908a34c753fSRafael Auler MemType = MemoryContentsType::POSSIBLE_JUMP_TABLE; 909a34c753fSRafael Auler break; 910a34c753fSRafael Auler case JumpTable::JTT_PIC: 911a34c753fSRafael Auler MemType = MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE; 912a34c753fSRafael Auler break; 913a34c753fSRafael Auler } 914a34c753fSRafael Auler } else { 915a34c753fSRafael Auler MemType = BC.analyzeMemoryAt(ArrayStart, *this); 916a34c753fSRafael Auler } 917a34c753fSRafael Auler 918a34c753fSRafael Auler // Check that jump table type in instruction pattern matches memory contents. 919a34c753fSRafael Auler JumpTable::JumpTableType JTType; 920a34c753fSRafael Auler if (BranchType == IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE) { 921a34c753fSRafael Auler if (MemType != MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE) 922a34c753fSRafael Auler return IndirectBranchType::UNKNOWN; 923a34c753fSRafael Auler JTType = JumpTable::JTT_PIC; 924a34c753fSRafael Auler } else { 925a34c753fSRafael Auler if (MemType == MemoryContentsType::POSSIBLE_PIC_JUMP_TABLE) 926a34c753fSRafael Auler return IndirectBranchType::UNKNOWN; 927a34c753fSRafael Auler 928a34c753fSRafael Auler if (MemType == MemoryContentsType::UNKNOWN) 929a34c753fSRafael Auler return IndirectBranchType::POSSIBLE_TAIL_CALL; 930a34c753fSRafael Auler 931a34c753fSRafael Auler BranchType = IndirectBranchType::POSSIBLE_JUMP_TABLE; 932a34c753fSRafael Auler JTType = JumpTable::JTT_NORMAL; 933a34c753fSRafael Auler } 934a34c753fSRafael Auler 935a34c753fSRafael Auler // Convert the instruction into jump table branch. 936a34c753fSRafael Auler const MCSymbol *JTLabel = BC.getOrCreateJumpTable(*this, ArrayStart, JTType); 937a34c753fSRafael Auler BC.MIB->replaceMemOperandDisp(*MemLocInstr, JTLabel, BC.Ctx.get()); 938a34c753fSRafael Auler BC.MIB->setJumpTable(Instruction, ArrayStart, IndexRegNum); 939a34c753fSRafael Auler 940a34c753fSRafael Auler JTSites.emplace_back(Offset, ArrayStart); 941a34c753fSRafael Auler 942a34c753fSRafael Auler return BranchType; 943a34c753fSRafael Auler } 944a34c753fSRafael Auler 945a34c753fSRafael Auler MCSymbol *BinaryFunction::getOrCreateLocalLabel(uint64_t Address, 946a34c753fSRafael Auler bool CreatePastEnd) { 947a34c753fSRafael Auler const uint64_t Offset = Address - getAddress(); 948a34c753fSRafael Auler 949a34c753fSRafael Auler if ((Offset == getSize()) && CreatePastEnd) 950a34c753fSRafael Auler return getFunctionEndLabel(); 951a34c753fSRafael Auler 952a34c753fSRafael Auler auto LI = Labels.find(Offset); 953a34c753fSRafael Auler if (LI != Labels.end()) 954a34c753fSRafael Auler return LI->second; 955a34c753fSRafael Auler 956a34c753fSRafael Auler // For AArch64, check if this address is part of a constant island. 957a34c753fSRafael Auler if (BC.isAArch64()) { 9583652483cSRafael Auler if (MCSymbol *IslandSym = getOrCreateIslandAccess(Address)) 959a34c753fSRafael Auler return IslandSym; 960a34c753fSRafael Auler } 961a34c753fSRafael Auler 962a34c753fSRafael Auler MCSymbol *Label = BC.Ctx->createNamedTempSymbol(); 963a34c753fSRafael Auler Labels[Offset] = Label; 964a34c753fSRafael Auler 965a34c753fSRafael Auler return Label; 966a34c753fSRafael Auler } 967a34c753fSRafael Auler 968a34c753fSRafael Auler ErrorOr<ArrayRef<uint8_t>> BinaryFunction::getData() const { 969a34c753fSRafael Auler BinarySection &Section = *getOriginSection(); 970a34c753fSRafael Auler assert(Section.containsRange(getAddress(), getMaxSize()) && 971a34c753fSRafael Auler "wrong section for function"); 972a34c753fSRafael Auler 9733652483cSRafael Auler if (!Section.isText() || Section.isVirtual() || !Section.getSize()) 974a34c753fSRafael Auler return std::make_error_code(std::errc::bad_address); 975a34c753fSRafael Auler 976a34c753fSRafael Auler StringRef SectionContents = Section.getContents(); 977a34c753fSRafael Auler 978a34c753fSRafael Auler assert(SectionContents.size() == Section.getSize() && 979a34c753fSRafael Auler "section size mismatch"); 980a34c753fSRafael Auler 981a34c753fSRafael Auler // Function offset from the section start. 982a34c753fSRafael Auler uint64_t Offset = getAddress() - Section.getAddress(); 983a34c753fSRafael Auler auto *Bytes = reinterpret_cast<const uint8_t *>(SectionContents.data()); 984a34c753fSRafael Auler return ArrayRef<uint8_t>(Bytes + Offset, getMaxSize()); 985a34c753fSRafael Auler } 986a34c753fSRafael Auler 987a34c753fSRafael Auler size_t BinaryFunction::getSizeOfDataInCodeAt(uint64_t Offset) const { 988a34c753fSRafael Auler if (!Islands) 989a34c753fSRafael Auler return 0; 990a34c753fSRafael Auler 9912eae9d8eSAmir Ayupov if (!llvm::is_contained(Islands->DataOffsets, Offset)) 992a34c753fSRafael Auler return 0; 993a34c753fSRafael Auler 994a34c753fSRafael Auler auto Iter = Islands->CodeOffsets.upper_bound(Offset); 9953652483cSRafael Auler if (Iter != Islands->CodeOffsets.end()) 996a34c753fSRafael Auler return *Iter - Offset; 997a34c753fSRafael Auler return getSize() - Offset; 998a34c753fSRafael Auler } 999a34c753fSRafael Auler 1000a34c753fSRafael Auler bool BinaryFunction::isZeroPaddingAt(uint64_t Offset) const { 1001a34c753fSRafael Auler ArrayRef<uint8_t> FunctionData = *getData(); 1002a34c753fSRafael Auler uint64_t EndOfCode = getSize(); 1003a34c753fSRafael Auler if (Islands) { 1004a34c753fSRafael Auler auto Iter = Islands->DataOffsets.upper_bound(Offset); 1005a34c753fSRafael Auler if (Iter != Islands->DataOffsets.end()) 1006a34c753fSRafael Auler EndOfCode = *Iter; 1007a34c753fSRafael Auler } 10083652483cSRafael Auler for (uint64_t I = Offset; I < EndOfCode; ++I) 10093652483cSRafael Auler if (FunctionData[I] != 0) 1010a34c753fSRafael Auler return false; 1011a34c753fSRafael Auler 1012a34c753fSRafael Auler return true; 1013a34c753fSRafael Auler } 1014a34c753fSRafael Auler 10156cd475f8SAmir Ayupov void BinaryFunction::handlePCRelOperand(MCInst &Instruction, uint64_t Address, 101640c2e0faSMaksim Panchenko uint64_t Size) { 10176cd475f8SAmir Ayupov auto &MIB = BC.MIB; 1018a34c753fSRafael Auler uint64_t TargetAddress = 0; 1019a34c753fSRafael Auler if (!MIB->evaluateMemOperandTarget(Instruction, TargetAddress, Address, 1020a34c753fSRafael Auler Size)) { 1021a34c753fSRafael Auler errs() << "BOLT-ERROR: PC-relative operand can't be evaluated:\n"; 1022a34c753fSRafael Auler BC.InstPrinter->printInst(&Instruction, 0, "", *BC.STI, errs()); 1023a34c753fSRafael Auler errs() << '\n'; 1024a34c753fSRafael Auler Instruction.dump_pretty(errs(), BC.InstPrinter.get()); 1025a34c753fSRafael Auler errs() << '\n'; 1026a34c753fSRafael Auler errs() << "BOLT-ERROR: cannot handle PC-relative operand at 0x" 1027a34c753fSRafael Auler << Twine::utohexstr(Address) << ". Skipping function " << *this 1028a34c753fSRafael Auler << ".\n"; 1029a34c753fSRafael Auler if (BC.HasRelocations) 1030a34c753fSRafael Auler exit(1); 1031a34c753fSRafael Auler IsSimple = false; 1032a34c753fSRafael Auler return; 1033a34c753fSRafael Auler } 1034a34c753fSRafael Auler if (TargetAddress == 0 && opts::Verbosity >= 1) { 1035a34c753fSRafael Auler outs() << "BOLT-INFO: PC-relative operand is zero in function " << *this 1036a34c753fSRafael Auler << '\n'; 1037a34c753fSRafael Auler } 1038a34c753fSRafael Auler 1039a34c753fSRafael Auler const MCSymbol *TargetSymbol; 1040a34c753fSRafael Auler uint64_t TargetOffset; 1041a34c753fSRafael Auler std::tie(TargetSymbol, TargetOffset) = 1042a34c753fSRafael Auler BC.handleAddressRef(TargetAddress, *this, /*IsPCRel*/ true); 10438d1fc45dSRafael Auler 10448d1fc45dSRafael Auler bool ReplaceSuccess = MIB->replaceMemOperandDisp( 10458d1fc45dSRafael Auler Instruction, TargetSymbol, static_cast<int64_t>(TargetOffset), &*BC.Ctx); 10468d1fc45dSRafael Auler (void)ReplaceSuccess; 10478d1fc45dSRafael Auler assert(ReplaceSuccess && "Failed to replace mem operand with symbol+off."); 10486cd475f8SAmir Ayupov } 10496cd475f8SAmir Ayupov 1050ec1fbf22SAmir Ayupov MCSymbol *BinaryFunction::handleExternalReference(MCInst &Instruction, 1051ec1fbf22SAmir Ayupov uint64_t Size, 1052ec1fbf22SAmir Ayupov uint64_t Offset, 1053ec1fbf22SAmir Ayupov uint64_t TargetAddress, 1054ec1fbf22SAmir Ayupov bool &IsCall) { 10556cd475f8SAmir Ayupov auto &MIB = BC.MIB; 10566cd475f8SAmir Ayupov 1057a34c753fSRafael Auler const uint64_t AbsoluteInstrAddr = getAddress() + Offset; 105835efe1d8SVladislav Khmelevsky BC.addInterproceduralReference(this, TargetAddress); 1059a34c753fSRafael Auler if (opts::Verbosity >= 2 && !IsCall && Size == 2 && !BC.HasRelocations) { 1060a34c753fSRafael Auler errs() << "BOLT-WARNING: relaxed tail call detected at 0x" 1061a34c753fSRafael Auler << Twine::utohexstr(AbsoluteInstrAddr) << " in function " << *this 1062a34c753fSRafael Auler << ". Code size will be increased.\n"; 1063a34c753fSRafael Auler } 1064a34c753fSRafael Auler 1065a34c753fSRafael Auler assert(!MIB->isTailCall(Instruction) && 1066a34c753fSRafael Auler "synthetic tail call instruction found"); 1067a34c753fSRafael Auler 1068a34c753fSRafael Auler // This is a call regardless of the opcode. 1069a34c753fSRafael Auler // Assign proper opcode for tail calls, so that they could be 1070a34c753fSRafael Auler // treated as calls. 1071a34c753fSRafael Auler if (!IsCall) { 1072a34c753fSRafael Auler if (!MIB->convertJmpToTailCall(Instruction)) { 1073139744acSAmir Ayupov assert(MIB->isConditionalBranch(Instruction) && 1074139744acSAmir Ayupov "unknown tail call instruction"); 1075a34c753fSRafael Auler if (opts::Verbosity >= 2) { 1076a34c753fSRafael Auler errs() << "BOLT-WARNING: conditional tail call detected in " 1077a34c753fSRafael Auler << "function " << *this << " at 0x" 1078a34c753fSRafael Auler << Twine::utohexstr(AbsoluteInstrAddr) << ".\n"; 1079a34c753fSRafael Auler } 1080a34c753fSRafael Auler } 1081a34c753fSRafael Auler IsCall = true; 1082a34c753fSRafael Auler } 1083a34c753fSRafael Auler 1084a34c753fSRafael Auler if (opts::Verbosity >= 2 && TargetAddress == 0) { 1085a34c753fSRafael Auler // We actually see calls to address 0 in presence of weak 1086a34c753fSRafael Auler // symbols originating from libraries. This code is never meant 1087a34c753fSRafael Auler // to be executed. 1088a34c753fSRafael Auler outs() << "BOLT-INFO: Function " << *this 1089a34c753fSRafael Auler << " has a call to address zero.\n"; 1090a34c753fSRafael Auler } 1091a34c753fSRafael Auler 1092ec1fbf22SAmir Ayupov return BC.getOrCreateGlobalSymbol(TargetAddress, "FUNCat"); 1093ec1fbf22SAmir Ayupov } 1094ec1fbf22SAmir Ayupov 1095c844850bSAmir Ayupov void BinaryFunction::handleIndirectBranch(MCInst &Instruction, uint64_t Size, 1096a34c753fSRafael Auler uint64_t Offset) { 1097c844850bSAmir Ayupov auto &MIB = BC.MIB; 1098a34c753fSRafael Auler uint64_t IndirectTarget = 0; 1099a34c753fSRafael Auler IndirectBranchType Result = 1100a34c753fSRafael Auler processIndirectBranch(Instruction, Size, Offset, IndirectTarget); 1101a34c753fSRafael Auler switch (Result) { 1102a34c753fSRafael Auler default: 1103a34c753fSRafael Auler llvm_unreachable("unexpected result"); 1104a34c753fSRafael Auler case IndirectBranchType::POSSIBLE_TAIL_CALL: { 1105a34c753fSRafael Auler bool Result = MIB->convertJmpToTailCall(Instruction); 1106a34c753fSRafael Auler (void)Result; 1107a34c753fSRafael Auler assert(Result); 1108a34c753fSRafael Auler break; 1109a34c753fSRafael Auler } 1110a34c753fSRafael Auler case IndirectBranchType::POSSIBLE_JUMP_TABLE: 1111a34c753fSRafael Auler case IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE: 1112a34c753fSRafael Auler if (opts::JumpTables == JTS_NONE) 1113a34c753fSRafael Auler IsSimple = false; 1114a34c753fSRafael Auler break; 1115a34c753fSRafael Auler case IndirectBranchType::POSSIBLE_FIXED_BRANCH: { 1116a34c753fSRafael Auler if (containsAddress(IndirectTarget)) { 1117a34c753fSRafael Auler const MCSymbol *TargetSymbol = getOrCreateLocalLabel(IndirectTarget); 1118a34c753fSRafael Auler Instruction.clear(); 1119a34c753fSRafael Auler MIB->createUncondBranch(Instruction, TargetSymbol, BC.Ctx.get()); 1120a34c753fSRafael Auler TakenBranches.emplace_back(Offset, IndirectTarget - getAddress()); 1121a34c753fSRafael Auler HasFixedIndirectBranch = true; 1122a34c753fSRafael Auler } else { 1123a34c753fSRafael Auler MIB->convertJmpToTailCall(Instruction); 112435efe1d8SVladislav Khmelevsky BC.addInterproceduralReference(this, IndirectTarget); 1125a34c753fSRafael Auler } 1126a34c753fSRafael Auler break; 1127a34c753fSRafael Auler } 1128a34c753fSRafael Auler case IndirectBranchType::UNKNOWN: 1129a34c753fSRafael Auler // Keep processing. We'll do more checks and fixes in 1130a34c753fSRafael Auler // postProcessIndirectBranches(). 1131a34c753fSRafael Auler UnknownIndirectBranchOffsets.emplace(Offset); 1132a34c753fSRafael Auler break; 1133a34c753fSRafael Auler } 1134c844850bSAmir Ayupov } 1135c844850bSAmir Ayupov 113637cbbea6SAmir Ayupov void BinaryFunction::handleAArch64IndirectCall(MCInst &Instruction, 113737cbbea6SAmir Ayupov const uint64_t Offset) { 1138c844850bSAmir Ayupov auto &MIB = BC.MIB; 1139a34c753fSRafael Auler const uint64_t AbsoluteInstrAddr = getAddress() + Offset; 1140a34c753fSRafael Auler MCInst *TargetHiBits, *TargetLowBits; 114135efe1d8SVladislav Khmelevsky uint64_t TargetAddress, Count; 114235efe1d8SVladislav Khmelevsky Count = MIB->matchLinkerVeneer(Instructions.begin(), Instructions.end(), 1143a34c753fSRafael Auler AbsoluteInstrAddr, Instruction, TargetHiBits, 114435efe1d8SVladislav Khmelevsky TargetLowBits, TargetAddress); 114535efe1d8SVladislav Khmelevsky if (Count) { 1146a34c753fSRafael Auler MIB->addAnnotation(Instruction, "AArch64Veneer", true); 114735efe1d8SVladislav Khmelevsky --Count; 114835efe1d8SVladislav Khmelevsky for (auto It = std::prev(Instructions.end()); Count != 0; 114935efe1d8SVladislav Khmelevsky It = std::prev(It), --Count) { 1150a34c753fSRafael Auler MIB->addAnnotation(It->second, "AArch64Veneer", true); 1151a34c753fSRafael Auler } 1152a34c753fSRafael Auler 115335efe1d8SVladislav Khmelevsky BC.addAdrpAddRelocAArch64(*this, *TargetLowBits, *TargetHiBits, 115435efe1d8SVladislav Khmelevsky TargetAddress); 1155a34c753fSRafael Auler } 115637cbbea6SAmir Ayupov } 115737cbbea6SAmir Ayupov 115837cbbea6SAmir Ayupov bool BinaryFunction::disassemble() { 115937cbbea6SAmir Ayupov NamedRegionTimer T("disassemble", "Disassemble function", "buildfuncs", 116037cbbea6SAmir Ayupov "Build Binary Functions", opts::TimeBuild); 116137cbbea6SAmir Ayupov ErrorOr<ArrayRef<uint8_t>> ErrorOrFunctionData = getData(); 116237cbbea6SAmir Ayupov assert(ErrorOrFunctionData && "function data is not available"); 116337cbbea6SAmir Ayupov ArrayRef<uint8_t> FunctionData = *ErrorOrFunctionData; 116437cbbea6SAmir Ayupov assert(FunctionData.size() == getMaxSize() && 116537cbbea6SAmir Ayupov "function size does not match raw data size"); 116637cbbea6SAmir Ayupov 116737cbbea6SAmir Ayupov auto &Ctx = BC.Ctx; 116837cbbea6SAmir Ayupov auto &MIB = BC.MIB; 116937cbbea6SAmir Ayupov 117037cbbea6SAmir Ayupov BC.SymbolicDisAsm->setSymbolizer(MIB->createTargetSymbolizer(*this)); 117137cbbea6SAmir Ayupov 117237cbbea6SAmir Ayupov // Insert a label at the beginning of the function. This will be our first 117337cbbea6SAmir Ayupov // basic block. 117437cbbea6SAmir Ayupov Labels[0] = Ctx->createNamedTempSymbol("BB0"); 1175a34c753fSRafael Auler 1176a34c753fSRafael Auler uint64_t Size = 0; // instruction size 1177a34c753fSRafael Auler for (uint64_t Offset = 0; Offset < getSize(); Offset += Size) { 1178a34c753fSRafael Auler MCInst Instruction; 1179a34c753fSRafael Auler const uint64_t AbsoluteInstrAddr = getAddress() + Offset; 1180a34c753fSRafael Auler 1181a34c753fSRafael Auler // Check for data inside code and ignore it 1182a34c753fSRafael Auler if (const size_t DataInCodeSize = getSizeOfDataInCodeAt(Offset)) { 1183a34c753fSRafael Auler Size = DataInCodeSize; 1184a34c753fSRafael Auler continue; 1185a34c753fSRafael Auler } 1186a34c753fSRafael Auler 1187e290133cSMaksim Panchenko if (!BC.SymbolicDisAsm->getInstruction(Instruction, Size, 1188a34c753fSRafael Auler FunctionData.slice(Offset), 118940c2e0faSMaksim Panchenko AbsoluteInstrAddr, nulls())) { 1190a34c753fSRafael Auler // Functions with "soft" boundaries, e.g. coming from assembly source, 1191a34c753fSRafael Auler // can have 0-byte padding at the end. 1192a34c753fSRafael Auler if (isZeroPaddingAt(Offset)) 1193a34c753fSRafael Auler break; 1194a34c753fSRafael Auler 1195a34c753fSRafael Auler errs() << "BOLT-WARNING: unable to disassemble instruction at offset 0x" 1196a34c753fSRafael Auler << Twine::utohexstr(Offset) << " (address 0x" 119740c2e0faSMaksim Panchenko << Twine::utohexstr(AbsoluteInstrAddr) << ") in function " << *this 119840c2e0faSMaksim Panchenko << '\n'; 1199a34c753fSRafael Auler // Some AVX-512 instructions could not be disassembled at all. 1200a34c753fSRafael Auler if (BC.HasRelocations && opts::TrapOnAVX512 && BC.isX86()) { 1201a34c753fSRafael Auler setTrapOnEntry(); 1202a34c753fSRafael Auler BC.TrappedFunctions.push_back(this); 1203a34c753fSRafael Auler } else { 1204a34c753fSRafael Auler setIgnored(); 1205a34c753fSRafael Auler } 1206a34c753fSRafael Auler 1207a34c753fSRafael Auler break; 1208a34c753fSRafael Auler } 1209a34c753fSRafael Auler 1210a34c753fSRafael Auler // Check integrity of LLVM assembler/disassembler. 1211a34c753fSRafael Auler if (opts::CheckEncoding && !BC.MIB->isBranch(Instruction) && 1212a34c753fSRafael Auler !BC.MIB->isCall(Instruction) && !BC.MIB->isNoop(Instruction)) { 1213bcc4c909SMaksim Panchenko if (!BC.validateInstructionEncoding(FunctionData.slice(Offset, Size))) { 1214a34c753fSRafael Auler errs() << "BOLT-WARNING: mismatching LLVM encoding detected in " 1215a34c753fSRafael Auler << "function " << *this << " for instruction :\n"; 1216a34c753fSRafael Auler BC.printInstruction(errs(), Instruction, AbsoluteInstrAddr); 1217a34c753fSRafael Auler errs() << '\n'; 1218a34c753fSRafael Auler } 1219a34c753fSRafael Auler } 1220a34c753fSRafael Auler 1221a34c753fSRafael Auler // Special handling for AVX-512 instructions. 1222a34c753fSRafael Auler if (MIB->hasEVEXEncoding(Instruction)) { 1223a34c753fSRafael Auler if (BC.HasRelocations && opts::TrapOnAVX512) { 1224a34c753fSRafael Auler setTrapOnEntry(); 1225a34c753fSRafael Auler BC.TrappedFunctions.push_back(this); 1226a34c753fSRafael Auler break; 1227a34c753fSRafael Auler } 1228a34c753fSRafael Auler 1229bcc4c909SMaksim Panchenko if (!BC.validateInstructionEncoding(FunctionData.slice(Offset, Size))) { 1230a34c753fSRafael Auler errs() << "BOLT-WARNING: internal assembler/disassembler error " 1231a34c753fSRafael Auler "detected for AVX512 instruction:\n"; 1232bcc4c909SMaksim Panchenko BC.printInstruction(errs(), Instruction, AbsoluteInstrAddr); 1233a34c753fSRafael Auler errs() << " in function " << *this << '\n'; 1234a34c753fSRafael Auler setIgnored(); 1235a34c753fSRafael Auler break; 1236a34c753fSRafael Auler } 1237a34c753fSRafael Auler } 1238a34c753fSRafael Auler 1239a34c753fSRafael Auler if (MIB->isBranch(Instruction) || MIB->isCall(Instruction)) { 1240a34c753fSRafael Auler uint64_t TargetAddress = 0; 1241a34c753fSRafael Auler if (MIB->evaluateBranch(Instruction, AbsoluteInstrAddr, Size, 1242a34c753fSRafael Auler TargetAddress)) { 1243a34c753fSRafael Auler // Check if the target is within the same function. Otherwise it's 1244a34c753fSRafael Auler // a call, possibly a tail call. 1245a34c753fSRafael Auler // 1246a34c753fSRafael Auler // If the target *is* the function address it could be either a branch 1247a34c753fSRafael Auler // or a recursive call. 1248a34c753fSRafael Auler bool IsCall = MIB->isCall(Instruction); 1249a34c753fSRafael Auler const bool IsCondBranch = MIB->isConditionalBranch(Instruction); 1250a34c753fSRafael Auler MCSymbol *TargetSymbol = nullptr; 1251a34c753fSRafael Auler 12525c4d306aSMaksim Panchenko if (BC.MIB->isUnsupportedBranch(Instruction)) { 1253a34c753fSRafael Auler setIgnored(); 1254a34c753fSRafael Auler if (BinaryFunction *TargetFunc = 1255a34c753fSRafael Auler BC.getBinaryFunctionContainingAddress(TargetAddress)) 1256a34c753fSRafael Auler TargetFunc->setIgnored(); 1257a34c753fSRafael Auler } 1258a34c753fSRafael Auler 1259a34c753fSRafael Auler if (IsCall && containsAddress(TargetAddress)) { 1260a34c753fSRafael Auler if (TargetAddress == getAddress()) { 1261a34c753fSRafael Auler // Recursive call. 1262a34c753fSRafael Auler TargetSymbol = getSymbol(); 1263a34c753fSRafael Auler } else { 1264a34c753fSRafael Auler if (BC.isX86()) { 1265a34c753fSRafael Auler // Dangerous old-style x86 PIC code. We may need to freeze this 1266a34c753fSRafael Auler // function, so preserve the function as is for now. 1267a34c753fSRafael Auler PreserveNops = true; 1268a34c753fSRafael Auler } else { 1269a34c753fSRafael Auler errs() << "BOLT-WARNING: internal call detected at 0x" 1270a34c753fSRafael Auler << Twine::utohexstr(AbsoluteInstrAddr) << " in function " 1271a34c753fSRafael Auler << *this << ". Skipping.\n"; 1272a34c753fSRafael Auler IsSimple = false; 1273a34c753fSRafael Auler } 1274a34c753fSRafael Auler } 1275a34c753fSRafael Auler } 1276a34c753fSRafael Auler 1277a34c753fSRafael Auler if (!TargetSymbol) { 1278a34c753fSRafael Auler // Create either local label or external symbol. 1279a34c753fSRafael Auler if (containsAddress(TargetAddress)) { 1280a34c753fSRafael Auler TargetSymbol = getOrCreateLocalLabel(TargetAddress); 1281a34c753fSRafael Auler } else { 1282a34c753fSRafael Auler if (TargetAddress == getAddress() + getSize() && 128335efe1d8SVladislav Khmelevsky TargetAddress < getAddress() + getMaxSize() && 128435efe1d8SVladislav Khmelevsky !(BC.isAArch64() && 128535efe1d8SVladislav Khmelevsky BC.handleAArch64Veneer(TargetAddress, /*MatchOnly*/ true))) { 1286a34c753fSRafael Auler // Result of __builtin_unreachable(). 1287a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: jump past end detected at 0x" 1288a34c753fSRafael Auler << Twine::utohexstr(AbsoluteInstrAddr) 1289a34c753fSRafael Auler << " in function " << *this 1290a34c753fSRafael Auler << " : replacing with nop.\n"); 1291a34c753fSRafael Auler BC.MIB->createNoop(Instruction); 1292a34c753fSRafael Auler if (IsCondBranch) { 1293a34c753fSRafael Auler // Register branch offset for profile validation. 1294a34c753fSRafael Auler IgnoredBranches.emplace_back(Offset, Offset + Size); 1295a34c753fSRafael Auler } 1296a34c753fSRafael Auler goto add_instruction; 1297a34c753fSRafael Auler } 1298a34c753fSRafael Auler // May update Instruction and IsCall 1299a34c753fSRafael Auler TargetSymbol = handleExternalReference(Instruction, Size, Offset, 1300a34c753fSRafael Auler TargetAddress, IsCall); 1301a34c753fSRafael Auler } 1302a34c753fSRafael Auler } 1303a34c753fSRafael Auler 1304a34c753fSRafael Auler if (!IsCall) { 1305a34c753fSRafael Auler // Add taken branch info. 1306a34c753fSRafael Auler TakenBranches.emplace_back(Offset, TargetAddress - getAddress()); 1307a34c753fSRafael Auler } 1308a34c753fSRafael Auler BC.MIB->replaceBranchTarget(Instruction, TargetSymbol, &*Ctx); 1309a34c753fSRafael Auler 1310a34c753fSRafael Auler // Mark CTC. 13113652483cSRafael Auler if (IsCondBranch && IsCall) 1312a34c753fSRafael Auler MIB->setConditionalTailCall(Instruction, TargetAddress); 1313a34c753fSRafael Auler } else { 1314a34c753fSRafael Auler // Could not evaluate branch. Should be an indirect call or an 1315a34c753fSRafael Auler // indirect branch. Bail out on the latter case. 1316a34c753fSRafael Auler if (MIB->isIndirectBranch(Instruction)) 1317a34c753fSRafael Auler handleIndirectBranch(Instruction, Size, Offset); 1318a34c753fSRafael Auler // Indirect call. We only need to fix it if the operand is RIP-relative. 1319a34c753fSRafael Auler if (IsSimple && MIB->hasPCRelOperand(Instruction)) 1320a34c753fSRafael Auler handlePCRelOperand(Instruction, AbsoluteInstrAddr, Size); 1321a34c753fSRafael Auler 1322a34c753fSRafael Auler if (BC.isAArch64()) 1323a34c753fSRafael Auler handleAArch64IndirectCall(Instruction, Offset); 1324a34c753fSRafael Auler } 1325f8730293SJob Noorman } else if (BC.isAArch64() || BC.isRISCV()) { 13264101aa13SMaksim Panchenko // Check if there's a relocation associated with this instruction. 13274101aa13SMaksim Panchenko bool UsedReloc = false; 13284101aa13SMaksim Panchenko for (auto Itr = Relocations.lower_bound(Offset), 13294101aa13SMaksim Panchenko ItrE = Relocations.lower_bound(Offset + Size); 13304101aa13SMaksim Panchenko Itr != ItrE; ++Itr) { 13314101aa13SMaksim Panchenko const Relocation &Relocation = Itr->second; 13324101aa13SMaksim Panchenko int64_t Value = Relocation.Value; 13334101aa13SMaksim Panchenko const bool Result = BC.MIB->replaceImmWithSymbolRef( 1334e290133cSMaksim Panchenko Instruction, Relocation.Symbol, Relocation.Addend, Ctx.get(), Value, 1335e290133cSMaksim Panchenko Relocation.Type); 13364101aa13SMaksim Panchenko (void)Result; 13374101aa13SMaksim Panchenko assert(Result && "cannot replace immediate with relocation"); 13384101aa13SMaksim Panchenko 1339e290133cSMaksim Panchenko // For aarch64, if we replaced an immediate with a symbol from a 13404101aa13SMaksim Panchenko // relocation, we mark it so we do not try to further process a 13414101aa13SMaksim Panchenko // pc-relative operand. All we need is the symbol. 13424101aa13SMaksim Panchenko UsedReloc = true; 13434101aa13SMaksim Panchenko } 13444101aa13SMaksim Panchenko 1345f8730293SJob Noorman if (!BC.isRISCV() && MIB->hasPCRelOperand(Instruction) && !UsedReloc) 1346a34c753fSRafael Auler handlePCRelOperand(Instruction, AbsoluteInstrAddr, Size); 13473652483cSRafael Auler } 1348a34c753fSRafael Auler 1349a34c753fSRafael Auler add_instruction: 1350a34c753fSRafael Auler if (getDWARFLineTable()) { 135140c2e0faSMaksim Panchenko Instruction.setLoc(findDebugLineInformationForInstructionAt( 135240c2e0faSMaksim Panchenko AbsoluteInstrAddr, getDWARFUnit(), getDWARFLineTable())); 1353a34c753fSRafael Auler } 1354a34c753fSRafael Auler 1355a34c753fSRafael Auler // Record offset of the instruction for profile matching. 13563652483cSRafael Auler if (BC.keepOffsetForInstruction(Instruction)) 1357a9cd49d5SAmir Ayupov MIB->setOffset(Instruction, static_cast<uint32_t>(Offset)); 1358a34c753fSRafael Auler 135908f56926SVladislav Khmelevsky if (BC.MIB->isNoop(Instruction)) { 136008f56926SVladislav Khmelevsky // NOTE: disassembly loses the correct size information for noops. 136108f56926SVladislav Khmelevsky // E.g. nopw 0x0(%rax,%rax,1) is 9 bytes, but re-encoded it's only 136208f56926SVladislav Khmelevsky // 5 bytes. Preserve the size info using annotations. 136308f56926SVladislav Khmelevsky MIB->addAnnotation(Instruction, "Size", static_cast<uint32_t>(Size)); 136408f56926SVladislav Khmelevsky } 136508f56926SVladislav Khmelevsky 1366a34c753fSRafael Auler addInstruction(Offset, std::move(Instruction)); 1367a34c753fSRafael Auler } 1368a34c753fSRafael Auler 1369e290133cSMaksim Panchenko // Reset symbolizer for the disassembler. 1370e290133cSMaksim Panchenko BC.SymbolicDisAsm->setSymbolizer(nullptr); 1371e290133cSMaksim Panchenko 13720b7e8bafSDenis Revunov if (uint64_t Offset = getFirstInstructionOffset()) 13730b7e8bafSDenis Revunov Labels[Offset] = BC.Ctx->createNamedTempSymbol(); 13740b7e8bafSDenis Revunov 1375a34c753fSRafael Auler clearList(Relocations); 1376a34c753fSRafael Auler 1377a34c753fSRafael Auler if (!IsSimple) { 1378a34c753fSRafael Auler clearList(Instructions); 1379a34c753fSRafael Auler return false; 1380a34c753fSRafael Auler } 1381a34c753fSRafael Auler 1382a34c753fSRafael Auler updateState(State::Disassembled); 1383a34c753fSRafael Auler 1384a34c753fSRafael Auler return true; 1385a34c753fSRafael Auler } 1386a34c753fSRafael Auler 1387a34c753fSRafael Auler bool BinaryFunction::scanExternalRefs() { 1388a34c753fSRafael Auler bool Success = true; 1389a34c753fSRafael Auler bool DisassemblyFailed = false; 1390a34c753fSRafael Auler 1391a34c753fSRafael Auler // Ignore pseudo functions. 1392a34c753fSRafael Auler if (isPseudo()) 1393a34c753fSRafael Auler return Success; 1394a34c753fSRafael Auler 1395a34c753fSRafael Auler if (opts::NoScan) { 1396a34c753fSRafael Auler clearList(Relocations); 1397a34c753fSRafael Auler clearList(ExternallyReferencedOffsets); 1398a34c753fSRafael Auler 1399a34c753fSRafael Auler return false; 1400a34c753fSRafael Auler } 1401a34c753fSRafael Auler 1402a34c753fSRafael Auler // List of external references for this function. 1403a34c753fSRafael Auler std::vector<Relocation> FunctionRelocations; 1404a34c753fSRafael Auler 1405a34c753fSRafael Auler static BinaryContext::IndependentCodeEmitter Emitter = 1406a34c753fSRafael Auler BC.createIndependentMCCodeEmitter(); 1407a34c753fSRafael Auler 1408a34c753fSRafael Auler ErrorOr<ArrayRef<uint8_t>> ErrorOrFunctionData = getData(); 1409a34c753fSRafael Auler assert(ErrorOrFunctionData && "function data is not available"); 1410a34c753fSRafael Auler ArrayRef<uint8_t> FunctionData = *ErrorOrFunctionData; 1411a34c753fSRafael Auler assert(FunctionData.size() == getMaxSize() && 1412a34c753fSRafael Auler "function size does not match raw data size"); 1413a34c753fSRafael Auler 141443f56a2fSMaksim Panchenko BC.SymbolicDisAsm->setSymbolizer( 141543f56a2fSMaksim Panchenko BC.MIB->createTargetSymbolizer(*this, /*CreateSymbols*/ false)); 141643f56a2fSMaksim Panchenko 141743f56a2fSMaksim Panchenko // Disassemble contents of the function. Detect code entry points and create 141843f56a2fSMaksim Panchenko // relocations for references to code that will be moved. 1419a34c753fSRafael Auler uint64_t Size = 0; // instruction size 1420a34c753fSRafael Auler for (uint64_t Offset = 0; Offset < getSize(); Offset += Size) { 1421a34c753fSRafael Auler // Check for data inside code and ignore it 1422a34c753fSRafael Auler if (const size_t DataInCodeSize = getSizeOfDataInCodeAt(Offset)) { 1423a34c753fSRafael Auler Size = DataInCodeSize; 1424a34c753fSRafael Auler continue; 1425a34c753fSRafael Auler } 1426a34c753fSRafael Auler 1427a34c753fSRafael Auler const uint64_t AbsoluteInstrAddr = getAddress() + Offset; 1428a34c753fSRafael Auler MCInst Instruction; 142943f56a2fSMaksim Panchenko if (!BC.SymbolicDisAsm->getInstruction(Instruction, Size, 1430a34c753fSRafael Auler FunctionData.slice(Offset), 143140c2e0faSMaksim Panchenko AbsoluteInstrAddr, nulls())) { 1432a34c753fSRafael Auler if (opts::Verbosity >= 1 && !isZeroPaddingAt(Offset)) { 1433a34c753fSRafael Auler errs() << "BOLT-WARNING: unable to disassemble instruction at offset 0x" 1434a34c753fSRafael Auler << Twine::utohexstr(Offset) << " (address 0x" 1435a34c753fSRafael Auler << Twine::utohexstr(AbsoluteInstrAddr) << ") in function " 1436a34c753fSRafael Auler << *this << '\n'; 1437a34c753fSRafael Auler } 1438a34c753fSRafael Auler Success = false; 1439a34c753fSRafael Auler DisassemblyFailed = true; 1440a34c753fSRafael Auler break; 1441a34c753fSRafael Auler } 1442a34c753fSRafael Auler 1443a34c753fSRafael Auler // Return true if we can skip handling the Target function reference. 1444a34c753fSRafael Auler auto ignoreFunctionRef = [&](const BinaryFunction &Target) { 1445a34c753fSRafael Auler if (&Target == this) 1446a34c753fSRafael Auler return true; 1447a34c753fSRafael Auler 1448a34c753fSRafael Auler // Note that later we may decide not to emit Target function. In that 1449a34c753fSRafael Auler // case, we conservatively create references that will be ignored or 1450a34c753fSRafael Auler // resolved to the same function. 1451a34c753fSRafael Auler if (!BC.shouldEmit(Target)) 1452a34c753fSRafael Auler return true; 1453a34c753fSRafael Auler 1454a34c753fSRafael Auler return false; 1455a34c753fSRafael Auler }; 1456a34c753fSRafael Auler 1457a34c753fSRafael Auler // Return true if we can ignore reference to the symbol. 1458a34c753fSRafael Auler auto ignoreReference = [&](const MCSymbol *TargetSymbol) { 1459a34c753fSRafael Auler if (!TargetSymbol) 1460a34c753fSRafael Auler return true; 1461a34c753fSRafael Auler 1462a34c753fSRafael Auler if (BC.forceSymbolRelocations(TargetSymbol->getName())) 1463a34c753fSRafael Auler return false; 1464a34c753fSRafael Auler 1465a34c753fSRafael Auler BinaryFunction *TargetFunction = BC.getFunctionForSymbol(TargetSymbol); 1466a34c753fSRafael Auler if (!TargetFunction) 1467a34c753fSRafael Auler return true; 1468a34c753fSRafael Auler 1469a34c753fSRafael Auler return ignoreFunctionRef(*TargetFunction); 1470a34c753fSRafael Auler }; 1471a34c753fSRafael Auler 147243f56a2fSMaksim Panchenko // Handle calls and branches separately as symbolization doesn't work for 147343f56a2fSMaksim Panchenko // them yet. 147443f56a2fSMaksim Panchenko MCSymbol *BranchTargetSymbol = nullptr; 147543f56a2fSMaksim Panchenko if (BC.MIB->isCall(Instruction) || BC.MIB->isBranch(Instruction)) { 1476a34c753fSRafael Auler uint64_t TargetAddress = 0; 147743f56a2fSMaksim Panchenko BC.MIB->evaluateBranch(Instruction, AbsoluteInstrAddr, Size, 1478cdef841fSAmir Ayupov TargetAddress); 1479a34c753fSRafael Auler 1480a34c753fSRafael Auler // Create an entry point at reference address if needed. 1481a34c753fSRafael Auler BinaryFunction *TargetFunction = 1482a34c753fSRafael Auler BC.getBinaryFunctionContainingAddress(TargetAddress); 148343f56a2fSMaksim Panchenko 148443f56a2fSMaksim Panchenko if (!TargetFunction || ignoreFunctionRef(*TargetFunction)) 148543f56a2fSMaksim Panchenko continue; 148643f56a2fSMaksim Panchenko 1487a34c753fSRafael Auler const uint64_t FunctionOffset = 1488a34c753fSRafael Auler TargetAddress - TargetFunction->getAddress(); 148943f56a2fSMaksim Panchenko BranchTargetSymbol = 149043f56a2fSMaksim Panchenko FunctionOffset ? TargetFunction->addEntryPointAtOffset(FunctionOffset) 1491a34c753fSRafael Auler : TargetFunction->getSymbol(); 1492a34c753fSRafael Auler } 1493a34c753fSRafael Auler 149443f56a2fSMaksim Panchenko // Can't find more references. Not creating relocations since we are not 149543f56a2fSMaksim Panchenko // moving code. 1496a34c753fSRafael Auler if (!BC.HasRelocations) 1497a34c753fSRafael Auler continue; 1498a34c753fSRafael Auler 149943f56a2fSMaksim Panchenko if (BranchTargetSymbol) { 150043f56a2fSMaksim Panchenko BC.MIB->replaceBranchTarget(Instruction, BranchTargetSymbol, 1501a34c753fSRafael Auler Emitter.LocalCtx.get()); 150243f56a2fSMaksim Panchenko } else if (!llvm::any_of(Instruction, 150343f56a2fSMaksim Panchenko [](const MCOperand &Op) { return Op.isExpr(); })) { 150443f56a2fSMaksim Panchenko // Skip assembly if the instruction may not have any symbolic operands. 15054101aa13SMaksim Panchenko continue; 1506a34c753fSRafael Auler } 1507a34c753fSRafael Auler 1508a34c753fSRafael Auler // Emit the instruction using temp emitter and generate relocations. 1509a34c753fSRafael Auler SmallString<256> Code; 1510a34c753fSRafael Auler SmallVector<MCFixup, 4> Fixups; 15110c049ea6SAlexis Engelke Emitter.MCE->encodeInstruction(Instruction, Code, Fixups, *BC.STI); 1512a34c753fSRafael Auler 1513a34c753fSRafael Auler // Create relocation for every fixup. 1514a34c753fSRafael Auler for (const MCFixup &Fixup : Fixups) { 15152563fd63SAmir Ayupov std::optional<Relocation> Rel = BC.MIB->createRelocation(Fixup, *BC.MAB); 1516a34c753fSRafael Auler if (!Rel) { 1517a34c753fSRafael Auler Success = false; 1518a34c753fSRafael Auler continue; 1519a34c753fSRafael Auler } 1520a34c753fSRafael Auler 152143f56a2fSMaksim Panchenko if (ignoreReference(Rel->Symbol)) 152243f56a2fSMaksim Panchenko continue; 152343f56a2fSMaksim Panchenko 1524a34c753fSRafael Auler if (Relocation::getSizeForType(Rel->Type) < 4) { 1525a34c753fSRafael Auler // If the instruction uses a short form, then we might not be able 1526a34c753fSRafael Auler // to handle the rewrite without relaxation, and hence cannot reliably 1527a34c753fSRafael Auler // create an external reference relocation. 1528a34c753fSRafael Auler Success = false; 1529a34c753fSRafael Auler continue; 1530a34c753fSRafael Auler } 1531a34c753fSRafael Auler Rel->Offset += getAddress() - getOriginSection()->getAddress() + Offset; 1532a34c753fSRafael Auler FunctionRelocations.push_back(*Rel); 1533a34c753fSRafael Auler } 1534a34c753fSRafael Auler 1535a34c753fSRafael Auler if (!Success) 1536a34c753fSRafael Auler break; 1537a34c753fSRafael Auler } 1538a34c753fSRafael Auler 153943f56a2fSMaksim Panchenko // Reset symbolizer for the disassembler. 154043f56a2fSMaksim Panchenko BC.SymbolicDisAsm->setSymbolizer(nullptr); 154143f56a2fSMaksim Panchenko 1542a34c753fSRafael Auler // Add relocations unless disassembly failed for this function. 15433652483cSRafael Auler if (!DisassemblyFailed) 15443652483cSRafael Auler for (Relocation &Rel : FunctionRelocations) 1545a34c753fSRafael Auler getOriginSection()->addPendingRelocation(Rel); 1546a34c753fSRafael Auler 1547a34c753fSRafael Auler // Inform BinaryContext that this function symbols will not be defined and 1548a34c753fSRafael Auler // relocations should not be created against them. 1549a34c753fSRafael Auler if (BC.HasRelocations) { 15503652483cSRafael Auler for (std::pair<const uint32_t, MCSymbol *> &LI : Labels) 1551a34c753fSRafael Auler BC.UndefinedSymbols.insert(LI.second); 1552a191ea7dSFabian Parzefall for (MCSymbol *const EndLabel : FunctionEndLabels) 1553a191ea7dSFabian Parzefall if (EndLabel) 1554a191ea7dSFabian Parzefall BC.UndefinedSymbols.insert(EndLabel); 1555a34c753fSRafael Auler } 1556a34c753fSRafael Auler 1557a34c753fSRafael Auler clearList(Relocations); 1558a34c753fSRafael Auler clearList(ExternallyReferencedOffsets); 1559a34c753fSRafael Auler 15603652483cSRafael Auler if (Success && BC.HasRelocations) 1561a34c753fSRafael Auler HasExternalRefRelocations = true; 1562a34c753fSRafael Auler 15633652483cSRafael Auler if (opts::Verbosity >= 1 && !Success) 1564a34c753fSRafael Auler outs() << "BOLT-INFO: failed to scan refs for " << *this << '\n'; 1565a34c753fSRafael Auler 1566a34c753fSRafael Auler return Success; 1567a34c753fSRafael Auler } 1568a34c753fSRafael Auler 1569a34c753fSRafael Auler void BinaryFunction::postProcessEntryPoints() { 1570a34c753fSRafael Auler if (!isSimple()) 1571a34c753fSRafael Auler return; 1572a34c753fSRafael Auler 1573a34c753fSRafael Auler for (auto &KV : Labels) { 1574a34c753fSRafael Auler MCSymbol *Label = KV.second; 1575a34c753fSRafael Auler if (!getSecondaryEntryPointSymbol(Label)) 1576a34c753fSRafael Auler continue; 1577a34c753fSRafael Auler 1578a34c753fSRafael Auler // In non-relocation mode there's potentially an external undetectable 1579a34c753fSRafael Auler // reference to the entry point and hence we cannot move this entry 1580a34c753fSRafael Auler // point. Optimizing without moving could be difficult. 1581a34c753fSRafael Auler if (!BC.HasRelocations) 1582a34c753fSRafael Auler setSimple(false); 1583a34c753fSRafael Auler 1584a34c753fSRafael Auler const uint32_t Offset = KV.first; 1585a34c753fSRafael Auler 1586a34c753fSRafael Auler // If we are at Offset 0 and there is no instruction associated with it, 1587a34c753fSRafael Auler // this means this is an empty function. Just ignore. If we find an 1588a34c753fSRafael Auler // instruction at this offset, this entry point is valid. 15893652483cSRafael Auler if (!Offset || getInstructionAtOffset(Offset)) 1590a34c753fSRafael Auler continue; 1591a34c753fSRafael Auler 1592a34c753fSRafael Auler // On AArch64 there are legitimate reasons to have references past the 1593a34c753fSRafael Auler // end of the function, e.g. jump tables. 15943652483cSRafael Auler if (BC.isAArch64() && Offset == getSize()) 1595a34c753fSRafael Auler continue; 1596a34c753fSRafael Auler 1597a34c753fSRafael Auler errs() << "BOLT-WARNING: reference in the middle of instruction " 159840c2e0faSMaksim Panchenko "detected in function " 159940c2e0faSMaksim Panchenko << *this << " at offset 0x" << Twine::utohexstr(Offset) << '\n'; 16003652483cSRafael Auler if (BC.HasRelocations) 1601a34c753fSRafael Auler setIgnored(); 1602a34c753fSRafael Auler setSimple(false); 1603a34c753fSRafael Auler return; 1604a34c753fSRafael Auler } 1605a34c753fSRafael Auler } 1606a34c753fSRafael Auler 1607a34c753fSRafael Auler void BinaryFunction::postProcessJumpTables() { 1608a34c753fSRafael Auler // Create labels for all entries. 1609a34c753fSRafael Auler for (auto &JTI : JumpTables) { 1610a34c753fSRafael Auler JumpTable &JT = *JTI.second; 1611a34c753fSRafael Auler if (JT.Type == JumpTable::JTT_PIC && opts::JumpTables == JTS_BASIC) { 1612a34c753fSRafael Auler opts::JumpTables = JTS_MOVE; 1613a34c753fSRafael Auler outs() << "BOLT-INFO: forcing -jump-tables=move as PIC jump table was " 161440c2e0faSMaksim Panchenko "detected in function " 161540c2e0faSMaksim Panchenko << *this << '\n'; 1616a34c753fSRafael Auler } 1617a34c753fSRafael Auler const uint64_t BDSize = 1618a34c753fSRafael Auler BC.getBinaryDataAtAddress(JT.getAddress())->getSize(); 1619a34c753fSRafael Auler if (!BDSize) { 1620a34c753fSRafael Auler BC.setBinaryDataSize(JT.getAddress(), JT.getSize()); 1621a34c753fSRafael Auler } else { 1622a34c753fSRafael Auler assert(BDSize >= JT.getSize() && 1623a34c753fSRafael Auler "jump table cannot be larger than the containing object"); 1624a34c753fSRafael Auler } 162559a27170SAmir Ayupov if (!JT.Entries.empty()) 162659a27170SAmir Ayupov continue; 162759a27170SAmir Ayupov 162859a27170SAmir Ayupov bool HasOneParent = (JT.Parents.size() == 1); 162959a27170SAmir Ayupov for (uint64_t EntryAddress : JT.EntriesAsAddress) { 163059a27170SAmir Ayupov // builtin_unreachable does not belong to any function 163159a27170SAmir Ayupov // Need to handle separately 163259a27170SAmir Ayupov bool IsBuiltinUnreachable = 163359a27170SAmir Ayupov llvm::any_of(JT.Parents, [&](const BinaryFunction *Parent) { 163459a27170SAmir Ayupov return EntryAddress == Parent->getAddress() + Parent->getSize(); 163559a27170SAmir Ayupov }); 163659a27170SAmir Ayupov if (IsBuiltinUnreachable) { 163759a27170SAmir Ayupov MCSymbol *Label = getOrCreateLocalLabel(EntryAddress, true); 163859a27170SAmir Ayupov JT.Entries.push_back(Label); 163959a27170SAmir Ayupov continue; 164059a27170SAmir Ayupov } 1641b6fbb64dSMaksim Panchenko // Create a local label for targets that cannot be reached by other 1642b6fbb64dSMaksim Panchenko // fragments. Otherwise, create a secondary entry point in the target 1643b6fbb64dSMaksim Panchenko // function. 164459a27170SAmir Ayupov BinaryFunction *TargetBF = 164559a27170SAmir Ayupov BC.getBinaryFunctionContainingAddress(EntryAddress); 1646b6fbb64dSMaksim Panchenko MCSymbol *Label; 1647b6fbb64dSMaksim Panchenko if (HasOneParent && TargetBF == this) { 1648b6fbb64dSMaksim Panchenko Label = getOrCreateLocalLabel(EntryAddress, true); 1649b6fbb64dSMaksim Panchenko } else { 1650b6fbb64dSMaksim Panchenko const uint64_t Offset = EntryAddress - TargetBF->getAddress(); 1651b6fbb64dSMaksim Panchenko Label = Offset ? TargetBF->addEntryPointAtOffset(Offset) 1652b6fbb64dSMaksim Panchenko : TargetBF->getSymbol(); 165359a27170SAmir Ayupov } 1654b6fbb64dSMaksim Panchenko JT.Entries.push_back(Label); 165559a27170SAmir Ayupov } 1656a34c753fSRafael Auler } 1657a34c753fSRafael Auler 1658a34c753fSRafael Auler // Add TakenBranches from JumpTables. 1659a34c753fSRafael Auler // 1660a34c753fSRafael Auler // We want to do it after initial processing since we don't know jump tables' 1661a34c753fSRafael Auler // boundaries until we process them all. 1662a34c753fSRafael Auler for (auto &JTSite : JTSites) { 1663a34c753fSRafael Auler const uint64_t JTSiteOffset = JTSite.first; 1664a34c753fSRafael Auler const uint64_t JTAddress = JTSite.second; 1665a34c753fSRafael Auler const JumpTable *JT = getJumpTableContainingAddress(JTAddress); 1666a34c753fSRafael Auler assert(JT && "cannot find jump table for address"); 1667a34c753fSRafael Auler 1668a34c753fSRafael Auler uint64_t EntryOffset = JTAddress - JT->getAddress(); 1669a34c753fSRafael Auler while (EntryOffset < JT->getSize()) { 167005523dc3SHuan Nguyen uint64_t EntryAddress = JT->EntriesAsAddress[EntryOffset / JT->EntrySize]; 167105523dc3SHuan Nguyen uint64_t TargetOffset = EntryAddress - getAddress(); 1672a34c753fSRafael Auler if (TargetOffset < getSize()) { 1673a34c753fSRafael Auler TakenBranches.emplace_back(JTSiteOffset, TargetOffset); 1674a34c753fSRafael Auler 1675a34c753fSRafael Auler if (opts::StrictMode) 1676a34c753fSRafael Auler registerReferencedOffset(TargetOffset); 1677a34c753fSRafael Auler } 1678a34c753fSRafael Auler 1679a34c753fSRafael Auler EntryOffset += JT->EntrySize; 1680a34c753fSRafael Auler 1681a34c753fSRafael Auler // A label at the next entry means the end of this jump table. 1682a34c753fSRafael Auler if (JT->Labels.count(EntryOffset)) 1683a34c753fSRafael Auler break; 1684a34c753fSRafael Auler } 1685a34c753fSRafael Auler } 1686a34c753fSRafael Auler clearList(JTSites); 1687a34c753fSRafael Auler 1688a34c753fSRafael Auler // Conservatively populate all possible destinations for unknown indirect 1689a34c753fSRafael Auler // branches. 1690a34c753fSRafael Auler if (opts::StrictMode && hasInternalReference()) { 1691a34c753fSRafael Auler for (uint64_t Offset : UnknownIndirectBranchOffsets) { 1692a34c753fSRafael Auler for (uint64_t PossibleDestination : ExternallyReferencedOffsets) { 1693a34c753fSRafael Auler // Ignore __builtin_unreachable(). 1694a34c753fSRafael Auler if (PossibleDestination == getSize()) 1695a34c753fSRafael Auler continue; 1696a34c753fSRafael Auler TakenBranches.emplace_back(Offset, PossibleDestination); 1697a34c753fSRafael Auler } 1698a34c753fSRafael Auler } 1699a34c753fSRafael Auler } 1700a34c753fSRafael Auler 1701a34c753fSRafael Auler // Remove duplicates branches. We can get a bunch of them from jump tables. 1702a34c753fSRafael Auler // Without doing jump table value profiling we don't have use for extra 1703a34c753fSRafael Auler // (duplicate) branches. 1704d2c87699SAmir Ayupov llvm::sort(TakenBranches); 1705a34c753fSRafael Auler auto NewEnd = std::unique(TakenBranches.begin(), TakenBranches.end()); 1706a34c753fSRafael Auler TakenBranches.erase(NewEnd, TakenBranches.end()); 1707a34c753fSRafael Auler } 1708a34c753fSRafael Auler 1709e002523bSAmir Ayupov bool BinaryFunction::validateExternallyReferencedOffsets() { 1710e002523bSAmir Ayupov SmallPtrSet<MCSymbol *, 4> JTTargets; 1711e002523bSAmir Ayupov for (const JumpTable *JT : llvm::make_second_range(JumpTables)) 1712e002523bSAmir Ayupov JTTargets.insert(JT->Entries.begin(), JT->Entries.end()); 1713e002523bSAmir Ayupov 1714e002523bSAmir Ayupov bool HasUnclaimedReference = false; 1715e002523bSAmir Ayupov for (uint64_t Destination : ExternallyReferencedOffsets) { 1716e002523bSAmir Ayupov // Ignore __builtin_unreachable(). 1717e002523bSAmir Ayupov if (Destination == getSize()) 1718e002523bSAmir Ayupov continue; 1719e002523bSAmir Ayupov // Ignore constant islands 1720e002523bSAmir Ayupov if (isInConstantIsland(Destination + getAddress())) 1721e002523bSAmir Ayupov continue; 1722e002523bSAmir Ayupov 1723e002523bSAmir Ayupov if (BinaryBasicBlock *BB = getBasicBlockAtOffset(Destination)) { 1724e002523bSAmir Ayupov // Check if the externally referenced offset is a recognized jump table 1725e002523bSAmir Ayupov // target. 1726e002523bSAmir Ayupov if (JTTargets.contains(BB->getLabel())) 1727e002523bSAmir Ayupov continue; 1728e002523bSAmir Ayupov 1729e002523bSAmir Ayupov if (opts::Verbosity >= 1) { 1730e002523bSAmir Ayupov errs() << "BOLT-WARNING: unclaimed data to code reference (possibly " 1731e002523bSAmir Ayupov << "an unrecognized jump table entry) to " << BB->getName() 1732e002523bSAmir Ayupov << " in " << *this << "\n"; 1733e002523bSAmir Ayupov } 1734e002523bSAmir Ayupov auto L = BC.scopeLock(); 1735e002523bSAmir Ayupov addEntryPoint(*BB); 1736e002523bSAmir Ayupov } else { 1737e002523bSAmir Ayupov errs() << "BOLT-WARNING: unknown data to code reference to offset " 1738e002523bSAmir Ayupov << Twine::utohexstr(Destination) << " in " << *this << "\n"; 1739e002523bSAmir Ayupov setIgnored(); 1740e002523bSAmir Ayupov } 1741e002523bSAmir Ayupov HasUnclaimedReference = true; 1742e002523bSAmir Ayupov } 1743e002523bSAmir Ayupov return !HasUnclaimedReference; 1744e002523bSAmir Ayupov } 1745e002523bSAmir Ayupov 1746a34c753fSRafael Auler bool BinaryFunction::postProcessIndirectBranches( 1747a34c753fSRafael Auler MCPlusBuilder::AllocatorIdTy AllocId) { 1748a34c753fSRafael Auler auto addUnknownControlFlow = [&](BinaryBasicBlock &BB) { 17491c286acfSAmir Ayupov LLVM_DEBUG(dbgs() << "BOLT-DEBUG: adding unknown control flow in " << *this 17501c286acfSAmir Ayupov << " for " << BB.getName() << "\n"); 1751a34c753fSRafael Auler HasUnknownControlFlow = true; 1752a34c753fSRafael Auler BB.removeAllSuccessors(); 17533652483cSRafael Auler for (uint64_t PossibleDestination : ExternallyReferencedOffsets) 1754a34c753fSRafael Auler if (BinaryBasicBlock *SuccBB = getBasicBlockAtOffset(PossibleDestination)) 1755a34c753fSRafael Auler BB.addSuccessor(SuccBB); 1756a34c753fSRafael Auler }; 1757a34c753fSRafael Auler 1758a34c753fSRafael Auler uint64_t NumIndirectJumps = 0; 1759a34c753fSRafael Auler MCInst *LastIndirectJump = nullptr; 1760a34c753fSRafael Auler BinaryBasicBlock *LastIndirectJumpBB = nullptr; 1761a34c753fSRafael Auler uint64_t LastJT = 0; 1762a34c753fSRafael Auler uint16_t LastJTIndexReg = BC.MIB->getNoRegister(); 1763d55dfeafSFabian Parzefall for (BinaryBasicBlock &BB : blocks()) { 1764d55dfeafSFabian Parzefall for (MCInst &Instr : BB) { 1765a34c753fSRafael Auler if (!BC.MIB->isIndirectBranch(Instr)) 1766a34c753fSRafael Auler continue; 1767a34c753fSRafael Auler 1768a34c753fSRafael Auler // If there's an indirect branch in a single-block function - 1769a34c753fSRafael Auler // it must be a tail call. 1770d55dfeafSFabian Parzefall if (BasicBlocks.size() == 1) { 1771a34c753fSRafael Auler BC.MIB->convertJmpToTailCall(Instr); 1772a34c753fSRafael Auler return true; 1773a34c753fSRafael Auler } 1774a34c753fSRafael Auler 1775a34c753fSRafael Auler ++NumIndirectJumps; 1776a34c753fSRafael Auler 1777a34c753fSRafael Auler if (opts::StrictMode && !hasInternalReference()) { 1778a34c753fSRafael Auler BC.MIB->convertJmpToTailCall(Instr); 1779a34c753fSRafael Auler break; 1780a34c753fSRafael Auler } 1781a34c753fSRafael Auler 1782a34c753fSRafael Auler // Validate the tail call or jump table assumptions now that we know 1783a34c753fSRafael Auler // basic block boundaries. 1784a34c753fSRafael Auler if (BC.MIB->isTailCall(Instr) || BC.MIB->getJumpTable(Instr)) { 1785a34c753fSRafael Auler const unsigned PtrSize = BC.AsmInfo->getCodePointerSize(); 1786a34c753fSRafael Auler MCInst *MemLocInstr; 1787a34c753fSRafael Auler unsigned BaseRegNum, IndexRegNum; 1788a34c753fSRafael Auler int64_t DispValue; 1789a34c753fSRafael Auler const MCExpr *DispExpr; 1790a34c753fSRafael Auler MCInst *PCRelBaseInstr; 1791a34c753fSRafael Auler IndirectBranchType Type = BC.MIB->analyzeIndirectBranch( 1792d55dfeafSFabian Parzefall Instr, BB.begin(), BB.end(), PtrSize, MemLocInstr, BaseRegNum, 1793a34c753fSRafael Auler IndexRegNum, DispValue, DispExpr, PCRelBaseInstr); 1794a34c753fSRafael Auler if (Type != IndirectBranchType::UNKNOWN || MemLocInstr != nullptr) 1795a34c753fSRafael Auler continue; 1796a34c753fSRafael Auler 1797a34c753fSRafael Auler if (!opts::StrictMode) 1798a34c753fSRafael Auler return false; 1799a34c753fSRafael Auler 1800a34c753fSRafael Auler if (BC.MIB->isTailCall(Instr)) { 1801a34c753fSRafael Auler BC.MIB->convertTailCallToJmp(Instr); 1802a34c753fSRafael Auler } else { 1803a34c753fSRafael Auler LastIndirectJump = &Instr; 1804d55dfeafSFabian Parzefall LastIndirectJumpBB = &BB; 1805a34c753fSRafael Auler LastJT = BC.MIB->getJumpTable(Instr); 1806a34c753fSRafael Auler LastJTIndexReg = BC.MIB->getJumpTableIndexReg(Instr); 1807a34c753fSRafael Auler BC.MIB->unsetJumpTable(Instr); 1808a34c753fSRafael Auler 1809a34c753fSRafael Auler JumpTable *JT = BC.getJumpTableContainingAddress(LastJT); 1810a34c753fSRafael Auler if (JT->Type == JumpTable::JTT_NORMAL) { 1811a34c753fSRafael Auler // Invalidating the jump table may also invalidate other jump table 1812a34c753fSRafael Auler // boundaries. Until we have/need a support for this, mark the 1813a34c753fSRafael Auler // function as non-simple. 1814a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: rejected jump table reference" 1815a34c753fSRafael Auler << JT->getName() << " in " << *this << '\n'); 1816a34c753fSRafael Auler return false; 1817a34c753fSRafael Auler } 1818a34c753fSRafael Auler } 1819a34c753fSRafael Auler 1820d55dfeafSFabian Parzefall addUnknownControlFlow(BB); 1821a34c753fSRafael Auler continue; 1822a34c753fSRafael Auler } 1823a34c753fSRafael Auler 1824a34c753fSRafael Auler // If this block contains an epilogue code and has an indirect branch, 1825a34c753fSRafael Auler // then most likely it's a tail call. Otherwise, we cannot tell for sure 1826a34c753fSRafael Auler // what it is and conservatively reject the function's CFG. 1827f119a248SAmir Ayupov bool IsEpilogue = llvm::any_of(BB, [&](const MCInst &Instr) { 1828f119a248SAmir Ayupov return BC.MIB->isLeave(Instr) || BC.MIB->isPop(Instr); 1829f119a248SAmir Ayupov }); 1830a34c753fSRafael Auler if (IsEpilogue) { 1831a34c753fSRafael Auler BC.MIB->convertJmpToTailCall(Instr); 1832d55dfeafSFabian Parzefall BB.removeAllSuccessors(); 1833a34c753fSRafael Auler continue; 1834a34c753fSRafael Auler } 1835a34c753fSRafael Auler 1836a34c753fSRafael Auler if (opts::Verbosity >= 2) { 1837a34c753fSRafael Auler outs() << "BOLT-INFO: rejected potential indirect tail call in " 1838d55dfeafSFabian Parzefall << "function " << *this << " in basic block " << BB.getName() 183940c2e0faSMaksim Panchenko << ".\n"; 1840d55dfeafSFabian Parzefall LLVM_DEBUG(BC.printInstructions(dbgs(), BB.begin(), BB.end(), 1841d55dfeafSFabian Parzefall BB.getOffset(), this, true)); 1842a34c753fSRafael Auler } 1843a34c753fSRafael Auler 1844a34c753fSRafael Auler if (!opts::StrictMode) 1845a34c753fSRafael Auler return false; 1846a34c753fSRafael Auler 1847d55dfeafSFabian Parzefall addUnknownControlFlow(BB); 1848a34c753fSRafael Auler } 1849a34c753fSRafael Auler } 1850a34c753fSRafael Auler 1851a34c753fSRafael Auler if (HasInternalLabelReference) 1852a34c753fSRafael Auler return false; 1853a34c753fSRafael Auler 1854a34c753fSRafael Auler // If there's only one jump table, and one indirect jump, and no other 1855a34c753fSRafael Auler // references, then we should be able to derive the jump table even if we 1856a34c753fSRafael Auler // fail to match the pattern. 1857a34c753fSRafael Auler if (HasUnknownControlFlow && NumIndirectJumps == 1 && 18581c286acfSAmir Ayupov JumpTables.size() == 1 && LastIndirectJump && 18591c286acfSAmir Ayupov !BC.getJumpTableContainingAddress(LastJT)->IsSplit) { 18601c286acfSAmir Ayupov LLVM_DEBUG(dbgs() << "BOLT-DEBUG: unsetting unknown control flow in " 18611c286acfSAmir Ayupov << *this << '\n'); 1862a34c753fSRafael Auler BC.MIB->setJumpTable(*LastIndirectJump, LastJT, LastJTIndexReg, AllocId); 1863a34c753fSRafael Auler HasUnknownControlFlow = false; 1864a34c753fSRafael Auler 18655a343994SMaksim Panchenko LastIndirectJumpBB->updateJumpTableSuccessors(); 1866a34c753fSRafael Auler } 1867a34c753fSRafael Auler 1868a34c753fSRafael Auler if (HasFixedIndirectBranch) 1869a34c753fSRafael Auler return false; 1870a34c753fSRafael Auler 1871e002523bSAmir Ayupov // Validate that all data references to function offsets are claimed by 1872e002523bSAmir Ayupov // recognized jump tables. Register externally referenced blocks as entry 1873e002523bSAmir Ayupov // points. 1874e002523bSAmir Ayupov if (!opts::StrictMode && hasInternalReference()) { 1875e002523bSAmir Ayupov if (!validateExternallyReferencedOffsets()) 1876e002523bSAmir Ayupov return false; 1877e002523bSAmir Ayupov } 1878e002523bSAmir Ayupov 1879a34c753fSRafael Auler if (HasUnknownControlFlow && !BC.HasRelocations) 1880a34c753fSRafael Auler return false; 1881a34c753fSRafael Auler 1882a34c753fSRafael Auler return true; 1883a34c753fSRafael Auler } 1884a34c753fSRafael Auler 1885a34c753fSRafael Auler void BinaryFunction::recomputeLandingPads() { 1886a34c753fSRafael Auler updateBBIndices(0); 1887a34c753fSRafael Auler 1888a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 1889a34c753fSRafael Auler BB->LandingPads.clear(); 1890a34c753fSRafael Auler BB->Throwers.clear(); 1891a34c753fSRafael Auler } 1892a34c753fSRafael Auler 1893a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 1894a34c753fSRafael Auler std::unordered_set<const BinaryBasicBlock *> BBLandingPads; 1895a34c753fSRafael Auler for (MCInst &Instr : *BB) { 1896a34c753fSRafael Auler if (!BC.MIB->isInvoke(Instr)) 1897a34c753fSRafael Auler continue; 1898a34c753fSRafael Auler 18992563fd63SAmir Ayupov const std::optional<MCPlus::MCLandingPad> EHInfo = 19002563fd63SAmir Ayupov BC.MIB->getEHInfo(Instr); 1901a34c753fSRafael Auler if (!EHInfo || !EHInfo->first) 1902a34c753fSRafael Auler continue; 1903a34c753fSRafael Auler 1904a34c753fSRafael Auler BinaryBasicBlock *LPBlock = getBasicBlockForLabel(EHInfo->first); 1905a34c753fSRafael Auler if (!BBLandingPads.count(LPBlock)) { 1906a34c753fSRafael Auler BBLandingPads.insert(LPBlock); 1907a34c753fSRafael Auler BB->LandingPads.emplace_back(LPBlock); 1908a34c753fSRafael Auler LPBlock->Throwers.emplace_back(BB); 1909a34c753fSRafael Auler } 1910a34c753fSRafael Auler } 1911a34c753fSRafael Auler } 1912a34c753fSRafael Auler } 1913a34c753fSRafael Auler 1914a34c753fSRafael Auler bool BinaryFunction::buildCFG(MCPlusBuilder::AllocatorIdTy AllocatorId) { 1915a34c753fSRafael Auler auto &MIB = BC.MIB; 1916a34c753fSRafael Auler 1917a34c753fSRafael Auler if (!isSimple()) { 1918a34c753fSRafael Auler assert(!BC.HasRelocations && 1919a34c753fSRafael Auler "cannot process file with non-simple function in relocs mode"); 1920a34c753fSRafael Auler return false; 1921a34c753fSRafael Auler } 1922a34c753fSRafael Auler 1923a34c753fSRafael Auler if (CurrentState != State::Disassembled) 1924a34c753fSRafael Auler return false; 1925a34c753fSRafael Auler 1926a34c753fSRafael Auler assert(BasicBlocks.empty() && "basic block list should be empty"); 19270b7e8bafSDenis Revunov assert((Labels.find(getFirstInstructionOffset()) != Labels.end()) && 1928a34c753fSRafael Auler "first instruction should always have a label"); 1929a34c753fSRafael Auler 1930a34c753fSRafael Auler // Create basic blocks in the original layout order: 1931a34c753fSRafael Auler // 1932a34c753fSRafael Auler // * Every instruction with associated label marks 1933a34c753fSRafael Auler // the beginning of a basic block. 1934a34c753fSRafael Auler // * Conditional instruction marks the end of a basic block, 1935a34c753fSRafael Auler // except when the following instruction is an 1936a34c753fSRafael Auler // unconditional branch, and the unconditional branch is not 1937a34c753fSRafael Auler // a destination of another branch. In the latter case, the 1938a34c753fSRafael Auler // basic block will consist of a single unconditional branch 1939a34c753fSRafael Auler // (missed "double-jump" optimization). 1940a34c753fSRafael Auler // 1941a34c753fSRafael Auler // Created basic blocks are sorted in layout order since they are 1942a34c753fSRafael Auler // created in the same order as instructions, and instructions are 1943a34c753fSRafael Auler // sorted by offsets. 1944a34c753fSRafael Auler BinaryBasicBlock *InsertBB = nullptr; 1945a34c753fSRafael Auler BinaryBasicBlock *PrevBB = nullptr; 1946a34c753fSRafael Auler bool IsLastInstrNop = false; 1947ccb99dd1SMaksim Panchenko // Offset of the last non-nop instruction. 1948a34c753fSRafael Auler uint64_t LastInstrOffset = 0; 1949a34c753fSRafael Auler 195040c2e0faSMaksim Panchenko auto addCFIPlaceholders = [this](uint64_t CFIOffset, 195140c2e0faSMaksim Panchenko BinaryBasicBlock *InsertBB) { 1952a34c753fSRafael Auler for (auto FI = OffsetToCFI.lower_bound(CFIOffset), 1953a34c753fSRafael Auler FE = OffsetToCFI.upper_bound(CFIOffset); 1954a34c753fSRafael Auler FI != FE; ++FI) { 1955a34c753fSRafael Auler addCFIPseudo(InsertBB, InsertBB->end(), FI->second); 1956a34c753fSRafael Auler } 1957a34c753fSRafael Auler }; 1958a34c753fSRafael Auler 1959a34c753fSRafael Auler // For profiling purposes we need to save the offset of the last instruction 1960ccb99dd1SMaksim Panchenko // in the basic block. 1961ccb99dd1SMaksim Panchenko // NOTE: nops always have an Offset annotation. Annotate the last non-nop as 1962ccb99dd1SMaksim Panchenko // older profiles ignored nops. 1963a34c753fSRafael Auler auto updateOffset = [&](uint64_t Offset) { 1964a34c753fSRafael Auler assert(PrevBB && PrevBB != InsertBB && "invalid previous block"); 1965ccb99dd1SMaksim Panchenko MCInst *LastNonNop = nullptr; 1966ccb99dd1SMaksim Panchenko for (BinaryBasicBlock::reverse_iterator RII = PrevBB->getLastNonPseudo(), 1967ccb99dd1SMaksim Panchenko E = PrevBB->rend(); 1968ccb99dd1SMaksim Panchenko RII != E; ++RII) { 1969ccb99dd1SMaksim Panchenko if (!BC.MIB->isPseudo(*RII) && !BC.MIB->isNoop(*RII)) { 1970ccb99dd1SMaksim Panchenko LastNonNop = &*RII; 1971ccb99dd1SMaksim Panchenko break; 1972ccb99dd1SMaksim Panchenko } 1973ccb99dd1SMaksim Panchenko } 1974a9cd49d5SAmir Ayupov if (LastNonNop && !MIB->getOffset(*LastNonNop)) 1975a9cd49d5SAmir Ayupov MIB->setOffset(*LastNonNop, static_cast<uint32_t>(Offset), AllocatorId); 1976a34c753fSRafael Auler }; 1977a34c753fSRafael Auler 1978a34c753fSRafael Auler for (auto I = Instructions.begin(), E = Instructions.end(); I != E; ++I) { 1979a34c753fSRafael Auler const uint32_t Offset = I->first; 1980a34c753fSRafael Auler MCInst &Instr = I->second; 1981a34c753fSRafael Auler 1982a34c753fSRafael Auler auto LI = Labels.find(Offset); 1983a34c753fSRafael Auler if (LI != Labels.end()) { 1984a34c753fSRafael Auler // Always create new BB at branch destination. 1985ccb99dd1SMaksim Panchenko PrevBB = InsertBB ? InsertBB : PrevBB; 19868228c703SMaksim Panchenko InsertBB = addBasicBlockAt(LI->first, LI->second); 19878228c703SMaksim Panchenko if (opts::PreserveBlocksAlignment && IsLastInstrNop) 19888228c703SMaksim Panchenko InsertBB->setDerivedAlignment(); 19898228c703SMaksim Panchenko 1990a34c753fSRafael Auler if (PrevBB) 1991a34c753fSRafael Auler updateOffset(LastInstrOffset); 1992a34c753fSRafael Auler } 1993a34c753fSRafael Auler 1994ccb99dd1SMaksim Panchenko // Mark all nops with Offset for profile tracking purposes. 199538639a81SMaksim Panchenko if (MIB->isNoop(Instr) && !MIB->getOffset(Instr)) { 199698e2d630SMaksim Panchenko // If "Offset" annotation is not present, set it and mark the nop for 199798e2d630SMaksim Panchenko // deletion. 1998a9cd49d5SAmir Ayupov MIB->setOffset(Instr, static_cast<uint32_t>(Offset), AllocatorId); 1999ccb99dd1SMaksim Panchenko // Annotate ordinary nops, so we can safely delete them if required. 200038639a81SMaksim Panchenko MIB->addAnnotation(Instr, "NOP", static_cast<uint32_t>(1), AllocatorId); 2001a34c753fSRafael Auler } 2002a34c753fSRafael Auler 2003a34c753fSRafael Auler if (!InsertBB) { 2004a34c753fSRafael Auler // It must be a fallthrough or unreachable code. Create a new block unless 2005a34c753fSRafael Auler // we see an unconditional branch following a conditional one. The latter 2006a34c753fSRafael Auler // should not be a conditional tail call. 2007a34c753fSRafael Auler assert(PrevBB && "no previous basic block for a fall through"); 2008a34c753fSRafael Auler MCInst *PrevInstr = PrevBB->getLastNonPseudoInstr(); 2009a34c753fSRafael Auler assert(PrevInstr && "no previous instruction for a fall through"); 2010a34c753fSRafael Auler if (MIB->isUnconditionalBranch(Instr) && 2011b87bf744SRafael Auler !MIB->isIndirectBranch(*PrevInstr) && 2012a34c753fSRafael Auler !MIB->isUnconditionalBranch(*PrevInstr) && 2013bb8e7ebaSVladislav Khmelevsky !MIB->getConditionalTailCall(*PrevInstr) && 2014bb8e7ebaSVladislav Khmelevsky !MIB->isReturn(*PrevInstr)) { 2015a34c753fSRafael Auler // Temporarily restore inserter basic block. 2016a34c753fSRafael Auler InsertBB = PrevBB; 2017a34c753fSRafael Auler } else { 2018a34c753fSRafael Auler MCSymbol *Label; 2019a34c753fSRafael Auler { 2020a34c753fSRafael Auler auto L = BC.scopeLock(); 2021a34c753fSRafael Auler Label = BC.Ctx->createNamedTempSymbol("FT"); 2022a34c753fSRafael Auler } 20238228c703SMaksim Panchenko InsertBB = addBasicBlockAt(Offset, Label); 20248228c703SMaksim Panchenko if (opts::PreserveBlocksAlignment && IsLastInstrNop) 20258228c703SMaksim Panchenko InsertBB->setDerivedAlignment(); 2026a34c753fSRafael Auler updateOffset(LastInstrOffset); 2027a34c753fSRafael Auler } 2028a34c753fSRafael Auler } 20290b7e8bafSDenis Revunov if (Offset == getFirstInstructionOffset()) { 20300b7e8bafSDenis Revunov // Add associated CFI pseudos in the first offset 20310b7e8bafSDenis Revunov addCFIPlaceholders(Offset, InsertBB); 2032a34c753fSRafael Auler } 2033a34c753fSRafael Auler 2034a34c753fSRafael Auler const bool IsBlockEnd = MIB->isTerminator(Instr); 2035a34c753fSRafael Auler IsLastInstrNop = MIB->isNoop(Instr); 2036ccb99dd1SMaksim Panchenko if (!IsLastInstrNop) 2037a34c753fSRafael Auler LastInstrOffset = Offset; 2038a34c753fSRafael Auler InsertBB->addInstruction(std::move(Instr)); 2039a34c753fSRafael Auler 2040a34c753fSRafael Auler // Add associated CFI instrs. We always add the CFI instruction that is 2041a34c753fSRafael Auler // located immediately after this instruction, since the next CFI 2042a34c753fSRafael Auler // instruction reflects the change in state caused by this instruction. 2043a34c753fSRafael Auler auto NextInstr = std::next(I); 2044a34c753fSRafael Auler uint64_t CFIOffset; 2045a34c753fSRafael Auler if (NextInstr != E) 2046a34c753fSRafael Auler CFIOffset = NextInstr->first; 2047a34c753fSRafael Auler else 2048a34c753fSRafael Auler CFIOffset = getSize(); 2049a34c753fSRafael Auler 2050a34c753fSRafael Auler // Note: this potentially invalidates instruction pointers/iterators. 2051a34c753fSRafael Auler addCFIPlaceholders(CFIOffset, InsertBB); 2052a34c753fSRafael Auler 2053a34c753fSRafael Auler if (IsBlockEnd) { 2054a34c753fSRafael Auler PrevBB = InsertBB; 2055a34c753fSRafael Auler InsertBB = nullptr; 2056a34c753fSRafael Auler } 2057a34c753fSRafael Auler } 2058a34c753fSRafael Auler 2059a34c753fSRafael Auler if (BasicBlocks.empty()) { 2060a34c753fSRafael Auler setSimple(false); 2061a34c753fSRafael Auler return false; 2062a34c753fSRafael Auler } 2063a34c753fSRafael Auler 2064a34c753fSRafael Auler // Intermediate dump. 2065a34c753fSRafael Auler LLVM_DEBUG(print(dbgs(), "after creating basic blocks")); 2066a34c753fSRafael Auler 2067a34c753fSRafael Auler // TODO: handle properly calls to no-return functions, 2068a34c753fSRafael Auler // e.g. exit(3), etc. Otherwise we'll see a false fall-through 2069a34c753fSRafael Auler // blocks. 2070a34c753fSRafael Auler 2071a34c753fSRafael Auler for (std::pair<uint32_t, uint32_t> &Branch : TakenBranches) { 2072a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "registering branch [0x" 2073a34c753fSRafael Auler << Twine::utohexstr(Branch.first) << "] -> [0x" 2074a34c753fSRafael Auler << Twine::utohexstr(Branch.second) << "]\n"); 2075a34c753fSRafael Auler BinaryBasicBlock *FromBB = getBasicBlockContainingOffset(Branch.first); 2076a34c753fSRafael Auler BinaryBasicBlock *ToBB = getBasicBlockAtOffset(Branch.second); 2077a34c753fSRafael Auler if (!FromBB || !ToBB) { 2078a34c753fSRafael Auler if (!FromBB) 2079a34c753fSRafael Auler errs() << "BOLT-ERROR: cannot find BB containing the branch.\n"; 2080a34c753fSRafael Auler if (!ToBB) 2081a34c753fSRafael Auler errs() << "BOLT-ERROR: cannot find BB containing branch destination.\n"; 2082a34c753fSRafael Auler BC.exitWithBugReport("disassembly failed - inconsistent branch found.", 2083a34c753fSRafael Auler *this); 2084a34c753fSRafael Auler } 2085a34c753fSRafael Auler 2086a34c753fSRafael Auler FromBB->addSuccessor(ToBB); 2087a34c753fSRafael Auler } 2088a34c753fSRafael Auler 2089a34c753fSRafael Auler // Add fall-through branches. 2090a34c753fSRafael Auler PrevBB = nullptr; 2091a34c753fSRafael Auler bool IsPrevFT = false; // Is previous block a fall-through. 2092a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 20933652483cSRafael Auler if (IsPrevFT) 2094a34c753fSRafael Auler PrevBB->addSuccessor(BB); 20953652483cSRafael Auler 2096a34c753fSRafael Auler if (BB->empty()) { 2097a34c753fSRafael Auler IsPrevFT = true; 2098a34c753fSRafael Auler PrevBB = BB; 2099a34c753fSRafael Auler continue; 2100a34c753fSRafael Auler } 2101a34c753fSRafael Auler 2102a34c753fSRafael Auler MCInst *LastInstr = BB->getLastNonPseudoInstr(); 2103a34c753fSRafael Auler assert(LastInstr && 2104a34c753fSRafael Auler "should have non-pseudo instruction in non-empty block"); 2105a34c753fSRafael Auler 2106a34c753fSRafael Auler if (BB->succ_size() == 0) { 2107a34c753fSRafael Auler // Since there's no existing successors, we know the last instruction is 2108a34c753fSRafael Auler // not a conditional branch. Thus if it's a terminator, it shouldn't be a 2109a34c753fSRafael Auler // fall-through. 2110a34c753fSRafael Auler // 2111a34c753fSRafael Auler // Conditional tail call is a special case since we don't add a taken 2112a34c753fSRafael Auler // branch successor for it. 2113a34c753fSRafael Auler IsPrevFT = !MIB->isTerminator(*LastInstr) || 2114a34c753fSRafael Auler MIB->getConditionalTailCall(*LastInstr); 2115a34c753fSRafael Auler } else if (BB->succ_size() == 1) { 2116a34c753fSRafael Auler IsPrevFT = MIB->isConditionalBranch(*LastInstr); 2117a34c753fSRafael Auler } else { 2118a34c753fSRafael Auler IsPrevFT = false; 2119a34c753fSRafael Auler } 2120a34c753fSRafael Auler 2121a34c753fSRafael Auler PrevBB = BB; 2122a34c753fSRafael Auler } 2123a34c753fSRafael Auler 2124a34c753fSRafael Auler // Assign landing pads and throwers info. 2125a34c753fSRafael Auler recomputeLandingPads(); 2126a34c753fSRafael Auler 2127a34c753fSRafael Auler // Assign CFI information to each BB entry. 2128a34c753fSRafael Auler annotateCFIState(); 2129a34c753fSRafael Auler 2130a34c753fSRafael Auler // Annotate invoke instructions with GNU_args_size data. 2131a34c753fSRafael Auler propagateGnuArgsSizeInfo(AllocatorId); 2132a34c753fSRafael Auler 2133a34c753fSRafael Auler // Set the basic block layout to the original order and set end offsets. 2134a34c753fSRafael Auler PrevBB = nullptr; 2135a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 21368477bc67SFabian Parzefall Layout.addBasicBlock(BB); 2137a34c753fSRafael Auler if (PrevBB) 2138a34c753fSRafael Auler PrevBB->setEndOffset(BB->getOffset()); 2139a34c753fSRafael Auler PrevBB = BB; 2140a34c753fSRafael Auler } 2141a34c753fSRafael Auler PrevBB->setEndOffset(getSize()); 2142a34c753fSRafael Auler 21438477bc67SFabian Parzefall Layout.updateLayoutIndices(); 2144a34c753fSRafael Auler 2145a34c753fSRafael Auler normalizeCFIState(); 2146a34c753fSRafael Auler 2147a34c753fSRafael Auler // Clean-up memory taken by intermediate structures. 2148a34c753fSRafael Auler // 2149a34c753fSRafael Auler // NB: don't clear Labels list as we may need them if we mark the function 2150a34c753fSRafael Auler // as non-simple later in the process of discovering extra entry points. 2151a34c753fSRafael Auler clearList(Instructions); 2152a34c753fSRafael Auler clearList(OffsetToCFI); 2153a34c753fSRafael Auler clearList(TakenBranches); 2154a34c753fSRafael Auler 2155a34c753fSRafael Auler // Update the state. 2156a34c753fSRafael Auler CurrentState = State::CFG; 2157a34c753fSRafael Auler 2158a34c753fSRafael Auler // Make any necessary adjustments for indirect branches. 2159a34c753fSRafael Auler if (!postProcessIndirectBranches(AllocatorId)) { 2160a34c753fSRafael Auler if (opts::Verbosity) { 2161a34c753fSRafael Auler errs() << "BOLT-WARNING: failed to post-process indirect branches for " 2162a34c753fSRafael Auler << *this << '\n'; 2163a34c753fSRafael Auler } 2164a34c753fSRafael Auler // In relocation mode we want to keep processing the function but avoid 2165a34c753fSRafael Auler // optimizing it. 2166a34c753fSRafael Auler setSimple(false); 2167a34c753fSRafael Auler } 2168a34c753fSRafael Auler 2169a34c753fSRafael Auler clearList(ExternallyReferencedOffsets); 2170a34c753fSRafael Auler clearList(UnknownIndirectBranchOffsets); 2171a34c753fSRafael Auler 2172a34c753fSRafael Auler return true; 2173a34c753fSRafael Auler } 2174a34c753fSRafael Auler 2175a34c753fSRafael Auler void BinaryFunction::postProcessCFG() { 2176a34c753fSRafael Auler if (isSimple() && !BasicBlocks.empty()) { 2177a34c753fSRafael Auler // Convert conditional tail call branches to conditional branches that jump 2178a34c753fSRafael Auler // to a tail call. 2179a34c753fSRafael Auler removeConditionalTailCalls(); 2180a34c753fSRafael Auler 2181a34c753fSRafael Auler postProcessProfile(); 2182a34c753fSRafael Auler 2183a34c753fSRafael Auler // Eliminate inconsistencies between branch instructions and CFG. 2184a34c753fSRafael Auler postProcessBranches(); 2185a34c753fSRafael Auler } 2186a34c753fSRafael Auler 2187a34c753fSRafael Auler calculateMacroOpFusionStats(); 2188a34c753fSRafael Auler 2189a34c753fSRafael Auler // The final cleanup of intermediate structures. 2190a34c753fSRafael Auler clearList(IgnoredBranches); 2191a34c753fSRafael Auler 2192a34c753fSRafael Auler // Remove "Offset" annotations, unless we need an address-translation table 2193a34c753fSRafael Auler // later. This has no cost, since annotations are allocated by a bumpptr 2194a34c753fSRafael Auler // allocator and won't be released anyway until late in the pipeline. 21953652483cSRafael Auler if (!requiresAddressTranslation() && !opts::Instrument) { 2196d55dfeafSFabian Parzefall for (BinaryBasicBlock &BB : blocks()) 2197d55dfeafSFabian Parzefall for (MCInst &Inst : BB) 2198a9cd49d5SAmir Ayupov BC.MIB->clearOffset(Inst); 21993652483cSRafael Auler } 2200a34c753fSRafael Auler 2201a34c753fSRafael Auler assert((!isSimple() || validateCFG()) && 2202a34c753fSRafael Auler "invalid CFG detected after post-processing"); 2203a34c753fSRafael Auler } 2204a34c753fSRafael Auler 2205a34c753fSRafael Auler void BinaryFunction::calculateMacroOpFusionStats() { 2206a34c753fSRafael Auler if (!getBinaryContext().isX86()) 2207a34c753fSRafael Auler return; 2208d55dfeafSFabian Parzefall for (const BinaryBasicBlock &BB : blocks()) { 2209d55dfeafSFabian Parzefall auto II = BB.getMacroOpFusionPair(); 2210d55dfeafSFabian Parzefall if (II == BB.end()) 2211a34c753fSRafael Auler continue; 2212a34c753fSRafael Auler 2213a34c753fSRafael Auler // Check offset of the second instruction. 2214a34c753fSRafael Auler // FIXME: arch-specific. 2215a9cd49d5SAmir Ayupov const uint32_t Offset = BC.MIB->getOffsetWithDefault(*std::next(II), 0); 2216a34c753fSRafael Auler if (!Offset || (getAddress() + Offset) % 64) 2217a34c753fSRafael Auler continue; 2218a34c753fSRafael Auler 2219a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\nmissed macro-op fusion at address 0x" 2220a34c753fSRafael Auler << Twine::utohexstr(getAddress() + Offset) 2221a34c753fSRafael Auler << " in function " << *this << "; executed " 2222d55dfeafSFabian Parzefall << BB.getKnownExecutionCount() << " times.\n"); 222331e8a9f4Sspupyrev ++BC.Stats.MissedMacroFusionPairs; 222431e8a9f4Sspupyrev BC.Stats.MissedMacroFusionExecCount += BB.getKnownExecutionCount(); 2225a34c753fSRafael Auler } 2226a34c753fSRafael Auler } 2227a34c753fSRafael Auler 2228a34c753fSRafael Auler void BinaryFunction::removeTagsFromProfile() { 2229a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 2230a34c753fSRafael Auler if (BB->ExecutionCount == BinaryBasicBlock::COUNT_NO_PROFILE) 2231a34c753fSRafael Auler BB->ExecutionCount = 0; 2232a34c753fSRafael Auler for (BinaryBasicBlock::BinaryBranchInfo &BI : BB->branch_info()) { 2233a34c753fSRafael Auler if (BI.Count != BinaryBasicBlock::COUNT_NO_PROFILE && 2234a34c753fSRafael Auler BI.MispredictedCount != BinaryBasicBlock::COUNT_NO_PROFILE) 2235a34c753fSRafael Auler continue; 2236a34c753fSRafael Auler BI.Count = 0; 2237a34c753fSRafael Auler BI.MispredictedCount = 0; 2238a34c753fSRafael Auler } 2239a34c753fSRafael Auler } 2240a34c753fSRafael Auler } 2241a34c753fSRafael Auler 2242a34c753fSRafael Auler void BinaryFunction::removeConditionalTailCalls() { 2243a34c753fSRafael Auler // Blocks to be appended at the end. 2244a34c753fSRafael Auler std::vector<std::unique_ptr<BinaryBasicBlock>> NewBlocks; 2245a34c753fSRafael Auler 2246a34c753fSRafael Auler for (auto BBI = begin(); BBI != end(); ++BBI) { 2247a34c753fSRafael Auler BinaryBasicBlock &BB = *BBI; 2248a34c753fSRafael Auler MCInst *CTCInstr = BB.getLastNonPseudoInstr(); 2249a34c753fSRafael Auler if (!CTCInstr) 2250a34c753fSRafael Auler continue; 2251a34c753fSRafael Auler 22522563fd63SAmir Ayupov std::optional<uint64_t> TargetAddressOrNone = 2253a34c753fSRafael Auler BC.MIB->getConditionalTailCall(*CTCInstr); 2254a34c753fSRafael Auler if (!TargetAddressOrNone) 2255a34c753fSRafael Auler continue; 2256a34c753fSRafael Auler 2257a34c753fSRafael Auler // Gather all necessary information about CTC instruction before 2258a34c753fSRafael Auler // annotations are destroyed. 2259a34c753fSRafael Auler const int32_t CFIStateBeforeCTC = BB.getCFIStateAtInstr(CTCInstr); 2260a34c753fSRafael Auler uint64_t CTCTakenCount = BinaryBasicBlock::COUNT_NO_PROFILE; 2261a34c753fSRafael Auler uint64_t CTCMispredCount = BinaryBasicBlock::COUNT_NO_PROFILE; 2262a34c753fSRafael Auler if (hasValidProfile()) { 226340c2e0faSMaksim Panchenko CTCTakenCount = BC.MIB->getAnnotationWithDefault<uint64_t>( 226440c2e0faSMaksim Panchenko *CTCInstr, "CTCTakenCount"); 226540c2e0faSMaksim Panchenko CTCMispredCount = BC.MIB->getAnnotationWithDefault<uint64_t>( 226640c2e0faSMaksim Panchenko *CTCInstr, "CTCMispredCount"); 2267a34c753fSRafael Auler } 2268a34c753fSRafael Auler 2269a34c753fSRafael Auler // Assert that the tail call does not throw. 2270a34c753fSRafael Auler assert(!BC.MIB->getEHInfo(*CTCInstr) && 2271a34c753fSRafael Auler "found tail call with associated landing pad"); 2272a34c753fSRafael Auler 2273a34c753fSRafael Auler // Create a basic block with an unconditional tail call instruction using 2274a34c753fSRafael Auler // the same destination. 2275a34c753fSRafael Auler const MCSymbol *CTCTargetLabel = BC.MIB->getTargetSymbol(*CTCInstr); 2276a34c753fSRafael Auler assert(CTCTargetLabel && "symbol expected for conditional tail call"); 2277a34c753fSRafael Auler MCInst TailCallInstr; 2278a34c753fSRafael Auler BC.MIB->createTailCall(TailCallInstr, CTCTargetLabel, BC.Ctx.get()); 2279a34c753fSRafael Auler // Link new BBs to the original input offset of the BB where the CTC 2280a34c753fSRafael Auler // is, so we can map samples recorded in new BBs back to the original BB 2281a34c753fSRafael Auler // seem in the input binary (if using BAT) 22828228c703SMaksim Panchenko std::unique_ptr<BinaryBasicBlock> TailCallBB = 22838228c703SMaksim Panchenko createBasicBlock(BC.Ctx->createNamedTempSymbol("TC")); 22848228c703SMaksim Panchenko TailCallBB->setOffset(BB.getInputOffset()); 2285a34c753fSRafael Auler TailCallBB->addInstruction(TailCallInstr); 2286a34c753fSRafael Auler TailCallBB->setCFIState(CFIStateBeforeCTC); 2287a34c753fSRafael Auler 2288a34c753fSRafael Auler // Add CFG edge with profile info from BB to TailCallBB. 2289a34c753fSRafael Auler BB.addSuccessor(TailCallBB.get(), CTCTakenCount, CTCMispredCount); 2290a34c753fSRafael Auler 2291a34c753fSRafael Auler // Add execution count for the block. 2292a34c753fSRafael Auler TailCallBB->setExecutionCount(CTCTakenCount); 2293a34c753fSRafael Auler 2294a34c753fSRafael Auler BC.MIB->convertTailCallToJmp(*CTCInstr); 2295a34c753fSRafael Auler 2296a34c753fSRafael Auler BC.MIB->replaceBranchTarget(*CTCInstr, TailCallBB->getLabel(), 2297a34c753fSRafael Auler BC.Ctx.get()); 2298a34c753fSRafael Auler 2299a34c753fSRafael Auler // Add basic block to the list that will be added to the end. 2300a34c753fSRafael Auler NewBlocks.emplace_back(std::move(TailCallBB)); 2301a34c753fSRafael Auler 2302a34c753fSRafael Auler // Swap edges as the TailCallBB corresponds to the taken branch. 2303a34c753fSRafael Auler BB.swapConditionalSuccessors(); 2304a34c753fSRafael Auler 2305a34c753fSRafael Auler // This branch is no longer a conditional tail call. 2306a34c753fSRafael Auler BC.MIB->unsetConditionalTailCall(*CTCInstr); 230770e76e09SAmir Ayupov 230870e76e09SAmir Ayupov // Move offset from CTCInstr to TailCallInstr. 230970e76e09SAmir Ayupov if (std::optional<uint32_t> Offset = BC.MIB->getOffset(*CTCInstr)) { 231070e76e09SAmir Ayupov BC.MIB->setOffset(TailCallInstr, *Offset); 231170e76e09SAmir Ayupov BC.MIB->clearOffset(*CTCInstr); 231270e76e09SAmir Ayupov } 2313a34c753fSRafael Auler } 2314a34c753fSRafael Auler 231540c2e0faSMaksim Panchenko insertBasicBlocks(std::prev(end()), std::move(NewBlocks), 2316a34c753fSRafael Auler /* UpdateLayout */ true, 2317a34c753fSRafael Auler /* UpdateCFIState */ false); 2318a34c753fSRafael Auler } 2319a34c753fSRafael Auler 2320a34c753fSRafael Auler uint64_t BinaryFunction::getFunctionScore() const { 2321a34c753fSRafael Auler if (FunctionScore != -1) 2322a34c753fSRafael Auler return FunctionScore; 2323a34c753fSRafael Auler 2324a34c753fSRafael Auler if (!isSimple() || !hasValidProfile()) { 2325a34c753fSRafael Auler FunctionScore = 0; 2326a34c753fSRafael Auler return FunctionScore; 2327a34c753fSRafael Auler } 2328a34c753fSRafael Auler 2329a34c753fSRafael Auler uint64_t TotalScore = 0ULL; 2330d55dfeafSFabian Parzefall for (const BinaryBasicBlock &BB : blocks()) { 2331d55dfeafSFabian Parzefall uint64_t BBExecCount = BB.getExecutionCount(); 2332a34c753fSRafael Auler if (BBExecCount == BinaryBasicBlock::COUNT_NO_PROFILE) 2333a34c753fSRafael Auler continue; 2334d55dfeafSFabian Parzefall TotalScore += BBExecCount * BB.getNumNonPseudos(); 2335a34c753fSRafael Auler } 2336a34c753fSRafael Auler FunctionScore = TotalScore; 2337a34c753fSRafael Auler return FunctionScore; 2338a34c753fSRafael Auler } 2339a34c753fSRafael Auler 2340a34c753fSRafael Auler void BinaryFunction::annotateCFIState() { 2341a34c753fSRafael Auler assert(CurrentState == State::Disassembled && "unexpected function state"); 2342a34c753fSRafael Auler assert(!BasicBlocks.empty() && "basic block list should not be empty"); 2343a34c753fSRafael Auler 2344a34c753fSRafael Auler // This is an index of the last processed CFI in FDE CFI program. 2345a34c753fSRafael Auler uint32_t State = 0; 2346a34c753fSRafael Auler 2347a34c753fSRafael Auler // This is an index of RememberState CFI reflecting effective state right 2348a34c753fSRafael Auler // after execution of RestoreState CFI. 2349a34c753fSRafael Auler // 2350a34c753fSRafael Auler // It differs from State iff the CFI at (State-1) 2351a34c753fSRafael Auler // was RestoreState (modulo GNU_args_size CFIs, which are ignored). 2352a34c753fSRafael Auler // 2353a34c753fSRafael Auler // This allows us to generate shorter replay sequences when producing new 2354a34c753fSRafael Auler // CFI programs. 2355a34c753fSRafael Auler uint32_t EffectiveState = 0; 2356a34c753fSRafael Auler 2357a34c753fSRafael Auler // For tracking RememberState/RestoreState sequences. 2358a34c753fSRafael Auler std::stack<uint32_t> StateStack; 2359a34c753fSRafael Auler 2360a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 2361a34c753fSRafael Auler BB->setCFIState(EffectiveState); 2362a34c753fSRafael Auler 2363a34c753fSRafael Auler for (const MCInst &Instr : *BB) { 2364a34c753fSRafael Auler const MCCFIInstruction *CFI = getCFIFor(Instr); 2365a34c753fSRafael Auler if (!CFI) 2366a34c753fSRafael Auler continue; 2367a34c753fSRafael Auler 2368a34c753fSRafael Auler ++State; 2369a34c753fSRafael Auler 2370a34c753fSRafael Auler switch (CFI->getOperation()) { 2371a34c753fSRafael Auler case MCCFIInstruction::OpRememberState: 2372a34c753fSRafael Auler StateStack.push(EffectiveState); 2373a34c753fSRafael Auler EffectiveState = State; 2374a34c753fSRafael Auler break; 2375a34c753fSRafael Auler case MCCFIInstruction::OpRestoreState: 2376a34c753fSRafael Auler assert(!StateStack.empty() && "corrupt CFI stack"); 2377a34c753fSRafael Auler EffectiveState = StateStack.top(); 2378a34c753fSRafael Auler StateStack.pop(); 2379a34c753fSRafael Auler break; 2380a34c753fSRafael Auler case MCCFIInstruction::OpGnuArgsSize: 2381a34c753fSRafael Auler // OpGnuArgsSize CFIs do not affect the CFI state. 2382a34c753fSRafael Auler break; 2383a34c753fSRafael Auler default: 2384a34c753fSRafael Auler // Any other CFI updates the state. 2385a34c753fSRafael Auler EffectiveState = State; 2386a34c753fSRafael Auler break; 2387a34c753fSRafael Auler } 2388a34c753fSRafael Auler } 2389a34c753fSRafael Auler } 2390a34c753fSRafael Auler 2391a34c753fSRafael Auler assert(StateStack.empty() && "corrupt CFI stack"); 2392a34c753fSRafael Auler } 2393a34c753fSRafael Auler 2394a34c753fSRafael Auler namespace { 2395a34c753fSRafael Auler 2396a34c753fSRafael Auler /// Our full interpretation of a DWARF CFI machine state at a given point 2397a34c753fSRafael Auler struct CFISnapshot { 2398a34c753fSRafael Auler /// CFA register number and offset defining the canonical frame at this 2399a34c753fSRafael Auler /// point, or the number of a rule (CFI state) that computes it with a 2400a34c753fSRafael Auler /// DWARF expression. This number will be negative if it refers to a CFI 2401a34c753fSRafael Auler /// located in the CIE instead of the FDE. 2402a34c753fSRafael Auler uint32_t CFAReg; 2403a34c753fSRafael Auler int32_t CFAOffset; 2404a34c753fSRafael Auler int32_t CFARule; 2405a34c753fSRafael Auler /// Mapping of rules (CFI states) that define the location of each 2406a34c753fSRafael Auler /// register. If absent, no rule defining the location of such register 2407a34c753fSRafael Auler /// was ever read. This number will be negative if it refers to a CFI 2408a34c753fSRafael Auler /// located in the CIE instead of the FDE. 2409a34c753fSRafael Auler DenseMap<int32_t, int32_t> RegRule; 2410a34c753fSRafael Auler 2411a34c753fSRafael Auler /// References to CIE, FDE and expanded instructions after a restore state 2412ebe51c4dSMaksim Panchenko const BinaryFunction::CFIInstrMapType &CIE; 2413ebe51c4dSMaksim Panchenko const BinaryFunction::CFIInstrMapType &FDE; 2414a34c753fSRafael Auler const DenseMap<int32_t, SmallVector<int32_t, 4>> &FrameRestoreEquivalents; 2415a34c753fSRafael Auler 2416a34c753fSRafael Auler /// Current FDE CFI number representing the state where the snapshot is at 2417a34c753fSRafael Auler int32_t CurState; 2418a34c753fSRafael Auler 2419a34c753fSRafael Auler /// Used when we don't have information about which state/rule to apply 2420a34c753fSRafael Auler /// to recover the location of either the CFA or a specific register 2421a34c753fSRafael Auler constexpr static int32_t UNKNOWN = std::numeric_limits<int32_t>::min(); 2422a34c753fSRafael Auler 2423a34c753fSRafael Auler private: 2424a34c753fSRafael Auler /// Update our snapshot by executing a single CFI 2425a34c753fSRafael Auler void update(const MCCFIInstruction &Instr, int32_t RuleNumber) { 2426a34c753fSRafael Auler switch (Instr.getOperation()) { 2427a34c753fSRafael Auler case MCCFIInstruction::OpSameValue: 2428a34c753fSRafael Auler case MCCFIInstruction::OpRelOffset: 2429a34c753fSRafael Auler case MCCFIInstruction::OpOffset: 2430a34c753fSRafael Auler case MCCFIInstruction::OpRestore: 2431a34c753fSRafael Auler case MCCFIInstruction::OpUndefined: 2432a34c753fSRafael Auler case MCCFIInstruction::OpRegister: 2433a34c753fSRafael Auler RegRule[Instr.getRegister()] = RuleNumber; 2434a34c753fSRafael Auler break; 2435a34c753fSRafael Auler case MCCFIInstruction::OpDefCfaRegister: 2436a34c753fSRafael Auler CFAReg = Instr.getRegister(); 2437a34c753fSRafael Auler CFARule = UNKNOWN; 2438a34c753fSRafael Auler break; 2439a34c753fSRafael Auler case MCCFIInstruction::OpDefCfaOffset: 2440a34c753fSRafael Auler CFAOffset = Instr.getOffset(); 2441a34c753fSRafael Auler CFARule = UNKNOWN; 2442a34c753fSRafael Auler break; 2443a34c753fSRafael Auler case MCCFIInstruction::OpDefCfa: 2444a34c753fSRafael Auler CFAReg = Instr.getRegister(); 2445a34c753fSRafael Auler CFAOffset = Instr.getOffset(); 2446a34c753fSRafael Auler CFARule = UNKNOWN; 2447a34c753fSRafael Auler break; 2448a34c753fSRafael Auler case MCCFIInstruction::OpEscape: { 244976cfea0cSAmir Ayupov std::optional<uint8_t> Reg = 245076cfea0cSAmir Ayupov readDWARFExpressionTargetReg(Instr.getValues()); 2451a34c753fSRafael Auler // Handle DW_CFA_def_cfa_expression 2452a34c753fSRafael Auler if (!Reg) { 2453a34c753fSRafael Auler CFARule = RuleNumber; 2454a34c753fSRafael Auler break; 2455a34c753fSRafael Auler } 2456a34c753fSRafael Auler RegRule[*Reg] = RuleNumber; 2457a34c753fSRafael Auler break; 2458a34c753fSRafael Auler } 2459a34c753fSRafael Auler case MCCFIInstruction::OpAdjustCfaOffset: 2460a34c753fSRafael Auler case MCCFIInstruction::OpWindowSave: 2461a34c753fSRafael Auler case MCCFIInstruction::OpNegateRAState: 2462a34c753fSRafael Auler case MCCFIInstruction::OpLLVMDefAspaceCfa: 2463a34c753fSRafael Auler llvm_unreachable("unsupported CFI opcode"); 2464a34c753fSRafael Auler break; 2465a34c753fSRafael Auler case MCCFIInstruction::OpRememberState: 2466a34c753fSRafael Auler case MCCFIInstruction::OpRestoreState: 2467a34c753fSRafael Auler case MCCFIInstruction::OpGnuArgsSize: 2468a34c753fSRafael Auler // do not affect CFI state 2469a34c753fSRafael Auler break; 2470a34c753fSRafael Auler } 2471a34c753fSRafael Auler } 2472a34c753fSRafael Auler 2473a34c753fSRafael Auler public: 2474a34c753fSRafael Auler /// Advance state reading FDE CFI instructions up to State number 2475a34c753fSRafael Auler void advanceTo(int32_t State) { 2476a34c753fSRafael Auler for (int32_t I = CurState, E = State; I != E; ++I) { 2477a34c753fSRafael Auler const MCCFIInstruction &Instr = FDE[I]; 2478a34c753fSRafael Auler if (Instr.getOperation() != MCCFIInstruction::OpRestoreState) { 2479a34c753fSRafael Auler update(Instr, I); 2480a34c753fSRafael Auler continue; 2481a34c753fSRafael Auler } 2482a34c753fSRafael Auler // If restore state instruction, fetch the equivalent CFIs that have 2483a34c753fSRafael Auler // the same effect of this restore. This is used to ensure remember- 2484a34c753fSRafael Auler // restore pairs are completely removed. 2485a34c753fSRafael Auler auto Iter = FrameRestoreEquivalents.find(I); 2486a34c753fSRafael Auler if (Iter == FrameRestoreEquivalents.end()) 2487a34c753fSRafael Auler continue; 24883652483cSRafael Auler for (int32_t RuleNumber : Iter->second) 2489a34c753fSRafael Auler update(FDE[RuleNumber], RuleNumber); 2490a34c753fSRafael Auler } 2491a34c753fSRafael Auler 2492a34c753fSRafael Auler assert(((CFAReg != (uint32_t)UNKNOWN && CFAOffset != UNKNOWN) || 2493a34c753fSRafael Auler CFARule != UNKNOWN) && 2494a34c753fSRafael Auler "CIE did not define default CFA?"); 2495a34c753fSRafael Auler 2496a34c753fSRafael Auler CurState = State; 2497a34c753fSRafael Auler } 2498a34c753fSRafael Auler 2499a34c753fSRafael Auler /// Interpret all CIE and FDE instructions up until CFI State number and 2500a34c753fSRafael Auler /// populate this snapshot 2501a34c753fSRafael Auler CFISnapshot( 2502ebe51c4dSMaksim Panchenko const BinaryFunction::CFIInstrMapType &CIE, 2503ebe51c4dSMaksim Panchenko const BinaryFunction::CFIInstrMapType &FDE, 2504a34c753fSRafael Auler const DenseMap<int32_t, SmallVector<int32_t, 4>> &FrameRestoreEquivalents, 2505a34c753fSRafael Auler int32_t State) 2506a34c753fSRafael Auler : CIE(CIE), FDE(FDE), FrameRestoreEquivalents(FrameRestoreEquivalents) { 2507a34c753fSRafael Auler CFAReg = UNKNOWN; 2508a34c753fSRafael Auler CFAOffset = UNKNOWN; 2509a34c753fSRafael Auler CFARule = UNKNOWN; 2510a34c753fSRafael Auler CurState = 0; 2511a34c753fSRafael Auler 2512a34c753fSRafael Auler for (int32_t I = 0, E = CIE.size(); I != E; ++I) { 2513a34c753fSRafael Auler const MCCFIInstruction &Instr = CIE[I]; 2514a34c753fSRafael Auler update(Instr, -I); 2515a34c753fSRafael Auler } 2516a34c753fSRafael Auler 2517a34c753fSRafael Auler advanceTo(State); 2518a34c753fSRafael Auler } 2519a34c753fSRafael Auler }; 2520a34c753fSRafael Auler 2521a34c753fSRafael Auler /// A CFI snapshot with the capability of checking if incremental additions to 2522a34c753fSRafael Auler /// it are redundant. This is used to ensure we do not emit two CFI instructions 2523a34c753fSRafael Auler /// back-to-back that are doing the same state change, or to avoid emitting a 2524a34c753fSRafael Auler /// CFI at all when the state at that point would not be modified after that CFI 2525a34c753fSRafael Auler struct CFISnapshotDiff : public CFISnapshot { 2526a34c753fSRafael Auler bool RestoredCFAReg{false}; 2527a34c753fSRafael Auler bool RestoredCFAOffset{false}; 2528a34c753fSRafael Auler DenseMap<int32_t, bool> RestoredRegs; 2529a34c753fSRafael Auler 2530a34c753fSRafael Auler CFISnapshotDiff(const CFISnapshot &S) : CFISnapshot(S) {} 2531a34c753fSRafael Auler 2532a34c753fSRafael Auler CFISnapshotDiff( 2533ebe51c4dSMaksim Panchenko const BinaryFunction::CFIInstrMapType &CIE, 2534ebe51c4dSMaksim Panchenko const BinaryFunction::CFIInstrMapType &FDE, 2535a34c753fSRafael Auler const DenseMap<int32_t, SmallVector<int32_t, 4>> &FrameRestoreEquivalents, 2536a34c753fSRafael Auler int32_t State) 2537a34c753fSRafael Auler : CFISnapshot(CIE, FDE, FrameRestoreEquivalents, State) {} 2538a34c753fSRafael Auler 2539a34c753fSRafael Auler /// Return true if applying Instr to this state is redundant and can be 2540a34c753fSRafael Auler /// dismissed. 2541a34c753fSRafael Auler bool isRedundant(const MCCFIInstruction &Instr) { 2542a34c753fSRafael Auler switch (Instr.getOperation()) { 2543a34c753fSRafael Auler case MCCFIInstruction::OpSameValue: 2544a34c753fSRafael Auler case MCCFIInstruction::OpRelOffset: 2545a34c753fSRafael Auler case MCCFIInstruction::OpOffset: 2546a34c753fSRafael Auler case MCCFIInstruction::OpRestore: 2547a34c753fSRafael Auler case MCCFIInstruction::OpUndefined: 2548a34c753fSRafael Auler case MCCFIInstruction::OpRegister: 2549a34c753fSRafael Auler case MCCFIInstruction::OpEscape: { 2550a34c753fSRafael Auler uint32_t Reg; 2551a34c753fSRafael Auler if (Instr.getOperation() != MCCFIInstruction::OpEscape) { 2552a34c753fSRafael Auler Reg = Instr.getRegister(); 2553a34c753fSRafael Auler } else { 255476cfea0cSAmir Ayupov std::optional<uint8_t> R = 255576cfea0cSAmir Ayupov readDWARFExpressionTargetReg(Instr.getValues()); 2556a34c753fSRafael Auler // Handle DW_CFA_def_cfa_expression 2557a34c753fSRafael Auler if (!R) { 2558a34c753fSRafael Auler if (RestoredCFAReg && RestoredCFAOffset) 2559a34c753fSRafael Auler return true; 2560a34c753fSRafael Auler RestoredCFAReg = true; 2561a34c753fSRafael Auler RestoredCFAOffset = true; 2562a34c753fSRafael Auler return false; 2563a34c753fSRafael Auler } 2564a34c753fSRafael Auler Reg = *R; 2565a34c753fSRafael Auler } 2566a34c753fSRafael Auler if (RestoredRegs[Reg]) 2567a34c753fSRafael Auler return true; 2568a34c753fSRafael Auler RestoredRegs[Reg] = true; 25694e585e51SKazu Hirata const int32_t CurRegRule = RegRule.contains(Reg) ? RegRule[Reg] : UNKNOWN; 2570a34c753fSRafael Auler if (CurRegRule == UNKNOWN) { 2571a34c753fSRafael Auler if (Instr.getOperation() == MCCFIInstruction::OpRestore || 2572a34c753fSRafael Auler Instr.getOperation() == MCCFIInstruction::OpSameValue) 2573a34c753fSRafael Auler return true; 2574a34c753fSRafael Auler return false; 2575a34c753fSRafael Auler } 2576a34c753fSRafael Auler const MCCFIInstruction &LastDef = 2577a34c753fSRafael Auler CurRegRule < 0 ? CIE[-CurRegRule] : FDE[CurRegRule]; 2578a34c753fSRafael Auler return LastDef == Instr; 2579a34c753fSRafael Auler } 2580a34c753fSRafael Auler case MCCFIInstruction::OpDefCfaRegister: 2581a34c753fSRafael Auler if (RestoredCFAReg) 2582a34c753fSRafael Auler return true; 2583a34c753fSRafael Auler RestoredCFAReg = true; 2584a34c753fSRafael Auler return CFAReg == Instr.getRegister(); 2585a34c753fSRafael Auler case MCCFIInstruction::OpDefCfaOffset: 2586a34c753fSRafael Auler if (RestoredCFAOffset) 2587a34c753fSRafael Auler return true; 2588a34c753fSRafael Auler RestoredCFAOffset = true; 2589a34c753fSRafael Auler return CFAOffset == Instr.getOffset(); 2590a34c753fSRafael Auler case MCCFIInstruction::OpDefCfa: 2591a34c753fSRafael Auler if (RestoredCFAReg && RestoredCFAOffset) 2592a34c753fSRafael Auler return true; 2593a34c753fSRafael Auler RestoredCFAReg = true; 2594a34c753fSRafael Auler RestoredCFAOffset = true; 2595a34c753fSRafael Auler return CFAReg == Instr.getRegister() && CFAOffset == Instr.getOffset(); 2596a34c753fSRafael Auler case MCCFIInstruction::OpAdjustCfaOffset: 2597a34c753fSRafael Auler case MCCFIInstruction::OpWindowSave: 2598a34c753fSRafael Auler case MCCFIInstruction::OpNegateRAState: 2599a34c753fSRafael Auler case MCCFIInstruction::OpLLVMDefAspaceCfa: 2600a34c753fSRafael Auler llvm_unreachable("unsupported CFI opcode"); 2601a34c753fSRafael Auler return false; 2602a34c753fSRafael Auler case MCCFIInstruction::OpRememberState: 2603a34c753fSRafael Auler case MCCFIInstruction::OpRestoreState: 2604a34c753fSRafael Auler case MCCFIInstruction::OpGnuArgsSize: 2605a34c753fSRafael Auler // do not affect CFI state 2606a34c753fSRafael Auler return true; 2607a34c753fSRafael Auler } 2608a34c753fSRafael Auler return false; 2609a34c753fSRafael Auler } 2610a34c753fSRafael Auler }; 2611a34c753fSRafael Auler 2612a34c753fSRafael Auler } // end anonymous namespace 2613a34c753fSRafael Auler 2614a34c753fSRafael Auler bool BinaryFunction::replayCFIInstrs(int32_t FromState, int32_t ToState, 2615a34c753fSRafael Auler BinaryBasicBlock *InBB, 2616a34c753fSRafael Auler BinaryBasicBlock::iterator InsertIt) { 2617a34c753fSRafael Auler if (FromState == ToState) 2618a34c753fSRafael Auler return true; 2619a34c753fSRafael Auler assert(FromState < ToState && "can only replay CFIs forward"); 2620a34c753fSRafael Auler 2621a34c753fSRafael Auler CFISnapshotDiff CFIDiff(CIEFrameInstructions, FrameInstructions, 2622a34c753fSRafael Auler FrameRestoreEquivalents, FromState); 2623a34c753fSRafael Auler 2624a34c753fSRafael Auler std::vector<uint32_t> NewCFIs; 2625a34c753fSRafael Auler for (int32_t CurState = FromState; CurState < ToState; ++CurState) { 2626a34c753fSRafael Auler MCCFIInstruction *Instr = &FrameInstructions[CurState]; 2627a34c753fSRafael Auler if (Instr->getOperation() == MCCFIInstruction::OpRestoreState) { 2628a34c753fSRafael Auler auto Iter = FrameRestoreEquivalents.find(CurState); 2629a34c753fSRafael Auler assert(Iter != FrameRestoreEquivalents.end()); 263040c2e0faSMaksim Panchenko NewCFIs.insert(NewCFIs.end(), Iter->second.begin(), Iter->second.end()); 2631a34c753fSRafael Auler // RestoreState / Remember will be filtered out later by CFISnapshotDiff, 2632a34c753fSRafael Auler // so we might as well fall-through here. 2633a34c753fSRafael Auler } 2634a34c753fSRafael Auler NewCFIs.push_back(CurState); 2635a34c753fSRafael Auler } 2636a34c753fSRafael Auler 2637a34c753fSRafael Auler // Replay instructions while avoiding duplicates 2638f40d25ddSAmir Ayupov for (int32_t State : llvm::reverse(NewCFIs)) { 2639f40d25ddSAmir Ayupov if (CFIDiff.isRedundant(FrameInstructions[State])) 2640a34c753fSRafael Auler continue; 2641f40d25ddSAmir Ayupov InsertIt = addCFIPseudo(InBB, InsertIt, State); 2642a34c753fSRafael Auler } 2643a34c753fSRafael Auler 2644a34c753fSRafael Auler return true; 2645a34c753fSRafael Auler } 2646a34c753fSRafael Auler 2647a34c753fSRafael Auler SmallVector<int32_t, 4> 2648a34c753fSRafael Auler BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState, 2649a34c753fSRafael Auler BinaryBasicBlock *InBB, 2650a34c753fSRafael Auler BinaryBasicBlock::iterator &InsertIt) { 2651a34c753fSRafael Auler SmallVector<int32_t, 4> NewStates; 2652a34c753fSRafael Auler 2653a34c753fSRafael Auler CFISnapshot ToCFITable(CIEFrameInstructions, FrameInstructions, 2654a34c753fSRafael Auler FrameRestoreEquivalents, ToState); 2655a34c753fSRafael Auler CFISnapshotDiff FromCFITable(ToCFITable); 2656a34c753fSRafael Auler FromCFITable.advanceTo(FromState); 2657a34c753fSRafael Auler 2658a34c753fSRafael Auler auto undoStateDefCfa = [&]() { 2659a34c753fSRafael Auler if (ToCFITable.CFARule == CFISnapshot::UNKNOWN) { 2660a34c753fSRafael Auler FrameInstructions.emplace_back(MCCFIInstruction::cfiDefCfa( 2661a34c753fSRafael Auler nullptr, ToCFITable.CFAReg, ToCFITable.CFAOffset)); 2662a34c753fSRafael Auler if (FromCFITable.isRedundant(FrameInstructions.back())) { 2663a34c753fSRafael Auler FrameInstructions.pop_back(); 2664a34c753fSRafael Auler return; 2665a34c753fSRafael Auler } 2666a34c753fSRafael Auler NewStates.push_back(FrameInstructions.size() - 1); 2667a34c753fSRafael Auler InsertIt = addCFIPseudo(InBB, InsertIt, FrameInstructions.size() - 1); 2668a34c753fSRafael Auler ++InsertIt; 2669a34c753fSRafael Auler } else if (ToCFITable.CFARule < 0) { 2670a34c753fSRafael Auler if (FromCFITable.isRedundant(CIEFrameInstructions[-ToCFITable.CFARule])) 2671a34c753fSRafael Auler return; 2672a34c753fSRafael Auler NewStates.push_back(FrameInstructions.size()); 2673a34c753fSRafael Auler InsertIt = addCFIPseudo(InBB, InsertIt, FrameInstructions.size()); 2674a34c753fSRafael Auler ++InsertIt; 2675a34c753fSRafael Auler FrameInstructions.emplace_back(CIEFrameInstructions[-ToCFITable.CFARule]); 2676a34c753fSRafael Auler } else if (!FromCFITable.isRedundant( 2677a34c753fSRafael Auler FrameInstructions[ToCFITable.CFARule])) { 2678a34c753fSRafael Auler NewStates.push_back(ToCFITable.CFARule); 2679a34c753fSRafael Auler InsertIt = addCFIPseudo(InBB, InsertIt, ToCFITable.CFARule); 2680a34c753fSRafael Auler ++InsertIt; 2681a34c753fSRafael Auler } 2682a34c753fSRafael Auler }; 2683a34c753fSRafael Auler 2684a34c753fSRafael Auler auto undoState = [&](const MCCFIInstruction &Instr) { 2685a34c753fSRafael Auler switch (Instr.getOperation()) { 2686a34c753fSRafael Auler case MCCFIInstruction::OpRememberState: 2687a34c753fSRafael Auler case MCCFIInstruction::OpRestoreState: 2688a34c753fSRafael Auler break; 2689a34c753fSRafael Auler case MCCFIInstruction::OpSameValue: 2690a34c753fSRafael Auler case MCCFIInstruction::OpRelOffset: 2691a34c753fSRafael Auler case MCCFIInstruction::OpOffset: 2692a34c753fSRafael Auler case MCCFIInstruction::OpRestore: 2693a34c753fSRafael Auler case MCCFIInstruction::OpUndefined: 2694a34c753fSRafael Auler case MCCFIInstruction::OpEscape: 2695a34c753fSRafael Auler case MCCFIInstruction::OpRegister: { 2696a34c753fSRafael Auler uint32_t Reg; 2697a34c753fSRafael Auler if (Instr.getOperation() != MCCFIInstruction::OpEscape) { 2698a34c753fSRafael Auler Reg = Instr.getRegister(); 2699a34c753fSRafael Auler } else { 270076cfea0cSAmir Ayupov std::optional<uint8_t> R = 270176cfea0cSAmir Ayupov readDWARFExpressionTargetReg(Instr.getValues()); 2702a34c753fSRafael Auler // Handle DW_CFA_def_cfa_expression 2703a34c753fSRafael Auler if (!R) { 2704a34c753fSRafael Auler undoStateDefCfa(); 2705a34c753fSRafael Auler return; 2706a34c753fSRafael Auler } 2707a34c753fSRafael Auler Reg = *R; 2708a34c753fSRafael Auler } 2709a34c753fSRafael Auler 27104e585e51SKazu Hirata if (!ToCFITable.RegRule.contains(Reg)) { 2711a34c753fSRafael Auler FrameInstructions.emplace_back( 2712a34c753fSRafael Auler MCCFIInstruction::createRestore(nullptr, Reg)); 2713a34c753fSRafael Auler if (FromCFITable.isRedundant(FrameInstructions.back())) { 2714a34c753fSRafael Auler FrameInstructions.pop_back(); 2715a34c753fSRafael Auler break; 2716a34c753fSRafael Auler } 2717a34c753fSRafael Auler NewStates.push_back(FrameInstructions.size() - 1); 2718a34c753fSRafael Auler InsertIt = addCFIPseudo(InBB, InsertIt, FrameInstructions.size() - 1); 2719a34c753fSRafael Auler ++InsertIt; 2720a34c753fSRafael Auler break; 2721a34c753fSRafael Auler } 2722a34c753fSRafael Auler const int32_t Rule = ToCFITable.RegRule[Reg]; 2723a34c753fSRafael Auler if (Rule < 0) { 2724a34c753fSRafael Auler if (FromCFITable.isRedundant(CIEFrameInstructions[-Rule])) 2725a34c753fSRafael Auler break; 2726a34c753fSRafael Auler NewStates.push_back(FrameInstructions.size()); 2727a34c753fSRafael Auler InsertIt = addCFIPseudo(InBB, InsertIt, FrameInstructions.size()); 2728a34c753fSRafael Auler ++InsertIt; 2729a34c753fSRafael Auler FrameInstructions.emplace_back(CIEFrameInstructions[-Rule]); 2730a34c753fSRafael Auler break; 2731a34c753fSRafael Auler } 2732a34c753fSRafael Auler if (FromCFITable.isRedundant(FrameInstructions[Rule])) 2733a34c753fSRafael Auler break; 2734a34c753fSRafael Auler NewStates.push_back(Rule); 2735a34c753fSRafael Auler InsertIt = addCFIPseudo(InBB, InsertIt, Rule); 2736a34c753fSRafael Auler ++InsertIt; 2737a34c753fSRafael Auler break; 2738a34c753fSRafael Auler } 2739a34c753fSRafael Auler case MCCFIInstruction::OpDefCfaRegister: 2740a34c753fSRafael Auler case MCCFIInstruction::OpDefCfaOffset: 2741a34c753fSRafael Auler case MCCFIInstruction::OpDefCfa: 2742a34c753fSRafael Auler undoStateDefCfa(); 2743a34c753fSRafael Auler break; 2744a34c753fSRafael Auler case MCCFIInstruction::OpAdjustCfaOffset: 2745a34c753fSRafael Auler case MCCFIInstruction::OpWindowSave: 2746a34c753fSRafael Auler case MCCFIInstruction::OpNegateRAState: 2747a34c753fSRafael Auler case MCCFIInstruction::OpLLVMDefAspaceCfa: 2748a34c753fSRafael Auler llvm_unreachable("unsupported CFI opcode"); 2749a34c753fSRafael Auler break; 2750a34c753fSRafael Auler case MCCFIInstruction::OpGnuArgsSize: 2751a34c753fSRafael Auler // do not affect CFI state 2752a34c753fSRafael Auler break; 2753a34c753fSRafael Auler } 2754a34c753fSRafael Auler }; 2755a34c753fSRafael Auler 2756a34c753fSRafael Auler // Undo all modifications from ToState to FromState 2757a34c753fSRafael Auler for (int32_t I = ToState, E = FromState; I != E; ++I) { 2758a34c753fSRafael Auler const MCCFIInstruction &Instr = FrameInstructions[I]; 2759a34c753fSRafael Auler if (Instr.getOperation() != MCCFIInstruction::OpRestoreState) { 2760a34c753fSRafael Auler undoState(Instr); 2761a34c753fSRafael Auler continue; 2762a34c753fSRafael Auler } 2763a34c753fSRafael Auler auto Iter = FrameRestoreEquivalents.find(I); 2764a34c753fSRafael Auler if (Iter == FrameRestoreEquivalents.end()) 2765a34c753fSRafael Auler continue; 2766a34c753fSRafael Auler for (int32_t State : Iter->second) 2767a34c753fSRafael Auler undoState(FrameInstructions[State]); 2768a34c753fSRafael Auler } 2769a34c753fSRafael Auler 2770a34c753fSRafael Auler return NewStates; 2771a34c753fSRafael Auler } 2772a34c753fSRafael Auler 2773a34c753fSRafael Auler void BinaryFunction::normalizeCFIState() { 2774a34c753fSRafael Auler // Reordering blocks with remember-restore state instructions can be specially 2775a34c753fSRafael Auler // tricky. When rewriting the CFI, we omit remember-restore state instructions 2776a34c753fSRafael Auler // entirely. For restore state, we build a map expanding each restore to the 2777a34c753fSRafael Auler // equivalent unwindCFIState sequence required at that point to achieve the 2778a34c753fSRafael Auler // same effect of the restore. All remember state are then just ignored. 2779a34c753fSRafael Auler std::stack<int32_t> Stack; 27808477bc67SFabian Parzefall for (BinaryBasicBlock *CurBB : Layout.blocks()) { 2781a34c753fSRafael Auler for (auto II = CurBB->begin(); II != CurBB->end(); ++II) { 2782a34c753fSRafael Auler if (const MCCFIInstruction *CFI = getCFIFor(*II)) { 2783a34c753fSRafael Auler if (CFI->getOperation() == MCCFIInstruction::OpRememberState) { 2784a34c753fSRafael Auler Stack.push(II->getOperand(0).getImm()); 2785a34c753fSRafael Auler continue; 2786a34c753fSRafael Auler } 2787a34c753fSRafael Auler if (CFI->getOperation() == MCCFIInstruction::OpRestoreState) { 2788a34c753fSRafael Auler const int32_t RememberState = Stack.top(); 2789a34c753fSRafael Auler const int32_t CurState = II->getOperand(0).getImm(); 2790a34c753fSRafael Auler FrameRestoreEquivalents[CurState] = 2791a34c753fSRafael Auler unwindCFIState(CurState, RememberState, CurBB, II); 2792a34c753fSRafael Auler Stack.pop(); 2793a34c753fSRafael Auler } 2794a34c753fSRafael Auler } 2795a34c753fSRafael Auler } 2796a34c753fSRafael Auler } 2797a34c753fSRafael Auler } 2798a34c753fSRafael Auler 2799a34c753fSRafael Auler bool BinaryFunction::finalizeCFIState() { 2800a34c753fSRafael Auler LLVM_DEBUG( 2801a34c753fSRafael Auler dbgs() << "Trying to fix CFI states for each BB after reordering.\n"); 2802a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "This is the list of CFI states for each BB of " << *this 2803a34c753fSRafael Auler << ": "); 2804a34c753fSRafael Auler 2805a34c753fSRafael Auler const char *Sep = ""; 2806a34c753fSRafael Auler (void)Sep; 280707f63b0aSFabian Parzefall for (FunctionFragment &FF : Layout.fragments()) { 28088477bc67SFabian Parzefall // Hot-cold border: at start of each region (with a different FDE) we need 28098477bc67SFabian Parzefall // to reset the CFI state. 28108477bc67SFabian Parzefall int32_t State = 0; 2811a34c753fSRafael Auler 28120f8412c1SFabian Parzefall for (BinaryBasicBlock *BB : FF) { 28138477bc67SFabian Parzefall const int32_t CFIStateAtExit = BB->getCFIStateAtExit(); 2814a34c753fSRafael Auler 2815a34c753fSRafael Auler // We need to recover the correct state if it doesn't match expected 2816a34c753fSRafael Auler // state at BB entry point. 2817a34c753fSRafael Auler if (BB->getCFIState() < State) { 2818a34c753fSRafael Auler // In this case, State is currently higher than what this BB expect it 2819a34c753fSRafael Auler // to be. To solve this, we need to insert CFI instructions to undo 2820a34c753fSRafael Auler // the effect of all CFI from BB's state to current State. 2821a34c753fSRafael Auler auto InsertIt = BB->begin(); 2822a34c753fSRafael Auler unwindCFIState(State, BB->getCFIState(), BB, InsertIt); 2823a34c753fSRafael Auler } else if (BB->getCFIState() > State) { 28248477bc67SFabian Parzefall // If BB's CFI state is greater than State, it means we are behind in 28258477bc67SFabian Parzefall // the state. Just emit all instructions to reach this state at the 2826a34c753fSRafael Auler // beginning of this BB. If this sequence of instructions involve 2827a34c753fSRafael Auler // remember state or restore state, bail out. 2828a34c753fSRafael Auler if (!replayCFIInstrs(State, BB->getCFIState(), BB, BB->begin())) 2829a34c753fSRafael Auler return false; 2830a34c753fSRafael Auler } 2831a34c753fSRafael Auler 2832a34c753fSRafael Auler State = CFIStateAtExit; 2833a34c753fSRafael Auler LLVM_DEBUG(dbgs() << Sep << State; Sep = ", "); 2834a34c753fSRafael Auler } 28358477bc67SFabian Parzefall } 2836a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\n"); 2837a34c753fSRafael Auler 2838d55dfeafSFabian Parzefall for (BinaryBasicBlock &BB : blocks()) { 2839d55dfeafSFabian Parzefall for (auto II = BB.begin(); II != BB.end();) { 2840a34c753fSRafael Auler const MCCFIInstruction *CFI = getCFIFor(*II); 284140c2e0faSMaksim Panchenko if (CFI && (CFI->getOperation() == MCCFIInstruction::OpRememberState || 2842a34c753fSRafael Auler CFI->getOperation() == MCCFIInstruction::OpRestoreState)) { 2843d55dfeafSFabian Parzefall II = BB.eraseInstruction(II); 2844a34c753fSRafael Auler } else { 2845a34c753fSRafael Auler ++II; 2846a34c753fSRafael Auler } 2847a34c753fSRafael Auler } 2848a34c753fSRafael Auler } 2849a34c753fSRafael Auler 2850a34c753fSRafael Auler return true; 2851a34c753fSRafael Auler } 2852a34c753fSRafael Auler 2853a34c753fSRafael Auler bool BinaryFunction::requiresAddressTranslation() const { 2854a34c753fSRafael Auler return opts::EnableBAT || hasSDTMarker() || hasPseudoProbe(); 2855a34c753fSRafael Auler } 2856a34c753fSRafael Auler 285723c8d382SJob Noorman bool BinaryFunction::requiresAddressMap() const { 285823c8d382SJob Noorman if (isInjected()) 285923c8d382SJob Noorman return false; 286023c8d382SJob Noorman 286123c8d382SJob Noorman return opts::UpdateDebugSections || isMultiEntry() || 286223c8d382SJob Noorman requiresAddressTranslation(); 286323c8d382SJob Noorman } 286423c8d382SJob Noorman 2865a34c753fSRafael Auler uint64_t BinaryFunction::getInstructionCount() const { 2866a34c753fSRafael Auler uint64_t Count = 0; 2867d55dfeafSFabian Parzefall for (const BinaryBasicBlock &BB : blocks()) 2868d55dfeafSFabian Parzefall Count += BB.getNumNonPseudos(); 2869a34c753fSRafael Auler return Count; 2870a34c753fSRafael Auler } 2871a34c753fSRafael Auler 2872a34c753fSRafael Auler void BinaryFunction::clearDisasmState() { 2873a34c753fSRafael Auler clearList(Instructions); 2874a34c753fSRafael Auler clearList(IgnoredBranches); 2875a34c753fSRafael Auler clearList(TakenBranches); 2876a34c753fSRafael Auler 2877a34c753fSRafael Auler if (BC.HasRelocations) { 28783652483cSRafael Auler for (std::pair<const uint32_t, MCSymbol *> &LI : Labels) 2879a34c753fSRafael Auler BC.UndefinedSymbols.insert(LI.second); 2880a191ea7dSFabian Parzefall for (MCSymbol *const EndLabel : FunctionEndLabels) 2881a191ea7dSFabian Parzefall if (EndLabel) 2882a191ea7dSFabian Parzefall BC.UndefinedSymbols.insert(EndLabel); 2883a34c753fSRafael Auler } 2884a34c753fSRafael Auler } 2885a34c753fSRafael Auler 2886a34c753fSRafael Auler void BinaryFunction::setTrapOnEntry() { 2887a34c753fSRafael Auler clearDisasmState(); 2888a34c753fSRafael Auler 2889d77f96a9SAmir Ayupov forEachEntryPoint([&](uint64_t Offset, const MCSymbol *Label) -> bool { 2890a34c753fSRafael Auler MCInst TrapInstr; 2891a34c753fSRafael Auler BC.MIB->createTrap(TrapInstr); 2892a34c753fSRafael Auler addInstruction(Offset, std::move(TrapInstr)); 2893d77f96a9SAmir Ayupov return true; 2894d77f96a9SAmir Ayupov }); 2895a34c753fSRafael Auler 2896a34c753fSRafael Auler TrapsOnEntry = true; 2897a34c753fSRafael Auler } 2898a34c753fSRafael Auler 2899a34c753fSRafael Auler void BinaryFunction::setIgnored() { 2900a34c753fSRafael Auler if (opts::processAllFunctions()) { 2901a34c753fSRafael Auler // We can accept ignored functions before they've been disassembled. 2902a34c753fSRafael Auler // In that case, they would still get disassembled and emited, but not 2903a34c753fSRafael Auler // optimized. 2904a34c753fSRafael Auler assert(CurrentState == State::Empty && 2905a34c753fSRafael Auler "cannot ignore non-empty functions in current mode"); 2906a34c753fSRafael Auler IsIgnored = true; 2907a34c753fSRafael Auler return; 2908a34c753fSRafael Auler } 2909a34c753fSRafael Auler 2910a34c753fSRafael Auler clearDisasmState(); 2911a34c753fSRafael Auler 2912a34c753fSRafael Auler // Clear CFG state too. 2913a34c753fSRafael Auler if (hasCFG()) { 2914a34c753fSRafael Auler releaseCFG(); 2915a34c753fSRafael Auler 29163652483cSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) 2917a34c753fSRafael Auler delete BB; 2918a34c753fSRafael Auler clearList(BasicBlocks); 2919a34c753fSRafael Auler 29203652483cSRafael Auler for (BinaryBasicBlock *BB : DeletedBasicBlocks) 2921a34c753fSRafael Auler delete BB; 2922a34c753fSRafael Auler clearList(DeletedBasicBlocks); 2923a34c753fSRafael Auler 29248477bc67SFabian Parzefall Layout.clear(); 2925a34c753fSRafael Auler } 2926a34c753fSRafael Auler 2927a34c753fSRafael Auler CurrentState = State::Empty; 2928a34c753fSRafael Auler 2929a34c753fSRafael Auler IsIgnored = true; 2930a34c753fSRafael Auler IsSimple = false; 2931a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Ignoring " << getPrintName() << '\n'); 2932a34c753fSRafael Auler } 2933a34c753fSRafael Auler 2934a34c753fSRafael Auler void BinaryFunction::duplicateConstantIslands() { 2935a34c753fSRafael Auler assert(Islands && "function expected to have constant islands"); 2936a34c753fSRafael Auler 29378477bc67SFabian Parzefall for (BinaryBasicBlock *BB : getLayout().blocks()) { 2938a34c753fSRafael Auler if (!BB->isCold()) 2939a34c753fSRafael Auler continue; 2940a34c753fSRafael Auler 2941a34c753fSRafael Auler for (MCInst &Inst : *BB) { 2942a34c753fSRafael Auler int OpNum = 0; 2943a34c753fSRafael Auler for (MCOperand &Operand : Inst) { 2944a34c753fSRafael Auler if (!Operand.isExpr()) { 2945a34c753fSRafael Auler ++OpNum; 2946a34c753fSRafael Auler continue; 2947a34c753fSRafael Auler } 2948a34c753fSRafael Auler const MCSymbol *Symbol = BC.MIB->getTargetSymbol(Inst, OpNum); 2949a34c753fSRafael Auler // Check if this is an island symbol 2950a34c753fSRafael Auler if (!Islands->Symbols.count(Symbol) && 2951a34c753fSRafael Auler !Islands->ProxySymbols.count(Symbol)) 2952a34c753fSRafael Auler continue; 2953a34c753fSRafael Auler 2954a34c753fSRafael Auler // Create cold symbol, if missing 2955a34c753fSRafael Auler auto ISym = Islands->ColdSymbols.find(Symbol); 2956a34c753fSRafael Auler MCSymbol *ColdSymbol; 2957a34c753fSRafael Auler if (ISym != Islands->ColdSymbols.end()) { 2958a34c753fSRafael Auler ColdSymbol = ISym->second; 2959a34c753fSRafael Auler } else { 2960a34c753fSRafael Auler ColdSymbol = BC.Ctx->getOrCreateSymbol(Symbol->getName() + ".cold"); 2961a34c753fSRafael Auler Islands->ColdSymbols[Symbol] = ColdSymbol; 2962a34c753fSRafael Auler // Check if this is a proxy island symbol and update owner proxy map 2963a34c753fSRafael Auler if (Islands->ProxySymbols.count(Symbol)) { 2964a34c753fSRafael Auler BinaryFunction *Owner = Islands->ProxySymbols[Symbol]; 2965a34c753fSRafael Auler auto IProxiedSym = Owner->Islands->Proxies[this].find(Symbol); 2966a34c753fSRafael Auler Owner->Islands->ColdProxies[this][IProxiedSym->second] = ColdSymbol; 2967a34c753fSRafael Auler } 2968a34c753fSRafael Auler } 2969a34c753fSRafael Auler 2970a34c753fSRafael Auler // Update instruction reference 2971a34c753fSRafael Auler Operand = MCOperand::createExpr(BC.MIB->getTargetExprFor( 2972a34c753fSRafael Auler Inst, 2973a34c753fSRafael Auler MCSymbolRefExpr::create(ColdSymbol, MCSymbolRefExpr::VK_None, 2974a34c753fSRafael Auler *BC.Ctx), 2975a34c753fSRafael Auler *BC.Ctx, 0)); 2976a34c753fSRafael Auler ++OpNum; 2977a34c753fSRafael Auler } 2978a34c753fSRafael Auler } 2979a34c753fSRafael Auler } 2980a34c753fSRafael Auler } 2981a34c753fSRafael Auler 2982a34c753fSRafael Auler #ifndef MAX_PATH 2983a34c753fSRafael Auler #define MAX_PATH 255 2984a34c753fSRafael Auler #endif 2985a34c753fSRafael Auler 2986be2f67c4SAmir Ayupov static std::string constructFilename(std::string Filename, 2987be2f67c4SAmir Ayupov std::string Annotation, 2988a34c753fSRafael Auler std::string Suffix) { 2989a34c753fSRafael Auler std::replace(Filename.begin(), Filename.end(), '/', '-'); 29903652483cSRafael Auler if (!Annotation.empty()) 2991a34c753fSRafael Auler Annotation.insert(0, "-"); 2992a34c753fSRafael Auler if (Filename.size() + Annotation.size() + Suffix.size() > MAX_PATH) { 2993a34c753fSRafael Auler assert(Suffix.size() + Annotation.size() <= MAX_PATH); 2994a34c753fSRafael Auler if (opts::Verbosity >= 1) { 2995a34c753fSRafael Auler errs() << "BOLT-WARNING: Filename \"" << Filename << Annotation << Suffix 2996a34c753fSRafael Auler << "\" exceeds the " << MAX_PATH << " size limit, truncating.\n"; 2997a34c753fSRafael Auler } 2998a34c753fSRafael Auler Filename.resize(MAX_PATH - (Suffix.size() + Annotation.size())); 2999a34c753fSRafael Auler } 3000a34c753fSRafael Auler Filename += Annotation; 3001a34c753fSRafael Auler Filename += Suffix; 3002a34c753fSRafael Auler return Filename; 3003a34c753fSRafael Auler } 3004a34c753fSRafael Auler 3005be2f67c4SAmir Ayupov static std::string formatEscapes(const std::string &Str) { 3006a34c753fSRafael Auler std::string Result; 3007a34c753fSRafael Auler for (unsigned I = 0; I < Str.size(); ++I) { 3008a34c753fSRafael Auler char C = Str[I]; 3009a34c753fSRafael Auler switch (C) { 3010a34c753fSRafael Auler case '\n': 3011a34c753fSRafael Auler Result += " "; 3012a34c753fSRafael Auler break; 3013a34c753fSRafael Auler case '"': 3014a34c753fSRafael Auler break; 3015a34c753fSRafael Auler default: 3016a34c753fSRafael Auler Result += C; 3017a34c753fSRafael Auler break; 3018a34c753fSRafael Auler } 3019a34c753fSRafael Auler } 3020a34c753fSRafael Auler return Result; 3021a34c753fSRafael Auler } 3022a34c753fSRafael Auler 3023a34c753fSRafael Auler void BinaryFunction::dumpGraph(raw_ostream &OS) const { 30246333e5ddSAmir Ayupov OS << "digraph \"" << getPrintName() << "\" {\n" 30256333e5ddSAmir Ayupov << "node [fontname=courier, shape=box, style=filled, colorscheme=brbg9]\n"; 3026a34c753fSRafael Auler uint64_t Offset = Address; 3027a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 30288477bc67SFabian Parzefall auto LayoutPos = find(Layout.blocks(), BB); 30298477bc67SFabian Parzefall unsigned LayoutIndex = LayoutPos - Layout.block_begin(); 3030a34c753fSRafael Auler const char *ColdStr = BB->isCold() ? " (cold)" : ""; 30316333e5ddSAmir Ayupov std::vector<std::string> Attrs; 30326333e5ddSAmir Ayupov // Bold box for entry points 30336333e5ddSAmir Ayupov if (isEntryPoint(*BB)) 30346333e5ddSAmir Ayupov Attrs.push_back("penwidth=2"); 30356333e5ddSAmir Ayupov if (BLI && BLI->getLoopFor(BB)) { 30366333e5ddSAmir Ayupov // Distinguish innermost loops 30376333e5ddSAmir Ayupov const BinaryLoop *Loop = BLI->getLoopFor(BB); 30386333e5ddSAmir Ayupov if (Loop->isInnermost()) 30396333e5ddSAmir Ayupov Attrs.push_back("fillcolor=6"); 30406333e5ddSAmir Ayupov else // some outer loop 30416333e5ddSAmir Ayupov Attrs.push_back("fillcolor=4"); 30426333e5ddSAmir Ayupov } else { // non-loopy code 30436333e5ddSAmir Ayupov Attrs.push_back("fillcolor=5"); 30446333e5ddSAmir Ayupov } 30456333e5ddSAmir Ayupov ListSeparator LS; 30466333e5ddSAmir Ayupov OS << "\"" << BB->getName() << "\" ["; 30476333e5ddSAmir Ayupov for (StringRef Attr : Attrs) 30486333e5ddSAmir Ayupov OS << LS << Attr; 30496333e5ddSAmir Ayupov OS << "]\n"; 3050cc23c64fSAmir Ayupov OS << format("\"%s\" [label=\"%s%s\\n(C:%lu,O:%lu,I:%u,L:%u,CFI:%u)\\n", 3051cc23c64fSAmir Ayupov BB->getName().data(), BB->getName().data(), ColdStr, 3052cc23c64fSAmir Ayupov BB->getKnownExecutionCount(), BB->getOffset(), getIndex(BB), 30538477bc67SFabian Parzefall LayoutIndex, BB->getCFIState()); 3054cc23c64fSAmir Ayupov 3055a34c753fSRafael Auler if (opts::DotToolTipCode) { 3056a34c753fSRafael Auler std::string Str; 3057a34c753fSRafael Auler raw_string_ostream CS(Str); 3058cc23c64fSAmir Ayupov Offset = BC.printInstructions(CS, BB->begin(), BB->end(), Offset, this, 3059cc23c64fSAmir Ayupov /* PrintMCInst = */ false, 3060cc23c64fSAmir Ayupov /* PrintMemData = */ false, 3061cc23c64fSAmir Ayupov /* PrintRelocations = */ false, 3062cc23c64fSAmir Ayupov /* Endl = */ R"(\\l)"); 3063cc23c64fSAmir Ayupov OS << formatEscapes(CS.str()) << '\n'; 3064a34c753fSRafael Auler } 3065cc23c64fSAmir Ayupov OS << "\"]\n"; 3066a34c753fSRafael Auler 3067a34c753fSRafael Auler // analyzeBranch is just used to get the names of the branch 3068a34c753fSRafael Auler // opcodes. 3069a34c753fSRafael Auler const MCSymbol *TBB = nullptr; 3070a34c753fSRafael Auler const MCSymbol *FBB = nullptr; 3071a34c753fSRafael Auler MCInst *CondBranch = nullptr; 3072a34c753fSRafael Auler MCInst *UncondBranch = nullptr; 307340c2e0faSMaksim Panchenko const bool Success = BB->analyzeBranch(TBB, FBB, CondBranch, UncondBranch); 3074a34c753fSRafael Auler 3075a34c753fSRafael Auler const MCInst *LastInstr = BB->getLastNonPseudoInstr(); 3076a34c753fSRafael Auler const bool IsJumpTable = LastInstr && BC.MIB->getJumpTable(*LastInstr); 3077a34c753fSRafael Auler 3078a34c753fSRafael Auler auto BI = BB->branch_info_begin(); 3079a34c753fSRafael Auler for (BinaryBasicBlock *Succ : BB->successors()) { 3080a34c753fSRafael Auler std::string Branch; 3081a34c753fSRafael Auler if (Success) { 3082a34c753fSRafael Auler if (Succ == BB->getConditionalSuccessor(true)) { 3083a34c753fSRafael Auler Branch = CondBranch ? std::string(BC.InstPrinter->getOpcodeName( 3084a34c753fSRafael Auler CondBranch->getOpcode())) 3085a34c753fSRafael Auler : "TB"; 3086a34c753fSRafael Auler } else if (Succ == BB->getConditionalSuccessor(false)) { 3087a34c753fSRafael Auler Branch = UncondBranch ? std::string(BC.InstPrinter->getOpcodeName( 3088a34c753fSRafael Auler UncondBranch->getOpcode())) 3089a34c753fSRafael Auler : "FB"; 3090a34c753fSRafael Auler } else { 3091a34c753fSRafael Auler Branch = "FT"; 3092a34c753fSRafael Auler } 3093a34c753fSRafael Auler } 30943652483cSRafael Auler if (IsJumpTable) 3095a34c753fSRafael Auler Branch = "JT"; 309640c2e0faSMaksim Panchenko OS << format("\"%s\" -> \"%s\" [label=\"%s", BB->getName().data(), 309740c2e0faSMaksim Panchenko Succ->getName().data(), Branch.c_str()); 3098a34c753fSRafael Auler 3099a34c753fSRafael Auler if (BB->getExecutionCount() != COUNT_NO_PROFILE && 3100a34c753fSRafael Auler BI->MispredictedCount != BinaryBasicBlock::COUNT_INFERRED) { 3101a34c753fSRafael Auler OS << "\\n(C:" << BI->Count << ",M:" << BI->MispredictedCount << ")"; 3102a34c753fSRafael Auler } else if (ExecutionCount != COUNT_NO_PROFILE && 3103a34c753fSRafael Auler BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE) { 3104a34c753fSRafael Auler OS << "\\n(IC:" << BI->Count << ")"; 3105a34c753fSRafael Auler } 3106a34c753fSRafael Auler OS << "\"]\n"; 3107a34c753fSRafael Auler 3108a34c753fSRafael Auler ++BI; 3109a34c753fSRafael Auler } 3110a34c753fSRafael Auler for (BinaryBasicBlock *LP : BB->landing_pads()) { 3111a34c753fSRafael Auler OS << format("\"%s\" -> \"%s\" [constraint=false style=dashed]\n", 311240c2e0faSMaksim Panchenko BB->getName().data(), LP->getName().data()); 3113a34c753fSRafael Auler } 3114a34c753fSRafael Auler } 3115a34c753fSRafael Auler OS << "}\n"; 3116a34c753fSRafael Auler } 3117a34c753fSRafael Auler 3118a34c753fSRafael Auler void BinaryFunction::viewGraph() const { 3119a34c753fSRafael Auler SmallString<MAX_PATH> Filename; 3120a34c753fSRafael Auler if (std::error_code EC = 3121a34c753fSRafael Auler sys::fs::createTemporaryFile("bolt-cfg", "dot", Filename)) { 3122a34c753fSRafael Auler errs() << "BOLT-ERROR: " << EC.message() << ", unable to create " 3123a34c753fSRafael Auler << " bolt-cfg-XXXXX.dot temporary file.\n"; 3124a34c753fSRafael Auler return; 3125a34c753fSRafael Auler } 3126a34c753fSRafael Auler dumpGraphToFile(std::string(Filename)); 31273652483cSRafael Auler if (DisplayGraph(Filename)) 3128a34c753fSRafael Auler errs() << "BOLT-ERROR: Can't display " << Filename << " with graphviz.\n"; 3129a34c753fSRafael Auler if (std::error_code EC = sys::fs::remove(Filename)) { 3130a34c753fSRafael Auler errs() << "BOLT-WARNING: " << EC.message() << ", failed to remove " 3131a34c753fSRafael Auler << Filename << "\n"; 3132a34c753fSRafael Auler } 3133a34c753fSRafael Auler } 3134a34c753fSRafael Auler 3135a34c753fSRafael Auler void BinaryFunction::dumpGraphForPass(std::string Annotation) const { 3136798e92c6SAmir Ayupov if (!opts::shouldPrint(*this)) 3137798e92c6SAmir Ayupov return; 3138798e92c6SAmir Ayupov 3139a34c753fSRafael Auler std::string Filename = constructFilename(getPrintName(), Annotation, ".dot"); 3140798e92c6SAmir Ayupov if (opts::Verbosity >= 1) 3141798e92c6SAmir Ayupov outs() << "BOLT-INFO: dumping CFG to " << Filename << "\n"; 3142a34c753fSRafael Auler dumpGraphToFile(Filename); 3143a34c753fSRafael Auler } 3144a34c753fSRafael Auler 3145a34c753fSRafael Auler void BinaryFunction::dumpGraphToFile(std::string Filename) const { 3146a34c753fSRafael Auler std::error_code EC; 3147a34c753fSRafael Auler raw_fd_ostream of(Filename, EC, sys::fs::OF_None); 3148a34c753fSRafael Auler if (EC) { 3149a34c753fSRafael Auler if (opts::Verbosity >= 1) { 3150a34c753fSRafael Auler errs() << "BOLT-WARNING: " << EC.message() << ", unable to open " 3151a34c753fSRafael Auler << Filename << " for output.\n"; 3152a34c753fSRafael Auler } 3153a34c753fSRafael Auler return; 3154a34c753fSRafael Auler } 3155a34c753fSRafael Auler dumpGraph(of); 3156a34c753fSRafael Auler } 3157a34c753fSRafael Auler 3158a34c753fSRafael Auler bool BinaryFunction::validateCFG() const { 3159*16fd8799Szhoujiapeng // Skip the validation of CFG after it is finalized 3160*16fd8799Szhoujiapeng if (CurrentState == State::CFG_Finalized) 3161*16fd8799Szhoujiapeng return true; 3162*16fd8799Szhoujiapeng 3163a34c753fSRafael Auler bool Valid = true; 31643652483cSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) 3165a34c753fSRafael Auler Valid &= BB->validateSuccessorInvariants(); 3166a34c753fSRafael Auler 3167a34c753fSRafael Auler if (!Valid) 3168a34c753fSRafael Auler return Valid; 3169a34c753fSRafael Auler 3170a34c753fSRafael Auler // Make sure all blocks in CFG are valid. 3171a34c753fSRafael Auler auto validateBlock = [this](const BinaryBasicBlock *BB, StringRef Desc) { 3172a34c753fSRafael Auler if (!BB->isValid()) { 3173a34c753fSRafael Auler errs() << "BOLT-ERROR: deleted " << Desc << " " << BB->getName() 3174a34c753fSRafael Auler << " detected in:\n"; 3175a34c753fSRafael Auler this->dump(); 3176a34c753fSRafael Auler return false; 3177a34c753fSRafael Auler } 3178a34c753fSRafael Auler return true; 3179a34c753fSRafael Auler }; 3180a34c753fSRafael Auler for (const BinaryBasicBlock *BB : BasicBlocks) { 3181a34c753fSRafael Auler if (!validateBlock(BB, "block")) 3182a34c753fSRafael Auler return false; 3183a34c753fSRafael Auler for (const BinaryBasicBlock *PredBB : BB->predecessors()) 3184a34c753fSRafael Auler if (!validateBlock(PredBB, "predecessor")) 3185a34c753fSRafael Auler return false; 3186a34c753fSRafael Auler for (const BinaryBasicBlock *SuccBB : BB->successors()) 3187a34c753fSRafael Auler if (!validateBlock(SuccBB, "successor")) 3188a34c753fSRafael Auler return false; 3189a34c753fSRafael Auler for (const BinaryBasicBlock *LP : BB->landing_pads()) 3190a34c753fSRafael Auler if (!validateBlock(LP, "landing pad")) 3191a34c753fSRafael Auler return false; 3192a34c753fSRafael Auler for (const BinaryBasicBlock *Thrower : BB->throwers()) 3193a34c753fSRafael Auler if (!validateBlock(Thrower, "thrower")) 3194a34c753fSRafael Auler return false; 3195a34c753fSRafael Auler } 3196a34c753fSRafael Auler 3197a34c753fSRafael Auler for (const BinaryBasicBlock *BB : BasicBlocks) { 3198a34c753fSRafael Auler std::unordered_set<const BinaryBasicBlock *> BBLandingPads; 3199a34c753fSRafael Auler for (const BinaryBasicBlock *LP : BB->landing_pads()) { 3200a34c753fSRafael Auler if (BBLandingPads.count(LP)) { 3201a34c753fSRafael Auler errs() << "BOLT-ERROR: duplicate landing pad detected in" 3202a34c753fSRafael Auler << BB->getName() << " in function " << *this << '\n'; 3203a34c753fSRafael Auler return false; 3204a34c753fSRafael Auler } 3205a34c753fSRafael Auler BBLandingPads.insert(LP); 3206a34c753fSRafael Auler } 3207a34c753fSRafael Auler 3208a34c753fSRafael Auler std::unordered_set<const BinaryBasicBlock *> BBThrowers; 3209a34c753fSRafael Auler for (const BinaryBasicBlock *Thrower : BB->throwers()) { 3210a34c753fSRafael Auler if (BBThrowers.count(Thrower)) { 321140c2e0faSMaksim Panchenko errs() << "BOLT-ERROR: duplicate thrower detected in" << BB->getName() 321240c2e0faSMaksim Panchenko << " in function " << *this << '\n'; 3213a34c753fSRafael Auler return false; 3214a34c753fSRafael Auler } 3215a34c753fSRafael Auler BBThrowers.insert(Thrower); 3216a34c753fSRafael Auler } 3217a34c753fSRafael Auler 3218a34c753fSRafael Auler for (const BinaryBasicBlock *LPBlock : BB->landing_pads()) { 3219d2c87699SAmir Ayupov if (!llvm::is_contained(LPBlock->throwers(), BB)) { 322040c2e0faSMaksim Panchenko errs() << "BOLT-ERROR: inconsistent landing pad detected in " << *this 322140c2e0faSMaksim Panchenko << ": " << BB->getName() << " is in LandingPads but not in " 322240c2e0faSMaksim Panchenko << LPBlock->getName() << " Throwers\n"; 3223a34c753fSRafael Auler return false; 3224a34c753fSRafael Auler } 3225a34c753fSRafael Auler } 3226a34c753fSRafael Auler for (const BinaryBasicBlock *Thrower : BB->throwers()) { 3227d2c87699SAmir Ayupov if (!llvm::is_contained(Thrower->landing_pads(), BB)) { 322840c2e0faSMaksim Panchenko errs() << "BOLT-ERROR: inconsistent thrower detected in " << *this 322940c2e0faSMaksim Panchenko << ": " << BB->getName() << " is in Throwers list but not in " 323040c2e0faSMaksim Panchenko << Thrower->getName() << " LandingPads\n"; 3231a34c753fSRafael Auler return false; 3232a34c753fSRafael Auler } 3233a34c753fSRafael Auler } 3234a34c753fSRafael Auler } 3235a34c753fSRafael Auler 3236a34c753fSRafael Auler return Valid; 3237a34c753fSRafael Auler } 3238a34c753fSRafael Auler 3239a34c753fSRafael Auler void BinaryFunction::fixBranches() { 3240a34c753fSRafael Auler auto &MIB = BC.MIB; 3241a34c753fSRafael Auler MCContext *Ctx = BC.Ctx.get(); 3242a34c753fSRafael Auler 32438477bc67SFabian Parzefall for (BinaryBasicBlock *BB : BasicBlocks) { 3244a34c753fSRafael Auler const MCSymbol *TBB = nullptr; 3245a34c753fSRafael Auler const MCSymbol *FBB = nullptr; 3246a34c753fSRafael Auler MCInst *CondBranch = nullptr; 3247a34c753fSRafael Auler MCInst *UncondBranch = nullptr; 3248a34c753fSRafael Auler if (!BB->analyzeBranch(TBB, FBB, CondBranch, UncondBranch)) 3249a34c753fSRafael Auler continue; 3250a34c753fSRafael Auler 3251a34c753fSRafael Auler // We will create unconditional branch with correct destination if needed. 3252a34c753fSRafael Auler if (UncondBranch) 3253a34c753fSRafael Auler BB->eraseInstruction(BB->findInstruction(UncondBranch)); 3254a34c753fSRafael Auler 3255a34c753fSRafael Auler // Basic block that follows the current one in the final layout. 32568477bc67SFabian Parzefall const BinaryBasicBlock *NextBB = 32578477bc67SFabian Parzefall Layout.getBasicBlockAfter(BB, /*IgnoreSplits=*/false); 3258a34c753fSRafael Auler 3259a34c753fSRafael Auler if (BB->succ_size() == 1) { 3260a34c753fSRafael Auler // __builtin_unreachable() could create a conditional branch that 3261a34c753fSRafael Auler // falls-through into the next function - hence the block will have only 3262a34c753fSRafael Auler // one valid successor. Since behaviour is undefined - we replace 3263a34c753fSRafael Auler // the conditional branch with an unconditional if required. 3264a34c753fSRafael Auler if (CondBranch) 3265a34c753fSRafael Auler BB->eraseInstruction(BB->findInstruction(CondBranch)); 3266a34c753fSRafael Auler if (BB->getSuccessor() == NextBB) 3267a34c753fSRafael Auler continue; 3268a34c753fSRafael Auler BB->addBranchInstruction(BB->getSuccessor()); 3269a34c753fSRafael Auler } else if (BB->succ_size() == 2) { 3270a34c753fSRafael Auler assert(CondBranch && "conditional branch expected"); 3271a34c753fSRafael Auler const BinaryBasicBlock *TSuccessor = BB->getConditionalSuccessor(true); 3272a34c753fSRafael Auler const BinaryBasicBlock *FSuccessor = BB->getConditionalSuccessor(false); 3273a34c753fSRafael Auler // Check whether we support reversing this branch direction 32745c4d306aSMaksim Panchenko const bool IsSupported = !MIB->isUnsupportedBranch(*CondBranch); 3275a34c753fSRafael Auler if (NextBB && NextBB == TSuccessor && IsSupported) { 3276a34c753fSRafael Auler std::swap(TSuccessor, FSuccessor); 3277a34c753fSRafael Auler { 3278a34c753fSRafael Auler auto L = BC.scopeLock(); 3279a34c753fSRafael Auler MIB->reverseBranchCondition(*CondBranch, TSuccessor->getLabel(), Ctx); 3280a34c753fSRafael Auler } 3281a34c753fSRafael Auler BB->swapConditionalSuccessors(); 3282a34c753fSRafael Auler } else { 3283a34c753fSRafael Auler auto L = BC.scopeLock(); 3284a34c753fSRafael Auler MIB->replaceBranchTarget(*CondBranch, TSuccessor->getLabel(), Ctx); 3285a34c753fSRafael Auler } 32863652483cSRafael Auler if (TSuccessor == FSuccessor) 3287a34c753fSRafael Auler BB->removeDuplicateConditionalSuccessor(CondBranch); 3288a34c753fSRafael Auler if (!NextBB || 3289a34c753fSRafael Auler ((NextBB != TSuccessor || !IsSupported) && NextBB != FSuccessor)) { 3290a34c753fSRafael Auler // If one of the branches is guaranteed to be "long" while the other 3291a34c753fSRafael Auler // could be "short", then prioritize short for "taken". This will 3292a34c753fSRafael Auler // generate a sequence 1 byte shorter on x86. 3293a34c753fSRafael Auler if (IsSupported && BC.isX86() && 3294275e075cSFabian Parzefall TSuccessor->getFragmentNum() != FSuccessor->getFragmentNum() && 3295275e075cSFabian Parzefall BB->getFragmentNum() != TSuccessor->getFragmentNum()) { 3296a34c753fSRafael Auler std::swap(TSuccessor, FSuccessor); 3297a34c753fSRafael Auler { 3298a34c753fSRafael Auler auto L = BC.scopeLock(); 3299a34c753fSRafael Auler MIB->reverseBranchCondition(*CondBranch, TSuccessor->getLabel(), 3300a34c753fSRafael Auler Ctx); 3301a34c753fSRafael Auler } 3302a34c753fSRafael Auler BB->swapConditionalSuccessors(); 3303a34c753fSRafael Auler } 3304a34c753fSRafael Auler BB->addBranchInstruction(FSuccessor); 3305a34c753fSRafael Auler } 3306a34c753fSRafael Auler } 3307a34c753fSRafael Auler // Cases where the number of successors is 0 (block ends with a 3308a34c753fSRafael Auler // terminator) or more than 2 (switch table) don't require branch 3309a34c753fSRafael Auler // instruction adjustments. 3310a34c753fSRafael Auler } 331140c2e0faSMaksim Panchenko assert((!isSimple() || validateCFG()) && 331240c2e0faSMaksim Panchenko "Invalid CFG detected after fixing branches"); 3313a34c753fSRafael Auler } 3314a34c753fSRafael Auler 3315a34c753fSRafael Auler void BinaryFunction::propagateGnuArgsSizeInfo( 3316a34c753fSRafael Auler MCPlusBuilder::AllocatorIdTy AllocId) { 3317a34c753fSRafael Auler assert(CurrentState == State::Disassembled && "unexpected function state"); 3318a34c753fSRafael Auler 3319a34c753fSRafael Auler if (!hasEHRanges() || !usesGnuArgsSize()) 3320a34c753fSRafael Auler return; 3321a34c753fSRafael Auler 3322a34c753fSRafael Auler // The current value of DW_CFA_GNU_args_size affects all following 3323a34c753fSRafael Auler // invoke instructions until the next CFI overrides it. 3324a34c753fSRafael Auler // It is important to iterate basic blocks in the original order when 3325a34c753fSRafael Auler // assigning the value. 3326a34c753fSRafael Auler uint64_t CurrentGnuArgsSize = 0; 3327a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 3328a34c753fSRafael Auler for (auto II = BB->begin(); II != BB->end();) { 3329a34c753fSRafael Auler MCInst &Instr = *II; 3330a34c753fSRafael Auler if (BC.MIB->isCFI(Instr)) { 3331a34c753fSRafael Auler const MCCFIInstruction *CFI = getCFIFor(Instr); 3332a34c753fSRafael Auler if (CFI->getOperation() == MCCFIInstruction::OpGnuArgsSize) { 3333a34c753fSRafael Auler CurrentGnuArgsSize = CFI->getOffset(); 3334a34c753fSRafael Auler // Delete DW_CFA_GNU_args_size instructions and only regenerate 3335a34c753fSRafael Auler // during the final code emission. The information is embedded 3336a34c753fSRafael Auler // inside call instructions. 3337a34c753fSRafael Auler II = BB->erasePseudoInstruction(II); 3338a34c753fSRafael Auler continue; 3339a34c753fSRafael Auler } 3340a34c753fSRafael Auler } else if (BC.MIB->isInvoke(Instr)) { 3341a34c753fSRafael Auler // Add the value of GNU_args_size as an extra operand to invokes. 3342a34c753fSRafael Auler BC.MIB->addGnuArgsSize(Instr, CurrentGnuArgsSize, AllocId); 3343a34c753fSRafael Auler } 3344a34c753fSRafael Auler ++II; 3345a34c753fSRafael Auler } 3346a34c753fSRafael Auler } 3347a34c753fSRafael Auler } 3348a34c753fSRafael Auler 3349a34c753fSRafael Auler void BinaryFunction::postProcessBranches() { 3350a34c753fSRafael Auler if (!isSimple()) 3351a34c753fSRafael Auler return; 3352d55dfeafSFabian Parzefall for (BinaryBasicBlock &BB : blocks()) { 3353d55dfeafSFabian Parzefall auto LastInstrRI = BB.getLastNonPseudo(); 3354d55dfeafSFabian Parzefall if (BB.succ_size() == 1) { 3355d55dfeafSFabian Parzefall if (LastInstrRI != BB.rend() && 3356a34c753fSRafael Auler BC.MIB->isConditionalBranch(*LastInstrRI)) { 3357a34c753fSRafael Auler // __builtin_unreachable() could create a conditional branch that 3358a34c753fSRafael Auler // falls-through into the next function - hence the block will have only 3359a34c753fSRafael Auler // one valid successor. Such behaviour is undefined and thus we remove 3360a34c753fSRafael Auler // the conditional branch while leaving a valid successor. 3361d55dfeafSFabian Parzefall BB.eraseInstruction(std::prev(LastInstrRI.base())); 3362a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: erasing conditional branch in " 3363d55dfeafSFabian Parzefall << BB.getName() << " in function " << *this << '\n'); 3364a34c753fSRafael Auler } 3365d55dfeafSFabian Parzefall } else if (BB.succ_size() == 0) { 3366a34c753fSRafael Auler // Ignore unreachable basic blocks. 3367d55dfeafSFabian Parzefall if (BB.pred_size() == 0 || BB.isLandingPad()) 3368a34c753fSRafael Auler continue; 3369a34c753fSRafael Auler 3370a34c753fSRafael Auler // If it's the basic block that does not end up with a terminator - we 3371a34c753fSRafael Auler // insert a return instruction unless it's a call instruction. 3372d55dfeafSFabian Parzefall if (LastInstrRI == BB.rend()) { 3373a34c753fSRafael Auler LLVM_DEBUG( 3374a34c753fSRafael Auler dbgs() << "BOLT-DEBUG: at least one instruction expected in BB " 3375d55dfeafSFabian Parzefall << BB.getName() << " in function " << *this << '\n'); 3376a34c753fSRafael Auler continue; 3377a34c753fSRafael Auler } 3378a34c753fSRafael Auler if (!BC.MIB->isTerminator(*LastInstrRI) && 3379a34c753fSRafael Auler !BC.MIB->isCall(*LastInstrRI)) { 3380a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: adding return to basic block " 3381d55dfeafSFabian Parzefall << BB.getName() << " in function " << *this << '\n'); 3382a34c753fSRafael Auler MCInst ReturnInstr; 3383a34c753fSRafael Auler BC.MIB->createReturn(ReturnInstr); 3384d55dfeafSFabian Parzefall BB.addInstruction(ReturnInstr); 3385a34c753fSRafael Auler } 3386a34c753fSRafael Auler } 3387a34c753fSRafael Auler } 3388a34c753fSRafael Auler assert(validateCFG() && "invalid CFG"); 3389a34c753fSRafael Auler } 3390a34c753fSRafael Auler 3391a34c753fSRafael Auler MCSymbol *BinaryFunction::addEntryPointAtOffset(uint64_t Offset) { 3392a34c753fSRafael Auler assert(Offset && "cannot add primary entry point"); 3393a34c753fSRafael Auler assert(CurrentState == State::Empty || CurrentState == State::Disassembled); 3394a34c753fSRafael Auler 3395a34c753fSRafael Auler const uint64_t EntryPointAddress = getAddress() + Offset; 3396a34c753fSRafael Auler MCSymbol *LocalSymbol = getOrCreateLocalLabel(EntryPointAddress); 3397a34c753fSRafael Auler 3398a34c753fSRafael Auler MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(LocalSymbol); 3399a34c753fSRafael Auler if (EntrySymbol) 3400a34c753fSRafael Auler return EntrySymbol; 3401a34c753fSRafael Auler 3402a34c753fSRafael Auler if (BinaryData *EntryBD = BC.getBinaryDataAtAddress(EntryPointAddress)) { 3403a34c753fSRafael Auler EntrySymbol = EntryBD->getSymbol(); 3404a34c753fSRafael Auler } else { 340540c2e0faSMaksim Panchenko EntrySymbol = BC.getOrCreateGlobalSymbol( 340640c2e0faSMaksim Panchenko EntryPointAddress, Twine("__ENTRY_") + getOneName() + "@"); 3407a34c753fSRafael Auler } 3408a34c753fSRafael Auler SecondaryEntryPoints[LocalSymbol] = EntrySymbol; 3409a34c753fSRafael Auler 3410a34c753fSRafael Auler BC.setSymbolToFunctionMap(EntrySymbol, this); 3411a34c753fSRafael Auler 3412a34c753fSRafael Auler return EntrySymbol; 3413a34c753fSRafael Auler } 3414a34c753fSRafael Auler 3415a34c753fSRafael Auler MCSymbol *BinaryFunction::addEntryPoint(const BinaryBasicBlock &BB) { 3416a34c753fSRafael Auler assert(CurrentState == State::CFG && 3417a34c753fSRafael Auler "basic block can be added as an entry only in a function with CFG"); 3418a34c753fSRafael Auler 3419a34c753fSRafael Auler if (&BB == BasicBlocks.front()) 3420a34c753fSRafael Auler return getSymbol(); 3421a34c753fSRafael Auler 3422a34c753fSRafael Auler MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(BB); 3423a34c753fSRafael Auler if (EntrySymbol) 3424a34c753fSRafael Auler return EntrySymbol; 3425a34c753fSRafael Auler 3426a34c753fSRafael Auler EntrySymbol = 3427a34c753fSRafael Auler BC.Ctx->getOrCreateSymbol("__ENTRY_" + BB.getLabel()->getName()); 3428a34c753fSRafael Auler 3429a34c753fSRafael Auler SecondaryEntryPoints[BB.getLabel()] = EntrySymbol; 3430a34c753fSRafael Auler 3431a34c753fSRafael Auler BC.setSymbolToFunctionMap(EntrySymbol, this); 3432a34c753fSRafael Auler 3433a34c753fSRafael Auler return EntrySymbol; 3434a34c753fSRafael Auler } 3435a34c753fSRafael Auler 3436a34c753fSRafael Auler MCSymbol *BinaryFunction::getSymbolForEntryID(uint64_t EntryID) { 3437a34c753fSRafael Auler if (EntryID == 0) 3438a34c753fSRafael Auler return getSymbol(); 3439a34c753fSRafael Auler 3440a34c753fSRafael Auler if (!isMultiEntry()) 3441a34c753fSRafael Auler return nullptr; 3442a34c753fSRafael Auler 3443a34c753fSRafael Auler uint64_t NumEntries = 0; 3444a34c753fSRafael Auler if (hasCFG()) { 3445a34c753fSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) { 3446a34c753fSRafael Auler MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(*BB); 3447a34c753fSRafael Auler if (!EntrySymbol) 3448a34c753fSRafael Auler continue; 3449a34c753fSRafael Auler if (NumEntries == EntryID) 3450a34c753fSRafael Auler return EntrySymbol; 3451a34c753fSRafael Auler ++NumEntries; 3452a34c753fSRafael Auler } 3453a34c753fSRafael Auler } else { 3454a34c753fSRafael Auler for (std::pair<const uint32_t, MCSymbol *> &KV : Labels) { 3455a34c753fSRafael Auler MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(KV.second); 3456a34c753fSRafael Auler if (!EntrySymbol) 3457a34c753fSRafael Auler continue; 3458a34c753fSRafael Auler if (NumEntries == EntryID) 3459a34c753fSRafael Auler return EntrySymbol; 3460a34c753fSRafael Auler ++NumEntries; 3461a34c753fSRafael Auler } 3462a34c753fSRafael Auler } 3463a34c753fSRafael Auler 3464a34c753fSRafael Auler return nullptr; 3465a34c753fSRafael Auler } 3466a34c753fSRafael Auler 3467a34c753fSRafael Auler uint64_t BinaryFunction::getEntryIDForSymbol(const MCSymbol *Symbol) const { 3468a34c753fSRafael Auler if (!isMultiEntry()) 3469a34c753fSRafael Auler return 0; 3470a34c753fSRafael Auler 3471a34c753fSRafael Auler for (const MCSymbol *FunctionSymbol : getSymbols()) 3472a34c753fSRafael Auler if (FunctionSymbol == Symbol) 3473a34c753fSRafael Auler return 0; 3474a34c753fSRafael Auler 3475a34c753fSRafael Auler // Check all secondary entries available as either basic blocks or lables. 3476a34c753fSRafael Auler uint64_t NumEntries = 0; 3477a34c753fSRafael Auler for (const BinaryBasicBlock *BB : BasicBlocks) { 3478a34c753fSRafael Auler MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(*BB); 3479a34c753fSRafael Auler if (!EntrySymbol) 3480a34c753fSRafael Auler continue; 3481a34c753fSRafael Auler if (EntrySymbol == Symbol) 3482a34c753fSRafael Auler return NumEntries; 3483a34c753fSRafael Auler ++NumEntries; 3484a34c753fSRafael Auler } 3485a34c753fSRafael Auler NumEntries = 0; 3486a34c753fSRafael Auler for (const std::pair<const uint32_t, MCSymbol *> &KV : Labels) { 3487a34c753fSRafael Auler MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(KV.second); 3488a34c753fSRafael Auler if (!EntrySymbol) 3489a34c753fSRafael Auler continue; 3490a34c753fSRafael Auler if (EntrySymbol == Symbol) 3491a34c753fSRafael Auler return NumEntries; 3492a34c753fSRafael Auler ++NumEntries; 3493a34c753fSRafael Auler } 3494a34c753fSRafael Auler 3495a34c753fSRafael Auler llvm_unreachable("symbol not found"); 3496a34c753fSRafael Auler } 3497a34c753fSRafael Auler 3498a34c753fSRafael Auler bool BinaryFunction::forEachEntryPoint(EntryPointCallbackTy Callback) const { 3499a34c753fSRafael Auler bool Status = Callback(0, getSymbol()); 3500a34c753fSRafael Auler if (!isMultiEntry()) 3501a34c753fSRafael Auler return Status; 3502a34c753fSRafael Auler 3503a34c753fSRafael Auler for (const std::pair<const uint32_t, MCSymbol *> &KV : Labels) { 3504a34c753fSRafael Auler if (!Status) 3505a34c753fSRafael Auler break; 3506a34c753fSRafael Auler 3507a34c753fSRafael Auler MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(KV.second); 3508a34c753fSRafael Auler if (!EntrySymbol) 3509a34c753fSRafael Auler continue; 3510a34c753fSRafael Auler 3511a34c753fSRafael Auler Status = Callback(KV.first, EntrySymbol); 3512a34c753fSRafael Auler } 3513a34c753fSRafael Auler 3514a34c753fSRafael Auler return Status; 3515a34c753fSRafael Auler } 3516a34c753fSRafael Auler 3517d55dfeafSFabian Parzefall BinaryFunction::BasicBlockListType BinaryFunction::dfs() const { 3518d55dfeafSFabian Parzefall BasicBlockListType DFS; 3519a34c753fSRafael Auler unsigned Index = 0; 3520a34c753fSRafael Auler std::stack<BinaryBasicBlock *> Stack; 3521a34c753fSRafael Auler 3522a34c753fSRafael Auler // Push entry points to the stack in reverse order. 3523a34c753fSRafael Auler // 3524a34c753fSRafael Auler // NB: we rely on the original order of entries to match. 3525d55dfeafSFabian Parzefall SmallVector<BinaryBasicBlock *> EntryPoints; 3526d55dfeafSFabian Parzefall llvm::copy_if(BasicBlocks, std::back_inserter(EntryPoints), 3527d55dfeafSFabian Parzefall [&](const BinaryBasicBlock *const BB) { return isEntryPoint(*BB); }); 3528d55dfeafSFabian Parzefall // Sort entry points by their offset to make sure we got them in the right 3529d55dfeafSFabian Parzefall // order. 3530d55dfeafSFabian Parzefall llvm::stable_sort(EntryPoints, [](const BinaryBasicBlock *const A, 3531d55dfeafSFabian Parzefall const BinaryBasicBlock *const B) { 3532d55dfeafSFabian Parzefall return A->getOffset() < B->getOffset(); 3533d55dfeafSFabian Parzefall }); 3534d55dfeafSFabian Parzefall for (BinaryBasicBlock *const BB : reverse(EntryPoints)) 3535a34c753fSRafael Auler Stack.push(BB); 3536d55dfeafSFabian Parzefall 3537d55dfeafSFabian Parzefall for (BinaryBasicBlock &BB : blocks()) 3538d55dfeafSFabian Parzefall BB.setLayoutIndex(BinaryBasicBlock::InvalidIndex); 3539a34c753fSRafael Auler 3540a34c753fSRafael Auler while (!Stack.empty()) { 3541a34c753fSRafael Auler BinaryBasicBlock *BB = Stack.top(); 3542a34c753fSRafael Auler Stack.pop(); 3543a34c753fSRafael Auler 3544a34c753fSRafael Auler if (BB->getLayoutIndex() != BinaryBasicBlock::InvalidIndex) 3545a34c753fSRafael Auler continue; 3546a34c753fSRafael Auler 3547a34c753fSRafael Auler BB->setLayoutIndex(Index++); 3548a34c753fSRafael Auler DFS.push_back(BB); 3549a34c753fSRafael Auler 3550a34c753fSRafael Auler for (BinaryBasicBlock *SuccBB : BB->landing_pads()) { 3551a34c753fSRafael Auler Stack.push(SuccBB); 3552a34c753fSRafael Auler } 3553a34c753fSRafael Auler 3554a34c753fSRafael Auler const MCSymbol *TBB = nullptr; 3555a34c753fSRafael Auler const MCSymbol *FBB = nullptr; 3556a34c753fSRafael Auler MCInst *CondBranch = nullptr; 3557a34c753fSRafael Auler MCInst *UncondBranch = nullptr; 355840c2e0faSMaksim Panchenko if (BB->analyzeBranch(TBB, FBB, CondBranch, UncondBranch) && CondBranch && 355940c2e0faSMaksim Panchenko BB->succ_size() == 2) { 3560a34c753fSRafael Auler if (BC.MIB->getCanonicalBranchCondCode(BC.MIB->getCondCode( 3561a34c753fSRafael Auler *CondBranch)) == BC.MIB->getCondCode(*CondBranch)) { 3562a34c753fSRafael Auler Stack.push(BB->getConditionalSuccessor(true)); 3563a34c753fSRafael Auler Stack.push(BB->getConditionalSuccessor(false)); 3564a34c753fSRafael Auler } else { 3565a34c753fSRafael Auler Stack.push(BB->getConditionalSuccessor(false)); 3566a34c753fSRafael Auler Stack.push(BB->getConditionalSuccessor(true)); 3567a34c753fSRafael Auler } 3568a34c753fSRafael Auler } else { 3569a34c753fSRafael Auler for (BinaryBasicBlock *SuccBB : BB->successors()) { 3570a34c753fSRafael Auler Stack.push(SuccBB); 3571a34c753fSRafael Auler } 3572a34c753fSRafael Auler } 3573a34c753fSRafael Auler } 3574a34c753fSRafael Auler 3575a34c753fSRafael Auler return DFS; 3576a34c753fSRafael Auler } 3577a34c753fSRafael Auler 3578a34c753fSRafael Auler size_t BinaryFunction::computeHash(bool UseDFS, 3579a34c753fSRafael Auler OperandHashFuncTy OperandHashFunc) const { 3580a34c753fSRafael Auler if (size() == 0) 3581a34c753fSRafael Auler return 0; 3582a34c753fSRafael Auler 3583a34c753fSRafael Auler assert(hasCFG() && "function is expected to have CFG"); 3584a34c753fSRafael Auler 3585d5c03defSFabian Parzefall SmallVector<const BinaryBasicBlock *, 0> Order; 35868477bc67SFabian Parzefall if (UseDFS) 3587d5c03defSFabian Parzefall llvm::copy(dfs(), std::back_inserter(Order)); 35888477bc67SFabian Parzefall else 35898477bc67SFabian Parzefall llvm::copy(Layout.blocks(), std::back_inserter(Order)); 3590a34c753fSRafael Auler 3591a34c753fSRafael Auler // The hash is computed by creating a string of all instruction opcodes and 3592a34c753fSRafael Auler // possibly their operands and then hashing that string with std::hash. 3593a34c753fSRafael Auler std::string HashString; 35943e3a926bSspupyrev for (const BinaryBasicBlock *BB : Order) 35953e3a926bSspupyrev HashString.append(hashBlock(BC, *BB, OperandHashFunc)); 3596a34c753fSRafael Auler 3597a34c753fSRafael Auler return Hash = std::hash<std::string>{}(HashString); 3598a34c753fSRafael Auler } 3599a34c753fSRafael Auler 3600a34c753fSRafael Auler void BinaryFunction::insertBasicBlocks( 3601a34c753fSRafael Auler BinaryBasicBlock *Start, 3602a34c753fSRafael Auler std::vector<std::unique_ptr<BinaryBasicBlock>> &&NewBBs, 360340c2e0faSMaksim Panchenko const bool UpdateLayout, const bool UpdateCFIState, 3604a34c753fSRafael Auler const bool RecomputeLandingPads) { 3605f18fcdabSAmir Ayupov const int64_t StartIndex = Start ? getIndex(Start) : -1LL; 3606a34c753fSRafael Auler const size_t NumNewBlocks = NewBBs.size(); 3607a34c753fSRafael Auler 360840c2e0faSMaksim Panchenko BasicBlocks.insert(BasicBlocks.begin() + (StartIndex + 1), NumNewBlocks, 3609a34c753fSRafael Auler nullptr); 3610a34c753fSRafael Auler 3611f18fcdabSAmir Ayupov int64_t I = StartIndex + 1; 3612a34c753fSRafael Auler for (std::unique_ptr<BinaryBasicBlock> &BB : NewBBs) { 3613a34c753fSRafael Auler assert(!BasicBlocks[I]); 3614a34c753fSRafael Auler BasicBlocks[I++] = BB.release(); 3615a34c753fSRafael Auler } 3616a34c753fSRafael Auler 36173652483cSRafael Auler if (RecomputeLandingPads) 3618a34c753fSRafael Auler recomputeLandingPads(); 36193652483cSRafael Auler else 3620a34c753fSRafael Auler updateBBIndices(0); 3621a34c753fSRafael Auler 36223652483cSRafael Auler if (UpdateLayout) 3623a34c753fSRafael Auler updateLayout(Start, NumNewBlocks); 3624a34c753fSRafael Auler 36253652483cSRafael Auler if (UpdateCFIState) 3626a34c753fSRafael Auler updateCFIState(Start, NumNewBlocks); 3627a34c753fSRafael Auler } 3628a34c753fSRafael Auler 3629a34c753fSRafael Auler BinaryFunction::iterator BinaryFunction::insertBasicBlocks( 3630a34c753fSRafael Auler BinaryFunction::iterator StartBB, 3631a34c753fSRafael Auler std::vector<std::unique_ptr<BinaryBasicBlock>> &&NewBBs, 363240c2e0faSMaksim Panchenko const bool UpdateLayout, const bool UpdateCFIState, 3633a34c753fSRafael Auler const bool RecomputeLandingPads) { 3634a34c753fSRafael Auler const unsigned StartIndex = getIndex(&*StartBB); 3635a34c753fSRafael Auler const size_t NumNewBlocks = NewBBs.size(); 3636a34c753fSRafael Auler 3637a34c753fSRafael Auler BasicBlocks.insert(BasicBlocks.begin() + StartIndex + 1, NumNewBlocks, 3638a34c753fSRafael Auler nullptr); 3639a34c753fSRafael Auler auto RetIter = BasicBlocks.begin() + StartIndex + 1; 3640a34c753fSRafael Auler 3641a34c753fSRafael Auler unsigned I = StartIndex + 1; 3642a34c753fSRafael Auler for (std::unique_ptr<BinaryBasicBlock> &BB : NewBBs) { 3643a34c753fSRafael Auler assert(!BasicBlocks[I]); 3644a34c753fSRafael Auler BasicBlocks[I++] = BB.release(); 3645a34c753fSRafael Auler } 3646a34c753fSRafael Auler 36473652483cSRafael Auler if (RecomputeLandingPads) 3648a34c753fSRafael Auler recomputeLandingPads(); 36493652483cSRafael Auler else 3650a34c753fSRafael Auler updateBBIndices(0); 3651a34c753fSRafael Auler 36523652483cSRafael Auler if (UpdateLayout) 3653a34c753fSRafael Auler updateLayout(*std::prev(RetIter), NumNewBlocks); 3654a34c753fSRafael Auler 36553652483cSRafael Auler if (UpdateCFIState) 3656a34c753fSRafael Auler updateCFIState(*std::prev(RetIter), NumNewBlocks); 3657a34c753fSRafael Auler 3658a34c753fSRafael Auler return RetIter; 3659a34c753fSRafael Auler } 3660a34c753fSRafael Auler 3661a34c753fSRafael Auler void BinaryFunction::updateBBIndices(const unsigned StartIndex) { 36623652483cSRafael Auler for (unsigned I = StartIndex; I < BasicBlocks.size(); ++I) 3663a34c753fSRafael Auler BasicBlocks[I]->Index = I; 3664a34c753fSRafael Auler } 3665a34c753fSRafael Auler 3666a34c753fSRafael Auler void BinaryFunction::updateCFIState(BinaryBasicBlock *Start, 3667a34c753fSRafael Auler const unsigned NumNewBlocks) { 3668a34c753fSRafael Auler const int32_t CFIState = Start->getCFIStateAtExit(); 3669a34c753fSRafael Auler const unsigned StartIndex = getIndex(Start) + 1; 36703652483cSRafael Auler for (unsigned I = 0; I < NumNewBlocks; ++I) 3671a34c753fSRafael Auler BasicBlocks[StartIndex + I]->setCFIState(CFIState); 3672a34c753fSRafael Auler } 3673a34c753fSRafael Auler 3674a34c753fSRafael Auler void BinaryFunction::updateLayout(BinaryBasicBlock *Start, 3675a34c753fSRafael Auler const unsigned NumNewBlocks) { 36768477bc67SFabian Parzefall BasicBlockListType::iterator Begin; 36778477bc67SFabian Parzefall BasicBlockListType::iterator End; 36788477bc67SFabian Parzefall 36798477bc67SFabian Parzefall // If start not provided copy new blocks from the beginning of BasicBlocks 3680a34c753fSRafael Auler if (!Start) { 36818477bc67SFabian Parzefall Begin = BasicBlocks.begin(); 36828477bc67SFabian Parzefall End = BasicBlocks.begin() + NumNewBlocks; 36838477bc67SFabian Parzefall } else { 36848477bc67SFabian Parzefall unsigned StartIndex = getIndex(Start); 36858477bc67SFabian Parzefall Begin = std::next(BasicBlocks.begin(), StartIndex + 1); 36868477bc67SFabian Parzefall End = std::next(BasicBlocks.begin(), StartIndex + NumNewBlocks + 1); 3687a34c753fSRafael Auler } 3688a34c753fSRafael Auler 3689a34c753fSRafael Auler // Insert new blocks in the layout immediately after Start. 36908477bc67SFabian Parzefall Layout.insertBasicBlocks(Start, {Begin, End}); 36918477bc67SFabian Parzefall Layout.updateLayoutIndices(); 3692a34c753fSRafael Auler } 3693a34c753fSRafael Auler 3694a34c753fSRafael Auler bool BinaryFunction::checkForAmbiguousJumpTables() { 3695a34c753fSRafael Auler SmallSet<uint64_t, 4> JumpTables; 3696a34c753fSRafael Auler for (BinaryBasicBlock *&BB : BasicBlocks) { 3697a34c753fSRafael Auler for (MCInst &Inst : *BB) { 3698a34c753fSRafael Auler if (!BC.MIB->isIndirectBranch(Inst)) 3699a34c753fSRafael Auler continue; 3700a34c753fSRafael Auler uint64_t JTAddress = BC.MIB->getJumpTable(Inst); 3701a34c753fSRafael Auler if (!JTAddress) 3702a34c753fSRafael Auler continue; 3703a34c753fSRafael Auler // This address can be inside another jump table, but we only consider 3704a34c753fSRafael Auler // it ambiguous when the same start address is used, not the same JT 3705a34c753fSRafael Auler // object. 3706a34c753fSRafael Auler if (!JumpTables.count(JTAddress)) { 3707a34c753fSRafael Auler JumpTables.insert(JTAddress); 3708a34c753fSRafael Auler continue; 3709a34c753fSRafael Auler } 3710a34c753fSRafael Auler return true; 3711a34c753fSRafael Auler } 3712a34c753fSRafael Auler } 3713a34c753fSRafael Auler return false; 3714a34c753fSRafael Auler } 3715a34c753fSRafael Auler 3716a34c753fSRafael Auler void BinaryFunction::disambiguateJumpTables( 3717a34c753fSRafael Auler MCPlusBuilder::AllocatorIdTy AllocId) { 3718a34c753fSRafael Auler assert((opts::JumpTables != JTS_BASIC && isSimple()) || !BC.HasRelocations); 3719a34c753fSRafael Auler SmallPtrSet<JumpTable *, 4> JumpTables; 3720a34c753fSRafael Auler for (BinaryBasicBlock *&BB : BasicBlocks) { 3721a34c753fSRafael Auler for (MCInst &Inst : *BB) { 3722a34c753fSRafael Auler if (!BC.MIB->isIndirectBranch(Inst)) 3723a34c753fSRafael Auler continue; 3724a34c753fSRafael Auler JumpTable *JT = getJumpTable(Inst); 3725a34c753fSRafael Auler if (!JT) 3726a34c753fSRafael Auler continue; 3727a34c753fSRafael Auler auto Iter = JumpTables.find(JT); 3728a34c753fSRafael Auler if (Iter == JumpTables.end()) { 3729a34c753fSRafael Auler JumpTables.insert(JT); 3730a34c753fSRafael Auler continue; 3731a34c753fSRafael Auler } 3732a34c753fSRafael Auler // This instruction is an indirect jump using a jump table, but it is 3733a34c753fSRafael Auler // using the same jump table of another jump. Try all our tricks to 3734a34c753fSRafael Auler // extract the jump table symbol and make it point to a new, duplicated JT 3735a34c753fSRafael Auler MCPhysReg BaseReg1; 3736a34c753fSRafael Auler uint64_t Scale; 3737a34c753fSRafael Auler const MCSymbol *Target; 3738a34c753fSRafael Auler // In case we match if our first matcher, first instruction is the one to 3739a34c753fSRafael Auler // patch 3740a34c753fSRafael Auler MCInst *JTLoadInst = &Inst; 3741a34c753fSRafael Auler // Try a standard indirect jump matcher, scale 8 3742a34c753fSRafael Auler std::unique_ptr<MCPlusBuilder::MCInstMatcher> IndJmpMatcher = 3743a34c753fSRafael Auler BC.MIB->matchIndJmp(BC.MIB->matchReg(BaseReg1), 3744a34c753fSRafael Auler BC.MIB->matchImm(Scale), BC.MIB->matchReg(), 3745a34c753fSRafael Auler /*Offset=*/BC.MIB->matchSymbol(Target)); 3746a34c753fSRafael Auler if (!IndJmpMatcher->match( 3747a34c753fSRafael Auler *BC.MRI, *BC.MIB, 3748a34c753fSRafael Auler MutableArrayRef<MCInst>(&*BB->begin(), &Inst + 1), -1) || 374940c2e0faSMaksim Panchenko BaseReg1 != BC.MIB->getNoRegister() || Scale != 8) { 3750a34c753fSRafael Auler MCPhysReg BaseReg2; 3751a34c753fSRafael Auler uint64_t Offset; 3752a34c753fSRafael Auler // Standard JT matching failed. Trying now: 3753a34c753fSRafael Auler // movq "jt.2397/1"(,%rax,8), %rax 3754a34c753fSRafael Auler // jmpq *%rax 3755a34c753fSRafael Auler std::unique_ptr<MCPlusBuilder::MCInstMatcher> LoadMatcherOwner = 3756a34c753fSRafael Auler BC.MIB->matchLoad(BC.MIB->matchReg(BaseReg1), 3757a34c753fSRafael Auler BC.MIB->matchImm(Scale), BC.MIB->matchReg(), 3758a34c753fSRafael Auler /*Offset=*/BC.MIB->matchSymbol(Target)); 3759a34c753fSRafael Auler MCPlusBuilder::MCInstMatcher *LoadMatcher = LoadMatcherOwner.get(); 3760a34c753fSRafael Auler std::unique_ptr<MCPlusBuilder::MCInstMatcher> IndJmpMatcher2 = 3761a34c753fSRafael Auler BC.MIB->matchIndJmp(std::move(LoadMatcherOwner)); 3762a34c753fSRafael Auler if (!IndJmpMatcher2->match( 3763a34c753fSRafael Auler *BC.MRI, *BC.MIB, 3764a34c753fSRafael Auler MutableArrayRef<MCInst>(&*BB->begin(), &Inst + 1), -1) || 3765a34c753fSRafael Auler BaseReg1 != BC.MIB->getNoRegister() || Scale != 8) { 3766a34c753fSRafael Auler // JT matching failed. Trying now: 3767a34c753fSRafael Auler // PIC-style matcher, scale 4 3768a34c753fSRafael Auler // addq %rdx, %rsi 3769a34c753fSRafael Auler // addq %rdx, %rdi 3770a34c753fSRafael Auler // leaq DATAat0x402450(%rip), %r11 3771a34c753fSRafael Auler // movslq (%r11,%rdx,4), %rcx 3772a34c753fSRafael Auler // addq %r11, %rcx 3773a34c753fSRafael Auler // jmpq *%rcx # JUMPTABLE @0x402450 3774a34c753fSRafael Auler std::unique_ptr<MCPlusBuilder::MCInstMatcher> PICIndJmpMatcher = 3775a34c753fSRafael Auler BC.MIB->matchIndJmp(BC.MIB->matchAdd( 3776a34c753fSRafael Auler BC.MIB->matchReg(BaseReg1), 3777a34c753fSRafael Auler BC.MIB->matchLoad(BC.MIB->matchReg(BaseReg2), 3778a34c753fSRafael Auler BC.MIB->matchImm(Scale), BC.MIB->matchReg(), 3779a34c753fSRafael Auler BC.MIB->matchImm(Offset)))); 3780a34c753fSRafael Auler std::unique_ptr<MCPlusBuilder::MCInstMatcher> LEAMatcherOwner = 3781a34c753fSRafael Auler BC.MIB->matchLoadAddr(BC.MIB->matchSymbol(Target)); 3782a34c753fSRafael Auler MCPlusBuilder::MCInstMatcher *LEAMatcher = LEAMatcherOwner.get(); 3783a34c753fSRafael Auler std::unique_ptr<MCPlusBuilder::MCInstMatcher> PICBaseAddrMatcher = 3784a34c753fSRafael Auler BC.MIB->matchIndJmp(BC.MIB->matchAdd(std::move(LEAMatcherOwner), 3785a34c753fSRafael Auler BC.MIB->matchAnyOperand())); 3786a34c753fSRafael Auler if (!PICIndJmpMatcher->match( 3787a34c753fSRafael Auler *BC.MRI, *BC.MIB, 3788a34c753fSRafael Auler MutableArrayRef<MCInst>(&*BB->begin(), &Inst + 1), -1) || 3789a34c753fSRafael Auler Scale != 4 || BaseReg1 != BaseReg2 || Offset != 0 || 3790a34c753fSRafael Auler !PICBaseAddrMatcher->match( 3791a34c753fSRafael Auler *BC.MRI, *BC.MIB, 3792a34c753fSRafael Auler MutableArrayRef<MCInst>(&*BB->begin(), &Inst + 1), -1)) { 3793a34c753fSRafael Auler llvm_unreachable("Failed to extract jump table base"); 3794a34c753fSRafael Auler continue; 3795a34c753fSRafael Auler } 3796a34c753fSRafael Auler // Matched PIC, identify the instruction with the reference to the JT 3797a34c753fSRafael Auler JTLoadInst = LEAMatcher->CurInst; 3798a34c753fSRafael Auler } else { 3799a34c753fSRafael Auler // Matched non-PIC 3800a34c753fSRafael Auler JTLoadInst = LoadMatcher->CurInst; 3801a34c753fSRafael Auler } 3802a34c753fSRafael Auler } 3803a34c753fSRafael Auler 3804a34c753fSRafael Auler uint64_t NewJumpTableID = 0; 3805a34c753fSRafael Auler const MCSymbol *NewJTLabel; 3806a34c753fSRafael Auler std::tie(NewJumpTableID, NewJTLabel) = 3807a34c753fSRafael Auler BC.duplicateJumpTable(*this, JT, Target); 3808a34c753fSRafael Auler { 3809a34c753fSRafael Auler auto L = BC.scopeLock(); 3810a34c753fSRafael Auler BC.MIB->replaceMemOperandDisp(*JTLoadInst, NewJTLabel, BC.Ctx.get()); 3811a34c753fSRafael Auler } 3812a34c753fSRafael Auler // We use a unique ID with the high bit set as address for this "injected" 3813a34c753fSRafael Auler // jump table (not originally in the input binary). 3814a34c753fSRafael Auler BC.MIB->setJumpTable(Inst, NewJumpTableID, 0, AllocId); 3815a34c753fSRafael Auler } 3816a34c753fSRafael Auler } 3817a34c753fSRafael Auler } 3818a34c753fSRafael Auler 3819a34c753fSRafael Auler bool BinaryFunction::replaceJumpTableEntryIn(BinaryBasicBlock *BB, 3820a34c753fSRafael Auler BinaryBasicBlock *OldDest, 3821a34c753fSRafael Auler BinaryBasicBlock *NewDest) { 3822a34c753fSRafael Auler MCInst *Instr = BB->getLastNonPseudoInstr(); 3823a34c753fSRafael Auler if (!Instr || !BC.MIB->isIndirectBranch(*Instr)) 3824a34c753fSRafael Auler return false; 3825a34c753fSRafael Auler uint64_t JTAddress = BC.MIB->getJumpTable(*Instr); 3826a34c753fSRafael Auler assert(JTAddress && "Invalid jump table address"); 3827a34c753fSRafael Auler JumpTable *JT = getJumpTableContainingAddress(JTAddress); 3828a34c753fSRafael Auler assert(JT && "No jump table structure for this indirect branch"); 3829a34c753fSRafael Auler bool Patched = JT->replaceDestination(JTAddress, OldDest->getLabel(), 3830a34c753fSRafael Auler NewDest->getLabel()); 3831a34c753fSRafael Auler (void)Patched; 3832a34c753fSRafael Auler assert(Patched && "Invalid entry to be replaced in jump table"); 3833a34c753fSRafael Auler return true; 3834a34c753fSRafael Auler } 3835a34c753fSRafael Auler 3836a34c753fSRafael Auler BinaryBasicBlock *BinaryFunction::splitEdge(BinaryBasicBlock *From, 3837a34c753fSRafael Auler BinaryBasicBlock *To) { 3838a34c753fSRafael Auler // Create intermediate BB 3839a34c753fSRafael Auler MCSymbol *Tmp; 3840a34c753fSRafael Auler { 3841a34c753fSRafael Auler auto L = BC.scopeLock(); 3842a34c753fSRafael Auler Tmp = BC.Ctx->createNamedTempSymbol("SplitEdge"); 3843a34c753fSRafael Auler } 3844a34c753fSRafael Auler // Link new BBs to the original input offset of the From BB, so we can map 3845a34c753fSRafael Auler // samples recorded in new BBs back to the original BB seem in the input 3846a34c753fSRafael Auler // binary (if using BAT) 38478228c703SMaksim Panchenko std::unique_ptr<BinaryBasicBlock> NewBB = createBasicBlock(Tmp); 38488228c703SMaksim Panchenko NewBB->setOffset(From->getInputOffset()); 3849a34c753fSRafael Auler BinaryBasicBlock *NewBBPtr = NewBB.get(); 3850a34c753fSRafael Auler 3851a34c753fSRafael Auler // Update "From" BB 3852a34c753fSRafael Auler auto I = From->succ_begin(); 3853a34c753fSRafael Auler auto BI = From->branch_info_begin(); 3854a34c753fSRafael Auler for (; I != From->succ_end(); ++I) { 3855a34c753fSRafael Auler if (*I == To) 3856a34c753fSRafael Auler break; 3857a34c753fSRafael Auler ++BI; 3858a34c753fSRafael Auler } 3859a34c753fSRafael Auler assert(I != From->succ_end() && "Invalid CFG edge in splitEdge!"); 3860a34c753fSRafael Auler uint64_t OrigCount = BI->Count; 3861a34c753fSRafael Auler uint64_t OrigMispreds = BI->MispredictedCount; 3862a34c753fSRafael Auler replaceJumpTableEntryIn(From, To, NewBBPtr); 3863a34c753fSRafael Auler From->replaceSuccessor(To, NewBBPtr, OrigCount, OrigMispreds); 3864a34c753fSRafael Auler 3865a34c753fSRafael Auler NewBB->addSuccessor(To, OrigCount, OrigMispreds); 3866a34c753fSRafael Auler NewBB->setExecutionCount(OrigCount); 3867a34c753fSRafael Auler NewBB->setIsCold(From->isCold()); 3868a34c753fSRafael Auler 3869a34c753fSRafael Auler // Update CFI and BB layout with new intermediate BB 3870a34c753fSRafael Auler std::vector<std::unique_ptr<BinaryBasicBlock>> NewBBs; 3871a34c753fSRafael Auler NewBBs.emplace_back(std::move(NewBB)); 3872a34c753fSRafael Auler insertBasicBlocks(From, std::move(NewBBs), true, true, 3873a34c753fSRafael Auler /*RecomputeLandingPads=*/false); 3874a34c753fSRafael Auler return NewBBPtr; 3875a34c753fSRafael Auler } 3876a34c753fSRafael Auler 3877a34c753fSRafael Auler void BinaryFunction::deleteConservativeEdges() { 3878a34c753fSRafael Auler // Our goal is to aggressively remove edges from the CFG that we believe are 3879a34c753fSRafael Auler // wrong. This is used for instrumentation, where it is safe to remove 3880a34c753fSRafael Auler // fallthrough edges because we won't reorder blocks. 3881a34c753fSRafael Auler for (auto I = BasicBlocks.begin(), E = BasicBlocks.end(); I != E; ++I) { 3882a34c753fSRafael Auler BinaryBasicBlock *BB = *I; 3883a34c753fSRafael Auler if (BB->succ_size() != 1 || BB->size() == 0) 3884a34c753fSRafael Auler continue; 3885a34c753fSRafael Auler 3886a34c753fSRafael Auler auto NextBB = std::next(I); 3887a34c753fSRafael Auler MCInst *Last = BB->getLastNonPseudoInstr(); 3888a34c753fSRafael Auler // Fallthrough is a landing pad? Delete this edge (as long as we don't 3889a34c753fSRafael Auler // have a direct jump to it) 3890a34c753fSRafael Auler if ((*BB->succ_begin())->isLandingPad() && NextBB != E && 3891a34c753fSRafael Auler *BB->succ_begin() == *NextBB && Last && !BC.MIB->isBranch(*Last)) { 3892a34c753fSRafael Auler BB->removeAllSuccessors(); 3893a34c753fSRafael Auler continue; 3894a34c753fSRafael Auler } 3895a34c753fSRafael Auler 3896a34c753fSRafael Auler // Look for suspicious calls at the end of BB where gcc may optimize it and 3897a34c753fSRafael Auler // remove the jump to the epilogue when it knows the call won't return. 3898a34c753fSRafael Auler if (!Last || !BC.MIB->isCall(*Last)) 3899a34c753fSRafael Auler continue; 3900a34c753fSRafael Auler 3901a34c753fSRafael Auler const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(*Last); 3902a34c753fSRafael Auler if (!CalleeSymbol) 3903a34c753fSRafael Auler continue; 3904a34c753fSRafael Auler 3905a34c753fSRafael Auler StringRef CalleeName = CalleeSymbol->getName(); 390640c2e0faSMaksim Panchenko if (CalleeName != "__cxa_throw@PLT" && CalleeName != "_Unwind_Resume@PLT" && 390740c2e0faSMaksim Panchenko CalleeName != "__cxa_rethrow@PLT" && CalleeName != "exit@PLT" && 3908a34c753fSRafael Auler CalleeName != "abort@PLT") 3909a34c753fSRafael Auler continue; 3910a34c753fSRafael Auler 3911a34c753fSRafael Auler BB->removeAllSuccessors(); 3912a34c753fSRafael Auler } 3913a34c753fSRafael Auler } 3914a34c753fSRafael Auler 3915a34c753fSRafael Auler bool BinaryFunction::isSymbolValidInScope(const SymbolRef &Symbol, 3916a34c753fSRafael Auler uint64_t SymbolSize) const { 3917a34c753fSRafael Auler // If this symbol is in a different section from the one where the 3918a34c753fSRafael Auler // function symbol is, don't consider it as valid. 3919a34c753fSRafael Auler if (!getOriginSection()->containsAddress( 3920a34c753fSRafael Auler cantFail(Symbol.getAddress(), "cannot get symbol address"))) 3921a34c753fSRafael Auler return false; 3922a34c753fSRafael Auler 3923a34c753fSRafael Auler // Some symbols are tolerated inside function bodies, others are not. 3924a34c753fSRafael Auler // The real function boundaries may not be known at this point. 39258579db96SDenis Revunov if (BC.isMarker(Symbol)) 3926a34c753fSRafael Auler return true; 3927a34c753fSRafael Auler 3928a34c753fSRafael Auler // It's okay to have a zero-sized symbol in the middle of non-zero-sized 3929a34c753fSRafael Auler // function. 3930a34c753fSRafael Auler if (SymbolSize == 0 && containsAddress(cantFail(Symbol.getAddress()))) 3931a34c753fSRafael Auler return true; 3932a34c753fSRafael Auler 3933a34c753fSRafael Auler if (cantFail(Symbol.getType()) != SymbolRef::ST_Unknown) 3934a34c753fSRafael Auler return false; 3935a34c753fSRafael Auler 3936a34c753fSRafael Auler if (cantFail(Symbol.getFlags()) & SymbolRef::SF_Global) 3937a34c753fSRafael Auler return false; 3938a34c753fSRafael Auler 3939a34c753fSRafael Auler return true; 3940a34c753fSRafael Auler } 3941a34c753fSRafael Auler 3942a34c753fSRafael Auler void BinaryFunction::adjustExecutionCount(uint64_t Count) { 3943a34c753fSRafael Auler if (getKnownExecutionCount() == 0 || Count == 0) 3944a34c753fSRafael Auler return; 3945a34c753fSRafael Auler 3946a34c753fSRafael Auler if (ExecutionCount < Count) 3947a34c753fSRafael Auler Count = ExecutionCount; 3948a34c753fSRafael Auler 3949a34c753fSRafael Auler double AdjustmentRatio = ((double)ExecutionCount - Count) / ExecutionCount; 3950a34c753fSRafael Auler if (AdjustmentRatio < 0.0) 3951a34c753fSRafael Auler AdjustmentRatio = 0.0; 3952a34c753fSRafael Auler 3953d55dfeafSFabian Parzefall for (BinaryBasicBlock &BB : blocks()) 3954d55dfeafSFabian Parzefall BB.adjustExecutionCount(AdjustmentRatio); 3955a34c753fSRafael Auler 3956a34c753fSRafael Auler ExecutionCount -= Count; 3957a34c753fSRafael Auler } 3958a34c753fSRafael Auler 3959a34c753fSRafael Auler BinaryFunction::~BinaryFunction() { 39603652483cSRafael Auler for (BinaryBasicBlock *BB : BasicBlocks) 3961a34c753fSRafael Auler delete BB; 39623652483cSRafael Auler for (BinaryBasicBlock *BB : DeletedBasicBlocks) 3963a34c753fSRafael Auler delete BB; 3964a34c753fSRafael Auler } 3965a34c753fSRafael Auler 3966a34c753fSRafael Auler void BinaryFunction::calculateLoopInfo() { 3967a34c753fSRafael Auler // Discover loops. 3968a34c753fSRafael Auler BinaryDominatorTree DomTree; 3969a34c753fSRafael Auler DomTree.recalculate(*this); 3970a34c753fSRafael Auler BLI.reset(new BinaryLoopInfo()); 3971a34c753fSRafael Auler BLI->analyze(DomTree); 3972a34c753fSRafael Auler 3973a34c753fSRafael Auler // Traverse discovered loops and add depth and profile information. 3974a34c753fSRafael Auler std::stack<BinaryLoop *> St; 3975a34c753fSRafael Auler for (auto I = BLI->begin(), E = BLI->end(); I != E; ++I) { 3976a34c753fSRafael Auler St.push(*I); 3977a34c753fSRafael Auler ++BLI->OuterLoops; 3978a34c753fSRafael Auler } 3979a34c753fSRafael Auler 3980a34c753fSRafael Auler while (!St.empty()) { 3981a34c753fSRafael Auler BinaryLoop *L = St.top(); 3982a34c753fSRafael Auler St.pop(); 3983a34c753fSRafael Auler ++BLI->TotalLoops; 3984a34c753fSRafael Auler BLI->MaximumDepth = std::max(L->getLoopDepth(), BLI->MaximumDepth); 3985a34c753fSRafael Auler 3986a34c753fSRafael Auler // Add nested loops in the stack. 39873652483cSRafael Auler for (BinaryLoop::iterator I = L->begin(), E = L->end(); I != E; ++I) 3988a34c753fSRafael Auler St.push(*I); 3989a34c753fSRafael Auler 3990a34c753fSRafael Auler // Skip if no valid profile is found. 3991a34c753fSRafael Auler if (!hasValidProfile()) { 3992a34c753fSRafael Auler L->EntryCount = COUNT_NO_PROFILE; 3993a34c753fSRafael Auler L->ExitCount = COUNT_NO_PROFILE; 3994a34c753fSRafael Auler L->TotalBackEdgeCount = COUNT_NO_PROFILE; 3995a34c753fSRafael Auler continue; 3996a34c753fSRafael Auler } 3997a34c753fSRafael Auler 3998a34c753fSRafael Auler // Compute back edge count. 3999a34c753fSRafael Auler SmallVector<BinaryBasicBlock *, 1> Latches; 4000a34c753fSRafael Auler L->getLoopLatches(Latches); 4001a34c753fSRafael Auler 4002a34c753fSRafael Auler for (BinaryBasicBlock *Latch : Latches) { 4003a34c753fSRafael Auler auto BI = Latch->branch_info_begin(); 4004a34c753fSRafael Auler for (BinaryBasicBlock *Succ : Latch->successors()) { 4005a34c753fSRafael Auler if (Succ == L->getHeader()) { 4006a34c753fSRafael Auler assert(BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE && 4007a34c753fSRafael Auler "profile data not found"); 4008a34c753fSRafael Auler L->TotalBackEdgeCount += BI->Count; 4009a34c753fSRafael Auler } 4010a34c753fSRafael Auler ++BI; 4011a34c753fSRafael Auler } 4012a34c753fSRafael Auler } 4013a34c753fSRafael Auler 4014a34c753fSRafael Auler // Compute entry count. 4015a34c753fSRafael Auler L->EntryCount = L->getHeader()->getExecutionCount() - L->TotalBackEdgeCount; 4016a34c753fSRafael Auler 4017a34c753fSRafael Auler // Compute exit count. 4018a34c753fSRafael Auler SmallVector<BinaryLoop::Edge, 1> ExitEdges; 4019a34c753fSRafael Auler L->getExitEdges(ExitEdges); 4020a34c753fSRafael Auler for (BinaryLoop::Edge &Exit : ExitEdges) { 4021a34c753fSRafael Auler const BinaryBasicBlock *Exiting = Exit.first; 4022a34c753fSRafael Auler const BinaryBasicBlock *ExitTarget = Exit.second; 4023a34c753fSRafael Auler auto BI = Exiting->branch_info_begin(); 4024a34c753fSRafael Auler for (BinaryBasicBlock *Succ : Exiting->successors()) { 4025a34c753fSRafael Auler if (Succ == ExitTarget) { 4026a34c753fSRafael Auler assert(BI->Count != BinaryBasicBlock::COUNT_NO_PROFILE && 4027a34c753fSRafael Auler "profile data not found"); 4028a34c753fSRafael Auler L->ExitCount += BI->Count; 4029a34c753fSRafael Auler } 4030a34c753fSRafael Auler ++BI; 4031a34c753fSRafael Auler } 4032a34c753fSRafael Auler } 4033a34c753fSRafael Auler } 4034a34c753fSRafael Auler } 4035a34c753fSRafael Auler 4036475a93a0SJob Noorman void BinaryFunction::updateOutputValues(const BOLTLinker &Linker) { 4037a34c753fSRafael Auler if (!isEmitted()) { 4038a34c753fSRafael Auler assert(!isInjected() && "injected function should be emitted"); 4039a34c753fSRafael Auler setOutputAddress(getAddress()); 4040a34c753fSRafael Auler setOutputSize(getSize()); 4041a34c753fSRafael Auler return; 4042a34c753fSRafael Auler } 4043a34c753fSRafael Auler 4044475a93a0SJob Noorman const auto SymbolInfo = Linker.lookupSymbolInfo(getSymbol()->getName()); 4045475a93a0SJob Noorman assert(SymbolInfo && "Cannot find function entry symbol"); 4046475a93a0SJob Noorman setOutputAddress(SymbolInfo->Address); 4047475a93a0SJob Noorman setOutputSize(SymbolInfo->Size); 4048475a93a0SJob Noorman 4049a34c753fSRafael Auler if (BC.HasRelocations || isInjected()) { 4050a34c753fSRafael Auler if (hasConstantIsland()) { 4051475a93a0SJob Noorman const auto DataAddress = 4052475a93a0SJob Noorman Linker.lookupSymbol(getFunctionConstantIslandLabel()->getName()); 4053475a93a0SJob Noorman assert(DataAddress && "Cannot find function CI symbol"); 4054475a93a0SJob Noorman setOutputDataAddress(*DataAddress); 40557117af52SVladislav Khmelevsky for (auto It : Islands->Offsets) { 40567117af52SVladislav Khmelevsky const uint64_t OldOffset = It.first; 40577117af52SVladislav Khmelevsky BinaryData *BD = BC.getBinaryDataAtAddress(getAddress() + OldOffset); 40587117af52SVladislav Khmelevsky if (!BD) 40597117af52SVladislav Khmelevsky continue; 40607117af52SVladislav Khmelevsky 40617117af52SVladislav Khmelevsky MCSymbol *Symbol = It.second; 4062475a93a0SJob Noorman const auto NewAddress = Linker.lookupSymbol(Symbol->getName()); 4063475a93a0SJob Noorman assert(NewAddress && "Cannot find CI symbol"); 4064475a93a0SJob Noorman auto &Section = *getCodeSection(); 4065475a93a0SJob Noorman const auto NewOffset = *NewAddress - Section.getOutputAddress(); 4066475a93a0SJob Noorman BD->setOutputLocation(Section, NewOffset); 40677117af52SVladislav Khmelevsky } 4068a34c753fSRafael Auler } 4069a34c753fSRafael Auler if (isSplit()) { 40709b6e7861SFabian Parzefall for (FunctionFragment &FF : getLayout().getSplitFragments()) { 40710f74d191SFabian Parzefall ErrorOr<BinarySection &> ColdSection = 40720f74d191SFabian Parzefall getCodeSection(FF.getFragmentNum()); 40730f74d191SFabian Parzefall // If fragment is empty, cold section might not exist 40740f74d191SFabian Parzefall if (FF.empty() && ColdSection.getError()) 40750f74d191SFabian Parzefall continue; 40760f74d191SFabian Parzefall 40770f74d191SFabian Parzefall const MCSymbol *ColdStartSymbol = getSymbol(FF.getFragmentNum()); 40780f74d191SFabian Parzefall // If fragment is empty, symbol might have not been emitted 40790f74d191SFabian Parzefall if (FF.empty() && (!ColdStartSymbol || !ColdStartSymbol->isDefined()) && 40800f74d191SFabian Parzefall !hasConstantIsland()) 40810f74d191SFabian Parzefall continue; 4082a34c753fSRafael Auler assert(ColdStartSymbol && ColdStartSymbol->isDefined() && 4083a34c753fSRafael Auler "split function should have defined cold symbol"); 4084475a93a0SJob Noorman const auto ColdStartSymbolInfo = 4085475a93a0SJob Noorman Linker.lookupSymbolInfo(ColdStartSymbol->getName()); 4086475a93a0SJob Noorman assert(ColdStartSymbolInfo && "Cannot find cold start symbol"); 4087475a93a0SJob Noorman FF.setAddress(ColdStartSymbolInfo->Address); 4088475a93a0SJob Noorman FF.setImageSize(ColdStartSymbolInfo->Size); 4089a34c753fSRafael Auler if (hasConstantIsland()) { 4090475a93a0SJob Noorman const auto DataAddress = Linker.lookupSymbol( 4091475a93a0SJob Noorman getFunctionColdConstantIslandLabel()->getName()); 4092475a93a0SJob Noorman assert(DataAddress && "Cannot find cold CI symbol"); 4093475a93a0SJob Noorman setOutputColdDataAddress(*DataAddress); 4094a34c753fSRafael Auler } 4095a34c753fSRafael Auler } 40960f74d191SFabian Parzefall } 4097a34c753fSRafael Auler } 4098a34c753fSRafael Auler 4099a34c753fSRafael Auler // Update basic block output ranges for the debug info, if we have 4100a34c753fSRafael Auler // secondary entry points in the symbol table to update or if writing BAT. 4101475a93a0SJob Noorman if (!requiresAddressMap()) 4102a34c753fSRafael Auler return; 4103a34c753fSRafael Auler 4104a34c753fSRafael Auler // Output ranges should match the input if the body hasn't changed. 4105a34c753fSRafael Auler if (!isSimple() && !BC.HasRelocations) 4106a34c753fSRafael Auler return; 4107a34c753fSRafael Auler 4108a34c753fSRafael Auler // AArch64 may have functions that only contains a constant island (no code). 41098477bc67SFabian Parzefall if (getLayout().block_empty()) 4110a34c753fSRafael Auler return; 4111a34c753fSRafael Auler 411207f63b0aSFabian Parzefall for (FunctionFragment &FF : getLayout().fragments()) { 41139b6e7861SFabian Parzefall if (FF.empty()) 41149b6e7861SFabian Parzefall continue; 41159b6e7861SFabian Parzefall 41160f74d191SFabian Parzefall const uint64_t FragmentBaseAddress = 41170f74d191SFabian Parzefall getCodeSection(isSimple() ? FF.getFragmentNum() : FragmentNum::main()) 41180f74d191SFabian Parzefall ->getOutputAddress(); 41199b6e7861SFabian Parzefall 41209b6e7861SFabian Parzefall BinaryBasicBlock *PrevBB = nullptr; 41210f74d191SFabian Parzefall for (BinaryBasicBlock *const BB : FF) { 4122a34c753fSRafael Auler assert(BB->getLabel()->isDefined() && "symbol should be defined"); 4123a34c753fSRafael Auler if (!BC.HasRelocations) { 41249b6e7861SFabian Parzefall if (BB->isSplit()) 41259b6e7861SFabian Parzefall assert(FragmentBaseAddress == FF.getAddress()); 41269b6e7861SFabian Parzefall else 41270f74d191SFabian Parzefall assert(FragmentBaseAddress == getOutputAddress()); 4128ff22d125SKazu Hirata (void)FragmentBaseAddress; 4129a34c753fSRafael Auler } 41309b6e7861SFabian Parzefall 4131b59cf211SRafael Auler // Injected functions likely will fail lookup, as they have no 4132b59cf211SRafael Auler // input range. Just assign the BB the output address of the 4133b59cf211SRafael Auler // function. 4134b59cf211SRafael Auler auto MaybeBBAddress = 4135b59cf211SRafael Auler BC.getIOAddressMap().lookup(BB->getInputOffset() + getAddress()); 4136b59cf211SRafael Auler const uint64_t BBAddress = MaybeBBAddress ? *MaybeBBAddress 4137b59cf211SRafael Auler : BB->isSplit() ? FF.getAddress() 4138b59cf211SRafael Auler : getOutputAddress(); 4139a34c753fSRafael Auler BB->setOutputStartAddress(BBAddress); 4140a34c753fSRafael Auler 41419b6e7861SFabian Parzefall if (PrevBB) 41429b6e7861SFabian Parzefall PrevBB->setOutputEndAddress(BBAddress); 4143a34c753fSRafael Auler PrevBB = BB; 4144a34c753fSRafael Auler } 41459b6e7861SFabian Parzefall 41466304e382SFabian Parzefall PrevBB->setOutputEndAddress(PrevBB->isSplit() 41479b6e7861SFabian Parzefall ? FF.getAddress() + FF.getImageSize() 41486304e382SFabian Parzefall : getOutputAddress() + getOutputSize()); 41497e254818SFabian Parzefall } 41509b6e7861SFabian Parzefall } 4151a34c753fSRafael Auler 4152a34c753fSRafael Auler DebugAddressRangesVector BinaryFunction::getOutputAddressRanges() const { 4153a34c753fSRafael Auler DebugAddressRangesVector OutputRanges; 4154a34c753fSRafael Auler 4155a34c753fSRafael Auler if (isFolded()) 4156a34c753fSRafael Auler return OutputRanges; 4157a34c753fSRafael Auler 4158a34c753fSRafael Auler if (IsFragment) 4159a34c753fSRafael Auler return OutputRanges; 4160a34c753fSRafael Auler 4161a34c753fSRafael Auler OutputRanges.emplace_back(getOutputAddress(), 4162a34c753fSRafael Auler getOutputAddress() + getOutputSize()); 4163a34c753fSRafael Auler if (isSplit()) { 4164a34c753fSRafael Auler assert(isEmitted() && "split function should be emitted"); 41659b6e7861SFabian Parzefall for (const FunctionFragment &FF : getLayout().getSplitFragments()) 41669b6e7861SFabian Parzefall OutputRanges.emplace_back(FF.getAddress(), 41679b6e7861SFabian Parzefall FF.getAddress() + FF.getImageSize()); 4168a34c753fSRafael Auler } 4169a34c753fSRafael Auler 4170a34c753fSRafael Auler if (isSimple()) 4171a34c753fSRafael Auler return OutputRanges; 4172a34c753fSRafael Auler 4173a34c753fSRafael Auler for (BinaryFunction *Frag : Fragments) { 4174a34c753fSRafael Auler assert(!Frag->isSimple() && 4175a34c753fSRafael Auler "fragment of non-simple function should also be non-simple"); 4176a34c753fSRafael Auler OutputRanges.emplace_back(Frag->getOutputAddress(), 4177a34c753fSRafael Auler Frag->getOutputAddress() + Frag->getOutputSize()); 4178a34c753fSRafael Auler } 4179a34c753fSRafael Auler 4180a34c753fSRafael Auler return OutputRanges; 4181a34c753fSRafael Auler } 4182a34c753fSRafael Auler 4183a34c753fSRafael Auler uint64_t BinaryFunction::translateInputToOutputAddress(uint64_t Address) const { 4184a34c753fSRafael Auler if (isFolded()) 4185a34c753fSRafael Auler return 0; 4186a34c753fSRafael Auler 4187a34c753fSRafael Auler // If the function hasn't changed return the same address. 4188a34c753fSRafael Auler if (!isEmitted()) 4189a34c753fSRafael Auler return Address; 4190a34c753fSRafael Auler 4191a34c753fSRafael Auler if (Address < getAddress()) 4192a34c753fSRafael Auler return 0; 4193a34c753fSRafael Auler 4194a34c753fSRafael Auler // Check if the address is associated with an instruction that is tracked 4195a34c753fSRafael Auler // by address translation. 419623c8d382SJob Noorman if (auto OutputAddress = BC.getIOAddressMap().lookup(Address)) 419723c8d382SJob Noorman return *OutputAddress; 4198a34c753fSRafael Auler 4199a34c753fSRafael Auler // FIXME: #18950828 - we rely on relative offsets inside basic blocks to stay 4200a34c753fSRafael Auler // intact. Instead we can use pseudo instructions and/or annotations. 4201a34c753fSRafael Auler const uint64_t Offset = Address - getAddress(); 4202a34c753fSRafael Auler const BinaryBasicBlock *BB = getBasicBlockContainingOffset(Offset); 4203a34c753fSRafael Auler if (!BB) { 4204a34c753fSRafael Auler // Special case for address immediately past the end of the function. 4205a34c753fSRafael Auler if (Offset == getSize()) 4206a34c753fSRafael Auler return getOutputAddress() + getOutputSize(); 4207a34c753fSRafael Auler 4208a34c753fSRafael Auler return 0; 4209a34c753fSRafael Auler } 4210a34c753fSRafael Auler 4211a34c753fSRafael Auler return std::min(BB->getOutputAddressRange().first + Offset - BB->getOffset(), 4212a34c753fSRafael Auler BB->getOutputAddressRange().second); 4213a34c753fSRafael Auler } 4214a34c753fSRafael Auler 4215a34c753fSRafael Auler DebugAddressRangesVector BinaryFunction::translateInputToOutputRanges( 4216a34c753fSRafael Auler const DWARFAddressRangesVector &InputRanges) const { 4217a34c753fSRafael Auler DebugAddressRangesVector OutputRanges; 4218a34c753fSRafael Auler 4219a34c753fSRafael Auler if (isFolded()) 4220a34c753fSRafael Auler return OutputRanges; 4221a34c753fSRafael Auler 4222a34c753fSRafael Auler // If the function hasn't changed return the same ranges. 4223a34c753fSRafael Auler if (!isEmitted()) { 4224a34c753fSRafael Auler OutputRanges.resize(InputRanges.size()); 4225d2c87699SAmir Ayupov llvm::transform(InputRanges, OutputRanges.begin(), 4226a34c753fSRafael Auler [](const DWARFAddressRange &Range) { 4227a34c753fSRafael Auler return DebugAddressRange(Range.LowPC, Range.HighPC); 4228a34c753fSRafael Auler }); 4229a34c753fSRafael Auler return OutputRanges; 4230a34c753fSRafael Auler } 4231a34c753fSRafael Auler 4232a34c753fSRafael Auler // Even though we will merge ranges in a post-processing pass, we attempt to 4233a34c753fSRafael Auler // merge them in a main processing loop as it improves the processing time. 4234a34c753fSRafael Auler uint64_t PrevEndAddress = 0; 4235a34c753fSRafael Auler for (const DWARFAddressRange &Range : InputRanges) { 4236a34c753fSRafael Auler if (!containsAddress(Range.LowPC)) { 4237a34c753fSRafael Auler LLVM_DEBUG( 4238a34c753fSRafael Auler dbgs() << "BOLT-DEBUG: invalid debug address range detected for " 4239a34c753fSRafael Auler << *this << " : [0x" << Twine::utohexstr(Range.LowPC) << ", 0x" 4240a34c753fSRafael Auler << Twine::utohexstr(Range.HighPC) << "]\n"); 4241a34c753fSRafael Auler PrevEndAddress = 0; 4242a34c753fSRafael Auler continue; 4243a34c753fSRafael Auler } 4244a34c753fSRafael Auler uint64_t InputOffset = Range.LowPC - getAddress(); 4245a34c753fSRafael Auler const uint64_t InputEndOffset = 4246a34c753fSRafael Auler std::min(Range.HighPC - getAddress(), getSize()); 4247a34c753fSRafael Auler 4248d2c87699SAmir Ayupov auto BBI = llvm::upper_bound(BasicBlockOffsets, 4249d2c87699SAmir Ayupov BasicBlockOffset(InputOffset, nullptr), 4250d2c87699SAmir Ayupov CompareBasicBlockOffsets()); 4251a34c753fSRafael Auler --BBI; 4252a34c753fSRafael Auler do { 4253a34c753fSRafael Auler const BinaryBasicBlock *BB = BBI->second; 4254a34c753fSRafael Auler if (InputOffset < BB->getOffset() || InputOffset >= BB->getEndOffset()) { 4255a34c753fSRafael Auler LLVM_DEBUG( 4256a34c753fSRafael Auler dbgs() << "BOLT-DEBUG: invalid debug address range detected for " 4257a34c753fSRafael Auler << *this << " : [0x" << Twine::utohexstr(Range.LowPC) 4258a34c753fSRafael Auler << ", 0x" << Twine::utohexstr(Range.HighPC) << "]\n"); 4259a34c753fSRafael Auler PrevEndAddress = 0; 4260a34c753fSRafael Auler break; 4261a34c753fSRafael Auler } 4262a34c753fSRafael Auler 4263a34c753fSRafael Auler // Skip the range if the block was deleted. 4264a34c753fSRafael Auler if (const uint64_t OutputStart = BB->getOutputAddressRange().first) { 4265a34c753fSRafael Auler const uint64_t StartAddress = 4266a34c753fSRafael Auler OutputStart + InputOffset - BB->getOffset(); 4267a34c753fSRafael Auler uint64_t EndAddress = BB->getOutputAddressRange().second; 4268a34c753fSRafael Auler if (InputEndOffset < BB->getEndOffset()) 4269a34c753fSRafael Auler EndAddress = StartAddress + InputEndOffset - InputOffset; 4270a34c753fSRafael Auler 4271a34c753fSRafael Auler if (StartAddress == PrevEndAddress) { 427240c2e0faSMaksim Panchenko OutputRanges.back().HighPC = 427340c2e0faSMaksim Panchenko std::max(OutputRanges.back().HighPC, EndAddress); 4274a34c753fSRafael Auler } else { 4275a34c753fSRafael Auler OutputRanges.emplace_back(StartAddress, 4276a34c753fSRafael Auler std::max(StartAddress, EndAddress)); 4277a34c753fSRafael Auler } 4278a34c753fSRafael Auler PrevEndAddress = OutputRanges.back().HighPC; 4279a34c753fSRafael Auler } 4280a34c753fSRafael Auler 4281a34c753fSRafael Auler InputOffset = BB->getEndOffset(); 4282a34c753fSRafael Auler ++BBI; 4283a34c753fSRafael Auler } while (InputOffset < InputEndOffset); 4284a34c753fSRafael Auler } 4285a34c753fSRafael Auler 4286a34c753fSRafael Auler // Post-processing pass to sort and merge ranges. 4287d2c87699SAmir Ayupov llvm::sort(OutputRanges); 4288a34c753fSRafael Auler DebugAddressRangesVector MergedRanges; 4289a34c753fSRafael Auler PrevEndAddress = 0; 4290a34c753fSRafael Auler for (const DebugAddressRange &Range : OutputRanges) { 4291a34c753fSRafael Auler if (Range.LowPC <= PrevEndAddress) { 429240c2e0faSMaksim Panchenko MergedRanges.back().HighPC = 429340c2e0faSMaksim Panchenko std::max(MergedRanges.back().HighPC, Range.HighPC); 4294a34c753fSRafael Auler } else { 4295a34c753fSRafael Auler MergedRanges.emplace_back(Range.LowPC, Range.HighPC); 4296a34c753fSRafael Auler } 4297a34c753fSRafael Auler PrevEndAddress = MergedRanges.back().HighPC; 4298a34c753fSRafael Auler } 4299a34c753fSRafael Auler 4300a34c753fSRafael Auler return MergedRanges; 4301a34c753fSRafael Auler } 4302a34c753fSRafael Auler 4303a34c753fSRafael Auler MCInst *BinaryFunction::getInstructionAtOffset(uint64_t Offset) { 4304a34c753fSRafael Auler if (CurrentState == State::Disassembled) { 4305a34c753fSRafael Auler auto II = Instructions.find(Offset); 4306a34c753fSRafael Auler return (II == Instructions.end()) ? nullptr : &II->second; 4307a34c753fSRafael Auler } else if (CurrentState == State::CFG) { 4308a34c753fSRafael Auler BinaryBasicBlock *BB = getBasicBlockContainingOffset(Offset); 4309a34c753fSRafael Auler if (!BB) 4310a34c753fSRafael Auler return nullptr; 4311a34c753fSRafael Auler 4312a34c753fSRafael Auler for (MCInst &Inst : *BB) { 4313a34c753fSRafael Auler constexpr uint32_t InvalidOffset = std::numeric_limits<uint32_t>::max(); 4314a9cd49d5SAmir Ayupov if (Offset == BC.MIB->getOffsetWithDefault(Inst, InvalidOffset)) 4315a34c753fSRafael Auler return &Inst; 4316a34c753fSRafael Auler } 4317a34c753fSRafael Auler 4318ccb99dd1SMaksim Panchenko if (MCInst *LastInstr = BB->getLastNonPseudoInstr()) { 4319ccb99dd1SMaksim Panchenko const uint32_t Size = 4320ccb99dd1SMaksim Panchenko BC.MIB->getAnnotationWithDefault<uint32_t>(*LastInstr, "Size"); 4321ccb99dd1SMaksim Panchenko if (BB->getEndOffset() - Offset == Size) 4322ccb99dd1SMaksim Panchenko return LastInstr; 4323ccb99dd1SMaksim Panchenko } 4324ccb99dd1SMaksim Panchenko 4325a34c753fSRafael Auler return nullptr; 4326a34c753fSRafael Auler } else { 4327a34c753fSRafael Auler llvm_unreachable("invalid CFG state to use getInstructionAtOffset()"); 4328a34c753fSRafael Auler } 4329a34c753fSRafael Auler } 4330a34c753fSRafael Auler 4331a34c753fSRafael Auler DebugLocationsVector BinaryFunction::translateInputToOutputLocationList( 4332a34c753fSRafael Auler const DebugLocationsVector &InputLL) const { 4333a34c753fSRafael Auler DebugLocationsVector OutputLL; 4334a34c753fSRafael Auler 43353652483cSRafael Auler if (isFolded()) 4336a34c753fSRafael Auler return OutputLL; 4337a34c753fSRafael Auler 4338a34c753fSRafael Auler // If the function hasn't changed - there's nothing to update. 43393652483cSRafael Auler if (!isEmitted()) 4340a34c753fSRafael Auler return InputLL; 4341a34c753fSRafael Auler 4342a34c753fSRafael Auler uint64_t PrevEndAddress = 0; 4343a34c753fSRafael Auler SmallVectorImpl<uint8_t> *PrevExpr = nullptr; 4344a34c753fSRafael Auler for (const DebugLocationEntry &Entry : InputLL) { 4345a34c753fSRafael Auler const uint64_t Start = Entry.LowPC; 4346a34c753fSRafael Auler const uint64_t End = Entry.HighPC; 4347a34c753fSRafael Auler if (!containsAddress(Start)) { 4348a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: invalid debug address range detected " 4349a34c753fSRafael Auler "for " 4350a34c753fSRafael Auler << *this << " : [0x" << Twine::utohexstr(Start) 4351a34c753fSRafael Auler << ", 0x" << Twine::utohexstr(End) << "]\n"); 4352a34c753fSRafael Auler continue; 4353a34c753fSRafael Auler } 4354a34c753fSRafael Auler uint64_t InputOffset = Start - getAddress(); 4355a34c753fSRafael Auler const uint64_t InputEndOffset = std::min(End - getAddress(), getSize()); 4356d2c87699SAmir Ayupov auto BBI = llvm::upper_bound(BasicBlockOffsets, 4357d2c87699SAmir Ayupov BasicBlockOffset(InputOffset, nullptr), 4358d2c87699SAmir Ayupov CompareBasicBlockOffsets()); 4359a34c753fSRafael Auler --BBI; 4360a34c753fSRafael Auler do { 4361a34c753fSRafael Auler const BinaryBasicBlock *BB = BBI->second; 4362a34c753fSRafael Auler if (InputOffset < BB->getOffset() || InputOffset >= BB->getEndOffset()) { 4363a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: invalid debug address range detected " 4364a34c753fSRafael Auler "for " 4365a34c753fSRafael Auler << *this << " : [0x" << Twine::utohexstr(Start) 4366a34c753fSRafael Auler << ", 0x" << Twine::utohexstr(End) << "]\n"); 4367a34c753fSRafael Auler PrevEndAddress = 0; 4368a34c753fSRafael Auler break; 4369a34c753fSRafael Auler } 4370a34c753fSRafael Auler 4371a34c753fSRafael Auler // Skip the range if the block was deleted. 4372a34c753fSRafael Auler if (const uint64_t OutputStart = BB->getOutputAddressRange().first) { 4373a34c753fSRafael Auler const uint64_t StartAddress = 4374a34c753fSRafael Auler OutputStart + InputOffset - BB->getOffset(); 4375a34c753fSRafael Auler uint64_t EndAddress = BB->getOutputAddressRange().second; 4376a34c753fSRafael Auler if (InputEndOffset < BB->getEndOffset()) 4377a34c753fSRafael Auler EndAddress = StartAddress + InputEndOffset - InputOffset; 4378a34c753fSRafael Auler 4379a34c753fSRafael Auler if (StartAddress == PrevEndAddress && Entry.Expr == *PrevExpr) { 4380a34c753fSRafael Auler OutputLL.back().HighPC = std::max(OutputLL.back().HighPC, EndAddress); 4381a34c753fSRafael Auler } else { 438240c2e0faSMaksim Panchenko OutputLL.emplace_back(DebugLocationEntry{ 438340c2e0faSMaksim Panchenko StartAddress, std::max(StartAddress, EndAddress), Entry.Expr}); 4384a34c753fSRafael Auler } 4385a34c753fSRafael Auler PrevEndAddress = OutputLL.back().HighPC; 4386a34c753fSRafael Auler PrevExpr = &OutputLL.back().Expr; 4387a34c753fSRafael Auler } 4388a34c753fSRafael Auler 4389a34c753fSRafael Auler ++BBI; 4390a34c753fSRafael Auler InputOffset = BB->getEndOffset(); 4391a34c753fSRafael Auler } while (InputOffset < InputEndOffset); 4392a34c753fSRafael Auler } 4393a34c753fSRafael Auler 4394a34c753fSRafael Auler // Sort and merge adjacent entries with identical location. 4395d2c87699SAmir Ayupov llvm::stable_sort( 4396d2c87699SAmir Ayupov OutputLL, [](const DebugLocationEntry &A, const DebugLocationEntry &B) { 4397a34c753fSRafael Auler return A.LowPC < B.LowPC; 4398a34c753fSRafael Auler }); 4399a34c753fSRafael Auler DebugLocationsVector MergedLL; 4400a34c753fSRafael Auler PrevEndAddress = 0; 4401a34c753fSRafael Auler PrevExpr = nullptr; 4402a34c753fSRafael Auler for (const DebugLocationEntry &Entry : OutputLL) { 4403a34c753fSRafael Auler if (Entry.LowPC <= PrevEndAddress && *PrevExpr == Entry.Expr) { 4404a34c753fSRafael Auler MergedLL.back().HighPC = std::max(Entry.HighPC, MergedLL.back().HighPC); 4405a34c753fSRafael Auler } else { 4406a34c753fSRafael Auler const uint64_t Begin = std::max(Entry.LowPC, PrevEndAddress); 4407a34c753fSRafael Auler const uint64_t End = std::max(Begin, Entry.HighPC); 4408a34c753fSRafael Auler MergedLL.emplace_back(DebugLocationEntry{Begin, End, Entry.Expr}); 4409a34c753fSRafael Auler } 4410a34c753fSRafael Auler PrevEndAddress = MergedLL.back().HighPC; 4411a34c753fSRafael Auler PrevExpr = &MergedLL.back().Expr; 4412a34c753fSRafael Auler } 4413a34c753fSRafael Auler 4414a34c753fSRafael Auler return MergedLL; 4415a34c753fSRafael Auler } 4416a34c753fSRafael Auler 4417a34c753fSRafael Auler void BinaryFunction::printLoopInfo(raw_ostream &OS) const { 4418798e92c6SAmir Ayupov if (!opts::shouldPrint(*this)) 4419798e92c6SAmir Ayupov return; 4420798e92c6SAmir Ayupov 4421a34c753fSRafael Auler OS << "Loop Info for Function \"" << *this << "\""; 44223652483cSRafael Auler if (hasValidProfile()) 4423a34c753fSRafael Auler OS << " (count: " << getExecutionCount() << ")"; 4424a34c753fSRafael Auler OS << "\n"; 4425a34c753fSRafael Auler 4426a34c753fSRafael Auler std::stack<BinaryLoop *> St; 4427a0c7ca8aSKazu Hirata for (BinaryLoop *L : *BLI) 4428a0c7ca8aSKazu Hirata St.push(L); 4429a34c753fSRafael Auler while (!St.empty()) { 4430a34c753fSRafael Auler BinaryLoop *L = St.top(); 4431a34c753fSRafael Auler St.pop(); 4432a34c753fSRafael Auler 4433a0c7ca8aSKazu Hirata for (BinaryLoop *Inner : *L) 4434a0c7ca8aSKazu Hirata St.push(Inner); 4435a34c753fSRafael Auler 4436a34c753fSRafael Auler if (!hasValidProfile()) 4437a34c753fSRafael Auler continue; 4438a34c753fSRafael Auler 443940c2e0faSMaksim Panchenko OS << (L->getLoopDepth() > 1 ? "Nested" : "Outer") 444040c2e0faSMaksim Panchenko << " loop header: " << L->getHeader()->getName(); 4441a34c753fSRafael Auler OS << "\n"; 4442a34c753fSRafael Auler OS << "Loop basic blocks: "; 4443f7581a39SAmir Ayupov ListSeparator LS; 4444f7581a39SAmir Ayupov for (BinaryBasicBlock *BB : L->blocks()) 4445f7581a39SAmir Ayupov OS << LS << BB->getName(); 4446a34c753fSRafael Auler OS << "\n"; 4447a34c753fSRafael Auler if (hasValidProfile()) { 4448a34c753fSRafael Auler OS << "Total back edge count: " << L->TotalBackEdgeCount << "\n"; 4449a34c753fSRafael Auler OS << "Loop entry count: " << L->EntryCount << "\n"; 4450a34c753fSRafael Auler OS << "Loop exit count: " << L->ExitCount << "\n"; 4451a34c753fSRafael Auler if (L->EntryCount > 0) { 4452a34c753fSRafael Auler OS << "Average iters per entry: " 4453a34c753fSRafael Auler << format("%.4lf", (double)L->TotalBackEdgeCount / L->EntryCount) 4454a34c753fSRafael Auler << "\n"; 4455a34c753fSRafael Auler } 4456a34c753fSRafael Auler } 4457a34c753fSRafael Auler OS << "----\n"; 4458a34c753fSRafael Auler } 4459a34c753fSRafael Auler 4460a34c753fSRafael Auler OS << "Total number of loops: " << BLI->TotalLoops << "\n"; 4461a34c753fSRafael Auler OS << "Number of outer loops: " << BLI->OuterLoops << "\n"; 4462a34c753fSRafael Auler OS << "Maximum nested loop depth: " << BLI->MaximumDepth << "\n\n"; 4463a34c753fSRafael Auler } 4464a34c753fSRafael Auler 4465a34c753fSRafael Auler bool BinaryFunction::isAArch64Veneer() const { 4466d0e29e87SDenis Revunov if (empty() || hasIslandsInfo()) 4467a34c753fSRafael Auler return false; 4468a34c753fSRafael Auler 4469a34c753fSRafael Auler BinaryBasicBlock &BB = **BasicBlocks.begin(); 44703652483cSRafael Auler for (MCInst &Inst : BB) 4471a34c753fSRafael Auler if (!BC.MIB->hasAnnotation(Inst, "AArch64Veneer")) 4472a34c753fSRafael Auler return false; 4473a34c753fSRafael Auler 447435efe1d8SVladislav Khmelevsky for (auto I = BasicBlocks.begin() + 1, E = BasicBlocks.end(); I != E; ++I) { 447535efe1d8SVladislav Khmelevsky for (MCInst &Inst : **I) 447635efe1d8SVladislav Khmelevsky if (!BC.MIB->isNoop(Inst)) 447735efe1d8SVladislav Khmelevsky return false; 447835efe1d8SVladislav Khmelevsky } 447935efe1d8SVladislav Khmelevsky 4480a34c753fSRafael Auler return true; 4481a34c753fSRafael Auler } 4482a34c753fSRafael Auler 4483edda8577SAmir Ayupov void BinaryFunction::addRelocation(uint64_t Address, MCSymbol *Symbol, 4484edda8577SAmir Ayupov uint64_t RelType, uint64_t Addend, 4485edda8577SAmir Ayupov uint64_t Value) { 4486edda8577SAmir Ayupov assert(Address >= getAddress() && Address < getAddress() + getMaxSize() && 4487edda8577SAmir Ayupov "address is outside of the function"); 4488edda8577SAmir Ayupov uint64_t Offset = Address - getAddress(); 4489edda8577SAmir Ayupov LLVM_DEBUG(dbgs() << "BOLT-DEBUG: addRelocation in " 4490713b2853SAmir Ayupov << formatv("{0}@{1:x} against {2}\n", *this, Offset, 4491edda8577SAmir Ayupov Symbol->getName())); 4492edda8577SAmir Ayupov bool IsCI = BC.isAArch64() && isInConstantIsland(Address); 4493edda8577SAmir Ayupov std::map<uint64_t, Relocation> &Rels = 4494edda8577SAmir Ayupov IsCI ? Islands->Relocations : Relocations; 4495edda8577SAmir Ayupov if (BC.MIB->shouldRecordCodeRelocation(RelType)) 4496edda8577SAmir Ayupov Rels[Offset] = Relocation{Offset, Symbol, RelType, Addend, Value}; 4497edda8577SAmir Ayupov } 4498edda8577SAmir Ayupov 4499a34c753fSRafael Auler } // namespace bolt 4500a34c753fSRafael Auler } // namespace llvm 4501