xref: /freebsd/contrib/lua/src/ldebug.c (revision bf9580a118e399f3f3d37b3466877ba1c2c2a6f6)
18e3e3a7aSWarner Losh /*
2e112e9d2SKyle Evans ** $Id: ldebug.c,v 2.121.1.2 2017/07/10 17:21:50 roberto Exp $
38e3e3a7aSWarner Losh ** Debug Interface
48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h
58e3e3a7aSWarner Losh */
68e3e3a7aSWarner Losh 
78e3e3a7aSWarner Losh #define ldebug_c
88e3e3a7aSWarner Losh #define LUA_CORE
98e3e3a7aSWarner Losh 
108e3e3a7aSWarner Losh #include "lprefix.h"
118e3e3a7aSWarner Losh 
128e3e3a7aSWarner Losh 
138e3e3a7aSWarner Losh #include <stdarg.h>
148e3e3a7aSWarner Losh #include <stddef.h>
158e3e3a7aSWarner Losh #include <string.h>
168e3e3a7aSWarner Losh 
178e3e3a7aSWarner Losh #include "lua.h"
188e3e3a7aSWarner Losh 
198e3e3a7aSWarner Losh #include "lapi.h"
208e3e3a7aSWarner Losh #include "lcode.h"
218e3e3a7aSWarner Losh #include "ldebug.h"
228e3e3a7aSWarner Losh #include "ldo.h"
238e3e3a7aSWarner Losh #include "lfunc.h"
248e3e3a7aSWarner Losh #include "lobject.h"
258e3e3a7aSWarner Losh #include "lopcodes.h"
268e3e3a7aSWarner Losh #include "lstate.h"
278e3e3a7aSWarner Losh #include "lstring.h"
288e3e3a7aSWarner Losh #include "ltable.h"
298e3e3a7aSWarner Losh #include "ltm.h"
308e3e3a7aSWarner Losh #include "lvm.h"
318e3e3a7aSWarner Losh 
328e3e3a7aSWarner Losh 
338e3e3a7aSWarner Losh 
348e3e3a7aSWarner Losh #define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_TCCL)
358e3e3a7aSWarner Losh 
368e3e3a7aSWarner Losh 
378e3e3a7aSWarner Losh /* Active Lua function (given call info) */
388e3e3a7aSWarner Losh #define ci_func(ci)		(clLvalue((ci)->func))
398e3e3a7aSWarner Losh 
408e3e3a7aSWarner Losh 
418e3e3a7aSWarner Losh static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
428e3e3a7aSWarner Losh                                     const char **name);
438e3e3a7aSWarner Losh 
448e3e3a7aSWarner Losh 
458e3e3a7aSWarner Losh static int currentpc (CallInfo *ci) {
468e3e3a7aSWarner Losh   lua_assert(isLua(ci));
478e3e3a7aSWarner Losh   return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
488e3e3a7aSWarner Losh }
498e3e3a7aSWarner Losh 
508e3e3a7aSWarner Losh 
518e3e3a7aSWarner Losh static int currentline (CallInfo *ci) {
528e3e3a7aSWarner Losh   return getfuncline(ci_func(ci)->p, currentpc(ci));
538e3e3a7aSWarner Losh }
548e3e3a7aSWarner Losh 
558e3e3a7aSWarner Losh 
568e3e3a7aSWarner Losh /*
578e3e3a7aSWarner Losh ** If function yielded, its 'func' can be in the 'extra' field. The
588e3e3a7aSWarner Losh ** next function restores 'func' to its correct value for debugging
598e3e3a7aSWarner Losh ** purposes. (It exchanges 'func' and 'extra'; so, when called again,
608e3e3a7aSWarner Losh ** after debugging, it also "re-restores" ** 'func' to its altered value.
618e3e3a7aSWarner Losh */
628e3e3a7aSWarner Losh static void swapextra (lua_State *L) {
638e3e3a7aSWarner Losh   if (L->status == LUA_YIELD) {
648e3e3a7aSWarner Losh     CallInfo *ci = L->ci;  /* get function that yielded */
658e3e3a7aSWarner Losh     StkId temp = ci->func;  /* exchange its 'func' and 'extra' values */
668e3e3a7aSWarner Losh     ci->func = restorestack(L, ci->extra);
678e3e3a7aSWarner Losh     ci->extra = savestack(L, temp);
688e3e3a7aSWarner Losh   }
698e3e3a7aSWarner Losh }
708e3e3a7aSWarner Losh 
718e3e3a7aSWarner Losh 
728e3e3a7aSWarner Losh /*
738e3e3a7aSWarner Losh ** This function can be called asynchronously (e.g. during a signal).
748e3e3a7aSWarner Losh ** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
758e3e3a7aSWarner Losh ** 'resethookcount') are for debug only, and it is no problem if they
768e3e3a7aSWarner Losh ** get arbitrary values (causes at most one wrong hook call). 'hookmask'
778e3e3a7aSWarner Losh ** is an atomic value. We assume that pointers are atomic too (e.g., gcc
788e3e3a7aSWarner Losh ** ensures that for all platforms where it runs). Moreover, 'hook' is
798e3e3a7aSWarner Losh ** always checked before being called (see 'luaD_hook').
808e3e3a7aSWarner Losh */
818e3e3a7aSWarner Losh LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
828e3e3a7aSWarner Losh   if (func == NULL || mask == 0) {  /* turn off hooks? */
838e3e3a7aSWarner Losh     mask = 0;
848e3e3a7aSWarner Losh     func = NULL;
858e3e3a7aSWarner Losh   }
868e3e3a7aSWarner Losh   if (isLua(L->ci))
878e3e3a7aSWarner Losh     L->oldpc = L->ci->u.l.savedpc;
888e3e3a7aSWarner Losh   L->hook = func;
898e3e3a7aSWarner Losh   L->basehookcount = count;
908e3e3a7aSWarner Losh   resethookcount(L);
918e3e3a7aSWarner Losh   L->hookmask = cast_byte(mask);
928e3e3a7aSWarner Losh }
938e3e3a7aSWarner Losh 
948e3e3a7aSWarner Losh 
958e3e3a7aSWarner Losh LUA_API lua_Hook lua_gethook (lua_State *L) {
968e3e3a7aSWarner Losh   return L->hook;
978e3e3a7aSWarner Losh }
988e3e3a7aSWarner Losh 
998e3e3a7aSWarner Losh 
1008e3e3a7aSWarner Losh LUA_API int lua_gethookmask (lua_State *L) {
1018e3e3a7aSWarner Losh   return L->hookmask;
1028e3e3a7aSWarner Losh }
1038e3e3a7aSWarner Losh 
1048e3e3a7aSWarner Losh 
1058e3e3a7aSWarner Losh LUA_API int lua_gethookcount (lua_State *L) {
1068e3e3a7aSWarner Losh   return L->basehookcount;
1078e3e3a7aSWarner Losh }
1088e3e3a7aSWarner Losh 
1098e3e3a7aSWarner Losh 
1108e3e3a7aSWarner Losh LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
1118e3e3a7aSWarner Losh   int status;
1128e3e3a7aSWarner Losh   CallInfo *ci;
1138e3e3a7aSWarner Losh   if (level < 0) return 0;  /* invalid (negative) level */
1148e3e3a7aSWarner Losh   lua_lock(L);
1158e3e3a7aSWarner Losh   for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
1168e3e3a7aSWarner Losh     level--;
1178e3e3a7aSWarner Losh   if (level == 0 && ci != &L->base_ci) {  /* level found? */
1188e3e3a7aSWarner Losh     status = 1;
1198e3e3a7aSWarner Losh     ar->i_ci = ci;
1208e3e3a7aSWarner Losh   }
1218e3e3a7aSWarner Losh   else status = 0;  /* no such level */
1228e3e3a7aSWarner Losh   lua_unlock(L);
1238e3e3a7aSWarner Losh   return status;
1248e3e3a7aSWarner Losh }
1258e3e3a7aSWarner Losh 
1268e3e3a7aSWarner Losh 
1278e3e3a7aSWarner Losh static const char *upvalname (Proto *p, int uv) {
1288e3e3a7aSWarner Losh   TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
1298e3e3a7aSWarner Losh   if (s == NULL) return "?";
1308e3e3a7aSWarner Losh   else return getstr(s);
1318e3e3a7aSWarner Losh }
1328e3e3a7aSWarner Losh 
1338e3e3a7aSWarner Losh 
1348e3e3a7aSWarner Losh static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
1358e3e3a7aSWarner Losh   int nparams = clLvalue(ci->func)->p->numparams;
136*bf9580a1SKyle Evans   int nvararg = cast_int(ci->u.l.base - ci->func) - nparams;
137*bf9580a1SKyle Evans   if (n <= -nvararg)
1388e3e3a7aSWarner Losh     return NULL;  /* no such vararg */
1398e3e3a7aSWarner Losh   else {
140*bf9580a1SKyle Evans     *pos = ci->func + nparams - n;
1418e3e3a7aSWarner Losh     return "(*vararg)";  /* generic name for any vararg */
1428e3e3a7aSWarner Losh   }
1438e3e3a7aSWarner Losh }
1448e3e3a7aSWarner Losh 
1458e3e3a7aSWarner Losh 
1468e3e3a7aSWarner Losh static const char *findlocal (lua_State *L, CallInfo *ci, int n,
1478e3e3a7aSWarner Losh                               StkId *pos) {
1488e3e3a7aSWarner Losh   const char *name = NULL;
1498e3e3a7aSWarner Losh   StkId base;
1508e3e3a7aSWarner Losh   if (isLua(ci)) {
1518e3e3a7aSWarner Losh     if (n < 0)  /* access to vararg values? */
152*bf9580a1SKyle Evans       return findvararg(ci, n, pos);
1538e3e3a7aSWarner Losh     else {
1548e3e3a7aSWarner Losh       base = ci->u.l.base;
1558e3e3a7aSWarner Losh       name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
1568e3e3a7aSWarner Losh     }
1578e3e3a7aSWarner Losh   }
1588e3e3a7aSWarner Losh   else
1598e3e3a7aSWarner Losh     base = ci->func + 1;
1608e3e3a7aSWarner Losh   if (name == NULL) {  /* no 'standard' name? */
1618e3e3a7aSWarner Losh     StkId limit = (ci == L->ci) ? L->top : ci->next->func;
1628e3e3a7aSWarner Losh     if (limit - base >= n && n > 0)  /* is 'n' inside 'ci' stack? */
1638e3e3a7aSWarner Losh       name = "(*temporary)";  /* generic name for any valid slot */
1648e3e3a7aSWarner Losh     else
1658e3e3a7aSWarner Losh       return NULL;  /* no name */
1668e3e3a7aSWarner Losh   }
1678e3e3a7aSWarner Losh   *pos = base + (n - 1);
1688e3e3a7aSWarner Losh   return name;
1698e3e3a7aSWarner Losh }
1708e3e3a7aSWarner Losh 
1718e3e3a7aSWarner Losh 
1728e3e3a7aSWarner Losh LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
1738e3e3a7aSWarner Losh   const char *name;
1748e3e3a7aSWarner Losh   lua_lock(L);
1758e3e3a7aSWarner Losh   swapextra(L);
1768e3e3a7aSWarner Losh   if (ar == NULL) {  /* information about non-active function? */
1778e3e3a7aSWarner Losh     if (!isLfunction(L->top - 1))  /* not a Lua function? */
1788e3e3a7aSWarner Losh       name = NULL;
1798e3e3a7aSWarner Losh     else  /* consider live variables at function start (parameters) */
1808e3e3a7aSWarner Losh       name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
1818e3e3a7aSWarner Losh   }
1828e3e3a7aSWarner Losh   else {  /* active function; get information through 'ar' */
1838e3e3a7aSWarner Losh     StkId pos = NULL;  /* to avoid warnings */
1848e3e3a7aSWarner Losh     name = findlocal(L, ar->i_ci, n, &pos);
1858e3e3a7aSWarner Losh     if (name) {
1868e3e3a7aSWarner Losh       setobj2s(L, L->top, pos);
1878e3e3a7aSWarner Losh       api_incr_top(L);
1888e3e3a7aSWarner Losh     }
1898e3e3a7aSWarner Losh   }
1908e3e3a7aSWarner Losh   swapextra(L);
1918e3e3a7aSWarner Losh   lua_unlock(L);
1928e3e3a7aSWarner Losh   return name;
1938e3e3a7aSWarner Losh }
1948e3e3a7aSWarner Losh 
1958e3e3a7aSWarner Losh 
1968e3e3a7aSWarner Losh LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
1978e3e3a7aSWarner Losh   StkId pos = NULL;  /* to avoid warnings */
1988e3e3a7aSWarner Losh   const char *name;
1998e3e3a7aSWarner Losh   lua_lock(L);
2008e3e3a7aSWarner Losh   swapextra(L);
2018e3e3a7aSWarner Losh   name = findlocal(L, ar->i_ci, n, &pos);
2028e3e3a7aSWarner Losh   if (name) {
2038e3e3a7aSWarner Losh     setobjs2s(L, pos, L->top - 1);
2048e3e3a7aSWarner Losh     L->top--;  /* pop value */
2058e3e3a7aSWarner Losh   }
2068e3e3a7aSWarner Losh   swapextra(L);
2078e3e3a7aSWarner Losh   lua_unlock(L);
2088e3e3a7aSWarner Losh   return name;
2098e3e3a7aSWarner Losh }
2108e3e3a7aSWarner Losh 
2118e3e3a7aSWarner Losh 
2128e3e3a7aSWarner Losh static void funcinfo (lua_Debug *ar, Closure *cl) {
2138e3e3a7aSWarner Losh   if (noLuaClosure(cl)) {
2148e3e3a7aSWarner Losh     ar->source = "=[C]";
2158e3e3a7aSWarner Losh     ar->linedefined = -1;
2168e3e3a7aSWarner Losh     ar->lastlinedefined = -1;
2178e3e3a7aSWarner Losh     ar->what = "C";
2188e3e3a7aSWarner Losh   }
2198e3e3a7aSWarner Losh   else {
2208e3e3a7aSWarner Losh     Proto *p = cl->l.p;
2218e3e3a7aSWarner Losh     ar->source = p->source ? getstr(p->source) : "=?";
2228e3e3a7aSWarner Losh     ar->linedefined = p->linedefined;
2238e3e3a7aSWarner Losh     ar->lastlinedefined = p->lastlinedefined;
2248e3e3a7aSWarner Losh     ar->what = (ar->linedefined == 0) ? "main" : "Lua";
2258e3e3a7aSWarner Losh   }
2268e3e3a7aSWarner Losh   luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
2278e3e3a7aSWarner Losh }
2288e3e3a7aSWarner Losh 
2298e3e3a7aSWarner Losh 
2308e3e3a7aSWarner Losh static void collectvalidlines (lua_State *L, Closure *f) {
2318e3e3a7aSWarner Losh   if (noLuaClosure(f)) {
2328e3e3a7aSWarner Losh     setnilvalue(L->top);
2338e3e3a7aSWarner Losh     api_incr_top(L);
2348e3e3a7aSWarner Losh   }
2358e3e3a7aSWarner Losh   else {
2368e3e3a7aSWarner Losh     int i;
2378e3e3a7aSWarner Losh     TValue v;
2388e3e3a7aSWarner Losh     int *lineinfo = f->l.p->lineinfo;
2398e3e3a7aSWarner Losh     Table *t = luaH_new(L);  /* new table to store active lines */
2408e3e3a7aSWarner Losh     sethvalue(L, L->top, t);  /* push it on stack */
2418e3e3a7aSWarner Losh     api_incr_top(L);
2428e3e3a7aSWarner Losh     setbvalue(&v, 1);  /* boolean 'true' to be the value of all indices */
2438e3e3a7aSWarner Losh     for (i = 0; i < f->l.p->sizelineinfo; i++)  /* for all lines with code */
2448e3e3a7aSWarner Losh       luaH_setint(L, t, lineinfo[i], &v);  /* table[line] = true */
2458e3e3a7aSWarner Losh   }
2468e3e3a7aSWarner Losh }
2478e3e3a7aSWarner Losh 
2488e3e3a7aSWarner Losh 
2498e3e3a7aSWarner Losh static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
2508e3e3a7aSWarner Losh   if (ci == NULL)  /* no 'ci'? */
2518e3e3a7aSWarner Losh     return NULL;  /* no info */
2528e3e3a7aSWarner Losh   else if (ci->callstatus & CIST_FIN) {  /* is this a finalizer? */
2538e3e3a7aSWarner Losh     *name = "__gc";
2548e3e3a7aSWarner Losh     return "metamethod";  /* report it as such */
2558e3e3a7aSWarner Losh   }
2568e3e3a7aSWarner Losh   /* calling function is a known Lua function? */
2578e3e3a7aSWarner Losh   else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
2588e3e3a7aSWarner Losh     return funcnamefromcode(L, ci->previous, name);
2598e3e3a7aSWarner Losh   else return NULL;  /* no way to find a name */
2608e3e3a7aSWarner Losh }
2618e3e3a7aSWarner Losh 
2628e3e3a7aSWarner Losh 
2638e3e3a7aSWarner Losh static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
2648e3e3a7aSWarner Losh                        Closure *f, CallInfo *ci) {
2658e3e3a7aSWarner Losh   int status = 1;
2668e3e3a7aSWarner Losh   for (; *what; what++) {
2678e3e3a7aSWarner Losh     switch (*what) {
2688e3e3a7aSWarner Losh       case 'S': {
2698e3e3a7aSWarner Losh         funcinfo(ar, f);
2708e3e3a7aSWarner Losh         break;
2718e3e3a7aSWarner Losh       }
2728e3e3a7aSWarner Losh       case 'l': {
2738e3e3a7aSWarner Losh         ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
2748e3e3a7aSWarner Losh         break;
2758e3e3a7aSWarner Losh       }
2768e3e3a7aSWarner Losh       case 'u': {
2778e3e3a7aSWarner Losh         ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
2788e3e3a7aSWarner Losh         if (noLuaClosure(f)) {
2798e3e3a7aSWarner Losh           ar->isvararg = 1;
2808e3e3a7aSWarner Losh           ar->nparams = 0;
2818e3e3a7aSWarner Losh         }
2828e3e3a7aSWarner Losh         else {
2838e3e3a7aSWarner Losh           ar->isvararg = f->l.p->is_vararg;
2848e3e3a7aSWarner Losh           ar->nparams = f->l.p->numparams;
2858e3e3a7aSWarner Losh         }
2868e3e3a7aSWarner Losh         break;
2878e3e3a7aSWarner Losh       }
2888e3e3a7aSWarner Losh       case 't': {
2898e3e3a7aSWarner Losh         ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
2908e3e3a7aSWarner Losh         break;
2918e3e3a7aSWarner Losh       }
2928e3e3a7aSWarner Losh       case 'n': {
2938e3e3a7aSWarner Losh         ar->namewhat = getfuncname(L, ci, &ar->name);
2948e3e3a7aSWarner Losh         if (ar->namewhat == NULL) {
2958e3e3a7aSWarner Losh           ar->namewhat = "";  /* not found */
2968e3e3a7aSWarner Losh           ar->name = NULL;
2978e3e3a7aSWarner Losh         }
2988e3e3a7aSWarner Losh         break;
2998e3e3a7aSWarner Losh       }
3008e3e3a7aSWarner Losh       case 'L':
3018e3e3a7aSWarner Losh       case 'f':  /* handled by lua_getinfo */
3028e3e3a7aSWarner Losh         break;
3038e3e3a7aSWarner Losh       default: status = 0;  /* invalid option */
3048e3e3a7aSWarner Losh     }
3058e3e3a7aSWarner Losh   }
3068e3e3a7aSWarner Losh   return status;
3078e3e3a7aSWarner Losh }
3088e3e3a7aSWarner Losh 
3098e3e3a7aSWarner Losh 
3108e3e3a7aSWarner Losh LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
3118e3e3a7aSWarner Losh   int status;
3128e3e3a7aSWarner Losh   Closure *cl;
3138e3e3a7aSWarner Losh   CallInfo *ci;
3148e3e3a7aSWarner Losh   StkId func;
3158e3e3a7aSWarner Losh   lua_lock(L);
3168e3e3a7aSWarner Losh   swapextra(L);
3178e3e3a7aSWarner Losh   if (*what == '>') {
3188e3e3a7aSWarner Losh     ci = NULL;
3198e3e3a7aSWarner Losh     func = L->top - 1;
3208e3e3a7aSWarner Losh     api_check(L, ttisfunction(func), "function expected");
3218e3e3a7aSWarner Losh     what++;  /* skip the '>' */
3228e3e3a7aSWarner Losh     L->top--;  /* pop function */
3238e3e3a7aSWarner Losh   }
3248e3e3a7aSWarner Losh   else {
3258e3e3a7aSWarner Losh     ci = ar->i_ci;
3268e3e3a7aSWarner Losh     func = ci->func;
3278e3e3a7aSWarner Losh     lua_assert(ttisfunction(ci->func));
3288e3e3a7aSWarner Losh   }
3298e3e3a7aSWarner Losh   cl = ttisclosure(func) ? clvalue(func) : NULL;
3308e3e3a7aSWarner Losh   status = auxgetinfo(L, what, ar, cl, ci);
3318e3e3a7aSWarner Losh   if (strchr(what, 'f')) {
3328e3e3a7aSWarner Losh     setobjs2s(L, L->top, func);
3338e3e3a7aSWarner Losh     api_incr_top(L);
3348e3e3a7aSWarner Losh   }
3358e3e3a7aSWarner Losh   swapextra(L);  /* correct before option 'L', which can raise a mem. error */
3368e3e3a7aSWarner Losh   if (strchr(what, 'L'))
3378e3e3a7aSWarner Losh     collectvalidlines(L, cl);
3388e3e3a7aSWarner Losh   lua_unlock(L);
3398e3e3a7aSWarner Losh   return status;
3408e3e3a7aSWarner Losh }
3418e3e3a7aSWarner Losh 
3428e3e3a7aSWarner Losh 
3438e3e3a7aSWarner Losh /*
3448e3e3a7aSWarner Losh ** {======================================================
3458e3e3a7aSWarner Losh ** Symbolic Execution
3468e3e3a7aSWarner Losh ** =======================================================
3478e3e3a7aSWarner Losh */
3488e3e3a7aSWarner Losh 
3498e3e3a7aSWarner Losh static const char *getobjname (Proto *p, int lastpc, int reg,
3508e3e3a7aSWarner Losh                                const char **name);
3518e3e3a7aSWarner Losh 
3528e3e3a7aSWarner Losh 
3538e3e3a7aSWarner Losh /*
3548e3e3a7aSWarner Losh ** find a "name" for the RK value 'c'
3558e3e3a7aSWarner Losh */
3568e3e3a7aSWarner Losh static void kname (Proto *p, int pc, int c, const char **name) {
3578e3e3a7aSWarner Losh   if (ISK(c)) {  /* is 'c' a constant? */
3588e3e3a7aSWarner Losh     TValue *kvalue = &p->k[INDEXK(c)];
3598e3e3a7aSWarner Losh     if (ttisstring(kvalue)) {  /* literal constant? */
3608e3e3a7aSWarner Losh       *name = svalue(kvalue);  /* it is its own name */
3618e3e3a7aSWarner Losh       return;
3628e3e3a7aSWarner Losh     }
3638e3e3a7aSWarner Losh     /* else no reasonable name found */
3648e3e3a7aSWarner Losh   }
3658e3e3a7aSWarner Losh   else {  /* 'c' is a register */
3668e3e3a7aSWarner Losh     const char *what = getobjname(p, pc, c, name); /* search for 'c' */
3678e3e3a7aSWarner Losh     if (what && *what == 'c') {  /* found a constant name? */
3688e3e3a7aSWarner Losh       return;  /* 'name' already filled */
3698e3e3a7aSWarner Losh     }
3708e3e3a7aSWarner Losh     /* else no reasonable name found */
3718e3e3a7aSWarner Losh   }
3728e3e3a7aSWarner Losh   *name = "?";  /* no reasonable name found */
3738e3e3a7aSWarner Losh }
3748e3e3a7aSWarner Losh 
3758e3e3a7aSWarner Losh 
3768e3e3a7aSWarner Losh static int filterpc (int pc, int jmptarget) {
3778e3e3a7aSWarner Losh   if (pc < jmptarget)  /* is code conditional (inside a jump)? */
3788e3e3a7aSWarner Losh     return -1;  /* cannot know who sets that register */
3798e3e3a7aSWarner Losh   else return pc;  /* current position sets that register */
3808e3e3a7aSWarner Losh }
3818e3e3a7aSWarner Losh 
3828e3e3a7aSWarner Losh 
3838e3e3a7aSWarner Losh /*
3848e3e3a7aSWarner Losh ** try to find last instruction before 'lastpc' that modified register 'reg'
3858e3e3a7aSWarner Losh */
3868e3e3a7aSWarner Losh static int findsetreg (Proto *p, int lastpc, int reg) {
3878e3e3a7aSWarner Losh   int pc;
3888e3e3a7aSWarner Losh   int setreg = -1;  /* keep last instruction that changed 'reg' */
3898e3e3a7aSWarner Losh   int jmptarget = 0;  /* any code before this address is conditional */
3908e3e3a7aSWarner Losh   for (pc = 0; pc < lastpc; pc++) {
3918e3e3a7aSWarner Losh     Instruction i = p->code[pc];
3928e3e3a7aSWarner Losh     OpCode op = GET_OPCODE(i);
3938e3e3a7aSWarner Losh     int a = GETARG_A(i);
3948e3e3a7aSWarner Losh     switch (op) {
3958e3e3a7aSWarner Losh       case OP_LOADNIL: {
3968e3e3a7aSWarner Losh         int b = GETARG_B(i);
3978e3e3a7aSWarner Losh         if (a <= reg && reg <= a + b)  /* set registers from 'a' to 'a+b' */
3988e3e3a7aSWarner Losh           setreg = filterpc(pc, jmptarget);
3998e3e3a7aSWarner Losh         break;
4008e3e3a7aSWarner Losh       }
4018e3e3a7aSWarner Losh       case OP_TFORCALL: {
4028e3e3a7aSWarner Losh         if (reg >= a + 2)  /* affect all regs above its base */
4038e3e3a7aSWarner Losh           setreg = filterpc(pc, jmptarget);
4048e3e3a7aSWarner Losh         break;
4058e3e3a7aSWarner Losh       }
4068e3e3a7aSWarner Losh       case OP_CALL:
4078e3e3a7aSWarner Losh       case OP_TAILCALL: {
4088e3e3a7aSWarner Losh         if (reg >= a)  /* affect all registers above base */
4098e3e3a7aSWarner Losh           setreg = filterpc(pc, jmptarget);
4108e3e3a7aSWarner Losh         break;
4118e3e3a7aSWarner Losh       }
4128e3e3a7aSWarner Losh       case OP_JMP: {
4138e3e3a7aSWarner Losh         int b = GETARG_sBx(i);
4148e3e3a7aSWarner Losh         int dest = pc + 1 + b;
4158e3e3a7aSWarner Losh         /* jump is forward and do not skip 'lastpc'? */
4168e3e3a7aSWarner Losh         if (pc < dest && dest <= lastpc) {
4178e3e3a7aSWarner Losh           if (dest > jmptarget)
4188e3e3a7aSWarner Losh             jmptarget = dest;  /* update 'jmptarget' */
4198e3e3a7aSWarner Losh         }
4208e3e3a7aSWarner Losh         break;
4218e3e3a7aSWarner Losh       }
4228e3e3a7aSWarner Losh       default:
4238e3e3a7aSWarner Losh         if (testAMode(op) && reg == a)  /* any instruction that set A */
4248e3e3a7aSWarner Losh           setreg = filterpc(pc, jmptarget);
4258e3e3a7aSWarner Losh         break;
4268e3e3a7aSWarner Losh     }
4278e3e3a7aSWarner Losh   }
4288e3e3a7aSWarner Losh   return setreg;
4298e3e3a7aSWarner Losh }
4308e3e3a7aSWarner Losh 
4318e3e3a7aSWarner Losh 
4328e3e3a7aSWarner Losh static const char *getobjname (Proto *p, int lastpc, int reg,
4338e3e3a7aSWarner Losh                                const char **name) {
4348e3e3a7aSWarner Losh   int pc;
4358e3e3a7aSWarner Losh   *name = luaF_getlocalname(p, reg + 1, lastpc);
4368e3e3a7aSWarner Losh   if (*name)  /* is a local? */
4378e3e3a7aSWarner Losh     return "local";
4388e3e3a7aSWarner Losh   /* else try symbolic execution */
4398e3e3a7aSWarner Losh   pc = findsetreg(p, lastpc, reg);
4408e3e3a7aSWarner Losh   if (pc != -1) {  /* could find instruction? */
4418e3e3a7aSWarner Losh     Instruction i = p->code[pc];
4428e3e3a7aSWarner Losh     OpCode op = GET_OPCODE(i);
4438e3e3a7aSWarner Losh     switch (op) {
4448e3e3a7aSWarner Losh       case OP_MOVE: {
4458e3e3a7aSWarner Losh         int b = GETARG_B(i);  /* move from 'b' to 'a' */
4468e3e3a7aSWarner Losh         if (b < GETARG_A(i))
4478e3e3a7aSWarner Losh           return getobjname(p, pc, b, name);  /* get name for 'b' */
4488e3e3a7aSWarner Losh         break;
4498e3e3a7aSWarner Losh       }
4508e3e3a7aSWarner Losh       case OP_GETTABUP:
4518e3e3a7aSWarner Losh       case OP_GETTABLE: {
4528e3e3a7aSWarner Losh         int k = GETARG_C(i);  /* key index */
4538e3e3a7aSWarner Losh         int t = GETARG_B(i);  /* table index */
4548e3e3a7aSWarner Losh         const char *vn = (op == OP_GETTABLE)  /* name of indexed variable */
4558e3e3a7aSWarner Losh                          ? luaF_getlocalname(p, t + 1, pc)
4568e3e3a7aSWarner Losh                          : upvalname(p, t);
4578e3e3a7aSWarner Losh         kname(p, pc, k, name);
4588e3e3a7aSWarner Losh         return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
4598e3e3a7aSWarner Losh       }
4608e3e3a7aSWarner Losh       case OP_GETUPVAL: {
4618e3e3a7aSWarner Losh         *name = upvalname(p, GETARG_B(i));
4628e3e3a7aSWarner Losh         return "upvalue";
4638e3e3a7aSWarner Losh       }
4648e3e3a7aSWarner Losh       case OP_LOADK:
4658e3e3a7aSWarner Losh       case OP_LOADKX: {
4668e3e3a7aSWarner Losh         int b = (op == OP_LOADK) ? GETARG_Bx(i)
4678e3e3a7aSWarner Losh                                  : GETARG_Ax(p->code[pc + 1]);
4688e3e3a7aSWarner Losh         if (ttisstring(&p->k[b])) {
4698e3e3a7aSWarner Losh           *name = svalue(&p->k[b]);
4708e3e3a7aSWarner Losh           return "constant";
4718e3e3a7aSWarner Losh         }
4728e3e3a7aSWarner Losh         break;
4738e3e3a7aSWarner Losh       }
4748e3e3a7aSWarner Losh       case OP_SELF: {
4758e3e3a7aSWarner Losh         int k = GETARG_C(i);  /* key index */
4768e3e3a7aSWarner Losh         kname(p, pc, k, name);
4778e3e3a7aSWarner Losh         return "method";
4788e3e3a7aSWarner Losh       }
4798e3e3a7aSWarner Losh       default: break;  /* go through to return NULL */
4808e3e3a7aSWarner Losh     }
4818e3e3a7aSWarner Losh   }
4828e3e3a7aSWarner Losh   return NULL;  /* could not find reasonable name */
4838e3e3a7aSWarner Losh }
4848e3e3a7aSWarner Losh 
4858e3e3a7aSWarner Losh 
4868e3e3a7aSWarner Losh /*
4878e3e3a7aSWarner Losh ** Try to find a name for a function based on the code that called it.
4888e3e3a7aSWarner Losh ** (Only works when function was called by a Lua function.)
4898e3e3a7aSWarner Losh ** Returns what the name is (e.g., "for iterator", "method",
4908e3e3a7aSWarner Losh ** "metamethod") and sets '*name' to point to the name.
4918e3e3a7aSWarner Losh */
4928e3e3a7aSWarner Losh static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
4938e3e3a7aSWarner Losh                                      const char **name) {
4948e3e3a7aSWarner Losh   TMS tm = (TMS)0;  /* (initial value avoids warnings) */
4958e3e3a7aSWarner Losh   Proto *p = ci_func(ci)->p;  /* calling function */
4968e3e3a7aSWarner Losh   int pc = currentpc(ci);  /* calling instruction index */
4978e3e3a7aSWarner Losh   Instruction i = p->code[pc];  /* calling instruction */
4988e3e3a7aSWarner Losh   if (ci->callstatus & CIST_HOOKED) {  /* was it called inside a hook? */
4998e3e3a7aSWarner Losh     *name = "?";
5008e3e3a7aSWarner Losh     return "hook";
5018e3e3a7aSWarner Losh   }
5028e3e3a7aSWarner Losh   switch (GET_OPCODE(i)) {
5038e3e3a7aSWarner Losh     case OP_CALL:
5048e3e3a7aSWarner Losh     case OP_TAILCALL:
5058e3e3a7aSWarner Losh       return getobjname(p, pc, GETARG_A(i), name);  /* get function name */
5068e3e3a7aSWarner Losh     case OP_TFORCALL: {  /* for iterator */
5078e3e3a7aSWarner Losh       *name = "for iterator";
5088e3e3a7aSWarner Losh        return "for iterator";
5098e3e3a7aSWarner Losh     }
5108e3e3a7aSWarner Losh     /* other instructions can do calls through metamethods */
5118e3e3a7aSWarner Losh     case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
5128e3e3a7aSWarner Losh       tm = TM_INDEX;
5138e3e3a7aSWarner Losh       break;
5148e3e3a7aSWarner Losh     case OP_SETTABUP: case OP_SETTABLE:
5158e3e3a7aSWarner Losh       tm = TM_NEWINDEX;
5168e3e3a7aSWarner Losh       break;
5178e3e3a7aSWarner Losh     case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD:
5188e3e3a7aSWarner Losh     case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND:
5198e3e3a7aSWarner Losh     case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: {
5208e3e3a7aSWarner Losh       int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD);  /* ORDER OP */
5218e3e3a7aSWarner Losh       tm = cast(TMS, offset + cast_int(TM_ADD));  /* ORDER TM */
5228e3e3a7aSWarner Losh       break;
5238e3e3a7aSWarner Losh     }
5248e3e3a7aSWarner Losh     case OP_UNM: tm = TM_UNM; break;
5258e3e3a7aSWarner Losh     case OP_BNOT: tm = TM_BNOT; break;
5268e3e3a7aSWarner Losh     case OP_LEN: tm = TM_LEN; break;
5278e3e3a7aSWarner Losh     case OP_CONCAT: tm = TM_CONCAT; break;
5288e3e3a7aSWarner Losh     case OP_EQ: tm = TM_EQ; break;
5298e3e3a7aSWarner Losh     case OP_LT: tm = TM_LT; break;
5308e3e3a7aSWarner Losh     case OP_LE: tm = TM_LE; break;
5318e3e3a7aSWarner Losh     default:
5328e3e3a7aSWarner Losh       return NULL;  /* cannot find a reasonable name */
5338e3e3a7aSWarner Losh   }
5348e3e3a7aSWarner Losh   *name = getstr(G(L)->tmname[tm]);
5358e3e3a7aSWarner Losh   return "metamethod";
5368e3e3a7aSWarner Losh }
5378e3e3a7aSWarner Losh 
5388e3e3a7aSWarner Losh /* }====================================================== */
5398e3e3a7aSWarner Losh 
5408e3e3a7aSWarner Losh 
5418e3e3a7aSWarner Losh 
5428e3e3a7aSWarner Losh /*
5438e3e3a7aSWarner Losh ** The subtraction of two potentially unrelated pointers is
5448e3e3a7aSWarner Losh ** not ISO C, but it should not crash a program; the subsequent
5458e3e3a7aSWarner Losh ** checks are ISO C and ensure a correct result.
5468e3e3a7aSWarner Losh */
5478e3e3a7aSWarner Losh static int isinstack (CallInfo *ci, const TValue *o) {
5488e3e3a7aSWarner Losh   ptrdiff_t i = o - ci->u.l.base;
5498e3e3a7aSWarner Losh   return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o);
5508e3e3a7aSWarner Losh }
5518e3e3a7aSWarner Losh 
5528e3e3a7aSWarner Losh 
5538e3e3a7aSWarner Losh /*
5548e3e3a7aSWarner Losh ** Checks whether value 'o' came from an upvalue. (That can only happen
5558e3e3a7aSWarner Losh ** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on
5568e3e3a7aSWarner Losh ** upvalues.)
5578e3e3a7aSWarner Losh */
5588e3e3a7aSWarner Losh static const char *getupvalname (CallInfo *ci, const TValue *o,
5598e3e3a7aSWarner Losh                                  const char **name) {
5608e3e3a7aSWarner Losh   LClosure *c = ci_func(ci);
5618e3e3a7aSWarner Losh   int i;
5628e3e3a7aSWarner Losh   for (i = 0; i < c->nupvalues; i++) {
5638e3e3a7aSWarner Losh     if (c->upvals[i]->v == o) {
5648e3e3a7aSWarner Losh       *name = upvalname(c->p, i);
5658e3e3a7aSWarner Losh       return "upvalue";
5668e3e3a7aSWarner Losh     }
5678e3e3a7aSWarner Losh   }
5688e3e3a7aSWarner Losh   return NULL;
5698e3e3a7aSWarner Losh }
5708e3e3a7aSWarner Losh 
5718e3e3a7aSWarner Losh 
5728e3e3a7aSWarner Losh static const char *varinfo (lua_State *L, const TValue *o) {
5738e3e3a7aSWarner Losh   const char *name = NULL;  /* to avoid warnings */
5748e3e3a7aSWarner Losh   CallInfo *ci = L->ci;
5758e3e3a7aSWarner Losh   const char *kind = NULL;
5768e3e3a7aSWarner Losh   if (isLua(ci)) {
5778e3e3a7aSWarner Losh     kind = getupvalname(ci, o, &name);  /* check whether 'o' is an upvalue */
5788e3e3a7aSWarner Losh     if (!kind && isinstack(ci, o))  /* no? try a register */
5798e3e3a7aSWarner Losh       kind = getobjname(ci_func(ci)->p, currentpc(ci),
5808e3e3a7aSWarner Losh                         cast_int(o - ci->u.l.base), &name);
5818e3e3a7aSWarner Losh   }
5828e3e3a7aSWarner Losh   return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : "";
5838e3e3a7aSWarner Losh }
5848e3e3a7aSWarner Losh 
5858e3e3a7aSWarner Losh 
5868e3e3a7aSWarner Losh l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
5878e3e3a7aSWarner Losh   const char *t = luaT_objtypename(L, o);
5888e3e3a7aSWarner Losh   luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
5898e3e3a7aSWarner Losh }
5908e3e3a7aSWarner Losh 
5918e3e3a7aSWarner Losh 
5928e3e3a7aSWarner Losh l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) {
5938e3e3a7aSWarner Losh   if (ttisstring(p1) || cvt2str(p1)) p1 = p2;
5948e3e3a7aSWarner Losh   luaG_typeerror(L, p1, "concatenate");
5958e3e3a7aSWarner Losh }
5968e3e3a7aSWarner Losh 
5978e3e3a7aSWarner Losh 
5988e3e3a7aSWarner Losh l_noret luaG_opinterror (lua_State *L, const TValue *p1,
5998e3e3a7aSWarner Losh                          const TValue *p2, const char *msg) {
6008e3e3a7aSWarner Losh   lua_Number temp;
6018e3e3a7aSWarner Losh   if (!tonumber(p1, &temp))  /* first operand is wrong? */
6028e3e3a7aSWarner Losh     p2 = p1;  /* now second is wrong */
6038e3e3a7aSWarner Losh   luaG_typeerror(L, p2, msg);
6048e3e3a7aSWarner Losh }
6058e3e3a7aSWarner Losh 
6068e3e3a7aSWarner Losh 
6078e3e3a7aSWarner Losh /*
6088e3e3a7aSWarner Losh ** Error when both values are convertible to numbers, but not to integers
6098e3e3a7aSWarner Losh */
6108e3e3a7aSWarner Losh l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
6118e3e3a7aSWarner Losh   lua_Integer temp;
6128e3e3a7aSWarner Losh   if (!tointeger(p1, &temp))
6138e3e3a7aSWarner Losh     p2 = p1;
6148e3e3a7aSWarner Losh   luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
6158e3e3a7aSWarner Losh }
6168e3e3a7aSWarner Losh 
6178e3e3a7aSWarner Losh 
6188e3e3a7aSWarner Losh l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
6198e3e3a7aSWarner Losh   const char *t1 = luaT_objtypename(L, p1);
6208e3e3a7aSWarner Losh   const char *t2 = luaT_objtypename(L, p2);
6218e3e3a7aSWarner Losh   if (strcmp(t1, t2) == 0)
6228e3e3a7aSWarner Losh     luaG_runerror(L, "attempt to compare two %s values", t1);
6238e3e3a7aSWarner Losh   else
6248e3e3a7aSWarner Losh     luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
6258e3e3a7aSWarner Losh }
6268e3e3a7aSWarner Losh 
6278e3e3a7aSWarner Losh 
6288e3e3a7aSWarner Losh /* add src:line information to 'msg' */
6298e3e3a7aSWarner Losh const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
6308e3e3a7aSWarner Losh                                         int line) {
6318e3e3a7aSWarner Losh   char buff[LUA_IDSIZE];
6328e3e3a7aSWarner Losh   if (src)
6338e3e3a7aSWarner Losh     luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
6348e3e3a7aSWarner Losh   else {  /* no source available; use "?" instead */
6358e3e3a7aSWarner Losh     buff[0] = '?'; buff[1] = '\0';
6368e3e3a7aSWarner Losh   }
6378e3e3a7aSWarner Losh   return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
6388e3e3a7aSWarner Losh }
6398e3e3a7aSWarner Losh 
6408e3e3a7aSWarner Losh 
6418e3e3a7aSWarner Losh l_noret luaG_errormsg (lua_State *L) {
6428e3e3a7aSWarner Losh   if (L->errfunc != 0) {  /* is there an error handling function? */
6438e3e3a7aSWarner Losh     StkId errfunc = restorestack(L, L->errfunc);
6448e3e3a7aSWarner Losh     setobjs2s(L, L->top, L->top - 1);  /* move argument */
6458e3e3a7aSWarner Losh     setobjs2s(L, L->top - 1, errfunc);  /* push function */
6468e3e3a7aSWarner Losh     L->top++;  /* assume EXTRA_STACK */
6478e3e3a7aSWarner Losh     luaD_callnoyield(L, L->top - 2, 1);  /* call it */
6488e3e3a7aSWarner Losh   }
6498e3e3a7aSWarner Losh   luaD_throw(L, LUA_ERRRUN);
6508e3e3a7aSWarner Losh }
6518e3e3a7aSWarner Losh 
6528e3e3a7aSWarner Losh 
6538e3e3a7aSWarner Losh l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
6548e3e3a7aSWarner Losh   CallInfo *ci = L->ci;
6558e3e3a7aSWarner Losh   const char *msg;
6568e3e3a7aSWarner Losh   va_list argp;
657e112e9d2SKyle Evans   luaC_checkGC(L);  /* error message uses memory */
6588e3e3a7aSWarner Losh   va_start(argp, fmt);
6598e3e3a7aSWarner Losh   msg = luaO_pushvfstring(L, fmt, argp);  /* format message */
6608e3e3a7aSWarner Losh   va_end(argp);
6618e3e3a7aSWarner Losh   if (isLua(ci))  /* if Lua function, add source:line information */
6628e3e3a7aSWarner Losh     luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
6638e3e3a7aSWarner Losh   luaG_errormsg(L);
6648e3e3a7aSWarner Losh }
6658e3e3a7aSWarner Losh 
6668e3e3a7aSWarner Losh 
6678e3e3a7aSWarner Losh void luaG_traceexec (lua_State *L) {
6688e3e3a7aSWarner Losh   CallInfo *ci = L->ci;
6698e3e3a7aSWarner Losh   lu_byte mask = L->hookmask;
6708e3e3a7aSWarner Losh   int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
6718e3e3a7aSWarner Losh   if (counthook)
6728e3e3a7aSWarner Losh     resethookcount(L);  /* reset count */
6738e3e3a7aSWarner Losh   else if (!(mask & LUA_MASKLINE))
6748e3e3a7aSWarner Losh     return;  /* no line hook and count != 0; nothing to be done */
6758e3e3a7aSWarner Losh   if (ci->callstatus & CIST_HOOKYIELD) {  /* called hook last time? */
6768e3e3a7aSWarner Losh     ci->callstatus &= ~CIST_HOOKYIELD;  /* erase mark */
6778e3e3a7aSWarner Losh     return;  /* do not call hook again (VM yielded, so it did not move) */
6788e3e3a7aSWarner Losh   }
6798e3e3a7aSWarner Losh   if (counthook)
6808e3e3a7aSWarner Losh     luaD_hook(L, LUA_HOOKCOUNT, -1);  /* call count hook */
6818e3e3a7aSWarner Losh   if (mask & LUA_MASKLINE) {
6828e3e3a7aSWarner Losh     Proto *p = ci_func(ci)->p;
6838e3e3a7aSWarner Losh     int npc = pcRel(ci->u.l.savedpc, p);
6848e3e3a7aSWarner Losh     int newline = getfuncline(p, npc);
6858e3e3a7aSWarner Losh     if (npc == 0 ||  /* call linehook when enter a new function, */
6868e3e3a7aSWarner Losh         ci->u.l.savedpc <= L->oldpc ||  /* when jump back (loop), or when */
6878e3e3a7aSWarner Losh         newline != getfuncline(p, pcRel(L->oldpc, p)))  /* enter a new line */
6888e3e3a7aSWarner Losh       luaD_hook(L, LUA_HOOKLINE, newline);  /* call line hook */
6898e3e3a7aSWarner Losh   }
6908e3e3a7aSWarner Losh   L->oldpc = ci->u.l.savedpc;
6918e3e3a7aSWarner Losh   if (L->status == LUA_YIELD) {  /* did hook yield? */
6928e3e3a7aSWarner Losh     if (counthook)
6938e3e3a7aSWarner Losh       L->hookcount = 1;  /* undo decrement to zero */
6948e3e3a7aSWarner Losh     ci->u.l.savedpc--;  /* undo increment (resume will increment it again) */
6958e3e3a7aSWarner Losh     ci->callstatus |= CIST_HOOKYIELD;  /* mark that it yielded */
6968e3e3a7aSWarner Losh     ci->func = L->top - 1;  /* protect stack below results */
6978e3e3a7aSWarner Losh     luaD_throw(L, LUA_YIELD);
6988e3e3a7aSWarner Losh   }
6998e3e3a7aSWarner Losh }
7008e3e3a7aSWarner Losh 
701