1 | //===---- ExecutorProcessControl.cpp -- Executor process control APIs -----===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" |
10 | |
11 | #include "llvm/ExecutionEngine/Orc/Core.h" |
12 | #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" |
13 | #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" |
14 | #include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h" |
15 | #include "llvm/Support/FormatVariadic.h" |
16 | #include "llvm/Support/Process.h" |
17 | #include "llvm/TargetParser/Host.h" |
18 | |
19 | #define DEBUG_TYPE "orc" |
20 | |
21 | namespace llvm { |
22 | namespace orc { |
23 | |
24 | ExecutorProcessControl::MemoryAccess::~MemoryAccess() = default; |
25 | |
26 | ExecutorProcessControl::~ExecutorProcessControl() = default; |
27 | |
28 | SelfExecutorProcessControl::SelfExecutorProcessControl( |
29 | std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D, |
30 | Triple TargetTriple, unsigned PageSize, |
31 | std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) |
32 | : ExecutorProcessControl(std::move(SSP), std::move(D)), |
33 | InProcessMemoryAccess(TargetTriple.isArch64Bit()) { |
34 | |
35 | OwnedMemMgr = std::move(MemMgr); |
36 | if (!OwnedMemMgr) |
37 | OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>( |
38 | args: sys::Process::getPageSizeEstimate()); |
39 | |
40 | this->TargetTriple = std::move(TargetTriple); |
41 | this->PageSize = PageSize; |
42 | this->MemMgr = OwnedMemMgr.get(); |
43 | this->MemAccess = this; |
44 | this->JDI = {.JITDispatchFunction: ExecutorAddr::fromPtr(Ptr: jitDispatchViaWrapperFunctionManager), |
45 | .JITDispatchContext: ExecutorAddr::fromPtr(Ptr: this)}; |
46 | if (this->TargetTriple.isOSBinFormatMachO()) |
47 | GlobalManglingPrefix = '_'; |
48 | |
49 | this->BootstrapSymbols[rt::RegisterEHFrameSectionWrapperName] = |
50 | ExecutorAddr::fromPtr(Ptr: &llvm_orc_registerEHFrameSectionWrapper); |
51 | this->BootstrapSymbols[rt::DeregisterEHFrameSectionWrapperName] = |
52 | ExecutorAddr::fromPtr(Ptr: &llvm_orc_deregisterEHFrameSectionWrapper); |
53 | } |
54 | |
55 | Expected<std::unique_ptr<SelfExecutorProcessControl>> |
56 | SelfExecutorProcessControl::Create( |
57 | std::shared_ptr<SymbolStringPool> SSP, |
58 | std::unique_ptr<TaskDispatcher> D, |
59 | std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) { |
60 | |
61 | if (!SSP) |
62 | SSP = std::make_shared<SymbolStringPool>(); |
63 | |
64 | if (!D) |
65 | D = std::make_unique<InPlaceTaskDispatcher>(); |
66 | |
67 | auto PageSize = sys::Process::getPageSize(); |
68 | if (!PageSize) |
69 | return PageSize.takeError(); |
70 | |
71 | Triple TT(sys::getProcessTriple()); |
72 | |
73 | return std::make_unique<SelfExecutorProcessControl>( |
74 | args: std::move(SSP), args: std::move(D), args: std::move(TT), args&: *PageSize, |
75 | args: std::move(MemMgr)); |
76 | } |
77 | |
78 | Expected<tpctypes::DylibHandle> |
79 | SelfExecutorProcessControl::loadDylib(const char *DylibPath) { |
80 | std::string ErrMsg; |
81 | auto Dylib = sys::DynamicLibrary::getPermanentLibrary(filename: DylibPath, errMsg: &ErrMsg); |
82 | if (!Dylib.isValid()) |
83 | return make_error<StringError>(Args: std::move(ErrMsg), Args: inconvertibleErrorCode()); |
84 | return ExecutorAddr::fromPtr(Ptr: Dylib.getOSSpecificHandle()); |
85 | } |
86 | |
87 | void SelfExecutorProcessControl::lookupSymbolsAsync( |
88 | ArrayRef<LookupRequest> Request, |
89 | ExecutorProcessControl::SymbolLookupCompleteFn Complete) { |
90 | std::vector<tpctypes::LookupResult> R; |
91 | |
92 | for (auto &Elem : Request) { |
93 | sys::DynamicLibrary Dylib(Elem.Handle.toPtr<void *>()); |
94 | R.push_back(x: std::vector<ExecutorSymbolDef>()); |
95 | for (auto &KV : Elem.Symbols) { |
96 | auto &Sym = KV.first; |
97 | std::string Tmp((*Sym).data() + !!GlobalManglingPrefix, |
98 | (*Sym).size() - !!GlobalManglingPrefix); |
99 | void *Addr = Dylib.getAddressOfSymbol(symbolName: Tmp.c_str()); |
100 | if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) { |
101 | // FIXME: Collect all failing symbols before erroring out. |
102 | SymbolNameVector MissingSymbols; |
103 | MissingSymbols.push_back(x: Sym); |
104 | return Complete( |
105 | make_error<SymbolsNotFound>(Args&: SSP, Args: std::move(MissingSymbols))); |
106 | } |
107 | // FIXME: determine accurate JITSymbolFlags. |
108 | R.back().push_back( |
109 | x: {ExecutorAddr::fromPtr(Ptr: Addr), JITSymbolFlags::Exported}); |
110 | } |
111 | } |
112 | |
113 | Complete(std::move(R)); |
114 | } |
115 | |
116 | Expected<int32_t> |
117 | SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr, |
118 | ArrayRef<std::string> Args) { |
119 | using MainTy = int (*)(int, char *[]); |
120 | return orc::runAsMain(Main: MainFnAddr.toPtr<MainTy>(), Args); |
121 | } |
122 | |
123 | Expected<int32_t> |
124 | SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) { |
125 | using VoidTy = int (*)(); |
126 | return orc::runAsVoidFunction(Func: VoidFnAddr.toPtr<VoidTy>()); |
127 | } |
128 | |
129 | Expected<int32_t> |
130 | SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) { |
131 | using IntTy = int (*)(int); |
132 | return orc::runAsIntFunction(Func: IntFnAddr.toPtr<IntTy>(), Arg); |
133 | } |
134 | |
135 | void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr, |
136 | IncomingWFRHandler SendResult, |
137 | ArrayRef<char> ArgBuffer) { |
138 | using WrapperFnTy = |
139 | shared::CWrapperFunctionResult (*)(const char *Data, size_t Size); |
140 | auto *WrapperFn = WrapperFnAddr.toPtr<WrapperFnTy>(); |
141 | SendResult(WrapperFn(ArgBuffer.data(), ArgBuffer.size())); |
142 | } |
143 | |
144 | Error SelfExecutorProcessControl::disconnect() { |
145 | D->shutdown(); |
146 | return Error::success(); |
147 | } |
148 | |
149 | void InProcessMemoryAccess::writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws, |
150 | WriteResultFn OnWriteComplete) { |
151 | for (auto &W : Ws) |
152 | *W.Addr.toPtr<uint8_t *>() = W.Value; |
153 | OnWriteComplete(Error::success()); |
154 | } |
155 | |
156 | void InProcessMemoryAccess::writeUInt16sAsync( |
157 | ArrayRef<tpctypes::UInt16Write> Ws, WriteResultFn OnWriteComplete) { |
158 | for (auto &W : Ws) |
159 | *W.Addr.toPtr<uint16_t *>() = W.Value; |
160 | OnWriteComplete(Error::success()); |
161 | } |
162 | |
163 | void InProcessMemoryAccess::writeUInt32sAsync( |
164 | ArrayRef<tpctypes::UInt32Write> Ws, WriteResultFn OnWriteComplete) { |
165 | for (auto &W : Ws) |
166 | *W.Addr.toPtr<uint32_t *>() = W.Value; |
167 | OnWriteComplete(Error::success()); |
168 | } |
169 | |
170 | void InProcessMemoryAccess::writeUInt64sAsync( |
171 | ArrayRef<tpctypes::UInt64Write> Ws, WriteResultFn OnWriteComplete) { |
172 | for (auto &W : Ws) |
173 | *W.Addr.toPtr<uint64_t *>() = W.Value; |
174 | OnWriteComplete(Error::success()); |
175 | } |
176 | |
177 | void InProcessMemoryAccess::writeBuffersAsync( |
178 | ArrayRef<tpctypes::BufferWrite> Ws, WriteResultFn OnWriteComplete) { |
179 | for (auto &W : Ws) |
180 | memcpy(dest: W.Addr.toPtr<char *>(), src: W.Buffer.data(), n: W.Buffer.size()); |
181 | OnWriteComplete(Error::success()); |
182 | } |
183 | |
184 | void InProcessMemoryAccess::writePointersAsync( |
185 | ArrayRef<tpctypes::PointerWrite> Ws, WriteResultFn OnWriteComplete) { |
186 | if (IsArch64Bit) { |
187 | for (auto &W : Ws) |
188 | *W.Addr.toPtr<uint64_t *>() = W.Value.getValue(); |
189 | } else { |
190 | for (auto &W : Ws) |
191 | *W.Addr.toPtr<uint32_t *>() = static_cast<uint32_t>(W.Value.getValue()); |
192 | } |
193 | |
194 | OnWriteComplete(Error::success()); |
195 | } |
196 | |
197 | shared::CWrapperFunctionResult |
198 | SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager( |
199 | void *Ctx, const void *FnTag, const char *Data, size_t Size) { |
200 | |
201 | LLVM_DEBUG({ |
202 | dbgs() << "jit-dispatch call with tag " << FnTag << " and " << Size |
203 | << " byte payload.\n" ; |
204 | }); |
205 | |
206 | std::promise<shared::WrapperFunctionResult> ResultP; |
207 | auto ResultF = ResultP.get_future(); |
208 | static_cast<SelfExecutorProcessControl *>(Ctx) |
209 | ->getExecutionSession() |
210 | .runJITDispatchHandler( |
211 | SendResult: [ResultP = std::move(ResultP)]( |
212 | shared::WrapperFunctionResult Result) mutable { |
213 | ResultP.set_value(std::move(Result)); |
214 | }, |
215 | HandlerFnTagAddr: ExecutorAddr::fromPtr(Ptr: FnTag), ArgBuffer: {Data, Size}); |
216 | |
217 | return ResultF.get().release(); |
218 | } |
219 | |
220 | } // end namespace orc |
221 | } // end namespace llvm |
222 | |