diff options
Diffstat (limited to 'ldebug.c')
-rw-r--r-- | ldebug.c | 148 |
1 files changed, 136 insertions, 12 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldebug.c,v 1.23 2000/06/12 13:52:05 roberto Exp roberto $ | 2 | ** $Id: ldebug.c,v 1.24 2000/06/26 19:28:31 roberto Exp roberto $ |
3 | ** Debug Interface | 3 | ** Debug Interface |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -13,10 +13,12 @@ | |||
13 | 13 | ||
14 | #include "lapi.h" | 14 | #include "lapi.h" |
15 | #include "lauxlib.h" | 15 | #include "lauxlib.h" |
16 | #include "lcode.h" | ||
16 | #include "ldebug.h" | 17 | #include "ldebug.h" |
17 | #include "ldo.h" | 18 | #include "ldo.h" |
18 | #include "lfunc.h" | 19 | #include "lfunc.h" |
19 | #include "lobject.h" | 20 | #include "lobject.h" |
21 | #include "lopcodes.h" | ||
20 | #include "lstate.h" | 22 | #include "lstate.h" |
21 | #include "ltable.h" | 23 | #include "ltable.h" |
22 | #include "ltm.h" | 24 | #include "ltm.h" |
@@ -97,6 +99,13 @@ static int lua_nups (StkId f) { | |||
97 | } | 99 | } |
98 | 100 | ||
99 | 101 | ||
102 | static int lua_currentpc (StkId f) { | ||
103 | CallInfo *ci = infovalue(f); | ||
104 | LUA_ASSERT(L, ttype(f) == TAG_LMARK, "function has no pc"); | ||
105 | return (*ci->pc - 1) - ci->func->f.l->code; | ||
106 | } | ||
107 | |||
108 | |||
100 | static int lua_currentline (StkId f) { | 109 | static int lua_currentline (StkId f) { |
101 | if (ttype(f) != TAG_LMARK) | 110 | if (ttype(f) != TAG_LMARK) |
102 | return -1; /* only active lua functions have current-line information */ | 111 | return -1; /* only active lua functions have current-line information */ |
@@ -104,15 +113,11 @@ static int lua_currentline (StkId f) { | |||
104 | CallInfo *ci = infovalue(f); | 113 | CallInfo *ci = infovalue(f); |
105 | int *lines = ci->func->f.l->lines; | 114 | int *lines = ci->func->f.l->lines; |
106 | if (!lines) return -1; /* no static debug information */ | 115 | if (!lines) return -1; /* no static debug information */ |
107 | else return lines[ci->pc]; | 116 | else return lines[lua_currentpc(f)]; |
108 | } | 117 | } |
109 | } | 118 | } |
110 | 119 | ||
111 | 120 | ||
112 | static int lua_currentpc (StkId f) { | ||
113 | return infovalue(f)->pc; | ||
114 | } | ||
115 | |||
116 | 121 | ||
117 | static Proto *getluaproto (StkId f) { | 122 | static Proto *getluaproto (StkId f) { |
118 | return (ttype(f) == TAG_LMARK) ? infovalue(f)->func->f.l : NULL; | 123 | return (ttype(f) == TAG_LMARK) ? infovalue(f)->func->f.l : NULL; |
@@ -225,17 +230,136 @@ int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { | |||
225 | } | 230 | } |
226 | 231 | ||
227 | 232 | ||
233 | /* | ||
234 | ** {====================================================== | ||
235 | ** Symbolic Execution | ||
236 | ** ======================================================= | ||
237 | */ | ||
238 | |||
239 | static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) { | ||
240 | int stack[MAXSTACK]; /* stores last instruction that changes each value */ | ||
241 | const Instruction *code = pt->code; | ||
242 | int top = pt->numparams; | ||
243 | int pc = 0; | ||
244 | if (pt->is_vararg) /* varargs? */ | ||
245 | top++; /* `arg' */ | ||
246 | while (pc < lastpc) { | ||
247 | const Instruction i = code[pc++]; | ||
248 | switch (GET_OPCODE(i)) { | ||
249 | case OP_CALL: { | ||
250 | int nresults = GETARG_B(i); | ||
251 | if (nresults == MULT_RET) nresults = 1; | ||
252 | top = GETARG_A(i); | ||
253 | while (nresults--) | ||
254 | stack[top++] = pc-1; | ||
255 | break; | ||
256 | } | ||
257 | case OP_PUSHNIL: { | ||
258 | int n; | ||
259 | for (n=0; n<GETARG_U(i); n++) | ||
260 | stack[top++] = pc-1; | ||
261 | break; | ||
262 | } | ||
263 | case OP_POP: { | ||
264 | top -= GETARG_U(i); | ||
265 | break; | ||
266 | } | ||
267 | case OP_SETTABLE: | ||
268 | case OP_SETLIST: { | ||
269 | top -= GETARG_B(i); | ||
270 | break; | ||
271 | } | ||
272 | case OP_SETMAP: { | ||
273 | top -= 2*GETARG_U(i); | ||
274 | break; | ||
275 | } | ||
276 | case OP_CONCAT: { | ||
277 | top -= GETARG_U(i); | ||
278 | stack[top++] = pc-1; | ||
279 | break; | ||
280 | } | ||
281 | case OP_JMPONT: | ||
282 | case OP_JMPONF: { | ||
283 | int newpc = pc + GETARG_S(i); | ||
284 | if (newpc >= lastpc) { | ||
285 | stack[top-1] = pc-1; /* value generated by or-and */ | ||
286 | pc = newpc; /* do the jump */ | ||
287 | } | ||
288 | else | ||
289 | top--; /* original code did not jump; condition was false */ | ||
290 | break; | ||
291 | } | ||
292 | case OP_PUSHNILJMP: { | ||
293 | break; /* do not `push', to compensate next instruction */ | ||
294 | } | ||
295 | case OP_CLOSURE: { | ||
296 | top -= GETARG_B(i); | ||
297 | stack[top++] = pc-1; | ||
298 | break; | ||
299 | } | ||
300 | default: { | ||
301 | int n; | ||
302 | LUA_ASSERT(NULL, luaK_opproperties[GET_OPCODE(i)].push != VD, | ||
303 | "invalid opcode for default"); | ||
304 | top -= luaK_opproperties[GET_OPCODE(i)].pop; | ||
305 | for (n=0; n<luaK_opproperties[GET_OPCODE(i)].push; n++) | ||
306 | stack[top++] = pc-1; | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | return code[stack[stackpos]]; | ||
311 | } | ||
312 | |||
313 | |||
314 | static const char *getname (lua_State *L, StkId obj, const char **name) { | ||
315 | StkId func = aux_stackedfunction(L, 0, obj); | ||
316 | if (func == NULL || ttype(func) != TAG_LMARK) | ||
317 | return NULL; /* not a Lua function */ | ||
318 | else { | ||
319 | Proto *p = infovalue(func)->func->f.l; | ||
320 | int pc = lua_currentpc(func); | ||
321 | int stackpos = obj - (func+1); /* func+1 == function base */ | ||
322 | Instruction i = luaG_symbexec(p, pc, stackpos); | ||
323 | switch (GET_OPCODE(i)) { | ||
324 | case OP_GETGLOBAL: { | ||
325 | *name = p->kstr[GETARG_U(i)]->str; | ||
326 | return "global"; | ||
327 | } | ||
328 | case OP_GETLOCAL: { | ||
329 | *name = luaF_getlocalname(p, GETARG_U(i)+1, pc); | ||
330 | return (*name) ? "local" : NULL; | ||
331 | } | ||
332 | case OP_PUSHSELF: | ||
333 | case OP_GETDOTTED: { | ||
334 | *name = p->kstr[GETARG_U(i)]->str; | ||
335 | return "field"; | ||
336 | } | ||
337 | default: | ||
338 | return NULL; /* no usefull name found */ | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | |||
343 | |||
344 | /* }====================================================== */ | ||
345 | |||
228 | 346 | ||
229 | static void call_index_error (lua_State *L, TObject *o, const char *v) { | 347 | static void call_index_error (lua_State *L, StkId o, const char *op, |
230 | luaL_verror(L, "attempt to %.10s a %.10s value", v, lua_type(L, o)); | 348 | const char *tp) { |
349 | const char *name; | ||
350 | const char *kind = getname(L, o, &name); | ||
351 | if (kind) | ||
352 | luaL_verror(L, "%s `%s' is not a %s", kind, name, tp); | ||
353 | else | ||
354 | luaL_verror(L, "attempt to %.10s a %.10s value", op, lua_type(L, o)); | ||
231 | } | 355 | } |
232 | 356 | ||
233 | 357 | ||
234 | void luaG_callerror (lua_State *L, TObject *func) { | 358 | void luaG_callerror (lua_State *L, StkId func) { |
235 | call_index_error(L, func, "call"); | 359 | call_index_error(L, func, "call", "function"); |
236 | } | 360 | } |
237 | 361 | ||
238 | 362 | ||
239 | void luaG_indexerror (lua_State *L, TObject *t) { | 363 | void luaG_indexerror (lua_State *L, StkId t) { |
240 | call_index_error(L, t, "index"); | 364 | call_index_error(L, t, "index", "table"); |
241 | } | 365 | } |