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

tarantool / luajit / 7003855917

27 Nov 2023 10:35AM UTC coverage: 88.579% (+0.06%) from 88.517%
7003855917

push

github

Buristan
Fix FOLD rule for BUFHDR append.

Reported by XmiliaH.

(cherry-picked from commit bc1bdbf62)

`bufput_append()` may fold `BUFHDR RESET` + `BUFPUT` IRs to `BUFHDR
APPEND` even if the right operand (`BUFSTR`) is the PHI. If it's not the
last IR in the `BUFSTR` chain, this may lead to an incorrect resulting
value in the buffer, which contains a longer string since `APPEND` is
used instead of `RESET`.

This patch adds the corresponding check inside the fold rule.

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#9145

5379 of 5987 branches covered (0.0%)

Branch coverage included in aggregate %.

2 of 2 new or added lines in 1 file covered. (100.0%)

11 existing lines in 4 files now uncovered.

20611 of 23354 relevant lines covered (88.25%)

2755489.57 hits per line

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

83.19
/src/lj_sysprof.c
1
/*
2
** Implementation of sysprof - platform and Lua profiler.
3
*/
4

5
#define lj_sysprof_c
6
#define LUA_CORE
7

8
#include "lj_arch.h"
9
#include "lj_sysprof.h"
10

11
#if LJ_HASSYSPROF
12

13
#include "lj_obj.h"
14
#include "lj_debug.h"
15
#include "lj_dispatch.h"
16
#include "lj_frame.h"
17

18
#if LJ_HASJIT
19
#include "lj_jit.h"
20
#include "lj_trace.h"
21
#endif
22

23
#include "lj_wbuf.h"
24
#include "lj_profile_timer.h"
25
#include "lj_symtab.h"
26

27
#include <pthread.h>
28
#include <errno.h>
29
#include <execinfo.h>
30

31
/*
32
** Number of profiler frames we need to omit during stack
33
** unwinding.
34
**   +------------------------+
35
** 0 | default_backtrace_host |
36
**   +------------------------+
37
** 1 | stream_backtrace_host  |
38
**   +------------------------+
39
** 2 |  stream_{guest/host}   |
40
**   +------------------------+
41
** 3 |      stream_event      |
42
**   +------------------------+
43
** 4 | sysprof_record_sample  |
44
**   +------------------------+
45
** 5 | sysprof_signal_handler |
46
**   +------------------------+
47
*/
48
#define SYSPROF_HANDLER_STACK_DEPTH 6
49
#define SYSPROF_BACKTRACE_FRAME_MAX 512
50

51
/* Check that vmstate fits in 4 bits (see streaming format) */
52
#define vmstfit4(st) ((st & ~(uint32_t)((1 << 4) - 1)) == 0)
53

54
enum sysprof_state {
55
  /* Profiler is not running. */
56
  SPS_IDLE,
57
  /* Profiler is running. */
58
  SPS_PROFILE,
59
  /*
60
  ** Stopped in case of stopped or failed stream.
61
  ** Saved errno is set at luaM_sysprof_stop.
62
  */
63
  SPS_HALT
64
};
65

66
struct sysprof {
67
  global_State *g; /* Profiled VM. */
68
  pthread_t thread; /* Profiled thread. */
69
  volatile sig_atomic_t state; /* Internal state. */
70
  struct lj_wbuf out; /* Output accumulator. */
71
  struct luam_Sysprof_Counters counters; /* Profiling counters. */
72
  struct luam_Sysprof_Options opt; /* Profiling options. */
73
  luam_Sysprof_writer writer; /* Writer function for profile events. */
74
  luam_Sysprof_on_stop on_stop; /* Callback on profiling stopping. */
75
  luam_Sysprof_backtracer backtracer; /* Backtracing function for the host stack. */
76
  lj_profile_timer timer; /* Profiling timer. */
77
  int saved_errno; /* Saved errno when profiler failed. */
78
  uint32_t lib_adds; /* Number of libs loaded. Monotonic. */
79
};
80
/*
81
** XXX: Only one VM can be profiled at a time.
82
*/
83

84
static struct sysprof sysprof = {0};
85

86
/* --- Stream ------------------------------------------------------------- */
87

88
static const uint8_t ljp_header[] = {'l', 'j', 'p', LJP_FORMAT_VERSION,
89
                                      0x0, 0x0, 0x0};
