diff options
Diffstat (limited to 'src/lj_err.c')
-rw-r--r-- | src/lj_err.c | 714 |
1 files changed, 514 insertions, 200 deletions
diff --git a/src/lj_err.c b/src/lj_err.c index 4a2d6bbd..6e50cbee 100644 --- a/src/lj_err.c +++ b/src/lj_err.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include "lj_ff.h" | 16 | #include "lj_ff.h" |
17 | #include "lj_trace.h" | 17 | #include "lj_trace.h" |
18 | #include "lj_vm.h" | 18 | #include "lj_vm.h" |
19 | #include "lj_strfmt.h" | ||
19 | 20 | ||
20 | /* | 21 | /* |
21 | ** LuaJIT can either use internal or external frame unwinding: | 22 | ** LuaJIT can either use internal or external frame unwinding: |
@@ -28,12 +29,18 @@ | |||
28 | ** Pros and Cons: | 29 | ** Pros and Cons: |
29 | ** | 30 | ** |
30 | ** - 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 |
31 | ** 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 |
32 | ** 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. | ||
33 | ** | 36 | ** |
34 | ** - INT is faster when actually throwing errors (but this happens rarely). | 37 | ** - INT is faster when actually throwing errors, but this happens rarely. |
35 | ** Setting up error handlers is zero-cost in any case. | 38 | ** Setting up error handlers is zero-cost in any case. |
36 | ** | 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 | ** | ||
37 | ** - EXT provides full interoperability with C++ exceptions. You can throw | 44 | ** - EXT provides full interoperability with C++ exceptions. You can throw |
38 | ** 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. |
39 | ** C++ destructors are called as needed. C++ exceptions caught by pcall | 46 | ** C++ destructors are called as needed. C++ exceptions caught by pcall |
@@ -45,27 +52,38 @@ | |||
45 | ** the wrapper function feature. Lua errors thrown through C++ frames | 52 | ** the wrapper function feature. Lua errors thrown through C++ frames |
46 | ** 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. |
47 | ** | 54 | ** |
48 | ** EXT is the default on x64 systems, INT is the default on all other systems. | 55 | ** - EXT can handle errors from internal helper functions that are called |
56 | ** from JIT-compiled code (except for Windows/x86 and 32 bit ARM). | ||
57 | ** INT has no choice but to call the panic handler, if this happens. | ||
58 | ** Note: this is mainly relevant for out-of-memory errors. | ||
59 | ** | ||
60 | ** EXT is the default on all systems where the toolchain produces unwind | ||
61 | ** tables by default (*). This is hard-coded and/or detected in src/Makefile. | ||
62 | ** You can thwart the detection with: TARGET_XCFLAGS=-DLUAJIT_UNWIND_INTERNAL | ||
63 | ** | ||
64 | ** INT is the default on all other systems. | ||
65 | ** | ||
66 | ** EXT can be manually enabled for toolchains that are able to produce | ||
67 | ** conforming unwind tables: | ||
68 | ** "TARGET_XCFLAGS=-funwind-tables -DLUAJIT_UNWIND_EXTERNAL" | ||
69 | ** As explained above, *all* C code used directly or indirectly by LuaJIT | ||
70 | ** must be compiled with -funwind-tables (or -fexceptions). C++ code must | ||
71 | ** *not* be compiled with -fno-exceptions. | ||
72 | ** | ||
73 | ** If you're unsure whether error handling inside the VM works correctly, | ||
74 | ** try running this and check whether it prints "OK": | ||
49 | ** | 75 | ** |
50 | ** EXT can be manually enabled on POSIX systems using GCC and DWARF2 stack | 76 | ** luajit -e "print(select(2, load('OK')):match('OK'))" |
51 | ** unwinding with -DLUAJIT_UNWIND_EXTERNAL. *All* C code must be compiled | ||
52 | ** with -funwind-tables (or -fexceptions). This includes LuaJIT itself (set | ||
53 | ** TARGET_CFLAGS), all of your C/Lua binding code, all loadable C modules | ||
54 | ** and all C libraries that have callbacks which may be used to call back | ||
55 | ** into Lua. C++ code must *not* be compiled with -fno-exceptions. | ||
56 | ** | 77 | ** |
57 | ** EXT cannot be enabled on WIN32 since system exceptions use code-driven SEH. | 78 | ** (*) Originally, toolchains only generated unwind tables for C++ code. For |
58 | ** EXT is mandatory on WIN64 since the calling convention has an abundance | 79 | ** interoperability reasons, this can be manually enabled for plain C code, |
59 | ** of callee-saved registers (rbx, rbp, rsi, rdi, r12-r15, xmm6-xmm15). | 80 | ** too (with -funwind-tables). With the introduction of the x64 architecture, |
60 | ** The POSIX/x64 interpreter only saves r12/r13 for INT (e.g. PS4). | 81 | ** the corresponding POSIX and Windows ABIs mandated unwind tables for all |
82 | ** code. Over the following years most desktop and server platforms have | ||
83 | ** enabled unwind tables by default on all architectures. OTOH mobile and | ||
84 | ** embedded platforms do not consistently mandate unwind tables. | ||
61 | */ | 85 | */ |
62 | 86 | ||
63 | #if defined(__GNUC__) && (LJ_TARGET_X64 || defined(LUAJIT_UNWIND_EXTERNAL)) && !LJ_NO_UNWIND | ||
64 | #define LJ_UNWIND_EXT 1 | ||
65 | #elif LJ_TARGET_X64 && LJ_TARGET_WINDOWS | ||
66 | #define LJ_UNWIND_EXT 1 | ||
67 | #endif | ||
68 | |||
69 | /* -- Error messages ------------------------------------------------------ */ | 87 | /* -- Error messages ------------------------------------------------------ */ |
70 | 88 | ||
71 | /* Error message strings. */ | 89 | /* Error message strings. */ |
@@ -98,14 +116,14 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
98 | TValue *top = restorestack(L, -nres); | 116 | TValue *top = restorestack(L, -nres); |
99 | if (frame < top) { /* Frame reached? */ | 117 | if (frame < top) { /* Frame reached? */ |
100 | if (errcode) { | 118 | if (errcode) { |
101 | L->cframe = cframe_prev(cf); | ||
102 | L->base = frame+1; | 119 | L->base = frame+1; |
120 | L->cframe = cframe_prev(cf); | ||
103 | unwindstack(L, top); | 121 | unwindstack(L, top); |
104 | } | 122 | } |
105 | return cf; | 123 | return cf; |
106 | } | 124 | } |
107 | } | 125 | } |
108 | if (frame <= tvref(L->stack)) | 126 | if (frame <= tvref(L->stack)+LJ_FR2) |
109 | break; | 127 | break; |
110 | switch (frame_typep(frame)) { | 128 | switch (frame_typep(frame)) { |
111 | case FRAME_LUA: /* Lua frame. */ | 129 | case FRAME_LUA: /* Lua frame. */ |
@@ -113,14 +131,12 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
113 | frame = frame_prevl(frame); | 131 | frame = frame_prevl(frame); |
114 | break; | 132 | break; |
115 | case FRAME_C: /* C frame. */ | 133 | case FRAME_C: /* C frame. */ |
116 | #if LJ_HASFFI | ||
117 | unwind_c: | 134 | unwind_c: |
118 | #endif | ||
119 | #if LJ_UNWIND_EXT | 135 | #if LJ_UNWIND_EXT |
120 | if (errcode) { | 136 | if (errcode) { |
121 | L->cframe = cframe_prev(cf); | ||
122 | L->base = frame_prevd(frame) + 1; | 137 | L->base = frame_prevd(frame) + 1; |
123 | unwindstack(L, frame); | 138 | L->cframe = cframe_prev(cf); |
139 | unwindstack(L, frame - LJ_FR2); | ||
124 | } else if (cf != stopcf) { | 140 | } else if (cf != stopcf) { |
125 | cf = cframe_prev(cf); | 141 | cf = cframe_prev(cf); |
126 | frame = frame_prevd(frame); | 142 | frame = frame_prevd(frame); |
@@ -143,16 +159,14 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
143 | return cf; | 159 | return cf; |
144 | } | 160 | } |
145 | if (errcode) { | 161 | if (errcode) { |
146 | L->cframe = cframe_prev(cf); | ||
147 | L->base = frame_prevd(frame) + 1; | 162 | L->base = frame_prevd(frame) + 1; |
148 | unwindstack(L, frame); | 163 | L->cframe = cframe_prev(cf); |
164 | unwindstack(L, frame - LJ_FR2); | ||
149 | } | 165 | } |
150 | return cf; | 166 | return cf; |
151 | case FRAME_CONT: /* Continuation frame. */ | 167 | case FRAME_CONT: /* Continuation frame. */ |
152 | #if LJ_HASFFI | 168 | if (frame_iscont_fficb(frame)) |
153 | if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK) | ||
154 | goto unwind_c; | 169 | goto unwind_c; |
155 | #endif | ||
156 | /* fallthrough */ | 170 | /* fallthrough */ |
157 | case FRAME_VARG: /* Vararg frame. */ | 171 | case FRAME_VARG: /* Vararg frame. */ |
158 | frame = frame_prevd(frame); | 172 | frame = frame_prevd(frame); |
@@ -166,8 +180,8 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
166 | } | 180 | } |
167 | if (frame_typep(frame) == FRAME_PCALL) | 181 | if (frame_typep(frame) == FRAME_PCALL) |
168 | hook_leave(G(L)); | 182 | hook_leave(G(L)); |
169 | L->cframe = cf; | ||
170 | L->base = frame_prevd(frame) + 1; | 183 | L->base = frame_prevd(frame) + 1; |
184 | L->cframe = cf; | ||
171 | unwindstack(L, L->base); | 185 | unwindstack(L, L->base); |
172 | } | 186 | } |
173 | return (void *)((intptr_t)cf | CFRAME_UNWIND_FF); | 187 | return (void *)((intptr_t)cf | CFRAME_UNWIND_FF); |
@@ -175,8 +189,8 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
175 | } | 189 | } |
176 | /* No C frame. */ | 190 | /* No C frame. */ |
177 | if (errcode) { | 191 | if (errcode) { |
192 | L->base = tvref(L->stack)+1+LJ_FR2; | ||
178 | L->cframe = NULL; | 193 | L->cframe = NULL; |
179 | L->base = tvref(L->stack)+1; | ||
180 | unwindstack(L, L->base); | 194 | unwindstack(L, L->base); |
181 | if (G(L)->panic) | 195 | if (G(L)->panic) |
182 | G(L)->panic(L); | 196 | G(L)->panic(L); |
@@ -187,33 +201,206 @@ static void *err_unwind(lua_State *L, void *stopcf, int errcode) | |||
187 | 201 | ||
188 | /* -- External frame unwinding -------------------------------------------- */ | 202 | /* -- External frame unwinding -------------------------------------------- */ |
189 | 203 | ||
190 | #if defined(__GNUC__) && !LJ_NO_UNWIND && !LJ_ABI_WIN | 204 | #if LJ_ABI_WIN |
191 | 205 | ||
192 | /* | 206 | /* |
193 | ** We have to use our own definitions instead of the mandatory (!) unwind.h, | 207 | ** Someone in Redmond owes me several days of my life. A lot of this is |
194 | ** since various OS, distros and compilers mess up the header installation. | 208 | ** undocumented or just plain wrong on MSDN. Some of it can be gathered |
209 | ** from 3rd party docs or must be found by trial-and-error. They really | ||
210 | ** don't want you to write your own language-specific exception handler | ||
211 | ** or to interact gracefully with MSVC. :-( | ||
212 | ** | ||
213 | ** Apparently MSVC doesn't call C++ destructors for foreign exceptions | ||
214 | ** unless you compile your C++ code with /EHa. Unfortunately this means | ||
215 | ** catch (...) also catches things like access violations. The use of | ||
216 | ** _set_se_translator doesn't really help, because it requires /EHa, too. | ||
195 | */ | 217 | */ |
196 | 218 | ||
197 | typedef struct _Unwind_Exception | 219 | #define WIN32_LEAN_AND_MEAN |
220 | #include <windows.h> | ||
221 | |||
222 | #if LJ_TARGET_X86 | ||
223 | typedef void *UndocumentedDispatcherContext; /* Unused on x86. */ | ||
224 | #else | ||
225 | /* Taken from: http://www.nynaeve.net/?p=99 */ | ||
226 | typedef struct UndocumentedDispatcherContext { | ||
227 | ULONG64 ControlPc; | ||
228 | ULONG64 ImageBase; | ||
229 | PRUNTIME_FUNCTION FunctionEntry; | ||
230 | ULONG64 EstablisherFrame; | ||
231 | ULONG64 TargetIp; | ||
232 | PCONTEXT ContextRecord; | ||
233 | void (*LanguageHandler)(void); | ||
234 | PVOID HandlerData; | ||
235 | PUNWIND_HISTORY_TABLE HistoryTable; | ||
236 | ULONG ScopeIndex; | ||
237 | ULONG Fill0; | ||
238 | } UndocumentedDispatcherContext; | ||
239 | #endif | ||
240 | |||
241 | /* Another wild guess. */ | ||
242 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | ||
243 | |||
244 | #if LJ_TARGET_X64 && defined(MINGW_SDK_INIT) | ||
245 | /* Workaround for broken MinGW64 declaration. */ | ||
246 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | ||
247 | #define RtlUnwindEx RtlUnwindEx_FIXED | ||
248 | #endif | ||
249 | |||
250 | #define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) | ||
251 | #define LJ_GCC_EXCODE ((DWORD)0x20474343) | ||
252 | |||
253 | #define LJ_EXCODE ((DWORD)0xe24c4a00) | ||
254 | #define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) | ||
255 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | ||
256 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) | ||
257 | |||
258 | /* Windows exception handler for interpreter frame. */ | ||
259 | LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec, | ||
260 | void *f, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | ||
198 | { | 261 | { |
199 | uint64_t exclass; | 262 | #if LJ_TARGET_X86 |
200 | void (*excleanup)(int, struct _Unwind_Exception *); | 263 | void *cf = (char *)f - CFRAME_OFS_SEH; |
201 | uintptr_t p1, p2; | 264 | #else |
202 | } __attribute__((__aligned__)) _Unwind_Exception; | 265 | void *cf = f; |
266 | #endif | ||
267 | lua_State *L = cframe_L(cf); | ||
268 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? | ||
269 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; | ||
270 | if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ | ||
271 | /* Unwind internal frames. */ | ||
272 | err_unwind(L, cf, errcode); | ||
273 | } else { | ||
274 | void *cf2 = err_unwind(L, cf, 0); | ||
275 | if (cf2) { /* We catch it, so start unwinding the upper frames. */ | ||
276 | if (rec->ExceptionCode == LJ_MSVC_EXCODE || | ||
277 | rec->ExceptionCode == LJ_GCC_EXCODE) { | ||
278 | #if !LJ_TARGET_CYGWIN | ||
279 | __DestructExceptionObject(rec, 1); | ||
280 | #endif | ||
281 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); | ||
282 | } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { | ||
283 | /* Don't catch access violations etc. */ | ||
284 | return 1; /* ExceptionContinueSearch */ | ||
285 | } | ||
286 | #if LJ_TARGET_X86 | ||
287 | UNUSED(ctx); | ||
288 | UNUSED(dispatch); | ||
289 | /* Call all handlers for all lower C frames (including ourselves) again | ||
290 | ** with EH_UNWINDING set. Then call the specified function, passing cf | ||
291 | ** and errcode. | ||
292 | */ | ||
293 | lj_vm_rtlunwind(cf, (void *)rec, | ||
294 | (cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
295 | (void *)lj_vm_unwind_ff : (void *)lj_vm_unwind_c, errcode); | ||
296 | /* lj_vm_rtlunwind does not return. */ | ||
297 | #else | ||
298 | /* Unwind the stack and call all handlers for all lower C frames | ||
299 | ** (including ourselves) again with EH_UNWINDING set. Then set | ||
300 | ** stack pointer = cf, result = errcode and jump to the specified target. | ||
301 | */ | ||
302 | RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
303 | lj_vm_unwind_ff_eh : | ||
304 | lj_vm_unwind_c_eh), | ||
305 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); | ||
306 | /* RtlUnwindEx should never return. */ | ||
307 | #endif | ||
308 | } | ||
309 | } | ||
310 | return 1; /* ExceptionContinueSearch */ | ||
311 | } | ||
312 | |||
313 | #if LJ_UNWIND_JIT | ||
314 | |||
315 | #if LJ_TARGET_X64 | ||
316 | #define CONTEXT_REG_PC Rip | ||
317 | #elif LJ_TARGET_ARM64 | ||
318 | #define CONTEXT_REG_PC Pc | ||
319 | #else | ||
320 | #error "NYI: Windows arch-specific unwinder for JIT-compiled code" | ||
321 | #endif | ||
322 | |||
323 | /* Windows unwinder for JIT-compiled code. */ | ||
324 | static void err_unwind_win_jit(global_State *g, int errcode) | ||
325 | { | ||
326 | CONTEXT ctx; | ||
327 | UNWIND_HISTORY_TABLE hist; | ||
328 | |||
329 | memset(&hist, 0, sizeof(hist)); | ||
330 | RtlCaptureContext(&ctx); | ||
331 | while (1) { | ||
332 | DWORD64 frame, base, addr = ctx.CONTEXT_REG_PC; | ||
333 | void *hdata; | ||
334 | PRUNTIME_FUNCTION func = RtlLookupFunctionEntry(addr, &base, &hist); | ||
335 | if (!func) { /* Found frame without .pdata: must be JIT-compiled code. */ | ||
336 | ExitNo exitno; | ||
337 | uintptr_t stub = lj_trace_unwind(G2J(g), (uintptr_t)(addr - sizeof(MCode)), &exitno); | ||
338 | if (stub) { /* Jump to side exit to unwind the trace. */ | ||
339 | ctx.CONTEXT_REG_PC = stub; | ||
340 | G2J(g)->exitcode = errcode; | ||
341 | RtlRestoreContext(&ctx, NULL); /* Does not return. */ | ||
342 | } | ||
343 | break; | ||
344 | } | ||
345 | RtlVirtualUnwind(UNW_FLAG_NHANDLER, base, addr, func, | ||
346 | &ctx, &hdata, &frame, NULL); | ||
347 | if (!addr) break; | ||
348 | } | ||
349 | /* Unwinding failed, if we end up here. */ | ||
350 | } | ||
351 | #endif | ||
352 | |||
353 | /* Raise Windows exception. */ | ||
354 | static void err_raise_ext(global_State *g, int errcode) | ||
355 | { | ||
356 | #if LJ_UNWIND_JIT | ||
357 | if (tvref(g->jit_base)) { | ||
358 | err_unwind_win_jit(g, errcode); | ||
359 | return; /* Unwinding failed. */ | ||
360 | } | ||
361 | #elif LJ_HASJIT | ||
362 | /* Cannot catch on-trace errors for Windows/x86 SEH. Unwind to interpreter. */ | ||
363 | setmref(g->jit_base, NULL); | ||
364 | #endif | ||
365 | UNUSED(g); | ||
366 | RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); | ||
367 | } | ||
368 | |||
369 | #elif !LJ_NO_UNWIND && (defined(__GNUC__) || defined(__clang__)) | ||
370 | |||
371 | /* | ||
372 | ** We have to use our own definitions instead of the mandatory (!) unwind.h, | ||
373 | ** since various OS, distros and compilers mess up the header installation. | ||
374 | */ | ||
203 | 375 | ||
204 | typedef struct _Unwind_Context _Unwind_Context; | 376 | typedef struct _Unwind_Context _Unwind_Context; |
205 | 377 | ||
206 | #define _URC_OK 0 | 378 | #define _URC_OK 0 |
379 | #define _URC_FATAL_PHASE2_ERROR 2 | ||
207 | #define _URC_FATAL_PHASE1_ERROR 3 | 380 | #define _URC_FATAL_PHASE1_ERROR 3 |
208 | #define _URC_HANDLER_FOUND 6 | 381 | #define _URC_HANDLER_FOUND 6 |
209 | #define _URC_INSTALL_CONTEXT 7 | 382 | #define _URC_INSTALL_CONTEXT 7 |
210 | #define _URC_CONTINUE_UNWIND 8 | 383 | #define _URC_CONTINUE_UNWIND 8 |
211 | #define _URC_FAILURE 9 | 384 | #define _URC_FAILURE 9 |
212 | 385 | ||
386 | #define LJ_UEXCLASS 0x4c55414a49543200ULL /* LUAJIT2\0 */ | ||
387 | #define LJ_UEXCLASS_MAKE(c) (LJ_UEXCLASS | (uint64_t)(c)) | ||
388 | #define LJ_UEXCLASS_CHECK(cl) (((cl) ^ LJ_UEXCLASS) <= 0xff) | ||
389 | #define LJ_UEXCLASS_ERRCODE(cl) ((int)((cl) & 0xff)) | ||
390 | |||
213 | #if !LJ_TARGET_ARM | 391 | #if !LJ_TARGET_ARM |
214 | 392 | ||
393 | typedef struct _Unwind_Exception | ||
394 | { | ||
395 | uint64_t exclass; | ||
396 | void (*excleanup)(int, struct _Unwind_Exception *); | ||
397 | uintptr_t p1, p2; | ||
398 | } __attribute__((__aligned__)) _Unwind_Exception; | ||
399 | #define UNWIND_EXCEPTION_TYPE _Unwind_Exception | ||
400 | |||
215 | extern uintptr_t _Unwind_GetCFA(_Unwind_Context *); | 401 | extern uintptr_t _Unwind_GetCFA(_Unwind_Context *); |
216 | extern void _Unwind_SetGR(_Unwind_Context *, int, uintptr_t); | 402 | extern void _Unwind_SetGR(_Unwind_Context *, int, uintptr_t); |
403 | extern uintptr_t _Unwind_GetIP(_Unwind_Context *); | ||
217 | extern void _Unwind_SetIP(_Unwind_Context *, uintptr_t); | 404 | extern void _Unwind_SetIP(_Unwind_Context *, uintptr_t); |
218 | extern void _Unwind_DeleteException(_Unwind_Exception *); | 405 | extern void _Unwind_DeleteException(_Unwind_Exception *); |
219 | extern int _Unwind_RaiseException(_Unwind_Exception *); | 406 | extern int _Unwind_RaiseException(_Unwind_Exception *); |
@@ -223,11 +410,6 @@ extern int _Unwind_RaiseException(_Unwind_Exception *); | |||
223 | #define _UA_HANDLER_FRAME 4 | 410 | #define _UA_HANDLER_FRAME 4 |
224 | #define _UA_FORCE_UNWIND 8 | 411 | #define _UA_FORCE_UNWIND 8 |
225 | 412 | ||
226 | #define LJ_UEXCLASS 0x4c55414a49543200ULL /* LUAJIT2\0 */ | ||
227 | #define LJ_UEXCLASS_MAKE(c) (LJ_UEXCLASS | (uint64_t)(c)) | ||
228 | #define LJ_UEXCLASS_CHECK(cl) (((cl) ^ LJ_UEXCLASS) <= 0xff) | ||
229 | #define LJ_UEXCLASS_ERRCODE(cl) ((int)((cl) & 0xff)) | ||
230 | |||
231 | /* DWARF2 personality handler referenced from interpreter .eh_frame. */ | 413 | /* DWARF2 personality handler referenced from interpreter .eh_frame. */ |
232 | LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, | 414 | LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, |
233 | uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx) | 415 | uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx) |
@@ -236,7 +418,6 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, | |||
236 | lua_State *L; | 418 | lua_State *L; |
237 | if (version != 1) | 419 | if (version != 1) |
238 | return _URC_FATAL_PHASE1_ERROR; | 420 | return _URC_FATAL_PHASE1_ERROR; |
239 | UNUSED(uexclass); | ||
240 | cf = (void *)_Unwind_GetCFA(ctx); | 421 | cf = (void *)_Unwind_GetCFA(ctx); |
241 | L = cframe_L(cf); | 422 | L = cframe_L(cf); |
242 | if ((actions & _UA_SEARCH_PHASE)) { | 423 | if ((actions & _UA_SEARCH_PHASE)) { |
@@ -263,10 +444,10 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, | |||
263 | if ((actions & _UA_FORCE_UNWIND)) { | 444 | if ((actions & _UA_FORCE_UNWIND)) { |
264 | return _URC_CONTINUE_UNWIND; | 445 | return _URC_CONTINUE_UNWIND; |
265 | } else if (cf) { | 446 | } else if (cf) { |
447 | ASMFunction ip; | ||
266 | _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); | 448 | _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); |
267 | _Unwind_SetIP(ctx, (uintptr_t)(cframe_unwind_ff(cf) ? | 449 | ip = cframe_unwind_ff(cf) ? lj_vm_unwind_ff_eh : lj_vm_unwind_c_eh; |
268 | lj_vm_unwind_ff_eh : | 450 | _Unwind_SetIP(ctx, (uintptr_t)lj_ptr_strip(ip)); |
269 | lj_vm_unwind_c_eh)); | ||
270 | return _URC_INSTALL_CONTEXT; | 451 | return _URC_INSTALL_CONTEXT; |
271 | } | 452 | } |
272 | #if LJ_TARGET_X86ORX64 | 453 | #if LJ_TARGET_X86ORX64 |
@@ -284,27 +465,170 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions, | |||
284 | ** it on non-x64 because the interpreter restores all callee-saved regs. | 465 | ** it on non-x64 because the interpreter restores all callee-saved regs. |
285 | */ | 466 | */ |
286 | lj_err_throw(L, errcode); | 467 | lj_err_throw(L, errcode); |
468 | #if LJ_TARGET_X64 | ||
469 | #error "Broken build system -- only use the provided Makefiles!" | ||
470 | #endif | ||
287 | #endif | 471 | #endif |
288 | } | 472 | } |
289 | return _URC_CONTINUE_UNWIND; | 473 | return _URC_CONTINUE_UNWIND; |
290 | } | 474 | } |
291 | 475 | ||
292 | #if LJ_UNWIND_EXT | 476 | #if LJ_UNWIND_EXT && defined(LUA_USE_ASSERT) |
293 | static __thread _Unwind_Exception static_uex; | 477 | struct dwarf_eh_bases { void *tbase, *dbase, *func; }; |
478 | extern const void *_Unwind_Find_FDE(void *pc, struct dwarf_eh_bases *bases); | ||
294 | 479 | ||
295 | /* Raise DWARF2 exception. */ | 480 | /* Verify that external error handling actually has a chance to work. */ |
296 | static void err_raise_ext(int errcode) | 481 | void lj_err_verify(void) |
297 | { | 482 | { |
298 | static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); | 483 | #if !LJ_TARGET_OSX |
299 | static_uex.excleanup = NULL; | 484 | /* Check disabled on MacOS due to brilliant software engineering at Apple. */ |
300 | _Unwind_RaiseException(&static_uex); | 485 | struct dwarf_eh_bases ehb; |
486 | lj_assertX(_Unwind_Find_FDE((void *)lj_err_throw, &ehb), "broken build: external frame unwinding enabled, but missing -funwind-tables"); | ||
487 | #endif | ||
488 | /* Check disabled, because of broken Fedora/ARM64. See #722. | ||
489 | lj_assertX(_Unwind_Find_FDE((void *)_Unwind_RaiseException, &ehb), "broken build: external frame unwinding enabled, but system libraries have no unwind tables"); | ||
490 | */ | ||
301 | } | 491 | } |
302 | #endif | 492 | #endif |
303 | 493 | ||
494 | #if LJ_UNWIND_JIT | ||
495 | /* DWARF2 personality handler for JIT-compiled code. */ | ||
496 | static int err_unwind_jit(int version, int actions, | ||
497 | uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx) | ||
498 | { | ||
499 | /* NYI: FFI C++ exception interoperability. */ | ||
500 | if (version != 1 || !LJ_UEXCLASS_CHECK(uexclass)) | ||
501 | return _URC_FATAL_PHASE1_ERROR; | ||
502 | if ((actions & _UA_SEARCH_PHASE)) { | ||
503 | return _URC_HANDLER_FOUND; | ||
504 | } | ||
505 | if ((actions & _UA_CLEANUP_PHASE)) { | ||
506 | global_State *g = *(global_State **)(uex+1); | ||
507 | ExitNo exitno; | ||
508 | uintptr_t addr = _Unwind_GetIP(ctx); /* Return address _after_ call. */ | ||
509 | uintptr_t stub = lj_trace_unwind(G2J(g), addr - sizeof(MCode), &exitno); | ||
510 | lj_assertG(tvref(g->jit_base), "unexpected throw across mcode frame"); | ||
511 | if (stub) { /* Jump to side exit to unwind the trace. */ | ||
512 | G2J(g)->exitcode = LJ_UEXCLASS_ERRCODE(uexclass); | ||
513 | #ifdef LJ_TARGET_MIPS | ||
514 | _Unwind_SetGR(ctx, 4, stub); | ||
515 | _Unwind_SetGR(ctx, 5, exitno); | ||
516 | _Unwind_SetIP(ctx, (uintptr_t)(void *)lj_vm_unwind_stub); | ||
304 | #else | 517 | #else |
518 | _Unwind_SetIP(ctx, stub); | ||
519 | #endif | ||
520 | return _URC_INSTALL_CONTEXT; | ||
521 | } | ||
522 | return _URC_FATAL_PHASE2_ERROR; | ||
523 | } | ||
524 | return _URC_FATAL_PHASE1_ERROR; | ||
525 | } | ||
305 | 526 | ||
306 | extern void _Unwind_DeleteException(void *); | 527 | /* DWARF2 template frame info for JIT-compiled code. |
307 | extern int __gnu_unwind_frame (void *, _Unwind_Context *); | 528 | ** |
529 | ** After copying the template to the start of the mcode segment, | ||
530 | ** the frame handler function and the code size is patched. | ||
531 | ** The frame handler always installs a new context to jump to the exit, | ||
532 | ** so don't bother to add any unwind opcodes. | ||
533 | */ | ||
534 | static const uint8_t err_frame_jit_template[] = { | ||
535 | #if LJ_BE | ||
536 | 0,0,0, | ||
537 | #endif | ||
538 | LJ_64 ? 0x1c : 0x14, /* CIE length. */ | ||
539 | #if LJ_LE | ||
540 | 0,0,0, | ||
541 | #endif | ||
542 | 0,0,0,0, 1, 'z','P','R',0, /* CIE mark, CIE version, augmentation. */ | ||
543 | 1, LJ_64 ? 0x78 : 0x7c, LJ_TARGET_EHRAREG, /* Code/data align, RA. */ | ||
544 | #if LJ_64 | ||
545 | 10, 0, 0,0,0,0,0,0,0,0, 0x1b, /* Aug. data ABS handler, PCREL|SDATA4 code. */ | ||
546 | 0,0,0,0,0, /* Alignment. */ | ||
547 | #else | ||
548 | 6, 0, 0,0,0,0, 0x1b, /* Aug. data ABS handler, PCREL|SDATA4 code. */ | ||
549 | 0, /* Alignment. */ | ||
550 | #endif | ||
551 | #if LJ_BE | ||
552 | 0,0,0, | ||
553 | #endif | ||
554 | LJ_64 ? 0x14 : 0x10, /* FDE length. */ | ||
555 | 0,0,0, | ||
556 | LJ_64 ? 0x24 : 0x1c, /* CIE offset. */ | ||
557 | 0,0,0, | ||
558 | LJ_64 ? 0x14 : 0x10, /* Code offset. After Final FDE. */ | ||
559 | #if LJ_LE | ||
560 | 0,0,0, | ||
561 | #endif | ||
562 | 0,0,0,0, 0, 0,0,0, /* Code size, augmentation length, alignment. */ | ||
563 | #if LJ_64 | ||
564 | 0,0,0,0, /* Alignment. */ | ||
565 | #endif | ||
566 | 0,0,0,0 /* Final FDE. */ | ||
567 | }; | ||
568 | |||
569 | #define ERR_FRAME_JIT_OFS_HANDLER 0x12 | ||
570 | #define ERR_FRAME_JIT_OFS_FDE (LJ_64 ? 0x20 : 0x18) | ||
571 | #define ERR_FRAME_JIT_OFS_CODE_SIZE (LJ_64 ? 0x2c : 0x24) | ||
572 | #if LJ_TARGET_OSX | ||
573 | #define ERR_FRAME_JIT_OFS_REGISTER ERR_FRAME_JIT_OFS_FDE | ||
574 | #else | ||
575 | #define ERR_FRAME_JIT_OFS_REGISTER 0 | ||
576 | #endif | ||
577 | |||
578 | extern void __register_frame(const void *); | ||
579 | extern void __deregister_frame(const void *); | ||
580 | |||
581 | uint8_t *lj_err_register_mcode(void *base, size_t sz, uint8_t *info) | ||
582 | { | ||
583 | ASMFunction handler = (ASMFunction)err_unwind_jit; | ||
584 | memcpy(info, err_frame_jit_template, sizeof(err_frame_jit_template)); | ||
585 | #if LJ_ABI_PAUTH | ||
586 | #if LJ_TARGET_ARM64 | ||
587 | handler = ptrauth_auth_and_resign(handler, | ||
588 | ptrauth_key_function_pointer, 0, | ||
589 | ptrauth_key_process_independent_code, info + ERR_FRAME_JIT_OFS_HANDLER); | ||
590 | #else | ||
591 | #error "missing pointer authentication support for this architecture" | ||
592 | #endif | ||
593 | #endif | ||
594 | memcpy(info + ERR_FRAME_JIT_OFS_HANDLER, &handler, sizeof(handler)); | ||
595 | *(uint32_t *)(info + ERR_FRAME_JIT_OFS_CODE_SIZE) = | ||
596 | (uint32_t)(sz - sizeof(err_frame_jit_template) - (info - (uint8_t *)base)); | ||
597 | __register_frame(info + ERR_FRAME_JIT_OFS_REGISTER); | ||
598 | #ifdef LUA_USE_ASSERT | ||
599 | { | ||
600 | struct dwarf_eh_bases ehb; | ||
601 | lj_assertX(_Unwind_Find_FDE(info + sizeof(err_frame_jit_template)+1, &ehb), | ||
602 | "bad JIT unwind table registration"); | ||
603 | } | ||
604 | #endif | ||
605 | return info + sizeof(err_frame_jit_template); | ||
606 | } | ||
607 | |||
608 | void lj_err_deregister_mcode(void *base, size_t sz, uint8_t *info) | ||
609 | { | ||
610 | UNUSED(base); UNUSED(sz); | ||
611 | __deregister_frame(info + ERR_FRAME_JIT_OFS_REGISTER); | ||
612 | } | ||
613 | #endif | ||
614 | |||
615 | #else /* LJ_TARGET_ARM */ | ||
616 | |||
617 | #define _US_VIRTUAL_UNWIND_FRAME 0 | ||
618 | #define _US_UNWIND_FRAME_STARTING 1 | ||
619 | #define _US_ACTION_MASK 3 | ||
620 | #define _US_FORCE_UNWIND 8 | ||
621 | |||
622 | typedef struct _Unwind_Control_Block _Unwind_Control_Block; | ||
623 | #define UNWIND_EXCEPTION_TYPE _Unwind_Control_Block | ||
624 | |||
625 | struct _Unwind_Control_Block { | ||
626 | uint64_t exclass; | ||
627 | uint32_t misc[20]; | ||
628 | }; | ||
629 | |||
630 | extern int _Unwind_RaiseException(_Unwind_Control_Block *); | ||
631 | extern int __gnu_unwind_frame(_Unwind_Control_Block *, _Unwind_Context *); | ||
308 | extern int _Unwind_VRS_Set(_Unwind_Context *, int, uint32_t, int, void *); | 632 | extern int _Unwind_VRS_Set(_Unwind_Context *, int, uint32_t, int, void *); |
309 | extern int _Unwind_VRS_Get(_Unwind_Context *, int, uint32_t, int, void *); | 633 | extern int _Unwind_VRS_Get(_Unwind_Context *, int, uint32_t, int, void *); |
310 | 634 | ||
@@ -320,126 +644,98 @@ static inline void _Unwind_SetGR(_Unwind_Context *ctx, int r, uint32_t v) | |||
320 | _Unwind_VRS_Set(ctx, 0, r, 0, &v); | 644 | _Unwind_VRS_Set(ctx, 0, r, 0, &v); |
321 | } | 645 | } |
322 | 646 | ||
323 | #define _US_VIRTUAL_UNWIND_FRAME 0 | 647 | extern void lj_vm_unwind_ext(void); |
324 | #define _US_UNWIND_FRAME_STARTING 1 | ||
325 | #define _US_ACTION_MASK 3 | ||
326 | #define _US_FORCE_UNWIND 8 | ||
327 | 648 | ||
328 | /* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ | 649 | /* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ |
329 | LJ_FUNCA int lj_err_unwind_arm(int state, void *ucb, _Unwind_Context *ctx) | 650 | LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb, |
651 | _Unwind_Context *ctx) | ||
330 | { | 652 | { |
331 | void *cf = (void *)_Unwind_GetGR(ctx, 13); | 653 | void *cf = (void *)_Unwind_GetGR(ctx, 13); |
332 | lua_State *L = cframe_L(cf); | 654 | lua_State *L = cframe_L(cf); |
333 | if ((state & _US_ACTION_MASK) == _US_VIRTUAL_UNWIND_FRAME) { | 655 | int errcode; |
334 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); | 656 | |
657 | switch ((state & _US_ACTION_MASK)) { | ||
658 | case _US_VIRTUAL_UNWIND_FRAME: | ||
659 | if ((state & _US_FORCE_UNWIND)) break; | ||
335 | return _URC_HANDLER_FOUND; | 660 | return _URC_HANDLER_FOUND; |
336 | } | 661 | case _US_UNWIND_FRAME_STARTING: |
337 | if ((state&(_US_ACTION_MASK|_US_FORCE_UNWIND)) == _US_UNWIND_FRAME_STARTING) { | 662 | if (LJ_UEXCLASS_CHECK(ucb->exclass)) { |
338 | _Unwind_DeleteException(ucb); | 663 | errcode = LJ_UEXCLASS_ERRCODE(ucb->exclass); |
339 | _Unwind_SetGR(ctx, 15, (uint32_t)(void *)lj_err_throw); | 664 | } else { |
340 | _Unwind_SetGR(ctx, 0, (uint32_t)L); | 665 | errcode = LUA_ERRRUN; |
341 | _Unwind_SetGR(ctx, 1, (uint32_t)LUA_ERRRUN); | 666 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); |
667 | } | ||
668 | cf = err_unwind(L, cf, errcode); | ||
669 | if ((state & _US_FORCE_UNWIND) || cf == NULL) break; | ||
670 | _Unwind_SetGR(ctx, 15, (uint32_t)lj_vm_unwind_ext); | ||
671 | _Unwind_SetGR(ctx, 0, (uint32_t)ucb); | ||
672 | _Unwind_SetGR(ctx, 1, (uint32_t)errcode); | ||
673 | _Unwind_SetGR(ctx, 2, cframe_unwind_ff(cf) ? | ||
674 | (uint32_t)lj_vm_unwind_ff_eh : | ||
675 | (uint32_t)lj_vm_unwind_c_eh); | ||
342 | return _URC_INSTALL_CONTEXT; | 676 | return _URC_INSTALL_CONTEXT; |
677 | default: | ||
678 | return _URC_FAILURE; | ||
343 | } | 679 | } |
344 | if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) | 680 | if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) |
345 | return _URC_FAILURE; | 681 | return _URC_FAILURE; |
682 | #ifdef LUA_USE_ASSERT | ||
683 | /* We should never get here unless this is a forced unwind aka backtrace. */ | ||
684 | if (_Unwind_GetGR(ctx, 0) == 0xff33aa77) { | ||
685 | _Unwind_SetGR(ctx, 0, 0xff33aa88); | ||
686 | } | ||
687 | #endif | ||
346 | return _URC_CONTINUE_UNWIND; | 688 | return _URC_CONTINUE_UNWIND; |
347 | } | 689 | } |
348 | 690 | ||
349 | #endif | 691 | #if LJ_UNWIND_EXT && defined(LUA_USE_ASSERT) |
692 | typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *); | ||
693 | extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *); | ||
350 | 694 | ||
351 | #elif LJ_TARGET_X64 && LJ_ABI_WIN | 695 | static int err_verify_bt(_Unwind_Context *ctx, int *got) |
696 | { | ||
697 | if (_Unwind_GetGR(ctx, 0) == 0xff33aa88) { *got = 2; } | ||
698 | else if (*got == 0) { *got = 1; _Unwind_SetGR(ctx, 0, 0xff33aa77); } | ||
699 | return _URC_OK; | ||
700 | } | ||
701 | |||
702 | /* Verify that external error handling actually has a chance to work. */ | ||
703 | void lj_err_verify(void) | ||
704 | { | ||
705 | int got = 0; | ||
706 | _Unwind_Backtrace((_Unwind_Trace_Fn)err_verify_bt, &got); | ||
707 | lj_assertX(got == 2, "broken build: external frame unwinding enabled, but missing -funwind-tables"); | ||
708 | } | ||
709 | #endif | ||
352 | 710 | ||
353 | /* | 711 | /* |
354 | ** Someone in Redmond owes me several days of my life. A lot of this is | 712 | ** Note: LJ_UNWIND_JIT is not implemented for 32 bit ARM. |
355 | ** undocumented or just plain wrong on MSDN. Some of it can be gathered | ||
356 | ** from 3rd party docs or must be found by trial-and-error. They really | ||
357 | ** don't want you to write your own language-specific exception handler | ||
358 | ** or to interact gracefully with MSVC. :-( | ||
359 | ** | 713 | ** |
360 | ** Apparently MSVC doesn't call C++ destructors for foreign exceptions | 714 | ** The quirky ARM unwind API doesn't have __register_frame(). |
361 | ** unless you compile your C++ code with /EHa. Unfortunately this means | 715 | ** A potential workaround might involve _Unwind_Backtrace. |
362 | ** catch (...) also catches things like access violations. The use of | 716 | ** But most 32 bit ARM targets don't qualify for LJ_UNWIND_EXT, anyway, |
363 | ** _set_se_translator doesn't really help, because it requires /EHa, too. | 717 | ** since they are built without unwind tables by default. |
364 | */ | 718 | */ |
365 | 719 | ||
366 | #define WIN32_LEAN_AND_MEAN | 720 | #endif /* LJ_TARGET_ARM */ |
367 | #include <windows.h> | ||
368 | 721 | ||
369 | /* Taken from: http://www.nynaeve.net/?p=99 */ | ||
370 | typedef struct UndocumentedDispatcherContext { | ||
371 | ULONG64 ControlPc; | ||
372 | ULONG64 ImageBase; | ||
373 | PRUNTIME_FUNCTION FunctionEntry; | ||
374 | ULONG64 EstablisherFrame; | ||
375 | ULONG64 TargetIp; | ||
376 | PCONTEXT ContextRecord; | ||
377 | void (*LanguageHandler)(void); | ||
378 | PVOID HandlerData; | ||
379 | PUNWIND_HISTORY_TABLE HistoryTable; | ||
380 | ULONG ScopeIndex; | ||
381 | ULONG Fill0; | ||
382 | } UndocumentedDispatcherContext; | ||
383 | |||
384 | /* Another wild guess. */ | ||
385 | extern void __DestructExceptionObject(EXCEPTION_RECORD *rec, int nothrow); | ||
386 | |||
387 | #ifdef MINGW_SDK_INIT | ||
388 | /* Workaround for broken MinGW64 declaration. */ | ||
389 | VOID RtlUnwindEx_FIXED(PVOID,PVOID,PVOID,PVOID,PVOID,PVOID) asm("RtlUnwindEx"); | ||
390 | #define RtlUnwindEx RtlUnwindEx_FIXED | ||
391 | #endif | ||
392 | |||
393 | #define LJ_MSVC_EXCODE ((DWORD)0xe06d7363) | ||
394 | #define LJ_GCC_EXCODE ((DWORD)0x20474343) | ||
395 | 722 | ||
396 | #define LJ_EXCODE ((DWORD)0xe24c4a00) | 723 | #if LJ_UNWIND_EXT |
397 | #define LJ_EXCODE_MAKE(c) (LJ_EXCODE | (DWORD)(c)) | 724 | static __thread struct { |
398 | #define LJ_EXCODE_CHECK(cl) (((cl) ^ LJ_EXCODE) <= 0xff) | 725 | UNWIND_EXCEPTION_TYPE ex; |
399 | #define LJ_EXCODE_ERRCODE(cl) ((int)((cl) & 0xff)) | 726 | global_State *g; |
727 | } static_uex; | ||
400 | 728 | ||
401 | /* Win64 exception handler for interpreter frame. */ | 729 | /* Raise external exception. */ |
402 | LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, | 730 | static void err_raise_ext(global_State *g, int errcode) |
403 | void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) | ||
404 | { | 731 | { |
405 | lua_State *L = cframe_L(cf); | 732 | memset(&static_uex, 0, sizeof(static_uex)); |
406 | int errcode = LJ_EXCODE_CHECK(rec->ExceptionCode) ? | 733 | static_uex.ex.exclass = LJ_UEXCLASS_MAKE(errcode); |
407 | LJ_EXCODE_ERRCODE(rec->ExceptionCode) : LUA_ERRRUN; | 734 | static_uex.g = g; |
408 | if ((rec->ExceptionFlags & 6)) { /* EH_UNWINDING|EH_EXIT_UNWIND */ | 735 | _Unwind_RaiseException(&static_uex.ex); |
409 | /* Unwind internal frames. */ | ||
410 | err_unwind(L, cf, errcode); | ||
411 | } else { | ||
412 | void *cf2 = err_unwind(L, cf, 0); | ||
413 | if (cf2) { /* We catch it, so start unwinding the upper frames. */ | ||
414 | if (rec->ExceptionCode == LJ_MSVC_EXCODE || | ||
415 | rec->ExceptionCode == LJ_GCC_EXCODE) { | ||
416 | #if LJ_TARGET_WINDOWS | ||
417 | __DestructExceptionObject(rec, 1); | ||
418 | #endif | ||
419 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); | ||
420 | } else if (!LJ_EXCODE_CHECK(rec->ExceptionCode)) { | ||
421 | /* Don't catch access violations etc. */ | ||
422 | return ExceptionContinueSearch; | ||
423 | } | ||
424 | /* Unwind the stack and call all handlers for all lower C frames | ||
425 | ** (including ourselves) again with EH_UNWINDING set. Then set | ||
426 | ** rsp = cf, rax = errcode and jump to the specified target. | ||
427 | */ | ||
428 | RtlUnwindEx(cf, (void *)((cframe_unwind_ff(cf2) && errcode != LUA_YIELD) ? | ||
429 | lj_vm_unwind_ff_eh : | ||
430 | lj_vm_unwind_c_eh), | ||
431 | rec, (void *)(uintptr_t)errcode, ctx, dispatch->HistoryTable); | ||
432 | /* RtlUnwindEx should never return. */ | ||
433 | } | ||
434 | } | ||
435 | return ExceptionContinueSearch; | ||
436 | } | 736 | } |
437 | 737 | ||
438 | /* Raise Windows exception. */ | 738 | #endif |
439 | static void err_raise_ext(int errcode) | ||
440 | { | ||
441 | RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); | ||
442 | } | ||
443 | 739 | ||
444 | #endif | 740 | #endif |
445 | 741 | ||
@@ -450,22 +746,23 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode) | |||
450 | { | 746 | { |
451 | global_State *g = G(L); | 747 | global_State *g = G(L); |
452 | lj_trace_abort(g); | 748 | lj_trace_abort(g); |
453 | setgcrefnull(g->jit_L); | 749 | L->status = LUA_OK; |
454 | L->status = 0; | ||
455 | #if LJ_UNWIND_EXT | 750 | #if LJ_UNWIND_EXT |
456 | err_raise_ext(errcode); | 751 | err_raise_ext(g, errcode); |
457 | /* | 752 | /* |
458 | ** A return from this function signals a corrupt C stack that cannot be | 753 | ** A return from this function signals a corrupt C stack that cannot be |
459 | ** unwound. We have no choice but to call the panic function and exit. | 754 | ** unwound. We have no choice but to call the panic function and exit. |
460 | ** | 755 | ** |
461 | ** Usually this is caused by a C function without unwind information. | 756 | ** Usually this is caused by a C function without unwind information. |
462 | ** This should never happen on x64, but may happen if you've manually | 757 | ** This may happen if you've manually enabled LUAJIT_UNWIND_EXTERNAL |
463 | ** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every* | 758 | ** and forgot to recompile *every* non-C++ file with -funwind-tables. |
464 | ** non-C++ file with -funwind-tables. | ||
465 | */ | 759 | */ |
466 | if (G(L)->panic) | 760 | if (G(L)->panic) |
467 | G(L)->panic(L); | 761 | G(L)->panic(L); |
468 | #else | 762 | #else |
763 | #if LJ_HASJIT | ||
764 | setmref(g->jit_base, NULL); | ||
765 | #endif | ||
469 | { | 766 | { |
470 | void *cf = err_unwind(L, NULL, errcode); | 767 | void *cf = err_unwind(L, NULL, errcode); |
471 | if (cframe_unwind_ff(cf)) | 768 | if (cframe_unwind_ff(cf)) |
@@ -488,6 +785,10 @@ LJ_NOINLINE void lj_err_mem(lua_State *L) | |||
488 | { | 785 | { |
489 | if (L->status == LUA_ERRERR+1) /* Don't touch the stack during lua_open. */ | 786 | if (L->status == LUA_ERRERR+1) /* Don't touch the stack during lua_open. */ |
490 | lj_vm_unwind_c(L->cframe, LUA_ERRMEM); | 787 | lj_vm_unwind_c(L->cframe, LUA_ERRMEM); |
788 | if (LJ_HASJIT) { | ||
789 | TValue *base = tvref(G(L)->jit_base); | ||
790 | if (base) L->base = base; | ||
791 | } | ||
491 | if (curr_funcisL(L)) L->top = curr_topL(L); | 792 | if (curr_funcisL(L)) L->top = curr_topL(L); |
492 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM)); | 793 | setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRMEM)); |
493 | lj_err_throw(L, LUA_ERRMEM); | 794 | lj_err_throw(L, LUA_ERRMEM); |
@@ -496,7 +797,7 @@ LJ_NOINLINE void lj_err_mem(lua_State *L) | |||
496 | /* Find error function for runtime errors. Requires an extra stack traversal. */ | 797 | /* Find error function for runtime errors. Requires an extra stack traversal. */ |
497 | static ptrdiff_t finderrfunc(lua_State *L) | 798 | static ptrdiff_t finderrfunc(lua_State *L) |
498 | { | 799 | { |
499 | cTValue *frame = L->base-1, *bot = tvref(L->stack); | 800 | cTValue *frame = L->base-1, *bot = tvref(L->stack)+LJ_FR2; |
500 | void *cf = L->cframe; | 801 | void *cf = L->cframe; |
501 | while (frame > bot && cf) { | 802 | while (frame > bot && cf) { |
502 | while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ | 803 | while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ |
@@ -520,10 +821,8 @@ static ptrdiff_t finderrfunc(lua_State *L) | |||
520 | frame = frame_prevd(frame); | 821 | frame = frame_prevd(frame); |
521 | break; | 822 | break; |
522 | case FRAME_CONT: | 823 | case FRAME_CONT: |
523 | #if LJ_HASFFI | 824 | if (frame_iscont_fficb(frame)) |
524 | if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK) | ||
525 | cf = cframe_prev(cf); | 825 | cf = cframe_prev(cf); |
526 | #endif | ||
527 | frame = frame_prevd(frame); | 826 | frame = frame_prevd(frame); |
528 | break; | 827 | break; |
529 | case FRAME_CP: | 828 | case FRAME_CP: |
@@ -535,11 +834,11 @@ static ptrdiff_t finderrfunc(lua_State *L) | |||
535 | break; | 834 | break; |
536 | case FRAME_PCALL: | 835 | case FRAME_PCALL: |
537 | case FRAME_PCALLH: | 836 | case FRAME_PCALLH: |
538 | if (frame_ftsz(frame) >= (ptrdiff_t)(2*sizeof(TValue))) /* xpcall? */ | 837 | if (frame_func(frame_prevd(frame))->c.ffid == FF_xpcall) |
539 | return savestack(L, frame-1); /* Point to xpcall's errorfunc. */ | 838 | return savestack(L, frame_prevd(frame)+1); /* xpcall's errorfunc. */ |
540 | return 0; | 839 | return 0; |
541 | default: | 840 | default: |
542 | lua_assert(0); | 841 | lj_assertL(0, "bad frame type"); |
543 | return 0; | 842 | return 0; |
544 | } | 843 | } |
545 | } | 844 | } |
@@ -549,7 +848,7 @@ static ptrdiff_t finderrfunc(lua_State *L) | |||
549 | /* Runtime error. */ | 848 | /* Runtime error. */ |
550 | LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L) | 849 | LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L) |
551 | { | 850 | { |
552 | ptrdiff_t ef = finderrfunc(L); | 851 | ptrdiff_t ef = (LJ_HASJIT && tvref(G(L)->jit_base)) ? 0 : finderrfunc(L); |
553 | if (ef) { | 852 | if (ef) { |
554 | TValue *errfunc = restorestack(L, ef); | 853 | TValue *errfunc = restorestack(L, ef); |
555 | TValue *top = L->top; | 854 | TValue *top = L->top; |
@@ -559,22 +858,37 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L) | |||
559 | lj_err_throw(L, LUA_ERRERR); | 858 | lj_err_throw(L, LUA_ERRERR); |
560 | } | 859 | } |
561 | L->status = LUA_ERRERR; | 860 | L->status = LUA_ERRERR; |
562 | copyTV(L, top, top-1); | 861 | copyTV(L, top+LJ_FR2, top-1); |
563 | copyTV(L, top-1, errfunc); | 862 | copyTV(L, top-1, errfunc); |
863 | if (LJ_FR2) setnilV(top++); | ||
564 | L->top = top+1; | 864 | L->top = top+1; |
565 | lj_vm_call(L, top, 1+1); /* Stack: |errfunc|msg| -> |msg| */ | 865 | lj_vm_call(L, top, 1+1); /* Stack: |errfunc|msg| -> |msg| */ |
566 | } | 866 | } |
567 | lj_err_throw(L, LUA_ERRRUN); | 867 | lj_err_throw(L, LUA_ERRRUN); |
568 | } | 868 | } |
569 | 869 | ||
870 | #if LJ_HASJIT | ||
871 | LJ_NOINLINE void LJ_FASTCALL lj_err_trace(lua_State *L, int errcode) | ||
872 | { | ||
873 | if (errcode == LUA_ERRRUN) | ||
874 | lj_err_run(L); | ||
875 | else | ||
876 | lj_err_throw(L, errcode); | ||
877 | } | ||
878 | #endif | ||
879 | |||
570 | /* Formatted runtime error message. */ | 880 | /* Formatted runtime error message. */ |
571 | LJ_NORET LJ_NOINLINE static void err_msgv(lua_State *L, ErrMsg em, ...) | 881 | LJ_NORET LJ_NOINLINE static void err_msgv(lua_State *L, ErrMsg em, ...) |
572 | { | 882 | { |
573 | const char *msg; | 883 | const char *msg; |
574 | va_list argp; | 884 | va_list argp; |
575 | va_start(argp, em); | 885 | va_start(argp, em); |
886 | if (LJ_HASJIT) { | ||
887 | TValue *base = tvref(G(L)->jit_base); | ||
888 | if (base) L->base = base; | ||
889 | } | ||
576 | if (curr_funcisL(L)) L->top = curr_topL(L); | 890 | if (curr_funcisL(L)) L->top = curr_topL(L); |
577 | msg = lj_str_pushvf(L, err2msg(em), argp); | 891 | msg = lj_strfmt_pushvf(L, err2msg(em), argp); |
578 | va_end(argp); | 892 | va_end(argp); |
579 | lj_debug_addloc(L, msg, L->base-1, NULL); | 893 | lj_debug_addloc(L, msg, L->base-1, NULL); |
580 | lj_err_run(L); | 894 | lj_err_run(L); |
@@ -592,11 +906,11 @@ LJ_NOINLINE void lj_err_lex(lua_State *L, GCstr *src, const char *tok, | |||
592 | { | 906 | { |
593 | char buff[LUA_IDSIZE]; | 907 | char buff[LUA_IDSIZE]; |
594 | const char *msg; | 908 | const char *msg; |
595 | lj_debug_shortname(buff, src); | 909 | lj_debug_shortname(buff, src, line); |
596 | msg = lj_str_pushvf(L, err2msg(em), argp); | 910 | msg = lj_strfmt_pushvf(L, err2msg(em), argp); |
597 | msg = lj_str_pushf(L, "%s:%d: %s", buff, line, msg); | 911 | msg = lj_strfmt_pushf(L, "%s:%d: %s", buff, line, msg); |
598 | if (tok) | 912 | if (tok) |
599 | lj_str_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tok); | 913 | lj_strfmt_pushf(L, err2msg(LJ_ERR_XNEAR), msg, tok); |
600 | lj_err_throw(L, LUA_ERRSYNTAX); | 914 | lj_err_throw(L, LUA_ERRSYNTAX); |
601 | } | 915 | } |
602 | 916 | ||
@@ -635,8 +949,9 @@ LJ_NOINLINE void lj_err_optype_call(lua_State *L, TValue *o) | |||
635 | const BCIns *pc = cframe_Lpc(L); | 949 | const BCIns *pc = cframe_Lpc(L); |
636 | if (((ptrdiff_t)pc & FRAME_TYPE) != FRAME_LUA) { | 950 | if (((ptrdiff_t)pc & FRAME_TYPE) != FRAME_LUA) { |
637 | const char *tname = lj_typename(o); | 951 | const char *tname = lj_typename(o); |
952 | setframe_gc(o, obj2gco(L), LJ_TTHREAD); | ||
953 | if (LJ_FR2) o++; | ||
638 | setframe_pc(o, pc); | 954 | setframe_pc(o, pc); |
639 | setframe_gc(o, obj2gco(L)); | ||
640 | L->top = L->base = o+1; | 955 | L->top = L->base = o+1; |
641 | err_msgv(L, LJ_ERR_BADCALL, tname); | 956 | err_msgv(L, LJ_ERR_BADCALL, tname); |
642 | } | 957 | } |
@@ -646,28 +961,27 @@ LJ_NOINLINE void lj_err_optype_call(lua_State *L, TValue *o) | |||
646 | /* Error in context of caller. */ | 961 | /* Error in context of caller. */ |
647 | LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg) | 962 | LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg) |
648 | { | 963 | { |
649 | TValue *frame = L->base-1; | 964 | TValue *frame = NULL, *pframe = NULL; |
650 | TValue *pframe = NULL; | 965 | if (!(LJ_HASJIT && tvref(G(L)->jit_base))) { |
651 | if (frame_islua(frame)) { | 966 | frame = L->base-1; |
652 | pframe = frame_prevl(frame); | 967 | if (frame_islua(frame)) { |
653 | } else if (frame_iscont(frame)) { | 968 | pframe = frame_prevl(frame); |
969 | } else if (frame_iscont(frame)) { | ||
970 | if (frame_iscont_fficb(frame)) { | ||
971 | pframe = frame; | ||
972 | frame = NULL; | ||
973 | } else { | ||
974 | pframe = frame_prevd(frame); | ||
654 | #if LJ_HASFFI | 975 | #if LJ_HASFFI |
655 | if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK) { | 976 | /* Remove frame for FFI metamethods. */ |
656 | pframe = frame; | 977 | if (frame_func(frame)->c.ffid >= FF_ffi_meta___index && |
657 | frame = NULL; | 978 | frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) { |
658 | } else | 979 | L->base = pframe+1; |
980 | L->top = frame; | ||
981 | setcframe_pc(cframe_raw(L->cframe), frame_contpc(frame)); | ||
982 | } | ||
659 | #endif | 983 | #endif |
660 | { | ||
661 | pframe = frame_prevd(frame); | ||
662 | #if LJ_HASFFI | ||
663 | /* Remove frame for FFI metamethods. */ | ||
664 | if (frame_func(frame)->c.ffid >= FF_ffi_meta___index && | ||
665 | frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) { | ||
666 | L->base = pframe+1; | ||
667 | L->top = frame; | ||
668 | setcframe_pc(cframe_raw(L->cframe), frame_contpc(frame)); | ||
669 | } | 984 | } |
670 | #endif | ||
671 | } | 985 | } |
672 | } | 986 | } |
673 | lj_debug_addloc(L, msg, pframe, frame); | 987 | lj_debug_addloc(L, msg, pframe, frame); |
@@ -680,7 +994,7 @@ LJ_NOINLINE void lj_err_callerv(lua_State *L, ErrMsg em, ...) | |||
680 | const char *msg; | 994 | const char *msg; |
681 | va_list argp; | 995 | va_list argp; |
682 | va_start(argp, em); | 996 | va_start(argp, em); |
683 | msg = lj_str_pushvf(L, err2msg(em), argp); | 997 | msg = lj_strfmt_pushvf(L, err2msg(em), argp); |
684 | va_end(argp); | 998 | va_end(argp); |
685 | lj_err_callermsg(L, msg); | 999 | lj_err_callermsg(L, msg); |
686 | } | 1000 | } |
@@ -700,9 +1014,9 @@ LJ_NORET LJ_NOINLINE static void err_argmsg(lua_State *L, int narg, | |||
700 | if (narg < 0 && narg > LUA_REGISTRYINDEX) | 1014 | if (narg < 0 && narg > LUA_REGISTRYINDEX) |
701 | narg = (int)(L->top - L->base) + narg + 1; | 1015 | narg = (int)(L->top - L->base) + narg + 1; |
702 | if (ftype && ftype[3] == 'h' && --narg == 0) /* Check for "method". */ | 1016 | if (ftype && ftype[3] == 'h' && --narg == 0) /* Check for "method". */ |
703 | msg = lj_str_pushf(L, err2msg(LJ_ERR_BADSELF), fname, msg); | 1017 | msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_BADSELF), fname, msg); |
704 | else | 1018 | else |
705 | msg = lj_str_pushf(L, err2msg(LJ_ERR_BADARG), narg, fname, msg); | 1019 | msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_BADARG), narg, fname, msg); |
706 | lj_err_callermsg(L, msg); | 1020 | lj_err_callermsg(L, msg); |
707 | } | 1021 | } |
708 | 1022 | ||
@@ -712,7 +1026,7 @@ LJ_NOINLINE void lj_err_argv(lua_State *L, int narg, ErrMsg em, ...) | |||
712 | const char *msg; | 1026 | const char *msg; |
713 | va_list argp; | 1027 | va_list argp; |
714 | va_start(argp, em); | 1028 | va_start(argp, em); |
715 | msg = lj_str_pushvf(L, err2msg(em), argp); | 1029 | msg = lj_strfmt_pushvf(L, err2msg(em), argp); |
716 | va_end(argp); | 1030 | va_end(argp); |
717 | err_argmsg(L, narg, msg); | 1031 | err_argmsg(L, narg, msg); |
718 | } | 1032 | } |
@@ -742,7 +1056,7 @@ LJ_NOINLINE void lj_err_argtype(lua_State *L, int narg, const char *xname) | |||
742 | TValue *o = narg < 0 ? L->top + narg : L->base + narg-1; | 1056 | TValue *o = narg < 0 ? L->top + narg : L->base + narg-1; |
743 | tname = o < L->top ? lj_typename(o) : lj_obj_typename[0]; | 1057 | tname = o < L->top ? lj_typename(o) : lj_obj_typename[0]; |
744 | } | 1058 | } |
745 | msg = lj_str_pushf(L, err2msg(LJ_ERR_BADTYPE), xname, tname); | 1059 | msg = lj_strfmt_pushf(L, err2msg(LJ_ERR_BADTYPE), xname, tname); |
746 | err_argmsg(L, narg, msg); | 1060 | err_argmsg(L, narg, msg); |
747 | } | 1061 | } |
748 | 1062 | ||
@@ -792,7 +1106,7 @@ LUALIB_API int luaL_error(lua_State *L, const char *fmt, ...) | |||
792 | const char *msg; | 1106 | const char *msg; |
793 | va_list argp; | 1107 | va_list argp; |
794 | va_start(argp, fmt); | 1108 | va_start(argp, fmt); |
795 | msg = lj_str_pushvf(L, fmt, argp); | 1109 | msg = lj_strfmt_pushvf(L, fmt, argp); |
796 | va_end(argp); | 1110 | va_end(argp); |
797 | lj_err_callermsg(L, msg); | 1111 | lj_err_callermsg(L, msg); |
798 | return 0; /* unreachable */ | 1112 | return 0; /* unreachable */ |