Skip to content

Commit 34be164

Browse files
liu-song-6acmel
authored andcommitted
tools lib bpf: Introduce bpf_program__get_prog_info_linear()
Currently, bpf_prog_info includes 9 arrays. The user has the option to fetch any combination of these arrays. However, this requires a lot of handling. This work becomes more tricky when we need to store bpf_prog_info to a file, because these arrays are allocated independently. This patch introduces 'struct bpf_prog_info_linear', which stores arrays of bpf_prog_info in continuous memory. Helper functions are introduced to unify the work to get different sets of bpf_prog_info. Specifically, bpf_program__get_prog_info_linear() allows the user to select which arrays to fetch, and handles details for the user. Please see the comments right before 'enum bpf_prog_info_array' for more details and examples. Signed-off-by: Song Liu <[email protected]> Reviewed-by: Jiri Olsa <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Tested-by: Arnaldo Carvalho de Melo <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: [email protected] Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stanislav Fomichev <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 71184c6 commit 34be164

File tree

3 files changed

+317
-0
lines changed

3 files changed

+317
-0
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
112112
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
113113
#endif
114114

115+
static inline __u64 ptr_to_u64(const void *ptr)
116+
{
117+
return (__u64) (unsigned long) ptr;
118+
}
119+
115120
struct bpf_capabilities {
116121
/* v4.14: kernel support for program & map names. */
117122
__u32 name:1;
@@ -2997,3 +3002,249 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
29973002
ring_buffer_write_tail(header, data_tail);
29983003
return ret;
29993004
}
3005+
3006+
struct bpf_prog_info_array_desc {
3007+
int array_offset; /* e.g. offset of jited_prog_insns */
3008+
int count_offset; /* e.g. offset of jited_prog_len */
3009+
int size_offset; /* > 0: offset of rec size,
3010+
* < 0: fix size of -size_offset
3011+
*/
3012+
};
3013+
3014+
static struct bpf_prog_info_array_desc bpf_prog_info_array_desc[] = {
3015+
[BPF_PROG_INFO_JITED_INSNS] = {
3016+
offsetof(struct bpf_prog_info, jited_prog_insns),
3017+
offsetof(struct bpf_prog_info, jited_prog_len),
3018+
-1,
3019+
},
3020+
[BPF_PROG_INFO_XLATED_INSNS] = {
3021+
offsetof(struct bpf_prog_info, xlated_prog_insns),
3022+
offsetof(struct bpf_prog_info, xlated_prog_len),
3023+
-1,
3024+
},
3025+
[BPF_PROG_INFO_MAP_IDS] = {
3026+
offsetof(struct bpf_prog_info, map_ids),
3027+
offsetof(struct bpf_prog_info, nr_map_ids),
3028+
-(int)sizeof(__u32),
3029+
},
3030+
[BPF_PROG_INFO_JITED_KSYMS] = {
3031+
offsetof(struct bpf_prog_info, jited_ksyms),
3032+
offsetof(struct bpf_prog_info, nr_jited_ksyms),
3033+
-(int)sizeof(__u64),
3034+
},
3035+
[BPF_PROG_INFO_JITED_FUNC_LENS] = {
3036+
offsetof(struct bpf_prog_info, jited_func_lens),
3037+
offsetof(struct bpf_prog_info, nr_jited_func_lens),
3038+
-(int)sizeof(__u32),
3039+
},
3040+
[BPF_PROG_INFO_FUNC_INFO] = {
3041+
offsetof(struct bpf_prog_info, func_info),
3042+
offsetof(struct bpf_prog_info, nr_func_info),
3043+
offsetof(struct bpf_prog_info, func_info_rec_size),
3044+
},
3045+
[BPF_PROG_INFO_LINE_INFO] = {
3046+
offsetof(struct bpf_prog_info, line_info),
3047+
offsetof(struct bpf_prog_info, nr_line_info),
3048+
offsetof(struct bpf_prog_info, line_info_rec_size),
3049+
},
3050+
[BPF_PROG_INFO_JITED_LINE_INFO] = {
3051+
offsetof(struct bpf_prog_info, jited_line_info),
3052+
offsetof(struct bpf_prog_info, nr_jited_line_info),
3053+
offsetof(struct bpf_prog_info, jited_line_info_rec_size),
3054+
},
3055+
[BPF_PROG_INFO_PROG_TAGS] = {
3056+
offsetof(struct bpf_prog_info, prog_tags),
3057+
offsetof(struct bpf_prog_info, nr_prog_tags),
3058+
-(int)sizeof(__u8) * BPF_TAG_SIZE,
3059+
},
3060+
3061+
};
3062+
3063+
static __u32 bpf_prog_info_read_offset_u32(struct bpf_prog_info *info, int offset)
3064+
{
3065+
__u32 *array = (__u32 *)info;
3066+
3067+
if (offset >= 0)
3068+
return array[offset / sizeof(__u32)];
3069+
return -(int)offset;
3070+
}
3071+
3072+
static __u64 bpf_prog_info_read_offset_u64(struct bpf_prog_info *info, int offset)
3073+
{
3074+
__u64 *array = (__u64 *)info;
3075+
3076+
if (offset >= 0)
3077+
return array[offset / sizeof(__u64)];
3078+
return -(int)offset;
3079+
}
3080+
3081+
static void bpf_prog_info_set_offset_u32(struct bpf_prog_info *info, int offset,
3082+
__u32 val)
3083+
{
3084+
__u32 *array = (__u32 *)info;
3085+
3086+
if (offset >= 0)
3087+
array[offset / sizeof(__u32)] = val;
3088+
}
3089+
3090+
static void bpf_prog_info_set_offset_u64(struct bpf_prog_info *info, int offset,
3091+
__u64 val)
3092+
{
3093+
__u64 *array = (__u64 *)info;
3094+
3095+
if (offset >= 0)
3096+
array[offset / sizeof(__u64)] = val;
3097+
}
3098+
3099+
struct bpf_prog_info_linear *
3100+
bpf_program__get_prog_info_linear(int fd, __u64 arrays)
3101+
{
3102+
struct bpf_prog_info_linear *info_linear;
3103+
struct bpf_prog_info info = {};
3104+
__u32 info_len = sizeof(info);
3105+
__u32 data_len = 0;
3106+
int i, err;
3107+
void *ptr;
3108+
3109+
if (arrays >> BPF_PROG_INFO_LAST_ARRAY)
3110+
return ERR_PTR(-EINVAL);
3111+
3112+
/* step 1: get array dimensions */
3113+
err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
3114+
if (err) {
3115+
pr_debug("can't get prog info: %s", strerror(errno));
3116+
return ERR_PTR(-EFAULT);
3117+
}
3118+
3119+
/* step 2: calculate total size of all arrays */
3120+
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
3121+
bool include_array = (arrays & (1UL << i)) > 0;
3122+
struct bpf_prog_info_array_desc *desc;
3123+
__u32 count, size;
3124+
3125+
desc = bpf_prog_info_array_desc + i;
3126+
3127+
/* kernel is too old to support this field */
3128+
if (info_len < desc->array_offset + sizeof(__u32) ||
3129+
info_len < desc->count_offset + sizeof(__u32) ||
3130+
(desc->size_offset > 0 && info_len < desc->size_offset))
3131+
include_array = false;
3132+
3133+
if (!include_array) {
3134+
arrays &= ~(1UL << i); /* clear the bit */
3135+
continue;
3136+
}
3137+
3138+
count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
3139+
size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
3140+
3141+
data_len += count * size;
3142+
}
3143+
3144+
/* step 3: allocate continuous memory */
3145+
data_len = roundup(data_len, sizeof(__u64));
3146+
info_linear = malloc(sizeof(struct bpf_prog_info_linear) + data_len);
3147+
if (!info_linear)
3148+
return ERR_PTR(-ENOMEM);
3149+
3150+
/* step 4: fill data to info_linear->info */
3151+
info_linear->arrays = arrays;
3152+
memset(&info_linear->info, 0, sizeof(info));
3153+
ptr = info_linear->data;
3154+
3155+
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
3156+
struct bpf_prog_info_array_desc *desc;
3157+
__u32 count, size;
3158+
3159+
if ((arrays & (1UL << i)) == 0)
3160+
continue;
3161+
3162+
desc = bpf_prog_info_array_desc + i;
3163+
count = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
3164+
size = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
3165+
bpf_prog_info_set_offset_u32(&info_linear->info,
3166+
desc->count_offset, count);
3167+
bpf_prog_info_set_offset_u32(&info_linear->info,
3168+
desc->size_offset, size);
3169+
bpf_prog_info_set_offset_u64(&info_linear->info,
3170+
desc->array_offset,
3171+
ptr_to_u64(ptr));
3172+
ptr += count * size;
3173+
}
3174+
3175+
/* step 5: call syscall again to get required arrays */
3176+
err = bpf_obj_get_info_by_fd(fd, &info_linear->info, &info_len);
3177+
if (err) {
3178+
pr_debug("can't get prog info: %s", strerror(errno));
3179+
free(info_linear);
3180+
return ERR_PTR(-EFAULT);
3181+
}
3182+
3183+
/* step 6: verify the data */
3184+
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
3185+
struct bpf_prog_info_array_desc *desc;
3186+
__u32 v1, v2;
3187+
3188+
if ((arrays & (1UL << i)) == 0)
3189+
continue;
3190+
3191+
desc = bpf_prog_info_array_desc + i;
3192+
v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
3193+
v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
3194+
desc->count_offset);
3195+
if (v1 != v2)
3196+
pr_warning("%s: mismatch in element count\n", __func__);
3197+
3198+
v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
3199+
v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
3200+
desc->size_offset);
3201+
if (v1 != v2)
3202+
pr_warning("%s: mismatch in rec size\n", __func__);
3203+
}
3204+
3205+
/* step 7: update info_len and data_len */
3206+
info_linear->info_len = sizeof(struct bpf_prog_info);
3207+
info_linear->data_len = data_len;
3208+
3209+
return info_linear;
3210+
}
3211+
3212+
void bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear)
3213+
{
3214+
int i;
3215+
3216+
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
3217+
struct bpf_prog_info_array_desc *desc;
3218+
__u64 addr, offs;
3219+
3220+
if ((info_linear->arrays & (1UL << i)) == 0)
3221+
continue;
3222+
3223+
desc = bpf_prog_info_array_desc + i;
3224+
addr = bpf_prog_info_read_offset_u64(&info_linear->info,
3225+
desc->array_offset);
3226+
offs = addr - ptr_to_u64(info_linear->data);
3227+
bpf_prog_info_set_offset_u64(&info_linear->info,
3228+
desc->array_offset, offs);
3229+
}
3230+
}
3231+
3232+
void bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear)
3233+
{
3234+
int i;
3235+
3236+
for (i = BPF_PROG_INFO_FIRST_ARRAY; i < BPF_PROG_INFO_LAST_ARRAY; ++i) {
3237+
struct bpf_prog_info_array_desc *desc;
3238+
__u64 addr, offs;
3239+
3240+
if ((info_linear->arrays & (1UL << i)) == 0)
3241+
continue;
3242+
3243+
desc = bpf_prog_info_array_desc + i;
3244+
offs = bpf_prog_info_read_offset_u64(&info_linear->info,
3245+
desc->array_offset);
3246+
addr = offs + ptr_to_u64(info_linear->data);
3247+
bpf_prog_info_set_offset_u64(&info_linear->info,
3248+
desc->array_offset, addr);
3249+
}
3250+
}

