libbpf: Generalize BTF and BTF.ext type ID and strings iteration
authorAndrii Nakryiko <andrii@kernel.org>
Thu, 18 Mar 2021 19:40:26 +0000 (12:40 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Thu, 18 Mar 2021 23:14:22 +0000 (16:14 -0700)
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
tools/lib/bpf/btf.c
tools/lib/bpf/libbpf_internal.h

index e0b0a78..e137781 100644 (file)
@@ -3155,95 +3155,28 @@ done:
        return d;
 }
 
-typedef int (*str_off_fn_t)(__u32 *str_off_ptr, void *ctx);
-
 /*
  * Iterate over all possible places in .BTF and .BTF.ext that can reference
  * string and pass pointer to it to a provided callback `fn`.
  */
-static int btf_for_each_str_off(struct btf_dedup *d, str_off_fn_t fn, void *ctx)
+static int btf_for_each_str_off(struct btf_dedup *d, str_off_visit_fn fn, void *ctx)
 {
-       void *line_data_cur, *line_data_end;
-       int i, j, r, rec_size;
-       struct btf_type *t;
+       int i, r;
 
        for (i = 0; i < d->btf->nr_types; i++) {
-               t = btf_type_by_id(d->btf, d->btf->start_id + i);
-               r = fn(&t->name_off, ctx);
+               struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
+
+               r = btf_type_visit_str_offs(t, fn, ctx);
                if (r)
                        return r;
-
-               switch (btf_kind(t)) {
-               case BTF_KIND_STRUCT:
-               case BTF_KIND_UNION: {
-                       struct btf_member *m = btf_members(t);
-                       __u16 vlen = btf_vlen(t);
-
-                       for (j = 0; j < vlen; j++) {
-                               r = fn(&m->name_off, ctx);
-                               if (r)
-                                       return r;
-                               m++;
-                       }
-                       break;
-               }
-               case BTF_KIND_ENUM: {
-                       struct btf_enum *m = btf_enum(t);
-                       __u16 vlen = btf_vlen(t);
-
-                       for (j = 0; j < vlen; j++) {
-                               r = fn(&m->name_off, ctx);
-                               if (r)
-                                       return r;
-                               m++;
-                       }
-                       break;
-               }
-               case BTF_KIND_FUNC_PROTO: {
-                       struct btf_param *m = btf_params(t);
-                       __u16 vlen = btf_vlen(t);
-
-                       for (j = 0; j < vlen; j++) {
-                               r = fn(&m->name_off, ctx);
-                               if (r)
-                                       return r;
-                               m++;
-                       }
-                       break;
-               }
-               default:
-                       break;
-               }
        }
 
        if (!d->btf_ext)
                return 0;
 
-       line_data_cur = d->btf_ext->line_info.info;
-       line_data_end = d->btf_ext->line_info.info + d->btf_ext->line_info.len;
-       rec_size = d->btf_ext->line_info.rec_size;
-
-       while (line_data_cur < line_data_end) {
-               struct btf_ext_info_sec *sec = line_data_cur;
-               struct bpf_line_info_min *line_info;
-               __u32 num_info = sec->num_info;
-
-               r = fn(&sec->sec_name_off, ctx);
-               if (r)
-                       return r;
-
-               line_data_cur += sizeof(struct btf_ext_info_sec);
-               for (i = 0; i < num_info; i++) {
-                       line_info = line_data_cur;
-                       r = fn(&line_info->file_name_off, ctx);
-                       if (r)
-                               return r;
-                       r = fn(&line_info->line_off, ctx);
-                       if (r)
-                               return r;
-                       line_data_cur += rec_size;
-               }
-       }
+       r = btf_ext_visit_str_offs(d->btf_ext, fn, ctx);
+       if (r)
+               return r;
 
        return 0;
 }
@@ -4498,15 +4431,18 @@ static int btf_dedup_compact_types(struct btf_dedup *d)
  * then mapping it to a deduplicated type ID, stored in btf_dedup->hypot_map,
  * which is populated during compaction phase.
  */
-static int btf_dedup_remap_type_id(struct btf_dedup *d, __u32 type_id)
+static int btf_dedup_remap_type_id(__u32 *type_id, void *ctx)
 {
+       struct btf_dedup *d = ctx;
        __u32 resolved_type_id, new_type_id;
 
-       resolved_type_id = resolve_type_id(d, type_id);
+       resolved_type_id = resolve_type_id(d, *type_id);
        new_type_id = d->hypot_map[resolved_type_id];
        if (new_type_id > BTF_MAX_NR_TYPES)
                return -EINVAL;
-       return new_type_id;
+
+       *type_id = new_type_id;
+       return 0;
 }
 
 /*
@@ -4519,109 +4455,25 @@ static int btf_dedup_remap_type_id(struct btf_dedup *d, __u32 type_id)
  * referenced from any BTF type (e.g., struct fields, func proto args, etc) to
  * their final deduped type IDs.
  */
