rlm@1: /* rlm@1: ** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $ rlm@1: ** Debug Interface rlm@1: ** See Copyright Notice in lua.h rlm@1: */ rlm@1: rlm@1: rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: rlm@1: #define ldebug_c rlm@1: #define LUA_CORE rlm@1: rlm@1: #include "lua.h" rlm@1: rlm@1: #include "lapi.h" rlm@1: #include "lcode.h" rlm@1: #include "ldebug.h" rlm@1: #include "ldo.h" rlm@1: #include "lfunc.h" rlm@1: #include "lobject.h" rlm@1: #include "lopcodes.h" rlm@1: #include "lstate.h" rlm@1: #include "lstring.h" rlm@1: #include "ltable.h" rlm@1: #include "ltm.h" rlm@1: #include "lvm.h" rlm@1: rlm@1: rlm@1: rlm@1: static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); rlm@1: rlm@1: rlm@1: static int currentpc (lua_State *L, CallInfo *ci) { rlm@1: if (!isLua(ci)) return -1; /* function is not a Lua function? */ rlm@1: if (ci == L->ci) rlm@1: ci->savedpc = L->savedpc; rlm@1: return pcRel(ci->savedpc, ci_func(ci)->l.p); rlm@1: } rlm@1: rlm@1: rlm@1: static int currentline (lua_State *L, CallInfo *ci) { rlm@1: int pc = currentpc(L, ci); rlm@1: if (pc < 0) rlm@1: return -1; /* only active lua functions have current-line information */ rlm@1: else rlm@1: return getline(ci_func(ci)->l.p, pc); rlm@1: } rlm@1: rlm@1: rlm@1: /* rlm@1: ** this function can be called asynchronous (e.g. during a signal) rlm@1: */ rlm@1: LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { rlm@1: if (func == NULL || mask == 0) { /* turn off hooks? */ rlm@1: mask = 0; rlm@1: func = NULL; rlm@1: } rlm@1: L->hook = func; rlm@1: L->basehookcount = count; rlm@1: resethookcount(L); rlm@1: L->hookmask = cast_byte(mask); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API lua_Hook lua_gethook (lua_State *L) { rlm@1: return L->hook; rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API int lua_gethookmask (lua_State *L) { rlm@1: return L->hookmask; rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API int lua_gethookcount (lua_State *L) { rlm@1: return L->basehookcount; rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { rlm@1: int status; rlm@1: CallInfo *ci; rlm@1: lua_lock(L); rlm@1: for (ci = L->ci; level > 0 && ci > L->base_ci; ci--) { rlm@1: level--; rlm@1: if (f_isLua(ci)) /* Lua function? */ rlm@1: level -= ci->tailcalls; /* skip lost tail calls */ rlm@1: } rlm@1: if (level == 0 && ci > L->base_ci) { /* level found? */ rlm@1: status = 1; rlm@1: ar->i_ci = cast_int(ci - L->base_ci); rlm@1: } rlm@1: else if (level < 0) { /* level is of a lost tail call? */ rlm@1: status = 1; rlm@1: ar->i_ci = 0; rlm@1: } rlm@1: else status = 0; /* no such level */ rlm@1: lua_unlock(L); rlm@1: return status; rlm@1: } rlm@1: rlm@1: rlm@1: static Proto *getluaproto (CallInfo *ci) { rlm@1: return (isLua(ci) ? ci_func(ci)->l.p : NULL); rlm@1: } rlm@1: rlm@1: rlm@1: static const char *findlocal (lua_State *L, CallInfo *ci, int n) { rlm@1: const char *name; rlm@1: Proto *fp = getluaproto(ci); rlm@1: if (fp && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != NULL) rlm@1: return name; /* is a local variable in a Lua function */ rlm@1: else { rlm@1: StkId limit = (ci == L->ci) ? L->top : (ci+1)->func; rlm@1: if (limit - ci->base >= n && n > 0) /* is 'n' inside 'ci' stack? */ rlm@1: return "(*temporary)"; rlm@1: else rlm@1: return NULL; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { rlm@1: CallInfo *ci = L->base_ci + ar->i_ci; rlm@1: const char *name = findlocal(L, ci, n); rlm@1: lua_lock(L); rlm@1: if (name) rlm@1: luaA_pushobject(L, ci->base + (n - 1)); rlm@1: lua_unlock(L); rlm@1: return name; rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { rlm@1: CallInfo *ci = L->base_ci + ar->i_ci; rlm@1: const char *name = findlocal(L, ci, n); rlm@1: lua_lock(L); rlm@1: if (name) rlm@1: setobjs2s(L, ci->base + (n - 1), L->top - 1); rlm@1: L->top--; /* pop value */ rlm@1: lua_unlock(L); rlm@1: return name; rlm@1: } rlm@1: rlm@1: rlm@1: static void funcinfo (lua_Debug *ar, Closure *cl) { rlm@1: if (cl->c.isC) { rlm@1: ar->source = "=[C]"; rlm@1: ar->linedefined = -1; rlm@1: ar->lastlinedefined = -1; rlm@1: ar->what = "C"; rlm@1: } rlm@1: else { rlm@1: ar->source = getstr(cl->l.p->source); rlm@1: ar->linedefined = cl->l.p->linedefined; rlm@1: ar->lastlinedefined = cl->l.p->lastlinedefined; rlm@1: ar->what = (ar->linedefined == 0) ? "main" : "Lua"; rlm@1: } rlm@1: luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); rlm@1: } rlm@1: rlm@1: rlm@1: static void info_tailcall (lua_Debug *ar) { rlm@1: ar->name = ar->namewhat = ""; rlm@1: ar->what = "tail"; rlm@1: ar->lastlinedefined = ar->linedefined = ar->currentline = -1; rlm@1: ar->source = "=(tail call)"; rlm@1: luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); rlm@1: ar->nups = 0; rlm@1: } rlm@1: rlm@1: rlm@1: static void collectvalidlines (lua_State *L, Closure *f) { rlm@1: if (f == NULL || f->c.isC) { rlm@1: setnilvalue(L->top); rlm@1: } rlm@1: else { rlm@1: Table *t = luaH_new(L, 0, 0); rlm@1: int *lineinfo = f->l.p->lineinfo; rlm@1: int i; rlm@1: for (i=0; il.p->sizelineinfo; i++) rlm@1: setbvalue(luaH_setnum(L, t, lineinfo[i]), 1); rlm@1: sethvalue(L, L->top, t); rlm@1: } rlm@1: incr_top(L); rlm@1: } rlm@1: rlm@1: rlm@1: static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, rlm@1: Closure *f, CallInfo *ci) { rlm@1: int status = 1; rlm@1: if (f == NULL) { rlm@1: info_tailcall(ar); rlm@1: return status; rlm@1: } rlm@1: for (; *what; what++) { rlm@1: switch (*what) { rlm@1: case 'S': { rlm@1: funcinfo(ar, f); rlm@1: break; rlm@1: } rlm@1: case 'l': { rlm@1: ar->currentline = (ci) ? currentline(L, ci) : -1; rlm@1: break; rlm@1: } rlm@1: case 'u': { rlm@1: ar->nups = f->c.nupvalues; rlm@1: break; rlm@1: } rlm@1: case 'n': { rlm@1: ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL; rlm@1: if (ar->namewhat == NULL) { rlm@1: ar->namewhat = ""; /* not found */ rlm@1: ar->name = NULL; rlm@1: } rlm@1: break; rlm@1: } rlm@1: case 'L': rlm@1: case 'f': /* handled by lua_getinfo */ rlm@1: break; rlm@1: default: status = 0; /* invalid option */ rlm@1: } rlm@1: } rlm@1: return status; rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { rlm@1: int status; rlm@1: Closure *f = NULL; rlm@1: CallInfo *ci = NULL; rlm@1: lua_lock(L); rlm@1: if (*what == '>') { rlm@1: StkId func = L->top - 1; rlm@1: luai_apicheck(L, ttisfunction(func)); rlm@1: what++; /* skip the '>' */ rlm@1: f = clvalue(func); rlm@1: L->top--; /* pop function */ rlm@1: } rlm@1: else if (ar->i_ci != 0) { /* no tail call? */ rlm@1: ci = L->base_ci + ar->i_ci; rlm@1: lua_assert(ttisfunction(ci->func)); rlm@1: f = clvalue(ci->func); rlm@1: } rlm@1: status = auxgetinfo(L, what, ar, f, ci); rlm@1: if (strchr(what, 'f')) { rlm@1: if (f == NULL) setnilvalue(L->top); rlm@1: else setclvalue(L, L->top, f); rlm@1: incr_top(L); rlm@1: } rlm@1: if (strchr(what, 'L')) rlm@1: collectvalidlines(L, f); rlm@1: lua_unlock(L); rlm@1: return status; rlm@1: } rlm@1: rlm@1: rlm@1: /* rlm@1: ** {====================================================== rlm@1: ** Symbolic Execution and code checker rlm@1: ** ======================================================= rlm@1: */ rlm@1: rlm@1: #define check(x) if (!(x)) return 0; rlm@1: rlm@1: #define checkjump(pt,pc) check(0 <= pc && pc < pt->sizecode) rlm@1: rlm@1: #define checkreg(pt,reg) check((reg) < (pt)->maxstacksize) rlm@1: rlm@1: rlm@1: rlm@1: static int precheck (const Proto *pt) { rlm@1: check(pt->maxstacksize <= MAXSTACK); rlm@1: check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize); rlm@1: check(!(pt->is_vararg & VARARG_NEEDSARG) || rlm@1: (pt->is_vararg & VARARG_HASARG)); rlm@1: check(pt->sizeupvalues <= pt->nups); rlm@1: check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0); rlm@1: check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: #define checkopenop(pt,pc) luaG_checkopenop((pt)->code[(pc)+1]) rlm@1: rlm@1: int luaG_checkopenop (Instruction i) { rlm@1: switch (GET_OPCODE(i)) { rlm@1: case OP_CALL: rlm@1: case OP_TAILCALL: rlm@1: case OP_RETURN: rlm@1: case OP_SETLIST: { rlm@1: check(GETARG_B(i) == 0); rlm@1: return 1; rlm@1: } rlm@1: default: return 0; /* invalid instruction after an open call */ rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static int checkArgMode (const Proto *pt, int r, enum OpArgMask mode) { rlm@1: switch (mode) { rlm@1: case OpArgN: check(r == 0); break; rlm@1: case OpArgU: break; rlm@1: case OpArgR: checkreg(pt, r); break; rlm@1: case OpArgK: rlm@1: check(ISK(r) ? INDEXK(r) < pt->sizek : r < pt->maxstacksize); rlm@1: break; rlm@1: } rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static Instruction symbexec (const Proto *pt, int lastpc, int reg) { rlm@1: int pc; rlm@1: int last; /* stores position of last instruction that changed `reg' */ rlm@1: last = pt->sizecode-1; /* points to final return (a `neutral' instruction) */ rlm@1: check(precheck(pt)); rlm@1: for (pc = 0; pc < lastpc; pc++) { rlm@1: Instruction i = pt->code[pc]; rlm@1: OpCode op = GET_OPCODE(i); rlm@1: int a = GETARG_A(i); rlm@1: int b = 0; rlm@1: int c = 0; rlm@1: check(op < NUM_OPCODES); rlm@1: checkreg(pt, a); rlm@1: switch (getOpMode(op)) { rlm@1: case iABC: { rlm@1: b = GETARG_B(i); rlm@1: c = GETARG_C(i); rlm@1: check(checkArgMode(pt, b, getBMode(op))); rlm@1: check(checkArgMode(pt, c, getCMode(op))); rlm@1: break; rlm@1: } rlm@1: case iABx: { rlm@1: b = GETARG_Bx(i); rlm@1: if (getBMode(op) == OpArgK) check(b < pt->sizek); rlm@1: break; rlm@1: } rlm@1: case iAsBx: { rlm@1: b = GETARG_sBx(i); rlm@1: if (getBMode(op) == OpArgR) { rlm@1: int dest = pc+1+b; rlm@1: check(0 <= dest && dest < pt->sizecode); rlm@1: if (dest > 0) { rlm@1: int j; rlm@1: /* check that it does not jump to a setlist count; this rlm@1: is tricky, because the count from a previous setlist may rlm@1: have the same value of an invalid setlist; so, we must rlm@1: go all the way back to the first of them (if any) */ rlm@1: for (j = 0; j < dest; j++) { rlm@1: Instruction d = pt->code[dest-1-j]; rlm@1: if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break; rlm@1: } rlm@1: /* if 'j' is even, previous value is not a setlist (even if rlm@1: it looks like one) */ rlm@1: check((j&1) == 0); rlm@1: } rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: if (testAMode(op)) { rlm@1: if (a == reg) last = pc; /* change register `a' */ rlm@1: } rlm@1: if (testTMode(op)) { rlm@1: check(pc+2 < pt->sizecode); /* check skip */ rlm@1: check(GET_OPCODE(pt->code[pc+1]) == OP_JMP); rlm@1: } rlm@1: switch (op) { rlm@1: case OP_LOADBOOL: { rlm@1: if (c == 1) { /* does it jump? */ rlm@1: check(pc+2 < pt->sizecode); /* check its jump */ rlm@1: check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST || rlm@1: GETARG_C(pt->code[pc+1]) != 0); rlm@1: } rlm@1: break; rlm@1: } rlm@1: case OP_LOADNIL: { rlm@1: if (a <= reg && reg <= b) rlm@1: last = pc; /* set registers from `a' to `b' */ rlm@1: break; rlm@1: } rlm@1: case OP_GETUPVAL: rlm@1: case OP_SETUPVAL: { rlm@1: check(b < pt->nups); rlm@1: break; rlm@1: } rlm@1: case OP_GETGLOBAL: rlm@1: case OP_SETGLOBAL: { rlm@1: check(ttisstring(&pt->k[b])); rlm@1: break; rlm@1: } rlm@1: case OP_SELF: { rlm@1: checkreg(pt, a+1); rlm@1: if (reg == a+1) last = pc; rlm@1: break; rlm@1: } rlm@1: case OP_CONCAT: { rlm@1: check(b < c); /* at least two operands */ rlm@1: break; rlm@1: } rlm@1: case OP_TFORLOOP: { rlm@1: check(c >= 1); /* at least one result (control variable) */ rlm@1: checkreg(pt, a+2+c); /* space for results */ rlm@1: if (reg >= a+2) last = pc; /* affect all regs above its base */ rlm@1: break; rlm@1: } rlm@1: case OP_FORLOOP: rlm@1: case OP_FORPREP: rlm@1: checkreg(pt, a+3); rlm@1: /* go through */ rlm@1: case OP_JMP: { rlm@1: int dest = pc+1+b; rlm@1: /* not full check and jump is forward and do not skip `lastpc'? */ rlm@1: if (reg != NO_REG && pc < dest && dest <= lastpc) rlm@1: pc += b; /* do the jump */ rlm@1: break; rlm@1: } rlm@1: case OP_CALL: rlm@1: case OP_TAILCALL: { rlm@1: if (b != 0) { rlm@1: checkreg(pt, a+b-1); rlm@1: } rlm@1: c--; /* c = num. returns */ rlm@1: if (c == LUA_MULTRET) { rlm@1: check(checkopenop(pt, pc)); rlm@1: } rlm@1: else if (c != 0) rlm@1: checkreg(pt, a+c-1); rlm@1: if (reg >= a) last = pc; /* affect all registers above base */ rlm@1: break; rlm@1: } rlm@1: case OP_RETURN: { rlm@1: b--; /* b = num. returns */ rlm@1: if (b > 0) checkreg(pt, a+b-1); rlm@1: break; rlm@1: } rlm@1: case OP_SETLIST: { rlm@1: if (b > 0) checkreg(pt, a + b); rlm@1: if (c == 0) { rlm@1: pc++; rlm@1: check(pc < pt->sizecode - 1); rlm@1: } rlm@1: break; rlm@1: } rlm@1: case OP_CLOSURE: { rlm@1: int nup, j; rlm@1: check(b < pt->sizep); rlm@1: nup = pt->p[b]->nups; rlm@1: check(pc + nup < pt->sizecode); rlm@1: for (j = 1; j <= nup; j++) { rlm@1: OpCode op1 = GET_OPCODE(pt->code[pc + j]); rlm@1: check(op1 == OP_GETUPVAL || op1 == OP_MOVE); rlm@1: } rlm@1: if (reg != NO_REG) /* tracing? */ rlm@1: pc += nup; /* do not 'execute' these pseudo-instructions */ rlm@1: break; rlm@1: } rlm@1: case OP_VARARG: { rlm@1: check((pt->is_vararg & VARARG_ISVARARG) && rlm@1: !(pt->is_vararg & VARARG_NEEDSARG)); rlm@1: b--; rlm@1: if (b == LUA_MULTRET) check(checkopenop(pt, pc)); rlm@1: checkreg(pt, a+b-1); rlm@1: break; rlm@1: } rlm@1: default: break; rlm@1: } rlm@1: } rlm@1: return pt->code[last]; rlm@1: } rlm@1: rlm@1: #undef check rlm@1: #undef checkjump rlm@1: #undef checkreg rlm@1: rlm@1: /* }====================================================== */ rlm@1: rlm@1: rlm@1: int luaG_checkcode (const Proto *pt) { rlm@1: return (symbexec(pt, pt->sizecode, NO_REG) != 0); rlm@1: } rlm@1: rlm@1: rlm@1: static const char *kname (Proto *p, int c) { rlm@1: if (ISK(c) && ttisstring(&p->k[INDEXK(c)])) rlm@1: return svalue(&p->k[INDEXK(c)]); rlm@1: else rlm@1: return "?"; rlm@1: } rlm@1: rlm@1: rlm@1: static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, rlm@1: const char **name) { rlm@1: if (isLua(ci)) { /* a Lua function? */ rlm@1: Proto *p = ci_func(ci)->l.p; rlm@1: int pc = currentpc(L, ci); rlm@1: Instruction i; rlm@1: *name = luaF_getlocalname(p, stackpos+1, pc); rlm@1: if (*name) /* is a local? */ rlm@1: return "local"; rlm@1: i = symbexec(p, pc, stackpos); /* try symbolic execution */ rlm@1: lua_assert(pc != -1); rlm@1: switch (GET_OPCODE(i)) { rlm@1: case OP_GETGLOBAL: { rlm@1: int g = GETARG_Bx(i); /* global index */ rlm@1: lua_assert(ttisstring(&p->k[g])); rlm@1: *name = svalue(&p->k[g]); rlm@1: return "global"; rlm@1: } rlm@1: case OP_MOVE: { rlm@1: int a = GETARG_A(i); rlm@1: int b = GETARG_B(i); /* move from `b' to `a' */ rlm@1: if (b < a) rlm@1: return getobjname(L, ci, b, name); /* get name for `b' */ rlm@1: break; rlm@1: } rlm@1: case OP_GETTABLE: { rlm@1: int k = GETARG_C(i); /* key index */ rlm@1: *name = kname(p, k); rlm@1: return "field"; rlm@1: } rlm@1: case OP_GETUPVAL: { rlm@1: int u = GETARG_B(i); /* upvalue index */ rlm@1: *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; rlm@1: return "upvalue"; rlm@1: } rlm@1: case OP_SELF: { rlm@1: int k = GETARG_C(i); /* key index */ rlm@1: *name = kname(p, k); rlm@1: return "method"; rlm@1: } rlm@1: default: break; rlm@1: } rlm@1: } rlm@1: return NULL; /* no useful name found */ rlm@1: } rlm@1: rlm@1: rlm@1: static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { rlm@1: Instruction i; rlm@1: if ((isLua(ci) && ci->tailcalls > 0) || !isLua(ci - 1)) rlm@1: return NULL; /* calling function is not Lua (or is unknown) */ rlm@1: ci--; /* calling function */ rlm@1: i = ci_func(ci)->l.p->code[currentpc(L, ci)]; rlm@1: if (GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || rlm@1: GET_OPCODE(i) == OP_TFORLOOP) rlm@1: return getobjname(L, ci, GETARG_A(i), name); rlm@1: else rlm@1: return NULL; /* no useful name can be found */ rlm@1: } rlm@1: rlm@1: rlm@1: /* only ANSI way to check whether a pointer points to an array */ rlm@1: static int isinstack (CallInfo *ci, const TValue *o) { rlm@1: StkId p; rlm@1: for (p = ci->base; p < ci->top; p++) rlm@1: if (o == p) return 1; rlm@1: return 0; rlm@1: } rlm@1: rlm@1: rlm@1: void luaG_typeerror (lua_State *L, const TValue *o, const char *op) { rlm@1: const char *name = NULL; rlm@1: const char *t = luaT_typenames[ttype(o)]; rlm@1: const char *kind = (isinstack(L->ci, o)) ? rlm@1: getobjname(L, L->ci, cast_int(o - L->base), &name) : rlm@1: NULL; rlm@1: if (kind) rlm@1: luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", rlm@1: op, kind, name, t); rlm@1: else rlm@1: luaG_runerror(L, "attempt to %s a %s value", op, t); rlm@1: } rlm@1: rlm@1: rlm@1: void luaG_concaterror (lua_State *L, StkId p1, StkId p2) { rlm@1: if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; rlm@1: lua_assert(!ttisstring(p1) && !ttisnumber(p1)); rlm@1: luaG_typeerror(L, p1, "concatenate"); rlm@1: } rlm@1: rlm@1: rlm@1: void luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) { rlm@1: TValue temp; rlm@1: if (luaV_tonumber(p1, &temp) == NULL) rlm@1: p2 = p1; /* first operand is wrong */ rlm@1: luaG_typeerror(L, p2, "perform arithmetic on"); rlm@1: } rlm@1: rlm@1: rlm@1: int luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { rlm@1: const char *t1 = luaT_typenames[ttype(p1)]; rlm@1: const char *t2 = luaT_typenames[ttype(p2)]; rlm@1: if (t1[2] == t2[2]) rlm@1: luaG_runerror(L, "attempt to compare two %s values", t1); rlm@1: else rlm@1: luaG_runerror(L, "attempt to compare %s with %s", t1, t2); rlm@1: return 0; rlm@1: } rlm@1: rlm@1: rlm@1: static void addinfo (lua_State *L, const char *msg) { rlm@1: CallInfo *ci = L->ci; rlm@1: if (isLua(ci)) { /* is Lua code? */ rlm@1: char buff[LUA_IDSIZE]; /* add file:line information */ rlm@1: int line = currentline(L, ci); rlm@1: luaO_chunkid(buff, getstr(getluaproto(ci)->source), LUA_IDSIZE); rlm@1: luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: void luaG_errormsg (lua_State *L) { rlm@1: if (L->errfunc != 0) { /* is there an error handling function? */ rlm@1: StkId errfunc = restorestack(L, L->errfunc); rlm@1: if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); rlm@1: setobjs2s(L, L->top, L->top - 1); /* move argument */ rlm@1: setobjs2s(L, L->top - 1, errfunc); /* push function */ rlm@1: incr_top(L); rlm@1: luaD_call(L, L->top - 2, 1); /* call it */ rlm@1: } rlm@1: luaD_throw(L, LUA_ERRRUN); rlm@1: } rlm@1: rlm@1: rlm@1: void luaG_runerror (lua_State *L, const char *fmt, ...) { rlm@1: va_list argp; rlm@1: va_start(argp, fmt); rlm@1: addinfo(L, luaO_pushvfstring(L, fmt, argp)); rlm@1: va_end(argp); rlm@1: luaG_errormsg(L); rlm@1: } rlm@1: