Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: Generalize BTF and BTF.ext type ID and strings iteration

Extract and generalize the logic to iterate BTF type ID and string offset
fields within BTF types and .BTF.ext data. Expose this internally in libbpf
for re-use by bpf_linker.

Additionally, complete strings deduplication handling for BTF.ext (e.g., CO-RE
access strings), which was previously missing. There previously was no
case of deduplicating .BTF.ext data, but bpf_linker is going to use it.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20210318194036.3521577-3-andrii@kernel.org

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
f36e99a4 e14ef4bf

+230 -174
+223 -174
tools/lib/bpf/btf.c
··· 3155 3155 return d; 3156 3156 } 3157 3157 3158 - typedef int (*str_off_fn_t)(__u32 *str_off_ptr, void *ctx); 3159 - 3160 3158 /* 3161 3159 * Iterate over all possible places in .BTF and .BTF.ext that can reference 3162 3160 * string and pass pointer to it to a provided callback `fn`. 3163 3161 */ 3164 - static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx) 3162 + static int btf_for_each_str_off(struct btf_dedup *d, str_off_visit_fn fn, void *ctx) 3165 3163 { 3166 - void *line_data_cur, *line_data_end; 3167 - int i, j, r, rec_size; 3168 - struct btf_type *t; 3164 + int i, r; 3169 3165 3170 3166 for (i = 0; i < d->btf->nr_types; i++) { 3171 - t = btf_type_by_id(d->btf, d->btf->start_id + i); 3172 - r = fn(&t->name_off, ctx); 3167 + struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i); 3168 + 3169 + r = btf_type_visit_str_offs(t, fn, ctx); 3173 3170 if (r) 3174 3171 return r; 3175 - 3176 - switch (btf_kind(t)) { 3177 - case BTF_KIND_STRUCT: 3178 - case BTF_KIND_UNION: { 3179 - struct btf_member *m = btf_members(t); 3180 - __u16 vlen = btf_vlen(t); 3181 - 3182 - for (j = 0; j < vlen; j++) { 3183 - r = fn(&m->name_off, ctx); 3184 - if (r) 3185 - return r; 3186 - m++; 3187 - } 3188 - break; 3189 - } 3190 - case BTF_KIND_ENUM: { 3191 - struct btf_enum *m = btf_enum(t); 3192 - __u16 vlen = btf_vlen(t); 3193 - 3194 - for (j = 0; j < vlen; j++) { 3195 - r = fn(&m->name_off, ctx); 3196 - if (r) 3197 - return r; 3198 - m++; 3199 - } 3200 - break; 3201 - } 3202 - case BTF_KIND_FUNC_PROTO: { 3203 - struct btf_param *m = btf_params(t); 3204 - __u16 vlen = btf_vlen(t); 3205 - 3206 - for (j = 0; j < vlen; j++) { 3207 - r = fn(&m->name_off, ctx); 3208 - if (r) 3209 - return r; 3210 - m++; 3211 - } 3212 - break; 3213 - } 3214 - default: 3215 - break; 3216 - } 3217 3172 } 3218 3173 3219 3174 if (!d->btf_ext) 3220 3175 return 0; 3221 3176 3222 - line_data_cur = d->btf_ext->line_info.info; 3223 - line_data_end = d->btf_ext->line_info.info + d->btf_ext->line_info.len; 3224 - rec_size = d->btf_ext->line_info.rec_size; 3225 - 3226 - while (line_data_cur < line_data_end) { 3227 - struct btf_ext_info_sec *sec = line_data_cur; 3228 - struct bpf_line_info_min *line_info; 3229 - __u32 num_info = sec->num_info; 3230 - 3231 - r = fn(&sec->sec_name_off, ctx); 3232 - if (r) 3233 - return r; 3234 - 3235 - line_data_cur += sizeof(struct btf_ext_info_sec); 3236 - for (i = 0; i < num_info; i++) { 3237 - line_info = line_data_cur; 3238 - r = fn(&line_info->file_name_off, ctx); 3239 - if (r) 3240 - return r; 3241 - r = fn(&line_info->line_off, ctx); 3242 - if (r) 3243 - return r; 3244 - line_data_cur += rec_size; 3245 - } 3246 - } 3177 + r = btf_ext_visit_str_offs(d->btf_ext, fn, ctx); 3178 + if (r) 3179 + return r; 3247 3180 3248 3181 return 0; 3249 3182 } ··· 4431 4498 * then mapping it to a deduplicated type ID, stored in btf_dedup->hypot_map, 4432 4499 * which is populated during compaction phase. 4433 4500 */ 4434 - static int btf_dedup_remap_type_id(struct btf_dedup *d, __u32 type_id) 4501 + static int btf_dedup_remap_type_id(__u32 *type_id, void *ctx) 4435 4502 { 4503 + struct btf_dedup *d = ctx; 4436 4504 __u32 resolved_type_id, new_type_id; 4437 4505 4438 - resolved_type_id = resolve_type_id(d, type_id); 4506 + resolved_type_id = resolve_type_id(d, *type_id); 4439 4507 new_type_id = d->hypot_map[resolved_type_id]; 4440 4508 if (new_type_id > BTF_MAX_NR_TYPES) 4441 4509 return -EINVAL; 4442 - return new_type_id; 4510 + 4511 + *type_id = new_type_id; 4512 + return 0; 4443 4513 } 4444 4514 4445 4515 /* ··· 4455 4519 * referenced from any BTF type (e.g., struct fields, func proto args, etc) to 4456 4520 * their final deduped type IDs. 4457 4521 */ 4458 - static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id) 4459 - { 4460 - struct btf_type *t = btf_type_by_id(d->btf, type_id); 4461 - int i, r; 4462 - 4463 - switch (btf_kind(t)) { 4464 - case BTF_KIND_INT: 4465 - case BTF_KIND_ENUM: 4466 - case BTF_KIND_FLOAT: 4467 - break; 4468 - 4469 - case BTF_KIND_FWD: 4470 - case BTF_KIND_CONST: 4471 - case BTF_KIND_VOLATILE: 4472 - case BTF_KIND_RESTRICT: 4473 - case BTF_KIND_PTR: 4474 - case BTF_KIND_TYPEDEF: 4475 - case BTF_KIND_FUNC: 4476 - case BTF_KIND_VAR: 4477 - r = btf_dedup_remap_type_id(d, t->type); 4478 - if (r < 0) 4479 - return r; 4480 - t->type = r; 4481 - break; 4482 - 4483 - case BTF_KIND_ARRAY: { 4484 - struct btf_array *arr_info = btf_array(t); 4485 - 4486 - r = btf_dedup_remap_type_id(d, arr_info->type); 4487 - if (r < 0) 4488 - return r; 4489 - arr_info->type = r; 4490 - r = btf_dedup_remap_type_id(d, arr_info->index_type); 4491 - if (r < 0) 4492 - return r; 4493 - arr_info->index_type = r; 4494 - break; 4495 - } 4496 - 4497 - case BTF_KIND_STRUCT: 4498 - case BTF_KIND_UNION: { 4499 - struct btf_member *member = btf_members(t); 4500 - __u16 vlen = btf_vlen(t); 4501 - 4502 - for (i = 0; i < vlen; i++) { 4503 - r = btf_dedup_remap_type_id(d, member->type); 4504 - if (r < 0) 4505 - return r; 4506 - member->type = r; 4507 - member++; 4508 - } 4509 - break; 4510 - } 4511 - 4512 - case BTF_KIND_FUNC_PROTO: { 4513 - struct btf_param *param = btf_params(t); 4514 - __u16 vlen = btf_vlen(t); 4515 - 4516 - r = btf_dedup_remap_type_id(d, t->type); 4517 - if (r < 0) 4518 - return r; 4519 - t->type = r; 4520 - 4521 - for (i = 0; i < vlen; i++) { 4522 - r = btf_dedup_remap_type_id(d, param->type); 4523 - if (r < 0) 4524 - return r; 4525 - param->type = r; 4526 - param++; 4527 - } 4528 - break; 4529 - } 4530 - 4531 - case BTF_KIND_DATASEC: { 4532 - struct btf_var_secinfo *var = btf_var_secinfos(t); 4533 - __u16 vlen = btf_vlen(t); 4534 - 4535 - for (i = 0; i < vlen; i++) { 4536 - r = btf_dedup_remap_type_id(d, var->type); 4537 - if (r < 0) 4538 - return r; 4539 - var->type = r; 4540 - var++; 4541 - } 4542 - break; 4543 - } 4544 - 4545 - default: 4546 - return -EINVAL; 4547 - } 4548 - 4549 - return 0; 4550 - } 4551 - 4552 4522 static int btf_dedup_remap_types(struct btf_dedup *d) 4553 4523 { 4554 4524 int i, r; 4555 4525 4556 4526 for (i = 0; i < d->btf->nr_types; i++) { 4557 - r = btf_dedup_remap_type(d, d->btf->start_id + i); 4558 - if (r < 0) 4527 + struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i); 4528 + 4529 + r = btf_type_visit_type_ids(t, btf_dedup_remap_type_id, d); 4530 + if (r) 4559 4531 return r; 4560 4532 } 4533 + 4534 + if (!d->btf_ext) 4535 + return 0; 4536 + 4537 + r = btf_ext_visit_type_ids(d->btf_ext, btf_dedup_remap_type_id, d); 4538 + if (r) 4539 + return r; 4540 + 4561 4541 return 0; 4562 4542 } 4563 4543 ··· 4526 4674 4527 4675 pr_warn("failed to find valid kernel BTF\n"); 4528 4676 return ERR_PTR(-ESRCH); 4677 + } 4678 + 4679 + int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx) 4680 + { 4681 + int i, n, err; 4682 + 4683 + switch (btf_kind(t)) { 4684 + case BTF_KIND_INT: 4685 + case BTF_KIND_FLOAT: 4686 + case BTF_KIND_ENUM: 4687 + return 0; 4688 + 4689 + case BTF_KIND_FWD: 4690 + case BTF_KIND_CONST: 4691 + case BTF_KIND_VOLATILE: 4692 + case BTF_KIND_RESTRICT: 4693 + case BTF_KIND_PTR: 4694 + case BTF_KIND_TYPEDEF: 4695 + case BTF_KIND_FUNC: 4696 + case BTF_KIND_VAR: 4697 + return visit(&t->type, ctx); 4698 + 4699 + case BTF_KIND_ARRAY: { 4700 + struct btf_array *a = btf_array(t); 4701 + 4702 + err = visit(&a->type, ctx); 4703 + err = err ?: visit(&a->index_type, ctx); 4704 + return err; 4705 + } 4706 + 4707 + case BTF_KIND_STRUCT: 4708 + case BTF_KIND_UNION: { 4709 + struct btf_member *m = btf_members(t); 4710 + 4711 + for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4712 + err = visit(&m->type, ctx); 4713 + if (err) 4714 + return err; 4715 + } 4716 + return 0; 4717 + } 4718 + 4719 + case BTF_KIND_FUNC_PROTO: { 4720 + struct btf_param *m = btf_params(t); 4721 + 4722 + err = visit(&t->type, ctx); 4723 + if (err) 4724 + return err; 4725 + for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4726 + err = visit(&m->type, ctx); 4727 + if (err) 4728 + return err; 4729 + } 4730 + return 0; 4731 + } 4732 + 4733 + case BTF_KIND_DATASEC: { 4734 + struct btf_var_secinfo *m = btf_var_secinfos(t); 4735 + 4736 + for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4737 + err = visit(&m->type, ctx); 4738 + if (err) 4739 + return err; 4740 + } 4741 + return 0; 4742 + } 4743 + 4744 + default: 4745 + return -EINVAL; 4746 + } 4747 + } 4748 + 4749 + int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx) 4750 + { 4751 + int i, n, err; 4752 + 4753 + err = visit(&t->name_off, ctx); 4754 + if (err) 4755 + return err; 4756 + 4757 + switch (btf_kind(t)) { 4758 + case BTF_KIND_STRUCT: 4759 + case BTF_KIND_UNION: { 4760 + struct btf_member *m = btf_members(t); 4761 + 4762 + for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4763 + err = visit(&m->name_off, ctx); 4764 + if (err) 4765 + return err; 4766 + } 4767 + break; 4768 + } 4769 + case BTF_KIND_ENUM: { 4770 + struct btf_enum *m = btf_enum(t); 4771 + 4772 + for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4773 + err = visit(&m->name_off, ctx); 4774 + if (err) 4775 + return err; 4776 + } 4777 + break; 4778 + } 4779 + case BTF_KIND_FUNC_PROTO: { 4780 + struct btf_param *m = btf_params(t); 4781 + 4782 + for (i = 0, n = btf_vlen(t); i < n; i++, m++) { 4783 + err = visit(&m->name_off, ctx); 4784 + if (err) 4785 + return err; 4786 + } 4787 + break; 4788 + } 4789 + default: 4790 + break; 4791 + } 4792 + 4793 + return 0; 4794 + } 4795 + 4796 + int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx) 4797 + { 4798 + const struct btf_ext_info *seg; 4799 + struct btf_ext_info_sec *sec; 4800 + int i, err; 4801 + 4802 + seg = &btf_ext->func_info; 4803 + for_each_btf_ext_sec(seg, sec) { 4804 + struct bpf_func_info_min *rec; 4805 + 4806 + for_each_btf_ext_rec(seg, sec, i, rec) { 4807 + err = visit(&rec->type_id, ctx); 4808 + if (err < 0) 4809 + return err; 4810 + } 4811 + } 4812 + 4813 + seg = &btf_ext->core_relo_info; 4814 + for_each_btf_ext_sec(seg, sec) { 4815 + struct bpf_core_relo *rec; 4816 + 4817 + for_each_btf_ext_rec(seg, sec, i, rec) { 4818 + err = visit(&rec->type_id, ctx); 4819 + if (err < 0) 4820 + return err; 4821 + } 4822 + } 4823 + 4824 + return 0; 4825 + } 4826 + 4827 + int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx) 4828 + { 4829 + const struct btf_ext_info *seg; 4830 + struct btf_ext_info_sec *sec; 4831 + int i, err; 4832 + 4833 + seg = &btf_ext->func_info; 4834 + for_each_btf_ext_sec(seg, sec) { 4835 + err = visit(&sec->sec_name_off, ctx); 4836 + if (err) 4837 + return err; 4838 + } 4839 + 4840 + seg = &btf_ext->line_info; 4841 + for_each_btf_ext_sec(seg, sec) { 4842 + struct bpf_line_info_min *rec; 4843 + 4844 + err = visit(&sec->sec_name_off, ctx); 4845 + if (err) 4846 + return err; 4847 + 4848 + for_each_btf_ext_rec(seg, sec, i, rec) { 4849 + err = visit(&rec->file_name_off, ctx); 4850 + if (err) 4851 + return err; 4852 + err = visit(&rec->line_off, ctx); 4853 + if (err) 4854 + return err; 4855 + } 4856 + } 4857 + 4858 + seg = &btf_ext->core_relo_info; 4859 + for_each_btf_ext_sec(seg, sec) { 4860 + struct bpf_core_relo *rec; 4861 + 4862 + err = visit(&sec->sec_name_off, ctx); 4863 + if (err) 4864 + return err; 4865 + 4866 + for_each_btf_ext_rec(seg, sec, i, rec) { 4867 + err = visit(&rec->access_str_off, ctx); 4868 + if (err) 4869 + return err; 4870 + } 4871 + } 4872 + 4873 + return 0; 4529 4874 }
+7
tools/lib/bpf/libbpf_internal.h
··· 356 356 enum bpf_core_relo_kind kind; 357 357 }; 358 358 359 + typedef int (*type_id_visit_fn)(__u32 *type_id, void *ctx); 360 + typedef int (*str_off_visit_fn)(__u32 *str_off, void *ctx); 361 + int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx); 362 + int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx); 363 + int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx); 364 + int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx); 365 + 359 366 #endif /* __LIBBPF_LIBBPF_INTERNAL_H */