/* 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; }
/* 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; }
/* 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; }
/* Return bytecode position for function/frame or NO_BCPOS. */ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) { const BCIns *ins; GCproto *pt; BCPos pos; lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD); if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */ return NO_BCPOS; } else if (nextframe == NULL) { /* Lua function on top. */ void *cf = cframe_raw(L->cframe); if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf)) return NO_BCPOS; ins = cframe_pc(cf); /* Only happens during error/hook handling. */ } else { if (frame_islua(nextframe)) { ins = frame_pc(nextframe); } else if (frame_iscont(nextframe)) { ins = frame_contpc(nextframe); } else { /* Lua function below errfunc/gc/hook: find cframe to get the PC. */ void *cf = cframe_raw(L->cframe); TValue *f = L->base-1; for (;;) { if (cf == NULL) return NO_BCPOS; while (cframe_nres(cf) < 0) { if (f >= restorestack(L, -cframe_nres(cf))) break; cf = cframe_raw(cframe_prev(cf)); if (cf == NULL) return NO_BCPOS; } if (f < nextframe) break; if (frame_islua(f)) { f = frame_prevl(f); } else { if (frame_isc(f) || (LJ_HASFFI && frame_iscont(f) && (f-1)->u32.lo == LJ_CONT_FFI_CALLBACK)) cf = cframe_raw(cframe_prev(cf)); f = frame_prevd(f); } } ins = cframe_pc(cf); } } pt = funcproto(fn); pos = proto_bcpos(pt, ins) - 1; #if LJ_HASJIT if (pos > pt->sizebc) { /* Undo the effects of lj_trace_exit for JLOOP. */ GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins)); lua_assert(bc_isret(bc_op(ins[-1]))); pos = proto_bcpos(pt, mref(T->startpc, const BCIns)); }
/* ARM unwinder personality handler referenced from interpreter .ARM.extab. */ LJ_FUNCA int lj_err_unwind_arm(int state, void *ucb, _Unwind_Context *ctx) { void *cf = (void *)_Unwind_GetGR(ctx, 13); lua_State *L = cframe_L(cf); if ((state & _US_ACTION_MASK) == _US_VIRTUAL_UNWIND_FRAME) { setstrV(L, L->top++, lj_err_str(L, LJ_ERR_ERRCPP)); return _URC_HANDLER_FOUND; } if ((state&(_US_ACTION_MASK|_US_FORCE_UNWIND)) == _US_UNWIND_FRAME_STARTING) { _Unwind_DeleteException(ucb); _Unwind_SetGR(ctx, 15, (uint32_t)(void *)lj_err_throw); _Unwind_SetGR(ctx, 0, (uint32_t)L); _Unwind_SetGR(ctx, 1, (uint32_t)LUA_ERRRUN); return _URC_INSTALL_CONTEXT; } if (__gnu_unwind_frame(ucb, ctx) != _URC_OK) return _URC_FAILURE; return _URC_CONTINUE_UNWIND; }