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