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

tarantool / luajit / 5784751762

07 Aug 2023 11:54AM UTC coverage: 84.282% (-3.1%) from 87.373%
5784751762

push

github

ligurio
setup-gcovr [TO SQUASH]

5157 of 6002 branches covered (85.92%)

Branch coverage included in aggregate %.

19632 of 23410 relevant lines covered (83.86%)

229380.51 hits per line

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

86.4
/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)
235✔
26
{
27
  cTValue *frame, *nextframe, *bot = tvref(L->stack)+LJ_FR2;
235✔
28
  /* Traverse frames backwards. */
29
  for (nextframe = frame = L->base-1; frame > bot; ) {
519✔
30
    if (frame_gc(frame) == obj2gco(L))
504✔
31
      level++;  /* Skip dummy frames. See lj_err_optype_call(). */
×
32
    if (level-- == 0) {
504✔
33
      *size = (int)(nextframe - frame);
220✔
34
      return frame;  /* Level found. */
220✔
35
    }
36
    nextframe = frame;
284✔
37
    if (frame_islua(frame)) {
284✔
38
      frame = frame_prevl(frame);
139✔
39
    } else {
40
      if (frame_isvarg(frame))
145✔
41
        level++;  /* Skip vararg pseudo-frame. */
21✔
42
      frame = frame_prevd(frame);
145✔
43
    }
44
  }
45
  *size = level;
15✔
46
  return NULL;  /* Level not found. */
15✔
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
      if (!ins) return NO_BCPOS;
97
    }
98
  }
99
  pt = funcproto(fn);
100
  pos = proto_bcpos(pt, ins) - 1;
101
#if LJ_HASJIT
102
  if (pos > pt->sizebc) {  /* Undo the effects of lj_trace_exit for JLOOP. */
103
    GCtrace *T = (GCtrace *)((char *)(ins-1) - offsetof(GCtrace, startins));
104
    lua_assert(bc_isret(bc_op(ins[-1])));
105
    pos = proto_bcpos(pt, mref(T->startpc, const BCIns));
106
  }
107
#endif
108
  return pos;
109
}
110

111
/* -- Line numbers -------------------------------------------------------- */
112

113
/* Get line number for a bytecode position. */
114
BCLine LJ_FASTCALL lj_debug_line(GCproto *pt, BCPos pc)
426✔
115
{
116
  const void *lineinfo = proto_lineinfo(pt);
426✔
117
  if (pc <= pt->sizebc && lineinfo) {
426✔
118
    BCLine first = pt->firstline;
424✔
119
    if (pc == pt->sizebc) return first + pt->numline;
424✔
120
    if (pc-- == 0) return first;
424✔
121
    if (pt->numline < 256)
406✔
122
      return first + (BCLine)((const uint8_t *)lineinfo)[pc];
398✔
123
    else if (pt->numline < 65536)
8✔
124
      return first + (BCLine)((const uint16_t *)lineinfo)[pc];
8✔
125
    else
126
      return first + (BCLine)((const uint32_t *)lineinfo)[pc];
×
127
  }
128
  return 0;
129
}
130

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

143
/* -- Variable names ------------------------------------------------------ */
144

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

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

214
/* Get name of upvalue. */
215
const char *lj_debug_uvname(GCproto *pt, uint32_t idx)
122✔
216
{
217
  const uint8_t *p = proto_uvinfo(pt);
122✔
218
  lua_assert(idx < pt->sizeuv);
122✔
219
  if (!p) return "";
64✔
220
  if (idx) while (*p++ || --idx) ;
755✔
221
  return (const char *)p;
222
}
223

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

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

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

320
/* -- Source code locations ----------------------------------------------- */
321

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

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

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

399
/* -- Public debug API ---------------------------------------------------- */
400

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

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

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

