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 #define DEBUG_TYPE "bolt-instrumentation"
27 extern cl::OptionCategory BoltInstrCategory
;
29 cl::opt
<std::string
> InstrumentationFilename(
30 "instrumentation-file",
31 cl::desc("file name where instrumented profile will be saved (default: "
33 cl::init("/tmp/prof.fdata"), cl::Optional
, cl::cat(BoltInstrCategory
));
35 cl::opt
<std::string
> InstrumentationBinpath(
36 "instrumentation-binpath",
37 cl::desc("path to instumented binary in case if /proc/self/map_files "
38 "is not accessible due to access restriction issues"),
39 cl::Optional
, cl::cat(BoltInstrCategory
));
41 cl::opt
<bool> InstrumentationFileAppendPID(
42 "instrumentation-file-append-pid",
43 cl::desc("append PID to saved profile file name (default: false)"),
44 cl::init(false), cl::Optional
, cl::cat(BoltInstrCategory
));
46 cl::opt
<bool> ConservativeInstrumentation(
47 "conservative-instrumentation",
48 cl::desc("disable instrumentation optimizations that sacrifice profile "
49 "accuracy (for debugging, default: false)"),
50 cl::init(false), cl::Optional
, cl::cat(BoltInstrCategory
));
52 cl::opt
<uint32_t> InstrumentationSleepTime(
53 "instrumentation-sleep-time",
54 cl::desc("interval between profile writes (default: 0 = write only at "
55 "program end). This is useful for service workloads when you "
56 "want to dump profile every X minutes or if you are killing the "
57 "program and the profile is not being dumped at the end."),
58 cl::init(0), cl::Optional
, cl::cat(BoltInstrCategory
));
60 cl::opt
<bool> InstrumentationNoCountersClear(
61 "instrumentation-no-counters-clear",
62 cl::desc("Don't clear counters across dumps "
63 "(use with instrumentation-sleep-time option)"),
64 cl::init(false), cl::Optional
, cl::cat(BoltInstrCategory
));
66 cl::opt
<bool> InstrumentationWaitForks(
67 "instrumentation-wait-forks",
68 cl::desc("Wait until all forks of instrumented process will finish "
69 "(use with instrumentation-sleep-time option)"),
70 cl::init(false), cl::Optional
, cl::cat(BoltInstrCategory
));
73 InstrumentHotOnly("instrument-hot-only",
74 cl::desc("only insert instrumentation on hot functions "
75 "(needs profile, default: false)"),
76 cl::init(false), cl::Optional
,
77 cl::cat(BoltInstrCategory
));
79 cl::opt
<bool> InstrumentCalls("instrument-calls",
80 cl::desc("record profile for inter-function "
81 "control flow activity (default: true)"),
82 cl::init(true), cl::Optional
,
83 cl::cat(BoltInstrCategory
));
89 static bool hasAArch64ExclusiveMemop(BinaryFunction
&Function
) {
90 // FIXME ARMv8-a architecture reference manual says that software must avoid
91 // having any explicit memory accesses between exclusive load and associated
92 // store instruction. So for now skip instrumentation for functions that have
93 // these instructions, since it might lead to runtime deadlock.
94 BinaryContext
&BC
= Function
.getBinaryContext();
95 for (const BinaryBasicBlock
&BB
: Function
)
96 for (const MCInst
&Inst
: BB
)
97 if (BC
.MIB
->isAArch64Exclusive(Inst
)) {
98 if (opts::Verbosity
>= 1)
99 outs() << "BOLT-INSTRUMENTER: Function " << Function
100 << " has exclusive instructions, skip instrumentation\n";
107 uint32_t Instrumentation::getFunctionNameIndex(const BinaryFunction
&Function
) {
108 auto Iter
= FuncToStringIdx
.find(&Function
);
109 if (Iter
!= FuncToStringIdx
.end())
111 size_t Idx
= Summary
->StringTable
.size();
112 FuncToStringIdx
.emplace(std::make_pair(&Function
, Idx
));
113 Summary
->StringTable
.append(getEscapedName(Function
.getOneName()));
114 Summary
->StringTable
.append(1, '\0');
118 bool Instrumentation::createCallDescription(FunctionDescription
&FuncDesc
,
119 const BinaryFunction
&FromFunction
,
120 uint32_t From
, uint32_t FromNodeID
,
121 const BinaryFunction
&ToFunction
,
122 uint32_t To
, bool IsInvoke
) {
124 // Ordinarily, we don't augment direct calls with an explicit counter, except
125 // when forced to do so or when we know this callee could be throwing
126 // exceptions, in which case there is no other way to accurately record its
128 bool ForceInstrumentation
= opts::ConservativeInstrumentation
|| IsInvoke
;
129 CD
.FromLoc
.FuncString
= getFunctionNameIndex(FromFunction
);
130 CD
.FromLoc
.Offset
= From
;
131 CD
.FromNode
= FromNodeID
;
132 CD
.Target
= &ToFunction
;
133 CD
.ToLoc
.FuncString
= getFunctionNameIndex(ToFunction
);
134 CD
.ToLoc
.Offset
= To
;
135 CD
.Counter
= ForceInstrumentation
? Summary
->Counters
.size() : 0xffffffff;
136 if (ForceInstrumentation
)
137 ++DirectCallCounters
;
138 FuncDesc
.Calls
.emplace_back(CD
);
139 return ForceInstrumentation
;
142 void Instrumentation::createIndCallDescription(
143 const BinaryFunction
&FromFunction
, uint32_t From
) {
144 IndCallDescription ICD
;
145 ICD
.FromLoc
.FuncString
= getFunctionNameIndex(FromFunction
);
146 ICD
.FromLoc
.Offset
= From
;
147 Summary
->IndCallDescriptions
.emplace_back(ICD
);
150 void Instrumentation::createIndCallTargetDescription(
151 const BinaryFunction
&ToFunction
, uint32_t To
) {
152 IndCallTargetDescription ICD
;
153 ICD
.ToLoc
.FuncString
= getFunctionNameIndex(ToFunction
);
154 ICD
.ToLoc
.Offset
= To
;
155 ICD
.Target
= &ToFunction
;
156 Summary
->IndCallTargetDescriptions
.emplace_back(ICD
);
159 bool Instrumentation::createEdgeDescription(FunctionDescription
&FuncDesc
,
160 const BinaryFunction
&FromFunction
,
161 uint32_t From
, uint32_t FromNodeID
,
162 const BinaryFunction
&ToFunction
,
163 uint32_t To
, uint32_t ToNodeID
,
166 auto Result
= FuncDesc
.EdgesSet
.insert(std::make_pair(FromNodeID
, ToNodeID
));
167 // Avoid creating duplicated edge descriptions. This happens in CFGs where a
168 // block jumps to its fall-through.
169 if (Result
.second
== false)
171 ED
.FromLoc
.FuncString
= getFunctionNameIndex(FromFunction
);
172 ED
.FromLoc
.Offset
= From
;
173 ED
.FromNode
= FromNodeID
;
174 ED
.ToLoc
.FuncString
= getFunctionNameIndex(ToFunction
);
175 ED
.ToLoc
.Offset
= To
;
176 ED
.ToNode
= ToNodeID
;
177 ED
.Counter
= Instrumented
? Summary
->Counters
.size() : 0xffffffff;
180 FuncDesc
.Edges
.emplace_back(ED
);
184 void Instrumentation::createLeafNodeDescription(FunctionDescription
&FuncDesc
,
188 IN
.Counter
= Summary
->Counters
.size();
190 FuncDesc
.LeafNodes
.emplace_back(IN
);
194 Instrumentation::createInstrumentationSnippet(BinaryContext
&BC
, bool IsLeaf
) {
195 auto L
= BC
.scopeLock();
196 MCSymbol
*Label
= BC
.Ctx
->createNamedTempSymbol("InstrEntry");
197 Summary
->Counters
.emplace_back(Label
);
198 return BC
.MIB
->createInstrIncMemory(Label
, BC
.Ctx
.get(), IsLeaf
,
199 BC
.AsmInfo
->getCodePointerSize());
202 // Helper instruction sequence insertion function
203 static BinaryBasicBlock::iterator
204 insertInstructions(InstructionListType
&Instrs
, BinaryBasicBlock
&BB
,
205 BinaryBasicBlock::iterator Iter
) {
206 for (MCInst
&NewInst
: Instrs
) {
207 Iter
= BB
.insertInstruction(Iter
, NewInst
);
213 void Instrumentation::instrumentLeafNode(BinaryBasicBlock
&BB
,
214 BinaryBasicBlock::iterator Iter
,
216 FunctionDescription
&FuncDesc
,
218 createLeafNodeDescription(FuncDesc
, Node
);
219 InstructionListType CounterInstrs
= createInstrumentationSnippet(
220 BB
.getFunction()->getBinaryContext(), IsLeaf
);
221 insertInstructions(CounterInstrs
, BB
, Iter
);
224 void Instrumentation::instrumentIndirectTarget(BinaryBasicBlock
&BB
,
225 BinaryBasicBlock::iterator
&Iter
,
226 BinaryFunction
&FromFunction
,
228 auto L
= FromFunction
.getBinaryContext().scopeLock();
229 const size_t IndCallSiteID
= Summary
->IndCallDescriptions
.size();
230 createIndCallDescription(FromFunction
, From
);
232 BinaryContext
&BC
= FromFunction
.getBinaryContext();
233 bool IsTailCall
= BC
.MIB
->isTailCall(*Iter
);
234 InstructionListType CounterInstrs
= BC
.MIB
->createInstrumentedIndirectCall(
236 IsTailCall
? IndTailCallHandlerExitBBFunction
->getSymbol()
237 : IndCallHandlerExitBBFunction
->getSymbol(),
238 IndCallSiteID
, &*BC
.Ctx
);
240 Iter
= BB
.eraseInstruction(Iter
);
241 Iter
= insertInstructions(CounterInstrs
, BB
, Iter
);
245 bool Instrumentation::instrumentOneTarget(
246 SplitWorklistTy
&SplitWorklist
, SplitInstrsTy
&SplitInstrs
,
247 BinaryBasicBlock::iterator
&Iter
, BinaryFunction
&FromFunction
,
248 BinaryBasicBlock
&FromBB
, uint32_t From
, BinaryFunction
&ToFunc
,
249 BinaryBasicBlock
*TargetBB
, uint32_t ToOffset
, bool IsLeaf
, bool IsInvoke
,
250 FunctionDescription
*FuncDesc
, uint32_t FromNodeID
, uint32_t ToNodeID
) {
251 BinaryContext
&BC
= FromFunction
.getBinaryContext();
253 auto L
= BC
.scopeLock();
256 Created
= createCallDescription(*FuncDesc
, FromFunction
, From
, FromNodeID
,
257 ToFunc
, ToOffset
, IsInvoke
);
259 Created
= createEdgeDescription(*FuncDesc
, FromFunction
, From
, FromNodeID
,
260 ToFunc
, ToOffset
, ToNodeID
,
261 /*Instrumented=*/true);
266 InstructionListType CounterInstrs
= createInstrumentationSnippet(BC
, IsLeaf
);
268 const MCInst
&Inst
= *Iter
;
269 if (BC
.MIB
->isCall(Inst
)) {
270 // This code handles both
271 // - (regular) inter-function calls (cross-function control transfer),
272 // - (rare) intra-function calls (function-local control transfer)
273 Iter
= insertInstructions(CounterInstrs
, FromBB
, Iter
);
277 if (!TargetBB
|| !FuncDesc
)
280 // Indirect branch, conditional branches or fall-throughs
281 // Regular cond branch, put counter at start of target block
283 // N.B.: (FromBB != TargetBBs) checks below handle conditional jumps where
284 // we can't put the instrumentation counter in this block because not all
285 // paths that reach it at this point will be taken and going to the target.
286 if (TargetBB
->pred_size() == 1 && &FromBB
!= TargetBB
&&
287 !TargetBB
->isEntryPoint()) {
288 insertInstructions(CounterInstrs
, *TargetBB
, TargetBB
->begin());
291 if (FromBB
.succ_size() == 1 && &FromBB
!= TargetBB
) {
292 Iter
= insertInstructions(CounterInstrs
, FromBB
, Iter
);
295 // Critical edge, create BB and put counter there
296 SplitWorklist
.emplace_back(&FromBB
, TargetBB
);
297 SplitInstrs
.emplace_back(std::move(CounterInstrs
));
301 void Instrumentation::instrumentFunction(BinaryFunction
&Function
,
302 MCPlusBuilder::AllocatorIdTy AllocId
) {
303 if (Function
.hasUnknownControlFlow())
306 BinaryContext
&BC
= Function
.getBinaryContext();
307 if (BC
.isMachO() && Function
.hasName("___GLOBAL_init_65535/1"))
310 if (BC
.isAArch64() && hasAArch64ExclusiveMemop(Function
))
313 SplitWorklistTy SplitWorklist
;
314 SplitInstrsTy SplitInstrs
;
316 FunctionDescription
*FuncDesc
= nullptr;
318 std::unique_lock
<llvm::sys::RWMutex
> L(FDMutex
);
319 Summary
->FunctionDescriptions
.emplace_back();
320 FuncDesc
= &Summary
->FunctionDescriptions
.back();
323 FuncDesc
->Function
= &Function
;
324 Function
.disambiguateJumpTables(AllocId
);
325 Function
.deleteConservativeEdges();
327 std::unordered_map
<const BinaryBasicBlock
*, uint32_t> BBToID
;
329 for (auto BBI
= Function
.begin(); BBI
!= Function
.end(); ++BBI
) {
330 BBToID
[&*BBI
] = Id
++;
332 std::unordered_set
<const BinaryBasicBlock
*> VisitedSet
;
333 // DFS to establish edges we will use for a spanning tree. Edges in the
334 // spanning tree can be instrumentation-free since their count can be
335 // inferred by solving flow equations on a bottom-up traversal of the tree.
336 // Exit basic blocks are always instrumented so we start the traversal with
337 // a minimum number of defined variables to make the equation solvable.
338 std::stack
<std::pair
<const BinaryBasicBlock
*, BinaryBasicBlock
*>> Stack
;
339 std::unordered_map
<const BinaryBasicBlock
*,
340 std::set
<const BinaryBasicBlock
*>>
342 for (auto BBI
= Function
.getLayout().block_rbegin();
343 BBI
!= Function
.getLayout().block_rend(); ++BBI
) {
344 if ((*BBI
)->isEntryPoint() || (*BBI
)->isLandingPad()) {
345 Stack
.push(std::make_pair(nullptr, *BBI
));
346 if (opts::InstrumentCalls
&& (*BBI
)->isEntryPoint()) {
348 E
.Node
= BBToID
[&**BBI
];
349 E
.Address
= (*BBI
)->getInputOffset();
350 FuncDesc
->EntryNodes
.emplace_back(E
);
351 createIndCallTargetDescription(Function
, (*BBI
)->getInputOffset());
356 // Modified version of BinaryFunction::dfs() to build a spanning tree
357 if (!opts::ConservativeInstrumentation
) {
358 while (!Stack
.empty()) {
359 BinaryBasicBlock
*BB
;
360 const BinaryBasicBlock
*Pred
;
361 std::tie(Pred
, BB
) = Stack
.top();
363 if (llvm::is_contained(VisitedSet
, BB
))
366 VisitedSet
.insert(BB
);
368 STOutSet
[Pred
].insert(BB
);
370 for (BinaryBasicBlock
*SuccBB
: BB
->successors())
371 Stack
.push(std::make_pair(BB
, SuccBB
));
375 // Determine whether this is a leaf function, which needs special
376 // instructions to protect the red zone
377 bool IsLeafFunction
= true;
378 DenseSet
<const BinaryBasicBlock
*> InvokeBlocks
;
379 for (const BinaryBasicBlock
&BB
: Function
) {
380 for (const MCInst
&Inst
: BB
) {
381 if (BC
.MIB
->isCall(Inst
)) {
382 if (BC
.MIB
->isInvoke(Inst
))
383 InvokeBlocks
.insert(&BB
);
384 if (!BC
.MIB
->isTailCall(Inst
))
385 IsLeafFunction
= false;
390 for (auto BBI
= Function
.begin(), BBE
= Function
.end(); BBI
!= BBE
; ++BBI
) {
391 BinaryBasicBlock
&BB
= *BBI
;
392 bool HasUnconditionalBranch
= false;
393 bool HasJumpTable
= false;
394 bool IsInvokeBlock
= InvokeBlocks
.count(&BB
) > 0;
396 for (auto I
= BB
.begin(); I
!= BB
.end(); ++I
) {
397 const MCInst
&Inst
= *I
;
398 if (!BC
.MIB
->getOffset(Inst
))
401 const bool IsJumpTable
= Function
.getJumpTable(Inst
);
404 else if (BC
.MIB
->isUnconditionalBranch(Inst
))
405 HasUnconditionalBranch
= true;
406 else if ((!BC
.MIB
->isCall(Inst
) && !BC
.MIB
->isConditionalBranch(Inst
)) ||
407 BC
.MIB
->isUnsupportedBranch(Inst
))
410 const uint32_t FromOffset
= *BC
.MIB
->getOffset(Inst
);
411 const MCSymbol
*Target
= BC
.MIB
->getTargetSymbol(Inst
);
412 BinaryBasicBlock
*TargetBB
= Function
.getBasicBlockForLabel(Target
);
413 uint32_t ToOffset
= TargetBB
? TargetBB
->getInputOffset() : 0;
414 BinaryFunction
*TargetFunc
=
415 TargetBB
? &Function
: BC
.getFunctionForSymbol(Target
);
416 if (TargetFunc
&& BC
.MIB
->isCall(Inst
)) {
417 if (opts::InstrumentCalls
) {
418 const BinaryBasicBlock
*ForeignBB
=
419 TargetFunc
->getBasicBlockForLabel(Target
);
421 ToOffset
= ForeignBB
->getInputOffset();
422 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
423 FromOffset
, *TargetFunc
, TargetBB
, ToOffset
,
424 IsLeafFunction
, IsInvokeBlock
, FuncDesc
,
430 // Do not instrument edges in the spanning tree
431 if (llvm::is_contained(STOutSet
[&BB
], TargetBB
)) {
432 auto L
= BC
.scopeLock();
433 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
434 Function
, ToOffset
, BBToID
[TargetBB
],
435 /*Instrumented=*/false);
438 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
439 FromOffset
, *TargetFunc
, TargetBB
, ToOffset
,
440 IsLeafFunction
, IsInvokeBlock
, FuncDesc
,
441 BBToID
[&BB
], BBToID
[TargetBB
]);
446 for (BinaryBasicBlock
*&Succ
: BB
.successors()) {
447 // Do not instrument edges in the spanning tree
448 if (llvm::is_contained(STOutSet
[&BB
], &*Succ
)) {
449 auto L
= BC
.scopeLock();
450 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
451 Function
, Succ
->getInputOffset(),
452 BBToID
[&*Succ
], /*Instrumented=*/false);
456 SplitWorklist
, SplitInstrs
, I
, Function
, BB
, FromOffset
, Function
,
457 &*Succ
, Succ
->getInputOffset(), IsLeafFunction
, IsInvokeBlock
,
458 FuncDesc
, BBToID
[&BB
], BBToID
[&*Succ
]);
463 // Handle indirect calls -- could be direct calls with unknown targets
464 // or secondary entry points of known functions, so check it is indirect
466 if (opts::InstrumentCalls
&& BC
.MIB
->isIndirectCall(*I
))
467 instrumentIndirectTarget(BB
, I
, Function
, FromOffset
);
469 } // End of instructions loop
471 // Instrument fallthroughs (when the direct jump instruction is missing)
472 if (!HasUnconditionalBranch
&& !HasJumpTable
&& BB
.succ_size() > 0 &&
474 BinaryBasicBlock
*FTBB
= BB
.getFallthrough();
475 assert(FTBB
&& "expected valid fall-through basic block");
477 auto LastInstr
= BB
.end();
479 while (LastInstr
!= I
&& BC
.MIB
->isPseudo(*LastInstr
))
481 uint32_t FromOffset
= 0;
482 // The last instruction in the BB should have an annotation, except
483 // if it was branching to the end of the function as a result of
484 // __builtin_unreachable(), in which case it was deleted by fixBranches.
485 // Ignore this case. FIXME: force fixBranches() to preserve the offset.
486 if (!BC
.MIB
->getOffset(*LastInstr
))
488 FromOffset
= *BC
.MIB
->getOffset(*LastInstr
);
490 // Do not instrument edges in the spanning tree
491 if (llvm::is_contained(STOutSet
[&BB
], FTBB
)) {
492 auto L
= BC
.scopeLock();
493 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
494 Function
, FTBB
->getInputOffset(), BBToID
[FTBB
],
495 /*Instrumented=*/false);
498 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
499 FromOffset
, Function
, FTBB
, FTBB
->getInputOffset(),
500 IsLeafFunction
, IsInvokeBlock
, FuncDesc
, BBToID
[&BB
],
505 // Instrument spanning tree leaves
506 if (!opts::ConservativeInstrumentation
) {
507 for (auto BBI
= Function
.begin(), BBE
= Function
.end(); BBI
!= BBE
; ++BBI
) {
508 BinaryBasicBlock
&BB
= *BBI
;
509 if (STOutSet
[&BB
].size() == 0)
510 instrumentLeafNode(BB
, BB
.begin(), IsLeafFunction
, *FuncDesc
,
515 // Consume list of critical edges: split them and add instrumentation to the
517 auto Iter
= SplitInstrs
.begin();
518 for (std::pair
<BinaryBasicBlock
*, BinaryBasicBlock
*> &BBPair
:
520 BinaryBasicBlock
*NewBB
= Function
.splitEdge(BBPair
.first
, BBPair
.second
);
521 NewBB
->addInstructions(Iter
->begin(), Iter
->end());
526 FuncDesc
->EdgesSet
.clear();
529 void Instrumentation::runOnFunctions(BinaryContext
&BC
) {
530 const unsigned Flags
= BinarySection::getFlags(/*IsReadOnly=*/false,
532 /*IsAllocatable=*/true);
533 BC
.registerOrUpdateSection(".bolt.instr.counters", ELF::SHT_PROGBITS
, Flags
,
536 BC
.registerOrUpdateNoteSection(".bolt.instr.tables", nullptr, 0,
538 /*IsReadOnly=*/true, ELF::SHT_NOTE
);
540 Summary
->IndCallCounterFuncPtr
=
541 BC
.Ctx
->getOrCreateSymbol("__bolt_ind_call_counter_func_pointer");
542 Summary
->IndTailCallCounterFuncPtr
=
543 BC
.Ctx
->getOrCreateSymbol("__bolt_ind_tailcall_counter_func_pointer");
545 createAuxiliaryFunctions(BC
);
547 ParallelUtilities::PredicateTy SkipPredicate
= [&](const BinaryFunction
&BF
) {
548 return (!BF
.isSimple() || BF
.isIgnored() ||
549 (opts::InstrumentHotOnly
&& !BF
.getKnownExecutionCount()));
552 ParallelUtilities::WorkFuncWithAllocTy WorkFun
=
553 [&](BinaryFunction
&BF
, MCPlusBuilder::AllocatorIdTy AllocatorId
) {
554 instrumentFunction(BF
, AllocatorId
);
557 ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
558 BC
, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC
, WorkFun
,
559 SkipPredicate
, "instrumentation", /* ForceSequential=*/true);
562 if (BC
.StartFunctionAddress
) {
563 BinaryFunction
*Main
=
564 BC
.getBinaryFunctionAtAddress(*BC
.StartFunctionAddress
);
565 assert(Main
&& "Entry point function not found");
566 BinaryBasicBlock
&BB
= Main
->front();
568 ErrorOr
<BinarySection
&> SetupSection
=
569 BC
.getUniqueSectionByName("I__setup");
571 llvm::errs() << "Cannot find I__setup section\n";
574 MCSymbol
*Target
= BC
.registerNameAtAddress(
575 "__bolt_instr_setup", SetupSection
->getAddress(), 0, 0);
577 BC
.MIB
->createCall(NewInst
, Target
, BC
.Ctx
.get());
578 BB
.insertInstruction(BB
.begin(), std::move(NewInst
));
580 llvm::errs() << "BOLT-WARNING: Entry point not found\n";
583 if (BinaryData
*BD
= BC
.getBinaryDataByName("___GLOBAL_init_65535/1")) {
584 BinaryFunction
*Ctor
= BC
.getBinaryFunctionAtAddress(BD
->getAddress());
585 assert(Ctor
&& "___GLOBAL_init_65535 function not found");
586 BinaryBasicBlock
&BB
= Ctor
->front();
587 ErrorOr
<BinarySection
&> FiniSection
=
588 BC
.getUniqueSectionByName("I__fini");
590 llvm::errs() << "Cannot find I__fini section\n";
593 MCSymbol
*Target
= BC
.registerNameAtAddress(
594 "__bolt_instr_fini", FiniSection
->getAddress(), 0, 0);
595 auto IsLEA
= [&BC
](const MCInst
&Inst
) { return BC
.MIB
->isLEA64r(Inst
); };
596 const auto LEA
= std::find_if(
597 std::next(llvm::find_if(reverse(BB
), IsLEA
)), BB
.rend(), IsLEA
);
598 LEA
->getOperand(4).setExpr(
599 MCSymbolRefExpr::create(Target
, MCSymbolRefExpr::VK_None
, *BC
.Ctx
));
601 llvm::errs() << "BOLT-WARNING: ___GLOBAL_init_65535 not found\n";
605 setupRuntimeLibrary(BC
);
608 void Instrumentation::createAuxiliaryFunctions(BinaryContext
&BC
) {
609 auto createSimpleFunction
=
610 [&](StringRef Title
, InstructionListType Instrs
) -> BinaryFunction
* {
611 BinaryFunction
*Func
= BC
.createInjectedBinaryFunction(std::string(Title
));
613 std::vector
<std::unique_ptr
<BinaryBasicBlock
>> BBs
;
614 BBs
.emplace_back(Func
->createBasicBlock());
615 BBs
.back()->addInstructions(Instrs
.begin(), Instrs
.end());
616 BBs
.back()->setCFIState(0);
617 Func
->insertBasicBlocks(nullptr, std::move(BBs
),
618 /*UpdateLayout=*/true,
619 /*UpdateCFIState=*/false);
620 Func
->updateState(BinaryFunction::State::CFG_Finalized
);
624 // Here we are creating a set of functions to handle BB entry/exit.
625 // IndCallHandlerExitBB contains instructions to finish handling traffic to an
626 // indirect call. We pass it to createInstrumentedIndCallHandlerEntryBB(),
627 // which will check if a pointer to runtime library traffic accounting
628 // function was initialized (it is done during initialization of runtime
629 // library). If it is so - calls it. Then this routine returns to normal
630 // execution by jumping to exit BB.
631 BinaryFunction
*IndCallHandlerExitBB
=
632 createSimpleFunction("__bolt_instr_ind_call_handler",
633 BC
.MIB
->createInstrumentedIndCallHandlerExitBB());
635 IndCallHandlerExitBBFunction
=
636 createSimpleFunction("__bolt_instr_ind_call_handler_func",
637 BC
.MIB
->createInstrumentedIndCallHandlerEntryBB(
638 Summary
->IndCallCounterFuncPtr
,
639 IndCallHandlerExitBB
->getSymbol(), &*BC
.Ctx
));
641 BinaryFunction
*IndTailCallHandlerExitBB
= createSimpleFunction(
642 "__bolt_instr_ind_tail_call_handler",
643 BC
.MIB
->createInstrumentedIndTailCallHandlerExitBB());
645 IndTailCallHandlerExitBBFunction
= createSimpleFunction(
646 "__bolt_instr_ind_tailcall_handler_func",
647 BC
.MIB
->createInstrumentedIndCallHandlerEntryBB(
648 Summary
->IndTailCallCounterFuncPtr
,
649 IndTailCallHandlerExitBB
->getSymbol(), &*BC
.Ctx
));
651 createSimpleFunction("__bolt_num_counters_getter",
652 BC
.MIB
->createNumCountersGetter(BC
.Ctx
.get()));
653 createSimpleFunction("__bolt_instr_locations_getter",
654 BC
.MIB
->createInstrLocationsGetter(BC
.Ctx
.get()));
655 createSimpleFunction("__bolt_instr_tables_getter",
656 BC
.MIB
->createInstrTablesGetter(BC
.Ctx
.get()));
657 createSimpleFunction("__bolt_instr_num_funcs_getter",
658 BC
.MIB
->createInstrNumFuncsGetter(BC
.Ctx
.get()));
661 if (BC
.StartFunctionAddress
) {
662 BinaryFunction
*Start
=
663 BC
.getBinaryFunctionAtAddress(*BC
.StartFunctionAddress
);
664 assert(Start
&& "Entry point function not found");
665 const MCSymbol
*StartSym
= Start
->getSymbol();
666 createSimpleFunction(
667 "__bolt_start_trampoline",
668 BC
.MIB
->createSymbolTrampoline(StartSym
, BC
.Ctx
.get()));
670 if (BC
.FiniFunctionAddress
) {
671 BinaryFunction
*Fini
=
672 BC
.getBinaryFunctionAtAddress(*BC
.FiniFunctionAddress
);
673 assert(Fini
&& "Finalization function not found");
674 const MCSymbol
*FiniSym
= Fini
->getSymbol();
675 createSimpleFunction(
676 "__bolt_fini_trampoline",
677 BC
.MIB
->createSymbolTrampoline(FiniSym
, BC
.Ctx
.get()));
679 // Create dummy return function for trampoline to avoid issues
680 // with unknown symbol in runtime library. E.g. for static PIE
682 createSimpleFunction("__bolt_fini_trampoline",
683 BC
.MIB
->createDummyReturnFunction(BC
.Ctx
.get()));
688 void Instrumentation::setupRuntimeLibrary(BinaryContext
&BC
) {
689 uint32_t FuncDescSize
= Summary
->getFDSize();
691 outs() << "BOLT-INSTRUMENTER: Number of indirect call site descriptors: "
692 << Summary
->IndCallDescriptions
.size() << "\n";
693 outs() << "BOLT-INSTRUMENTER: Number of indirect call target descriptors: "
694 << Summary
->IndCallTargetDescriptions
.size() << "\n";
695 outs() << "BOLT-INSTRUMENTER: Number of function descriptors: "
696 << Summary
->FunctionDescriptions
.size() << "\n";
697 outs() << "BOLT-INSTRUMENTER: Number of branch counters: " << BranchCounters
699 outs() << "BOLT-INSTRUMENTER: Number of ST leaf node counters: "
700 << LeafNodeCounters
<< "\n";
701 outs() << "BOLT-INSTRUMENTER: Number of direct call counters: "
702 << DirectCallCounters
<< "\n";
703 outs() << "BOLT-INSTRUMENTER: Total number of counters: "
704 << Summary
->Counters
.size() << "\n";
705 outs() << "BOLT-INSTRUMENTER: Total size of counters: "
706 << (Summary
->Counters
.size() * 8) << " bytes (static alloc memory)\n";
707 outs() << "BOLT-INSTRUMENTER: Total size of string table emitted: "
708 << Summary
->StringTable
.size() << " bytes in file\n";
709 outs() << "BOLT-INSTRUMENTER: Total size of descriptors: "
711 Summary
->IndCallDescriptions
.size() * sizeof(IndCallDescription
) +
712 Summary
->IndCallTargetDescriptions
.size() *
713 sizeof(IndCallTargetDescription
))
714 << " bytes in file\n";
715 outs() << "BOLT-INSTRUMENTER: Profile will be saved to file "
716 << opts::InstrumentationFilename
<< "\n";
718 InstrumentationRuntimeLibrary
*RtLibrary
=
719 static_cast<InstrumentationRuntimeLibrary
*>(BC
.getRuntimeLibrary());
720 assert(RtLibrary
&& "instrumentation runtime library object must be set");
721 RtLibrary
->setSummary(std::move(Summary
));