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

Configure Feed

Select the types of activity you want to include in your feed.

libbpf: Resolve enum fwd as full enum64 and vice versa

Changes de-duplication logic for enums in the following way:
- update btf_hash_enum to ignore size and kind fields to get
ENUM and ENUM64 types in a same hash bucket;
- update btf_compat_enum to consider enum fwd to be compatible with
full enum64 (and vice versa);

This allows BTF de-duplication in the following case:

// CU #1
enum foo;

struct s {
enum foo *a;
} *x;

// CU #2
enum foo {
x = 0xfffffffff // big enough to force enum64
};

struct s {
enum foo *a;
} *y;

De-duplicated BTF prior to this commit:

[1] ENUM64 'foo' encoding=UNSIGNED size=8 vlen=1
'x' val=68719476735ULL
[2] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64
encoding=(none)
[3] STRUCT 's' size=8 vlen=1
'a' type_id=4 bits_offset=0
[4] PTR '(anon)' type_id=1
[5] PTR '(anon)' type_id=3
[6] STRUCT 's' size=8 vlen=1
'a' type_id=8 bits_offset=0
[7] ENUM 'foo' encoding=UNSIGNED size=4 vlen=0
[8] PTR '(anon)' type_id=7
[9] PTR '(anon)' type_id=6

De-duplicated BTF after this commit:

[1] ENUM64 'foo' encoding=UNSIGNED size=8 vlen=1
'x' val=68719476735ULL
[2] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64
encoding=(none)
[3] STRUCT 's' size=8 vlen=1
'a' type_id=4 bits_offset=0
[4] PTR '(anon)' type_id=1
[5] PTR '(anon)' type_id=3

Enum forward declarations in C do not provide information about
enumeration values range. Thus the `btf_type->size` field is
meaningless for forward enum declarations. In fact, GCC does not
encode size in DWARF for forward enum declarations
(but dwarves sets enumeration size to a default value of `sizeof(int) * 8`
when size is not specified see dwarf_loader.c:die__create_new_enumeration).

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20221101235413.1824260-1-eddyz87@gmail.com

authored by

Eduard Zingerman and committed by
Andrii Nakryiko
de048b6e 07d90c72

