Skip to content

Commit f0187f0

Browse files
iamkafaiAlexei Starovoitov
authored andcommitted
bpf: libbpf: Refactor and bug fix on the bpf_func_info loading logic
This patch refactor and fix a bug in the libbpf's bpf_func_info loading logic. The bug fix and refactoring are targeting the same commit 2993e05 ("tools/bpf: add support to read .BTF.ext sections") which is in the bpf-next branch. 1) In bpf_load_program_xattr(), it should retry when errno == E2BIG regardless of log_buf and log_buf_sz. This patch fixes it. 2) btf_ext__reloc_init() and btf_ext__reloc() are essentially the same except btf_ext__reloc_init() always has insns_cnt == 0. Hence, btf_ext__reloc_init() is removed. btf_ext__reloc() is also renamed to btf_ext__reloc_func_info() to get ready for the line_info support in the next patch. 3) Consolidate func_info section logic from "btf_ext_parse_hdr()", "btf_ext_validate_func_info()" and "btf_ext__new()" to a new function "btf_ext_copy_func_info()" such that similar logic can be reused by the later libbpf's line_info patch. 4) The next line_info patch will store line_info_cnt instead of line_info_len in the bpf_program because the kernel is taking line_info_cnt also. It will save a few "len" to "cnt" conversions and will also save some function args. Hence, this patch also makes bpf_program to store func_info_cnt instead of func_info_len. 5) btf_ext depends on btf. e.g. the func_info's type_id in ".BTF.ext" is not useful when ".BTF" is absent. This patch only init the obj->btf_ext pointer after it has successfully init the obj->btf pointer. This can avoid always checking "obj->btf && obj->btf_ext" together for accessing ".BTF.ext". Checking "obj->btf_ext" alone will do. 6) Move "struct btf_sec_func_info" from btf.h to btf.c. There is no external usage outside btf.c. Fixes: 2993e05 ("tools/bpf: add support to read .BTF.ext sections") Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Yonghong Song <yhs@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 4d6304c commit f0187f0

File tree

4 files changed

+177
-177
lines changed

4 files changed

+177
-177
lines changed

tools/lib/bpf/bpf.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
205205
min(name_len, BPF_OBJ_NAME_LEN - 1));
206206

207207
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
208-
if (fd >= 0 || !log_buf || !log_buf_sz)
208+
if (fd >= 0)
209209
return fd;
210210

211211
/* After bpf_prog_load, the kernel may modify certain attributes
@@ -244,10 +244,13 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
244244

245245
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
246246

247-
if (fd >= 0 || !log_buf || !log_buf_sz)
247+
if (fd >= 0)
248248
goto done;
249249
}
250250

251+
if (!log_buf || !log_buf_sz)
252+
goto done;
253+
251254
/* Try again with log */
252255
attr.log_buf = ptr_to_u64(log_buf);
253256
attr.log_size = log_buf_sz;

tools/lib/bpf/btf.c

Lines changed: 73 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ struct btf_ext {
4343
__u32 func_info_len;
4444
};
4545

46+
struct btf_sec_func_info {
47+
__u32 sec_name_off;
48+
__u32 num_func_info;
49+
/* Followed by num_func_info number of bpf func_info records */
50+
__u8 data[0];
51+
};
52+
4653
/* The minimum bpf_func_info checked by the loader */
4754
struct bpf_func_info_min {
4855
__u32 insn_off;
@@ -479,41 +486,66 @@ int btf__get_from_id(__u32 id, struct btf **btf)
479486
return err;
480487
}
481488