428
int lj_debug_getinfo(lua_State *L, const char *what, lj_Debug *ar, int ext)
78✔
429
{
430
  int opt_f = 0, opt_L = 0;
78✔
431
  TValue *frame = NULL;
78✔
432
  TValue *nextframe = NULL;
78✔
433
  GCfunc *fn;
78✔
434
  if (*what == '>') { /* we have to have an extra arg on stack */
78✔
435
    if (lua_gettop(L) > 2) {
4✔
436
      TValue *func = L->top - 1;
4✔
437
      api_check(L, tvisfunc(func));
4✔
438
      fn = funcV(func);
4✔
439
      L->top--;
4✔
440
      what++;
4✔
441
    } else { /* need better error to display? */
442
      return 0;
443
    }
444
  } else {
445
    uint32_t offset = (uint32_t)ar->i_ci & 0xffff;
74✔
446
    uint32_t size = (uint32_t)ar->i_ci >> 16;
74✔
447
    lua_assert(offset != 0);
74✔
448
    frame = tvref(L->stack) + offset;
74✔
449
    if (size) nextframe = frame + size;
74✔
450
    lua_assert(frame <= tvref(L->maxstack) &&
74✔
451
               (!nextframe || nextframe <= tvref(L->maxstack)));
452
    fn = frame_func(frame);
74✔
453
    lua_assert(fn->c.gct == ~LJ_TFUNC);
454
  }
455
  for (; *what; what++) {
406✔
456
    if (*what == 'S') {
329✔
457
      if (isluafunc(fn)) {
72✔
458
        GCproto *pt = funcproto(fn);
56✔
459
        BCLine firstline = pt->firstline;
56✔
460
        GCstr *name = proto_chunkname(pt);
56✔
461
        ar->source = strdata(name);
56✔
462
        lj_debug_shortname(ar->short_src, name, pt->firstline);
56✔
463
        ar->linedefined = (int)firstline;
56✔
464
        ar->lastlinedefined = (int)(firstline + pt->numline);
56✔
465
        ar->what = (firstline || !pt->numline) ? "Lua" : "main";
65✔
466
      } else {
467
        ar->source = "=[C]";
16✔
468
        ar->short_src[0] = '[';
16✔
469
        ar->short_src[1] = 'C';
16✔
470
        ar->short_src[2] = ']';
16✔
471
        ar->short_src[3] = '\0';
16✔
472
        ar->linedefined = -1;
16✔
473
        ar->lastlinedefined = -1;
16✔
474
        ar->what = "C";
16✔
475
      }
476
    } else if (*what == 'l') {
257✔
477
      ar->currentline = frame ? lj_debug_frameline(L, fn, nextframe) : -1;
73✔
478
    } else if (*what == 'u') {
184✔
479
      ar->nups = fn->c.nupvalues;
38✔
480
      if (ext) {
38✔
481
        if (isluafunc(fn)) {
38✔
482
          GCproto *pt = funcproto(fn);
38✔
483
          ar->nparams = pt->numparams;
38✔
484
          ar->isvararg = !!(pt->flags & PROTO_VARARG);
38✔
485
        } else {
486
          ar->nparams = 0;
×
487
          ar->isvararg = 1;
×
488
        }
489
      }
490
    } else if (*what == 'n') {
146✔
491
      ar->namewhat = frame ? lj_debug_funcname(L, frame, &ar->name) : NULL;
71✔
492
      if (ar->namewhat == NULL) {
71✔
493
        ar->namewhat = "";
24✔
494
        ar->name = NULL;
24✔
495
      }
496
    } else if (*what == 'f') {
75✔
497
      opt_f = 1;
498
    } else if (*what == 'L') {
2✔
499
      opt_L = 1;
500
    } else {
501
      return 0;  /* Bad option. */
502
    }
503
  }
504
  if (opt_f) {
77✔
505
    setfuncV(L, L->top, fn);
73✔
506
    incr_top(L);
73✔
507
  }
508
  if (opt_L) {
77✔
509
    if (isluafunc(fn)) {
1✔
510
      GCtab *t = lj_tab_new(L, 0, 0);
1✔
511
      GCproto *pt = funcproto(fn);
1✔
512
      const void *lineinfo = proto_lineinfo(pt);
1✔
513
      if (lineinfo) {
1✔
514
        BCLine first = pt->firstline;
1✔
515
        int sz = pt->numline < 256 ? 1 : pt->numline < 65536 ? 2 : 4;
1✔
516
        MSize i, szl = pt->sizebc-1;
1✔
517
        for (i = 0; i < szl; i++) {
27✔
518
          BCLine line = first +
52✔
519
            (sz == 1 ? (BCLine)((const uint8_t *)lineinfo)[i] :
26✔
520
             sz == 2 ? (BCLine)((const uint16_t *)lineinfo)[i] :
×
521
             (BCLine)((const uint32_t *)lineinfo)[i]);
×
522
          setboolV(lj_tab_setint(L, t, line), 1);
26✔
523
        }
524
      }
525
      settabV(L, L->top, t);
1✔
526
    } else {
527
      setnilV(L->top);
×
528
    }
529
    incr_top(L);
1✔
530
  }
531
  return 1;  /* Ok. */
532
}
533

534
LUA_API int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar)
35✔
535
{
536
  return lj_debug_getinfo(L, what, (lj_Debug *)ar, 0);
2✔
537
}
538

539
LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
90✔
540
{
541
  int size;
90✔
542
  cTValue *frame = lj_debug_frame(L, level, &size);
90✔
543
  if (frame) {
90✔
544
    ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
79✔
545
    return 1;
79✔
546
  } else {
547
    ar->i_ci = level - size;
11✔
548
    return 0;
11✔
549
  }
550
}
551

