/* Throw error. Find catch frame, unwind stack and continue. */ LJ_NOINLINE void LJ_FASTCALL lj_err_throw(lua_State *L, int errcode) { global_State *g = G(L); lj_trace_abort(g); setgcrefnull(g->jit_L); L->status = 0; #if LJ_UNWIND_EXT err_raise_ext(errcode); /* ** 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. ** ** Usually this is caused by a C function without unwind information. ** This should never happen on x64, but may happen if you've manually ** enabled LUAJIT_UNWIND_EXTERNAL and forgot to recompile *every* ** non-C++ file with -funwind-tables. */ if (G(L)->panic) G(L)->panic(L); #else { void *cf = err_unwind(L, NULL, errcode); if (cframe_unwind_ff(cf)) lj_vm_unwind_ff(cframe_raw(cf)); else lj_vm_unwind_c(cframe_raw(cf), errcode); } #endif exit(EXIT_FAILURE); }
/* DWARF2 personality handler referenced from interpreter .eh_frame. */ LJ_FUNCA int lj_err_unwind_dwarf(int version, _Unwind_Action actions, uint64_t uexclass, struct _Unwind_Exception *uex, struct _Unwind_Context *ctx) { void *cf; lua_State *L; if (version != 1) return _URC_FATAL_PHASE1_ERROR; UNUSED(uexclass); cf = (void *)_Unwind_GetCFA(ctx); L = cframe_L(cf); if ((actions & _UA_SEARCH_PHASE)) { #if LJ_UNWIND_EXT if (err_unwind(L, cf, 0) == NULL) return _URC_CONTINUE_UNWIND; #endif if (!LJ_UEXCLASS_CHECK(uexclass)) { setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); } return _URC_HANDLER_FOUND; } if ((actions & _UA_CLEANUP_PHASE)) { int errcode; if (LJ_UEXCLASS_CHECK(uexclass)) { errcode = LJ_UEXCLASS_ERRCODE(uexclass); } else { if ((actions & _UA_HANDLER_FRAME)) _Unwind_DeleteException(uex); errcode = LUA_ERRRUN; } #if LJ_UNWIND_EXT cf = err_unwind(L, cf, errcode); if ((actions & _UA_FORCE_UNWIND)) { return _URC_CONTINUE_UNWIND; } else if (cf) { _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); _Unwind_SetIP(ctx, (uintptr_t)(cframe_unwind_ff(cf) ? lj_vm_unwind_ff_eh : lj_vm_unwind_c_eh)); return _URC_INSTALL_CONTEXT; } #if LJ_TARGET_X86ORX64 else if ((actions & _UA_HANDLER_FRAME)) { /* Workaround for ancient libgcc bug. Still present in RHEL 5.5. :-/ ** Real fix: http://gcc.gnu.org/viewcvs/trunk/gcc/unwind-dw2.c?r1=121165&r2=124837&pathrev=153877&diff_format=h */ _Unwind_SetGR(ctx, LJ_TARGET_EHRETREG, errcode); _Unwind_SetIP(ctx, (uintptr_t)lj_vm_unwind_rethrow); return _URC_INSTALL_CONTEXT; } #endif #else /* This is not the proper way to escape from the unwinder. We get away with ** it on x86/PPC because the interpreter restores all callee-saved regs. */ lj_err_throw(L, errcode); #endif } return _URC_CONTINUE_UNWIND; }
/* Win64 exception handler for interpreter frame. */ LJ_FUNCA EXCEPTION_DISPOSITION lj_err_unwind_win64(EXCEPTION_RECORD *rec, void *cf, CONTEXT *ctx, UndocumentedDispatcherContext *dispatch) { 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) { #ifdef _MSC_VER __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 ExceptionContinueSearch; } /* 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 *)errcode, ctx, dispatch->HistoryTable); /* RtlUnwindEx should never return. */ } } return ExceptionContinueSearch; }
/* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ LJ_FUNCA int lj_err_unwind_arm(int state, _Unwind_Control_Block *ucb, _Unwind_Context *ctx) { void *cf = (void *)_Unwind_GetGR(ctx, 13); lua_State *L = cframe_L(cf); int errcode; switch ((state & _US_ACTION_MASK)) { case _US_VIRTUAL_UNWIND_FRAME: if ((state & _US_FORCE_UNWIND)) break; return _URC_HANDLER_FOUND; case _US_UNWIND_FRAME_STARTING: if (LJ_UEXCLASS_CHECK(ucb->exclass)) { errcode = LJ_UEXCLASS_ERRCODE(ucb->exclass); } else { errcode = LUA_ERRRUN; setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); } cf = err_unwind(L, cf, errcode); if ((state & _US_FORCE_UNWIND) || cf == NULL) break; _Unwind_SetGR(ctx, 15, (uint32_t)lj_vm_unwind_ext); _Unwind_SetGR(ctx, 0, (uint32_t)ucb); _Unwind_SetGR(ctx, 1, (uint32_t)errcode); _Unwind_SetGR(ctx, 2, cframe_unwind_ff(cf) ? (uint32_t)lj_vm_unwind_ff_eh : (uint32_t)lj_vm_unwind_c_eh); return _URC_INSTALL_CONTEXT; default: return _URC_FAILURE; } if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) return _URC_FAILURE; return _URC_CONTINUE_UNWIND; }