• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 6035198545

31 Aug 2023 08:55AM UTC coverage: 88.225% (+0.4%) from 87.822%
6035198545

push

github

fckxorg
test: don't skip tool CLI flag for tarantool

That skipcond was introduced to overcome the obstacles
of LuaJIT's integration testing in Tarantool. Since
the required patch is now in the Tarantool master, this
skipcond is now unnecessary.

Related to tarantool/tarantool#5688

5340 of 5975 branches covered (0.0%)

Branch coverage included in aggregate %.

20495 of 23308 relevant lines covered (87.93%)

1297339.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.45
/src/lj_debug.c
1
/*
2
** Debugging and introspection.
3
** Copyright (C) 2005-2017 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)
71,422✔
26
{
27
  cTValue *frame, *nextframe, *bot = tvref(L->stack)+LJ_FR2;
71,422✔
28
  /* Traverse frames backwards. */
29
  for (nextframe = frame = L->base-1; frame > bot; ) {
535,881✔
30
    if (frame_gc(frame) == obj2gco(L))
535,850✔
31
      level++;  /* Skip dummy frames. See lj_err_optype_call(). */
×
32
    if (level-- == 0) {
535,850✔
33
      *size = (int)(nextframe - frame);
71,391✔
34
      return frame;  /* Level found. */
71,391✔
35
    }
36
    nextframe = frame;
464,459✔
37
    if (frame_islua(frame)) {
464,459✔
38
      frame = frame_prevl(frame);
464,153✔
39
    } else {
40
      if (frame_isvarg(frame))
306✔
41
        level++;  /* Skip vararg pseudo-frame. */
56✔
42
      frame = frame_prevd(frame);
306✔
43
    }
44
  }
45
  *size = level;
31✔
46
  return NULL;  /* Level not found. */
31✔
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
  lj_assertL(fn->c.gct == ~LJ_TFUNC || fn->c.gct == ~LJ_TTHREAD,
59
             "function or frame expected");
60
  if (!isluafunc(fn)) {  /* Cannot derive a PC for non-Lua functions. */
61
    return NO_BCPOS;
62
  } else if (nextframe == NULL) {  /* Lua function on top. */
63
    void *cf = cframe_raw(L->cframe);
64
    if (cf == NULL || (char *)cframe_pc(cf) == (char *)cframe_L(cf))
65
      return NO_BCPOS;
66
    ins = cframe_pc(cf);  /* Only happens during error/hook handling. */
67
  } else {
68
    if (frame_islua(nextframe)) {
69
      ins = frame_pc(nextframe);
70
    } else if (frame_iscont(nextframe)) {
71
      ins = frame_contpc(nextframe);
72
    } else {
73
      /* Lua function below errfunc/gc/hook: find cframe to get the PC. */
74
      void *cf = cframe_raw(L->cframe);
75
      TValue *f = L->base-1;
76
      for (;;) {
77
        if (cf == NULL)
78
          return NO_BCPOS;
79
        while (cframe_nres(cf) < 0) {
80
          if (f >= restorestack(L, -cframe_nres(cf)))
81
            break;
82
          cf = cframe_raw(cframe_prev(cf));
83
          if (cf == NULL)
84
            return NO_BCPOS;
85
        }
86
        if (f < nextframe)
87
          break;
88
        if (frame_islua(f)) {
89
          f = frame_prevl(f);
90
        } else {
91
          if (frame_isc(f) || (frame_iscont(f) && frame_iscont_fficb(f)))
92
            cf = cframe_raw(cframe_prev(cf));
93
          f = frame_prevd(f);
94
        }
95
      }
96
      ins = cframe_pc(cf);
97
      if (!ins) return NO_BCPOS;
98
    }
99
  }
100
  pt = funcproto(fn);
101
  pos = proto_bcpos(pt, ins) - 1;
102
#if LJ_HASJIT
103
  if (pos > pt->sizebc) {  /* Undo the effects of lj_trace_exit for JLOOP. */
104
    GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins));
105
    lj_assertL(bc_isret(bc_op(ins[-1])), "return bytecode expected");
