diff options
author | Mike Pall <mike> | 2021-03-23 00:22:34 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2021-03-23 00:22:34 +0100 |
commit | e131936133c58de4426c595db2341caf5a1665b5 (patch) | |
tree | e8659c1bbc626acde7bbcb998eac5ad93349d113 | |
parent | ce9faf2e0d627aa043b84f290aebc4ef87c5a3b4 (diff) | |
download | luajit-e131936133c58de4426c595db2341caf5a1665b5.tar.gz luajit-e131936133c58de4426c595db2341caf5a1665b5.tar.bz2 luajit-e131936133c58de4426c595db2341caf5a1665b5.zip |
Cleanup and enable external unwinding for more platforms.
-rw-r--r-- | doc/extensions.html | 22 | ||||
-rw-r--r-- | src/Makefile | 11 | ||||
-rw-r--r-- | src/lj_arch.h | 33 | ||||
-rw-r--r-- | src/lj_err.c | 321 |
4 files changed, 197 insertions, 190 deletions
diff --git a/doc/extensions.html b/doc/extensions.html index d0c3ca7a..be7e66d8 100644 --- a/doc/extensions.html +++ b/doc/extensions.html | |||
@@ -392,29 +392,19 @@ the toolchain used to compile LuaJIT: | |||
392 | <td class="excinterop">Interoperability</td> | 392 | <td class="excinterop">Interoperability</td> |
393 | </tr> | 393 | </tr> |
394 | <tr class="odd separate"> | 394 | <tr class="odd separate"> |
395 | <td class="excplatform">POSIX/x64, DWARF2 unwinding</td> | 395 | <td class="excplatform">External frame unwinding</td> |
396 | <td class="exccompiler">GCC 4.3+, Clang</td> | 396 | <td class="exccompiler">GCC, Clang, MSVC</td> |
397 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> | 397 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> |
398 | </tr> | 398 | </tr> |
399 | <tr class="even"> | 399 | <tr class="even"> |
400 | <td class="excplatform">ARM <tt>-DLUAJIT_UNWIND_EXTERNAL</tt></td> | 400 | <td class="excplatform">Internal frame unwinding + DWARF2</td> |
401 | <td class="exccompiler">GCC, Clang</td> | ||
402 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> | ||
403 | </tr> | ||
404 | <tr class="odd"> | ||
405 | <td class="excplatform">Other platforms, DWARF2 unwinding</td> | ||
406 | <td class="exccompiler">GCC, Clang</td> | 401 | <td class="exccompiler">GCC, Clang</td> |
407 | <td class="excinterop"><b style="color: #c06000;">Limited</b></td> | 402 | <td class="excinterop"><b style="color: #c06000;">Limited</b></td> |
408 | </tr> | 403 | </tr> |
409 | <tr class="even"> | ||
410 | <td class="excplatform">Windows/x64</td> | ||
411 | <td class="exccompiler">MSVC</td> | ||
412 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> | ||
413 | </tr> | ||
414 | <tr class="odd"> | 404 | <tr class="odd"> |
415 | <td class="excplatform">Windows/x86</td> | 405 | <td class="excplatform">Windows 64 bit</td> |
416 | <td class="exccompiler">Any</td> | 406 | <td class="exccompiler">non-MSVC</td> |
417 | <td class="excinterop"><b style="color: #00a000;">Full</b></td> | 407 | <td class="excinterop"><b style="color: #c06000;">Limited</b></td> |
418 | </tr> | 408 | </tr> |
419 | <tr class="even"> | 409 | <tr class="even"> |
420 | <td class="excplatform">Other platforms</td> | 410 | <td class="excplatform">Other platforms</td> |
diff --git a/src/Makefile b/src/Makefile index 2e1a2888..6f17bafd 100644 --- a/src/Makefile +++ b/src/Makefile | |||
@@ -314,6 +314,13 @@ else | |||
314 | ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1)) | 314 | ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1)) |
315 | TARGET_XCFLAGS+= -fno-stack-protector | 315 | TARGET_XCFLAGS+= -fno-stack-protector |
316 | endif | 316 | endif |
317 | ifeq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH))) | ||
318 | # Find out whether the target toolchain always generates unwind tables. | ||
319 | TARGET_TESTUNWIND=$(shell exec 2>/dev/null; echo 'extern void b(void);int a(void){b();return 0;}' | $(TARGET_CC) -c -x c - -o tmpunwind.o && grep -qa -e eh_frame -e __unwind_info tmpunwind.o && echo E; rm -f tmpunwind.o) | ||
320 | ifneq (,$(findstring E,$(TARGET_TESTUNWIND))) | ||
321 | TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL | ||
322 | endif | ||
323 | endif | ||
317 | ifeq (Darwin,$(TARGET_SYS)) | 324 | ifeq (Darwin,$(TARGET_SYS)) |
318 | ifeq (,$(MACOSX_DEPLOYMENT_TARGET)) | 325 | ifeq (,$(MACOSX_DEPLOYMENT_TARGET)) |
319 | $(error missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY) | 326 | $(error missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY) |
@@ -322,10 +329,6 @@ ifeq (Darwin,$(TARGET_SYS)) | |||
322 | TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC | 329 | TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC |
323 | TARGET_DYNXLDOPTS= | 330 | TARGET_DYNXLDOPTS= |
324 | TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER) | 331 | TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER) |
325 | ifeq (x64,$(TARGET_LJARCH)) | ||
326 | TARGET_XLDFLAGS+= -pagezero_size 10000 -image_base 100000000 | ||
327 | TARGET_XSHLDFLAGS+= -image_base 7fff04c4a000 | ||
328 | endif | ||
329 | else | 332 | else |
330 | ifeq (iOS,$(TARGET_SYS)) | 333 | ifeq (iOS,$(TARGET_SYS)) |
331 | TARGET_STRIP+= -x | 334 | TARGET_STRIP+= -x |
diff --git a/src/lj_arch.h b/src/lj_arch.h index d4fd9c9d..ac3e3753 100644 --- a/src/lj_arch.h +++ b/src/lj_arch.h | |||
@@ -170,11 +170,6 @@ | |||
170 | #define LJ_ARCH_NAME "x86" | 170 | #define LJ_ARCH_NAME "x86" |
171 | #define LJ_ARCH_BITS 32 | 171 | #define LJ_ARCH_BITS 32 |
172 | #define LJ_ARCH_ENDIAN LUAJIT_LE | 172 | #define LJ_ARCH_ENDIAN LUAJIT_LE |
173 | #if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN | ||
174 | #define LJ_ABI_WIN 1 | ||
175 | #else | ||
176 | #define LJ_ABI_WIN 0 | ||
177 | #endif | ||
178 | #define LJ_TARGET_X86 1 | 173 | #define LJ_TARGET_X86 1 |
179 | #define LJ_TARGET_X86ORX64 1 | 174 | #define LJ_TARGET_X86ORX64 1 |
180 | #define LJ_TARGET_EHRETREG 0 | 175 | #define LJ_TARGET_EHRETREG 0 |
@@ -188,11 +183,6 @@ | |||
188 | #define LJ_ARCH_NAME "x64" | 183 | #define LJ_ARCH_NAME "x64" |
189 | #define LJ_ARCH_BITS 64 | 184 | #define LJ_ARCH_BITS 64 |
190 | #define LJ_ARCH_ENDIAN LUAJIT_LE | 185 | #define LJ_ARCH_ENDIAN LUAJIT_LE |
191 | #if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN | ||
192 | #define LJ_ABI_WIN 1 | ||
193 | #else | ||
194 | #define LJ_ABI_WIN 0 | ||
195 | #endif | ||
196 | #define LJ_TARGET_X64 1 | 186 | #define LJ_TARGET_X64 1 |
197 | #define LJ_TARGET_X86ORX64 1 | 187 | #define LJ_TARGET_X86ORX64 1 |
198 | #define LJ_TARGET_EHRETREG 0 | 188 | #define LJ_TARGET_EHRETREG 0 |
@@ -203,6 +193,8 @@ | |||
203 | #define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL | 193 | #define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL |
204 | #ifndef LUAJIT_DISABLE_GC64 | 194 | #ifndef LUAJIT_DISABLE_GC64 |
205 | #define LJ_TARGET_GC64 1 | 195 | #define LJ_TARGET_GC64 1 |
196 | #elif LJ_TARGET_OSX | ||
197 | #error "macOS requires GC64 -- don't disable it" | ||
206 | #endif | 198 | #endif |
207 | 199 | ||
208 | #elif LUAJIT_TARGET == LUAJIT_ARCH_ARM | 200 | #elif LUAJIT_TARGET == LUAJIT_ARCH_ARM |
@@ -611,13 +603,10 @@ | |||
611 | #define LJ_NO_SYSTEM 1 | 603 | #define LJ_NO_SYSTEM 1 |
612 | #endif | 604 | #endif |
613 | 605 | ||
614 | #if !defined(LUAJIT_NO_UNWIND) && __GNU_COMPACT_EH__ | 606 | #if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN |
615 | /* NYI: no support for compact unwind specification, yet. */ | 607 | #define LJ_ABI_WIN 1 |
616 | #define LUAJIT_NO_UNWIND 1 | 608 | #else |
617 | #endif | 609 | #define LJ_ABI_WIN 0 |
618 | |||
619 | #if defined(LUAJIT_NO_UNWIND) || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 | ||
620 | #define LJ_NO_UNWIND 1 | ||
621 | #endif | 610 | #endif |
622 | 611 | ||
623 | #if LJ_TARGET_WINDOWS | 612 | #if LJ_TARGET_WINDOWS |
@@ -632,6 +621,16 @@ extern void *LJ_WIN_LOADLIBA(const char *path); | |||
632 | #endif | 621 | #endif |
633 | #endif | 622 | #endif |
634 | 623 | ||
624 | #if defined(LUAJIT_NO_UNWIND) || __GNU_COMPACT_EH__ || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4 | ||
625 | #define LJ_NO_UNWIND 1 | ||
626 | #endif | ||
627 | |||
628 | #if !LJ_NO_UNWIND && !defined(LUAJIT_UNWIND_INTERNAL) && (LJ_ABI_WIN || (defined(LUAJIT_UNWIND_EXTERNAL) && (defined(__GNUC__) || defined(__clang__)))) | ||
629 | #define LJ_UNWIND_EXT 1 | ||
630 | #else | ||
631 | #define LJ_UNWIND_EXT 0 | ||
632 | #endif | ||
633 | |||
635 | /* Compatibility with Lua 5.1 vs. 5.2. */ | 634 | /* Compatibility with Lua 5.1 vs. 5.2. */ |
636 | #ifdef LUAJIT_ENABLE_LUA52COMPAT | 635 | #ifdef LUAJIT_ENABLE_LUA52COMPAT |
637 | #define LJ_52 1 | 636 | #define LJ_52 1 |
diff --git a/src/lj_err.c b/src/lj_err.c index c0bf38c2..ba0fac0a 100644 --- a/src/lj_err.c +++ b/src/lj_err.c | |||
@@ -29,12 +29,18 @@ | |||
29 | ** Pros and Cons: | 29 | ** Pros and Cons: |
30 | ** | 30 | ** |
31 | ** - EXT requires unwind tables for *all* functions on the C stack between | 31 | ** - EXT requires unwind tables for *all* functions on the C stack between |
32 | ** the pcall/catch and the error/throw. This is the default on x64, | 32 | ** the pcall/catch and the error/throw. C modules used by Lua code can |
33 | ** but needs to be manually enabled on x86/PPC for non-C++ code. | 33 | ** throw errors, so these need to have unwind tables, too. Transitively |
34 | ** this applies to all system libraries used by C modules -- at least | ||
35 | ** when they have callbacks which may throw an error. | ||
34 | ** | 36 | ** |
35 | ** - INT is faster when actually throwing errors (but this happens rarely). | 37 | ** - INT is faster when actually throwing errors, but this happens rarely. |
36 | ** Setting up error handlers is zero-cost in any case. | 38 | ** Setting up error handlers is zero-cost in any case. |
37 | ** | 39 | ** |
40 | ** - INT needs to save *all* callee-saved registers when entering the | ||
41 | ** interpreter. EXT only needs to save those actually used inside the | ||
42 | ** interpreter. JIT-compiled code may need to save some more. | ||
43 | ** | ||
38 | ** - EXT provides full interoperability with C++ exceptions. You can throw | 44 | ** - EXT provides full interoperability with C++ exceptions. You can throw |
39 | ** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames. | 45 | ** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames. |
40 | ** C++ destructors are called as needed. C++ exceptions caught by pcall | 46 | ** C++ destructors are called as needed. C++ exceptions caught by pcall |
@@ -46,27 +52,33 @@ | |||
46 | ** the wrapper function feature. Lua errors thrown through C++ frames | 52 | ** the wrapper function feature. Lua errors thrown through C++ frames |
47 | ** cannot be caught by C++ code and C++ destructors are not run. | 53 | ** cannot be caught by C++ code and C++ destructors are not run. |
48 | ** | 54 | ** |
49 | ** EXT is the default on x64 systems and on Windows, INT is the default on all | 55 | ** EXT is the default on all systems where the toolchain produces unwind |
50 | ** other systems. | 56 | ** tables by default (*). This is hard-coded and/or detected in src/Makefile. |
57 | ** You can thwart the detection with: TARGET_XCFLAGS=-DLUAJIT_UNWIND_INTERNAL | ||
58 | ** | ||
59 | ** INT is the default on all other systems. | ||
60 | ** | ||
61 | ** EXT can be manually enabled for toolchains that are able to produce | ||
62 | ** conforming unwind tables: | ||
63 | ** "TARGET_XCFLAGS=-funwind-tables -DLUAJIT_UNWIND_EXTERNAL" | ||
64 | ** As explained above, *all* C code used directly or indirectly by LuaJIT | ||
65 | ** must be compiled with -funwind-tables (or -fexceptions). C++ code must | ||
66 | ** *not* be compiled with -fno-exceptions. | ||
67 | ** | ||
68 | ** If you're unsure whether error handling inside the VM works correctly, | ||
69 | ** try running this and check whether it prints "OK": | ||
51 | ** | 70 | ** |
52 | ** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack | 71 | ** luajit -e "print(select(2, load('OK')):match('OK'))" |
53 | ** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled | ||
54 | ** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set | ||
55 | ** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules | ||
56 | ** and all C libraries that have callbacks which may be used to call back | ||
57 | ** into Lua. C++ code must *not* be compiled with -fno-exceptions. | ||
58 | ** | 72 | ** |
59 | ** EXT is mandatory on WIN64 since the calling convention has an abundance | 73 | ** (*) Originally, toolchains only generated unwind tables for C++ code. For |
60 | ** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). | 74 | ** interoperability reasons, this can be manually enabled for plain C code, |
61 | ** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). | 75 | ** too (with -funwind-tables). With the introduction of the x64 architecture, |
76 | ** the corresponding POSIX and Windows ABIs mandated unwind tables for all | ||
77 | ** code. Over the following years most desktop and server platforms have | ||
78 | ** enabled unwind tables by default on all architectures. OTOH mobile and | ||
79 | ** embedded platforms do not consistently mandate unwind tables. | ||
62 | */ | 80 | */ |
63 | 81 | ||
64 | #if (defined(__GNUC__) || defined(__clang__)) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND | ||
65 | #define LJ_UNWIND_EXT 1 | ||
66 | #elif LJ_TARGET_WINDOWS | ||
67 | #define LJ_UNWIND_EXT 1 | ||
68 | #endif | ||
69 | |||
70 | /* -- Error messages ------------------------------------------------------ */ | 82 | /* -- Error messages ------------------------------------------------------ */ |
71 | 83 | ||
72 | /* Error message strings. */ | 84 | /* Error message strings. */ |
@@ -184,7 +196,125 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
184 | 196 | ||
185 | /* -- External frame unwinding -------------------------------------------- */ | 197 | /* -- External frame unwinding -------------------------------------------- */ |
186 | 198 | ||
187 | #if (defined(__GNUC__) || defined(__clang__)) && !LJ_NO_UNWIND && !LJ_ABI_WIN | 199 | #if LJ_ABI_WIN |
200 | |||
201 | /* | ||
202 | ** Someone in Redmond owes me several days of my life. A lot of this is | ||
203 | ** undocumented or just plain wrong on MSDN. Some of it can be gathered | ||
204 | ** from 3rd party docs or must be found by trial-and-error. They really | ||
205 | ** don't want you to write your own language-specific exception handler | ||
206 | ** or to interact gracefully with MSVC. :-( | ||
207 | ** | ||
208 | ** Apparently MSVC doesn't call C++ destructors for foreign exceptions | ||
209 | ** unless you compile your C++ code with /EHa. Unfortunately this means | ||
210 | ** catch (...) also catches things like access violations. The use of | ||
211 | ** _set_se_translator doesn't really help, because it requires /EHa, too. | ||
212 | */ | ||
213 | |||
214 | #define WIN32_LEAN_AND_MEAN | ||
215 | #include <windows.h> | ||
216 | |||
217 | #if LJ_TARGET_X86 | ||
218 | typedef void *UndocumentedDispatcherContext; /* Unused on x86. */ | ||
219 | #else | ||
220 | /* Taken from: http://www.nynaeve.net/?p=99 */ | ||
221 | typedef struct UndocumentedDispatcherContext { | ||
222 | ULONG64 ControlPc; | ||
223 | ULONG64 ImageBase; | ||
224 | PRUNTIME_FUNCTION FunctionEntry; | ||
225 | ULONG64 EstablisherFrame; | ||
226 | ULONG64 TargetIp; | ||
227 | PCONTEXT ContextRecord; | ||
228 | void (*LanguageHandler)(void); | ||
229 | PVOID HandlerData; | ||
230 | PUNWIND_HISTORY_TABLE HistoryTable; | ||
231 | ULONG ScopeIndex; | ||
232 | ULONG Fill0; | ||
233 | } UndocumentedDispatcherContext; | ||
234 | #endif | ||
235 | |||
236 | /* Another wild guess. */ | ||
237 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | ||
238 | |||
239 | #if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) | ||
240 | /* Workaround for broken MinGW64 declaration. */ | ||
241 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | ||
242 | #define RtlUnwindEx RtlUnwindEx_FIXED | ||
243 | #endif | ||
244 | |||
245 | #define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) | ||
246 | #define LJ_GCC_EXCODE ((DWORD)0x20474343) | ||
247 | |||
248 | #define LJ_EXCODE ((DWORD)0xe24c4a00) | ||
249 | #define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) | ||
250 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | ||
251 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) | ||
252 | |||
253 | /* Windows exception handler for interpreter frame. */ | ||
254 | LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, | ||
255 | void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | ||
256 | { | ||
257 | #if LJ_TARGET_X86 | ||
258 | void *cf = (char *)f - CFRAME_OFS_SEH; | ||
259 | #else | ||
260 | void *cf = f; | ||
261 | #endif | ||
262 | lua_State *L = cframe_L(cf); | ||
263 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? | ||
264 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; | ||
265 | if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ | ||
266 | /* Unwind internal frames. */ | ||
267 | err_unwind(L, cf, errcode); | ||
268 | } else { | ||
269 | void *cf2 = err_unwind(L, cf, 0); | ||
270 | if (cf2) { /* We catch it, so start unwinding the upper frames. */ | ||
271 | if (rec->ExceptionCode == LJ_MSVC_EXCODE || | ||
272 | rec->ExceptionCode == LJ_GCC_EXCODE) { | ||
273 | #if !LJ_TARGET_CYGWIN | ||
274 | __DestructExceptionObject(rec, 1); | ||
275 | #endif | ||
276 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); | ||
277 | } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { | ||
278 | /* Don't catch access violations etc. */ | ||
279 | return 1; /* ExceptionContinueSearch */ | ||
280 | } | ||
281 | #if LJ_TARGET_X86 | ||
282 | UNUSED(ctx); | ||
283 | UNUSED(dispatch); | ||
284 | /* Call all handlers for all lower C frames (including ourselves) again | ||
285 | ** with EH_UNWINDING set. Then call the specified function, passing cf | ||
286 | ** and errcode. | ||
287 | */ | ||
288 | lj_vm_rtlunwind(cf, (void *)rec, | ||
289 | (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
290 | (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); | ||
291 | /* lj_vm_rtlunwind does not return. */ | ||
292 | #else | ||
293 | /* Unwind the stack and call all handlers for all lower C frames | ||
294 | ** (including ourselves) again with EH_UNWINDING set. Then set | ||
295 | ** stack pointer = cf, result = errcode and jump to the specified target. | ||
296 | */ | ||
297 | RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
298 | lj_vm_unwind_ff_eh : | ||
299 | lj_vm_unwind_c_eh), | ||
300 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); | ||
301 | /* RtlUnwindEx should never return. */ | ||
302 | #endif | ||
303 | } | ||
304 | } | ||
305 | return 1; /* ExceptionContinueSearch */ | ||
306 | } | ||
307 | |||
308 | /* Raise Windows exception. */ | ||
309 | static void err_raise_ext(global_State *g, int errcode) | ||
310 | { | ||
311 | #if LJ_HASJIT | ||
312 | setmref(g->jit_base, NULL); | ||
313 | #endif | ||
314 | RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); | ||
315 | } | ||
316 | |||
317 | #elif !LJ_NO_UNWIND && (defined(__GNUC__) || defined(__clang__)) | ||
188 | 318 | ||
189 | /* | 319 | /* |
190 | ** We have to use our own definitions instead of the mandatory (!) unwind.h, | 320 | ** We have to use our own definitions instead of the mandatory (!) unwind.h, |
@@ -233,7 +363,6 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, | |||
233 | lua_State *L; | 363 | lua_State *L; |
234 | if (version != 1) | 364 | if (version != 1) |
235 | return _URC_FATAL_PHASE1_ERROR; | 365 | return _URC_FATAL_PHASE1_ERROR; |
236 | UNUSED(uexclass); | ||
237 | cf = (void *)_Unwind_GetCFA(ctx); | 366 | cf = (void *)_Unwind_GetCFA(ctx); |
238 | L = cframe_L(cf); | 367 | L = cframe_L(cf); |
239 | if ((actions & _UA_SEARCH_PHASE)) { | 368 | if ((actions & _UA_SEARCH_PHASE)) { |
@@ -281,6 +410,9 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, | |||
281 | ** it on non-x64 because the interpreter restores all callee-saved regs. | 410 | ** it on non-x64 because the interpreter restores all callee-saved regs. |
282 | */ | 411 | */ |
283 | lj_err_throw(L, errcode); | 412 | lj_err_throw(L, errcode); |
413 | #if LJ_TARGET_X64 | ||
414 | #error "Broken build system -- only use the provided Makefiles!" | ||
415 | #endif | ||
284 | #endif | 416 | #endif |
285 | } | 417 | } |
286 | return _URC_CONTINUE_UNWIND; | 418 | return _URC_CONTINUE_UNWIND; |
@@ -288,14 +420,6 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, | |||
288 | 420 | ||
289 | #if LJ_UNWIND_EXT | 421 | #if LJ_UNWIND_EXT |
290 | static __thread _Unwind_Exception static_uex; | 422 | static __thread _Unwind_Exception static_uex; |
291 | |||
292 | /* Raise DWARF2 exception. */ | ||
293 | static void err_raise_ext(int errcode) | ||
294 | { | ||
295 | static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); | ||
296 | static_uex.excleanup = NULL; | ||
297 | _Unwind_RaiseException(&static_uex); | ||
298 | } | ||
299 | #endif | 423 | #endif |
300 | 424 | ||
301 | #else /* LJ_TARGET_ARM */ | 425 | #else /* LJ_TARGET_ARM */ |
@@ -369,132 +493,22 @@ LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb, | |||
369 | 493 | ||
370 | #if LJ_UNWIND_EXT | 494 | #if LJ_UNWIND_EXT |
371 | static __thread _Unwind_Control_Block static_uex; | 495 | static __thread _Unwind_Control_Block static_uex; |
496 | #endif | ||
497 | #endif /* LJ_TARGET_ARM */ | ||
372 | 498 | ||
373 | static void err_raise_ext(int errcode) | 499 | #if LJ_UNWIND_EXT |
500 | /* Raise external exception. */ | ||
501 | static void err_raise_ext(global_State *g, int errcode) | ||
374 | { | 502 | { |
503 | #if LJ_HASJIT | ||
504 | setmref(g->jit_base, NULL); | ||
505 | #endif | ||
375 | memset(&static_uex, 0, sizeof(static_uex)); | 506 | memset(&static_uex, 0, sizeof(static_uex)); |
376 | static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); | 507 | static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); |
377 | _Unwind_RaiseException(&static_uex); | 508 | _Unwind_RaiseException(&static_uex); |
378 | } | 509 | } |
379 | #endif | 510 | #endif |
380 | 511 | ||
381 | #endif /* LJ_TARGET_ARM */ | ||
382 | |||
383 | #elif LJ_ABI_WIN | ||
384 | |||
385 | /* | ||
386 | ** Someone in Redmond owes me several days of my life. A lot of this is | ||
387 | ** undocumented or just plain wrong on MSDN. Some of it can be gathered | ||
388 | ** from 3rd party docs or must be found by trial-and-error. They really | ||
389 | ** don't want you to write your own language-specific exception handler | ||
390 | ** or to interact gracefully with MSVC. :-( | ||
391 | ** | ||
392 | ** Apparently MSVC doesn't call C++ destructors for foreign exceptions | ||
393 | ** unless you compile your C++ code with /EHa. Unfortunately this means | ||
394 | ** catch (...) also catches things like access violations. The use of | ||
395 | ** _set_se_translator doesn't really help, because it requires /EHa, too. | ||
396 | */ | ||
397 | |||
398 | #define WIN32_LEAN_AND_MEAN | ||
399 | #include <windows.h> | ||
400 | |||
401 | #if LJ_TARGET_X64 | ||
402 | /* Taken from: http://www.nynaeve.net/?p=99 */ | ||
403 | typedef struct UndocumentedDispatcherContext { | ||
404 | ULONG64 ControlPc; | ||
405 | ULONG64 ImageBase; | ||
406 | PRUNTIME_FUNCTION FunctionEntry; | ||
407 | ULONG64 EstablisherFrame; | ||
408 | ULONG64 TargetIp; | ||
409 | PCONTEXT ContextRecord; | ||
410 | void (*LanguageHandler)(void); | ||
411 | PVOID HandlerData; | ||
412 | PUNWIND_HISTORY_TABLE HistoryTable; | ||
413 | ULONG ScopeIndex; | ||
414 | ULONG Fill0; | ||
415 | } UndocumentedDispatcherContext; | ||
416 | #else | ||
417 | typedef void *UndocumentedDispatcherContext; | ||
418 | #endif | ||
419 | |||
420 | /* Another wild guess. */ | ||
421 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | ||
422 | |||
423 | #if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) | ||
424 | /* Workaround for broken MinGW64 declaration. */ | ||
425 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | ||
426 | #define RtlUnwindEx RtlUnwindEx_FIXED | ||
427 | #endif | ||
428 | |||
429 | #define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) | ||
430 | #define LJ_GCC_EXCODE ((DWORD)0x20474343) | ||
431 | |||
432 | #define LJ_EXCODE ((DWORD)0xe24c4a00) | ||
433 | #define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) | ||
434 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | ||
435 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) | ||
436 | |||
437 | /* Windows exception handler for interpreter frame. */ | ||
438 | LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, | ||
439 | void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | ||
440 | { | ||
441 | #if LJ_TARGET_X64 | ||
442 | void *cf = f; | ||
443 | #else | ||
444 | void *cf = (char *)f - CFRAME_OFS_SEH; | ||
445 | #endif | ||
446 | lua_State *L = cframe_L(cf); | ||
447 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? | ||
448 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; | ||
449 | if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ | ||
450 | /* Unwind internal frames. */ | ||
451 | err_unwind(L, cf, errcode); | ||
452 | } else { | ||
453 | void *cf2 = err_unwind(L, cf, 0); | ||
454 | if (cf2) { /* We catch it, so start unwinding the upper frames. */ | ||
455 | if (rec->ExceptionCode == LJ_MSVC_EXCODE || | ||
456 | rec->ExceptionCode == LJ_GCC_EXCODE) { | ||
457 | #if LJ_TARGET_WINDOWS | ||
458 | __DestructExceptionObject(rec, 1); | ||
459 | #endif | ||
460 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); | ||
461 | } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { | ||
462 | /* Don't catch access violations etc. */ | ||
463 | return 1; /* ExceptionContinueSearch */ | ||
464 | } | ||
465 | #if LJ_TARGET_X64 | ||
466 | /* Unwind the stack and call all handlers for all lower C frames | ||
467 | ** (including ourselves) again with EH_UNWINDING set. Then set | ||
468 | ** rsp = cf, rax = errcode and jump to the specified target. | ||
469 | */ | ||
470 | RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
471 | lj_vm_unwind_ff_eh : | ||
472 | lj_vm_unwind_c_eh), | ||
473 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); | ||
474 | /* RtlUnwindEx should never return. */ | ||
475 | #else | ||
476 | UNUSED(ctx); | ||
477 | UNUSED(dispatch); | ||
478 | /* Call all handlers for all lower C frames (including ourselves) again | ||
479 | ** with EH_UNWINDING set. Then call the specified function, passing cf | ||
480 | ** and errcode. | ||
481 | */ | ||
482 | lj_vm_rtlunwind(cf, (void *)rec, | ||
483 | (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
484 | (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); | ||
485 | /* lj_vm_rtlunwind does not return. */ | ||
486 | #endif | ||
487 | } | ||
488 | } | ||
489 | return 1; /* ExceptionContinueSearch */ | ||
490 | } | ||
491 | |||
492 | /* Raise Windows exception. */ | ||
493 | static void err_raise_ext(int errcode) | ||
494 | { | ||
495 | RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); | ||
496 | } | ||
497 | |||
498 | #endif | 512 | #endif |
499 | 513 | ||
500 | /* -- Error handling ------------------------------------------------------ */ | 514 | /* -- Error handling ------------------------------------------------------ */ |
@@ -504,22 +518,23 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode) | |||
504 | { | 518 | { |
505 | global_State *g = G(L); | 519 | global_State *g = G(L); |
506 | lj_trace_abort(g); | 520 | lj_trace_abort(g); |
507 | setmref(g->jit_base, NULL); | ||
508 | L->status = LUA_OK; | 521 | L->status = LUA_OK; |
509 | #if LJ_UNWIND_EXT | 522 | #if LJ_UNWIND_EXT |
510 | err_raise_ext(errcode); | 523 | err_raise_ext(g, errcode); |
511 | /* | 524 | /* |
512 | ** A return from this function signals a corrupt C stack that cannot be | 525 | ** A return from this function signals a corrupt C stack that cannot be |
513 | ** unwound. We have no choice but to call the panic function and exit. | 526 | ** unwound. We have no choice but to call the panic function and exit. |
514 | ** | 527 | ** |
515 | ** Usually this is caused by a C function without unwind information. | 528 | ** Usually this is caused by a C function without unwind information. |
516 | ** This should never happen on x64, but may happen if you've manually | 529 | ** This may happen if you've manually enabled LUAJIT_UNWIND_EXTERNAL |
517 | ** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every* | 530 | ** and forgot to recompile *every* non-C++ file with -funwind-tables. |
518 | ** non-C++ file with -funwind-tables. | ||
519 | */ | 531 | */ |
520 | if (G(L)->panic) | 532 | if (G(L)->panic) |
521 | G(L)->panic(L); | 533 | G(L)->panic(L); |
522 | #else | 534 | #else |
535 | #if LJ_HASJIT | ||
536 | setmref(g->jit_base, NULL); | ||
537 | #endif | ||
523 | { | 538 | { |
524 | void *cf = err_unwind(L, NULL, errcode); | 539 | void *cf = err_unwind(L, NULL, errcode); |
525 | if (cframe_unwind_ff(cf)) | 540 | if (cframe_unwind_ff(cf)) |