libbpf: Add enum64 parsing and new enum64 public API
authorYonghong Song <yhs@fb.com>
Tue, 7 Jun 2022 06:26:21 +0000 (23:26 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 7 Jun 2022 17:20:43 +0000 (10:20 -0700)
Add enum64 parsing support and two new enum64 public APIs:
  btf__add_enum64
  btf__add_enum64_value

Also add support of signedness for BTF_KIND_ENUM. The
BTF_KIND_ENUM API signatures are not changed. The signedness
will be changed from unsigned to signed if btf__add_enum_value()
finds any negative values.

Acked-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20220607062621.3719391-1-yhs@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/lib/bpf/btf.c
tools/lib/bpf/btf.h
tools/lib/bpf/libbpf.map

index 1972d0c65e0c59d5a50e85fdd153c1bbeda0f292..8676efb2baba0c3953c41937fc231db1c6d73419 100644 (file)
@@ -305,6 +305,8 @@ static int btf_type_size(const struct btf_type *t)
                return base_size + sizeof(__u32);
        case BTF_KIND_ENUM:
                return base_size + vlen * sizeof(struct btf_enum);
+       case BTF_KIND_ENUM64:
+               return base_size + vlen * sizeof(struct btf_enum64);
        case BTF_KIND_ARRAY:
                return base_size + sizeof(struct btf_array);
        case BTF_KIND_STRUCT:
@@ -334,6 +336,7 @@ static void btf_bswap_type_base(struct btf_type *t)
 static int btf_bswap_type_rest(struct btf_type *t)
 {
        struct btf_var_secinfo *v;
+       struct btf_enum64 *e64;
        struct btf_member *m;
        struct btf_array *a;
        struct btf_param *p;
@@ -361,6 +364,13 @@ static int btf_bswap_type_rest(struct btf_type *t)
                        e->val = bswap_32(e->val);
                }
                return 0;
+       case BTF_KIND_ENUM64:
+               for (i = 0, e64 = btf_enum64(t); i < vlen; i++, e64++) {
+                       e64->name_off = bswap_32(e64->name_off);
+                       e64->val_lo32 = bswap_32(e64->val_lo32);
+                       e64->val_hi32 = bswap_32(e64->val_hi32);
+               }
+               return 0;
        case BTF_KIND_ARRAY:
                a = btf_array(t);
                a->type = bswap_32(a->type);
@@ -611,6 +621,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
                case BTF_KIND_STRUCT:
                case BTF_KIND_UNION:
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                case BTF_KIND_DATASEC:
                case BTF_KIND_FLOAT:
                        size = t->size;
@@ -658,6 +669,7 @@ int btf__align_of(const struct btf *btf, __u32 id)
        switch (kind) {
        case BTF_KIND_INT:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_FLOAT:
                return min(btf_ptr_sz(btf), (size_t)t->size);
        case BTF_KIND_PTR:
@@ -2176,6 +2188,10 @@ static int btf_add_enum_common(struct btf *btf, const char *name, __u32 byte_sz,
  */
 int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)
 {
+       /*
+        * set the signedness to be unsigned, it will change to signed
+        * if any later enumerator is negative.
+        */
        return btf_add_enum_common(btf, name, byte_sz, false, BTF_KIND_ENUM);
 }
 
@@ -2226,6 +2242,82 @@ int btf__add_enum_value(struct btf *btf, const char *name, __s64 value)
        t = btf_last_type(btf);
        btf_type_inc_vlen(t);
 
+       /* if negative value, set signedness to signed */
+       if (value < 0)
+               t->info = btf_type_info(btf_kind(t), btf_vlen(t), true);
+
+       btf->hdr->type_len += sz;
+       btf->hdr->str_off += sz;
+       return 0;
+}
+
+/*
+ * Append new BTF_KIND_ENUM64 type with:
+ *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
+ *   - *byte_sz* - size of the enum, in bytes.
+ *   - *is_signed* - whether the enum values are signed or not;
+ *
+ * Enum initially has no enum values in it (and corresponds to enum forward
+ * declaration). Enumerator values can be added by btf__add_enum64_value()
+ * immediately after btf__add_enum64() succeeds.
+ *
+ * Returns:
+ *   - >0, type ID of newly added BTF type;
+ *   - <0, on error.
+ */
+int btf__add_enum64(struct btf *btf, const char *name, __u32 byte_sz,
+                   bool is_signed)
+{
+       return btf_add_enum_common(btf, name, byte_sz, is_signed,
+                                  BTF_KIND_ENUM64);
+}
+
+/*
+ * Append new enum value for the current ENUM64 type with:
+ *   - *name* - name of the enumerator value, can't be NULL or empty;
+ *   - *value* - integer value corresponding to enum value *name*;
+ * Returns:
+ *   -  0, on success;
+ *   - <0, on error.
+ */
+int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value)
+{
+       struct btf_enum64 *v;
+       struct btf_type *t;
+       int sz, name_off;
+
+       /* last type should be BTF_KIND_ENUM64 */
+       if (btf->nr_types == 0)
+               return libbpf_err(-EINVAL);
+       t = btf_last_type(btf);
+       if (!btf_is_enum64(t))
+               return libbpf_err(-EINVAL);
+
+       /* non-empty name */
+       if (!name || !name[0])
+               return libbpf_err(-EINVAL);
+
+       /* decompose and invalidate raw data */
+       if (btf_ensure_modifiable(btf))
+               return libbpf_err(-ENOMEM);
+
+       sz = sizeof(struct btf_enum64);
+       v = btf_add_type_mem(btf, sz);
+       if (!v)
+               return libbpf_err(-ENOMEM);
+
+       name_off = btf__add_str(btf, name);
+       if (name_off < 0)
+               return name_off;
+
+       v->name_off = name_off;
+       v->val_lo32 = (__u32)value;
+       v->val_hi32 = value >> 32;
+
+       /* update parent type's vlen */
+       t = btf_last_type(btf);
+       btf_type_inc_vlen(t);
+
        btf->hdr->type_len += sz;
        btf->hdr->str_off += sz;
        return 0;
@@ -4737,6 +4829,7 @@ int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ct
        case BTF_KIND_INT:
        case BTF_KIND_FLOAT:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                return 0;
 
        case BTF_KIND_FWD:
@@ -4831,6 +4924,16 @@ int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ct
                }
                break;
        }
+       case BTF_KIND_ENUM64: {
+               struct btf_enum64 *m = btf_enum64(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);
 
index 951ac74757948fd473a7ab18273f06b21c54d3a6..a41463bf9060caa920dc98f28edf3551633e6119 100644 (file)
@@ -215,6 +215,8 @@ LIBBPF_API int btf__add_field(struct btf *btf, const char *name, int field_type_
 /* enum construction APIs */
 LIBBPF_API int btf__add_enum(struct btf *btf, const char *name, __u32 bytes_sz);
 LIBBPF_API int btf__add_enum_value(struct btf *btf, const char *name, __s64 value);
+LIBBPF_API int btf__add_enum64(struct btf *btf, const char *name, __u32 bytes_sz, bool is_signed);
+LIBBPF_API int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value);
 
 enum btf_fwd_kind {
        BTF_FWD_STRUCT = 0,
@@ -454,6 +456,11 @@ static inline bool btf_is_enum(const struct btf_type *t)
        return btf_kind(t) == BTF_KIND_ENUM;
 }
 
+static inline bool btf_is_enum64(const struct btf_type *t)
+{
+       return btf_kind(t) == BTF_KIND_ENUM64;
+}
+
 static inline bool btf_is_fwd(const struct btf_type *t)
 {
        return btf_kind(t) == BTF_KIND_FWD;
@@ -549,6 +556,11 @@ static inline struct btf_enum *btf_enum(const struct btf_type *t)
        return (struct btf_enum *)(t + 1);
 }
 
+static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
+{
+       return (struct btf_enum64 *)(t + 1);
+}
+
 static inline struct btf_member *btf_members(const struct btf_type *t)
 {
        return (struct btf_member *)(t + 1);
index 38e284ff057dfc3f4920b13b1a986209b28fbd5f..116a2a8ee7c218eb6446cefe63819972b8ba8b2b 100644 (file)
@@ -462,6 +462,8 @@ LIBBPF_0.8.0 {
 
 LIBBPF_1.0.0 {
        global:
+               btf__add_enum64;
+               btf__add_enum64_value;
                libbpf_bpf_attach_type_str;
                libbpf_bpf_link_type_str;
                libbpf_bpf_map_type_str;