106
    pos = proto_bcpos(pt, mref(T->startpc, const BCIns));
107
  }
108
#endif
109
  return pos;
110
}
111

112
/* -- Line numbers -------------------------------------------------------- */
113

114
/* Get line number for a bytecode position. */
115
BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
32,321,634✔
116
{
117
  const void *lineinfo = proto_lineinfo(pt);
32,321,634✔
118
  if (pc <= pt->sizebc && lineinfo) {
32,321,634✔
119
    BCLine first = pt->firstline;
32,319,403✔
120
    if (pc == pt->sizebc) return first + pt->numline;
32,319,403✔
121
    if (pc-- == 0) return first;
32,319,403✔
122
    if (pt->numline < 256)
32,319,361✔
123
      return first + (BCLine)((const uint8_t *)lineinfo)[pc];
30,121,872✔
124
    else if (pt->numline < 65536)
2,197,489✔
125
      return first + (BCLine)((const uint16_t *)lineinfo)[pc];
1,287,278✔
126
    else
127
      return first + (BCLine)((const uint32_t *)lineinfo)[pc];
910,211✔
128
  }
129
  return 0;
130
}
131

132
/* Get line number for function/frame. */
133
BCLine lj_debug_frameline(lua_State *L, GCfunc *fn, cTValue *nextframe)
2,140✔
134
{
135
  BCPos pc = debug_framepc(L, fn, nextframe);
2,140✔
136
  if (pc != NO_BCPOS) {
2,140✔
137
    GCproto *pt = funcproto(fn);
2,102✔
138
    lj_assertL(pc <= pt->sizebc, "PC out of range");
2,102✔
139
    return lj_debug_line(pt, pc);
2,102✔
140
  }
141
  return -1;
142
}
143

144
/* -- Variable names ------------------------------------------------------ */
145

146
/* Get name of a local variable from slot number and PC. */
147
static const char *debug_varname(const GCproto *pt, BCPos pc, BCReg slot)
148
{
149
  const char *p = (const char *)proto_varinfo(pt);
150
  if (p) {
151
    BCPos lastpc = 0;
152
    for (;;) {
153
      const char *name = p;
154
      uint32_t vn = *(const uint8_t *)p;
155
      BCPos startpc, endpc;
156
      if (vn < VARNAME__MAX) {
157
        if (vn == VARNAME_END) break;  /* End of varinfo. */
158
      } else {
159
        do { p++; } while (*(const uint8_t *)p);  /* Skip over variable name. */
160
      }
161
      p++;
162
      lastpc = startpc = lastpc + lj_buf_ruleb128(&p);
163
      if (startpc > pc) break;
164
      endpc = startpc + lj_buf_ruleb128(&p);
165
      if (pc < endpc && slot-- == 0) {
166
        if (vn < VARNAME__MAX) {
167
#define VARNAMESTR(name, str)        str "\0"
168
          name = VARNAMEDEF(VARNAMESTR);
169
#undef VARNAMESTR
170
          if (--vn) while (*name++ || --vn) ;
171
        }
172
        return name;
173
      }
174
    }
175
  }
176
  return NULL;
177
}
178

179
/* Get name of local variable from 1-based slot number and function/frame. */
180
static TValue *debug_localname(lua_State *L, const lua_Debug *ar,
181
                               const char **name, BCReg slot1)
