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 65ec26f0..112f5358 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. */ |
@@ -87,8 +88,7 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
87 | if (frame_islua(f)) { | 88 | if (frame_islua(f)) { |
88 | f = frame_prevl(f); | 89 | f = frame_prevl(f); |
89 | } else { | 90 | } else { |
90 | if (frame_isc(f) || (LJ_HASFFI && frame_iscont(f) && | 91 | 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)); | 92 | cf = cframe_raw(cframe_prev(cf)); |
93 | f = frame_prevd(f); | 93 | f = frame_prevd(f); |
94 | } | 94 | } |
@@ -102,7 +102,7 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
102 | #if LJ_HASJIT | 102 | #if LJ_HASJIT |
103 | if (pos > pt->sizebc) { /* Undo the effects of lj_trace_exit for JLOOP. */ | 103 | if (pos > pt->sizebc) { /* Undo the effects of lj_trace_exit for JLOOP. */ |
104 | GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins)); | 104 | GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins)); |
105 | lua_assert(bc_isret(bc_op(ins[-1]))); | 105 | lj_assertL(bc_isret(bc_op(ins[-1])), "return bytecode expected"); |
106 | pos = proto_bcpos(pt, mref(T->startpc, const BCIns)); | 106 | pos = proto_bcpos(pt, mref(T->startpc, const BCIns)); |
107 | } | 107 | } |
108 | #endif | 108 | #endif |
@@ -135,7 +135,7 @@ static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
135 | BCPos pc = debug_framepc(L, fn, nextframe); | 135 | BCPos pc = debug_framepc(L, fn, nextframe); |
136 | if (pc != NO_BCPOS) { | 136 | if (pc != NO_BCPOS) { |
137 | GCproto *pt = funcproto(fn); | 137 | GCproto *pt = funcproto(fn); |
138 | lua_assert(pc <= pt->sizebc); | 138 | lj_assertL(pc <= pt->sizebc, "PC out of range"); |
139 | return lj_debug_line(pt, pc); | 139 | return lj_debug_line(pt, pc); |
140 | } | 140 | } |
141 | return -1; | 141 | return -1; |
@@ -143,38 +143,25 @@ static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
143 | 143 | ||
144 | /* -- Variable names ------------------------------------------------------ */ | 144 | /* -- Variable names ------------------------------------------------------ */ |
145 | 145 | ||
146 | /* Read ULEB128 value. */ | ||
147 | static uint32_t debug_read_uleb128(const uint8_t **pp) | ||
148 | { | ||
149 | const uint8_t *p = *pp; | ||
150 | uint32_t v = *p++; | ||
151 | if (LJ_UNLIKELY(v >= 0x80)) { | ||
152 | int sh = 0; | ||
153 | v &= 0x7f; | ||
154 | do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80); | ||
155 | } | ||
156 | *pp = p; | ||
157 | return v; | ||
158 | } | ||
159 | |||
160 | /* Get name of a local variable from slot number and PC. */ | 146 | /* Get name of a local variable from slot number and PC. */ |
161 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) | 147 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) |
162 | { | 148 | { |
163 | const uint8_t *p = proto_varinfo(pt); | 149 | const char *p = (const char *)proto_varinfo(pt); |
164 | if (p) { | 150 | if (p) { |
165 | BCPos lastpc = 0; | 151 | BCPos lastpc = 0; |
166 | for (;;) { | 152 | for (;;) { |
167 | const char *name = (const char *)p; | 153 | const char *name = p; |
168 | uint32_t vn = *p++; | 154 | uint32_t vn = *(const uint8_t *)p; |
169 | BCPos startpc, endpc; | 155 | BCPos startpc, endpc; |
170 | if (vn < VARNAME__MAX) { | 156 | if (vn < VARNAME__MAX) { |
171 | if (vn == VARNAME_END) break; /* End of varinfo. */ | 157 | if (vn == VARNAME_END) break; /* End of varinfo. */ |
172 | } else { | 158 | } else { |
173 | while (*p++) ; /* Skip over variable name string. */ | 159 | do { p++; } while (*(const uint8_t *)p); /* Skip over variable name. */ |
174 | } | 160 | } |
175 | lastpc = startpc = lastpc + debug_read_uleb128(&p); | 161 | p++; |
162 | lastpc = startpc = lastpc + lj_buf_ruleb128(&p); | ||
176 | if (startpc > pc) break; | 163 | if (startpc > pc) break; |
177 | endpc = startpc + debug_read_uleb128(&p); | 164 | endpc = startpc + lj_buf_ruleb128(&p); |
178 | if (pc < endpc && slot-- == 0) { | 165 | if (pc < endpc && slot-- == 0) { |
179 | if (vn < VARNAME__MAX) { | 166 | if (vn < VARNAME__MAX) { |
180 | #define VARNAMESTR(name, str) str "\0" | 167 | #define VARNAMESTR(name, str) str "\0" |
@@ -199,7 +186,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
199 | TValue *nextframe = size ? frame + size : NULL; | 186 | TValue *nextframe = size ? frame + size : NULL; |
200 | GCfunc *fn = frame_func(frame); | 187 | GCfunc *fn = frame_func(frame); |
201 | BCPos pc = debug_framepc(L, fn, nextframe); | 188 | BCPos pc = debug_framepc(L, fn, nextframe); |
202 | if (!nextframe) nextframe = L->top; | 189 | if (!nextframe) nextframe = L->top+LJ_FR2; |
203 | if ((int)slot1 < 0) { /* Negative slot number is for varargs. */ | 190 | if ((int)slot1 < 0) { /* Negative slot number is for varargs. */ |
204 | if (pc != NO_BCPOS) { | 191 | if (pc != NO_BCPOS) { |
205 | GCproto *pt = funcproto(fn); | 192 | GCproto *pt = funcproto(fn); |
@@ -209,7 +196,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
209 | nextframe = frame; | 196 | nextframe = frame; |
210 | frame = frame_prevd(frame); | 197 | frame = frame_prevd(frame); |
211 | } | 198 | } |
212 | if (frame + slot1 < nextframe) { | 199 | if (frame + slot1+LJ_FR2 < nextframe) { |
213 | *name = "(*vararg)"; | 200 | *name = "(*vararg)"; |
214 | return frame+slot1; | 201 | return frame+slot1; |
215 | } | 202 | } |
@@ -220,7 +207,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
220 | if (pc != NO_BCPOS && | 207 | if (pc != NO_BCPOS && |
221 | (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL) | 208 | (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL) |
222 | ; | 209 | ; |
223 | else if (slot1 > 0 && frame + slot1 < nextframe) | 210 | else if (slot1 > 0 && frame + slot1+LJ_FR2 < nextframe) |
224 | *name = "(*temporary)"; | 211 | *name = "(*temporary)"; |
225 | return frame+slot1; | 212 | return frame+slot1; |
226 | } | 213 | } |
@@ -229,7 +216,7 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
229 | const char *lj_debug_uvname(GCproto *pt, uint32_t idx) | 216 | const char *lj_debug_uvname(GCproto *pt, uint32_t idx) |
230 | { | 217 | { |
231 | const uint8_t *p = proto_uvinfo(pt); | 218 | const uint8_t *p = proto_uvinfo(pt); |
232 | lua_assert(idx < pt->sizeuv); | 219 | lj_assertX(idx < pt->sizeuv, "bad upvalue index"); |
233 | if (!p) return ""; | 220 | if (!p) return ""; |
234 | if (idx) while (*p++ || --idx) ; | 221 | if (idx) while (*p++ || --idx) ; |
235 | return (const char *)p; | 222 | return (const char *)p; |
@@ -286,7 +273,7 @@ restart: | |||
286 | *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); | 273 | *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins)))); |
287 | if (ip > proto_bc(pt)) { | 274 | if (ip > proto_bc(pt)) { |
288 | BCIns insp = ip[-1]; | 275 | BCIns insp = ip[-1]; |
289 | if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1 && | 276 | if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 && |
290 | bc_d(insp) == bc_b(ins)) | 277 | bc_d(insp) == bc_b(ins)) |
291 | return "method"; | 278 | return "method"; |
292 | } | 279 | } |
@@ -303,12 +290,12 @@ restart: | |||
303 | } | 290 | } |
304 | 291 | ||
305 | /* Deduce function name from caller of a frame. */ | 292 | /* Deduce function name from caller of a frame. */ |
306 | const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | 293 | const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name) |
307 | { | 294 | { |
308 | TValue *pframe; | 295 | cTValue *pframe; |
309 | GCfunc *fn; | 296 | GCfunc *fn; |
310 | BCPos pc; | 297 | BCPos pc; |
311 | if (frame <= tvref(L->stack)) | 298 | if (frame <= tvref(L->stack)+LJ_FR2) |
312 | return NULL; | 299 | return NULL; |
313 | if (frame_isvarg(frame)) | 300 | if (frame_isvarg(frame)) |
314 | frame = frame_prevd(frame); | 301 | frame = frame_prevd(frame); |
@@ -334,7 +321,7 @@ const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | |||
334 | /* -- Source code locations ----------------------------------------------- */ | 321 | /* -- Source code locations ----------------------------------------------- */ |
335 | 322 | ||
336 | /* Generate shortened source name. */ | 323 | /* Generate shortened source name. */ |
337 | void lj_debug_shortname(char *out, GCstr *str) | 324 | void lj_debug_shortname(char *out, GCstr *str, BCLine line) |
338 | { | 325 | { |
339 | const char *src = strdata(str); | 326 | const char *src = strdata(str); |
340 | if (*src == '=') { | 327 | if (*src == '=') { |
@@ -348,11 +335,11 @@ void lj_debug_shortname(char *out, GCstr *str) | |||
348 | *out++ = '.'; *out++ = '.'; *out++ = '.'; | 335 | *out++ = '.'; *out++ = '.'; *out++ = '.'; |
349 | } | 336 | } |
350 | strcpy(out, src); | 337 | strcpy(out, src); |
351 | } else { /* Output [string "string"]. */ | 338 | } else { /* Output [string "string"] or [builtin:name]. */ |
352 | size_t len; /* Length, up to first control char. */ | 339 | size_t len; /* Length, up to first control char. */ |
353 | for (len = 0; len < LUA_IDSIZE-12; len++) | 340 | for (len = 0; len < LUA_IDSIZE-12; len++) |
354 | if (((const unsigned char *)src)[len] < ' ') break; | 341 | if (((const unsigned char *)src)[len] < ' ') break; |
355 | strcpy(out, "[string \""); out += 9; | 342 | strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9; |
356 | if (src[len] != '\0') { /* Must truncate? */ | 343 | if (src[len] != '\0') { /* Must truncate? */ |
357 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; | 344 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; |
358 | strncpy(out, src, len); out += len; | 345 | strncpy(out, src, len); out += len; |
@@ -360,7 +347,7 @@ void lj_debug_shortname(char *out, GCstr *str) | |||
360 | } else { | 347 | } else { |
361 | strcpy(out, src); out += len; | 348 | strcpy(out, src); out += len; |
362 | } | 349 | } |
363 | strcpy(out, "\"]"); | 350 | strcpy(out, line == ~(BCLine)0 ? "]" : "\"]"); |
364 | } | 351 | } |
365 | } | 352 | } |
366 | 353 | ||
@@ -373,14 +360,15 @@ void lj_debug_addloc(lua_State *L, const char *msg, | |||
373 | if (isluafunc(fn)) { | 360 | if (isluafunc(fn)) { |
374 | BCLine line = debug_frameline(L, fn, nextframe); | 361 | BCLine line = debug_frameline(L, fn, nextframe); |
375 | if (line >= 0) { | 362 | if (line >= 0) { |
363 | GCproto *pt = funcproto(fn); | ||
376 | char buf[LUA_IDSIZE]; | 364 | char buf[LUA_IDSIZE]; |
377 | lj_debug_shortname(buf, proto_chunkname(funcproto(fn))); | 365 | lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline); |
378 | lj_str_pushf(L, "%s:%d: %s", buf, line, msg); | 366 | lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg); |
379 | return; | 367 | return; |
380 | } | 368 | } |
381 | } | 369 | } |
382 | } | 370 | } |
383 | lj_str_pushf(L, "%s", msg); | 371 | lj_strfmt_pushf(L, "%s", msg); |
384 | } | 372 | } |
385 | 373 | ||
386 | /* Push location string for a bytecode position to Lua stack. */ | 374 | /* Push location string for a bytecode position to Lua stack. */ |
@@ -390,20 +378,22 @@ void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc) | |||
390 | const char *s = strdata(name); | 378 | const char *s = strdata(name); |
391 | MSize i, len = name->len; | 379 | MSize i, len = name->len; |
392 | BCLine line = lj_debug_line(pt, pc); | 380 | BCLine line = lj_debug_line(pt, pc); |
393 | if (*s == '@') { | 381 | if (pt->firstline == ~(BCLine)0) { |
382 | lj_strfmt_pushf(L, "builtin:%s", s); | ||
383 | } else if (*s == '@') { | ||
394 | s++; len--; | 384 | s++; len--; |
395 | for (i = len; i > 0; i--) | 385 | for (i = len; i > 0; i--) |
396 | if (s[i] == '/' || s[i] == '\\') { | 386 | if (s[i] == '/' || s[i] == '\\') { |
397 | s += i+1; | 387 | s += i+1; |
398 | break; | 388 | break; |
399 | } | 389 | } |
400 | lj_str_pushf(L, "%s:%d", s, line); | 390 | lj_strfmt_pushf(L, "%s:%d", s, line); |
401 | } else if (len > 40) { | 391 | } else if (len > 40) { |
402 | lj_str_pushf(L, "%p:%d", pt, line); | 392 | lj_strfmt_pushf(L, "%p:%d", pt, line); |
403 | } else if (*s == '=') { | 393 | } else if (*s == '=') { |
404 | lj_str_pushf(L, "%s:%d", s+1, line); | 394 | lj_strfmt_pushf(L, "%s:%d", s+1, line); |
405 | } else { | 395 | } else { |
406 | lj_str_pushf(L, "\"%s\":%d", s, line); | 396 | lj_strfmt_pushf(L, "\"%s\":%d", s, line); |
407 | } | 397 | } |
408 | } | 398 | } |
409 | 399 | ||
@@ -451,13 +441,14 @@ int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext) | |||
451 | } else { | 441 | } else { |
452 | uint32_t offset = (uint32_t)ar->i_ci & 0xffff; | 442 | uint32_t offset = (uint32_t)ar->i_ci & 0xffff; |
453 | uint32_t size = (uint32_t)ar->i_ci >> 16; | 443 | uint32_t size = (uint32_t)ar->i_ci >> 16; |
454 | lua_assert(offset != 0); | 444 | lj_assertL(offset != 0, "bad frame offset"); |
455 | frame = tvref(L->stack) + offset; | 445 | frame = tvref(L->stack) + offset; |
456 | if (size) nextframe = frame + size; | 446 | if (size) nextframe = frame + size; |
457 | lua_assert(frame <= tvref(L->maxstack) && | 447 | lj_assertL(frame <= tvref(L->maxstack) && |
458 | (!nextframe || nextframe <= tvref(L->maxstack))); | 448 | (!nextframe || nextframe <= tvref(L->maxstack)), |
449 | "broken frame chain"); | ||
459 | fn = frame_func(frame); | 450 | fn = frame_func(frame); |
460 | lua_assert(fn->c.gct == ~LJ_TFUNC); | 451 | lj_assertL(fn->c.gct == ~LJ_TFUNC, "bad frame function"); |
461 | } | 452 | } |
462 | for (; *what; what++) { | 453 | for (; *what; what++) { |
463 | if (*what == 'S') { | 454 | if (*what == 'S') { |
@@ -466,7 +457,7 @@ int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext) | |||
466 | BCLine firstline = pt->firstline; | 457 | BCLine firstline = pt->firstline; |
467 | GCstr *name = proto_chunkname(pt); | 458 | GCstr *name = proto_chunkname(pt); |
468 | ar->source = strdata(name); | 459 | ar->source = strdata(name); |
469 | lj_debug_shortname(ar->short_src, name); | 460 | lj_debug_shortname(ar->short_src, name, pt->firstline); |
470 | ar->linedefined = (int)firstline; | 461 | ar->linedefined = (int)firstline; |
471 | ar->lastlinedefined = (int)(firstline + pt->numline); | 462 | ar->lastlinedefined = (int)(firstline + pt->numline); |
472 | ar->what = (firstline || !pt->numline) ? "Lua" : "main"; | 463 | ar->what = (firstline || !pt->numline) ? "Lua" : "main"; |
@@ -556,6 +547,111 @@ LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar) | |||
556 | } | 547 | } |
557 | } | 548 | } |
558 | 549 | ||
550 | #if LJ_HASPROFILE | ||
551 | /* Put the chunkname into a buffer. */ | ||
552 | static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip) | ||
553 | { | ||
554 | GCstr *name = proto_chunkname(pt); | ||
555 | const char *p = strdata(name); | ||
556 | if (pt->firstline == ~(BCLine)0) { | ||
557 | lj_buf_putmem(sb, "[builtin:", 9); | ||
558 | lj_buf_putstr(sb, name); | ||
559 | lj_buf_putb(sb, ']'); | ||
560 | return 0; | ||
561 | } | ||
562 | if (*p == '=' || *p == '@') { | ||
563 | MSize len = name->len-1; | ||
564 | p++; | ||
565 | if (pathstrip) { | ||
566 | int i; | ||
567 | for (i = len-1; i >= 0; i--) | ||
568 | if (p[i] == '/' || p[i] == '\\') { | ||
569 | len -= i+1; | ||
570 | p = p+i+1; | ||
571 | break; | ||
572 | } | ||
573 | } | ||
574 | lj_buf_putmem(sb, p, len); | ||
575 | } else { | ||
576 | lj_buf_putmem(sb, "[string]", 8); | ||
577 | } | ||
578 | return 1; | ||
579 | } | ||
580 | |||
581 | /* Put a compact stack dump into a buffer. */ | ||
582 | void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth) | ||
583 | { | ||
584 | int level = 0, dir = 1, pathstrip = 1; | ||
585 | MSize lastlen = 0; | ||
586 | if (depth < 0) { level = ~depth; depth = dir = -1; } /* Reverse frames. */ | ||
587 | while (level != depth) { /* Loop through all frame. */ | ||
588 | int size; | ||
589 | cTValue *frame = lj_debug_frame(L, level, &size); | ||
590 | if (frame) { | ||
591 | cTValue *nextframe = size ? frame+size : NULL; | ||
592 | GCfunc *fn = frame_func(frame); | ||
593 | const uint8_t *p = (const uint8_t *)fmt; | ||
594 | int c; | ||
595 | while ((c = *p++)) { | ||
596 | switch (c) { | ||
597 | case 'p': /* Preserve full path. */ | ||
598 | pathstrip = 0; | ||
599 | break; | ||
600 | case 'F': case 'f': { /* Dump function name. */ | ||
601 | const char *name; | ||
602 | const char *what = lj_debug_funcname(L, frame, &name); | ||
603 | if (what) { | ||
604 | if (c == 'F' && isluafunc(fn)) { /* Dump module:name for 'F'. */ | ||
605 | GCproto *pt = funcproto(fn); | ||
606 | if (pt->firstline != ~(BCLine)0) { /* Not a bytecode builtin. */ | ||
607 | debug_putchunkname(sb, pt, pathstrip); | ||
608 | lj_buf_putb(sb, ':'); | ||
609 | } | ||
610 | } | ||
611 | lj_buf_putmem(sb, name, (MSize)strlen(name)); | ||
612 | break; | ||
613 | } /* else: can't derive a name, dump module:line. */ | ||
614 | } | ||
615 | /* fallthrough */ | ||
616 | case 'l': /* Dump module:line. */ | ||
617 | if (isluafunc(fn)) { | ||
618 | GCproto *pt = funcproto(fn); | ||
619 | if (debug_putchunkname(sb, pt, pathstrip)) { | ||
620 | /* Regular Lua function. */ | ||
621 | BCLine line = c == 'l' ? debug_frameline(L, fn, nextframe) : | ||
622 | pt->firstline; | ||
623 | lj_buf_putb(sb, ':'); | ||
624 | lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline); | ||
625 | } | ||
626 | } else if (isffunc(fn)) { /* Dump numbered builtins. */ | ||
627 | lj_buf_putmem(sb, "[builtin#", 9); | ||
628 | lj_strfmt_putint(sb, fn->c.ffid); | ||
629 | lj_buf_putb(sb, ']'); | ||
630 | } else { /* Dump C function address. */ | ||
631 | lj_buf_putb(sb, '@'); | ||
632 | lj_strfmt_putptr(sb, fn->c.f); | ||
633 | } | ||
634 | break; | ||
635 | case 'Z': /* Zap trailing separator. */ | ||
636 | lastlen = sbuflen(sb); | ||
637 | break; | ||
638 | default: | ||
639 | lj_buf_putb(sb, c); | ||
640 | break; | ||
641 | } | ||
642 | } | ||
643 | } else if (dir == 1) { | ||
644 | break; | ||
645 | } else { | ||
646 | level -= size; /* Reverse frame order: quickly skip missing level. */ | ||
647 | } | ||
648 | level += dir; | ||
649 | } | ||
650 | if (lastlen) | ||
651 | sb->w = sb->b + lastlen; /* Zap trailing separator. */ | ||
652 | } | ||
653 | #endif | ||
654 | |||
559 | /* Number of frames for the leading and trailing part of a traceback. */ | 655 | /* Number of frames for the leading and trailing part of a traceback. */ |
560 | #define TRACEBACK_LEVELS1 12 | 656 | #define TRACEBACK_LEVELS1 12 |
561 | #define TRACEBACK_LEVELS2 10 | 657 | #define TRACEBACK_LEVELS2 10 |