1 //===---------- ExecutorSharedMemoryMapperService.cpp -----------*- C++ -*-===//
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/TargetProcess/ExecutorSharedMemoryMapperService.h"
10 
11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
12 #include "llvm/Support/Process.h"
13 #include "llvm/Support/WindowsError.h"
14 
15 #include <sstream>
16 
17 #if defined(LLVM_ON_UNIX)
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <sys/mman.h>
21 #include <unistd.h>
22 #endif
23 
24 #if defined(_WIN32)
25 static DWORD getWindowsProtectionFlags(unsigned Flags) {
26   switch (Flags & llvm::sys::Memory::MF_RWE_MASK) {
27   case llvm::sys::Memory::MF_READ:
28     return PAGE_READONLY;
29   case llvm::sys::Memory::MF_WRITE:
30     // Note: PAGE_WRITE is not supported by VirtualProtect
31     return PAGE_READWRITE;
32   case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE:
33     return PAGE_READWRITE;
34   case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_EXEC:
35     return PAGE_EXECUTE_READ;
36   case llvm::sys::Memory::MF_READ | llvm::sys::Memory::MF_WRITE |
37       llvm::sys::Memory::MF_EXEC:
38     return PAGE_EXECUTE_READWRITE;
39   case llvm::sys::Memory::MF_EXEC:
40     return PAGE_EXECUTE;
41   default:
42     llvm_unreachable("Illegal memory protection flag specified!");
43   }
44   // Provide a default return value as required by some compilers.
45   return PAGE_NOACCESS;
46 }
47 #endif
48 
49 namespace llvm {
50 namespace orc {
51 namespace rt_bootstrap {
52 
53 Expected<std::pair<ExecutorAddr, std::string>>
54 ExecutorSharedMemoryMapperService::reserve(uint64_t Size) {
55 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
56 
57 #if defined(LLVM_ON_UNIX)
58 
59   std::string SharedMemoryName;
60   {
61     std::stringstream SharedMemoryNameStream;
62     SharedMemoryNameStream << "/jitlink_" << sys::Process::getProcessId() << '_'
63                            << (++SharedMemoryCount);
64     SharedMemoryName = SharedMemoryNameStream.str();
65   }
66 
67   int SharedMemoryFile =
68       shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0700);
69   if (SharedMemoryFile < 0)
70     return errorCodeToError(std::error_code(errno, std::generic_category()));
71 
72   // by default size is 0
73   if (ftruncate(SharedMemoryFile, Size) < 0)
74     return errorCodeToError(std::error_code(errno, std::generic_category()));
75 
76   void *Addr = mmap(nullptr, Size, PROT_NONE, MAP_SHARED, SharedMemoryFile, 0);
77   if (Addr == MAP_FAILED)
78     return errorCodeToError(std::error_code(errno, std::generic_category()));
79 
80   close(SharedMemoryFile);
81 
82 #elif defined(_WIN32)
83 
84   std::string SharedMemoryName;
85   {
86     std::stringstream SharedMemoryNameStream;
87     SharedMemoryNameStream << "jitlink_" << sys::Process::getProcessId() << '_'
88                            << (++SharedMemoryCount);
89     SharedMemoryName = SharedMemoryNameStream.str();
90   }
91 
92   std::wstring WideSharedMemoryName(SharedMemoryName.begin(),
93                                     SharedMemoryName.end());
94   HANDLE SharedMemoryFile = CreateFileMappingW(
95       INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, Size >> 32,
96       Size & 0xffffffff, WideSharedMemoryName.c_str());
97   if (!SharedMemoryFile)
98     return errorCodeToError(mapWindowsError(GetLastError()));
99 
100   void *Addr = MapViewOfFile(SharedMemoryFile,
101                              FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0);
102   if (!Addr) {
103     CloseHandle(SharedMemoryFile);
104     return errorCodeToError(mapWindowsError(GetLastError()));
105   }
106 
107 #endif
108 
109   {
110     std::lock_guard<std::mutex> Lock(Mutex);
111     Reservations[Addr].Size = Size;
112 #if defined(_WIN32)
113     Reservations[Addr].SharedMemoryFile = SharedMemoryFile;
114 #endif
115   }
116 
117   return std::make_pair(ExecutorAddr::fromPtr(Addr),
118                         std::move(SharedMemoryName));
119 #else
120   return make_error<StringError>(
121       "SharedMemoryMapper is not supported on this platform yet",
122       inconvertibleErrorCode());
123 #endif
124 }
125 
126 Expected<ExecutorAddr> ExecutorSharedMemoryMapperService::initialize(
127     ExecutorAddr Reservation, tpctypes::SharedMemoryFinalizeRequest &FR) {
128 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
129 
130   ExecutorAddr MinAddr(~0ULL);
131 
132   // Contents are already in place
133   for (auto &Segment : FR.Segments) {
134     if (Segment.Addr < MinAddr)
135       MinAddr = Segment.Addr;
136 
137 #if defined(LLVM_ON_UNIX)
138 
139     int NativeProt = 0;
140     if (Segment.Prot & tpctypes::WPF_Read)
141       NativeProt |= PROT_READ;
142     if (Segment.Prot & tpctypes::WPF_Write)
143       NativeProt |= PROT_WRITE;
144     if (Segment.Prot & tpctypes::WPF_Exec)
145       NativeProt |= PROT_EXEC;
146 
147     if (mprotect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt))
148       return errorCodeToError(std::error_code(errno, std::generic_category()));
149 
150 #elif defined(_WIN32)
151 
152     DWORD NativeProt =
153         getWindowsProtectionFlags(fromWireProtectionFlags(Segment.Prot));
154 
155     if (!VirtualProtect(Segment.Addr.toPtr<void *>(), Segment.Size, NativeProt,
156                         &NativeProt))
157       return errorCodeToError(mapWindowsError(GetLastError()));
158 
159 #endif
160 
161     if (Segment.Prot & tpctypes::WPF_Exec)
162       sys::Memory::InvalidateInstructionCache(Segment.Addr.toPtr<void *>(),
163                                               Segment.Size);
164   }
165 
166   // Run finalization actions and get deinitlization action list.
167   auto DeinitializeActions = shared::runFinalizeActions(FR.Actions);
168   if (!DeinitializeActions) {
169     return DeinitializeActions.takeError();
170   }
171 
172   {
173     std::lock_guard<std::mutex> Lock(Mutex);
174     Allocations[MinAddr].DeinitializationActions =
175         std::move(*DeinitializeActions);
176     Reservations[Reservation.toPtr<void *>()].Allocations.push_back(MinAddr);
177   }
178 
179   return MinAddr;
180 
181 #else
182   return make_error<StringError>(
183       "SharedMemoryMapper is not supported on this platform yet",
184       inconvertibleErrorCode());
185 #endif
186 }
187 
188 Error ExecutorSharedMemoryMapperService::deinitialize(
189     const std::vector<ExecutorAddr> &Bases) {
190   Error AllErr = Error::success();
191 
192   {
193     std::lock_guard<std::mutex> Lock(Mutex);
194 
195     for (auto Base : Bases) {
196       if (Error Err = shared::runDeallocActions(
197               Allocations[Base].DeinitializationActions)) {
198         AllErr = joinErrors(std::move(AllErr), std::move(Err));
199       }
200 
201       Allocations.erase(Base);
202     }
203   }
204 
205   return AllErr;
206 }
207 
208 Error ExecutorSharedMemoryMapperService::release(
209     const std::vector<ExecutorAddr> &Bases) {
210 #if (defined(LLVM_ON_UNIX) && !defined(__ANDROID__)) || defined(_WIN32)
211   Error Err = Error::success();
212 
213   for (auto Base : Bases) {
214     std::vector<ExecutorAddr> AllocAddrs;
215     size_t Size;
216 
217 #if defined(_WIN32)
218     HANDLE SharedMemoryFile;
219 #endif
220 
221     {
222       std::lock_guard<std::mutex> Lock(Mutex);
223       auto &R = Reservations[Base.toPtr<void *>()];
224       Size = R.Size;
225 
226 #if defined(_WIN32)
227       SharedMemoryFile = R.SharedMemoryFile;
228 #endif
229 
230       AllocAddrs.swap(R.Allocations);
231     }
232 
233     // deinitialize sub allocations
234     if (Error E = deinitialize(AllocAddrs))
235       Err = joinErrors(std::move(Err), std::move(E));
236 
237 #if defined(LLVM_ON_UNIX)
238 
239     if (munmap(Base.toPtr<void *>(), Size) != 0)
240       Err = joinErrors(std::move(Err), errorCodeToError(std::error_code(
241                                            errno, std::generic_category())));
242 
243 #elif defined(_WIN32)
244     (void)Size;
245 
246     if (!UnmapViewOfFile(Base.toPtr<void *>()))
247       Err = joinErrors(std::move(Err),
248                        errorCodeToError(mapWindowsError(GetLastError())));
249 
250     CloseHandle(SharedMemoryFile);
251 
252 #endif
253 
254     std::lock_guard<std::mutex> Lock(Mutex);
255     Reservations.erase(Base.toPtr<void *>());
256   }
257 
258   return Err;
259 #else
260   return make_error<StringError>(
261       "SharedMemoryMapper is not supported on this platform yet",
262       inconvertibleErrorCode());
263 #endif
264 }
265 
266 Error ExecutorSharedMemoryMapperService::shutdown() {
267   std::vector<ExecutorAddr> ReservationAddrs;
268   if (!Reservations.empty()) {
269     std::lock_guard<std::mutex> Lock(Mutex);
270     {
271       ReservationAddrs.reserve(Reservations.size());
272       for (const auto &R : Reservations) {
273         ReservationAddrs.push_back(ExecutorAddr::fromPtr(R.getFirst()));
274       }
275     }
276   }
277   return release(ReservationAddrs);
278 
279   return Error::success();
280 }
281 
282 void ExecutorSharedMemoryMapperService::addBootstrapSymbols(
283     StringMap<ExecutorAddr> &M) {
284   M[rt::ExecutorSharedMemoryMapperServiceInstanceName] =
285       ExecutorAddr::fromPtr(this);
286   M[rt::ExecutorSharedMemoryMapperServiceReserveWrapperName] =
287       ExecutorAddr::fromPtr(&reserveWrapper);
288   M[rt::ExecutorSharedMemoryMapperServiceInitializeWrapperName] =
289       ExecutorAddr::fromPtr(&initializeWrapper);
290   M[rt::ExecutorSharedMemoryMapperServiceDeinitializeWrapperName] =
291       ExecutorAddr::fromPtr(&deinitializeWrapper);
292   M[rt::ExecutorSharedMemoryMapperServiceReleaseWrapperName] =
293       ExecutorAddr::fromPtr(&releaseWrapper);
294 }
295 
296 llvm::orc::shared::CWrapperFunctionResult
297 ExecutorSharedMemoryMapperService::reserveWrapper(const char *ArgData,
298                                                   size_t ArgSize) {
299   return shared::WrapperFunction<
300              rt::SPSExecutorSharedMemoryMapperServiceReserveSignature>::
301       handle(ArgData, ArgSize,
302              shared::makeMethodWrapperHandler(
303                  &ExecutorSharedMemoryMapperService::reserve))
304           .release();
305 }
306 
307 llvm::orc::shared::CWrapperFunctionResult
308 ExecutorSharedMemoryMapperService::initializeWrapper(const char *ArgData,
309                                                      size_t ArgSize) {
310   return shared::WrapperFunction<
311              rt::SPSExecutorSharedMemoryMapperServiceInitializeSignature>::
312       handle(ArgData, ArgSize,
313              shared::makeMethodWrapperHandler(
314                  &ExecutorSharedMemoryMapperService::initialize))
315           .release();
316 }
317 
318 llvm::orc::shared::CWrapperFunctionResult
319 ExecutorSharedMemoryMapperService::deinitializeWrapper(const char *ArgData,
320                                                        size_t ArgSize) {
321   return shared::WrapperFunction<
322              rt::SPSExecutorSharedMemoryMapperServiceDeinitializeSignature>::
323       handle(ArgData, ArgSize,
324              shared::makeMethodWrapperHandler(
325                  &ExecutorSharedMemoryMapperService::deinitialize))
326           .release();
327 }
328 
329 llvm::orc::shared::CWrapperFunctionResult
330 ExecutorSharedMemoryMapperService::releaseWrapper(const char *ArgData,
331                                                   size_t ArgSize) {
332   return shared::WrapperFunction<
333              rt::SPSExecutorSharedMemoryMapperServiceReleaseSignature>::
334       handle(ArgData, ArgSize,
335              shared::makeMethodWrapperHandler(
336                  &ExecutorSharedMemoryMapperService::release))
337           .release();
338 }
339 
340 } // namespace rt_bootstrap
341 } // end namespace orc
342 } // end namespace llvm
343