90

91
static int stream_is_needed(struct sysprof *sp)
20✔
92
{
93
  return sp->opt.mode != LUAM_SYSPROF_DEFAULT;
20✔
94
}
95

96
static int is_unconfigured(struct sysprof *sp)
796✔
97
{
98
  return sp->backtracer == NULL || sp->on_stop == NULL || sp->writer == NULL;
268✔
99
}
100

101
static void stream_prologue(struct sysprof *sp)
4✔
102
{
103
  lj_symtab_dump(&sp->out, sp->g, &sp->lib_adds);
4✔
104
  lj_wbuf_addn(&sp->out, ljp_header, sizeof(ljp_header));
4✔
105
}
4✔
106

107
static void stream_epilogue(struct sysprof *sp)
4✔
108
{
109
  lj_wbuf_addbyte(&sp->out, LJP_EPILOGUE_BYTE);
4✔
110
}
111

112
static void stream_ffunc_impl(struct lj_wbuf *buf, uint8_t ffid)
3✔
113
{
114
  lj_wbuf_addbyte(buf, LJP_FRAME_FFUNC);
3✔
115
  lj_wbuf_addu64(buf, ffid);
3✔
116
}
3✔
117

118
static void stream_lfunc(struct lj_wbuf *buf, const GCfunc *func)
119
{
120
  lj_assertX(isluafunc(func), "bad lua function in sysprof stream");
121
  const GCproto *pt = funcproto(func);
122
  lj_assertX(pt != NULL, "bad lua function prototype in sysprof stream");
123
  lj_wbuf_addbyte(buf, LJP_FRAME_LFUNC);
124
  lj_wbuf_addu64(buf, (uintptr_t)pt);
125
  lj_wbuf_addu64(buf, (uint64_t)pt->firstline);
126
}
127

128
static void stream_cfunc(struct lj_wbuf *buf, const GCfunc *func)
11✔
129
{
130
  lj_assertX(iscfunc(func), "bad C function in sysprof stream");
11✔
131
  lj_wbuf_addbyte(buf, LJP_FRAME_CFUNC);
11✔
132
  lj_wbuf_addu64(buf, (uintptr_t)func->c.f);
11✔
133
}
11✔
134

UNCOV
135
static void stream_ffunc(struct lj_wbuf *buf, const GCfunc *func)
×
136
{
UNCOV
137
  lj_assertX(isffunc(func), "bad fast function in sysprof stream");
×
UNCOV
138
  stream_ffunc_impl(buf, func->c.ffid);
×
UNCOV
139
}
×
140

141
static void stream_frame_lua(struct lj_wbuf *buf, const cTValue *frame)
184✔
142
{
143
  const GCfunc *func = frame_func(frame);
184✔
144
  lj_assertX(func != NULL, "bad function in sysprof stream");
184✔
145
  if (isluafunc(func))
184✔
146
    stream_lfunc(buf, func);
173✔
147
  else if (isffunc(func))
11✔
UNCOV
148
    stream_ffunc(buf, func);
×
149
  else if (iscfunc(func))
11✔
150
    stream_cfunc(buf, func);
11✔
151
  else
152
    /* Unreachable. */
153
    lj_assertX(0, "bad function type in sysprof stream");
184✔
154
}
184✔
155

156
static void stream_backtrace_lua(struct sysprof *sp, uint32_t vmstate)
11✔
157
{
158
  global_State *g = sp->g;
11✔
159
  struct lj_wbuf *buf = &sp->out;
11✔
160
  cTValue *top_frame = NULL, *frame = NULL, *bot = NULL;
11✔
161
  lua_State *L = NULL;
11✔
162

163
  lj_assertX(g != NULL, "uninitialized global state in sysprof state");
11✔
164
  L = gco2th(gcref(g->cur_L));
11✔
165
  lj_assertG(L != NULL, "uninitialized Lua state in sysprof state");
11✔
166
  /*
167
  ** Lua stack may be inconsistent during the execution of a
168
  ** fast-function, so instead of updating the `top_frame` for
169
  ** it, its `ffid` is set instead. The first frame on the
170
  ** result stack is streamed manually, and the rest of the
171
  ** stack is streamed based on the previous `top_frame` value.
172
  */
173
  if (vmstate == LJ_VMST_FFUNC) {
11✔
174
    uint8_t ffid = g->top_frame_info.ffid;
3✔
175
    stream_ffunc_impl(buf, ffid);
3✔
176
  }
177

178
  top_frame = g->top_frame_info.top_frame - 1;
11✔
179

180
  bot = tvref(L->stack) + LJ_FR2;
11✔
181
  /* Traverse frames backwards */
182
  for (frame = top_frame; frame > bot; frame = frame_prev(frame)) {
401✔
183
    if (frame_gc(frame) == obj2gco(L) || frame_isvarg(frame))
195✔
184
      continue;  /* Skip dummy frames. See lj_err_optype_call(). */
11✔
185
    stream_frame_lua(buf, frame);
184✔
186
  }
187

188
  lj_wbuf_addbyte(buf, LJP_FRAME_LUA_LAST);
11✔
189
}
11✔
190

191
static void *stream_frame_host(int frame_no, void *addr)
133✔
192
{
193
  struct sysprof *sp = &sysprof;
133✔
194
  /*
195
  ** We don't want the profiler stack to be streamed, as it will
196
  ** burden the profile with unnecessary information.
197
  */
198
  if (LJ_UNLIKELY(frame_no <= SYSPROF_HANDLER_STACK_DEPTH))
133✔
199
    return addr;
200
  else if (LJ_UNLIKELY(sp->opt.mode == LUAM_SYSPROF_LEAF &&
24✔
201
                         frame_no > SYSPROF_HANDLER_STACK_DEPTH))
202
    return NULL;
203

204
  lj_wbuf_addu64(&sp->out, (uintptr_t)addr);
24✔
205
  return addr;
24✔
206
}
207

208
static void default_backtrace_host(void *(writer)(int frame_no, void *addr))
19✔
209
{
210
  static void *backtrace_buf[SYSPROF_BACKTRACE_FRAME_MAX] = {};
19✔
211

212
  struct sysprof *sp = &sysprof;
19✔
213
  int max_depth = sp->opt.mode == LUAM_SYSPROF_LEAF
38✔
214
                  ? SYSPROF_HANDLER_STACK_DEPTH + 1
215
                  : SYSPROF_BACKTRACE_FRAME_MAX;
19✔
216
  const int depth = backtrace(backtrace_buf, max_depth);
19✔
217
  int level;
19✔
218

219
  lj_assertX(depth <= max_depth, "depth of C stack is too big");
19✔
220
  for (level = SYSPROF_HANDLER_STACK_DEPTH; level < depth; ++level) {
171✔
221
    if (!writer(level - SYSPROF_HANDLER_STACK_DEPTH + 1, backtrace_buf[level]))
133✔
222
      return;
223
  }
224
}
225

226
static void stream_backtrace_host(struct sysprof *sp)
19✔
227
{
228
  lj_assertX(sp->backtracer != NULL, "uninitialized sysprof backtracer");
19✔
229
  sp->backtracer(stream_frame_host);
19✔
230
  lj_wbuf_addu64(&sp->out, (uintptr_t)LJP_FRAME_HOST_LAST);
19✔
231
}
232

233
#if LJ_HASJIT
234
static void stream_trace(struct sysprof *sp, uint32_t vmstate)
×
235
{
236
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
×
237
  struct lj_wbuf *out = &sp->out;
×
238
  uint32_t traceno = sp->g->vmstate;
×
239
  jit_State *J = G2J(sp->g);
×
240
  GCtrace *trace = traceref(J, traceno);
×
241

242
  GCproto *startpt = gco2pt(gcref(trace->startpt));
×
243

244
  lj_wbuf_addu64(out, traceno);
×
245
  lj_wbuf_addu64(out, (uintptr_t)startpt);
×
246
  lj_wbuf_addu64(out, startpt->firstline);
×
247
}
×
248
#endif
249

250
static void stream_guest(struct sysprof *sp, uint32_t vmstate)
11✔
251
{
252
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
11✔
253
  stream_backtrace_lua(sp, vmstate);
11✔
254
  stream_backtrace_host(sp);
11✔
255
}
11✔
256

257
static void stream_host(struct sysprof *sp, uint32_t vmstate)
8✔
258
{
259
  struct lua_State *L = gco2th(gcref(sp->g->cur_L));
8✔
260
  lj_symtab_dump_newc(&sp->lib_adds, &sp->out, LJP_SYMTAB_CFUNC_EVENT, L);
8✔
261
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
8✔
262
  stream_backtrace_host(sp);
8✔
263
}
8✔
264

