|
26 | 26 |
|
27 | 27 | #define BTF_MAX_NR_TYPES 0x7fffffffU |
28 | 28 | #define BTF_MAX_STR_OFFSET 0x7fffffffU |
| 29 | +/* |
| 30 | + * sort verification occurs lazily upon first btf_find_type_by_name_kind() call |
| 31 | + */ |
| 32 | +#define BTF_NEED_SORT_CHECK ((__u32)-1) |
29 | 33 |
|
30 | 34 | static struct btf_type btf_void; |
31 | 35 |
|
@@ -92,6 +96,16 @@ struct btf { |
92 | 96 | * - for split BTF counts number of types added on top of base BTF. |
93 | 97 | */ |
94 | 98 | __u32 nr_types; |
| 99 | + /* number of sorted and named types in this BTF instance: |
| 100 | + * - doesn't include special [0] void type; |
| 101 | + * - for split BTF counts number of sorted and named types added on |
| 102 | + * top of base BTF. |
| 103 | + * - BTF_NEED_SORT_CHECK value indicates sort validation will be performed |
| 104 | + * on first call to btf_find_type_by_name_kind. |
| 105 | + * - zero value indicates applied sorting check with unsorted BTF or no |
| 106 | + * named types. |
| 107 | + */ |
| 108 | + __u32 nr_sorted_types; |
95 | 109 | /* if not NULL, points to the base BTF on top of which the current |
96 | 110 | * split BTF is based |
97 | 111 | */ |
@@ -897,44 +911,126 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id) |
897 | 911 | return type_id; |
898 | 912 | } |
899 | 913 |
|
900 | | -__s32 btf__find_by_name(const struct btf *btf, const char *type_name) |
| 914 | +/* Performs binary search within specified type ID range to find the leftmost |
| 915 | + * BTF type matching the given name. The search assumes types are sorted by |
| 916 | + * name in lexicographical order within the specified range. |
| 917 | + * |
| 918 | + * Return: Type ID of leftmost matching type, or -ENOENT if not found |
| 919 | + */ |
| 920 | +static __s32 btf_find_type_by_name_bsearch(const struct btf *btf, const char *name, |
| 921 | + __s32 start_id, __s32 end_id) |
901 | 922 | { |
902 | | - __u32 i, nr_types = btf__type_cnt(btf); |
| 923 | + const struct btf_type *t; |
| 924 | + const char *tname; |
| 925 | + __s32 l, r, m, lmost = -ENOENT; |
| 926 | + int ret; |
| 927 | + |
| 928 | + l = start_id; |
| 929 | + r = end_id; |
| 930 | + while (l <= r) { |
| 931 | + m = l + (r - l) / 2; |
| 932 | + t = btf_type_by_id(btf, m); |
| 933 | + tname = btf__str_by_offset(btf, t->name_off); |
| 934 | + ret = strcmp(tname, name); |
| 935 | + if (ret < 0) { |
| 936 | + l = m + 1; |
| 937 | + } else { |
| 938 | + if (ret == 0) |
| 939 | + lmost = m; |
| 940 | + r = m - 1; |
| 941 | + } |
| 942 | + } |
903 | 943 |
|
904 | | - if (!strcmp(type_name, "void")) |
905 | | - return 0; |
| 944 | + return lmost; |
| 945 | +} |
906 | 946 |
|
907 | | - for (i = 1; i < nr_types; i++) { |
908 | | - const struct btf_type *t = btf__type_by_id(btf, i); |
909 | | - const char *name = btf__name_by_offset(btf, t->name_off); |
| 947 | +/* Searches for a BTF type by name and optionally by kind. The function first |
| 948 | + * checks if the search should start from the base BTF (if @start_id is before |
| 949 | + * current BTF's start_id). If types are sorted, it uses binary search to find |
| 950 | + * the leftmost matching type and then verifies the kind. For unsorted types, |
| 951 | + * it falls back to linear search through all types. |
| 952 | + * |
| 953 | + * The function handles split BTF scenarios by recursively searching in base |
| 954 | + * BTFs when necessary. When @kind is -1, only the name matching is performed. |
| 955 | + * |
| 956 | + * Return: Type ID of matching type on success, -ENOENT if not found |
| 957 | + */ |
| 958 | +static __s32 btf_find_type_by_name_kind(const struct btf *btf, int start_id, |
| 959 | + const char *type_name, __u32 kind) |
| 960 | +{ |
| 961 | + const struct btf_type *t; |
| 962 | + const char *tname; |
| 963 | + int err = -ENOENT; |
| 964 | + |
| 965 | + if (start_id < btf->start_id) { |
| 966 | + err = btf_find_type_by_name_kind(btf->base_btf, start_id, |
| 967 | + type_name, kind); |
| 968 | + if (err > 0) |
| 969 | + goto out; |
| 970 | + start_id = btf->start_id; |
| 971 | + } |
| 972 | + |
| 973 | + if (btf->nr_sorted_types != BTF_NEED_SORT_CHECK) { |
| 974 | + /* binary search */ |
| 975 | + __s32 end_id; |
| 976 | + bool skip_first; |
| 977 | + int ret; |
| 978 | + |
| 979 | + end_id = btf->start_id + btf->nr_sorted_types - 1; |
| 980 | + ret = btf_find_type_by_name_bsearch(btf, type_name, start_id, end_id); |
| 981 | + if (ret < 0) |
| 982 | + goto out; |
| 983 | + if (kind == -1) |
| 984 | + return ret; |
| 985 | + skip_first = true; |
| 986 | + do { |
| 987 | + t = btf_type_by_id(btf, ret); |
| 988 | + if (BTF_INFO_KIND(t->info) != kind) { |
| 989 | + if (skip_first) { |
| 990 | + skip_first = false; |
| 991 | + continue; |
| 992 | + } |
| 993 | + } else if (skip_first) { |
| 994 | + return ret; |
| 995 | + } |
| 996 | + tname = btf__str_by_offset(btf, t->name_off); |
| 997 | + if (!strcmp(tname, type_name)) |
| 998 | + return ret; |
| 999 | + else |
| 1000 | + break; |
| 1001 | + } while (++ret <= end_id); |
| 1002 | + } else { |
| 1003 | + /* linear search */ |
| 1004 | + __u32 i, total; |
910 | 1005 |
|
911 | | - if (name && !strcmp(type_name, name)) |
912 | | - return i; |
| 1006 | + total = btf__type_cnt(btf); |
| 1007 | + for (i = start_id; i < total; i++) { |
| 1008 | + t = btf_type_by_id(btf, i); |
| 1009 | + if (kind != -1 && btf_kind(t) != kind) |
| 1010 | + continue; |
| 1011 | + tname = btf__str_by_offset(btf, t->name_off); |
| 1012 | + if (tname && !strcmp(tname, type_name)) |
| 1013 | + return i; |
| 1014 | + } |
913 | 1015 | } |
914 | 1016 |
|
915 | | - return libbpf_err(-ENOENT); |
| 1017 | +out: |
| 1018 | + return err; |
916 | 1019 | } |
917 | 1020 |
|
918 | 1021 | static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id, |
919 | 1022 | const char *type_name, __u32 kind) |
920 | 1023 | { |
921 | | - __u32 i, nr_types = btf__type_cnt(btf); |
922 | | - |
923 | 1024 | if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void")) |
924 | 1025 | return 0; |
925 | 1026 |
|
926 | | - for (i = start_id; i < nr_types; i++) { |
927 | | - const struct btf_type *t = btf__type_by_id(btf, i); |
928 | | - const char *name; |
929 | | - |
930 | | - if (btf_kind(t) != kind) |
931 | | - continue; |
932 | | - name = btf__name_by_offset(btf, t->name_off); |
933 | | - if (name && !strcmp(type_name, name)) |
934 | | - return i; |
935 | | - } |
| 1027 | + return libbpf_err(btf_find_type_by_name_kind(btf, start_id, type_name, kind)); |
| 1028 | +} |
936 | 1029 |
|
937 | | - return libbpf_err(-ENOENT); |
| 1030 | +/* the kind value of -1 indicates that kind matching should be skipped */ |
| 1031 | +__s32 btf__find_by_name(const struct btf *btf, const char *type_name) |
| 1032 | +{ |
| 1033 | + return btf_find_by_name_kind(btf, btf->start_id, type_name, -1); |
938 | 1034 | } |
939 | 1035 |
|
940 | 1036 | __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name, |
@@ -1006,6 +1102,7 @@ static struct btf *btf_new_empty(struct btf *base_btf) |
1006 | 1102 | btf->fd = -1; |
1007 | 1103 | btf->ptr_sz = sizeof(void *); |
1008 | 1104 | btf->swapped_endian = false; |
| 1105 | + btf->nr_sorted_types = BTF_NEED_SORT_CHECK; |
1009 | 1106 |
|
1010 | 1107 | if (base_btf) { |
1011 | 1108 | btf->base_btf = base_btf; |
@@ -1057,6 +1154,7 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, b |
1057 | 1154 | btf->start_id = 1; |
1058 | 1155 | btf->start_str_off = 0; |
1059 | 1156 | btf->fd = -1; |
| 1157 | + btf->nr_sorted_types = BTF_NEED_SORT_CHECK; |
1060 | 1158 |
|
1061 | 1159 | if (base_btf) { |
1062 | 1160 | btf->base_btf = base_btf; |
@@ -1715,6 +1813,7 @@ static void btf_invalidate_raw_data(struct btf *btf) |
1715 | 1813 | free(btf->raw_data_swapped); |
1716 | 1814 | btf->raw_data_swapped = NULL; |
1717 | 1815 | } |
| 1816 | + btf->nr_sorted_types = BTF_NEED_SORT_CHECK; |
1718 | 1817 | } |
1719 | 1818 |
|
1720 | 1819 | /* Ensure BTF is ready to be modified (by splitting into a three memory |
|
0 commit comments