1*c9157d92SDimitry Andric //===----- PerfSupportPlugin.cpp --- Utils for perf support -----*- C++ -*-===//
2*c9157d92SDimitry Andric //
3*c9157d92SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c9157d92SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*c9157d92SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c9157d92SDimitry Andric //
7*c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
8*c9157d92SDimitry Andric //
9*c9157d92SDimitry Andric // Handles support for registering code with perf
10*c9157d92SDimitry Andric //
11*c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
12*c9157d92SDimitry Andric 
13*c9157d92SDimitry Andric #include "llvm/ExecutionEngine/Orc/Debugging/PerfSupportPlugin.h"
14*c9157d92SDimitry Andric 
15*c9157d92SDimitry Andric #include "llvm/ExecutionEngine/JITLink/x86_64.h"
16*c9157d92SDimitry Andric #include "llvm/ExecutionEngine/Orc/Debugging/DebugInfoSupport.h"
17*c9157d92SDimitry Andric #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
18*c9157d92SDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h"
19*c9157d92SDimitry Andric 
20*c9157d92SDimitry Andric #define DEBUG_TYPE "orc"
21*c9157d92SDimitry Andric 
22*c9157d92SDimitry Andric using namespace llvm;
23*c9157d92SDimitry Andric using namespace llvm::orc;
24*c9157d92SDimitry Andric using namespace llvm::jitlink;
25*c9157d92SDimitry Andric 
26*c9157d92SDimitry Andric namespace {
27*c9157d92SDimitry Andric 
28*c9157d92SDimitry Andric // Creates an EH frame header prepared for a 32-bit relative relocation
29*c9157d92SDimitry Andric // to the start of the .eh_frame section. Absolute injects a 64-bit absolute
30*c9157d92SDimitry Andric // address space offset 4 bytes from the start instead of 4 bytes
createX64EHFrameHeader(Section & EHFrame,llvm::endianness endianness,bool absolute)31*c9157d92SDimitry Andric Expected<std::string> createX64EHFrameHeader(Section &EHFrame,
32*c9157d92SDimitry Andric                                              llvm::endianness endianness,
33*c9157d92SDimitry Andric                                              bool absolute) {
34*c9157d92SDimitry Andric   uint8_t Version = 1;
35*c9157d92SDimitry Andric   uint8_t EhFramePtrEnc = 0;
36*c9157d92SDimitry Andric   if (absolute) {
37*c9157d92SDimitry Andric     EhFramePtrEnc |= dwarf::DW_EH_PE_sdata8 | dwarf::DW_EH_PE_absptr;
38*c9157d92SDimitry Andric   } else {
39*c9157d92SDimitry Andric     EhFramePtrEnc |= dwarf::DW_EH_PE_sdata4 | dwarf::DW_EH_PE_datarel;
40*c9157d92SDimitry Andric   }
41*c9157d92SDimitry Andric   uint8_t FDECountEnc = dwarf::DW_EH_PE_omit;
42*c9157d92SDimitry Andric   uint8_t TableEnc = dwarf::DW_EH_PE_omit;
43*c9157d92SDimitry Andric   // X86_64_64 relocation to the start of the .eh_frame section
44*c9157d92SDimitry Andric   uint32_t EHFrameRelocation = 0;
45*c9157d92SDimitry Andric   // uint32_t FDECount = 0;
46*c9157d92SDimitry Andric   // Skip the FDE binary search table
47*c9157d92SDimitry Andric   // We'd have to reprocess the CIEs to get this information,
48*c9157d92SDimitry Andric   // which seems like more trouble than it's worth
49*c9157d92SDimitry Andric   // TODO consider implementing this.
50*c9157d92SDimitry Andric   // binary search table goes here
51*c9157d92SDimitry Andric 
52*c9157d92SDimitry Andric   size_t HeaderSize =
53*c9157d92SDimitry Andric       (sizeof(Version) + sizeof(EhFramePtrEnc) + sizeof(FDECountEnc) +
54*c9157d92SDimitry Andric        sizeof(TableEnc) +
55*c9157d92SDimitry Andric        (absolute ? sizeof(uint64_t) : sizeof(EHFrameRelocation)));
56*c9157d92SDimitry Andric   std::string HeaderContent(HeaderSize, '\0');
57*c9157d92SDimitry Andric   BinaryStreamWriter Writer(
58*c9157d92SDimitry Andric       MutableArrayRef<uint8_t>(
59*c9157d92SDimitry Andric           reinterpret_cast<uint8_t *>(HeaderContent.data()), HeaderSize),
60*c9157d92SDimitry Andric       endianness);
61*c9157d92SDimitry Andric   if (auto Err = Writer.writeInteger(Version))
62*c9157d92SDimitry Andric     return std::move(Err);
63*c9157d92SDimitry Andric   if (auto Err = Writer.writeInteger(EhFramePtrEnc))
64*c9157d92SDimitry Andric     return std::move(Err);
65*c9157d92SDimitry Andric   if (auto Err = Writer.writeInteger(FDECountEnc))
66*c9157d92SDimitry Andric     return std::move(Err);
67*c9157d92SDimitry Andric   if (auto Err = Writer.writeInteger(TableEnc))
68*c9157d92SDimitry Andric     return std::move(Err);
69*c9157d92SDimitry Andric   if (absolute) {
70*c9157d92SDimitry Andric     uint64_t EHFrameAddr = SectionRange(EHFrame).getStart().getValue();
71*c9157d92SDimitry Andric     if (auto Err = Writer.writeInteger(EHFrameAddr))
72*c9157d92SDimitry Andric       return std::move(Err);
73*c9157d92SDimitry Andric   } else {
74*c9157d92SDimitry Andric     if (auto Err = Writer.writeInteger(EHFrameRelocation))
75*c9157d92SDimitry Andric       return std::move(Err);
76*c9157d92SDimitry Andric   }
77*c9157d92SDimitry Andric   return HeaderContent;
78*c9157d92SDimitry Andric }
79*c9157d92SDimitry Andric 
80*c9157d92SDimitry Andric constexpr StringRef RegisterPerfStartSymbolName =
81*c9157d92SDimitry Andric     "llvm_orc_registerJITLoaderPerfStart";
82*c9157d92SDimitry Andric constexpr StringRef RegisterPerfEndSymbolName =
83*c9157d92SDimitry Andric     "llvm_orc_registerJITLoaderPerfEnd";
84*c9157d92SDimitry Andric constexpr StringRef RegisterPerfImplSymbolName =
85*c9157d92SDimitry Andric     "llvm_orc_registerJITLoaderPerfImpl";
86*c9157d92SDimitry Andric 
87*c9157d92SDimitry Andric static PerfJITCodeLoadRecord
getCodeLoadRecord(const Symbol & Sym,std::atomic<uint64_t> & CodeIndex)88*c9157d92SDimitry Andric getCodeLoadRecord(const Symbol &Sym, std::atomic<uint64_t> &CodeIndex) {
89*c9157d92SDimitry Andric   PerfJITCodeLoadRecord Record;
90*c9157d92SDimitry Andric   auto Name = Sym.getName();
91*c9157d92SDimitry Andric   auto Addr = Sym.getAddress();
92*c9157d92SDimitry Andric   auto Size = Sym.getSize();
93*c9157d92SDimitry Andric   Record.Prefix.Id = PerfJITRecordType::JIT_CODE_LOAD;
94*c9157d92SDimitry Andric   // Runtime sets PID
95*c9157d92SDimitry Andric   Record.Pid = 0;
96*c9157d92SDimitry Andric   // Runtime sets TID
97*c9157d92SDimitry Andric   Record.Tid = 0;
98*c9157d92SDimitry Andric   Record.Vma = Addr.getValue();
99*c9157d92SDimitry Andric   Record.CodeAddr = Addr.getValue();
100*c9157d92SDimitry Andric   Record.CodeSize = Size;
101*c9157d92SDimitry Andric   Record.CodeIndex = CodeIndex++;
102*c9157d92SDimitry Andric   Record.Name = Name.str();
103*c9157d92SDimitry Andric   // Initialize last, once all the other fields are filled
104*c9157d92SDimitry Andric   Record.Prefix.TotalSize =
105*c9157d92SDimitry Andric       (2 * sizeof(uint32_t)   // id, total_size
106*c9157d92SDimitry Andric        + sizeof(uint64_t)     // timestamp
107*c9157d92SDimitry Andric        + 2 * sizeof(uint32_t) // pid, tid
108*c9157d92SDimitry Andric        + 4 * sizeof(uint64_t) // vma, code_addr, code_size, code_index
109*c9157d92SDimitry Andric        + Name.size() + 1      // symbol name
110*c9157d92SDimitry Andric        + Record.CodeSize      // code
111*c9157d92SDimitry Andric       );
112*c9157d92SDimitry Andric   return Record;
113*c9157d92SDimitry Andric }
114*c9157d92SDimitry Andric 
115*c9157d92SDimitry Andric static std::optional<PerfJITDebugInfoRecord>
getDebugInfoRecord(const Symbol & Sym,DWARFContext & DC)116*c9157d92SDimitry Andric getDebugInfoRecord(const Symbol &Sym, DWARFContext &DC) {
117*c9157d92SDimitry Andric   auto &Section = Sym.getBlock().getSection();
118*c9157d92SDimitry Andric   auto Addr = Sym.getAddress();
119*c9157d92SDimitry Andric   auto Size = Sym.getSize();
120*c9157d92SDimitry Andric   auto SAddr = object::SectionedAddress{Addr.getValue(), Section.getOrdinal()};
121*c9157d92SDimitry Andric   LLVM_DEBUG(dbgs() << "Getting debug info for symbol " << Sym.getName()
122*c9157d92SDimitry Andric                     << " at address " << Addr.getValue() << " with size "
123*c9157d92SDimitry Andric                     << Size << "\n"
124*c9157d92SDimitry Andric                     << "Section ordinal: " << Section.getOrdinal() << "\n");
125*c9157d92SDimitry Andric   auto LInfo = DC.getLineInfoForAddressRange(
126*c9157d92SDimitry Andric       SAddr, Size, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
127*c9157d92SDimitry Andric   if (LInfo.empty()) {
128*c9157d92SDimitry Andric     // No line info available
129*c9157d92SDimitry Andric     LLVM_DEBUG(dbgs() << "No line info available\n");
130*c9157d92SDimitry Andric     return std::nullopt;
131*c9157d92SDimitry Andric   }
132*c9157d92SDimitry Andric   PerfJITDebugInfoRecord Record;
133*c9157d92SDimitry Andric   Record.Prefix.Id = PerfJITRecordType::JIT_CODE_DEBUG_INFO;
134*c9157d92SDimitry Andric   Record.CodeAddr = Addr.getValue();
135*c9157d92SDimitry Andric   for (const auto &Entry : LInfo) {
136*c9157d92SDimitry Andric     auto Addr = Entry.first;
137*c9157d92SDimitry Andric     // The function re-created by perf is preceded by a elf
138*c9157d92SDimitry Andric     // header. Need to adjust for that, otherwise the results are
139*c9157d92SDimitry Andric     // wrong.
140*c9157d92SDimitry Andric     Addr += 0x40;
141*c9157d92SDimitry Andric     Record.Entries.push_back({Addr, Entry.second.Line,
142*c9157d92SDimitry Andric                               Entry.second.Discriminator,
143*c9157d92SDimitry Andric                               Entry.second.FileName});
144*c9157d92SDimitry Andric   }
145*c9157d92SDimitry Andric   size_t EntriesBytes = (2   // record header
146*c9157d92SDimitry Andric                          + 2 // record fields
147*c9157d92SDimitry Andric                          ) *
148*c9157d92SDimitry Andric                         sizeof(uint64_t);
149*c9157d92SDimitry Andric   for (const auto &Entry : Record.Entries) {
150*c9157d92SDimitry Andric     EntriesBytes +=
151*c9157d92SDimitry Andric         sizeof(uint64_t) + 2 * sizeof(uint32_t); // Addr, Line/Discrim
152*c9157d92SDimitry Andric     EntriesBytes += Entry.Name.size() + 1;       // Name
153*c9157d92SDimitry Andric   }
154*c9157d92SDimitry Andric   Record.Prefix.TotalSize = EntriesBytes;
155*c9157d92SDimitry Andric   LLVM_DEBUG(dbgs() << "Created debug info record\n"
156*c9157d92SDimitry Andric                     << "Total size: " << Record.Prefix.TotalSize << "\n"
157*c9157d92SDimitry Andric                     << "Nr entries: " << Record.Entries.size() << "\n");
158*c9157d92SDimitry Andric   return Record;
159*c9157d92SDimitry Andric }
160*c9157d92SDimitry Andric 
161*c9157d92SDimitry Andric static Expected<PerfJITCodeUnwindingInfoRecord>
getUnwindingRecord(LinkGraph & G)162*c9157d92SDimitry Andric getUnwindingRecord(LinkGraph &G) {
163*c9157d92SDimitry Andric   PerfJITCodeUnwindingInfoRecord Record;
164*c9157d92SDimitry Andric   Record.Prefix.Id = PerfJITRecordType::JIT_CODE_UNWINDING_INFO;
165*c9157d92SDimitry Andric   Record.Prefix.TotalSize = 0;
166*c9157d92SDimitry Andric   auto Eh_frame = G.findSectionByName(".eh_frame");
167*c9157d92SDimitry Andric   if (!Eh_frame) {
168*c9157d92SDimitry Andric     LLVM_DEBUG(dbgs() << "No .eh_frame section found\n");
169*c9157d92SDimitry Andric     return Record;
170*c9157d92SDimitry Andric   }
171*c9157d92SDimitry Andric   if (!G.getTargetTriple().isOSBinFormatELF()) {
172*c9157d92SDimitry Andric     LLVM_DEBUG(dbgs() << "Not an ELF file, will not emit unwinding info\n");
173*c9157d92SDimitry Andric     return Record;
174*c9157d92SDimitry Andric   }
175*c9157d92SDimitry Andric   auto SR = SectionRange(*Eh_frame);
176*c9157d92SDimitry Andric   auto EHFrameSize = SR.getSize();
177*c9157d92SDimitry Andric   auto Eh_frame_hdr = G.findSectionByName(".eh_frame_hdr");
178*c9157d92SDimitry Andric   if (!Eh_frame_hdr) {
179*c9157d92SDimitry Andric     if (G.getTargetTriple().getArch() == Triple::x86_64) {
180*c9157d92SDimitry Andric       auto Hdr = createX64EHFrameHeader(*Eh_frame, G.getEndianness(), true);
181*c9157d92SDimitry Andric       if (!Hdr)
182*c9157d92SDimitry Andric         return Hdr.takeError();
183*c9157d92SDimitry Andric       Record.EHFrameHdr = std::move(*Hdr);
184*c9157d92SDimitry Andric     } else {
185*c9157d92SDimitry Andric       LLVM_DEBUG(dbgs() << "No .eh_frame_hdr section found\n");
186*c9157d92SDimitry Andric       return Record;
187*c9157d92SDimitry Andric     }
188*c9157d92SDimitry Andric     Record.EHFrameHdrAddr = 0;
189*c9157d92SDimitry Andric     Record.EHFrameHdrSize = Record.EHFrameHdr.size();
190*c9157d92SDimitry Andric     Record.UnwindDataSize = EHFrameSize + Record.EHFrameHdrSize;
191*c9157d92SDimitry Andric     Record.MappedSize = 0; // Because the EHFrame header was not mapped
192*c9157d92SDimitry Andric   } else {
193*c9157d92SDimitry Andric     auto SR = SectionRange(*Eh_frame_hdr);
194*c9157d92SDimitry Andric     Record.EHFrameHdrAddr = SR.getStart().getValue();
195*c9157d92SDimitry Andric     Record.EHFrameHdrSize = SR.getSize();
196*c9157d92SDimitry Andric     Record.UnwindDataSize = EHFrameSize + Record.EHFrameHdrSize;
197*c9157d92SDimitry Andric     Record.MappedSize = Record.UnwindDataSize;
198*c9157d92SDimitry Andric   }
199*c9157d92SDimitry Andric   Record.EHFrameAddr = SR.getStart().getValue();
200*c9157d92SDimitry Andric   Record.Prefix.TotalSize =
201*c9157d92SDimitry Andric       (2 * sizeof(uint32_t) // id, total_size
202*c9157d92SDimitry Andric        + sizeof(uint64_t)   // timestamp
203*c9157d92SDimitry Andric        +
204*c9157d92SDimitry Andric        3 * sizeof(uint64_t) // unwind_data_size, eh_frame_hdr_size, mapped_size
205*c9157d92SDimitry Andric        + Record.UnwindDataSize // eh_frame_hdr, eh_frame
206*c9157d92SDimitry Andric       );
207*c9157d92SDimitry Andric   LLVM_DEBUG(dbgs() << "Created unwind record\n"
208*c9157d92SDimitry Andric                     << "Total size: " << Record.Prefix.TotalSize << "\n"
209*c9157d92SDimitry Andric                     << "Unwind size: " << Record.UnwindDataSize << "\n"
210*c9157d92SDimitry Andric                     << "EHFrame size: " << EHFrameSize << "\n"
211*c9157d92SDimitry Andric                     << "EHFrameHdr size: " << Record.EHFrameHdrSize << "\n");
212*c9157d92SDimitry Andric   return Record;
213*c9157d92SDimitry Andric }
214*c9157d92SDimitry Andric 
getRecords(ExecutionSession & ES,LinkGraph & G,std::atomic<uint64_t> & CodeIndex,bool EmitDebugInfo,bool EmitUnwindInfo)215*c9157d92SDimitry Andric static PerfJITRecordBatch getRecords(ExecutionSession &ES, LinkGraph &G,
216*c9157d92SDimitry Andric                                      std::atomic<uint64_t> &CodeIndex,
217*c9157d92SDimitry Andric                                      bool EmitDebugInfo, bool EmitUnwindInfo) {
218*c9157d92SDimitry Andric   std::unique_ptr<DWARFContext> DC;
219*c9157d92SDimitry Andric   StringMap<std::unique_ptr<MemoryBuffer>> DCBacking;
220*c9157d92SDimitry Andric   if (EmitDebugInfo) {
221*c9157d92SDimitry Andric     auto EDC = createDWARFContext(G);
222*c9157d92SDimitry Andric     if (!EDC) {
223*c9157d92SDimitry Andric       ES.reportError(EDC.takeError());
224*c9157d92SDimitry Andric       EmitDebugInfo = false;
225*c9157d92SDimitry Andric     } else {
226*c9157d92SDimitry Andric       DC = std::move(EDC->first);
227*c9157d92SDimitry Andric       DCBacking = std::move(EDC->second);
228*c9157d92SDimitry Andric     }
229*c9157d92SDimitry Andric   }
230*c9157d92SDimitry Andric   PerfJITRecordBatch Batch;
231*c9157d92SDimitry Andric   for (auto Sym : G.defined_symbols()) {
232*c9157d92SDimitry Andric     if (!Sym->hasName() || !Sym->isCallable())
233*c9157d92SDimitry Andric       continue;
234*c9157d92SDimitry Andric     if (EmitDebugInfo) {
235*c9157d92SDimitry Andric       auto DebugInfo = getDebugInfoRecord(*Sym, *DC);
236*c9157d92SDimitry Andric       if (DebugInfo)
237*c9157d92SDimitry Andric         Batch.DebugInfoRecords.push_back(std::move(*DebugInfo));
238*c9157d92SDimitry Andric     }
239*c9157d92SDimitry Andric     Batch.CodeLoadRecords.push_back(getCodeLoadRecord(*Sym, CodeIndex));
240*c9157d92SDimitry Andric   }
241*c9157d92SDimitry Andric   if (EmitUnwindInfo) {
242*c9157d92SDimitry Andric     auto UWR = getUnwindingRecord(G);
243*c9157d92SDimitry Andric     if (!UWR) {
244*c9157d92SDimitry Andric       ES.reportError(UWR.takeError());
245*c9157d92SDimitry Andric     } else {
246*c9157d92SDimitry Andric       Batch.UnwindingRecord = std::move(*UWR);
247*c9157d92SDimitry Andric     }
248*c9157d92SDimitry Andric   } else {
249*c9157d92SDimitry Andric     Batch.UnwindingRecord.Prefix.TotalSize = 0;
250*c9157d92SDimitry Andric   }
251*c9157d92SDimitry Andric   return Batch;
252*c9157d92SDimitry Andric }
253*c9157d92SDimitry Andric } // namespace
254*c9157d92SDimitry Andric 
PerfSupportPlugin(ExecutorProcessControl & EPC,ExecutorAddr RegisterPerfStartAddr,ExecutorAddr RegisterPerfEndAddr,ExecutorAddr RegisterPerfImplAddr,bool EmitDebugInfo,bool EmitUnwindInfo)255*c9157d92SDimitry Andric PerfSupportPlugin::PerfSupportPlugin(ExecutorProcessControl &EPC,
256*c9157d92SDimitry Andric                                      ExecutorAddr RegisterPerfStartAddr,
257*c9157d92SDimitry Andric                                      ExecutorAddr RegisterPerfEndAddr,
258*c9157d92SDimitry Andric                                      ExecutorAddr RegisterPerfImplAddr,
259*c9157d92SDimitry Andric                                      bool EmitDebugInfo, bool EmitUnwindInfo)
260*c9157d92SDimitry Andric     : EPC(EPC), RegisterPerfStartAddr(RegisterPerfStartAddr),
261*c9157d92SDimitry Andric       RegisterPerfEndAddr(RegisterPerfEndAddr),
262*c9157d92SDimitry Andric       RegisterPerfImplAddr(RegisterPerfImplAddr), CodeIndex(0),
263*c9157d92SDimitry Andric       EmitDebugInfo(EmitDebugInfo), EmitUnwindInfo(EmitUnwindInfo) {
264*c9157d92SDimitry Andric   cantFail(EPC.callSPSWrapper<void()>(RegisterPerfStartAddr));
265*c9157d92SDimitry Andric }
~PerfSupportPlugin()266*c9157d92SDimitry Andric PerfSupportPlugin::~PerfSupportPlugin() {
267*c9157d92SDimitry Andric   cantFail(EPC.callSPSWrapper<void()>(RegisterPerfEndAddr));
268*c9157d92SDimitry Andric }
269*c9157d92SDimitry Andric 
modifyPassConfig(MaterializationResponsibility & MR,LinkGraph & G,PassConfiguration & Config)270*c9157d92SDimitry Andric void PerfSupportPlugin::modifyPassConfig(MaterializationResponsibility &MR,
271*c9157d92SDimitry Andric                                          LinkGraph &G,
272*c9157d92SDimitry Andric                                          PassConfiguration &Config) {
273*c9157d92SDimitry Andric   Config.PostFixupPasses.push_back([this](LinkGraph &G) {
274*c9157d92SDimitry Andric     auto Batch = getRecords(EPC.getExecutionSession(), G, CodeIndex,
275*c9157d92SDimitry Andric                             EmitDebugInfo, EmitUnwindInfo);
276*c9157d92SDimitry Andric     G.allocActions().push_back(
277*c9157d92SDimitry Andric         {cantFail(shared::WrapperFunctionCall::Create<
278*c9157d92SDimitry Andric                   shared::SPSArgList<shared::SPSPerfJITRecordBatch>>(
279*c9157d92SDimitry Andric              RegisterPerfImplAddr, Batch)),
280*c9157d92SDimitry Andric          {}});
281*c9157d92SDimitry Andric     return Error::success();
282*c9157d92SDimitry Andric   });
283*c9157d92SDimitry Andric }
284*c9157d92SDimitry Andric 
285*c9157d92SDimitry Andric Expected<std::unique_ptr<PerfSupportPlugin>>
Create(ExecutorProcessControl & EPC,JITDylib & JD,bool EmitDebugInfo,bool EmitUnwindInfo)286*c9157d92SDimitry Andric PerfSupportPlugin::Create(ExecutorProcessControl &EPC, JITDylib &JD,
287*c9157d92SDimitry Andric                           bool EmitDebugInfo, bool EmitUnwindInfo) {
288*c9157d92SDimitry Andric   if (!EPC.getTargetTriple().isOSBinFormatELF()) {
289*c9157d92SDimitry Andric     return make_error<StringError>(
290*c9157d92SDimitry Andric         "Perf support only available for ELF LinkGraphs!",
291*c9157d92SDimitry Andric         inconvertibleErrorCode());
292*c9157d92SDimitry Andric   }
293*c9157d92SDimitry Andric   auto &ES = EPC.getExecutionSession();
294*c9157d92SDimitry Andric   ExecutorAddr StartAddr, EndAddr, ImplAddr;
295*c9157d92SDimitry Andric   if (auto Err = lookupAndRecordAddrs(
296*c9157d92SDimitry Andric           ES, LookupKind::Static, makeJITDylibSearchOrder({&JD}),
297*c9157d92SDimitry Andric           {{ES.intern(RegisterPerfStartSymbolName), &StartAddr},
298*c9157d92SDimitry Andric            {ES.intern(RegisterPerfEndSymbolName), &EndAddr},
299*c9157d92SDimitry Andric            {ES.intern(RegisterPerfImplSymbolName), &ImplAddr}}))
300*c9157d92SDimitry Andric     return std::move(Err);
301*c9157d92SDimitry Andric   return std::make_unique<PerfSupportPlugin>(EPC, StartAddr, EndAddr, ImplAddr,
302*c9157d92SDimitry Andric                                              EmitDebugInfo, EmitUnwindInfo);
303*c9157d92SDimitry Andric }
304