265
typedef void (*event_streamer)(struct sysprof *sp, uint32_t vmstate);
266

267
static event_streamer event_streamers[] = {
268
  /* XXX: order is important */
269
  stream_host,  /* LJ_VMST_INTERP */
270
  stream_guest, /* LJ_VMST_LFUNC */
271
  stream_guest, /* LJ_VMST_FFUNC */
272
  stream_guest, /* LJ_VMST_CFUNC */
273
  stream_host,  /* LJ_VMST_GC */
274
  stream_host,  /* LJ_VMST_EXIT */
275
  stream_host,  /* LJ_VMST_RECORD */
276
  stream_host,  /* LJ_VMST_OPT */
277
  stream_host,  /* LJ_VMST_ASM */
278
#if LJ_HASJIT
279
  stream_trace  /* LJ_VMST_TRACE */
280
#endif
281
};
282

283
static void stream_event(struct sysprof *sp, uint32_t vmstate)
284
{
285
  event_streamer stream = NULL;
286

287
  lj_assertX(vmstfit4(vmstate), "vmstate don't fit in 4 bits");
288
  stream = event_streamers[vmstate];
289
  lj_assertX(stream != NULL, "uninitialized sysprof stream");
290
  stream(sp, vmstate);
291
}
292

293
/* -- Signal handler ------------------------------------------------------ */
294

295
static void sysprof_record_sample(struct sysprof *sp, siginfo_t *info)
296
{
297
  global_State *g = sp->g;
298
  uint32_t _vmstate = ~(uint32_t)(g->vmstate);
299
  uint32_t vmstate = _vmstate < LJ_VMST_TRACE ? _vmstate : LJ_VMST_TRACE;
300

301
  lj_assertX(pthread_self() == sp->thread,
302
             "bad thread during sysprof record sample");
303

304
  /* Caveat: order of counters must match vmstate order in <lj_obj.h>. */
305
  ((uint64_t *)&sp->counters)[vmstate]++;
306

307
  sp->counters.samples++;
308

309
  if (!stream_is_needed(sp))
310
    return;
311

312
  stream_event(sp, vmstate);
313
  if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
314
    sp->saved_errno = lj_wbuf_errno(&sp->out);
315
    lj_wbuf_terminate(&sp->out);
316
    sp->state = SPS_HALT;
317
  }
318
}
319

320
static void sysprof_signal_handler(int sig, siginfo_t *info, void *ctx)
20✔
321
{
322
  struct sysprof *sp = &sysprof;
20✔
323
  UNUSED(sig);
20✔
324
  UNUSED(ctx);
20✔
325

326
  switch (sp->state) {
20✔
327
    case SPS_PROFILE:
20✔
328
      sysprof_record_sample(sp, info);
20✔
329
      break;
20✔
330

331
    case SPS_IDLE:
332
    case SPS_HALT:
333
      /* noop */
334
      break;
335

336
    default:
337
      lj_assertX(0, "bad sysprof profiler state");
338
      break;
339
  }
340
}
20✔
341

342
/* -- Internal ------------------------------------------------------------ */
343

344
static int sysprof_validate(struct sysprof *sp,
15✔
345
                            const struct luam_Sysprof_Options *opt)
346
{
347
  switch (sp->state) {
15✔
348
    case SPS_IDLE:
13✔
349
      if (opt->mode > LUAM_SYSPROF_CALLGRAPH) {
13✔
350
        return PROFILE_ERRUSE;
351
      } else if (opt->mode != LUAM_SYSPROF_DEFAULT &&
12✔
352
                 (opt->buf == NULL || opt->len == 0 || is_unconfigured(sp))) {
5✔
353
        return PROFILE_ERRUSE;
354
      } else if (opt->interval == 0) {
11✔
355
        return PROFILE_ERRUSE;
1✔
356
      }
357
      break;
358

359
    case SPS_PROFILE:
360
    case SPS_HALT:
361
      return PROFILE_ERRRUN;
362

363
    default:
364
      lj_assertX(0, "bad sysprof profiler state");
365
      break;
366
  }
367

368
  return PROFILE_SUCCESS;
369
}
370

371
static int sysprof_init(struct sysprof *sp, lua_State *L,
372
                        const struct luam_Sysprof_Options *opt)