+25 -50
+25 -50
tools/lib/bpf/btf.c
··· 3404 3404 { 3405 3405 long h; 3406 3406 3407 - /* don't hash vlen and enum members to support enum fwd resolving */ 3407 + /* don't hash vlen, enum members and size to support enum fwd resolving */ 3408 3408 h = hash_combine(0, t->name_off); 3409 - h = hash_combine(h, t->info & ~0xffff); 3410 - h = hash_combine(h, t->size); 3411 3409 return h; 3412 3410 } 3413 3411 3414 - /* Check structural equality of two ENUMs. */ 3415 - static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2) 3412 + static bool btf_equal_enum_members(struct btf_type *t1, struct btf_type *t2) 3416 3413 { 3417 3414 const struct btf_enum *m1, *m2; 3418 3415 __u16 vlen; 3419 3416 int i; 3420 - 3421 - if (!btf_equal_common(t1, t2)) 3422 - return false; 3423 3417 3424 3418 vlen = btf_vlen(t1); 3425 3419 m1 = btf_enum(t1); ··· 3427 3433 return true; 3428 3434 } 3429 3435 3430 - static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2) 3436 + static bool btf_equal_enum64_members(struct btf_type *t1, struct btf_type *t2) 3431 3437 { 3432 3438 const struct btf_enum64 *m1, *m2; 3433 3439 __u16 vlen; 3434 3440 int i; 3435 - 3436 - if (!btf_equal_common(t1, t2)) 3437 - return false; 3438 3441 3439 3442 vlen = btf_vlen(t1); 3440 3443 m1 = btf_enum64(t1); ··· 3446 3455 return true; 3447 3456 } 3448 3457 3458 + /* Check structural equality of two ENUMs or ENUM64s. */ 3459 + static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2) 3460 + { 3461 + if (!btf_equal_common(t1, t2)) 3462 + return false; 3463 + 3464 + /* t1 & t2 kinds are identical because of btf_equal_common */ 3465 + if (btf_kind(t1) == BTF_KIND_ENUM) 3466 + return btf_equal_enum_members(t1, t2); 3467 + else 3468 + return btf_equal_enum64_members(t1, t2); 3469 + } 3470 + 3449 3471 static inline bool btf_is_enum_fwd(struct btf_type *t) 3450 3472 { 3451 3473 return btf_is_any_enum(t) && btf_vlen(t) == 0; ··· 3468 3464 { 3469 3465 if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2)) 3470 3466 return btf_equal_enum(t1, t2); 3471 - /* ignore vlen when comparing */ 3467 + /* At this point either t1 or t2 or both are forward declarations, thus: 3468 + * - skip comparing vlen because it is zero for forward declarations; 3469 + * - skip comparing size to allow enum forward declarations 3470 + * to be compatible with enum64 full declarations; 3471 + * - skip comparing kind for the same reason. 3472 + */ 3472 3473 return t1->name_off == t2->name_off && 3473 - (t1->info & ~0xffff) == (t2->info & ~0xffff) && 3474 - t1->size == t2->size; 3475 - } 3476 - 3477 - static bool btf_compat_enum64(struct btf_type *t1, struct btf_type *t2) 3478 - { 3479 - if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2)) 3480 - return btf_equal_enum64(t1, t2); 3481 - 3482 - /* ignore vlen when comparing */ 3483 - return t1->name_off == t2->name_off && 3484 - (t1->info & ~0xffff) == (t2->info & ~0xffff) && 3485 - t1->size == t2->size; 3474 + btf_is_any_enum(t1) && btf_is_any_enum(t2); 3486 3475 } 3487 3476 3488 3477 /* ··· 3760 3763 break; 3761 3764 3762 3765 case BTF_KIND_ENUM: 3766 + case BTF_KIND_ENUM64: 3763 3767 h = btf_hash_enum(t); 3764 3768 for_each_dedup_cand(d, hash_entry, h) { 3765 3769 cand_id = (__u32)(long)hash_entry->value; ··· 3770 3772 break; 3771 3773 } 3772 3774 if (btf_compat_enum(t, cand)) { 3773 - if (btf_is_enum_fwd(t)) { 3774 - /* resolve fwd to full enum */ 3775 - new_id = cand_id; 3776 - break; 3777 - } 3778 - /* resolve canonical enum fwd to full enum */ 3779 - d->map[cand_id] = type_id; 3780 - } 3781 - } 3782 - break; 3783 - 3784 - case BTF_KIND_ENUM64: 3785 - h = btf_hash_enum(t); 3786 - for_each_dedup_cand(d, hash_entry, h) { 3787 - cand_id = (__u32)(long)hash_entry->value; 3788 - cand = btf_type_by_id(d->btf, cand_id); 3789 - if (btf_equal_enum64(t, cand)) { 3790 - new_id = cand_id; 3791 - break; 3792 - } 3793 - if (btf_compat_enum64(t, cand)) { 3794 3775 if (btf_is_enum_fwd(t)) { 3795 3776 /* resolve fwd to full enum */ 3796 3777 new_id = cand_id; ··· 4076 4099 return btf_equal_int_tag(cand_type, canon_type); 4077 4100 4078 4101 case BTF_KIND_ENUM: 4079 - return btf_compat_enum(cand_type, canon_type); 4080 - 4081 4102 case BTF_KIND_ENUM64: 4082 - return btf_compat_enum64(cand_type, canon_type); 4103 + return btf_compat_enum(cand_type, canon_type); 4083 4104 4084 4105 case BTF_KIND_FWD: 4085 4106 case BTF_KIND_FLOAT: