|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
-** $Id: ldebug.c,v 2.82 2011/06/02 19:31:40 roberto Exp roberto $
|
|
|
|
|
|
+** $Id: ldebug.c,v 2.83 2011/08/09 20:58:29 roberto Exp roberto $
|
|
** Debug Interface
|
|
** Debug Interface
|
|
** See Copyright Notice in lua.h
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
*/
|
|
@@ -232,7 +232,11 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case 'n': {
|
|
case 'n': {
|
|
- ar->namewhat = (ci) ? getfuncname(L, ci, &ar->name) : NULL;
|
|
|
|
|
|
+ /* calling function is a known Lua function? */
|
|
|
|
+ if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
|
|
|
|
+ ar->namewhat = getfuncname(L, ci->previous, &ar->name);
|
|
|
|
+ else
|
|
|
|
+ ar->namewhat = NULL;
|
|
if (ar->namewhat == NULL) {
|
|
if (ar->namewhat == NULL) {
|
|
ar->namewhat = ""; /* not found */
|
|
ar->namewhat = ""; /* not found */
|
|
ar->name = NULL;
|
|
ar->name = NULL;
|
|
@@ -286,17 +290,16 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
|
** =======================================================
|
|
** =======================================================
|
|
*/
|
|
*/
|
|
|
|
|
|
-static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
|
|
|
|
|
|
+static const char *getobjname (Proto *p, int lastpc, int reg,
|
|
const char **name);
|
|
const char **name);
|
|
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
** find a "name" for the RK value 'c'
|
|
** find a "name" for the RK value 'c'
|
|
*/
|
|
*/
|
|
-static void kname (lua_State *L, CallInfo *ci, int c, int oreg,
|
|
|
|
- const char *what, const char **name) {
|
|
|
|
|
|
+static void kname (Proto *p, int pc, int c, const char **name) {
|
|
if (ISK(c)) { /* is 'c' a constant? */
|
|
if (ISK(c)) { /* is 'c' a constant? */
|
|
- TValue *kvalue = &ci_func(ci)->p->k[INDEXK(c)];
|
|
|
|
|
|
+ TValue *kvalue = &p->k[INDEXK(c)];
|
|
if (ttisstring(kvalue)) { /* literal constant? */
|
|
if (ttisstring(kvalue)) { /* literal constant? */
|
|
*name = svalue(kvalue); /* it is its own name */
|
|
*name = svalue(kvalue); /* it is its own name */
|
|
return;
|
|
return;
|
|
@@ -304,8 +307,7 @@ static void kname (lua_State *L, CallInfo *ci, int c, int oreg,
|
|
/* else no reasonable name found */
|
|
/* else no reasonable name found */
|
|
}
|
|
}
|
|
else { /* 'c' is a register */
|
|
else { /* 'c' is a register */
|
|
- if (c != oreg) /* not the original register? */
|
|
|
|
- what = getobjname(L, ci, c, name); /* search for 'c' */
|
|
|
|
|
|
+ const char *what = getobjname(p, pc, c, name); /* search for 'c' */
|
|
if (what && *what == 'c') { /* found a constant name? */
|
|
if (what && *what == 'c') { /* found a constant name? */
|
|
return; /* 'name' already filled */
|
|
return; /* 'name' already filled */
|
|
}
|
|
}
|
|
@@ -315,85 +317,30 @@ static void kname (lua_State *L, CallInfo *ci, int c, int oreg,
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
|
|
|
|
- const char **name) {
|
|
|
|
- Proto *p = ci_func(ci)->p;
|
|
|
|
- const char *what = NULL;
|
|
|
|
- int lastpc = currentpc(ci);
|
|
|
|
|
|
+/*
|
|
|
|
+** try to find last instruction before 'lastpc' that modified register 'reg'
|
|
|
|
+*/
|
|
|
|
+static int findsetreg (Proto *p, int lastpc, int reg) {
|
|
int pc;
|
|
int pc;
|
|
- *name = luaF_getlocalname(p, reg + 1, lastpc);
|
|
|
|
- if (*name) /* is a local? */
|
|
|
|
- return "local";
|
|
|
|
- /* else try symbolic execution */
|
|
|
|
|
|
+ int setreg = -1; /* keep last instruction that changed 'reg' */
|
|
for (pc = 0; pc < lastpc; pc++) {
|
|
for (pc = 0; pc < lastpc; pc++) {
|
|
Instruction i = p->code[pc];
|
|
Instruction i = p->code[pc];
|
|
OpCode op = GET_OPCODE(i);
|
|
OpCode op = GET_OPCODE(i);
|
|
int a = GETARG_A(i);
|
|
int a = GETARG_A(i);
|
|
switch (op) {
|
|
switch (op) {
|
|
- case OP_MOVE: {
|
|
|
|
- if (reg == a) {
|
|
|
|
- int b = GETARG_B(i); /* move from 'b' to 'a' */
|
|
|
|
- if (b < a)
|
|
|
|
- what = getobjname(L, ci, b, name); /* get name for 'b' */
|
|
|
|
- else what = NULL;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case OP_GETTABUP:
|
|
|
|
- case OP_GETTABLE: {
|
|
|
|
- if (reg == a) {
|
|
|
|
- int k = GETARG_C(i); /* key index */
|
|
|
|
- int t = GETARG_B(i);
|
|
|
|
- const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
|
|
|
|
- ? luaF_getlocalname(p, t + 1, pc)
|
|
|
|
- : getstr(p->upvalues[t].name);
|
|
|
|
- kname(L, ci, k, a, what, name);
|
|
|
|
- what = (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case OP_GETUPVAL: {
|
|
|
|
- if (reg == a) {
|
|
|
|
- int u = GETARG_B(i); /* upvalue index */
|
|
|
|
- TString *tn = p->upvalues[u].name;
|
|
|
|
- *name = tn ? getstr(tn) : "?";
|
|
|
|
- what = "upvalue";
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case OP_LOADK:
|
|
|
|
- case OP_LOADKX: {
|
|
|
|
- if (reg == a) {
|
|
|
|
- int b = (op == OP_LOADK) ? GETARG_Bx(i)
|
|
|
|
- : GETARG_Ax(p->code[pc + 1]);
|
|
|
|
- if (ttisstring(&p->k[b])) {
|
|
|
|
- what = "constant";
|
|
|
|
- *name = svalue(&p->k[b]);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
case OP_LOADNIL: {
|
|
case OP_LOADNIL: {
|
|
int b = GETARG_B(i);
|
|
int b = GETARG_B(i);
|
|
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
|
|
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
|
|
- what = NULL;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- case OP_SELF: {
|
|
|
|
- if (reg == a) {
|
|
|
|
- int k = GETARG_C(i); /* key index */
|
|
|
|
- kname(L, ci, k, a, what, name);
|
|
|
|
- what = "method";
|
|
|
|
- }
|
|
|
|
|
|
+ setreg = pc;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case OP_TFORCALL: {
|
|
case OP_TFORCALL: {
|
|
- if (reg >= a + 2) what = NULL; /* affect all regs above its base */
|
|
|
|
|
|
+ if (reg >= a + 2) setreg = pc; /* affect all regs above its base */
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case OP_CALL:
|
|
case OP_CALL:
|
|
case OP_TAILCALL: {
|
|
case OP_TAILCALL: {
|
|
- if (reg >= a) what = NULL; /* affect all registers above base */
|
|
|
|
|
|
+ if (reg >= a) setreg = pc; /* affect all registers above base */
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case OP_JMP: {
|
|
case OP_JMP: {
|
|
@@ -405,35 +352,89 @@ static const char *getobjname (lua_State *L, CallInfo *ci, int reg,
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case OP_TEST: {
|
|
case OP_TEST: {
|
|
- if (reg == a) what = NULL; /* jumped code can change 'a' */
|
|
|
|
|
|
+ if (reg == a) setreg = pc; /* jumped code can change 'a' */
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
default:
|
|
- if (testAMode(op) && reg == a) what = NULL;
|
|
|
|
|
|
+ if (testAMode(op) && reg == a) /* any instruction that set A */
|
|
|
|
+ setreg = pc;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return what;
|
|
|
|
|
|
+ return setreg;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+static const char *getobjname (Proto *p, int lastpc, int reg,
|
|
|
|
+ const char **name) {
|
|
|
|
+ int pc;
|
|
|
|
+ *name = luaF_getlocalname(p, reg + 1, lastpc);
|
|
|
|
+ if (*name) /* is a local? */
|
|
|
|
+ return "local";
|
|
|
|
+ /* else try symbolic execution */
|
|
|
|
+ pc = findsetreg(p, lastpc, reg);
|
|
|
|
+ if (pc != -1) { /* could find instruction? */
|
|
|
|
+ Instruction i = p->code[pc];
|
|
|
|
+ OpCode op = GET_OPCODE(i);
|
|
|
|
+ int a = GETARG_A(i);
|
|
|
|
+ switch (op) {
|
|
|
|
+ case OP_MOVE: {
|
|
|
|
+ int b = GETARG_B(i); /* move from 'b' to 'a' */
|
|
|
|
+ lua_assert(reg == a);
|
|
|
|
+ if (b < a)
|
|
|
|
+ return getobjname(p, pc, b, name); /* get name for 'b' */
|
|
|
|
+ }
|
|
|
|
+ case OP_GETTABUP:
|
|
|
|
+ case OP_GETTABLE: {
|
|
|
|
+ int k = GETARG_C(i); /* key index */
|
|
|
|
+ int t = GETARG_B(i);
|
|
|
|
+ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
|
|
|
|
+ ? luaF_getlocalname(p, t + 1, pc)
|
|
|
|
+ : getstr(p->upvalues[t].name);
|
|
|
|
+ kname(p, pc, k, name);
|
|
|
|
+ return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
|
|
|
|
+ }
|
|
|
|
+ case OP_GETUPVAL: {
|
|
|
|
+ int u = GETARG_B(i); /* upvalue index */
|
|
|
|
+ TString *tn = p->upvalues[u].name;
|
|
|
|
+ *name = tn ? getstr(tn) : "?";
|
|
|
|
+ return "upvalue";
|
|
|
|
+ }
|
|
|
|
+ case OP_LOADK:
|
|
|
|
+ case OP_LOADKX: {
|
|
|
|
+ int b = (op == OP_LOADK) ? GETARG_Bx(i)
|
|
|
|
+ : GETARG_Ax(p->code[pc + 1]);
|
|
|
|
+ if (ttisstring(&p->k[b])) {
|
|
|
|
+ *name = svalue(&p->k[b]);
|
|
|
|
+ return "constant";
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ case OP_SELF: {
|
|
|
|
+ int k = GETARG_C(i); /* key index */
|
|
|
|
+ kname(p, pc, k, name);
|
|
|
|
+ return "method";
|
|
|
|
+ }
|
|
|
|
+ default: break; /* go through to return NULL */
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return NULL; /* could not find reasonable name */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
|
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
|
TMS tm;
|
|
TMS tm;
|
|
- Instruction i;
|
|
|
|
- if ((ci->callstatus & CIST_TAIL) || !isLua(ci->previous))
|
|
|
|
- return NULL; /* calling function is not Lua (or is unknown) */
|
|
|
|
- ci = ci->previous; /* calling function */
|
|
|
|
- i = ci_func(ci)->p->code[currentpc(ci)];
|
|
|
|
- if (GET_OPCODE(i) == OP_EXTRAARG) /* extra argument? */
|
|
|
|
- i = ci_func(ci)->p->code[currentpc(ci) - 1]; /* get 'real' instruction */
|
|
|
|
|
|
+ Proto *p = ci_func(ci)->p; /* calling function */
|
|
|
|
+ int pc = currentpc(ci); /* calling instruction index */
|
|
|
|
+ Instruction i = p->code[pc]; /* calling instruction */
|
|
switch (GET_OPCODE(i)) {
|
|
switch (GET_OPCODE(i)) {
|
|
case OP_CALL:
|
|
case OP_CALL:
|
|
- case OP_TAILCALL:
|
|
|
|
- return getobjname(L, ci, GETARG_A(i), name);
|
|
|
|
- case OP_TFORCALL: {
|
|
|
|
|
|
+ case OP_TAILCALL: /* get function name */
|
|
|
|
+ return getobjname(p, pc, GETARG_A(i), name);
|
|
|
|
+ case OP_TFORCALL: { /* for iterator */
|
|
*name = "for iterator";
|
|
*name = "for iterator";
|
|
return "for iterator";
|
|
return "for iterator";
|
|
}
|
|
}
|
|
|
|
+ /* all other instructions can call only through metamethods */
|
|
case OP_SELF:
|
|
case OP_SELF:
|
|
case OP_GETTABUP:
|
|
case OP_GETTABUP:
|
|
case OP_GETTABLE: tm = TM_INDEX; break;
|
|
case OP_GETTABLE: tm = TM_INDEX; break;
|
|
@@ -496,7 +497,8 @@ void luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
|
if (isLua(ci)) {
|
|
if (isLua(ci)) {
|
|
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
|
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
|
if (!kind && isinstack(ci, o)) /* no? try a register */
|
|
if (!kind && isinstack(ci, o)) /* no? try a register */
|
|
- kind = getobjname(L, ci, cast_int(o - ci->u.l.base), &name);
|
|
|
|
|
|
+ kind = getobjname(ci_func(ci)->p, currentpc(ci),
|
|
|
|
+ cast_int(o - ci->u.l.base), &name);
|
|
}
|
|
}
|
|
if (kind)
|
|
if (kind)
|
|
luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
|
|
luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
|