-static int btf_dedup_remap_type(struct btf_dedup *d, __u32 type_id)
+static int btf_dedup_remap_types(struct btf_dedup *d)
 {
-       struct btf_type *t = btf_type_by_id(d->btf, type_id);
        int i, r;
 
-       switch (btf_kind(t)) {
-       case BTF_KIND_INT:
-       case BTF_KIND_ENUM:
-       case BTF_KIND_FLOAT:
-               break;
-
-       case BTF_KIND_FWD:
-       case BTF_KIND_CONST:
-       case BTF_KIND_VOLATILE:
-       case BTF_KIND_RESTRICT:
-       case BTF_KIND_PTR:
-       case BTF_KIND_TYPEDEF:
-       case BTF_KIND_FUNC:
-       case BTF_KIND_VAR:
-               r = btf_dedup_remap_type_id(d, t->type);
-               if (r < 0)
-                       return r;
-               t->type = r;
-               break;
-
-       case BTF_KIND_ARRAY: {
-               struct btf_array *arr_info = btf_array(t);
-
-               r = btf_dedup_remap_type_id(d, arr_info->type);
-               if (r < 0)
-                       return r;
-               arr_info->type = r;
-               r = btf_dedup_remap_type_id(d, arr_info->index_type);
-               if (r < 0)
-                       return r;
-               arr_info->index_type = r;
-               break;
-       }
-
-       case BTF_KIND_STRUCT:
-       case BTF_KIND_UNION: {
-               struct btf_member *member = btf_members(t);
-               __u16 vlen = btf_vlen(t);
-
-               for (i = 0; i < vlen; i++) {
-                       r = btf_dedup_remap_type_id(d, member->type);
-                       if (r < 0)
-                               return r;
-                       member->type = r;
-                       member++;
-               }
-               break;
-       }
-
-       case BTF_KIND_FUNC_PROTO: {
-               struct btf_param *param = btf_params(t);
-               __u16 vlen = btf_vlen(t);
+       for (i = 0; i < d->btf->nr_types; i++) {
+               struct btf_type *t = btf_type_by_id(d->btf, d->btf->start_id + i);
 
-               r = btf_dedup_remap_type_id(d, t->type);
-               if (r < 0)
+               r = btf_type_visit_type_ids(t, btf_dedup_remap_type_id, d);
+               if (r)
                        return r;
-               t->type = r;
-
-               for (i = 0; i < vlen; i++) {
-                       r = btf_dedup_remap_type_id(d, param->type);
-                       if (r < 0)
-                               return r;
-                       param->type = r;
-                       param++;
-               }
-               break;
-       }
-
-       case BTF_KIND_DATASEC: {
-               struct btf_var_secinfo *var = btf_var_secinfos(t);
-               __u16 vlen = btf_vlen(t);
-
-               for (i = 0; i < vlen; i++) {
-                       r = btf_dedup_remap_type_id(d, var->type);
-                       if (r < 0)
-                               return r;
-                       var->type = r;
-                       var++;
-               }
-               break;
-       }
-
-       default:
-               return -EINVAL;
        }
 
-       return 0;
-}
+       if (!d->btf_ext)
+               return 0;
 
-static int btf_dedup_remap_types(struct btf_dedup *d)
-{
-       int i, r;
+       r = btf_ext_visit_type_ids(d->btf_ext, btf_dedup_remap_type_id, d);
+       if (r)
+               return r;
 
-       for (i = 0; i < d->btf->nr_types; i++) {
-               r = btf_dedup_remap_type(d, d->btf->start_id + i);
-               if (r < 0)
-                       return r;
-       }
        return 0;
 }
 
@@ -4675,3 +4527,200 @@ struct btf *libbpf_find_kernel_btf(void)
        pr_warn("failed to find valid kernel BTF\n");
        return ERR_PTR(-ESRCH);
 }
