1 //===- bolt/Passes/Instrumentation.cpp ------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the Instrumentation class.
11 //===----------------------------------------------------------------------===//
13 #include "bolt/Passes/Instrumentation.h"
14 #include "bolt/Core/ParallelUtilities.h"
15 #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h"
16 #include "bolt/Utils/CommandLineOpts.h"
17 #include "bolt/Utils/Utils.h"
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/RWMutex.h"
22 #include <unordered_set>
24 #define DEBUG_TYPE "bolt-instrumentation"
29 extern cl::OptionCategory BoltInstrCategory
;
31 cl::opt
<std::string
> InstrumentationFilename(
32 "instrumentation-file",
33 cl::desc("file name where instrumented profile will be saved (default: "
35 cl::init("/tmp/prof.fdata"), cl::Optional
, cl::cat(BoltInstrCategory
));
37 cl::opt
<std::string
> InstrumentationBinpath(
38 "instrumentation-binpath",
39 cl::desc("path to instrumented binary in case if /proc/self/map_files "
40 "is not accessible due to access restriction issues"),
41 cl::Optional
, cl::cat(BoltInstrCategory
));
43 cl::opt
<bool> InstrumentationFileAppendPID(
44 "instrumentation-file-append-pid",
45 cl::desc("append PID to saved profile file name (default: false)"),
46 cl::init(false), cl::Optional
, cl::cat(BoltInstrCategory
));
48 cl::opt
<bool> ConservativeInstrumentation(
49 "conservative-instrumentation",
50 cl::desc("disable instrumentation optimizations that sacrifice profile "
51 "accuracy (for debugging, default: false)"),
52 cl::init(false), cl::Optional
, cl::cat(BoltInstrCategory
));
54 cl::opt
<uint32_t> InstrumentationSleepTime(
55 "instrumentation-sleep-time",
56 cl::desc("interval between profile writes (default: 0 = write only at "
57 "program end). This is useful for service workloads when you "
58 "want to dump profile every X minutes or if you are killing the "
59 "program and the profile is not being dumped at the end."),
60 cl::init(0), cl::Optional
, cl::cat(BoltInstrCategory
));
62 cl::opt
<bool> InstrumentationNoCountersClear(
63 "instrumentation-no-counters-clear",
64 cl::desc("Don't clear counters across dumps "
65 "(use with instrumentation-sleep-time option)"),
66 cl::init(false), cl::Optional
, cl::cat(BoltInstrCategory
));
68 cl::opt
<bool> InstrumentationWaitForks(
69 "instrumentation-wait-forks",
70 cl::desc("Wait until all forks of instrumented process will finish "
71 "(use with instrumentation-sleep-time option)"),
72 cl::init(false), cl::Optional
, cl::cat(BoltInstrCategory
));
75 InstrumentHotOnly("instrument-hot-only",
76 cl::desc("only insert instrumentation on hot functions "
77 "(needs profile, default: false)"),
78 cl::init(false), cl::Optional
,
79 cl::cat(BoltInstrCategory
));
81 cl::opt
<bool> InstrumentCalls("instrument-calls",
82 cl::desc("record profile for inter-function "
83 "control flow activity (default: true)"),
84 cl::init(true), cl::Optional
,
85 cl::cat(BoltInstrCategory
));
91 static bool hasAArch64ExclusiveMemop(
92 BinaryFunction
&Function
,
93 std::unordered_set
<const BinaryBasicBlock
*> &BBToSkip
) {
94 // FIXME ARMv8-a architecture reference manual says that software must avoid
95 // having any explicit memory accesses between exclusive load and associated
96 // store instruction. So for now skip instrumentation for basic blocks that
97 // have these instructions, since it might lead to runtime deadlock.
98 BinaryContext
&BC
= Function
.getBinaryContext();
99 std::queue
<std::pair
<BinaryBasicBlock
*, bool>> BBQueue
; // {BB, isLoad}
100 std::unordered_set
<BinaryBasicBlock
*> Visited
;
102 if (Function
.getLayout().block_begin() == Function
.getLayout().block_end())
105 BinaryBasicBlock
*BBfirst
= *Function
.getLayout().block_begin();
106 BBQueue
.push({BBfirst
, false});
108 while (!BBQueue
.empty()) {
109 BinaryBasicBlock
*BB
= BBQueue
.front().first
;
110 bool IsLoad
= BBQueue
.front().second
;
112 if (!Visited
.insert(BB
).second
)
115 for (const MCInst
&Inst
: *BB
) {
116 // Two loads one after another - skip whole function
117 if (BC
.MIB
->isAArch64ExclusiveLoad(Inst
) && IsLoad
) {
118 if (opts::Verbosity
>= 2) {
119 outs() << "BOLT-INSTRUMENTER: function " << Function
.getPrintName()
120 << " has two exclusive loads. Ignoring the function.\n";
125 if (BC
.MIB
->isAArch64ExclusiveLoad(Inst
))
128 if (IsLoad
&& BBToSkip
.insert(BB
).second
) {
129 if (opts::Verbosity
>= 2) {
130 outs() << "BOLT-INSTRUMENTER: skip BB " << BB
->getName()
131 << " due to exclusive instruction in function "
132 << Function
.getPrintName() << "\n";
136 if (!IsLoad
&& BC
.MIB
->isAArch64ExclusiveStore(Inst
)) {
137 if (opts::Verbosity
>= 2) {
138 outs() << "BOLT-INSTRUMENTER: function " << Function
.getPrintName()
139 << " has exclusive store without corresponding load. Ignoring "
145 if (IsLoad
&& (BC
.MIB
->isAArch64ExclusiveStore(Inst
) ||
146 BC
.MIB
->isAArch64ExclusiveClear(Inst
)))
150 if (IsLoad
&& BB
->succ_size() == 0) {
151 if (opts::Verbosity
>= 2) {
153 << "BOLT-INSTRUMENTER: function " << Function
.getPrintName()
154 << " has exclusive load in trailing BB. Ignoring the function.\n";
159 for (BinaryBasicBlock
*BBS
: BB
->successors())
160 BBQueue
.push({BBS
, IsLoad
});
163 if (BBToSkip
.size() == Visited
.size()) {
164 if (opts::Verbosity
>= 2) {
165 outs() << "BOLT-INSTRUMENTER: all BBs are marked with true. Ignoring the "
167 << Function
.getPrintName() << "\n";
175 uint32_t Instrumentation::getFunctionNameIndex(const BinaryFunction
&Function
) {
176 auto Iter
= FuncToStringIdx
.find(&Function
);
177 if (Iter
!= FuncToStringIdx
.end())
179 size_t Idx
= Summary
->StringTable
.size();
180 FuncToStringIdx
.emplace(std::make_pair(&Function
, Idx
));
181 Summary
->StringTable
.append(getEscapedName(Function
.getOneName()));
182 Summary
->StringTable
.append(1, '\0');
186 bool Instrumentation::createCallDescription(FunctionDescription
&FuncDesc
,
187 const BinaryFunction
&FromFunction
,
188 uint32_t From
, uint32_t FromNodeID
,
189 const BinaryFunction
&ToFunction
,
190 uint32_t To
, bool IsInvoke
) {
192 // Ordinarily, we don't augment direct calls with an explicit counter, except
193 // when forced to do so or when we know this callee could be throwing
194 // exceptions, in which case there is no other way to accurately record its
196 bool ForceInstrumentation
= opts::ConservativeInstrumentation
|| IsInvoke
;
197 CD
.FromLoc
.FuncString
= getFunctionNameIndex(FromFunction
);
198 CD
.FromLoc
.Offset
= From
;
199 CD
.FromNode
= FromNodeID
;
200 CD
.Target
= &ToFunction
;
201 CD
.ToLoc
.FuncString
= getFunctionNameIndex(ToFunction
);
202 CD
.ToLoc
.Offset
= To
;
203 CD
.Counter
= ForceInstrumentation
? Summary
->Counters
.size() : 0xffffffff;
204 if (ForceInstrumentation
)
205 ++DirectCallCounters
;
206 FuncDesc
.Calls
.emplace_back(CD
);
207 return ForceInstrumentation
;
210 void Instrumentation::createIndCallDescription(
211 const BinaryFunction
&FromFunction
, uint32_t From
) {
212 IndCallDescription ICD
;
213 ICD
.FromLoc
.FuncString
= getFunctionNameIndex(FromFunction
);
214 ICD
.FromLoc
.Offset
= From
;
215 Summary
->IndCallDescriptions
.emplace_back(ICD
);
218 void Instrumentation::createIndCallTargetDescription(
219 const BinaryFunction
&ToFunction
, uint32_t To
) {
220 IndCallTargetDescription ICD
;
221 ICD
.ToLoc
.FuncString
= getFunctionNameIndex(ToFunction
);
222 ICD
.ToLoc
.Offset
= To
;
223 ICD
.Target
= &ToFunction
;
224 Summary
->IndCallTargetDescriptions
.emplace_back(ICD
);
227 bool Instrumentation::createEdgeDescription(FunctionDescription
&FuncDesc
,
228 const BinaryFunction
&FromFunction
,
229 uint32_t From
, uint32_t FromNodeID
,
230 const BinaryFunction
&ToFunction
,
231 uint32_t To
, uint32_t ToNodeID
,
234 auto Result
= FuncDesc
.EdgesSet
.insert(std::make_pair(FromNodeID
, ToNodeID
));
235 // Avoid creating duplicated edge descriptions. This happens in CFGs where a
236 // block jumps to its fall-through.
237 if (Result
.second
== false)
239 ED
.FromLoc
.FuncString
= getFunctionNameIndex(FromFunction
);
240 ED
.FromLoc
.Offset
= From
;
241 ED
.FromNode
= FromNodeID
;
242 ED
.ToLoc
.FuncString
= getFunctionNameIndex(ToFunction
);
243 ED
.ToLoc
.Offset
= To
;
244 ED
.ToNode
= ToNodeID
;
245 ED
.Counter
= Instrumented
? Summary
->Counters
.size() : 0xffffffff;
248 FuncDesc
.Edges
.emplace_back(ED
);
252 void Instrumentation::createLeafNodeDescription(FunctionDescription
&FuncDesc
,
256 IN
.Counter
= Summary
->Counters
.size();
258 FuncDesc
.LeafNodes
.emplace_back(IN
);
262 Instrumentation::createInstrumentationSnippet(BinaryContext
&BC
, bool IsLeaf
) {
263 auto L
= BC
.scopeLock();
264 MCSymbol
*Label
= BC
.Ctx
->createNamedTempSymbol("InstrEntry");
265 Summary
->Counters
.emplace_back(Label
);
266 return BC
.MIB
->createInstrIncMemory(Label
, BC
.Ctx
.get(), IsLeaf
,
267 BC
.AsmInfo
->getCodePointerSize());
270 // Helper instruction sequence insertion function
271 static BinaryBasicBlock::iterator
272 insertInstructions(InstructionListType
&Instrs
, BinaryBasicBlock
&BB
,
273 BinaryBasicBlock::iterator Iter
) {
274 for (MCInst
&NewInst
: Instrs
) {
275 Iter
= BB
.insertInstruction(Iter
, NewInst
);
281 void Instrumentation::instrumentLeafNode(BinaryBasicBlock
&BB
,
282 BinaryBasicBlock::iterator Iter
,
284 FunctionDescription
&FuncDesc
,
286 createLeafNodeDescription(FuncDesc
, Node
);
287 InstructionListType CounterInstrs
= createInstrumentationSnippet(
288 BB
.getFunction()->getBinaryContext(), IsLeaf
);
289 insertInstructions(CounterInstrs
, BB
, Iter
);
292 void Instrumentation::instrumentIndirectTarget(BinaryBasicBlock
&BB
,
293 BinaryBasicBlock::iterator
&Iter
,
294 BinaryFunction
&FromFunction
,
296 auto L
= FromFunction
.getBinaryContext().scopeLock();
297 const size_t IndCallSiteID
= Summary
->IndCallDescriptions
.size();
298 createIndCallDescription(FromFunction
, From
);
300 BinaryContext
&BC
= FromFunction
.getBinaryContext();
301 bool IsTailCall
= BC
.MIB
->isTailCall(*Iter
);
302 InstructionListType CounterInstrs
= BC
.MIB
->createInstrumentedIndirectCall(
304 IsTailCall
? IndTailCallHandlerExitBBFunction
->getSymbol()
305 : IndCallHandlerExitBBFunction
->getSymbol(),
306 IndCallSiteID
, &*BC
.Ctx
);
308 Iter
= BB
.eraseInstruction(Iter
);
309 Iter
= insertInstructions(CounterInstrs
, BB
, Iter
);
313 bool Instrumentation::instrumentOneTarget(
314 SplitWorklistTy
&SplitWorklist
, SplitInstrsTy
&SplitInstrs
,
315 BinaryBasicBlock::iterator
&Iter
, BinaryFunction
&FromFunction
,
316 BinaryBasicBlock
&FromBB
, uint32_t From
, BinaryFunction
&ToFunc
,
317 BinaryBasicBlock
*TargetBB
, uint32_t ToOffset
, bool IsLeaf
, bool IsInvoke
,
318 FunctionDescription
*FuncDesc
, uint32_t FromNodeID
, uint32_t ToNodeID
) {
319 BinaryContext
&BC
= FromFunction
.getBinaryContext();
321 auto L
= BC
.scopeLock();
324 Created
= createCallDescription(*FuncDesc
, FromFunction
, From
, FromNodeID
,
325 ToFunc
, ToOffset
, IsInvoke
);
327 Created
= createEdgeDescription(*FuncDesc
, FromFunction
, From
, FromNodeID
,
328 ToFunc
, ToOffset
, ToNodeID
,
329 /*Instrumented=*/true);
334 InstructionListType CounterInstrs
= createInstrumentationSnippet(BC
, IsLeaf
);
336 const MCInst
&Inst
= *Iter
;
337 if (BC
.MIB
->isCall(Inst
)) {
338 // This code handles both
339 // - (regular) inter-function calls (cross-function control transfer),
340 // - (rare) intra-function calls (function-local control transfer)
341 Iter
= insertInstructions(CounterInstrs
, FromBB
, Iter
);
345 if (!TargetBB
|| !FuncDesc
)
348 // Indirect branch, conditional branches or fall-throughs
349 // Regular cond branch, put counter at start of target block
351 // N.B.: (FromBB != TargetBBs) checks below handle conditional jumps where
352 // we can't put the instrumentation counter in this block because not all
353 // paths that reach it at this point will be taken and going to the target.
354 if (TargetBB
->pred_size() == 1 && &FromBB
!= TargetBB
&&
355 !TargetBB
->isEntryPoint()) {
356 insertInstructions(CounterInstrs
, *TargetBB
, TargetBB
->begin());
359 if (FromBB
.succ_size() == 1 && &FromBB
!= TargetBB
) {
360 Iter
= insertInstructions(CounterInstrs
, FromBB
, Iter
);
363 // Critical edge, create BB and put counter there
364 SplitWorklist
.emplace_back(&FromBB
, TargetBB
);
365 SplitInstrs
.emplace_back(std::move(CounterInstrs
));
369 void Instrumentation::instrumentFunction(BinaryFunction
&Function
,
370 MCPlusBuilder::AllocatorIdTy AllocId
) {
371 if (Function
.hasUnknownControlFlow())
374 BinaryContext
&BC
= Function
.getBinaryContext();
375 if (BC
.isMachO() && Function
.hasName("___GLOBAL_init_65535/1"))
378 std::unordered_set
<const BinaryBasicBlock
*> BBToSkip
;
379 if (BC
.isAArch64() && hasAArch64ExclusiveMemop(Function
, BBToSkip
))
382 SplitWorklistTy SplitWorklist
;
383 SplitInstrsTy SplitInstrs
;
385 FunctionDescription
*FuncDesc
= nullptr;
387 std::unique_lock
<llvm::sys::RWMutex
> L(FDMutex
);
388 Summary
->FunctionDescriptions
.emplace_back();
389 FuncDesc
= &Summary
->FunctionDescriptions
.back();
392 FuncDesc
->Function
= &Function
;
393 Function
.disambiguateJumpTables(AllocId
);
394 Function
.deleteConservativeEdges();
396 std::unordered_map
<const BinaryBasicBlock
*, uint32_t> BBToID
;
398 for (auto BBI
= Function
.begin(); BBI
!= Function
.end(); ++BBI
) {
399 BBToID
[&*BBI
] = Id
++;
401 std::unordered_set
<const BinaryBasicBlock
*> VisitedSet
;
402 // DFS to establish edges we will use for a spanning tree. Edges in the
403 // spanning tree can be instrumentation-free since their count can be
404 // inferred by solving flow equations on a bottom-up traversal of the tree.
405 // Exit basic blocks are always instrumented so we start the traversal with
406 // a minimum number of defined variables to make the equation solvable.
407 std::stack
<std::pair
<const BinaryBasicBlock
*, BinaryBasicBlock
*>> Stack
;
408 std::unordered_map
<const BinaryBasicBlock
*,
409 std::set
<const BinaryBasicBlock
*>>
411 for (auto BBI
= Function
.getLayout().block_rbegin();
412 BBI
!= Function
.getLayout().block_rend(); ++BBI
) {
413 if ((*BBI
)->isEntryPoint() || (*BBI
)->isLandingPad()) {
414 Stack
.push(std::make_pair(nullptr, *BBI
));
415 if (opts::InstrumentCalls
&& (*BBI
)->isEntryPoint()) {
417 E
.Node
= BBToID
[&**BBI
];
418 E
.Address
= (*BBI
)->getInputOffset();
419 FuncDesc
->EntryNodes
.emplace_back(E
);
420 createIndCallTargetDescription(Function
, (*BBI
)->getInputOffset());
425 // Modified version of BinaryFunction::dfs() to build a spanning tree
426 if (!opts::ConservativeInstrumentation
) {
427 while (!Stack
.empty()) {
428 BinaryBasicBlock
*BB
;
429 const BinaryBasicBlock
*Pred
;
430 std::tie(Pred
, BB
) = Stack
.top();
432 if (llvm::is_contained(VisitedSet
, BB
))
435 VisitedSet
.insert(BB
);
437 STOutSet
[Pred
].insert(BB
);
439 for (BinaryBasicBlock
*SuccBB
: BB
->successors())
440 Stack
.push(std::make_pair(BB
, SuccBB
));
444 // Determine whether this is a leaf function, which needs special
445 // instructions to protect the red zone
446 bool IsLeafFunction
= true;
447 DenseSet
<const BinaryBasicBlock
*> InvokeBlocks
;
448 for (const BinaryBasicBlock
&BB
: Function
) {
449 for (const MCInst
&Inst
: BB
) {
450 if (BC
.MIB
->isCall(Inst
)) {
451 if (BC
.MIB
->isInvoke(Inst
))
452 InvokeBlocks
.insert(&BB
);
453 if (!BC
.MIB
->isTailCall(Inst
))
454 IsLeafFunction
= false;
459 for (auto BBI
= Function
.begin(), BBE
= Function
.end(); BBI
!= BBE
; ++BBI
) {
460 BinaryBasicBlock
&BB
= *BBI
;
462 // Skip BBs with exclusive load/stores
463 if (BBToSkip
.find(&BB
) != BBToSkip
.end())
466 bool HasUnconditionalBranch
= false;
467 bool HasJumpTable
= false;
468 bool IsInvokeBlock
= InvokeBlocks
.count(&BB
) > 0;
470 for (auto I
= BB
.begin(); I
!= BB
.end(); ++I
) {
471 const MCInst
&Inst
= *I
;
472 if (!BC
.MIB
->getOffset(Inst
))
475 const bool IsJumpTable
= Function
.getJumpTable(Inst
);
478 else if (BC
.MIB
->isUnconditionalBranch(Inst
))
479 HasUnconditionalBranch
= true;
480 else if (!(BC
.MIB
->isCall(Inst
) || BC
.MIB
->isConditionalBranch(Inst
)))
483 const uint32_t FromOffset
= *BC
.MIB
->getOffset(Inst
);
484 const MCSymbol
*Target
= BC
.MIB
->getTargetSymbol(Inst
);
485 BinaryBasicBlock
*TargetBB
= Function
.getBasicBlockForLabel(Target
);
486 uint32_t ToOffset
= TargetBB
? TargetBB
->getInputOffset() : 0;
487 BinaryFunction
*TargetFunc
=
488 TargetBB
? &Function
: BC
.getFunctionForSymbol(Target
);
489 if (TargetFunc
&& BC
.MIB
->isCall(Inst
)) {
490 if (opts::InstrumentCalls
) {
491 const BinaryBasicBlock
*ForeignBB
=
492 TargetFunc
->getBasicBlockForLabel(Target
);
494 ToOffset
= ForeignBB
->getInputOffset();
495 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
496 FromOffset
, *TargetFunc
, TargetBB
, ToOffset
,
497 IsLeafFunction
, IsInvokeBlock
, FuncDesc
,
503 // Do not instrument edges in the spanning tree
504 if (llvm::is_contained(STOutSet
[&BB
], TargetBB
)) {
505 auto L
= BC
.scopeLock();
506 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
507 Function
, ToOffset
, BBToID
[TargetBB
],
508 /*Instrumented=*/false);
511 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
512 FromOffset
, *TargetFunc
, TargetBB
, ToOffset
,
513 IsLeafFunction
, IsInvokeBlock
, FuncDesc
,
514 BBToID
[&BB
], BBToID
[TargetBB
]);
519 for (BinaryBasicBlock
*&Succ
: BB
.successors()) {
520 // Do not instrument edges in the spanning tree
521 if (llvm::is_contained(STOutSet
[&BB
], &*Succ
)) {
522 auto L
= BC
.scopeLock();
523 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
524 Function
, Succ
->getInputOffset(),
525 BBToID
[&*Succ
], /*Instrumented=*/false);
529 SplitWorklist
, SplitInstrs
, I
, Function
, BB
, FromOffset
, Function
,
530 &*Succ
, Succ
->getInputOffset(), IsLeafFunction
, IsInvokeBlock
,
531 FuncDesc
, BBToID
[&BB
], BBToID
[&*Succ
]);
536 // Handle indirect calls -- could be direct calls with unknown targets
537 // or secondary entry points of known functions, so check it is indirect
539 if (opts::InstrumentCalls
&& BC
.MIB
->isIndirectCall(*I
))
540 instrumentIndirectTarget(BB
, I
, Function
, FromOffset
);
542 } // End of instructions loop
544 // Instrument fallthroughs (when the direct jump instruction is missing)
545 if (!HasUnconditionalBranch
&& !HasJumpTable
&& BB
.succ_size() > 0 &&
547 BinaryBasicBlock
*FTBB
= BB
.getFallthrough();
548 assert(FTBB
&& "expected valid fall-through basic block");
550 auto LastInstr
= BB
.end();
552 while (LastInstr
!= I
&& BC
.MIB
->isPseudo(*LastInstr
))
554 uint32_t FromOffset
= 0;
555 // The last instruction in the BB should have an annotation, except
556 // if it was branching to the end of the function as a result of
557 // __builtin_unreachable(), in which case it was deleted by fixBranches.
558 // Ignore this case. FIXME: force fixBranches() to preserve the offset.
559 if (!BC
.MIB
->getOffset(*LastInstr
))
561 FromOffset
= *BC
.MIB
->getOffset(*LastInstr
);
563 // Do not instrument edges in the spanning tree
564 if (llvm::is_contained(STOutSet
[&BB
], FTBB
)) {
565 auto L
= BC
.scopeLock();
566 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
567 Function
, FTBB
->getInputOffset(), BBToID
[FTBB
],
568 /*Instrumented=*/false);
571 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
572 FromOffset
, Function
, FTBB
, FTBB
->getInputOffset(),
573 IsLeafFunction
, IsInvokeBlock
, FuncDesc
, BBToID
[&BB
],
578 // Instrument spanning tree leaves
579 if (!opts::ConservativeInstrumentation
) {
580 for (auto BBI
= Function
.begin(), BBE
= Function
.end(); BBI
!= BBE
; ++BBI
) {
581 BinaryBasicBlock
&BB
= *BBI
;
582 if (STOutSet
[&BB
].size() == 0)
583 instrumentLeafNode(BB
, BB
.begin(), IsLeafFunction
, *FuncDesc
,
588 // Consume list of critical edges: split them and add instrumentation to the
590 auto Iter
= SplitInstrs
.begin();
591 for (std::pair
<BinaryBasicBlock
*, BinaryBasicBlock
*> &BBPair
:
593 BinaryBasicBlock
*NewBB
= Function
.splitEdge(BBPair
.first
, BBPair
.second
);
594 NewBB
->addInstructions(Iter
->begin(), Iter
->end());
599 FuncDesc
->EdgesSet
.clear();
602 Error
Instrumentation::runOnFunctions(BinaryContext
&BC
) {
603 const unsigned Flags
= BinarySection::getFlags(/*IsReadOnly=*/false,
605 /*IsAllocatable=*/true);
606 BC
.registerOrUpdateSection(".bolt.instr.counters", ELF::SHT_PROGBITS
, Flags
,
609 BC
.registerOrUpdateNoteSection(".bolt.instr.tables", nullptr, 0,
611 /*IsReadOnly=*/true, ELF::SHT_NOTE
);
613 Summary
->IndCallCounterFuncPtr
=
614 BC
.Ctx
->getOrCreateSymbol("__bolt_ind_call_counter_func_pointer");
615 Summary
->IndTailCallCounterFuncPtr
=
616 BC
.Ctx
->getOrCreateSymbol("__bolt_ind_tailcall_counter_func_pointer");
618 createAuxiliaryFunctions(BC
);
620 ParallelUtilities::PredicateTy SkipPredicate
= [&](const BinaryFunction
&BF
) {
621 return (!BF
.isSimple() || BF
.isIgnored() ||
622 (opts::InstrumentHotOnly
&& !BF
.getKnownExecutionCount()));
625 ParallelUtilities::WorkFuncWithAllocTy WorkFun
=
626 [&](BinaryFunction
&BF
, MCPlusBuilder::AllocatorIdTy AllocatorId
) {
627 instrumentFunction(BF
, AllocatorId
);
630 ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
631 BC
, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC
, WorkFun
,
632 SkipPredicate
, "instrumentation", /* ForceSequential=*/true);
635 if (BC
.StartFunctionAddress
) {
636 BinaryFunction
*Main
=
637 BC
.getBinaryFunctionAtAddress(*BC
.StartFunctionAddress
);
638 assert(Main
&& "Entry point function not found");
639 BinaryBasicBlock
&BB
= Main
->front();
641 ErrorOr
<BinarySection
&> SetupSection
=
642 BC
.getUniqueSectionByName("I__setup");
644 return createFatalBOLTError("Cannot find I__setup section\n");
646 MCSymbol
*Target
= BC
.registerNameAtAddress(
647 "__bolt_instr_setup", SetupSection
->getAddress(), 0, 0);
649 BC
.MIB
->createCall(NewInst
, Target
, BC
.Ctx
.get());
650 BB
.insertInstruction(BB
.begin(), std::move(NewInst
));
652 BC
.errs() << "BOLT-WARNING: Entry point not found\n";
655 if (BinaryData
*BD
= BC
.getBinaryDataByName("___GLOBAL_init_65535/1")) {
656 BinaryFunction
*Ctor
= BC
.getBinaryFunctionAtAddress(BD
->getAddress());
657 assert(Ctor
&& "___GLOBAL_init_65535 function not found");
658 BinaryBasicBlock
&BB
= Ctor
->front();
659 ErrorOr
<BinarySection
&> FiniSection
=
660 BC
.getUniqueSectionByName("I__fini");
662 return createFatalBOLTError("Cannot find I__fini section");
664 MCSymbol
*Target
= BC
.registerNameAtAddress(
665 "__bolt_instr_fini", FiniSection
->getAddress(), 0, 0);
666 auto IsLEA
= [&BC
](const MCInst
&Inst
) { return BC
.MIB
->isLEA64r(Inst
); };
667 const auto LEA
= std::find_if(
668 std::next(llvm::find_if(reverse(BB
), IsLEA
)), BB
.rend(), IsLEA
);
669 LEA
->getOperand(4).setExpr(
670 MCSymbolRefExpr::create(Target
, MCSymbolRefExpr::VK_None
, *BC
.Ctx
));
672 BC
.errs() << "BOLT-WARNING: ___GLOBAL_init_65535 not found\n";
676 setupRuntimeLibrary(BC
);
677 return Error::success();
680 void Instrumentation::createAuxiliaryFunctions(BinaryContext
&BC
) {
681 auto createSimpleFunction
=
682 [&](StringRef Title
, InstructionListType Instrs
) -> BinaryFunction
* {
683 BinaryFunction
*Func
= BC
.createInjectedBinaryFunction(std::string(Title
));
685 std::vector
<std::unique_ptr
<BinaryBasicBlock
>> BBs
;
686 BBs
.emplace_back(Func
->createBasicBlock());
687 BBs
.back()->addInstructions(Instrs
.begin(), Instrs
.end());
688 BBs
.back()->setCFIState(0);
689 Func
->insertBasicBlocks(nullptr, std::move(BBs
),
690 /*UpdateLayout=*/true,
691 /*UpdateCFIState=*/false);
692 Func
->updateState(BinaryFunction::State::CFG_Finalized
);
696 // Here we are creating a set of functions to handle BB entry/exit.
697 // IndCallHandlerExitBB contains instructions to finish handling traffic to an
698 // indirect call. We pass it to createInstrumentedIndCallHandlerEntryBB(),
699 // which will check if a pointer to runtime library traffic accounting
700 // function was initialized (it is done during initialization of runtime
701 // library). If it is so - calls it. Then this routine returns to normal
702 // execution by jumping to exit BB.
703 BinaryFunction
*IndCallHandlerExitBB
=
704 createSimpleFunction("__bolt_instr_ind_call_handler",
705 BC
.MIB
->createInstrumentedIndCallHandlerExitBB());
707 IndCallHandlerExitBBFunction
=
708 createSimpleFunction("__bolt_instr_ind_call_handler_func",
709 BC
.MIB
->createInstrumentedIndCallHandlerEntryBB(
710 Summary
->IndCallCounterFuncPtr
,
711 IndCallHandlerExitBB
->getSymbol(), &*BC
.Ctx
));
713 BinaryFunction
*IndTailCallHandlerExitBB
= createSimpleFunction(
714 "__bolt_instr_ind_tail_call_handler",
715 BC
.MIB
->createInstrumentedIndTailCallHandlerExitBB());
717 IndTailCallHandlerExitBBFunction
= createSimpleFunction(
718 "__bolt_instr_ind_tailcall_handler_func",
719 BC
.MIB
->createInstrumentedIndCallHandlerEntryBB(
720 Summary
->IndTailCallCounterFuncPtr
,
721 IndTailCallHandlerExitBB
->getSymbol(), &*BC
.Ctx
));
723 createSimpleFunction("__bolt_num_counters_getter",
724 BC
.MIB
->createNumCountersGetter(BC
.Ctx
.get()));
725 createSimpleFunction("__bolt_instr_locations_getter",
726 BC
.MIB
->createInstrLocationsGetter(BC
.Ctx
.get()));
727 createSimpleFunction("__bolt_instr_tables_getter",
728 BC
.MIB
->createInstrTablesGetter(BC
.Ctx
.get()));
729 createSimpleFunction("__bolt_instr_num_funcs_getter",
730 BC
.MIB
->createInstrNumFuncsGetter(BC
.Ctx
.get()));
733 if (BC
.StartFunctionAddress
) {
734 BinaryFunction
*Start
=
735 BC
.getBinaryFunctionAtAddress(*BC
.StartFunctionAddress
);
736 assert(Start
&& "Entry point function not found");
737 const MCSymbol
*StartSym
= Start
->getSymbol();
738 createSimpleFunction(
739 "__bolt_start_trampoline",
740 BC
.MIB
->createSymbolTrampoline(StartSym
, BC
.Ctx
.get()));
742 if (BC
.FiniFunctionAddress
) {
743 BinaryFunction
*Fini
=
744 BC
.getBinaryFunctionAtAddress(*BC
.FiniFunctionAddress
);
745 assert(Fini
&& "Finalization function not found");
746 const MCSymbol
*FiniSym
= Fini
->getSymbol();
747 createSimpleFunction(
748 "__bolt_fini_trampoline",
749 BC
.MIB
->createSymbolTrampoline(FiniSym
, BC
.Ctx
.get()));
751 // Create dummy return function for trampoline to avoid issues
752 // with unknown symbol in runtime library. E.g. for static PIE
754 createSimpleFunction("__bolt_fini_trampoline",
755 BC
.MIB
->createReturnInstructionList(BC
.Ctx
.get()));
760 void Instrumentation::setupRuntimeLibrary(BinaryContext
&BC
) {
761 uint32_t FuncDescSize
= Summary
->getFDSize();
763 BC
.outs() << "BOLT-INSTRUMENTER: Number of indirect call site descriptors: "
764 << Summary
->IndCallDescriptions
.size() << "\n";
765 BC
.outs() << "BOLT-INSTRUMENTER: Number of indirect call target descriptors: "
766 << Summary
->IndCallTargetDescriptions
.size() << "\n";
767 BC
.outs() << "BOLT-INSTRUMENTER: Number of function descriptors: "
768 << Summary
->FunctionDescriptions
.size() << "\n";
769 BC
.outs() << "BOLT-INSTRUMENTER: Number of branch counters: "
770 << BranchCounters
<< "\n";
771 BC
.outs() << "BOLT-INSTRUMENTER: Number of ST leaf node counters: "
772 << LeafNodeCounters
<< "\n";
773 BC
.outs() << "BOLT-INSTRUMENTER: Number of direct call counters: "
774 << DirectCallCounters
<< "\n";
775 BC
.outs() << "BOLT-INSTRUMENTER: Total number of counters: "
776 << Summary
->Counters
.size() << "\n";
777 BC
.outs() << "BOLT-INSTRUMENTER: Total size of counters: "
778 << (Summary
->Counters
.size() * 8)
779 << " bytes (static alloc memory)\n";
780 BC
.outs() << "BOLT-INSTRUMENTER: Total size of string table emitted: "
781 << Summary
->StringTable
.size() << " bytes in file\n";
782 BC
.outs() << "BOLT-INSTRUMENTER: Total size of descriptors: "
784 Summary
->IndCallDescriptions
.size() *
785 sizeof(IndCallDescription
) +
786 Summary
->IndCallTargetDescriptions
.size() *
787 sizeof(IndCallTargetDescription
))
788 << " bytes in file\n";
789 BC
.outs() << "BOLT-INSTRUMENTER: Profile will be saved to file "
790 << opts::InstrumentationFilename
<< "\n";
792 InstrumentationRuntimeLibrary
*RtLibrary
=
793 static_cast<InstrumentationRuntimeLibrary
*>(BC
.getRuntimeLibrary());
794 assert(RtLibrary
&& "instrumentation runtime library object must be set");
795 RtLibrary
->setSummary(std::move(Summary
));