Skip to content

Commit de048b6

Browse files
eddyz87anakryiko
authored andcommitted
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
1 parent 07d90c7 commit de048b6

1 file changed

Lines changed: 25 additions & 50 deletions

File tree

tools/lib/bpf/btf.c

Lines changed: 25 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3404,23 +3404,17 @@ static long btf_hash_enum(struct btf_type *t)
34043404
{
34053405
long h;
34063406

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 */
34083408
h = hash_combine(0, t->name_off);
3409-
h = hash_combine(h, t->info & ~0xffff);
3410-
h = hash_combine(h, t->size);
34113409
return h;
34123410
}
34133411

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)
34163413
{
34173414
const struct btf_enum *m1, *m2;
34183415
__u16 vlen;
34193416
int i;
34203417

3421-
if (!btf_equal_common(t1, t2))
3422-
return false;
3423-
34243418
vlen = btf_vlen(t1);
34253419
m1 = btf_enum(t1);
34263420
m2 = btf_enum(t2);
@@ -3433,15 +3427,12 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
34333427
return true;
34343428
}
34353429

3436-
static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2)
3430+
static bool btf_equal_enum64_members(struct btf_type *t1, struct btf_type *t2)
34373431
{
34383432
const struct btf_enum64 *m1, *m2;
34393433
__u16 vlen;
34403434
int i;
34413435

3442-
if (!btf_equal_common(t1, t2))
3443-
return false;
3444-
34453436
vlen = btf_vlen(t1);
34463437
m1 = btf_enum64(t1);
34473438
m2 = btf_enum64(t2);
@@ -3455,6 +3446,19 @@ static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2)
34553446
return true;
34563447
}
34573448

3449+
/* Check structural equality of two ENUMs or ENUM64s. */
3450+
static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
3451+
{
3452+
if (!btf_equal_common(t1, t2))
3453+
return false;
3454+
3455+
/* t1 & t2 kinds are identical because of btf_equal_common */
3456+
if (btf_kind(t1) == BTF_KIND_ENUM)
3457+
return btf_equal_enum_members(t1, t2);
3458+
else
3459+
return btf_equal_enum64_members(t1, t2);
3460+
}
3461+
34583462
static inline bool btf_is_enum_fwd(struct btf_type *t)
34593463
{
34603464
return btf_is_any_enum(t) && btf_vlen(t) == 0;
@@ -3464,21 +3468,14 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
34643468
{
34653469
if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
34663470
return btf_equal_enum(t1, t2);
3467-
/* ignore vlen when comparing */
3468-
return t1->name_off == t2->name_off &&
3469-
(t1->info & ~0xffff) == (t2->info & ~0xffff) &&
3470-
t1->size == t2->size;
3471-
}
3472-
3473-
static bool btf_compat_enum64(struct btf_type *t1, struct btf_type *t2)
3474-
{
3475-
if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
3476-
return btf_equal_enum64(t1, t2);
3477-
3478-
/* ignore vlen when comparing */
3471+
/* At this point either t1 or t2 or both are forward declarations, thus:
3472+
* - skip comparing vlen because it is zero for forward declarations;
3473+
* - skip comparing size to allow enum forward declarations
3474+
* to be compatible with enum64 full declarations;
3475+
* - skip comparing kind for the same reason.
3476+
*/
34793477
return t1->name_off == t2->name_off &&
3480-
(t1->info & ~0xffff) == (t2->info & ~0xffff) &&
3481-
t1->size == t2->size;
3478+
btf_is_any_enum(t1) && btf_is_any_enum(t2);
34823479
}
34833480

34843481
/*
@@ -3763,6 +3760,7 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
37633760
break;
37643761

37653762
case BTF_KIND_ENUM:
3763+
case BTF_KIND_ENUM64:
37663764
h = btf_hash_enum(t);
37673765
for_each_dedup_cand(d, hash_entry, h) {
37683766
cand_id = (__u32)(long)hash_entry->value;
@@ -3783,27 +3781,6 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
37833781
}
37843782
break;
37853783

3786-
case BTF_KIND_ENUM64:
3787-
h = btf_hash_enum(t);
3788-
for_each_dedup_cand(d, hash_entry, h) {
3789-
cand_id = (__u32)(long)hash_entry->value;
3790-
cand = btf_type_by_id(d->btf, cand_id);
3791-
if (btf_equal_enum64(t, cand)) {
3792-
new_id = cand_id;
3793-
break;
3794-
}
3795-
if (btf_compat_enum64(t, cand)) {
3796-
if (btf_is_enum_fwd(t)) {
3797-
/* resolve fwd to full enum */
3798-
new_id = cand_id;
3799-
break;
3800-
}
3801-
/* resolve canonical enum fwd to full enum */
3802-
d->map[cand_id] = type_id;
3803-
}
3804-
}
3805-
break;
3806-
38073784
case BTF_KIND_FWD:
38083785
case BTF_KIND_FLOAT:
38093786
h = btf_hash_common(t);
@@ -4099,10 +4076,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
40994076
return btf_equal_int_tag(cand_type, canon_type);
41004077

41014078
case BTF_KIND_ENUM:
4102-
return btf_compat_enum(cand_type, canon_type);
4103-
41044079
case BTF_KIND_ENUM64:
4105-
return btf_compat_enum64(cand_type, canon_type);
4080+
return btf_compat_enum(cand_type, canon_type);
41064081

41074082
case BTF_KIND_FWD:
41084083
case BTF_KIND_FLOAT:

0 commit comments

Comments
 (0)