373
{
374
  const int status = sysprof_validate(sp, opt);
375
  if (PROFILE_SUCCESS != status)
376
    return status;
377

378
  /* Copy validated options to sysprof state. */
379
  memcpy(&sp->opt, opt, sizeof(sp->opt));
380

381
  /* Init general fields. */
382
  sp->g = G(L);
383
  sp->thread = pthread_self();
384

385
  /* Reset counters. */
386
  memset(&sp->counters, 0, sizeof(sp->counters));
387

388
  /* Reset saved errno. */
389
  sp->saved_errno = 0;
390

391
  if (stream_is_needed(sp))
392
    lj_wbuf_init(&sp->out, sp->writer, opt->ctx, opt->buf, opt->len);
393

394
  return PROFILE_SUCCESS;
395
}
396

397
/* -- Public profiling API ------------------------------------------------ */
398

399
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
264✔
400
  struct sysprof *sp = &sysprof;
264✔
401

402
  if (sp->state != SPS_IDLE || writer == NULL)
264✔
403
    return PROFILE_ERRUSE;
404

405
  sp->writer = writer;
264✔
406
  if (!is_unconfigured(sp)) {
264✔
407
    sp->state = SPS_IDLE;
×
408
  }
409
  return PROFILE_SUCCESS;
410
}
411

412
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
264✔
413
  struct sysprof *sp = &sysprof;
264✔
414

415
  if (sp->state != SPS_IDLE || on_stop == NULL)
264✔
416
    return PROFILE_ERRUSE;
417

418
  sp->on_stop = on_stop;
264✔
419
  if (!is_unconfigured(sp)) {
264✔
420
    sp->state = SPS_IDLE;
×
421
  }
422
  return PROFILE_SUCCESS;
423
}
424

425
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
264✔
426
  struct sysprof *sp = &sysprof;
264✔
427

428
  if (sp->state != SPS_IDLE)
264✔
429
    return PROFILE_ERRUSE;
430
  if (backtracer == NULL) {
264✔
431
    sp->backtracer = default_backtrace_host;
264✔
432
    /*
433
    ** XXX: `backtrace` is not signal-safe, according to man,
434
    ** because it is lazy loaded on the first call, which triggers
435
    ** allocations. We need to call `backtrace` before starting profiling
436
    ** to avoid lazy loading.
437
    */
438
    void *dummy = NULL;
264✔
439
    backtrace(&dummy, 1);
264✔
440
  }
441
  else {
442
    sp->backtracer = backtracer;
×
443
  }
444
  if (!is_unconfigured(sp)) {
264✔
445
    sp->state = SPS_IDLE;
264✔
446
  }
447
  return PROFILE_SUCCESS;
448
}
449

450
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
15✔
451
{
452
  struct sysprof *sp = &sysprof;
15✔
453

454
  int status = sysprof_init(sp, L, opt);
15✔
455
  if (PROFILE_SUCCESS != status) {
15✔
456
    if (NULL != sp->on_stop) {
5✔
457
      /*
458
      ** Initialization may fail in case of unconfigured sysprof,
459
      ** so we cannot guarantee cleaning up resources in this case.
460
      */
461
      sp->on_stop(opt->ctx, opt->buf);
5✔
462
    }
463
    return status;
5✔
464
  }
465

466
  sp->state = SPS_PROFILE;
10✔
467

468
  if (stream_is_needed(sp)) {
10✔
469
    stream_prologue(sp);
4✔
470
    if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
4✔
471
      /* on_stop call may change errno value. */
472
      const int saved_errno = lj_wbuf_errno(&sp->out);
×
473
      /* Ignore possible errors. mp->out.buf may be NULL here. */
474
      sp->on_stop(opt->ctx, sp->out.buf);
×
475
      lj_wbuf_terminate(&sp->out);
×
476
      sp->state = SPS_IDLE;
×
477
      errno = saved_errno;
×
478
      return PROFILE_ERRIO;
×
479
    }
480
  }
481

482
  sp->timer.opt.interval_msec = opt->interval;
10✔
483
  sp->timer.opt.handler = sysprof_signal_handler;
10✔
484
  lj_profile_timer_start(&sp->timer);
10✔
485

486
  return PROFILE_SUCCESS;
10✔
487
}
488

