diff options
Diffstat (limited to '')
-rw-r--r-- | src/lj_debug.c | 186 |
1 files changed, 140 insertions, 46 deletions
diff --git a/src/lj_debug.c b/src/lj_debug.c index 429a76cd..153035a9 100644 --- a/src/lj_debug.c +++ b/src/lj_debug.c | |||
@@ -9,12 +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_vm.h" | 17 | #include "lj_strfmt.h" |
18 | #if LJ_HASJIT | 18 | #if LJ_HASJIT |
19 | #include "lj_jit.h" | 19 | #include "lj_jit.h" |
20 | #endif | 20 | #endif |
@@ -24,11 +24,11 @@ | |||
24 | /* Get frame corresponding to a level. */ | 24 | /* Get frame corresponding to a level. */ |
25 | cTValue *lj_debug_frame(lua_State *L, int level, int *size) | 25 | cTValue *lj_debug_frame(lua_State *L, int level, int *size) |
26 | { | 26 | { |
27 | cTValue *frame, *nextframe, *bot = tvref(L->stack); | 27 | cTValue *frame, *nextframe, *bot = tvref(L->stack)+LJ_FR2; |
28 | /* Traverse frames backwards. */ | 28 | /* Traverse frames backwards. */ |
29 | for (nextframe = frame = L->base-1; frame > bot; ) { | 29 | for (nextframe = frame = L->base-1; frame > bot; ) { |
30 | if (frame_gc(frame) == obj2gco(L)) | 30 | if (frame_gc(frame) == obj2gco(L)) |
31 | level++; /* Skip dummy frames. See lj_meta_call(). */ | 31 | level++; /* Skip dummy frames. See lj_err_optype_call(). */ |
32 | if (level-- == 0) { | 32 | if (level-- == 0) { |
33 | *size = (int)(nextframe - frame); | 33 | *size = (int)(nextframe - frame); |
34 | return frame; /* Level found. */ | 34 | return frame; /* Level found. */ |
@@ -87,8 +87,7 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
87 | if (frame_islua(f)) { | 87 | if (frame_islua(f)) { |
88 | f = frame_prevl(f); | 88 | f = frame_prevl(f); |
89 | } else { | 89 | } else { |
90 | if (frame_isc(f) || (LJ_HASFFI && frame_iscont(f) && | 90 | if (frame_isc(f) || (frame_iscont(f) && frame_iscont_fficb(f))) |
91 | (f-1)->u32.lo == LJ_CONT_FFI_CALLBACK)) | ||
92 | cf = cframe_raw(cframe_prev(cf)); | 91 | cf = cframe_raw(cframe_prev(cf)); |
93 | f = frame_prevd(f); | 92 | f = frame_prevd(f); |
94 | } | 93 | } |
@@ -142,38 +141,25 @@ static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
142 | 141 | ||
143 | /* -- Variable names ------------------------------------------------------ */ | 142 | /* -- Variable names ------------------------------------------------------ */ |
144 | 143 | ||
145 | /* Read ULEB128 value. */ | ||
146 | static uint32_t debug_read_uleb128(const uint8_t **pp) | ||
147 | { | ||
148 | const uint8_t *p = *pp; | ||
149 | uint32_t v = *p++; | ||
150 | if (LJ_UNLIKELY(v >= 0x80)) { | ||
151 | int sh = 0; | ||
152 | v &= 0x7f; | ||
153 | do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80); | ||
154 | } | ||
155 | *pp = p; | ||
156 | return v; | ||
157 | } | ||
158 | |||
159 | /* Get name of a local variable from slot number and PC. */ | 144 | /* Get name of a local variable from slot number and PC. */ |
160 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) | 145 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) |
161 | { | 146 | { |
162 | const uint8_t *p = proto_varinfo(pt); | 147 | const char *p = (const char *)proto_varinfo(pt); |
163 | if (p) { | 148 | if (p) { |
164 | BCPos lastpc = 0; | 149 | BCPos lastpc = 0; |
165 | for (;;) { | 150 | for (;;) { |
166 | const char *name = (const char *)p; | 151 | const char *name = p; |
167 | uint32_t vn = *p++; | 152 | uint32_t vn = *(const uint8_t *)p; |
168 | BCPos startpc, endpc; | 153 | BCPos startpc, endpc; |
169 | if (vn < VARNAME__MAX) { | 154 | if (vn < VARNAME__MAX) { |
170 | if (vn == VARNAME_END) break; /* End of varinfo. */ | 155 | if (vn == VARNAME_END) break; /* End of varinfo. */ |
171 | } else { | 156 | } else { |
172 | while (*p++) ; /* Skip over variable name string. */ | 157 | do { p++; } while (*(const uint8_t *)p); /* Skip over variable name. */ |
173 | } | 158 | } |
174 | lastpc = startpc = lastpc + debug_read_uleb128(&p); | 159 | p++; |
160 | lastpc = startpc = lastpc + lj_buf_ruleb128(&p); | ||
175 | if (startpc > pc) break; | 161 | if (startpc > pc) break; |
176 | endpc = startpc + debug_read_uleb128(&p); | 162 | endpc = startpc + lj_buf_ruleb128(&p); |
177 | if (pc < endpc && slot-- == 0) { | 163 | if (pc < endpc && slot-- == 0) { |
178 | if (vn < VARNAME__MAX) { | 164 | if (vn < VARNAME__MAX) { |
179 | #define VARNAMESTR(name, str) str "\0" | 165 | #define VARNAMESTR(name, str) str "\0" |
@@ -198,7 +184,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
198 | TValue *nextframe = size ? frame + size : NULL; | 184 | TValue *nextframe = size ? frame + size : NULL; |
199 | GCfunc *fn = frame_func(frame); | 185 | GCfunc *fn = frame_func(frame); |
200 | BCPos pc = debug_framepc(L, fn, nextframe); | 186 | BCPos pc = debug_framepc(L, fn, nextframe); |
201 | if (!nextframe) nextframe = L->top; | 187 | if (!nextframe) nextframe = L->top+LJ_FR2; |
202 | if ((int)slot1 < 0) { /* Negative slot number is for varargs. */ | 188 | if ((int)slot1 < 0) { /* Negative slot number is for varargs. */ |
203 | if (pc != NO_BCPOS) { | 189 | if (pc != NO_BCPOS) { |
204 | GCproto *pt = funcproto(fn); | 190 | GCproto *pt = funcproto(fn); |
@@ -208,7 +194,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
208 | nextframe = frame; | 194 | nextframe = frame; |
209 | frame = frame_prevd(frame); | 195 | frame = frame_prevd(frame); |
210 | } | 196 | } |
211 | if (frame + slot1 < nextframe) { | 197 | if (frame + slot1+LJ_FR2 < nextframe) { |
212 | *name = "(*vararg)"; | 198 | *name = "(*vararg)"; |
213 | return frame+slot1; | 199 | return frame+slot1; |
214 | } | 200 | } |
@@ -219,7 +205,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
219 | if (pc != NO_BCPOS && | 205 | if (pc != NO_BCPOS && |
220 | (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL) | 206 | (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL) |
221 | ; | 207 | ; |
222 | else if (slot1 > 0 && frame + slot1 < nextframe) | 208 | else if (slot1 > 0 && frame + slot1+LJ_FR2 < nextframe) |
223 | *name = "(*temporary)"; | 209 | *name = "(*temporary)"; |
224 | return frame+slot1; | 210 | return frame+slot1; |
225 | } | 211 | } |
@@ -282,7 +268,7 @@ restart: | |||
282 | *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); | 268 | *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); |
283 | if (ip > proto_bc(pt)) { | 269 | if (ip > proto_bc(pt)) { |
284 | BCIns insp = ip[-1]; | 270 | BCIns insp = ip[-1]; |
285 | if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1 && | 271 | if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 && |
286 | bc_d(insp) == bc_b(ins)) | 272 | bc_d(insp) == bc_b(ins)) |
287 | return "method"; | 273 | return "method"; |
288 | } | 274 | } |
@@ -299,12 +285,12 @@ restart: | |||
299 | } | 285 | } |
300 | 286 | ||
301 | /* Deduce function name from caller of a frame. */ | 287 | /* Deduce function name from caller of a frame. */ |
302 | const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | 288 | const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name) |
303 | { | 289 | { |
304 | TValue *pframe; | 290 | cTValue *pframe; |
305 | GCfunc *fn; | 291 | GCfunc *fn; |
306 | BCPos pc; | 292 | BCPos pc; |
307 | if (frame <= tvref(L->stack)) | 293 | if (frame <= tvref(L->stack)+LJ_FR2) |
308 | return NULL; | 294 | return NULL; |
309 | if (frame_isvarg(frame)) | 295 | if (frame_isvarg(frame)) |
310 | frame = frame_prevd(frame); | 296 | frame = frame_prevd(frame); |
@@ -330,7 +316,7 @@ const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | |||
330 | /* -- Source code locations ----------------------------------------------- */ | 316 | /* -- Source code locations ----------------------------------------------- */ |
331 | 317 | ||
332 | /* Generate shortened source name. */ | 318 | /* Generate shortened source name. */ |
333 | void lj_debug_shortname(char *out, GCstr *str) | 319 | void lj_debug_shortname(char *out, GCstr *str, BCLine line) |
334 | { | 320 | { |
335 | const char *src = strdata(str); | 321 | const char *src = strdata(str); |
336 | if (*src == '=') { | 322 | if (*src == '=') { |
@@ -344,11 +330,11 @@ void lj_debug_shortname(char *out, GCstr *str) | |||
344 | *out++ = '.'; *out++ = '.'; *out++ = '.'; | 330 | *out++ = '.'; *out++ = '.'; *out++ = '.'; |
345 | } | 331 | } |
346 | strcpy(out, src); | 332 | strcpy(out, src); |
347 | } else { /* Output [string "string"]. */ | 333 | } else { /* Output [string "string"] or [builtin:name]. */ |
348 | size_t len; /* Length, up to first control char. */ | 334 | size_t len; /* Length, up to first control char. */ |
349 | for (len = 0; len < LUA_IDSIZE-12; len++) | 335 | for (len = 0; len < LUA_IDSIZE-12; len++) |
350 | if (((const unsigned char *)src)[len] < ' ') break; | 336 | if (((const unsigned char *)src)[len] < ' ') break; |
351 | strcpy(out, "[string \""); out += 9; | 337 | strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9; |
352 | if (src[len] != '\0') { /* Must truncate? */ | 338 | if (src[len] != '\0') { /* Must truncate? */ |
353 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; | 339 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; |
354 | strncpy(out, src, len); out += len; | 340 | strncpy(out, src, len); out += len; |
@@ -356,7 +342,7 @@ void lj_debug_shortname(char *out, GCstr *str) | |||
356 | } else { | 342 | } else { |
357 | strcpy(out, src); out += len; | 343 | strcpy(out, src); out += len; |
358 | } | 344 | } |
359 | strcpy(out, "\"]"); | 345 | strcpy(out, line == ~(BCLine)0 ? "]" : "\"]"); |
360 | } | 346 | } |
361 | } | 347 | } |
362 | 348 | ||
@@ -369,14 +355,15 @@ void lj_debug_addloc(lua_State *L, const char *msg, | |||
369 | if (isluafunc(fn)) { | 355 | if (isluafunc(fn)) { |
370 | BCLine line = debug_frameline(L, fn, nextframe); | 356 | BCLine line = debug_frameline(L, fn, nextframe); |
371 | if (line >= 0) { | 357 | if (line >= 0) { |
358 | GCproto *pt = funcproto(fn); | ||
372 | char buf[LUA_IDSIZE]; | 359 | char buf[LUA_IDSIZE]; |
373 | lj_debug_shortname(buf, proto_chunkname(funcproto(fn))); | 360 | lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline); |
374 | lj_str_pushf(L, "%s:%d: %s", buf, line, msg); | 361 | lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg); |
375 | return; | 362 | return; |
376 | } | 363 | } |
377 | } | 364 | } |
378 | } | 365 | } |
379 | lj_str_pushf(L, "%s", msg); | 366 | lj_strfmt_pushf(L, "%s", msg); |
380 | } | 367 | } |
381 | 368 | ||
382 | /* Push location string for a bytecode position to Lua stack. */ | 369 | /* Push location string for a bytecode position to Lua stack. */ |
@@ -386,20 +373,22 @@ void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc) | |||
386 | const char *s = strdata(name); | 373 | const char *s = strdata(name); |
387 | MSize i, len = name->len; | 374 | MSize i, len = name->len; |
388 | BCLine line = lj_debug_line(pt, pc); | 375 | BCLine line = lj_debug_line(pt, pc); |
389 | if (*s == '@') { | 376 | if (pt->firstline == ~(BCLine)0) { |
377 | lj_strfmt_pushf(L, "builtin:%s", s); | ||
378 | } else if (*s == '@') { | ||
390 | s++; len--; | 379 | s++; len--; |
391 | for (i = len; i > 0; i--) | 380 | for (i = len; i > 0; i--) |
392 | if (s[i] == '/' || s[i] == '\\') { | 381 | if (s[i] == '/' || s[i] == '\\') { |
393 | s += i+1; | 382 | s += i+1; |
394 | break; | 383 | break; |
395 | } | 384 | } |
396 | lj_str_pushf(L, "%s:%d", s, line); | 385 | lj_strfmt_pushf(L, "%s:%d", s, line); |
397 | } else if (len > 40) { | 386 | } else if (len > 40) { |
398 | lj_str_pushf(L, "%p:%d", pt, line); | 387 | lj_strfmt_pushf(L, "%p:%d", pt, line); |
399 | } else if (*s == '=') { | 388 | } else if (*s == '=') { |
400 | lj_str_pushf(L, "%s:%d", s+1, line); | 389 | lj_strfmt_pushf(L, "%s:%d", s+1, line); |
401 | } else { | 390 | } else { |
402 | lj_str_pushf(L, "\"%s\":%d", s, line); | 391 | lj_strfmt_pushf(L, "\"%s\":%d", s, line); |
403 | } | 392 | } |
404 | } | 393 | } |
405 | 394 | ||
@@ -462,7 +451,7 @@ int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext) | |||
462 | BCLine firstline = pt->firstline; | 451 | BCLine firstline = pt->firstline; |
463 | GCstr *name = proto_chunkname(pt); | 452 | GCstr *name = proto_chunkname(pt); |
464 | ar->source = strdata(name); | 453 | ar->source = strdata(name); |
465 | lj_debug_shortname(ar->short_src, name); | 454 | lj_debug_shortname(ar->short_src, name, pt->firstline); |
466 | ar->linedefined = (int)firstline; | 455 | ar->linedefined = (int)firstline; |
467 | ar->lastlinedefined = (int)(firstline + pt->numline); | 456 | ar->lastlinedefined = (int)(firstline + pt->numline); |
468 | ar->what = (firstline || !pt->numline) ? "Lua" : "main"; | 457 | ar->what = (firstline || !pt->numline) ? "Lua" : "main"; |
@@ -552,6 +541,111 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar) | |||
552 | } | 541 | } |
553 | } | 542 | } |
554 | 543 | ||
544 | #if LJ_HASPROFILE | ||
545 | /* Put the chunkname into a buffer. */ | ||
546 | static 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]", 8); | ||
571 | } | ||
572 | return 1; | ||
573 | } | ||
574 | |||
575 | /* Put a compact stack dump into a buffer. */ | ||
576 | void 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 | |||
555 | /* 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. */ |
556 | #define TRACEBACK_LEVELS1 12 | 650 | #define TRACEBACK_LEVELS1 12 |
557 | #define TRACEBACK_LEVELS2 10 | 651 | #define TRACEBACK_LEVELS2 10 |