diff options
Diffstat (limited to 'src/lj_debug.c')
-rw-r--r-- | src/lj_debug.c | 194 |
1 files changed, 126 insertions, 68 deletions
diff --git a/src/lj_debug.c b/src/lj_debug.c index a5ffff74..1c4bac43 100644 --- a/src/lj_debug.c +++ b/src/lj_debug.c | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
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_str.h" | 12 | #include "lj_str.h" |
12 | #include "lj_tab.h" | 13 | #include "lj_tab.h" |
13 | #include "lj_state.h" | 14 | #include "lj_state.h" |
@@ -89,9 +90,17 @@ static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
89 | /* Get line number for a bytecode position. */ | 90 | /* Get line number for a bytecode position. */ |
90 | BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc) | 91 | BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc) |
91 | { | 92 | { |
92 | BCLine *lineinfo = proto_lineinfo(pt); | 93 | const void *lineinfo = proto_lineinfo(pt); |
93 | if (pc < pt->sizebc && lineinfo) | 94 | if (pc < pt->sizebc && lineinfo) { |
94 | return lineinfo[pc]; | 95 | BCLine first = pt->firstline; |
96 | if (pc-- == 0) return first; | ||
97 | if (pt->numline < 256) | ||
98 | return first + (BCLine)((const uint8_t *)lineinfo)[pc]; | ||
99 | else if (pt->numline < 65536) | ||
100 | return first + (BCLine)((const uint16_t *)lineinfo)[pc]; | ||
101 | else | ||
102 | return first + (BCLine)((const uint32_t *)lineinfo)[pc]; | ||
103 | } | ||
95 | return 0; | 104 | return 0; |
96 | } | 105 | } |
97 | 106 | ||
@@ -109,14 +118,49 @@ static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe) | |||
109 | 118 | ||
110 | /* -- Variable names ------------------------------------------------------ */ | 119 | /* -- Variable names ------------------------------------------------------ */ |
111 | 120 | ||
121 | /* Read ULEB128 value. */ | ||
122 | static uint32_t debug_read_uleb128(const uint8_t **pp) | ||
123 | { | ||
124 | const uint8_t *p = *pp; | ||
125 | uint32_t v = *p++; | ||
126 | if (LJ_UNLIKELY(v >= 0x80)) { | ||
127 | int sh = 0; | ||
128 | v &= 0x7f; | ||
129 | do { v |= ((*p & 0x7f) << (sh += 7)); } while (*p++ >= 0x80); | ||
130 | } | ||
131 | *pp = p; | ||
132 | return v; | ||
133 | } | ||
134 | |||
112 | /* Get name of a local variable from slot number and PC. */ | 135 | /* Get name of a local variable from slot number and PC. */ |
113 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) | 136 | static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot) |
114 | { | 137 | { |
115 | MSize i; | 138 | const uint8_t *p = proto_varinfo(pt); |
116 | VarInfo *vi = proto_varinfo(pt); | 139 | if (p) { |
117 | for (i = 0; i < pt->sizevarinfo && vi[i].startpc <= pc; i++) | 140 | BCPos lastpc = 0; |
118 | if (pc < vi[i].endpc && slot-- == 0) | 141 | for (;;) { |
119 | return strdata(gco2str(gcref(vi[i].name))); | 142 | const char *name = (const char *)p; |
143 | uint32_t vn = *p++; | ||
144 | BCPos startpc, endpc; | ||
145 | if (vn < VARNAME__MAX) { | ||
146 | if (vn == VARNAME_END) break; /* End of varinfo. */ | ||
147 | } else { | ||
148 | while (*p++) ; /* Skip over variable name string. */ | ||
149 | } | ||
150 | lastpc = startpc = lastpc + debug_read_uleb128(&p); | ||
151 | if (startpc > pc) break; | ||
152 | endpc = startpc + debug_read_uleb128(&p); | ||
153 | if (pc < endpc && slot-- == 0) { | ||
154 | if (vn < VARNAME__MAX) { | ||
155 | #define VARNAMESTR(name, str) str "\0" | ||
156 | name = VARNAMEDEF(VARNAMESTR); | ||
157 | #undef VARNAMESTR | ||
158 | if (--vn) while (*name++ || --vn) ; | ||
159 | } | ||
160 | return name; | ||
161 | } | ||
162 | } | ||
163 | } | ||
120 | return NULL; | 164 | return NULL; |
121 | } | 165 | } |
122 | 166 | ||
@@ -141,7 +185,17 @@ static TValue *debug_localname(lua_State *L, const lua_Debug *ar, | |||
141 | } | 185 | } |
142 | 186 | ||
143 | /* Get name of upvalue. */ | 187 | /* Get name of upvalue. */ |
144 | const char *lj_debug_uvname(cTValue *o, uint32_t idx, TValue **tvp) | 188 | const char *lj_debug_uvname(GCproto *pt, uint32_t idx) |
189 | { | ||
190 | const uint8_t *p = proto_uvinfo(pt); | ||
191 | lua_assert(idx < pt->sizeuv); | ||
192 | if (!p) return ""; | ||
193 | if (idx) while (*p++ || --idx) ; | ||
194 | return (const char *)p; | ||
195 | } | ||
196 | |||
197 | /* Get name and value of upvalue. */ | ||
198 | const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp) | ||
145 | { | 199 | { |
146 | if (tvisfunc(o)) { | 200 | if (tvisfunc(o)) { |
147 | GCfunc *fn = funcV(o); | 201 | GCfunc *fn = funcV(o); |
@@ -149,7 +203,7 @@ const char *lj_debug_uvname(cTValue *o, uint32_t idx, TValue **tvp) | |||
149 | GCproto *pt = funcproto(fn); | 203 | GCproto *pt = funcproto(fn); |
150 | if (idx < pt->sizeuv) { | 204 | if (idx < pt->sizeuv) { |
151 | *tvp = uvval(&gcref(fn->l.uvptr[idx])->uv); | 205 | *tvp = uvval(&gcref(fn->l.uvptr[idx])->uv); |
152 | return strdata(proto_uvname(pt, idx)); | 206 | return lj_debug_uvname(pt, idx); |
153 | } | 207 | } |
154 | } else { | 208 | } else { |
155 | if (idx < fn->c.nupvalues) { | 209 | if (idx < fn->c.nupvalues) { |
@@ -194,7 +248,7 @@ restart: | |||
194 | } | 248 | } |
195 | return "field"; | 249 | return "field"; |
196 | case BC_UGET: | 250 | case BC_UGET: |
197 | *name = strdata(proto_uvname(pt, bc_d(ins))); | 251 | *name = lj_debug_uvname(pt, bc_d(ins)); |
198 | return "upvalue"; | 252 | return "upvalue"; |
199 | default: | 253 | default: |
200 | return NULL; | 254 | return NULL; |
@@ -234,25 +288,26 @@ const char *lj_debug_funcname(lua_State *L, TValue *frame, const char **name) | |||
234 | /* -- Source code locations ----------------------------------------------- */ | 288 | /* -- Source code locations ----------------------------------------------- */ |
235 | 289 | ||
236 | /* Generate shortened source name. */ | 290 | /* Generate shortened source name. */ |
237 | void lj_debug_shortname(char *out, const char *src) | 291 | void lj_debug_shortname(char *out, GCstr *str) |
238 | { | 292 | { |
293 | const char *src = strdata(str); | ||
239 | if (*src == '=') { | 294 | if (*src == '=') { |
240 | strncpy(out, src+1, LUA_IDSIZE); /* remove first char */ | 295 | strncpy(out, src+1, LUA_IDSIZE); /* Remove first char. */ |
241 | out[LUA_IDSIZE-1] = '\0'; /* ensures null termination */ | 296 | out[LUA_IDSIZE-1] = '\0'; /* Ensures null termination. */ |
242 | } else if (*src == '@') { /* out = "source", or "...source" */ | 297 | } else if (*src == '@') { /* Output "source", or "...source". */ |
243 | size_t l = strlen(++src); /* skip the `@' */ | 298 | size_t len = str->len-1; |
244 | if (l >= LUA_IDSIZE) { | 299 | src++; /* Skip the `@' */ |
245 | src += l-(LUA_IDSIZE-4); /* get last part of file name */ | 300 | if (len >= LUA_IDSIZE) { |
246 | strcpy(out, "..."); | 301 | src += len-(LUA_IDSIZE-4); /* Get last part of file name. */ |
247 | out += 3; | 302 | *out++ = '.'; *out++ = '.'; *out++ = '.'; |
248 | } | 303 | } |
249 | strcpy(out, src); | 304 | strcpy(out, src); |
250 | } else { /* out = [string "string"] */ | 305 | } else { /* Output [string "string"]. */ |
251 | size_t len; /* Length, up to first control char. */ | 306 | size_t len; /* Length, up to first control char. */ |
252 | for (len = 0; len < LUA_IDSIZE-12; len++) | 307 | for (len = 0; len < LUA_IDSIZE-12; len++) |
253 | if (((const unsigned char *)src)[len] < ' ') break; | 308 | if (((const unsigned char *)src)[len] < ' ') break; |
254 | strcpy(out, "[string \""); out += 9; | 309 | strcpy(out, "[string \""); out += 9; |
255 | if (src[len] != '\0') { /* must truncate? */ | 310 | if (src[len] != '\0') { /* Must truncate? */ |
256 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; | 311 | if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15; |
257 | strncpy(out, src, len); out += len; | 312 | strncpy(out, src, len); out += len; |
258 | strcpy(out, "..."); out += 3; | 313 | strcpy(out, "..."); out += 3; |
@@ -273,7 +328,7 @@ void lj_debug_addloc(lua_State *L, const char *msg, | |||
273 | BCLine line = debug_frameline(L, fn, nextframe); | 328 | BCLine line = debug_frameline(L, fn, nextframe); |
274 | if (line >= 0) { | 329 | if (line >= 0) { |
275 | char buf[LUA_IDSIZE]; | 330 | char buf[LUA_IDSIZE]; |
276 | lj_debug_shortname(buf, strdata(proto_chunkname(funcproto(fn)))); | 331 | lj_debug_shortname(buf, proto_chunkname(funcproto(fn))); |
277 | lj_str_pushf(L, "%s:%d: %s", buf, line, msg); | 332 | lj_str_pushf(L, "%s:%d: %s", buf, line, msg); |
278 | return; | 333 | return; |
279 | } | 334 | } |
@@ -286,27 +341,23 @@ void lj_debug_addloc(lua_State *L, const char *msg, | |||
286 | void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc) | 341 | void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc) |
287 | { | 342 | { |
288 | GCstr *name = proto_chunkname(pt); | 343 | GCstr *name = proto_chunkname(pt); |
289 | if (name) { | 344 | const char *s = strdata(name); |
290 | const char *s = strdata(name); | 345 | MSize i, len = name->len; |
291 | MSize i, len = name->len; | 346 | BCLine line = lj_debug_line(pt, pc); |
292 | BCLine line = lj_debug_line(pt, pc); | 347 | if (*s == '@') { |
293 | if (*s == '@') { | 348 | s++; len--; |
294 | s++; len--; | 349 | for (i = len; i > 0; i--) |
295 | for (i = len; i > 0; i--) | 350 | if (s[i] == '/' || s[i] == '\\') { |
296 | if (s[i] == '/' || s[i] == '\\') { | 351 | s += i+1; |
297 | s += i+1; | 352 | break; |
298 | break; | 353 | } |
299 | } | 354 | lj_str_pushf(L, "%s:%d", s, line); |
300 | lj_str_pushf(L, "%s:%d", s, line); | 355 | } else if (len > 40) { |
301 | } else if (len > 40) { | 356 | lj_str_pushf(L, "%p:%d", pt, line); |
302 | lj_str_pushf(L, "%p:%d", pt, line); | 357 | } else if (*s == '=') { |
303 | } else if (*s == '=') { | 358 | lj_str_pushf(L, "%s:%d", s+1, line); |
304 | lj_str_pushf(L, "%s:%d", s+1, line); | ||
305 | } else { | ||
306 | lj_str_pushf(L, "\"%s\":%d", s, line); | ||
307 | } | ||
308 | } else { | 359 | } else { |
309 | lj_str_pushf(L, "%p:%u", pt, pc); | 360 | lj_str_pushf(L, "\"%s\":%d", s, line); |
310 | } | 361 | } |
311 | } | 362 | } |
312 | 363 | ||
@@ -359,56 +410,63 @@ LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) | |||
359 | lua_assert(fn->c.gct == ~LJ_TFUNC); | 410 | lua_assert(fn->c.gct == ~LJ_TFUNC); |
360 | } | 411 | } |
361 | for (; *what; what++) { | 412 | for (; *what; what++) { |
362 | switch (*what) { | 413 | if (*what == 'S') { |
363 | case 'S': | ||
364 | if (isluafunc(fn)) { | 414 | if (isluafunc(fn)) { |
365 | GCproto *pt = funcproto(fn); | 415 | GCproto *pt = funcproto(fn); |
366 | ar->source = strdata(proto_chunkname(pt)); | 416 | BCLine firstline = pt->firstline; |
367 | ar->linedefined = (int)proto_line(pt, 0); | 417 | GCstr *name = proto_chunkname(pt); |
368 | ar->lastlinedefined = (int)pt->lastlinedefined; | 418 | ar->source = strdata(name); |
369 | ar->what = ar->linedefined ? "Lua" : "main"; | 419 | lj_debug_shortname(ar->short_src, name); |
420 | ar->linedefined = (int)firstline; | ||
421 | ar->lastlinedefined = (int)(firstline + pt->numline); | ||
422 | ar->what = firstline ? "Lua" : "main"; | ||
370 | } else { | 423 | } else { |
371 | ar->source = "=[C]"; | 424 | ar->source = "=[C]"; |
425 | ar->short_src[0] = '['; | ||
426 | ar->short_src[1] = 'C'; | ||
427 | ar->short_src[2] = ']'; | ||
428 | ar->short_src[3] = '\0'; | ||
372 | ar->linedefined = -1; | 429 | ar->linedefined = -1; |
373 | ar->lastlinedefined = -1; | 430 | ar->lastlinedefined = -1; |
374 | ar->what = "C"; | 431 | ar->what = "C"; |
375 | } | 432 | } |
376 | lj_debug_shortname(ar->short_src, ar->source); | 433 | } else if (*what == 'l') { |
377 | break; | ||
378 | case 'l': | ||
379 | ar->currentline = frame ? debug_frameline(L, fn, nextframe) : -1; | 434 | ar->currentline = frame ? debug_frameline(L, fn, nextframe) : -1; |
380 | break; | 435 | } else if (*what == 'u') { |
381 | case 'u': | ||
382 | ar->nups = fn->c.nupvalues; | 436 | ar->nups = fn->c.nupvalues; |
383 | break; | 437 | } else if (*what == 'n') { |
384 | case 'n': | ||
385 | ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL; | 438 | ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL; |
386 | if (ar->namewhat == NULL) { | 439 | if (ar->namewhat == NULL) { |
387 | ar->namewhat = ""; | 440 | ar->namewhat = ""; |
388 | ar->name = NULL; | 441 | ar->name = NULL; |
389 | } | 442 | } |
390 | break; | 443 | } else if (*what == 'f') { |
391 | case 'f': | ||
392 | setfuncV(L, L->top, fn); | 444 | setfuncV(L, L->top, fn); |
393 | incr_top(L); | 445 | incr_top(L); |
394 | break; | 446 | } else if (*what == 'L') { |
395 | case 'L': | ||
396 | if (isluafunc(fn)) { | 447 | if (isluafunc(fn)) { |
397 | GCtab *t = lj_tab_new(L, 0, 0); | 448 | GCtab *t = lj_tab_new(L, 0, 0); |
398 | GCproto *pt = funcproto(fn); | 449 | GCproto *pt = funcproto(fn); |
399 | BCLine *lineinfo = proto_lineinfo(pt); | 450 | const void *lineinfo = proto_lineinfo(pt); |
400 | MSize i, szl = pt->sizebc; | 451 | if (lineinfo) { |
401 | for (i = 1; i < szl; i++) | 452 | BCLine first = pt->firstline; |
402 | setboolV(lj_tab_setint(L, t, lineinfo[i]), 1); | 453 | int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4; |
454 | MSize i, szl = pt->sizebc-1; | ||
455 | for (i = 0; i < szl; i++) { | ||
456 | BCLine line = first + | ||
457 | (sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] : | ||
458 | sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] : | ||
459 | (BCLine)((const uint32_t *)lineinfo)[i]); | ||
460 | setboolV(lj_tab_setint(L, t, line), 1); | ||
461 | } | ||
462 | } | ||
403 | settabV(L, L->top, t); | 463 | settabV(L, L->top, t); |
404 | } else { | 464 | } else { |
405 | setnilV(L->top); | 465 | setnilV(L->top); |
406 | } | 466 | } |
407 | incr_top(L); | 467 | incr_top(L); |
408 | break; | 468 | } else { |
409 | default: | ||
410 | status = 0; /* Bad option. */ | 469 | status = 0; /* Bad option. */ |
411 | break; | ||
412 | } | 470 | } |
413 | } | 471 | } |
414 | return status; | 472 | return status; |