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

tarantool / luajit / 6788978632

07 Nov 2023 06:45PM UTC coverage: 88.243% (-0.04%) from 88.283%
6788978632

push

github

igormunkin
Fix base register coalescing in side trace.

Thanks to Sergey Kaplun, NiLuJe and Peter Cawley.

(cherry-picked from commit aa2db7ebd)

The previous patch fixed just part of the problem with the register
coalesing. For example, the parent base register may be used inside the
parent or child register sets when it shouldn't. This leads to incorrect
register allocations, which may lead to crashes or undefined behaviour.
This patch fixes it by excluding the parent base register from both
register sets.

The test case for this patch doesn't fail before the commit since it
requires specific register allocation, which is hard to construct and
very fragile. Due to the lack of ideal sync with the upstream
repository, the test is passed before the patch.
It should become correct after backporting future patches.

Resolves tarantool/tarantool#8767
Part of tarantool/tarantool#9145

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

5344 of 5974 branches covered (0.0%)

Branch coverage included in aggregate %.

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

56 existing lines in 7 files now uncovered.

20490 of 23302 relevant lines covered (87.93%)

2743882.83 hits per line

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

82.22
/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)
16✔
92
{
93
  return sp->opt.mode != LUAM_SYSPROF_DEFAULT;
16✔
94
}
95

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

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

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

112
static void stream_lfunc(struct lj_wbuf *buf, const GCfunc *func)
113
{
114
  lj_assertX(isluafunc(func), "bad lua function in sysprof stream");
115
  const GCproto *pt = funcproto(func);
116
  lj_assertX(pt != NULL, "bad lua function prototype in sysprof stream");
117
  lj_wbuf_addbyte(buf, LJP_FRAME_LFUNC);
118
  lj_wbuf_addu64(buf, (uintptr_t)pt);
119
  lj_wbuf_addu64(buf, (uint64_t)pt->firstline);
120
}
121

122
static void stream_cfunc(struct lj_wbuf *buf, const GCfunc *func)
2✔
123
{
124
  lj_assertX(iscfunc(func), "bad C function in sysprof stream");
2✔
125
  lj_wbuf_addbyte(buf, LJP_FRAME_CFUNC);
2✔
126
  lj_wbuf_addu64(buf, (uintptr_t)func->c.f);
2✔
127
}
2✔
128

129
static void stream_ffunc(struct lj_wbuf *buf, const GCfunc *func)
2✔
130
{
131
  lj_assertX(isffunc(func), "bad fast function in sysprof stream");
2✔
132
  lj_wbuf_addbyte(buf, LJP_FRAME_FFUNC);
2✔
133
  lj_wbuf_addu64(buf, func->c.ffid);
2✔
134
}
2✔
135

136
static void stream_frame_lua(struct lj_wbuf *buf, const cTValue *frame)
56✔
137
{
138
  const GCfunc *func = frame_func(frame);
56✔
139
  lj_assertX(func != NULL, "bad function in sysprof stream");
56✔
140
  if (isluafunc(func))
56✔
141
    stream_lfunc(buf, func);
52✔
142
  else if (isffunc(func))
4✔
143
    stream_ffunc(buf, func);
2✔
144
  else if (iscfunc(func))
2✔
145
    stream_cfunc(buf, func);
2✔
146
  else
147
    /* Unreachable. */
148
    lj_assertX(0, "bad function type in sysprof stream");
56✔
149
}
56✔
150

151
static void stream_backtrace_lua(struct sysprof *sp)
2✔
152
{
153
  global_State *g = sp->g;
2✔
154
  struct lj_wbuf *buf = &sp->out;
2✔
155
  cTValue *top_frame = NULL, *frame = NULL, *bot = NULL;
2✔
156
  lua_State *L = NULL;
2✔
157

158
  lj_assertX(g != NULL, "uninitialized global state in sysprof state");
2✔
159
  L = gco2th(gcref(g->cur_L));
2✔
160
  lj_assertG(L != NULL, "uninitialized Lua state in sysprof state");
2✔
161

162
  top_frame = g->top_frame - 1; //(1 + LJ_FR2)
2✔
163

164
  bot = tvref(L->stack) + LJ_FR2;
2✔
165
  /* Traverse frames backwards */
166
  for (frame = top_frame; frame > bot; frame = frame_prev(frame)) {
118✔
167
    if (frame_gc(frame) == obj2gco(L) || frame_isvarg(frame))
58✔
168
      continue;  /* Skip dummy frames. See lj_err_optype_call(). */
2✔
169
    stream_frame_lua(buf, frame);
56✔
170
  }
171

172
  lj_wbuf_addbyte(buf, LJP_FRAME_LUA_LAST);
2✔
173
}
2✔
174

