aboutsummaryrefslogtreecommitdiff
path: root/src/lj_debug.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lj_debug.c170
1 files changed, 133 insertions, 37 deletions
diff --git a/src/lj_debug.c b/src/lj_debug.c
index 09896462..92c216f9 100644
--- a/src/lj_debug.c
+++ b/src/lj_debug.c
@@ -9,11 +9,12 @@
9#include "lj_obj.h" 9#include "lj_obj.h"
10#include "lj_err.h" 10#include "lj_err.h"
11#include "lj_debug.h" 11#include "lj_debug.h"
12#include "lj_str.h" 12#include "lj_buf.h"
13#include "lj_tab.h" 13#include "lj_tab.h"
14#include "lj_state.h" 14#include "lj_state.h"
15#include "lj_frame.h" 15#include "lj_frame.h"
16#include "lj_bc.h" 16#include "lj_bc.h"
17#include "lj_strfmt.h"
17#if LJ_HASJIT 18#if LJ_HASJIT
18#include "lj_jit.h" 19#include "lj_jit.h"
19#endif 20#endif
@@ -27,7 +28,7 @@ cTValue *lj_debug_frame(lua_State *L, int level, int *size)
27 /* Traverse frames backwards. */ 28 /* Traverse frames backwards. */
28 for (nextframe = frame = L->base-1; frame > bot; ) { 29 for (nextframe = frame = L->base-1; frame > bot; ) {
29 if (frame_gc(frame) == obj2gco(L)) 30 if (frame_gc(frame) == obj2gco(L))
30 level++; /* Skip dummy frames. See lj_meta_call(). */ 31 level++; /* Skip dummy frames. See lj_err_optype_call(). */
31 if (level-- == 0) { 32 if (level-- == 0) {
32 *size = (int)(nextframe - frame); 33 *size = (int)(nextframe - frame);
33 return frame; /* Level found. */ 34 return frame; /* Level found. */
@@ -140,38 +141,25 @@ static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
140 141
141/* -- Variable names ------------------------------------------------------ */ 142/* -- Variable names ------------------------------------------------------ */
142 143
143/* Read ULEB128 value. */
144static uint32_t debug_read_uleb128(const uint8_t **pp)
145{
146 const uint8_t *p = *pp;
147 uint32_t v = *p++;
148 if (LJ_UNLIKELY(v >= 0x80)) {
149 int sh = 0;
150 v &= 0x7f;
151 do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80);
152 }
153 *pp = p;
154 return v;
155}
156
157/* Get name of a local variable from slot number and PC. */ 144/* Get name of a local variable from slot number and PC. */
158static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) 145static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot)
159{ 146{
160 const uint8_t *p = proto_varinfo(pt); 147 const char *p = (const char *)proto_varinfo(pt);
161 if (p) { 148 if (p) {
162 BCPos lastpc = 0; 149 BCPos lastpc = 0;
163 for (;;) { 150 for (;;) {
164 const char *name = (const char *)p; 151 const char *name = p;
165 uint32_t vn = *p++; 152 uint32_t vn = *(const uint8_t *)p;
166 BCPos startpc, endpc; 153 BCPos startpc, endpc;
167 if (vn < VARNAME__MAX) { 154 if (vn < VARNAME__MAX) {
168 if (vn == VARNAME_END) break; /* End of varinfo. */ 155 if (vn == VARNAME_END) break; /* End of varinfo. */
169 } else { 156 } else {
170 while (*p++) ; /* Skip over variable name string. */ 157 do { p++; } while (*(const uint8_t *)p); /* Skip over variable name. */
171 } 158 }
172 lastpc = startpc = lastpc + debug_read_uleb128(&p); 159 p++;
160 lastpc = startpc = lastpc + lj_buf_ruleb128(&p);
173 if (startpc > pc) break; 161 if (startpc > pc) break;
174 endpc = startpc + debug_read_uleb128(&p); 162 endpc = startpc + lj_buf_ruleb128(&p);
175 if (pc < endpc && slot-- == 0) { 163 if (pc < endpc && slot-- == 0) {
176 if (vn < VARNAME__MAX) { 164 if (vn < VARNAME__MAX) {
177#define VARNAMESTR(name, str) str "\0" 165#define VARNAMESTR(name, str) str "\0"
@@ -297,9 +285,9 @@ restart:
297} 285}
298 286
299/* Deduce function name from caller of a frame. */ 287/* Deduce function name from caller of a frame. */
300const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) 288const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name)
301{ 289{
302 TValue *pframe; 290 cTValue *pframe;
303 GCfunc *fn; 291 GCfunc *fn;
304 BCPos pc; 292 BCPos pc;
305 if (frame <= tvref(L->stack)) 293 if (frame <= tvref(L->stack))
@@ -328,7 +316,7 @@ const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name)
328/* -- Source code locations ----------------------------------------------- */ 316/* -- Source code locations ----------------------------------------------- */
329 317
330/* Generate shortened source name. */ 318/* Generate shortened source name. */
331void lj_debug_shortname(char *out, GCstr *str) 319void lj_debug_shortname(char *out, GCstr *str, BCLine line)
332{ 320{
333 const char *src = strdata(str); 321 const char *src = strdata(str);
334 if (*src == '=') { 322 if (*src == '=') {
@@ -342,11 +330,11 @@ void lj_debug_shortname(char *out, GCstr *str)
342 *out++ = '.'; *out++ = '.'; *out++ = '.'; 330 *out++ = '.'; *out++ = '.'; *out++ = '.';
343 } 331 }
344 strcpy(out, src); 332 strcpy(out, src);
345 } else { /* Output [string "string"]. */ 333 } else { /* Output [string "string"] or [builtin:name]. */
346 size_t len; /* Length, up to first control char. */ 334 size_t len; /* Length, up to first control char. */
347 for (len = 0; len < LUA_IDSIZE-12; len++) 335 for (len = 0; len < LUA_IDSIZE-12; len++)
348 if (((const unsigned char *)src)[len] < ' ') break; 336 if (((const unsigned char *)src)[len] < ' ') break;
349 strcpy(out, "[string \""); out += 9; 337 strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9;
350 if (src[len] != '\0') { /* Must truncate? */ 338 if (src[len] != '\0') { /* Must truncate? */
351 if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; 339 if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
352 strncpy(out, src, len); out += len; 340 strncpy(out, src, len); out += len;
@@ -354,7 +342,7 @@ void lj_debug_shortname(char *out, GCstr *str)
354 } else { 342 } else {
355 strcpy(out, src); out += len; 343 strcpy(out, src); out += len;
356 } 344 }
357 strcpy(out, "\"]"); 345 strcpy(out, line == ~(BCLine)0 ? "]" : "\"]");
358 } 346 }
359} 347}
360 348
@@ -367,14 +355,15 @@ void lj_debug_addloc(lua_State *L, const char *msg,
367 if (isluafunc(fn)) { 355 if (isluafunc(fn)) {
368 BCLine line = debug_frameline(L, fn, nextframe); 356 BCLine line = debug_frameline(L, fn, nextframe);
369 if (line >= 0) { 357 if (line >= 0) {
358 GCproto *pt = funcproto(fn);
370 char buf[LUA_IDSIZE]; 359 char buf[LUA_IDSIZE];
371 lj_debug_shortname(buf, proto_chunkname(funcproto(fn))); 360 lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline);
372 lj_str_pushf(L, "%s:%d: %s", buf, line, msg); 361 lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg);
373 return; 362 return;
374 } 363 }
375 } 364 }
376 } 365 }
377 lj_str_pushf(L, "%s", msg); 366 lj_strfmt_pushf(L, "%s", msg);
378} 367}
379 368
380/* Push location string for a bytecode position to Lua stack. */ 369/* Push location string for a bytecode position to Lua stack. */
@@ -384,20 +373,22 @@ void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
384 const char *s = strdata(name); 373 const char *s = strdata(name);
385 MSize i, len = name->len; 374 MSize i, len = name->len;
386 BCLine line = lj_debug_line(pt, pc); 375 BCLine line = lj_debug_line(pt, pc);
387 if (*s == '@') { 376 if (pt->firstline == ~(BCLine)0) {
377 lj_strfmt_pushf(L, "builtin:%s", s);
378 } else if (*s == '@') {
388 s++; len--; 379 s++; len--;
389 for (i = len; i > 0; i--) 380 for (i = len; i > 0; i--)
390 if (s[i] == '/' || s[i] == '\\') { 381 if (s[i] == '/' || s[i] == '\\') {
391 s += i+1; 382 s += i+1;
392 break; 383 break;
393 } 384 }
394 lj_str_pushf(L, "%s:%d", s, line); 385 lj_strfmt_pushf(L, "%s:%d", s, line);
395 } else if (len > 40) { 386 } else if (len > 40) {
396 lj_str_pushf(L, "%p:%d", pt, line); 387 lj_strfmt_pushf(L, "%p:%d", pt, line);
397 } else if (*s == '=') { 388 } else if (*s == '=') {
398 lj_str_pushf(L, "%s:%d", s+1, line); 389 lj_strfmt_pushf(L, "%s:%d", s+1, line);
399 } else { 390 } else {
400 lj_str_pushf(L, "\"%s\":%d", s, line); 391 lj_strfmt_pushf(L, "\"%s\":%d", s, line);
401 } 392 }
402} 393}
403 394
@@ -460,7 +451,7 @@ int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
460 BCLine firstline = pt->firstline; 451 BCLine firstline = pt->firstline;
461 GCstr *name = proto_chunkname(pt); 452 GCstr *name = proto_chunkname(pt);
462 ar->source = strdata(name); 453 ar->source = strdata(name);
463 lj_debug_shortname(ar->short_src, name); 454 lj_debug_shortname(ar->short_src, name, pt->firstline);
464 ar->linedefined = (int)firstline; 455 ar->linedefined = (int)firstline;
465 ar->lastlinedefined = (int)(firstline + pt->numline); 456 ar->lastlinedefined = (int)(firstline + pt->numline);
466 ar->what = firstline ? "Lua" : "main"; 457 ar->what = firstline ? "Lua" : "main";
@@ -550,6 +541,111 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
550 } 541 }
551} 542}
552 543
544#if LJ_HASPROFILE
545/* Put the chunkname into a buffer. */
546static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip)
547{
548 GCstr *name = proto_chunkname(pt);
549 const char *p = strdata(name);
550 if (pt->firstline == ~(BCLine)0) {
551 lj_buf_putmem(sb, "[builtin:", 9);
552 lj_buf_putstr(sb, name);
553 lj_buf_putb(sb, ']');
554 return 0;
555 }
556 if (*p == '=' || *p == '@') {
557 MSize len = name->len-1;
558 p++;
559 if (pathstrip) {
560 int i;
561 for (i = len-1; i >= 0; i--)
562 if (p[i] == '/' || p[i] == '\\') {
563 len -= i+1;
564 p = p+i+1;
565 break;
566 }
567 }
568 lj_buf_putmem(sb, p, len);
569 } else {
570 lj_buf_putmem(sb, "[string]", 9);
571 }
572 return 1;
573}
574
575/* Put a compact stack dump into a buffer. */
576void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth)
577{
578 int level = 0, dir = 1, pathstrip = 1;
579 MSize lastlen = 0;
580 if (depth < 0) { level = ~depth; depth = dir = -1; } /* Reverse frames. */
581 while (level != depth) { /* Loop through all frame. */
582 int size;
583 cTValue *frame = lj_debug_frame(L, level, &size);
584 if (frame) {
585 cTValue *nextframe = size ? frame+size : NULL;
586 GCfunc *fn = frame_func(frame);
587 const uint8_t *p = (const uint8_t *)fmt;
588 int c;
589 while ((c = *p++)) {
590 switch (c) {
591 case 'p': /* Preserve full path. */
592 pathstrip = 0;
593 break;
594 case 'F': case 'f': { /* Dump function name. */
595 const char *name;
596 const char *what = lj_debug_funcname(L, frame, &name);
597 if (what) {
598 if (c == 'F' && isluafunc(fn)) { /* Dump module:name for 'F'. */
599 GCproto *pt = funcproto(fn);
600 if (pt->firstline != ~(BCLine)0) { /* Not a bytecode builtin. */
601 debug_putchunkname(sb, pt, pathstrip);
602 lj_buf_putb(sb, ':');
603 }
604 }
605 lj_buf_putmem(sb, name, (MSize)strlen(name));
606 break;
607 } /* else: can't derive a name, dump module:line. */
608 }
609 /* fallthrough */
610 case 'l': /* Dump module:line. */
611 if (isluafunc(fn)) {
612 GCproto *pt = funcproto(fn);
613 if (debug_putchunkname(sb, pt, pathstrip)) {
614 /* Regular Lua function. */
615 BCLine line = c == 'l' ? debug_frameline(L, fn, nextframe) :
616 pt->firstline;
617 lj_buf_putb(sb, ':');
618 lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline);
619 }
620 } else if (isffunc(fn)) { /* Dump numbered builtins. */
621 lj_buf_putmem(sb, "[builtin#", 9);
622 lj_strfmt_putint(sb, fn->c.ffid);
623 lj_buf_putb(sb, ']');
624 } else { /* Dump C function address. */
625 lj_buf_putb(sb, '@');
626 lj_strfmt_putptr(sb, fn->c.f);
627 }
628 break;
629 case 'Z': /* Zap trailing separator. */
630 lastlen = sbuflen(sb);
631 break;
632 default:
633 lj_buf_putb(sb, c);
634 break;
635 }
636 }
637 } else if (dir == 1) {
638 break;
639 } else {
640 level -= size; /* Reverse frame order: quickly skip missing level. */
641 }
642 level += dir;
643 }
644 if (lastlen)
645 setsbufP(sb, sbufB(sb) + lastlen); /* Zap trailing separator. */
646}
647#endif
648
553/* Number of frames for the leading and trailing part of a traceback. */ 649/* Number of frames for the leading and trailing part of a traceback. */
554#define TRACEBACK_LEVELS1 12 650#define TRACEBACK_LEVELS1 12
555#define TRACEBACK_LEVELS2 10 651#define TRACEBACK_LEVELS2 10