summaryrefslogtreecommitdiff
path: root/src/lj_debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_debug.c')
-rw-r--r--src/lj_debug.c429
1 files changed, 429 insertions, 0 deletions
diff --git a/src/lj_debug.c b/src/lj_debug.c
new file mode 100644
index 00000000..a5ffff74
--- /dev/null
+++ b/src/lj_debug.c
@@ -0,0 +1,429 @@
1/*
2** Debugging and introspection.
3** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lj_debug_c
7#define LUA_CORE
8
9#include "lj_obj.h"
10#include "lj_err.h"
11#include "lj_str.h"
12#include "lj_tab.h"
13#include "lj_state.h"
14#include "lj_frame.h"
15#include "lj_bc.h"
16
17/* -- Frames -------------------------------------------------------------- */
18
19/* Get frame corresponding to a level. */
20cTValue *lj_debug_frame(lua_State *L, int level, int *size)
21{
22 cTValue *frame, *nextframe, *bot = tvref(L->stack);
23 /* Traverse frames backwards. */
24 for (nextframe = frame = L->base-1; frame > bot; ) {
25 if (frame_gc(frame) == obj2gco(L))
26 level++; /* Skip dummy frames. See lj_meta_call(). */
27 if (level-- == 0) {
28 *size = (int)(nextframe - frame);
29 return frame; /* Level found. */
30 }
31 nextframe = frame;
32 if (frame_islua(frame)) {
33 frame = frame_prevl(frame);
34 } else {
35 if (frame_isvarg(frame))
36 level++; /* Skip vararg pseudo-frame. */
37 frame = frame_prevd(frame);
38 }
39 }
40 *size = level;
41 return NULL; /* Level not found. */
42}
43
44/* Invalid bytecode position. */
45#define NO_BCPOS (~(BCPos)0)
46
47/* Return bytecode position for function/frame or NO_BCPOS. */
48static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe)
49{
50 const BCIns *ins;
51 lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD);
52 if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */
53 return NO_BCPOS;
54 } else if (nextframe == NULL) { /* Lua function on top. */
55 void *cf = cframe_raw(L->cframe);
56 if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
57 return NO_BCPOS;
58 ins = cframe_pc(cf); /* Only happens during error/hook handling. */
59 } else {
60 if (frame_islua(nextframe)) {
61 ins = frame_pc(nextframe);
62 } else if (frame_iscont(nextframe)) {
63 ins = frame_contpc(nextframe);
64 } else {
65 /* Lua function below errfunc/gc/hook: find cframe to get the PC. */
66 void *cf = cframe_raw(L->cframe);
67 TValue *f = L->base-1;
68 if (cf == NULL)
69 return NO_BCPOS;
70 while (f > nextframe) {
71 if (frame_islua(f)) {
72 f = frame_prevl(f);
73 } else {
74 if (frame_isc(f))
75 cf = cframe_raw(cframe_prev(cf));
76 f = frame_prevd(f);
77 }
78 }
79 if (cframe_prev(cf))
80 cf = cframe_raw(cframe_prev(cf));
81 ins = cframe_pc(cf);
82 }
83 }
84 return proto_bcpos(funcproto(fn), ins) - 1;
85}
86
87/* -- Line numbers -------------------------------------------------------- */
88
89/* Get line number for a bytecode position. */
90BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
91{
92 BCLine *lineinfo = proto_lineinfo(pt);
93 if (pc < pt->sizebc && lineinfo)
94 return lineinfo[pc];
95 return 0;
96}
97
98/* Get line number for function/frame. */
99static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
100{
101 BCPos pc = debug_framepc(L, fn, nextframe);
102 if (pc != NO_BCPOS) {
103 GCproto *pt = funcproto(fn);
104 lua_assert(pc < pt->sizebc);
105 return lj_debug_line(pt, pc);
106 }
107 return -1;
108}
109
110/* -- Variable names ------------------------------------------------------ */
111
112/* Get name of a local variable from slot number and PC. */
113static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot)
114{
115 MSize i;
116 VarInfo *vi = proto_varinfo(pt);
117 for (i = 0; i < pt->sizevarinfo && vi[i].startpc <= pc; i++)
118 if (pc < vi[i].endpc && slot-- == 0)
119 return strdata(gco2str(gcref(vi[i].name)));
120 return NULL;
121}
122
123/* Get name of local variable from 1-based slot number and function/frame. */
124static TValue *debug_localname(lua_State *L, const lua_Debug *ar,
125 const char **name, BCReg slot1)
126{
127 uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
128 uint32_t size = (uint32_t)ar->i_ci >> 16;
129 TValue *frame = tvref(L->stack) + offset;
130 TValue *nextframe = size ? frame + size : NULL;
131 GCfunc *fn = frame_func(frame);
132 BCPos pc = debug_framepc(L, fn, nextframe);
133 if (pc != NO_BCPOS &&
134 (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL)
135 ;
136 else if (slot1 > 0 && frame + slot1 < (nextframe ? nextframe : L->top))
137 *name = "(*temporary)";
138 else
139 *name = NULL;
140 return frame+slot1;
141}
142
143/* Get name of upvalue. */
144const char *lj_debug_uvname(cTValue *o, uint32_t idx, TValue **tvp)
145{
146 if (tvisfunc(o)) {
147 GCfunc *fn = funcV(o);
148 if (isluafunc(fn)) {
149 GCproto *pt = funcproto(fn);
150 if (idx < pt->sizeuv) {
151 *tvp = uvval(&gcref(fn->l.uvptr[idx])->uv);
152 return strdata(proto_uvname(pt, idx));
153 }
154 } else {
155 if (idx < fn->c.nupvalues) {
156 *tvp = &fn->c.upvalue[idx];
157 return "";
158 }
159 }
160 }
161 return NULL;
162}
163
164/* Deduce name of an object from slot number and PC. */
165const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot,
166 const char **name)
167{
168 const char *lname;
169restart:
170 lname = debug_varname(pt, proto_bcpos(pt, ip), slot);
171 if (lname != NULL) { *name = lname; return "local"; }
172 while (--ip > proto_bc(pt)) {
173 BCIns ins = *ip;
174 BCOp op = bc_op(ins);
175 BCReg ra = bc_a(ins);
176 if (bcmode_a(op) == BCMbase) {
177 if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins)))
178 return NULL;
179 } else if (bcmode_a(op) == BCMdst && ra == slot) {
180 switch (bc_op(ins)) {
181 case BC_MOV:
182 if (ra == slot) { slot = bc_d(ins); goto restart; }
183 break;
184 case BC_GGET:
185 *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins))));
186 return "global";
187 case BC_TGETS:
188 *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins))));
189 if (ip > proto_bc(pt)) {
190 BCIns insp = ip[-1];
191 if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1 &&
192 bc_d(insp) == bc_b(ins))
193 return "method";
194 }
195 return "field";
196 case BC_UGET:
197 *name = strdata(proto_uvname(pt, bc_d(ins)));
198 return "upvalue";
199 default:
200 return NULL;
201 }
202 }
203 }
204 return NULL;
205}
206
207/* Deduce function name from caller of a frame. */
208const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name)
209{
210 TValue *pframe;
211 GCfunc *fn;
212 BCPos pc;
213 if (frame_isvarg(frame))
214 frame = frame_prevd(frame);
215 pframe = frame_prev(frame);
216 fn = frame_func(pframe);
217 pc = debug_framepc(L, fn, frame);
218 if (pc != NO_BCPOS) {
219 GCproto *pt = funcproto(fn);
220 const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)];
221 MMS mm = bcmode_mm(bc_op(*ip));
222 if (mm == MM_call) {
223 BCReg slot = bc_a(*ip);
224 if (bc_op(*ip) == BC_ITERC) slot -= 3;
225 return lj_debug_slotname(pt, ip, slot, name);
226 } else if (mm != MM__MAX) {
227 *name = strdata(mmname_str(G(L), mm));
228 return "metamethod";
229 }
230 }
231 return NULL;
232}
233
234/* -- Source code locations ----------------------------------------------- */
235
236/* Generate shortened source name. */
237void lj_debug_shortname(char *out, const char *src)
238{
239 if (*src == '=') {
240 strncpy(out, src+1, LUA_IDSIZE); /* remove first char */
241 out[LUA_IDSIZE-1] = '\0'; /* ensures null termination */
242 } else if (*src == '@') { /* out = "source", or "...source" */
243 size_t l = strlen(++src); /* skip the `@' */
244 if (l >= LUA_IDSIZE) {
245 src += l-(LUA_IDSIZE-4); /* get last part of file name */
246 strcpy(out, "...");
247 out += 3;
248 }
249 strcpy(out, src);
250 } else { /* out = [string "string"] */
251 size_t len; /* Length, up to first control char. */
252 for (len = 0; len < LUA_IDSIZE-12; len++)
253 if (((const unsigned char *)src)[len] < ' ') break;
254 strcpy(out, "[string \""); out += 9;
255 if (src[len] != '\0') { /* must truncate? */
256 if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
257 strncpy(out, src, len); out += len;
258 strcpy(out, "..."); out += 3;
259 } else {
260 strcpy(out, src); out += len;
261 }
262 strcpy(out, "\"]");
263 }
264}
265
266/* Add current location of a frame to error message. */
267void lj_debug_addloc(lua_State *L, const char *msg,
268 cTValue *frame, cTValue *nextframe)
269{
270 if (frame) {
271 GCfunc *fn = frame_func(frame);
272 if (isluafunc(fn)) {
273 BCLine line = debug_frameline(L, fn, nextframe);
274 if (line >= 0) {
275 char buf[LUA_IDSIZE];
276 lj_debug_shortname(buf, strdata(proto_chunkname(funcproto(fn))));
277 lj_str_pushf(L, "%s:%d: %s", buf, line, msg);
278 return;
279 }
280 }
281 }
282 lj_str_pushf(L, "%s", msg);
283}
284
285/* Push location string for a bytecode position to Lua stack. */
286void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
287{
288 GCstr *name = proto_chunkname(pt);
289 if (name) {
290 const char *s = strdata(name);
291 MSize i, len = name->len;
292 BCLine line = lj_debug_line(pt, pc);
293 if (*s == '@') {
294 s++; len--;
295 for (i = len; i > 0; i--)
296 if (s[i] == '/' || s[i] == '\\') {
297 s += i+1;
298 break;
299 }
300 lj_str_pushf(L, "%s:%d", s, line);
301 } else if (len > 40) {
302 lj_str_pushf(L, "%p:%d", pt, line);
303 } else if (*s == '=') {
304 lj_str_pushf(L, "%s:%d", s+1, line);
305 } else {
306 lj_str_pushf(L, "\"%s\":%d", s, line);
307 }
308 } else {
309 lj_str_pushf(L, "%p:%u", pt, pc);
310 }
311}
312
313/* -- Public debug API ---------------------------------------------------- */
314
315/* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */
316
317LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n)
318{
319 const char *name;
320 TValue *o = debug_localname(L, ar, &name, (BCReg)n);
321 if (name) {
322 copyTV(L, L->top, o);
323 incr_top(L);
324 }
325 return name;
326}
327
328LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n)
329{
330 const char *name;
331 TValue *o = debug_localname(L, ar, &name, (BCReg)n);
332 if (name)
333 copyTV(L, o, L->top-1);
334 L->top--;
335 return name;
336}
337
338LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar)
339{
340 int status = 1;
341 TValue *frame = NULL;
342 TValue *nextframe = NULL;
343 GCfunc *fn;
344 if (*what == '>') {
345 TValue *func = L->top - 1;
346 api_check(L, tvisfunc(func));
347 fn = funcV(func);
348 L->top--;
349 what++;
350 } else {
351 uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
352 uint32_t size = (uint32_t)ar->i_ci >> 16;
353 lua_assert(offset != 0);
354 frame = tvref(L->stack) + offset;
355 if (size) nextframe = frame + size;
356 lua_assert(frame <= tvref(L->maxstack) &&
357 (!nextframe || nextframe <= tvref(L->maxstack)));
358 fn = frame_func(frame);
359 lua_assert(fn->c.gct == ~LJ_TFUNC);
360 }
361 for (; *what; what++) {
362 switch (*what) {
363 case 'S':
364 if (isluafunc(fn)) {
365 GCproto *pt = funcproto(fn);
366 ar->source = strdata(proto_chunkname(pt));
367 ar->linedefined = (int)proto_line(pt, 0);
368 ar->lastlinedefined = (int)pt->lastlinedefined;
369 ar->what = ar->linedefined ? "Lua" : "main";
370 } else {
371 ar->source = "=[C]";
372 ar->linedefined = -1;
373 ar->lastlinedefined = -1;
374 ar->what = "C";
375 }
376 lj_debug_shortname(ar->short_src, ar->source);
377 break;
378 case 'l':
379 ar->currentline = frame ? debug_frameline(L, fn, nextframe) : -1;
380 break;
381 case 'u':
382 ar->nups = fn->c.nupvalues;
383 break;
384 case 'n':
385 ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL;
386 if (ar->namewhat == NULL) {
387 ar->namewhat = "";
388 ar->name = NULL;
389 }
390 break;
391 case 'f':
392 setfuncV(L, L->top, fn);
393 incr_top(L);
394 break;
395 case 'L':
396 if (isluafunc(fn)) {
397 GCtab *t = lj_tab_new(L, 0, 0);
398 GCproto *pt = funcproto(fn);
399 BCLine *lineinfo = proto_lineinfo(pt);
400 MSize i, szl = pt->sizebc;
401 for (i = 1; i < szl; i++)
402 setboolV(lj_tab_setint(L, t, lineinfo[i]), 1);
403 settabV(L, L->top, t);
404 } else {
405 setnilV(L->top);
406 }
407 incr_top(L);
408 break;
409 default:
410 status = 0; /* Bad option. */
411 break;
412 }
413 }
414 return status;
415}
416
417LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
418{
419 int size;
420 cTValue *frame = lj_debug_frame(L, level, &size);
421 if (frame) {
422 ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
423 return 1;
424 } else {
425 ar->i_ci = level - size;
426 return 0;
427 }
428}
429