175
static void *stream_frame_host(int frame_no, void *addr)
8✔
176
{
177
  struct sysprof *sp = &sysprof;
8✔
178
  /*
179
  ** We don't want the profiler stack to be streamed, as it will
180
  ** burden the profile with unnecessary information.
181
  */
182
  if (LJ_UNLIKELY(frame_no <= SYSPROF_HANDLER_STACK_DEPTH))
8✔
183
    return addr;
184
  else if (LJ_UNLIKELY(sp->opt.mode == LUAM_SYSPROF_LEAF &&
1✔
185
                         frame_no > SYSPROF_HANDLER_STACK_DEPTH))
186
    return NULL;
187

188
  lj_wbuf_addu64(&sp->out, (uintptr_t)addr);
1✔
189
  return addr;
1✔
190
}
191

192
static void default_backtrace_host(void *(writer)(int frame_no, void *addr))
2✔
193
{
194
  static void *backtrace_buf[SYSPROF_BACKTRACE_FRAME_MAX] = {};
2✔
195

196
  struct sysprof *sp = &sysprof;
2✔
197
  int max_depth = sp->opt.mode == LUAM_SYSPROF_LEAF
4✔
198
                  ? SYSPROF_HANDLER_STACK_DEPTH + 1
199
                  : SYSPROF_BACKTRACE_FRAME_MAX;
2✔
200
  const int depth = backtrace(backtrace_buf, max_depth);
2✔
201
  int level;
2✔
202

203
  lj_assertX(depth <= max_depth, "depth of C stack is too big");
2✔
204
  for (level = SYSPROF_HANDLER_STACK_DEPTH; level < depth; ++level) {
12✔
205
    if (!writer(level - SYSPROF_HANDLER_STACK_DEPTH + 1, backtrace_buf[level]))
8✔
206
      return;
207
  }
208
}
209

210
static void stream_backtrace_host(struct sysprof *sp)
2✔
211
{
212
  lj_assertX(sp->backtracer != NULL, "uninitialized sysprof backtracer");
2✔
213
  sp->backtracer(stream_frame_host);
2✔
214
  lj_wbuf_addu64(&sp->out, (uintptr_t)LJP_FRAME_HOST_LAST);
2✔
215
}
216

217
#if LJ_HASJIT
218
static void stream_trace(struct sysprof *sp, uint32_t vmstate)
×
219
{
220
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
×
221
  struct lj_wbuf *out = &sp->out;
×
222
  uint32_t traceno = sp->g->vmstate;
×
223
  jit_State *J = G2J(sp->g);
×
224
  GCtrace *trace = traceref(J, traceno);
×
225

226
  GCproto *startpt = gco2pt(gcref(trace->startpt));
×
227

228
  lj_wbuf_addu64(out, traceno);
×
229
  lj_wbuf_addu64(out, (uintptr_t)startpt);
×
230
  lj_wbuf_addu64(out, startpt->firstline);
×
231
}
×
232
#endif
233

234
static void stream_guest(struct sysprof *sp, uint32_t vmstate)
2✔
235
{
236
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
2✔
237
  stream_backtrace_lua(sp);
2✔
238
  stream_backtrace_host(sp);
2✔
239
}
2✔
240

UNCOV
241
static void stream_host(struct sysprof *sp, uint32_t vmstate)
×
242
{
UNCOV
243
  struct lua_State *L = gco2th(gcref(sp->g->cur_L));
×
UNCOV
244
  lj_symtab_dump_newc(&sp->lib_adds, &sp->out, LJP_SYMTAB_CFUNC_EVENT, L);
×
UNCOV
245
  lj_wbuf_addbyte(&sp->out, (uint8_t)vmstate);
×
UNCOV
246
  stream_backtrace_host(sp);
×
UNCOV
247
}
×
248

249
typedef void (*event_streamer)(struct sysprof *sp, uint32_t vmstate);
250

