Path: blob/main/sys/contrib/openzfs/module/lua/ldebug.c
48383 views
// SPDX-License-Identifier: MIT1/*2** $Id: ldebug.c,v 2.90.1.4 2015/02/19 17:05:13 roberto Exp $3** Debug Interface4** See Copyright Notice in lua.h5*/678#define ldebug_c9#define LUA_CORE1011#include <sys/lua/lua.h>1213#include "lapi.h"14#include "lcode.h"15#include "ldebug.h"16#include "ldo.h"17#include "lfunc.h"18#include "lobject.h"19#include "lopcodes.h"20#include "lstate.h"21#include "lstring.h"22#include "ltable.h"23#include "ltm.h"24#include "lvm.h"25262728#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)293031static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);323334static int currentpc (CallInfo *ci) {35lua_assert(isLua(ci));36return pcRel(ci->u.l.savedpc, ci_func(ci)->p);37}383940static int currentline (CallInfo *ci) {41return getfuncline(ci_func(ci)->p, currentpc(ci));42}434445static void swapextra (lua_State *L) {46if (L->status == LUA_YIELD) {47CallInfo *ci = L->ci; /* get function that yielded */48StkId temp = ci->func; /* exchange its 'func' and 'extra' values */49ci->func = restorestack(L, ci->extra);50ci->extra = savestack(L, temp);51}52}535455/*56** this function can be called asynchronous (e.g. during a signal)57*/58LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {59if (func == NULL || mask == 0) { /* turn off hooks? */60mask = 0;61func = NULL;62}63if (isLua(L->ci))64L->oldpc = L->ci->u.l.savedpc;65L->hook = func;66L->basehookcount = count;67resethookcount(L);68L->hookmask = cast_byte(mask);69return 1;70}717273LUA_API lua_Hook lua_gethook (lua_State *L) {74return L->hook;75}767778LUA_API int lua_gethookmask (lua_State *L) {79return L->hookmask;80}818283LUA_API int lua_gethookcount (lua_State *L) {84return L->basehookcount;85}868788LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {89int status;90CallInfo *ci;91if (level < 0) return 0; /* invalid (negative) level */92lua_lock(L);93for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)94level--;95if (level == 0 && ci != &L->base_ci) { /* level found? */96status = 1;97ar->i_ci = ci;98}99else status = 0; /* no such level */100lua_unlock(L);101return status;102}103104105static const char *upvalname (Proto *p, int uv) {106TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);107if (s == NULL) return "?";108else return getstr(s);109}110111112static const char *findvararg (CallInfo *ci, int n, StkId *pos) {113int nparams = clLvalue(ci->func)->p->numparams;114int nvararg = cast_int(ci->u.l.base - ci->func) - nparams;115if (n <= -nvararg)116return NULL; /* no such vararg */117else {118*pos = ci->func + nparams - n;119return "(*vararg)"; /* generic name for any vararg */120}121}122123124static const char *findlocal (lua_State *L, CallInfo *ci, int n,125StkId *pos) {126const char *name = NULL;127StkId base;128if (isLua(ci)) {129if (n < 0) /* access to vararg values? */130return findvararg(ci, n, pos);131else {132base = ci->u.l.base;133name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));134}135}136else137base = ci->func + 1;138if (name == NULL) { /* no 'standard' name? */139StkId limit = (ci == L->ci) ? L->top : ci->next->func;140if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */141name = "(*temporary)"; /* generic name for any valid slot */142else143return NULL; /* no name */144}145*pos = base + (n - 1);146return name;147}148149150LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {151const char *name;152lua_lock(L);153swapextra(L);154if (ar == NULL) { /* information about non-active function? */155if (!isLfunction(L->top - 1)) /* not a Lua function? */156name = NULL;157else /* consider live variables at function start (parameters) */158name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);159}160else { /* active function; get information through 'ar' */161StkId pos = 0; /* to avoid warnings */162name = findlocal(L, ar->i_ci, n, &pos);163if (name) {164setobj2s(L, L->top, pos);165api_incr_top(L);166}167}168swapextra(L);169lua_unlock(L);170return name;171}172173174LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {175StkId pos = 0; /* to avoid warnings */176const char *name;177lua_lock(L);178swapextra(L);179name = findlocal(L, ar->i_ci, n, &pos);180if (name)181setobjs2s(L, pos, L->top - 1);182L->top--; /* pop value */183swapextra(L);184lua_unlock(L);185return name;186}187188189static void funcinfo (lua_Debug *ar, Closure *cl) {190if (noLuaClosure(cl)) {191ar->source = "=[C]";192ar->linedefined = -1;193ar->lastlinedefined = -1;194ar->what = "C";195}196else {197Proto *p = cl->l.p;198ar->source = p->source ? getstr(p->source) : "=?";199ar->linedefined = p->linedefined;200ar->lastlinedefined = p->lastlinedefined;201ar->what = (ar->linedefined == 0) ? "main" : "Lua";202}203luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);204}205206207static void collectvalidlines (lua_State *L, Closure *f) {208if (noLuaClosure(f)) {209setnilvalue(L->top);210api_incr_top(L);211}212else {213int i;214TValue v;215int *lineinfo = f->l.p->lineinfo;216Table *t = luaH_new(L); /* new table to store active lines */217sethvalue(L, L->top, t); /* push it on stack */218api_incr_top(L);219setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */220for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */221luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */222}223}224225226static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,227Closure *f, CallInfo *ci) {228int status = 1;229for (; *what; what++) {230switch (*what) {231case 'S': {232funcinfo(ar, f);233break;234}235case 'l': {236ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;237break;238}239case 'u': {240ar->nups = (f == NULL) ? 0 : f->c.nupvalues;241if (noLuaClosure(f)) {242ar->isvararg = 1;243ar->nparams = 0;244}245else {246ar->isvararg = f->l.p->is_vararg;247ar->nparams = f->l.p->numparams;248}249break;250}251case 't': {252ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;253break;254}255case 'n': {256/* calling function is a known Lua function? */257if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))258ar->namewhat = getfuncname(L, ci->previous, &ar->name);259else260ar->namewhat = NULL;261if (ar->namewhat == NULL) {262ar->namewhat = ""; /* not found */263ar->name = NULL;264}265break;266}267case 'L':268case 'f': /* handled by lua_getinfo */269break;270default: status = 0; /* invalid option */271}272}273return status;274}275276277LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {278int status;279Closure *cl;280CallInfo *ci;281StkId func;282lua_lock(L);283swapextra(L);284if (*what == '>') {285ci = NULL;286func = L->top - 1;287api_check(L, ttisfunction(func), "function expected");288what++; /* skip the '>' */289L->top--; /* pop function */290}291else {292ci = ar->i_ci;293func = ci->func;294lua_assert(ttisfunction(ci->func));295}296cl = ttisclosure(func) ? clvalue(func) : NULL;297status = auxgetinfo(L, what, ar, cl, ci);298if (strchr(what, 'f')) {299setobjs2s(L, L->top, func);300api_incr_top(L);301}302swapextra(L);303if (strchr(what, 'L'))304collectvalidlines(L, cl);305lua_unlock(L);306return status;307}308309310/*311** {======================================================312** Symbolic Execution313** =======================================================314*/315316static const char *getobjname (Proto *p, int lastpc, int reg,317const char **name);318319320/*321** find a "name" for the RK value 'c'322*/323static void kname (Proto *p, int pc, int c, const char **name) {324if (ISK(c)) { /* is 'c' a constant? */325TValue *kvalue = &p->k[INDEXK(c)];326if (ttisstring(kvalue)) { /* literal constant? */327*name = svalue(kvalue); /* it is its own name */328return;329}330/* else no reasonable name found */331}332else { /* 'c' is a register */333const char *what = getobjname(p, pc, c, name); /* search for 'c' */334if (what && *what == 'c') { /* found a constant name? */335return; /* 'name' already filled */336}337/* else no reasonable name found */338}339*name = "?"; /* no reasonable name found */340}341342343static int filterpc (int pc, int jmptarget) {344if (pc < jmptarget) /* is code conditional (inside a jump)? */345return -1; /* cannot know who sets that register */346else return pc; /* current position sets that register */347}348349350/*351** try to find last instruction before 'lastpc' that modified register 'reg'352*/353static int findsetreg (Proto *p, int lastpc, int reg) {354int pc;355int setreg = -1; /* keep last instruction that changed 'reg' */356int jmptarget = 0; /* any code before this address is conditional */357for (pc = 0; pc < lastpc; pc++) {358Instruction i = p->code[pc];359OpCode op = GET_OPCODE(i);360int a = GETARG_A(i);361switch (op) {362case OP_LOADNIL: {363int b = GETARG_B(i);364if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */365setreg = filterpc(pc, jmptarget);366break;367}368case OP_TFORCALL: {369if (reg >= a + 2) /* affect all regs above its base */370setreg = filterpc(pc, jmptarget);371break;372}373case OP_CALL:374case OP_TAILCALL: {375if (reg >= a) /* affect all registers above base */376setreg = filterpc(pc, jmptarget);377break;378}379case OP_JMP: {380int b = GETARG_sBx(i);381int dest = pc + 1 + b;382/* jump is forward and do not skip `lastpc'? */383if (pc < dest && dest <= lastpc) {384if (dest > jmptarget)385jmptarget = dest; /* update 'jmptarget' */386}387break;388}389case OP_TEST: {390if (reg == a) /* jumped code can change 'a' */391setreg = filterpc(pc, jmptarget);392break;393}394default:395if (testAMode(op) && reg == a) /* any instruction that set A */396setreg = filterpc(pc, jmptarget);397break;398}399}400return setreg;401}402403404static const char *getobjname (Proto *p, int lastpc, int reg,405const char **name) {406int pc;407*name = luaF_getlocalname(p, reg + 1, lastpc);408if (*name) /* is a local? */409return "local";410/* else try symbolic execution */411pc = findsetreg(p, lastpc, reg);412if (pc != -1) { /* could find instruction? */413Instruction i = p->code[pc];414OpCode op = GET_OPCODE(i);415switch (op) {416case OP_MOVE: {417int b = GETARG_B(i); /* move from 'b' to 'a' */418if (b < GETARG_A(i))419return getobjname(p, pc, b, name); /* get name for 'b' */420break;421}422case OP_GETTABUP:423case OP_GETTABLE: {424int k = GETARG_C(i); /* key index */425int t = GETARG_B(i); /* table index */426const char *vn = (op == OP_GETTABLE) /* name of indexed variable */427? luaF_getlocalname(p, t + 1, pc)428: upvalname(p, t);429kname(p, pc, k, name);430return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";431}432case OP_GETUPVAL: {433*name = upvalname(p, GETARG_B(i));434return "upvalue";435}436case OP_LOADK:437case OP_LOADKX: {438int b = (op == OP_LOADK) ? GETARG_Bx(i)439: GETARG_Ax(p->code[pc + 1]);440if (ttisstring(&p->k[b])) {441*name = svalue(&p->k[b]);442return "constant";443}444break;445}446case OP_SELF: {447int k = GETARG_C(i); /* key index */448kname(p, pc, k, name);449return "method";450}451default: break; /* go through to return NULL */452}453}454return NULL; /* could not find reasonable name */455}456457458static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {459TMS tm;460Proto *p = ci_func(ci)->p; /* calling function */461int pc = currentpc(ci); /* calling instruction index */462Instruction i = p->code[pc]; /* calling instruction */463switch (GET_OPCODE(i)) {464case OP_CALL:465case OP_TAILCALL: /* get function name */466return getobjname(p, pc, GETARG_A(i), name);467case OP_TFORCALL: { /* for iterator */468*name = "for iterator";469return "for iterator";470}471/* all other instructions can call only through metamethods */472case OP_SELF:473case OP_GETTABUP:474case OP_GETTABLE: tm = TM_INDEX; break;475case OP_SETTABUP:476case OP_SETTABLE: tm = TM_NEWINDEX; break;477case OP_EQ: tm = TM_EQ; break;478case OP_ADD: tm = TM_ADD; break;479case OP_SUB: tm = TM_SUB; break;480case OP_MUL: tm = TM_MUL; break;481case OP_DIV: tm = TM_DIV; break;482case OP_MOD: tm = TM_MOD; break;483case OP_POW: tm = TM_POW; break;484case OP_UNM: tm = TM_UNM; break;485case OP_LEN: tm = TM_LEN; break;486case OP_LT: tm = TM_LT; break;487case OP_LE: tm = TM_LE; break;488case OP_CONCAT: tm = TM_CONCAT; break;489default:490return NULL; /* else no useful name can be found */491}492*name = getstr(G(L)->tmname[tm]);493return "metamethod";494}495496/* }====================================================== */497498499500/*501** only ANSI way to check whether a pointer points to an array502** (used only for error messages, so efficiency is not a big concern)503*/504static int isinstack (CallInfo *ci, const TValue *o) {505StkId p;506for (p = ci->u.l.base; p < ci->top; p++)507if (o == p) return 1;508return 0;509}510511512static const char *getupvalname (CallInfo *ci, const TValue *o,513const char **name) {514LClosure *c = ci_func(ci);515int i;516for (i = 0; i < c->nupvalues; i++) {517if (c->upvals[i]->v == o) {518*name = upvalname(c->p, i);519return "upvalue";520}521}522return NULL;523}524525526l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {527CallInfo *ci = L->ci;528const char *name = NULL;529const char *t = objtypename(o);530const char *kind = NULL;531if (isLua(ci)) {532kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */533if (!kind && isinstack(ci, o)) /* no? try a register */534kind = getobjname(ci_func(ci)->p, currentpc(ci),535cast_int(o - ci->u.l.base), &name);536}537if (kind)538luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",539op, kind, name, t);540else541luaG_runerror(L, "attempt to %s a %s value", op, t);542}543544545l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) {546if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;547lua_assert(!ttisstring(p1) && !ttisnumber(p1));548luaG_typeerror(L, p1, "concatenate");549}550551552l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {553TValue temp;554if (luaV_tonumber(p1, &temp) == NULL)555p2 = p1; /* first operand is wrong */556luaG_typeerror(L, p2, "perform arithmetic on");557}558559560l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {561const char *t1 = objtypename(p1);562const char *t2 = objtypename(p2);563if (t1 == t2)564luaG_runerror(L, "attempt to compare two %s values", t1);565else566luaG_runerror(L, "attempt to compare %s with %s", t1, t2);567}568569570static void addinfo (lua_State *L, const char *msg) {571CallInfo *ci = L->ci;572if (isLua(ci)) { /* is Lua code? */573char buff[LUA_IDSIZE]; /* add file:line information */574int line = currentline(ci);575TString *src = ci_func(ci)->p->source;576if (src)577luaO_chunkid(buff, getstr(src), LUA_IDSIZE);578else { /* no source available; use "?" instead */579buff[0] = '?'; buff[1] = '\0';580}581luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);582}583}584585586l_noret luaG_errormsg (lua_State *L) {587if (L->errfunc != 0) { /* is there an error handling function? */588StkId errfunc = restorestack(L, L->errfunc);589if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);590setobjs2s(L, L->top, L->top - 1); /* move argument */591setobjs2s(L, L->top - 1, errfunc); /* push function */592L->top++;593luaD_call(L, L->top - 2, 1, 0); /* call it */594}595luaD_throw(L, LUA_ERRRUN);596}597598599l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {600L->runerror++;601va_list argp;602va_start(argp, fmt);603addinfo(L, luaO_pushvfstring(L, fmt, argp));604va_end(argp);605luaG_errormsg(L);606L->runerror--;607}608609610