Skip to content

Commit 6f7c52a

Browse files
committed
Fix the launch of perforator on Linux kernel 5.10
1 parent 565b710 commit 6f7c52a

File tree

3 files changed

+129
-146
lines changed

3 files changed

+129
-146
lines changed

perforator/agent/collector/progs/unwinder/lua/trace.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33
// Temporary change to get rid of bad address error when running without --debug flag
44
#define LUA_TRACE(fmt, ...) \
5-
BPF_PRINTK("lua: " fmt "\n", ##__VA_ARGS__)
5+
BPF_TRACE("lua: " fmt "\n", ##__VA_ARGS__)

perforator/agent/collector/progs/unwinder/lua/types.h

Lines changed: 30 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,69 +6,38 @@
66

77
/* Read ULEB128 from buffer. */
88
// BPF version with loop unrolled and reading process memory via BPF API
9-
bool ALWAYS_INLINE LJ_FASTCALL lj_buf_ruleb128(const char **pp, uint32_t *out) {
10-
const uint8_t *w = (const uint8_t *)*pp;
11-
uint32_t value;
12-
uint8_t byte;
13-
int err = bpf_probe_read_user(&byte, sizeof(byte), w);
14-
if (err != 0) {
15-
return false;
16-
}
17-
w += 1;
18-
value = byte;
19-
if (value < 0x80) {
20-
*pp = (const char *)w;
21-
*out = value;
22-
return true;
23-
}
24-
value &= 0x7F;
25-
uint8_t more = 1;
26-
int shift = 7;
27-
// byte 2
28-
if (more) {
29-
int err = bpf_probe_read_user(&byte, sizeof(byte), w);
30-
if (err != 0) {
31-
return false;
32-
}
33-
w += 1;
34-
value |= (byte & 0x7F) << shift;
35-
more = (byte & 0x80) ? 1 : 0;
36-
shift += 7;
37-
}
38-
// byte 3
39-
if (more) {
40-
int err = bpf_probe_read_user(&byte, sizeof(byte), w);
41-
if (err != 0) {
42-
return false;
43-
}
44-
w += 1;
45-
value |= (byte & 0x7F) << shift;
46-
more = (byte & 0x80) ? 1 : 0;
47-
shift += 7;
48-
}
49-
// byte 4
50-
if (more) {
51-
int err = bpf_probe_read_user(&byte, sizeof(byte), w);
52-
if (err != 0) {
53-
return false;
9+
10+
uint64_t LJ_FASTCALL lj_buf_ruleb128_new(uint64_t pp) {
11+
12+
const uint8_t *p = (const uint8_t *)pp;
13+
uint64_t result = 0;
14+
uint32_t v = 0;
15+
uint8_t offset = 0;
16+
bool status = false;
17+
uint8_t b;
18+
int shift = 0;
19+
20+
for (int i = 0; i < 5; i++) {
21+
if (bpf_probe_read_user(&b, 1, p + i)){
22+
break;
5423
}
55-
w += 1;
56-
value |= (byte & 0x7F) << shift;
57-
more = (byte & 0x80) ? 1 : 0;
24+
25+
// Не последний — добавляем 7 бит
26+
v |= (uint32_t)(b & 0x7f) << shift;
5827
shift += 7;
59-
}
60-
// byte 5 (final)
61-
if (more) {
62-
int err = bpf_probe_read_user(&byte, sizeof(byte), w);
63-
if (err != 0) {
64-
return false;
65-
}
66-
w += 1;
67-
value |= (byte & 0x7F) << shift;
68-
}
69-
*pp = (const char *)w;
70-
*out = value;
71-
return true;
28+
// Сразу проверяем, последний ли это байт
29+
if (b < 0x80) {
30+
offset = i;
31+
status = true;
32+
break;
33+
}
34+
}
35+
36+
result |= status ? 0x800000000000000 : 0;
37+
result |= ((uint64_t) offset) << 32;
38+
result |= v;
39+
// Дошли до 5-го байта, а бит продолжения всё ещё был — это ошибка
40+
return result;
7241
}
7342

7443
enum {

perforator/agent/collector/progs/unwinder/lua/unwind.h

Lines changed: 98 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ static ALWAYS_INLINE void lua_frame_write(struct lua_state *state,
117117
static bool string_compare(const char *s1, const char *s2, size_t len) {
118118
for (size_t i = 0; i != 64 && i != len; ++i) {
119119
if (s1[i] != s2[i]) {
120-
LUA_TRACE("%c != %c", s1[i], s2[i]);
120+
//LUA_TRACE("%c != %c", s1[i], s2[i]);
121121
return false;
122122
}
123123
}
@@ -545,107 +545,120 @@ static void lua_push_invalid_frame(struct lua_state *state,
545545

546546
/* Get name of a local variable from slot number and PC. */
547547
// original function - debug_varname, lj_debug.c
548+
549+
static NOINLINE uint64_t read_varname(struct lua_state *state, uint64_t p_value, int i, BCPos lastpc){
550+
uint64_t p = p_value;
551+
uint64_t success_flag = 0;
552+
553+
if(p == NULL){
554+
goto return_result;
555+
}
556+
const char *name = p;
557+
uint8_t vn;
558+
559+
int status = bpf_probe_read_user(&vn, sizeof(vn), p);
560+
if(status != 0){
561+
goto return_result;
562+
}
563+
564+
BCPos startpc, endpc;
565+
if (vn < VARNAME__MAX) {
566+
// pre-defined variable, name index is stored as an integer constant
567+
// (uint8_t)
568+
if (vn == VARNAME_END) {
569+
/* End of varinfo. */
570+
goto return_result;
571+
}
572+
p += 1;
573+
} else {
574+
// an actual variable name stored as string
575+
status = bpf_probe_read_user_str(state->buffer, sizeof(state->buffer) , p);
576+
if (status < 0) {
577+
goto return_result;
578+
}
579+
p += status;
580+
}
581+
uint64_t result = lj_buf_ruleb128_new(p);
582+
583+
if (!(result & 0x800000000000000)) {
584+
goto return_result;
585+
}
586+
p += (uint8_t)(result>>32) +1;
587+
lastpc = startpc = lastpc + (uint32_t)result;
588+
589+
result = lj_buf_ruleb128_new(p);
590+
if (!(result & 0x800000000000000)) {
591+
goto return_result;
592+
}
593+
p += (uint8_t)(result>>32) +1;
594+
endpc = startpc + (uint32_t)result;
595+
596+
struct lua_variable *variable = bpf_map_lookup_elem(&lua_variables_storage, &i);
597+
if (variable) {
598+
variable->name = (u64)name;
599+
variable->startpc = startpc;
600+
variable->endpc = endpc;
601+
}
602+
success_flag = 0x8000000000000000;
603+
604+
return_result:
605+
return success_flag + ((uint64_t)(p - p_value) <<32) +lastpc;
606+
}
607+
548608
static ALWAYS_INLINE int bpf_debug_varname(struct lua_state *state, GCproto *pt,
549609
BCPos pc) {
550610
const char *p = (const char *)proto_varinfo(pt);
551611
if (!p) {
552612
return 0;
553613
}
614+
if(state == NULL){
615+
return 0;
616+
}
554617
BCPos lastpc = 0;
555-
556618
// original function uses an infinite loop to scan variables block
557619
// here in BPF program use some reasonable default - 200 local variables
558620
// (LJ_MAX_LOCVAR)
559621

560622
int i = 0;
561623
for (; i < 40 /*LJ_MAX_LOCVAR*/; ++i) {
562-
const char *name = p;
563-
uint8_t vn;
564-
565-
int status = bpf_probe_read_user(&vn, sizeof(vn), p);
566-
if (status != 0) {
624+
625+
uint64_t result = read_varname( state, (uint64_t)p, i, lastpc);
626+
p += (uint8_t)(result >> 32);
627+
if(!(result & 0x8000000000000000)){
567628
return i;
568629
}
569-
570-
BCPos startpc, endpc;
571-
572-
if (vn < VARNAME__MAX) {
573-
// pre-defined variable, name index is stored as an integer constant
574-
// (uint8_t)
575-
if (vn == VARNAME_END) {
576-
/* End of varinfo. */
577-
return i;
578-
}
579-
p++;
580-
581-
} else {
582-
// an actual variable name stored as string
583-
584-
status = bpf_probe_read_user_str(state->buffer,
585-
sizeof(state->buffer), p);
586-
if (status < 0) {
587-
return i;
588-
}
589-
p += status;
590-
}
591-
uint32_t value;
592-
if (!lj_buf_ruleb128(&p, &value)) {
593-
return i;
594-
}
595-
lastpc = startpc = lastpc + value;
596-
#if 0
597-
if (startpc > pc) {
598-
return i;
599-
}
600-
#endif
601-
if (!lj_buf_ruleb128(&p, &value)) {
602-
return i;
603-
}
604-
endpc = startpc + value;
605-
#if 0
606-
if (pc < endpc && slot-- == 0) {
607-
return name;
608-
} else {
609-
}
610-
#endif
611-
612-
struct lua_variable *variable =
613-
bpf_map_lookup_elem(&lua_variables_storage, &i);
614-
if (variable) {
615-
variable->name = (u64)name;
616-
variable->startpc = startpc;
617-
variable->endpc = endpc;
618-
}
630+
lastpc = (uint32_t)result;
619631
}
620632
return i + 1;
621633
}
622634

623-
// original function - lj_debug_uvname, lj_debug.c
624-
/* Get name of upvalue. */
625-
static ALWAYS_INLINE int bpf_debug_uvname(struct lua_state *state,
626-
GCproto *pt) {
635+
static __always_inline int bpf_debug_uvname(struct lua_state *L, GCproto *pt)
636+
{
627637
const uint8_t *p = proto_uvinfo(pt);
628-
if (!p) {
638+
if (!p)
629639
return 0;
630-
}
631-
int i = 0;
632-
for (; i < LJ_MAX_UPVAL; ++i) {
633-
const char *name = p;
634-
int status =
635-
bpf_probe_read_user_str(state->buffer, sizeof(state->buffer), p);
636640

637-
if (status < 0) {
638-
return i;
641+
int i = 0;
642+
int status;
643+
644+
#define READ_UV(n) \
645+
{ \
646+
const char *name_##n = (const char *)p; \
647+
status = bpf_probe_read_user_str(L->buffer, sizeof(L->buffer), p); \
648+
if (status <= 0) goto done; \
649+
p += status; \
650+
struct lua_variable *uv = bpf_map_lookup_elem(&lua_upvalues_storage, &i); \
651+
if (uv) uv->name = (uint64_t)name_##n; \
652+
i++; \
639653
}
640-
p += status;
641654

642-
struct lua_variable *upvalue =
643-
bpf_map_lookup_elem(&lua_upvalues_storage, &i);
644-
if (upvalue) {
645-
upvalue->name = (u64)name;
646-
}
647-
}
648-
return i + 1;
655+
READ_UV(0); READ_UV(1); READ_UV(2); READ_UV(3); READ_UV(4);
656+
READ_UV(5);
657+
658+
#undef READ_UV
659+
660+
done:
661+
return i;
649662
}
650663

651664
// original function - lj_debug_slotname, lj_debug.c
@@ -663,6 +676,7 @@ bpf_debug_slotname(struct lua_state *state, struct symbol_state *symbol,
663676
// variables array
664677
int count_variables = bpf_debug_varname(state, pt, pc);
665678
int count_upvalues = bpf_debug_uvname(state, pt);
679+
//int count_upvalues = 0;
666680
// local variable is only read on "start" and on "restart" (BCmov "ra ==
667681
// slot" condition)
668682
bool read_local = true;
@@ -1087,24 +1101,24 @@ static void lua_stack_walk(struct lua_state *state) {
10871101

10881102
for (int i = 0; i < 10 && frame > bottom; i++) {
10891103
if (!(frame <= max_stack && (!nextframe || nextframe <= max_stack))) {
1090-
LUA_TRACE("broken frame chain");
1104+
//LUA_TRACE("broken frame chain");
10911105
return;
10921106
}
10931107

10941108
if (frame_gc(frame) == obj2gco(L)) {
1095-
LUA_TRACE("Skip dummy frames.");
1109+
//LUA_TRACE("Skip dummy frames.");
10961110
should_visit_frame =
10971111
false; /* Skip dummy frames. See lj_err_optype_call(). */
10981112
}
10991113

11001114
/* Level found. */
11011115
if (should_visit_frame) {
1102-
LUA_TRACE("level=%d found frame=%px nextframe=%px", debug_count,
1103-
frame, nextframe);
1116+
//LUA_TRACE("level=%d found frame=%px nextframe=%px", debug_count,
1117+
// frame, nextframe);
11041118

11051119
if (!lua_get_function_info(state, frame, nextframe)) {
1106-
LUA_TRACE("lua_get_function_info error on level %d",
1107-
debug_count);
1120+
//LUA_TRACE("lua_get_function_info error on level %d",
1121+
// debug_count);
11081122
metric_increment(METRIC_LUA_GET_FUNCTION_INFO_FAIL_COUNT);
11091123
return;
11101124
}

0 commit comments

Comments
 (0)