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

tarantool / luajit / 5942561862

22 Aug 2023 05:18PM UTC coverage: 87.9% (+0.08%) from 87.818%
5942561862

push

github

igormunkin
MIPS: Add MIPS64 R6 port.

Contributed by Hua Zhang, YunQiang Su from Wave Computing,
and Radovan Birdic from RT-RK.
Sponsored by Wave Computing.

(cherry-picked from commit 94d0b5300)

This patch adds support for MIPS Release 6 [1] for the 64-bit build.
This includes:
* Global `_map_def` value is set with <dynasm/dynasm.lua>. `MIPSR6` key
  specifies the corresponding instruction set support. Also, `MIPSR6` is
  defined in `DYNASM_FLAGS` (`DASM_AFLAGS`).
* New instructions are added within <dynasm/dasm_mips.lua>, they are
  used if the aforementioned key is set.
* Obsolete instructions (that are no longer in use in r6) are used in
  the opposite case (if `MIPSR6` isn't set).
* New opcode maps are added to <src/jit/dis_mips.lua>.
* `map_arch` table in <jit/bcsave.lua> is refactored for more convenient
  usage. Now each arch key contains a table with the corresponding info
  about the supported architecture:
    - `e`: endianness "le" or "be"
    - `b`: bit-width of the supported architecture; 32 or 64
    - `m`: machine specification (see `e_machine` in man elf)
    - `f`: processor-specific flags (see `e_flags` in man elf)
    - `p`: number that identifies the type of target machine [2] for
      Portable Executable format [3].
* New `LJ_TARGET_MIPSR6` define is set for MIPSR6 in <src/lj_arch.h>.
* The corresponding "MIPS32R6", "MIPS64R6" CPU strings are added to the
  <src/jit.h>
* MIPSR6 instructions are added to the <src/lj_target_mips.h>, some
  obsolete instructions are removed or defined only for the non-MIPSR6
  build.
* All release-dependent instructions in <src/lj_asm_mips.h> are
  instrumented with `LJ_TARGET_MIPSR6` macro.
* `f20`, `f21`, `f22` FP registers are defined as `FTMP0`, `FTMP1`,
  `FTMP2` correspondingly in the VM.
* All release-dependent instructions in <src/vm_mips64.dasm> are
  instrumented with `MIPSR6` macro.
* `sfmin_max` macro now takes the third operand for the MIPSR6 build.
* Fix the impli... (continued)

5343 of 6000 branches covered (89.05%)

Branch coverage included in aggregate %.

20504 of 23405 relevant lines covered (87.61%)

1253254.78 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,455✔
26
{
27
  cTValue *frame, *nextframe, *bot = tvref(L->stack)+LJ_FR2;
71,455✔
28
  /* Traverse frames backwards. */
29
  for (nextframe = frame = L->base-1; frame > bot; ) {
535,900✔
30
    if (frame_gc(frame) == obj2gco(L))
535,870✔
31
      level++;  /* Skip dummy frames. See lj_err_optype_call(). */
×
32
    if (level-- == 0) {
535,870✔
33
      *size = (int)(nextframe - frame);
71,425✔
34
      return frame;  /* Level found. */
71,425✔
35
    }
36
    nextframe = frame;
464,445✔
37
    if (frame_islua(frame)) {
464,445✔
38
      frame = frame_prevl(frame);
464,135✔
39
    } else {
40
      if (frame_isvarg(frame))
310✔
41
        level++;  /* Skip vararg pseudo-frame. */
54✔
42
      frame = frame_prevd(frame);
310✔
43
    }
44
  }
45
  *size = level;
30✔
46
  return NULL;  /* Level not found. */
30✔
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)
32,321,732✔
115
{
116
  const void *lineinfo = proto_lineinfo(pt);
32,321,732✔
117
  if (pc <= pt->sizebc && lineinfo) {
32,321,732✔
118
    BCLine first = pt->firstline;
32,319,501✔
119
    if (pc == pt->sizebc) return first + pt->numline;
32,319,501✔
120
    if (pc-- == 0) return first;
32,319,501✔
121
    if (pt->numline < 256)
32,319,469✔
122
      return first + (BCLine)((const uint8_t *)lineinfo)[pc];
30,121,980✔
123
    else if (pt->numline < 65536)
2,197,489✔
124
      return first + (BCLine)((const uint16_t *)lineinfo)[pc];
1,287,278✔
125
    else
126
      return first + (BCLine)((const uint32_t *)lineinfo)[pc];
910,211✔
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)
2,132✔
133
{
134
  BCPos pc = debug_framepc(L, fn, nextframe);
2,132✔
135
  if (pc != NO_BCPOS) {
2,132✔
136
    GCproto *pt = funcproto(fn);
2,096✔
137
    lua_assert(pc <= pt->sizebc);
2,096✔
138
    return lj_debug_line(pt, pc);
2,096✔
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)
144✔
216
{
217
  const uint8_t *p = proto_uvinfo(pt);
144✔
218
  lua_assert(idx < pt->sizeuv);
144✔
219
  if (!p) return "";
64✔
220
  if (idx) while (*p++ || --idx) ;
787✔
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)
21✔
226
{
227
  if (tvisfunc(o)) {
21✔
228
    GCfunc *fn = funcV(o);
21✔
229
    if (isluafunc(fn)) {
21✔
230
      GCproto *pt = funcproto(fn);
19✔
231
      if (idx < pt->sizeuv) {
19✔
232
        GCobj *uvo = gcref(fn->l.uvptr[idx]);
12✔
233
        *tvp = uvval(&uvo->uv);
12✔
234
        *op = uvo;
12✔
235
        return lj_debug_uvname(pt, idx);
24✔
236
      }
237
    } else {
238
      if (idx < fn->c.nupvalues) {
2✔
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,
72,665✔
250
                              const char **name)
251
{
252
  const char *lname;
72,698✔
253
restart:
72,698✔
254
  lname = debug_varname(pt, proto_bcpos(pt, ip), slot);
72,698✔
255
  if (lname != NULL) { *name = lname; return "local"; }
72,698✔
256
  while (--ip > proto_bc(pt)) {
73,133✔
257
    BCIns ins = *ip;
73,131✔
258
    BCOp op = bc_op(ins);
73,131✔
259
    BCReg ra = bc_a(ins);
73,131✔
260
    if (bcmode_a(op) == BCMbase) {
73,131✔
261
      if (slot >= ra && (op != BC_KNIL || slot <= bc_d(ins)))
5✔
262
        return NULL;
263
    } else if (bcmode_a(op) == BCMdst && ra == slot) {
73,126✔
264
      switch (bc_op(ins)) {
72,640✔
265
      case BC_MOV:
266
        if (ra == slot) { slot = bc_d(ins); goto restart; }
33✔
267
        break;
268
      case BC_GGET:
71,440✔
269
        *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_d(ins))));
71,440✔
270
        return "global";
71,440✔
271
      case BC_TGETS:
39✔
272
        *name = strdata(gco2str(proto_kgc(pt, ~(ptrdiff_t)bc_c(ins))));
39✔
273
        if (ip > proto_bc(pt)) {
39✔
274
          BCIns insp = ip[-1];
39✔
275
          if (bc_op(insp) == BC_MOV && bc_a(insp) == ra+1+LJ_FR2 &&
39✔
276
              bc_d(insp) == bc_b(ins))
5✔
277
            return "method";
278
        }
279
        return "field";
34✔
280
      case BC_UGET:
68✔
281
        *name = lj_debug_uvname(pt, bc_d(ins));
68✔
282
        return "upvalue";
68✔
283
      default:
284
        return NULL;
285
      }
286
    }
486✔
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)
71,304✔
293
{
294
  cTValue *pframe;
71,304✔
295
  GCfunc *fn;
71,304✔
296
  BCPos pc;
71,304✔
297
  if (frame <= tvref(L->stack)+LJ_FR2)
71,304✔
298
    return NULL;
299
  if (frame_isvarg(frame))
71,304✔
300
    frame = frame_prevd(frame);
24✔
301
  pframe = frame_prev(frame);
71,304✔
302
  fn = frame_func(pframe);
71,304✔
303
  pc = debug_framepc(L, fn, frame);
71,304✔
304
  if (pc != NO_BCPOS) {
71,304✔
305
    GCproto *pt = funcproto(fn);
71,216✔
306
    const BCIns *ip = &proto_bc(pt)[check_exp(pc < pt->sizebc, pc)];
71,216✔
307
    MMS mm = bcmode_mm(bc_op(*ip));
71,216✔
308
    if (mm == MM_call) {
71,216✔
309
      BCReg slot = bc_a(*ip);
71,180✔
310
      if (bc_op(*ip) == BC_ITERC) slot -= 3;
71,180✔
311
      return lj_debug_slotname(pt, ip, slot, name);
71,180✔
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)
14,554✔
324
{
325
  const char *src = strdata(str);
14,554✔
326
  if (*src == '=') {
14,554✔
327
    strncpy(out, src+1, LUA_IDSIZE);  /* Remove first char. */
424✔
328
    out[LUA_IDSIZE-1] = '\0';  /* Ensures null termination. */
424✔
329
  } else if (*src == '@') {  /* Output "source", or "...source". */
14,130✔
330
    size_t len = str->len-1;
463✔
331
    src++;  /* Skip the `@' */
463✔
332
    if (len >= LUA_IDSIZE) {
463✔
333
      src += len-(LUA_IDSIZE-4);  /* Get last part of file name. */
459✔
334
      *out++ = '.'; *out++ = '.'; *out++ = '.';
459✔
335
    }
336
    strcpy(out, src);
463✔
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++)
176,519✔
340
      if (((const unsigned char *)src)[len] < ' ') break;
176,503✔
341
    strcpy(out, line == ~(BCLine)0 ? "[builtin:" : "[string \""); out += 9;
13,667✔
342
    if (src[len] != '\0') {  /* Must truncate? */
13,667✔
343
      if (len > LUA_IDSIZE-15) len = LUA_IDSIZE-15;
9,481✔
344
      strncpy(out, src, len); out += len;
9,481✔
345
      strcpy(out, "..."); out += 3;
9,481✔
346
    } else {
347
      strcpy(out, src); out += len;
4,186✔
348
    }
349
    strcpy(out, line == ~(BCLine)0 ? "]" : "\"]");
27,334✔
350
  }
351
}
14,554✔
352

353
/* Add current location of a frame to error message. */
354
void lj_debug_addloc(lua_State *L, const char *msg,
13,347✔
355
                     cTValue *frame, cTValue *nextframe)
356
{
357
  if (frame) {
13,347✔
358
    GCfunc *fn = frame_func(frame);
13,219✔
359
    if (isluafunc(fn)) {
13,219✔
360
      BCLine line = lj_debug_frameline(L, fn, nextframe);
1,705✔
361
      if (line >= 0) {
1,705✔
362
        GCproto *pt = funcproto(fn);
1,704✔
363
        char buf[LUA_IDSIZE];
1,704✔
364
        lj_debug_shortname(buf, proto_chunkname(pt), pt->firstline);
1,704✔
365
        lj_strfmt_pushf(L, "%s:%d: %s", buf, line, msg);
1,704✔
366
        return;
1,704✔
367
      }
368
    }
369
  }
370
  lj_strfmt_pushf(L, "%s", msg);
11,643✔
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)
19✔
404
{
405
  const char *name = NULL;
19✔
406
  if (ar) {
19✔
407
    TValue *o = debug_localname(L, ar, &name, (BCReg)n);
19✔
408
    if (name) {
19✔
409
      copyTV(L, L->top, o);
15✔
410
      incr_top(L);
15✔
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;
19✔
416
}
417

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

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

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

535
LUA_API int lua_getstack(lua_State *L, int level, lua_Debug *ar)
71,324✔
536
{
537
  int size;
71,324✔
538
  cTValue *frame = lj_debug_frame(L, level, &size);
71,324✔
539
  if (frame) {
71,324✔
540
    ar->i_ci = (size << 16) + (int)(frame - tvref(L->stack));
71,298✔
541
    return 1;
71,298✔
542
  } else {
543
    ar->i_ci = level - size;
26✔
544
    return 0;
26✔
545
  }
546
}
547

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

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

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

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

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