182
{
183
  uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
184
  uint32_t size = (uint32_t)ar->i_ci >> 16;
185
  TValue *frame = tvref(L->stack) + offset;
186
  TValue *nextframe = size ? frame + size : NULL;
187
  GCfunc *fn = frame_func(frame);
188
  BCPos pc = debug_framepc(L, fn, nextframe);
189
  if (!nextframe) nextframe = L->top+LJ_FR2;
190
  if ((int)slot1 < 0) {  /* Negative slot number is for varargs. */
191
    if (pc != NO_BCPOS) {
192
      GCproto *pt = funcproto(fn);
193
      if ((pt->flags & PROTO_VARARG)) {
194
        slot1 = pt->numparams + (BCReg)(-(int)slot1);
195
        if (frame_isvarg(frame)) {  /* Vararg frame has been set up? (pc!=0) */
196
          nextframe = frame;
197
          frame = frame_prevd(frame);
198
        }
199
        if (frame + slot1+LJ_FR2 < nextframe) {
200
          *name = "(*vararg)";
201
          return frame+slot1;
202
        }
203
      }
204
    }
205
    return NULL;
206
  }
207
  if (pc != NO_BCPOS &&
208
      (*name = debug_varname(funcproto(fn), pc, slot1-1)) != NULL)
209
    ;
210
  else if (slot1 > 0 && frame + slot1+LJ_FR2 < nextframe)
211
    *name = "(*temporary)";
212
  return frame+slot1;
213
}
214

215
/* Get name of upvalue. */
216
const char *lj_debug_uvname(GCproto *pt, uint32_t idx)
138✔
217
{
218
  const uint8_t *p = proto_uvinfo(pt);
138✔
219
  lj_assertX(idx < pt->sizeuv, "bad upvalue index");
138✔
220
  if (!p) return "";
58✔
221
  if (idx) while (*p++ || --idx) ;
605✔
222
  return (const char *)p;
223
}
224

225
/* Get name and value of upvalue. */
226
const char *lj_debug_uvnamev(cTValue *o, uint32_t idx, TValue **tvp, GCobj **op)
21✔
227
{
228
  if (tvisfunc(o)) {
21✔
229
    GCfunc *fn = funcV(o);
21✔
230
    if (isluafunc(fn)) {
21✔
231
      GCproto *pt = funcproto(fn);
19✔
232
      if (idx < pt->sizeuv) {
19✔
233
        GCobj *uvo = gcref(fn->l.uvptr[idx]);
12✔
234
        *tvp = uvval(&uvo->uv);
12✔
235
        *op = uvo;
12✔
236
        return lj_debug_uvname(pt, idx);
24✔
237
      }
238
    } else {
239
      if (idx < fn->c.nupvalues) {
2✔
240
        *tvp = &fn->c.upvalue[idx];
×
241
        *op = obj2gco(fn);
×
242
        return "";
×
243
      }
244
    }
245
  }
246
  return NULL;
247
}
248

249
/* Deduce name of an object from slot number and PC. */
250
const char *lj_debug_slotname(GCproto *pt, const BCIns *ip, BCReg slot,
72,667✔
251
                              const char **name)
252
{
253
  const char *lname;
72,700✔
254
restart:
72,700✔
255
  lname = debug_varname(pt, proto_bcpos(pt, ip), slot);
72,700✔
256
  if (lname != NULL) { *name = lname; return "local"; }
72,700✔
257
  while (--ip > proto_bc(pt)) {
73,142✔
258
    BCIns ins = *ip;
73,140✔
259
    BCOp op = bc_op(ins);
73,140✔
260
    BCReg ra = bc_a(ins);
73,140✔
261
    if (bcmode_a(op) == BCMbase) {
73,140✔
262
      if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins)))
7✔
263
        return NULL;
264
    } else if (bcmode_a(op) == BCMdst && ra == slot) {
73,133✔
265
      switch (bc_op(ins)) {
72,641✔
266
      case BC_MOV:
267
        if (ra == slot) { slot = bc_d(ins); goto restart; }
33✔
268
        break;
269
      case BC_GGET:
71,441✔
270
        *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins))));
71,441✔
271
        return "global";
71,441✔
272
      case BC_TGETS:
39✔
273
        *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins))));
39✔
274
        if (ip > proto_bc(pt)) {
39✔
275
          BCIns insp = ip[-1];
39✔
276
          if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 &&
39✔
277
              bc_d(insp) == bc_b(ins))
5✔
278
            return "method";
279
        }
280
        return "field";
34✔
281
      case BC_UGET:
68✔
282
        *name = lj_debug_uvname(pt, bc_d(ins));
68✔
283
        return "upvalue";
68✔
284
      default:
285
        return NULL;
286
      }
287
    }
492✔
288
  }