tools/lib/bpf/libbpf.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,69 @@ LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
378378
LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
379379
enum bpf_prog_type prog_type, __u32 ifindex);
380380

381+
/*
382+
* Get bpf_prog_info in continuous memory
383+
*
384+
* struct bpf_prog_info has multiple arrays. The user has option to choose
385+
* arrays to fetch from kernel. The following APIs provide an uniform way to
386+
* fetch these data. All arrays in bpf_prog_info are stored in a single
387+
* continuous memory region. This makes it easy to store the info in a
388+
* file.
389+
*
390+
* Before writing bpf_prog_info_linear to files, it is necessary to
391+
* translate pointers in bpf_prog_info to offsets. Helper functions
392+
* bpf_program__bpil_addr_to_offs() and bpf_program__bpil_offs_to_addr()
393+
* are introduced to switch between pointers and offsets.
394+
*
395+
* Examples:
396+
* # To fetch map_ids and prog_tags:
397+
* __u64 arrays = (1UL << BPF_PROG_INFO_MAP_IDS) |
398+
* (1UL << BPF_PROG_INFO_PROG_TAGS);
399+
* struct bpf_prog_info_linear *info_linear =
400+
* bpf_program__get_prog_info_linear(fd, arrays);
401+
*
402+
* # To save data in file
403+
* bpf_program__bpil_addr_to_offs(info_linear);
404+
* write(f, info_linear, sizeof(*info_linear) + info_linear->data_len);
405+
*
406+
* # To read data from file
407+
* read(f, info_linear, <proper_size>);
408+
* bpf_program__bpil_offs_to_addr(info_linear);
409+
*/
410+
enum bpf_prog_info_array {
411+
BPF_PROG_INFO_FIRST_ARRAY = 0,
412+
BPF_PROG_INFO_JITED_INSNS = 0,
413+
BPF_PROG_INFO_XLATED_INSNS,
414+
BPF_PROG_INFO_MAP_IDS,
415+
BPF_PROG_INFO_JITED_KSYMS,
416+
BPF_PROG_INFO_JITED_FUNC_LENS,
417+
BPF_PROG_INFO_FUNC_INFO,
418+
BPF_PROG_INFO_LINE_INFO,
419+
BPF_PROG_INFO_JITED_LINE_INFO,
420+
BPF_PROG_INFO_PROG_TAGS,
421+
BPF_PROG_INFO_LAST_ARRAY,
422+
};
423+
424+
struct bpf_prog_info_linear {
425+
/* size of struct bpf_prog_info, when the tool is compiled */
426+
__u32 info_len;
427+
/* total bytes allocated for data, round up to 8 bytes */
428+
__u32 data_len;
429+
/* which arrays are included in data */
430+
__u64 arrays;
431+
struct bpf_prog_info info;
432+
__u8 data[];
433+
};
434+
435+
LIBBPF_API struct bpf_prog_info_linear *
436+
bpf_program__get_prog_info_linear(int fd, __u64 arrays);
437+
438+
LIBBPF_API void
439+
bpf_program__bpil_addr_to_offs(struct bpf_prog_info_linear *info_linear);
440+
441+
LIBBPF_API void
442+
bpf_program__bpil_offs_to_addr(struct bpf_prog_info_linear *info_linear);
443+
381444
#ifdef __cplusplus
382445
} /* extern "C" */
383446
#endif

tools/lib/bpf/libbpf.map

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,4 +153,7 @@ LIBBPF_0.0.2 {
153153
xsk_socket__delete;
154154
xsk_umem__fd;
155155
xsk_socket__fd;
156+
bpf_program__get_prog_info_linear;
157+
bpf_program__bpil_addr_to_offs;
158+
bpf_program__bpil_offs_to_addr;
156159
} LIBBPF_0.0.1;

0 commit comments

Comments
 (0)