xref: /llvm-project/llvm/lib/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.cpp (revision 2ccf7ed277df28651b94bbee9fccefdf22fb074f)
17ddf7d87SPrem Chintalapudi //===----- PerfSupportPlugin.cpp --- Utils for perf support -----*- C++ -*-===//
27ddf7d87SPrem Chintalapudi //
37ddf7d87SPrem Chintalapudi // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47ddf7d87SPrem Chintalapudi // See https://llvm.org/LICENSE.txt for license information.
57ddf7d87SPrem Chintalapudi // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67ddf7d87SPrem Chintalapudi //
77ddf7d87SPrem Chintalapudi //===----------------------------------------------------------------------===//
87ddf7d87SPrem Chintalapudi //
97ddf7d87SPrem Chintalapudi // Handles support for registering code with perf
107ddf7d87SPrem Chintalapudi //
117ddf7d87SPrem Chintalapudi //===----------------------------------------------------------------------===//
127ddf7d87SPrem Chintalapudi 
137ddf7d87SPrem Chintalapudi #include "llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h"
147ddf7d87SPrem Chintalapudi 
157ddf7d87SPrem Chintalapudi #include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
167ddf7d87SPrem Chintalapudi #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
177ddf7d87SPrem Chintalapudi #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
187ddf7d87SPrem Chintalapudi 
197ddf7d87SPrem Chintalapudi #define DEBUG_TYPE "orc"
207ddf7d87SPrem Chintalapudi 
217ddf7d87SPrem Chintalapudi using namespace llvm;
227ddf7d87SPrem Chintalapudi using namespace llvm::orc;
237ddf7d87SPrem Chintalapudi using namespace llvm::jitlink;
247ddf7d87SPrem Chintalapudi 
257ddf7d87SPrem Chintalapudi namespace {
267ddf7d87SPrem Chintalapudi 
277ddf7d87SPrem Chintalapudi // Creates an EH frame header prepared for a 32-bit relative relocation
287ddf7d87SPrem Chintalapudi // to the start of the .eh_frame section. Absolute injects a 64-bit absolute
297ddf7d87SPrem Chintalapudi // address space offset 4 bytes from the start instead of 4 bytes
307ddf7d87SPrem Chintalapudi Expected<std::string> createX64EHFrameHeader(Section &EHFrame,
31a9d50568SKazu Hirata                                              llvm::endianness endianness,
327ddf7d87SPrem Chintalapudi                                              bool absolute) {
337ddf7d87SPrem Chintalapudi   uint8_t Version = 1;
347ddf7d87SPrem Chintalapudi   uint8_t EhFramePtrEnc = 0;
357ddf7d87SPrem Chintalapudi   if (absolute) {
367ddf7d87SPrem Chintalapudi     EhFramePtrEnc |= dwarf::DW_EH_PE_sdata8 | dwarf::DW_EH_PE_absptr;
377ddf7d87SPrem Chintalapudi   } else {
387ddf7d87SPrem Chintalapudi     EhFramePtrEnc |= dwarf::DW_EH_PE_sdata4 | dwarf::DW_EH_PE_datarel;
397ddf7d87SPrem Chintalapudi   }
407ddf7d87SPrem Chintalapudi   uint8_t FDECountEnc = dwarf::DW_EH_PE_omit;
417ddf7d87SPrem Chintalapudi   uint8_t TableEnc = dwarf::DW_EH_PE_omit;
427ddf7d87SPrem Chintalapudi   // X86_64_64 relocation to the start of the .eh_frame section
437ddf7d87SPrem Chintalapudi   uint32_t EHFrameRelocation = 0;
447ddf7d87SPrem Chintalapudi   // uint32_t FDECount = 0;
457ddf7d87SPrem Chintalapudi   // Skip the FDE binary search table
467ddf7d87SPrem Chintalapudi   // We'd have to reprocess the CIEs to get this information,
477ddf7d87SPrem Chintalapudi   // which seems like more trouble than it's worth
487ddf7d87SPrem Chintalapudi   // TODO consider implementing this.
497ddf7d87SPrem Chintalapudi   // binary search table goes here
507ddf7d87SPrem Chintalapudi 
517ddf7d87SPrem Chintalapudi   size_t HeaderSize =
527ddf7d87SPrem Chintalapudi       (sizeof(Version) + sizeof(EhFramePtrEnc) + sizeof(FDECountEnc) +
537ddf7d87SPrem Chintalapudi        sizeof(TableEnc) +
547ddf7d87SPrem Chintalapudi        (absolute ? sizeof(uint64_t) : sizeof(EHFrameRelocation)));
557ddf7d87SPrem Chintalapudi   std::string HeaderContent(HeaderSize, '\0');
567ddf7d87SPrem Chintalapudi   BinaryStreamWriter Writer(
577ddf7d87SPrem Chintalapudi       MutableArrayRef<uint8_t>(
587ddf7d87SPrem Chintalapudi           reinterpret_cast<uint8_t *>(HeaderContent.data()), HeaderSize),
597ddf7d87SPrem Chintalapudi       endianness);
607ddf7d87SPrem Chintalapudi   if (auto Err = Writer.writeInteger(Version))
617ddf7d87SPrem Chintalapudi     return std::move(Err);
627ddf7d87SPrem Chintalapudi   if (auto Err = Writer.writeInteger(EhFramePtrEnc))
637ddf7d87SPrem Chintalapudi     return std::move(Err);
647ddf7d87SPrem Chintalapudi   if (auto Err = Writer.writeInteger(FDECountEnc))
657ddf7d87SPrem Chintalapudi     return std::move(Err);
667ddf7d87SPrem Chintalapudi   if (auto Err = Writer.writeInteger(TableEnc))
677ddf7d87SPrem Chintalapudi     return std::move(Err);
687ddf7d87SPrem Chintalapudi   if (absolute) {
697ddf7d87SPrem Chintalapudi     uint64_t EHFrameAddr = SectionRange(EHFrame).getStart().getValue();
707ddf7d87SPrem Chintalapudi     if (auto Err = Writer.writeInteger(EHFrameAddr))
717ddf7d87SPrem Chintalapudi       return std::move(Err);
727ddf7d87SPrem Chintalapudi   } else {
737ddf7d87SPrem Chintalapudi     if (auto Err = Writer.writeInteger(EHFrameRelocation))
747ddf7d87SPrem Chintalapudi       return std::move(Err);
757ddf7d87SPrem Chintalapudi   }
767ddf7d87SPrem Chintalapudi   return HeaderContent;
777ddf7d87SPrem Chintalapudi }
787ddf7d87SPrem Chintalapudi 
797ddf7d87SPrem Chintalapudi constexpr StringRef RegisterPerfStartSymbolName =
807ddf7d87SPrem Chintalapudi     "llvm_orc_registerJITLoaderPerfStart";
817ddf7d87SPrem Chintalapudi constexpr StringRef RegisterPerfEndSymbolName =
827ddf7d87SPrem Chintalapudi     "llvm_orc_registerJITLoaderPerfEnd";
837ddf7d87SPrem Chintalapudi constexpr StringRef RegisterPerfImplSymbolName =
847ddf7d87SPrem Chintalapudi     "llvm_orc_registerJITLoaderPerfImpl";
857ddf7d87SPrem Chintalapudi 
867ddf7d87SPrem Chintalapudi static PerfJITCodeLoadRecord
877ddf7d87SPrem Chintalapudi getCodeLoadRecord(const Symbol &Sym, std::atomic<uint64_t> &CodeIndex) {
887ddf7d87SPrem Chintalapudi   PerfJITCodeLoadRecord Record;
89*2ccf7ed2SJared Wyles   auto Name = *Sym.getName();
907ddf7d87SPrem Chintalapudi   auto Addr = Sym.getAddress();
917ddf7d87SPrem Chintalapudi   auto Size = Sym.getSize();
927ddf7d87SPrem Chintalapudi   Record.Prefix.Id = PerfJITRecordType::JIT_CODE_LOAD;
937ddf7d87SPrem Chintalapudi   // Runtime sets PID
947ddf7d87SPrem Chintalapudi   Record.Pid = 0;
957ddf7d87SPrem Chintalapudi   // Runtime sets TID
967ddf7d87SPrem Chintalapudi   Record.Tid = 0;
977ddf7d87SPrem Chintalapudi   Record.Vma = Addr.getValue();
987ddf7d87SPrem Chintalapudi   Record.CodeAddr = Addr.getValue();
997ddf7d87SPrem Chintalapudi   Record.CodeSize = Size;
1007ddf7d87SPrem Chintalapudi   Record.CodeIndex = CodeIndex++;
1017ddf7d87SPrem Chintalapudi   Record.Name = Name.str();
1027ddf7d87SPrem Chintalapudi   // Initialize last, once all the other fields are filled
1037ddf7d87SPrem Chintalapudi   Record.Prefix.TotalSize =
1047ddf7d87SPrem Chintalapudi       (2 * sizeof(uint32_t)   // id, total_size
1057ddf7d87SPrem Chintalapudi        + sizeof(uint64_t)     // timestamp
1067ddf7d87SPrem Chintalapudi        + 2 * sizeof(uint32_t) // pid, tid
1077ddf7d87SPrem Chintalapudi        + 4 * sizeof(uint64_t) // vma, code_addr, code_size, code_index
1087ddf7d87SPrem Chintalapudi        + Name.size() + 1      // symbol name
1097ddf7d87SPrem Chintalapudi        + Record.CodeSize      // code
1107ddf7d87SPrem Chintalapudi       );
1117ddf7d87SPrem Chintalapudi   return Record;
1127ddf7d87SPrem Chintalapudi }
1137ddf7d87SPrem Chintalapudi 
1147ddf7d87SPrem Chintalapudi static std::optional<PerfJITDebugInfoRecord>
1157ddf7d87SPrem Chintalapudi getDebugInfoRecord(const Symbol &Sym, DWARFContext &DC) {
1167ddf7d87SPrem Chintalapudi   auto &Section = Sym.getBlock().getSection();
1177ddf7d87SPrem Chintalapudi   auto Addr = Sym.getAddress();
1187ddf7d87SPrem Chintalapudi   auto Size = Sym.getSize();
1197ddf7d87SPrem Chintalapudi   auto SAddr = object::SectionedAddress{Addr.getValue(), Section.getOrdinal()};
1207ddf7d87SPrem Chintalapudi   LLVM_DEBUG(dbgs() << "Getting debug info for symbol " << Sym.getName()
1217ddf7d87SPrem Chintalapudi                     << " at address " << Addr.getValue() << " with size "
1227ddf7d87SPrem Chintalapudi                     << Size << "\n"
1237ddf7d87SPrem Chintalapudi                     << "Section ordinal: " << Section.getOrdinal() << "\n");
1247ddf7d87SPrem Chintalapudi   auto LInfo = DC.getLineInfoForAddressRange(
1257ddf7d87SPrem Chintalapudi       SAddr, Size, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
1267ddf7d87SPrem Chintalapudi   if (LInfo.empty()) {
1277ddf7d87SPrem Chintalapudi     // No line info available
1287ddf7d87SPrem Chintalapudi     LLVM_DEBUG(dbgs() << "No line info available\n");
1297ddf7d87SPrem Chintalapudi     return std::nullopt;
1307ddf7d87SPrem Chintalapudi   }
1317ddf7d87SPrem Chintalapudi   PerfJITDebugInfoRecord Record;
1327ddf7d87SPrem Chintalapudi   Record.Prefix.Id = PerfJITRecordType::JIT_CODE_DEBUG_INFO;
1337ddf7d87SPrem Chintalapudi   Record.CodeAddr = Addr.getValue();
1347ddf7d87SPrem Chintalapudi   for (const auto &Entry : LInfo) {
1357ddf7d87SPrem Chintalapudi     auto Addr = Entry.first;
1367ddf7d87SPrem Chintalapudi     // The function re-created by perf is preceded by a elf
1377ddf7d87SPrem Chintalapudi     // header. Need to adjust for that, otherwise the results are
1387ddf7d87SPrem Chintalapudi     // wrong.
1397ddf7d87SPrem Chintalapudi     Addr += 0x40;
1407ddf7d87SPrem Chintalapudi     Record.Entries.push_back({Addr, Entry.second.Line,
1417ddf7d87SPrem Chintalapudi                               Entry.second.Discriminator,
1427ddf7d87SPrem Chintalapudi                               Entry.second.FileName});
1437ddf7d87SPrem Chintalapudi   }
1447ddf7d87SPrem Chintalapudi   size_t EntriesBytes = (2   // record header
1457ddf7d87SPrem Chintalapudi                          + 2 // record fields
1467ddf7d87SPrem Chintalapudi                          ) *
1477ddf7d87SPrem Chintalapudi                         sizeof(uint64_t);
1487ddf7d87SPrem Chintalapudi   for (const auto &Entry : Record.Entries) {
1497ddf7d87SPrem Chintalapudi     EntriesBytes +=
1507ddf7d87SPrem Chintalapudi         sizeof(uint64_t) + 2 * sizeof(uint32_t); // Addr, Line/Discrim
1517ddf7d87SPrem Chintalapudi     EntriesBytes += Entry.Name.size() + 1;       // Name
1527ddf7d87SPrem Chintalapudi   }
1537ddf7d87SPrem Chintalapudi   Record.Prefix.TotalSize = EntriesBytes;
1547ddf7d87SPrem Chintalapudi   LLVM_DEBUG(dbgs() << "Created debug info record\n"
1557ddf7d87SPrem Chintalapudi                     << "Total size: " << Record.Prefix.TotalSize << "\n"
1567ddf7d87SPrem Chintalapudi                     << "Nr entries: " << Record.Entries.size() << "\n");
1577ddf7d87SPrem Chintalapudi   return Record;
1587ddf7d87SPrem Chintalapudi }
1597ddf7d87SPrem Chintalapudi 
1607ddf7d87SPrem Chintalapudi static Expected<PerfJITCodeUnwindingInfoRecord>
1617ddf7d87SPrem Chintalapudi getUnwindingRecord(LinkGraph &G) {
1627ddf7d87SPrem Chintalapudi   PerfJITCodeUnwindingInfoRecord Record;
1637ddf7d87SPrem Chintalapudi   Record.Prefix.Id = PerfJITRecordType::JIT_CODE_UNWINDING_INFO;
1647ddf7d87SPrem Chintalapudi   Record.Prefix.TotalSize = 0;
1657ddf7d87SPrem Chintalapudi   auto Eh_frame = G.findSectionByName(".eh_frame");
1667ddf7d87SPrem Chintalapudi   if (!Eh_frame) {
1677ddf7d87SPrem Chintalapudi     LLVM_DEBUG(dbgs() << "No .eh_frame section found\n");
1687ddf7d87SPrem Chintalapudi     return Record;
1697ddf7d87SPrem Chintalapudi   }
1707ddf7d87SPrem Chintalapudi   if (!G.getTargetTriple().isOSBinFormatELF()) {
1717ddf7d87SPrem Chintalapudi     LLVM_DEBUG(dbgs() << "Not an ELF file, will not emit unwinding info\n");
1727ddf7d87SPrem Chintalapudi     return Record;
1737ddf7d87SPrem Chintalapudi   }
1747ddf7d87SPrem Chintalapudi   auto SR = SectionRange(*Eh_frame);
1757ddf7d87SPrem Chintalapudi   auto EHFrameSize = SR.getSize();
1767ddf7d87SPrem Chintalapudi   auto Eh_frame_hdr = G.findSectionByName(".eh_frame_hdr");
1777ddf7d87SPrem Chintalapudi   if (!Eh_frame_hdr) {
1787ddf7d87SPrem Chintalapudi     if (G.getTargetTriple().getArch() == Triple::x86_64) {
1797ddf7d87SPrem Chintalapudi       auto Hdr = createX64EHFrameHeader(*Eh_frame, G.getEndianness(), true);
1807ddf7d87SPrem Chintalapudi       if (!Hdr)
1817ddf7d87SPrem Chintalapudi         return Hdr.takeError();
1827ddf7d87SPrem Chintalapudi       Record.EHFrameHdr = std::move(*Hdr);
1837ddf7d87SPrem Chintalapudi     } else {
1847ddf7d87SPrem Chintalapudi       LLVM_DEBUG(dbgs() << "No .eh_frame_hdr section found\n");
1857ddf7d87SPrem Chintalapudi       return Record;
1867ddf7d87SPrem Chintalapudi     }
1877ddf7d87SPrem Chintalapudi     Record.EHFrameHdrAddr = 0;
1887ddf7d87SPrem Chintalapudi     Record.EHFrameHdrSize = Record.EHFrameHdr.size();
1897ddf7d87SPrem Chintalapudi     Record.UnwindDataSize = EHFrameSize + Record.EHFrameHdrSize;
1907ddf7d87SPrem Chintalapudi     Record.MappedSize = 0; // Because the EHFrame header was not mapped
1917ddf7d87SPrem Chintalapudi   } else {
1927ddf7d87SPrem Chintalapudi     auto SR = SectionRange(*Eh_frame_hdr);
1937ddf7d87SPrem Chintalapudi     Record.EHFrameHdrAddr = SR.getStart().getValue();
1947ddf7d87SPrem Chintalapudi     Record.EHFrameHdrSize = SR.getSize();
1957ddf7d87SPrem Chintalapudi     Record.UnwindDataSize = EHFrameSize + Record.EHFrameHdrSize;
1967ddf7d87SPrem Chintalapudi     Record.MappedSize = Record.UnwindDataSize;
1977ddf7d87SPrem Chintalapudi   }
1987ddf7d87SPrem Chintalapudi   Record.EHFrameAddr = SR.getStart().getValue();
1997ddf7d87SPrem Chintalapudi   Record.Prefix.TotalSize =
2007ddf7d87SPrem Chintalapudi       (2 * sizeof(uint32_t) // id, total_size
2017ddf7d87SPrem Chintalapudi        + sizeof(uint64_t)   // timestamp
2027ddf7d87SPrem Chintalapudi        +
2037ddf7d87SPrem Chintalapudi        3 * sizeof(uint64_t) // unwind_data_size, eh_frame_hdr_size, mapped_size
2047ddf7d87SPrem Chintalapudi        + Record.UnwindDataSize // eh_frame_hdr, eh_frame
2057ddf7d87SPrem Chintalapudi       );
2067ddf7d87SPrem Chintalapudi   LLVM_DEBUG(dbgs() << "Created unwind record\n"
2077ddf7d87SPrem Chintalapudi                     << "Total size: " << Record.Prefix.TotalSize << "\n"
2087ddf7d87SPrem Chintalapudi                     << "Unwind size: " << Record.UnwindDataSize << "\n"
2097ddf7d87SPrem Chintalapudi                     << "EHFrame size: " << EHFrameSize << "\n"
2107ddf7d87SPrem Chintalapudi                     << "EHFrameHdr size: " << Record.EHFrameHdrSize << "\n");
2117ddf7d87SPrem Chintalapudi   return Record;
2127ddf7d87SPrem Chintalapudi }
2137ddf7d87SPrem Chintalapudi 
2147ddf7d87SPrem Chintalapudi static PerfJITRecordBatch getRecords(ExecutionSession &ES, LinkGraph &G,
2157ddf7d87SPrem Chintalapudi                                      std::atomic<uint64_t> &CodeIndex,
2167ddf7d87SPrem Chintalapudi                                      bool EmitDebugInfo, bool EmitUnwindInfo) {
2177ddf7d87SPrem Chintalapudi   std::unique_ptr<DWARFContext> DC;
2187ddf7d87SPrem Chintalapudi   StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
2197ddf7d87SPrem Chintalapudi   if (EmitDebugInfo) {
2207ddf7d87SPrem Chintalapudi     auto EDC = createDWARFContext(G);
2217ddf7d87SPrem Chintalapudi     if (!EDC) {
2227ddf7d87SPrem Chintalapudi       ES.reportError(EDC.takeError());
2237ddf7d87SPrem Chintalapudi       EmitDebugInfo = false;
2247ddf7d87SPrem Chintalapudi     } else {
2257ddf7d87SPrem Chintalapudi       DC = std::move(EDC->first);
2267ddf7d87SPrem Chintalapudi       DCBacking = std::move(EDC->second);
2277ddf7d87SPrem Chintalapudi     }
2287ddf7d87SPrem Chintalapudi   }
2297ddf7d87SPrem Chintalapudi   PerfJITRecordBatch Batch;
2307ddf7d87SPrem Chintalapudi   for (auto Sym : G.defined_symbols()) {
2317ddf7d87SPrem Chintalapudi     if (!Sym->hasName() || !Sym->isCallable())
2327ddf7d87SPrem Chintalapudi       continue;
2337ddf7d87SPrem Chintalapudi     if (EmitDebugInfo) {
2347ddf7d87SPrem Chintalapudi       auto DebugInfo = getDebugInfoRecord(*Sym, *DC);
2357ddf7d87SPrem Chintalapudi       if (DebugInfo)
2367ddf7d87SPrem Chintalapudi         Batch.DebugInfoRecords.push_back(std::move(*DebugInfo));
2377ddf7d87SPrem Chintalapudi     }
2387ddf7d87SPrem Chintalapudi     Batch.CodeLoadRecords.push_back(getCodeLoadRecord(*Sym, CodeIndex));
2397ddf7d87SPrem Chintalapudi   }
2407ddf7d87SPrem Chintalapudi   if (EmitUnwindInfo) {
2417ddf7d87SPrem Chintalapudi     auto UWR = getUnwindingRecord(G);
2427ddf7d87SPrem Chintalapudi     if (!UWR) {
2437ddf7d87SPrem Chintalapudi       ES.reportError(UWR.takeError());
2447ddf7d87SPrem Chintalapudi     } else {
2457ddf7d87SPrem Chintalapudi       Batch.UnwindingRecord = std::move(*UWR);
2467ddf7d87SPrem Chintalapudi     }
2477ddf7d87SPrem Chintalapudi   } else {
2487ddf7d87SPrem Chintalapudi     Batch.UnwindingRecord.Prefix.TotalSize = 0;
2497ddf7d87SPrem Chintalapudi   }
2507ddf7d87SPrem Chintalapudi   return Batch;
2517ddf7d87SPrem Chintalapudi }
2527ddf7d87SPrem Chintalapudi } // namespace
2537ddf7d87SPrem Chintalapudi 
2547ddf7d87SPrem Chintalapudi PerfSupportPlugin::PerfSupportPlugin(ExecutorProcessControl &EPC,
2557ddf7d87SPrem Chintalapudi                                      ExecutorAddr RegisterPerfStartAddr,
2567ddf7d87SPrem Chintalapudi                                      ExecutorAddr RegisterPerfEndAddr,
2577ddf7d87SPrem Chintalapudi                                      ExecutorAddr RegisterPerfImplAddr,
2587ddf7d87SPrem Chintalapudi                                      bool EmitDebugInfo, bool EmitUnwindInfo)
2597ddf7d87SPrem Chintalapudi     : EPC(EPC), RegisterPerfStartAddr(RegisterPerfStartAddr),
2607ddf7d87SPrem Chintalapudi       RegisterPerfEndAddr(RegisterPerfEndAddr),
2617ddf7d87SPrem Chintalapudi       RegisterPerfImplAddr(RegisterPerfImplAddr), CodeIndex(0),
2627ddf7d87SPrem Chintalapudi       EmitDebugInfo(EmitDebugInfo), EmitUnwindInfo(EmitUnwindInfo) {
2637ddf7d87SPrem Chintalapudi   cantFail(EPC.callSPSWrapper<void()>(RegisterPerfStartAddr));
2647ddf7d87SPrem Chintalapudi }
2657ddf7d87SPrem Chintalapudi PerfSupportPlugin::~PerfSupportPlugin() {
2667ddf7d87SPrem Chintalapudi   cantFail(EPC.callSPSWrapper<void()>(RegisterPerfEndAddr));
2677ddf7d87SPrem Chintalapudi }
2687ddf7d87SPrem Chintalapudi 
2697ddf7d87SPrem Chintalapudi void PerfSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
2707ddf7d87SPrem Chintalapudi                                          LinkGraph &G,
2717ddf7d87SPrem Chintalapudi                                          PassConfiguration &Config) {
2727ddf7d87SPrem Chintalapudi   Config.PostFixupPasses.push_back([this](LinkGraph &G) {
2737ddf7d87SPrem Chintalapudi     auto Batch = getRecords(EPC.getExecutionSession(), G, CodeIndex,
2747ddf7d87SPrem Chintalapudi                             EmitDebugInfo, EmitUnwindInfo);
2757ddf7d87SPrem Chintalapudi     G.allocActions().push_back(
2767ddf7d87SPrem Chintalapudi         {cantFail(shared::WrapperFunctionCall::Create<
2777ddf7d87SPrem Chintalapudi                   shared::SPSArgList<shared::SPSPerfJITRecordBatch>>(
2787ddf7d87SPrem Chintalapudi              RegisterPerfImplAddr, Batch)),
2797ddf7d87SPrem Chintalapudi          {}});
2807ddf7d87SPrem Chintalapudi     return Error::success();
2817ddf7d87SPrem Chintalapudi   });
2827ddf7d87SPrem Chintalapudi }
2837ddf7d87SPrem Chintalapudi 
2847ddf7d87SPrem Chintalapudi Expected<std::unique_ptr<PerfSupportPlugin>>
2857ddf7d87SPrem Chintalapudi PerfSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
2867ddf7d87SPrem Chintalapudi                           bool EmitDebugInfo, bool EmitUnwindInfo) {
2877ddf7d87SPrem Chintalapudi   if (!EPC.getTargetTriple().isOSBinFormatELF()) {
2887ddf7d87SPrem Chintalapudi     return make_error<StringError>(
2897ddf7d87SPrem Chintalapudi         "Perf support only available for ELF LinkGraphs!",
2907ddf7d87SPrem Chintalapudi         inconvertibleErrorCode());
2917ddf7d87SPrem Chintalapudi   }
2927ddf7d87SPrem Chintalapudi   auto &ES = EPC.getExecutionSession();
2937ddf7d87SPrem Chintalapudi   ExecutorAddr StartAddr, EndAddr, ImplAddr;
2947ddf7d87SPrem Chintalapudi   if (auto Err = lookupAndRecordAddrs(
2957ddf7d87SPrem Chintalapudi           ES, LookupKind::Static, makeJITDylibSearchOrder({&JD}),
2967ddf7d87SPrem Chintalapudi           {{ES.intern(RegisterPerfStartSymbolName), &StartAddr},
2977ddf7d87SPrem Chintalapudi            {ES.intern(RegisterPerfEndSymbolName), &EndAddr},
2987ddf7d87SPrem Chintalapudi            {ES.intern(RegisterPerfImplSymbolName), &ImplAddr}}))
2997ddf7d87SPrem Chintalapudi     return std::move(Err);
3007ddf7d87SPrem Chintalapudi   return std::make_unique<PerfSupportPlugin>(EPC, StartAddr, EndAddr, ImplAddr,
3017ddf7d87SPrem Chintalapudi                                              EmitDebugInfo, EmitUnwindInfo);
3027ddf7d87SPrem Chintalapudi }
303