251
static event_streamer event_streamers[] = {
252
  /* XXX: order is important */
253
  stream_host,  /* LJ_VMST_INTERP */
254
  stream_guest, /* LJ_VMST_LFUNC */
255
  stream_guest, /* LJ_VMST_FFUNC */
256
  stream_guest, /* LJ_VMST_CFUNC */
257
  stream_host,  /* LJ_VMST_GC */
258
  stream_host,  /* LJ_VMST_EXIT */
259
  stream_host,  /* LJ_VMST_RECORD */
260
  stream_host,  /* LJ_VMST_OPT */
261
  stream_host,  /* LJ_VMST_ASM */
262
#if LJ_HASJIT
263
  stream_trace  /* LJ_VMST_TRACE */
264
#endif
265
};
266

267
static void stream_event(struct sysprof *sp, uint32_t vmstate)
268
{
269
  event_streamer stream = NULL;
270

271
  lj_assertX(vmstfit4(vmstate), "vmstate don't fit in 4 bits");
272
  stream = event_streamers[vmstate];
273
  lj_assertX(stream != NULL, "uninitialized sysprof stream");
274
  stream(sp, vmstate);
275
}
276

277
/* -- Signal handler ------------------------------------------------------ */
278

279
static void sysprof_record_sample(struct sysprof *sp, siginfo_t *info)
280
{
281
  global_State *g = sp->g;
282
  uint32_t _vmstate = ~(uint32_t)(g->vmstate);
283
  uint32_t vmstate = _vmstate < LJ_VMST_TRACE ? _vmstate : LJ_VMST_TRACE;
284

285
  lj_assertX(pthread_self() == sp->thread,
286
             "bad thread during sysprof record sample");
287

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

291
  sp->counters.samples++;
292

293
  if (!stream_is_needed(sp))
294
    return;
295

296
  stream_event(sp, vmstate);
297
  if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
298
    sp->saved_errno = lj_wbuf_errno(&sp->out);
299
    lj_wbuf_terminate(&sp->out);
300
    sp->state = SPS_HALT;
301
  }
302
}
303

304
static void sysprof_signal_handler(int sig, siginfo_t *info, void *ctx)
3✔
305
{
306
  struct sysprof *sp = &sysprof;
3✔
307
  UNUSED(sig);
3✔
308
  UNUSED(ctx);
3✔
309

310
  switch (sp->state) {
3✔
311
    case SPS_PROFILE:
3✔
312
      sysprof_record_sample(sp, info);
3✔
313
      break;
3✔
314

315
    case SPS_IDLE:
316
    case SPS_HALT:
317
      /* noop */
318
      break;
319

320
    default:
321
      lj_assertX(0, "bad sysprof profiler state");
322
      break;
323
  }
324
}
3✔
325

326
/* -- Internal ------------------------------------------------------------ */
327

328
static int sysprof_validate(struct sysprof *sp,
13✔
329
                            const struct luam_Sysprof_Options *opt)
330
{
331
  switch (sp->state) {
13✔
332
    case SPS_IDLE:
11✔
333
      if (opt->mode > LUAM_SYSPROF_CALLGRAPH) {
11✔
334
        return PROFILE_ERRUSE;
335
      } else if (opt->mode != LUAM_SYSPROF_DEFAULT &&
10✔
336
                 (opt->buf == NULL || opt->len == 0 || is_unconfigured(sp))) {
3✔
337
        return PROFILE_ERRUSE;
338
      } else if (opt->interval == 0) {
9✔
339
        return PROFILE_ERRUSE;
1✔
340
      }
341
      break;
342

343
    case SPS_PROFILE:
344
    case SPS_HALT:
345
      return PROFILE_ERRRUN;
346

347
    default:
348
      lj_assertX(0, "bad sysprof profiler state");
349
      break;
350
  }
351

352
  return PROFILE_SUCCESS;
353
}
354

355
static int sysprof_init(struct sysprof *sp, lua_State *L,
356
                        const struct luam_Sysprof_Options *opt)
357
{
358
  const int status = sysprof_validate(sp, opt);
359
  if (PROFILE_SUCCESS != status)
360
    return status;
361

362
  /* Copy validated options to sysprof state. */
363
  memcpy(&sp->opt, opt, sizeof(sp->opt));
364

365
  /* Init general fields. */
366
  sp->g = G(L);
367
  sp->thread = pthread_self();
368

369
  /* Reset counters. */
370
  memset(&sp->counters, 0, sizeof(sp->counters));
371

372
  /* Reset saved errno. */
373
  sp->saved_errno = 0;
374

375
  if (stream_is_needed(sp))
376
    lj_wbuf_init(&sp->out, sp->writer, opt->ctx, opt->buf, opt->len);
377

378
  return PROFILE_SUCCESS;
379
}
380

