1 | //===- coff_platform.cpp --------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains code required to load the rest of the COFF runtime. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #define NOMINMAX |
14 | #include <windows.h> |
15 | |
16 | #include "coff_platform.h" |
17 | |
18 | #include "debug.h" |
19 | #include "error.h" |
20 | #include "jit_dispatch.h" |
21 | #include "wrapper_function_utils.h" |
22 | |
23 | #include <array> |
24 | #include <list> |
25 | #include <map> |
26 | #include <mutex> |
27 | #include <sstream> |
28 | #include <string_view> |
29 | #include <vector> |
30 | |
31 | #define DEBUG_TYPE "coff_platform" |
32 | |
33 | using namespace orc_rt; |
34 | |
35 | namespace orc_rt { |
36 | |
37 | using COFFJITDylibDepInfo = std::vector<ExecutorAddr>; |
38 | using COFFJITDylibDepInfoMap = |
39 | std::unordered_map<ExecutorAddr, COFFJITDylibDepInfo>; |
40 | |
41 | using SPSCOFFObjectSectionsMap = |
42 | SPSSequence<SPSTuple<SPSString, SPSExecutorAddrRange>>; |
43 | |
44 | using SPSCOFFJITDylibDepInfo = SPSSequence<SPSExecutorAddr>; |
45 | |
46 | using SPSCOFFJITDylibDepInfoMap = |
47 | SPSSequence<SPSTuple<SPSExecutorAddr, SPSCOFFJITDylibDepInfo>>; |
48 | |
49 | } // namespace orc_rt |
50 | |
51 | ORC_RT_JIT_DISPATCH_TAG(__orc_rt_coff_symbol_lookup_tag) |
52 | ORC_RT_JIT_DISPATCH_TAG(__orc_rt_coff_push_initializers_tag) |
53 | |
54 | namespace { |
55 | class COFFPlatformRuntimeState { |
56 | private: |
57 | // Ctor/dtor section. |
58 | // Manage lists of *tor functions sorted by the last character of subsection |
59 | // name. |
60 | struct XtorSection { |
61 | void Register(char SubsectionChar, span<void (*)(void)> Xtors) { |
62 | Subsections[SubsectionChar - 'A'].push_back(x: Xtors); |
63 | SubsectionsNew[SubsectionChar - 'A'].push_back(x: Xtors); |
64 | } |
65 | |
66 | void RegisterNoRun(char SubsectionChar, span<void (*)(void)> Xtors) { |
67 | Subsections[SubsectionChar - 'A'].push_back(x: Xtors); |
68 | } |
69 | |
70 | void Reset() { SubsectionsNew = Subsections; } |
71 | |
72 | void RunAllNewAndFlush(); |
73 | |
74 | private: |
75 | std::array<std::vector<span<void (*)(void)>>, 26> Subsections; |
76 | std::array<std::vector<span<void (*)(void)>>, 26> SubsectionsNew; |
77 | }; |
78 | |
79 | struct JITDylibState { |
80 | std::string Name; |
81 | void * = nullptr; |
82 | size_t LinkedAgainstRefCount = 0; |
83 | size_t DlRefCount = 0; |
84 | std::vector<JITDylibState *> Deps; |
85 | std::vector<void (*)(void)> AtExits; |
86 | XtorSection CInitSection; // XIA~XIZ |
87 | XtorSection CXXInitSection; // XCA~XCZ |
88 | XtorSection CPreTermSection; // XPA~XPZ |
89 | XtorSection CTermSection; // XTA~XTZ |
90 | |
91 | bool referenced() const { |
92 | return LinkedAgainstRefCount != 0 || DlRefCount != 0; |
93 | } |
94 | }; |
95 | |
96 | public: |
97 | static void initialize(); |
98 | static COFFPlatformRuntimeState &get(); |
99 | static bool isInitialized() { return CPS; } |
100 | static void destroy(); |
101 | |
102 | COFFPlatformRuntimeState() = default; |
103 | |
104 | // Delete copy and move constructors. |
105 | COFFPlatformRuntimeState(const COFFPlatformRuntimeState &) = delete; |
106 | COFFPlatformRuntimeState & |
107 | operator=(const COFFPlatformRuntimeState &) = delete; |
108 | COFFPlatformRuntimeState(COFFPlatformRuntimeState &&) = delete; |
109 | COFFPlatformRuntimeState &operator=(COFFPlatformRuntimeState &&) = delete; |
110 | |
111 | const char *dlerror(); |
112 | void *dlopen(std::string_view Name, int Mode); |
113 | int dlclose(void *); |
114 | void *dlsym(void *, std::string_view Symbol); |
115 | |
116 | Error registerJITDylib(std::string Name, void *); |
117 | Error deregisterJITDylib(void *); |
118 | |
119 | Error registerAtExit(ExecutorAddr , void (*AtExit)(void)); |
120 | |
121 | Error registerObjectSections( |
122 | ExecutorAddr , |
123 | std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs, |
124 | bool RunInitializers); |
125 | Error deregisterObjectSections( |
126 | ExecutorAddr , |
127 | std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs); |
128 | |
129 | void *findJITDylibBaseByPC(uint64_t PC); |
130 | |
131 | private: |
132 | Error registerBlockRange(ExecutorAddr , ExecutorAddrRange Range); |
133 | Error deregisterBlockRange(ExecutorAddr , ExecutorAddrRange Range); |
134 | |
135 | Error registerSEHFrames(ExecutorAddr , |
136 | ExecutorAddrRange SEHFrameRange); |
137 | Error deregisterSEHFrames(ExecutorAddr , |
138 | ExecutorAddrRange SEHFrameRange); |
139 | |
140 | Expected<void *> dlopenImpl(std::string_view Path, int Mode); |
141 | Error dlopenFull(JITDylibState &JDS); |
142 | Error dlopenInitialize(JITDylibState &JDS, COFFJITDylibDepInfoMap &DepInfo); |
143 | |
144 | Error dlcloseImpl(void *DSOHandle); |
145 | Error dlcloseDeinitialize(JITDylibState &JDS); |
146 | |
147 | JITDylibState *getJITDylibStateByHeader(void *DSOHandle); |
148 | JITDylibState *getJITDylibStateByName(std::string_view Path); |
149 | Expected<ExecutorAddr> lookupSymbolInJITDylib(void *DSOHandle, |
150 | std::string_view Symbol); |
151 | |
152 | static COFFPlatformRuntimeState *CPS; |
153 | |
154 | std::recursive_mutex JDStatesMutex; |
155 | std::map<void *, JITDylibState> JDStates; |
156 | struct BlockRange { |
157 | void *; |
158 | size_t Size; |
159 | }; |
160 | std::map<void *, BlockRange> BlockRanges; |
161 | std::unordered_map<std::string_view, void *> ; |
162 | std::string DLFcnError; |
163 | }; |
164 | |
165 | } // namespace |
166 | |
167 | COFFPlatformRuntimeState *COFFPlatformRuntimeState::CPS = nullptr; |
168 | |
169 | COFFPlatformRuntimeState::JITDylibState * |
170 | COFFPlatformRuntimeState::(void *) { |
171 | auto I = JDStates.find(x: Header); |
172 | if (I == JDStates.end()) |
173 | return nullptr; |
174 | return &I->second; |
175 | } |
176 | |
177 | COFFPlatformRuntimeState::JITDylibState * |
178 | COFFPlatformRuntimeState::getJITDylibStateByName(std::string_view Name) { |
179 | // FIXME: Avoid creating string copy here. |
180 | auto I = JDNameToHeader.find(x: std::string(Name.data(), Name.size())); |
181 | if (I == JDNameToHeader.end()) |
182 | return nullptr; |
183 | void *H = I->second; |
184 | auto J = JDStates.find(x: H); |
185 | assert(J != JDStates.end() && |
186 | "JITDylib has name map entry but no header map entry" ); |
187 | return &J->second; |
188 | } |
189 | |
190 | Error COFFPlatformRuntimeState::registerJITDylib(std::string Name, |
191 | void *) { |
192 | ORC_RT_DEBUG({ |
193 | printdbg("Registering JITDylib %s: Header = %p\n" , Name.c_str(), Header); |
194 | }); |
195 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
196 | if (JDStates.count(x: Header)) { |
197 | std::ostringstream ErrStream; |
198 | ErrStream << "Duplicate JITDylib registration for header " << Header |
199 | << " (name = " << Name << ")" ; |
200 | return make_error<StringError>(Args: ErrStream.str()); |
201 | } |
202 | if (JDNameToHeader.count(x: Name)) { |
203 | std::ostringstream ErrStream; |
204 | ErrStream << "Duplicate JITDylib registration for header " << Header |
205 | << " (header = " << Header << ")" ; |
206 | return make_error<StringError>(Args: ErrStream.str()); |
207 | } |
208 | |
209 | auto &JDS = JDStates[Header]; |
210 | JDS.Name = std::move(t&: Name); |
211 | JDS.Header = Header; |
212 | JDNameToHeader[JDS.Name] = Header; |
213 | return Error::success(); |
214 | } |
215 | |
216 | Error COFFPlatformRuntimeState::deregisterJITDylib(void *) { |
217 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
218 | auto I = JDStates.find(x: Header); |
219 | if (I == JDStates.end()) { |
220 | std::ostringstream ErrStream; |
221 | ErrStream << "Attempted to deregister unrecognized header " << Header; |
222 | return make_error<StringError>(Args: ErrStream.str()); |
223 | } |
224 | |
225 | // Remove std::string construction once we can use C++20. |
226 | auto J = JDNameToHeader.find( |
227 | x: std::string(I->second.Name.data(), I->second.Name.size())); |
228 | assert(J != JDNameToHeader.end() && |
229 | "Missing JDNameToHeader entry for JITDylib" ); |
230 | |
231 | ORC_RT_DEBUG({ |
232 | printdbg("Deregistering JITDylib %s: Header = %p\n" , I->second.Name.c_str(), |
233 | Header); |
234 | }); |
235 | |
236 | JDNameToHeader.erase(position: J); |
237 | JDStates.erase(position: I); |
238 | return Error::success(); |
239 | } |
240 | |
241 | void COFFPlatformRuntimeState::XtorSection::RunAllNewAndFlush() { |
242 | for (auto &Subsection : SubsectionsNew) { |
243 | for (auto &XtorGroup : Subsection) |
244 | for (auto &Xtor : XtorGroup) |
245 | if (Xtor) |
246 | Xtor(); |
247 | Subsection.clear(); |
248 | } |
249 | } |
250 | |
251 | const char *COFFPlatformRuntimeState::dlerror() { return DLFcnError.c_str(); } |
252 | |
253 | void *COFFPlatformRuntimeState::dlopen(std::string_view Path, int Mode) { |
254 | ORC_RT_DEBUG({ |
255 | std::string S(Path.data(), Path.size()); |
256 | printdbg("COFFPlatform::dlopen(\"%s\")\n" , S.c_str()); |
257 | }); |
258 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
259 | if (auto H = dlopenImpl(Path, Mode)) |
260 | return *H; |
261 | else { |
262 | // FIXME: Make dlerror thread safe. |
263 | DLFcnError = toString(Err: H.takeError()); |
264 | return nullptr; |
265 | } |
266 | } |
267 | |
268 | int COFFPlatformRuntimeState::dlclose(void *DSOHandle) { |
269 | ORC_RT_DEBUG({ |
270 | auto *JDS = getJITDylibStateByHeader(DSOHandle); |
271 | std::string DylibName; |
272 | if (JDS) { |
273 | std::string S; |
274 | printdbg("COFFPlatform::dlclose(%p) (%s)\n" , DSOHandle, S.c_str()); |
275 | } else |
276 | printdbg("COFFPlatform::dlclose(%p) (%s)\n" , DSOHandle, "invalid handle" ); |
277 | }); |
278 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
279 | if (auto Err = dlcloseImpl(DSOHandle)) { |
280 | // FIXME: Make dlerror thread safe. |
281 | DLFcnError = toString(Err: std::move(t&: Err)); |
282 | return -1; |
283 | } |
284 | return 0; |
285 | } |
286 | |
287 | void *COFFPlatformRuntimeState::dlsym(void *, std::string_view Symbol) { |
288 | auto Addr = lookupSymbolInJITDylib(DSOHandle: Header, Symbol); |
289 | if (!Addr) { |
290 | return 0; |
291 | } |
292 | |
293 | return Addr->toPtr<void *>(); |
294 | } |
295 | |
296 | Expected<void *> COFFPlatformRuntimeState::dlopenImpl(std::string_view Path, |
297 | int Mode) { |
298 | // Try to find JITDylib state by name. |
299 | auto *JDS = getJITDylibStateByName(Name: Path); |
300 | |
301 | if (!JDS) |
302 | return make_error<StringError>(Args: "No registered JTIDylib for path " + |
303 | std::string(Path.data(), Path.size())); |
304 | |
305 | if (auto Err = dlopenFull(JDS&: *JDS)) |
306 | return std::move(t&: Err); |
307 | |
308 | // Bump the ref-count on this dylib. |
309 | ++JDS->DlRefCount; |
310 | |
311 | // Return the header address. |
312 | return JDS->Header; |
313 | } |
314 | |
315 | Error COFFPlatformRuntimeState::dlopenFull(JITDylibState &JDS) { |
316 | // Call back to the JIT to push the initializers. |
317 | Expected<COFFJITDylibDepInfoMap> DepInfoMap((COFFJITDylibDepInfoMap())); |
318 | if (auto Err = WrapperFunction<SPSExpected<SPSCOFFJITDylibDepInfoMap>( |
319 | SPSExecutorAddr)>:: |
320 | call(Dispatch: JITDispatch(&__orc_rt_coff_push_initializers_tag), Result&: DepInfoMap, |
321 | Args: ExecutorAddr::fromPtr(Ptr: JDS.Header))) |
322 | return Err; |
323 | if (!DepInfoMap) |
324 | return DepInfoMap.takeError(); |
325 | |
326 | if (auto Err = dlopenInitialize(JDS, DepInfo&: *DepInfoMap)) |
327 | return Err; |
328 | |
329 | if (!DepInfoMap->empty()) { |
330 | ORC_RT_DEBUG({ |
331 | printdbg("Unrecognized dep-info key headers in dlopen of %s\n" , |
332 | JDS.Name.c_str()); |
333 | }); |
334 | std::ostringstream ErrStream; |
335 | ErrStream << "Encountered unrecognized dep-info key headers " |
336 | "while processing dlopen of " |
337 | << JDS.Name; |
338 | return make_error<StringError>(Args: ErrStream.str()); |
339 | } |
340 | |
341 | return Error::success(); |
342 | } |
343 | |
344 | Error COFFPlatformRuntimeState::dlopenInitialize( |
345 | JITDylibState &JDS, COFFJITDylibDepInfoMap &DepInfo) { |
346 | ORC_RT_DEBUG({ |
347 | printdbg("COFFPlatformRuntimeState::dlopenInitialize(\"%s\")\n" , |
348 | JDS.Name.c_str()); |
349 | }); |
350 | |
351 | // Skip visited dependency. |
352 | auto I = DepInfo.find(x: ExecutorAddr::fromPtr(Ptr: JDS.Header)); |
353 | if (I == DepInfo.end()) |
354 | return Error::success(); |
355 | |
356 | auto DI = std::move(t&: I->second); |
357 | DepInfo.erase(position: I); |
358 | |
359 | // Run initializers of dependencies in proper order by depth-first traversal |
360 | // of dependency graph. |
361 | std::vector<JITDylibState *> OldDeps; |
362 | std::swap(x&: JDS.Deps, y&: OldDeps); |
363 | JDS.Deps.reserve(n: DI.size()); |
364 | for (auto : DI) { |
365 | auto *DepJDS = getJITDylibStateByHeader(Header: DepHeaderAddr.toPtr<void *>()); |
366 | if (!DepJDS) { |
367 | std::ostringstream ErrStream; |
368 | ErrStream << "Encountered unrecognized dep header " |
369 | << DepHeaderAddr.toPtr<void *>() << " while initializing " |
370 | << JDS.Name; |
371 | return make_error<StringError>(Args: ErrStream.str()); |
372 | } |
373 | ++DepJDS->LinkedAgainstRefCount; |
374 | if (auto Err = dlopenInitialize(JDS&: *DepJDS, DepInfo)) |
375 | return Err; |
376 | } |
377 | |
378 | // Run static initializers. |
379 | JDS.CInitSection.RunAllNewAndFlush(); |
380 | JDS.CXXInitSection.RunAllNewAndFlush(); |
381 | |
382 | // Decrement old deps. |
383 | for (auto *DepJDS : OldDeps) { |
384 | --DepJDS->LinkedAgainstRefCount; |
385 | if (!DepJDS->referenced()) |
386 | if (auto Err = dlcloseDeinitialize(JDS&: *DepJDS)) |
387 | return Err; |
388 | } |
389 | |
390 | return Error::success(); |
391 | } |
392 | |
393 | Error COFFPlatformRuntimeState::dlcloseImpl(void *DSOHandle) { |
394 | // Try to find JITDylib state by header. |
395 | auto *JDS = getJITDylibStateByHeader(Header: DSOHandle); |
396 | |
397 | if (!JDS) { |
398 | std::ostringstream ErrStream; |
399 | ErrStream << "No registered JITDylib for " << DSOHandle; |
400 | return make_error<StringError>(Args: ErrStream.str()); |
401 | } |
402 | |
403 | // Bump the ref-count. |
404 | --JDS->DlRefCount; |
405 | |
406 | if (!JDS->referenced()) |
407 | return dlcloseDeinitialize(JDS&: *JDS); |
408 | |
409 | return Error::success(); |
410 | } |
411 | |
412 | Error COFFPlatformRuntimeState::dlcloseDeinitialize(JITDylibState &JDS) { |
413 | ORC_RT_DEBUG({ |
414 | printdbg("COFFPlatformRuntimeState::dlcloseDeinitialize(\"%s\")\n" , |
415 | JDS.Name.c_str()); |
416 | }); |
417 | |
418 | // Run atexits |
419 | for (auto AtExit : JDS.AtExits) |
420 | AtExit(); |
421 | JDS.AtExits.clear(); |
422 | |
423 | // Run static terminators. |
424 | JDS.CPreTermSection.RunAllNewAndFlush(); |
425 | JDS.CTermSection.RunAllNewAndFlush(); |
426 | |
427 | // Queue all xtors as new again. |
428 | JDS.CInitSection.Reset(); |
429 | JDS.CXXInitSection.Reset(); |
430 | JDS.CPreTermSection.Reset(); |
431 | JDS.CTermSection.Reset(); |
432 | |
433 | // Deinitialize any dependencies. |
434 | for (auto *DepJDS : JDS.Deps) { |
435 | --DepJDS->LinkedAgainstRefCount; |
436 | if (!DepJDS->referenced()) |
437 | if (auto Err = dlcloseDeinitialize(JDS&: *DepJDS)) |
438 | return Err; |
439 | } |
440 | |
441 | return Error::success(); |
442 | } |
443 | |
444 | Expected<ExecutorAddr> |
445 | COFFPlatformRuntimeState::lookupSymbolInJITDylib(void *, |
446 | std::string_view Sym) { |
447 | Expected<ExecutorAddr> Result((ExecutorAddr())); |
448 | if (auto Err = WrapperFunction<SPSExpected<SPSExecutorAddr>( |
449 | SPSExecutorAddr, |
450 | SPSString)>::call(Dispatch: JITDispatch(&__orc_rt_coff_symbol_lookup_tag), |
451 | Result, Args: ExecutorAddr::fromPtr(Ptr: header), Args: Sym)) |
452 | return std::move(t&: Err); |
453 | return Result; |
454 | } |
455 | |
456 | Error COFFPlatformRuntimeState::registerObjectSections( |
457 | ExecutorAddr , |
458 | std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs, |
459 | bool RunInitializers) { |
460 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
461 | auto I = JDStates.find(x: HeaderAddr.toPtr<void *>()); |
462 | if (I == JDStates.end()) { |
463 | std::ostringstream ErrStream; |
464 | ErrStream << "Unrecognized header " << HeaderAddr.getValue(); |
465 | return make_error<StringError>(Args: ErrStream.str()); |
466 | } |
467 | auto &JDState = I->second; |
468 | for (auto &KV : Secs) { |
469 | if (auto Err = registerBlockRange(HeaderAddr, Range: KV.second)) |
470 | return Err; |
471 | if (KV.first.empty()) |
472 | continue; |
473 | char LastChar = KV.first.data()[KV.first.size() - 1]; |
474 | if (KV.first == ".pdata" ) { |
475 | if (auto Err = registerSEHFrames(HeaderAddr, SEHFrameRange: KV.second)) |
476 | return Err; |
477 | } else if (KV.first >= ".CRT$XIA" && KV.first <= ".CRT$XIZ" ) { |
478 | if (RunInitializers) |
479 | JDState.CInitSection.Register(SubsectionChar: LastChar, |
480 | Xtors: KV.second.toSpan<void (*)(void)>()); |
481 | else |
482 | JDState.CInitSection.RegisterNoRun(SubsectionChar: LastChar, |
483 | Xtors: KV.second.toSpan<void (*)(void)>()); |
484 | } else if (KV.first >= ".CRT$XCA" && KV.first <= ".CRT$XCZ" ) { |
485 | if (RunInitializers) |
486 | JDState.CXXInitSection.Register(SubsectionChar: LastChar, |
487 | Xtors: KV.second.toSpan<void (*)(void)>()); |
488 | else |
489 | JDState.CXXInitSection.RegisterNoRun( |
490 | SubsectionChar: LastChar, Xtors: KV.second.toSpan<void (*)(void)>()); |
491 | } else if (KV.first >= ".CRT$XPA" && KV.first <= ".CRT$XPZ" ) |
492 | JDState.CPreTermSection.Register(SubsectionChar: LastChar, |
493 | Xtors: KV.second.toSpan<void (*)(void)>()); |
494 | else if (KV.first >= ".CRT$XTA" && KV.first <= ".CRT$XTZ" ) |
495 | JDState.CTermSection.Register(SubsectionChar: LastChar, |
496 | Xtors: KV.second.toSpan<void (*)(void)>()); |
497 | } |
498 | return Error::success(); |
499 | } |
500 | |
501 | Error COFFPlatformRuntimeState::deregisterObjectSections( |
502 | ExecutorAddr , |
503 | std::vector<std::pair<std::string_view, ExecutorAddrRange>> Secs) { |
504 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
505 | auto I = JDStates.find(x: HeaderAddr.toPtr<void *>()); |
506 | if (I == JDStates.end()) { |
507 | std::ostringstream ErrStream; |
508 | ErrStream << "Attempted to deregister unrecognized header " |
509 | << HeaderAddr.getValue(); |
510 | return make_error<StringError>(Args: ErrStream.str()); |
511 | } |
512 | for (auto &KV : Secs) { |
513 | if (auto Err = deregisterBlockRange(HeaderAddr, Range: KV.second)) |
514 | return Err; |
515 | if (KV.first == ".pdata" ) |
516 | if (auto Err = deregisterSEHFrames(HeaderAddr, SEHFrameRange: KV.second)) |
517 | return Err; |
518 | } |
519 | return Error::success(); |
520 | } |
521 | |
522 | Error COFFPlatformRuntimeState::registerSEHFrames( |
523 | ExecutorAddr , ExecutorAddrRange SEHFrameRange) { |
524 | int N = (SEHFrameRange.End.getValue() - SEHFrameRange.Start.getValue()) / |
525 | sizeof(RUNTIME_FUNCTION); |
526 | auto Func = SEHFrameRange.Start.toPtr<PRUNTIME_FUNCTION>(); |
527 | if (!RtlAddFunctionTable(Func, N, |
528 | static_cast<DWORD64>(HeaderAddr.getValue()))) |
529 | return make_error<StringError>(Args: "Failed to register SEH frames" ); |
530 | return Error::success(); |
531 | } |
532 | |
533 | Error COFFPlatformRuntimeState::deregisterSEHFrames( |
534 | ExecutorAddr , ExecutorAddrRange SEHFrameRange) { |
535 | if (!RtlDeleteFunctionTable(SEHFrameRange.Start.toPtr<PRUNTIME_FUNCTION>())) |
536 | return make_error<StringError>(Args: "Failed to deregister SEH frames" ); |
537 | return Error::success(); |
538 | } |
539 | |
540 | Error COFFPlatformRuntimeState::registerBlockRange(ExecutorAddr , |
541 | ExecutorAddrRange Range) { |
542 | assert(!BlockRanges.count(Range.Start.toPtr<void *>()) && |
543 | "Block range address already registered" ); |
544 | BlockRange B = {.Header: HeaderAddr.toPtr<void *>(), .Size: Range.size()}; |
545 | BlockRanges.emplace(args: Range.Start.toPtr<void *>(), args&: B); |
546 | return Error::success(); |
547 | } |
548 | |
549 | Error COFFPlatformRuntimeState::deregisterBlockRange(ExecutorAddr , |
550 | ExecutorAddrRange Range) { |
551 | assert(BlockRanges.count(Range.Start.toPtr<void *>()) && |
552 | "Block range address not registered" ); |
553 | BlockRanges.erase(x: Range.Start.toPtr<void *>()); |
554 | return Error::success(); |
555 | } |
556 | |
557 | Error COFFPlatformRuntimeState::registerAtExit(ExecutorAddr , |
558 | void (*AtExit)(void)) { |
559 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
560 | auto I = JDStates.find(x: HeaderAddr.toPtr<void *>()); |
561 | if (I == JDStates.end()) { |
562 | std::ostringstream ErrStream; |
563 | ErrStream << "Unrecognized header " << HeaderAddr.getValue(); |
564 | return make_error<StringError>(Args: ErrStream.str()); |
565 | } |
566 | I->second.AtExits.push_back(x: AtExit); |
567 | return Error::success(); |
568 | } |
569 | |
570 | void COFFPlatformRuntimeState::initialize() { |
571 | assert(!CPS && "COFFPlatformRuntimeState should be null" ); |
572 | CPS = new COFFPlatformRuntimeState(); |
573 | } |
574 | |
575 | COFFPlatformRuntimeState &COFFPlatformRuntimeState::get() { |
576 | assert(CPS && "COFFPlatformRuntimeState not initialized" ); |
577 | return *CPS; |
578 | } |
579 | |
580 | void COFFPlatformRuntimeState::destroy() { |
581 | assert(CPS && "COFFPlatformRuntimeState not initialized" ); |
582 | delete CPS; |
583 | } |
584 | |
585 | void *COFFPlatformRuntimeState::findJITDylibBaseByPC(uint64_t PC) { |
586 | std::lock_guard<std::recursive_mutex> Lock(JDStatesMutex); |
587 | auto It = BlockRanges.upper_bound(x: reinterpret_cast<void *>(PC)); |
588 | if (It == BlockRanges.begin()) |
589 | return nullptr; |
590 | --It; |
591 | auto &Range = It->second; |
592 | if (PC >= reinterpret_cast<uint64_t>(It->first) + Range.Size) |
593 | return nullptr; |
594 | return Range.Header; |
595 | } |
596 | |
597 | ORC_RT_INTERFACE orc_rt_WrapperFunctionResult |
598 | __orc_rt_coff_platform_bootstrap(char *ArgData, size_t ArgSize) { |
599 | COFFPlatformRuntimeState::initialize(); |
600 | return WrapperFunctionResult().release(); |
601 | } |
602 | |
603 | ORC_RT_INTERFACE orc_rt_WrapperFunctionResult |
604 | __orc_rt_coff_platform_shutdown(char *ArgData, size_t ArgSize) { |
605 | COFFPlatformRuntimeState::destroy(); |
606 | return WrapperFunctionResult().release(); |
607 | } |
608 | |
609 | ORC_RT_INTERFACE orc_rt_WrapperFunctionResult |
610 | __orc_rt_coff_register_jitdylib(char *ArgData, size_t ArgSize) { |
611 | return WrapperFunction<SPSError(SPSString, SPSExecutorAddr)>::handle( |
612 | ArgData, ArgSize, |
613 | Handler: [](std::string &Name, ExecutorAddr ) { |
614 | return COFFPlatformRuntimeState::get().registerJITDylib( |
615 | Name: std::move(t&: Name), Header: HeaderAddr.toPtr<void *>()); |
616 | }) |
617 | .release(); |
618 | } |
619 | |
620 | ORC_RT_INTERFACE orc_rt_WrapperFunctionResult |
621 | __orc_rt_coff_deregister_jitdylib(char *ArgData, size_t ArgSize) { |
622 | return WrapperFunction<SPSError(SPSExecutorAddr)>::handle( |
623 | ArgData, ArgSize, |
624 | Handler: [](ExecutorAddr ) { |
625 | return COFFPlatformRuntimeState::get().deregisterJITDylib( |
626 | Header: HeaderAddr.toPtr<void *>()); |
627 | }) |
628 | .release(); |
629 | } |
630 | |
631 | ORC_RT_INTERFACE orc_rt_WrapperFunctionResult |
632 | __orc_rt_coff_register_object_sections(char *ArgData, size_t ArgSize) { |
633 | return WrapperFunction<SPSError(SPSExecutorAddr, SPSCOFFObjectSectionsMap, |
634 | bool)>:: |
635 | handle(ArgData, ArgSize, |
636 | Handler: [](ExecutorAddr , |
637 | std::vector<std::pair<std::string_view, ExecutorAddrRange>> |
638 | &Secs, |
639 | bool RunInitializers) { |
640 | return COFFPlatformRuntimeState::get().registerObjectSections( |
641 | HeaderAddr, Secs: std::move(t&: Secs), RunInitializers); |
642 | }) |
643 | .release(); |
644 | } |
645 | |
646 | ORC_RT_INTERFACE orc_rt_WrapperFunctionResult |
647 | __orc_rt_coff_deregister_object_sections(char *ArgData, size_t ArgSize) { |
648 | return WrapperFunction<SPSError(SPSExecutorAddr, SPSCOFFObjectSectionsMap)>:: |
649 | handle(ArgData, ArgSize, |
650 | Handler: [](ExecutorAddr , |
651 | std::vector<std::pair<std::string_view, ExecutorAddrRange>> |
652 | &Secs) { |
653 | return COFFPlatformRuntimeState::get().deregisterObjectSections( |
654 | HeaderAddr, Secs: std::move(t&: Secs)); |
655 | }) |
656 | .release(); |
657 | } |
658 | //------------------------------------------------------------------------------ |
659 | // JIT'd dlfcn alternatives. |
660 | //------------------------------------------------------------------------------ |
661 | |
662 | const char *__orc_rt_coff_jit_dlerror() { |
663 | return COFFPlatformRuntimeState::get().dlerror(); |
664 | } |
665 | |
666 | void *__orc_rt_coff_jit_dlopen(const char *path, int mode) { |
667 | return COFFPlatformRuntimeState::get().dlopen(Path: path, Mode: mode); |
668 | } |
669 | |
670 | int __orc_rt_coff_jit_dlclose(void *) { |
671 | return COFFPlatformRuntimeState::get().dlclose(DSOHandle: header); |
672 | } |
673 | |
674 | void *__orc_rt_coff_jit_dlsym(void *, const char *symbol) { |
675 | return COFFPlatformRuntimeState::get().dlsym(Header: header, Symbol: symbol); |
676 | } |
677 | |
678 | //------------------------------------------------------------------------------ |
679 | // COFF SEH exception support |
680 | //------------------------------------------------------------------------------ |
681 | |
682 | struct ThrowInfo { |
683 | uint32_t attributes; |
684 | void *data; |
685 | }; |
686 | |
687 | ORC_RT_INTERFACE void __stdcall __orc_rt_coff_cxx_throw_exception( |
688 | void *pExceptionObject, ThrowInfo *pThrowInfo) { |
689 | #ifdef __clang__ |
690 | #pragma clang diagnostic push |
691 | #pragma clang diagnostic ignored "-Wmultichar" |
692 | #endif |
693 | constexpr uint32_t EH_EXCEPTION_NUMBER = 'msc' | 0xE0000000; |
694 | #ifdef __clang__ |
695 | #pragma clang diagnostic pop |
696 | #endif |
697 | constexpr uint32_t EH_MAGIC_NUMBER1 = 0x19930520; |
698 | auto BaseAddr = COFFPlatformRuntimeState::get().findJITDylibBaseByPC( |
699 | PC: reinterpret_cast<uint64_t>(pThrowInfo)); |
700 | if (!BaseAddr) { |
701 | // This is not from JIT'd region. |
702 | // FIXME: Use the default implementation like below when alias api is |
703 | // capable. _CxxThrowException(pExceptionObject, pThrowInfo); |
704 | fprintf(stderr, format: "Throwing exception from compiled callback into JIT'd " |
705 | "exception handler not supported yet.\n" ); |
706 | abort(); |
707 | return; |
708 | } |
709 | const ULONG_PTR parameters[] = { |
710 | EH_MAGIC_NUMBER1, |
711 | reinterpret_cast<ULONG_PTR>(pExceptionObject), |
712 | reinterpret_cast<ULONG_PTR>(pThrowInfo), |
713 | reinterpret_cast<ULONG_PTR>(BaseAddr), |
714 | }; |
715 | RaiseException(EH_EXCEPTION_NUMBER, EXCEPTION_NONCONTINUABLE, |
716 | _countof(parameters), parameters); |
717 | } |
718 | |
719 | //------------------------------------------------------------------------------ |
720 | // COFF atexits |
721 | //------------------------------------------------------------------------------ |
722 | |
723 | typedef int (*OnExitFunction)(void); |
724 | typedef void (*AtExitFunction)(void); |
725 | |
726 | ORC_RT_INTERFACE OnExitFunction __orc_rt_coff_onexit(void *, |
727 | OnExitFunction Func) { |
728 | if (auto Err = COFFPlatformRuntimeState::get().registerAtExit( |
729 | HeaderAddr: ExecutorAddr::fromPtr(Ptr: Header), AtExit: (void (*)(void))Func)) { |
730 | consumeError(Err: std::move(t&: Err)); |
731 | return nullptr; |
732 | } |
733 | return Func; |
734 | } |
735 | |
736 | ORC_RT_INTERFACE int __orc_rt_coff_atexit(void *, AtExitFunction Func) { |
737 | if (auto Err = COFFPlatformRuntimeState::get().registerAtExit( |
738 | HeaderAddr: ExecutorAddr::fromPtr(Ptr: Header), AtExit: (void (*)(void))Func)) { |
739 | consumeError(Err: std::move(t&: Err)); |
740 | return -1; |
741 | } |
742 | return 0; |
743 | } |
744 | |
745 | //------------------------------------------------------------------------------ |
746 | // COFF Run Program |
747 | //------------------------------------------------------------------------------ |
748 | |
749 | ORC_RT_INTERFACE int64_t __orc_rt_coff_run_program(const char *JITDylibName, |
750 | const char *EntrySymbolName, |
751 | int argc, char *argv[]) { |
752 | using MainTy = int (*)(int, char *[]); |
753 | |
754 | void *H = |
755 | __orc_rt_coff_jit_dlopen(path: JITDylibName, mode: orc_rt::coff::ORC_RT_RTLD_LAZY); |
756 | if (!H) { |
757 | __orc_rt_log_error(ErrMsg: __orc_rt_coff_jit_dlerror()); |
758 | return -1; |
759 | } |
760 | |
761 | auto *Main = |
762 | reinterpret_cast<MainTy>(__orc_rt_coff_jit_dlsym(header: H, symbol: EntrySymbolName)); |
763 | |
764 | if (!Main) { |
765 | __orc_rt_log_error(ErrMsg: __orc_rt_coff_jit_dlerror()); |
766 | return -1; |
767 | } |
768 | |
769 | int Result = Main(argc, argv); |
770 | |
771 | if (__orc_rt_coff_jit_dlclose(header: H) == -1) |
772 | __orc_rt_log_error(ErrMsg: __orc_rt_coff_jit_dlerror()); |
773 | |
774 | return Result; |
775 | } |
776 | |