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"
16a34c753fSRafael Auler #include "bolt/Utils/CommandLineOpts.h"
17a34c753fSRafael Auler #include "llvm/ExecutionEngine/RuntimeDyld.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",
29a34c753fSRafael Auler cl::desc("specify file name 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
adjustCommandLineOptions(const BinaryContext & BC) const43a34c753fSRafael 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 }
60a34c753fSRafael Auler if (!BC.FiniFunctionAddress && !BC.IsStaticExecutable) {
61a34c753fSRafael Auler errs() << "BOLT-ERROR: input binary lacks DT_FINI entry in the dynamic "
62a34c753fSRafael Auler "section but instrumentation currently relies on patching "
63a34c753fSRafael Auler "DT_FINI to write the profile\n";
64a34c753fSRafael Auler exit(1);
65a34c753fSRafael Auler }
66a34c753fSRafael Auler }
67a34c753fSRafael Auler
emitBinary(BinaryContext & BC,MCStreamer & Streamer)68a34c753fSRafael Auler void InstrumentationRuntimeLibrary::emitBinary(BinaryContext &BC,
69a34c753fSRafael Auler MCStreamer &Streamer) {
70a34c753fSRafael Auler MCSection *Section = BC.isELF()
71a34c753fSRafael Auler ? static_cast<MCSection *>(BC.Ctx->getELFSection(
72a34c753fSRafael Auler ".bolt.instr.counters", ELF::SHT_PROGBITS,
73a34c753fSRafael Auler BinarySection::getFlags(/*IsReadOnly=*/false,
74a34c753fSRafael Auler /*IsText=*/false,
75a34c753fSRafael Auler /*IsAllocatable=*/true)
76a34c753fSRafael Auler
77a34c753fSRafael Auler ))
78a34c753fSRafael Auler : static_cast<MCSection *>(BC.Ctx->getMachOSection(
79a34c753fSRafael Auler "__BOLT", "__counters", MachO::S_REGULAR,
80a34c753fSRafael Auler SectionKind::getData()));
81a34c753fSRafael Auler
82a34c753fSRafael Auler if (BC.IsStaticExecutable && !opts::InstrumentationSleepTime) {
83a34c753fSRafael Auler errs() << "BOLT-ERROR: instrumentation of static binary currently does not "
84a34c753fSRafael Auler "support profile output on binary finalization, so it "
85a34c753fSRafael Auler "requires -instrumentation-sleep-time=N (N>0) usage\n";
86a34c753fSRafael Auler exit(1);
87a34c753fSRafael Auler }
88a34c753fSRafael Auler
89a34c753fSRafael Auler Section->setAlignment(llvm::Align(BC.RegularPageSize));
90adf4142fSFangrui Song Streamer.switchSection(Section);
91a34c753fSRafael Auler
92a34c753fSRafael Auler // EmitOffset is used to determine padding size for data alignment
93a34c753fSRafael Auler uint64_t EmitOffset = 0;
94a34c753fSRafael Auler
95a34c753fSRafael Auler auto emitLabel = [&Streamer](MCSymbol *Symbol, bool IsGlobal = true) {
96a34c753fSRafael Auler Streamer.emitLabel(Symbol);
97a34c753fSRafael Auler if (IsGlobal)
98a34c753fSRafael Auler Streamer.emitSymbolAttribute(Symbol, MCSymbolAttr::MCSA_Global);
99a34c753fSRafael Auler };
100a34c753fSRafael Auler
101a34c753fSRafael Auler auto emitLabelByName = [&BC, emitLabel](StringRef Name,
102a34c753fSRafael Auler bool IsGlobal = true) {
103a34c753fSRafael Auler MCSymbol *Symbol = BC.Ctx->getOrCreateSymbol(Name);
104a34c753fSRafael Auler emitLabel(Symbol, IsGlobal);
105a34c753fSRafael Auler };
106a34c753fSRafael Auler
107a34c753fSRafael Auler auto emitPadding = [&Streamer, &EmitOffset](unsigned Size) {
108a34c753fSRafael Auler const uint64_t Padding = alignTo(EmitOffset, Size) - EmitOffset;
109a34c753fSRafael Auler if (Padding) {
110a34c753fSRafael Auler Streamer.emitFill(Padding, 0);
111a34c753fSRafael Auler EmitOffset += Padding;
112a34c753fSRafael Auler }
113a34c753fSRafael Auler };
114a34c753fSRafael Auler
115a34c753fSRafael Auler auto emitDataSize = [&EmitOffset](unsigned Size) { EmitOffset += Size; };
116a34c753fSRafael Auler
117a34c753fSRafael Auler auto emitDataPadding = [emitPadding, emitDataSize](unsigned Size) {
118a34c753fSRafael Auler emitPadding(Size);
119a34c753fSRafael Auler emitDataSize(Size);
120a34c753fSRafael Auler };
121a34c753fSRafael Auler
122a34c753fSRafael Auler auto emitFill = [&Streamer, emitDataSize,
123a34c753fSRafael Auler emitLabel](unsigned Size, MCSymbol *Symbol = nullptr,
124a34c753fSRafael Auler uint8_t Byte = 0) {
125a34c753fSRafael Auler emitDataSize(Size);
126a34c753fSRafael Auler if (Symbol)
127a34c753fSRafael Auler emitLabel(Symbol, /*IsGlobal*/ false);
128a34c753fSRafael Auler Streamer.emitFill(Size, Byte);
129a34c753fSRafael Auler };
130a34c753fSRafael Auler
131a34c753fSRafael Auler auto emitValue = [&BC, &Streamer, emitDataPadding,
132a34c753fSRafael Auler emitLabel](MCSymbol *Symbol, const MCExpr *Value) {
133a34c753fSRafael Auler const unsigned Psize = BC.AsmInfo->getCodePointerSize();
134a34c753fSRafael Auler emitDataPadding(Psize);
135a34c753fSRafael Auler emitLabel(Symbol);
136a34c753fSRafael Auler if (Value)
137a34c753fSRafael Auler Streamer.emitValue(Value, Psize);
138a34c753fSRafael Auler else
139a34c753fSRafael Auler Streamer.emitFill(Psize, 0);
140a34c753fSRafael Auler };
141a34c753fSRafael Auler
142a34c753fSRafael Auler auto emitIntValue = [&Streamer, emitDataPadding, emitLabelByName](
143a34c753fSRafael Auler StringRef Name, uint64_t Value, unsigned Size = 4) {
144a34c753fSRafael Auler emitDataPadding(Size);
145a34c753fSRafael Auler emitLabelByName(Name);
146a34c753fSRafael Auler Streamer.emitIntValue(Value, Size);
147a34c753fSRafael Auler };
148a34c753fSRafael Auler
149a34c753fSRafael Auler auto emitString = [&Streamer, emitDataSize, emitLabelByName,
150a34c753fSRafael Auler emitFill](StringRef Name, StringRef Contents) {
151a34c753fSRafael Auler emitDataSize(Contents.size());
152a34c753fSRafael Auler emitLabelByName(Name);
153a34c753fSRafael Auler Streamer.emitBytes(Contents);
154a34c753fSRafael Auler emitFill(1);
155a34c753fSRafael Auler };
156a34c753fSRafael Auler
157a34c753fSRafael Auler // All of the following symbols will be exported as globals to be used by the
158a34c753fSRafael Auler // instrumentation runtime library to dump the instrumentation data to disk.
159a34c753fSRafael Auler // Label marking start of the memory region containing instrumentation
160a34c753fSRafael Auler // counters, total vector size is Counters.size() 8-byte counters
161a34c753fSRafael Auler emitLabelByName("__bolt_instr_locations");
162a34c753fSRafael Auler for (MCSymbol *const &Label : Summary->Counters)
163a34c753fSRafael Auler emitFill(sizeof(uint64_t), Label);
164a34c753fSRafael Auler
165a34c753fSRafael Auler emitPadding(BC.RegularPageSize);
166a34c753fSRafael Auler emitIntValue("__bolt_instr_sleep_time", opts::InstrumentationSleepTime);
167a34c753fSRafael Auler emitIntValue("__bolt_instr_no_counters_clear",
168a34c753fSRafael Auler !!opts::InstrumentationNoCountersClear, 1);
169a34c753fSRafael Auler emitIntValue("__bolt_instr_conservative", !!opts::ConservativeInstrumentation,
170a34c753fSRafael Auler 1);
171a34c753fSRafael Auler emitIntValue("__bolt_instr_wait_forks", !!opts::InstrumentationWaitForks, 1);
172a34c753fSRafael Auler emitIntValue("__bolt_num_counters", Summary->Counters.size());
173a34c753fSRafael Auler emitValue(Summary->IndCallCounterFuncPtr, nullptr);
174a34c753fSRafael Auler emitValue(Summary->IndTailCallCounterFuncPtr, nullptr);
175a34c753fSRafael Auler emitIntValue("__bolt_instr_num_ind_calls",
176a34c753fSRafael Auler Summary->IndCallDescriptions.size());
177a34c753fSRafael Auler emitIntValue("__bolt_instr_num_ind_targets",
178a34c753fSRafael Auler Summary->IndCallTargetDescriptions.size());
179a34c753fSRafael Auler emitIntValue("__bolt_instr_num_funcs", Summary->FunctionDescriptions.size());
180a34c753fSRafael Auler emitString("__bolt_instr_filename", opts::InstrumentationFilename);
181a34c753fSRafael Auler emitString("__bolt_instr_binpath", opts::InstrumentationBinpath);
182a34c753fSRafael Auler emitIntValue("__bolt_instr_use_pid", !!opts::InstrumentationFileAppendPID, 1);
183a34c753fSRafael Auler
184a34c753fSRafael Auler if (BC.isMachO()) {
185a34c753fSRafael Auler MCSection *TablesSection = BC.Ctx->getMachOSection(
18640c2e0faSMaksim Panchenko "__BOLT", "__tables", MachO::S_REGULAR, SectionKind::getData());
187a34c753fSRafael Auler TablesSection->setAlignment(llvm::Align(BC.RegularPageSize));
188adf4142fSFangrui Song Streamer.switchSection(TablesSection);
189a34c753fSRafael Auler emitString("__bolt_instr_tables", buildTables(BC));
190a34c753fSRafael Auler }
191a34c753fSRafael Auler }
192a34c753fSRafael Auler
link(BinaryContext & BC,StringRef ToolPath,RuntimeDyld & RTDyld,std::function<void (RuntimeDyld &)> OnLoad)193a34c753fSRafael Auler void InstrumentationRuntimeLibrary::link(
194a34c753fSRafael Auler BinaryContext &BC, StringRef ToolPath, RuntimeDyld &RTDyld,
195a34c753fSRafael Auler std::function<void(RuntimeDyld &)> OnLoad) {
196a34c753fSRafael Auler std::string LibPath = getLibPath(ToolPath, opts::RuntimeInstrumentationLib);
197a34c753fSRafael Auler loadLibrary(LibPath, RTDyld);
198a34c753fSRafael Auler OnLoad(RTDyld);
199a34c753fSRafael Auler RTDyld.finalizeWithMemoryManagerLocking();
200a34c753fSRafael Auler if (RTDyld.hasError()) {
201a34c753fSRafael Auler outs() << "BOLT-ERROR: RTDyld failed: " << RTDyld.getErrorString() << "\n";
202a34c753fSRafael Auler exit(1);
203a34c753fSRafael Auler }
204a34c753fSRafael Auler
205a34c753fSRafael Auler if (BC.isMachO())
206a34c753fSRafael Auler return;
207a34c753fSRafael Auler
208a34c753fSRafael Auler RuntimeFiniAddress = RTDyld.getSymbol("__bolt_instr_fini").getAddress();
209a34c753fSRafael Auler if (!RuntimeFiniAddress) {
210a34c753fSRafael Auler errs() << "BOLT-ERROR: instrumentation library does not define "
211a34c753fSRafael Auler "__bolt_instr_fini: "
212a34c753fSRafael Auler << LibPath << "\n";
213a34c753fSRafael Auler exit(1);
214a34c753fSRafael Auler }
215a34c753fSRafael Auler RuntimeStartAddress = RTDyld.getSymbol("__bolt_instr_start").getAddress();
216a34c753fSRafael Auler if (!RuntimeStartAddress) {
217a34c753fSRafael Auler errs() << "BOLT-ERROR: instrumentation library does not define "
218a34c753fSRafael Auler "__bolt_instr_start: "
219a34c753fSRafael Auler << LibPath << "\n";
220a34c753fSRafael Auler exit(1);
221a34c753fSRafael Auler }
222a34c753fSRafael Auler outs() << "BOLT-INFO: output linked against instrumentation runtime "
223a34c753fSRafael Auler "library, lib entry point is 0x"
224a34c753fSRafael Auler << Twine::utohexstr(RuntimeFiniAddress) << "\n";
225a34c753fSRafael Auler outs() << "BOLT-INFO: clear procedure is 0x"
226a34c753fSRafael Auler << Twine::utohexstr(
227a34c753fSRafael Auler RTDyld.getSymbol("__bolt_instr_clear_counters").getAddress())
228a34c753fSRafael Auler << "\n";
229a34c753fSRafael Auler
230a34c753fSRafael Auler emitTablesAsELFNote(BC);
231a34c753fSRafael Auler }
232a34c753fSRafael Auler
buildTables(BinaryContext & BC)233a34c753fSRafael Auler std::string InstrumentationRuntimeLibrary::buildTables(BinaryContext &BC) {
234a34c753fSRafael Auler std::string TablesStr;
235a34c753fSRafael Auler raw_string_ostream OS(TablesStr);
236a34c753fSRafael Auler
237a34c753fSRafael Auler // This is sync'ed with runtime/instr.cpp:readDescriptions()
238a34c753fSRafael Auler auto getOutputAddress = [](const BinaryFunction &Func,
239a34c753fSRafael Auler uint64_t Offset) -> uint64_t {
240a34c753fSRafael Auler return Offset == 0
241a34c753fSRafael Auler ? Func.getOutputAddress()
242a34c753fSRafael Auler : Func.translateInputToOutputAddress(Func.getAddress() + Offset);
243a34c753fSRafael Auler };
244a34c753fSRafael Auler
245a34c753fSRafael Auler // Indirect targets need to be sorted for fast lookup during runtime
246*d2c87699SAmir Ayupov llvm::sort(Summary->IndCallTargetDescriptions,
247a34c753fSRafael Auler [&](const IndCallTargetDescription &A,
248a34c753fSRafael Auler const IndCallTargetDescription &B) {
249a34c753fSRafael Auler return getOutputAddress(*A.Target, A.ToLoc.Offset) <
250a34c753fSRafael Auler getOutputAddress(*B.Target, B.ToLoc.Offset);
251a34c753fSRafael Auler });
252a34c753fSRafael Auler
253a34c753fSRafael Auler // Start of the vector with descriptions (one CounterDescription for each
254a34c753fSRafael Auler // counter), vector size is Counters.size() CounterDescription-sized elmts
255a34c753fSRafael Auler const size_t IDSize =
256a34c753fSRafael Auler Summary->IndCallDescriptions.size() * sizeof(IndCallDescription);
257a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&IDSize), 4);
258a34c753fSRafael Auler for (const IndCallDescription &Desc : Summary->IndCallDescriptions) {
259a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Desc.FromLoc.FuncString), 4);
260a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Desc.FromLoc.Offset), 4);
261a34c753fSRafael Auler }
262a34c753fSRafael Auler
263a34c753fSRafael Auler const size_t ITDSize = Summary->IndCallTargetDescriptions.size() *
264a34c753fSRafael Auler sizeof(IndCallTargetDescription);
265a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&ITDSize), 4);
266a34c753fSRafael Auler for (const IndCallTargetDescription &Desc :
267a34c753fSRafael Auler Summary->IndCallTargetDescriptions) {
268a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Desc.ToLoc.FuncString), 4);
269a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Desc.ToLoc.Offset), 4);
270a34c753fSRafael Auler uint64_t TargetFuncAddress =
271a34c753fSRafael Auler getOutputAddress(*Desc.Target, Desc.ToLoc.Offset);
272a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&TargetFuncAddress), 8);
273a34c753fSRafael Auler }
274a34c753fSRafael Auler
275a34c753fSRafael Auler uint32_t FuncDescSize = Summary->getFDSize();
276a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&FuncDescSize), 4);
277a34c753fSRafael Auler for (const FunctionDescription &Desc : Summary->FunctionDescriptions) {
278a34c753fSRafael Auler const size_t LeafNum = Desc.LeafNodes.size();
279a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&LeafNum), 4);
280a34c753fSRafael Auler for (const InstrumentedNode &LeafNode : Desc.LeafNodes) {
281a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&LeafNode.Node), 4);
282a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&LeafNode.Counter), 4);
283a34c753fSRafael Auler }
284a34c753fSRafael Auler const size_t EdgesNum = Desc.Edges.size();
285a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&EdgesNum), 4);
286a34c753fSRafael Auler for (const EdgeDescription &Edge : Desc.Edges) {
287a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Edge.FromLoc.FuncString), 4);
288a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Edge.FromLoc.Offset), 4);
289a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Edge.FromNode), 4);
290a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Edge.ToLoc.FuncString), 4);
291a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Edge.ToLoc.Offset), 4);
292a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Edge.ToNode), 4);
293a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Edge.Counter), 4);
294a34c753fSRafael Auler }
295a34c753fSRafael Auler const size_t CallsNum = Desc.Calls.size();
296a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&CallsNum), 4);
297a34c753fSRafael Auler for (const CallDescription &Call : Desc.Calls) {
298a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Call.FromLoc.FuncString), 4);
299a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Call.FromLoc.Offset), 4);
300a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Call.FromNode), 4);
301a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Call.ToLoc.FuncString), 4);
302a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Call.ToLoc.Offset), 4);
303a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Call.Counter), 4);
304a34c753fSRafael Auler uint64_t TargetFuncAddress =
305a34c753fSRafael Auler getOutputAddress(*Call.Target, Call.ToLoc.Offset);
306a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&TargetFuncAddress), 8);
307a34c753fSRafael Auler }
308a34c753fSRafael Auler const size_t EntryNum = Desc.EntryNodes.size();
309a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&EntryNum), 4);
310a34c753fSRafael Auler for (const EntryNode &EntryNode : Desc.EntryNodes) {
311a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&EntryNode.Node), 8);
312a34c753fSRafael Auler uint64_t TargetFuncAddress =
313a34c753fSRafael Auler getOutputAddress(*Desc.Function, EntryNode.Address);
314a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&TargetFuncAddress), 8);
315a34c753fSRafael Auler }
316a34c753fSRafael Auler }
317a34c753fSRafael Auler // Our string table lives immediately after descriptions vector
318a34c753fSRafael Auler OS << Summary->StringTable;
319a34c753fSRafael Auler OS.flush();
320a34c753fSRafael Auler
321a34c753fSRafael Auler return TablesStr;
322a34c753fSRafael Auler }
323a34c753fSRafael Auler
emitTablesAsELFNote(BinaryContext & BC)324a34c753fSRafael Auler void InstrumentationRuntimeLibrary::emitTablesAsELFNote(BinaryContext &BC) {
325a34c753fSRafael Auler std::string TablesStr = buildTables(BC);
326a34c753fSRafael Auler const std::string BoltInfo = BinarySection::encodeELFNote(
327a34c753fSRafael Auler "BOLT", TablesStr, BinarySection::NT_BOLT_INSTRUMENTATION_TABLES);
328a34c753fSRafael Auler BC.registerOrUpdateNoteSection(".bolt.instr.tables", copyByteArray(BoltInfo),
329a34c753fSRafael Auler BoltInfo.size(),
330a34c753fSRafael Auler /*Alignment=*/1,
331a34c753fSRafael Auler /*IsReadOnly=*/true, ELF::SHT_NOTE);
332a34c753fSRafael Auler }
333