2 ** Debugging and introspection.
3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
17 #include "lj_strfmt.h"
22 /* -- Frames -------------------------------------------------------------- */
24 /* Get frame corresponding to a level. */
25 cTValue
*lj_debug_frame(lua_State
*L
, int level
, int *size
)
27 cTValue
*frame
, *nextframe
, *bot
= tvref(L
->stack
)+LJ_FR2
;
28 /* Traverse frames backwards. */
29 for (nextframe
= frame
= L
->base
-1; frame
> bot
; ) {
30 if (frame_gc(frame
) == obj2gco(L
))
31 level
++; /* Skip dummy frames. See lj_err_optype_call(). */
33 *size
= (int)(nextframe
- frame
);
34 return frame
; /* Level found. */
37 if (frame_islua(frame
)) {
38 frame
= frame_prevl(frame
);
40 if (frame_isvarg(frame
))
41 level
++; /* Skip vararg pseudo-frame. */
42 frame
= frame_prevd(frame
);
46 return NULL
; /* Level not found. */
49 /* Invalid bytecode position. */
50 #define NO_BCPOS (~(BCPos)0)
52 /* Return bytecode position for function/frame or NO_BCPOS. */
53 static BCPos
debug_framepc(lua_State
*L
, GCfunc
*fn
, cTValue
*nextframe
)
58 lj_assertL(fn
->c
.gct
== ~LJ_TFUNC
|| fn
->c
.gct
== ~LJ_TTHREAD
,
59 "function or frame expected");
60 if (!isluafunc(fn
)) { /* Cannot derive a PC for non-Lua functions. */
62 } else if (nextframe
== NULL
) { /* Lua function on top. */
63 void *cf
= cframe_raw(L
->cframe
);
64 if (cf
== NULL
|| (char *)cframe_pc(cf
) == (char *)cframe_L(cf
))
66 ins
= cframe_pc(cf
); /* Only happens during error/hook handling. */
67 if (!ins
) return NO_BCPOS
;
69 if (frame_islua(nextframe
)) {
70 ins
= frame_pc(nextframe
);
71 } else if (frame_iscont(nextframe
)) {
72 ins
= frame_contpc(nextframe
);
74 /* Lua function below errfunc/gc/hook: find cframe to get the PC. */
75 void *cf
= cframe_raw(L
->cframe
);
76 TValue
*f
= L
->base
-1;
80 while (cframe_nres(cf
) < 0) {
81 if (f
>= restorestack(L
, -cframe_nres(cf
)))
83 cf
= cframe_raw(cframe_prev(cf
));
92 if (frame_isc(f
) || (frame_iscont(f
) && frame_iscont_fficb(f
)))
93 cf
= cframe_raw(cframe_prev(cf
));
98 if (!ins
) return NO_BCPOS
;
102 pos
= proto_bcpos(pt
, ins
) - 1;
104 if (pos
> pt
->sizebc
) { /* Undo the effects of lj_trace_exit for JLOOP. */
105 if (bc_isret(bc_op(ins
[-1]))) {
106 GCtrace
*T
= (GCtrace
*)((char *)(ins
-1) - offsetof(GCtrace
, startins
));
107 pos
= proto_bcpos(pt
, mref(T
->startpc
, const BCIns
));
109 pos
= NO_BCPOS
; /* Punt in case of stack overflow for stitched trace. */
116 /* -- Line numbers -------------------------------------------------------- */
118 /* Get line number for a bytecode position. */
119 BCLine LJ_FASTCALL
lj_debug_line(GCproto
*pt
, BCPos pc
)
121 const void *lineinfo
= proto_lineinfo(pt
);
122 if (pc
<= pt
->sizebc
&& lineinfo
) {
123 BCLine first
= pt
->firstline
;
124 if (pc
== pt
->sizebc
) return first
+ pt
->numline
;
125 if (pc
-- == 0) return first
;
126 if (pt
->numline
< 256)
127 return first
+ (BCLine
)((const uint8_t *)lineinfo
)[pc
];
128 else if (pt
->numline
< 65536)
129 return first
+ (BCLine
)((const uint16_t *)lineinfo
)[pc
];
131 return first
+ (BCLine
)((const uint32_t *)lineinfo
)[pc
];
136 /* Get line number for function/frame. */
137 static BCLine
debug_frameline(lua_State
*L
, GCfunc
*fn
, cTValue
*nextframe
)
139 BCPos pc
= debug_framepc(L
, fn
, nextframe
);
140 if (pc
!= NO_BCPOS
) {
141 GCproto
*pt
= funcproto(fn
);
142 lj_assertL(pc
<= pt
->sizebc
, "PC out of range");
143 return lj_debug_line(pt
, pc
);
148 /* -- Variable names ------------------------------------------------------ */
150 /* Get name of a local variable from slot number and PC. */
151 static const char *debug_varname(const GCproto
*pt
, BCPos pc
, BCReg slot
)
153 const char *p
= (const char *)proto_varinfo(pt
);
157 const char *name
= p
;
158 uint32_t vn
= *(const uint8_t *)p
;
159 BCPos startpc
, endpc
;
160 if (vn
< VARNAME__MAX
) {
161 if (vn
== VARNAME_END
) break; /* End of varinfo. */
163 do { p
++; } while (*(const uint8_t *)p
); /* Skip over variable name. */
166 lastpc
= startpc
= lastpc
+ lj_buf_ruleb128(&p
);
167 if (startpc
> pc
) break;
168 endpc
= startpc
+ lj_buf_ruleb128(&p
);
169 if (pc
< endpc
&& slot
-- == 0) {
170 if (vn
< VARNAME__MAX
) {
171 #define VARNAMESTR(name, str) str "\0"
172 name
= VARNAMEDEF(VARNAMESTR
);
174 if (--vn
) while (*name
++ || --vn
) ;
183 /* Get name of local variable from 1-based slot number and function/frame. */
184 static TValue
*debug_localname(lua_State
*L
, const lua_Debug
*ar
,
185 const char **name
, BCReg slot1
)
187 uint32_t offset
= (uint32_t)ar
->i_ci
& 0xffff;
188 uint32_t size
= (uint32_t)ar
->i_ci
>> 16;
189 TValue
*frame
= tvref(L
->stack
) + offset
;
190 TValue
*nextframe
= size
? frame
+ size
: NULL
;
191 GCfunc
*fn
= frame_func(frame
);
192 BCPos pc
= debug_framepc(L
, fn
, nextframe
);
193 if (!nextframe
) nextframe
= L
->top
+LJ_FR2
;
194 if ((int)slot1
< 0) { /* Negative slot number is for varargs. */
195 if (pc
!= NO_BCPOS
) {
196 GCproto
*pt
= funcproto(fn
);
197 if ((pt
->flags
& PROTO_VARARG
)) {
198 slot1
= pt
->numparams
+ (BCReg
)(-(int)slot1
);
199 if (frame_isvarg(frame
)) { /* Vararg frame has been set up? (pc!=0) */
201 frame
= frame_prevd(frame
);
203 if (frame
+ slot1
+LJ_FR2
< nextframe
) {
211 if (pc
!= NO_BCPOS
&&
212 (*name
= debug_varname(funcproto(fn
), pc
, slot1
-1)) != NULL
)
214 else if (slot1
> 0 && frame
+ slot1
+LJ_FR2
< nextframe
)
215 *name
= "(*temporary)";
219 /* Get name of upvalue. */
220 const char *lj_debug_uvname(GCproto
*pt
, uint32_t idx
)
222 const uint8_t *p
= proto_uvinfo(pt
);
223 lj_assertX(idx
< pt
->sizeuv
, "bad upvalue index");
225 if (idx
) while (*p
++ || --idx
) ;
226 return (const char *)p
;
229 /* Get name and value of upvalue. */
230 const char *lj_debug_uvnamev(cTValue
*o
, uint32_t idx
, TValue
**tvp
, GCobj
**op
)
233 GCfunc
*fn
= funcV(o
);
235 GCproto
*pt
= funcproto(fn
);
236 if (idx
< pt
->sizeuv
) {
237 GCobj
*uvo
= gcref(fn
->l
.uvptr
[idx
]);
238 *tvp
= uvval(&uvo
->uv
);
240 return lj_debug_uvname(pt
, idx
);
243 if (idx
< fn
->c
.nupvalues
) {
244 *tvp
= &fn
->c
.upvalue
[idx
];
253 /* Deduce name of an object from slot number and PC. */
254 const char *lj_debug_slotname(GCproto
*pt
, const BCIns
*ip
, BCReg slot
,
259 lname
= debug_varname(pt
, proto_bcpos(pt
, ip
), slot
);
260 if (lname
!= NULL
) { *name
= lname
; return "local"; }
261 while (--ip
> proto_bc(pt
)) {
263 BCOp op
= bc_op(ins
);
264 BCReg ra
= bc_a(ins
);
265 if (bcmode_a(op
) == BCMbase
) {
266 if (slot
>= ra
&& (op
!= BC_KNIL
|| slot
<= bc_d(ins
)))
268 } else if (bcmode_a(op
) == BCMdst
&& ra
== slot
) {
269 switch (bc_op(ins
)) {
271 if (ra
== slot
) { slot
= bc_d(ins
); goto restart
; }
274 *name
= strdata(gco2str(proto_kgc(pt
, ~(ptrdiff_t)bc_d(ins
))));
277 *name
= strdata(gco2str(proto_kgc(pt
, ~(ptrdiff_t)bc_c(ins
))));
278 if (ip
> proto_bc(pt
)) {
280 if (bc_op(insp
) == BC_MOV
&& bc_a(insp
) == ra
+1+LJ_FR2
&&
281 bc_d(insp
) == bc_b(ins
))
286 *name
= lj_debug_uvname(pt
, bc_d(ins
));
296 /* Deduce function name from caller of a frame. */
297 const char *lj_debug_funcname(lua_State
*L
, cTValue
*frame
, const char **name
)
302 if (frame
<= tvref(L
->stack
)+LJ_FR2
)
304 if (frame_isvarg(frame
))
305 frame
= frame_prevd(frame
);
306 pframe
= frame_prev(frame
);
307 fn
= frame_func(pframe
);
308 pc
= debug_framepc(L
, fn
, frame
);
309 if (pc
!= NO_BCPOS
) {
310 GCproto
*pt
= funcproto(fn
);
311 const BCIns
*ip
= &proto_bc(pt
)[check_exp(pc
< pt
->sizebc
, pc
)];
312 MMS mm
= bcmode_mm(bc_op(*ip
));
314 BCReg slot
= bc_a(*ip
);
315 if (bc_op(*ip
) == BC_ITERC
) slot
-= 3;
316 return lj_debug_slotname(pt
, ip
, slot
, name
);
317 } else if (mm
!= MM__MAX
) {
318 *name
= strdata(mmname_str(G(L
), mm
));
325 /* -- Source code locations ----------------------------------------------- */
327 /* Generate shortened source name. */
328 void lj_debug_shortname(char *out
, GCstr
*str
, BCLine line
)
330 const char *src
= strdata(str
);
332 strncpy(out
, src
+1, LUA_IDSIZE
); /* Remove first char. */
333 out
[LUA_IDSIZE
-1] = '\0'; /* Ensures null termination. */
334 } else if (*src
== '@') { /* Output "source", or "...source". */
335 size_t len
= str
->len
-1;
336 src
++; /* Skip the `@' */
337 if (len
>= LUA_IDSIZE
) {
338 src
+= len
-(LUA_IDSIZE
-4); /* Get last part of file name. */
339 *out
++ = '.'; *out
++ = '.'; *out
++ = '.';
342 } else { /* Output [string "string"] or [builtin:name]. */
343 size_t len
; /* Length, up to first control char. */
344 for (len
= 0; len
< LUA_IDSIZE
-12; len
++)
345 if (((const unsigned char *)src
)[len
] < ' ') break;
346 strcpy(out
, line
== ~(BCLine
)0 ? "[builtin:" : "[string \""); out
+= 9;
347 if (src
[len
] != '\0') { /* Must truncate? */
348 if (len
> LUA_IDSIZE
-15) len
= LUA_IDSIZE
-15;
349 strncpy(out
, src
, len
); out
+= len
;
350 strcpy(out
, "..."); out
+= 3;
352 strcpy(out
, src
); out
+= len
;
354 strcpy(out
, line
== ~(BCLine
)0 ? "]" : "\"]");
358 /* Add current location of a frame to error message. */
359 void lj_debug_addloc(lua_State
*L
, const char *msg
,
360 cTValue
*frame
, cTValue
*nextframe
)
363 GCfunc
*fn
= frame_func(frame
);
365 BCLine line
= debug_frameline(L
, fn
, nextframe
);
367 GCproto
*pt
= funcproto(fn
);
368 char buf
[LUA_IDSIZE
];
369 lj_debug_shortname(buf
, proto_chunkname(pt
), pt
->firstline
);
370 lj_strfmt_pushf(L
, "%s:%d: %s", buf
, line
, msg
);
375 lj_strfmt_pushf(L
, "%s", msg
);
378 /* Push location string for a bytecode position to Lua stack. */
379 void lj_debug_pushloc(lua_State
*L
, GCproto
*pt
, BCPos pc
)
381 GCstr
*name
= proto_chunkname(pt
);
382 const char *s
= strdata(name
);
383 MSize i
, len
= name
->len
;
384 BCLine line
= lj_debug_line(pt
, pc
);
385 if (pt
->firstline
== ~(BCLine
)0) {
386 lj_strfmt_pushf(L
, "builtin:%s", s
);
387 } else if (*s
== '@') {
389 for (i
= len
; i
> 0; i
--)
390 if (s
[i
] == '/' || s
[i
] == '\\') {
394 lj_strfmt_pushf(L
, "%s:%d", s
, line
);
395 } else if (len
> 40) {
396 lj_strfmt_pushf(L
, "%p:%d", pt
, line
);
397 } else if (*s
== '=') {
398 lj_strfmt_pushf(L
, "%s:%d", s
+1, line
);
400 lj_strfmt_pushf(L
, "\"%s\":%d", s
, line
);
404 /* -- Public debug API ---------------------------------------------------- */
406 /* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */
408 LUA_API
const char *lua_getlocal(lua_State
*L
, const lua_Debug
*ar
, int n
)
410 const char *name
= NULL
;
412 TValue
*o
= debug_localname(L
, ar
, &name
, (BCReg
)n
);
414 copyTV(L
, L
->top
, o
);
417 } else if (tvisfunc(L
->top
-1) && isluafunc(funcV(L
->top
-1))) {
418 name
= debug_varname(funcproto(funcV(L
->top
-1)), 0, (BCReg
)n
-1);
423 LUA_API
const char *lua_setlocal(lua_State
*L
, const lua_Debug
*ar
, int n
)
425 const char *name
= NULL
;
426 TValue
*o
= debug_localname(L
, ar
, &name
, (BCReg
)n
);
428 copyTV(L
, o
, L
->top
-1);
433 int lj_debug_getinfo(lua_State
*L
, const char *what
, lj_Debug
*ar
, int ext
)
435 int opt_f
= 0, opt_L
= 0;
436 TValue
*frame
= NULL
;
437 TValue
*nextframe
= NULL
;
440 TValue
*func
= L
->top
- 1;
441 if (!tvisfunc(func
)) return 0;
446 uint32_t offset
= (uint32_t)ar
->i_ci
& 0xffff;
447 uint32_t size
= (uint32_t)ar
->i_ci
>> 16;
448 lj_assertL(offset
!= 0, "bad frame offset");
449 frame
= tvref(L
->stack
) + offset
;
450 if (size
) nextframe
= frame
+ size
;
451 lj_assertL(frame
<= tvref(L
->maxstack
) &&
452 (!nextframe
|| nextframe
<= tvref(L
->maxstack
)),
453 "broken frame chain");
454 fn
= frame_func(frame
);
455 lj_assertL(fn
->c
.gct
== ~LJ_TFUNC
, "bad frame function");
457 for (; *what
; what
++) {
460 GCproto
*pt
= funcproto(fn
);
461 BCLine firstline
= pt
->firstline
;
462 GCstr
*name
= proto_chunkname(pt
);
463 ar
->source
= strdata(name
);
464 lj_debug_shortname(ar
->short_src
, name
, pt
->firstline
);
465 ar
->linedefined
= (int)firstline
;
466 ar
->lastlinedefined
= (int)(firstline
+ pt
->numline
);
467 ar
->what
= (firstline
|| !pt
->numline
) ? "Lua" : "main";
470 ar
->short_src
[0] = '[';
471 ar
->short_src
[1] = 'C';
472 ar
->short_src
[2] = ']';
473 ar
->short_src
[3] = '\0';
474 ar
->linedefined
= -1;
475 ar
->lastlinedefined
= -1;
478 } else if (*what
== 'l') {
479 ar
->currentline
= frame
? debug_frameline(L
, fn
, nextframe
) : -1;
480 } else if (*what
== 'u') {
481 ar
->nups
= fn
->c
.nupvalues
;
484 GCproto
*pt
= funcproto(fn
);
485 ar
->nparams
= pt
->numparams
;
486 ar
->isvararg
= !!(pt
->flags
& PROTO_VARARG
);
492 } else if (*what
== 'n') {
493 ar
->namewhat
= frame
? lj_debug_funcname(L
, frame
, &ar
->name
) : NULL
;
494 if (ar
->namewhat
== NULL
) {
498 } else if (*what
== 'f') {
500 } else if (*what
== 'L') {
503 return 0; /* Bad option. */
507 setfuncV(L
, L
->top
, fn
);
512 GCtab
*t
= lj_tab_new(L
, 0, 0);
513 GCproto
*pt
= funcproto(fn
);
514 const void *lineinfo
= proto_lineinfo(pt
);
516 BCLine first
= pt
->firstline
;
517 int sz
= pt
->numline
< 256 ? 1 : pt
->numline
< 65536 ? 2 : 4;
518 MSize i
, szl
= pt
->sizebc
-1;
519 for (i
= 0; i
< szl
; i
++) {
520 BCLine line
= first
+
521 (sz
== 1 ? (BCLine
)((const uint8_t *)lineinfo
)[i
] :
522 sz
== 2 ? (BCLine
)((const uint16_t *)lineinfo
)[i
] :
523 (BCLine
)((const uint32_t *)lineinfo
)[i
]);
524 setboolV(lj_tab_setint(L
, t
, line
), 1);
527 settabV(L
, L
->top
, t
);
536 LUA_API
int lua_getinfo(lua_State
*L
, const char *what
, lua_Debug
*ar
)
538 return lj_debug_getinfo(L
, what
, (lj_Debug
*)ar
, 0);
541 LUA_API
int lua_getstack(lua_State
*L
, int level
, lua_Debug
*ar
)
544 cTValue
*frame
= lj_debug_frame(L
, level
, &size
);
546 ar
->i_ci
= (size
<< 16) + (int)(frame
- tvref(L
->stack
));
549 ar
->i_ci
= level
- size
;
555 /* Put the chunkname into a buffer. */
556 static int debug_putchunkname(SBuf
*sb
, GCproto
*pt
, int pathstrip
)
558 GCstr
*name
= proto_chunkname(pt
);
559 const char *p
= strdata(name
);
560 if (pt
->firstline
== ~(BCLine
)0) {
561 lj_buf_putmem(sb
, "[builtin:", 9);
562 lj_buf_putstr(sb
, name
);
563 lj_buf_putb(sb
, ']');
566 if (*p
== '=' || *p
== '@') {
567 MSize len
= name
->len
-1;
571 for (i
= len
-1; i
>= 0; i
--)
572 if (p
[i
] == '/' || p
[i
] == '\\') {
578 lj_buf_putmem(sb
, p
, len
);
580 lj_buf_putmem(sb
, "[string]", 8);
585 /* Put a compact stack dump into a buffer. */
586 void lj_debug_dumpstack(lua_State
*L
, SBuf
*sb
, const char *fmt
, int depth
)
588 int level
= 0, dir
= 1, pathstrip
= 1;
590 if (depth
< 0) { level
= ~depth
; depth
= dir
= -1; } /* Reverse frames. */
591 while (level
!= depth
) { /* Loop through all frame. */
593 cTValue
*frame
= lj_debug_frame(L
, level
, &size
);
595 cTValue
*nextframe
= size
? frame
+size
: NULL
;
596 GCfunc
*fn
= frame_func(frame
);
597 const uint8_t *p
= (const uint8_t *)fmt
;
601 case 'p': /* Preserve full path. */
604 case 'F': case 'f': { /* Dump function name. */
606 const char *what
= lj_debug_funcname(L
, frame
, &name
);
608 if (c
== 'F' && isluafunc(fn
)) { /* Dump module:name for 'F'. */
609 GCproto
*pt
= funcproto(fn
);
610 if (pt
->firstline
!= ~(BCLine
)0) { /* Not a bytecode builtin. */
611 debug_putchunkname(sb
, pt
, pathstrip
);
612 lj_buf_putb(sb
, ':');
615 lj_buf_putmem(sb
, name
, (MSize
)strlen(name
));
617 } /* else: can't derive a name, dump module:line. */
620 case 'l': /* Dump module:line. */
622 GCproto
*pt
= funcproto(fn
);
623 if (debug_putchunkname(sb
, pt
, pathstrip
)) {
624 /* Regular Lua function. */
625 BCLine line
= c
== 'l' ? debug_frameline(L
, fn
, nextframe
) :
627 lj_buf_putb(sb
, ':');
628 lj_strfmt_putint(sb
, line
>= 0 ? line
: pt
->firstline
);
630 } else if (isffunc(fn
)) { /* Dump numbered builtins. */
631 lj_buf_putmem(sb
, "[builtin#", 9);
632 lj_strfmt_putint(sb
, fn
->c
.ffid
);
633 lj_buf_putb(sb
, ']');
634 } else { /* Dump C function address. */
635 lj_buf_putb(sb
, '@');
636 lj_strfmt_putptr(sb
, fn
->c
.f
);
639 case 'Z': /* Zap trailing separator. */
640 lastlen
= sbuflen(sb
);
647 } else if (dir
== 1) {
650 level
-= size
; /* Reverse frame order: quickly skip missing level. */
655 sb
->w
= sb
->b
+ lastlen
; /* Zap trailing separator. */
659 /* Number of frames for the leading and trailing part of a traceback. */
660 #define TRACEBACK_LEVELS1 12
661 #define TRACEBACK_LEVELS2 10
663 LUALIB_API
void luaL_traceback (lua_State
*L
, lua_State
*L1
, const char *msg
,
666 int top
= (int)(L
->top
- L
->base
);
667 int lim
= TRACEBACK_LEVELS1
;
669 if (msg
) lua_pushfstring(L
, "%s\n", msg
);
670 lua_pushliteral(L
, "stack traceback:");
671 while (lua_getstack(L1
, level
++, &ar
)) {
674 if (!lua_getstack(L1
, level
+ TRACEBACK_LEVELS2
, &ar
)) {
677 lua_pushliteral(L
, "\n\t...");
678 lua_getstack(L1
, -10, &ar
);
679 level
= ar
.i_ci
- TRACEBACK_LEVELS2
;
684 lua_getinfo(L1
, "Snlf", &ar
);
685 fn
= funcV(L1
->top
-1); L1
->top
--;
686 if (isffunc(fn
) && !*ar
.namewhat
)
687 lua_pushfstring(L
, "\n\t[builtin#%d]:", fn
->c
.ffid
);
689 lua_pushfstring(L
, "\n\t%s:", ar
.short_src
);
690 if (ar
.currentline
> 0)
691 lua_pushfstring(L
, "%d:", ar
.currentline
);
693 lua_pushfstring(L
, " in function " LUA_QS
, ar
.name
);
695 if (*ar
.what
== 'm') {
696 lua_pushliteral(L
, " in main chunk");
697 } else if (*ar
.what
== 'C') {
698 lua_pushfstring(L
, " at %p", fn
->c
.f
);
700 lua_pushfstring(L
, " in function <%s:%d>",
701 ar
.short_src
, ar
.linedefined
);
704 if ((int)(L
->top
- L
->base
) - top
>= 15)
705 lua_concat(L
, (int)(L
->top
- L
->base
) - top
);
707 lua_concat(L
, (int)(L
->top
- L
->base
) - top
);