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 /src | |
| parent | ce9faf2e0d627aa043b84f290aebc4ef87c5a3b4 (diff) | |
| download | luajit-e131936133c58de4426c595db2341caf5a1665b5.tar.gz luajit-e131936133c58de4426c595db2341caf5a1665b5.tar.bz2 luajit-e131936133c58de4426c595db2341caf5a1665b5.zip | |
Cleanup and enable external unwinding for more platforms.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile | 11 | ||||
| -rw-r--r-- | src/lj_arch.h | 33 | ||||
| -rw-r--r-- | src/lj_err.c | 321 |
3 files changed, 191 insertions, 174 deletions
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)) |
