xref: /freebsd/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.cpp (revision 5fb307d29b364982acbde82cbf77db3cae486f8c)
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 "debug.h"
16 #include "error.h"
17 #include "interval_map.h"
18 #include "wrapper_function_utils.h"
19 
20 #include <algorithm>
21 #include <ios>
22 #include <map>
23 #include <mutex>
24 #include <sstream>
25 #include <string_view>
26 #include <unordered_map>
27 #include <unordered_set>
28 #include <vector>
29 
30 #define DEBUG_TYPE "macho_platform"
31 
32 using namespace __orc_rt;
33 using namespace __orc_rt::macho;
34 
35 // Declare function tags for functions in the JIT process.
36 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_push_initializers_tag)
37 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_symbol_lookup_tag)
38 
39 struct objc_image_info;
40 struct mach_header;
41 
42 // Objective-C registration functions.
43 // These are weakly imported. If the Objective-C runtime has not been loaded
44 // then code containing Objective-C sections will generate an error.
45 extern "C" void
46 _objc_map_images(unsigned count, const char *const paths[],
47                  const mach_header *const mhdrs[]) ORC_RT_WEAK_IMPORT;
48 
49 extern "C" void _objc_load_image(const char *path,
50                                  const mach_header *mh) ORC_RT_WEAK_IMPORT;
51 
52 // Libunwind prototypes.
53 struct unw_dynamic_unwind_sections {
54   uintptr_t dso_base;
55   uintptr_t dwarf_section;
56   size_t dwarf_section_length;
57   uintptr_t compact_unwind_section;
58   size_t compact_unwind_section_length;
59 };
60 
61 typedef int (*unw_find_dynamic_unwind_sections)(
62     uintptr_t addr, struct unw_dynamic_unwind_sections *info);
63 
64 extern "C" int __unw_add_find_dynamic_unwind_sections(
65     unw_find_dynamic_unwind_sections find_dynamic_unwind_sections)
66     ORC_RT_WEAK_IMPORT;
67 
68 extern "C" int __unw_remove_find_dynamic_unwind_sections(
69     unw_find_dynamic_unwind_sections find_dynamic_unwind_sections)
70     ORC_RT_WEAK_IMPORT;
71 
72 namespace {
73 
74 struct MachOJITDylibDepInfo {
75   bool Sealed = false;
76   std::vector<ExecutorAddr> DepHeaders;
77 };
78 
79 using MachOJITDylibDepInfoMap =
80     std::unordered_map<ExecutorAddr, MachOJITDylibDepInfo>;
81 
82 } // anonymous namespace
83 
84 namespace __orc_rt {
85 
86 using SPSMachOObjectPlatformSectionsMap =
87     SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>;
88 
89 using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
90 
91 using SPSMachOJITDylibDepInfoMap =
92     SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
93 
94 template <>
95 class SPSSerializationTraits<SPSMachOJITDylibDepInfo, MachOJITDylibDepInfo> {
96 public:
97   static size_t size(const MachOJITDylibDepInfo &JDI) {
98     return SPSMachOJITDylibDepInfo::AsArgList::size(JDI.Sealed, JDI.DepHeaders);
99   }
100 
101   static bool serialize(SPSOutputBuffer &OB, const MachOJITDylibDepInfo &JDI) {
102     return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, JDI.Sealed,
103                                                          JDI.DepHeaders);
104   }
105 
106   static bool deserialize(SPSInputBuffer &IB, MachOJITDylibDepInfo &JDI) {
107     return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, JDI.Sealed,
108                                                            JDI.DepHeaders);
109   }
110 };
111 
112 struct UnwindSectionInfo {
113   std::vector<ExecutorAddrRange> CodeRanges;
114   ExecutorAddrRange DwarfSection;
115   ExecutorAddrRange CompactUnwindSection;
116 };
117 
118 using SPSUnwindSectionInfo =
119     SPSTuple<SPSSequence<SPSExecutorAddrRange>, SPSExecutorAddrRange,
120              SPSExecutorAddrRange>;
121 
122 template <>
123 class SPSSerializationTraits<SPSUnwindSectionInfo, UnwindSectionInfo> {
124 public:
125   static size_t size(const UnwindSectionInfo &USI) {
126     return SPSUnwindSectionInfo::AsArgList::size(
127         USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
128   }
129 
130   static bool serialize(SPSOutputBuffer &OB, const UnwindSectionInfo &USI) {
131     return SPSUnwindSectionInfo::AsArgList::serialize(
132         OB, USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
133   }
134 
135   static bool deserialize(SPSInputBuffer &IB, UnwindSectionInfo &USI) {
136     return SPSUnwindSectionInfo::AsArgList::deserialize(
137         IB, USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
138   }
139 };
140 
141 } // namespace __orc_rt
142 
143 namespace {
144 struct TLVDescriptor {
145   void *(*Thunk)(TLVDescriptor *) = nullptr;
146   unsigned long Key = 0;
147   unsigned long DataAddress = 0;
148 };
149 
150 class MachOPlatformRuntimeState {
151 private:
152   struct AtExitEntry {
153     void (*Func)(void *);
154     void *Arg;
155   };
156 
157   using AtExitsVector = std::vector<AtExitEntry>;
158 
159   /// Used to manage sections of fixed-sized metadata records (e.g. pointer
160   /// sections, selector refs, etc.)
161   template <typename RecordElement> class RecordSectionsTracker {
162   public:
163     /// Add a section to the "new" list.
164     void add(span<RecordElement> Sec) { New.push_back(std::move(Sec)); }
165 
166     /// Returns true if there are new sections to process.
167     bool hasNewSections() const { return !New.empty(); }
168 
169     /// Returns the number of new sections to process.
170     size_t numNewSections() const { return New.size(); }
171 
172     /// Process all new sections.
173     template <typename ProcessSectionFunc>
174     std::enable_if_t<std::is_void_v<
175         std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>>
176     processNewSections(ProcessSectionFunc &&ProcessSection) {
177       for (auto &Sec : New)
178         ProcessSection(Sec);
179       moveNewToProcessed();
180     }
181 
182     /// Proces all new sections with a fallible handler.
183     ///
184     /// Successfully handled sections will be moved to the Processed
185     /// list.
186     template <typename ProcessSectionFunc>
187     std::enable_if_t<
188         std::is_same_v<Error, std::invoke_result_t<ProcessSectionFunc,
189                                                    span<RecordElement>>>,
190         Error>
191     processNewSections(ProcessSectionFunc &&ProcessSection) {
192       for (size_t I = 0; I != New.size(); ++I) {
193         if (auto Err = ProcessSection(New[I])) {
194           for (size_t J = 0; J != I; ++J)
195             Processed.push_back(New[J]);
196           New.erase(New.begin(), New.begin() + I);
197           return Err;
198         }
199       }
200       moveNewToProcessed();
201       return Error::success();
202     }
203 
204     /// Move all sections back to New for reprocessing.
205     void reset() {
206       moveNewToProcessed();
207       New = std::move(Processed);
208     }
209 
210     /// Remove the section with the given range.
211     bool removeIfPresent(ExecutorAddrRange R) {
212       if (removeIfPresent(New, R))
213         return true;
214       return removeIfPresent(Processed, R);
215     }
216 
217   private:
218     void moveNewToProcessed() {
219       if (Processed.empty())
220         Processed = std::move(New);
221       else {
222         Processed.reserve(Processed.size() + New.size());
223         std::copy(New.begin(), New.end(), std::back_inserter(Processed));
224         New.clear();
225       }
226     }
227 
228     bool removeIfPresent(std::vector<span<RecordElement>> &V,
229                          ExecutorAddrRange R) {
230       auto RI = std::find_if(
231           V.rbegin(), V.rend(),
232           [RS = R.toSpan<RecordElement>()](const span<RecordElement> &E) {
233             return E.data() == RS.data();
234           });
235       if (RI != V.rend()) {
236         V.erase(std::next(RI).base());
237         return true;
238       }
239       return false;
240     }
241 
242     std::vector<span<RecordElement>> Processed;
243     std::vector<span<RecordElement>> New;
244   };
245 
246   struct UnwindSections {
247     UnwindSections(const UnwindSectionInfo &USI)
248         : DwarfSection(USI.DwarfSection.toSpan<char>()),
249           CompactUnwindSection(USI.CompactUnwindSection.toSpan<char>()) {}
250 
251     span<char> DwarfSection;
252     span<char> CompactUnwindSection;
253   };
254 
255   using UnwindSectionsMap =
256       IntervalMap<char *, UnwindSections, IntervalCoalescing::Disabled>;
257 
258   struct JITDylibState {
259     std::string Name;
260     void *Header = nullptr;
261     bool Sealed = false;
262     size_t LinkedAgainstRefCount = 0;
263     size_t DlRefCount = 0;
264     std::vector<JITDylibState *> Deps;
265     AtExitsVector AtExits;
266     const objc_image_info *ObjCImageInfo = nullptr;
267     std::unordered_map<void *, std::vector<char>> DataSectionContent;
268     std::unordered_map<void *, size_t> ZeroInitRanges;
269     UnwindSectionsMap UnwindSections;
270     RecordSectionsTracker<void (*)()> ModInitsSections;
271     RecordSectionsTracker<char> ObjCRuntimeRegistrationObjects;
272 
273     bool referenced() const {
274       return LinkedAgainstRefCount != 0 || DlRefCount != 0;
275     }
276   };
277 
278 public:
279   static Error create();
280   static MachOPlatformRuntimeState &get();
281   static Error destroy();
282 
283   MachOPlatformRuntimeState() = default;
284 
285   // Delete copy and move constructors.
286   MachOPlatformRuntimeState(const MachOPlatformRuntimeState &) = delete;
287   MachOPlatformRuntimeState &
288   operator=(const MachOPlatformRuntimeState &) = delete;
289   MachOPlatformRuntimeState(MachOPlatformRuntimeState &&) = delete;
290   MachOPlatformRuntimeState &operator=(MachOPlatformRuntimeState &&) = delete;
291 
292   Error initialize();
293   Error shutdown();
294 
295   Error registerJITDylib(std::string Name, void *Header);
296   Error deregisterJITDylib(void *Header);
297   Error registerThreadDataSection(span<const char> ThreadDataSection);
298   Error deregisterThreadDataSection(span<const char> ThreadDataSection);
299   Error registerObjectPlatformSections(
300       ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindSections,
301       std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs);
302   Error deregisterObjectPlatformSections(
303       ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindSections,
304       std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs);
305 
306   const char *dlerror();
307   void *dlopen(std::string_view Name, int Mode);
308   int dlclose(void *DSOHandle);
309   void *dlsym(void *DSOHandle, std::string_view Symbol);
310 
311   int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle);
312   void runAtExits(std::unique_lock<std::mutex> &JDStatesLock,
313                   JITDylibState &JDS);
314   void runAtExits(void *DSOHandle);
315 
316   /// Returns the base address of the section containing ThreadData.
317   Expected<std::pair<const char *, size_t>>
318   getThreadDataSectionFor(const char *ThreadData);
319 
320 private:
321   JITDylibState *getJITDylibStateByHeader(void *DSOHandle);
322   JITDylibState *getJITDylibStateByName(std::string_view Path);
323 
324   Expected<ExecutorAddr> lookupSymbolInJITDylib(void *DSOHandle,
325                                                 std::string_view Symbol);
326 
327   bool lookupUnwindSections(void *Addr, unw_dynamic_unwind_sections &Info);
328 
329   static int findDynamicUnwindSections(uintptr_t addr,
330                                        unw_dynamic_unwind_sections *info);
331   static Error registerEHFrames(span<const char> EHFrameSection);
332   static Error deregisterEHFrames(span<const char> EHFrameSection);
333 
334   static Error registerObjCRegistrationObjects(JITDylibState &JDS);
335   static Error runModInits(std::unique_lock<std::mutex> &JDStatesLock,
336                            JITDylibState &JDS);
337 
338   Expected<void *> dlopenImpl(std::string_view Path, int Mode);
339   Error dlopenFull(std::unique_lock<std::mutex> &JDStatesLock,
340                    JITDylibState &JDS);
341   Error dlopenInitialize(std::unique_lock<std::mutex> &JDStatesLock,
342                          JITDylibState &JDS, MachOJITDylibDepInfoMap &DepInfo);
343 
344   Error dlcloseImpl(void *DSOHandle);
345   Error dlcloseDeinitialize(std::unique_lock<std::mutex> &JDStatesLock,
346                             JITDylibState &JDS);
347 
348   static MachOPlatformRuntimeState *MOPS;
349 
350   bool UseCallbackStyleUnwindInfo = false;
351 
352   // FIXME: Move to thread-state.
353   std::string DLFcnError;
354 
355   // APIMutex guards against concurrent entry into key "dyld" API functions
356   // (e.g. dlopen, dlclose).
357   std::recursive_mutex DyldAPIMutex;
358 
359   // JDStatesMutex guards the data structures that hold JITDylib state.
360   std::mutex JDStatesMutex;
361   std::unordered_map<void *, JITDylibState> JDStates;
362   std::unordered_map<std::string_view, void *> JDNameToHeader;
363 
364   // ThreadDataSectionsMutex guards thread local data section state.
365   std::mutex ThreadDataSectionsMutex;
366   std::map<const char *, size_t> ThreadDataSections;
367 };
368 
369 MachOPlatformRuntimeState *MachOPlatformRuntimeState::MOPS = nullptr;
370 
371 Error MachOPlatformRuntimeState::create() {
372   assert(!MOPS && "MachOPlatformRuntimeState should be null");
373   MOPS = new MachOPlatformRuntimeState();
374   return MOPS->initialize();
375 }
376 
377 MachOPlatformRuntimeState &MachOPlatformRuntimeState::get() {
378   assert(MOPS && "MachOPlatformRuntimeState not initialized");
379   return *MOPS;
380 }
381 
382 Error MachOPlatformRuntimeState::destroy() {
383   assert(MOPS && "MachOPlatformRuntimeState not initialized");
384   auto Err = MOPS->shutdown();
385   delete MOPS;
386   return Err;
387 }
388 
389 Error MachOPlatformRuntimeState::initialize() {
390   UseCallbackStyleUnwindInfo = __unw_add_find_dynamic_unwind_sections &&
391                                __unw_remove_find_dynamic_unwind_sections;
392   if (UseCallbackStyleUnwindInfo) {
393     ORC_RT_DEBUG({
394       printdbg("__unw_add/remove_find_dynamic_unwind_sections available."
395                " Using callback-based frame info lookup.\n");
396     });
397     if (__unw_add_find_dynamic_unwind_sections(&findDynamicUnwindSections))
398       return make_error<StringError>(
399           "Could not register findDynamicUnwindSections");
400   } else {
401     ORC_RT_DEBUG({
402       printdbg("__unw_add/remove_find_dynamic_unwind_sections not available."
403                " Using classic frame info registration.\n");
404     });
405   }
406   return Error::success();
407 }
408 
409 Error MachOPlatformRuntimeState::shutdown() {
410   if (UseCallbackStyleUnwindInfo) {
411     if (__unw_remove_find_dynamic_unwind_sections(&findDynamicUnwindSections)) {
412       ORC_RT_DEBUG(
413           { printdbg("__unw_remove_find_dynamic_unwind_sections failed.\n"); });
414     }
415   }
416   return Error::success();
417 }
418 
419 Error MachOPlatformRuntimeState::registerJITDylib(std::string Name,
420                                                   void *Header) {
421   ORC_RT_DEBUG({
422     printdbg("Registering JITDylib %s: Header = %p\n", Name.c_str(), Header);
423   });
424   std::lock_guard<std::mutex> Lock(JDStatesMutex);
425   if (JDStates.count(Header)) {
426     std::ostringstream ErrStream;
427     ErrStream << "Duplicate JITDylib registration for header " << Header
428               << " (name = " << Name << ")";
429     return make_error<StringError>(ErrStream.str());
430   }
431   if (JDNameToHeader.count(Name)) {
432     std::ostringstream ErrStream;
433     ErrStream << "Duplicate JITDylib registration for header " << Header
434               << " (header = " << Header << ")";
435     return make_error<StringError>(ErrStream.str());
436   }
437 
438   auto &JDS = JDStates[Header];
439   JDS.Name = std::move(Name);
440   JDS.Header = Header;
441   JDNameToHeader[JDS.Name] = Header;
442   return Error::success();
443 }
444 
445 Error MachOPlatformRuntimeState::deregisterJITDylib(void *Header) {
446   std::lock_guard<std::mutex> Lock(JDStatesMutex);
447   auto I = JDStates.find(Header);
448   if (I == JDStates.end()) {
449     std::ostringstream ErrStream;
450     ErrStream << "Attempted to deregister unrecognized header " << Header;
451     return make_error<StringError>(ErrStream.str());
452   }
453 
454   // Remove std::string construction once we can use C++20.
455   auto J = JDNameToHeader.find(
456       std::string(I->second.Name.data(), I->second.Name.size()));
457   assert(J != JDNameToHeader.end() &&
458          "Missing JDNameToHeader entry for JITDylib");
459 
460   ORC_RT_DEBUG({
461     printdbg("Deregistering JITDylib %s: Header = %p\n", I->second.Name.c_str(),
462              Header);
463   });
464 
465   JDNameToHeader.erase(J);
466   JDStates.erase(I);
467   return Error::success();
468 }
469 
470 Error MachOPlatformRuntimeState::registerThreadDataSection(
471     span<const char> ThreadDataSection) {
472   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
473   auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());
474   if (I != ThreadDataSections.begin()) {
475     auto J = std::prev(I);
476     if (J->first + J->second > ThreadDataSection.data())
477       return make_error<StringError>("Overlapping __thread_data sections");
478   }
479   ThreadDataSections.insert(
480       I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));
481   return Error::success();
482 }
483 
484 Error MachOPlatformRuntimeState::deregisterThreadDataSection(
485     span<const char> ThreadDataSection) {
486   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
487   auto I = ThreadDataSections.find(ThreadDataSection.data());
488   if (I == ThreadDataSections.end())
489     return make_error<StringError>("Attempt to deregister unknown thread data "
490                                    "section");
491   ThreadDataSections.erase(I);
492   return Error::success();
493 }
494 
495 Error MachOPlatformRuntimeState::registerObjectPlatformSections(
496     ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindInfo,
497     std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) {
498 
499   // FIXME: Reject platform section registration after the JITDylib is
500   // sealed?
501 
502   ORC_RT_DEBUG({
503     printdbg("MachOPlatform: Registering object sections for %p.\n",
504              HeaderAddr.toPtr<void *>());
505   });
506 
507   std::lock_guard<std::mutex> Lock(JDStatesMutex);
508   auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
509   if (!JDS) {
510     std::ostringstream ErrStream;
511     ErrStream << "Could not register object platform sections for "
512                  "unrecognized header "
513               << HeaderAddr.toPtr<void *>();
514     return make_error<StringError>(ErrStream.str());
515   }
516 
517   if (UnwindInfo && UseCallbackStyleUnwindInfo) {
518     ORC_RT_DEBUG({
519       printdbg("  Registering new-style unwind info for:\n"
520                "    DWARF: %p -- %p\n"
521                "    Compact-unwind: %p -- %p\n"
522                "  for:\n",
523                UnwindInfo->DwarfSection.Start.toPtr<void *>(),
524                UnwindInfo->DwarfSection.End.toPtr<void *>(),
525                UnwindInfo->CompactUnwindSection.Start.toPtr<void *>(),
526                UnwindInfo->CompactUnwindSection.End.toPtr<void *>());
527     });
528     for (auto &CodeRange : UnwindInfo->CodeRanges) {
529       JDS->UnwindSections.insert(CodeRange.Start.toPtr<char *>(),
530                                  CodeRange.End.toPtr<char *>(), *UnwindInfo);
531       ORC_RT_DEBUG({
532         printdbg("    [ %p -- %p ]\n", CodeRange.Start.toPtr<void *>(),
533                  CodeRange.End.toPtr<void *>());
534       });
535     }
536   }
537 
538   for (auto &KV : Secs) {
539     // FIXME: Validate section ranges?
540     if (KV.first == "__TEXT,__eh_frame") {
541       if (!UseCallbackStyleUnwindInfo) {
542         // Use classic libunwind registration.
543         if (auto Err = registerEHFrames(KV.second.toSpan<const char>()))
544           return Err;
545       }
546     } else if (KV.first == "__DATA,__data") {
547       assert(!JDS->DataSectionContent.count(KV.second.Start.toPtr<char *>()) &&
548              "Address already registered.");
549       auto S = KV.second.toSpan<char>();
550       JDS->DataSectionContent[KV.second.Start.toPtr<char *>()] =
551           std::vector<char>(S.begin(), S.end());
552     } else if (KV.first == "__DATA,__common") {
553       JDS->ZeroInitRanges[KV.second.Start.toPtr<char *>()] = KV.second.size();
554     } else if (KV.first == "__DATA,__thread_data") {
555       if (auto Err = registerThreadDataSection(KV.second.toSpan<const char>()))
556         return Err;
557     } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
558       JDS->ObjCRuntimeRegistrationObjects.add(KV.second.toSpan<char>());
559     else if (KV.first == "__DATA,__mod_init_func")
560       JDS->ModInitsSections.add(KV.second.toSpan<void (*)()>());
561     else {
562       // Should this be a warning instead?
563       return make_error<StringError>(
564           "Encountered unexpected section " +
565           std::string(KV.first.data(), KV.first.size()) +
566           " while registering object platform sections");
567     }
568   }
569 
570   return Error::success();
571 }
572 
573 Error MachOPlatformRuntimeState::deregisterObjectPlatformSections(
574     ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindInfo,
575     std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) {
576   // TODO: Make this more efficient? (maybe unnecessary if removal is rare?)
577   // TODO: Add a JITDylib prepare-for-teardown operation that clears all
578   //       registered sections, causing this function to take the fast-path.
579   ORC_RT_DEBUG({
580     printdbg("MachOPlatform: Registering object sections for %p.\n",
581              HeaderAddr.toPtr<void *>());
582   });
583 
584   std::lock_guard<std::mutex> Lock(JDStatesMutex);
585   auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
586   if (!JDS) {
587     std::ostringstream ErrStream;
588     ErrStream << "Could not register object platform sections for unrecognized "
589                  "header "
590               << HeaderAddr.toPtr<void *>();
591     return make_error<StringError>(ErrStream.str());
592   }
593 
594   // FIXME: Implement faster-path by returning immediately if JDS is being
595   // torn down entirely?
596 
597   // TODO: Make library permanent (i.e. not able to be dlclosed) if it contains
598   // any Swift or ObjC. Once this happens we can clear (and no longer record)
599   // data section content, as the library could never be re-initialized.
600 
601   if (UnwindInfo && UseCallbackStyleUnwindInfo) {
602     ORC_RT_DEBUG({
603       printdbg("  Deregistering new-style unwind info for:\n"
604                "    DWARF: %p -- %p\n"
605                "    Compact-unwind: %p -- %p\n"
606                "  for:\n",
607                UnwindInfo->DwarfSection.Start.toPtr<void *>(),
608                UnwindInfo->DwarfSection.End.toPtr<void *>(),
609                UnwindInfo->CompactUnwindSection.Start.toPtr<void *>(),
610                UnwindInfo->CompactUnwindSection.End.toPtr<void *>());
611     });
612     for (auto &CodeRange : UnwindInfo->CodeRanges) {
613       JDS->UnwindSections.erase(CodeRange.Start.toPtr<char *>(),
614                                 CodeRange.End.toPtr<char *>());
615       ORC_RT_DEBUG({
616         printdbg("    [ %p -- %p ]\n", CodeRange.Start.toPtr<void *>(),
617                  CodeRange.End.toPtr<void *>());
618       });
619     }
620   }
621 
622   for (auto &KV : Secs) {
623     // FIXME: Validate section ranges?
624     if (KV.first == "__TEXT,__eh_frame") {
625       if (!UseCallbackStyleUnwindInfo) {
626         // Use classic libunwind registration.
627         if (auto Err = deregisterEHFrames(KV.second.toSpan<const char>()))
628           return Err;
629       }
630     } else if (KV.first == "__DATA,__data") {
631       JDS->DataSectionContent.erase(KV.second.Start.toPtr<char *>());
632     } else if (KV.first == "__DATA,__common") {
633       JDS->ZeroInitRanges.erase(KV.second.Start.toPtr<char *>());
634     } else if (KV.first == "__DATA,__thread_data") {
635       if (auto Err =
636               deregisterThreadDataSection(KV.second.toSpan<const char>()))
637         return Err;
638     } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
639       JDS->ObjCRuntimeRegistrationObjects.removeIfPresent(KV.second);
640     else if (KV.first == "__DATA,__mod_init_func")
641       JDS->ModInitsSections.removeIfPresent(KV.second);
642     else {
643       // Should this be a warning instead?
644       return make_error<StringError>(
645           "Encountered unexpected section " +
646           std::string(KV.first.data(), KV.first.size()) +
647           " while deregistering object platform sections");
648     }
649   }
650   return Error::success();
651 }
652 
653 const char *MachOPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); }
654 
655 void *MachOPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {
656   ORC_RT_DEBUG({
657     std::string S(Path.data(), Path.size());
658     printdbg("MachOPlatform::dlopen(\"%s\")\n", S.c_str());
659   });
660   std::lock_guard<std::recursive_mutex> Lock(DyldAPIMutex);
661   if (auto H = dlopenImpl(Path, Mode))
662     return *H;
663   else {
664     // FIXME: Make dlerror thread safe.
665     DLFcnError = toString(H.takeError());
666     return nullptr;
667   }
668 }
669 
670 int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
671   ORC_RT_DEBUG({
672     auto *JDS = getJITDylibStateByHeader(DSOHandle);
673     std::string DylibName;
674     if (JDS) {
675       std::string S;
676       printdbg("MachOPlatform::dlclose(%p) (%s)\n", DSOHandle, S.c_str());
677     } else
678       printdbg("MachOPlatform::dlclose(%p) (%s)\n", DSOHandle,
679                "invalid handle");
680   });
681   std::lock_guard<std::recursive_mutex> Lock(DyldAPIMutex);
682   if (auto Err = dlcloseImpl(DSOHandle)) {
683     // FIXME: Make dlerror thread safe.
684     DLFcnError = toString(std::move(Err));
685     return -1;
686   }
687   return 0;
688 }
689 
690 void *MachOPlatformRuntimeState::dlsym(void *DSOHandle,
691                                        std::string_view Symbol) {
692   auto Addr = lookupSymbolInJITDylib(DSOHandle, Symbol);
693   if (!Addr) {
694     DLFcnError = toString(Addr.takeError());
695     return 0;
696   }
697 
698   return Addr->toPtr<void *>();
699 }
700 
701 int MachOPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg,
702                                               void *DSOHandle) {
703   // FIXME: Handle out-of-memory errors, returning -1 if OOM.
704   std::lock_guard<std::mutex> Lock(JDStatesMutex);
705   auto *JDS = getJITDylibStateByHeader(DSOHandle);
706   if (!JDS) {
707     ORC_RT_DEBUG({
708       printdbg("MachOPlatformRuntimeState::registerAtExit called with "
709                "unrecognized dso handle %p\n",
710                DSOHandle);
711     });
712     return -1;
713   }
714   JDS->AtExits.push_back({F, Arg});
715   return 0;
716 }
717 
718 void MachOPlatformRuntimeState::runAtExits(
719     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
720   auto AtExits = std::move(JDS.AtExits);
721 
722   // Unlock while running atexits, as they may trigger operations that modify
723   // JDStates.
724   JDStatesLock.unlock();
725   while (!AtExits.empty()) {
726     auto &AE = AtExits.back();
727     AE.Func(AE.Arg);
728     AtExits.pop_back();
729   }
730   JDStatesLock.lock();
731 }
732 
733 void MachOPlatformRuntimeState::runAtExits(void *DSOHandle) {
734   std::unique_lock<std::mutex> Lock(JDStatesMutex);
735   auto *JDS = getJITDylibStateByHeader(DSOHandle);
736   ORC_RT_DEBUG({
737     printdbg("MachOPlatformRuntimeState::runAtExits called on unrecognized "
738              "dso_handle %p\n",
739              DSOHandle);
740   });
741   if (JDS)
742     runAtExits(Lock, *JDS);
743 }
744 
745 Expected<std::pair<const char *, size_t>>
746 MachOPlatformRuntimeState::getThreadDataSectionFor(const char *ThreadData) {
747   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
748   auto I = ThreadDataSections.upper_bound(ThreadData);
749   // Check that we have a valid entry covering this address.
750   if (I == ThreadDataSections.begin())
751     return make_error<StringError>("No thread local data section for key");
752   I = std::prev(I);
753   if (ThreadData >= I->first + I->second)
754     return make_error<StringError>("No thread local data section for key");
755   return *I;
756 }
757 
758 MachOPlatformRuntimeState::JITDylibState *
759 MachOPlatformRuntimeState::getJITDylibStateByHeader(void *DSOHandle) {
760   auto I = JDStates.find(DSOHandle);
761   if (I == JDStates.end()) {
762     I = JDStates.insert(std::make_pair(DSOHandle, JITDylibState())).first;
763     I->second.Header = DSOHandle;
764   }
765   return &I->second;
766 }
767 
768 MachOPlatformRuntimeState::JITDylibState *
769 MachOPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) {
770   // FIXME: Avoid creating string once we have C++20.
771   auto I = JDNameToHeader.find(std::string(Name.data(), Name.size()));
772   if (I != JDNameToHeader.end())
773     return getJITDylibStateByHeader(I->second);
774   return nullptr;
775 }
776 
777 Expected<ExecutorAddr>
778 MachOPlatformRuntimeState::lookupSymbolInJITDylib(void *DSOHandle,
779                                                   std::string_view Sym) {
780   Expected<ExecutorAddr> Result((ExecutorAddr()));
781   if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddr>(
782           SPSExecutorAddr, SPSString)>::call(&__orc_rt_macho_symbol_lookup_tag,
783                                              Result,
784                                              ExecutorAddr::fromPtr(DSOHandle),
785                                              Sym))
786     return std::move(Err);
787   return Result;
788 }
789 
790 // eh-frame registration functions.
791 // We expect these to be available for all processes.
792 extern "C" void __register_frame(const void *);
793 extern "C" void __deregister_frame(const void *);
794 
795 template <typename HandleFDEFn>
796 void walkEHFrameSection(span<const char> EHFrameSection,
797                         HandleFDEFn HandleFDE) {
798   const char *CurCFIRecord = EHFrameSection.data();
799   uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
800 
801   while (CurCFIRecord != EHFrameSection.end() && Size != 0) {
802     const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
803     if (Size == 0xffffffff)
804       Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
805     else
806       Size += 4;
807     uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
808 
809     if (Offset != 0)
810       HandleFDE(CurCFIRecord);
811 
812     CurCFIRecord += Size;
813     Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
814   }
815 }
816 
817 bool MachOPlatformRuntimeState::lookupUnwindSections(
818     void *Addr, unw_dynamic_unwind_sections &Info) {
819   ORC_RT_DEBUG(
820       { printdbg("Tried to lookup unwind-info via new lookup call.\n"); });
821   std::lock_guard<std::mutex> Lock(JDStatesMutex);
822   for (auto &KV : JDStates) {
823     auto &JD = KV.second;
824     auto I = JD.UnwindSections.find(reinterpret_cast<char *>(Addr));
825     if (I != JD.UnwindSections.end()) {
826       Info.dso_base = reinterpret_cast<uintptr_t>(JD.Header);
827       Info.dwarf_section =
828           reinterpret_cast<uintptr_t>(I->second.DwarfSection.data());
829       Info.dwarf_section_length = I->second.DwarfSection.size();
830       Info.compact_unwind_section =
831           reinterpret_cast<uintptr_t>(I->second.CompactUnwindSection.data());
832       Info.compact_unwind_section_length =
833           I->second.CompactUnwindSection.size();
834       return true;
835     }
836   }
837   return false;
838 }
839 
840 int MachOPlatformRuntimeState::findDynamicUnwindSections(
841     uintptr_t addr, unw_dynamic_unwind_sections *info) {
842   if (!info)
843     return 0;
844   return MachOPlatformRuntimeState::get().lookupUnwindSections((void *)addr,
845                                                                *info);
846 }
847 
848 Error MachOPlatformRuntimeState::registerEHFrames(
849     span<const char> EHFrameSection) {
850   walkEHFrameSection(EHFrameSection, __register_frame);
851   return Error::success();
852 }
853 
854 Error MachOPlatformRuntimeState::deregisterEHFrames(
855     span<const char> EHFrameSection) {
856   walkEHFrameSection(EHFrameSection, __deregister_frame);
857   return Error::success();
858 }
859 
860 Error MachOPlatformRuntimeState::registerObjCRegistrationObjects(
861     JITDylibState &JDS) {
862   ORC_RT_DEBUG(printdbg("Registering Objective-C / Swift metadata.\n"));
863 
864   std::vector<char *> RegObjBases;
865   JDS.ObjCRuntimeRegistrationObjects.processNewSections(
866       [&](span<char> RegObj) { RegObjBases.push_back(RegObj.data()); });
867 
868   if (RegObjBases.empty())
869     return Error::success();
870 
871   if (!_objc_map_images || !_objc_load_image)
872     return make_error<StringError>(
873         "Could not register Objective-C / Swift metadata: _objc_map_images / "
874         "_objc_load_image not found");
875 
876   std::vector<char *> Paths;
877   Paths.resize(RegObjBases.size());
878   _objc_map_images(RegObjBases.size(), Paths.data(),
879                    reinterpret_cast<mach_header **>(RegObjBases.data()));
880 
881   for (void *RegObjBase : RegObjBases)
882     _objc_load_image(nullptr, reinterpret_cast<mach_header *>(RegObjBase));
883 
884   return Error::success();
885 }
886 
887 Error MachOPlatformRuntimeState::runModInits(
888     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
889   std::vector<span<void (*)()>> InitSections;
890   InitSections.reserve(JDS.ModInitsSections.numNewSections());
891 
892   // Copy initializer sections: If the JITDylib is unsealed then the
893   // initializers could reach back into the JIT and cause more initializers to
894   // be added.
895   // FIXME: Skip unlock and run in-place on sealed JITDylibs?
896   JDS.ModInitsSections.processNewSections(
897       [&](span<void (*)()> Inits) { InitSections.push_back(Inits); });
898 
899   JDStatesLock.unlock();
900   for (auto InitSec : InitSections)
901     for (auto *Init : InitSec)
902       Init();
903   JDStatesLock.lock();
904 
905   return Error::success();
906 }
907 
908 Expected<void *> MachOPlatformRuntimeState::dlopenImpl(std::string_view Path,
909                                                        int Mode) {
910   std::unique_lock<std::mutex> Lock(JDStatesMutex);
911 
912   // Try to find JITDylib state by name.
913   auto *JDS = getJITDylibStateByName(Path);
914 
915   if (!JDS)
916     return make_error<StringError>("No registered JTIDylib for path " +
917                                    std::string(Path.data(), Path.size()));
918 
919   // If this JITDylib is unsealed, or this is the first dlopen then run
920   // full dlopen path (update deps, push and run initializers, update ref
921   // counts on all JITDylibs in the dep tree).
922   if (!JDS->referenced() || !JDS->Sealed) {
923     if (auto Err = dlopenFull(Lock, *JDS))
924       return std::move(Err);
925   }
926 
927   // Bump the ref-count on this dylib.
928   ++JDS->DlRefCount;
929 
930   // Return the header address.
931   return JDS->Header;
932 }
933 
934 Error MachOPlatformRuntimeState::dlopenFull(
935     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
936   // Call back to the JIT to push the initializers.
937   Expected<MachOJITDylibDepInfoMap> DepInfo((MachOJITDylibDepInfoMap()));
938   // Unlock so that we can accept the initializer update.
939   JDStatesLock.unlock();
940   if (auto Err = WrapperFunction<SPSExpected<SPSMachOJITDylibDepInfoMap>(
941           SPSExecutorAddr)>::call(&__orc_rt_macho_push_initializers_tag,
942                                   DepInfo, ExecutorAddr::fromPtr(JDS.Header)))
943     return Err;
944   JDStatesLock.lock();
945 
946   if (!DepInfo)
947     return DepInfo.takeError();
948 
949   if (auto Err = dlopenInitialize(JDStatesLock, JDS, *DepInfo))
950     return Err;
951 
952   if (!DepInfo->empty()) {
953     ORC_RT_DEBUG({
954       printdbg("Unrecognized dep-info key headers in dlopen of %s\n",
955                JDS.Name.c_str());
956     });
957     std::ostringstream ErrStream;
958     ErrStream << "Encountered unrecognized dep-info key headers "
959                  "while processing dlopen of "
960               << JDS.Name;
961     return make_error<StringError>(ErrStream.str());
962   }
963 
964   return Error::success();
965 }
966 
967 Error MachOPlatformRuntimeState::dlopenInitialize(
968     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS,
969     MachOJITDylibDepInfoMap &DepInfo) {
970   ORC_RT_DEBUG({
971     printdbg("MachOPlatformRuntimeState::dlopenInitialize(\"%s\")\n",
972              JDS.Name.c_str());
973   });
974 
975   // If the header is not present in the dep map then assume that we
976   // already processed it earlier in the dlopenInitialize traversal and
977   // return.
978   // TODO: Keep a visited set instead so that we can error out on missing
979   //       entries?
980   auto I = DepInfo.find(ExecutorAddr::fromPtr(JDS.Header));
981   if (I == DepInfo.end())
982     return Error::success();
983 
984   auto DI = std::move(I->second);
985   DepInfo.erase(I);
986 
987   // We don't need to re-initialize sealed JITDylibs that have already been
988   // initialized. Just check that their dep-map entry is empty as expected.
989   if (JDS.Sealed) {
990     if (!DI.DepHeaders.empty()) {
991       std::ostringstream ErrStream;
992       ErrStream << "Sealed JITDylib " << JDS.Header
993                 << " already has registered dependencies";
994       return make_error<StringError>(ErrStream.str());
995     }
996     if (JDS.referenced())
997       return Error::success();
998   } else
999     JDS.Sealed = DI.Sealed;
1000 
1001   // This is an unsealed or newly sealed JITDylib. Run initializers.
1002   std::vector<JITDylibState *> OldDeps;
1003   std::swap(JDS.Deps, OldDeps);
1004   JDS.Deps.reserve(DI.DepHeaders.size());
1005   for (auto DepHeaderAddr : DI.DepHeaders) {
1006     auto *DepJDS = getJITDylibStateByHeader(DepHeaderAddr.toPtr<void *>());
1007     if (!DepJDS) {
1008       std::ostringstream ErrStream;
1009       ErrStream << "Encountered unrecognized dep header "
1010                 << DepHeaderAddr.toPtr<void *>() << " while initializing "
1011                 << JDS.Name;
1012       return make_error<StringError>(ErrStream.str());
1013     }
1014     ++DepJDS->LinkedAgainstRefCount;
1015     if (auto Err = dlopenInitialize(JDStatesLock, *DepJDS, DepInfo))
1016       return Err;
1017   }
1018 
1019   // Initialize this JITDylib.
1020   if (auto Err = registerObjCRegistrationObjects(JDS))
1021     return Err;
1022   if (auto Err = runModInits(JDStatesLock, JDS))
1023     return Err;
1024 
1025   // Decrement old deps.
1026   // FIXME: We should probably continue and just report deinitialize errors
1027   // here.
1028   for (auto *DepJDS : OldDeps) {
1029     --DepJDS->LinkedAgainstRefCount;
1030     if (!DepJDS->referenced())
1031       if (auto Err = dlcloseDeinitialize(JDStatesLock, *DepJDS))
1032         return Err;
1033   }
1034 
1035   return Error::success();
1036 }
1037 
1038 Error MachOPlatformRuntimeState::dlcloseImpl(void *DSOHandle) {
1039   std::unique_lock<std::mutex> Lock(JDStatesMutex);
1040 
1041   // Try to find JITDylib state by header.
1042   auto *JDS = getJITDylibStateByHeader(DSOHandle);
1043 
1044   if (!JDS) {
1045     std::ostringstream ErrStream;
1046     ErrStream << "No registered JITDylib for " << DSOHandle;
1047     return make_error<StringError>(ErrStream.str());
1048   }
1049 
1050   // Bump the ref-count.
1051   --JDS->DlRefCount;
1052 
1053   if (!JDS->referenced())
1054     return dlcloseDeinitialize(Lock, *JDS);
1055 
1056   return Error::success();
1057 }
1058 
1059 Error MachOPlatformRuntimeState::dlcloseDeinitialize(
1060     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
1061 
1062   ORC_RT_DEBUG({
1063     printdbg("MachOPlatformRuntimeState::dlcloseDeinitialize(\"%s\")\n",
1064              JDS.Name.c_str());
1065   });
1066 
1067   runAtExits(JDStatesLock, JDS);
1068 
1069   // Reset mod-inits
1070   JDS.ModInitsSections.reset();
1071 
1072   // Reset data section contents.
1073   for (auto &KV : JDS.DataSectionContent)
1074     memcpy(KV.first, KV.second.data(), KV.second.size());
1075   for (auto &KV : JDS.ZeroInitRanges)
1076     memset(KV.first, 0, KV.second);
1077 
1078   // Deinitialize any dependencies.
1079   for (auto *DepJDS : JDS.Deps) {
1080     --DepJDS->LinkedAgainstRefCount;
1081     if (!DepJDS->referenced())
1082       if (auto Err = dlcloseDeinitialize(JDStatesLock, *DepJDS))
1083         return Err;
1084   }
1085 
1086   return Error::success();
1087 }
1088 
1089 class MachOPlatformRuntimeTLVManager {
1090 public:
1091   void *getInstance(const char *ThreadData);
1092 
1093 private:
1094   std::unordered_map<const char *, char *> Instances;
1095   std::unordered_map<const char *, std::unique_ptr<char[]>> AllocatedSections;
1096 };
1097 
1098 void *MachOPlatformRuntimeTLVManager::getInstance(const char *ThreadData) {
1099   auto I = Instances.find(ThreadData);
1100   if (I != Instances.end())
1101     return I->second;
1102 
1103   auto TDS =
1104       MachOPlatformRuntimeState::get().getThreadDataSectionFor(ThreadData);
1105   if (!TDS) {
1106     __orc_rt_log_error(toString(TDS.takeError()).c_str());
1107     return nullptr;
1108   }
1109 
1110   auto &Allocated = AllocatedSections[TDS->first];
1111   if (!Allocated) {
1112     Allocated = std::make_unique<char[]>(TDS->second);
1113     memcpy(Allocated.get(), TDS->first, TDS->second);
1114   }
1115 
1116   size_t ThreadDataDelta = ThreadData - TDS->first;
1117   assert(ThreadDataDelta <= TDS->second && "ThreadData outside section bounds");
1118 
1119   char *Instance = Allocated.get() + ThreadDataDelta;
1120   Instances[ThreadData] = Instance;
1121   return Instance;
1122 }
1123 
1124 void destroyMachOTLVMgr(void *MachOTLVMgr) {
1125   delete static_cast<MachOPlatformRuntimeTLVManager *>(MachOTLVMgr);
1126 }
1127 
1128 Error runWrapperFunctionCalls(std::vector<WrapperFunctionCall> WFCs) {
1129   for (auto &WFC : WFCs)
1130     if (auto Err = WFC.runWithSPSRet<void>())
1131       return Err;
1132   return Error::success();
1133 }
1134 
1135 } // end anonymous namespace
1136 
1137 //------------------------------------------------------------------------------
1138 //                             JIT entry points
1139 //------------------------------------------------------------------------------
1140 
1141 ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1142 __orc_rt_macho_platform_bootstrap(char *ArgData, size_t ArgSize) {
1143   return WrapperFunction<SPSError()>::handle(
1144              ArgData, ArgSize,
1145              []() { return MachOPlatformRuntimeState::create(); })
1146       .release();
1147 }
1148 
1149 ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1150 __orc_rt_macho_platform_shutdown(char *ArgData, size_t ArgSize) {
1151   return WrapperFunction<SPSError()>::handle(
1152              ArgData, ArgSize,
1153              []() { return MachOPlatformRuntimeState::destroy(); })
1154       .release();
1155 }
1156 
1157 ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1158 __orc_rt_macho_register_jitdylib(char *ArgData, size_t ArgSize) {
1159   return WrapperFunction<SPSError(SPSString, SPSExecutorAddr)>::handle(
1160              ArgData, ArgSize,
1161              [](std::string &Name, ExecutorAddr HeaderAddr) {
1162                return MachOPlatformRuntimeState::get().registerJITDylib(
1163                    std::move(Name), HeaderAddr.toPtr<void *>());
1164              })
1165       .release();
1166 }
1167 
1168 ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1169 __orc_rt_macho_deregister_jitdylib(char *ArgData, size_t ArgSize) {
1170   return WrapperFunction<SPSError(SPSExecutorAddr)>::handle(
1171              ArgData, ArgSize,
1172              [](ExecutorAddr HeaderAddr) {
1173                return MachOPlatformRuntimeState::get().deregisterJITDylib(
1174                    HeaderAddr.toPtr<void *>());
1175              })
1176       .release();
1177 }
1178 
1179 ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1180 __orc_rt_macho_register_object_platform_sections(char *ArgData,
1181                                                  size_t ArgSize) {
1182   return WrapperFunction<SPSError(SPSExecutorAddr,
1183                                   SPSOptional<SPSUnwindSectionInfo>,
1184                                   SPSMachOObjectPlatformSectionsMap)>::
1185       handle(ArgData, ArgSize,
1186              [](ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> USI,
1187                 std::vector<std::pair<std::string_view, ExecutorAddrRange>>
1188                     &Secs) {
1189                return MachOPlatformRuntimeState::get()
1190                    .registerObjectPlatformSections(HeaderAddr, std::move(USI),
1191                                                    std::move(Secs));
1192              })
1193           .release();
1194 }
1195 
1196 ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1197 __orc_rt_macho_deregister_object_platform_sections(char *ArgData,
1198                                                    size_t ArgSize) {
1199   return WrapperFunction<SPSError(SPSExecutorAddr,
1200                                   SPSOptional<SPSUnwindSectionInfo>,
1201                                   SPSMachOObjectPlatformSectionsMap)>::
1202       handle(ArgData, ArgSize,
1203              [](ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> USI,
1204                 std::vector<std::pair<std::string_view, ExecutorAddrRange>>
1205                     &Secs) {
1206                return MachOPlatformRuntimeState::get()
1207                    .deregisterObjectPlatformSections(HeaderAddr, std::move(USI),
1208                                                      std::move(Secs));
1209              })
1210           .release();
1211 }
1212 
1213 ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1214 __orc_rt_macho_run_wrapper_function_calls(char *ArgData, size_t ArgSize) {
1215   return WrapperFunction<SPSError(SPSSequence<SPSWrapperFunctionCall>)>::handle(
1216              ArgData, ArgSize, runWrapperFunctionCalls)
1217       .release();
1218 }
1219 
1220 //------------------------------------------------------------------------------
1221 //                            TLV support
1222 //------------------------------------------------------------------------------
1223 
1224 ORC_RT_INTERFACE void *__orc_rt_macho_tlv_get_addr_impl(TLVDescriptor *D) {
1225   auto *TLVMgr = static_cast<MachOPlatformRuntimeTLVManager *>(
1226       pthread_getspecific(D->Key));
1227   if (!TLVMgr) {
1228     TLVMgr = new MachOPlatformRuntimeTLVManager();
1229     if (pthread_setspecific(D->Key, TLVMgr)) {
1230       __orc_rt_log_error("Call to pthread_setspecific failed");
1231       return nullptr;
1232     }
1233   }
1234 
1235   return TLVMgr->getInstance(
1236       reinterpret_cast<char *>(static_cast<uintptr_t>(D->DataAddress)));
1237 }
1238 
1239 ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
1240 __orc_rt_macho_create_pthread_key(char *ArgData, size_t ArgSize) {
1241   return WrapperFunction<SPSExpected<uint64_t>(void)>::handle(
1242              ArgData, ArgSize,
1243              []() -> Expected<uint64_t> {
1244                pthread_key_t Key;
1245                if (int Err = pthread_key_create(&Key, destroyMachOTLVMgr)) {
1246                  __orc_rt_log_error("Call to pthread_key_create failed");
1247                  return make_error<StringError>(strerror(Err));
1248                }
1249                return static_cast<uint64_t>(Key);
1250              })
1251       .release();
1252 }
1253 
1254 //------------------------------------------------------------------------------
1255 //                           cxa_atexit support
1256 //------------------------------------------------------------------------------
1257 
1258 int __orc_rt_macho_cxa_atexit(void (*func)(void *), void *arg,
1259                               void *dso_handle) {
1260   return MachOPlatformRuntimeState::get().registerAtExit(func, arg, dso_handle);
1261 }
1262 
1263 void __orc_rt_macho_cxa_finalize(void *dso_handle) {
1264   MachOPlatformRuntimeState::get().runAtExits(dso_handle);
1265 }
1266 
1267 //------------------------------------------------------------------------------
1268 //                        JIT'd dlfcn alternatives.
1269 //------------------------------------------------------------------------------
1270 
1271 const char *__orc_rt_macho_jit_dlerror() {
1272   return MachOPlatformRuntimeState::get().dlerror();
1273 }
1274 
1275 void *__orc_rt_macho_jit_dlopen(const char *path, int mode) {
1276   return MachOPlatformRuntimeState::get().dlopen(path, mode);
1277 }
1278 
1279 int __orc_rt_macho_jit_dlclose(void *dso_handle) {
1280   return MachOPlatformRuntimeState::get().dlclose(dso_handle);
1281 }
1282 
1283 void *__orc_rt_macho_jit_dlsym(void *dso_handle, const char *symbol) {
1284   return MachOPlatformRuntimeState::get().dlsym(dso_handle, symbol);
1285 }
1286 
1287 //------------------------------------------------------------------------------
1288 //                             MachO Run Program
1289 //------------------------------------------------------------------------------
1290 
1291 ORC_RT_INTERFACE int64_t __orc_rt_macho_run_program(const char *JITDylibName,
1292                                                     const char *EntrySymbolName,
1293                                                     int argc, char *argv[]) {
1294   using MainTy = int (*)(int, char *[]);
1295 
1296   void *H = __orc_rt_macho_jit_dlopen(JITDylibName,
1297                                       __orc_rt::macho::ORC_RT_RTLD_LAZY);
1298   if (!H) {
1299     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
1300     return -1;
1301   }
1302 
1303   auto *Main =
1304       reinterpret_cast<MainTy>(__orc_rt_macho_jit_dlsym(H, EntrySymbolName));
1305 
1306   if (!Main) {
1307     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
1308     return -1;
1309   }
1310 
1311   int Result = Main(argc, argv);
1312 
1313   if (__orc_rt_macho_jit_dlclose(H) == -1)
1314     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
1315 
1316   return Result;
1317 }
1318