289
  return NULL;
290
}
291

292
/* Deduce function name from caller of a frame. */
293
const char *lj_debug_funcname(lua_State *L, cTValue *frame, const char **name)
71,307✔
294
{
295
  cTValue *pframe;
71,307✔
296
  GCfunc *fn;
71,307✔
297
  BCPos pc;
71,307✔
298
  if (frame <= tvref(L->stack)+LJ_FR2)
71,307✔
299
    return NULL;
300
  if (frame_isvarg(frame))
71,307✔
301
    frame = frame_prevd(frame);
25✔
302
  pframe = frame_prev(frame);
71,307✔
303
  fn = frame_func(pframe);
71,307✔
304
  pc = debug_framepc(L, fn, frame);
71,307✔
305
  if (pc != NO_BCPOS) {
71,307✔
306
    GCproto *pt = funcproto(fn);
71,217✔
307
    const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)];
71,217✔
308
    MMS mm = bcmode_mm(bc_op(*ip));
71,217✔
309
    if (mm == MM_call) {
71,217✔
310
      BCReg slot = bc_a(*ip);
71,181✔
311
      if (bc_op(*ip) == BC_ITERC) slot -= 3;
71,181✔
312
      return lj_debug_slotname(pt, ip, slot, name);
71,181✔
313
    } else if (mm != MM__MAX) {
36✔
314
      *name = strdata(mmname_str(G(L), mm));
36✔
315
      return "metamethod";
36✔
316
    }
317
  }
318
  return NULL;
319
}
320

321
/* -- Source code locations ----------------------------------------------- */
322

323
/* Generate shortened source name. */
324
void lj_debug_shortname(char *out, GCstr *str, BCLine line)
14,558✔
325
{
326
  const char *src = strdata(str);
14,558✔
327
  if (*src == '=') {
14,558✔
328
    strncpy(out, src+1, LUA_IDSIZE);  /* Remove first char. */
425✔
329
    out[LUA_IDSIZE-1] = '\0';  /* Ensures null termination. */
425✔
330
  } else if (*src == '@') {  /* Output "source", or "...source". */
14,133✔
331
    size_t len = str->len-1;
465✔
332
    src++;  /* Skip the `@' */
465✔
333
    if (len >= LUA_IDSIZE) {
465✔
334
      src += len-(LUA_IDSIZE-4);  /* Get last part of file name. */
461✔
335
      *out++ = '.'; *out++ = '.'; *out++ = '.';
461✔
336
    }
337
    strcpy(out, src);
465✔
338
  } else {  /* Output [string "string"] or [builtin:name]. */
339
    size_t len;  /* Length, up to first control char. */
340
    for (len = 0; len < LUA_IDSIZE-12; len++)
176,568✔
341
      if (((const unsigned char *)src)[len] < ' ') break;
176,551✔
342
    strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9;
13,668✔
343
    if (src[len] != '\0') {  /* Must truncate? */
13,668✔
344
      if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
9,482✔
345
      strncpy(out, src, len); out += len;
9,482✔
346
      strcpy(out, "..."); out += 3;
9,482✔
347
    } else {
348
      strcpy(out, src); out += len;
4,186✔
349
    }
350
    strcpy(out, line == ~(BCLine)0 ? "]" : "\"]");
27,336✔
351
  }
352
}
14,558✔
353

354
/* Add current location of a frame to error message. */
355
void lj_debug_addloc(lua_State *L, const char *msg,
13,350✔
356
                     cTValue *frame, cTValue *nextframe)
357
{
358
  if (frame) {
13,350✔
359
    GCfunc *fn = frame_func(frame);
13,222✔
360
    if (isluafunc(fn)) {
13,222✔
361
      BCLine line = lj_debug_frameline(L, fn, nextframe);
1,708✔
362
      if (line >= 0) {
1,708✔
363
        GCproto *pt = funcproto(fn);
1,707✔
364
        char buf[LUA_IDSIZE];
1,707✔
365
        lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline);
1,707✔
366
        lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg);
1,707✔
367
        return;
1,707✔
368
      }
369
    }
