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