1 //===- macho_platform.cpp -------------------------------------------------===//
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 // This file contains code required to load the rest of the MachO runtime.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "macho_platform.h"
14 #include "common.h"
15 #include "error.h"
16 #include "wrapper_function_utils.h"
17 
18 #include <map>
19 #include <mutex>
20 #include <sstream>
21 #include <unordered_map>
22 #include <vector>
23 
24 using namespace __orc_rt;
25 using namespace __orc_rt::macho;
26 
27 // Declare function tags for functions in the JIT process.
28 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_get_initializers_tag)
29 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_get_deinitializers_tag)
30 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_symbol_lookup_tag)
31 
32 // eh-frame registration functions.
33 // We expect these to be available for all processes.
34 extern "C" void __register_frame(const void *);
35 extern "C" void __deregister_frame(const void *);
36 
37 namespace {
38 
39 template <typename HandleFDEFn>
40 void walkEHFrameSection(span<const char> EHFrameSection,
41                         HandleFDEFn HandleFDE) {
42   const char *CurCFIRecord = EHFrameSection.data();
43   uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
44 
45   while (CurCFIRecord != EHFrameSection.end() && Size != 0) {
46     const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
47     if (Size == 0xffffffff)
48       Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
49     else
50       Size += 4;
51     uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
52 
53     if (Offset != 0)
54       HandleFDE(CurCFIRecord);
55 
56     CurCFIRecord += Size;
57     Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
58   }
59 }
60 
61 Error validatePointerSectionExtent(const char *SectionName,
62                                    const ExecutorAddressRange &SE) {
63   if (SE.size().getValue() % sizeof(uintptr_t)) {
64     std::ostringstream ErrMsg;
65     ErrMsg << std::hex << "Size of " << SectionName << " 0x"
66            << SE.StartAddress.getValue() << " -- 0x" << SE.EndAddress.getValue()
67            << " is not a pointer multiple";
68     return make_error<StringError>(ErrMsg.str());
69   }
70   return Error::success();
71 }
72 
73 Error runModInits(const std::vector<ExecutorAddressRange> &ModInitsSections,
74                   const MachOJITDylibInitializers &MOJDIs) {
75 
76   for (const auto &ModInits : ModInitsSections) {
77     if (auto Err = validatePointerSectionExtent("__mod_inits", ModInits))
78       return Err;
79 
80     using InitFunc = void (*)();
81     for (auto *Init : ModInits.toSpan<InitFunc>())
82       (*Init)();
83   }
84 
85   return Error::success();
86 }
87 
88 class MachOPlatformRuntimeState {
89 private:
90   struct AtExitEntry {
91     void (*Func)(void *);
92     void *Arg;
93   };
94 
95   using AtExitsVector = std::vector<AtExitEntry>;
96 
97   struct PerJITDylibState {
98     void *Header = nullptr;
99     size_t RefCount = 0;
100     bool AllowReinitialization = false;
101     AtExitsVector AtExits;
102   };
103 
104 public:
105   static void initialize();
106   static MachOPlatformRuntimeState &get();
107   static void destroy();
108 
109   MachOPlatformRuntimeState() = default;
110 
111   // Delete copy and move constructors.
112   MachOPlatformRuntimeState(const MachOPlatformRuntimeState &) = delete;
113   MachOPlatformRuntimeState &
114   operator=(const MachOPlatformRuntimeState &) = delete;
115   MachOPlatformRuntimeState(MachOPlatformRuntimeState &&) = delete;
116   MachOPlatformRuntimeState &operator=(MachOPlatformRuntimeState &&) = delete;
117 
118   Error registerObjectSections(MachOPerObjectSectionsToRegister POSR);
119   Error deregisterObjectSections(MachOPerObjectSectionsToRegister POSR);
120 
121   const char *dlerror();
122   void *dlopen(string_view Name, int Mode);
123   int dlclose(void *DSOHandle);
124   void *dlsym(void *DSOHandle, string_view Symbol);
125 
126   int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle);
127   void runAtExits(void *DSOHandle);
128 
129 private:
130   PerJITDylibState *getJITDylibStateByHeaderAddr(void *DSOHandle);
131   PerJITDylibState *getJITDylibStateByName(string_view Path);
132   PerJITDylibState &getOrCreateJITDylibState(MachOJITDylibInitializers &MOJDIs);
133 
134   Expected<ExecutorAddress> lookupSymbolInJITDylib(void *DSOHandle,
135                                                    string_view Symbol);
136 
137   Expected<MachOJITDylibInitializerSequence>
138   getJITDylibInitializersByName(string_view Path);
139   Expected<void *> dlopenInitialize(string_view Path, int Mode);
140   Error initializeJITDylib(MachOJITDylibInitializers &MOJDIs);
141 
142   static MachOPlatformRuntimeState *MOPS;
143 
144   using InitSectionHandler =
145       Error (*)(const std::vector<ExecutorAddressRange> &Sections,
146                 const MachOJITDylibInitializers &MOJDIs);
147   const std::vector<std::pair<string_view, InitSectionHandler>> InitSections = {
148       {"__DATA,__mod_init_func", runModInits}};
149 
150   // FIXME: Move to thread-state.
151   std::string DLFcnError;
152 
153   std::recursive_mutex JDStatesMutex;
154   std::unordered_map<void *, PerJITDylibState> JDStates;
155   std::unordered_map<std::string, void *> JDNameToHeader;
156 };
157 
158 MachOPlatformRuntimeState *MachOPlatformRuntimeState::MOPS = nullptr;
159 
160 void MachOPlatformRuntimeState::initialize() {
161   assert(!MOPS && "MachOPlatformRuntimeState should be null");
162   MOPS = new MachOPlatformRuntimeState();
163 }
164 
165 MachOPlatformRuntimeState &MachOPlatformRuntimeState::get() {
166   assert(MOPS && "MachOPlatformRuntimeState not initialized");
167   return *MOPS;
168 }
169 
170 void MachOPlatformRuntimeState::destroy() {
171   assert(MOPS && "MachOPlatformRuntimeState not initialized");
172   delete MOPS;
173 }
174 
175 Error MachOPlatformRuntimeState::registerObjectSections(
176     MachOPerObjectSectionsToRegister POSR) {
177   if (POSR.EHFrameSection.StartAddress)
178     walkEHFrameSection(POSR.EHFrameSection.toSpan<const char>(),
179                        __register_frame);
180 
181   return Error::success();
182 }
183 
184 Error MachOPlatformRuntimeState::deregisterObjectSections(
185     MachOPerObjectSectionsToRegister POSR) {
186   if (POSR.EHFrameSection.StartAddress)
187     walkEHFrameSection(POSR.EHFrameSection.toSpan<const char>(),
188                        __deregister_frame);
189 
190   return Error::success();
191 }
192 
193 const char *MachOPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); }
194 
195 void *MachOPlatformRuntimeState::dlopen(string_view Path, int Mode) {
196   std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
197 
198   // Use fast path if all JITDylibs are already loaded and don't require
199   // re-running initializers.
200   if (auto *JDS = getJITDylibStateByName(Path)) {
201     if (!JDS->AllowReinitialization) {
202       ++JDS->RefCount;
203       return JDS->Header;
204     }
205   }
206 
207   auto H = dlopenInitialize(Path, Mode);
208   if (!H) {
209     DLFcnError = toString(H.takeError());
210     return nullptr;
211   }
212 
213   return *H;
214 }
215 
216 int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
217   runAtExits(DSOHandle);
218   return 0;
219 }
220 
221 void *MachOPlatformRuntimeState::dlsym(void *DSOHandle, string_view Symbol) {
222   auto Addr = lookupSymbolInJITDylib(DSOHandle, Symbol);
223   if (!Addr) {
224     DLFcnError = toString(Addr.takeError());
225     return 0;
226   }
227 
228   return Addr->toPtr<void *>();
229 }
230 
231 int MachOPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg,
232                                               void *DSOHandle) {
233   // FIXME: Handle out-of-memory errors, returning -1 if OOM.
234   std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
235   auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle);
236   assert(JDS && "JITDylib state not initialized");
237   JDS->AtExits.push_back({F, Arg});
238   return 0;
239 }
240 
241 void MachOPlatformRuntimeState::runAtExits(void *DSOHandle) {
242   // FIXME: Should atexits be allowed to run concurrently with access to
243   // JDState?
244   AtExitsVector V;
245   {
246     std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex);
247     auto *JDS = getJITDylibStateByHeaderAddr(DSOHandle);
248     assert(JDS && "JITDlybi state not initialized");
249     std::swap(V, JDS->AtExits);
250   }
251 
252   while (!V.empty()) {
253     auto &AE = V.back();
254     AE.Func(AE.Arg);
255     V.pop_back();
256   }
257 }
258 
259 MachOPlatformRuntimeState::PerJITDylibState *
260 MachOPlatformRuntimeState::getJITDylibStateByHeaderAddr(void *DSOHandle) {
261   auto I = JDStates.find(DSOHandle);
262   if (I == JDStates.end())
263     return nullptr;
264   return &I->second;
265 }
266 
267 MachOPlatformRuntimeState::PerJITDylibState *
268 MachOPlatformRuntimeState::getJITDylibStateByName(string_view Name) {
269   // FIXME: Avoid creating string copy here.
270   auto I = JDNameToHeader.find(std::string(Name.data(), Name.size()));
271   if (I == JDNameToHeader.end())
272     return nullptr;
273   void *H = I->second;
274   auto J = JDStates.find(H);
275   assert(J != JDStates.end() &&
276          "JITDylib has name map entry but no header map entry");
277   return &J->second;
278 }
279 
280 MachOPlatformRuntimeState::PerJITDylibState &
281 MachOPlatformRuntimeState::getOrCreateJITDylibState(
282     MachOJITDylibInitializers &MOJDIs) {
283   void *Header = MOJDIs.MachOHeaderAddress.toPtr<void *>();
284 
285   auto &JDS = JDStates[Header];
286 
287   // If this entry hasn't been created yet.
288   if (!JDS.Header) {
289     assert(!JDNameToHeader.count(MOJDIs.Name) &&
290            "JITDylib has header map entry but no name map entry");
291     JDNameToHeader[MOJDIs.Name] = Header;
292     JDS.Header = Header;
293   }
294 
295   return JDS;
296 }
297 
298 Expected<ExecutorAddress>
299 MachOPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle,
300                                                   string_view Sym) {
301   Expected<ExecutorAddress> Result((ExecutorAddress()));
302   if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddress>(
303           SPSExecutorAddress,
304           SPSString)>::call(&__orc_rt_macho_symbol_lookup_tag, Result,
305                             ExecutorAddress::fromPtr(DSOHandle), Sym))
306     return std::move(Err);
307   return Result;
308 }
309 
310 Expected<MachOJITDylibInitializerSequence>
311 MachOPlatformRuntimeState::getJITDylibInitializersByName(string_view Path) {
312   Expected<MachOJITDylibInitializerSequence> Result(
313       (MachOJITDylibInitializerSequence()));
314   std::string PathStr(Path.data(), Path.size());
315   if (auto Err =
316           WrapperFunction<SPSExpected<SPSMachOJITDylibInitializerSequence>(
317               SPSString)>::call(&__orc_rt_macho_get_initializers_tag, Result,
318                                 Path))
319     return std::move(Err);
320   return Result;
321 }
322 
323 Expected<void *> MachOPlatformRuntimeState::dlopenInitialize(string_view Path,
324                                                              int Mode) {
325   // Either our JITDylib wasn't loaded, or it or one of its dependencies allows
326   // reinitialization. We need to call in to the JIT to see if there's any new
327   // work pending.
328   auto InitSeq = getJITDylibInitializersByName(Path);
329   if (!InitSeq)
330     return InitSeq.takeError();
331 
332   // Init sequences should be non-empty.
333   if (InitSeq->empty())
334     return make_error<StringError>(
335         "__orc_rt_macho_get_initializers returned an "
336         "empty init sequence");
337 
338   // Otherwise register and run initializers for each JITDylib.
339   for (auto &MOJDIs : *InitSeq)
340     if (auto Err = initializeJITDylib(MOJDIs))
341       return std::move(Err);
342 
343   // Return the header for the last item in the list.
344   auto *JDS = getJITDylibStateByHeaderAddr(
345       InitSeq->back().MachOHeaderAddress.toPtr<void *>());
346   assert(JDS && "Missing state entry for JD");
347   return JDS->Header;
348 }
349 
350 Error MachOPlatformRuntimeState::initializeJITDylib(
351     MachOJITDylibInitializers &MOJDIs) {
352 
353   auto &JDS = getOrCreateJITDylibState(MOJDIs);
354   ++JDS.RefCount;
355 
356   for (auto &KV : InitSections) {
357     const auto &Name = KV.first;
358     const auto &Handler = KV.second;
359     // FIXME: Remove copy once we have C++17.
360     auto I = MOJDIs.InitSections.find(to_string(Name));
361     if (I != MOJDIs.InitSections.end()) {
362       if (auto Err = Handler(I->second, MOJDIs))
363         return Err;
364     }
365   }
366 
367   return Error::success();
368 }
369 
370 } // end anonymous namespace
371 
372 //------------------------------------------------------------------------------
373 //                             JIT entry points
374 //------------------------------------------------------------------------------
375 
376 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
377 __orc_rt_macho_platform_bootstrap(char *ArgData, size_t ArgSize) {
378   MachOPlatformRuntimeState::initialize();
379   return WrapperFunctionResult().release();
380 }
381 
382 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
383 __orc_rt_macho_platform_shutdown(char *ArgData, size_t ArgSize) {
384   MachOPlatformRuntimeState::destroy();
385   return WrapperFunctionResult().release();
386 }
387 
388 /// Wrapper function for registering metadata on a per-object basis.
389 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
390 __orc_rt_macho_register_object_sections(char *ArgData, size_t ArgSize) {
391   return WrapperFunction<SPSError(SPSMachOPerObjectSectionsToRegister)>::handle(
392              ArgData, ArgSize,
393              [](MachOPerObjectSectionsToRegister &POSR) {
394                return MachOPlatformRuntimeState::get().registerObjectSections(
395                    std::move(POSR));
396              })
397       .release();
398 }
399 
400 /// Wrapper for releasing per-object metadat.
401 ORC_RT_INTERFACE __orc_rt_CWrapperFunctionResult
402 __orc_rt_macho_deregister_object_sections(char *ArgData, size_t ArgSize) {
403   return WrapperFunction<SPSError(SPSMachOPerObjectSectionsToRegister)>::handle(
404              ArgData, ArgSize,
405              [](MachOPerObjectSectionsToRegister &POSR) {
406                return MachOPlatformRuntimeState::get().deregisterObjectSections(
407                    std::move(POSR));
408              })
409       .release();
410 }
411 
412 //------------------------------------------------------------------------------
413 //                           cxa_atexit support
414 //------------------------------------------------------------------------------
415 
416 int __orc_rt_macho_cxa_atexit(void (*func)(void *), void *arg,
417                               void *dso_handle) {
418   return MachOPlatformRuntimeState::get().registerAtExit(func, arg, dso_handle);
419 }
420 
421 void __orc_rt_macho_cxa_finalize(void *dso_handle) {
422   MachOPlatformRuntimeState::get().runAtExits(dso_handle);
423 }
424 
425 //------------------------------------------------------------------------------
426 //                        JIT'd dlfcn alternatives.
427 //------------------------------------------------------------------------------
428 
429 const char *__orc_rt_macho_jit_dlerror() {
430   return MachOPlatformRuntimeState::get().dlerror();
431 }
432 
433 void *__orc_rt_macho_jit_dlopen(const char *path, int mode) {
434   return MachOPlatformRuntimeState::get().dlopen(path, mode);
435 }
436 
437 int __orc_rt_macho_jit_dlclose(void *dso_handle) {
438   return MachOPlatformRuntimeState::get().dlclose(dso_handle);
439 }
440 
441 void *__orc_rt_macho_jit_dlsym(void *dso_handle, const char *symbol) {
442   return MachOPlatformRuntimeState::get().dlsym(dso_handle, symbol);
443 }
444 
445 //------------------------------------------------------------------------------
446 //                             MachO Run Program
447 //------------------------------------------------------------------------------
448 
449 ORC_RT_INTERFACE int64_t __orc_rt_macho_run_program(const char *JITDylibName,
450                                                     const char *EntrySymbolName,
451                                                     int argc, char *argv[]) {
452   using MainTy = int (*)(int, char *[]);
453 
454   void *H = __orc_rt_macho_jit_dlopen(JITDylibName,
455                                       __orc_rt::macho::ORC_RT_RTLD_LAZY);
456   if (!H) {
457     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
458     return -1;
459   }
460 
461   auto *Main =
462       reinterpret_cast<MainTy>(__orc_rt_macho_jit_dlsym(H, EntrySymbolName));
463 
464   if (!Main) {
465     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
466     return -1;
467   }
468 
469   int Result = Main(argc, argv);
470 
471   if (__orc_rt_macho_jit_dlclose(H) == -1)
472     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
473 
474   return Result;
475 }
476