Skip to content

Commit f8c6b79

Browse files
mykyta5anakryiko
authored andcommitted
bpftool: Improve btf c dump sorting stability
Existing algorithm for BTF C dump sorting uses only types and names of the structs and unions for ordering. As dump contains structs with the same names but different contents, relative to each other ordering of those structs will be accidental. This patch addresses this problem by introducing a new sorting field that contains hash of the struct/union field names and types to disambiguate comparison of the non-unique named structs. Signed-off-by: Mykyta Yatsenko <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 04bb60d commit f8c6b79

File tree

1 file changed

+75
-5
lines changed

1 file changed

+75
-5
lines changed

tools/bpf/bpftool/btf.c

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct sort_datum {
5050
int type_rank;
5151
const char *sort_name;
5252
const char *own_name;
53+
__u64 disambig_hash;
5354
};
5455

5556
static const char *btf_int_enc_str(__u8 encoding)
@@ -584,20 +585,88 @@ static const char *btf_type_sort_name(const struct btf *btf, __u32 index, bool f
584585
return NULL;
585586
}
586587

588+
static __u64 hasher(__u64 hash, __u64 val)
589+
{
590+
return hash * 31 + val;
591+
}
592+
593+
static __u64 btf_name_hasher(__u64 hash, const struct btf *btf, __u32 name_off)
594+
{
595+
if (!name_off)
596+
return hash;
597+
598+
return hasher(hash, str_hash(btf__name_by_offset(btf, name_off)));
599+
}
600+
601+
static __u64 btf_type_disambig_hash(const struct btf *btf, __u32 id, bool include_members)
602+
{
603+
const struct btf_type *t = btf__type_by_id(btf, id);
604+
int i;
605+
size_t hash = 0;
606+
607+
hash = btf_name_hasher(hash, btf, t->name_off);
608+
609+
switch (btf_kind(t)) {
610+
case BTF_KIND_ENUM:
611+
case BTF_KIND_ENUM64:
612+
for (i = 0; i < btf_vlen(t); i++) {
613+
__u32 name_off = btf_is_enum(t) ?
614+
btf_enum(t)[i].name_off :
615+
btf_enum64(t)[i].name_off;
616+
617+
hash = btf_name_hasher(hash, btf, name_off);
618+
}
619+
break;
620+
case BTF_KIND_STRUCT:
621+
case BTF_KIND_UNION:
622+
if (!include_members)
623+
break;
624+
for (i = 0; i < btf_vlen(t); i++) {
625+
const struct btf_member *m = btf_members(t) + i;
626+
627+
hash = btf_name_hasher(hash, btf, m->name_off);
628+
/* resolve field type's name and hash it as well */
629+
hash = hasher(hash, btf_type_disambig_hash(btf, m->type, false));
630+
}
631+
break;
632+
case BTF_KIND_TYPE_TAG:
633+
case BTF_KIND_CONST:
634+
case BTF_KIND_PTR:
635+
case BTF_KIND_VOLATILE:
636+
case BTF_KIND_RESTRICT:
637+
case BTF_KIND_TYPEDEF:
638+
case BTF_KIND_DECL_TAG:
639+
hash = hasher(hash, btf_type_disambig_hash(btf, t->type, include_members));
640+
break;
641+
case BTF_KIND_ARRAY: {
642+
struct btf_array *arr = btf_array(t);
643+
644+
hash = hasher(hash, arr->nelems);
645+
hash = hasher(hash, btf_type_disambig_hash(btf, arr->type, include_members));
646+
break;
647+
}
648+
default:
649+
break;
650+
}
651+
return hash;
652+
}
653+
587654
static int btf_type_compare(const void *left, const void *right)
588655
{
589656
const struct sort_datum *d1 = (const struct sort_datum *)left;
590657
const struct sort_datum *d2 = (const struct sort_datum *)right;
591658
int r;
592659

593-
if (d1->type_rank != d2->type_rank)
594-
return d1->type_rank < d2->type_rank ? -1 : 1;
595-
596-
r = strcmp(d1->sort_name, d2->sort_name);
660+
r = d1->type_rank - d2->type_rank;
661+
r = r ?: strcmp(d1->sort_name, d2->sort_name);
662+
r = r ?: strcmp(d1->own_name, d2->own_name);
597663
if (r)
598664
return r;
599665

600-
return strcmp(d1->own_name, d2->own_name);
666+
if (d1->disambig_hash != d2->disambig_hash)
667+
return d1->disambig_hash < d2->disambig_hash ? -1 : 1;
668+
669+
return d1->index - d2->index;
601670
}
602671

603672
static struct sort_datum *sort_btf_c(const struct btf *btf)
@@ -618,6 +687,7 @@ static struct sort_datum *sort_btf_c(const struct btf *btf)
618687
d->type_rank = btf_type_rank(btf, i, false);
619688
d->sort_name = btf_type_sort_name(btf, i, false);
620689
d->own_name = btf__name_by_offset(btf, t->name_off);
690+
d->disambig_hash = btf_type_disambig_hash(btf, i, true);
621691
}
622692

623693
qsort(datums, n, sizeof(struct sort_datum), btf_type_compare);

0 commit comments

Comments
 (0)