diff options
Diffstat (limited to 'src/lj_debug.c')
| -rw-r--r-- | src/lj_debug.c | 204 |
1 files changed, 150 insertions, 54 deletions
diff --git a/src/lj_debug.c b/src/lj_debug.c index afa94384..03d86651 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. */ |
| @@ -55,7 +55,8 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
| 55 | const BCIns *ins; | 55 | const BCIns *ins; |
| 56 | GCproto *pt; | 56 | GCproto *pt; |
| 57 | BCPos pos; | 57 | BCPos pos; |
| 58 | lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD); | 58 | lj_assertL(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD, |
| 59 | "function or frame expected"); | ||
| 59 | if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */ | 60 | if (!isluafunc(fn)) { /* Cannot derive a PC for non-Lua functions. */ |
| 60 | return NO_BCPOS; | 61 | return NO_BCPOS; |
| 61 | } else if (nextframe == NULL) { /* Lua function on top. */ | 62 | } else if (nextframe == NULL) { /* Lua function on top. */ |
| @@ -88,8 +89,7 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
| 88 | if (frame_islua(f)) { | 89 | if (frame_islua(f)) { |
| 89 | f = frame_prevl(f); | 90 | f = frame_prevl(f); |
| 90 | } else { | 91 | } else { |
| 91 | if (frame_isc(f) || (LJ_HASFFI && frame_iscont(f) && | 92 | if (frame_isc(f) || (frame_iscont(f) && frame_iscont_fficb(f))) |
| 92 | (f-1)->u32.lo == LJ_CONT_FFI_CALLBACK)) | ||
| 93 | cf = cframe_raw(cframe_prev(cf)); | 93 | cf = cframe_raw(cframe_prev(cf)); |
| 94 | f = frame_prevd(f); | 94 | f = frame_prevd(f); |
| 95 | } | 95 | } |
| @@ -107,7 +107,7 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
| 107 | GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins)); | 107 | GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins)); |
| 108 | pos = proto_bcpos(pt, mref(T->startpc, const BCIns)); | 108 | pos = proto_bcpos(pt, mref(T->startpc, const BCIns)); |
| 109 | } else { | 109 | } else { |
| 110 | pos = NO_BCPOS; /* Punt in case of stack overflow. */ | 110 | pos = NO_BCPOS; /* Punt in case of stack overflow for stitched trace. */ |
| 111 | } | 111 | } |
| 112 | } | 112 | } |
| 113 | #endif | 113 | #endif |
| @@ -140,7 +140,7 @@ static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
| 140 | BCPos pc = debug_framepc(L, fn, nextframe); | 140 | BCPos pc = debug_framepc(L, fn, nextframe); |
| 141 | if (pc != NO_BCPOS) { | 141 | if (pc != NO_BCPOS) { |
| 142 | GCproto *pt = funcproto(fn); | 142 | GCproto *pt = funcproto(fn); |
| 143 | lua_assert(pc <= pt->sizebc); | 143 | lj_assertL(pc <= pt->sizebc, "PC out of range"); |
| 144 | return lj_debug_line(pt, pc); | 144 | return lj_debug_line(pt, pc); |
| 145 | } | 145 | } |
| 146 | return -1; | 146 | return -1; |
| @@ -148,38 +148,25 @@ static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
| 148 | 148 | ||
| 149 | /* -- Variable names ------------------------------------------------------ */ | 149 | /* -- Variable names ------------------------------------------------------ */ |
| 150 | 150 | ||
| 151 | /* Read ULEB128 value. */ | ||
| 152 | static uint32_t debug_read_uleb128(const uint8_t **pp) | ||
| 153 | { | ||
| 154 | const uint8_t *p = *pp; | ||
| 155 | uint32_t v = *p++; | ||
| 156 | if (LJ_UNLIKELY(v >= 0x80)) { | ||
| 157 | int sh = 0; | ||
| 158 | v &= 0x7f; | ||
| 159 | do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80); | ||
| 160 | } | ||
| 161 | *pp = p; | ||
| 162 | return v; | ||
| 163 | } | ||
| 164 | |||
| 165 | /* Get name of a local variable from slot number and PC. */ | 151 | /* Get name of a local variable from slot number and PC. */ |
| 166 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) | 152 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) |
| 167 | { | 153 | { |
| 168 | const uint8_t *p = proto_varinfo(pt); | 154 | const char *p = (const char *)proto_varinfo(pt); |
| 169 | if (p) { | 155 | if (p) { |
| 170 | BCPos lastpc = 0; | 156 | BCPos lastpc = 0; |
| 171 | for (;;) { | 157 | for (;;) { |
| 172 | const char *name = (const char *)p; | 158 | const char *name = p; |
| 173 | uint32_t vn = *p++; | 159 | uint32_t vn = *(const uint8_t *)p; |
| 174 | BCPos startpc, endpc; | 160 | BCPos startpc, endpc; |
| 175 | if (vn < VARNAME__MAX) { | 161 | if (vn < VARNAME__MAX) { |
| 176 | if (vn == VARNAME_END) break; /* End of varinfo. */ | 162 | if (vn == VARNAME_END) break; /* End of varinfo. */ |
| 177 | } else { | 163 | } else { |
| 178 | while (*p++) ; /* Skip over variable name string. */ | 164 | do { p++; } while (*(const uint8_t *)p); /* Skip over variable name. */ |
| 179 | } | 165 | } |
| 180 | lastpc = startpc = lastpc + debug_read_uleb128(&p); | 166 | p++; |
| 167 | lastpc = startpc = lastpc + lj_buf_ruleb128(&p); | ||
| 181 | if (startpc > pc) break; | 168 | if (startpc > pc) break; |
| 182 | endpc = startpc + debug_read_uleb128(&p); | 169 | endpc = startpc + lj_buf_ruleb128(&p); |
| 183 | if (pc < endpc && slot-- == 0) { | 170 | if (pc < endpc && slot-- == 0) { |
| 184 | if (vn < VARNAME__MAX) { | 171 | if (vn < VARNAME__MAX) { |
| 185 | #define VARNAMESTR(name, str) str "\0" | 172 | #define VARNAMESTR(name, str) str "\0" |
| @@ -204,7 +191,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
| 204 | TValue *nextframe = size ? frame + size : NULL; | 191 | TValue *nextframe = size ? frame + size : NULL; |
| 205 | GCfunc *fn = frame_func(frame); | 192 | GCfunc *fn = frame_func(frame); |
| 206 | BCPos pc = debug_framepc(L, fn, nextframe); | 193 | BCPos pc = debug_framepc(L, fn, nextframe); |
| 207 | if (!nextframe) nextframe = L->top; | 194 | if (!nextframe) nextframe = L->top+LJ_FR2; |
| 208 | if ((int)slot1 < 0) { /* Negative slot number is for varargs. */ | 195 | if ((int)slot1 < 0) { /* Negative slot number is for varargs. */ |
| 209 | if (pc != NO_BCPOS) { | 196 | if (pc != NO_BCPOS) { |
| 210 | GCproto *pt = funcproto(fn); | 197 | GCproto *pt = funcproto(fn); |
| @@ -214,7 +201,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
| 214 | nextframe = frame; | 201 | nextframe = frame; |
| 215 | frame = frame_prevd(frame); | 202 | frame = frame_prevd(frame); |
| 216 | } | 203 | } |
| 217 | if (frame + slot1 < nextframe) { | 204 | if (frame + slot1+LJ_FR2 < nextframe) { |
| 218 | *name = "(*vararg)"; | 205 | *name = "(*vararg)"; |
| 219 | return frame+slot1; | 206 | return frame+slot1; |
| 220 | } | 207 | } |
| @@ -225,7 +212,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
| 225 | if (pc != NO_BCPOS && | 212 | if (pc != NO_BCPOS && |
| 226 | (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL) | 213 | (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL) |
| 227 | ; | 214 | ; |
| 228 | else if (slot1 > 0 && frame + slot1 < nextframe) | 215 | else if (slot1 > 0 && frame + slot1+LJ_FR2 < nextframe) |
| 229 | *name = "(*temporary)"; | 216 | *name = "(*temporary)"; |
| 230 | return frame+slot1; | 217 | return frame+slot1; |
| 231 | } | 218 | } |
| @@ -234,7 +221,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
| 234 | const char *lj_debug_uvname(GCproto *pt, uint32_t idx) | 221 | const char *lj_debug_uvname(GCproto *pt, uint32_t idx) |
| 235 | { | 222 | { |
| 236 | const uint8_t *p = proto_uvinfo(pt); | 223 | const uint8_t *p = proto_uvinfo(pt); |
| 237 | lua_assert(idx < pt->sizeuv); | 224 | lj_assertX(idx < pt->sizeuv, "bad upvalue index"); |
| 238 | if (!p) return ""; | 225 | if (!p) return ""; |
| 239 | if (idx) while (*p++ || --idx) ; | 226 | if (idx) while (*p++ || --idx) ; |
| 240 | return (const char *)p; | 227 | return (const char *)p; |
| @@ -291,7 +278,7 @@ restart: | |||
| 291 | *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); | 278 | *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); |
| 292 | if (ip > proto_bc(pt)) { | 279 | if (ip > proto_bc(pt)) { |
| 293 | BCIns insp = ip[-1]; | 280 | BCIns insp = ip[-1]; |
| 294 | if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1 && | 281 | if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 && |
| 295 | bc_d(insp) == bc_b(ins)) | 282 | bc_d(insp) == bc_b(ins)) |
| 296 | return "method"; | 283 | return "method"; |
| 297 | } | 284 | } |
| @@ -308,12 +295,12 @@ restart: | |||
| 308 | } | 295 | } |
| 309 | 296 | ||
| 310 | /* Deduce function name from caller of a frame. */ | 297 | /* Deduce function name from caller of a frame. */ |
| 311 | const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | 298 | const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name) |
| 312 | { | 299 | { |
| 313 | TValue *pframe; | 300 | cTValue *pframe; |
| 314 | GCfunc *fn; | 301 | GCfunc *fn; |
| 315 | BCPos pc; | 302 | BCPos pc; |
| 316 | if (frame <= tvref(L->stack)) | 303 | if (frame <= tvref(L->stack)+LJ_FR2) |
| 317 | return NULL; | 304 | return NULL; |
| 318 | if (frame_isvarg(frame)) | 305 | if (frame_isvarg(frame)) |
| 319 | frame = frame_prevd(frame); | 306 | frame = frame_prevd(frame); |
| @@ -339,7 +326,7 @@ const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | |||
| 339 | /* -- Source code locations ----------------------------------------------- */ | 326 | /* -- Source code locations ----------------------------------------------- */ |
| 340 | 327 | ||
| 341 | /* Generate shortened source name. */ | 328 | /* Generate shortened source name. */ |
| 342 | void lj_debug_shortname(char *out, GCstr *str) | 329 | void lj_debug_shortname(char *out, GCstr *str, BCLine line) |
| 343 | { | 330 | { |
| 344 | const char *src = strdata(str); | 331 | const char *src = strdata(str); |
| 345 | if (*src == '=') { | 332 | if (*src == '=') { |
| @@ -353,11 +340,11 @@ void lj_debug_shortname(char *out, GCstr *str) | |||
| 353 | *out++ = '.'; *out++ = '.'; *out++ = '.'; | 340 | *out++ = '.'; *out++ = '.'; *out++ = '.'; |
| 354 | } | 341 | } |
| 355 | strcpy(out, src); | 342 | strcpy(out, src); |
| 356 | } else { /* Output [string "string"]. */ | 343 | } else { /* Output [string "string"] or [builtin:name]. */ |
| 357 | size_t len; /* Length, up to first control char. */ | 344 | size_t len; /* Length, up to first control char. */ |
| 358 | for (len = 0; len < LUA_IDSIZE-12; len++) | 345 | for (len = 0; len < LUA_IDSIZE-12; len++) |
| 359 | if (((const unsigned char *)src)[len] < ' ') break; | 346 | if (((const unsigned char *)src)[len] < ' ') break; |
| 360 | strcpy(out, "[string \""); out += 9; | 347 | strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9; |
| 361 | if (src[len] != '\0') { /* Must truncate? */ | 348 | if (src[len] != '\0') { /* Must truncate? */ |
| 362 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; | 349 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; |
| 363 | strncpy(out, src, len); out += len; | 350 | strncpy(out, src, len); out += len; |
| @@ -365,7 +352,7 @@ void lj_debug_shortname(char *out, GCstr *str) | |||
| 365 | } else { | 352 | } else { |
| 366 | strcpy(out, src); out += len; | 353 | strcpy(out, src); out += len; |
| 367 | } | 354 | } |
| 368 | strcpy(out, "\"]"); | 355 | strcpy(out, line == ~(BCLine)0 ? "]" : "\"]"); |
| 369 | } | 356 | } |
| 370 | } | 357 | } |
| 371 | 358 | ||
| @@ -378,14 +365,15 @@ void lj_debug_addloc(lua_State *L, const char *msg, | |||
| 378 | if (isluafunc(fn)) { | 365 | if (isluafunc(fn)) { |
| 379 | BCLine line = debug_frameline(L, fn, nextframe); | 366 | BCLine line = debug_frameline(L, fn, nextframe); |
| 380 | if (line >= 0) { | 367 | if (line >= 0) { |
| 368 | GCproto *pt = funcproto(fn); | ||
| 381 | char buf[LUA_IDSIZE]; | 369 | char buf[LUA_IDSIZE]; |
| 382 | lj_debug_shortname(buf, proto_chunkname(funcproto(fn))); | 370 | lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline); |
| 383 | lj_str_pushf(L, "%s:%d: %s", buf, line, msg); | 371 | lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg); |
| 384 | return; | 372 | return; |
| 385 | } | 373 | } |
| 386 | } | 374 | } |
| 387 | } | 375 | } |
| 388 | lj_str_pushf(L, "%s", msg); | 376 | lj_strfmt_pushf(L, "%s", msg); |
| 389 | } | 377 | } |
| 390 | 378 | ||
| 391 | /* Push location string for a bytecode position to Lua stack. */ | 379 | /* Push location string for a bytecode position to Lua stack. */ |
| @@ -395,20 +383,22 @@ void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc) | |||
| 395 | const char *s = strdata(name); | 383 | const char *s = strdata(name); |
| 396 | MSize i, len = name->len; | 384 | MSize i, len = name->len; |
| 397 | BCLine line = lj_debug_line(pt, pc); | 385 | BCLine line = lj_debug_line(pt, pc); |
| 398 | if (*s == '@') { | 386 | if (pt->firstline == ~(BCLine)0) { |
| 387 | lj_strfmt_pushf(L, "builtin:%s", s); | ||
| 388 | } else if (*s == '@') { | ||
| 399 | s++; len--; | 389 | s++; len--; |
| 400 | for (i = len; i > 0; i--) | 390 | for (i = len; i > 0; i--) |
| 401 | if (s[i] == '/' || s[i] == '\\') { | 391 | if (s[i] == '/' || s[i] == '\\') { |
| 402 | s += i+1; | 392 | s += i+1; |
| 403 | break; | 393 | break; |
| 404 | } | 394 | } |
| 405 | lj_str_pushf(L, "%s:%d", s, line); | 395 | lj_strfmt_pushf(L, "%s:%d", s, line); |
| 406 | } else if (len > 40) { | 396 | } else if (len > 40) { |
| 407 | lj_str_pushf(L, "%p:%d", pt, line); | 397 | lj_strfmt_pushf(L, "%p:%d", pt, line); |
| 408 | } else if (*s == '=') { | 398 | } else if (*s == '=') { |
| 409 | lj_str_pushf(L, "%s:%d", s+1, line); | 399 | lj_strfmt_pushf(L, "%s:%d", s+1, line); |
| 410 | } else { | 400 | } else { |
| 411 | lj_str_pushf(L, "\"%s\":%d", s, line); | 401 | lj_strfmt_pushf(L, "\"%s\":%d", s, line); |
| 412 | } | 402 | } |
| 413 | } | 403 | } |
| 414 | 404 | ||
| @@ -456,13 +446,14 @@ int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext) | |||
| 456 | } else { | 446 | } else { |
| 457 | uint32_t offset = (uint32_t)ar->i_ci & 0xffff; | 447 | uint32_t offset = (uint32_t)ar->i_ci & 0xffff; |
| 458 | uint32_t size = (uint32_t)ar->i_ci >> 16; | 448 | uint32_t size = (uint32_t)ar->i_ci >> 16; |
| 459 | lua_assert(offset != 0); | 449 | lj_assertL(offset != 0, "bad frame offset"); |
| 460 | frame = tvref(L->stack) + offset; | 450 | frame = tvref(L->stack) + offset; |
| 461 | if (size) nextframe = frame + size; | 451 | if (size) nextframe = frame + size; |
| 462 | lua_assert(frame <= tvref(L->maxstack) && | 452 | lj_assertL(frame <= tvref(L->maxstack) && |
| 463 | (!nextframe || nextframe <= tvref(L->maxstack))); | 453 | (!nextframe || nextframe <= tvref(L->maxstack)), |
| 454 | "broken frame chain"); | ||
| 464 | fn = frame_func(frame); | 455 | fn = frame_func(frame); |
| 465 | lua_assert(fn->c.gct == ~LJ_TFUNC); | 456 | lj_assertL(fn->c.gct == ~LJ_TFUNC, "bad frame function"); |
| 466 | } | 457 | } |
| 467 | for (; *what; what++) { | 458 | for (; *what; what++) { |
| 468 | if (*what == 'S') { | 459 | if (*what == 'S') { |
| @@ -471,7 +462,7 @@ int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext) | |||
| 471 | BCLine firstline = pt->firstline; | 462 | BCLine firstline = pt->firstline; |
| 472 | GCstr *name = proto_chunkname(pt); | 463 | GCstr *name = proto_chunkname(pt); |
| 473 | ar->source = strdata(name); | 464 | ar->source = strdata(name); |
| 474 | lj_debug_shortname(ar->short_src, name); | 465 | lj_debug_shortname(ar->short_src, name, pt->firstline); |
| 475 | ar->linedefined = (int)firstline; | 466 | ar->linedefined = (int)firstline; |
| 476 | ar->lastlinedefined = (int)(firstline + pt->numline); | 467 | ar->lastlinedefined = (int)(firstline + pt->numline); |
| 477 | ar->what = (firstline || !pt->numline) ? "Lua" : "main"; | 468 | ar->what = (firstline || !pt->numline) ? "Lua" : "main"; |
| @@ -561,6 +552,111 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar) | |||
| 561 | } | 552 | } |
| 562 | } | 553 | } |
| 563 | 554 | ||
| 555 | #if LJ_HASPROFILE | ||
| 556 | /* Put the chunkname into a buffer. */ | ||
| 557 | static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip) | ||
| 558 | { | ||
| 559 | GCstr *name = proto_chunkname(pt); | ||
| 560 | const char *p = strdata(name); | ||
| 561 | if (pt->firstline == ~(BCLine)0) { | ||
| 562 | lj_buf_putmem(sb, "[builtin:", 9); | ||
| 563 | lj_buf_putstr(sb, name); | ||
| 564 | lj_buf_putb(sb, ']'); | ||
| 565 | return 0; | ||
| 566 | } | ||
| 567 | if (*p == '=' || *p == '@') { | ||
| 568 | MSize len = name->len-1; | ||
| 569 | p++; | ||
| 570 | if (pathstrip) { | ||
| 571 | int i; | ||
| 572 | for (i = len-1; i >= 0; i--) | ||
| 573 | if (p[i] == '/' || p[i] == '\\') { | ||
| 574 | len -= i+1; | ||
| 575 | p = p+i+1; | ||
| 576 | break; | ||
| 577 | } | ||
| 578 | } | ||
| 579 | lj_buf_putmem(sb, p, len); | ||
| 580 | } else { | ||
| 581 | lj_buf_putmem(sb, "[string]", 8); | ||
| 582 | } | ||
| 583 | return 1; | ||
| 584 | } | ||
| 585 | |||
| 586 | /* Put a compact stack dump into a buffer. */ | ||
| 587 | void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth) | ||
| 588 | { | ||
| 589 | int level = 0, dir = 1, pathstrip = 1; | ||
| 590 | MSize lastlen = 0; | ||
| 591 | if (depth < 0) { level = ~depth; depth = dir = -1; } /* Reverse frames. */ | ||
| 592 | while (level != depth) { /* Loop through all frame. */ | ||
| 593 | int size; | ||
| 594 | cTValue *frame = lj_debug_frame(L, level, &size); | ||
| 595 | if (frame) { | ||
| 596 | cTValue *nextframe = size ? frame+size : NULL; | ||
| 597 | GCfunc *fn = frame_func(frame); | ||
| 598 | const uint8_t *p = (const uint8_t *)fmt; | ||
| 599 | int c; | ||
| 600 | while ((c = *p++)) { | ||
| 601 | switch (c) { | ||
| 602 | case 'p': /* Preserve full path. */ | ||
| 603 | pathstrip = 0; | ||
| 604 | break; | ||
| 605 | case 'F': case 'f': { /* Dump function name. */ | ||
| 606 | const char *name; | ||
| 607 | const char *what = lj_debug_funcname(L, frame, &name); | ||
| 608 | if (what) { | ||
| 609 | if (c == 'F' && isluafunc(fn)) { /* Dump module:name for 'F'. */ | ||
| 610 | GCproto *pt = funcproto(fn); | ||
| 611 | if (pt->firstline != ~(BCLine)0) { /* Not a bytecode builtin. */ | ||
| 612 | debug_putchunkname(sb, pt, pathstrip); | ||
| 613 | lj_buf_putb(sb, ':'); | ||
| 614 | } | ||
| 615 | } | ||
| 616 | lj_buf_putmem(sb, name, (MSize)strlen(name)); | ||
| 617 | break; | ||
| 618 | } /* else: can't derive a name, dump module:line. */ | ||
| 619 | } | ||
| 620 | /* fallthrough */ | ||
| 621 | case 'l': /* Dump module:line. */ | ||
| 622 | if (isluafunc(fn)) { | ||
| 623 | GCproto *pt = funcproto(fn); | ||
| 624 | if (debug_putchunkname(sb, pt, pathstrip)) { | ||
| 625 | /* Regular Lua function. */ | ||
| 626 | BCLine line = c == 'l' ? debug_frameline(L, fn, nextframe) : | ||
| 627 | pt->firstline; | ||
| 628 | lj_buf_putb(sb, ':'); | ||
| 629 | lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline); | ||
| 630 | } | ||
| 631 | } else if (isffunc(fn)) { /* Dump numbered builtins. */ | ||
| 632 | lj_buf_putmem(sb, "[builtin#", 9); | ||
| 633 | lj_strfmt_putint(sb, fn->c.ffid); | ||
| 634 | lj_buf_putb(sb, ']'); | ||
| 635 | } else { /* Dump C function address. */ | ||
| 636 | lj_buf_putb(sb, '@'); | ||
| 637 | lj_strfmt_putptr(sb, fn->c.f); | ||
| 638 | } | ||
| 639 | break; | ||
| 640 | case 'Z': /* Zap trailing separator. */ | ||
| 641 | lastlen = sbuflen(sb); | ||
| 642 | break; | ||
| 643 | default: | ||
| 644 | lj_buf_putb(sb, c); | ||
| 645 | break; | ||
| 646 | } | ||
| 647 | } | ||
| 648 | } else if (dir == 1) { | ||
| 649 | break; | ||
| 650 | } else { | ||
| 651 | level -= size; /* Reverse frame order: quickly skip missing level. */ | ||
| 652 | } | ||
| 653 | level += dir; | ||
| 654 | } | ||
| 655 | if (lastlen) | ||
| 656 | sb->w = sb->b + lastlen; /* Zap trailing separator. */ | ||
| 657 | } | ||
| 658 | #endif | ||
| 659 | |||
| 564 | /* Number of frames for the leading and trailing part of a traceback. */ | 660 | /* Number of frames for the leading and trailing part of a traceback. */ |
| 565 | #define TRACEBACK_LEVELS1 12 | 661 | #define TRACEBACK_LEVELS1 12 |
| 566 | #define TRACEBACK_LEVELS2 10 | 662 | #define TRACEBACK_LEVELS2 10 |
