libbpf: Add enum64 deduplication support
authorYonghong Song <yhs@fb.com>
Tue, 7 Jun 2022 06:26:26 +0000 (23:26 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 7 Jun 2022 17:20:43 +0000 (10:20 -0700)
Add enum64 deduplication support. BTF_KIND_ENUM64 handling
is very similar to BTF_KIND_ENUM.

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

index 8676efb2baba0c3953c41937fc231db1c6d73419..ae1520f7e1b0f3fbe5e62d068997e9cde4c39bd5 100644 (file)
@@ -3582,7 +3582,7 @@ static bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2)
        return info1 == info2;
 }
 
-/* Calculate type signature hash of ENUM. */
+/* Calculate type signature hash of ENUM/ENUM64. */
 static long btf_hash_enum(struct btf_type *t)
 {
        long h;
@@ -3616,9 +3616,31 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
        return true;
 }
 
+static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2)
+{
+       const struct btf_enum64 *m1, *m2;
+       __u16 vlen;
+       int i;
+
+       if (!btf_equal_common(t1, t2))
+               return false;
+
+       vlen = btf_vlen(t1);
+       m1 = btf_enum64(t1);
+       m2 = btf_enum64(t2);
+       for (i = 0; i < vlen; i++) {
+               if (m1->name_off != m2->name_off || m1->val_lo32 != m2->val_lo32 ||
+                   m1->val_hi32 != m2->val_hi32)
+                       return false;
+               m1++;
+               m2++;
+       }
+       return true;
+}
+
 static inline bool btf_is_enum_fwd(struct btf_type *t)
 {
-       return btf_is_enum(t) && btf_vlen(t) == 0;
+       return btf_is_any_enum(t) && btf_vlen(t) == 0;
 }
 
 static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
@@ -3631,6 +3653,17 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
               t1->size == t2->size;
 }
 
+static bool btf_compat_enum64(struct btf_type *t1, struct btf_type *t2)
+{
+       if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
+               return btf_equal_enum64(t1, t2);
+
+       /* ignore vlen when comparing */
+       return t1->name_off == t2->name_off &&
+              (t1->info & ~0xffff) == (t2->info & ~0xffff) &&
+              t1->size == t2->size;
+}
+
 /*
  * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,
  * as referenced type IDs equivalence is established separately during type
@@ -3843,6 +3876,7 @@ static int btf_dedup_prep(struct btf_dedup *d)
                        h = btf_hash_int_decl_tag(t);
                        break;
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                        h = btf_hash_enum(t);
                        break;
                case BTF_KIND_STRUCT:
@@ -3932,6 +3966,27 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
                }
                break;
 
+       case BTF_KIND_ENUM64:
+               h = btf_hash_enum(t);
+               for_each_dedup_cand(d, hash_entry, h) {
+                       cand_id = (__u32)(long)hash_entry->value;
+                       cand = btf_type_by_id(d->btf, cand_id);
+                       if (btf_equal_enum64(t, cand)) {
+                               new_id = cand_id;
+                               break;
+                       }
+                       if (btf_compat_enum64(t, cand)) {
+                               if (btf_is_enum_fwd(t)) {
+                                       /* resolve fwd to full enum */
+                                       new_id = cand_id;
+                                       break;
+                               }
+                               /* resolve canonical enum fwd to full enum */
+                               d->map[cand_id] = type_id;
+                       }
+               }
+               break;
+
        case BTF_KIND_FWD:
        case BTF_KIND_FLOAT:
                h = btf_hash_common(t);
@@ -4227,6 +4282,9 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
        case BTF_KIND_ENUM:
                return btf_compat_enum(cand_type, canon_type);
 
+       case BTF_KIND_ENUM64:
+               return btf_compat_enum64(cand_type, canon_type);
+
        case BTF_KIND_FWD:
        case BTF_KIND_FLOAT:
                return btf_equal_common(cand_type, canon_type);
index a41463bf9060caa920dc98f28edf3551633e6119..c7e8b1fdfe2492de547e71d008975f3c6ebfd81c 100644 (file)
@@ -531,6 +531,11 @@ static inline bool btf_is_type_tag(const struct btf_type *t)
        return btf_kind(t) == BTF_KIND_TYPE_TAG;
 }
 
+static inline bool btf_is_any_enum(const struct btf_type *t)
+{
+       return btf_is_enum(t) || btf_is_enum64(t);
+}
+
 static inline __u8 btf_int_encoding(const struct btf_type *t)
 {
        return BTF_INT_ENCODING(*(__u32 *)(t + 1));