+
+int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx)
+{
+       int i, n, err;
+
+       switch (btf_kind(t)) {
+       case BTF_KIND_INT:
+       case BTF_KIND_FLOAT:
+       case BTF_KIND_ENUM:
+               return 0;
+
+       case BTF_KIND_FWD:
+       case BTF_KIND_CONST:
+       case BTF_KIND_VOLATILE:
+       case BTF_KIND_RESTRICT:
+       case BTF_KIND_PTR:
+       case BTF_KIND_TYPEDEF:
+       case BTF_KIND_FUNC:
+       case BTF_KIND_VAR:
+               return visit(&t->type, ctx);
+
+       case BTF_KIND_ARRAY: {
+               struct btf_array *a = btf_array(t);
+
+               err = visit(&a->type, ctx);
+               err = err ?: visit(&a->index_type, ctx);
+               return err;
+       }
+
+       case BTF_KIND_STRUCT:
+       case BTF_KIND_UNION: {
+               struct btf_member *m = btf_members(t);
+
+               for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
+                       err = visit(&m->type, ctx);
+                       if (err)
+                               return err;
+               }
+               return 0;
+       }
+
+       case BTF_KIND_FUNC_PROTO: {
+               struct btf_param *m = btf_params(t);
+
+               err = visit(&t->type, ctx);
+               if (err)
+                       return err;
+               for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
+                       err = visit(&m->type, ctx);
+                       if (err)
+                               return err;
+               }
+               return 0;
+       }
+
+       case BTF_KIND_DATASEC: {
+               struct btf_var_secinfo *m = btf_var_secinfos(t);
+
+               for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
+                       err = visit(&m->type, ctx);
+                       if (err)
+                               return err;
+               }
+               return 0;
+       }
+
+       default:
+               return -EINVAL;
+       }
+}
+
+int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx)
+{
+       int i, n, err;
+
+       err = visit(&t->name_off, ctx);
+       if (err)
+               return err;
+
+       switch (btf_kind(t)) {
+       case BTF_KIND_STRUCT:
+       case BTF_KIND_UNION: {
+               struct btf_member *m = btf_members(t);
+
+               for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
+                       err = visit(&m->name_off, ctx);
+                       if (err)
+                               return err;
+               }
+               break;
+       }
+       case BTF_KIND_ENUM: {
+               struct btf_enum *m = btf_enum(t);
+
+               for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
+                       err = visit(&m->name_off, ctx);
+                       if (err)
+                               return err;
+               }
+               break;
+       }
+       case BTF_KIND_FUNC_PROTO: {
+               struct btf_param *m = btf_params(t);
+
+               for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
+                       err = visit(&m->name_off, ctx);
+                       if (err)
+                               return err;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx)
+{
+       const struct btf_ext_info *seg;
+       struct btf_ext_info_sec *sec;
+       int i, err;
+
+       seg = &btf_ext->func_info;
+       for_each_btf_ext_sec(seg, sec) {
+               struct bpf_func_info_min *rec;
+
+               for_each_btf_ext_rec(seg, sec, i, rec) {
+                       err = visit(&rec->type_id, ctx);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       seg = &btf_ext->core_relo_info;
+       for_each_btf_ext_sec(seg, sec) {
+               struct bpf_core_relo *rec;
+
+               for_each_btf_ext_rec(seg, sec, i, rec) {
+                       err = visit(&rec->type_id, ctx);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx)
+{
+       const struct btf_ext_info *seg;
+       struct btf_ext_info_sec *sec;
+       int i, err;
+
+       seg = &btf_ext->func_info;
+       for_each_btf_ext_sec(seg, sec) {
+               err = visit(&sec->sec_name_off, ctx);
+               if (err)
+                       return err;
+       }
+
+       seg = &btf_ext->line_info;
+       for_each_btf_ext_sec(seg, sec) {
+               struct bpf_line_info_min *rec;
+
+               err = visit(&sec->sec_name_off, ctx);
+               if (err)
+                       return err;
+
+               for_each_btf_ext_rec(seg, sec, i, rec) {
+                       err = visit(&rec->file_name_off, ctx);
+                       if (err)
+                               return err;
+                       err = visit(&rec->line_off, ctx);
+                       if (err)
+                               return err;
+               }
+       }
+
+       seg = &btf_ext->core_relo_info;
+       for_each_btf_ext_sec(seg, sec) {
+               struct bpf_core_relo *rec;
+
+               err = visit(&sec->sec_name_off, ctx);
+               if (err)
+                       return err;
+
+               for_each_btf_ext_rec(seg, sec, i, rec) {
+                       err = visit(&rec->access_str_off, ctx);
+                       if (err)
+                               return err;
+               }
+       }
+
+       return 0;
+}
index d09860e..97b6b9c 100644 (file)
@@ -356,4 +356,11 @@ struct bpf_core_relo {
        enum bpf_core_relo_kind kind;
 };
 
+typedef int (*type_id_visit_fn)(__u32 *type_id, void *ctx);
+typedef int (*str_off_visit_fn)(__u32 *str_off, void *ctx);
+int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ctx);
+int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ctx);
+int btf_ext_visit_type_ids(struct btf_ext *btf_ext, type_id_visit_fn visit, void *ctx);
+int btf_ext_visit_str_offs(struct btf_ext *btf_ext, str_off_visit_fn visit, void *ctx);
+
 #endif /* __LIBBPF_LIBBPF_INTERNAL_H */