381
/* -- Public profiling API ------------------------------------------------ */
382

383
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
239✔
384
  struct sysprof *sp = &sysprof;
239✔
385

386
  if (sp->state != SPS_IDLE || writer == NULL)
239✔
387
    return PROFILE_ERRUSE;
388

389
  sp->writer = writer;
239✔
390
  if (!is_unconfigured(sp)) {
239✔
391
    sp->state = SPS_IDLE;
×
392
  }
393
  return PROFILE_SUCCESS;
394
}
395

396
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
239✔
397
  struct sysprof *sp = &sysprof;
239✔
398

399
  if (sp->state != SPS_IDLE || on_stop == NULL)
239✔
400
    return PROFILE_ERRUSE;
401

402
  sp->on_stop = on_stop;
239✔
403
  if (!is_unconfigured(sp)) {
239✔
404
    sp->state = SPS_IDLE;
×
405
  }
406
  return PROFILE_SUCCESS;
407
}
408

409
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
239✔
410
  struct sysprof *sp = &sysprof;
239✔
411

412
  if (sp->state != SPS_IDLE)
239✔
413
    return PROFILE_ERRUSE;
414
  if (backtracer == NULL) {
239✔
415
    sp->backtracer = default_backtrace_host;
239✔
416
    /*
417
    ** XXX: `backtrace` is not signal-safe, according to man,
418
    ** because it is lazy loaded on the first call, which triggers
419
    ** allocations. We need to call `backtrace` before starting profiling
420
    ** to avoid lazy loading.
421
    */
422
    void *dummy = NULL;
239✔
423
    backtrace(&dummy, 1);
239✔
424
  }
425
  else {
426
    sp->backtracer = backtracer;
×
427
  }
428
  if (!is_unconfigured(sp)) {
239✔
429
    sp->state = SPS_IDLE;
239✔
430
  }
431
  return PROFILE_SUCCESS;
432
}
433

434
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
13✔
435
{
436
  struct sysprof *sp = &sysprof;
13✔
437

438
  int status = sysprof_init(sp, L, opt);
13✔
439
  if (PROFILE_SUCCESS != status) {
13✔
440
    if (NULL != sp->on_stop) {
5✔
441
      /*
442
      ** Initialization may fail in case of unconfigured sysprof,
443
      ** so we cannot guarantee cleaning up resources in this case.
444
      */
445
      sp->on_stop(opt->ctx, opt->buf);
5✔
446
    }
447
    return status;
5✔
448
  }
449

450
  sp->state = SPS_PROFILE;
8✔
451

452
  if (stream_is_needed(sp)) {
8✔
453
    stream_prologue(sp);
2✔
454
    if (LJ_UNLIKELY(lj_wbuf_test_flag(&sp->out, STREAM_ERRIO|STREAM_STOP))) {
2✔
455
      /* on_stop call may change errno value. */
456
      const int saved_errno = lj_wbuf_errno(&sp->out);
×
457
      /* Ignore possible errors. mp->out.buf may be NULL here. */
458
      sp->on_stop(opt->ctx, sp->out.buf);
×
459
      lj_wbuf_terminate(&sp->out);
×
460
      sp->state = SPS_IDLE;
×
461
      errno = saved_errno;
×
462
      return PROFILE_ERRIO;
×
463
    }
464
  }
465

466
  sp->timer.opt.interval_msec = opt->interval;
8✔
467
  sp->timer.opt.handler = sysprof_signal_handler;
8✔
468
  lj_profile_timer_start(&sp->timer);
8✔
469

470
  return PROFILE_SUCCESS;
8✔
471
}
472

