aboutsummaryrefslogtreecommitdiff
path: root/src/lj_err.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_err.c')
-rw-r--r--src/lj_err.c247
1 files changed, 236 insertions, 11 deletions
diff --git a/src/lj_err.c b/src/lj_err.c
index ba0fac0a..9fc3adc7 100644
--- a/src/lj_err.c
+++ b/src/lj_err.c
@@ -52,6 +52,11 @@
52** the wrapper function feature. Lua errors thrown through C++ frames 52** the wrapper function feature. Lua errors thrown through C++ frames
53** 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.
54** 54**
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**
55** EXT is the default on all systems where the toolchain produces unwind 60** EXT is the default on all systems where the toolchain produces unwind
56** tables by default (*). This is hard-coded and/or detected in src/Makefile. 61** 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 62** You can thwart the detection with: TARGET_XCFLAGS=-DLUAJIT_UNWIND_INTERNAL
@@ -305,12 +310,59 @@ LJ_FUNCA int lj_err_unwind_win(EXCEPTION_RECORD *rec,
305 return 1; /* ExceptionContinueSearch */ 310 return 1; /* ExceptionContinueSearch */
306} 311}
307 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. */
324static 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 uintptr_t 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), 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
308/* Raise Windows exception. */ 353/* Raise Windows exception. */
309static void err_raise_ext(global_State *g, int errcode) 354static void err_raise_ext(global_State *g, int errcode)
310{ 355{
311#if LJ_HASJIT 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. */
312 setmref(g->jit_base, NULL); 363 setmref(g->jit_base, NULL);
313#endif 364#endif
365 UNUSED(g);
314 RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL); 366 RaiseException(LJ_EXCODE_MAKE(errcode), 1 /* EH_NONCONTINUABLE */, 0, NULL);
315} 367}
316 368
@@ -324,6 +376,7 @@ static void err_raise_ext(global_State *g, int errcode)
324typedef struct _Unwind_Context _Unwind_Context; 376typedef struct _Unwind_Context _Unwind_Context;
325 377
326#define _URC_OK 0 378#define _URC_OK 0
379#define _URC_FATAL_PHASE2_ERROR 2
327#define _URC_FATAL_PHASE1_ERROR 3 380#define _URC_FATAL_PHASE1_ERROR 3
328#define _URC_HANDLER_FOUND 6 381#define _URC_HANDLER_FOUND 6
329#define _URC_INSTALL_CONTEXT 7 382#define _URC_INSTALL_CONTEXT 7
@@ -343,9 +396,11 @@ typedef struct _Unwind_Exception
343 void (*excleanup)(int, struct _Unwind_Exception *); 396 void (*excleanup)(int, struct _Unwind_Exception *);
344 uintptr_t p1, p2; 397 uintptr_t p1, p2;
345} __attribute__((__aligned__)) _Unwind_Exception; 398} __attribute__((__aligned__)) _Unwind_Exception;
399#define UNWIND_EXCEPTION_TYPE _Unwind_Exception
346 400
347extern uintptr_t _Unwind_GetCFA(_Unwind_Context *); 401extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
348extern void _Unwind_SetGR(_Unwind_Context *, int, uintptr_t); 402extern void _Unwind_SetGR(_Unwind_Context *, int, uintptr_t);
403extern uintptr_t _Unwind_GetIP(_Unwind_Context *);
349extern void _Unwind_SetIP(_Unwind_Context *, uintptr_t); 404extern void _Unwind_SetIP(_Unwind_Context *, uintptr_t);
350extern void _Unwind_DeleteException(_Unwind_Exception *); 405extern void _Unwind_DeleteException(_Unwind_Exception *);
351extern int _Unwind_RaiseException(_Unwind_Exception *); 406extern int _Unwind_RaiseException(_Unwind_Exception *);
@@ -418,8 +473,130 @@ LJ_FUNCA int lj_err_unwind_dwarf(int version, int actions,
418 return _URC_CONTINUE_UNWIND; 473 return _URC_CONTINUE_UNWIND;
419} 474}
420 475
421#if LJ_UNWIND_EXT 476#if LJ_UNWIND_EXT && defined(LUA_USE_ASSERT)
422static __thread _Unwind_Exception static_uex; 477struct dwarf_eh_bases { void *tbase, *dbase, *func; };
478extern const void *_Unwind_Find_FDE(void *pc, struct dwarf_eh_bases *bases);
479
480/* Verify that external error handling actually has a chance to work. */
481void lj_err_verify(void)
482{
483 struct dwarf_eh_bases ehb;
484 lj_assertX(_Unwind_Find_FDE((void *)lj_err_throw, &ehb), "broken build: external frame unwinding enabled, but missing -funwind-tables");
485 lj_assertX(_Unwind_Find_FDE((void *)_Unwind_RaiseException, &ehb), "broken build: external frame unwinding enabled, but system libraries have no unwind tables");
486}
487#endif
488
489#if LJ_UNWIND_JIT
490/* DWARF2 personality handler for JIT-compiled code. */
491static int err_unwind_jit(int version, int actions,
492 uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx)
493{
494 /* NYI: FFI C++ exception interoperability. */
495 if (version != 1 || !LJ_UEXCLASS_CHECK(uexclass))
496 return _URC_FATAL_PHASE1_ERROR;
497 if ((actions & _UA_SEARCH_PHASE)) {
498 return _URC_HANDLER_FOUND;
499 }
500 if ((actions & _UA_CLEANUP_PHASE)) {
501 global_State *g = *(global_State **)(uex+1);
502 ExitNo exitno;
503 uintptr_t addr = _Unwind_GetIP(ctx); /* Return address _after_ call. */
504 uintptr_t stub = lj_trace_unwind(G2J(g), addr - sizeof(MCode), &exitno);
505 lj_assertG(tvref(g->jit_base), "unexpected throw across mcode frame");
506 if (stub) { /* Jump to side exit to unwind the trace. */
507 G2J(g)->exitcode = LJ_UEXCLASS_ERRCODE(uexclass);
508#ifdef LJ_TARGET_MIPS
509 _Unwind_SetGR(ctx, 4, stub);
510 _Unwind_SetGR(ctx, 5, exitno);
511 _Unwind_SetIP(ctx, (uintptr_t)(void *)lj_vm_unwind_stub);
512#else
513 _Unwind_SetIP(ctx, stub);
514#endif
515 return _URC_INSTALL_CONTEXT;
516 }
517 return _URC_FATAL_PHASE2_ERROR;
518 }
519 return _URC_FATAL_PHASE1_ERROR;
520}
521
522/* DWARF2 template frame info for JIT-compiled code.
523**
524** After copying the template to the start of the mcode segment,
525** the frame handler function and the code size is patched.
526** The frame handler always installs a new context to jump to the exit,
527** so don't bother to add any unwind opcodes.
528*/
529static const uint8_t err_frame_jit_template[] = {
530#if LJ_BE
531 0,0,0,
532#endif
533 LJ_64 ? 0x1c : 0x14, /* CIE length. */
534#if LJ_LE
535 0,0,0,
536#endif
537 0,0,0,0, 1, 'z','P','R',0, /* CIE mark, CIE version, augmentation. */
538 1, LJ_64 ? 0x78 : 0x7c, LJ_TARGET_EHRAREG, /* Code/data align, RA. */
539#if LJ_64
540 10, 0, 0,0,0,0,0,0,0,0, 0x1b, /* Aug. data ABS handler, PCREL|SDATA4 code. */
541 0,0,0,0,0, /* Alignment. */
542#else
543 6, 0, 0,0,0,0, 0x1b, /* Aug. data ABS handler, PCREL|SDATA4 code. */
544 0, /* Alignment. */
545#endif
546#if LJ_BE
547 0,0,0,
548#endif
549 LJ_64 ? 0x14 : 0x10, /* FDE length. */
550 0,0,0,
551 LJ_64 ? 0x24 : 0x1c, /* CIE offset. */
552 0,0,0,
553 LJ_64 ? 0x14 : 0x10, /* Code offset. After Final FDE. */
554#if LJ_LE
555 0,0,0,
556#endif
557 0,0,0,0, 0, 0,0,0, /* Code size, augmentation length, alignment. */
558#if LJ_64
559 0,0,0,0, /* Alignment. */
560#endif
561 0,0,0,0 /* Final FDE. */
562};
563
564#define ERR_FRAME_JIT_OFS_HANDLER 0x12
565#define ERR_FRAME_JIT_OFS_FDE (LJ_64 ? 0x20 : 0x18)
566#define ERR_FRAME_JIT_OFS_CODE_SIZE (LJ_64 ? 0x2c : 0x24)
567#if LJ_TARGET_OSX
568#define ERR_FRAME_JIT_OFS_REGISTER ERR_FRAME_JIT_OFS_FDE
569#else
570#define ERR_FRAME_JIT_OFS_REGISTER 0
571#endif
572
573extern void __register_frame(const void *);
574extern void __deregister_frame(const void *);
575
576uint8_t *lj_err_register_mcode(void *base, size_t sz, uint8_t *info)
577{
578 void **handler;
579 memcpy(info, err_frame_jit_template, sizeof(err_frame_jit_template));
580 handler = (void *)err_unwind_jit;
581 memcpy(info + ERR_FRAME_JIT_OFS_HANDLER, &handler, sizeof(handler));
582 *(uint32_t *)(info + ERR_FRAME_JIT_OFS_CODE_SIZE) =
583 (uint32_t)(sz - sizeof(err_frame_jit_template) - (info - (uint8_t *)base));
584 __register_frame(info + ERR_FRAME_JIT_OFS_REGISTER);
585#ifdef LUA_USE_ASSERT
586 {
587 struct dwarf_eh_bases ehb;
588 lj_assertX(_Unwind_Find_FDE(info + sizeof(err_frame_jit_template)+1, &ehb),
589 "bad JIT unwind table registration");
590 }
591#endif
592 return info + sizeof(err_frame_jit_template);
593}
594
595void lj_err_deregister_mcode(void *base, size_t sz, uint8_t *info)
596{
597 UNUSED(base); UNUSED(sz);
598 __deregister_frame(info + ERR_FRAME_JIT_OFS_REGISTER);
599}
423#endif 600#endif
424 601
425#else /* LJ_TARGET_ARM */ 602#else /* LJ_TARGET_ARM */
@@ -430,6 +607,7 @@ static __thread _Unwind_Exception static_uex;
430#define _US_FORCE_UNWIND 8 607#define _US_FORCE_UNWIND 8
431 608
432typedef struct _Unwind_Control_Block _Unwind_Control_Block; 609typedef struct _Unwind_Control_Block _Unwind_Control_Block;
610#define UNWIND_EXCEPTION_TYPE _Unwind_Control_Block
433 611
434struct _Unwind_Control_Block { 612struct _Unwind_Control_Block {
435 uint64_t exclass; 613 uint64_t exclass;
@@ -488,25 +666,62 @@ LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb,
488 } 666 }
489 if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) 667 if (__gnu_unwind_frame(ucb, ctx) != _URC_OK)
490 return _URC_FAILURE; 668 return _URC_FAILURE;
669#ifdef LUA_USE_ASSERT
670 /* We should never get here unless this is a forced unwind aka backtrace. */
671 if (_Unwind_GetGR(ctx, 0) == 0xff33aa77) {
672 _Unwind_SetGR(ctx, 0, 0xff33aa88);
673 }
674#endif
491 return _URC_CONTINUE_UNWIND; 675 return _URC_CONTINUE_UNWIND;
492} 676}
493 677
494#if LJ_UNWIND_EXT 678#if LJ_UNWIND_EXT && defined(LUA_USE_ASSERT)
495static __thread _Unwind_Control_Block static_uex; 679typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
680extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
681
682static int err_verify_bt(_Unwind_Context *ctx, int *got)
683{
684 if (_Unwind_GetGR(ctx, 0) == 0xff33aa88) { *got = 2; }
685 else if (*got == 0) { *got = 1; _Unwind_SetGR(ctx, 0, 0xff33aa77); }
686 return _URC_OK;
687}
688
689/* Verify that external error handling actually has a chance to work. */
690void lj_err_verify(void)
691{
692 int got = 0;
693 _Unwind_Backtrace((_Unwind_Trace_Fn)err_verify_bt, &got);
694 lj_assertX(got == 2, "broken build: external frame unwinding enabled, but missing -funwind-tables");
695}
496#endif 696#endif
697
698/*
699** Note: LJ_UNWIND_JIT is not implemented for 32 bit ARM.
700**
701** The quirky ARM unwind API doesn't have __register_frame().
702** A potential workaround might involve _Unwind_Backtrace.
703** But most 32 bit ARM targets don't qualify for LJ_UNWIND_EXT, anyway,
704** since they are built without unwind tables by default.
705*/
706
497#endif /* LJ_TARGET_ARM */ 707#endif /* LJ_TARGET_ARM */
498 708
709
499#if LJ_UNWIND_EXT 710#if LJ_UNWIND_EXT
711static __thread struct {
712 UNWIND_EXCEPTION_TYPE ex;
713 global_State *g;
714} static_uex;
715
500/* Raise external exception. */ 716/* Raise external exception. */
501static void err_raise_ext(global_State *g, int errcode) 717static void err_raise_ext(global_State *g, int errcode)
502{ 718{
503#if LJ_HASJIT
504 setmref(g->jit_base, NULL);
505#endif
506 memset(&static_uex, 0, sizeof(static_uex)); 719 memset(&static_uex, 0, sizeof(static_uex));
507 static_uex.exclass = LJ_UEXCLASS_MAKE(errcode); 720 static_uex.ex.exclass = LJ_UEXCLASS_MAKE(errcode);
508 _Unwind_RaiseException(&static_uex); 721 static_uex.g = g;
722 _Unwind_RaiseException(&static_uex.ex);
509} 723}
724
510#endif 725#endif
511 726
512#endif 727#endif
@@ -615,7 +830,7 @@ static ptrdiff_t finderrfunc(lua_State *L)
615/* Runtime error. */ 830/* Runtime error. */
616LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L) 831LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L)
617{ 832{
618 ptrdiff_t ef = finderrfunc(L); 833 ptrdiff_t ef = (LJ_HASJIT && tvref(G(L)->jit_base)) ? 0 : finderrfunc(L);
619 if (ef) { 834 if (ef) {
620 TValue *errfunc = restorestack(L, ef); 835 TValue *errfunc = restorestack(L, ef);
621 TValue *top = L->top; 836 TValue *top = L->top;
@@ -634,6 +849,16 @@ LJ_NOINLINE void LJ_FASTCALL lj_err_run(lua_State *L)
634 lj_err_throw(L, LUA_ERRRUN); 849 lj_err_throw(L, LUA_ERRRUN);
635} 850}
636 851
852#if LJ_HASJIT
853LJ_NOINLINE void LJ_FASTCALL lj_err_trace(lua_State *L, int errcode)
854{
855 if (errcode == LUA_ERRRUN)
856 lj_err_run(L);
857 else
858 lj_err_throw(L, errcode);
859}
860#endif
861
637/* Formatted runtime error message. */ 862/* Formatted runtime error message. */
638LJ_NORET LJ_NOINLINE static void err_msgv(lua_State *L, ErrMsg em, ...) 863LJ_NORET LJ_NOINLINE static void err_msgv(lua_State *L, ErrMsg em, ...)
639{ 864{