370
  }
371
  lj_strfmt_pushf(L, "%s", msg);
11,643✔
372
}
373

374
/* Push location string for a bytecode position to Lua stack. */
375
void lj_debug_pushloc(lua_State *L, GCproto *pt, BCPos pc)
24✔
376
{
377
  GCstr *name = proto_chunkname(pt);
24✔
378
  const char *s = strdata(name);
24✔
379
  MSize i, len = name->len;
24✔
380
  BCLine line = lj_debug_line(pt, pc);
24✔
381
  if (pt->firstline == ~(BCLine)0) {
24✔
382
    lj_strfmt_pushf(L, "builtin:%s", s);
1✔
383
  } else if (*s == '@') {
23✔
384
    s++; len--;
23✔
385
    for (i = len; i > 0; i--)
528✔
386
      if (s[i] == '/' || s[i] == '\\') {
526✔
387
        s += i+1;
21✔
388
        break;
21✔
389
      }
390
    lj_strfmt_pushf(L, "%s:%d", s, line);
23✔
391
  } else if (len > 40) {
×
392
    lj_strfmt_pushf(L, "%p:%d", pt, line);
×
393
  } else if (*s == '=') {
×
394
    lj_strfmt_pushf(L, "%s:%d", s+1, line);
×
395
  } else {
396
    lj_strfmt_pushf(L, "\"%s\":%d", s, line);
×
397
  }
398
}
24✔
399

400
/* -- Public debug API ---------------------------------------------------- */
401

402
/* lua_getupvalue() and lua_setupvalue() are in lj_api.c. */
403

404
LUA_API const char *lua_getlocal(lua_State *L, const lua_Debug *ar, int n)
19✔
405
{
406
  const char *name = NULL;
19✔
407
  if (ar) {
19✔
408
    TValue *o = debug_localname(L, ar, &name, (BCReg)n);
19✔
409
    if (name) {
19✔
410
      copyTV(L, L->top, o);
15✔
411
      incr_top(L);
15✔
412
    }
413
  } else if (tvisfunc(L->top-1) && isluafunc(funcV(L->top-1))) {
×
414
    name = debug_varname(funcproto(funcV(L->top-1)), 0, (BCReg)n-1);
×
415
  }
416
  return name;
19✔
417
}
418

419
LUA_API const char *lua_setlocal(lua_State *L, const lua_Debug *ar, int n)
6✔
420
{
421
  const char *name = NULL;
6✔
422
  TValue *o = debug_localname(L, ar, &name, (BCReg)n);
6✔
423
  if (name)
6✔
424
    copyTV(L, o, L->top-1);
5✔
425
  L->top--;
6✔
426
  return name;
6✔
427
}
428