473
int lj_sysprof_stop(lua_State *L)
246✔
474
{
475
  struct sysprof *sp = &sysprof;
246✔
476
  global_State *g = sp->g;
246✔
477
  struct lj_wbuf *out = &sp->out;
246✔
478

479
  if (SPS_IDLE == sp->state)
246✔
480
    return PROFILE_ERRRUN;
481
  else if (G(L) != g)
8✔
482
    return PROFILE_ERRUSE;
483

484
  lj_profile_timer_stop(&sp->timer);
8✔
485

486
  if (SPS_HALT == sp->state) {
8✔
487
    errno = sp->saved_errno;
×
488
    sp->state = SPS_IDLE;
×
489
    /* wbuf was terminated when error occured. */
490
    return PROFILE_ERRIO;
×
491
  }
492

493
  sp->state = SPS_IDLE;
8✔
494

495
  if (stream_is_needed(sp)) {
8✔
496
    int cb_status = 0;
2✔
497

498
    stream_epilogue(sp);
2✔
499
    lj_wbuf_flush(out);
2✔
500

501
    cb_status = sp->on_stop(sp->opt.ctx, out->buf);
2✔
502
    if (LJ_UNLIKELY(lj_wbuf_test_flag(out, STREAM_ERRIO | STREAM_STOP)) ||
2✔
503
        cb_status != 0) {
504
      errno = lj_wbuf_errno(out);
×
505
      lj_wbuf_terminate(out);
×
506
      return PROFILE_ERRIO;
×
507
    }
508

509
    lj_wbuf_terminate(out);
2✔
510
  }
511

512
  return PROFILE_SUCCESS;
513
}
514

515
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
3✔
516
{
517
  const struct sysprof *sp = &sysprof;
3✔
518
  if (sp->state != SPS_IDLE)
3✔
519
    return PROFILE_ERRUSE;
520
  memcpy(counters, &sp->counters, sizeof(sp->counters));
3✔
521
  return PROFILE_SUCCESS;
3✔
522
}
523

524
void lj_sysprof_add_proto(const struct GCproto *pt)
55,903✔
525
{
526
  struct sysprof *sp = &sysprof;
55,903✔
527

528
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
55,903✔
529
    return;
530

531
  /*
532
  ** XXX: Avoid sampling during the symtab extension. That shouldn't have any
533
  ** significant effect on profile precision, but if it does, it's better to
534
  ** implement an async-safe queue for the symtab events.
535
  */
536
  sp->state = SPS_IDLE;
×
537
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_LFUNC_EVENT);
×
538
  lj_symtab_dump_proto(&sp->out, pt);
×
539
  sp->state = SPS_PROFILE;
×
540
}
541

542
#if LJ_HASJIT
543
void lj_sysprof_add_trace(const struct GCtrace *tr)
3,696✔
544
{
545
  struct sysprof *sp = &sysprof;
3,696✔
546

547
  if (sp->state != SPS_PROFILE || sp->opt.mode == LUAM_SYSPROF_DEFAULT)
3,696✔
548
    return;
549

550
  /* See the comment about the sysprof state above. */
551
  sp->state = SPS_IDLE;
×
552
  lj_wbuf_addbyte(&sp->out, LJP_SYMTAB_TRACE_EVENT);
×
553
  lj_symtab_dump_trace(&sp->out, tr);
×
554
  sp->state = SPS_PROFILE;
×
555
}
556
#endif /* LJ_HASJIT */
557

558
#else /* LJ_HASSYSPROF */
559

560
int lj_sysprof_set_writer(luam_Sysprof_writer writer) {
561
  UNUSED(writer);
562
  return PROFILE_ERRUSE;
563
}
564

565
int lj_sysprof_set_on_stop(luam_Sysprof_on_stop on_stop) {
566
  UNUSED(on_stop);
567
  return PROFILE_ERRUSE;
568
}
569

570
int lj_sysprof_set_backtracer(luam_Sysprof_backtracer backtracer) {
571
  UNUSED(backtracer);
572
  return PROFILE_ERRUSE;
573
}
574

575
int lj_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)
576
{
577
  UNUSED(L);
578
  return PROFILE_ERRUSE;
579
}
580

581
int lj_sysprof_stop(lua_State *L)
582
{
583
  UNUSED(L);
584
  return PROFILE_ERRUSE;
585
}
586

587
int lj_sysprof_report(struct luam_Sysprof_Counters *counters)
588
{
589
  UNUSED(counters);
590
  return PROFILE_ERRUSE;
591
}
592

593
void lj_sysprof_add_proto(const struct GCproto *pt)
594
{
595
  UNUSED(pt);
596
}
597

598
#if LJ_HASJIT
599
void lj_sysprof_add_trace(const struct GCtrace *tr)
600
{
601
  UNUSED(tr);
602
}
603
#endif /* LJ_HASJIT */
604

605
#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