482-
static int btf_ext_validate_func_info(const void *finfo, __u32 size,
483-
btf_print_fn_t err_log)
489+
static int btf_ext_copy_func_info(struct btf_ext *btf_ext,
490+
__u8 *data, __u32 data_size,
491+
btf_print_fn_t err_log)
484492
{
485-
int sec_hdrlen = sizeof(struct btf_sec_func_info);
486-
__u32 size_left, num_records, record_size;
493+
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
487494
const struct btf_sec_func_info *sinfo;
488-
__u64 total_record_size;
495+
__u32 info_left, record_size;
496+
/* The start of the info sec (including the __u32 record_size). */
497+
const void *info;
498+
499+
/* data and data_size do not include btf_ext_header from now on */
500+
data = data + hdr->hdr_len;
501+
data_size -= hdr->hdr_len;
502+
503+
if (hdr->func_info_off & 0x03) {
504+
elog("BTF.ext func_info section is not aligned to 4 bytes\n");
505+
return -EINVAL;
506+
}
507+
508+
if (data_size < hdr->func_info_off ||
509+
hdr->func_info_len > data_size - hdr->func_info_off) {
510+
elog("func_info section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
511+
hdr->func_info_off, hdr->func_info_len);
512+
return -EINVAL;
513+
}
514+
515+
info = data + hdr->func_info_off;
516+
info_left = hdr->func_info_len;
489517

490518
/* At least a func_info record size */
491-
if (size < sizeof(__u32)) {
519+
if (info_left < sizeof(__u32)) {
492520
elog("BTF.ext func_info record size not found");
493521
return -EINVAL;
494522
}
495523

496-
/* The record size needs to meet below minimum standard */
497-
record_size = *(__u32 *)finfo;
524+
/* The record size needs to meet the minimum standard */
525+
record_size = *(__u32 *)info;
498526
if (record_size < sizeof(struct bpf_func_info_min) ||
499-
record_size % sizeof(__u32)) {
527+
record_size & 0x03) {
500528
elog("BTF.ext func_info invalid record size");
501529
return -EINVAL;
502530
}
503531

504-
sinfo = finfo + sizeof(__u32);
505-
size_left = size - sizeof(__u32);
532+
sinfo = info + sizeof(__u32);
533+
info_left -= sizeof(__u32);
506534

507535
/* If no func_info records, return failure now so .BTF.ext
508536
* won't be used.
509537
*/
510-
if (!size_left) {
538+
if (!info_left) {
511539
elog("BTF.ext no func info records");
512540
return -EINVAL;
513541
}
514542

515-
while (size_left) {
516-
if (size_left < sec_hdrlen) {
543+
while (info_left) {
544+
unsigned int sec_hdrlen = sizeof(struct btf_sec_func_info);
545+
__u64 total_record_size;
546+
__u32 num_records;
547+
548+
if (info_left < sec_hdrlen) {
517549
elog("BTF.ext func_info header not found");
518550
return -EINVAL;
519551
}
@@ -526,24 +558,30 @@ static int btf_ext_validate_func_info(const void *finfo, __u32 size,
526558

527559
total_record_size = sec_hdrlen +
528560
(__u64)num_records * record_size;
529-
if (size_left < total_record_size) {
561+
if (info_left < total_record_size) {
530562
elog("incorrect BTF.ext num_func_info");
531563
return -EINVAL;
532564
}
533565

534-
size_left -= total_record_size;
566+
info_left -= total_record_size;
535567
sinfo = (void *)sinfo + total_record_size;
536568
}
537569

570+
btf_ext->func_info_len = hdr->func_info_len - sizeof(__u32);
571+
btf_ext->func_info_rec_size = record_size;
572+
btf_ext->func_info = malloc(btf_ext->func_info_len);
573+
if (!btf_ext->func_info)
574+
return -ENOMEM;
575+
memcpy(btf_ext->func_info, info + sizeof(__u32),
576+
btf_ext->func_info_len);
577+
538578
return 0;
539579
}
540580

541581
static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
542582
btf_print_fn_t err_log)
543583
{
544584
const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
545-
__u32 meta_left, last_func_info_pos;
546-
void *finfo;
547585

548586
if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
549587
data_size < hdr->hdr_len) {
@@ -566,34 +604,12 @@ static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
566604
return -ENOTSUP;
567605
}
568606

569-
meta_left = data_size - hdr->hdr_len;
570-
if (!meta_left) {
607+
if (data_size == hdr->hdr_len) {
571608
elog("BTF.ext has no data\n");
572609
return -EINVAL;
573610
}
574611

575-
if (meta_left < hdr->func_info_off) {
576-
elog("Invalid BTF.ext func_info section offset:%u\n",
577-
hdr->func_info_off);
578-
return -EINVAL;
579-
}
580-
581-
if (hdr->func_info_off & 0x03) {
582-
elog("BTF.ext func_info section is not aligned to 4 bytes\n");
583-
return -EINVAL;
584-
}
585-
586-
last_func_info_pos = hdr->hdr_len + hdr->func_info_off +
587-
hdr->func_info_len;
588-
if (last_func_info_pos > data_size) {
589-
elog("Invalid BTF.ext func_info section size:%u\n",
590-
hdr->func_info_len);
591-
return -EINVAL;
592-
}
593-
594-
finfo = data + hdr->hdr_len + hdr->func_info_off;
595-
return btf_ext_validate_func_info(finfo, hdr->func_info_len,
596-
err_log);
612+
return 0;
597613
}
598614

599615
void btf_ext__free(struct btf_ext *btf_ext)
@@ -607,10 +623,7 @@ void btf_ext__free(struct btf_ext *btf_ext)
607623

608624
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
609625
{
610-
const struct btf_ext_header *hdr;
611626
struct btf_ext *btf_ext;
612-
void *org_fdata, *fdata;
613-
__u32 hdrlen, size_u32;
614627
int err;
615628

616629
err = btf_ext_parse_hdr(data, size, err_log);
@@ -621,81 +634,18 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
621634
if (!btf_ext)
622635
return ERR_PTR(-ENOMEM);
623636

624-
hdr = (const struct btf_ext_header *)data;
625-
hdrlen = hdr->hdr_len;
626-
size_u32 = sizeof(__u32);
627-
fdata = malloc(hdr->func_info_len - size_u32);
628-
if (!fdata) {
629-
free(btf_ext);
630-
return ERR_PTR(-ENOMEM);
637+
err = btf_ext_copy_func_info(btf_ext, data, size, err_log);
638+
if (err) {
639+
btf_ext__free(btf_ext);
640+
return ERR_PTR(err);
631641
}
632642

633-
/* remember record size and copy rest of func_info data */
634-
org_fdata = data + hdrlen + hdr->func_info_off;
635-
btf_ext->func_info_rec_size = *(__u32 *)org_fdata;
636-
memcpy(fdata, org_fdata + size_u32, hdr->func_info_len - size_u32);
637-
btf_ext->func_info = fdata;
638-
btf_ext->func_info_len = hdr->func_info_len - size_u32;
639-
640643
return btf_ext;
641644
}
642645

643-
int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
644-
const char *sec_name, void **func_info,
645-
__u32 *func_info_rec_size, __u32 *func_info_len)
646-
{
647-
__u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
648-
__u32 i, record_size, records_len;
649-
struct btf_sec_func_info *sinfo;
650-
const char *info_sec_name;
651-
__s64 remain_len;
652-
void *data;
653-
654-
record_size = btf_ext->func_info_rec_size;
655-
sinfo = btf_ext->func_info;
656-
remain_len = btf_ext->func_info_len;
657-
658-
while (remain_len > 0) {
659-
records_len = sinfo->num_func_info * record_size;
660-
info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
661-
if (strcmp(info_sec_name, sec_name)) {
662-
remain_len -= sec_hdrlen + records_len;
663-
sinfo = (void *)sinfo + sec_hdrlen + records_len;
664-
continue;
665-
}
666-
667-
data = malloc(records_len);
668-
if (!data)
669-
return -ENOMEM;
670-
671-
memcpy(data, sinfo->data, records_len);
672-
673-
/* adjust the insn_off, the data in .BTF.ext is
674-
* the actual byte offset, and the kernel expects
675-
* the offset in term of bpf_insn.
676-
*
677-
* adjust the insn offset only, the rest data will
678-
* be passed to kernel.
679-
*/
680-
for (i = 0; i < sinfo->num_func_info; i++) {
681-
struct bpf_func_info_min *record;
682-
683-
record = data + i * record_size;
684-
record->insn_off /= sizeof(struct bpf_insn);
685-
}
686-
687-
*func_info = data;
688-
*func_info_len = records_len;
689-
*func_info_rec_size = record_size;
690-
return 0;
691-
}
692-
693-
return -EINVAL;
694-
}
695-
696-
int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
697-
const char *sec_name, __u32 insns_cnt,
698-
void **func_info, __u32 *func_info_len)
646+
int btf_ext__reloc_func_info(struct btf *btf, struct btf_ext *btf_ext,
647+
const char *sec_name, __u32 insns_cnt,
648+
void **func_info, __u32 *cnt)
699649
{
700650
__u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
701651
__u32 i, record_size, existing_flen, records_len;
@@ -716,7 +666,7 @@ int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
716666
continue;
717667
}
718668

719-
existing_flen = *func_info_len;
669+
existing_flen = (*cnt) * record_size;
720670
data = realloc(*func_info, existing_flen + records_len);
721671
if (!data)
722672
return -ENOMEM;
@@ -734,9 +684,14 @@ int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
734684
insns_cnt;
735685
}
736686
*func_info = data;
737-
*func_info_len = existing_flen + records_len;
687+
*cnt += sinfo->num_func_info;
738688
return 0;
739689
}
740690

741-
return -EINVAL;
691+
return -ENOENT;
692+
}
693+
694+
__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext)
695+
{
696+
return btf_ext->func_info_rec_size;
742697
}

tools/lib/bpf/btf.h

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,6 @@ struct btf_ext_header {
5353
__u32 func_info_len;
5454
};
5555

56-
struct btf_sec_func_info {
57-
__u32 sec_name_off;
58-
__u32 num_func_info;
59-
/* Followed by num_func_info number of bpf func_info records */
60-
__u8 data[0];
61-
};
62-
6356
typedef int (*btf_print_fn_t)(const char *, ...)
6457
__attribute__((format(printf, 1, 2)));
6558

@@ -77,12 +70,10 @@ LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);
7770

7871
struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
7972
void btf_ext__free(struct btf_ext *btf_ext);
80-
int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
81-
const char *sec_name, void **func_info,
82-
__u32 *func_info_rec_size, __u32 *func_info_len);
83-
int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
84-
const char *sec_name, __u32 insns_cnt, void **func_info,
85-
__u32 *func_info_len);
73+
int btf_ext__reloc_func_info(struct btf *btf, struct btf_ext *btf_ext,
74+
const char *sec_name, __u32 insns_cnt,
75+
void **func_info, __u32 *func_info_len);
76+
__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
8677

8778
#ifdef __cplusplus
8879
} /* extern "C" */

0 commit comments

Comments
 (0)