429
int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
71,295✔
430
{
431
  int opt_f = 0, opt_L = 0;
71,295✔
432
  TValue *frame = NULL;
71,295✔
433
  TValue *nextframe = NULL;
71,295✔
434
  GCfunc *fn;
71,295✔
435
  if (*what == '>') {
71,295✔
436
    TValue *func = L->top - 1;
22✔
437
    if (!tvisfunc(func)) return 0;
22✔
438
    fn = funcV(func);
21✔
439
    L->top--;
21✔
440
    what++;
21✔
441
  } else {
442
    uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
71,273✔
443
    uint32_t size = (uint32_t)ar->i_ci >> 16;
71,273✔
444
    lj_assertL(offset != 0, "bad frame offset");
71,273✔
445
    frame = tvref(L->stack) + offset;
71,273✔
446
    if (size) nextframe = frame + size;
71,273✔
447
    lj_assertL(frame <= tvref(L->maxstack) &&
71,273✔
448
               (!nextframe || nextframe <= tvref(L->maxstack)),
449
               "broken frame chain");
450
    fn = frame_func(frame);
71,273✔
451
    lj_assertL(fn->c.gct == ~LJ_TFUNC, "bad frame function");
452
  }
453
  for (; *what; what++) {
143,197✔
454
    if (*what == 'S') {
71,904✔
455
      if (isluafunc(fn)) {
182✔
456
        GCproto *pt = funcproto(fn);
149✔
457
        BCLine firstline = pt->firstline;
149✔
458
        GCstr *name = proto_chunkname(pt);
149✔
459
        ar->source = strdata(name);
149✔
460
        lj_debug_shortname(ar->short_src, name, pt->firstline);
149✔
461
        ar->linedefined = (int)firstline;
149✔
462
        ar->lastlinedefined = (int)(firstline + pt->numline);
149✔
463
        ar->what = (firstline || !pt->numline) ? "Lua" : "main";
178✔
464
      } else {
465
        ar->source = "=[C]";
33✔
466
        ar->short_src[0] = '[';
33✔
467
        ar->short_src[1] = 'C';
33✔
468
        ar->short_src[2] = ']';
33✔
469
        ar->short_src[3] = '\0';
33✔
470
        ar->linedefined = -1;
33✔
471
        ar->lastlinedefined = -1;
33✔
472
        ar->what = "C";
33✔
473
      }
474
    } else if (*what == 'l') {
71,722✔
475
      ar->currentline = frame ? lj_debug_frameline(L, fn, nextframe) : -1;
187✔
476
    } else if (*what == 'u') {
71,535✔
477
      ar->nups = fn->c.nupvalues;
80✔
478
      if (ext) {
80✔
479
        if (isluafunc(fn)) {
80✔
480
          GCproto *pt = funcproto(fn);
79✔
481
          ar->nparams = pt->numparams;
79✔
482
          ar->isvararg = !!(pt->flags & PROTO_VARARG);
79✔
483
        } else {
484
          ar->nparams = 0;
1✔
485
          ar->isvararg = 1;
1✔
486
        }
487
      }
488
    } else if (*what == 'n') {
71,455✔
489
      ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL;
71,217✔
490
      if (ar->namewhat == NULL) {
71,217✔
491
        ar->namewhat = "";
62✔
492
        ar->name = NULL;
62✔
493
      }
494
    } else if (*what == 'f') {
238✔
495
      opt_f = 1;
496
    } else if (*what == 'L') {
4✔
497
      opt_L = 1;
498
    } else {
499
      return 0;  /* Bad option. */
500
    }
501
  }
502
  if (opt_f) {
71,293✔
503
    setfuncV(L, L->top, fn);
234✔
504
    incr_top(L);
234✔
505
  }
506
  if (opt_L) {
71,293✔
507
    if (isluafunc(fn)) {
3✔
508
      GCtab *t = lj_tab_new(L, 0, 0);
3✔
509
      GCproto *pt = funcproto(fn);
3✔
510
      const void *lineinfo = proto_lineinfo(pt);
3✔
511
      if (lineinfo) {
3✔
512
        BCLine first = pt->firstline;
3✔
513
        int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4;
3✔
514
        MSize i, szl = pt->sizebc-1;
3✔
515
        for (i = 0; i < szl; i++) {
87✔
516
          BCLine line = first +
168✔
517
            (sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] :
84✔
518
             sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] :
×
519
             (BCLine)((const uint32_t *)lineinfo)[i]);
×
520
          setboolV(lj_tab_setint(L, t, line), 1);
84✔
521
        }
522
      }
523
      settabV(L, L->top, t);
3✔
524
    } else {
525
      setnilV(L->top);
×
526
    }
527
    incr_top(L);
3✔
528
  }
529
  return 1;  /* Ok. */
530
}
531

532
LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar)
107✔
533
{
534
  return lj_debug_getinfo(L, what, (lj_Debug *)ar, 0);
12✔
535
}
536

