ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

lj_debug.c (19859B)


      1 /*
      2 ** Debugging and introspection.
      3 ** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h
      4 */
      5 
      6 #define lj_debug_c
      7 #define LUA_CORE
      8 
      9 #include "lj_obj.h"
     10 #include "lj_err.h"
     11 #include "lj_debug.h"
     12 #include "lj_buf.h"
     13 #include "lj_tab.h"
     14 #include "lj_state.h"
     15 #include "lj_frame.h"
     16 #include "lj_bc.h"
     17 #include "lj_strfmt.h"
     18 #if LJ_HASJIT
     19 #include "lj_jit.h"
     20 #endif
     21 
     22 /* -- Frames -------------------------------------------------------------- */
     23 
     24 /* Get frame corresponding to a level. */
     25 cTValue *lj_debug_frame(lua_State *L, int level, int *size)
     26 {
     27   cTValue *frame, *nextframe, *bot = tvref(L->stack)+LJ_FR2;
     28   /* Traverse frames backwards. */
     29   for (nextframe = frame = L->base-1; frame > bot; ) {
     30     if (frame_gc(frame) == obj2gco(L))
     31       level++;  /* Skip dummy frames. See lj_err_optype_call(). */
     32     if (level-- == 0) {
     33       *size = (int)(nextframe - frame);
     34       return frame;  /* Level found. */
     35     }
     36     nextframe = frame;
     37     if (frame_islua(frame)) {
     38       frame = frame_prevl(frame);
     39     } else {
     40       if (frame_isvarg(frame))
     41 	level++;  /* Skip vararg pseudo-frame. */
     42       frame = frame_prevd(frame);
     43     }
     44   }
     45   *size = level;
     46   return NULL;  /* Level not found. */
     47 }
     48 
     49 /* Invalid bytecode position. */
     50 #define NO_BCPOS	(~(BCPos)0)
     51 
     52 /* Return bytecode position for function/frame or NO_BCPOS. */
     53 static BCPos debug_framepc(lua_State *L, GCfunc *fn, cTValue *nextframe)
     54 {
     55   const BCIns *ins;
     56   GCproto *pt;
     57   BCPos pos;
     58   lua_assert(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD);
     59   if (!isluafunc(fn)) {  /* Cannot derive a PC for non-Lua functions. */
     60     return NO_BCPOS;
     61   } else if (nextframe == NULL) {  /* Lua function on top. */
     62     void *cf = cframe_raw(L->cframe);
     63     if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
     64       return NO_BCPOS;
     65     ins = cframe_pc(cf);  /* Only happens during error/hook handling. */
     66   } else {
     67     if (frame_islua(nextframe)) {
     68       ins = frame_pc(nextframe);
     69     } else if (frame_iscont(nextframe)) {
     70       ins = frame_contpc(nextframe);
     71     } else {
     72       /* Lua function below errfunc/gc/hook: find cframe to get the PC. */
     73       void *cf = cframe_raw(L->cframe);
     74       TValue *f = L->base-1;
     75       for (;;) {
     76 	if (cf == NULL)
     77 	  return NO_BCPOS;
     78 	while (cframe_nres(cf) < 0) {
     79 	  if (f >= restorestack(L, -cframe_nres(cf)))
     80 	    break;
     81 	  cf = cframe_raw(cframe_prev(cf));
     82 	  if (cf == NULL)
     83 	    return NO_BCPOS;
     84 	}
     85 	if (f < nextframe)
     86 	  break;
     87 	if (frame_islua(f)) {
     88 	  f = frame_prevl(f);
     89 	} else {
     90 	  if (frame_isc(f) || (frame_iscont(f) && frame_iscont_fficb(f)))
     91 	    cf = cframe_raw(cframe_prev(cf));
     92 	  f = frame_prevd(f);
     93 	}
     94       }
     95       ins = cframe_pc(cf);
     96     }
     97   }
     98   pt = funcproto(fn);
     99   pos = proto_bcpos(pt, ins) - 1;
    100 #if LJ_HASJIT
    101   if (pos > pt->sizebc) {  /* Undo the effects of lj_trace_exit for JLOOP. */
    102     GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins));
    103     lua_assert(bc_isret(bc_op(ins[-1])));
    104     pos = proto_bcpos(pt, mref(T->startpc, const BCIns));
    105   }
    106 #endif
    107   return pos;
    108 }
    109 
    110 /* -- Line numbers -------------------------------------------------------- */
    111 
    112 /* Get line number for a bytecode position. */
    113 BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
    114 {
    115   const void *lineinfo = proto_lineinfo(pt);
    116   if (pc <= pt->sizebc && lineinfo) {
    117     BCLine first = pt->firstline;
    118     if (pc == pt->sizebc) return first + pt->numline;
    119     if (pc-- == 0) return first;
    120     if (pt->numline < 256)
    121       return first + (BCLine)((const uint8_t *)lineinfo)[pc];
    122     else if (pt->numline < 65536)
    123       return first + (BCLine)((const uint16_t *)lineinfo)[pc];
    124     else
    125       return first + (BCLine)((const uint32_t *)lineinfo)[pc];
    126   }
    127   return 0;
    128 }
    129 
    130 /* Get line number for function/frame. */
    131 static BCLine debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
    132 {
    133   BCPos pc = debug_framepc(L, fn, nextframe);
    134   if (pc != NO_BCPOS) {
    135     GCproto *pt = funcproto(fn);
    136     lua_assert(pc <= pt->sizebc);
    137     return lj_debug_line(pt, pc);
    138   }
    139   return -1;
    140 }
    141 
    142 /* -- Variable names ------------------------------------------------------ */
    143 
    144 /* Get name of a local variable from slot number and PC. */
    145 static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot)
    146 {
    147   const char *p = (const char *)proto_varinfo(pt);
    148   if (p) {
    149     BCPos lastpc = 0;
    150     for (;;) {
    151       const char *name = p;
    152       uint32_t vn = *(const uint8_t *)p;
    153       BCPos startpc, endpc;
    154       if (vn < VARNAME__MAX) {
    155 	if (vn == VARNAME_END) break;  /* End of varinfo. */
    156       } else {
    157 	do { p++; } while (*(const uint8_t *)p);  /* Skip over variable name. */
    158       }
    159       p++;
    160       lastpc = startpc = lastpc + lj_buf_ruleb128(&p);
    161       if (startpc > pc) break;
    162       endpc = startpc + lj_buf_ruleb128(&p);
    163       if (pc < endpc && slot-- == 0) {
    164 	if (vn < VARNAME__MAX) {
    165 #define VARNAMESTR(name, str)	str "\0"
    166 	  name = VARNAMEDEF(VARNAMESTR);
    167 #undef VARNAMESTR
    168 	  if (--vn) while (*name++ || --vn) ;
    169 	}
    170 	return name;
    171       }
    172     }
    173   }
    174   return NULL;
    175 }
    176 
    177 /* Get name of local variable from 1-based slot number and function/frame. */
    178 static TValue *debug_localname(lua_State *L, const lua_Debug *ar,
    179 			       const char **name, BCReg slot1)
    180 {
    181   uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
    182   uint32_t size = (uint32_t)ar->i_ci >> 16;
    183   TValue *frame = tvref(L->stack) + offset;
    184   TValue *nextframe = size ? frame + size : NULL;
    185   GCfunc *fn = frame_func(frame);
    186   BCPos pc = debug_framepc(L, fn, nextframe);
    187   if (!nextframe) nextframe = L->top+LJ_FR2;
    188   if ((int)slot1 < 0) {  /* Negative slot number is for varargs. */
    189     if (pc != NO_BCPOS) {
    190       GCproto *pt = funcproto(fn);
    191       if ((pt->flags & PROTO_VARARG)) {
    192 	slot1 = pt->numparams + (BCReg)(-(int)slot1);
    193 	if (frame_isvarg(frame)) {  /* Vararg frame has been set up? (pc!=0) */
    194 	  nextframe = frame;
    195 	  frame = frame_prevd(frame);
    196 	}
    197 	if (frame + slot1+LJ_FR2 < nextframe) {
    198 	  *name = "(*vararg)";
    199 	  return frame+slot1;
    200 	}
    201       }
    202     }
    203     return NULL;
    204   }
    205   if (pc != NO_BCPOS &&
    206       (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL)
    207     ;
    208   else if (slot1 > 0 && frame + slot1+LJ_FR2 < nextframe)
    209     *name = "(*temporary)";
    210   return frame+slot1;
    211 }
    212 
    213 /* Get name of upvalue. */
    214 const char *lj_debug_uvname(GCproto *pt, uint32_t idx)
    215 {
    216   const uint8_t *p = proto_uvinfo(pt);
    217   lua_assert(idx < pt->sizeuv);
    218   if (!p) return "";
    219   if (idx) while (*p++ || --idx) ;
    220   return (const char *)p;
    221 }
    222 
    223 /* Get name and value of upvalue. */
    224 const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp)
    225 {
    226   if (tvisfunc(o)) {
    227     GCfunc *fn = funcV(o);
    228     if (isluafunc(fn)) {
    229       GCproto *pt = funcproto(fn);
    230       if (idx < pt->sizeuv) {
    231 	*tvp = uvval(&gcref(fn->l.uvptr[idx])->uv);
    232 	return lj_debug_uvname(pt, idx);
    233       }
    234     } else {
    235       if (idx < fn->c.nupvalues) {
    236 	*tvp = &fn->c.upvalue[idx];
    237 	return "";
    238       }
    239     }
    240   }
    241   return NULL;
    242 }
    243 
    244 /* Deduce name of an object from slot number and PC. */
    245 const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot,
    246 			      const char **name)
    247 {
    248   const char *lname;
    249 restart:
    250   lname = debug_varname(pt, proto_bcpos(pt, ip), slot);
    251   if (lname != NULL) { *name = lname; return "local"; }
    252   while (--ip > proto_bc(pt)) {
    253     BCIns ins = *ip;
    254     BCOp op = bc_op(ins);
    255     BCReg ra = bc_a(ins);
    256     if (bcmode_a(op) == BCMbase) {
    257       if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins)))
    258 	return NULL;
    259     } else if (bcmode_a(op) == BCMdst && ra == slot) {
    260       switch (bc_op(ins)) {
    261       case BC_MOV:
    262 	if (ra == slot) { slot = bc_d(ins); goto restart; }
    263 	break;
    264       case BC_GGET:
    265 	*name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins))));
    266 	return "global";
    267       case BC_TGETS:
    268 	*name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins))));
    269 	if (ip > proto_bc(pt)) {
    270 	  BCIns insp = ip[-1];
    271 	  if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 &&
    272 	      bc_d(insp) == bc_b(ins))
    273 	    return "method";
    274 	}
    275 	return "field";
    276       case BC_UGET:
    277 	*name = lj_debug_uvname(pt, bc_d(ins));
    278 	return "upvalue";
    279       default:
    280 	return NULL;
    281       }
    282     }
    283   }
    284   return NULL;
    285 }
    286 
    287 /* Deduce function name from caller of a frame. */
    288 const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name)
    289 {
    290   cTValue *pframe;
    291   GCfunc *fn;
    292   BCPos pc;
    293   if (frame <= tvref(L->stack)+LJ_FR2)
    294     return NULL;
    295   if (frame_isvarg(frame))
    296     frame = frame_prevd(frame);
    297   pframe = frame_prev(frame);
    298   fn = frame_func(pframe);
    299   pc = debug_framepc(L, fn, frame);
    300   if (pc != NO_BCPOS) {
    301     GCproto *pt = funcproto(fn);
    302     const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)];
    303     MMS mm = bcmode_mm(bc_op(*ip));
    304     if (mm == MM_call) {
    305       BCReg slot = bc_a(*ip);
    306       if (bc_op(*ip) == BC_ITERC) slot -= 3;
    307       return lj_debug_slotname(pt, ip, slot, name);
    308     } else if (mm != MM__MAX) {
    309       *name = strdata(mmname_str(G(L), mm));
    310       return "metamethod";
    311     }
    312   }
    313   return NULL;
    314 }
    315 
    316 /* -- Source code locations ----------------------------------------------- */
    317 
    318 /* Generate shortened source name. */
    319 void lj_debug_shortname(char *out, GCstr *str, BCLine line)
    320 {
    321   const char *src = strdata(str);
    322   if (*src == '=') {
    323     strncpy(out, src+1, LUA_IDSIZE);  /* Remove first char. */
    324     out[LUA_IDSIZE-1] = '\0';  /* Ensures null termination. */
    325   } else if (*src == '@') {  /* Output "source", or "...source". */
    326     size_t len = str->len-1;
    327     src++;  /* Skip the `@' */
    328     if (len >= LUA_IDSIZE) {
    329       src += len-(LUA_IDSIZE-4);  /* Get last part of file name. */
    330       *out++ = '.'; *out++ = '.'; *out++ = '.';
    331     }
    332     strcpy(out, src);
    333   } else {  /* Output [string "string"] or [builtin:name]. */
    334     size_t len;  /* Length, up to first control char. */
    335     for (len = 0; len < LUA_IDSIZE-12; len++)
    336       if (((const unsigned char *)src)[len] < ' ') break;
    337     strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9;
    338     if (src[len] != '\0') {  /* Must truncate? */
    339       if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
    340       strncpy(out, src, len); out += len;
    341       strcpy(out, "..."); out += 3;
    342     } else {
    343       strcpy(out, src); out += len;
    344     }
    345     strcpy(out, line == ~(BCLine)0 ? "]" : "\"]");
    346   }
    347 }
    348 
    349 /* Add current location of a frame to error message. */
    350 void lj_debug_addloc(lua_State *L, const char *msg,
    351 		     cTValue *frame, cTValue *nextframe)
    352 {
    353   if (frame) {
    354     GCfunc *fn = frame_func(frame);
    355     if (isluafunc(fn)) {
    356       BCLine line = debug_frameline(L, fn, nextframe);
    357       if (line >= 0) {
    358 	GCproto *pt = funcproto(fn);
    359 	char buf[LUA_IDSIZE];
    360 	lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline);
    361 	lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg);
    362 	return;
    363       }
    364     }
    365   }
    366   lj_strfmt_pushf(L, "%s", msg);
    367 }
    368 
    369 /* Push location string for a bytecode position to Lua stack. */
    370 void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
    371 {
    372   GCstr *name = proto_chunkname(pt);
    373   const char *s = strdata(name);
    374   MSize i, len = name->len;
    375   BCLine line = lj_debug_line(pt, pc);
    376   if (pt->firstline == ~(BCLine)0) {
    377     lj_strfmt_pushf(L, "builtin:%s", s);
    378   } else if (*s == '@') {
    379     s++; len--;
    380     for (i = len; i > 0; i--)
    381       if (s[i] == '/' || s[i] == '\\') {
    382 	s += i+1;
    383 	break;
    384       }
    385     lj_strfmt_pushf(L, "%s:%d", s, line);
    386   } else if (len > 40) {
    387     lj_strfmt_pushf(L, "%p:%d", pt, line);
    388   } else if (*s == '=') {
    389     lj_strfmt_pushf(L, "%s:%d", s+1, line);
    390   } else {
    391     lj_strfmt_pushf(L, "\"%s\":%d", s, line);
    392   }
    393 }
    394 
    395 /* -- Public debug API ---------------------------------------------------- */
    396 
    397 /* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */
    398 
    399 LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n)
    400 {
    401   const char *name = NULL;
    402   if (ar) {
    403     TValue *o = debug_localname(L, ar, &name, (BCReg)n);
    404     if (name) {
    405       copyTV(L, L->top, o);
    406       incr_top(L);
    407     }
    408   } else if (tvisfunc(L->top-1) && isluafunc(funcV(L->top-1))) {
    409     name = debug_varname(funcproto(funcV(L->top-1)), 0, (BCReg)n-1);
    410   }
    411   return name;
    412 }
    413 
    414 LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n)
    415 {
    416   const char *name = NULL;
    417   TValue *o = debug_localname(L, ar, &name, (BCReg)n);
    418   if (name)
    419     copyTV(L, o, L->top-1);
    420   L->top--;
    421   return name;
    422 }
    423 
    424 int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
    425 {
    426   int opt_f = 0, opt_L = 0;
    427   TValue *frame = NULL;
    428   TValue *nextframe = NULL;
    429   GCfunc *fn;
    430   if (*what == '>') {
    431     TValue *func = L->top - 1;
    432     api_check(L, tvisfunc(func));
    433     fn = funcV(func);
    434     L->top--;
    435     what++;
    436   } else {
    437     uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
    438     uint32_t size = (uint32_t)ar->i_ci >> 16;
    439     lua_assert(offset != 0);
    440     frame = tvref(L->stack) + offset;
    441     if (size) nextframe = frame + size;
    442     lua_assert(frame <= tvref(L->maxstack) &&
    443 	       (!nextframe || nextframe <= tvref(L->maxstack)));
    444     fn = frame_func(frame);
    445     lua_assert(fn->c.gct == ~LJ_TFUNC);
    446   }
    447   for (; *what; what++) {
    448     if (*what == 'S') {
    449       if (isluafunc(fn)) {
    450 	GCproto *pt = funcproto(fn);
    451 	BCLine firstline = pt->firstline;
    452 	GCstr *name = proto_chunkname(pt);
    453 	ar->source = strdata(name);
    454 	lj_debug_shortname(ar->short_src, name, pt->firstline);
    455 	ar->linedefined = (int)firstline;
    456 	ar->lastlinedefined = (int)(firstline + pt->numline);
    457 	ar->what = (firstline || !pt->numline) ? "Lua" : "main";
    458       } else {
    459 	ar->source = "=[C]";
    460 	ar->short_src[0] = '[';
    461 	ar->short_src[1] = 'C';
    462 	ar->short_src[2] = ']';
    463 	ar->short_src[3] = '\0';
    464 	ar->linedefined = -1;
    465 	ar->lastlinedefined = -1;
    466 	ar->what = "C";
    467       }
    468     } else if (*what == 'l') {
    469       ar->currentline = frame ? debug_frameline(L, fn, nextframe) : -1;
    470     } else if (*what == 'u') {
    471       ar->nups = fn->c.nupvalues;
    472       if (ext) {
    473 	if (isluafunc(fn)) {
    474 	  GCproto *pt = funcproto(fn);
    475 	  ar->nparams = pt->numparams;
    476 	  ar->isvararg = !!(pt->flags & PROTO_VARARG);
    477 	} else {
    478 	  ar->nparams = 0;
    479 	  ar->isvararg = 1;
    480 	}
    481       }
    482     } else if (*what == 'n') {
    483       ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL;
    484       if (ar->namewhat == NULL) {
    485 	ar->namewhat = "";
    486 	ar->name = NULL;
    487       }
    488     } else if (*what == 'f') {
    489       opt_f = 1;
    490     } else if (*what == 'L') {
    491       opt_L = 1;
    492     } else {
    493       return 0;  /* Bad option. */
    494     }
    495   }
    496   if (opt_f) {
    497     setfuncV(L, L->top, fn);
    498     incr_top(L);
    499   }
    500   if (opt_L) {
    501     if (isluafunc(fn)) {
    502       GCtab *t = lj_tab_new(L, 0, 0);
    503       GCproto *pt = funcproto(fn);
    504       const void *lineinfo = proto_lineinfo(pt);
    505       if (lineinfo) {
    506 	BCLine first = pt->firstline;
    507 	int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4;
    508 	MSize i, szl = pt->sizebc-1;
    509 	for (i = 0; i < szl; i++) {
    510 	  BCLine line = first +
    511 	    (sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] :
    512 	     sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] :
    513 	     (BCLine)((const uint32_t *)lineinfo)[i]);
    514 	  setboolV(lj_tab_setint(L, t, line), 1);
    515 	}
    516       }
    517       settabV(L, L->top, t);
    518     } else {
    519       setnilV(L->top);
    520     }
    521     incr_top(L);
    522   }
    523   return 1;  /* Ok. */
    524 }
    525 
    526 LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar)
    527 {
    528   return lj_debug_getinfo(L, what, (lj_Debug *)ar, 0);
    529 }
    530 
    531 LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
    532 {
    533   int size;
    534   cTValue *frame = lj_debug_frame(L, level, &size);
    535   if (frame) {
    536     ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
    537     return 1;
    538   } else {
    539     ar->i_ci = level - size;
    540     return 0;
    541   }
    542 }
    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 
    649 /* Number of frames for the leading and trailing part of a traceback. */
    650 #define TRACEBACK_LEVELS1	12
    651 #define TRACEBACK_LEVELS2	10
    652 
    653 LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
    654 				int level)
    655 {
    656   int top = (int)(L->top - L->base);
    657   int lim = TRACEBACK_LEVELS1;
    658   lua_Debug ar;
    659   if (msg) lua_pushfstring(L, "%s\n", msg);
    660   lua_pushliteral(L, "stack traceback:");
    661   while (lua_getstack(L1, level++, &ar)) {
    662     GCfunc *fn;
    663     if (level > lim) {
    664       if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) {
    665 	level--;
    666       } else {
    667 	lua_pushliteral(L, "\n\t...");
    668 	lua_getstack(L1, -10, &ar);
    669 	level = ar.i_ci - TRACEBACK_LEVELS2;
    670       }
    671       lim = 2147483647;
    672       continue;
    673     }
    674     lua_getinfo(L1, "Snlf", &ar);
    675     fn = funcV(L1->top-1); L1->top--;
    676     if (isffunc(fn) && !*ar.namewhat)
    677       lua_pushfstring(L, "\n\t[builtin#%d]:", fn->c.ffid);
    678     else
    679       lua_pushfstring(L, "\n\t%s:", ar.short_src);
    680     if (ar.currentline > 0)
    681       lua_pushfstring(L, "%d:", ar.currentline);
    682     if (*ar.namewhat) {
    683       lua_pushfstring(L, " in function " LUA_QS, ar.name);
    684     } else {
    685       if (*ar.what == 'm') {
    686 	lua_pushliteral(L, " in main chunk");
    687       } else if (*ar.what == 'C') {
    688 	lua_pushfstring(L, " at %p", fn->c.f);
    689       } else {
    690 	lua_pushfstring(L, " in function <%s:%d>",
    691 			ar.short_src, ar.linedefined);
    692       }
    693     }
    694     if ((int)(L->top - L->base) - top >= 15)
    695       lua_concat(L, (int)(L->top - L->base) - top);
    696   }
    697   lua_concat(L, (int)(L->top - L->base) - top);
    698 }
    699