1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
10 #include <linux/kernel.h>
12 #include "bpf-utils.h"
15 struct bpil_array_desc
{
16 int array_offset
; /* e.g. offset of jited_prog_insns */
17 int count_offset
; /* e.g. offset of jited_prog_len */
18 int size_offset
; /* > 0: offset of rec size,
19 * < 0: fix size of -size_offset
23 static struct bpil_array_desc bpil_array_desc
[] = {
24 [PERF_BPIL_JITED_INSNS
] = {
25 offsetof(struct bpf_prog_info
, jited_prog_insns
),
26 offsetof(struct bpf_prog_info
, jited_prog_len
),
29 [PERF_BPIL_XLATED_INSNS
] = {
30 offsetof(struct bpf_prog_info
, xlated_prog_insns
),
31 offsetof(struct bpf_prog_info
, xlated_prog_len
),
34 [PERF_BPIL_MAP_IDS
] = {
35 offsetof(struct bpf_prog_info
, map_ids
),
36 offsetof(struct bpf_prog_info
, nr_map_ids
),
39 [PERF_BPIL_JITED_KSYMS
] = {
40 offsetof(struct bpf_prog_info
, jited_ksyms
),
41 offsetof(struct bpf_prog_info
, nr_jited_ksyms
),
44 [PERF_BPIL_JITED_FUNC_LENS
] = {
45 offsetof(struct bpf_prog_info
, jited_func_lens
),
46 offsetof(struct bpf_prog_info
, nr_jited_func_lens
),
49 [PERF_BPIL_FUNC_INFO
] = {
50 offsetof(struct bpf_prog_info
, func_info
),
51 offsetof(struct bpf_prog_info
, nr_func_info
),
52 offsetof(struct bpf_prog_info
, func_info_rec_size
),
54 [PERF_BPIL_LINE_INFO
] = {
55 offsetof(struct bpf_prog_info
, line_info
),
56 offsetof(struct bpf_prog_info
, nr_line_info
),
57 offsetof(struct bpf_prog_info
, line_info_rec_size
),
59 [PERF_BPIL_JITED_LINE_INFO
] = {
60 offsetof(struct bpf_prog_info
, jited_line_info
),
61 offsetof(struct bpf_prog_info
, nr_jited_line_info
),
62 offsetof(struct bpf_prog_info
, jited_line_info_rec_size
),
64 [PERF_BPIL_PROG_TAGS
] = {
65 offsetof(struct bpf_prog_info
, prog_tags
),
66 offsetof(struct bpf_prog_info
, nr_prog_tags
),
67 -(int)sizeof(__u8
) * BPF_TAG_SIZE
,
72 static __u32
bpf_prog_info_read_offset_u32(struct bpf_prog_info
*info
,
75 __u32
*array
= (__u32
*)info
;
78 return array
[offset
/ sizeof(__u32
)];
82 static __u64
bpf_prog_info_read_offset_u64(struct bpf_prog_info
*info
,
85 __u64
*array
= (__u64
*)info
;
88 return array
[offset
/ sizeof(__u64
)];
92 static void bpf_prog_info_set_offset_u32(struct bpf_prog_info
*info
, int offset
,
95 __u32
*array
= (__u32
*)info
;
98 array
[offset
/ sizeof(__u32
)] = val
;
101 static void bpf_prog_info_set_offset_u64(struct bpf_prog_info
*info
, int offset
,
104 __u64
*array
= (__u64
*)info
;
107 array
[offset
/ sizeof(__u64
)] = val
;
111 get_bpf_prog_info_linear(int fd
, __u64 arrays
)
113 struct bpf_prog_info info
= {};
114 struct perf_bpil
*info_linear
;
115 __u32 info_len
= sizeof(info
);
120 if (arrays
>> PERF_BPIL_LAST_ARRAY
)
121 return ERR_PTR(-EINVAL
);
123 /* step 1: get array dimensions */
124 err
= bpf_obj_get_info_by_fd(fd
, &info
, &info_len
);
126 pr_debug("can't get prog info: %s", strerror(errno
));
127 return ERR_PTR(-EFAULT
);
130 /* step 2: calculate total size of all arrays */
131 for (i
= PERF_BPIL_FIRST_ARRAY
; i
< PERF_BPIL_LAST_ARRAY
; ++i
) {
132 bool include_array
= (arrays
& (1UL << i
)) > 0;
133 struct bpil_array_desc
*desc
;
136 desc
= bpil_array_desc
+ i
;
138 /* kernel is too old to support this field */
139 if (info_len
< desc
->array_offset
+ sizeof(__u32
) ||
140 info_len
< desc
->count_offset
+ sizeof(__u32
) ||
141 (desc
->size_offset
> 0 && info_len
< (__u32
)desc
->size_offset
))
142 include_array
= false;
144 if (!include_array
) {
145 arrays
&= ~(1UL << i
); /* clear the bit */
149 count
= bpf_prog_info_read_offset_u32(&info
, desc
->count_offset
);
150 size
= bpf_prog_info_read_offset_u32(&info
, desc
->size_offset
);
152 data_len
+= roundup(count
* size
, sizeof(__u64
));
155 /* step 3: allocate continuous memory */
156 info_linear
= malloc(sizeof(struct perf_bpil
) + data_len
);
158 return ERR_PTR(-ENOMEM
);
160 /* step 4: fill data to info_linear->info */
161 info_linear
->arrays
= arrays
;
162 memset(&info_linear
->info
, 0, sizeof(info
));
163 ptr
= info_linear
->data
;
165 for (i
= PERF_BPIL_FIRST_ARRAY
; i
< PERF_BPIL_LAST_ARRAY
; ++i
) {
166 struct bpil_array_desc
*desc
;
169 if ((arrays
& (1UL << i
)) == 0)
172 desc
= bpil_array_desc
+ i
;
173 count
= bpf_prog_info_read_offset_u32(&info
, desc
->count_offset
);
174 size
= bpf_prog_info_read_offset_u32(&info
, desc
->size_offset
);
175 bpf_prog_info_set_offset_u32(&info_linear
->info
,
176 desc
->count_offset
, count
);
177 bpf_prog_info_set_offset_u32(&info_linear
->info
,
178 desc
->size_offset
, size
);
179 bpf_prog_info_set_offset_u64(&info_linear
->info
,
182 ptr
+= roundup(count
* size
, sizeof(__u64
));
185 /* step 5: call syscall again to get required arrays */
186 err
= bpf_obj_get_info_by_fd(fd
, &info_linear
->info
, &info_len
);
188 pr_debug("can't get prog info: %s", strerror(errno
));
190 return ERR_PTR(-EFAULT
);
193 /* step 6: verify the data */
194 for (i
= PERF_BPIL_FIRST_ARRAY
; i
< PERF_BPIL_LAST_ARRAY
; ++i
) {
195 struct bpil_array_desc
*desc
;
198 if ((arrays
& (1UL << i
)) == 0)
201 desc
= bpil_array_desc
+ i
;
202 v1
= bpf_prog_info_read_offset_u32(&info
, desc
->count_offset
);
203 v2
= bpf_prog_info_read_offset_u32(&info_linear
->info
,
206 pr_warning("%s: mismatch in element count\n", __func__
);
208 v1
= bpf_prog_info_read_offset_u32(&info
, desc
->size_offset
);
209 v2
= bpf_prog_info_read_offset_u32(&info_linear
->info
,
212 pr_warning("%s: mismatch in rec size\n", __func__
);
215 /* step 7: update info_len and data_len */
216 info_linear
->info_len
= sizeof(struct bpf_prog_info
);
217 info_linear
->data_len
= data_len
;
222 void bpil_addr_to_offs(struct perf_bpil
*info_linear
)
226 for (i
= PERF_BPIL_FIRST_ARRAY
; i
< PERF_BPIL_LAST_ARRAY
; ++i
) {
227 struct bpil_array_desc
*desc
;
230 if ((info_linear
->arrays
& (1UL << i
)) == 0)
233 desc
= bpil_array_desc
+ i
;
234 addr
= bpf_prog_info_read_offset_u64(&info_linear
->info
,
236 offs
= addr
- ptr_to_u64(info_linear
->data
);
237 bpf_prog_info_set_offset_u64(&info_linear
->info
,
238 desc
->array_offset
, offs
);
242 void bpil_offs_to_addr(struct perf_bpil
*info_linear
)
246 for (i
= PERF_BPIL_FIRST_ARRAY
; i
< PERF_BPIL_LAST_ARRAY
; ++i
) {
247 struct bpil_array_desc
*desc
;
250 if ((info_linear
->arrays
& (1UL << i
)) == 0)
253 desc
= bpil_array_desc
+ i
;
254 offs
= bpf_prog_info_read_offset_u64(&info_linear
->info
,
256 addr
= offs
+ ptr_to_u64(info_linear
->data
);
257 bpf_prog_info_set_offset_u64(&info_linear
->info
,
258 desc
->array_offset
, addr
);