xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/orc/macho_platform.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
1fe6060f1SDimitry Andric //===- macho_platform.cpp -------------------------------------------------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // This file contains code required to load the rest of the MachO runtime.
10fe6060f1SDimitry Andric //
11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
12fe6060f1SDimitry Andric 
13fe6060f1SDimitry Andric #include "macho_platform.h"
145f757f3fSDimitry Andric #include "bitmask_enum.h"
15fe6060f1SDimitry Andric #include "common.h"
1681ad6265SDimitry Andric #include "debug.h"
17fe6060f1SDimitry Andric #include "error.h"
18bdd1243dSDimitry Andric #include "interval_map.h"
19fe6060f1SDimitry Andric #include "wrapper_function_utils.h"
20fe6060f1SDimitry Andric 
2181ad6265SDimitry Andric #include <algorithm>
2281ad6265SDimitry Andric #include <ios>
23fe6060f1SDimitry Andric #include <map>
24fe6060f1SDimitry Andric #include <mutex>
25fe6060f1SDimitry Andric #include <sstream>
26bdd1243dSDimitry Andric #include <string_view>
27fe6060f1SDimitry Andric #include <unordered_map>
2881ad6265SDimitry Andric #include <unordered_set>
29fe6060f1SDimitry Andric #include <vector>
30fe6060f1SDimitry Andric 
3181ad6265SDimitry Andric #define DEBUG_TYPE "macho_platform"
3281ad6265SDimitry Andric 
33fe6060f1SDimitry Andric using namespace __orc_rt;
34fe6060f1SDimitry Andric using namespace __orc_rt::macho;
35fe6060f1SDimitry Andric 
36fe6060f1SDimitry Andric // Declare function tags for functions in the JIT process.
3781ad6265SDimitry Andric ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_push_initializers_tag)
385f757f3fSDimitry Andric ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_push_symbols_tag)
39fe6060f1SDimitry Andric 
40fe6060f1SDimitry Andric struct objc_image_info;
4106c3fb27SDimitry Andric struct mach_header;
42fe6060f1SDimitry Andric 
43fe6060f1SDimitry Andric // Objective-C registration functions.
44fe6060f1SDimitry Andric // These are weakly imported. If the Objective-C runtime has not been loaded
45fe6060f1SDimitry Andric // then code containing Objective-C sections will generate an error.
46fe6060f1SDimitry Andric extern "C" void
4706c3fb27SDimitry Andric _objc_map_images(unsigned count, const char *const paths[],
4806c3fb27SDimitry Andric                  const mach_header *const mhdrs[]) ORC_RT_WEAK_IMPORT;
49fe6060f1SDimitry Andric 
5006c3fb27SDimitry Andric extern "C" void _objc_load_image(const char *path,
5106c3fb27SDimitry Andric                                  const mach_header *mh) ORC_RT_WEAK_IMPORT;
52349cc55cSDimitry Andric 
53bdd1243dSDimitry Andric // Libunwind prototypes.
54bdd1243dSDimitry Andric struct unw_dynamic_unwind_sections {
55bdd1243dSDimitry Andric   uintptr_t dso_base;
56bdd1243dSDimitry Andric   uintptr_t dwarf_section;
57bdd1243dSDimitry Andric   size_t dwarf_section_length;
58bdd1243dSDimitry Andric   uintptr_t compact_unwind_section;
59bdd1243dSDimitry Andric   size_t compact_unwind_section_length;
60bdd1243dSDimitry Andric };
61bdd1243dSDimitry Andric 
62bdd1243dSDimitry Andric typedef int (*unw_find_dynamic_unwind_sections)(
63bdd1243dSDimitry Andric     uintptr_t addr, struct unw_dynamic_unwind_sections *info);
64bdd1243dSDimitry Andric 
65bdd1243dSDimitry Andric extern "C" int __unw_add_find_dynamic_unwind_sections(
66bdd1243dSDimitry Andric     unw_find_dynamic_unwind_sections find_dynamic_unwind_sections)
67bdd1243dSDimitry Andric     ORC_RT_WEAK_IMPORT;
68bdd1243dSDimitry Andric 
69bdd1243dSDimitry Andric extern "C" int __unw_remove_find_dynamic_unwind_sections(
70bdd1243dSDimitry Andric     unw_find_dynamic_unwind_sections find_dynamic_unwind_sections)
71bdd1243dSDimitry Andric     ORC_RT_WEAK_IMPORT;
72bdd1243dSDimitry Andric 
73fe6060f1SDimitry Andric namespace {
74fe6060f1SDimitry Andric 
7581ad6265SDimitry Andric struct MachOJITDylibDepInfo {
7681ad6265SDimitry Andric   bool Sealed = false;
7781ad6265SDimitry Andric   std::vector<ExecutorAddr> DepHeaders;
78fe6060f1SDimitry Andric };
79fe6060f1SDimitry Andric 
8081ad6265SDimitry Andric using MachOJITDylibDepInfoMap =
8181ad6265SDimitry Andric     std::unordered_map<ExecutorAddr, MachOJITDylibDepInfo>;
82fe6060f1SDimitry Andric 
8381ad6265SDimitry Andric } // anonymous namespace
84fe6060f1SDimitry Andric 
8581ad6265SDimitry Andric namespace __orc_rt {
86fe6060f1SDimitry Andric 
8781ad6265SDimitry Andric using SPSMachOObjectPlatformSectionsMap =
8881ad6265SDimitry Andric     SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>;
89fe6060f1SDimitry Andric 
9081ad6265SDimitry Andric using SPSMachOJITDylibDepInfo = SPSTuple<bool, SPSSequence<SPSExecutorAddr>>;
9181ad6265SDimitry Andric 
9281ad6265SDimitry Andric using SPSMachOJITDylibDepInfoMap =
9381ad6265SDimitry Andric     SPSSequence<SPSTuple<SPSExecutorAddr, SPSMachOJITDylibDepInfo>>;
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric template <>
9681ad6265SDimitry Andric class SPSSerializationTraits<SPSMachOJITDylibDepInfo, MachOJITDylibDepInfo> {
9781ad6265SDimitry Andric public:
size(const MachOJITDylibDepInfo & JDI)9881ad6265SDimitry Andric   static size_t size(const MachOJITDylibDepInfo &JDI) {
9981ad6265SDimitry Andric     return SPSMachOJITDylibDepInfo::AsArgList::size(JDI.Sealed, JDI.DepHeaders);
100fe6060f1SDimitry Andric   }
101fe6060f1SDimitry Andric 
serialize(SPSOutputBuffer & OB,const MachOJITDylibDepInfo & JDI)10281ad6265SDimitry Andric   static bool serialize(SPSOutputBuffer &OB, const MachOJITDylibDepInfo &JDI) {
10381ad6265SDimitry Andric     return SPSMachOJITDylibDepInfo::AsArgList::serialize(OB, JDI.Sealed,
10481ad6265SDimitry Andric                                                          JDI.DepHeaders);
105fe6060f1SDimitry Andric   }
106fe6060f1SDimitry Andric 
deserialize(SPSInputBuffer & IB,MachOJITDylibDepInfo & JDI)10781ad6265SDimitry Andric   static bool deserialize(SPSInputBuffer &IB, MachOJITDylibDepInfo &JDI) {
10881ad6265SDimitry Andric     return SPSMachOJITDylibDepInfo::AsArgList::deserialize(IB, JDI.Sealed,
10981ad6265SDimitry Andric                                                            JDI.DepHeaders);
110fe6060f1SDimitry Andric   }
11181ad6265SDimitry Andric };
112fe6060f1SDimitry Andric 
113bdd1243dSDimitry Andric struct UnwindSectionInfo {
114bdd1243dSDimitry Andric   std::vector<ExecutorAddrRange> CodeRanges;
115bdd1243dSDimitry Andric   ExecutorAddrRange DwarfSection;
116bdd1243dSDimitry Andric   ExecutorAddrRange CompactUnwindSection;
117bdd1243dSDimitry Andric };
118bdd1243dSDimitry Andric 
119bdd1243dSDimitry Andric using SPSUnwindSectionInfo =
120bdd1243dSDimitry Andric     SPSTuple<SPSSequence<SPSExecutorAddrRange>, SPSExecutorAddrRange,
121bdd1243dSDimitry Andric              SPSExecutorAddrRange>;
122bdd1243dSDimitry Andric 
123bdd1243dSDimitry Andric template <>
124bdd1243dSDimitry Andric class SPSSerializationTraits<SPSUnwindSectionInfo, UnwindSectionInfo> {
125bdd1243dSDimitry Andric public:
size(const UnwindSectionInfo & USI)126bdd1243dSDimitry Andric   static size_t size(const UnwindSectionInfo &USI) {
127bdd1243dSDimitry Andric     return SPSUnwindSectionInfo::AsArgList::size(
128bdd1243dSDimitry Andric         USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
129bdd1243dSDimitry Andric   }
130bdd1243dSDimitry Andric 
serialize(SPSOutputBuffer & OB,const UnwindSectionInfo & USI)131bdd1243dSDimitry Andric   static bool serialize(SPSOutputBuffer &OB, const UnwindSectionInfo &USI) {
132bdd1243dSDimitry Andric     return SPSUnwindSectionInfo::AsArgList::serialize(
133bdd1243dSDimitry Andric         OB, USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
134bdd1243dSDimitry Andric   }
135bdd1243dSDimitry Andric 
deserialize(SPSInputBuffer & IB,UnwindSectionInfo & USI)136bdd1243dSDimitry Andric   static bool deserialize(SPSInputBuffer &IB, UnwindSectionInfo &USI) {
137bdd1243dSDimitry Andric     return SPSUnwindSectionInfo::AsArgList::deserialize(
138bdd1243dSDimitry Andric         IB, USI.CodeRanges, USI.DwarfSection, USI.CompactUnwindSection);
139bdd1243dSDimitry Andric   }
140bdd1243dSDimitry Andric };
141bdd1243dSDimitry Andric 
14281ad6265SDimitry Andric } // namespace __orc_rt
143349cc55cSDimitry Andric 
14481ad6265SDimitry Andric namespace {
145fe6060f1SDimitry Andric struct TLVDescriptor {
146fe6060f1SDimitry Andric   void *(*Thunk)(TLVDescriptor *) = nullptr;
147fe6060f1SDimitry Andric   unsigned long Key = 0;
148fe6060f1SDimitry Andric   unsigned long DataAddress = 0;
149fe6060f1SDimitry Andric };
150fe6060f1SDimitry Andric 
151fe6060f1SDimitry Andric class MachOPlatformRuntimeState {
1525f757f3fSDimitry Andric public:
1535f757f3fSDimitry Andric   // Used internally by MachOPlatformRuntimeState, but made public to enable
1545f757f3fSDimitry Andric   // serialization.
1555f757f3fSDimitry Andric   enum class MachOExecutorSymbolFlags : uint8_t {
1565f757f3fSDimitry Andric     None = 0,
1575f757f3fSDimitry Andric     Weak = 1U << 0,
1585f757f3fSDimitry Andric     Callable = 1U << 1,
1595f757f3fSDimitry Andric     ORC_RT_MARK_AS_BITMASK_ENUM(/* LargestValue = */ Callable)
1605f757f3fSDimitry Andric   };
1615f757f3fSDimitry Andric 
162fe6060f1SDimitry Andric private:
163fe6060f1SDimitry Andric   struct AtExitEntry {
164fe6060f1SDimitry Andric     void (*Func)(void *);
165fe6060f1SDimitry Andric     void *Arg;
166fe6060f1SDimitry Andric   };
167fe6060f1SDimitry Andric 
168fe6060f1SDimitry Andric   using AtExitsVector = std::vector<AtExitEntry>;
169fe6060f1SDimitry Andric 
170bdd1243dSDimitry Andric   /// Used to manage sections of fixed-sized metadata records (e.g. pointer
171bdd1243dSDimitry Andric   /// sections, selector refs, etc.)
172bdd1243dSDimitry Andric   template <typename RecordElement> class RecordSectionsTracker {
173bdd1243dSDimitry Andric   public:
174bdd1243dSDimitry Andric     /// Add a section to the "new" list.
add(span<RecordElement> Sec)175bdd1243dSDimitry Andric     void add(span<RecordElement> Sec) { New.push_back(std::move(Sec)); }
176bdd1243dSDimitry Andric 
177bdd1243dSDimitry Andric     /// Returns true if there are new sections to process.
hasNewSections() const178bdd1243dSDimitry Andric     bool hasNewSections() const { return !New.empty(); }
179bdd1243dSDimitry Andric 
180bdd1243dSDimitry Andric     /// Returns the number of new sections to process.
numNewSections() const181bdd1243dSDimitry Andric     size_t numNewSections() const { return New.size(); }
182bdd1243dSDimitry Andric 
183bdd1243dSDimitry Andric     /// Process all new sections.
184bdd1243dSDimitry Andric     template <typename ProcessSectionFunc>
185bdd1243dSDimitry Andric     std::enable_if_t<std::is_void_v<
186bdd1243dSDimitry Andric         std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>>
processNewSections(ProcessSectionFunc && ProcessSection)187bdd1243dSDimitry Andric     processNewSections(ProcessSectionFunc &&ProcessSection) {
188bdd1243dSDimitry Andric       for (auto &Sec : New)
189bdd1243dSDimitry Andric         ProcessSection(Sec);
190bdd1243dSDimitry Andric       moveNewToProcessed();
191bdd1243dSDimitry Andric     }
192bdd1243dSDimitry Andric 
193bdd1243dSDimitry Andric     /// Proces all new sections with a fallible handler.
194bdd1243dSDimitry Andric     ///
195bdd1243dSDimitry Andric     /// Successfully handled sections will be moved to the Processed
196bdd1243dSDimitry Andric     /// list.
197bdd1243dSDimitry Andric     template <typename ProcessSectionFunc>
198bdd1243dSDimitry Andric     std::enable_if_t<
199bdd1243dSDimitry Andric         std::is_same_v<Error, std::invoke_result_t<ProcessSectionFunc,
200bdd1243dSDimitry Andric                                                    span<RecordElement>>>,
201bdd1243dSDimitry Andric         Error>
processNewSections(ProcessSectionFunc && ProcessSection)202bdd1243dSDimitry Andric     processNewSections(ProcessSectionFunc &&ProcessSection) {
203bdd1243dSDimitry Andric       for (size_t I = 0; I != New.size(); ++I) {
204bdd1243dSDimitry Andric         if (auto Err = ProcessSection(New[I])) {
205bdd1243dSDimitry Andric           for (size_t J = 0; J != I; ++J)
206bdd1243dSDimitry Andric             Processed.push_back(New[J]);
207bdd1243dSDimitry Andric           New.erase(New.begin(), New.begin() + I);
208bdd1243dSDimitry Andric           return Err;
209bdd1243dSDimitry Andric         }
210bdd1243dSDimitry Andric       }
211bdd1243dSDimitry Andric       moveNewToProcessed();
212bdd1243dSDimitry Andric       return Error::success();
213bdd1243dSDimitry Andric     }
214bdd1243dSDimitry Andric 
215bdd1243dSDimitry Andric     /// Move all sections back to New for reprocessing.
reset()216bdd1243dSDimitry Andric     void reset() {
217bdd1243dSDimitry Andric       moveNewToProcessed();
218bdd1243dSDimitry Andric       New = std::move(Processed);
219bdd1243dSDimitry Andric     }
220bdd1243dSDimitry Andric 
221bdd1243dSDimitry Andric     /// Remove the section with the given range.
removeIfPresent(ExecutorAddrRange R)222bdd1243dSDimitry Andric     bool removeIfPresent(ExecutorAddrRange R) {
223bdd1243dSDimitry Andric       if (removeIfPresent(New, R))
224bdd1243dSDimitry Andric         return true;
225bdd1243dSDimitry Andric       return removeIfPresent(Processed, R);
226bdd1243dSDimitry Andric     }
227bdd1243dSDimitry Andric 
228bdd1243dSDimitry Andric   private:
moveNewToProcessed()229bdd1243dSDimitry Andric     void moveNewToProcessed() {
230bdd1243dSDimitry Andric       if (Processed.empty())
231bdd1243dSDimitry Andric         Processed = std::move(New);
232bdd1243dSDimitry Andric       else {
233bdd1243dSDimitry Andric         Processed.reserve(Processed.size() + New.size());
234bdd1243dSDimitry Andric         std::copy(New.begin(), New.end(), std::back_inserter(Processed));
235bdd1243dSDimitry Andric         New.clear();
236bdd1243dSDimitry Andric       }
237bdd1243dSDimitry Andric     }
238bdd1243dSDimitry Andric 
removeIfPresent(std::vector<span<RecordElement>> & V,ExecutorAddrRange R)239bdd1243dSDimitry Andric     bool removeIfPresent(std::vector<span<RecordElement>> &V,
240bdd1243dSDimitry Andric                          ExecutorAddrRange R) {
241bdd1243dSDimitry Andric       auto RI = std::find_if(
242bdd1243dSDimitry Andric           V.rbegin(), V.rend(),
243bdd1243dSDimitry Andric           [RS = R.toSpan<RecordElement>()](const span<RecordElement> &E) {
244bdd1243dSDimitry Andric             return E.data() == RS.data();
245bdd1243dSDimitry Andric           });
246bdd1243dSDimitry Andric       if (RI != V.rend()) {
247bdd1243dSDimitry Andric         V.erase(std::next(RI).base());
248bdd1243dSDimitry Andric         return true;
249bdd1243dSDimitry Andric       }
250bdd1243dSDimitry Andric       return false;
251bdd1243dSDimitry Andric     }
252bdd1243dSDimitry Andric 
253bdd1243dSDimitry Andric     std::vector<span<RecordElement>> Processed;
254bdd1243dSDimitry Andric     std::vector<span<RecordElement>> New;
255bdd1243dSDimitry Andric   };
256bdd1243dSDimitry Andric 
257bdd1243dSDimitry Andric   struct UnwindSections {
UnwindSections__anon068503140211::MachOPlatformRuntimeState::UnwindSections258bdd1243dSDimitry Andric     UnwindSections(const UnwindSectionInfo &USI)
259bdd1243dSDimitry Andric         : DwarfSection(USI.DwarfSection.toSpan<char>()),
260bdd1243dSDimitry Andric           CompactUnwindSection(USI.CompactUnwindSection.toSpan<char>()) {}
261bdd1243dSDimitry Andric 
262bdd1243dSDimitry Andric     span<char> DwarfSection;
263bdd1243dSDimitry Andric     span<char> CompactUnwindSection;
264bdd1243dSDimitry Andric   };
265bdd1243dSDimitry Andric 
266bdd1243dSDimitry Andric   using UnwindSectionsMap =
267bdd1243dSDimitry Andric       IntervalMap<char *, UnwindSections, IntervalCoalescing::Disabled>;
268bdd1243dSDimitry Andric 
26981ad6265SDimitry Andric   struct JITDylibState {
2705f757f3fSDimitry Andric 
2715f757f3fSDimitry Andric     using SymbolTableMap =
2725f757f3fSDimitry Andric         std::unordered_map<std::string_view,
2735f757f3fSDimitry Andric                            std::pair<ExecutorAddr, MachOExecutorSymbolFlags>>;
2745f757f3fSDimitry Andric 
27581ad6265SDimitry Andric     std::string Name;
276fe6060f1SDimitry Andric     void *Header = nullptr;
27781ad6265SDimitry Andric     bool Sealed = false;
27881ad6265SDimitry Andric     size_t LinkedAgainstRefCount = 0;
27981ad6265SDimitry Andric     size_t DlRefCount = 0;
2805f757f3fSDimitry Andric     SymbolTableMap SymbolTable;
28181ad6265SDimitry Andric     std::vector<JITDylibState *> Deps;
282fe6060f1SDimitry Andric     AtExitsVector AtExits;
28381ad6265SDimitry Andric     const objc_image_info *ObjCImageInfo = nullptr;
284bdd1243dSDimitry Andric     std::unordered_map<void *, std::vector<char>> DataSectionContent;
285bdd1243dSDimitry Andric     std::unordered_map<void *, size_t> ZeroInitRanges;
286bdd1243dSDimitry Andric     UnwindSectionsMap UnwindSections;
287bdd1243dSDimitry Andric     RecordSectionsTracker<void (*)()> ModInitsSections;
28806c3fb27SDimitry Andric     RecordSectionsTracker<char> ObjCRuntimeRegistrationObjects;
28981ad6265SDimitry Andric 
referenced__anon068503140211::MachOPlatformRuntimeState::JITDylibState29081ad6265SDimitry Andric     bool referenced() const {
29181ad6265SDimitry Andric       return LinkedAgainstRefCount != 0 || DlRefCount != 0;
29281ad6265SDimitry Andric     }
293fe6060f1SDimitry Andric   };
294fe6060f1SDimitry Andric 
295fe6060f1SDimitry Andric public:
296bdd1243dSDimitry Andric   static Error create();
297fe6060f1SDimitry Andric   static MachOPlatformRuntimeState &get();
298bdd1243dSDimitry Andric   static Error destroy();
299fe6060f1SDimitry Andric 
300fe6060f1SDimitry Andric   MachOPlatformRuntimeState() = default;
301fe6060f1SDimitry Andric 
302fe6060f1SDimitry Andric   // Delete copy and move constructors.
303fe6060f1SDimitry Andric   MachOPlatformRuntimeState(const MachOPlatformRuntimeState &) = delete;
304fe6060f1SDimitry Andric   MachOPlatformRuntimeState &
305fe6060f1SDimitry Andric   operator=(const MachOPlatformRuntimeState &) = delete;
306fe6060f1SDimitry Andric   MachOPlatformRuntimeState(MachOPlatformRuntimeState &&) = delete;
307fe6060f1SDimitry Andric   MachOPlatformRuntimeState &operator=(MachOPlatformRuntimeState &&) = delete;
308fe6060f1SDimitry Andric 
309bdd1243dSDimitry Andric   Error initialize();
310bdd1243dSDimitry Andric   Error shutdown();
311bdd1243dSDimitry Andric 
31281ad6265SDimitry Andric   Error registerJITDylib(std::string Name, void *Header);
31381ad6265SDimitry Andric   Error deregisterJITDylib(void *Header);
31481ad6265SDimitry Andric   Error registerThreadDataSection(span<const char> ThreadDataSection);
31581ad6265SDimitry Andric   Error deregisterThreadDataSection(span<const char> ThreadDataSection);
3165f757f3fSDimitry Andric   Error registerObjectSymbolTable(
3175f757f3fSDimitry Andric       ExecutorAddr HeaderAddr,
3185f757f3fSDimitry Andric       const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
3195f757f3fSDimitry Andric                                    MachOExecutorSymbolFlags>> &Entries);
3205f757f3fSDimitry Andric   Error deregisterObjectSymbolTable(
3215f757f3fSDimitry Andric       ExecutorAddr HeaderAddr,
3225f757f3fSDimitry Andric       const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
3235f757f3fSDimitry Andric                                    MachOExecutorSymbolFlags>> &Entries);
32481ad6265SDimitry Andric   Error registerObjectPlatformSections(
325bdd1243dSDimitry Andric       ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindSections,
326bdd1243dSDimitry Andric       std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs);
32781ad6265SDimitry Andric   Error deregisterObjectPlatformSections(
328bdd1243dSDimitry Andric       ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindSections,
329bdd1243dSDimitry Andric       std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs);
330fe6060f1SDimitry Andric 
331fe6060f1SDimitry Andric   const char *dlerror();
332bdd1243dSDimitry Andric   void *dlopen(std::string_view Name, int Mode);
333fe6060f1SDimitry Andric   int dlclose(void *DSOHandle);
3345f757f3fSDimitry Andric   void *dlsym(void *DSOHandle, const char *Symbol);
335fe6060f1SDimitry Andric 
336fe6060f1SDimitry Andric   int registerAtExit(void (*F)(void *), void *Arg, void *DSOHandle);
337bdd1243dSDimitry Andric   void runAtExits(std::unique_lock<std::mutex> &JDStatesLock,
338bdd1243dSDimitry Andric                   JITDylibState &JDS);
339fe6060f1SDimitry Andric   void runAtExits(void *DSOHandle);
340fe6060f1SDimitry Andric 
341fe6060f1SDimitry Andric   /// Returns the base address of the section containing ThreadData.
342fe6060f1SDimitry Andric   Expected<std::pair<const char *, size_t>>
343fe6060f1SDimitry Andric   getThreadDataSectionFor(const char *ThreadData);
344fe6060f1SDimitry Andric 
345fe6060f1SDimitry Andric private:
34681ad6265SDimitry Andric   JITDylibState *getJITDylibStateByHeader(void *DSOHandle);
347bdd1243dSDimitry Andric   JITDylibState *getJITDylibStateByName(std::string_view Path);
348fe6060f1SDimitry Andric 
3495f757f3fSDimitry Andric   /// Requests materialization of the given symbols. For each pair, the bool
3505f757f3fSDimitry Andric   /// element indicates whether the symbol is required (true) or weakly
3515f757f3fSDimitry Andric   /// referenced (false).
3525f757f3fSDimitry Andric   Error requestPushSymbols(JITDylibState &JDS,
3535f757f3fSDimitry Andric                            span<std::pair<std::string_view, bool>> Symbols);
3545f757f3fSDimitry Andric 
3555f757f3fSDimitry Andric   /// Attempts to look up the given symbols locally, requesting a push from the
3565f757f3fSDimitry Andric   /// remote if they're not found. Results are written to the Result span, which
3575f757f3fSDimitry Andric   /// must have the same size as the Symbols span.
3585f757f3fSDimitry Andric   Error
3595f757f3fSDimitry Andric   lookupSymbols(JITDylibState &JDS, std::unique_lock<std::mutex> &JDStatesLock,
3605f757f3fSDimitry Andric                 span<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>> Result,
3615f757f3fSDimitry Andric                 span<std::pair<std::string_view, bool>> Symbols);
362bdd1243dSDimitry Andric 
363bdd1243dSDimitry Andric   bool lookupUnwindSections(void *Addr, unw_dynamic_unwind_sections &Info);
364bdd1243dSDimitry Andric 
365bdd1243dSDimitry Andric   static int findDynamicUnwindSections(uintptr_t addr,
366bdd1243dSDimitry Andric                                        unw_dynamic_unwind_sections *info);
367bdd1243dSDimitry Andric   static Error registerEHFrames(span<const char> EHFrameSection);
368bdd1243dSDimitry Andric   static Error deregisterEHFrames(span<const char> EHFrameSection);
369fe6060f1SDimitry Andric 
37006c3fb27SDimitry Andric   static Error registerObjCRegistrationObjects(JITDylibState &JDS);
371bdd1243dSDimitry Andric   static Error runModInits(std::unique_lock<std::mutex> &JDStatesLock,
372bdd1243dSDimitry Andric                            JITDylibState &JDS);
37381ad6265SDimitry Andric 
374bdd1243dSDimitry Andric   Expected<void *> dlopenImpl(std::string_view Path, int Mode);
375bdd1243dSDimitry Andric   Error dlopenFull(std::unique_lock<std::mutex> &JDStatesLock,
376bdd1243dSDimitry Andric                    JITDylibState &JDS);
377bdd1243dSDimitry Andric   Error dlopenInitialize(std::unique_lock<std::mutex> &JDStatesLock,
378bdd1243dSDimitry Andric                          JITDylibState &JDS, MachOJITDylibDepInfoMap &DepInfo);
37981ad6265SDimitry Andric 
38081ad6265SDimitry Andric   Error dlcloseImpl(void *DSOHandle);
381bdd1243dSDimitry Andric   Error dlcloseDeinitialize(std::unique_lock<std::mutex> &JDStatesLock,
382bdd1243dSDimitry Andric                             JITDylibState &JDS);
383fe6060f1SDimitry Andric 
384fe6060f1SDimitry Andric   static MachOPlatformRuntimeState *MOPS;
385fe6060f1SDimitry Andric 
386bdd1243dSDimitry Andric   bool UseCallbackStyleUnwindInfo = false;
387bdd1243dSDimitry Andric 
388fe6060f1SDimitry Andric   // FIXME: Move to thread-state.
389fe6060f1SDimitry Andric   std::string DLFcnError;
390fe6060f1SDimitry Andric 
391bdd1243dSDimitry Andric   // APIMutex guards against concurrent entry into key "dyld" API functions
392bdd1243dSDimitry Andric   // (e.g. dlopen, dlclose).
393bdd1243dSDimitry Andric   std::recursive_mutex DyldAPIMutex;
394fe6060f1SDimitry Andric 
395bdd1243dSDimitry Andric   // JDStatesMutex guards the data structures that hold JITDylib state.
396bdd1243dSDimitry Andric   std::mutex JDStatesMutex;
397bdd1243dSDimitry Andric   std::unordered_map<void *, JITDylibState> JDStates;
398bdd1243dSDimitry Andric   std::unordered_map<std::string_view, void *> JDNameToHeader;
399bdd1243dSDimitry Andric 
400bdd1243dSDimitry Andric   // ThreadDataSectionsMutex guards thread local data section state.
401fe6060f1SDimitry Andric   std::mutex ThreadDataSectionsMutex;
402fe6060f1SDimitry Andric   std::map<const char *, size_t> ThreadDataSections;
403fe6060f1SDimitry Andric };
404fe6060f1SDimitry Andric 
4055f757f3fSDimitry Andric } // anonymous namespace
4065f757f3fSDimitry Andric 
4075f757f3fSDimitry Andric namespace __orc_rt {
4085f757f3fSDimitry Andric 
4095f757f3fSDimitry Andric class SPSMachOExecutorSymbolFlags;
4105f757f3fSDimitry Andric 
4115f757f3fSDimitry Andric template <>
4125f757f3fSDimitry Andric class SPSSerializationTraits<
4135f757f3fSDimitry Andric     SPSMachOExecutorSymbolFlags,
4145f757f3fSDimitry Andric     MachOPlatformRuntimeState::MachOExecutorSymbolFlags> {
4155f757f3fSDimitry Andric private:
4165f757f3fSDimitry Andric   using UT = std::underlying_type_t<
4175f757f3fSDimitry Andric       MachOPlatformRuntimeState::MachOExecutorSymbolFlags>;
4185f757f3fSDimitry Andric 
4195f757f3fSDimitry Andric public:
4205f757f3fSDimitry Andric   static size_t
size(const MachOPlatformRuntimeState::MachOExecutorSymbolFlags & SF)4215f757f3fSDimitry Andric   size(const MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
4225f757f3fSDimitry Andric     return sizeof(UT);
4235f757f3fSDimitry Andric   }
4245f757f3fSDimitry Andric 
4255f757f3fSDimitry Andric   static bool
serialize(SPSOutputBuffer & OB,const MachOPlatformRuntimeState::MachOExecutorSymbolFlags & SF)4265f757f3fSDimitry Andric   serialize(SPSOutputBuffer &OB,
4275f757f3fSDimitry Andric             const MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
4285f757f3fSDimitry Andric     return SPSArgList<UT>::serialize(OB, static_cast<UT>(SF));
4295f757f3fSDimitry Andric   }
4305f757f3fSDimitry Andric 
4315f757f3fSDimitry Andric   static bool
deserialize(SPSInputBuffer & IB,MachOPlatformRuntimeState::MachOExecutorSymbolFlags & SF)4325f757f3fSDimitry Andric   deserialize(SPSInputBuffer &IB,
4335f757f3fSDimitry Andric               MachOPlatformRuntimeState::MachOExecutorSymbolFlags &SF) {
4345f757f3fSDimitry Andric     UT Tmp;
4355f757f3fSDimitry Andric     if (!SPSArgList<UT>::deserialize(IB, Tmp))
4365f757f3fSDimitry Andric       return false;
4375f757f3fSDimitry Andric     SF = static_cast<MachOPlatformRuntimeState::MachOExecutorSymbolFlags>(Tmp);
4385f757f3fSDimitry Andric     return true;
4395f757f3fSDimitry Andric   }
4405f757f3fSDimitry Andric };
4415f757f3fSDimitry Andric 
4425f757f3fSDimitry Andric } // namespace __orc_rt
4435f757f3fSDimitry Andric 
4445f757f3fSDimitry Andric namespace {
4455f757f3fSDimitry Andric 
446fe6060f1SDimitry Andric MachOPlatformRuntimeState *MachOPlatformRuntimeState::MOPS = nullptr;
447fe6060f1SDimitry Andric 
create()448bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::create() {
449fe6060f1SDimitry Andric   assert(!MOPS && "MachOPlatformRuntimeState should be null");
450fe6060f1SDimitry Andric   MOPS = new MachOPlatformRuntimeState();
451bdd1243dSDimitry Andric   return MOPS->initialize();
452fe6060f1SDimitry Andric }
453fe6060f1SDimitry Andric 
get()454fe6060f1SDimitry Andric MachOPlatformRuntimeState &MachOPlatformRuntimeState::get() {
455fe6060f1SDimitry Andric   assert(MOPS && "MachOPlatformRuntimeState not initialized");
456fe6060f1SDimitry Andric   return *MOPS;
457fe6060f1SDimitry Andric }
458fe6060f1SDimitry Andric 
destroy()459bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::destroy() {
460fe6060f1SDimitry Andric   assert(MOPS && "MachOPlatformRuntimeState not initialized");
461bdd1243dSDimitry Andric   auto Err = MOPS->shutdown();
462fe6060f1SDimitry Andric   delete MOPS;
463bdd1243dSDimitry Andric   return Err;
464bdd1243dSDimitry Andric }
465bdd1243dSDimitry Andric 
initialize()466bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::initialize() {
467bdd1243dSDimitry Andric   UseCallbackStyleUnwindInfo = __unw_add_find_dynamic_unwind_sections &&
468bdd1243dSDimitry Andric                                __unw_remove_find_dynamic_unwind_sections;
469bdd1243dSDimitry Andric   if (UseCallbackStyleUnwindInfo) {
470bdd1243dSDimitry Andric     ORC_RT_DEBUG({
471bdd1243dSDimitry Andric       printdbg("__unw_add/remove_find_dynamic_unwind_sections available."
472bdd1243dSDimitry Andric                " Using callback-based frame info lookup.\n");
473bdd1243dSDimitry Andric     });
474bdd1243dSDimitry Andric     if (__unw_add_find_dynamic_unwind_sections(&findDynamicUnwindSections))
475bdd1243dSDimitry Andric       return make_error<StringError>(
476bdd1243dSDimitry Andric           "Could not register findDynamicUnwindSections");
477bdd1243dSDimitry Andric   } else {
478bdd1243dSDimitry Andric     ORC_RT_DEBUG({
479bdd1243dSDimitry Andric       printdbg("__unw_add/remove_find_dynamic_unwind_sections not available."
480bdd1243dSDimitry Andric                " Using classic frame info registration.\n");
481bdd1243dSDimitry Andric     });
482bdd1243dSDimitry Andric   }
483bdd1243dSDimitry Andric   return Error::success();
484bdd1243dSDimitry Andric }
485bdd1243dSDimitry Andric 
shutdown()486bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::shutdown() {
48706c3fb27SDimitry Andric   if (UseCallbackStyleUnwindInfo) {
488bdd1243dSDimitry Andric     if (__unw_remove_find_dynamic_unwind_sections(&findDynamicUnwindSections)) {
489bdd1243dSDimitry Andric       ORC_RT_DEBUG(
490bdd1243dSDimitry Andric           { printdbg("__unw_remove_find_dynamic_unwind_sections failed.\n"); });
491bdd1243dSDimitry Andric     }
492bdd1243dSDimitry Andric   }
493bdd1243dSDimitry Andric   return Error::success();
494fe6060f1SDimitry Andric }
495fe6060f1SDimitry Andric 
registerJITDylib(std::string Name,void * Header)49681ad6265SDimitry Andric Error MachOPlatformRuntimeState::registerJITDylib(std::string Name,
49781ad6265SDimitry Andric                                                   void *Header) {
49881ad6265SDimitry Andric   ORC_RT_DEBUG({
49981ad6265SDimitry Andric     printdbg("Registering JITDylib %s: Header = %p\n", Name.c_str(), Header);
50081ad6265SDimitry Andric   });
501bdd1243dSDimitry Andric   std::lock_guard<std::mutex> Lock(JDStatesMutex);
50281ad6265SDimitry Andric   if (JDStates.count(Header)) {
50381ad6265SDimitry Andric     std::ostringstream ErrStream;
50481ad6265SDimitry Andric     ErrStream << "Duplicate JITDylib registration for header " << Header
50581ad6265SDimitry Andric               << " (name = " << Name << ")";
50681ad6265SDimitry Andric     return make_error<StringError>(ErrStream.str());
50781ad6265SDimitry Andric   }
50881ad6265SDimitry Andric   if (JDNameToHeader.count(Name)) {
50981ad6265SDimitry Andric     std::ostringstream ErrStream;
51081ad6265SDimitry Andric     ErrStream << "Duplicate JITDylib registration for header " << Header
51181ad6265SDimitry Andric               << " (header = " << Header << ")";
51281ad6265SDimitry Andric     return make_error<StringError>(ErrStream.str());
51381ad6265SDimitry Andric   }
51481ad6265SDimitry Andric 
51581ad6265SDimitry Andric   auto &JDS = JDStates[Header];
51681ad6265SDimitry Andric   JDS.Name = std::move(Name);
51781ad6265SDimitry Andric   JDS.Header = Header;
51881ad6265SDimitry Andric   JDNameToHeader[JDS.Name] = Header;
51981ad6265SDimitry Andric   return Error::success();
52081ad6265SDimitry Andric }
52181ad6265SDimitry Andric 
deregisterJITDylib(void * Header)52281ad6265SDimitry Andric Error MachOPlatformRuntimeState::deregisterJITDylib(void *Header) {
523bdd1243dSDimitry Andric   std::lock_guard<std::mutex> Lock(JDStatesMutex);
52481ad6265SDimitry Andric   auto I = JDStates.find(Header);
52581ad6265SDimitry Andric   if (I == JDStates.end()) {
52681ad6265SDimitry Andric     std::ostringstream ErrStream;
52781ad6265SDimitry Andric     ErrStream << "Attempted to deregister unrecognized header " << Header;
52881ad6265SDimitry Andric     return make_error<StringError>(ErrStream.str());
52981ad6265SDimitry Andric   }
53081ad6265SDimitry Andric 
53181ad6265SDimitry Andric   // Remove std::string construction once we can use C++20.
53281ad6265SDimitry Andric   auto J = JDNameToHeader.find(
53381ad6265SDimitry Andric       std::string(I->second.Name.data(), I->second.Name.size()));
53481ad6265SDimitry Andric   assert(J != JDNameToHeader.end() &&
53581ad6265SDimitry Andric          "Missing JDNameToHeader entry for JITDylib");
53681ad6265SDimitry Andric 
53781ad6265SDimitry Andric   ORC_RT_DEBUG({
53881ad6265SDimitry Andric     printdbg("Deregistering JITDylib %s: Header = %p\n", I->second.Name.c_str(),
53981ad6265SDimitry Andric              Header);
54081ad6265SDimitry Andric   });
54181ad6265SDimitry Andric 
54281ad6265SDimitry Andric   JDNameToHeader.erase(J);
54381ad6265SDimitry Andric   JDStates.erase(I);
54481ad6265SDimitry Andric   return Error::success();
54581ad6265SDimitry Andric }
54681ad6265SDimitry Andric 
registerThreadDataSection(span<const char> ThreadDataSection)547349cc55cSDimitry Andric Error MachOPlatformRuntimeState::registerThreadDataSection(
548349cc55cSDimitry Andric     span<const char> ThreadDataSection) {
549349cc55cSDimitry Andric   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
550349cc55cSDimitry Andric   auto I = ThreadDataSections.upper_bound(ThreadDataSection.data());
551349cc55cSDimitry Andric   if (I != ThreadDataSections.begin()) {
552349cc55cSDimitry Andric     auto J = std::prev(I);
553349cc55cSDimitry Andric     if (J->first + J->second > ThreadDataSection.data())
554349cc55cSDimitry Andric       return make_error<StringError>("Overlapping __thread_data sections");
555fe6060f1SDimitry Andric   }
556349cc55cSDimitry Andric   ThreadDataSections.insert(
557349cc55cSDimitry Andric       I, std::make_pair(ThreadDataSection.data(), ThreadDataSection.size()));
558fe6060f1SDimitry Andric   return Error::success();
559fe6060f1SDimitry Andric }
560fe6060f1SDimitry Andric 
deregisterThreadDataSection(span<const char> ThreadDataSection)561349cc55cSDimitry Andric Error MachOPlatformRuntimeState::deregisterThreadDataSection(
562349cc55cSDimitry Andric     span<const char> ThreadDataSection) {
563349cc55cSDimitry Andric   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
564349cc55cSDimitry Andric   auto I = ThreadDataSections.find(ThreadDataSection.data());
565349cc55cSDimitry Andric   if (I == ThreadDataSections.end())
566349cc55cSDimitry Andric     return make_error<StringError>("Attempt to deregister unknown thread data "
567349cc55cSDimitry Andric                                    "section");
568349cc55cSDimitry Andric   ThreadDataSections.erase(I);
569fe6060f1SDimitry Andric   return Error::success();
570fe6060f1SDimitry Andric }
571fe6060f1SDimitry Andric 
registerObjectSymbolTable(ExecutorAddr HeaderAddr,const std::vector<std::tuple<ExecutorAddr,ExecutorAddr,MachOExecutorSymbolFlags>> & Entries)5725f757f3fSDimitry Andric Error MachOPlatformRuntimeState::registerObjectSymbolTable(
5735f757f3fSDimitry Andric     ExecutorAddr HeaderAddr,
5745f757f3fSDimitry Andric     const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
5755f757f3fSDimitry Andric                                  MachOExecutorSymbolFlags>> &Entries) {
5765f757f3fSDimitry Andric 
5775f757f3fSDimitry Andric   std::lock_guard<std::mutex> Lock(JDStatesMutex);
5785f757f3fSDimitry Andric   auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
5795f757f3fSDimitry Andric   if (!JDS) {
5805f757f3fSDimitry Andric     std::ostringstream ErrStream;
5815f757f3fSDimitry Andric     ErrStream << "Could not register object platform sections for "
5825f757f3fSDimitry Andric                  "unrecognized header "
5835f757f3fSDimitry Andric               << HeaderAddr.toPtr<void *>();
5845f757f3fSDimitry Andric     return make_error<StringError>(ErrStream.str());
5855f757f3fSDimitry Andric   }
5865f757f3fSDimitry Andric 
5875f757f3fSDimitry Andric   for (auto &[NameAddr, SymAddr, Flags] : Entries)
5885f757f3fSDimitry Andric     JDS->SymbolTable[NameAddr.toPtr<const char *>()] = {SymAddr, Flags};
5895f757f3fSDimitry Andric 
5905f757f3fSDimitry Andric   return Error::success();
5915f757f3fSDimitry Andric }
5925f757f3fSDimitry Andric 
deregisterObjectSymbolTable(ExecutorAddr HeaderAddr,const std::vector<std::tuple<ExecutorAddr,ExecutorAddr,MachOExecutorSymbolFlags>> & Entries)5935f757f3fSDimitry Andric Error MachOPlatformRuntimeState::deregisterObjectSymbolTable(
5945f757f3fSDimitry Andric     ExecutorAddr HeaderAddr,
5955f757f3fSDimitry Andric     const std::vector<std::tuple<ExecutorAddr, ExecutorAddr,
5965f757f3fSDimitry Andric                                  MachOExecutorSymbolFlags>> &Entries) {
5975f757f3fSDimitry Andric 
5985f757f3fSDimitry Andric   std::lock_guard<std::mutex> Lock(JDStatesMutex);
5995f757f3fSDimitry Andric   auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
6005f757f3fSDimitry Andric   if (!JDS) {
6015f757f3fSDimitry Andric     std::ostringstream ErrStream;
6025f757f3fSDimitry Andric     ErrStream << "Could not register object platform sections for "
6035f757f3fSDimitry Andric                  "unrecognized header "
6045f757f3fSDimitry Andric               << HeaderAddr.toPtr<void *>();
6055f757f3fSDimitry Andric     return make_error<StringError>(ErrStream.str());
6065f757f3fSDimitry Andric   }
6075f757f3fSDimitry Andric 
6085f757f3fSDimitry Andric   for (auto &[NameAddr, SymAddr, Flags] : Entries)
6095f757f3fSDimitry Andric     JDS->SymbolTable.erase(NameAddr.toPtr<const char *>());
6105f757f3fSDimitry Andric 
6115f757f3fSDimitry Andric   return Error::success();
6125f757f3fSDimitry Andric }
6135f757f3fSDimitry Andric 
registerObjectPlatformSections(ExecutorAddr HeaderAddr,std::optional<UnwindSectionInfo> UnwindInfo,std::vector<std::pair<std::string_view,ExecutorAddrRange>> Secs)61481ad6265SDimitry Andric Error MachOPlatformRuntimeState::registerObjectPlatformSections(
615bdd1243dSDimitry Andric     ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindInfo,
616bdd1243dSDimitry Andric     std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) {
617bdd1243dSDimitry Andric 
618bdd1243dSDimitry Andric   // FIXME: Reject platform section registration after the JITDylib is
619bdd1243dSDimitry Andric   // sealed?
620bdd1243dSDimitry Andric 
62181ad6265SDimitry Andric   ORC_RT_DEBUG({
62281ad6265SDimitry Andric     printdbg("MachOPlatform: Registering object sections for %p.\n",
62381ad6265SDimitry Andric              HeaderAddr.toPtr<void *>());
62481ad6265SDimitry Andric   });
62581ad6265SDimitry Andric 
626bdd1243dSDimitry Andric   std::lock_guard<std::mutex> Lock(JDStatesMutex);
62781ad6265SDimitry Andric   auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
62881ad6265SDimitry Andric   if (!JDS) {
62981ad6265SDimitry Andric     std::ostringstream ErrStream;
63081ad6265SDimitry Andric     ErrStream << "Could not register object platform sections for "
63181ad6265SDimitry Andric                  "unrecognized header "
63281ad6265SDimitry Andric               << HeaderAddr.toPtr<void *>();
63381ad6265SDimitry Andric     return make_error<StringError>(ErrStream.str());
63481ad6265SDimitry Andric   }
63581ad6265SDimitry Andric 
636bdd1243dSDimitry Andric   if (UnwindInfo && UseCallbackStyleUnwindInfo) {
637bdd1243dSDimitry Andric     ORC_RT_DEBUG({
638bdd1243dSDimitry Andric       printdbg("  Registering new-style unwind info for:\n"
639bdd1243dSDimitry Andric                "    DWARF: %p -- %p\n"
640bdd1243dSDimitry Andric                "    Compact-unwind: %p -- %p\n"
641bdd1243dSDimitry Andric                "  for:\n",
642bdd1243dSDimitry Andric                UnwindInfo->DwarfSection.Start.toPtr<void *>(),
643bdd1243dSDimitry Andric                UnwindInfo->DwarfSection.End.toPtr<void *>(),
644bdd1243dSDimitry Andric                UnwindInfo->CompactUnwindSection.Start.toPtr<void *>(),
645bdd1243dSDimitry Andric                UnwindInfo->CompactUnwindSection.End.toPtr<void *>());
646bdd1243dSDimitry Andric     });
647bdd1243dSDimitry Andric     for (auto &CodeRange : UnwindInfo->CodeRanges) {
648bdd1243dSDimitry Andric       JDS->UnwindSections.insert(CodeRange.Start.toPtr<char *>(),
649bdd1243dSDimitry Andric                                  CodeRange.End.toPtr<char *>(), *UnwindInfo);
650bdd1243dSDimitry Andric       ORC_RT_DEBUG({
651bdd1243dSDimitry Andric         printdbg("    [ %p -- %p ]\n", CodeRange.Start.toPtr<void *>(),
652bdd1243dSDimitry Andric                  CodeRange.End.toPtr<void *>());
653bdd1243dSDimitry Andric       });
654bdd1243dSDimitry Andric     }
655bdd1243dSDimitry Andric   }
656bdd1243dSDimitry Andric 
65781ad6265SDimitry Andric   for (auto &KV : Secs) {
65881ad6265SDimitry Andric     // FIXME: Validate section ranges?
659bdd1243dSDimitry Andric     if (KV.first == "__TEXT,__eh_frame") {
660bdd1243dSDimitry Andric       if (!UseCallbackStyleUnwindInfo) {
661bdd1243dSDimitry Andric         // Use classic libunwind registration.
662bdd1243dSDimitry Andric         if (auto Err = registerEHFrames(KV.second.toSpan<const char>()))
663bdd1243dSDimitry Andric           return Err;
664bdd1243dSDimitry Andric       }
665bdd1243dSDimitry Andric     } else if (KV.first == "__DATA,__data") {
666bdd1243dSDimitry Andric       assert(!JDS->DataSectionContent.count(KV.second.Start.toPtr<char *>()) &&
667bdd1243dSDimitry Andric              "Address already registered.");
668bdd1243dSDimitry Andric       auto S = KV.second.toSpan<char>();
669bdd1243dSDimitry Andric       JDS->DataSectionContent[KV.second.Start.toPtr<char *>()] =
670bdd1243dSDimitry Andric           std::vector<char>(S.begin(), S.end());
671bdd1243dSDimitry Andric     } else if (KV.first == "__DATA,__common") {
672bdd1243dSDimitry Andric       JDS->ZeroInitRanges[KV.second.Start.toPtr<char *>()] = KV.second.size();
673bdd1243dSDimitry Andric     } else if (KV.first == "__DATA,__thread_data") {
67481ad6265SDimitry Andric       if (auto Err = registerThreadDataSection(KV.second.toSpan<const char>()))
67581ad6265SDimitry Andric         return Err;
67606c3fb27SDimitry Andric     } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
67706c3fb27SDimitry Andric       JDS->ObjCRuntimeRegistrationObjects.add(KV.second.toSpan<char>());
67881ad6265SDimitry Andric     else if (KV.first == "__DATA,__mod_init_func")
679bdd1243dSDimitry Andric       JDS->ModInitsSections.add(KV.second.toSpan<void (*)()>());
68081ad6265SDimitry Andric     else {
68181ad6265SDimitry Andric       // Should this be a warning instead?
68281ad6265SDimitry Andric       return make_error<StringError>(
68381ad6265SDimitry Andric           "Encountered unexpected section " +
68481ad6265SDimitry Andric           std::string(KV.first.data(), KV.first.size()) +
68581ad6265SDimitry Andric           " while registering object platform sections");
68681ad6265SDimitry Andric     }
68781ad6265SDimitry Andric   }
68881ad6265SDimitry Andric 
68981ad6265SDimitry Andric   return Error::success();
69081ad6265SDimitry Andric }
69181ad6265SDimitry Andric 
deregisterObjectPlatformSections(ExecutorAddr HeaderAddr,std::optional<UnwindSectionInfo> UnwindInfo,std::vector<std::pair<std::string_view,ExecutorAddrRange>> Secs)69281ad6265SDimitry Andric Error MachOPlatformRuntimeState::deregisterObjectPlatformSections(
693bdd1243dSDimitry Andric     ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> UnwindInfo,
694bdd1243dSDimitry Andric     std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) {
69581ad6265SDimitry Andric   // TODO: Make this more efficient? (maybe unnecessary if removal is rare?)
69681ad6265SDimitry Andric   // TODO: Add a JITDylib prepare-for-teardown operation that clears all
69781ad6265SDimitry Andric   //       registered sections, causing this function to take the fast-path.
69881ad6265SDimitry Andric   ORC_RT_DEBUG({
6995f757f3fSDimitry Andric     printdbg("MachOPlatform: Deregistering object sections for %p.\n",
70081ad6265SDimitry Andric              HeaderAddr.toPtr<void *>());
70181ad6265SDimitry Andric   });
70281ad6265SDimitry Andric 
703bdd1243dSDimitry Andric   std::lock_guard<std::mutex> Lock(JDStatesMutex);
70481ad6265SDimitry Andric   auto *JDS = getJITDylibStateByHeader(HeaderAddr.toPtr<void *>());
70581ad6265SDimitry Andric   if (!JDS) {
70681ad6265SDimitry Andric     std::ostringstream ErrStream;
70781ad6265SDimitry Andric     ErrStream << "Could not register object platform sections for unrecognized "
70881ad6265SDimitry Andric                  "header "
70981ad6265SDimitry Andric               << HeaderAddr.toPtr<void *>();
71081ad6265SDimitry Andric     return make_error<StringError>(ErrStream.str());
71181ad6265SDimitry Andric   }
71281ad6265SDimitry Andric 
71381ad6265SDimitry Andric   // FIXME: Implement faster-path by returning immediately if JDS is being
71481ad6265SDimitry Andric   // torn down entirely?
71581ad6265SDimitry Andric 
716bdd1243dSDimitry Andric   // TODO: Make library permanent (i.e. not able to be dlclosed) if it contains
717bdd1243dSDimitry Andric   // any Swift or ObjC. Once this happens we can clear (and no longer record)
718bdd1243dSDimitry Andric   // data section content, as the library could never be re-initialized.
719bdd1243dSDimitry Andric 
720bdd1243dSDimitry Andric   if (UnwindInfo && UseCallbackStyleUnwindInfo) {
721bdd1243dSDimitry Andric     ORC_RT_DEBUG({
722bdd1243dSDimitry Andric       printdbg("  Deregistering new-style unwind info for:\n"
723bdd1243dSDimitry Andric                "    DWARF: %p -- %p\n"
724bdd1243dSDimitry Andric                "    Compact-unwind: %p -- %p\n"
725bdd1243dSDimitry Andric                "  for:\n",
726bdd1243dSDimitry Andric                UnwindInfo->DwarfSection.Start.toPtr<void *>(),
727bdd1243dSDimitry Andric                UnwindInfo->DwarfSection.End.toPtr<void *>(),
728bdd1243dSDimitry Andric                UnwindInfo->CompactUnwindSection.Start.toPtr<void *>(),
729bdd1243dSDimitry Andric                UnwindInfo->CompactUnwindSection.End.toPtr<void *>());
730bdd1243dSDimitry Andric     });
731bdd1243dSDimitry Andric     for (auto &CodeRange : UnwindInfo->CodeRanges) {
732bdd1243dSDimitry Andric       JDS->UnwindSections.erase(CodeRange.Start.toPtr<char *>(),
733bdd1243dSDimitry Andric                                 CodeRange.End.toPtr<char *>());
734bdd1243dSDimitry Andric       ORC_RT_DEBUG({
735bdd1243dSDimitry Andric         printdbg("    [ %p -- %p ]\n", CodeRange.Start.toPtr<void *>(),
736bdd1243dSDimitry Andric                  CodeRange.End.toPtr<void *>());
737bdd1243dSDimitry Andric       });
738bdd1243dSDimitry Andric     }
739bdd1243dSDimitry Andric   }
740bdd1243dSDimitry Andric 
74181ad6265SDimitry Andric   for (auto &KV : Secs) {
74281ad6265SDimitry Andric     // FIXME: Validate section ranges?
743bdd1243dSDimitry Andric     if (KV.first == "__TEXT,__eh_frame") {
744bdd1243dSDimitry Andric       if (!UseCallbackStyleUnwindInfo) {
745bdd1243dSDimitry Andric         // Use classic libunwind registration.
746bdd1243dSDimitry Andric         if (auto Err = deregisterEHFrames(KV.second.toSpan<const char>()))
747bdd1243dSDimitry Andric           return Err;
748bdd1243dSDimitry Andric       }
749bdd1243dSDimitry Andric     } else if (KV.first == "__DATA,__data") {
750bdd1243dSDimitry Andric       JDS->DataSectionContent.erase(KV.second.Start.toPtr<char *>());
751bdd1243dSDimitry Andric     } else if (KV.first == "__DATA,__common") {
752bdd1243dSDimitry Andric       JDS->ZeroInitRanges.erase(KV.second.Start.toPtr<char *>());
753bdd1243dSDimitry Andric     } else if (KV.first == "__DATA,__thread_data") {
75481ad6265SDimitry Andric       if (auto Err =
75581ad6265SDimitry Andric               deregisterThreadDataSection(KV.second.toSpan<const char>()))
75681ad6265SDimitry Andric         return Err;
75706c3fb27SDimitry Andric     } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
75806c3fb27SDimitry Andric       JDS->ObjCRuntimeRegistrationObjects.removeIfPresent(KV.second);
759bdd1243dSDimitry Andric     else if (KV.first == "__DATA,__mod_init_func")
760bdd1243dSDimitry Andric       JDS->ModInitsSections.removeIfPresent(KV.second);
761bdd1243dSDimitry Andric     else {
76281ad6265SDimitry Andric       // Should this be a warning instead?
76381ad6265SDimitry Andric       return make_error<StringError>(
76481ad6265SDimitry Andric           "Encountered unexpected section " +
76581ad6265SDimitry Andric           std::string(KV.first.data(), KV.first.size()) +
76681ad6265SDimitry Andric           " while deregistering object platform sections");
76781ad6265SDimitry Andric     }
76881ad6265SDimitry Andric   }
76981ad6265SDimitry Andric   return Error::success();
77081ad6265SDimitry Andric }
77181ad6265SDimitry Andric 
dlerror()772fe6060f1SDimitry Andric const char *MachOPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); }
773fe6060f1SDimitry Andric 
dlopen(std::string_view Path,int Mode)774bdd1243dSDimitry Andric void *MachOPlatformRuntimeState::dlopen(std::string_view Path, int Mode) {
77581ad6265SDimitry Andric   ORC_RT_DEBUG({
77681ad6265SDimitry Andric     std::string S(Path.data(), Path.size());
77781ad6265SDimitry Andric     printdbg("MachOPlatform::dlopen(\"%s\")\n", S.c_str());
77881ad6265SDimitry Andric   });
779bdd1243dSDimitry Andric   std::lock_guard<std::recursive_mutex> Lock(DyldAPIMutex);
78081ad6265SDimitry Andric   if (auto H = dlopenImpl(Path, Mode))
78181ad6265SDimitry Andric     return *H;
78281ad6265SDimitry Andric   else {
78381ad6265SDimitry Andric     // FIXME: Make dlerror thread safe.
784fe6060f1SDimitry Andric     DLFcnError = toString(H.takeError());
785fe6060f1SDimitry Andric     return nullptr;
786fe6060f1SDimitry Andric   }
787fe6060f1SDimitry Andric }
788fe6060f1SDimitry Andric 
dlclose(void * DSOHandle)789fe6060f1SDimitry Andric int MachOPlatformRuntimeState::dlclose(void *DSOHandle) {
79081ad6265SDimitry Andric   ORC_RT_DEBUG({
79181ad6265SDimitry Andric     auto *JDS = getJITDylibStateByHeader(DSOHandle);
79281ad6265SDimitry Andric     std::string DylibName;
79381ad6265SDimitry Andric     if (JDS) {
79481ad6265SDimitry Andric       std::string S;
79581ad6265SDimitry Andric       printdbg("MachOPlatform::dlclose(%p) (%s)\n", DSOHandle, S.c_str());
79681ad6265SDimitry Andric     } else
79781ad6265SDimitry Andric       printdbg("MachOPlatform::dlclose(%p) (%s)\n", DSOHandle,
79881ad6265SDimitry Andric                "invalid handle");
79981ad6265SDimitry Andric   });
800bdd1243dSDimitry Andric   std::lock_guard<std::recursive_mutex> Lock(DyldAPIMutex);
80181ad6265SDimitry Andric   if (auto Err = dlcloseImpl(DSOHandle)) {
80281ad6265SDimitry Andric     // FIXME: Make dlerror thread safe.
80381ad6265SDimitry Andric     DLFcnError = toString(std::move(Err));
80481ad6265SDimitry Andric     return -1;
80581ad6265SDimitry Andric   }
806fe6060f1SDimitry Andric   return 0;
807fe6060f1SDimitry Andric }
808fe6060f1SDimitry Andric 
dlsym(void * DSOHandle,const char * Symbol)8095f757f3fSDimitry Andric void *MachOPlatformRuntimeState::dlsym(void *DSOHandle, const char *Symbol) {
8105f757f3fSDimitry Andric   std::unique_lock<std::mutex> Lock(JDStatesMutex);
8115f757f3fSDimitry Andric   auto *JDS = getJITDylibStateByHeader(DSOHandle);
8125f757f3fSDimitry Andric   if (!JDS) {
8135f757f3fSDimitry Andric     std::ostringstream ErrStream;
8145f757f3fSDimitry Andric     ErrStream << "In call to dlsym, unrecognized header address " << DSOHandle;
8155f757f3fSDimitry Andric     DLFcnError = ErrStream.str();
8165f757f3fSDimitry Andric     return nullptr;
817fe6060f1SDimitry Andric   }
818fe6060f1SDimitry Andric 
8195f757f3fSDimitry Andric   std::string MangledName = std::string("_") + Symbol;
8205f757f3fSDimitry Andric   std::pair<std::string_view, bool> Lookup(MangledName, false);
8215f757f3fSDimitry Andric   std::pair<ExecutorAddr, MachOExecutorSymbolFlags> Result;
8225f757f3fSDimitry Andric 
8235f757f3fSDimitry Andric   if (auto Err = lookupSymbols(*JDS, Lock, {&Result, 1}, {&Lookup, 1})) {
8245f757f3fSDimitry Andric     DLFcnError = toString(std::move(Err));
8255f757f3fSDimitry Andric     return nullptr;
8265f757f3fSDimitry Andric   }
8275f757f3fSDimitry Andric 
828*cb14a3feSDimitry Andric   // Sign callable symbols as functions, to match dyld.
829*cb14a3feSDimitry Andric   if ((Result.second & MachOExecutorSymbolFlags::Callable) ==
830*cb14a3feSDimitry Andric       MachOExecutorSymbolFlags::Callable)
831*cb14a3feSDimitry Andric     return reinterpret_cast<void *>(Result.first.toPtr<void(void)>());
8325f757f3fSDimitry Andric   return Result.first.toPtr<void *>();
833fe6060f1SDimitry Andric }
834fe6060f1SDimitry Andric 
registerAtExit(void (* F)(void *),void * Arg,void * DSOHandle)835fe6060f1SDimitry Andric int MachOPlatformRuntimeState::registerAtExit(void (*F)(void *), void *Arg,
836fe6060f1SDimitry Andric                                               void *DSOHandle) {
837fe6060f1SDimitry Andric   // FIXME: Handle out-of-memory errors, returning -1 if OOM.
838bdd1243dSDimitry Andric   std::lock_guard<std::mutex> Lock(JDStatesMutex);
83981ad6265SDimitry Andric   auto *JDS = getJITDylibStateByHeader(DSOHandle);
84081ad6265SDimitry Andric   if (!JDS) {
84181ad6265SDimitry Andric     ORC_RT_DEBUG({
84281ad6265SDimitry Andric       printdbg("MachOPlatformRuntimeState::registerAtExit called with "
84381ad6265SDimitry Andric                "unrecognized dso handle %p\n",
84481ad6265SDimitry Andric                DSOHandle);
84581ad6265SDimitry Andric     });
84681ad6265SDimitry Andric     return -1;
84781ad6265SDimitry Andric   }
848fe6060f1SDimitry Andric   JDS->AtExits.push_back({F, Arg});
849fe6060f1SDimitry Andric   return 0;
850fe6060f1SDimitry Andric }
851fe6060f1SDimitry Andric 
runAtExits(std::unique_lock<std::mutex> & JDStatesLock,JITDylibState & JDS)852bdd1243dSDimitry Andric void MachOPlatformRuntimeState::runAtExits(
853bdd1243dSDimitry Andric     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
854bdd1243dSDimitry Andric   auto AtExits = std::move(JDS.AtExits);
855bdd1243dSDimitry Andric 
856bdd1243dSDimitry Andric   // Unlock while running atexits, as they may trigger operations that modify
857bdd1243dSDimitry Andric   // JDStates.
858bdd1243dSDimitry Andric   JDStatesLock.unlock();
859bdd1243dSDimitry Andric   while (!AtExits.empty()) {
860bdd1243dSDimitry Andric     auto &AE = AtExits.back();
86181ad6265SDimitry Andric     AE.Func(AE.Arg);
862bdd1243dSDimitry Andric     AtExits.pop_back();
86381ad6265SDimitry Andric   }
864bdd1243dSDimitry Andric   JDStatesLock.lock();
865fe6060f1SDimitry Andric }
866fe6060f1SDimitry Andric 
runAtExits(void * DSOHandle)86781ad6265SDimitry Andric void MachOPlatformRuntimeState::runAtExits(void *DSOHandle) {
868bdd1243dSDimitry Andric   std::unique_lock<std::mutex> Lock(JDStatesMutex);
86981ad6265SDimitry Andric   auto *JDS = getJITDylibStateByHeader(DSOHandle);
87081ad6265SDimitry Andric   ORC_RT_DEBUG({
87181ad6265SDimitry Andric     printdbg("MachOPlatformRuntimeState::runAtExits called on unrecognized "
87281ad6265SDimitry Andric              "dso_handle %p\n",
87381ad6265SDimitry Andric              DSOHandle);
87481ad6265SDimitry Andric   });
87581ad6265SDimitry Andric   if (JDS)
876bdd1243dSDimitry Andric     runAtExits(Lock, *JDS);
877fe6060f1SDimitry Andric }
878fe6060f1SDimitry Andric 
879fe6060f1SDimitry Andric Expected<std::pair<const char *, size_t>>
getThreadDataSectionFor(const char * ThreadData)880fe6060f1SDimitry Andric MachOPlatformRuntimeState::getThreadDataSectionFor(const char *ThreadData) {
881fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(ThreadDataSectionsMutex);
882fe6060f1SDimitry Andric   auto I = ThreadDataSections.upper_bound(ThreadData);
883fe6060f1SDimitry Andric   // Check that we have a valid entry covering this address.
884fe6060f1SDimitry Andric   if (I == ThreadDataSections.begin())
885fe6060f1SDimitry Andric     return make_error<StringError>("No thread local data section for key");
886fe6060f1SDimitry Andric   I = std::prev(I);
887fe6060f1SDimitry Andric   if (ThreadData >= I->first + I->second)
888fe6060f1SDimitry Andric     return make_error<StringError>("No thread local data section for key");
889fe6060f1SDimitry Andric   return *I;
890fe6060f1SDimitry Andric }
891fe6060f1SDimitry Andric 
89281ad6265SDimitry Andric MachOPlatformRuntimeState::JITDylibState *
getJITDylibStateByHeader(void * DSOHandle)89381ad6265SDimitry Andric MachOPlatformRuntimeState::getJITDylibStateByHeader(void *DSOHandle) {
894fe6060f1SDimitry Andric   auto I = JDStates.find(DSOHandle);
89581ad6265SDimitry Andric   if (I == JDStates.end()) {
89681ad6265SDimitry Andric     I = JDStates.insert(std::make_pair(DSOHandle, JITDylibState())).first;
89781ad6265SDimitry Andric     I->second.Header = DSOHandle;
89881ad6265SDimitry Andric   }
899fe6060f1SDimitry Andric   return &I->second;
900fe6060f1SDimitry Andric }
901fe6060f1SDimitry Andric 
90281ad6265SDimitry Andric MachOPlatformRuntimeState::JITDylibState *
getJITDylibStateByName(std::string_view Name)903bdd1243dSDimitry Andric MachOPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) {
90481ad6265SDimitry Andric   // FIXME: Avoid creating string once we have C++20.
905fe6060f1SDimitry Andric   auto I = JDNameToHeader.find(std::string(Name.data(), Name.size()));
90681ad6265SDimitry Andric   if (I != JDNameToHeader.end())
90781ad6265SDimitry Andric     return getJITDylibStateByHeader(I->second);
908fe6060f1SDimitry Andric   return nullptr;
909fe6060f1SDimitry Andric }
910fe6060f1SDimitry Andric 
requestPushSymbols(JITDylibState & JDS,span<std::pair<std::string_view,bool>> Symbols)9115f757f3fSDimitry Andric Error MachOPlatformRuntimeState::requestPushSymbols(
9125f757f3fSDimitry Andric     JITDylibState &JDS, span<std::pair<std::string_view, bool>> Symbols) {
9135f757f3fSDimitry Andric   Error OpErr = Error::success();
9145f757f3fSDimitry Andric   if (auto Err = WrapperFunction<SPSError(
9155f757f3fSDimitry Andric           SPSExecutorAddr, SPSSequence<SPSTuple<SPSString, bool>>)>::
9165f757f3fSDimitry Andric           call(&__orc_rt_macho_push_symbols_tag, OpErr,
9175f757f3fSDimitry Andric                ExecutorAddr::fromPtr(JDS.Header), Symbols)) {
9185f757f3fSDimitry Andric     cantFail(std::move(OpErr));
919fe6060f1SDimitry Andric     return std::move(Err);
9205f757f3fSDimitry Andric   }
9215f757f3fSDimitry Andric   return OpErr;
9225f757f3fSDimitry Andric }
9235f757f3fSDimitry Andric 
lookupSymbols(JITDylibState & JDS,std::unique_lock<std::mutex> & JDStatesLock,span<std::pair<ExecutorAddr,MachOExecutorSymbolFlags>> Result,span<std::pair<std::string_view,bool>> Symbols)9245f757f3fSDimitry Andric Error MachOPlatformRuntimeState::lookupSymbols(
9255f757f3fSDimitry Andric     JITDylibState &JDS, std::unique_lock<std::mutex> &JDStatesLock,
9265f757f3fSDimitry Andric     span<std::pair<ExecutorAddr, MachOExecutorSymbolFlags>> Result,
9275f757f3fSDimitry Andric     span<std::pair<std::string_view, bool>> Symbols) {
9285f757f3fSDimitry Andric   assert(JDStatesLock.owns_lock() &&
9295f757f3fSDimitry Andric          "JDStatesLock should be locked at call-site");
9305f757f3fSDimitry Andric   assert(Result.size() == Symbols.size() &&
9315f757f3fSDimitry Andric          "Results and Symbols span sizes should match");
9325f757f3fSDimitry Andric 
9335f757f3fSDimitry Andric   // Make an initial pass over the local symbol table.
9345f757f3fSDimitry Andric   std::vector<size_t> MissingSymbolIndexes;
9355f757f3fSDimitry Andric   for (size_t Idx = 0; Idx != Symbols.size(); ++Idx) {
9365f757f3fSDimitry Andric     auto I = JDS.SymbolTable.find(Symbols[Idx].first);
9375f757f3fSDimitry Andric     if (I != JDS.SymbolTable.end())
9385f757f3fSDimitry Andric       Result[Idx] = I->second;
9395f757f3fSDimitry Andric     else
9405f757f3fSDimitry Andric       MissingSymbolIndexes.push_back(Idx);
9415f757f3fSDimitry Andric   }
9425f757f3fSDimitry Andric 
9435f757f3fSDimitry Andric   // If everything has been resolved already then bail out early.
9445f757f3fSDimitry Andric   if (MissingSymbolIndexes.empty())
9455f757f3fSDimitry Andric     return Error::success();
9465f757f3fSDimitry Andric 
9475f757f3fSDimitry Andric   // Otherwise call back to the controller to try to request that the symbol
9485f757f3fSDimitry Andric   // be materialized.
9495f757f3fSDimitry Andric   std::vector<std::pair<std::string_view, bool>> MissingSymbols;
9505f757f3fSDimitry Andric   MissingSymbols.reserve(MissingSymbolIndexes.size());
9515f757f3fSDimitry Andric   ORC_RT_DEBUG({
9525f757f3fSDimitry Andric     printdbg("requesting push of %i missing symbols...\n",
9535f757f3fSDimitry Andric              MissingSymbolIndexes.size());
9545f757f3fSDimitry Andric   });
9555f757f3fSDimitry Andric   for (auto MissingIdx : MissingSymbolIndexes)
9565f757f3fSDimitry Andric     MissingSymbols.push_back(Symbols[MissingIdx]);
9575f757f3fSDimitry Andric 
9585f757f3fSDimitry Andric   JDStatesLock.unlock();
9595f757f3fSDimitry Andric   if (auto Err = requestPushSymbols(
9605f757f3fSDimitry Andric           JDS, {MissingSymbols.data(), MissingSymbols.size()}))
9615f757f3fSDimitry Andric     return Err;
9625f757f3fSDimitry Andric   JDStatesLock.lock();
9635f757f3fSDimitry Andric 
9645f757f3fSDimitry Andric   // Try to resolve the previously missing symbols locally.
9655f757f3fSDimitry Andric   std::vector<size_t> MissingRequiredSymbols;
9665f757f3fSDimitry Andric   for (auto MissingIdx : MissingSymbolIndexes) {
9675f757f3fSDimitry Andric     auto I = JDS.SymbolTable.find(Symbols[MissingIdx].first);
9685f757f3fSDimitry Andric     if (I != JDS.SymbolTable.end())
9695f757f3fSDimitry Andric       Result[MissingIdx] = I->second;
9705f757f3fSDimitry Andric     else {
9715f757f3fSDimitry Andric       if (Symbols[MissingIdx].second)
9725f757f3fSDimitry Andric         MissingRequiredSymbols.push_back(MissingIdx);
9735f757f3fSDimitry Andric       else
9745f757f3fSDimitry Andric         Result[MissingIdx] = {ExecutorAddr(), {}};
9755f757f3fSDimitry Andric     }
9765f757f3fSDimitry Andric   }
9775f757f3fSDimitry Andric 
9785f757f3fSDimitry Andric   // Error out if any missing symbols could not be resolved.
9795f757f3fSDimitry Andric   if (!MissingRequiredSymbols.empty()) {
9805f757f3fSDimitry Andric     std::ostringstream ErrStream;
9815f757f3fSDimitry Andric     ErrStream << "Lookup could not find required symbols: [ ";
9825f757f3fSDimitry Andric     for (auto MissingIdx : MissingRequiredSymbols)
9835f757f3fSDimitry Andric       ErrStream << "\"" << Symbols[MissingIdx].first << "\" ";
9845f757f3fSDimitry Andric     ErrStream << "]";
9855f757f3fSDimitry Andric     return make_error<StringError>(ErrStream.str());
9865f757f3fSDimitry Andric   }
9875f757f3fSDimitry Andric 
9885f757f3fSDimitry Andric   return Error::success();
989fe6060f1SDimitry Andric }
990fe6060f1SDimitry Andric 
991bdd1243dSDimitry Andric // eh-frame registration functions.
992bdd1243dSDimitry Andric // We expect these to be available for all processes.
993bdd1243dSDimitry Andric extern "C" void __register_frame(const void *);
994bdd1243dSDimitry Andric extern "C" void __deregister_frame(const void *);
995bdd1243dSDimitry Andric 
996bdd1243dSDimitry Andric template <typename HandleFDEFn>
walkEHFrameSection(span<const char> EHFrameSection,HandleFDEFn HandleFDE)997bdd1243dSDimitry Andric void walkEHFrameSection(span<const char> EHFrameSection,
998bdd1243dSDimitry Andric                         HandleFDEFn HandleFDE) {
999bdd1243dSDimitry Andric   const char *CurCFIRecord = EHFrameSection.data();
1000bdd1243dSDimitry Andric   uint64_t Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
1001bdd1243dSDimitry Andric 
1002bdd1243dSDimitry Andric   while (CurCFIRecord != EHFrameSection.end() && Size != 0) {
1003bdd1243dSDimitry Andric     const char *OffsetField = CurCFIRecord + (Size == 0xffffffff ? 12 : 4);
1004bdd1243dSDimitry Andric     if (Size == 0xffffffff)
1005bdd1243dSDimitry Andric       Size = *reinterpret_cast<const uint64_t *>(CurCFIRecord + 4) + 12;
1006bdd1243dSDimitry Andric     else
1007bdd1243dSDimitry Andric       Size += 4;
1008bdd1243dSDimitry Andric     uint32_t Offset = *reinterpret_cast<const uint32_t *>(OffsetField);
1009bdd1243dSDimitry Andric 
1010bdd1243dSDimitry Andric     if (Offset != 0)
1011bdd1243dSDimitry Andric       HandleFDE(CurCFIRecord);
1012bdd1243dSDimitry Andric 
1013bdd1243dSDimitry Andric     CurCFIRecord += Size;
1014bdd1243dSDimitry Andric     Size = *reinterpret_cast<const uint32_t *>(CurCFIRecord);
1015bdd1243dSDimitry Andric   }
1016fe6060f1SDimitry Andric }
1017fe6060f1SDimitry Andric 
lookupUnwindSections(void * Addr,unw_dynamic_unwind_sections & Info)1018bdd1243dSDimitry Andric bool MachOPlatformRuntimeState::lookupUnwindSections(
1019bdd1243dSDimitry Andric     void *Addr, unw_dynamic_unwind_sections &Info) {
1020bdd1243dSDimitry Andric   ORC_RT_DEBUG(
1021bdd1243dSDimitry Andric       { printdbg("Tried to lookup unwind-info via new lookup call.\n"); });
1022bdd1243dSDimitry Andric   std::lock_guard<std::mutex> Lock(JDStatesMutex);
1023bdd1243dSDimitry Andric   for (auto &KV : JDStates) {
1024bdd1243dSDimitry Andric     auto &JD = KV.second;
1025bdd1243dSDimitry Andric     auto I = JD.UnwindSections.find(reinterpret_cast<char *>(Addr));
1026bdd1243dSDimitry Andric     if (I != JD.UnwindSections.end()) {
1027bdd1243dSDimitry Andric       Info.dso_base = reinterpret_cast<uintptr_t>(JD.Header);
1028bdd1243dSDimitry Andric       Info.dwarf_section =
1029bdd1243dSDimitry Andric           reinterpret_cast<uintptr_t>(I->second.DwarfSection.data());
1030bdd1243dSDimitry Andric       Info.dwarf_section_length = I->second.DwarfSection.size();
1031bdd1243dSDimitry Andric       Info.compact_unwind_section =
1032bdd1243dSDimitry Andric           reinterpret_cast<uintptr_t>(I->second.CompactUnwindSection.data());
1033bdd1243dSDimitry Andric       Info.compact_unwind_section_length =
1034bdd1243dSDimitry Andric           I->second.CompactUnwindSection.size();
1035bdd1243dSDimitry Andric       return true;
1036bdd1243dSDimitry Andric     }
1037bdd1243dSDimitry Andric   }
1038bdd1243dSDimitry Andric   return false;
1039bdd1243dSDimitry Andric }
1040bdd1243dSDimitry Andric 
findDynamicUnwindSections(uintptr_t addr,unw_dynamic_unwind_sections * info)1041bdd1243dSDimitry Andric int MachOPlatformRuntimeState::findDynamicUnwindSections(
1042bdd1243dSDimitry Andric     uintptr_t addr, unw_dynamic_unwind_sections *info) {
1043bdd1243dSDimitry Andric   if (!info)
1044bdd1243dSDimitry Andric     return 0;
1045bdd1243dSDimitry Andric   return MachOPlatformRuntimeState::get().lookupUnwindSections((void *)addr,
1046bdd1243dSDimitry Andric                                                                *info);
1047bdd1243dSDimitry Andric }
1048bdd1243dSDimitry Andric 
registerEHFrames(span<const char> EHFrameSection)1049bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::registerEHFrames(
1050bdd1243dSDimitry Andric     span<const char> EHFrameSection) {
1051bdd1243dSDimitry Andric   walkEHFrameSection(EHFrameSection, __register_frame);
1052bdd1243dSDimitry Andric   return Error::success();
1053bdd1243dSDimitry Andric }
1054bdd1243dSDimitry Andric 
deregisterEHFrames(span<const char> EHFrameSection)1055bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::deregisterEHFrames(
1056bdd1243dSDimitry Andric     span<const char> EHFrameSection) {
1057bdd1243dSDimitry Andric   walkEHFrameSection(EHFrameSection, __deregister_frame);
1058bdd1243dSDimitry Andric   return Error::success();
105981ad6265SDimitry Andric }
1060fe6060f1SDimitry Andric 
registerObjCRegistrationObjects(JITDylibState & JDS)106106c3fb27SDimitry Andric Error MachOPlatformRuntimeState::registerObjCRegistrationObjects(
106281ad6265SDimitry Andric     JITDylibState &JDS) {
106306c3fb27SDimitry Andric   ORC_RT_DEBUG(printdbg("Registering Objective-C / Swift metadata.\n"));
106481ad6265SDimitry Andric 
106506c3fb27SDimitry Andric   std::vector<char *> RegObjBases;
106606c3fb27SDimitry Andric   JDS.ObjCRuntimeRegistrationObjects.processNewSections(
106706c3fb27SDimitry Andric       [&](span<char> RegObj) { RegObjBases.push_back(RegObj.data()); });
106806c3fb27SDimitry Andric 
106906c3fb27SDimitry Andric   if (RegObjBases.empty())
107081ad6265SDimitry Andric     return Error::success();
107181ad6265SDimitry Andric 
107206c3fb27SDimitry Andric   if (!_objc_map_images || !_objc_load_image)
1073fe6060f1SDimitry Andric     return make_error<StringError>(
107406c3fb27SDimitry Andric         "Could not register Objective-C / Swift metadata: _objc_map_images / "
107506c3fb27SDimitry Andric         "_objc_load_image not found");
1076fe6060f1SDimitry Andric 
107706c3fb27SDimitry Andric   std::vector<char *> Paths;
107806c3fb27SDimitry Andric   Paths.resize(RegObjBases.size());
107906c3fb27SDimitry Andric   _objc_map_images(RegObjBases.size(), Paths.data(),
108006c3fb27SDimitry Andric                    reinterpret_cast<mach_header **>(RegObjBases.data()));
108181ad6265SDimitry Andric 
108206c3fb27SDimitry Andric   for (void *RegObjBase : RegObjBases)
108306c3fb27SDimitry Andric     _objc_load_image(nullptr, reinterpret_cast<mach_header *>(RegObjBase));
108481ad6265SDimitry Andric 
108581ad6265SDimitry Andric   return Error::success();
108681ad6265SDimitry Andric }
108781ad6265SDimitry Andric 
runModInits(std::unique_lock<std::mutex> & JDStatesLock,JITDylibState & JDS)1088bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::runModInits(
1089bdd1243dSDimitry Andric     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
1090bdd1243dSDimitry Andric   std::vector<span<void (*)()>> InitSections;
1091bdd1243dSDimitry Andric   InitSections.reserve(JDS.ModInitsSections.numNewSections());
109281ad6265SDimitry Andric 
1093bdd1243dSDimitry Andric   // Copy initializer sections: If the JITDylib is unsealed then the
1094bdd1243dSDimitry Andric   // initializers could reach back into the JIT and cause more initializers to
1095bdd1243dSDimitry Andric   // be added.
1096bdd1243dSDimitry Andric   // FIXME: Skip unlock and run in-place on sealed JITDylibs?
1097bdd1243dSDimitry Andric   JDS.ModInitsSections.processNewSections(
1098bdd1243dSDimitry Andric       [&](span<void (*)()> Inits) { InitSections.push_back(Inits); });
109981ad6265SDimitry Andric 
1100bdd1243dSDimitry Andric   JDStatesLock.unlock();
1101bdd1243dSDimitry Andric   for (auto InitSec : InitSections)
1102bdd1243dSDimitry Andric     for (auto *Init : InitSec)
1103bdd1243dSDimitry Andric       Init();
1104bdd1243dSDimitry Andric   JDStatesLock.lock();
1105bdd1243dSDimitry Andric 
110681ad6265SDimitry Andric   return Error::success();
110781ad6265SDimitry Andric }
110881ad6265SDimitry Andric 
dlopenImpl(std::string_view Path,int Mode)1109bdd1243dSDimitry Andric Expected<void *> MachOPlatformRuntimeState::dlopenImpl(std::string_view Path,
111081ad6265SDimitry Andric                                                        int Mode) {
1111bdd1243dSDimitry Andric   std::unique_lock<std::mutex> Lock(JDStatesMutex);
1112bdd1243dSDimitry Andric 
111381ad6265SDimitry Andric   // Try to find JITDylib state by name.
111481ad6265SDimitry Andric   auto *JDS = getJITDylibStateByName(Path);
111581ad6265SDimitry Andric 
111681ad6265SDimitry Andric   if (!JDS)
111781ad6265SDimitry Andric     return make_error<StringError>("No registered JTIDylib for path " +
111881ad6265SDimitry Andric                                    std::string(Path.data(), Path.size()));
111981ad6265SDimitry Andric 
112081ad6265SDimitry Andric   // If this JITDylib is unsealed, or this is the first dlopen then run
112181ad6265SDimitry Andric   // full dlopen path (update deps, push and run initializers, update ref
112281ad6265SDimitry Andric   // counts on all JITDylibs in the dep tree).
112381ad6265SDimitry Andric   if (!JDS->referenced() || !JDS->Sealed) {
1124bdd1243dSDimitry Andric     if (auto Err = dlopenFull(Lock, *JDS))
1125fe6060f1SDimitry Andric       return std::move(Err);
112681ad6265SDimitry Andric   }
1127fe6060f1SDimitry Andric 
112881ad6265SDimitry Andric   // Bump the ref-count on this dylib.
112981ad6265SDimitry Andric   ++JDS->DlRefCount;
113081ad6265SDimitry Andric 
113181ad6265SDimitry Andric   // Return the header address.
1132fe6060f1SDimitry Andric   return JDS->Header;
1133fe6060f1SDimitry Andric }
1134fe6060f1SDimitry Andric 
dlopenFull(std::unique_lock<std::mutex> & JDStatesLock,JITDylibState & JDS)1135bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::dlopenFull(
1136bdd1243dSDimitry Andric     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
113781ad6265SDimitry Andric   // Call back to the JIT to push the initializers.
113881ad6265SDimitry Andric   Expected<MachOJITDylibDepInfoMap> DepInfo((MachOJITDylibDepInfoMap()));
1139bdd1243dSDimitry Andric   // Unlock so that we can accept the initializer update.
1140bdd1243dSDimitry Andric   JDStatesLock.unlock();
114181ad6265SDimitry Andric   if (auto Err = WrapperFunction<SPSExpected<SPSMachOJITDylibDepInfoMap>(
114281ad6265SDimitry Andric           SPSExecutorAddr)>::call(&__orc_rt_macho_push_initializers_tag,
114381ad6265SDimitry Andric                                   DepInfo, ExecutorAddr::fromPtr(JDS.Header)))
114481ad6265SDimitry Andric     return Err;
1145bdd1243dSDimitry Andric   JDStatesLock.lock();
1146bdd1243dSDimitry Andric 
114781ad6265SDimitry Andric   if (!DepInfo)
114881ad6265SDimitry Andric     return DepInfo.takeError();
1149fe6060f1SDimitry Andric 
1150bdd1243dSDimitry Andric   if (auto Err = dlopenInitialize(JDStatesLock, JDS, *DepInfo))
115181ad6265SDimitry Andric     return Err;
1152fe6060f1SDimitry Andric 
115381ad6265SDimitry Andric   if (!DepInfo->empty()) {
115481ad6265SDimitry Andric     ORC_RT_DEBUG({
115581ad6265SDimitry Andric       printdbg("Unrecognized dep-info key headers in dlopen of %s\n",
115681ad6265SDimitry Andric                JDS.Name.c_str());
115781ad6265SDimitry Andric     });
115881ad6265SDimitry Andric     std::ostringstream ErrStream;
115981ad6265SDimitry Andric     ErrStream << "Encountered unrecognized dep-info key headers "
116081ad6265SDimitry Andric                  "while processing dlopen of "
116181ad6265SDimitry Andric               << JDS.Name;
116281ad6265SDimitry Andric     return make_error<StringError>(ErrStream.str());
116381ad6265SDimitry Andric   }
116481ad6265SDimitry Andric 
116581ad6265SDimitry Andric   return Error::success();
116681ad6265SDimitry Andric }
116781ad6265SDimitry Andric 
dlopenInitialize(std::unique_lock<std::mutex> & JDStatesLock,JITDylibState & JDS,MachOJITDylibDepInfoMap & DepInfo)116881ad6265SDimitry Andric Error MachOPlatformRuntimeState::dlopenInitialize(
1169bdd1243dSDimitry Andric     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS,
1170bdd1243dSDimitry Andric     MachOJITDylibDepInfoMap &DepInfo) {
117181ad6265SDimitry Andric   ORC_RT_DEBUG({
117281ad6265SDimitry Andric     printdbg("MachOPlatformRuntimeState::dlopenInitialize(\"%s\")\n",
117381ad6265SDimitry Andric              JDS.Name.c_str());
117481ad6265SDimitry Andric   });
117581ad6265SDimitry Andric 
117681ad6265SDimitry Andric   // If the header is not present in the dep map then assume that we
117781ad6265SDimitry Andric   // already processed it earlier in the dlopenInitialize traversal and
117881ad6265SDimitry Andric   // return.
117981ad6265SDimitry Andric   // TODO: Keep a visited set instead so that we can error out on missing
118081ad6265SDimitry Andric   //       entries?
118181ad6265SDimitry Andric   auto I = DepInfo.find(ExecutorAddr::fromPtr(JDS.Header));
118281ad6265SDimitry Andric   if (I == DepInfo.end())
118381ad6265SDimitry Andric     return Error::success();
118481ad6265SDimitry Andric 
118581ad6265SDimitry Andric   auto DI = std::move(I->second);
118681ad6265SDimitry Andric   DepInfo.erase(I);
118781ad6265SDimitry Andric 
118881ad6265SDimitry Andric   // We don't need to re-initialize sealed JITDylibs that have already been
118981ad6265SDimitry Andric   // initialized. Just check that their dep-map entry is empty as expected.
119081ad6265SDimitry Andric   if (JDS.Sealed) {
119181ad6265SDimitry Andric     if (!DI.DepHeaders.empty()) {
119281ad6265SDimitry Andric       std::ostringstream ErrStream;
119381ad6265SDimitry Andric       ErrStream << "Sealed JITDylib " << JDS.Header
119481ad6265SDimitry Andric                 << " already has registered dependencies";
119581ad6265SDimitry Andric       return make_error<StringError>(ErrStream.str());
119681ad6265SDimitry Andric     }
119781ad6265SDimitry Andric     if (JDS.referenced())
119881ad6265SDimitry Andric       return Error::success();
119981ad6265SDimitry Andric   } else
120081ad6265SDimitry Andric     JDS.Sealed = DI.Sealed;
120181ad6265SDimitry Andric 
120281ad6265SDimitry Andric   // This is an unsealed or newly sealed JITDylib. Run initializers.
120381ad6265SDimitry Andric   std::vector<JITDylibState *> OldDeps;
120481ad6265SDimitry Andric   std::swap(JDS.Deps, OldDeps);
120581ad6265SDimitry Andric   JDS.Deps.reserve(DI.DepHeaders.size());
120681ad6265SDimitry Andric   for (auto DepHeaderAddr : DI.DepHeaders) {
120781ad6265SDimitry Andric     auto *DepJDS = getJITDylibStateByHeader(DepHeaderAddr.toPtr<void *>());
120881ad6265SDimitry Andric     if (!DepJDS) {
120981ad6265SDimitry Andric       std::ostringstream ErrStream;
121081ad6265SDimitry Andric       ErrStream << "Encountered unrecognized dep header "
121181ad6265SDimitry Andric                 << DepHeaderAddr.toPtr<void *>() << " while initializing "
121281ad6265SDimitry Andric                 << JDS.Name;
121381ad6265SDimitry Andric       return make_error<StringError>(ErrStream.str());
121481ad6265SDimitry Andric     }
121581ad6265SDimitry Andric     ++DepJDS->LinkedAgainstRefCount;
1216bdd1243dSDimitry Andric     if (auto Err = dlopenInitialize(JDStatesLock, *DepJDS, DepInfo))
1217fe6060f1SDimitry Andric       return Err;
1218fe6060f1SDimitry Andric   }
121981ad6265SDimitry Andric 
122081ad6265SDimitry Andric   // Initialize this JITDylib.
122106c3fb27SDimitry Andric   if (auto Err = registerObjCRegistrationObjects(JDS))
122281ad6265SDimitry Andric     return Err;
1223bdd1243dSDimitry Andric   if (auto Err = runModInits(JDStatesLock, JDS))
122481ad6265SDimitry Andric     return Err;
122581ad6265SDimitry Andric 
122681ad6265SDimitry Andric   // Decrement old deps.
122781ad6265SDimitry Andric   // FIXME: We should probably continue and just report deinitialize errors
122881ad6265SDimitry Andric   // here.
122981ad6265SDimitry Andric   for (auto *DepJDS : OldDeps) {
123081ad6265SDimitry Andric     --DepJDS->LinkedAgainstRefCount;
123181ad6265SDimitry Andric     if (!DepJDS->referenced())
1232bdd1243dSDimitry Andric       if (auto Err = dlcloseDeinitialize(JDStatesLock, *DepJDS))
123381ad6265SDimitry Andric         return Err;
123481ad6265SDimitry Andric   }
123581ad6265SDimitry Andric 
123681ad6265SDimitry Andric   return Error::success();
123781ad6265SDimitry Andric }
123881ad6265SDimitry Andric 
dlcloseImpl(void * DSOHandle)123981ad6265SDimitry Andric Error MachOPlatformRuntimeState::dlcloseImpl(void *DSOHandle) {
1240bdd1243dSDimitry Andric   std::unique_lock<std::mutex> Lock(JDStatesMutex);
1241bdd1243dSDimitry Andric 
124281ad6265SDimitry Andric   // Try to find JITDylib state by header.
124381ad6265SDimitry Andric   auto *JDS = getJITDylibStateByHeader(DSOHandle);
124481ad6265SDimitry Andric 
124581ad6265SDimitry Andric   if (!JDS) {
124681ad6265SDimitry Andric     std::ostringstream ErrStream;
124781ad6265SDimitry Andric     ErrStream << "No registered JITDylib for " << DSOHandle;
124881ad6265SDimitry Andric     return make_error<StringError>(ErrStream.str());
124981ad6265SDimitry Andric   }
125081ad6265SDimitry Andric 
125181ad6265SDimitry Andric   // Bump the ref-count.
125281ad6265SDimitry Andric   --JDS->DlRefCount;
125381ad6265SDimitry Andric 
125481ad6265SDimitry Andric   if (!JDS->referenced())
1255bdd1243dSDimitry Andric     return dlcloseDeinitialize(Lock, *JDS);
125681ad6265SDimitry Andric 
125781ad6265SDimitry Andric   return Error::success();
125881ad6265SDimitry Andric }
125981ad6265SDimitry Andric 
dlcloseDeinitialize(std::unique_lock<std::mutex> & JDStatesLock,JITDylibState & JDS)1260bdd1243dSDimitry Andric Error MachOPlatformRuntimeState::dlcloseDeinitialize(
1261bdd1243dSDimitry Andric     std::unique_lock<std::mutex> &JDStatesLock, JITDylibState &JDS) {
126281ad6265SDimitry Andric 
126381ad6265SDimitry Andric   ORC_RT_DEBUG({
126481ad6265SDimitry Andric     printdbg("MachOPlatformRuntimeState::dlcloseDeinitialize(\"%s\")\n",
126581ad6265SDimitry Andric              JDS.Name.c_str());
126681ad6265SDimitry Andric   });
126781ad6265SDimitry Andric 
1268bdd1243dSDimitry Andric   runAtExits(JDStatesLock, JDS);
126981ad6265SDimitry Andric 
127081ad6265SDimitry Andric   // Reset mod-inits
1271bdd1243dSDimitry Andric   JDS.ModInitsSections.reset();
1272bdd1243dSDimitry Andric 
1273bdd1243dSDimitry Andric   // Reset data section contents.
1274bdd1243dSDimitry Andric   for (auto &KV : JDS.DataSectionContent)
1275bdd1243dSDimitry Andric     memcpy(KV.first, KV.second.data(), KV.second.size());
1276bdd1243dSDimitry Andric   for (auto &KV : JDS.ZeroInitRanges)
1277bdd1243dSDimitry Andric     memset(KV.first, 0, KV.second);
127881ad6265SDimitry Andric 
127981ad6265SDimitry Andric   // Deinitialize any dependencies.
128081ad6265SDimitry Andric   for (auto *DepJDS : JDS.Deps) {
128181ad6265SDimitry Andric     --DepJDS->LinkedAgainstRefCount;
128281ad6265SDimitry Andric     if (!DepJDS->referenced())
1283bdd1243dSDimitry Andric       if (auto Err = dlcloseDeinitialize(JDStatesLock, *DepJDS))
128481ad6265SDimitry Andric         return Err;
1285fe6060f1SDimitry Andric   }
1286fe6060f1SDimitry Andric 
1287fe6060f1SDimitry Andric   return Error::success();
1288fe6060f1SDimitry Andric }
1289fe6060f1SDimitry Andric 
1290fe6060f1SDimitry Andric class MachOPlatformRuntimeTLVManager {
1291fe6060f1SDimitry Andric public:
1292fe6060f1SDimitry Andric   void *getInstance(const char *ThreadData);
1293fe6060f1SDimitry Andric 
1294fe6060f1SDimitry Andric private:
1295fe6060f1SDimitry Andric   std::unordered_map<const char *, char *> Instances;
1296fe6060f1SDimitry Andric   std::unordered_map<const char *, std::unique_ptr<char[]>> AllocatedSections;
1297fe6060f1SDimitry Andric };
1298fe6060f1SDimitry Andric 
getInstance(const char * ThreadData)1299fe6060f1SDimitry Andric void *MachOPlatformRuntimeTLVManager::getInstance(const char *ThreadData) {
1300fe6060f1SDimitry Andric   auto I = Instances.find(ThreadData);
1301fe6060f1SDimitry Andric   if (I != Instances.end())
1302fe6060f1SDimitry Andric     return I->second;
1303fe6060f1SDimitry Andric 
1304fe6060f1SDimitry Andric   auto TDS =
1305fe6060f1SDimitry Andric       MachOPlatformRuntimeState::get().getThreadDataSectionFor(ThreadData);
1306fe6060f1SDimitry Andric   if (!TDS) {
1307fe6060f1SDimitry Andric     __orc_rt_log_error(toString(TDS.takeError()).c_str());
1308fe6060f1SDimitry Andric     return nullptr;
1309fe6060f1SDimitry Andric   }
1310fe6060f1SDimitry Andric 
1311fe6060f1SDimitry Andric   auto &Allocated = AllocatedSections[TDS->first];
1312fe6060f1SDimitry Andric   if (!Allocated) {
1313fe6060f1SDimitry Andric     Allocated = std::make_unique<char[]>(TDS->second);
1314fe6060f1SDimitry Andric     memcpy(Allocated.get(), TDS->first, TDS->second);
1315fe6060f1SDimitry Andric   }
1316fe6060f1SDimitry Andric 
1317fe6060f1SDimitry Andric   size_t ThreadDataDelta = ThreadData - TDS->first;
1318fe6060f1SDimitry Andric   assert(ThreadDataDelta <= TDS->second && "ThreadData outside section bounds");
1319fe6060f1SDimitry Andric 
1320fe6060f1SDimitry Andric   char *Instance = Allocated.get() + ThreadDataDelta;
1321fe6060f1SDimitry Andric   Instances[ThreadData] = Instance;
1322fe6060f1SDimitry Andric   return Instance;
1323fe6060f1SDimitry Andric }
1324fe6060f1SDimitry Andric 
destroyMachOTLVMgr(void * MachOTLVMgr)1325fe6060f1SDimitry Andric void destroyMachOTLVMgr(void *MachOTLVMgr) {
1326fe6060f1SDimitry Andric   delete static_cast<MachOPlatformRuntimeTLVManager *>(MachOTLVMgr);
1327fe6060f1SDimitry Andric }
1328fe6060f1SDimitry Andric 
runWrapperFunctionCalls(std::vector<WrapperFunctionCall> WFCs)1329349cc55cSDimitry Andric Error runWrapperFunctionCalls(std::vector<WrapperFunctionCall> WFCs) {
1330349cc55cSDimitry Andric   for (auto &WFC : WFCs)
133104eeddc0SDimitry Andric     if (auto Err = WFC.runWithSPSRet<void>())
1332349cc55cSDimitry Andric       return Err;
1333349cc55cSDimitry Andric   return Error::success();
1334349cc55cSDimitry Andric }
1335349cc55cSDimitry Andric 
1336fe6060f1SDimitry Andric } // end anonymous namespace
1337fe6060f1SDimitry Andric 
1338fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1339fe6060f1SDimitry Andric //                             JIT entry points
1340fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1341fe6060f1SDimitry Andric 
134206c3fb27SDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_platform_bootstrap(char * ArgData,size_t ArgSize)1343fe6060f1SDimitry Andric __orc_rt_macho_platform_bootstrap(char *ArgData, size_t ArgSize) {
1344bdd1243dSDimitry Andric   return WrapperFunction<SPSError()>::handle(
1345bdd1243dSDimitry Andric              ArgData, ArgSize,
1346bdd1243dSDimitry Andric              []() { return MachOPlatformRuntimeState::create(); })
1347bdd1243dSDimitry Andric       .release();
1348fe6060f1SDimitry Andric }
1349fe6060f1SDimitry Andric 
135006c3fb27SDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_platform_shutdown(char * ArgData,size_t ArgSize)1351fe6060f1SDimitry Andric __orc_rt_macho_platform_shutdown(char *ArgData, size_t ArgSize) {
1352bdd1243dSDimitry Andric   return WrapperFunction<SPSError()>::handle(
1353bdd1243dSDimitry Andric              ArgData, ArgSize,
1354bdd1243dSDimitry Andric              []() { return MachOPlatformRuntimeState::destroy(); })
1355bdd1243dSDimitry Andric       .release();
1356fe6060f1SDimitry Andric }
1357fe6060f1SDimitry Andric 
135806c3fb27SDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_register_jitdylib(char * ArgData,size_t ArgSize)135981ad6265SDimitry Andric __orc_rt_macho_register_jitdylib(char *ArgData, size_t ArgSize) {
136081ad6265SDimitry Andric   return WrapperFunction<SPSError(SPSString, SPSExecutorAddr)>::handle(
136104eeddc0SDimitry Andric              ArgData, ArgSize,
136281ad6265SDimitry Andric              [](std::string &Name, ExecutorAddr HeaderAddr) {
136381ad6265SDimitry Andric                return MachOPlatformRuntimeState::get().registerJITDylib(
136481ad6265SDimitry Andric                    std::move(Name), HeaderAddr.toPtr<void *>());
1365fe6060f1SDimitry Andric              })
1366fe6060f1SDimitry Andric       .release();
1367fe6060f1SDimitry Andric }
1368fe6060f1SDimitry Andric 
136906c3fb27SDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_deregister_jitdylib(char * ArgData,size_t ArgSize)137081ad6265SDimitry Andric __orc_rt_macho_deregister_jitdylib(char *ArgData, size_t ArgSize) {
137181ad6265SDimitry Andric   return WrapperFunction<SPSError(SPSExecutorAddr)>::handle(
137204eeddc0SDimitry Andric              ArgData, ArgSize,
137381ad6265SDimitry Andric              [](ExecutorAddr HeaderAddr) {
137481ad6265SDimitry Andric                return MachOPlatformRuntimeState::get().deregisterJITDylib(
137581ad6265SDimitry Andric                    HeaderAddr.toPtr<void *>());
137681ad6265SDimitry Andric              })
137781ad6265SDimitry Andric       .release();
137881ad6265SDimitry Andric }
137981ad6265SDimitry Andric 
138006c3fb27SDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_register_object_platform_sections(char * ArgData,size_t ArgSize)138181ad6265SDimitry Andric __orc_rt_macho_register_object_platform_sections(char *ArgData,
138281ad6265SDimitry Andric                                                  size_t ArgSize) {
138381ad6265SDimitry Andric   return WrapperFunction<SPSError(SPSExecutorAddr,
1384bdd1243dSDimitry Andric                                   SPSOptional<SPSUnwindSectionInfo>,
138581ad6265SDimitry Andric                                   SPSMachOObjectPlatformSectionsMap)>::
138681ad6265SDimitry Andric       handle(ArgData, ArgSize,
1387bdd1243dSDimitry Andric              [](ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> USI,
1388bdd1243dSDimitry Andric                 std::vector<std::pair<std::string_view, ExecutorAddrRange>>
1389bdd1243dSDimitry Andric                     &Secs) {
1390349cc55cSDimitry Andric                return MachOPlatformRuntimeState::get()
1391bdd1243dSDimitry Andric                    .registerObjectPlatformSections(HeaderAddr, std::move(USI),
1392bdd1243dSDimitry Andric                                                    std::move(Secs));
139381ad6265SDimitry Andric              })
139481ad6265SDimitry Andric           .release();
139581ad6265SDimitry Andric }
139681ad6265SDimitry Andric 
139706c3fb27SDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_register_object_symbol_table(char * ArgData,size_t ArgSize)13985f757f3fSDimitry Andric __orc_rt_macho_register_object_symbol_table(char *ArgData, size_t ArgSize) {
13995f757f3fSDimitry Andric   using SymtabContainer = std::vector<
14005f757f3fSDimitry Andric       std::tuple<ExecutorAddr, ExecutorAddr,
14015f757f3fSDimitry Andric                  MachOPlatformRuntimeState::MachOExecutorSymbolFlags>>;
14025f757f3fSDimitry Andric   return WrapperFunction<SPSError(
14035f757f3fSDimitry Andric       SPSExecutorAddr, SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
14045f757f3fSDimitry Andric                                             SPSMachOExecutorSymbolFlags>>)>::
14055f757f3fSDimitry Andric       handle(ArgData, ArgSize,
14065f757f3fSDimitry Andric              [](ExecutorAddr HeaderAddr, SymtabContainer &Symbols) {
14075f757f3fSDimitry Andric                return MachOPlatformRuntimeState::get()
14085f757f3fSDimitry Andric                    .registerObjectSymbolTable(HeaderAddr, Symbols);
14095f757f3fSDimitry Andric              })
14105f757f3fSDimitry Andric           .release();
14115f757f3fSDimitry Andric }
14125f757f3fSDimitry Andric 
14135f757f3fSDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_deregister_object_symbol_table(char * ArgData,size_t ArgSize)14145f757f3fSDimitry Andric __orc_rt_macho_deregister_object_symbol_table(char *ArgData, size_t ArgSize) {
14155f757f3fSDimitry Andric   using SymtabContainer = std::vector<
14165f757f3fSDimitry Andric       std::tuple<ExecutorAddr, ExecutorAddr,
14175f757f3fSDimitry Andric                  MachOPlatformRuntimeState::MachOExecutorSymbolFlags>>;
14185f757f3fSDimitry Andric   return WrapperFunction<SPSError(
14195f757f3fSDimitry Andric       SPSExecutorAddr, SPSSequence<SPSTuple<SPSExecutorAddr, SPSExecutorAddr,
14205f757f3fSDimitry Andric                                             SPSMachOExecutorSymbolFlags>>)>::
14215f757f3fSDimitry Andric       handle(ArgData, ArgSize,
14225f757f3fSDimitry Andric              [](ExecutorAddr HeaderAddr, SymtabContainer &Symbols) {
14235f757f3fSDimitry Andric                return MachOPlatformRuntimeState::get()
14245f757f3fSDimitry Andric                    .deregisterObjectSymbolTable(HeaderAddr, Symbols);
14255f757f3fSDimitry Andric              })
14265f757f3fSDimitry Andric           .release();
14275f757f3fSDimitry Andric }
14285f757f3fSDimitry Andric 
14295f757f3fSDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_deregister_object_platform_sections(char * ArgData,size_t ArgSize)143081ad6265SDimitry Andric __orc_rt_macho_deregister_object_platform_sections(char *ArgData,
143181ad6265SDimitry Andric                                                    size_t ArgSize) {
143281ad6265SDimitry Andric   return WrapperFunction<SPSError(SPSExecutorAddr,
1433bdd1243dSDimitry Andric                                   SPSOptional<SPSUnwindSectionInfo>,
143481ad6265SDimitry Andric                                   SPSMachOObjectPlatformSectionsMap)>::
143581ad6265SDimitry Andric       handle(ArgData, ArgSize,
1436bdd1243dSDimitry Andric              [](ExecutorAddr HeaderAddr, std::optional<UnwindSectionInfo> USI,
1437bdd1243dSDimitry Andric                 std::vector<std::pair<std::string_view, ExecutorAddrRange>>
1438bdd1243dSDimitry Andric                     &Secs) {
143981ad6265SDimitry Andric                return MachOPlatformRuntimeState::get()
1440bdd1243dSDimitry Andric                    .deregisterObjectPlatformSections(HeaderAddr, std::move(USI),
144181ad6265SDimitry Andric                                                      std::move(Secs));
1442fe6060f1SDimitry Andric              })
1443fe6060f1SDimitry Andric           .release();
1444fe6060f1SDimitry Andric }
1445fe6060f1SDimitry Andric 
144606c3fb27SDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_run_wrapper_function_calls(char * ArgData,size_t ArgSize)1447349cc55cSDimitry Andric __orc_rt_macho_run_wrapper_function_calls(char *ArgData, size_t ArgSize) {
1448349cc55cSDimitry Andric   return WrapperFunction<SPSError(SPSSequence<SPSWrapperFunctionCall>)>::handle(
1449349cc55cSDimitry Andric              ArgData, ArgSize, runWrapperFunctionCalls)
1450349cc55cSDimitry Andric       .release();
1451349cc55cSDimitry Andric }
1452349cc55cSDimitry Andric 
1453fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1454fe6060f1SDimitry Andric //                            TLV support
1455fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1456fe6060f1SDimitry Andric 
__orc_rt_macho_tlv_get_addr_impl(TLVDescriptor * D)1457fe6060f1SDimitry Andric ORC_RT_INTERFACE void *__orc_rt_macho_tlv_get_addr_impl(TLVDescriptor *D) {
1458fe6060f1SDimitry Andric   auto *TLVMgr = static_cast<MachOPlatformRuntimeTLVManager *>(
1459fe6060f1SDimitry Andric       pthread_getspecific(D->Key));
1460fe6060f1SDimitry Andric   if (!TLVMgr) {
1461fe6060f1SDimitry Andric     TLVMgr = new MachOPlatformRuntimeTLVManager();
1462fe6060f1SDimitry Andric     if (pthread_setspecific(D->Key, TLVMgr)) {
1463fe6060f1SDimitry Andric       __orc_rt_log_error("Call to pthread_setspecific failed");
1464fe6060f1SDimitry Andric       return nullptr;
1465fe6060f1SDimitry Andric     }
1466fe6060f1SDimitry Andric   }
1467fe6060f1SDimitry Andric 
1468fe6060f1SDimitry Andric   return TLVMgr->getInstance(
1469fe6060f1SDimitry Andric       reinterpret_cast<char *>(static_cast<uintptr_t>(D->DataAddress)));
1470fe6060f1SDimitry Andric }
1471fe6060f1SDimitry Andric 
147206c3fb27SDimitry Andric ORC_RT_INTERFACE orc_rt_CWrapperFunctionResult
__orc_rt_macho_create_pthread_key(char * ArgData,size_t ArgSize)1473fe6060f1SDimitry Andric __orc_rt_macho_create_pthread_key(char *ArgData, size_t ArgSize) {
1474fe6060f1SDimitry Andric   return WrapperFunction<SPSExpected<uint64_t>(void)>::handle(
1475fe6060f1SDimitry Andric              ArgData, ArgSize,
1476fe6060f1SDimitry Andric              []() -> Expected<uint64_t> {
1477fe6060f1SDimitry Andric                pthread_key_t Key;
1478fe6060f1SDimitry Andric                if (int Err = pthread_key_create(&Key, destroyMachOTLVMgr)) {
1479fe6060f1SDimitry Andric                  __orc_rt_log_error("Call to pthread_key_create failed");
1480fe6060f1SDimitry Andric                  return make_error<StringError>(strerror(Err));
1481fe6060f1SDimitry Andric                }
1482fe6060f1SDimitry Andric                return static_cast<uint64_t>(Key);
1483fe6060f1SDimitry Andric              })
1484fe6060f1SDimitry Andric       .release();
1485fe6060f1SDimitry Andric }
1486fe6060f1SDimitry Andric 
1487fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1488fe6060f1SDimitry Andric //                           cxa_atexit support
1489fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1490fe6060f1SDimitry Andric 
__orc_rt_macho_cxa_atexit(void (* func)(void *),void * arg,void * dso_handle)1491fe6060f1SDimitry Andric int __orc_rt_macho_cxa_atexit(void (*func)(void *), void *arg,
1492fe6060f1SDimitry Andric                               void *dso_handle) {
1493fe6060f1SDimitry Andric   return MachOPlatformRuntimeState::get().registerAtExit(func, arg, dso_handle);
1494fe6060f1SDimitry Andric }
1495fe6060f1SDimitry Andric 
__orc_rt_macho_cxa_finalize(void * dso_handle)1496fe6060f1SDimitry Andric void __orc_rt_macho_cxa_finalize(void *dso_handle) {
1497fe6060f1SDimitry Andric   MachOPlatformRuntimeState::get().runAtExits(dso_handle);
1498fe6060f1SDimitry Andric }
1499fe6060f1SDimitry Andric 
1500fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1501fe6060f1SDimitry Andric //                        JIT'd dlfcn alternatives.
1502fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1503fe6060f1SDimitry Andric 
__orc_rt_macho_jit_dlerror()1504fe6060f1SDimitry Andric const char *__orc_rt_macho_jit_dlerror() {
1505fe6060f1SDimitry Andric   return MachOPlatformRuntimeState::get().dlerror();
1506fe6060f1SDimitry Andric }
1507fe6060f1SDimitry Andric 
__orc_rt_macho_jit_dlopen(const char * path,int mode)1508fe6060f1SDimitry Andric void *__orc_rt_macho_jit_dlopen(const char *path, int mode) {
1509fe6060f1SDimitry Andric   return MachOPlatformRuntimeState::get().dlopen(path, mode);
1510fe6060f1SDimitry Andric }
1511fe6060f1SDimitry Andric 
__orc_rt_macho_jit_dlclose(void * dso_handle)1512fe6060f1SDimitry Andric int __orc_rt_macho_jit_dlclose(void *dso_handle) {
1513fe6060f1SDimitry Andric   return MachOPlatformRuntimeState::get().dlclose(dso_handle);
1514fe6060f1SDimitry Andric }
1515fe6060f1SDimitry Andric 
__orc_rt_macho_jit_dlsym(void * dso_handle,const char * symbol)1516fe6060f1SDimitry Andric void *__orc_rt_macho_jit_dlsym(void *dso_handle, const char *symbol) {
1517fe6060f1SDimitry Andric   return MachOPlatformRuntimeState::get().dlsym(dso_handle, symbol);
1518fe6060f1SDimitry Andric }
1519fe6060f1SDimitry Andric 
1520fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1521fe6060f1SDimitry Andric //                             MachO Run Program
1522fe6060f1SDimitry Andric //------------------------------------------------------------------------------
1523fe6060f1SDimitry Andric 
__orc_rt_macho_run_program(const char * JITDylibName,const char * EntrySymbolName,int argc,char * argv[])1524fe6060f1SDimitry Andric ORC_RT_INTERFACE int64_t __orc_rt_macho_run_program(const char *JITDylibName,
1525fe6060f1SDimitry Andric                                                     const char *EntrySymbolName,
1526fe6060f1SDimitry Andric                                                     int argc, char *argv[]) {
1527fe6060f1SDimitry Andric   using MainTy = int (*)(int, char *[]);
1528fe6060f1SDimitry Andric 
1529fe6060f1SDimitry Andric   void *H = __orc_rt_macho_jit_dlopen(JITDylibName,
1530fe6060f1SDimitry Andric                                       __orc_rt::macho::ORC_RT_RTLD_LAZY);
1531fe6060f1SDimitry Andric   if (!H) {
1532fe6060f1SDimitry Andric     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
1533fe6060f1SDimitry Andric     return -1;
1534fe6060f1SDimitry Andric   }
1535fe6060f1SDimitry Andric 
1536fe6060f1SDimitry Andric   auto *Main =
1537fe6060f1SDimitry Andric       reinterpret_cast<MainTy>(__orc_rt_macho_jit_dlsym(H, EntrySymbolName));
1538fe6060f1SDimitry Andric 
1539fe6060f1SDimitry Andric   if (!Main) {
1540fe6060f1SDimitry Andric     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
1541fe6060f1SDimitry Andric     return -1;
1542fe6060f1SDimitry Andric   }
1543fe6060f1SDimitry Andric 
1544fe6060f1SDimitry Andric   int Result = Main(argc, argv);
1545fe6060f1SDimitry Andric 
1546fe6060f1SDimitry Andric   if (__orc_rt_macho_jit_dlclose(H) == -1)
1547fe6060f1SDimitry Andric     __orc_rt_log_error(__orc_rt_macho_jit_dlerror());
1548fe6060f1SDimitry Andric 
1549fe6060f1SDimitry Andric   return Result;
1550fe6060f1SDimitry Andric }
1551