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.

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 <yatsenko@meta.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20240906132453.146085-1-mykyta.yatsenko5@gmail.com

authored by

Mykyta Yatsenko and committed by
Andrii Nakryiko
f8c6b791 04bb60d0

+75 -5
+75 -5
tools/bpf/bpftool/btf.c
··· 50 50 int type_rank; 51 51 const char *sort_name; 52 52 const char *own_name; 53 + __u64 disambig_hash; 53 54 }; 54 55 55 56 static const char *btf_int_enc_str(__u8 encoding) ··· 585 584 return NULL; 586 585 } 587 586 587 + static __u64 hasher(__u64 hash, __u64 val) 588 + { 589 + return hash * 31 + val; 590 + } 591 + 592 + static __u64 btf_name_hasher(__u64 hash, const struct btf *btf, __u32 name_off) 593 + { 594 + if (!name_off) 595 + return hash; 596 + 597 + return hasher(hash, str_hash(btf__name_by_offset(btf, name_off))); 598 + } 599 + 600 + static __u64 btf_type_disambig_hash(const struct btf *btf, __u32 id, bool include_members) 601 + { 602 + const struct btf_type *t = btf__type_by_id(btf, id); 603 + int i; 604 + size_t hash = 0; 605 + 606 + hash = btf_name_hasher(hash, btf, t->name_off); 607 + 608 + switch (btf_kind(t)) { 609 + case BTF_KIND_ENUM: 610 + case BTF_KIND_ENUM64: 611 + for (i = 0; i < btf_vlen(t); i++) { 612 + __u32 name_off = btf_is_enum(t) ? 613 + btf_enum(t)[i].name_off : 614 + btf_enum64(t)[i].name_off; 615 + 616 + hash = btf_name_hasher(hash, btf, name_off); 617 + } 618 + break; 619 + case BTF_KIND_STRUCT: 620 + case BTF_KIND_UNION: 621 + if (!include_members) 622 + break; 623 + for (i = 0; i < btf_vlen(t); i++) { 624 + const struct btf_member *m = btf_members(t) + i; 625 + 626 + hash = btf_name_hasher(hash, btf, m->name_off); 627 + /* resolve field type's name and hash it as well */ 628 + hash = hasher(hash, btf_type_disambig_hash(btf, m->type, false)); 629 + } 630 + break; 631 + case BTF_KIND_TYPE_TAG: 632 + case BTF_KIND_CONST: 633 + case BTF_KIND_PTR: 634 + case BTF_KIND_VOLATILE: 635 + case BTF_KIND_RESTRICT: 636 + case BTF_KIND_TYPEDEF: 637 + case BTF_KIND_DECL_TAG: 638 + hash = hasher(hash, btf_type_disambig_hash(btf, t->type, include_members)); 639 + break; 640 + case BTF_KIND_ARRAY: { 641 + struct btf_array *arr = btf_array(t); 642 + 643 + hash = hasher(hash, arr->nelems); 644 + hash = hasher(hash, btf_type_disambig_hash(btf, arr->type, include_members)); 645 + break; 646 + } 647 + default: 648 + break; 649 + } 650 + return hash; 651 + } 652 + 588 653 static int btf_type_compare(const void *left, const void *right) 589 654 { 590 655 const struct sort_datum *d1 = (const struct sort_datum *)left; 591 656 const struct sort_datum *d2 = (const struct sort_datum *)right; 592 657 int r; 593 658 594 - if (d1->type_rank != d2->type_rank) 595 - return d1->type_rank < d2->type_rank ? -1 : 1; 596 - 597 - r = strcmp(d1->sort_name, d2->sort_name); 659 + r = d1->type_rank - d2->type_rank; 660 + r = r ?: strcmp(d1->sort_name, d2->sort_name); 661 + r = r ?: strcmp(d1->own_name, d2->own_name); 598 662 if (r) 599 663 return r; 600 664 601 - return strcmp(d1->own_name, d2->own_name); 665 + if (d1->disambig_hash != d2->disambig_hash) 666 + return d1->disambig_hash < d2->disambig_hash ? -1 : 1; 667 + 668 + return d1->index - d2->index; 602 669 } 603 670 604 671 static struct sort_datum *sort_btf_c(const struct btf *btf) ··· 687 618 d->type_rank = btf_type_rank(btf, i, false); 688 619 d->sort_name = btf_type_sort_name(btf, i, false); 689 620 d->own_name = btf__name_by_offset(btf, t->name_off); 621 + d->disambig_hash = btf_type_disambig_hash(btf, i, true); 690 622 } 691 623 692 624 qsort(datums, n, sizeof(struct sort_datum), btf_type_compare);