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/Utils.h"
17 #include "llvm/Support/CommandLine.h"
20 #define DEBUG_TYPE "bolt-instrumentation"
25 extern cl::OptionCategory BoltInstrCategory
;
27 cl::opt
<std::string
> InstrumentationFilename(
28 "instrumentation-file",
29 cl::desc("file name where instrumented profile will be saved (default: "
31 cl::init("/tmp/prof.fdata"), cl::Optional
, cl::cat(BoltInstrCategory
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
87 uint32_t Instrumentation::getFunctionNameIndex(const BinaryFunction
&Function
) {
88 auto Iter
= FuncToStringIdx
.find(&Function
);
89 if (Iter
!= FuncToStringIdx
.end())
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');
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
) {
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
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
;
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
);
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
);
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
,
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)
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;
160 FuncDesc
.Edges
.emplace_back(ED
);
164 void Instrumentation::createLeafNodeDescription(FunctionDescription
&FuncDesc
,
168 IN
.Counter
= Summary
->Counters
.size();
170 FuncDesc
.LeafNodes
.emplace_back(IN
);
174 Instrumentation::createInstrumentationSnippet(BinaryContext
&BC
, bool IsLeaf
) {
175 auto L
= BC
.scopeLock();
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
;
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
);
198 void Instrumentation::instrumentLeafNode(BinaryBasicBlock
&BB
,
199 BinaryBasicBlock::iterator Iter
,
201 FunctionDescription
&FuncDesc
,
203 createLeafNodeDescription(FuncDesc
, Node
);
204 InstructionListType CounterInstrs
= createInstrumentationSnippet(
205 BB
.getFunction()->getBinaryContext(), IsLeaf
);
206 insertInstructions(CounterInstrs
, BB
, Iter
);
209 void Instrumentation::instrumentIndirectTarget(BinaryBasicBlock
&BB
,
210 BinaryBasicBlock::iterator
&Iter
,
211 BinaryFunction
&FromFunction
,
213 auto L
= FromFunction
.getBinaryContext().scopeLock();
214 const size_t IndCallSiteID
= Summary
->IndCallDescriptions
.size();
215 createIndCallDescription(FromFunction
, From
);
217 BinaryContext
&BC
= FromFunction
.getBinaryContext();
218 bool IsTailCall
= BC
.MIB
->isTailCall(*Iter
);
219 InstructionListType CounterInstrs
= BC
.MIB
->createInstrumentedIndirectCall(
221 IsTailCall
? IndTailCallHandlerExitBBFunction
->getSymbol()
222 : IndCallHandlerExitBBFunction
->getSymbol(),
223 IndCallSiteID
, &*BC
.Ctx
);
225 Iter
= BB
.eraseInstruction(Iter
);
226 Iter
= insertInstructions(CounterInstrs
, BB
, Iter
);
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
) {
237 auto L
= FromFunction
.getBinaryContext().scopeLock();
240 Created
= createCallDescription(*FuncDesc
, FromFunction
, From
, FromNodeID
,
241 ToFunc
, ToOffset
, IsInvoke
);
243 Created
= createEdgeDescription(*FuncDesc
, FromFunction
, From
, FromNodeID
,
244 ToFunc
, ToOffset
, ToNodeID
,
245 /*Instrumented=*/true);
250 InstructionListType CounterInstrs
=
251 createInstrumentationSnippet(FromFunction
.getBinaryContext(), IsLeaf
);
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
);
263 if (!TargetBB
|| !FuncDesc
)
266 // Indirect branch, conditional branches or fall-throughs
267 // Regular cond branch, put counter at start of target block
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());
277 if (FromBB
.succ_size() == 1 && &FromBB
!= TargetBB
) {
278 Iter
= insertInstructions(CounterInstrs
, FromBB
, Iter
);
281 // Critical edge, create BB and put counter there
282 SplitWorklist
.emplace_back(&FromBB
, TargetBB
);
283 SplitInstrs
.emplace_back(std::move(CounterInstrs
));
287 void Instrumentation::instrumentFunction(BinaryFunction
&Function
,
288 MCPlusBuilder::AllocatorIdTy AllocId
) {
289 if (Function
.hasUnknownControlFlow())
292 BinaryContext
&BC
= Function
.getBinaryContext();
293 if (BC
.isMachO() && Function
.hasName("___GLOBAL_init_65535/1"))
296 SplitWorklistTy SplitWorklist
;
297 SplitInstrsTy SplitInstrs
;
299 FunctionDescription
*FuncDesc
= nullptr;
301 std::unique_lock
<std::shared_timed_mutex
> L(FDMutex
);
302 Summary
->FunctionDescriptions
.emplace_back();
303 FuncDesc
= &Summary
->FunctionDescriptions
.back();
306 FuncDesc
->Function
= &Function
;
307 Function
.disambiguateJumpTables(AllocId
);
308 Function
.deleteConservativeEdges();
310 std::unordered_map
<const BinaryBasicBlock
*, uint32_t> BBToID
;
312 for (auto BBI
= Function
.begin(); BBI
!= Function
.end(); ++BBI
) {
313 BBToID
[&*BBI
] = Id
++;
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
*>>
325 for (auto BBI
= Function
.layout_rbegin(); BBI
!= Function
.layout_rend();
327 if ((*BBI
)->isEntryPoint() || (*BBI
)->isLandingPad()) {
328 Stack
.push(std::make_pair(nullptr, *BBI
));
329 if (opts::InstrumentCalls
&& (*BBI
)->isEntryPoint()) {
331 E
.Node
= BBToID
[&**BBI
];
332 E
.Address
= (*BBI
)->getInputOffset();
333 FuncDesc
->EntryNodes
.emplace_back(E
);
334 createIndCallTargetDescription(Function
, (*BBI
)->getInputOffset());
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();
346 if (VisitedSet
.find(BB
) != VisitedSet
.end())
349 VisitedSet
.insert(BB
);
351 STOutSet
[Pred
].insert(BB
);
353 for (BinaryBasicBlock
*SuccBB
: BB
->successors())
354 Stack
.push(std::make_pair(BB
, SuccBB
));
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 IsLeafFunction
= false;
372 for (auto BBI
= Function
.begin(), BBE
= Function
.end(); BBI
!= BBE
; ++BBI
) {
373 BinaryBasicBlock
&BB
= *BBI
;
374 bool HasUnconditionalBranch
= false;
375 bool HasJumpTable
= false;
376 bool IsInvokeBlock
= InvokeBlocks
.count(&BB
) > 0;
378 for (auto I
= BB
.begin(); I
!= BB
.end(); ++I
) {
379 const MCInst
&Inst
= *I
;
380 if (!BC
.MIB
->getOffset(Inst
))
383 const bool IsJumpTable
= Function
.getJumpTable(Inst
);
386 else if (BC
.MIB
->isUnconditionalBranch(Inst
))
387 HasUnconditionalBranch
= true;
388 else if ((!BC
.MIB
->isCall(Inst
) && !BC
.MIB
->isConditionalBranch(Inst
)) ||
389 BC
.MIB
->isUnsupportedBranch(Inst
.getOpcode()))
392 const uint32_t FromOffset
= *BC
.MIB
->getOffset(Inst
);
393 const MCSymbol
*Target
= BC
.MIB
->getTargetSymbol(Inst
);
394 BinaryBasicBlock
*TargetBB
= Function
.getBasicBlockForLabel(Target
);
395 uint32_t ToOffset
= TargetBB
? TargetBB
->getInputOffset() : 0;
396 BinaryFunction
*TargetFunc
=
397 TargetBB
? &Function
: BC
.getFunctionForSymbol(Target
);
398 if (TargetFunc
&& BC
.MIB
->isCall(Inst
)) {
399 if (opts::InstrumentCalls
) {
400 const BinaryBasicBlock
*ForeignBB
=
401 TargetFunc
->getBasicBlockForLabel(Target
);
403 ToOffset
= ForeignBB
->getInputOffset();
404 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
405 FromOffset
, *TargetFunc
, TargetBB
, ToOffset
,
406 IsLeafFunction
, IsInvokeBlock
, FuncDesc
,
412 // Do not instrument edges in the spanning tree
413 if (STOutSet
[&BB
].find(TargetBB
) != STOutSet
[&BB
].end()) {
414 auto L
= BC
.scopeLock();
415 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
416 Function
, ToOffset
, BBToID
[TargetBB
],
417 /*Instrumented=*/false);
420 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
421 FromOffset
, *TargetFunc
, TargetBB
, ToOffset
,
422 IsLeafFunction
, IsInvokeBlock
, FuncDesc
,
423 BBToID
[&BB
], BBToID
[TargetBB
]);
428 for (BinaryBasicBlock
*&Succ
: BB
.successors()) {
429 // Do not instrument edges in the spanning tree
430 if (STOutSet
[&BB
].find(&*Succ
) != STOutSet
[&BB
].end()) {
431 auto L
= BC
.scopeLock();
432 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
433 Function
, Succ
->getInputOffset(),
434 BBToID
[&*Succ
], /*Instrumented=*/false);
438 SplitWorklist
, SplitInstrs
, I
, Function
, BB
, FromOffset
, Function
,
439 &*Succ
, Succ
->getInputOffset(), IsLeafFunction
, IsInvokeBlock
,
440 FuncDesc
, BBToID
[&BB
], BBToID
[&*Succ
]);
445 // Handle indirect calls -- could be direct calls with unknown targets
446 // or secondary entry points of known functions, so check it is indirect
448 if (opts::InstrumentCalls
&& BC
.MIB
->isIndirectCall(*I
))
449 instrumentIndirectTarget(BB
, I
, Function
, FromOffset
);
451 } // End of instructions loop
453 // Instrument fallthroughs (when the direct jump instruction is missing)
454 if (!HasUnconditionalBranch
&& !HasJumpTable
&& BB
.succ_size() > 0 &&
456 BinaryBasicBlock
*FTBB
= BB
.getFallthrough();
457 assert(FTBB
&& "expected valid fall-through basic block");
459 auto LastInstr
= BB
.end();
461 while (LastInstr
!= I
&& BC
.MIB
->isPseudo(*LastInstr
))
463 uint32_t FromOffset
= 0;
464 // The last instruction in the BB should have an annotation, except
465 // if it was branching to the end of the function as a result of
466 // __builtin_unreachable(), in which case it was deleted by fixBranches.
467 // Ignore this case. FIXME: force fixBranches() to preserve the offset.
468 if (!BC
.MIB
->getOffset(*LastInstr
))
470 FromOffset
= *BC
.MIB
->getOffset(*LastInstr
);
472 // Do not instrument edges in the spanning tree
473 if (STOutSet
[&BB
].find(FTBB
) != STOutSet
[&BB
].end()) {
474 auto L
= BC
.scopeLock();
475 createEdgeDescription(*FuncDesc
, Function
, FromOffset
, BBToID
[&BB
],
476 Function
, FTBB
->getInputOffset(), BBToID
[FTBB
],
477 /*Instrumented=*/false);
480 instrumentOneTarget(SplitWorklist
, SplitInstrs
, I
, Function
, BB
,
481 FromOffset
, Function
, FTBB
, FTBB
->getInputOffset(),
482 IsLeafFunction
, IsInvokeBlock
, FuncDesc
, BBToID
[&BB
],
487 // Instrument spanning tree leaves
488 if (!opts::ConservativeInstrumentation
) {
489 for (auto BBI
= Function
.begin(), BBE
= Function
.end(); BBI
!= BBE
; ++BBI
) {
490 BinaryBasicBlock
&BB
= *BBI
;
491 if (STOutSet
[&BB
].size() == 0)
492 instrumentLeafNode(BB
, BB
.begin(), IsLeafFunction
, *FuncDesc
,
497 // Consume list of critical edges: split them and add instrumentation to the
499 auto Iter
= SplitInstrs
.begin();
500 for (std::pair
<BinaryBasicBlock
*, BinaryBasicBlock
*> &BBPair
:
502 BinaryBasicBlock
*NewBB
= Function
.splitEdge(BBPair
.first
, BBPair
.second
);
503 NewBB
->addInstructions(Iter
->begin(), Iter
->end());
508 FuncDesc
->EdgesSet
.clear();
511 void Instrumentation::runOnFunctions(BinaryContext
&BC
) {
515 const unsigned Flags
= BinarySection::getFlags(/*IsReadOnly=*/false,
517 /*IsAllocatable=*/true);
518 BC
.registerOrUpdateSection(".bolt.instr.counters", ELF::SHT_PROGBITS
, Flags
,
521 BC
.registerOrUpdateNoteSection(".bolt.instr.tables", nullptr, 0,
523 /*IsReadOnly=*/true, ELF::SHT_NOTE
);
525 Summary
->IndCallCounterFuncPtr
=
526 BC
.Ctx
->getOrCreateSymbol("__bolt_ind_call_counter_func_pointer");
527 Summary
->IndTailCallCounterFuncPtr
=
528 BC
.Ctx
->getOrCreateSymbol("__bolt_ind_tailcall_counter_func_pointer");
530 createAuxiliaryFunctions(BC
);
532 ParallelUtilities::PredicateTy SkipPredicate
= [&](const BinaryFunction
&BF
) {
533 return (!BF
.isSimple() || BF
.isIgnored() ||
534 (opts::InstrumentHotOnly
&& !BF
.getKnownExecutionCount()));
537 ParallelUtilities::WorkFuncWithAllocTy WorkFun
=
538 [&](BinaryFunction
&BF
, MCPlusBuilder::AllocatorIdTy AllocatorId
) {
539 instrumentFunction(BF
, AllocatorId
);
542 ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
543 BC
, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC
, WorkFun
,
544 SkipPredicate
, "instrumentation", /* ForceSequential=*/true);
547 if (BC
.StartFunctionAddress
) {
548 BinaryFunction
*Main
=
549 BC
.getBinaryFunctionAtAddress(*BC
.StartFunctionAddress
);
550 assert(Main
&& "Entry point function not found");
551 BinaryBasicBlock
&BB
= Main
->front();
553 ErrorOr
<BinarySection
&> SetupSection
=
554 BC
.getUniqueSectionByName("I__setup");
556 llvm::errs() << "Cannot find I__setup section\n";
559 MCSymbol
*Target
= BC
.registerNameAtAddress(
560 "__bolt_instr_setup", SetupSection
->getAddress(), 0, 0);
562 BC
.MIB
->createCall(NewInst
, Target
, BC
.Ctx
.get());
563 BB
.insertInstruction(BB
.begin(), std::move(NewInst
));
565 llvm::errs() << "BOLT-WARNING: Entry point not found\n";
568 if (BinaryData
*BD
= BC
.getBinaryDataByName("___GLOBAL_init_65535/1")) {
569 BinaryFunction
*Ctor
= BC
.getBinaryFunctionAtAddress(BD
->getAddress());
570 assert(Ctor
&& "___GLOBAL_init_65535 function not found");
571 BinaryBasicBlock
&BB
= Ctor
->front();
572 ErrorOr
<BinarySection
&> FiniSection
=
573 BC
.getUniqueSectionByName("I__fini");
575 llvm::errs() << "Cannot find I__fini section\n";
578 MCSymbol
*Target
= BC
.registerNameAtAddress(
579 "__bolt_instr_fini", FiniSection
->getAddress(), 0, 0);
580 auto IsLEA
= [&BC
](const MCInst
&Inst
) { return BC
.MIB
->isLEA64r(Inst
); };
581 const auto LEA
= std::find_if(
582 std::next(llvm::find_if(reverse(BB
), IsLEA
)), BB
.rend(), IsLEA
);
583 LEA
->getOperand(4).setExpr(
584 MCSymbolRefExpr::create(Target
, MCSymbolRefExpr::VK_None
, *BC
.Ctx
));
586 llvm::errs() << "BOLT-WARNING: ___GLOBAL_init_65535 not found\n";
590 setupRuntimeLibrary(BC
);
593 void Instrumentation::createAuxiliaryFunctions(BinaryContext
&BC
) {
594 auto createSimpleFunction
=
595 [&](StringRef Title
, InstructionListType Instrs
) -> BinaryFunction
* {
596 BinaryFunction
*Func
= BC
.createInjectedBinaryFunction(std::string(Title
));
598 std::vector
<std::unique_ptr
<BinaryBasicBlock
>> BBs
;
599 BBs
.emplace_back(Func
->createBasicBlock());
600 BBs
.back()->addInstructions(Instrs
.begin(), Instrs
.end());
601 BBs
.back()->setCFIState(0);
602 Func
->insertBasicBlocks(nullptr, std::move(BBs
),
603 /*UpdateLayout=*/true,
604 /*UpdateCFIState=*/false);
605 Func
->updateState(BinaryFunction::State::CFG_Finalized
);
609 // Here we are creating a set of functions to handle BB entry/exit.
610 // IndCallHandlerExitBB contains instructions to finish handling traffic to an
611 // indirect call. We pass it to createInstrumentedIndCallHandlerEntryBB(),
612 // which will check if a pointer to runtime library traffic accounting
613 // function was initialized (it is done during initialization of runtime
614 // library). If it is so - calls it. Then this routine returns to normal
615 // execution by jumping to exit BB.
616 BinaryFunction
*IndCallHandlerExitBB
=
617 createSimpleFunction("__bolt_instr_ind_call_handler",
618 BC
.MIB
->createInstrumentedIndCallHandlerExitBB());
620 IndCallHandlerExitBBFunction
=
621 createSimpleFunction("__bolt_instr_ind_call_handler_func",
622 BC
.MIB
->createInstrumentedIndCallHandlerEntryBB(
623 Summary
->IndCallCounterFuncPtr
,
624 IndCallHandlerExitBB
->getSymbol(), &*BC
.Ctx
));
626 BinaryFunction
*IndTailCallHandlerExitBB
= createSimpleFunction(
627 "__bolt_instr_ind_tail_call_handler",
628 BC
.MIB
->createInstrumentedIndTailCallHandlerExitBB());
630 IndTailCallHandlerExitBBFunction
= createSimpleFunction(
631 "__bolt_instr_ind_tailcall_handler_func",
632 BC
.MIB
->createInstrumentedIndCallHandlerEntryBB(
633 Summary
->IndTailCallCounterFuncPtr
,
634 IndTailCallHandlerExitBB
->getSymbol(), &*BC
.Ctx
));
636 createSimpleFunction("__bolt_num_counters_getter",
637 BC
.MIB
->createNumCountersGetter(BC
.Ctx
.get()));
638 createSimpleFunction("__bolt_instr_locations_getter",
639 BC
.MIB
->createInstrLocationsGetter(BC
.Ctx
.get()));
640 createSimpleFunction("__bolt_instr_tables_getter",
641 BC
.MIB
->createInstrTablesGetter(BC
.Ctx
.get()));
642 createSimpleFunction("__bolt_instr_num_funcs_getter",
643 BC
.MIB
->createInstrNumFuncsGetter(BC
.Ctx
.get()));
646 if (BC
.StartFunctionAddress
) {
647 BinaryFunction
*Start
=
648 BC
.getBinaryFunctionAtAddress(*BC
.StartFunctionAddress
);
649 assert(Start
&& "Entry point function not found");
650 const MCSymbol
*StartSym
= Start
->getSymbol();
651 createSimpleFunction(
652 "__bolt_start_trampoline",
653 BC
.MIB
->createSymbolTrampoline(StartSym
, BC
.Ctx
.get()));
655 if (BC
.FiniFunctionAddress
) {
656 BinaryFunction
*Fini
=
657 BC
.getBinaryFunctionAtAddress(*BC
.FiniFunctionAddress
);
658 assert(Fini
&& "Finalization function not found");
659 const MCSymbol
*FiniSym
= Fini
->getSymbol();
660 createSimpleFunction(
661 "__bolt_fini_trampoline",
662 BC
.MIB
->createSymbolTrampoline(FiniSym
, BC
.Ctx
.get()));
664 // Create dummy return function for trampoline to avoid issues
665 // with unknown symbol in runtime library. E.g. for static PIE
667 createSimpleFunction("__bolt_fini_trampoline",
668 BC
.MIB
->createDummyReturnFunction(BC
.Ctx
.get()));
673 void Instrumentation::setupRuntimeLibrary(BinaryContext
&BC
) {
674 uint32_t FuncDescSize
= Summary
->getFDSize();
676 outs() << "BOLT-INSTRUMENTER: Number of indirect call site descriptors: "
677 << Summary
->IndCallDescriptions
.size() << "\n";
678 outs() << "BOLT-INSTRUMENTER: Number of indirect call target descriptors: "
679 << Summary
->IndCallTargetDescriptions
.size() << "\n";
680 outs() << "BOLT-INSTRUMENTER: Number of function descriptors: "
681 << Summary
->FunctionDescriptions
.size() << "\n";
682 outs() << "BOLT-INSTRUMENTER: Number of branch counters: " << BranchCounters
684 outs() << "BOLT-INSTRUMENTER: Number of ST leaf node counters: "
685 << LeafNodeCounters
<< "\n";
686 outs() << "BOLT-INSTRUMENTER: Number of direct call counters: "
687 << DirectCallCounters
<< "\n";
688 outs() << "BOLT-INSTRUMENTER: Total number of counters: "
689 << Summary
->Counters
.size() << "\n";
690 outs() << "BOLT-INSTRUMENTER: Total size of counters: "
691 << (Summary
->Counters
.size() * 8) << " bytes (static alloc memory)\n";
692 outs() << "BOLT-INSTRUMENTER: Total size of string table emitted: "
693 << Summary
->StringTable
.size() << " bytes in file\n";
694 outs() << "BOLT-INSTRUMENTER: Total size of descriptors: "
696 Summary
->IndCallDescriptions
.size() * sizeof(IndCallDescription
) +
697 Summary
->IndCallTargetDescriptions
.size() *
698 sizeof(IndCallTargetDescription
))
699 << " bytes in file\n";
700 outs() << "BOLT-INSTRUMENTER: Profile will be saved to file "
701 << opts::InstrumentationFilename
<< "\n";
703 InstrumentationRuntimeLibrary
*RtLibrary
=
704 static_cast<InstrumentationRuntimeLibrary
*>(BC
.getRuntimeLibrary());
705 assert(RtLibrary
&& "instrumentation runtime library object must be set");
706 RtLibrary
->setSummary(std::move(Summary
));