537
LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
71,328✔
538
{
539
  int size;
71,328✔
540
  cTValue *frame = lj_debug_frame(L, level, &size);
71,328✔
541
  if (frame) {
71,328✔
542
    ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
71,301✔
543
    return 1;
71,301✔
544
  } else {
545
    ar->i_ci = level - size;
27✔
546
    return 0;
27✔
547
  }
548
}
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)
1✔
583
{
584
  int level = 0, dir = 1, pathstrip = 1;
1✔
585
  MSize lastlen = 0;
1✔
586
  if (depth < 0) { level = ~depth; depth = dir = -1; }  /* Reverse frames. */
1✔
587
  while (level != depth) {  /* Loop through all frame. */
2✔
588
    int size;
1✔
589
    cTValue *frame = lj_debug_frame(L, level, &size);
1✔
590
    if (frame) {
1✔
591
      cTValue *nextframe = size ? frame+size : NULL;
1✔
592
      GCfunc *fn = frame_func(frame);
1✔
593
      const uint8_t *p = (const uint8_t *)fmt;
1✔
594
      int c;
1✔
595
      while ((c = *p++)) {
1✔
596
        switch (c) {
5✔
597
        case 'p':  /* Preserve full path. */
598
          pathstrip = 0;
599
          break;
600
        case 'F': case 'f': {  /* Dump function name. */
1✔
601
          const char *name;
1✔
602
          const char *what = lj_debug_funcname(L, frame, &name);
1✔
603
          if (what) {
1✔
604
            if (c == 'F' && isluafunc(fn)) {  /* Dump module:name for 'F'. */
1✔
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));
1✔
612
            break;
1✔
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' ? lj_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. */
1✔
636
          lastlen = sbuflen(sb);
1✔
637
          break;
1✔
638
        default:
639
          lj_buf_putb(sb, c);
9✔
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;
1✔
649
  }
650
  if (lastlen)
1✔
651
    setsbufP(sb, sbufB(sb) + lastlen);  /* Zap trailing separator. */
1✔
652
}
1✔
653
#endif
654

655
/* Number of frames for the leading and trailing part of a traceback. */
656
#define TRACEBACK_LEVELS1        12
657
#define TRACEBACK_LEVELS2        10
658

659
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
22✔
660
                                int level)
661
{
662
  int top = (int)(L->top - L->base);
22✔
663
  int lim = TRACEBACK_LEVELS1;
22✔
664
  lua_Debug ar;
22✔
665
  if (msg) lua_pushfstring(L, "%s\n", msg);
22✔
666
  lua_pushliteral(L, "stack traceback:");
22✔
667
  while (lua_getstack(L1, level++, &ar)) {
118✔
668
    GCfunc *fn;
96✔
669
    if (level > lim) {
96✔
670
      if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) {
1✔
671
        level--;
672
      } else {
673
        lua_pushliteral(L, "\n\t...");
1✔
674
        lua_getstack(L1, -10, &ar);
1✔
675
        level = ar.i_ci - TRACEBACK_LEVELS2;
1✔
676
      }
677
      lim = 2147483647;
1✔
678
      continue;
1✔
679
    }
680
    lua_getinfo(L1, "Snlf", &ar);
95✔
681
    fn = funcV(L1->top-1); L1->top--;
95✔
682
    if (isffunc(fn) && !*ar.namewhat)
95✔
683
      lua_pushfstring(L, "\n\t[builtin#%d]:", fn->c.ffid);
×
684
    else
685
      lua_pushfstring(L, "\n\t%s:", ar.short_src);
95✔
686
    if (ar.currentline > 0)
95✔
687
      lua_pushfstring(L, "%d:", ar.currentline);
62✔
688
    if (*ar.namewhat) {
95✔
689
      lua_pushfstring(L, " in function " LUA_QS, ar.name);
54✔
690
    } else {
691
      if (*ar.what == 'm') {
41✔
692
        lua_pushliteral(L, " in main chunk");
13✔
693
      } else if (*ar.what == 'C') {
28✔
694
        lua_pushfstring(L, " at %p", fn->c.f);
13✔
695
      } else {
696
        lua_pushfstring(L, " in function <%s:%d>",
15✔
697
                        ar.short_src, ar.linedefined);
698
      }
699
    }
700
    if ((int)(L->top - L->base) - top >= 15)
95✔
701
      lua_concat(L, (int)(L->top - L->base) - top);
10✔
702
  }
703
  lua_concat(L, (int)(L->top - L->base) - top);
22✔
704
}
22✔
705

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc