xref: /llvm-project/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp (revision 0a5edb4de408ae0405f85c3e4c6da5233f185f63)
12f09f445SMaksim Panchenko //===- bolt/RuntimeLibs/InstrumentationRuntimeLibrary.cpp -----------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
92f09f445SMaksim Panchenko // This file implements the InstrumentationRuntimeLibrary class.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h"
14a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h"
15a34c753fSRafael Auler #include "bolt/Core/JumpTable.h"
1605634f73SJob Noorman #include "bolt/Core/Linker.h"
17a34c753fSRafael Auler #include "bolt/Utils/CommandLineOpts.h"
18a34c753fSRafael Auler #include "llvm/MC/MCStreamer.h"
19a34c753fSRafael Auler #include "llvm/Support/Alignment.h"
20a34c753fSRafael Auler #include "llvm/Support/CommandLine.h"
21a34c753fSRafael Auler 
22a34c753fSRafael Auler using namespace llvm;
23a34c753fSRafael Auler using namespace bolt;
24a34c753fSRafael Auler 
25a34c753fSRafael Auler namespace opts {
26a34c753fSRafael Auler 
27a34c753fSRafael Auler cl::opt<std::string> RuntimeInstrumentationLib(
28a34c753fSRafael Auler     "runtime-instrumentation-lib",
29*abc2eae6STristan Ross     cl::desc("specify path of the runtime instrumentation library"),
30b92436efSFangrui Song     cl::init("libbolt_rt_instr.a"), cl::cat(BoltOptCategory));
31a34c753fSRafael Auler 
32a34c753fSRafael Auler extern cl::opt<bool> InstrumentationFileAppendPID;
33a34c753fSRafael Auler extern cl::opt<bool> ConservativeInstrumentation;
34a34c753fSRafael Auler extern cl::opt<std::string> InstrumentationFilename;
35a34c753fSRafael Auler extern cl::opt<std::string> InstrumentationBinpath;
36a34c753fSRafael Auler extern cl::opt<uint32_t> InstrumentationSleepTime;
37a34c753fSRafael Auler extern cl::opt<bool> InstrumentationNoCountersClear;
38a34c753fSRafael Auler extern cl::opt<bool> InstrumentationWaitForks;
39a34c753fSRafael Auler extern cl::opt<JumpTableSupportLevel> JumpTables;
40a34c753fSRafael Auler 
41a34c753fSRafael Auler } // namespace opts
42a34c753fSRafael Auler 
43a34c753fSRafael Auler void InstrumentationRuntimeLibrary::adjustCommandLineOptions(
44a34c753fSRafael Auler     const BinaryContext &BC) const {
45a34c753fSRafael Auler   if (!BC.HasRelocations) {
46a34c753fSRafael Auler     errs() << "BOLT-ERROR: instrumentation runtime libraries require "
47a34c753fSRafael Auler               "relocations\n";
48a34c753fSRafael Auler     exit(1);
49a34c753fSRafael Auler   }
50a34c753fSRafael Auler   if (opts::JumpTables != JTS_MOVE) {
51a34c753fSRafael Auler     opts::JumpTables = JTS_MOVE;
52a34c753fSRafael Auler     outs() << "BOLT-INFO: forcing -jump-tables=move for instrumentation\n";
53a34c753fSRafael Auler   }
54a34c753fSRafael Auler   if (!BC.StartFunctionAddress) {
55a34c753fSRafael Auler     errs() << "BOLT-ERROR: instrumentation runtime libraries require a known "
56a34c753fSRafael Auler               "entry point of "
57a34c753fSRafael Auler               "the input binary\n";
58a34c753fSRafael Auler     exit(1);
59a34c753fSRafael Auler   }
602e6f722bSVladislav Khmelevsky 
612e6f722bSVladislav Khmelevsky   if (BC.IsStaticExecutable && !opts::InstrumentationSleepTime) {
622e6f722bSVladislav Khmelevsky     errs() << "BOLT-ERROR: instrumentation of static binary currently does not "
632e6f722bSVladislav Khmelevsky               "support profile output on binary finalization, so it "
642e6f722bSVladislav Khmelevsky               "requires -instrumentation-sleep-time=N (N>0) usage\n";
652e6f722bSVladislav Khmelevsky     exit(1);
662e6f722bSVladislav Khmelevsky   }
672e6f722bSVladislav Khmelevsky 
68f6682ad0SDenis Revunov   if ((opts::InstrumentationWaitForks || opts::InstrumentationSleepTime) &&
69f6682ad0SDenis Revunov       opts::InstrumentationFileAppendPID) {
70f6682ad0SDenis Revunov     errs()
71f6682ad0SDenis Revunov         << "BOLT-ERROR: instrumentation-file-append-pid is not compatible with "
72f6682ad0SDenis Revunov            "instrumentation-sleep-time and instrumentation-wait-forks. If you "
73f6682ad0SDenis Revunov            "want a separate profile for each fork, it can only be dumped in "
74f6682ad0SDenis Revunov            "the end of process when instrumentation-file-append-pid is used.\n";
75f6682ad0SDenis Revunov     exit(1);
76f6682ad0SDenis Revunov   }
77a34c753fSRafael Auler }
78a34c753fSRafael Auler 
79a34c753fSRafael Auler void InstrumentationRuntimeLibrary::emitBinary(BinaryContext &BC,
80a34c753fSRafael Auler                                                MCStreamer &Streamer) {
81a34c753fSRafael Auler   MCSection *Section = BC.isELF()
82a34c753fSRafael Auler                            ? static_cast<MCSection *>(BC.Ctx->getELFSection(
83a34c753fSRafael Auler                                  ".bolt.instr.counters", ELF::SHT_PROGBITS,
84a34c753fSRafael Auler                                  BinarySection::getFlags(/*IsReadOnly=*/false,
85a34c753fSRafael Auler                                                          /*IsText=*/false,
86a34c753fSRafael Auler                                                          /*IsAllocatable=*/true)
87a34c753fSRafael Auler 
88a34c753fSRafael Auler                                      ))
89a34c753fSRafael Auler                            : static_cast<MCSection *>(BC.Ctx->getMachOSection(
90a34c753fSRafael Auler                                  "__BOLT", "__counters", MachO::S_REGULAR,
91a34c753fSRafael Auler                                  SectionKind::getData()));
92a34c753fSRafael Auler 
93a34c753fSRafael Auler   Section->setAlignment(llvm::Align(BC.RegularPageSize));
94adf4142fSFangrui Song   Streamer.switchSection(Section);
95a34c753fSRafael Auler 
96a34c753fSRafael Auler   // EmitOffset is used to determine padding size for data alignment
97a34c753fSRafael Auler   uint64_t EmitOffset = 0;
98a34c753fSRafael Auler 
99a34c753fSRafael Auler   auto emitLabel = [&Streamer](MCSymbol *Symbol, bool IsGlobal = true) {
100a34c753fSRafael Auler     Streamer.emitLabel(Symbol);
101a34c753fSRafael Auler     if (IsGlobal)
102a34c753fSRafael Auler       Streamer.emitSymbolAttribute(Symbol, MCSymbolAttr::MCSA_Global);
103a34c753fSRafael Auler   };
104a34c753fSRafael Auler 
105a34c753fSRafael Auler   auto emitLabelByName = [&BC, emitLabel](StringRef Name,
106a34c753fSRafael Auler                                           bool IsGlobal = true) {
107a34c753fSRafael Auler     MCSymbol *Symbol = BC.Ctx->getOrCreateSymbol(Name);
108a34c753fSRafael Auler     emitLabel(Symbol, IsGlobal);
109a34c753fSRafael Auler   };
110a34c753fSRafael Auler 
111a34c753fSRafael Auler   auto emitPadding = [&Streamer, &EmitOffset](unsigned Size) {
112a34c753fSRafael Auler     const uint64_t Padding = alignTo(EmitOffset, Size) - EmitOffset;
113a34c753fSRafael Auler     if (Padding) {
114a34c753fSRafael Auler       Streamer.emitFill(Padding, 0);
115a34c753fSRafael Auler       EmitOffset += Padding;
116a34c753fSRafael Auler     }
117a34c753fSRafael Auler   };
118a34c753fSRafael Auler 
119a34c753fSRafael Auler   auto emitDataSize = [&EmitOffset](unsigned Size) { EmitOffset += Size; };
120a34c753fSRafael Auler 
121a34c753fSRafael Auler   auto emitDataPadding = [emitPadding, emitDataSize](unsigned Size) {
122a34c753fSRafael Auler     emitPadding(Size);
123a34c753fSRafael Auler     emitDataSize(Size);
124a34c753fSRafael Auler   };
125a34c753fSRafael Auler 
126a34c753fSRafael Auler   auto emitFill = [&Streamer, emitDataSize,
127a34c753fSRafael Auler                    emitLabel](unsigned Size, MCSymbol *Symbol = nullptr,
128a34c753fSRafael Auler                               uint8_t Byte = 0) {
129a34c753fSRafael Auler     emitDataSize(Size);
130a34c753fSRafael Auler     if (Symbol)
131a34c753fSRafael Auler       emitLabel(Symbol, /*IsGlobal*/ false);
132a34c753fSRafael Auler     Streamer.emitFill(Size, Byte);
133a34c753fSRafael Auler   };
134a34c753fSRafael Auler 
135a34c753fSRafael Auler   auto emitValue = [&BC, &Streamer, emitDataPadding,
136a34c753fSRafael Auler                     emitLabel](MCSymbol *Symbol, const MCExpr *Value) {
137a34c753fSRafael Auler     const unsigned Psize = BC.AsmInfo->getCodePointerSize();
138a34c753fSRafael Auler     emitDataPadding(Psize);
139a34c753fSRafael Auler     emitLabel(Symbol);
140a34c753fSRafael Auler     if (Value)
141a34c753fSRafael Auler       Streamer.emitValue(Value, Psize);
142a34c753fSRafael Auler     else
143a34c753fSRafael Auler       Streamer.emitFill(Psize, 0);
144a34c753fSRafael Auler   };
145a34c753fSRafael Auler 
146a34c753fSRafael Auler   auto emitIntValue = [&Streamer, emitDataPadding, emitLabelByName](
147a34c753fSRafael Auler                           StringRef Name, uint64_t Value, unsigned Size = 4) {
148a34c753fSRafael Auler     emitDataPadding(Size);
149a34c753fSRafael Auler     emitLabelByName(Name);
150a34c753fSRafael Auler     Streamer.emitIntValue(Value, Size);
151a34c753fSRafael Auler   };
152a34c753fSRafael Auler 
153a34c753fSRafael Auler   auto emitString = [&Streamer, emitDataSize, emitLabelByName,
154a34c753fSRafael Auler                      emitFill](StringRef Name, StringRef Contents) {
155a34c753fSRafael Auler     emitDataSize(Contents.size());
156a34c753fSRafael Auler     emitLabelByName(Name);
157a34c753fSRafael Auler     Streamer.emitBytes(Contents);
158a34c753fSRafael Auler     emitFill(1);
159a34c753fSRafael Auler   };
160a34c753fSRafael Auler 
161a34c753fSRafael Auler   // All of the following symbols will be exported as globals to be used by the
162a34c753fSRafael Auler   // instrumentation runtime library to dump the instrumentation data to disk.
163a34c753fSRafael Auler   // Label marking start of the memory region containing instrumentation
164a34c753fSRafael Auler   // counters, total vector size is Counters.size() 8-byte counters
165a34c753fSRafael Auler   emitLabelByName("__bolt_instr_locations");
166a34c753fSRafael Auler   for (MCSymbol *const &Label : Summary->Counters)
167a34c753fSRafael Auler     emitFill(sizeof(uint64_t), Label);
168a34c753fSRafael Auler 
169a34c753fSRafael Auler   emitPadding(BC.RegularPageSize);
170a34c753fSRafael Auler   emitIntValue("__bolt_instr_sleep_time", opts::InstrumentationSleepTime);
171a34c753fSRafael Auler   emitIntValue("__bolt_instr_no_counters_clear",
172a34c753fSRafael Auler                !!opts::InstrumentationNoCountersClear, 1);
173a34c753fSRafael Auler   emitIntValue("__bolt_instr_conservative", !!opts::ConservativeInstrumentation,
174a34c753fSRafael Auler                1);
175a34c753fSRafael Auler   emitIntValue("__bolt_instr_wait_forks", !!opts::InstrumentationWaitForks, 1);
176a34c753fSRafael Auler   emitIntValue("__bolt_num_counters", Summary->Counters.size());
177a34c753fSRafael Auler   emitValue(Summary->IndCallCounterFuncPtr, nullptr);
178a34c753fSRafael Auler   emitValue(Summary->IndTailCallCounterFuncPtr, nullptr);
179a34c753fSRafael Auler   emitIntValue("__bolt_instr_num_ind_calls",
180a34c753fSRafael Auler                Summary->IndCallDescriptions.size());
181a34c753fSRafael Auler   emitIntValue("__bolt_instr_num_ind_targets",
182a34c753fSRafael Auler                Summary->IndCallTargetDescriptions.size());
183a34c753fSRafael Auler   emitIntValue("__bolt_instr_num_funcs", Summary->FunctionDescriptions.size());
184a34c753fSRafael Auler   emitString("__bolt_instr_filename", opts::InstrumentationFilename);
185a34c753fSRafael Auler   emitString("__bolt_instr_binpath", opts::InstrumentationBinpath);
186a34c753fSRafael Auler   emitIntValue("__bolt_instr_use_pid", !!opts::InstrumentationFileAppendPID, 1);
187a34c753fSRafael Auler 
188a34c753fSRafael Auler   if (BC.isMachO()) {
189a34c753fSRafael Auler     MCSection *TablesSection = BC.Ctx->getMachOSection(
19040c2e0faSMaksim Panchenko         "__BOLT", "__tables", MachO::S_REGULAR, SectionKind::getData());
191a34c753fSRafael Auler     TablesSection->setAlignment(llvm::Align(BC.RegularPageSize));
192adf4142fSFangrui Song     Streamer.switchSection(TablesSection);
193a34c753fSRafael Auler     emitString("__bolt_instr_tables", buildTables(BC));
194a34c753fSRafael Auler   }
195a34c753fSRafael Auler }
196a34c753fSRafael Auler 
197a34c753fSRafael Auler void InstrumentationRuntimeLibrary::link(
19805634f73SJob Noorman     BinaryContext &BC, StringRef ToolPath, BOLTLinker &Linker,
19905634f73SJob Noorman     BOLTLinker::SectionsMapper MapSections) {
200a34c753fSRafael Auler   std::string LibPath = getLibPath(ToolPath, opts::RuntimeInstrumentationLib);
20105634f73SJob Noorman   loadLibrary(LibPath, Linker, MapSections);
202a34c753fSRafael Auler 
203a34c753fSRafael Auler   if (BC.isMachO())
204a34c753fSRafael Auler     return;
205a34c753fSRafael Auler 
20605634f73SJob Noorman   RuntimeFiniAddress = Linker.lookupSymbol("__bolt_instr_fini").value_or(0);
207a34c753fSRafael Auler   if (!RuntimeFiniAddress) {
208a34c753fSRafael Auler     errs() << "BOLT-ERROR: instrumentation library does not define "
209a34c753fSRafael Auler               "__bolt_instr_fini: "
210a34c753fSRafael Auler            << LibPath << "\n";
211a34c753fSRafael Auler     exit(1);
212a34c753fSRafael Auler   }
21305634f73SJob Noorman   RuntimeStartAddress = Linker.lookupSymbol("__bolt_instr_start").value_or(0);
214a34c753fSRafael Auler   if (!RuntimeStartAddress) {
215a34c753fSRafael Auler     errs() << "BOLT-ERROR: instrumentation library does not define "
216a34c753fSRafael Auler               "__bolt_instr_start: "
217a34c753fSRafael Auler            << LibPath << "\n";
218a34c753fSRafael Auler     exit(1);
219a34c753fSRafael Auler   }
220a34c753fSRafael Auler   outs() << "BOLT-INFO: output linked against instrumentation runtime "
221a34c753fSRafael Auler             "library, lib entry point is 0x"
222a34c753fSRafael Auler          << Twine::utohexstr(RuntimeFiniAddress) << "\n";
223a34c753fSRafael Auler   outs() << "BOLT-INFO: clear procedure is 0x"
224a34c753fSRafael Auler          << Twine::utohexstr(
22505634f73SJob Noorman                 Linker.lookupSymbol("__bolt_instr_clear_counters").value_or(0))
226a34c753fSRafael Auler          << "\n";
227a34c753fSRafael Auler 
228a34c753fSRafael Auler   emitTablesAsELFNote(BC);
229a34c753fSRafael Auler }
230a34c753fSRafael Auler 
231a34c753fSRafael Auler std::string InstrumentationRuntimeLibrary::buildTables(BinaryContext &BC) {
232a34c753fSRafael Auler   std::string TablesStr;
233a34c753fSRafael Auler   raw_string_ostream OS(TablesStr);
234a34c753fSRafael Auler 
235a34c753fSRafael Auler   // This is sync'ed with runtime/instr.cpp:readDescriptions()
236a34c753fSRafael Auler   auto getOutputAddress = [](const BinaryFunction &Func,
237a34c753fSRafael Auler                              uint64_t Offset) -> uint64_t {
238a34c753fSRafael Auler     return Offset == 0
239a34c753fSRafael Auler                ? Func.getOutputAddress()
240a34c753fSRafael Auler                : Func.translateInputToOutputAddress(Func.getAddress() + Offset);
241a34c753fSRafael Auler   };
242a34c753fSRafael Auler 
243a34c753fSRafael Auler   // Indirect targets need to be sorted for fast lookup during runtime
244d2c87699SAmir Ayupov   llvm::sort(Summary->IndCallTargetDescriptions,
245a34c753fSRafael Auler              [&](const IndCallTargetDescription &A,
246a34c753fSRafael Auler                  const IndCallTargetDescription &B) {
247a34c753fSRafael Auler                return getOutputAddress(*A.Target, A.ToLoc.Offset) <
248a34c753fSRafael Auler                       getOutputAddress(*B.Target, B.ToLoc.Offset);
249a34c753fSRafael Auler              });
250a34c753fSRafael Auler 
251a34c753fSRafael Auler   // Start of the vector with descriptions (one CounterDescription for each
252a34c753fSRafael Auler   // counter), vector size is Counters.size() CounterDescription-sized elmts
253a34c753fSRafael Auler   const size_t IDSize =
254a34c753fSRafael Auler       Summary->IndCallDescriptions.size() * sizeof(IndCallDescription);
255a34c753fSRafael Auler   OS.write(reinterpret_cast<const char *>(&IDSize), 4);
256a34c753fSRafael Auler   for (const IndCallDescription &Desc : Summary->IndCallDescriptions) {
257a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&Desc.FromLoc.FuncString), 4);
258a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&Desc.FromLoc.Offset), 4);
259a34c753fSRafael Auler   }
260a34c753fSRafael Auler 
261a34c753fSRafael Auler   const size_t ITDSize = Summary->IndCallTargetDescriptions.size() *
262a34c753fSRafael Auler                          sizeof(IndCallTargetDescription);
263a34c753fSRafael Auler   OS.write(reinterpret_cast<const char *>(&ITDSize), 4);
264a34c753fSRafael Auler   for (const IndCallTargetDescription &Desc :
265a34c753fSRafael Auler        Summary->IndCallTargetDescriptions) {
266a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&Desc.ToLoc.FuncString), 4);
267a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&Desc.ToLoc.Offset), 4);
268a34c753fSRafael Auler     uint64_t TargetFuncAddress =
269a34c753fSRafael Auler         getOutputAddress(*Desc.Target, Desc.ToLoc.Offset);
270a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&TargetFuncAddress), 8);
271a34c753fSRafael Auler   }
272a34c753fSRafael Auler 
273a34c753fSRafael Auler   uint32_t FuncDescSize = Summary->getFDSize();
274a34c753fSRafael Auler   OS.write(reinterpret_cast<const char *>(&FuncDescSize), 4);
275a34c753fSRafael Auler   for (const FunctionDescription &Desc : Summary->FunctionDescriptions) {
276a34c753fSRafael Auler     const size_t LeafNum = Desc.LeafNodes.size();
277a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&LeafNum), 4);
278a34c753fSRafael Auler     for (const InstrumentedNode &LeafNode : Desc.LeafNodes) {
279a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&LeafNode.Node), 4);
280a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&LeafNode.Counter), 4);
281a34c753fSRafael Auler     }
282a34c753fSRafael Auler     const size_t EdgesNum = Desc.Edges.size();
283a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&EdgesNum), 4);
284a34c753fSRafael Auler     for (const EdgeDescription &Edge : Desc.Edges) {
285a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Edge.FromLoc.FuncString), 4);
286a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Edge.FromLoc.Offset), 4);
287a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Edge.FromNode), 4);
288a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Edge.ToLoc.FuncString), 4);
289a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Edge.ToLoc.Offset), 4);
290a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Edge.ToNode), 4);
291a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Edge.Counter), 4);
292a34c753fSRafael Auler     }
293a34c753fSRafael Auler     const size_t CallsNum = Desc.Calls.size();
294a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&CallsNum), 4);
295a34c753fSRafael Auler     for (const CallDescription &Call : Desc.Calls) {
296a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Call.FromLoc.FuncString), 4);
297a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Call.FromLoc.Offset), 4);
298a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Call.FromNode), 4);
299a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Call.ToLoc.FuncString), 4);
300a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Call.ToLoc.Offset), 4);
301a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&Call.Counter), 4);
302a34c753fSRafael Auler       uint64_t TargetFuncAddress =
303a34c753fSRafael Auler           getOutputAddress(*Call.Target, Call.ToLoc.Offset);
304a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&TargetFuncAddress), 8);
305a34c753fSRafael Auler     }
306a34c753fSRafael Auler     const size_t EntryNum = Desc.EntryNodes.size();
307a34c753fSRafael Auler     OS.write(reinterpret_cast<const char *>(&EntryNum), 4);
308a34c753fSRafael Auler     for (const EntryNode &EntryNode : Desc.EntryNodes) {
309a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&EntryNode.Node), 8);
310a34c753fSRafael Auler       uint64_t TargetFuncAddress =
311a34c753fSRafael Auler           getOutputAddress(*Desc.Function, EntryNode.Address);
312a34c753fSRafael Auler       OS.write(reinterpret_cast<const char *>(&TargetFuncAddress), 8);
313a34c753fSRafael Auler     }
314a34c753fSRafael Auler   }
315a34c753fSRafael Auler   // Our string table lives immediately after descriptions vector
316a34c753fSRafael Auler   OS << Summary->StringTable;
317a34c753fSRafael Auler 
318a34c753fSRafael Auler   return TablesStr;
319a34c753fSRafael Auler }
320a34c753fSRafael Auler 
321a34c753fSRafael Auler void InstrumentationRuntimeLibrary::emitTablesAsELFNote(BinaryContext &BC) {
322a34c753fSRafael Auler   std::string TablesStr = buildTables(BC);
323a34c753fSRafael Auler   const std::string BoltInfo = BinarySection::encodeELFNote(
324a34c753fSRafael Auler       "BOLT", TablesStr, BinarySection::NT_BOLT_INSTRUMENTATION_TABLES);
325a34c753fSRafael Auler   BC.registerOrUpdateNoteSection(".bolt.instr.tables", copyByteArray(BoltInfo),
326a34c753fSRafael Auler                                  BoltInfo.size(),
327a34c753fSRafael Auler                                  /*Alignment=*/1,
328a34c753fSRafael Auler                                  /*IsReadOnly=*/true, ELF::SHT_NOTE);
329a34c753fSRafael Auler }
330