489
int lj_sysprof_stop(lua_State *L)
270✔
490
{
491
  struct sysprof *sp = &sysprof;
270✔
492
  global_State *g = sp->g;
270✔
493
  struct lj_wbuf *out = &sp->out;
270✔
494

495
  if (SPS_IDLE == sp->state)
270✔
496
    return PROFILE_ERRRUN;
497
  else if (G(L) != g)
10✔
498
    return PROFILE_ERRUSE;
499

500
  lj_profile_timer_stop(&sp->timer);
10✔
501

502
  if (SPS_HALT == sp->state) {
10✔
503
    errno = sp->saved_errno;
×
504
    sp->state = SPS_IDLE;
×
505
    /* wbuf was terminated when error occurred. */
506
    return PROFILE_ERRIO;
×
507
  }
508

509
  sp->state = SPS_IDLE;
10✔
510

511
  if (stream_is_needed(sp)) {
10✔
512
    int cb_status = 0;
4✔
513

514
    stream_epilogue(sp);
4✔
515
    lj_wbuf_flush(out);
4✔
516

517
    cb_status = sp->on_stop(sp->opt.ctx, out->buf);
4✔
518
    if (LJ_UNLIKELY(lj_wbuf_test_flag(out, STREAM_ERRIO | STREAM_STOP)) ||
4✔
519
        cb_status != 0) {
520
      errno = lj_wbuf_errno(out);
×
521
      lj_wbuf_terminate(out);
×
522
      return PROFILE_ERRIO;
×
523
    }
524

525
    lj_wbuf_terminate(out);
4✔
526
  }
527

528
  return PROFILE_SUCCESS;
529
}
530

531
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
3✔
532
{
533
  const struct sysprof *sp = &sysprof;
3✔
534
  if (sp->state != SPS_IDLE)
3✔
535
    return PROFILE_ERRUSE;
536
  memcpy(counters, &sp->counters, sizeof(sp->counters));
3✔
537
  return PROFILE_SUCCESS;
3✔
538
}
539

540
void lj_sysprof_add_proto(const struct GCproto *pt)
57,347✔
541
{
542
  struct sysprof *sp = &sysprof;
57,347✔
543

544
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
57,347✔
545
    return;
546

547
  /*
548
  ** XXX: Avoid sampling during the symtab extension. That shouldn't have any
549
  ** significant effect on profile precision, but if it does, it's better to
550
  ** implement an async-safe queue for the symtab events.
551
  */
552
  sp->state = SPS_IDLE;
×
553
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_LFUNC_EVENT);
×
554
  lj_symtab_dump_proto(&sp->out, pt);
×
555
  sp->state = SPS_PROFILE;
×
556
}
557

558
#if LJ_HASJIT
559
void lj_sysprof_add_trace(const struct GCtrace *tr)
5,140✔
560
{
561
  struct sysprof *sp = &sysprof;
5,140✔
562

563
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
5,140✔
564
    return;
565

566
  /* See the comment about the sysprof state above. */
567
  sp->state = SPS_IDLE;
×
568
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_TRACE_EVENT);
×
569
  lj_symtab_dump_trace(&sp->out, tr);
×
570
  sp->state = SPS_PROFILE;
×
571
}
572
#endif /* LJ_HASJIT */
573

574
#else /* LJ_HASSYSPROF */
575

576
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
577
  UNUSED(writer);
578
  return PROFILE_ERRUSE;
579
}
580

581
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
582
  UNUSED(on_stop);
583
  return PROFILE_ERRUSE;
584
}
585

586
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
587
  UNUSED(backtracer);
588
  return PROFILE_ERRUSE;
589
}
590

591
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
592
{
593
  UNUSED(L);
594
  return PROFILE_ERRUSE;
595
}
596

597
int lj_sysprof_stop(lua_State *L)
598
{
599
  UNUSED(L);
600
  return PROFILE_ERRUSE;
601
}
602

603
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
604
{
605
  UNUSED(counters);
606
  return PROFILE_ERRUSE;
607
}
608

609
void lj_sysprof_add_proto(const struct GCproto *pt)
610
{
611
  UNUSED(pt);
612
}
613

614
#if LJ_HASJIT
615
void lj_sysprof_add_trace(const struct GCtrace *tr)
616
{
617
  UNUSED(tr);
618
}
619
#endif /* LJ_HASJIT */
620

621
#endif /* LJ_HASSYSPROF */
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

© 2025 Coveralls, Inc