0001
0002
0003 #ifndef _GNU_SOURCE
0004 #define _GNU_SOURCE
0005 #endif
0006
0007 #include <errno.h>
0008 #include <stdlib.h>
0009 #include <linux/err.h>
0010 #include <linux/kernel.h>
0011 #include <bpf/bpf.h>
0012 #include "bpf-utils.h"
0013 #include "debug.h"
0014
0015 struct bpil_array_desc {
0016 int array_offset;
0017 int count_offset;
0018 int size_offset;
0019
0020
0021 };
0022
0023 static struct bpil_array_desc bpil_array_desc[] = {
0024 [PERF_BPIL_JITED_INSNS] = {
0025 offsetof(struct bpf_prog_info, jited_prog_insns),
0026 offsetof(struct bpf_prog_info, jited_prog_len),
0027 -1,
0028 },
0029 [PERF_BPIL_XLATED_INSNS] = {
0030 offsetof(struct bpf_prog_info, xlated_prog_insns),
0031 offsetof(struct bpf_prog_info, xlated_prog_len),
0032 -1,
0033 },
0034 [PERF_BPIL_MAP_IDS] = {
0035 offsetof(struct bpf_prog_info, map_ids),
0036 offsetof(struct bpf_prog_info, nr_map_ids),
0037 -(int)sizeof(__u32),
0038 },
0039 [PERF_BPIL_JITED_KSYMS] = {
0040 offsetof(struct bpf_prog_info, jited_ksyms),
0041 offsetof(struct bpf_prog_info, nr_jited_ksyms),
0042 -(int)sizeof(__u64),
0043 },
0044 [PERF_BPIL_JITED_FUNC_LENS] = {
0045 offsetof(struct bpf_prog_info, jited_func_lens),
0046 offsetof(struct bpf_prog_info, nr_jited_func_lens),
0047 -(int)sizeof(__u32),
0048 },
0049 [PERF_BPIL_FUNC_INFO] = {
0050 offsetof(struct bpf_prog_info, func_info),
0051 offsetof(struct bpf_prog_info, nr_func_info),
0052 offsetof(struct bpf_prog_info, func_info_rec_size),
0053 },
0054 [PERF_BPIL_LINE_INFO] = {
0055 offsetof(struct bpf_prog_info, line_info),
0056 offsetof(struct bpf_prog_info, nr_line_info),
0057 offsetof(struct bpf_prog_info, line_info_rec_size),
0058 },
0059 [PERF_BPIL_JITED_LINE_INFO] = {
0060 offsetof(struct bpf_prog_info, jited_line_info),
0061 offsetof(struct bpf_prog_info, nr_jited_line_info),
0062 offsetof(struct bpf_prog_info, jited_line_info_rec_size),
0063 },
0064 [PERF_BPIL_PROG_TAGS] = {
0065 offsetof(struct bpf_prog_info, prog_tags),
0066 offsetof(struct bpf_prog_info, nr_prog_tags),
0067 -(int)sizeof(__u8) * BPF_TAG_SIZE,
0068 },
0069
0070 };
0071
0072 static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info,
0073 int offset)
0074 {
0075 __u32 *array = (__u32 *)info;
0076
0077 if (offset >= 0)
0078 return array[offset / sizeof(__u32)];
0079 return -(int)offset;
0080 }
0081
0082 static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info,
0083 int offset)
0084 {
0085 __u64 *array = (__u64 *)info;
0086
0087 if (offset >= 0)
0088 return array[offset / sizeof(__u64)];
0089 return -(int)offset;
0090 }
0091
0092 static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
0093 __u32 val)
0094 {
0095 __u32 *array = (__u32 *)info;
0096
0097 if (offset >= 0)
0098 array[offset / sizeof(__u32)] = val;
0099 }
0100
0101 static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
0102 __u64 val)
0103 {
0104 __u64 *array = (__u64 *)info;
0105
0106 if (offset >= 0)
0107 array[offset / sizeof(__u64)] = val;
0108 }
0109
0110 struct perf_bpil *
0111 get_bpf_prog_info_linear(int fd, __u64 arrays)
0112 {
0113 struct bpf_prog_info info = {};
0114 struct perf_bpil *info_linear;
0115 __u32 info_len = sizeof(info);
0116 __u32 data_len = 0;
0117 int i, err;
0118 void *ptr;
0119
0120 if (arrays >> PERF_BPIL_LAST_ARRAY)
0121 return ERR_PTR(-EINVAL);
0122
0123
0124 err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
0125 if (err) {
0126 pr_debug("can't get prog info: %s", strerror(errno));
0127 return ERR_PTR(-EFAULT);
0128 }
0129
0130
0131 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
0132 bool include_array = (arrays & (1UL << i)) > 0;
0133 struct bpil_array_desc *desc;
0134 __u32 count, size;
0135
0136 desc = bpil_array_desc + i;
0137
0138
0139 if (info_len < desc->array_offset + sizeof(__u32) ||
0140 info_len < desc->count_offset + sizeof(__u32) ||
0141 (desc->size_offset > 0 && info_len < (__u32)desc->size_offset))
0142 include_array = false;
0143
0144 if (!include_array) {
0145 arrays &= ~(1UL << i);
0146 continue;
0147 }
0148
0149 count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
0150 size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
0151
0152 data_len += roundup(count * size, sizeof(__u64));
0153 }
0154
0155
0156 info_linear = malloc(sizeof(struct perf_bpil) + data_len);
0157 if (!info_linear)
0158 return ERR_PTR(-ENOMEM);
0159
0160
0161 info_linear->arrays = arrays;
0162 memset(&info_linear->info, 0, sizeof(info));
0163 ptr = info_linear->data;
0164
0165 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
0166 struct bpil_array_desc *desc;
0167 __u32 count, size;
0168
0169 if ((arrays & (1UL << i)) == 0)
0170 continue;
0171
0172 desc = bpil_array_desc + i;
0173 count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
0174 size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
0175 bpf_prog_info_set_offset_u32(&info_linear->info,
0176 desc->count_offset, count);
0177 bpf_prog_info_set_offset_u32(&info_linear->info,
0178 desc->size_offset, size);
0179 bpf_prog_info_set_offset_u64(&info_linear->info,
0180 desc->array_offset,
0181 ptr_to_u64(ptr));
0182 ptr += roundup(count * size, sizeof(__u64));
0183 }
0184
0185
0186 err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
0187 if (err) {
0188 pr_debug("can't get prog info: %s", strerror(errno));
0189 free(info_linear);
0190 return ERR_PTR(-EFAULT);
0191 }
0192
0193
0194 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
0195 struct bpil_array_desc *desc;
0196 __u32 v1, v2;
0197
0198 if ((arrays & (1UL << i)) == 0)
0199 continue;
0200
0201 desc = bpil_array_desc + i;
0202 v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
0203 v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
0204 desc->count_offset);
0205 if (v1 != v2)
0206 pr_warning("%s: mismatch in element count\n", __func__);
0207
0208 v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
0209 v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
0210 desc->size_offset);
0211 if (v1 != v2)
0212 pr_warning("%s: mismatch in rec size\n", __func__);
0213 }
0214
0215
0216 info_linear->info_len = sizeof(struct bpf_prog_info);
0217 info_linear->data_len = data_len;
0218
0219 return info_linear;
0220 }
0221
0222 void bpil_addr_to_offs(struct perf_bpil *info_linear)
0223 {
0224 int i;
0225
0226 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
0227 struct bpil_array_desc *desc;
0228 __u64 addr, offs;
0229
0230 if ((info_linear->arrays & (1UL << i)) == 0)
0231 continue;
0232
0233 desc = bpil_array_desc + i;
0234 addr = bpf_prog_info_read_offset_u64(&info_linear->info,
0235 desc->array_offset);
0236 offs = addr - ptr_to_u64(info_linear->data);
0237 bpf_prog_info_set_offset_u64(&info_linear->info,
0238 desc->array_offset, offs);
0239 }
0240 }
0241
0242 void bpil_offs_to_addr(struct perf_bpil *info_linear)
0243 {
0244 int i;
0245
0246 for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
0247 struct bpil_array_desc *desc;
0248 __u64 addr, offs;
0249
0250 if ((info_linear->arrays & (1UL << i)) == 0)
0251 continue;
0252
0253 desc = bpil_array_desc + i;
0254 offs = bpf_prog_info_read_offset_u64(&info_linear->info,
0255 desc->array_offset);
0256 addr = offs + ptr_to_u64(info_linear->data);
0257 bpf_prog_info_set_offset_u64(&info_linear->info,
0258 desc->array_offset, addr);
0259 }
0260 }