/* Add frame links at the end of the snapshot. */ static BCReg snapshot_framelinks(jit_State *J, SnapEntry *map) { cTValue *frame = J->L->base - 1; cTValue *lim = J->L->base - J->baseslot; GCfunc *fn = frame_func(frame); cTValue *ftop = isluafunc(fn) ? (frame+funcproto(fn)->framesize) : J->L->top; MSize f = 0; lua_assert(!LJ_FR2); /* TODO_FR2: store 64 bit PCs. */ map[f++] = SNAP_MKPC(J->pc); /* The current PC is always the first entry. */ while (frame > lim) { /* Backwards traversal of all frames above base. */ if (frame_islua(frame)) { map[f++] = SNAP_MKPC(frame_pc(frame)); frame = frame_prevl(frame); } else if (frame_iscont(frame)) { map[f++] = SNAP_MKFTSZ(frame_ftsz(frame)); map[f++] = SNAP_MKPC(frame_contpc(frame)); frame = frame_prevd(frame); } else { lua_assert(!frame_isc(frame)); map[f++] = SNAP_MKFTSZ(frame_ftsz(frame)); frame = frame_prevd(frame); continue; } if (frame + funcproto(frame_func(frame))->framesize > ftop) ftop = frame + funcproto(frame_func(frame))->framesize; } lua_assert(f == (MSize)(1 + J->framedepth)); return (BCReg)(ftop - lim); }
/* Find error function for runtime errors. Requires an extra stack traversal. */ static ptrdiff_t finderrfunc(lua_State *L) { cTValue *frame = L->base-1, *bot = tvref(L->stack); void *cf = L->cframe; while (frame > bot && cf) { while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ if (frame >= restorestack(L, -cframe_nres(cf))) break; if (cframe_errfunc(cf) >= 0) /* Error handler not inherited (-1)? */ return cframe_errfunc(cf); cf = cframe_prev(cf); /* Else unwind cframe and continue searching. */ if (cf == NULL) return 0; } switch (frame_typep(frame)) { case FRAME_LUA: case FRAME_LUAP: frame = frame_prevl(frame); break; case FRAME_C: cf = cframe_prev(cf); /* fallthrough */ case FRAME_VARG: frame = frame_prevd(frame); break; case FRAME_CONT: #if LJ_HASFFI if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK) cf = cframe_prev(cf); #endif frame = frame_prevd(frame); break; case FRAME_CP: if (cframe_canyield(cf)) return 0; if (cframe_errfunc(cf) >= 0) return cframe_errfunc(cf); frame = frame_prevd(frame); break; case FRAME_PCALL: case FRAME_PCALLH: if (frame_ftsz(frame) >= (ptrdiff_t)(2*sizeof(TValue))) /* xpcall? */ return savestack(L, frame-1); /* Point to xpcall's errorfunc. */ return 0; default: lua_assert(0); return 0; } } return 0; }
/* Find error function for runtime errors. Requires an extra stack traversal. */ static ptrdiff_t finderrfunc(lua_State *L) { cTValue *frame = L->base-1, *bot = tvref(L->stack)+LJ_FR2; void *cf = L->cframe; while (frame > bot && cf) { while (cframe_nres(cframe_raw(cf)) < 0) { /* cframe without frame? */ if (frame >= restorestack(L, -cframe_nres(cf))) break; if (cframe_errfunc(cf) >= 0) /* Error handler not inherited (-1)? */ return cframe_errfunc(cf); cf = cframe_prev(cf); /* Else unwind cframe and continue searching. */ if (cf == NULL) return 0; } switch (frame_typep(frame)) { case FRAME_LUA: case FRAME_LUAP: frame = frame_prevl(frame); break; case FRAME_C: cf = cframe_prev(cf); /* fallthrough */ case FRAME_VARG: frame = frame_prevd(frame); break; case FRAME_CONT: if (frame_iscont_fficb(frame)) cf = cframe_prev(cf); frame = frame_prevd(frame); break; case FRAME_CP: if (cframe_canyield(cf)) return 0; if (cframe_errfunc(cf) >= 0) return cframe_errfunc(cf); frame = frame_prevd(frame); break; case FRAME_PCALL: case FRAME_PCALLH: if (frame_func(frame_prevd(frame))->c.ffid == FF_xpcall) return savestack(L, frame_prevd(frame)+1); /* xpcall's errorfunc. */ return 0; default: lua_assert(0); return 0; } } return 0; }
/* Error in context of caller. */ LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg) { TValue *frame = L->base-1; TValue *pframe = NULL; if (frame_islua(frame)) { pframe = frame_prevl(frame); } else if (frame_iscont(frame)) { #if LJ_HASFFI if ((frame-1)->u32.lo == LJ_CONT_FFI_CALLBACK) { pframe = frame; frame = NULL; } else #endif { pframe = frame_prevd(frame); #if LJ_HASFFI /* Remove frame for FFI metamethods. */ if (frame_func(frame)->c.ffid >= FF_ffi_meta___index && frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) { L->base = pframe+1; L->top = frame; setcframe_pc(cframe_raw(L->cframe), frame_contpc(frame)); } #endif } } lj_debug_addloc(L, msg, pframe, frame); lj_err_run(L); }
/* 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)); }
/* Add frame links at the end of the snapshot. */ static void snapshot_framelinks(jit_State *J, SnapEntry *map) { cTValue *frame = J->L->base - 1; cTValue *lim = J->L->base - J->baseslot; MSize f = 0; map[f++] = SNAP_MKPC(J->pc); /* The current PC is always the first entry. */ while (frame > lim) { /* Backwards traversal of all frames above base. */ if (frame_islua(frame)) { map[f++] = SNAP_MKPC(frame_pc(frame)); frame = frame_prevl(frame); } else if (frame_iscont(frame)) { map[f++] = SNAP_MKFTSZ(frame_ftsz(frame)); map[f++] = SNAP_MKPC(frame_contpc(frame)); frame = frame_prevd(frame); } else { lua_assert(!frame_isc(frame)); map[f++] = SNAP_MKFTSZ(frame_ftsz(frame)); frame = frame_prevd(frame); } } lua_assert(f == (MSize)(1 + J->framedepth)); }
/* Add frame links at the end of the snapshot. */ static MSize snapshot_framelinks(jit_State *J, IRRef2 *map) { cTValue *frame = J->L->base - 1; cTValue *lim = J->L->base - J->baseslot; MSize f = 0; map[f++] = u32ptr(J->pc); while (frame > lim) { if (frame_islua(frame)) { map[f++] = u32ptr(frame_pc(frame)); frame = frame_prevl(frame); } else if (frame_ispcall(frame)) { map[f++] = (uint32_t)frame_ftsz(frame); frame = frame_prevd(frame); } else if (frame_iscont(frame)) { map[f++] = (uint32_t)frame_ftsz(frame); map[f++] = u32ptr(frame_contpc(frame)); frame = frame_prevd(frame); } else { lua_assert(0); } } return f; }
/* Error in context of caller. */ LJ_NOINLINE void lj_err_callermsg(lua_State *L, const char *msg) { TValue *frame = L->base-1; TValue *pframe = NULL; if (frame_islua(frame)) { pframe = frame_prevl(frame); } else if (frame_iscont(frame)) { pframe = frame_prevd(frame); #if LJ_HASFFI /* Remove frame for FFI metamethods. */ if (frame_func(frame)->c.ffid >= FF_ffi_meta___index && frame_func(frame)->c.ffid <= FF_ffi_meta___tostring) { L->base = pframe+1; L->top = frame; } #endif } lj_debug_addloc(L, msg, pframe, frame); lj_err_run(L); }
/* Get frame corresponding to a level. */ cTValue *lj_debug_frame(lua_State *L, int level, int *size) { cTValue *frame, *nextframe, *bot = tvref(L->stack); /* Traverse frames backwards. */ for (nextframe = frame = L->base-1; frame > bot; ) { if (frame_gc(frame) == obj2gco(L)) level++; /* Skip dummy frames. See lj_meta_call(). */ if (level-- == 0) { *size = (int)(nextframe - frame); return frame; /* Level found. */ } nextframe = frame; if (frame_islua(frame)) { frame = frame_prevl(frame); } else { if (frame_isvarg(frame)) level++; /* Skip vararg pseudo-frame. */ frame = frame_prevd(frame); } } *size = level; return NULL; /* Level not found. */ }
/* Unwind until stop frame. Optionally cleanup frames. */ static void *err_unwind(lua_State *L, void *stopcf, int errcode) { TValue *frame = L->base-1; void *cf = L->cframe; while (cf) { int32_t nres = cframe_nres(cframe_raw(cf)); if (nres < 0) { /* C frame without Lua frame? */ TValue *top = restorestack(L, -nres); if (frame < top) { /* Frame reached? */ if (errcode) { L->cframe = cframe_prev(cf); L->base = frame+1; unwindstack(L, top); } return cf; } } if (frame <= tvref(L->stack)) break; switch (frame_typep(frame)) { case FRAME_LUA: /* Lua frame. */ case FRAME_LUAP: frame = frame_prevl(frame); break; case FRAME_C: /* C frame. */ #if LJ_UNWIND_EXT if (errcode) { L->cframe = cframe_prev(cf); L->base = frame_prevd(frame) + 1; unwindstack(L, frame); } else if (cf != stopcf) { cf = cframe_prev(cf); frame = frame_prevd(frame); break; } return NULL; /* Continue unwinding. */ #else UNUSED(stopcf); cf = cframe_prev(cf); frame = frame_prevd(frame); break; #endif case FRAME_CP: /* Protected C frame. */ if (cframe_canyield(cf)) { /* Resume? */ if (errcode) { L->cframe = NULL; L->status = (uint8_t)errcode; } return cf; } if (errcode) { L->cframe = cframe_prev(cf); L->base = frame_prevd(frame) + 1; unwindstack(L, frame); } return cf; case FRAME_CONT: /* Continuation frame. */ case FRAME_VARG: /* Vararg frame. */ frame = frame_prevd(frame); break; case FRAME_PCALL: /* FF pcall() frame. */ case FRAME_PCALLH: /* FF pcall() frame inside hook. */ if (errcode) { if (errcode == LUA_YIELD) { frame = frame_prevd(frame); break; } if (frame_typep(frame) == FRAME_PCALL) hook_leave(G(L)); L->cframe = cf; L->base = frame_prevd(frame) + 1; unwindstack(L, L->base); } return (void *)((intptr_t)cf | CFRAME_UNWIND_FF); } } /* No C frame. */ if (errcode) { L->cframe = NULL; L->base = tvref(L->stack)+1; unwindstack(L, L->base); if (G(L)->panic) G(L)->panic(L); exit(EXIT_FAILURE); } return L; /* Anything non-NULL will do. */ }