mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-07 15:14:08 +00:00
Cleanup and enable external unwinding for more platforms.
This commit is contained in:
parent
ce9faf2e0d
commit
e131936133
@ -392,29 +392,19 @@ the toolchain used to compile LuaJIT:
|
|||||||
<td class="excinterop">Interoperability</td>
|
<td class="excinterop">Interoperability</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="odd separate">
|
<tr class="odd separate">
|
||||||
<td class="excplatform">POSIX/x64, DWARF2 unwinding</td>
|
<td class="excplatform">External frame unwinding</td>
|
||||||
<td class="exccompiler">GCC 4.3+, Clang</td>
|
<td class="exccompiler">GCC, Clang, MSVC</td>
|
||||||
<td class="excinterop"><b style="color: #00a000;">Full</b></td>
|
<td class="excinterop"><b style="color: #00a000;">Full</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="even">
|
<tr class="even">
|
||||||
<td class="excplatform">ARM <tt>-DLUAJIT_UNWIND_EXTERNAL</tt></td>
|
<td class="excplatform">Internal frame unwinding + DWARF2</td>
|
||||||
<td class="exccompiler">GCC, Clang</td>
|
|
||||||
<td class="excinterop"><b style="color: #00a000;">Full</b></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="odd">
|
|
||||||
<td class="excplatform">Other platforms, DWARF2 unwinding</td>
|
|
||||||
<td class="exccompiler">GCC, Clang</td>
|
<td class="exccompiler">GCC, Clang</td>
|
||||||
<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
|
<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="even">
|
|
||||||
<td class="excplatform">Windows/x64</td>
|
|
||||||
<td class="exccompiler">MSVC</td>
|
|
||||||
<td class="excinterop"><b style="color: #00a000;">Full</b></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="odd">
|
<tr class="odd">
|
||||||
<td class="excplatform">Windows/x86</td>
|
<td class="excplatform">Windows 64 bit</td>
|
||||||
<td class="exccompiler">Any</td>
|
<td class="exccompiler">non-MSVC</td>
|
||||||
<td class="excinterop"><b style="color: #00a000;">Full</b></td>
|
<td class="excinterop"><b style="color: #c06000;">Limited</b></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="even">
|
<tr class="even">
|
||||||
<td class="excplatform">Other platforms</td>
|
<td class="excplatform">Other platforms</td>
|
||||||
|
11
src/Makefile
11
src/Makefile
@ -314,6 +314,13 @@ else
|
|||||||
ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1))
|
ifeq (,$(shell $(TARGET_CC) -o /dev/null -c -x c /dev/null -fno-stack-protector 2>/dev/null || echo 1))
|
||||||
TARGET_XCFLAGS+= -fno-stack-protector
|
TARGET_XCFLAGS+= -fno-stack-protector
|
||||||
endif
|
endif
|
||||||
|
ifeq (,$(findstring LJ_NO_UNWIND 1,$(TARGET_TESTARCH)))
|
||||||
|
# Find out whether the target toolchain always generates unwind tables.
|
||||||
|
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)
|
||||||
|
ifneq (,$(findstring E,$(TARGET_TESTUNWIND)))
|
||||||
|
TARGET_XCFLAGS+= -DLUAJIT_UNWIND_EXTERNAL
|
||||||
|
endif
|
||||||
|
endif
|
||||||
ifeq (Darwin,$(TARGET_SYS))
|
ifeq (Darwin,$(TARGET_SYS))
|
||||||
ifeq (,$(MACOSX_DEPLOYMENT_TARGET))
|
ifeq (,$(MACOSX_DEPLOYMENT_TARGET))
|
||||||
$(error missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY)
|
$(error missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY)
|
||||||
@ -322,10 +329,6 @@ ifeq (Darwin,$(TARGET_SYS))
|
|||||||
TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
|
TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fPIC
|
||||||
TARGET_DYNXLDOPTS=
|
TARGET_DYNXLDOPTS=
|
||||||
TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER)
|
TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER)
|
||||||
ifeq (x64,$(TARGET_LJARCH))
|
|
||||||
TARGET_XLDFLAGS+= -pagezero_size 10000 -image_base 100000000
|
|
||||||
TARGET_XSHLDFLAGS+= -image_base 7fff04c4a000
|
|
||||||
endif
|
|
||||||
else
|
else
|
||||||
ifeq (iOS,$(TARGET_SYS))
|
ifeq (iOS,$(TARGET_SYS))
|
||||||
TARGET_STRIP+= -x
|
TARGET_STRIP+= -x
|
||||||
|
@ -170,11 +170,6 @@
|
|||||||
#define LJ_ARCH_NAME "x86"
|
#define LJ_ARCH_NAME "x86"
|
||||||
#define LJ_ARCH_BITS 32
|
#define LJ_ARCH_BITS 32
|
||||||
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
||||||
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
|
|
||||||
#define LJ_ABI_WIN 1
|
|
||||||
#else
|
|
||||||
#define LJ_ABI_WIN 0
|
|
||||||
#endif
|
|
||||||
#define LJ_TARGET_X86 1
|
#define LJ_TARGET_X86 1
|
||||||
#define LJ_TARGET_X86ORX64 1
|
#define LJ_TARGET_X86ORX64 1
|
||||||
#define LJ_TARGET_EHRETREG 0
|
#define LJ_TARGET_EHRETREG 0
|
||||||
@ -188,11 +183,6 @@
|
|||||||
#define LJ_ARCH_NAME "x64"
|
#define LJ_ARCH_NAME "x64"
|
||||||
#define LJ_ARCH_BITS 64
|
#define LJ_ARCH_BITS 64
|
||||||
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
#define LJ_ARCH_ENDIAN LUAJIT_LE
|
||||||
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
|
|
||||||
#define LJ_ABI_WIN 1
|
|
||||||
#else
|
|
||||||
#define LJ_ABI_WIN 0
|
|
||||||
#endif
|
|
||||||
#define LJ_TARGET_X64 1
|
#define LJ_TARGET_X64 1
|
||||||
#define LJ_TARGET_X86ORX64 1
|
#define LJ_TARGET_X86ORX64 1
|
||||||
#define LJ_TARGET_EHRETREG 0
|
#define LJ_TARGET_EHRETREG 0
|
||||||
@ -203,6 +193,8 @@
|
|||||||
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
|
#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE_DUAL
|
||||||
#ifndef LUAJIT_DISABLE_GC64
|
#ifndef LUAJIT_DISABLE_GC64
|
||||||
#define LJ_TARGET_GC64 1
|
#define LJ_TARGET_GC64 1
|
||||||
|
#elif LJ_TARGET_OSX
|
||||||
|
#error "macOS requires GC64 -- don't disable it"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM
|
#elif LUAJIT_TARGET == LUAJIT_ARCH_ARM
|
||||||
@ -611,13 +603,10 @@
|
|||||||
#define LJ_NO_SYSTEM 1
|
#define LJ_NO_SYSTEM 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(LUAJIT_NO_UNWIND) && __GNU_COMPACT_EH__
|
#if LJ_TARGET_WINDOWS || LJ_TARGET_CYGWIN
|
||||||
/* NYI: no support for compact unwind specification, yet. */
|
#define LJ_ABI_WIN 1
|
||||||
#define LUAJIT_NO_UNWIND 1
|
#else
|
||||||
#endif
|
#define LJ_ABI_WIN 0
|
||||||
|
|
||||||
#if defined(LUAJIT_NO_UNWIND) || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4
|
|
||||||
#define LJ_NO_UNWIND 1
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LJ_TARGET_WINDOWS
|
#if LJ_TARGET_WINDOWS
|
||||||
@ -632,6 +621,16 @@ extern void *LJ_WIN_LOADLIBA(const char *path);
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(LUAJIT_NO_UNWIND) || __GNU_COMPACT_EH__ || defined(__symbian__) || LJ_TARGET_IOS || LJ_TARGET_PS3 || LJ_TARGET_PS4
|
||||||
|
#define LJ_NO_UNWIND 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !LJ_NO_UNWIND && !defined(LUAJIT_UNWIND_INTERNAL) && (LJ_ABI_WIN || (defined(LUAJIT_UNWIND_EXTERNAL) && (defined(__GNUC__) || defined(__clang__))))
|
||||||
|
#define LJ_UNWIND_EXT 1
|
||||||
|
#else
|
||||||
|
#define LJ_UNWIND_EXT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Compatibility with Lua 5.1 vs. 5.2. */
|
/* Compatibility with Lua 5.1 vs. 5.2. */
|
||||||
#ifdef LUAJIT_ENABLE_LUA52COMPAT
|
#ifdef LUAJIT_ENABLE_LUA52COMPAT
|
||||||
#define LJ_52 1
|
#define LJ_52 1
|
||||||
|
321
src/lj_err.c
321
src/lj_err.c
@ -29,12 +29,18 @@
|
|||||||
** Pros and Cons:
|
** Pros and Cons:
|
||||||
**
|
**
|
||||||
** - EXT requires unwind tables for *all* functions on the C stack between
|
** - EXT requires unwind tables for *all* functions on the C stack between
|
||||||
** the pcall/catch and the error/throw. This is the default on x64,
|
** the pcall/catch and the error/throw. C modules used by Lua code can
|
||||||
** but needs to be manually enabled on x86/PPC for non-C++ code.
|
** throw errors, so these need to have unwind tables, too. Transitively
|
||||||
|
** this applies to all system libraries used by C modules -- at least
|
||||||
|
** when they have callbacks which may throw an error.
|
||||||
**
|
**
|
||||||
** - INT is faster when actually throwing errors (but this happens rarely).
|
** - INT is faster when actually throwing errors, but this happens rarely.
|
||||||
** Setting up error handlers is zero-cost in any case.
|
** Setting up error handlers is zero-cost in any case.
|
||||||
**
|
**
|
||||||
|
** - INT needs to save *all* callee-saved registers when entering the
|
||||||
|
** interpreter. EXT only needs to save those actually used inside the
|
||||||
|
** interpreter. JIT-compiled code may need to save some more.
|
||||||
|
**
|
||||||
** - EXT provides full interoperability with C++ exceptions. You can throw
|
** - EXT provides full interoperability with C++ exceptions. You can throw
|
||||||
** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames.
|
** Lua errors or C++ exceptions through a mix of Lua frames and C++ frames.
|
||||||
** C++ destructors are called as needed. C++ exceptions caught by pcall
|
** C++ destructors are called as needed. C++ exceptions caught by pcall
|
||||||
@ -46,27 +52,33 @@
|
|||||||
** the wrapper function feature. Lua errors thrown through C++ frames
|
** the wrapper function feature. Lua errors thrown through C++ frames
|
||||||
** cannot be caught by C++ code and C++ destructors are not run.
|
** cannot be caught by C++ code and C++ destructors are not run.
|
||||||
**
|
**
|
||||||
** EXT is the default on x64 systems and on Windows, INT is the default on all
|
** EXT is the default on all systems where the toolchain produces unwind
|
||||||
** other systems.
|
** tables by default (*). This is hard-coded and/or detected in src/Makefile.
|
||||||
|
** You can thwart the detection with: TARGET_XCFLAGS=-DLUAJIT_UNWIND_INTERNAL
|
||||||
**
|
**
|
||||||
** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack
|
** INT is the default on all other systems.
|
||||||
** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled
|
|
||||||
** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set
|
|
||||||
** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules
|
|
||||||
** and all C libraries that have callbacks which may be used to call back
|
|
||||||
** into Lua. C++ code must *not* be compiled with -fno-exceptions.
|
|
||||||
**
|
**
|
||||||
** EXT is mandatory on WIN64 since the calling convention has an abundance
|
** EXT can be manually enabled for toolchains that are able to produce
|
||||||
** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15).
|
** conforming unwind tables:
|
||||||
** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4).
|
** "TARGET_XCFLAGS=-funwind-tables -DLUAJIT_UNWIND_EXTERNAL"
|
||||||
|
** As explained above, *all* C code used directly or indirectly by LuaJIT
|
||||||
|
** must be compiled with -funwind-tables (or -fexceptions). C++ code must
|
||||||
|
** *not* be compiled with -fno-exceptions.
|
||||||
|
**
|
||||||
|
** If you're unsure whether error handling inside the VM works correctly,
|
||||||
|
** try running this and check whether it prints "OK":
|
||||||
|
**
|
||||||
|
** luajit -e "print(select(2, load('OK')):match('OK'))"
|
||||||
|
**
|
||||||
|
** (*) Originally, toolchains only generated unwind tables for C++ code. For
|
||||||
|
** interoperability reasons, this can be manually enabled for plain C code,
|
||||||
|
** too (with -funwind-tables). With the introduction of the x64 architecture,
|
||||||
|
** the corresponding POSIX and Windows ABIs mandated unwind tables for all
|
||||||
|
** code. Over the following years most desktop and server platforms have
|
||||||
|
** enabled unwind tables by default on all architectures. OTOH mobile and
|
||||||
|
** embedded platforms do not consistently mandate unwind tables.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if (defined(__GNUC__) || defined(__clang__)) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND
|
|
||||||
#define LJ_UNWIND_EXT 1
|
|
||||||
#elif LJ_TARGET_WINDOWS
|
|
||||||
#define LJ_UNWIND_EXT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* -- Error messages ------------------------------------------------------ */
|
/* -- Error messages ------------------------------------------------------ */
|
||||||
|
|
||||||
/* Error message strings. */
|
/* Error message strings. */
|
||||||
@ -184,7 +196,125 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode)
|
|||||||
|
|
||||||
/* -- External frame unwinding -------------------------------------------- */
|
/* -- External frame unwinding -------------------------------------------- */
|
||||||
|
|
||||||
#if (defined(__GNUC__) || defined(__clang__)) && !LJ_NO_UNWIND && !LJ_ABI_WIN
|
#if LJ_ABI_WIN
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Someone in Redmond owes me several days of my life. A lot of this is
|
||||||
|
** undocumented or just plain wrong on MSDN. Some of it can be gathered
|
||||||
|
** from 3rd party docs or must be found by trial-and-error. They really
|
||||||
|
** don't want you to write your own language-specific exception handler
|
||||||
|
** or to interact gracefully with MSVC. :-(
|
||||||
|
**
|
||||||
|
** Apparently MSVC doesn't call C++ destructors for foreign exceptions
|
||||||
|
** unless you compile your C++ code with /EHa. Unfortunately this means
|
||||||
|
** catch (...) also catches things like access violations. The use of
|
||||||
|
** _set_se_translator doesn't really help, because it requires /EHa, too.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#if LJ_TARGET_X86
|
||||||
|
typedef void *UndocumentedDispatcherContext; /* Unused on x86. */
|
||||||
|
#else
|
||||||
|
/* Taken from: http://www.nynaeve.net/?p=99 */
|
||||||
|
typedef struct UndocumentedDispatcherContext {
|
||||||
|
ULONG64 ControlPc;
|
||||||
|
ULONG64 ImageBase;
|
||||||
|
PRUNTIME_FUNCTION FunctionEntry;
|
||||||
|
ULONG64 EstablisherFrame;
|
||||||
|
ULONG64 TargetIp;
|
||||||
|
PCONTEXT ContextRecord;
|
||||||
|
void (*LanguageHandler)(void);
|
||||||
|
PVOID HandlerData;
|
||||||
|
PUNWIND_HISTORY_TABLE HistoryTable;
|
||||||
|
ULONG ScopeIndex;
|
||||||
|
ULONG Fill0;
|
||||||
|
} UndocumentedDispatcherContext;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Another wild guess. */
|
||||||
|
extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow);
|
||||||
|
|
||||||
|
#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT)
|
||||||
|
/* Workaround for broken MinGW64 declaration. */
|
||||||
|
VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx");
|
||||||
|
#define RtlUnwindEx RtlUnwindEx_FIXED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363)
|
||||||
|
#define LJ_GCC_EXCODE ((DWORD)0x20474343)
|
||||||
|
|
||||||
|
#define LJ_EXCODE ((DWORD)0xe24c4a00)
|
||||||
|
#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c))
|
||||||
|
#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff)
|
||||||
|
#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff))
|
||||||
|
|
||||||
|
/* Windows exception handler for interpreter frame. */
|
||||||
|
LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
|
||||||
|
void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch)
|
||||||
|
{
|
||||||
|
#if LJ_TARGET_X86
|
||||||
|
void *cf = (char *)f - CFRAME_OFS_SEH;
|
||||||
|
#else
|
||||||
|
void *cf = f;
|
||||||
|
#endif
|
||||||
|
lua_State *L = cframe_L(cf);
|
||||||
|
int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
|
||||||
|
LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
|
||||||
|
if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
|
||||||
|
/* Unwind internal frames. */
|
||||||
|
err_unwind(L, cf, errcode);
|
||||||
|
} else {
|
||||||
|
void *cf2 = err_unwind(L, cf, 0);
|
||||||
|
if (cf2) { /* We catch it, so start unwinding the upper frames. */
|
||||||
|
if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
|
||||||
|
rec->ExceptionCode == LJ_GCC_EXCODE) {
|
||||||
|
#if !LJ_TARGET_CYGWIN
|
||||||
|
__DestructExceptionObject(rec, 1);
|
||||||
|
#endif
|
||||||
|
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
|
||||||
|
} else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) {
|
||||||
|
/* Don't catch access violations etc. */
|
||||||
|
return 1; /* ExceptionContinueSearch */
|
||||||
|
}
|
||||||
|
#if LJ_TARGET_X86
|
||||||
|
UNUSED(ctx);
|
||||||
|
UNUSED(dispatch);
|
||||||
|
/* Call all handlers for all lower C frames (including ourselves) again
|
||||||
|
** with EH_UNWINDING set. Then call the specified function, passing cf
|
||||||
|
** and errcode.
|
||||||
|
*/
|
||||||
|
lj_vm_rtlunwind(cf, (void *)rec,
|
||||||
|
(cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
|
||||||
|
(void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
|
||||||
|
/* lj_vm_rtlunwind does not return. */
|
||||||
|
#else
|
||||||
|
/* Unwind the stack and call all handlers for all lower C frames
|
||||||
|
** (including ourselves) again with EH_UNWINDING set. Then set
|
||||||
|
** stack pointer = cf, result = errcode and jump to the specified target.
|
||||||
|
*/
|
||||||
|
RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
|
||||||
|
lj_vm_unwind_ff_eh :
|
||||||
|
lj_vm_unwind_c_eh),
|
||||||
|
rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable);
|
||||||
|
/* RtlUnwindEx should never return. */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1; /* ExceptionContinueSearch */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Raise Windows exception. */
|
||||||
|
static void err_raise_ext(global_State *g, int errcode)
|
||||||
|
{
|
||||||
|
#if LJ_HASJIT
|
||||||
|
setmref(g->jit_base, NULL);
|
||||||
|
#endif
|
||||||
|
RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif !LJ_NO_UNWIND && (defined(__GNUC__) || defined(__clang__))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** We have to use our own definitions instead of the mandatory (!) unwind.h,
|
** 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,
|
|||||||
lua_State *L;
|
lua_State *L;
|
||||||
if (version != 1)
|
if (version != 1)
|
||||||
return _URC_FATAL_PHASE1_ERROR;
|
return _URC_FATAL_PHASE1_ERROR;
|
||||||
UNUSED(uexclass);
|
|
||||||
cf = (void *)_Unwind_GetCFA(ctx);
|
cf = (void *)_Unwind_GetCFA(ctx);
|
||||||
L = cframe_L(cf);
|
L = cframe_L(cf);
|
||||||
if ((actions & _UA_SEARCH_PHASE)) {
|
if ((actions & _UA_SEARCH_PHASE)) {
|
||||||
@ -281,6 +410,9 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions,
|
|||||||
** it on non-x64 because the interpreter restores all callee-saved regs.
|
** it on non-x64 because the interpreter restores all callee-saved regs.
|
||||||
*/
|
*/
|
||||||
lj_err_throw(L, errcode);
|
lj_err_throw(L, errcode);
|
||||||
|
#if LJ_TARGET_X64
|
||||||
|
#error "Broken build system -- only use the provided Makefiles!"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return _URC_CONTINUE_UNWIND;
|
return _URC_CONTINUE_UNWIND;
|
||||||
@ -288,14 +420,6 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions,
|
|||||||
|
|
||||||
#if LJ_UNWIND_EXT
|
#if LJ_UNWIND_EXT
|
||||||
static __thread _Unwind_Exception static_uex;
|
static __thread _Unwind_Exception static_uex;
|
||||||
|
|
||||||
/* Raise DWARF2 exception. */
|
|
||||||
static void err_raise_ext(int errcode)
|
|
||||||
{
|
|
||||||
static_uex.exclass = LJ_UEXCLASS_MAKE(errcode);
|
|
||||||
static_uex.excleanup = NULL;
|
|
||||||
_Unwind_RaiseException(&static_uex);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else /* LJ_TARGET_ARM */
|
#else /* LJ_TARGET_ARM */
|
||||||
@ -369,132 +493,22 @@ LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb,
|
|||||||
|
|
||||||
#if LJ_UNWIND_EXT
|
#if LJ_UNWIND_EXT
|
||||||
static __thread _Unwind_Control_Block static_uex;
|
static __thread _Unwind_Control_Block static_uex;
|
||||||
|
#endif
|
||||||
|
#endif /* LJ_TARGET_ARM */
|
||||||
|
|
||||||
static void err_raise_ext(int errcode)
|
#if LJ_UNWIND_EXT
|
||||||
|
/* Raise external exception. */
|
||||||
|
static void err_raise_ext(global_State *g, int errcode)
|
||||||
{
|
{
|
||||||
|
#if LJ_HASJIT
|
||||||
|
setmref(g->jit_base, NULL);
|
||||||
|
#endif
|
||||||
memset(&static_uex, 0, sizeof(static_uex));
|
memset(&static_uex, 0, sizeof(static_uex));
|
||||||
static_uex.exclass = LJ_UEXCLASS_MAKE(errcode);
|
static_uex.exclass = LJ_UEXCLASS_MAKE(errcode);
|
||||||
_Unwind_RaiseException(&static_uex);
|
_Unwind_RaiseException(&static_uex);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* LJ_TARGET_ARM */
|
|
||||||
|
|
||||||
#elif LJ_ABI_WIN
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Someone in Redmond owes me several days of my life. A lot of this is
|
|
||||||
** undocumented or just plain wrong on MSDN. Some of it can be gathered
|
|
||||||
** from 3rd party docs or must be found by trial-and-error. They really
|
|
||||||
** don't want you to write your own language-specific exception handler
|
|
||||||
** or to interact gracefully with MSVC. :-(
|
|
||||||
**
|
|
||||||
** Apparently MSVC doesn't call C++ destructors for foreign exceptions
|
|
||||||
** unless you compile your C++ code with /EHa. Unfortunately this means
|
|
||||||
** catch (...) also catches things like access violations. The use of
|
|
||||||
** _set_se_translator doesn't really help, because it requires /EHa, too.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#if LJ_TARGET_X64
|
|
||||||
/* Taken from: http://www.nynaeve.net/?p=99 */
|
|
||||||
typedef struct UndocumentedDispatcherContext {
|
|
||||||
ULONG64 ControlPc;
|
|
||||||
ULONG64 ImageBase;
|
|
||||||
PRUNTIME_FUNCTION FunctionEntry;
|
|
||||||
ULONG64 EstablisherFrame;
|
|
||||||
ULONG64 TargetIp;
|
|
||||||
PCONTEXT ContextRecord;
|
|
||||||
void (*LanguageHandler)(void);
|
|
||||||
PVOID HandlerData;
|
|
||||||
PUNWIND_HISTORY_TABLE HistoryTable;
|
|
||||||
ULONG ScopeIndex;
|
|
||||||
ULONG Fill0;
|
|
||||||
} UndocumentedDispatcherContext;
|
|
||||||
#else
|
|
||||||
typedef void *UndocumentedDispatcherContext;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Another wild guess. */
|
|
||||||
extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow);
|
|
||||||
|
|
||||||
#if LJ_TARGET_X64 && defined(MINGW_SDK_INIT)
|
|
||||||
/* Workaround for broken MinGW64 declaration. */
|
|
||||||
VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx");
|
|
||||||
#define RtlUnwindEx RtlUnwindEx_FIXED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LJ_MSVC_EXCODE ((DWORD)0xe06d7363)
|
|
||||||
#define LJ_GCC_EXCODE ((DWORD)0x20474343)
|
|
||||||
|
|
||||||
#define LJ_EXCODE ((DWORD)0xe24c4a00)
|
|
||||||
#define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c))
|
|
||||||
#define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff)
|
|
||||||
#define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff))
|
|
||||||
|
|
||||||
/* Windows exception handler for interpreter frame. */
|
|
||||||
LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
|
|
||||||
void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch)
|
|
||||||
{
|
|
||||||
#if LJ_TARGET_X64
|
|
||||||
void *cf = f;
|
|
||||||
#else
|
|
||||||
void *cf = (char *)f - CFRAME_OFS_SEH;
|
|
||||||
#endif
|
|
||||||
lua_State *L = cframe_L(cf);
|
|
||||||
int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ?
|
|
||||||
LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN;
|
|
||||||
if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */
|
|
||||||
/* Unwind internal frames. */
|
|
||||||
err_unwind(L, cf, errcode);
|
|
||||||
} else {
|
|
||||||
void *cf2 = err_unwind(L, cf, 0);
|
|
||||||
if (cf2) { /* We catch it, so start unwinding the upper frames. */
|
|
||||||
if (rec->ExceptionCode == LJ_MSVC_EXCODE ||
|
|
||||||
rec->ExceptionCode == LJ_GCC_EXCODE) {
|
|
||||||
#if LJ_TARGET_WINDOWS
|
|
||||||
__DestructExceptionObject(rec, 1);
|
|
||||||
#endif
|
|
||||||
setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP));
|
|
||||||
} else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) {
|
|
||||||
/* Don't catch access violations etc. */
|
|
||||||
return 1; /* ExceptionContinueSearch */
|
|
||||||
}
|
|
||||||
#if LJ_TARGET_X64
|
|
||||||
/* Unwind the stack and call all handlers for all lower C frames
|
|
||||||
** (including ourselves) again with EH_UNWINDING set. Then set
|
|
||||||
** rsp = cf, rax = errcode and jump to the specified target.
|
|
||||||
*/
|
|
||||||
RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
|
|
||||||
lj_vm_unwind_ff_eh :
|
|
||||||
lj_vm_unwind_c_eh),
|
|
||||||
rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable);
|
|
||||||
/* RtlUnwindEx should never return. */
|
|
||||||
#else
|
|
||||||
UNUSED(ctx);
|
|
||||||
UNUSED(dispatch);
|
|
||||||
/* Call all handlers for all lower C frames (including ourselves) again
|
|
||||||
** with EH_UNWINDING set. Then call the specified function, passing cf
|
|
||||||
** and errcode.
|
|
||||||
*/
|
|
||||||
lj_vm_rtlunwind(cf, (void *)rec,
|
|
||||||
(cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ?
|
|
||||||
(void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode);
|
|
||||||
/* lj_vm_rtlunwind does not return. */
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1; /* ExceptionContinueSearch */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Raise Windows exception. */
|
|
||||||
static void err_raise_ext(int errcode)
|
|
||||||
{
|
|
||||||
RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* -- Error handling ------------------------------------------------------ */
|
/* -- Error handling ------------------------------------------------------ */
|
||||||
@ -504,22 +518,23 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode)
|
|||||||
{
|
{
|
||||||
global_State *g = G(L);
|
global_State *g = G(L);
|
||||||
lj_trace_abort(g);
|
lj_trace_abort(g);
|
||||||
setmref(g->jit_base, NULL);
|
|
||||||
L->status = LUA_OK;
|
L->status = LUA_OK;
|
||||||
#if LJ_UNWIND_EXT
|
#if LJ_UNWIND_EXT
|
||||||
err_raise_ext(errcode);
|
err_raise_ext(g, errcode);
|
||||||
/*
|
/*
|
||||||
** A return from this function signals a corrupt C stack that cannot be
|
** A return from this function signals a corrupt C stack that cannot be
|
||||||
** unwound. We have no choice but to call the panic function and exit.
|
** unwound. We have no choice but to call the panic function and exit.
|
||||||
**
|
**
|
||||||
** Usually this is caused by a C function without unwind information.
|
** Usually this is caused by a C function without unwind information.
|
||||||
** This should never happen on x64, but may happen if you've manually
|
** This may happen if you've manually enabled LUAJIT_UNWIND_EXTERNAL
|
||||||
** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every*
|
** and forgot to recompile *every* non-C++ file with -funwind-tables.
|
||||||
** non-C++ file with -funwind-tables.
|
|
||||||
*/
|
*/
|
||||||
if (G(L)->panic)
|
if (G(L)->panic)
|
||||||
G(L)->panic(L);
|
G(L)->panic(L);
|
||||||
#else
|
#else
|
||||||
|
#if LJ_HASJIT
|
||||||
|
setmref(g->jit_base, NULL);
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
void *cf = err_unwind(L, NULL, errcode);
|
void *cf = err_unwind(L, NULL, errcode);
|
||||||
if (cframe_unwind_ff(cf))
|
if (cframe_unwind_ff(cf))
|
||||||
|
Loading…
Reference in New Issue
Block a user