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