552
#if LJ_HASPROFILE
553
/* Put the chunkname into a buffer. */
554
static int debug_putchunkname(SBuf *sb, GCproto *pt, int pathstrip)
555
{
556
  GCstr *name = proto_chunkname(pt);
557
  const char *p = strdata(name);
558
  if (pt->firstline == ~(BCLine)0) {
559
    lj_buf_putmem(sb, "[builtin:", 9);
560
    lj_buf_putstr(sb, name);
561
    lj_buf_putb(sb, ']');
562
    return 0;
563
  }
564
  if (*p == '=' || *p == '@') {
565
    MSize len = name->len-1;
566
    p++;
567
    if (pathstrip) {
568
      int i;
569
      for (i = len-1; i >= 0; i--)
570
        if (p[i] == '/' || p[i] == '\\') {
571
          len -= i+1;
572
          p = p+i+1;
573
          break;
574
        }
575
    }
576
    lj_buf_putmem(sb, p, len);
577
  } else {
578
    lj_buf_putmem(sb, "[string]", 8);
579
  }
580
  return 1;
581
}
582

583
/* Put a compact stack dump into a buffer. */
584
void lj_debug_dumpstack(lua_State *L, SBuf *sb, const char *fmt, int depth)
1✔
585
{
586
  int level = 0, dir = 1, pathstrip = 1;
1✔
587
  MSize lastlen = 0;
1✔
588
  if (depth < 0) { level = ~depth; depth = dir = -1; }  /* Reverse frames. */
1✔
589
  while (level != depth) {  /* Loop through all frame. */
2✔
590
    int size;
1✔
591
    cTValue *frame = lj_debug_frame(L, level, &size);
1✔
592
    if (frame) {
1✔
593
      cTValue *nextframe = size ? frame+size : NULL;
1✔
594
      GCfunc *fn = frame_func(frame);
1✔
595
      const uint8_t *p = (const uint8_t *)fmt;
1✔
596
      int c;
1✔
597
      while ((c = *p++)) {
1✔
598
        switch (c) {
5✔
599
        case 'p':  /* Preserve full path. */
600
          pathstrip = 0;
601
          break;
602
        case 'F': case 'f': {  /* Dump function name. */
1✔
603
          const char *name;
1✔
604
          const char *what = lj_debug_funcname(L, frame, &name);
1✔
605
          if (what) {
1✔
606
            if (c == 'F' && isluafunc(fn)) {  /* Dump module:name for 'F'. */
1✔
607
              GCproto *pt = funcproto(fn);
×
608
              if (pt->firstline != ~(BCLine)0) {  /* Not a bytecode builtin. */
×
609
                debug_putchunkname(sb, pt, pathstrip);
×
610
                lj_buf_putb(sb, ':');
×
611
              }
612
            }
613
            lj_buf_putmem(sb, name, (MSize)strlen(name));
1✔
614
            break;
1✔
615
          }  /* else: can't derive a name, dump module:line. */
616
          }
617
          /* fallthrough */
618
        case 'l':  /* Dump module:line. */
619
          if (isluafunc(fn)) {
×
620
            GCproto *pt = funcproto(fn);
×
621
            if (debug_putchunkname(sb, pt, pathstrip)) {
×
622
              /* Regular Lua function. */
623
              BCLine line = c == 'l' ? lj_debug_frameline(L, fn, nextframe) :
×
624
                                       pt->firstline;
625
              lj_buf_putb(sb, ':');
×
626
              lj_strfmt_putint(sb, line >= 0 ? line : pt->firstline);
×
627
            }
628
          } else if (isffunc(fn)) {  /* Dump numbered builtins. */
×
629
            lj_buf_putmem(sb, "[builtin#", 9);
×
630
            lj_strfmt_putint(sb, fn->c.ffid);
×
631
            lj_buf_putb(sb, ']');
×
632
          } else {  /* Dump C function address. */
633
            lj_buf_putb(sb, '@');
×
634
            lj_strfmt_putptr(sb, fn->c.f);
×
635
          }
636
          break;
637
        case 'Z':  /* Zap trailing separator. */
1✔
638
          lastlen = sbuflen(sb);
1✔
639
          break;
1✔
640
        default:
641
          lj_buf_putb(sb, c);
9✔
642
          break;
643
        }
644
      }
645
    } else if (dir == 1) {
×
646
      break;
647
    } else {
648
      level -= size;  /* Reverse frame order: quickly skip missing level. */
×
649
    }
650
    level += dir;
1✔
651
  }
652
  if (lastlen)
1✔
653
    setsbufP(sb, sbufB(sb) + lastlen);  /* Zap trailing separator. */
1✔
654
}
1✔
655
#endif
656

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

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

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