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