xref: /llvm-project/bolt/lib/Passes/Instrumentation.cpp (revision 1a2f83366b86433bb86f3b60fa19b3f096313a21)
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/CommandLineOpts.h"
17 #include "bolt/Utils/Utils.h"
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/RWMutex.h"
20 #include <stack>
21 
22 #define DEBUG_TYPE "bolt-instrumentation"
23 
24 using namespace llvm;
25 
26 namespace opts {
27 extern cl::OptionCategory BoltInstrCategory;
28 
29 cl::opt<std::string> InstrumentationFilename(
30     "instrumentation-file",
31     cl::desc("file name where instrumented profile will be saved (default: "
32              "/tmp/prof.fdata)"),
33     cl::init("/tmp/prof.fdata"), cl::Optional, cl::cat(BoltInstrCategory));
34 
35 cl::opt<std::string> InstrumentationBinpath(
36     "instrumentation-binpath",
37     cl::desc("path to instrumented binary in case if /proc/self/map_files "
38              "is not accessible due to access restriction issues"),
39     cl::Optional, cl::cat(BoltInstrCategory));
40 
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));
45 
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));
51 
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));
59 
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));
65 
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));
71 
72 cl::opt<bool>
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));
78 
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));
84 } // namespace opts
85 
86 namespace llvm {
87 namespace bolt {
88 
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";
101         return true;
102       }
103 
104   return false;
105 }
106 
107 uint32_t Instrumentation::getFunctionNameIndex(const BinaryFunction &Function) {
108   auto Iter = FuncToStringIdx.find(&Function);
109   if (Iter != FuncToStringIdx.end())
110     return Iter->second;
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');
115   return Idx;
116 }
117 
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) {
123   CallDescription CD;
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
127   // frequency.
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;
140 }
141 
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);
148 }
149 
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);
157 }
158 
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,
164                                             bool Instrumented) {
165   EdgeDescription ED;
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)
170     return 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;
178   if (Instrumented)
179     ++BranchCounters;
180   FuncDesc.Edges.emplace_back(ED);
181   return Instrumented;
182 }
183 
184 void Instrumentation::createLeafNodeDescription(FunctionDescription &FuncDesc,
185                                                 uint32_t Node) {
186   InstrumentedNode IN;
187   IN.Node = Node;
188   IN.Counter = Summary->Counters.size();
189   ++LeafNodeCounters;
190   FuncDesc.LeafNodes.emplace_back(IN);
191 }
192 
193 InstructionListType
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());
200 }
201 
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);
208     ++Iter;
209   }
210   return Iter;
211 }
212 
213 void Instrumentation::instrumentLeafNode(BinaryBasicBlock &BB,
214                                          BinaryBasicBlock::iterator Iter,
215                                          bool IsLeaf,
216                                          FunctionDescription &FuncDesc,
217                                          uint32_t Node) {
218   createLeafNodeDescription(FuncDesc, Node);
219   InstructionListType CounterInstrs = createInstrumentationSnippet(
220       BB.getFunction()->getBinaryContext(), IsLeaf);
221   insertInstructions(CounterInstrs, BB, Iter);
222 }
223 
224 void Instrumentation::instrumentIndirectTarget(BinaryBasicBlock &BB,
225                                                BinaryBasicBlock::iterator &Iter,
226                                                BinaryFunction &FromFunction,
227                                                uint32_t From) {
228   auto L = FromFunction.getBinaryContext().scopeLock();
229   const size_t IndCallSiteID = Summary->IndCallDescriptions.size();
230   createIndCallDescription(FromFunction, From);
231 
232   BinaryContext &BC = FromFunction.getBinaryContext();
233   bool IsTailCall = BC.MIB->isTailCall(*Iter);
234   InstructionListType CounterInstrs = BC.MIB->createInstrumentedIndirectCall(
235       std::move(*Iter),
236       IsTailCall ? IndTailCallHandlerExitBBFunction->getSymbol()
237                  : IndCallHandlerExitBBFunction->getSymbol(),
238       IndCallSiteID, &*BC.Ctx);
239 
240   Iter = BB.eraseInstruction(Iter);
241   Iter = insertInstructions(CounterInstrs, BB, Iter);
242   --Iter;
243 }
244 
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();
252   {
253     auto L = BC.scopeLock();
254     bool Created = true;
255     if (!TargetBB)
256       Created = createCallDescription(*FuncDesc, FromFunction, From, FromNodeID,
257                                       ToFunc, ToOffset, IsInvoke);
258     else
259       Created = createEdgeDescription(*FuncDesc, FromFunction, From, FromNodeID,
260                                       ToFunc, ToOffset, ToNodeID,
261                                       /*Instrumented=*/true);
262     if (!Created)
263       return false;
264   }
265 
266   InstructionListType CounterInstrs = createInstrumentationSnippet(BC, IsLeaf);
267 
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);
274     return true;
275   }
276 
277   if (!TargetBB || !FuncDesc)
278     return false;
279 
280   // Indirect branch, conditional branches or fall-throughs
281   // Regular cond branch, put counter at start of target block
282   //
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());
289     return true;
290   }
291   if (FromBB.succ_size() == 1 && &FromBB != TargetBB) {
292     Iter = insertInstructions(CounterInstrs, FromBB, Iter);
293     return true;
294   }
295   // Critical edge, create BB and put counter there
296   SplitWorklist.emplace_back(&FromBB, TargetBB);
297   SplitInstrs.emplace_back(std::move(CounterInstrs));
298   return true;
299 }
300 
301 void Instrumentation::instrumentFunction(BinaryFunction &Function,
302                                          MCPlusBuilder::AllocatorIdTy AllocId) {
303   if (Function.hasUnknownControlFlow())
304     return;
305 
306   BinaryContext &BC = Function.getBinaryContext();
307   if (BC.isMachO() && Function.hasName("___GLOBAL_init_65535/1"))
308     return;
309 
310   if (BC.isAArch64() && hasAArch64ExclusiveMemop(Function))
311     return;
312 
313   SplitWorklistTy SplitWorklist;
314   SplitInstrsTy SplitInstrs;
315 
316   FunctionDescription *FuncDesc = nullptr;
317   {
318     std::unique_lock<llvm::sys::RWMutex> L(FDMutex);
319     Summary->FunctionDescriptions.emplace_back();
320     FuncDesc = &Summary->FunctionDescriptions.back();
321   }
322 
323   FuncDesc->Function = &Function;
324   Function.disambiguateJumpTables(AllocId);
325   Function.deleteConservativeEdges();
326 
327   std::unordered_map<const BinaryBasicBlock *, uint32_t> BBToID;
328   uint32_t Id = 0;
329   for (auto BBI = Function.begin(); BBI != Function.end(); ++BBI) {
330     BBToID[&*BBI] = Id++;
331   }
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 *>>
341       STOutSet;
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()) {
347         EntryNode E;
348         E.Node = BBToID[&**BBI];
349         E.Address = (*BBI)->getInputOffset();
350         FuncDesc->EntryNodes.emplace_back(E);
351         createIndCallTargetDescription(Function, (*BBI)->getInputOffset());
352       }
353     }
354   }
355 
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();
362       Stack.pop();
363       if (llvm::is_contained(VisitedSet, BB))
364         continue;
365 
366       VisitedSet.insert(BB);
367       if (Pred)
368         STOutSet[Pred].insert(BB);
369 
370       for (BinaryBasicBlock *SuccBB : BB->successors())
371         Stack.push(std::make_pair(BB, SuccBB));
372     }
373   }
374 
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;
386       }
387     }
388   }
389 
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;
395 
396     for (auto I = BB.begin(); I != BB.end(); ++I) {
397       const MCInst &Inst = *I;
398       if (!BC.MIB->getOffset(Inst))
399         continue;
400 
401       const bool IsJumpTable = Function.getJumpTable(Inst);
402       if (IsJumpTable)
403         HasJumpTable = true;
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))
408         continue;
409 
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);
420           if (ForeignBB)
421             ToOffset = ForeignBB->getInputOffset();
422           instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB,
423                               FromOffset, *TargetFunc, TargetBB, ToOffset,
424                               IsLeafFunction, IsInvokeBlock, FuncDesc,
425                               BBToID[&BB]);
426         }
427         continue;
428       }
429       if (TargetFunc) {
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);
436           continue;
437         }
438         instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB,
439                             FromOffset, *TargetFunc, TargetBB, ToOffset,
440                             IsLeafFunction, IsInvokeBlock, FuncDesc,
441                             BBToID[&BB], BBToID[TargetBB]);
442         continue;
443       }
444 
445       if (IsJumpTable) {
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);
453             continue;
454           }
455           instrumentOneTarget(
456               SplitWorklist, SplitInstrs, I, Function, BB, FromOffset, Function,
457               &*Succ, Succ->getInputOffset(), IsLeafFunction, IsInvokeBlock,
458               FuncDesc, BBToID[&BB], BBToID[&*Succ]);
459         }
460         continue;
461       }
462 
463       // Handle indirect calls -- could be direct calls with unknown targets
464       // or secondary entry points of known functions, so check it is indirect
465       // to be sure.
466       if (opts::InstrumentCalls && BC.MIB->isIndirectCall(*I))
467         instrumentIndirectTarget(BB, I, Function, FromOffset);
468 
469     } // End of instructions loop
470 
471     // Instrument fallthroughs (when the direct jump instruction is missing)
472     if (!HasUnconditionalBranch && !HasJumpTable && BB.succ_size() > 0 &&
473         BB.size() > 0) {
474       BinaryBasicBlock *FTBB = BB.getFallthrough();
475       assert(FTBB && "expected valid fall-through basic block");
476       auto I = BB.begin();
477       auto LastInstr = BB.end();
478       --LastInstr;
479       while (LastInstr != I && BC.MIB->isPseudo(*LastInstr))
480         --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))
487         continue;
488       FromOffset = *BC.MIB->getOffset(*LastInstr);
489 
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);
496         continue;
497       }
498       instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB,
499                           FromOffset, Function, FTBB, FTBB->getInputOffset(),
500                           IsLeafFunction, IsInvokeBlock, FuncDesc, BBToID[&BB],
501                           BBToID[FTBB]);
502     }
503   } // End of BBs loop
504 
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,
511                            BBToID[&BB]);
512     }
513   }
514 
515   // Consume list of critical edges: split them and add instrumentation to the
516   // newly created BBs
517   auto Iter = SplitInstrs.begin();
518   for (std::pair<BinaryBasicBlock *, BinaryBasicBlock *> &BBPair :
519        SplitWorklist) {
520     BinaryBasicBlock *NewBB = Function.splitEdge(BBPair.first, BBPair.second);
521     NewBB->addInstructions(Iter->begin(), Iter->end());
522     ++Iter;
523   }
524 
525   // Unused now
526   FuncDesc->EdgesSet.clear();
527 }
528 
529 void Instrumentation::runOnFunctions(BinaryContext &BC) {
530   const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/false,
531                                                  /*IsText=*/false,
532                                                  /*IsAllocatable=*/true);
533   BC.registerOrUpdateSection(".bolt.instr.counters", ELF::SHT_PROGBITS, Flags,
534                              nullptr, 0, 1);
535 
536   BC.registerOrUpdateNoteSection(".bolt.instr.tables", nullptr, 0,
537                                  /*Alignment=*/1,
538                                  /*IsReadOnly=*/true, ELF::SHT_NOTE);
539 
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");
544 
545   createAuxiliaryFunctions(BC);
546 
547   ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) {
548     return (!BF.isSimple() || BF.isIgnored() ||
549             (opts::InstrumentHotOnly && !BF.getKnownExecutionCount()));
550   };
551 
552   ParallelUtilities::WorkFuncWithAllocTy WorkFun =
553       [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) {
554         instrumentFunction(BF, AllocatorId);
555       };
556 
557   ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
558       BC, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC, WorkFun,
559       SkipPredicate, "instrumentation", /* ForceSequential=*/true);
560 
561   if (BC.isMachO()) {
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();
567 
568       ErrorOr<BinarySection &> SetupSection =
569           BC.getUniqueSectionByName("I__setup");
570       if (!SetupSection) {
571         llvm::errs() << "Cannot find I__setup section\n";
572         exit(1);
573       }
574       MCSymbol *Target = BC.registerNameAtAddress(
575           "__bolt_instr_setup", SetupSection->getAddress(), 0, 0);
576       MCInst NewInst;
577       BC.MIB->createCall(NewInst, Target, BC.Ctx.get());
578       BB.insertInstruction(BB.begin(), std::move(NewInst));
579     } else {
580       llvm::errs() << "BOLT-WARNING: Entry point not found\n";
581     }
582 
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");
589       if (!FiniSection) {
590         llvm::errs() << "Cannot find I__fini section\n";
591         exit(1);
592       }
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));
600     } else {
601       llvm::errs() << "BOLT-WARNING: ___GLOBAL_init_65535 not found\n";
602     }
603   }
604 
605   setupRuntimeLibrary(BC);
606 }
607 
608 void Instrumentation::createAuxiliaryFunctions(BinaryContext &BC) {
609   auto createSimpleFunction =
610       [&](StringRef Title, InstructionListType Instrs) -> BinaryFunction * {
611     BinaryFunction *Func = BC.createInjectedBinaryFunction(std::string(Title));
612 
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);
621     return Func;
622   };
623 
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());
634 
635   IndCallHandlerExitBBFunction =
636       createSimpleFunction("__bolt_instr_ind_call_handler_func",
637                            BC.MIB->createInstrumentedIndCallHandlerEntryBB(
638                                Summary->IndCallCounterFuncPtr,
639                                IndCallHandlerExitBB->getSymbol(), &*BC.Ctx));
640 
641   BinaryFunction *IndTailCallHandlerExitBB = createSimpleFunction(
642       "__bolt_instr_ind_tail_call_handler",
643       BC.MIB->createInstrumentedIndTailCallHandlerExitBB());
644 
645   IndTailCallHandlerExitBBFunction = createSimpleFunction(
646       "__bolt_instr_ind_tailcall_handler_func",
647       BC.MIB->createInstrumentedIndCallHandlerEntryBB(
648           Summary->IndTailCallCounterFuncPtr,
649           IndTailCallHandlerExitBB->getSymbol(), &*BC.Ctx));
650 
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()));
659 
660   if (BC.isELF()) {
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()));
669     }
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()));
678     } else {
679       // Create dummy return function for trampoline to avoid issues
680       // with unknown symbol in runtime library. E.g. for static PIE
681       // executable
682       createSimpleFunction("__bolt_fini_trampoline",
683                            BC.MIB->createDummyReturnFunction(BC.Ctx.get()));
684     }
685   }
686 }
687 
688 void Instrumentation::setupRuntimeLibrary(BinaryContext &BC) {
689   uint32_t FuncDescSize = Summary->getFDSize();
690 
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
698          << "\n";
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: "
710          << (FuncDescSize +
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";
717 
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));
722 }
723 } // namespace bolt
724 } // namespace llvm
725