1 //===- bolt/Passes/Instrumentation.cpp ------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the Instrumentation class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "bolt/Passes/Instrumentation.h" 14 #include "bolt/Core/ParallelUtilities.h" 15 #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h" 16 #include "bolt/Utils/Utils.h" 17 #include "llvm/Support/CommandLine.h" 18 #include "llvm/Support/RWMutex.h" 19 #include <stack> 20 21 #define DEBUG_TYPE "bolt-instrumentation" 22 23 using namespace llvm; 24 25 namespace opts { 26 extern cl::OptionCategory BoltInstrCategory; 27 28 cl::opt<std::string> InstrumentationFilename( 29 "instrumentation-file", 30 cl::desc("file name where instrumented profile will be saved (default: " 31 "/tmp/prof.fdata)"), 32 cl::init("/tmp/prof.fdata"), cl::Optional, cl::cat(BoltInstrCategory)); 33 34 cl::opt<std::string> InstrumentationBinpath( 35 "instrumentation-binpath", 36 cl::desc("path to instumented binary in case if /proc/self/map_files " 37 "is not accessible due to access restriction issues"), 38 cl::Optional, cl::cat(BoltInstrCategory)); 39 40 cl::opt<bool> InstrumentationFileAppendPID( 41 "instrumentation-file-append-pid", 42 cl::desc("append PID to saved profile file name (default: false)"), 43 cl::init(false), cl::Optional, cl::cat(BoltInstrCategory)); 44 45 cl::opt<bool> ConservativeInstrumentation( 46 "conservative-instrumentation", 47 cl::desc("disable instrumentation optimizations that sacrifice profile " 48 "accuracy (for debugging, default: false)"), 49 cl::init(false), cl::Optional, cl::cat(BoltInstrCategory)); 50 51 cl::opt<uint32_t> InstrumentationSleepTime( 52 "instrumentation-sleep-time", 53 cl::desc("interval between profile writes (default: 0 = write only at " 54 "program end). This is useful for service workloads when you " 55 "want to dump profile every X minutes or if you are killing the " 56 "program and the profile is not being dumped at the end."), 57 cl::init(0), cl::Optional, cl::cat(BoltInstrCategory)); 58 59 cl::opt<bool> InstrumentationNoCountersClear( 60 "instrumentation-no-counters-clear", 61 cl::desc("Don't clear counters across dumps " 62 "(use with instrumentation-sleep-time option)"), 63 cl::init(false), cl::Optional, cl::cat(BoltInstrCategory)); 64 65 cl::opt<bool> InstrumentationWaitForks( 66 "instrumentation-wait-forks", 67 cl::desc("Wait until all forks of instrumented process will finish " 68 "(use with instrumentation-sleep-time option)"), 69 cl::init(false), cl::Optional, cl::cat(BoltInstrCategory)); 70 71 cl::opt<bool> 72 InstrumentHotOnly("instrument-hot-only", 73 cl::desc("only insert instrumentation on hot functions " 74 "(needs profile, default: false)"), 75 cl::init(false), cl::Optional, 76 cl::cat(BoltInstrCategory)); 77 78 cl::opt<bool> InstrumentCalls("instrument-calls", 79 cl::desc("record profile for inter-function " 80 "control flow activity (default: true)"), 81 cl::init(true), cl::Optional, 82 cl::cat(BoltInstrCategory)); 83 } // namespace opts 84 85 namespace llvm { 86 namespace bolt { 87 88 uint32_t Instrumentation::getFunctionNameIndex(const BinaryFunction &Function) { 89 auto Iter = FuncToStringIdx.find(&Function); 90 if (Iter != FuncToStringIdx.end()) 91 return Iter->second; 92 size_t Idx = Summary->StringTable.size(); 93 FuncToStringIdx.emplace(std::make_pair(&Function, Idx)); 94 Summary->StringTable.append(getEscapedName(Function.getOneName())); 95 Summary->StringTable.append(1, '\0'); 96 return Idx; 97 } 98 99 bool Instrumentation::createCallDescription(FunctionDescription &FuncDesc, 100 const BinaryFunction &FromFunction, 101 uint32_t From, uint32_t FromNodeID, 102 const BinaryFunction &ToFunction, 103 uint32_t To, bool IsInvoke) { 104 CallDescription CD; 105 // Ordinarily, we don't augment direct calls with an explicit counter, except 106 // when forced to do so or when we know this callee could be throwing 107 // exceptions, in which case there is no other way to accurately record its 108 // frequency. 109 bool ForceInstrumentation = opts::ConservativeInstrumentation || IsInvoke; 110 CD.FromLoc.FuncString = getFunctionNameIndex(FromFunction); 111 CD.FromLoc.Offset = From; 112 CD.FromNode = FromNodeID; 113 CD.Target = &ToFunction; 114 CD.ToLoc.FuncString = getFunctionNameIndex(ToFunction); 115 CD.ToLoc.Offset = To; 116 CD.Counter = ForceInstrumentation ? Summary->Counters.size() : 0xffffffff; 117 if (ForceInstrumentation) 118 ++DirectCallCounters; 119 FuncDesc.Calls.emplace_back(CD); 120 return ForceInstrumentation; 121 } 122 123 void Instrumentation::createIndCallDescription( 124 const BinaryFunction &FromFunction, uint32_t From) { 125 IndCallDescription ICD; 126 ICD.FromLoc.FuncString = getFunctionNameIndex(FromFunction); 127 ICD.FromLoc.Offset = From; 128 Summary->IndCallDescriptions.emplace_back(ICD); 129 } 130 131 void Instrumentation::createIndCallTargetDescription( 132 const BinaryFunction &ToFunction, uint32_t To) { 133 IndCallTargetDescription ICD; 134 ICD.ToLoc.FuncString = getFunctionNameIndex(ToFunction); 135 ICD.ToLoc.Offset = To; 136 ICD.Target = &ToFunction; 137 Summary->IndCallTargetDescriptions.emplace_back(ICD); 138 } 139 140 bool Instrumentation::createEdgeDescription(FunctionDescription &FuncDesc, 141 const BinaryFunction &FromFunction, 142 uint32_t From, uint32_t FromNodeID, 143 const BinaryFunction &ToFunction, 144 uint32_t To, uint32_t ToNodeID, 145 bool Instrumented) { 146 EdgeDescription ED; 147 auto Result = FuncDesc.EdgesSet.insert(std::make_pair(FromNodeID, ToNodeID)); 148 // Avoid creating duplicated edge descriptions. This happens in CFGs where a 149 // block jumps to its fall-through. 150 if (Result.second == false) 151 return false; 152 ED.FromLoc.FuncString = getFunctionNameIndex(FromFunction); 153 ED.FromLoc.Offset = From; 154 ED.FromNode = FromNodeID; 155 ED.ToLoc.FuncString = getFunctionNameIndex(ToFunction); 156 ED.ToLoc.Offset = To; 157 ED.ToNode = ToNodeID; 158 ED.Counter = Instrumented ? Summary->Counters.size() : 0xffffffff; 159 if (Instrumented) 160 ++BranchCounters; 161 FuncDesc.Edges.emplace_back(ED); 162 return Instrumented; 163 } 164 165 void Instrumentation::createLeafNodeDescription(FunctionDescription &FuncDesc, 166 uint32_t Node) { 167 InstrumentedNode IN; 168 IN.Node = Node; 169 IN.Counter = Summary->Counters.size(); 170 ++LeafNodeCounters; 171 FuncDesc.LeafNodes.emplace_back(IN); 172 } 173 174 InstructionListType 175 Instrumentation::createInstrumentationSnippet(BinaryContext &BC, bool IsLeaf) { 176 auto L = BC.scopeLock(); 177 MCSymbol *Label; 178 Label = BC.Ctx->createNamedTempSymbol("InstrEntry"); 179 Summary->Counters.emplace_back(Label); 180 InstructionListType CounterInstrs; 181 BC.MIB->createInstrIncMemory(CounterInstrs, Label, &*BC.Ctx, IsLeaf); 182 return CounterInstrs; 183 } 184 185 // Helper instruction sequence insertion function 186 static BinaryBasicBlock::iterator 187 insertInstructions(InstructionListType &Instrs, BinaryBasicBlock &BB, 188 BinaryBasicBlock::iterator Iter) { 189 for (MCInst &NewInst : Instrs) { 190 Iter = BB.insertInstruction(Iter, NewInst); 191 ++Iter; 192 } 193 return Iter; 194 } 195 196 void Instrumentation::instrumentLeafNode(BinaryBasicBlock &BB, 197 BinaryBasicBlock::iterator Iter, 198 bool IsLeaf, 199 FunctionDescription &FuncDesc, 200 uint32_t Node) { 201 createLeafNodeDescription(FuncDesc, Node); 202 InstructionListType CounterInstrs = createInstrumentationSnippet( 203 BB.getFunction()->getBinaryContext(), IsLeaf); 204 insertInstructions(CounterInstrs, BB, Iter); 205 } 206 207 void Instrumentation::instrumentIndirectTarget(BinaryBasicBlock &BB, 208 BinaryBasicBlock::iterator &Iter, 209 BinaryFunction &FromFunction, 210 uint32_t From) { 211 auto L = FromFunction.getBinaryContext().scopeLock(); 212 const size_t IndCallSiteID = Summary->IndCallDescriptions.size(); 213 createIndCallDescription(FromFunction, From); 214 215 BinaryContext &BC = FromFunction.getBinaryContext(); 216 bool IsTailCall = BC.MIB->isTailCall(*Iter); 217 InstructionListType CounterInstrs = BC.MIB->createInstrumentedIndirectCall( 218 *Iter, IsTailCall, 219 IsTailCall ? IndTailCallHandlerExitBBFunction->getSymbol() 220 : IndCallHandlerExitBBFunction->getSymbol(), 221 IndCallSiteID, &*BC.Ctx); 222 223 Iter = BB.eraseInstruction(Iter); 224 Iter = insertInstructions(CounterInstrs, BB, Iter); 225 --Iter; 226 } 227 228 bool Instrumentation::instrumentOneTarget( 229 SplitWorklistTy &SplitWorklist, SplitInstrsTy &SplitInstrs, 230 BinaryBasicBlock::iterator &Iter, BinaryFunction &FromFunction, 231 BinaryBasicBlock &FromBB, uint32_t From, BinaryFunction &ToFunc, 232 BinaryBasicBlock *TargetBB, uint32_t ToOffset, bool IsLeaf, bool IsInvoke, 233 FunctionDescription *FuncDesc, uint32_t FromNodeID, uint32_t ToNodeID) { 234 { 235 auto L = FromFunction.getBinaryContext().scopeLock(); 236 bool Created = true; 237 if (!TargetBB) 238 Created = createCallDescription(*FuncDesc, FromFunction, From, FromNodeID, 239 ToFunc, ToOffset, IsInvoke); 240 else 241 Created = createEdgeDescription(*FuncDesc, FromFunction, From, FromNodeID, 242 ToFunc, ToOffset, ToNodeID, 243 /*Instrumented=*/true); 244 if (!Created) 245 return false; 246 } 247 248 InstructionListType CounterInstrs = 249 createInstrumentationSnippet(FromFunction.getBinaryContext(), IsLeaf); 250 251 BinaryContext &BC = FromFunction.getBinaryContext(); 252 const MCInst &Inst = *Iter; 253 if (BC.MIB->isCall(Inst)) { 254 // This code handles both 255 // - (regular) inter-function calls (cross-function control transfer), 256 // - (rare) intra-function calls (function-local control transfer) 257 Iter = insertInstructions(CounterInstrs, FromBB, Iter); 258 return true; 259 } 260 261 if (!TargetBB || !FuncDesc) 262 return false; 263 264 // Indirect branch, conditional branches or fall-throughs 265 // Regular cond branch, put counter at start of target block 266 // 267 // N.B.: (FromBB != TargetBBs) checks below handle conditional jumps where 268 // we can't put the instrumentation counter in this block because not all 269 // paths that reach it at this point will be taken and going to the target. 270 if (TargetBB->pred_size() == 1 && &FromBB != TargetBB && 271 !TargetBB->isEntryPoint()) { 272 insertInstructions(CounterInstrs, *TargetBB, TargetBB->begin()); 273 return true; 274 } 275 if (FromBB.succ_size() == 1 && &FromBB != TargetBB) { 276 Iter = insertInstructions(CounterInstrs, FromBB, Iter); 277 return true; 278 } 279 // Critical edge, create BB and put counter there 280 SplitWorklist.emplace_back(&FromBB, TargetBB); 281 SplitInstrs.emplace_back(std::move(CounterInstrs)); 282 return true; 283 } 284 285 void Instrumentation::instrumentFunction(BinaryFunction &Function, 286 MCPlusBuilder::AllocatorIdTy AllocId) { 287 if (Function.hasUnknownControlFlow()) 288 return; 289 290 BinaryContext &BC = Function.getBinaryContext(); 291 if (BC.isMachO() && Function.hasName("___GLOBAL_init_65535/1")) 292 return; 293 294 SplitWorklistTy SplitWorklist; 295 SplitInstrsTy SplitInstrs; 296 297 FunctionDescription *FuncDesc = nullptr; 298 { 299 std::unique_lock<llvm::sys::RWMutex> L(FDMutex); 300 Summary->FunctionDescriptions.emplace_back(); 301 FuncDesc = &Summary->FunctionDescriptions.back(); 302 } 303 304 FuncDesc->Function = &Function; 305 Function.disambiguateJumpTables(AllocId); 306 Function.deleteConservativeEdges(); 307 308 std::unordered_map<const BinaryBasicBlock *, uint32_t> BBToID; 309 uint32_t Id = 0; 310 for (auto BBI = Function.begin(); BBI != Function.end(); ++BBI) { 311 BBToID[&*BBI] = Id++; 312 } 313 std::unordered_set<const BinaryBasicBlock *> VisitedSet; 314 // DFS to establish edges we will use for a spanning tree. Edges in the 315 // spanning tree can be instrumentation-free since their count can be 316 // inferred by solving flow equations on a bottom-up traversal of the tree. 317 // Exit basic blocks are always instrumented so we start the traversal with 318 // a minimum number of defined variables to make the equation solvable. 319 std::stack<std::pair<const BinaryBasicBlock *, BinaryBasicBlock *>> Stack; 320 std::unordered_map<const BinaryBasicBlock *, 321 std::set<const BinaryBasicBlock *>> 322 STOutSet; 323 for (auto BBI = Function.getLayout().block_rbegin(); 324 BBI != Function.getLayout().block_rend(); ++BBI) { 325 if ((*BBI)->isEntryPoint() || (*BBI)->isLandingPad()) { 326 Stack.push(std::make_pair(nullptr, *BBI)); 327 if (opts::InstrumentCalls && (*BBI)->isEntryPoint()) { 328 EntryNode E; 329 E.Node = BBToID[&**BBI]; 330 E.Address = (*BBI)->getInputOffset(); 331 FuncDesc->EntryNodes.emplace_back(E); 332 createIndCallTargetDescription(Function, (*BBI)->getInputOffset()); 333 } 334 } 335 } 336 337 // Modified version of BinaryFunction::dfs() to build a spanning tree 338 if (!opts::ConservativeInstrumentation) { 339 while (!Stack.empty()) { 340 BinaryBasicBlock *BB; 341 const BinaryBasicBlock *Pred; 342 std::tie(Pred, BB) = Stack.top(); 343 Stack.pop(); 344 if (VisitedSet.find(BB) != VisitedSet.end()) 345 continue; 346 347 VisitedSet.insert(BB); 348 if (Pred) 349 STOutSet[Pred].insert(BB); 350 351 for (BinaryBasicBlock *SuccBB : BB->successors()) 352 Stack.push(std::make_pair(BB, SuccBB)); 353 } 354 } 355 356 // Determine whether this is a leaf function, which needs special 357 // instructions to protect the red zone 358 bool IsLeafFunction = true; 359 DenseSet<const BinaryBasicBlock *> InvokeBlocks; 360 for (auto BBI = Function.begin(), BBE = Function.end(); BBI != BBE; ++BBI) { 361 for (auto I = BBI->begin(), E = BBI->end(); I != E; ++I) { 362 if (BC.MIB->isCall(*I)) { 363 if (BC.MIB->isInvoke(*I)) 364 InvokeBlocks.insert(&*BBI); 365 IsLeafFunction = false; 366 } 367 } 368 } 369 370 for (auto BBI = Function.begin(), BBE = Function.end(); BBI != BBE; ++BBI) { 371 BinaryBasicBlock &BB = *BBI; 372 bool HasUnconditionalBranch = false; 373 bool HasJumpTable = false; 374 bool IsInvokeBlock = InvokeBlocks.count(&BB) > 0; 375 376 for (auto I = BB.begin(); I != BB.end(); ++I) { 377 const MCInst &Inst = *I; 378 if (!BC.MIB->getOffset(Inst)) 379 continue; 380 381 const bool IsJumpTable = Function.getJumpTable(Inst); 382 if (IsJumpTable) 383 HasJumpTable = true; 384 else if (BC.MIB->isUnconditionalBranch(Inst)) 385 HasUnconditionalBranch = true; 386 else if ((!BC.MIB->isCall(Inst) && !BC.MIB->isConditionalBranch(Inst)) || 387 BC.MIB->isUnsupportedBranch(Inst.getOpcode())) 388 continue; 389 390 const uint32_t FromOffset = *BC.MIB->getOffset(Inst); 391 const MCSymbol *Target = BC.MIB->getTargetSymbol(Inst); 392 BinaryBasicBlock *TargetBB = Function.getBasicBlockForLabel(Target); 393 uint32_t ToOffset = TargetBB ? TargetBB->getInputOffset() : 0; 394 BinaryFunction *TargetFunc = 395 TargetBB ? &Function : BC.getFunctionForSymbol(Target); 396 if (TargetFunc && BC.MIB->isCall(Inst)) { 397 if (opts::InstrumentCalls) { 398 const BinaryBasicBlock *ForeignBB = 399 TargetFunc->getBasicBlockForLabel(Target); 400 if (ForeignBB) 401 ToOffset = ForeignBB->getInputOffset(); 402 instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB, 403 FromOffset, *TargetFunc, TargetBB, ToOffset, 404 IsLeafFunction, IsInvokeBlock, FuncDesc, 405 BBToID[&BB]); 406 } 407 continue; 408 } 409 if (TargetFunc) { 410 // Do not instrument edges in the spanning tree 411 if (STOutSet[&BB].find(TargetBB) != STOutSet[&BB].end()) { 412 auto L = BC.scopeLock(); 413 createEdgeDescription(*FuncDesc, Function, FromOffset, BBToID[&BB], 414 Function, ToOffset, BBToID[TargetBB], 415 /*Instrumented=*/false); 416 continue; 417 } 418 instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB, 419 FromOffset, *TargetFunc, TargetBB, ToOffset, 420 IsLeafFunction, IsInvokeBlock, FuncDesc, 421 BBToID[&BB], BBToID[TargetBB]); 422 continue; 423 } 424 425 if (IsJumpTable) { 426 for (BinaryBasicBlock *&Succ : BB.successors()) { 427 // Do not instrument edges in the spanning tree 428 if (STOutSet[&BB].find(&*Succ) != STOutSet[&BB].end()) { 429 auto L = BC.scopeLock(); 430 createEdgeDescription(*FuncDesc, Function, FromOffset, BBToID[&BB], 431 Function, Succ->getInputOffset(), 432 BBToID[&*Succ], /*Instrumented=*/false); 433 continue; 434 } 435 instrumentOneTarget( 436 SplitWorklist, SplitInstrs, I, Function, BB, FromOffset, Function, 437 &*Succ, Succ->getInputOffset(), IsLeafFunction, IsInvokeBlock, 438 FuncDesc, BBToID[&BB], BBToID[&*Succ]); 439 } 440 continue; 441 } 442 443 // Handle indirect calls -- could be direct calls with unknown targets 444 // or secondary entry points of known functions, so check it is indirect 445 // to be sure. 446 if (opts::InstrumentCalls && BC.MIB->isIndirectCall(*I)) 447 instrumentIndirectTarget(BB, I, Function, FromOffset); 448 449 } // End of instructions loop 450 451 // Instrument fallthroughs (when the direct jump instruction is missing) 452 if (!HasUnconditionalBranch && !HasJumpTable && BB.succ_size() > 0 && 453 BB.size() > 0) { 454 BinaryBasicBlock *FTBB = BB.getFallthrough(); 455 assert(FTBB && "expected valid fall-through basic block"); 456 auto I = BB.begin(); 457 auto LastInstr = BB.end(); 458 --LastInstr; 459 while (LastInstr != I && BC.MIB->isPseudo(*LastInstr)) 460 --LastInstr; 461 uint32_t FromOffset = 0; 462 // The last instruction in the BB should have an annotation, except 463 // if it was branching to the end of the function as a result of 464 // __builtin_unreachable(), in which case it was deleted by fixBranches. 465 // Ignore this case. FIXME: force fixBranches() to preserve the offset. 466 if (!BC.MIB->getOffset(*LastInstr)) 467 continue; 468 FromOffset = *BC.MIB->getOffset(*LastInstr); 469 470 // Do not instrument edges in the spanning tree 471 if (STOutSet[&BB].find(FTBB) != STOutSet[&BB].end()) { 472 auto L = BC.scopeLock(); 473 createEdgeDescription(*FuncDesc, Function, FromOffset, BBToID[&BB], 474 Function, FTBB->getInputOffset(), BBToID[FTBB], 475 /*Instrumented=*/false); 476 continue; 477 } 478 instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB, 479 FromOffset, Function, FTBB, FTBB->getInputOffset(), 480 IsLeafFunction, IsInvokeBlock, FuncDesc, BBToID[&BB], 481 BBToID[FTBB]); 482 } 483 } // End of BBs loop 484 485 // Instrument spanning tree leaves 486 if (!opts::ConservativeInstrumentation) { 487 for (auto BBI = Function.begin(), BBE = Function.end(); BBI != BBE; ++BBI) { 488 BinaryBasicBlock &BB = *BBI; 489 if (STOutSet[&BB].size() == 0) 490 instrumentLeafNode(BB, BB.begin(), IsLeafFunction, *FuncDesc, 491 BBToID[&BB]); 492 } 493 } 494 495 // Consume list of critical edges: split them and add instrumentation to the 496 // newly created BBs 497 auto Iter = SplitInstrs.begin(); 498 for (std::pair<BinaryBasicBlock *, BinaryBasicBlock *> &BBPair : 499 SplitWorklist) { 500 BinaryBasicBlock *NewBB = Function.splitEdge(BBPair.first, BBPair.second); 501 NewBB->addInstructions(Iter->begin(), Iter->end()); 502 ++Iter; 503 } 504 505 // Unused now 506 FuncDesc->EdgesSet.clear(); 507 } 508 509 void Instrumentation::runOnFunctions(BinaryContext &BC) { 510 if (!BC.isX86()) 511 return; 512 513 const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/false, 514 /*IsText=*/false, 515 /*IsAllocatable=*/true); 516 BC.registerOrUpdateSection(".bolt.instr.counters", ELF::SHT_PROGBITS, Flags, 517 nullptr, 0, 1); 518 519 BC.registerOrUpdateNoteSection(".bolt.instr.tables", nullptr, 0, 520 /*Alignment=*/1, 521 /*IsReadOnly=*/true, ELF::SHT_NOTE); 522 523 Summary->IndCallCounterFuncPtr = 524 BC.Ctx->getOrCreateSymbol("__bolt_ind_call_counter_func_pointer"); 525 Summary->IndTailCallCounterFuncPtr = 526 BC.Ctx->getOrCreateSymbol("__bolt_ind_tailcall_counter_func_pointer"); 527 528 createAuxiliaryFunctions(BC); 529 530 ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) { 531 return (!BF.isSimple() || BF.isIgnored() || 532 (opts::InstrumentHotOnly && !BF.getKnownExecutionCount())); 533 }; 534 535 ParallelUtilities::WorkFuncWithAllocTy WorkFun = 536 [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) { 537 instrumentFunction(BF, AllocatorId); 538 }; 539 540 ParallelUtilities::runOnEachFunctionWithUniqueAllocId( 541 BC, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC, WorkFun, 542 SkipPredicate, "instrumentation", /* ForceSequential=*/true); 543 544 if (BC.isMachO()) { 545 if (BC.StartFunctionAddress) { 546 BinaryFunction *Main = 547 BC.getBinaryFunctionAtAddress(*BC.StartFunctionAddress); 548 assert(Main && "Entry point function not found"); 549 BinaryBasicBlock &BB = Main->front(); 550 551 ErrorOr<BinarySection &> SetupSection = 552 BC.getUniqueSectionByName("I__setup"); 553 if (!SetupSection) { 554 llvm::errs() << "Cannot find I__setup section\n"; 555 exit(1); 556 } 557 MCSymbol *Target = BC.registerNameAtAddress( 558 "__bolt_instr_setup", SetupSection->getAddress(), 0, 0); 559 MCInst NewInst; 560 BC.MIB->createCall(NewInst, Target, BC.Ctx.get()); 561 BB.insertInstruction(BB.begin(), std::move(NewInst)); 562 } else { 563 llvm::errs() << "BOLT-WARNING: Entry point not found\n"; 564 } 565 566 if (BinaryData *BD = BC.getBinaryDataByName("___GLOBAL_init_65535/1")) { 567 BinaryFunction *Ctor = BC.getBinaryFunctionAtAddress(BD->getAddress()); 568 assert(Ctor && "___GLOBAL_init_65535 function not found"); 569 BinaryBasicBlock &BB = Ctor->front(); 570 ErrorOr<BinarySection &> FiniSection = 571 BC.getUniqueSectionByName("I__fini"); 572 if (!FiniSection) { 573 llvm::errs() << "Cannot find I__fini section\n"; 574 exit(1); 575 } 576 MCSymbol *Target = BC.registerNameAtAddress( 577 "__bolt_instr_fini", FiniSection->getAddress(), 0, 0); 578 auto IsLEA = [&BC](const MCInst &Inst) { return BC.MIB->isLEA64r(Inst); }; 579 const auto LEA = std::find_if( 580 std::next(llvm::find_if(reverse(BB), IsLEA)), BB.rend(), IsLEA); 581 LEA->getOperand(4).setExpr( 582 MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *BC.Ctx)); 583 } else { 584 llvm::errs() << "BOLT-WARNING: ___GLOBAL_init_65535 not found\n"; 585 } 586 } 587 588 setupRuntimeLibrary(BC); 589 } 590 591 void Instrumentation::createAuxiliaryFunctions(BinaryContext &BC) { 592 auto createSimpleFunction = 593 [&](StringRef Title, InstructionListType Instrs) -> BinaryFunction * { 594 BinaryFunction *Func = BC.createInjectedBinaryFunction(std::string(Title)); 595 596 std::vector<std::unique_ptr<BinaryBasicBlock>> BBs; 597 BBs.emplace_back(Func->createBasicBlock()); 598 BBs.back()->addInstructions(Instrs.begin(), Instrs.end()); 599 BBs.back()->setCFIState(0); 600 Func->insertBasicBlocks(nullptr, std::move(BBs), 601 /*UpdateLayout=*/true, 602 /*UpdateCFIState=*/false); 603 Func->updateState(BinaryFunction::State::CFG_Finalized); 604 return Func; 605 }; 606 607 // Here we are creating a set of functions to handle BB entry/exit. 608 // IndCallHandlerExitBB contains instructions to finish handling traffic to an 609 // indirect call. We pass it to createInstrumentedIndCallHandlerEntryBB(), 610 // which will check if a pointer to runtime library traffic accounting 611 // function was initialized (it is done during initialization of runtime 612 // library). If it is so - calls it. Then this routine returns to normal 613 // execution by jumping to exit BB. 614 BinaryFunction *IndCallHandlerExitBB = 615 createSimpleFunction("__bolt_instr_ind_call_handler", 616 BC.MIB->createInstrumentedIndCallHandlerExitBB()); 617 618 IndCallHandlerExitBBFunction = 619 createSimpleFunction("__bolt_instr_ind_call_handler_func", 620 BC.MIB->createInstrumentedIndCallHandlerEntryBB( 621 Summary->IndCallCounterFuncPtr, 622 IndCallHandlerExitBB->getSymbol(), &*BC.Ctx)); 623 624 BinaryFunction *IndTailCallHandlerExitBB = createSimpleFunction( 625 "__bolt_instr_ind_tail_call_handler", 626 BC.MIB->createInstrumentedIndTailCallHandlerExitBB()); 627 628 IndTailCallHandlerExitBBFunction = createSimpleFunction( 629 "__bolt_instr_ind_tailcall_handler_func", 630 BC.MIB->createInstrumentedIndCallHandlerEntryBB( 631 Summary->IndTailCallCounterFuncPtr, 632 IndTailCallHandlerExitBB->getSymbol(), &*BC.Ctx)); 633 634 createSimpleFunction("__bolt_num_counters_getter", 635 BC.MIB->createNumCountersGetter(BC.Ctx.get())); 636 createSimpleFunction("__bolt_instr_locations_getter", 637 BC.MIB->createInstrLocationsGetter(BC.Ctx.get())); 638 createSimpleFunction("__bolt_instr_tables_getter", 639 BC.MIB->createInstrTablesGetter(BC.Ctx.get())); 640 createSimpleFunction("__bolt_instr_num_funcs_getter", 641 BC.MIB->createInstrNumFuncsGetter(BC.Ctx.get())); 642 643 if (BC.isELF()) { 644 if (BC.StartFunctionAddress) { 645 BinaryFunction *Start = 646 BC.getBinaryFunctionAtAddress(*BC.StartFunctionAddress); 647 assert(Start && "Entry point function not found"); 648 const MCSymbol *StartSym = Start->getSymbol(); 649 createSimpleFunction( 650 "__bolt_start_trampoline", 651 BC.MIB->createSymbolTrampoline(StartSym, BC.Ctx.get())); 652 } 653 if (BC.FiniFunctionAddress) { 654 BinaryFunction *Fini = 655 BC.getBinaryFunctionAtAddress(*BC.FiniFunctionAddress); 656 assert(Fini && "Finalization function not found"); 657 const MCSymbol *FiniSym = Fini->getSymbol(); 658 createSimpleFunction( 659 "__bolt_fini_trampoline", 660 BC.MIB->createSymbolTrampoline(FiniSym, BC.Ctx.get())); 661 } else { 662 // Create dummy return function for trampoline to avoid issues 663 // with unknown symbol in runtime library. E.g. for static PIE 664 // executable 665 createSimpleFunction("__bolt_fini_trampoline", 666 BC.MIB->createDummyReturnFunction(BC.Ctx.get())); 667 } 668 } 669 } 670 671 void Instrumentation::setupRuntimeLibrary(BinaryContext &BC) { 672 uint32_t FuncDescSize = Summary->getFDSize(); 673 674 outs() << "BOLT-INSTRUMENTER: Number of indirect call site descriptors: " 675 << Summary->IndCallDescriptions.size() << "\n"; 676 outs() << "BOLT-INSTRUMENTER: Number of indirect call target descriptors: " 677 << Summary->IndCallTargetDescriptions.size() << "\n"; 678 outs() << "BOLT-INSTRUMENTER: Number of function descriptors: " 679 << Summary->FunctionDescriptions.size() << "\n"; 680 outs() << "BOLT-INSTRUMENTER: Number of branch counters: " << BranchCounters 681 << "\n"; 682 outs() << "BOLT-INSTRUMENTER: Number of ST leaf node counters: " 683 << LeafNodeCounters << "\n"; 684 outs() << "BOLT-INSTRUMENTER: Number of direct call counters: " 685 << DirectCallCounters << "\n"; 686 outs() << "BOLT-INSTRUMENTER: Total number of counters: " 687 << Summary->Counters.size() << "\n"; 688 outs() << "BOLT-INSTRUMENTER: Total size of counters: " 689 << (Summary->Counters.size() * 8) << " bytes (static alloc memory)\n"; 690 outs() << "BOLT-INSTRUMENTER: Total size of string table emitted: " 691 << Summary->StringTable.size() << " bytes in file\n"; 692 outs() << "BOLT-INSTRUMENTER: Total size of descriptors: " 693 << (FuncDescSize + 694 Summary->IndCallDescriptions.size() * sizeof(IndCallDescription) + 695 Summary->IndCallTargetDescriptions.size() * 696 sizeof(IndCallTargetDescription)) 697 << " bytes in file\n"; 698 outs() << "BOLT-INSTRUMENTER: Profile will be saved to file " 699 << opts::InstrumentationFilename << "\n"; 700 701 InstrumentationRuntimeLibrary *RtLibrary = 702 static_cast<InstrumentationRuntimeLibrary *>(BC.getRuntimeLibrary()); 703 assert(RtLibrary && "instrumentation runtime library object must be set"); 704 RtLibrary->setSummary(std::move(Summary)); 705 } 706 } // namespace bolt 707 } // namespace llvm 708