diff options
Diffstat (limited to 'src/lj_debug.c')
-rw-r--r-- | src/lj_debug.c | 111 |
1 files changed, 108 insertions, 3 deletions
diff --git a/src/lj_debug.c b/src/lj_debug.c index 24efd2ff..8166fcc0 100644 --- a/src/lj_debug.c +++ b/src/lj_debug.c | |||
@@ -28,7 +28,7 @@ cTValue *lj_debug_frame(lua_State *L, int level, int *size) | |||
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. */ |
@@ -278,9 +278,9 @@ restart: | |||
278 | } | 278 | } |
279 | 279 | ||
280 | /* Deduce function name from caller of a frame. */ | 280 | /* Deduce function name from caller of a frame. */ |
281 | const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | 281 | const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name) |
282 | { | 282 | { |
283 | TValue *pframe; | 283 | cTValue *pframe; |
284 | GCfunc *fn; | 284 | GCfunc *fn; |
285 | BCPos pc; | 285 | BCPos pc; |
286 | if (frame <= tvref(L->stack)) | 286 | if (frame <= tvref(L->stack)) |
@@ -534,6 +534,111 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar) | |||
534 | } | 534 | } |
535 | } | 535 | } |
536 | 536 | ||
537 | #if LJ_HASPROFILE | ||
538 | /* Put the chunkname into a buffer. */ | ||
539 | static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip) | ||
540 | { | ||
541 | GCstr *name = proto_chunkname(pt); | ||
542 | const char *p = strdata(name); | ||
543 | if (pt->firstline == ~(BCLine)0) { | ||
544 | lj_buf_putmem(sb, "[builtin:", 9); | ||
545 | lj_buf_putstr(sb, name); | ||
546 | lj_buf_putb(sb, ']'); | ||
547 | return 0; | ||
548 | } | ||
549 | if (*p == '=' || *p == '@') { | ||
550 | MSize len = name->len-1; | ||
551 | p++; | ||
552 | if (pathstrip) { | ||
553 | int i; | ||
554 | for (i = len-1; i >= 0; i--) | ||
555 | if (p[i] == '/' || p[i] == '\\') { | ||
556 | len -= i+1; | ||
557 | p = p+i+1; | ||
558 | break; | ||
559 | } | ||
560 | } | ||
561 | lj_buf_putmem(sb, p, len); | ||
562 | } else { | ||
563 | lj_buf_putmem(sb, "[string]", 9); | ||
564 | } | ||
565 | return 1; | ||
566 | } | ||
567 | |||
568 | /* Put a compact stack dump into a buffer. */ | ||
569 | void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth) | ||
570 | { | ||
571 | int level = 0, dir = 1, pathstrip = 1; | ||
572 | MSize lastlen = 0; | ||
573 | if (depth < 0) { level = ~depth; depth = dir = -1; } /* Reverse frames. */ | ||
574 | while (level != depth) { /* Loop through all frame. */ | ||
575 | int size; | ||
576 | cTValue *frame = lj_debug_frame(L, level, &size); | ||
577 | if (frame) { | ||
578 | cTValue *nextframe = size ? frame+size : NULL; | ||
579 | GCfunc *fn = frame_func(frame); | ||
580 | const uint8_t *p = (const uint8_t *)fmt; | ||
581 | int c; | ||
582 | while ((c = *p++)) { | ||
583 | switch (c) { | ||
584 | case 'p': /* Preserve full path. */ | ||
585 | pathstrip = 0; | ||
586 | break; | ||
587 | case 'F': case 'f': { /* Dump function name. */ | ||
588 | const char *name; | ||
589 | const char *what = lj_debug_funcname(L, frame, &name); | ||
590 | if (what) { | ||
591 | if (c == 'F' && isluafunc(fn)) { /* Dump module:name for 'F'. */ | ||
592 | GCproto *pt = funcproto(fn); | ||
593 | if (pt->firstline != ~(BCLine)0) { /* Not a bytecode builtin. */ | ||
594 | debug_putchunkname(sb, pt, pathstrip); | ||
595 | lj_buf_putb(sb, ':'); | ||
596 | } | ||
597 | } | ||
598 | lj_buf_putmem(sb, name, (MSize)strlen(name)); | ||
599 | break; | ||
600 | } /* else: can't derive a name, dump module:line. */ | ||
601 | } | ||
602 | /* fallthrough */ | ||
603 | case 'l': /* Dump module:line. */ | ||
604 | if (isluafunc(fn)) { | ||
605 | GCproto *pt = funcproto(fn); | ||
606 | if (debug_putchunkname(sb, pt, pathstrip)) { | ||
607 | /* Regular Lua function. */ | ||
608 | BCLine line = c == 'l' ? debug_frameline(L, fn, nextframe) : | ||
609 | pt->firstline; | ||
610 | lj_buf_putb(sb, ':'); | ||
611 | lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline); | ||
612 | } | ||
613 | } else if (isffunc(fn)) { /* Dump numbered builtins. */ | ||
614 | lj_buf_putmem(sb, "[builtin#", 9); | ||
615 | lj_strfmt_putint(sb, fn->c.ffid); | ||
616 | lj_buf_putb(sb, ']'); | ||
617 | } else { /* Dump C function address. */ | ||
618 | lj_buf_putb(sb, '@'); | ||
619 | lj_strfmt_putptr(sb, fn->c.f); | ||
620 | } | ||
621 | break; | ||
622 | case 'Z': /* Zap trailing separator. */ | ||
623 | lastlen = sbuflen(sb); | ||
624 | break; | ||
625 | default: | ||
626 | lj_buf_putb(sb, c); | ||
627 | break; | ||
628 | } | ||
629 | } | ||
630 | } else if (dir == 1) { | ||
631 | break; | ||
632 | } else { | ||
633 | level -= size; /* Reverse frame order: quickly skip missing level. */ | ||
634 | } | ||
635 | level += dir; | ||
636 | } | ||
637 | if (lastlen) | ||
638 | setsbufP(sb, sbufB(sb) + lastlen); /* Zap trailing separator. */ | ||
639 | } | ||
640 | #endif | ||
641 | |||
537 | /* Number of frames for the leading and trailing part of a traceback. */ | 642 | /* Number of frames for the leading and trailing part of a traceback. */ |
538 | #define TRACEBACK_LEVELS1 12 | 643 | #define TRACEBACK_LEVELS1 12 |
539 | #define TRACEBACK_LEVELS2 10 | 644 | #define TRACEBACK_LEVELS2 10 |